diff --git a/pom.xml b/pom.xml
index fcbdbe0..4848d8b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
tsp.headdb
HeadDB
- 3.3.0
+ 4.0.0
jar
HeadDB
@@ -63,6 +63,13 @@
1.7
provided
+
+
+ me.lokka30
+ treasury-api
+ 1.1.0
+ provided
+
@@ -106,6 +113,13 @@
+
+
+
+ org.apache.maven.plugins
+ maven-javadoc-plugin
+ 3.3.2
+
diff --git a/src/main/java/tsp/headdb/HeadDB.java b/src/main/java/tsp/headdb/HeadDB.java
index 396ea0b..695be82 100644
--- a/src/main/java/tsp/headdb/HeadDB.java
+++ b/src/main/java/tsp/headdb/HeadDB.java
@@ -3,9 +3,10 @@
import org.bukkit.Bukkit;
import org.bukkit.plugin.java.JavaPlugin;
import tsp.headdb.api.HeadAPI;
-import tsp.headdb.command.CommandHeadDB;
-import tsp.headdb.database.DatabaseUpdateTask;
-import tsp.headdb.economy.HEconomyProvider;
+import tsp.headdb.command.HeadDBCommand;
+import tsp.headdb.economy.TreasuryProvider;
+import tsp.headdb.implementation.DatabaseUpdateTask;
+import tsp.headdb.economy.BasicEconomyProvider;
import tsp.headdb.economy.VaultProvider;
import tsp.headdb.listener.JoinListener;
import tsp.headdb.listener.MenuListener;
@@ -19,10 +20,13 @@
import javax.annotation.Nullable;
import java.io.File;
+/**
+ * Main class of HeadDB
+ */
public class HeadDB extends JavaPlugin {
private static HeadDB instance;
- private HEconomyProvider economyProvider;
+ private BasicEconomyProvider economyProvider;
private PlayerDataFile playerData;
private Localization localization;
@@ -42,11 +46,14 @@ public void onEnable() {
if (rawProvider.equalsIgnoreCase("vault")) {
economyProvider = new VaultProvider();
economyProvider.initProvider();
+ } else if (rawProvider.equalsIgnoreCase("treasury")) {
+ economyProvider = new TreasuryProvider();
+ economyProvider.initProvider();
}
}
long refresh = getConfig().getLong("refresh") * 20;
- HeadAPI.getDatabase().updateAsync(heads -> Log.info("Fetched " + HeadAPI.getHeads().size() + " heads!")); // Update database on startup
+ HeadAPI.getDatabase().update(heads -> Log.info("Fetched " + HeadAPI.getHeads().size() + " heads!")); // Update database on startup
Bukkit.getScheduler().runTaskTimerAsynchronously(this, new DatabaseUpdateTask(), refresh, refresh); // Update database on set interval (also saves data)
HeadAPI.getDatabase().setRefresh(refresh);
@@ -54,7 +61,7 @@ public void onEnable() {
new MenuListener(this);
new PagedPaneListener(this);
- getCommand("headdb").setExecutor(new CommandHeadDB());
+ getCommand("headdb").setExecutor(new HeadDBCommand());
Log.debug("Starting metrics...");
new Metrics(this, 9152);
@@ -83,7 +90,7 @@ public PlayerDataFile getPlayerData() {
}
@Nullable
- public HEconomyProvider getEconomyProvider() {
+ public BasicEconomyProvider getEconomyProvider() {
return economyProvider;
}
diff --git a/src/main/java/tsp/headdb/api/HeadAPI.java b/src/main/java/tsp/headdb/api/HeadAPI.java
index 1ee8736..22a4e4a 100644
--- a/src/main/java/tsp/headdb/api/HeadAPI.java
+++ b/src/main/java/tsp/headdb/api/HeadAPI.java
@@ -1,11 +1,14 @@
package tsp.headdb.api;
+import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import org.bukkit.entity.Player;
import tsp.headdb.HeadDB;
-import tsp.headdb.database.Category;
-import tsp.headdb.database.HeadDatabase;
+import tsp.headdb.implementation.Category;
+import tsp.headdb.implementation.Head;
+import tsp.headdb.implementation.HeadDatabase;
+import tsp.headdb.implementation.LocalHead;
import tsp.headdb.inventory.InventoryUtils;
import tsp.headdb.storage.PlayerDataFile;
@@ -14,6 +17,7 @@
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
+import java.util.stream.Collectors;
/**
* This class provides simple methods
@@ -21,7 +25,6 @@
*
* @author TheSilentPro
*/
-// TODO: Possibly change to singleton class
public final class HeadAPI {
private HeadAPI() {}
@@ -45,7 +48,9 @@ public static HeadDatabase getDatabase() {
*
* @param player Target player
*/
- public static void openDatabase(Player player) {
+ public static void openDatabase(@Nonnull Player player) {
+ Validate.notNull(player, "Player can not be null!");
+
InventoryUtils.openDatabase(player);
}
@@ -55,7 +60,10 @@ public static void openDatabase(Player player) {
* @param player Target player
* @param category Category to open
*/
- public static void openCategoryDatabase(Player player, Category category) {
+ public static void openCategoryDatabase(@Nonnull Player player, @Nonnull Category category) {
+ Validate.notNull(player, "Player can not be null!");
+ Validate.notNull(category, "Category can not be null!");
+
InventoryUtils.openCategoryDatabase(player, category);
}
@@ -65,7 +73,10 @@ public static void openCategoryDatabase(Player player, Category category) {
* @param player Target player
* @param search Search term
*/
- public static void openSearchDatabase(Player player, String search) {
+ public static void openSearchDatabase(@Nonnull Player player, @Nonnull String search) {
+ Validate.notNull(player, "Player can not be null!");
+ Validate.notNull(search, "Search can not be null!");
+
InventoryUtils.openSearchDatabase(player, search);
}
@@ -75,7 +86,10 @@ public static void openSearchDatabase(Player player, String search) {
* @param player Target player
* @param tag Tag search term
*/
- public static void openTagSearchDatabase(Player player, String tag) {
+ public static void openTagSearchDatabase(@Nonnull Player player, @Nonnull String tag) {
+ Validate.notNull(player, "Player can not be null!");
+ Validate.notNull(tag, "Tag can not be null!");
+
InventoryUtils.openTagSearchDatabase(player, tag);
}
@@ -97,7 +111,9 @@ public static Head getHeadByID(int id) {
* @return The head
*/
@Nullable
- public static Head getHeadByUniqueId(UUID uuid) {
+ public static Head getHeadByUniqueId(@Nonnull UUID uuid) {
+ Validate.notNull(uuid, "UUID can not be null!");
+
return database.getHeadByUniqueId(uuid);
}
@@ -108,7 +124,9 @@ public static Head getHeadByUniqueId(UUID uuid) {
* @return List of heads
*/
@Nonnull
- public static List
getHeadsByTag(String tag) {
+ public static List getHeadsByTag(@Nonnull String tag) {
+ Validate.notNull(tag, "Tag can not be null!");
+
return database.getHeadsByTag(tag);
}
@@ -119,7 +137,9 @@ public static List getHeadsByTag(String tag) {
* @return List of heads
*/
@Nonnull
- public static List getHeadsByName(String name) {
+ public static List getHeadsByName(@Nonnull String name) {
+ Validate.notNull(name, "Name can not be null!");
+
return database.getHeadsByName(name);
}
@@ -131,7 +151,10 @@ public static List getHeadsByName(String name) {
* @return List of heads
*/
@Nonnull
- public static List getHeadsByName(Category category, String name) {
+ public static List getHeadsByName(@Nonnull Category category, @Nonnull String name) {
+ Validate.notNull(category, "Category can not be null!");
+ Validate.notNull(name, "Name can not be null!");
+
return database.getHeadsByName(category, name);
}
@@ -142,7 +165,9 @@ public static List getHeadsByName(Category category, String name) {
* @return The head
*/
@Nullable
- public static Head getHeadByValue(String value) {
+ public static Head getHeadByValue(@Nonnull String value) {
+ Validate.notNull(value, "Value can not be null!");
+
return database.getHeadByValue(value);
}
@@ -153,7 +178,9 @@ public static Head getHeadByValue(String value) {
* @return List of heads
*/
@Nonnull
- public static List getHeads(Category category) {
+ public static List getHeads(@Nonnull Category category) {
+ Validate.notNull(category, "Category can not be null!");
+
return database.getHeads(category);
}
@@ -173,7 +200,10 @@ public static List getHeads() {
* @param uuid The player's unique id
* @param textureValue The head's texture value
*/
- public static void addFavoriteHead(UUID uuid, String textureValue) {
+ public static void addFavoriteHead(@Nonnull UUID uuid, @Nonnull String textureValue) {
+ Validate.notNull(uuid, "UUID can not be null!");
+ Validate.notNull(textureValue, "Value can not be null!");
+
HeadDB.getInstance().getPlayerData().modifyFavorite(uuid, textureValue, PlayerDataFile.ModificationType.SET);
}
@@ -183,7 +213,10 @@ public static void addFavoriteHead(UUID uuid, String textureValue) {
* @param uuid The player's unique id
* @param textureValue The head's texture value
*/
- public static void removeFavoriteHead(UUID uuid, String textureValue) {
+ public static void removeFavoriteHead(@Nonnull UUID uuid, @Nonnull String textureValue) {
+ Validate.notNull(uuid, "UUID can not be null!");
+ Validate.notNull(textureValue, "Value can not be null!");
+
HeadDB.getInstance().getPlayerData().modifyFavorite(uuid, textureValue, PlayerDataFile.ModificationType.REMOVE);
}
@@ -194,15 +227,13 @@ public static void removeFavoriteHead(UUID uuid, String textureValue) {
* @return List of favorite {@link Head}'s for the player
*/
@Nonnull
- public static List getFavoriteHeads(UUID uuid) {
- List result = new ArrayList<>();
-
- List textures = HeadDB.getInstance().getPlayerData().getFavoriteHeadsByTexture(uuid);
- for (String texture : textures) {
- result.add(HeadAPI.getHeadByValue(texture));
- }
+ public static List getFavoriteHeads(@Nonnull UUID uuid) {
+ Validate.notNull(uuid, "UUID can not be null!");
- return result;
+ return HeadDB.getInstance().getPlayerData().getFavoriteHeadsByTexture(uuid).stream()
+ .map(HeadAPI::getHeadByValue)
+ .filter(head -> head != null)
+ .collect(Collectors.toList());
}
/**
@@ -214,13 +245,10 @@ public static List getFavoriteHeads(UUID uuid) {
*/
@Nonnull
public static List getLocalHeads() {
- List result = new ArrayList<>();
- for (String entry : HeadDB.getInstance().getPlayerData().getEntries()) {
- OfflinePlayer player = Bukkit.getOfflinePlayer(UUID.fromString(entry));
- result.add(new LocalHead(player.getUniqueId()).name(player.getName()));
- }
-
- return result;
+ return HeadDB.getInstance().getPlayerData().getEntries().stream()
+ .map(entry -> Bukkit.getOfflinePlayer(UUID.fromString(entry)))
+ .map(player -> new LocalHead(player.getUniqueId()).name(player.getName()))
+ .collect(Collectors.toList());
}
}
diff --git a/src/main/java/tsp/headdb/event/DatabaseUpdateEvent.java b/src/main/java/tsp/headdb/api/event/DatabaseUpdateEvent.java
similarity index 82%
rename from src/main/java/tsp/headdb/event/DatabaseUpdateEvent.java
rename to src/main/java/tsp/headdb/api/event/DatabaseUpdateEvent.java
index b25b02f..f46f54f 100644
--- a/src/main/java/tsp/headdb/event/DatabaseUpdateEvent.java
+++ b/src/main/java/tsp/headdb/api/event/DatabaseUpdateEvent.java
@@ -1,16 +1,16 @@
-package tsp.headdb.event;
+package tsp.headdb.api.event;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
-import tsp.headdb.api.Head;
-import tsp.headdb.database.Category;
-import tsp.headdb.database.HeadDatabase;
+import tsp.headdb.implementation.Head;
+import tsp.headdb.implementation.Category;
+import tsp.headdb.implementation.HeadDatabase;
import java.util.List;
import java.util.Map;
/**
- * This event is called AFTER a {@link tsp.headdb.database.HeadDatabase} updates.
+ * This event is called AFTER a {@link HeadDatabase} updates.
* The event is called asynchronously and can not be cancelled.
*
* @author TheSilentPro
diff --git a/src/main/java/tsp/headdb/event/PlayerHeadPurchaseEvent.java b/src/main/java/tsp/headdb/api/event/PlayerHeadPurchaseEvent.java
similarity index 93%
rename from src/main/java/tsp/headdb/event/PlayerHeadPurchaseEvent.java
rename to src/main/java/tsp/headdb/api/event/PlayerHeadPurchaseEvent.java
index 0feaf18..a9faf87 100644
--- a/src/main/java/tsp/headdb/event/PlayerHeadPurchaseEvent.java
+++ b/src/main/java/tsp/headdb/api/event/PlayerHeadPurchaseEvent.java
@@ -1,10 +1,10 @@
-package tsp.headdb.event;
+package tsp.headdb.api.event;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;
import org.bukkit.event.HandlerList;
-import tsp.headdb.api.Head;
+import tsp.headdb.implementation.Head;
/**
* This event is called when a player purchases a {@link Head}
@@ -21,6 +21,7 @@ public class PlayerHeadPurchaseEvent extends Event implements Cancellable {
private double cost;
public PlayerHeadPurchaseEvent(Player player, Head head, double cost) {
+ super(true);
this.player = player;
this.head = head;
this.cost = cost;
diff --git a/src/main/java/tsp/headdb/command/CommandHeadDB.java b/src/main/java/tsp/headdb/command/CommandHeadDB.java
deleted file mode 100644
index 43f70e7..0000000
--- a/src/main/java/tsp/headdb/command/CommandHeadDB.java
+++ /dev/null
@@ -1,175 +0,0 @@
-package tsp.headdb.command;
-
-import org.bukkit.Bukkit;
-import org.bukkit.command.Command;
-import org.bukkit.command.CommandExecutor;
-import org.bukkit.command.CommandSender;
-import org.bukkit.entity.Player;
-import org.bukkit.inventory.ItemStack;
-import tsp.headdb.HeadDB;
-import tsp.headdb.api.Head;
-import tsp.headdb.api.HeadAPI;
-import tsp.headdb.util.Localization;
-import tsp.headdb.util.Utils;
-
-import java.util.concurrent.TimeUnit;
-
-// TODO: Cleaner way to handle this command
-public class CommandHeadDB implements CommandExecutor {
-
- @Override
- public boolean onCommand(CommandSender sender, Command command, String s, String[] args) {
- Localization localization = HeadDB.getInstance().getLocalization();
- if (args.length == 0) {
- if (!sender.hasPermission("headdb.open")) {
- Utils.sendMessage(sender, localization.getMessage("noPermission"));
- return true;
- }
- if (!(sender instanceof Player)) {
- Utils.sendMessage(sender, localization.getMessage("onlyPlayers"));
- return true;
- }
- Player player = (Player) sender;
-
- Utils.sendMessage(player, localization.getMessage("databaseOpen"));
- HeadAPI.openDatabase(player);
- return true;
- }
- String sub = args[0];
-
- if (sub.equalsIgnoreCase("info") || sub.equalsIgnoreCase("i")) {
- // These should not be customizable
- Utils.sendMessage(sender, "&7Running &cHeadDB - " + HeadDB.getInstance().getDescription().getVersion());
- Utils.sendMessage(sender, "&7Created by &c" + HeadDB.getInstance().getDescription().getAuthors());
- Utils.sendMessage(sender, "&7There are currently &c" + HeadAPI.getHeads().size() + " &7heads in the database.");
- return true;
- }
-
- if (sub.equalsIgnoreCase("reload") || sub.equalsIgnoreCase("r")) {
- if (!sender.hasPermission("headdb.reload")) {
- Utils.sendMessage(sender, localization.getMessage("noPermission"));
- return true;
- }
- HeadDB.getInstance().getLocalization().load();
- Utils.sendMessage(sender, localization.getMessage("reloadMessages"));
- return true;
- }
-
- if (sub.equalsIgnoreCase("search") || sub.equalsIgnoreCase("s")) {
- if (!sender.hasPermission("headdb.search")) {
- Utils.sendMessage(sender, localization.getMessage("noPermission"));
- return true;
- }
- if (!(sender instanceof Player)) {
- Utils.sendMessage(sender, localization.getMessage("onlyPlayers"));
- return true;
- }
- Player player = (Player) sender;
-
- if (args.length < 2) {
- Utils.sendMessage(player, "&c/hdb search ");
- return true;
- }
-
- StringBuilder builder = new StringBuilder();
- for (int i = 1; i < args.length; i++) {
- builder.append(args[i]);
- if (i != args.length - 1) {
- builder.append(" ");
- }
- }
- String name = builder.toString();
- Utils.sendMessage(sender, "&7Searching for &e" + name);
- HeadAPI.openSearchDatabase(player, name);
- return true;
- }
-
- if (sub.equalsIgnoreCase("tagsearch") || sub.equalsIgnoreCase("ts")) {
- if (!sender.hasPermission("headdb.tagsearch")) {
- Utils.sendMessage(sender, localization.getMessage("noPermission"));
- return true;
- }
- if (args.length < 2) {
- Utils.sendMessage(sender, "&c/hdb tagsearch ");
- return true;
- }
- if (!(sender instanceof Player)) {
- Utils.sendMessage(sender, localization.getMessage("onlyPlayers"));
- return true;
- }
- Player player = (Player) sender;
-
- String tag = args[1];
- Utils.sendMessage(sender, "&7Searching for heads with tag &e" + tag);
- HeadAPI.openTagSearchDatabase(player, tag);
- return true;
- }
-
- if (sub.equalsIgnoreCase("give") || sub.equalsIgnoreCase("g")) {
- if (!sender.hasPermission("headdb.give")) {
- Utils.sendMessage(sender, localization.getMessage("noPermission"));
- return true;
- }
- if (args.length < 3) {
- Utils.sendMessage(sender, "&c/hdb give &6[amount]");
- return true;
- }
- try {
- int id = Integer.parseInt(args[1]);
- Player target = Bukkit.getPlayer(args[2]);
- if (target == null) {
- Utils.sendMessage(sender, localization.getMessage("invalidPlayer"));
- return true;
- }
-
- int amount = 1;
- if (args.length > 3) {
- amount = Integer.parseInt(args[3]);
- }
-
- Head head = HeadAPI.getHeadByID(id);
- if (head == null) {
- Utils.sendMessage(sender, "&cCould not find head with id &e" + id);
- return true;
- }
- ItemStack item = head.getMenuItem();
- item.setAmount(amount);
- target.getInventory().addItem(item);
- Utils.sendMessage(sender, "&7Gave &6" + target.getName() + " &ex" + amount + " " + head.getName());
- return true;
- } catch (NumberFormatException nfe) {
- Utils.sendMessage(sender, "&cID/Amount must be a number!");
- return true;
- }
- }
-
- if (sub.equalsIgnoreCase("update") || sub.equalsIgnoreCase("u")) {
- if (!sender.hasPermission("headdb.update")) {
- Utils.sendMessage(sender, "&cNo permission!");
- return true;
- }
-
- Utils.sendMessage(sender, "&7Updating...");
- long start = System.currentTimeMillis();
- HeadAPI.getDatabase().updateAsync(heads -> {
- Utils.sendMessage(sender, "&7Done! Took: &a" + TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis() - start) + " &7seconds");
- Utils.sendMessage(sender, "&7There are &a" + HeadAPI.getHeads().size() + " &7heads in the database!");
- });
- return true;
- }
-
- Utils.sendMessage(sender, " ");
- Utils.sendMessage(sender, "&c&lHeadDB &c- &5Commands");
- Utils.sendMessage(sender, "&7&oParameters:&c command &9(aliases)&c arguments... &7- Description");
- Utils.sendMessage(sender, "&7 > &c/hdb &7- Opens the database");
- Utils.sendMessage(sender, "&7 > &c/hdb info &9(i) &7- Plugin Information");
- Utils.sendMessage(sender, "&7 > &c/hdb reload &9(r) &7- Reloads the messages file");
- Utils.sendMessage(sender, "&7 > &c/hdb search &9(s) &c &7- Search for heads matching a name");
- Utils.sendMessage(sender, "&7 > &c/hdb tagsearch &9(ts) &c &7- Search for heads matching a tag");
- Utils.sendMessage(sender, "&7 > &c/hdb update &9(u) &7- Forcefully update the database");
- Utils.sendMessage(sender, "&7 > &c/hdb give &9(g) &c &6[amount] &7- Give player a head");
- Utils.sendMessage(sender, " ");
- return true;
- }
-
-}
\ No newline at end of file
diff --git a/src/main/java/tsp/headdb/command/GiveCommand.java b/src/main/java/tsp/headdb/command/GiveCommand.java
new file mode 100644
index 0000000..99cd4f8
--- /dev/null
+++ b/src/main/java/tsp/headdb/command/GiveCommand.java
@@ -0,0 +1,53 @@
+package tsp.headdb.command;
+
+import org.bukkit.Bukkit;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+import org.bukkit.inventory.ItemStack;
+import tsp.headdb.api.HeadAPI;
+import tsp.headdb.implementation.Head;
+import tsp.headdb.util.Utils;
+
+public class GiveCommand implements HeadSubCommand {
+
+ @Override
+ public void handle(CommandSender sender, String[] args) {
+ if (!sender.hasPermission("headdb.give")) {
+ Utils.sendMessage(sender, getLocalization().getMessage("noPermission"));
+ return;
+ }
+
+ if (args.length < 3) {
+ Utils.sendMessage(sender, "&c/hdb give &6[amount]");
+ return;
+ }
+
+ try {
+ int id = Integer.parseInt(args[1]);
+ Player target = Bukkit.getPlayer(args[2]);
+ if (target == null) {
+ Utils.sendMessage(sender, getLocalization().getMessage("invalidPlayer"));
+ return;
+ }
+
+ int amount = 1;
+ if (args.length > 3) {
+ amount = Integer.parseInt(args[3]);
+ }
+
+ Head head = HeadAPI.getHeadByID(id);
+ if (head == null) {
+ Utils.sendMessage(sender, "&cCould not find head with id &e" + id);
+ return;
+ }
+
+ ItemStack item = head.getMenuItem();
+ item.setAmount(amount);
+ target.getInventory().addItem(item);
+ Utils.sendMessage(sender, "&7Gave &6" + target.getName() + " &ex" + amount + " " + head.getName());
+ } catch (NumberFormatException nfe) {
+ Utils.sendMessage(sender, "&cID/Amount must be a number!");
+ }
+ }
+
+}
diff --git a/src/main/java/tsp/headdb/command/HeadDBCommand.java b/src/main/java/tsp/headdb/command/HeadDBCommand.java
new file mode 100644
index 0000000..e9f7516
--- /dev/null
+++ b/src/main/java/tsp/headdb/command/HeadDBCommand.java
@@ -0,0 +1,68 @@
+package tsp.headdb.command;
+
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandExecutor;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+import tsp.headdb.HeadDB;
+import tsp.headdb.api.HeadAPI;
+import tsp.headdb.util.Localization;
+import tsp.headdb.util.Utils;
+
+public class HeadDBCommand implements CommandExecutor {
+
+ @Override
+ public boolean onCommand(CommandSender sender, Command command, String s, String[] args) {
+ Localization localization = HeadDB.getInstance().getLocalization();
+ if (args.length == 0) {
+ if (!sender.hasPermission("headdb.open")) {
+ Utils.sendMessage(sender, localization.getMessage("noPermission"));
+ return true;
+ }
+ if (!(sender instanceof Player)) {
+ Utils.sendMessage(sender, localization.getMessage("onlyPlayers"));
+ return true;
+ }
+ Player player = (Player) sender;
+
+ Utils.sendMessage(player, localization.getMessage("databaseOpen"));
+ HeadAPI.openDatabase(player);
+ return true;
+ }
+
+ String sub = args[0];
+ HeadSubCommand subCommand = null;
+ if (sub.equalsIgnoreCase("info") || sub.equalsIgnoreCase("i")) {
+ subCommand = new InfoCommand();
+ } else if (sub.equalsIgnoreCase("reload") || sub.equalsIgnoreCase("r")) {
+ subCommand = new ReloadCommand();
+ } else if (sub.equalsIgnoreCase("search") || sub.equalsIgnoreCase("s")) {
+ subCommand = new SearchCommand();
+ } else if (sub.equalsIgnoreCase("tagsearch") || sub.equalsIgnoreCase("ts")) {
+ subCommand = new TagSearchCommand();
+ } else if (sub.equalsIgnoreCase("give") || sub.equalsIgnoreCase("g")) {
+ subCommand = new GiveCommand();
+ } else if (sub.equalsIgnoreCase("update") || sub.equalsIgnoreCase("u")) {
+ subCommand = new UpdateCommand();
+ }
+
+ if (subCommand != null) {
+ subCommand.handle(sender, args);
+ return true;
+ }
+
+ Utils.sendMessage(sender, " ");
+ Utils.sendMessage(sender, "&c&lHeadDB &c- &5Commands");
+ Utils.sendMessage(sender, "&7&oParameters:&c command &9(aliases)&c arguments... &7- Description");
+ Utils.sendMessage(sender, "&7 > &c/hdb &7- Opens the database");
+ Utils.sendMessage(sender, "&7 > &c/hdb info &9(i) &7- Plugin Information");
+ Utils.sendMessage(sender, "&7 > &c/hdb reload &9(r) &7- Reloads the messages file");
+ Utils.sendMessage(sender, "&7 > &c/hdb search &9(s) &c &7- Search for heads matching a name");
+ Utils.sendMessage(sender, "&7 > &c/hdb tagsearch &9(ts) &c &7- Search for heads matching a tag");
+ Utils.sendMessage(sender, "&7 > &c/hdb update &9(u) &7- Forcefully update the database");
+ Utils.sendMessage(sender, "&7 > &c/hdb give &9(g) &c &6[amount] &7- Give player a head");
+ Utils.sendMessage(sender, " ");
+ return true;
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/tsp/headdb/command/HeadSubCommand.java b/src/main/java/tsp/headdb/command/HeadSubCommand.java
new file mode 100644
index 0000000..020f84f
--- /dev/null
+++ b/src/main/java/tsp/headdb/command/HeadSubCommand.java
@@ -0,0 +1,21 @@
+package tsp.headdb.command;
+
+import org.bukkit.command.CommandSender;
+import tsp.headdb.HeadDB;
+import tsp.headdb.util.Localization;
+
+/**
+ * An interface for a HeadDB sub-command
+ *
+ * @author TheSilentPro
+ * @since 4.0.0
+ */
+public interface HeadSubCommand {
+
+ void handle(CommandSender sender, String[] args);
+
+ default Localization getLocalization() {
+ return HeadDB.getInstance().getLocalization();
+ }
+
+}
diff --git a/src/main/java/tsp/headdb/command/InfoCommand.java b/src/main/java/tsp/headdb/command/InfoCommand.java
new file mode 100644
index 0000000..18a5694
--- /dev/null
+++ b/src/main/java/tsp/headdb/command/InfoCommand.java
@@ -0,0 +1,18 @@
+package tsp.headdb.command;
+
+import org.bukkit.command.CommandSender;
+import tsp.headdb.HeadDB;
+import tsp.headdb.api.HeadAPI;
+import tsp.headdb.util.Utils;
+
+public class InfoCommand implements HeadSubCommand {
+
+ @Override
+ public void handle(CommandSender sender, String[] args) {
+ // These should not be customizable
+ Utils.sendMessage(sender, "&7Running &cHeadDB - " + HeadDB.getInstance().getDescription().getVersion());
+ Utils.sendMessage(sender, "&7Created by &c" + HeadDB.getInstance().getDescription().getAuthors());
+ Utils.sendMessage(sender, "&7There are currently &c" + HeadAPI.getHeads().size() + " &7heads in the database.");
+ }
+
+}
diff --git a/src/main/java/tsp/headdb/command/ReloadCommand.java b/src/main/java/tsp/headdb/command/ReloadCommand.java
new file mode 100644
index 0000000..0665d6a
--- /dev/null
+++ b/src/main/java/tsp/headdb/command/ReloadCommand.java
@@ -0,0 +1,20 @@
+package tsp.headdb.command;
+
+import org.bukkit.command.CommandSender;
+import tsp.headdb.HeadDB;
+import tsp.headdb.util.Utils;
+
+public class ReloadCommand implements HeadSubCommand {
+
+ @Override
+ public void handle(CommandSender sender, String[] args) {
+ if (!sender.hasPermission("headdb.reload")) {
+ Utils.sendMessage(sender, getLocalization().getMessage("noPermission"));
+ return;
+ }
+
+ HeadDB.getInstance().getLocalization().load();
+ Utils.sendMessage(sender, getLocalization().getMessage("reloadMessages"));
+ }
+
+}
diff --git a/src/main/java/tsp/headdb/command/SearchCommand.java b/src/main/java/tsp/headdb/command/SearchCommand.java
new file mode 100644
index 0000000..e709b93
--- /dev/null
+++ b/src/main/java/tsp/headdb/command/SearchCommand.java
@@ -0,0 +1,40 @@
+package tsp.headdb.command;
+
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+import tsp.headdb.api.HeadAPI;
+import tsp.headdb.util.Utils;
+
+public class SearchCommand implements HeadSubCommand {
+
+ @Override
+ public void handle(CommandSender sender, String[] args) {
+ if (!sender.hasPermission("headdb.search")) {
+ Utils.sendMessage(sender, getLocalization().getMessage("noPermission"));
+ return;
+ }
+ if (!(sender instanceof Player)) {
+ Utils.sendMessage(sender, getLocalization().getMessage("onlyPlayers"));
+ return;
+ }
+ Player player = (Player) sender;
+
+ if (args.length < 2) {
+ Utils.sendMessage(player, "&c/hdb search ");
+ return;
+ }
+
+ StringBuilder builder = new StringBuilder();
+ for (int i = 1; i < args.length; i++) {
+ builder.append(args[i]);
+ if (i != args.length - 1) {
+ builder.append(" ");
+ }
+ }
+ String name = builder.toString();
+ Utils.sendMessage(sender, "&7Searching for &e" + name);
+ HeadAPI.openSearchDatabase(player, name);
+ return;
+ }
+
+}
diff --git a/src/main/java/tsp/headdb/command/TagSearchCommand.java b/src/main/java/tsp/headdb/command/TagSearchCommand.java
new file mode 100644
index 0000000..664c409
--- /dev/null
+++ b/src/main/java/tsp/headdb/command/TagSearchCommand.java
@@ -0,0 +1,34 @@
+package tsp.headdb.command;
+
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+import tsp.headdb.api.HeadAPI;
+import tsp.headdb.util.Utils;
+
+public class TagSearchCommand implements HeadSubCommand {
+
+ @Override
+ public void handle(CommandSender sender, String[] args) {
+ if (!sender.hasPermission("headdb.tagsearch")) {
+ Utils.sendMessage(sender, getLocalization().getMessage("noPermission"));
+ return;
+ }
+
+ if (args.length < 2) {
+ Utils.sendMessage(sender, "&c/hdb tagsearch ");
+ return;
+ }
+
+ if (!(sender instanceof Player)) {
+ Utils.sendMessage(sender, getLocalization().getMessage("onlyPlayers"));
+ return;
+ }
+
+ Player player = (Player) sender;
+ String tag = args[1];
+ Utils.sendMessage(sender, "&7Searching for heads with tag &e" + tag);
+ HeadAPI.openTagSearchDatabase(player, tag);
+ return;
+ }
+
+}
diff --git a/src/main/java/tsp/headdb/command/UpdateCommand.java b/src/main/java/tsp/headdb/command/UpdateCommand.java
new file mode 100644
index 0000000..d3765ff
--- /dev/null
+++ b/src/main/java/tsp/headdb/command/UpdateCommand.java
@@ -0,0 +1,26 @@
+package tsp.headdb.command;
+
+import org.bukkit.command.CommandSender;
+import tsp.headdb.api.HeadAPI;
+import tsp.headdb.util.Utils;
+
+import java.util.concurrent.TimeUnit;
+
+public class UpdateCommand implements HeadSubCommand {
+
+ @Override
+ public void handle(CommandSender sender, String[] args) {
+ if (!sender.hasPermission("headdb.update")) {
+ Utils.sendMessage(sender, getLocalization().getMessage("noPermission"));
+ return;
+ }
+
+ Utils.sendMessage(sender, "&7Updating...");
+ long start = System.currentTimeMillis();
+ HeadAPI.getDatabase().update(heads -> {
+ Utils.sendMessage(sender, "&7Done! Took: &a" + TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis() - start) + " &7seconds");
+ Utils.sendMessage(sender, "&7There are &a" + HeadAPI.getHeads().size() + " &7heads in the database!");
+ });
+ }
+
+}
diff --git a/src/main/java/tsp/headdb/economy/BasicEconomyProvider.java b/src/main/java/tsp/headdb/economy/BasicEconomyProvider.java
new file mode 100644
index 0000000..f1b3e83
--- /dev/null
+++ b/src/main/java/tsp/headdb/economy/BasicEconomyProvider.java
@@ -0,0 +1,48 @@
+package tsp.headdb.economy;
+
+import org.bukkit.entity.Player;
+
+import java.math.BigDecimal;
+import java.util.function.Consumer;
+
+/**
+ * An interface for generalizing Economy Provider's
+ *
+ * @author TheSilentPro
+ * @since 4.0.0
+ * @see VaultProvider
+ * @see TreasuryProvider
+ */
+public interface BasicEconomyProvider {
+
+ /**
+ * Retrieve if the player can purchase a head using this economy provider
+ *
+ * @param player The player
+ * @param cost The cost
+ * @param result If the player has enough to purchase
+ */
+ default void canPurchase(Player player, BigDecimal cost, Consumer result) {
+ result.accept(true);
+ }
+
+ /**
+ * Charge the player a specific amount using this economy provider
+ *
+ * @param player The player
+ * @param amount The amount
+ * @param result If the transaction was successful
+ */
+ default void charge(Player player, BigDecimal amount, Consumer result) {
+ result.accept(true);
+ }
+
+ /**
+ * Convenience method for initializing economy
+ *
+ * @see VaultProvider#initProvider()
+ * @see TreasuryProvider#initProvider()
+ */
+ void initProvider();
+
+}
diff --git a/src/main/java/tsp/headdb/economy/HEconomyProvider.java b/src/main/java/tsp/headdb/economy/HEconomyProvider.java
deleted file mode 100644
index aba0192..0000000
--- a/src/main/java/tsp/headdb/economy/HEconomyProvider.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package tsp.headdb.economy;
-
-import org.bukkit.entity.Player;
-
-import java.math.BigDecimal;
-
-public interface HEconomyProvider {
-
- default boolean canPurchase(Player player, BigDecimal cost) {
- return true;
- }
-
- default void charge(Player player, BigDecimal amount) {
-
- }
-
- default void initProvider() {
-
- }
-
-}
diff --git a/src/main/java/tsp/headdb/economy/TreasuryProvider.java b/src/main/java/tsp/headdb/economy/TreasuryProvider.java
new file mode 100644
index 0000000..480f107
--- /dev/null
+++ b/src/main/java/tsp/headdb/economy/TreasuryProvider.java
@@ -0,0 +1,101 @@
+package tsp.headdb.economy;
+
+import me.lokka30.treasury.api.common.service.Service;
+import me.lokka30.treasury.api.common.service.ServiceRegistry;
+import me.lokka30.treasury.api.economy.EconomyProvider;
+import me.lokka30.treasury.api.economy.account.PlayerAccount;
+import me.lokka30.treasury.api.economy.currency.Currency;
+import me.lokka30.treasury.api.economy.response.EconomyException;
+import me.lokka30.treasury.api.economy.response.EconomySubscriber;
+import me.lokka30.treasury.api.economy.transaction.EconomyTransactionInitiator;
+import org.bukkit.entity.Player;
+import org.jetbrains.annotations.NotNull;
+import tsp.headdb.HeadDB;
+import tsp.headdb.util.Log;
+
+import java.math.BigDecimal;
+import java.util.Optional;
+import java.util.function.Consumer;
+
+/**
+ * A {@link BasicEconomyProvider} for Treasury
+ *
+ * @author TheSilentPro
+ * @since 4.0.0
+ */
+public class TreasuryProvider implements BasicEconomyProvider {
+
+ private EconomyProvider provider;
+ private EconomyTransactionInitiator> transactionInitiator;
+ private Currency currency;
+
+ @Override
+ public void canPurchase(Player player, BigDecimal cost, Consumer result) {
+ EconomySubscriber
+ .asFuture(s -> provider.hasPlayerAccount(player.getUniqueId(), s))
+ .thenCompose(val -> {
+ if (val) {
+ return EconomySubscriber.asFuture(s -> provider.retrievePlayerAccount(player.getUniqueId(), s));
+ } else {
+ return EconomySubscriber.asFuture(s -> provider.createPlayerAccount(player.getUniqueId(), s));
+ }
+ })
+ .thenCompose(account -> EconomySubscriber.asFuture(s -> account.retrieveBalance(currency, s)))
+ .whenComplete((bal, ex) -> {
+ result.accept(bal.compareTo(cost) >= 0);
+ });
+ }
+
+ @Override
+ public void charge(Player player, BigDecimal amount, Consumer result) {
+ EconomySubscriber
+ .asFuture(s -> provider.hasPlayerAccount(player.getUniqueId(), s))
+ .thenCompose(val -> {
+ if (val) {
+ return EconomySubscriber.asFuture(s -> provider.retrievePlayerAccount(player.getUniqueId(), s));
+ } else {
+ return EconomySubscriber.asFuture(s -> provider.createPlayerAccount(player.getUniqueId(), s));
+ }
+ }).whenComplete((account, ex) -> {
+ account.withdrawBalance(
+ amount,
+ transactionInitiator,
+ currency,
+ new EconomySubscriber() {
+ @Override
+ public void succeed(@NotNull BigDecimal bigDecimal) {
+ result.accept(true);
+ }
+
+ @Override
+ public void fail(@NotNull EconomyException exception) {
+ result.accept(false);
+ exception.printStackTrace();
+ }
+ });
+ });
+ }
+
+ @Override
+ public void initProvider() {
+ Optional> service = ServiceRegistry.INSTANCE.serviceFor(EconomyProvider.class);
+
+ if(!service.isPresent()) {
+ Log.error("Unable to find a supported economy plugin for Treasury!");
+ return;
+ }
+
+ provider = service.get().get();
+ transactionInitiator = EconomyTransactionInitiator.createInitiator(EconomyTransactionInitiator.Type.PLUGIN, "HeadDB");
+
+ String rawCurrency = HeadDB.getInstance().getConfig().getString("economy.currency");
+ if (rawCurrency == null || rawCurrency.isEmpty()) {
+ currency = provider.getPrimaryCurrency();
+ } else {
+ currency = provider.getCurrencies().stream()
+ .filter(currency -> currency.getIdentifier().equalsIgnoreCase(rawCurrency))
+ .findFirst().get();
+ }
+ }
+
+}
diff --git a/src/main/java/tsp/headdb/economy/VaultProvider.java b/src/main/java/tsp/headdb/economy/VaultProvider.java
index c5c19f1..1b7d6b6 100644
--- a/src/main/java/tsp/headdb/economy/VaultProvider.java
+++ b/src/main/java/tsp/headdb/economy/VaultProvider.java
@@ -5,21 +5,29 @@
import org.bukkit.entity.Player;
import org.bukkit.plugin.RegisteredServiceProvider;
import tsp.headdb.util.Log;
+import tsp.headdb.util.Utils;
import java.math.BigDecimal;
+import java.util.function.Consumer;
-public class VaultProvider implements HEconomyProvider {
+/**
+ * A {@link BasicEconomyProvider} for Vault
+ *
+ * @author TheSilentPro
+ * @since 4.0.0
+ */
+public class VaultProvider implements BasicEconomyProvider {
private Economy economy;
@Override
- public boolean canPurchase(Player player, BigDecimal cost) {
- return economy.has(player, cost.doubleValue());
+ public void canPurchase(Player player, BigDecimal cost, Consumer result) {
+ Utils.async(t -> result.accept(economy.has(player, cost.doubleValue())));
}
@Override
- public void charge(Player player, BigDecimal amount) {
- economy.withdrawPlayer(player, amount.doubleValue());
+ public void charge(Player player, BigDecimal amount, Consumer result) {
+ Utils.async(t -> result.accept(economy.withdrawPlayer(player, amount.doubleValue()).transactionSuccess()));
}
public void initProvider() {
diff --git a/src/main/java/tsp/headdb/database/Category.java b/src/main/java/tsp/headdb/implementation/Category.java
similarity index 72%
rename from src/main/java/tsp/headdb/database/Category.java
rename to src/main/java/tsp/headdb/implementation/Category.java
index 0257c03..155f689 100644
--- a/src/main/java/tsp/headdb/database/Category.java
+++ b/src/main/java/tsp/headdb/implementation/Category.java
@@ -1,13 +1,18 @@
-package tsp.headdb.database;
+package tsp.headdb.implementation;
import org.bukkit.ChatColor;
import org.bukkit.inventory.ItemStack;
-import tsp.headdb.api.Head;
import tsp.headdb.api.HeadAPI;
+import javax.annotation.Nullable;
import java.util.HashMap;
import java.util.Map;
+/**
+ * Represents a category for heads
+ *
+ * @author TheSilentPro
+ */
public enum Category {
ALPHABET("alphabet", ChatColor.YELLOW, 20),
@@ -45,15 +50,24 @@ public int getLocation() {
return location;
}
+ /**
+ * Retrieve the first valid head from a category
+ *
+ * @return First valid head
+ */
public ItemStack getItem() {
- if (item.containsKey(this)) {
- return item.get(this).getMenuItem();
- }
-
- item.put(this, HeadAPI.getHeads(this).get(0));
- return getItem();
+ return HeadAPI.getHeads(this).stream()
+ .filter(head -> head != null)
+ .findFirst().get().getMenuItem();
}
+ /**
+ * Retrieve a {@link Category} by name
+ *
+ * @param name The name
+ * @return The category if it exists. Else it returns null
+ */
+ @Nullable
public static Category getByName(String name) {
for (Category category : cache) {
if (category.getName().equalsIgnoreCase(name)) {
diff --git a/src/main/java/tsp/headdb/database/DatabaseUpdateTask.java b/src/main/java/tsp/headdb/implementation/DatabaseUpdateTask.java
similarity index 54%
rename from src/main/java/tsp/headdb/database/DatabaseUpdateTask.java
rename to src/main/java/tsp/headdb/implementation/DatabaseUpdateTask.java
index 44d75f5..9889629 100644
--- a/src/main/java/tsp/headdb/database/DatabaseUpdateTask.java
+++ b/src/main/java/tsp/headdb/implementation/DatabaseUpdateTask.java
@@ -1,15 +1,18 @@
-package tsp.headdb.database;
+package tsp.headdb.implementation;
import tsp.headdb.HeadDB;
import tsp.headdb.api.HeadAPI;
import tsp.headdb.util.Log;
+/**
+ * Task that updates the database on an interval
+ */
public class DatabaseUpdateTask implements Runnable {
@Override
public void run() {
HeadDB.getInstance().getPlayerData().save();
- HeadAPI.getDatabase().updateAsync(heads -> Log.info("Fetched " + HeadAPI.getHeads().size() + " heads!"));
+ HeadAPI.getDatabase().update(heads -> Log.info("Fetched " + HeadAPI.getHeads().size() + " heads!"));
}
}
diff --git a/src/main/java/tsp/headdb/api/Head.java b/src/main/java/tsp/headdb/implementation/Head.java
similarity index 97%
rename from src/main/java/tsp/headdb/api/Head.java
rename to src/main/java/tsp/headdb/implementation/Head.java
index c34eb48..f30c0ff 100644
--- a/src/main/java/tsp/headdb/api/Head.java
+++ b/src/main/java/tsp/headdb/implementation/Head.java
@@ -1,14 +1,11 @@
-package tsp.headdb.api;
+package tsp.headdb.implementation;
import com.mojang.authlib.GameProfile;
import com.mojang.authlib.properties.Property;
import org.apache.commons.lang.Validate;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
-import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.inventory.meta.SkullMeta;
-import tsp.headdb.HeadDB;
-import tsp.headdb.database.Category;
import tsp.headdb.util.Log;
import tsp.headdb.util.Utils;
@@ -17,6 +14,11 @@
import java.util.List;
import java.util.UUID;
+/**
+ * Represents a Head that a player can obtain via the database
+ *
+ * @author TheSilentPro
+ */
public class Head {
private String name;
diff --git a/src/main/java/tsp/headdb/database/HeadDatabase.java b/src/main/java/tsp/headdb/implementation/HeadDatabase.java
similarity index 95%
rename from src/main/java/tsp/headdb/database/HeadDatabase.java
rename to src/main/java/tsp/headdb/implementation/HeadDatabase.java
index 03b388f..630d0c1 100644
--- a/src/main/java/tsp/headdb/database/HeadDatabase.java
+++ b/src/main/java/tsp/headdb/implementation/HeadDatabase.java
@@ -1,4 +1,4 @@
-package tsp.headdb.database;
+package tsp.headdb.implementation;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
@@ -7,8 +7,7 @@
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
-import tsp.headdb.api.Head;
-import tsp.headdb.event.DatabaseUpdateEvent;
+import tsp.headdb.api.event.DatabaseUpdateEvent;
import tsp.headdb.util.Log;
import tsp.headdb.util.Utils;
@@ -18,6 +17,7 @@
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
@@ -117,7 +117,7 @@ public List getHeadsByName(String name) {
}
public List getHeads(Category category) {
- return HEADS.get(category);
+ return Collections.unmodifiableList(HEADS.get(category));
}
/**
@@ -129,7 +129,7 @@ public List getHeads(Category category) {
public List getHeads() {
if (HEADS.isEmpty() || isLastUpdateOld()) {
// Technically this should never be reached due to the update task in the main class.
- updateAsync(result -> {
+ update(result -> {
if (result != null) {
for (Category category : result.keySet()) {
HEADS.put(category, result.get(category));
@@ -145,7 +145,7 @@ public List getHeads() {
return heads;
}
- public void getHeadsNoCacheAsync(Consumer