From b2796f59bde1b9d0db761789c78f8971cb06c4a7 Mon Sep 17 00:00:00 2001 From: Silent Date: Thu, 30 Dec 2021 12:50:47 +0100 Subject: [PATCH] HeadDB 3.0 --- pom.xml | 16 +- src/main/java/tsp/headdb/HeadDB.java | 63 ++++---- src/main/java/tsp/headdb/api/Head.java | 75 +++++---- src/main/java/tsp/headdb/api/HeadAPI.java | 80 +++------- src/main/java/tsp/headdb/api/LocalHead.java | 4 +- ...Command_headdb.java => CommandHeadDB.java} | 51 +++--- .../java/tsp/headdb/database/Category.java | 8 +- .../tsp/headdb/database/HeadDatabase.java | 145 ++++++++--------- .../headdb/event/PlayerHeadPurchaseEvent.java | 3 +- .../tsp/headdb/inventory/InventoryUtils.java | 40 ++--- .../tsp/headdb/listener/JoinListener.java | 6 +- .../tsp/headdb/listener/MenuListener.java | 1 + .../tsp/headdb/storage/PlayerDataFile.java | 149 ++++++++++++++++++ src/main/java/tsp/headdb/util/Log.java | 2 +- src/main/java/tsp/headdb/util/Storage.java | 27 ---- src/main/java/tsp/headdb/util/Utils.java | 2 +- src/main/resources/config.yml | 10 +- src/main/resources/player_data.json | 1 + src/main/resources/plugin.yml | 2 +- 19 files changed, 365 insertions(+), 320 deletions(-) rename src/main/java/tsp/headdb/command/{Command_headdb.java => CommandHeadDB.java} (71%) create mode 100644 src/main/java/tsp/headdb/storage/PlayerDataFile.java delete mode 100644 src/main/java/tsp/headdb/util/Storage.java create mode 100644 src/main/resources/player_data.json diff --git a/pom.xml b/pom.xml index 421e714..e7237f3 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ tsp.headdb HeadDB - 2.4.5 + 3.0.0 jar HeadDB @@ -43,12 +43,6 @@ 1.18-R0.1-SNAPSHOT provided - - - com.googlecode.json-simple - json-simple - 1.1.1 - com.mojang @@ -56,12 +50,6 @@ 1.5.21 provided - - - com.github.simplix-softworks - simplixstorage - 3.2.0 - net.wesjd @@ -111,7 +99,7 @@ - tsp.headdb.HeadDB + tsp.headdb.legacy.HeadDBLegacy diff --git a/src/main/java/tsp/headdb/HeadDB.java b/src/main/java/tsp/headdb/HeadDB.java index 5c9aad4..7e600d0 100644 --- a/src/main/java/tsp/headdb/HeadDB.java +++ b/src/main/java/tsp/headdb/HeadDB.java @@ -1,32 +1,34 @@ package tsp.headdb; -import de.leonhard.storage.Config; +import net.milkbowl.vault.economy.Economy; +import org.bukkit.Bukkit; +import org.bukkit.plugin.RegisteredServiceProvider; import org.bukkit.plugin.java.JavaPlugin; import tsp.headdb.api.HeadAPI; -import tsp.headdb.command.Command_headdb; +import tsp.headdb.command.CommandHeadDB; import tsp.headdb.listener.JoinListener; -import tsp.headdb.listener.PagedPaneListener; import tsp.headdb.listener.MenuListener; +import tsp.headdb.listener.PagedPaneListener; +import tsp.headdb.storage.PlayerDataFile; import tsp.headdb.util.Log; import tsp.headdb.util.Metrics; -import tsp.headdb.util.Storage; -import org.bukkit.plugin.RegisteredServiceProvider; -import net.milkbowl.vault.economy.Economy; public class HeadDB extends JavaPlugin { private static HeadDB instance; - private Storage storage; - private Economy economy = null; + private Economy economy; + private PlayerDataFile playerData; @Override public void onEnable() { instance = this; Log.info("Loading HeadDB - " + getDescription().getVersion()); saveDefaultConfig(); - storage = new Storage().init(this); - if (storage.getConfig().getBoolean("economy.enable")) { + this.playerData = new PlayerDataFile("player_data.json"); + this.playerData.load(); + + if (getConfig().getBoolean("economy.enable")) { Log.debug("Starting economy..."); this.economy = this.setupEconomy(); if (this.economy == null) { @@ -36,29 +38,28 @@ public class HeadDB extends JavaPlugin { } } - if (storage.getConfig().getBoolean("fetchStartup")) { - if (storage.getConfig().getBoolean("asyncStartup")) { - Log.debug("Initializing Database... (ASYNC)"); - HeadAPI.getDatabase().updateAsync(); - } else { - Log.debug("Initializing Database... (SYNC)"); - HeadAPI.updateDatabase(); - } - } + long refresh = getConfig().getLong("refresh") * 20; + HeadAPI.getDatabase().setRefresh(refresh); + Bukkit.getScheduler().runTaskTimerAsynchronously(this, task -> + HeadAPI.getDatabase().updateAsync(heads -> Log.info("Fetched " + HeadAPI.getHeads().size() + " heads!")), + 0L, refresh); - Log.debug("Registering listeners..."); - new PagedPaneListener(this); - new MenuListener(this); new JoinListener(this); + new MenuListener(this); + new PagedPaneListener(this); - Log.debug("Registering commands..."); - getCommand("headdb").setExecutor(new Command_headdb()); + getCommand("headdb").setExecutor(new CommandHeadDB()); Log.debug("Starting metrics..."); new Metrics(this, 9152); Log.info("Done!"); } + @Override + public void onDisable() { + this.playerData.save(); + } + private Economy setupEconomy() { if (!this.getServer().getPluginManager().isPluginEnabled("Vault")) return null; @@ -68,16 +69,12 @@ public class HeadDB extends JavaPlugin { return this.economy = economyProvider.getProvider(); } - public Config getConfiguration() { - return storage.getConfig(); - } - - public Storage getStorage() { - return storage; - } - public Economy getEconomy() { - return this.economy; + return economy; + } + + public PlayerDataFile getPlayerData() { + return playerData; } public static HeadDB getInstance() { diff --git a/src/main/java/tsp/headdb/api/Head.java b/src/main/java/tsp/headdb/api/Head.java index 13a188f..db754f1 100644 --- a/src/main/java/tsp/headdb/api/Head.java +++ b/src/main/java/tsp/headdb/api/Head.java @@ -23,6 +23,7 @@ public class Head { private Category category; private int id; private List tags; + private ItemStack itemStack; public Head() {} @@ -31,35 +32,39 @@ public class Head { } public ItemStack getItemStack() { - Validate.notNull(name, "name must not be null!"); - Validate.notNull(uuid, "uuid must not be null!"); - Validate.notNull(value, "value must not be null!"); + if (itemStack == null) { + Validate.notNull(name, "name must not be null!"); + Validate.notNull(uuid, "uuid must not be null!"); + Validate.notNull(value, "value must not be null!"); - ItemStack item = new ItemStack(Material.PLAYER_HEAD); - SkullMeta meta = (SkullMeta) item.getItemMeta(); - meta.setDisplayName(Utils.colorize(category != null ? category.getColor() + name : "&8" + name)); - // set skull owner - GameProfile profile = new GameProfile(uuid, name); - profile.getProperties().put("textures", new Property("textures", value)); - Field profileField; - try { - profileField = meta.getClass().getDeclaredField("profile"); - profileField.setAccessible(true); - profileField.set(meta, profile); - } catch (NoSuchFieldException | IllegalArgumentException | IllegalAccessException ex) { - Log.error("Could not set skull owner for " + uuid.toString() + " | Stack Trace:"); - ex.printStackTrace(); + ItemStack item = new ItemStack(Material.PLAYER_HEAD); + SkullMeta meta = (SkullMeta) item.getItemMeta(); + meta.setDisplayName(Utils.colorize(category != null ? category.getColor() + name : "&8" + name)); + // set skull owner + GameProfile profile = new GameProfile(uuid, name); + profile.getProperties().put("textures", new Property("textures", value)); + Field profileField; + try { + profileField = meta.getClass().getDeclaredField("profile"); + profileField.setAccessible(true); + profileField.set(meta, profile); + } catch (NoSuchFieldException | IllegalArgumentException | IllegalAccessException ex) { + Log.error("Could not set skull owner for " + uuid.toString() + " | Stack Trace:"); + ex.printStackTrace(); + } + + meta.setLore(Arrays.asList( + Utils.colorize("&cID: " + id), + Utils.colorize("&e" + buildTagLore(tags)), + "", + Utils.colorize("&8Right-Click to add/remove from favorites.") + )); + + item.setItemMeta(meta); + itemStack = item; } - meta.setLore(Arrays.asList( - Utils.colorize("&cID: " + id), - Utils.colorize("&e" + buildTagLore(tags)), - "", - Utils.colorize("&8Right-Click to add/remove from favorites.") - )); - item.setItemMeta(meta); - - return item; + return itemStack; } public String getName() { @@ -86,36 +91,36 @@ public class Head { return tags; } - public Head withName(String name) { + public Head name(String name) { this.name = name; return this; } - public Head withUniqueId(UUID uuid) { + public Head uniqueId(UUID uuid) { this.uuid = uuid; return this; } - public Head withValue(String value) { + public Head value(String value) { this.value = value; return this; } - public Head withCategory(Category category) { + public Head category(Category category) { this.category = category; return this; } - public Head withId(int id) { + public Head id(int id) { this.id = id; return this; } - - public Head withTags(String tags) { + + public Head tags(String tags) { this.tags = Arrays.asList(tags.split(",")); return this; } - + private String buildTagLore(List tags) { StringBuilder builder = new StringBuilder(); for (int i = 0; i < tags.size(); i++) { @@ -124,7 +129,7 @@ public class Head { builder.append(","); } } - + return builder.toString(); } diff --git a/src/main/java/tsp/headdb/api/HeadAPI.java b/src/main/java/tsp/headdb/api/HeadAPI.java index a8efe4b..2a30ca0 100644 --- a/src/main/java/tsp/headdb/api/HeadAPI.java +++ b/src/main/java/tsp/headdb/api/HeadAPI.java @@ -7,6 +7,7 @@ import tsp.headdb.HeadDB; import tsp.headdb.database.Category; import tsp.headdb.database.HeadDatabase; import tsp.headdb.inventory.InventoryUtils; +import tsp.headdb.storage.PlayerDataFile; import javax.annotation.Nullable; import java.util.ArrayList; @@ -143,77 +144,34 @@ public final class HeadAPI { public static List getHeads() { return database.getHeads(); } - - /** - * Add a {@link Head} to a players favorites - * - * @param uuid The UUID of the player - * @param id The ID of the head - */ - public static void addFavoriteHead(UUID uuid, int id) { - List favs = HeadDB.getInstance().getConfiguration().getIntegerList(uuid.toString() + ".favorites"); - if (!favs.contains(id)) { - favs.add(id); - } - HeadDB.getInstance().getStorage().getPlayerData().set(uuid.toString() + ".favorites", favs); + + public static void addFavoriteHead(UUID uuid, String textureValue) { + HeadDB.getInstance().getPlayerData().modifyFavorite(uuid, textureValue, PlayerDataFile.ModificationType.SET); } - - /** - * Remove a {@link Head} from a players favorites - * - * @param uuid The UUID of the player - * @param id The ID of the head - */ - public static void removeFavoriteHead(UUID uuid, int id) { - List favs = HeadDB.getInstance().getStorage().getPlayerData().getIntegerList(uuid.toString() + ".favorites"); - for (int i = 0; i < favs.size(); i++) { - if (favs.get(i) == id) { - favs.remove(i); - break; - } - } - HeadDB.getInstance().getStorage().getPlayerData().set(uuid.toString() + ".favorites", favs); + + public static void removeFavoriteHead(UUID uuid, String textureValue) { + HeadDB.getInstance().getPlayerData().modifyFavorite(uuid, textureValue, PlayerDataFile.ModificationType.REMOVE); } - - /** - * Retrieve a {@link List} of favorite {@link Head} for a player - * - * @param uuid The UUID of the player - * @return List of favorite heads - */ + public static List getFavoriteHeads(UUID uuid) { - List heads = new ArrayList<>(); - List ids = HeadDB.getInstance().getStorage().getPlayerData().getIntegerList(uuid.toString() + ".favorites"); - for (int id : ids) { - Head head = getHeadByID(id); - heads.add(head); + List result = new ArrayList<>(); + + List textures = HeadDB.getInstance().getPlayerData().getFavoriteHeadsByTexture(uuid); + for (String texture : textures) { + result.add(HeadAPI.getHeadByValue(texture)); } - return heads; + return result; } - /** - * Retrieve a {@link List} of local heads. - * These heads are from players that have joined the server at least once. - * - * @return List of {@link LocalHead}'s - */ public static List getLocalHeads() { - List heads = new ArrayList<>(); - for (String key : HeadDB.getInstance().getStorage().getPlayerData().singleLayerKeySet()) { - OfflinePlayer player = Bukkit.getOfflinePlayer(UUID.fromString(key)); - heads.add(new LocalHead(player.getUniqueId()) - .withName(player.getName())); + 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 heads; - } - - /** - * Update the Head Database - */ - public static boolean updateDatabase() { - return database.update(); + return result; } } diff --git a/src/main/java/tsp/headdb/api/LocalHead.java b/src/main/java/tsp/headdb/api/LocalHead.java index 111a7be..0460c12 100644 --- a/src/main/java/tsp/headdb/api/LocalHead.java +++ b/src/main/java/tsp/headdb/api/LocalHead.java @@ -68,13 +68,13 @@ public class LocalHead extends Head { } @Override - public LocalHead withUniqueId(UUID uuid) { + public LocalHead uniqueId(UUID uuid) { this.uuid = uuid; return this; } @Override - public LocalHead withName(String name) { + public LocalHead name(String name) { this.name = name; return this; } diff --git a/src/main/java/tsp/headdb/command/Command_headdb.java b/src/main/java/tsp/headdb/command/CommandHeadDB.java similarity index 71% rename from src/main/java/tsp/headdb/command/Command_headdb.java rename to src/main/java/tsp/headdb/command/CommandHeadDB.java index a01c2df..fd11ed7 100644 --- a/src/main/java/tsp/headdb/command/Command_headdb.java +++ b/src/main/java/tsp/headdb/command/CommandHeadDB.java @@ -13,7 +13,8 @@ import tsp.headdb.util.Utils; import java.util.concurrent.TimeUnit; -public class Command_headdb implements CommandExecutor { +// TODO: Cleaner way to handle this command +public class CommandHeadDB implements CommandExecutor { @Override public boolean onCommand(CommandSender sender, Command command, String s, String[] args) { @@ -28,16 +29,16 @@ public class Command_headdb implements CommandExecutor { } Player player = (Player) sender; - Utils.sendMessage(player, "Opening &cHead Database"); + Utils.sendMessage(player, "&7Opening &cHead Database"); HeadAPI.openDatabase(player); return true; } String sub = args[0]; if (sub.equalsIgnoreCase("info") || sub.equalsIgnoreCase("i")) { - Utils.sendMessage(sender, "Running &cHeadDB v" + HeadDB.getInstance().getDescription().getVersion()); - Utils.sendMessage(sender, "Created by &c" + HeadDB.getInstance().getDescription().getAuthors()); - Utils.sendMessage(sender, "There are currently &c" + HeadAPI.getHeads().size() + " &7heads in the database."); + 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; } @@ -64,7 +65,7 @@ public class Command_headdb implements CommandExecutor { } } String name = builder.toString(); - Utils.sendMessage(sender, "Searching for &e" + name); + Utils.sendMessage(sender, "&7Searching for &e" + name); HeadAPI.openSearchDatabase(player, name); return true; } @@ -85,7 +86,7 @@ public class Command_headdb implements CommandExecutor { Player player = (Player) sender; String tag = args[1]; - Utils.sendMessage(sender, "Searching for heads with tag &e" + tag); + Utils.sendMessage(sender, "&7Searching for heads with tag &e" + tag); HeadAPI.openTagSearchDatabase(player, tag); return true; } @@ -136,38 +137,24 @@ public class Command_headdb implements CommandExecutor { Utils.sendMessage(sender, "Updating..."); long start = System.currentTimeMillis(); - boolean result = HeadAPI.updateDatabase(); - if (result) { - Utils.sendMessage(sender, "&aDone! Took: " + TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis() - start) + " seconds"); - } else { - Utils.sendMessage(sender, "&cFailed! Check console for errors."); - } - return true; - } - - if (sub.equalsIgnoreCase("updateasync") || sub.equalsIgnoreCase("ua")) { - if (!sender.hasPermission("headdb.update")) { - Utils.sendMessage(sender, "&cNo permission!"); - return true; - } - - Utils.sendMessage(sender, "Updating..."); - HeadAPI.getDatabase().updateAsync(); + 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() + " &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, " > &c/hdb &7- Opens the database"); - Utils.sendMessage(sender, " > &c/hdb info &9(i) &7- Plugin Information"); - Utils.sendMessage(sender, " > &c/hdb search &9(s) &c &7- Search for heads matching a name"); - Utils.sendMessage(sender, " > &c/hdb tagsearch &9(ts) &c &7- Search for heads matching a tag"); - Utils.sendMessage(sender, " > &c/hdb update &9(u) &7- Forcefully update the database"); - Utils.sendMessage(sender, " > &c/hdb updateasync &9(ua) &7- Forcefully update the database ASYNCHRONOUSLY"); - Utils.sendMessage(sender, " > &c/hdb give &9(g) &c &6[amount] &7- Give player a head"); + 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 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/database/Category.java b/src/main/java/tsp/headdb/database/Category.java index 6214ad2..29114a3 100644 --- a/src/main/java/tsp/headdb/database/Category.java +++ b/src/main/java/tsp/headdb/database/Category.java @@ -25,7 +25,7 @@ public enum Category { private final ChatColor color; private final int location; private final Map item = new HashMap<>(); - private static final Category[] values = values(); + public static final Category[] cache = values(); Category(String name, ChatColor color, int location) { this.name = name; @@ -55,7 +55,7 @@ public enum Category { } public static Category getByName(String name) { - for (Category category : values) { + for (Category category : cache) { if (category.getName().equalsIgnoreCase(name)) { return category; } @@ -64,8 +64,4 @@ public enum Category { return null; } - public static Category[] getValues() { - return values; - } - } diff --git a/src/main/java/tsp/headdb/database/HeadDatabase.java b/src/main/java/tsp/headdb/database/HeadDatabase.java index f04c039..e6a2c15 100644 --- a/src/main/java/tsp/headdb/database/HeadDatabase.java +++ b/src/main/java/tsp/headdb/database/HeadDatabase.java @@ -23,8 +23,8 @@ import java.util.Locale; import java.util.Map; import java.util.UUID; import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; import javax.annotation.Nonnull; -import javax.annotation.Nullable; /** * This is the Database that holds all heads @@ -127,7 +127,14 @@ public class HeadDatabase { @Nonnull public List getHeads() { if (HEADS.isEmpty() || isLastUpdateOld()) { - update(); + // Technically this should never be reached due to the update task in the main class. + updateAsync(result -> { + if (result != null) { + for (Category category : result.keySet()) { + HEADS.put(category, result.get(category)); + } + } + }); } List heads = new ArrayList<>(); @@ -137,92 +144,80 @@ public class HeadDatabase { return heads; } - /** - * Gets all heads from the api provider - * - * @return Map containing each head in its category. Returns null if the fetching failed. - */ - @Nullable - public Map> getHeadsNoCache() { - Map> result = new HashMap<>(); - Category[] categories = Category.getValues(); + public void getHeadsNoCacheAsync(Consumer>> resultSet) { + Bukkit.getScheduler().runTaskAsynchronously(plugin, task -> { + Log.debug("[" + plugin.getName() + "] Updating database... "); + Map> result = new HashMap<>(); + Category[] categories = Category.cache; - int id = 1; - for (Category category : categories) { - Log.debug("Caching heads from: " + category.getName()); - long start = System.currentTimeMillis(); - List heads = new ArrayList<>(); - try { - String line; - StringBuilder response = new StringBuilder(); + int id = 1; + for (Category category : categories) { + Log.debug("Caching heads from: " + category.getName()); + long start = System.currentTimeMillis(); + List heads = new ArrayList<>(); + try { + String line; + StringBuilder response = new StringBuilder(); - URLConnection connection = new URL("https://minecraft-heads.com/scripts/api.php?cat=" + category.getName() + "&tags=true").openConnection(); - connection.setConnectTimeout(timeout); - connection.setRequestProperty("User-Agent", plugin.getName() + "-DatabaseUpdater"); - try (BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()))) { - while ((line = in.readLine()) != null) { - response.append(line); + URLConnection connection = new URL("https://minecraft-heads.com/scripts/api.php?cat=" + category.getName() + "&tags=true").openConnection(); + connection.setConnectTimeout(timeout); + connection.setRequestProperty("User-Agent", plugin.getName() + "-DatabaseUpdater"); + try (BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()))) { + while ((line = in.readLine()) != null) { + response.append(line); + } } - } - JSONParser parser = new JSONParser(); - JSONArray array = (JSONArray) parser.parse(response.toString()); - for (Object o : array) { - JSONObject obj = (JSONObject) o; - String rawUUID = obj.get("uuid").toString(); + JSONParser parser = new JSONParser(); + JSONArray array = (JSONArray) parser.parse(response.toString()); + for (Object o : array) { + JSONObject obj = (JSONObject) o; + String rawUUID = obj.get("uuid").toString(); - UUID uuid; - if (Utils.validateUniqueId(rawUUID)) { - uuid = UUID.fromString(rawUUID); - } else { - Log.debug("UUID " + rawUUID + " is invalid. Using random one for head id: " + id); - uuid = UUID.randomUUID(); + UUID uuid; + if (Utils.validateUniqueId(rawUUID)) { + uuid = UUID.fromString(rawUUID); + } else { + uuid = UUID.randomUUID(); + } + + Head head = new Head(id) + .name(obj.get("name").toString()) + .uniqueId(uuid) + .value(obj.get("value").toString()) + .tags(obj.get("tags") != null ? obj.get("tags").toString() : "None") + .category(category); + + id++; + heads.add(head); } - Head head = new Head(id) - .withName(obj.get("name").toString()) - .withUniqueId(uuid) - .withValue(obj.get("value").toString()) - .withTags(obj.get("tags") != null ? obj.get("tags").toString() : "None") - .withCategory(category); - - id++; - heads.add(head); + long elapsed = (System.currentTimeMillis() - start); + Log.debug(category.getName() + " -> Done! Time: " + elapsed + "ms (" + TimeUnit.MILLISECONDS.toSeconds(elapsed) + "s)"); + } catch (ParseException | IOException e) { + Log.error("[" + plugin.getName() + "] Failed to fetch heads (no-cache) | Stack Trace:"); + e.printStackTrace(); } - long elapsed = (System.currentTimeMillis() - start); - Log.debug(category.getName() + " -> Done! Time: " + elapsed + "ms (" + TimeUnit.MILLISECONDS.toSeconds(elapsed) + "s)"); - } catch (ParseException | IOException e) { - Log.error("Failed to fetch heads (no-cache) | Stack Trace:"); - e.printStackTrace(); - return null; + updated = System.nanoTime(); + result.put(category, heads); } - updated = System.nanoTime(); - result.put(category, heads); - } - - return result; + resultSet.accept(result); + }); } - /** - * Updates the cached heads - * - * @return Returns true if the update was successful. - */ - public boolean update() { - Map> heads = getHeadsNoCache(); - if (heads == null) { - Log.error("Failed to update database! Check above for any errors."); - return false; - } + public void updateAsync(Consumer>> result) { + Bukkit.getScheduler().runTaskAsynchronously(plugin, task -> getHeadsNoCacheAsync(heads -> { + if (heads == null) { + Log.error("[" + plugin.getName() + "] Failed to update database! Check above for any errors."); + result.accept(null); + return; + } - HEADS.clear(); - HEADS.putAll(heads); - return true; - } - - public void updateAsync() { - Bukkit.getScheduler().runTaskAsynchronously(plugin, this::update); + HEADS.clear(); + HEADS.putAll(heads); + result.accept(heads); + })); } /** diff --git a/src/main/java/tsp/headdb/event/PlayerHeadPurchaseEvent.java b/src/main/java/tsp/headdb/event/PlayerHeadPurchaseEvent.java index 2372e7c..0feaf18 100644 --- a/src/main/java/tsp/headdb/event/PlayerHeadPurchaseEvent.java +++ b/src/main/java/tsp/headdb/event/PlayerHeadPurchaseEvent.java @@ -4,7 +4,6 @@ import org.bukkit.entity.Player; import org.bukkit.event.Cancellable; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; -import org.jetbrains.annotations.NotNull; import tsp.headdb.api.Head; /** @@ -62,7 +61,7 @@ public class PlayerHeadPurchaseEvent extends Event implements Cancellable { } @Override - public @NotNull HandlerList getHandlers() { + public HandlerList getHandlers() { return handlerList; } diff --git a/src/main/java/tsp/headdb/inventory/InventoryUtils.java b/src/main/java/tsp/headdb/inventory/InventoryUtils.java index 0a93179..004b6af 100644 --- a/src/main/java/tsp/headdb/inventory/InventoryUtils.java +++ b/src/main/java/tsp/headdb/inventory/InventoryUtils.java @@ -33,8 +33,8 @@ public class InventoryUtils { if (uiLocation.containsKey(category)) return uiLocation.get(category); // Try to get the value from the config file. - if (HeadDB.getInstance().getConfiguration().contains("ui.category." + category + ".location")) { - uiLocation.put(category, HeadDB.getInstance().getConfiguration().getInt("ui.category." + category + ".location")); + if (HeadDB.getInstance().getConfig().contains("ui.category." + category + ".location")) { + uiLocation.put(category, HeadDB.getInstance().getConfig().getInt("ui.category." + category + ".location")); return uiLocation.get(category); } @@ -48,8 +48,8 @@ public class InventoryUtils { if (uiItem.containsKey(category)) return uiItem.get(category); // Try to get a head from the config file. - if (HeadDB.getInstance().getConfiguration().contains("ui.category." + category + ".head")) { - int id = HeadDB.getInstance().getConfiguration().getInt("ui.category." + category + ".head"); + if (HeadDB.getInstance().getConfig().contains("ui.category." + category + ".head")) { + int id = HeadDB.getInstance().getConfig().getInt("ui.category." + category + ".head"); Head head = HeadAPI.getHeadByID(id); if (head != null) { uiItem.put(category, head.getItemStack()); @@ -58,8 +58,8 @@ public class InventoryUtils { } // Try to get an item from the config file. - if (HeadDB.getInstance().getConfiguration().contains("ui.category." + category + ".item")) { - String cfg = HeadDB.getInstance().getConfiguration().getString("ui.category." + category + ".item"); + if (HeadDB.getInstance().getConfig().contains("ui.category." + category + ".item")) { + String cfg = HeadDB.getInstance().getConfig().getString("ui.category." + category + ".item"); Material mat = Material.matchMaterial(cfg); // AIR is allowed as the fill material for the menu, but not as a category item. @@ -112,9 +112,9 @@ public class InventoryUtils { purchaseHead(player, head, 1, head.getCategory().getName(), head.getName()); } if (e.getClick() == ClickType.RIGHT) { - HeadAPI.removeFavoriteHead(player.getUniqueId(), head.getId()); + HeadAPI.removeFavoriteHead(player.getUniqueId(), head.getValue()); openFavoritesMenu(player); - Utils.sendMessage(player, "Removed &e" + head.getName() + " &7from favorites."); + Utils.sendMessage(player, "&7Removed &e" + head.getName() + " &7from favorites."); } })); } @@ -136,8 +136,8 @@ public class InventoryUtils { purchaseHead(player, head, 1, head.getCategory().getName(), head.getName()); } if (e.getClick() == ClickType.RIGHT) { - HeadAPI.addFavoriteHead(player.getUniqueId(), head.getId()); - Utils.sendMessage(player, "Added &e" + head.getName() + " &7to favorites."); + HeadAPI.addFavoriteHead(player.getUniqueId(), head.getValue()); + Utils.sendMessage(player, "&7Added &e" + head.getName() + " &7to favorites."); } })); } @@ -160,8 +160,8 @@ public class InventoryUtils { purchaseHead(player, head, 1, head.getCategory().getName(), head.getName()); } if (e.getClick() == ClickType.RIGHT) { - HeadAPI.addFavoriteHead(player.getUniqueId(), head.getId()); - Utils.sendMessage(player, "Added &e" + head.getName() + " &7to favorites."); + HeadAPI.addFavoriteHead(player.getUniqueId(), head.getValue()); + Utils.sendMessage(player, "&7Added &e" + head.getName() + " &7to favorites."); } })); } @@ -183,8 +183,8 @@ public class InventoryUtils { purchaseHead(player, head, 1, head.getCategory().getName(), head.getName()); } if (e.getClick() == ClickType.RIGHT) { - HeadAPI.addFavoriteHead(player.getUniqueId(), head.getId()); - Utils.sendMessage(player, "Added &e" + head.getName() + " &8to favorites."); + HeadAPI.addFavoriteHead(player.getUniqueId(), head.getValue()); + Utils.sendMessage(player, "&7Added &e" + head.getName() + " &7to favorites."); } })); } @@ -195,7 +195,7 @@ public class InventoryUtils { public static void openDatabase(Player player) { Inventory inventory = Bukkit.createInventory(null, 54, Utils.colorize("&c&lHeadDB &8(" + HeadAPI.getHeads().size() + ")")); - for (Category category : Category.getValues()) { + for (Category category : Category.cache) { ItemStack item = getUIItem(category.getName(), category.getItem()); ItemMeta meta = item.getItemMeta(); meta.setDisplayName(Utils.colorize(category.getColor() + "&l" + category.getName().toUpperCase())); @@ -273,7 +273,7 @@ public class InventoryUtils { if (player.hasPermission("headdb.economy.free") || player.hasPermission("headdb.economy." + category + ".free")) return 0; // Otherwise, get the price for this category from the config file. - return HeadDB.getInstance().getConfiguration().getDouble("economy.cost." + category); + return HeadDB.getInstance().getConfig().getDouble("economy.cost." + category); } public static boolean processPayment(Player player, int amount, String category, String description) { @@ -282,7 +282,7 @@ public class InventoryUtils { // If economy is disabled or no plugin is present, the item is free. // Don't mention receiving it for free in this case, since it is always free. if (economy == null) { - player.sendMessage(String.format("You received %d x %s!", amount, description)); + Utils.sendMessage(player, String.format("&7You received &e%d &7x &e%s!", amount, description)); return true; } @@ -292,15 +292,15 @@ public class InventoryUtils { if (cost > 0) { if (economy.has(player, cost)) { economy.withdrawPlayer(player, cost); - player.sendMessage(String.format("You purchased %d x %s for %.2f %s!", amount, description, cost, economy.currencyNamePlural())); + player.sendMessage(String.format("&7You purchased &e%d &7x &e%s &7for &e%.2f %s!", amount, description, cost, economy.currencyNamePlural())); return true; } - player.sendMessage(String.format("You do not have enough %s to purchase %d x %s.", economy.currencyNamePlural(), amount, description)); + Utils.sendMessage(player, String.format("&7You do not have enough &e%s &cto purchase &e%d &cx &e%s.", economy.currencyNamePlural(), amount, description)); return false; } // Otherwise, the item is free. - player.sendMessage(String.format("You received %d x %s for free!", amount, description)); + Utils.sendMessage(player, String.format("&7You received &e%d &7x &e%s &7for &efree&7!", amount, description)); return true; } diff --git a/src/main/java/tsp/headdb/listener/JoinListener.java b/src/main/java/tsp/headdb/listener/JoinListener.java index 2ecdd2a..18044ae 100644 --- a/src/main/java/tsp/headdb/listener/JoinListener.java +++ b/src/main/java/tsp/headdb/listener/JoinListener.java @@ -4,19 +4,21 @@ import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerJoinEvent; import tsp.headdb.HeadDB; +import tsp.headdb.storage.PlayerDataFile; public class JoinListener implements Listener { public JoinListener(HeadDB plugin) { // If local heads are disabled, there is no need for this listener. - if (HeadDB.getInstance().getConfiguration().getBoolean("localHeads")) { + if (HeadDB.getInstance().getConfig().getBoolean("localHeads")) { plugin.getServer().getPluginManager().registerEvents(this, plugin); } } @EventHandler public void onJoin(PlayerJoinEvent e) { - HeadDB.getInstance().getStorage().getPlayerData().set(e.getPlayer().getUniqueId().toString() + ".username", e.getPlayer().getName()); + HeadDB.getInstance().getPlayerData().modifyUsername(e.getPlayer().getUniqueId(), e.getPlayer().getName(), PlayerDataFile.ModificationType.SET); + HeadDB.getInstance().getPlayerData().save(); } } diff --git a/src/main/java/tsp/headdb/listener/MenuListener.java b/src/main/java/tsp/headdb/listener/MenuListener.java index 09ae243..a85faa1 100644 --- a/src/main/java/tsp/headdb/listener/MenuListener.java +++ b/src/main/java/tsp/headdb/listener/MenuListener.java @@ -44,6 +44,7 @@ public class MenuListener implements Listener { player.closeInventory(); return; } + player.sendMessage("Clicked on favorites!"); InventoryUtils.openFavoritesMenu(player); return; } diff --git a/src/main/java/tsp/headdb/storage/PlayerDataFile.java b/src/main/java/tsp/headdb/storage/PlayerDataFile.java new file mode 100644 index 0000000..d74a266 --- /dev/null +++ b/src/main/java/tsp/headdb/storage/PlayerDataFile.java @@ -0,0 +1,149 @@ +package tsp.headdb.storage; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.google.gson.JsonPrimitive; +import tsp.headdb.HeadDB; +import tsp.headdb.util.Log; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.UUID; + +public class PlayerDataFile { + + private final File file; + private JsonObject main; + + public PlayerDataFile(String name) { + HeadDB plugin = HeadDB.getInstance(); + // This check avoids warning in console + if (plugin.getResource(name) != null && !new File(plugin.getDataFolder() + "/" + name).exists()) { + plugin.saveResource(name, false); + } + + this.file = new File(plugin.getDataFolder() + "/" + name); + } + + @Nonnull + public List getFavoriteHeadsByTexture(UUID uuid) { + List result = new ArrayList<>(); + + if (main.has(uuid.toString()) && main.get(uuid.toString()).getAsJsonObject().has("favorites")) { + JsonArray favorites = main.get(uuid.toString()).getAsJsonObject().get("favorites").getAsJsonArray(); + for (int i = 0; i < favorites.size(); i++) { + String str = favorites.get(i).toString(); + Log.debug("str: " + str.substring(1, str.length() - 1)); + result.add(str.substring(1, str.length() - 1)); + } + } + + return result; + } + + public void modifyFavorite(UUID uuid, String textureValue, ModificationType modificationType) { + JsonObject userObject; + if (main.has(uuid.toString())) { + userObject = main.get(uuid.toString()).getAsJsonObject(); + } else { + userObject = new JsonObject(); + } + + JsonArray favorites; + if (userObject.has("favorites")) { + favorites = userObject.get("favorites").getAsJsonArray(); + } else { + favorites = new JsonArray(); + } + + JsonPrimitive value = new JsonPrimitive(textureValue); + if (modificationType == ModificationType.SET) { + if (favorites.contains(value)) { + // Head is already in the list, no need to modify it + return; + } + + favorites.add(value); + } else if (modificationType == ModificationType.REMOVE) { + if (!favorites.contains(value)) { + // Head is not in the list, no need to modify it + return; + } + + favorites.remove(value); + } + + userObject.add("favorites", favorites); + main.add(uuid.toString(), userObject); + } + + @Nullable + public String getUsername(UUID uuid) { + return main.get(uuid.toString()).getAsJsonObject().get("username").toString(); + } + + public Set getEntries() { + return main.keySet(); + } + + public void modifyUsername(UUID uuid, String username, ModificationType modificationType) { + JsonObject userObject; + if (main.has(uuid.toString())) { + userObject = main.get(uuid.toString()).getAsJsonObject(); + } else { + userObject = new JsonObject(); + } + + if (modificationType == ModificationType.SET) { + userObject.addProperty("username", username); + } else { + userObject.remove("username"); + } + main.add(uuid.toString(), userObject); + } + + public void load() { + try { + main = new JsonParser().parse(new FileReader(file)).getAsJsonObject(); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } + } + + public void save() { + FileWriter writer; + try { + writer = new FileWriter(file); + writer.write(main.toString()); + writer.close(); + } catch (IOException e) { + Log.error("Failed to save player_data.json contents!"); + Log.error(e); + } + } + + public File getFile() { + return file; + } + + public void validateFile() { + if (!file.exists()) { + HeadDB.getInstance().saveResource(file.getName(), false); + } + } + + public enum ModificationType { + SET, + REMOVE; + } + +} diff --git a/src/main/java/tsp/headdb/util/Log.java b/src/main/java/tsp/headdb/util/Log.java index a4c224a..ce1185b 100644 --- a/src/main/java/tsp/headdb/util/Log.java +++ b/src/main/java/tsp/headdb/util/Log.java @@ -35,7 +35,7 @@ public class Log { } public static void log(LogLevel level, String message) { - if (level == LogLevel.DEBUG && !HeadDB.getInstance().getStorage().getConfig().getBoolean("debug")) { + if (level == LogLevel.DEBUG && !HeadDB.getInstance().getConfig().getBoolean("debug")) { return; } Bukkit.getConsoleSender().sendMessage(Utils.colorize("&7[&9&l" + name + "&7] " + level.getColor() + "[" + level.name() + "]: " + message)); diff --git a/src/main/java/tsp/headdb/util/Storage.java b/src/main/java/tsp/headdb/util/Storage.java deleted file mode 100644 index 4763099..0000000 --- a/src/main/java/tsp/headdb/util/Storage.java +++ /dev/null @@ -1,27 +0,0 @@ -package tsp.headdb.util; - -import de.leonhard.storage.Config; -import de.leonhard.storage.Json; -import de.leonhard.storage.LightningBuilder; -import org.bukkit.plugin.java.JavaPlugin; - -public class Storage { - - private Config config; - private Json playerdata; - - public Storage init(JavaPlugin plugin) { - config = LightningBuilder.fromPath("config.yml", plugin.getDataFolder().getAbsolutePath()).createConfig().addDefaultsFromInputStream(); - playerdata = LightningBuilder.fromPath("playerdata.json", plugin.getDataFolder().getAbsolutePath()).createJson(); - return this; - } - - public Config getConfig() { - return config; - } - - public Json getPlayerData() { - return playerdata; - } - -} diff --git a/src/main/java/tsp/headdb/util/Utils.java b/src/main/java/tsp/headdb/util/Utils.java index e0744dc..d40e375 100644 --- a/src/main/java/tsp/headdb/util/Utils.java +++ b/src/main/java/tsp/headdb/util/Utils.java @@ -24,7 +24,7 @@ public class Utils { } public static String colorize(String string) { - return ChatColor.translateAlternateColorCodes('&', ChatColor.GRAY + string); + return ChatColor.translateAlternateColorCodes('&', string); } } diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 76ccb8d..f7095b8 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -1,13 +1,7 @@ -# When enabled heads will be fetched from startup, otherwise when the /hdb command is ran -fetchStartup: true - -# When enabled, heads will be fetched async (Startup Only) -asyncStartup: true - -# If the cached heads are older than these amount of seconds, the plugin will refresh the database +# How often the database should be updated in seconds. refresh: 3600 -# If local heads should be enabled. Only keeps track of joined players when enabled! +# If local heads should be enabled. Only starts keeping track of joined players when enabled! localHeads: true # Economy options diff --git a/src/main/resources/player_data.json b/src/main/resources/player_data.json new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/src/main/resources/player_data.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index c9bd682..0a40ed8 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -11,7 +11,7 @@ commands: headdb: usage: /headdb description: Open the database - aliases: [hdb, headdatabase] + aliases: [hdb, headdatabase, headmenu] permissions: headdb.admin: