diff --git a/.gitignore b/.gitignore index eb7cc580..b943d2fe 100644 --- a/.gitignore +++ b/.gitignore @@ -29,4 +29,6 @@ dependency-reduced-pom.xml # Temporary and log files **/temp.** -*.log \ No newline at end of file +*.log +/.run/Run Test Server.run.xml +/.vscode/settings.json diff --git a/pom.xml b/pom.xml index bb39b04e..d5cd6332 100644 --- a/pom.xml +++ b/pom.xml @@ -63,7 +63,7 @@ org.shanerx tradeshop - 2.6.1-STABLE + 2.6.2-DEV jar TradeShop https://tradeshop.github.io/ @@ -179,12 +179,17 @@ maven-shade-plugin 3.3.0 - ${outputDir}/PreShade + true false + ${outputDir}/shade + target/server/plugins/${build.finalName}.jar + org.bstats:* de.themoep:* + com.bergerkiller.bukkit:* + com.github.simplix-softworks:* @@ -246,6 +251,12 @@ + + + MG-Dev Jenkins CI Maven Repository + https://ci.mg-dev.eu/plugin/repository/everything + + spigot-repo https://hub.spigotmc.org/nexus/content/repositories/snapshots/ @@ -265,6 +276,11 @@ papermc https://repo.papermc.io/repository/maven-public/ + + + jitpack.io + https://jitpack.io + @@ -307,6 +323,27 @@ paper-api 1.20.1-R0.1-20230627.215235-38 + + + com.bergerkiller.bukkit + BKCommonLib + 1.20.2-v1 + provided + + + + org.projectlombok + lombok + 1.18.26 + provided + + + + com.github.simplix-softworks + SimplixStorage + 3.2.7 + compile + diff --git a/src/main/java/org/shanerx/tradeshop/TradeShop.java b/src/main/java/org/shanerx/tradeshop/TradeShop.java index 07c0f584..4beb77ec 100644 --- a/src/main/java/org/shanerx/tradeshop/TradeShop.java +++ b/src/main/java/org/shanerx/tradeshop/TradeShop.java @@ -41,6 +41,7 @@ import org.shanerx.tradeshop.player.Permissions; import org.shanerx.tradeshop.shop.ShopSign; import org.shanerx.tradeshop.shop.ShopStorage; +import org.shanerx.tradeshop.shop.listeners.ChunkUnloadListener; import org.shanerx.tradeshop.shop.listeners.PaperShopProtectionListener; import org.shanerx.tradeshop.shop.listeners.ShopCreateListener; import org.shanerx.tradeshop.shop.listeners.ShopProtectionListener; @@ -90,18 +91,18 @@ public void onEnable() { registration(); - getSettingManager().updateSkipHoppers(); + getVarManager().getSettingManager().updateSkipHoppers(); - getSigns(); - getStorages(); - getListManager(); + getVarManager().getSigns(); + getVarManager().getStorages(); + getVarManager().getListManager(); if (Setting.CHECK_UPDATES.getBoolean()) { new Thread(() -> getUpdater().checkCurrentVersion()).start(); } if (Setting.ALLOW_METRICS.getBoolean()) { - getMetricsManager(); + getVarManager().getMetricsManager(); getLogger().info("Metrics successfully initialized!"); } else { getLogger().warning("Metrics are disabled! Please consider enabling them to support the authors!"); @@ -112,6 +113,8 @@ public void onEnable() { @Override public void onDisable() { + varManager.getDataStorage().ensureFinalSave(); + if (getListManager() != null) getListManager().clearManager(); } @@ -137,14 +140,19 @@ private boolean loadChecks() { getSettingManager().reload(); getMessageManager().reload(); - return getDataStorage() != null; + String lockout = "§a§3§c§2§f§6"; + if (Setting.MESSAGE_PREFIX.getString().startsWith(lockout)) { //TODO remove for release if old data will not be lost + getLogger().log(Level.SEVERE, "This version will most likely break existing data. To continue, please add `" + lockout + "` before the message prefix in the config and restart the server."); + return false; + } + + return getVarManager().getDataStorage() != null; } private void registration() { Permissions.registerPermissions(); - PluginManager pm = getServer().getPluginManager(); pm.registerEvents(new JoinEventListener(this), this); pm.registerEvents(new ShopProtectionListener(this), this); @@ -152,6 +160,7 @@ private void registration() { pm.registerEvents(new ShopTradeListener(), this); pm.registerEvents(new ShopRestockListener(this), this); pm.registerEvents(new SuccessfulTradeEventListener(this), this); + pm.registerEvents(new ChunkUnloadListener(this), this); if (getServer().getVersion().toLowerCase().contains("paper")) { pm.registerEvents(new PaperShopProtectionListener(), this); diff --git a/src/main/java/org/shanerx/tradeshop/commands/CommandTabCompleter.java b/src/main/java/org/shanerx/tradeshop/commands/CommandTabCompleter.java index 9964c22a..43b09bf6 100644 --- a/src/main/java/org/shanerx/tradeshop/commands/CommandTabCompleter.java +++ b/src/main/java/org/shanerx/tradeshop/commands/CommandTabCompleter.java @@ -41,11 +41,11 @@ import java.util.Collections; import java.util.List; -public class CommandTabCompleter extends Utils { +public class CommandTabCompleter { private final TradeShop plugin; - private CommandSender sender; - private String[] args; + private final CommandSender sender; + private final String[] args; private Player pSender; @@ -97,7 +97,7 @@ public List fillShopPlayer() { Sign s; if (plugin.getListManager().isInventory(b)) { - s = findShopSign(b); + s = new Utils().findShopSign(b); } else if (ShopType.isShop(b)) { s = (Sign) b.getState(); } else { diff --git a/src/main/java/org/shanerx/tradeshop/commands/SubCommand.java b/src/main/java/org/shanerx/tradeshop/commands/SubCommand.java index a025b7d4..442dc8af 100644 --- a/src/main/java/org/shanerx/tradeshop/commands/SubCommand.java +++ b/src/main/java/org/shanerx/tradeshop/commands/SubCommand.java @@ -26,12 +26,19 @@ package org.shanerx.tradeshop.commands; import com.google.common.collect.Lists; -import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.shanerx.tradeshop.TradeShop; -import org.shanerx.tradeshop.commands.commandrunners.*; -import org.shanerx.tradeshop.data.config.Message; +import org.shanerx.tradeshop.commands.commandrunners.AdminSubCommand; +import org.shanerx.tradeshop.commands.commandrunners.BasicTextSubCommand; +import org.shanerx.tradeshop.commands.commandrunners.CreateSubCommand; +import org.shanerx.tradeshop.commands.commandrunners.EditSubCommand; +import org.shanerx.tradeshop.commands.commandrunners.GeneralPlayerSubCommand; +import org.shanerx.tradeshop.commands.commandrunners.ShopFindSubCommand; +import org.shanerx.tradeshop.commands.commandrunners.ShopItemSubCommand; +import org.shanerx.tradeshop.commands.commandrunners.ShopSubCommand; +import org.shanerx.tradeshop.commands.commandrunners.ShopUserSubCommand; +import org.shanerx.tradeshop.commands.commandrunners.WhatSubCommand; import org.shanerx.tradeshop.framework.ShopChange; import org.shanerx.tradeshop.item.ShopItemSide; import org.shanerx.tradeshop.player.ShopRole; @@ -40,7 +47,7 @@ import java.util.ArrayList; -public abstract class SubCommand extends Utils { +public abstract class SubCommand { protected final TradeShop plugin; @@ -190,7 +197,7 @@ public String getArgAt(int index) { } } - public static String getArgAt(String args[], int index) { + public static String getArgAt(String[] args, int index) { if (index < args.length) { return args[index]; } diff --git a/src/main/java/org/shanerx/tradeshop/commands/commandrunners/AdminSubCommand.java b/src/main/java/org/shanerx/tradeshop/commands/commandrunners/AdminSubCommand.java index e43b0011..bcd856e7 100644 --- a/src/main/java/org/shanerx/tradeshop/commands/commandrunners/AdminSubCommand.java +++ b/src/main/java/org/shanerx/tradeshop/commands/commandrunners/AdminSubCommand.java @@ -26,7 +26,6 @@ package org.shanerx.tradeshop.commands.commandrunners; import org.bukkit.Bukkit; -import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.shanerx.tradeshop.TradeShop; import org.shanerx.tradeshop.commands.SubCommand; diff --git a/src/main/java/org/shanerx/tradeshop/commands/commandrunners/BasicTextSubCommand.java b/src/main/java/org/shanerx/tradeshop/commands/commandrunners/BasicTextSubCommand.java index a17e48c4..643bba3c 100644 --- a/src/main/java/org/shanerx/tradeshop/commands/commandrunners/BasicTextSubCommand.java +++ b/src/main/java/org/shanerx/tradeshop/commands/commandrunners/BasicTextSubCommand.java @@ -25,7 +25,6 @@ package org.shanerx.tradeshop.commands.commandrunners; -import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.shanerx.tradeshop.TradeShop; import org.shanerx.tradeshop.commands.CommandType; @@ -34,6 +33,7 @@ import org.shanerx.tradeshop.data.config.Setting; import org.shanerx.tradeshop.data.config.Variable; import org.shanerx.tradeshop.player.PermStatus; +import org.shanerx.tradeshop.utils.Utils; import org.shanerx.tradeshop.utils.objects.Tuple; /** @@ -59,10 +59,10 @@ public void help() { StringBuilder sb = new StringBuilder(); sb.append("\n&2") - .append(getPluginName()) + .append(new Utils().getPluginName()) .append(" ") - .append(getVersion()) - .append(" by ").append(pdf.getAuthors().get(0)).append(" & ").append(pdf.getAuthors().get(1)) + .append(new Utils().getVersion()) + .append(" by ").append(new Utils().getAuthors().get(0)).append(" & ").append(new Utils().getAuthors().get(1)) .append("\n\n&b/tradeshop &f &f Display help message\n"); for (CommandType c : CommandType.values()) { @@ -72,7 +72,7 @@ public void help() { } sb.append("\n "); - sendMessage(colorize(sb.toString())); + sendMessage(new Utils().colorize(sb.toString())); } /** diff --git a/src/main/java/org/shanerx/tradeshop/commands/commandrunners/CreateSubCommand.java b/src/main/java/org/shanerx/tradeshop/commands/commandrunners/CreateSubCommand.java index 30c91dfe..727ddc5d 100644 --- a/src/main/java/org/shanerx/tradeshop/commands/commandrunners/CreateSubCommand.java +++ b/src/main/java/org/shanerx/tradeshop/commands/commandrunners/CreateSubCommand.java @@ -26,12 +26,12 @@ package org.shanerx.tradeshop.commands.commandrunners; import org.bukkit.block.Sign; -import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.shanerx.tradeshop.TradeShop; import org.shanerx.tradeshop.commands.SubCommand; import org.shanerx.tradeshop.player.ShopUser; import org.shanerx.tradeshop.shop.ShopType; +import org.shanerx.tradeshop.utils.Utils; /** * Implementation of CommandRunner for plugin commands that create new shops @@ -53,6 +53,6 @@ public void createShop(ShopType shopType) { if (sign == null) return; - createShop(sign, getPlayerSender(), shopType); + new Utils().createShop(sign, getPlayerSender(), shopType); } } diff --git a/src/main/java/org/shanerx/tradeshop/commands/commandrunners/EditSubCommand.java b/src/main/java/org/shanerx/tradeshop/commands/commandrunners/EditSubCommand.java index 8795937a..73c24f03 100644 --- a/src/main/java/org/shanerx/tradeshop/commands/commandrunners/EditSubCommand.java +++ b/src/main/java/org/shanerx/tradeshop/commands/commandrunners/EditSubCommand.java @@ -31,7 +31,6 @@ import de.themoep.inventorygui.InventoryGui; import de.themoep.inventorygui.StaticGuiElement; import org.bukkit.Material; -import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.inventory.ItemStack; import org.shanerx.tradeshop.TradeShop; @@ -43,6 +42,7 @@ import org.shanerx.tradeshop.player.ShopUser; import org.shanerx.tradeshop.shop.Shop; import org.shanerx.tradeshop.shop.ShopSettingKeys; +import org.shanerx.tradeshop.utils.Utils; import org.shanerx.tradeshop.utils.objects.ObjectHolder; import java.util.HashMap; @@ -83,7 +83,7 @@ public void edit() { return; } - mainMenu = new InventoryGui(plugin, "Edit Menu-" + shop.getShopLocationAsSL().serialize(), MENU_LAYOUT); + mainMenu = new InventoryGui(plugin, "Edit Menu-" + shop.getShopLocationAsSL().toString(), MENU_LAYOUT); mainMenu.setFiller(new ItemStack(Material.LIGHT_GRAY_STAINED_GLASS_PANE, 1)); @@ -164,7 +164,7 @@ private GuiElement editSettingsMenu(char slotChar) { settingEdit.show(getPlayerSender()); return true; - }, colorize("&eEdit Shop Settings")); + }, new Utils().colorize("&eEdit Shop Settings")); } private GuiElement editUserMenu(char slotChar) { @@ -241,7 +241,7 @@ private GuiElement editUserMenu(char slotChar) { userEdit.addElement(userGroup); userEdit.show(getPlayerSender()); return true; - }, colorize("&eEdit Shop Users")); + }, new Utils().colorize("&eEdit Shop Users")); } private GuiElement editCostMenu(char slotChar) { @@ -270,7 +270,7 @@ private GuiElement editCostMenu(char slotChar) { if (costItemsRemoval.get(i)) costItems.remove(i); } - shop.updateSide(ShopItemSide.COST, costItems); + shop.updateSide(ShopItemSide.COST, costItems, false); shop.saveShop(); InventoryGui.goBack(getPlayerSender()); return true; @@ -285,7 +285,7 @@ private GuiElement editCostMenu(char slotChar) { costEdit.addElement(costGroup); costEdit.show(getPlayerSender()); return true; - }, colorize("&eEdit Shop Costs")); + }, new Utils().colorize("&eEdit Shop Costs")); } private GuiElement editProductMenu(char slotChar) { @@ -314,7 +314,7 @@ private GuiElement editProductMenu(char slotChar) { if (productItemsRemoval.get(i)) productItems.remove(i); } - shop.updateSide(ShopItemSide.PRODUCT, productItems); + shop.updateSide(ShopItemSide.PRODUCT, productItems, false); shop.saveShop(); InventoryGui.goBack(getPlayerSender()); return true; @@ -329,6 +329,6 @@ private GuiElement editProductMenu(char slotChar) { productEdit.addElement(productGroup); productEdit.show(getPlayerSender()); return true; - }, colorize("&eEdit Shop Products")); + }, new Utils().colorize("&eEdit Shop Products")); } } \ No newline at end of file diff --git a/src/main/java/org/shanerx/tradeshop/commands/commandrunners/GUISubCommand.java b/src/main/java/org/shanerx/tradeshop/commands/commandrunners/GUISubCommand.java index 32502786..16dfaaf1 100644 --- a/src/main/java/org/shanerx/tradeshop/commands/commandrunners/GUISubCommand.java +++ b/src/main/java/org/shanerx/tradeshop/commands/commandrunners/GUISubCommand.java @@ -32,7 +32,6 @@ import de.themoep.inventorygui.InventoryGui; import de.themoep.inventorygui.StaticGuiElement; import org.bukkit.Material; -import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.BookMeta; @@ -45,6 +44,7 @@ import org.shanerx.tradeshop.item.ShopItemStack; import org.shanerx.tradeshop.item.ShopItemStackSettingKeys; import org.shanerx.tradeshop.shop.Shop; +import org.shanerx.tradeshop.utils.Utils; import org.shanerx.tradeshop.utils.objects.ObjectHolder; import java.util.ArrayList; @@ -86,7 +86,7 @@ protected StaticGuiElement itemSettingMenu(Shop shop, int index, ShopItemSide si ItemStack tempStack = item.getItemStack().clone(); ItemMeta tempMeta = tempStack.getItemMeta(); List newLore = new ArrayList<>(); - newLore.add(colorize("&8Amount &7» &f" + item.getAmount())); + newLore.add(new Utils().colorize("&8Amount &7» &f" + item.getAmount())); if (tempMeta != null && tempMeta.hasLore()) { newLore.add(""); @@ -186,7 +186,7 @@ protected StaticGuiElement itemSettingMenu(Shop shop, int index, ShopItemSide si // Add Save button only when editable - Saves and Goes to previous screen if (editable) itemEdit.addElement(new StaticGuiElement('s', new ItemStack(Material.ANVIL), click3 -> { - shop.updateSideItem(side, item, index); + shop.updateSideItem(side, item, index, true); InventoryGui.goBack(getPlayerSender()); return true; }, "Save Changes")); diff --git a/src/main/java/org/shanerx/tradeshop/commands/commandrunners/GeneralPlayerSubCommand.java b/src/main/java/org/shanerx/tradeshop/commands/commandrunners/GeneralPlayerSubCommand.java index ba09d921..5645f0fd 100644 --- a/src/main/java/org/shanerx/tradeshop/commands/commandrunners/GeneralPlayerSubCommand.java +++ b/src/main/java/org/shanerx/tradeshop/commands/commandrunners/GeneralPlayerSubCommand.java @@ -26,7 +26,6 @@ package org.shanerx.tradeshop.commands.commandrunners; import org.bukkit.Bukkit; -import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.shanerx.tradeshop.TradeShop; import org.shanerx.tradeshop.commands.SubCommand; @@ -35,6 +34,7 @@ import org.shanerx.tradeshop.data.config.Variable; import org.shanerx.tradeshop.player.Permissions; import org.shanerx.tradeshop.player.PlayerSetting; +import org.shanerx.tradeshop.utils.Utils; import org.shanerx.tradeshop.utils.objects.Tuple; public class GeneralPlayerSubCommand extends SubCommand { @@ -59,7 +59,7 @@ public void multi() { } else { int amount = Setting.MULTI_TRADE_DEFAULT.getInt(); - if (isInt(getArgAt(1))) + if (new Utils().isInt(getArgAt(1))) amount = Integer.parseInt(getArgAt(1)); amount = Math.min(Math.max(2, amount), Setting.MULTI_TRADE_MAX.getInt()); diff --git a/src/main/java/org/shanerx/tradeshop/commands/commandrunners/ShopFindSubCommand.java b/src/main/java/org/shanerx/tradeshop/commands/commandrunners/ShopFindSubCommand.java index f7df2bde..a4f51222 100644 --- a/src/main/java/org/shanerx/tradeshop/commands/commandrunners/ShopFindSubCommand.java +++ b/src/main/java/org/shanerx/tradeshop/commands/commandrunners/ShopFindSubCommand.java @@ -73,100 +73,100 @@ public void run() { int desiredRange = Setting.MAX_FIND_RANGE.getInt(); boolean inStock = false; - if (desiredRange > 0) { - - ArrayList lowerArgs = (getArgs().stream().map(String::toLowerCase).collect(Collectors.toCollection(ArrayList::new))); - lowerArgs.remove("find"); - - List shops = new ArrayList<>(); - - for (String arg : lowerArgs) { - for (String str : arg.split(";")) { - String[] keyVal = str.contains("=") ? str.split("=") : str.split(":"); - plugin.getDebugger().log(" --- _S_F_ --- " + keyVal[0] + " = " + (keyVal.length > 1 ? keyVal[1] : "---No Value---"), DebugLevels.FIND_COMMAND); - if (keyVal.length != 2) { - Message.INVALID_ARGUMENTS.sendMessage(getSender()); - return; - } - - switch (keyVal[0]) { - case "c": - case "cost": - desiredCost.putAll(processItemDesires(keyVal[1])); - break; - case "p": - case "product": - desiredProduct.putAll(processItemDesires(keyVal[1])); - break; - case "s": - case "in-stock": - case "instock": - case "stock": - ObjectHolder stock = new ObjectHolder<>(keyVal[1]); - inStock = stock.asBoolean(); - break; - case "d": - case "r": - case "distance": - case "range": - ObjectHolder dist = new ObjectHolder<>(keyVal[1]); - desiredRange = (dist.canBeInteger() && dist.asInteger() < desiredRange) ? - dist.asInteger(): - Setting.DEFAULT_FIND_RANGE.getInt(); - } + if (desiredRange <= 0) { + Message.FEATURE_DISABLED.sendMessage(getSender()); + } + + ArrayList lowerArgs = (getArgs().stream().map(String::toLowerCase).collect(Collectors.toCollection(ArrayList::new))); + lowerArgs.remove("find"); + + List shops = new ArrayList<>(); + + for (String arg : lowerArgs) { + for (String str : arg.split(";")) { + String[] keyVal = str.contains("=") ? str.split("=") : str.split(":"); + plugin.getDebugger().log(" --- _S_F_ --- " + keyVal[0] + " = " + (keyVal.length > 1 ? keyVal[1] : "---No Value---"), DebugLevels.FIND_COMMAND); + if (keyVal.length != 2) { + Message.INVALID_ARGUMENTS.sendMessage(getSender()); + return; + } + + switch (keyVal[0]) { + case "c": + case "cost": + desiredCost.putAll(processItemDesires(keyVal[1])); + break; + case "p": + case "product": + desiredProduct.putAll(processItemDesires(keyVal[1])); + break; + case "s": + case "in-stock": + case "instock": + case "stock": + ObjectHolder stock = new ObjectHolder<>(keyVal[1]); + inStock = stock.asBoolean(); + break; + case "d": + case "r": + case "distance": + case "range": + case "radius": + ObjectHolder dist = new ObjectHolder<>(keyVal[1]); + desiredRange = (dist.canBeInteger() && dist.asInteger() < desiredRange) ? + dist.asInteger(): + Setting.DEFAULT_FIND_RANGE.getInt(); } } + } - plugin.getDebugger().log(" --- _F_F_ --- \n" + - "Cost" + " = " + desiredCost + "\n" + - "Product" + " = " + desiredProduct + "\n" + - "Range" + " = " + desiredRange + "\n" + - "InStock" + " = " + inStock, DebugLevels.FIND_COMMAND); + plugin.getDebugger().log(" --- _F_F_ --- \n" + + "Cost" + " = " + desiredCost + "\n" + + "Product" + " = " + desiredProduct + "\n" + + "Range" + " = " + desiredRange + "\n" + + "InStock" + " = " + inStock, DebugLevels.FIND_COMMAND); - if (desiredProduct.size() == 0) - desiredProduct.put(0, null); - if (desiredCost.size() == 0) - desiredCost.put(0, null); + if (desiredProduct.size() == 0) + desiredProduct.put(0, null); + if (desiredCost.size() == 0) + desiredCost.put(0, null); - final int finalDesiredRange = Math.min(desiredRange, Setting.MAX_FIND_RANGE.getInt()); - final boolean finalInStock = inStock; + final int finalDesiredRange = Math.min(desiredRange, Setting.MAX_FIND_RANGE.getInt()); + final boolean finalInStock = inStock; - desiredProduct.forEach((prodId, prodItems) -> { - desiredCost.forEach((costId, costItems) -> { - shops.addAll(ShopUser.findProximityShop(searchFrom, finalDesiredRange, finalInStock, costItems, prodItems)); - }); + desiredProduct.forEach((prodId, prodItems) -> { + desiredCost.forEach((costId, costItems) -> { + shops.addAll(ShopUser.findProximityShop(searchFrom, finalDesiredRange, finalInStock, costItems, prodItems)); }); + }); - ArrayList foundShops = new ArrayList<>(); + ArrayList foundShops = new ArrayList<>(); - shops.forEach((shop -> { - TextComponent message = new TextComponent(shop.getShopLocationAsSL().toString(false) + "\n"); + shops.forEach((shop -> { + TextComponent message = new TextComponent(shop.getShopLocationAsSL().toString(false) + "\n"); - message.setColor(shop.getAvailableTrades() > 0 ? ChatColor.DARK_GREEN : ChatColor.DARK_RED); + message.setColor(shop.getAvailableTrades() > 0 ? ChatColor.DARK_GREEN : ChatColor.DARK_RED); - message.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, - new ComponentBuilder( - String.join("\n", - Arrays.asList( - shop.getShopType().toString(), - shop.getStatus().getLine(), - "Cost: " + shop.getSideListNames(ShopItemSide.COST).toString(), - "Product: " + shop.getSideListNames(ShopItemSide.PRODUCT)) - )).create())); + message.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, + new ComponentBuilder( + String.join("\n", + Arrays.asList( + shop.getShopType().toString(), + shop.getStatus().getLine(), + "Cost: " + shop.getSideListNames(ShopItemSide.COST).toString(), + "Product: " + shop.getSideListNames(ShopItemSide.PRODUCT)) + )).create())); - foundShops.add(message); - })); + foundShops.add(message); + })); - plugin.getDebugger().log(" --- _F_D_ --- " + Arrays.toString(foundShops.toArray(new BaseComponent[]{})), DebugLevels.FIND_COMMAND); + plugin.getDebugger().log(" --- _F_D_ --- " + Arrays.toString(foundShops.toArray(new BaseComponent[]{})), DebugLevels.FIND_COMMAND); - if (foundShops.size() > 0) - getSender().spigot().sendMessage(foundShops.toArray(new BaseComponent[]{})); - else - Message.NO_SHOP_FOUND.sendMessage(getSender()); - } else { - Message.FEATURE_DISABLED.sendMessage(getSender()); - } + if (foundShops.size() > 0) + getSender().spigot().sendMessage(foundShops.toArray(new BaseComponent[]{})); + else + Message.NO_SHOP_FOUND.sendMessage(getSender()); } private Map> processItemDesires(String desire) { diff --git a/src/main/java/org/shanerx/tradeshop/commands/commandrunners/ShopItemSubCommand.java b/src/main/java/org/shanerx/tradeshop/commands/commandrunners/ShopItemSubCommand.java index e27a184a..254def5b 100644 --- a/src/main/java/org/shanerx/tradeshop/commands/commandrunners/ShopItemSubCommand.java +++ b/src/main/java/org/shanerx/tradeshop/commands/commandrunners/ShopItemSubCommand.java @@ -27,7 +27,6 @@ import org.bukkit.Bukkit; import org.bukkit.Material; -import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.inventory.ItemStack; import org.shanerx.tradeshop.TradeShop; @@ -43,6 +42,7 @@ import org.shanerx.tradeshop.player.ShopRole; import org.shanerx.tradeshop.player.ShopUser; import org.shanerx.tradeshop.shop.Shop; +import org.shanerx.tradeshop.utils.Utils; import org.shanerx.tradeshop.utils.objects.ObjectHolder; import org.shanerx.tradeshop.utils.objects.Tuple; @@ -86,7 +86,7 @@ public void removeSide() { int index; - if (isInt(getArgAt(1))) { + if (new Utils().isInt(getArgAt(1))) { index = Integer.parseInt(getArgAt(1)) - 1; } else if (shop.getSideList(side).size() == 1) { index = 0; @@ -132,7 +132,7 @@ public void setSide() { int amount = 0; Material mat = null; - if (hasArgAt(1) && isInt(getArgAt(1))) { + if (hasArgAt(1) && new Utils().isInt(getArgAt(1))) { amount = Integer.parseInt(getArgAt(1)); } @@ -159,7 +159,7 @@ public void setSide() { return; } - if (isIllegal(side, itemInHand.getType())) { + if (new Utils().isIllegal(side, itemInHand.getType())) { Message.ILLEGAL_ITEM.sendMessage(getPlayerSender()); return; } @@ -208,7 +208,7 @@ public void addSide() { int amount = 0; Material mat = null; - if (hasArgAt(1) && isInt(getArgAt(1))) { + if (hasArgAt(1) && new Utils().isInt(getArgAt(1))) { amount = Integer.parseInt(getArgAt(1)); } @@ -235,7 +235,7 @@ public void addSide() { return; } - if (isIllegal(side, itemInHand.getType())) { + if (new Utils().isIllegal(side, itemInHand.getType())) { Message.ILLEGAL_ITEM.sendMessage(getPlayerSender()); return; } diff --git a/src/main/java/org/shanerx/tradeshop/commands/commandrunners/ShopUserSubCommand.java b/src/main/java/org/shanerx/tradeshop/commands/commandrunners/ShopUserSubCommand.java index e2f4afc8..e125592b 100644 --- a/src/main/java/org/shanerx/tradeshop/commands/commandrunners/ShopUserSubCommand.java +++ b/src/main/java/org/shanerx/tradeshop/commands/commandrunners/ShopUserSubCommand.java @@ -27,7 +27,6 @@ import org.bukkit.Bukkit; import org.bukkit.OfflinePlayer; -import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.shanerx.tradeshop.TradeShop; import org.shanerx.tradeshop.commands.SubCommand; @@ -41,6 +40,7 @@ import org.shanerx.tradeshop.player.ShopUser; import org.shanerx.tradeshop.shop.Shop; import org.shanerx.tradeshop.shoplocation.ShopLocation; +import org.shanerx.tradeshop.utils.Utils; import org.shanerx.tradeshop.utils.objects.ObjectHolder; import org.shanerx.tradeshop.utils.objects.Tuple; @@ -96,7 +96,7 @@ public void who() { */ public void editUser(ShopRole role, ShopChange change) { try { - boolean applyAllOwned = hasArgAt(2) && getArgAt(2).length() > 0 && textToBool(getArgAt(2)); + boolean applyAllOwned = hasArgAt(2) && getArgAt(2).length() > 0 && new Utils().textToBool(getArgAt(2)); Set ownedShops = new HashSet<>(); Map updateStatuses = new HashMap<>(); @@ -125,7 +125,7 @@ public void editUser(ShopRole role, ShopChange change) { switch (change) { case REMOVE_USER: if (!shop.getUsersUUID(ShopRole.MANAGER, ShopRole.MEMBER).contains(target.getUniqueId())) { - updateStatuses.put(shop.getShopLocationAsSL().serialize(), UserOperationStatus.FAILED_MISSING.toString()); + updateStatuses.put(shop.getShopLocationAsSL().toString(), UserOperationStatus.FAILED_MISSING.toString()); break eachOwnedShop; } success = shop.removeUser(target.getUniqueId()); @@ -133,10 +133,10 @@ public void editUser(ShopRole role, ShopChange change) { case ADD_MANAGER: case ADD_MEMBER: if (shop.getUsersUUID(ShopRole.MANAGER, ShopRole.MEMBER).contains(target.getUniqueId())) { - updateStatuses.put(shop.getShopLocationAsSL().serialize(), UserOperationStatus.FAILED_EXISTING.toString()); + updateStatuses.put(shop.getShopLocationAsSL().toString(), UserOperationStatus.FAILED_EXISTING.toString()); break eachOwnedShop; } else if (shop.getUsers(ShopRole.MANAGER, ShopRole.MEMBER).size() >= Setting.MAX_SHOP_USERS.getInt()) { - updateStatuses.put(shop.getShopLocationAsSL().serialize(), UserOperationStatus.FAILED_CAPACITY.toString()); + updateStatuses.put(shop.getShopLocationAsSL().toString(), UserOperationStatus.FAILED_CAPACITY.toString()); break eachOwnedShop; } success = shop.addUser(target.getUniqueId(), role); @@ -144,7 +144,7 @@ public void editUser(ShopRole role, ShopChange change) { case SET_MANAGER: case SET_MEMBER: if (shop.getUsersExcluding(Collections.singletonList(target.getUniqueId()), ShopRole.MANAGER, ShopRole.MEMBER).size() >= Setting.MAX_SHOP_USERS.getInt()) { - updateStatuses.put(shop.getShopLocationAsSL().serialize(), UserOperationStatus.FAILED_CAPACITY.toString()); + updateStatuses.put(shop.getShopLocationAsSL().toString(), UserOperationStatus.FAILED_CAPACITY.toString()); break eachOwnedShop; } success = shop.setUser(target.getUniqueId(), role); @@ -152,9 +152,9 @@ public void editUser(ShopRole role, ShopChange change) { } if (success) - updateStatuses.put(shop.getShopLocationAsSL().serialize(), UserOperationStatus.SUCCESSFUL.toString()); + updateStatuses.put(shop.getShopLocationAsSL().toString(), UserOperationStatus.SUCCESSFUL.toString()); else - updateStatuses.put(shop.getShopLocationAsSL().serialize(), UserOperationStatus.FAILED.toString()); + updateStatuses.put(shop.getShopLocationAsSL().toString(), UserOperationStatus.FAILED.toString()); } } diff --git a/src/main/java/org/shanerx/tradeshop/commands/commandrunners/WhatSubCommand.java b/src/main/java/org/shanerx/tradeshop/commands/commandrunners/WhatSubCommand.java index 2bd91e24..dfdfb9e9 100644 --- a/src/main/java/org/shanerx/tradeshop/commands/commandrunners/WhatSubCommand.java +++ b/src/main/java/org/shanerx/tradeshop/commands/commandrunners/WhatSubCommand.java @@ -30,7 +30,6 @@ import de.themoep.inventorygui.StaticGuiElement; import org.bukkit.Bukkit; import org.bukkit.Material; -import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.inventory.ItemStack; import org.shanerx.tradeshop.TradeShop; @@ -42,6 +41,7 @@ import org.shanerx.tradeshop.player.ShopUser; import org.shanerx.tradeshop.shop.Shop; import org.shanerx.tradeshop.shop.ShopType; +import org.shanerx.tradeshop.utils.Utils; /** * Implementation of GUICommand for the `what` command @@ -90,7 +90,7 @@ public void what() { return; } - InventoryGui gui = new InventoryGui(plugin, colorize(shop.getShopType() == ShopType.ITRADE ? + InventoryGui gui = new InventoryGui(plugin, new Utils().colorize(shop.getShopType() == ShopType.ITRADE ? Setting.ITRADESHOP_OWNER.getString() : Bukkit.getOfflinePlayer(shop.getOwner().getUUID()).getName() + "'s Shop"), WHAT_MENU); diff --git a/src/main/java/org/shanerx/tradeshop/data/config/Message.java b/src/main/java/org/shanerx/tradeshop/data/config/Message.java index d745b7ce..6ad1156b 100644 --- a/src/main/java/org/shanerx/tradeshop/data/config/Message.java +++ b/src/main/java/org/shanerx/tradeshop/data/config/Message.java @@ -320,7 +320,7 @@ public final void sendItemMultiLineMessage(Player player, Map> entry : itemsToFill.entrySet()) { Pattern pattern = Pattern.compile(MULTILINEREGEX.replace("&V&", entry.getKey().toString())); @@ -367,7 +367,7 @@ public final void sendUserEditMultiLineMessage(Player player, Map> entry : valuesToFill.entrySet()) { Pattern pattern = Pattern.compile(MULTILINEREGEX.replace("&V&", entry.getKey().toString())); diff --git a/src/main/java/org/shanerx/tradeshop/data/config/Setting.java b/src/main/java/org/shanerx/tradeshop/data/config/Setting.java index c068e573..7f654a4a 100644 --- a/src/main/java/org/shanerx/tradeshop/data/config/Setting.java +++ b/src/main/java/org/shanerx/tradeshop/data/config/Setting.java @@ -25,7 +25,6 @@ package org.shanerx.tradeshop.data.config; -import org.bukkit.Bukkit; import org.shanerx.tradeshop.TradeShop; import org.shanerx.tradeshop.item.IllegalItemList; import org.shanerx.tradeshop.item.ShopItemStackSettingKeys; @@ -51,6 +50,7 @@ public enum Setting { // System Options DATA_STORAGE_TYPE(SettingSection.SYSTEM_OPTIONS, "data-storage-type", "FLATFILE"), + MAX_SAVE_THREADS(SettingSection.SYSTEM_OPTIONS, "max-save-threads", 3), ENABLE_DEBUG(SettingSection.SYSTEM_OPTIONS, "enable-debug", 0), CHECK_UPDATES(SettingSection.SYSTEM_OPTIONS, "check-updates", true), ALLOW_METRICS(SettingSection.SYSTEM_OPTIONS, "allow-metrics", true), @@ -132,7 +132,7 @@ public enum Setting { PRODUCT_ILLEGAL_ITEMS_TYPE(SettingSection.PRODUCT_ILLEGAL_ITEMS, "type", IllegalItemList.ListType.DISABLED.toString()), PRODUCT_ILLEGAL_ITEMS_LIST(SettingSection.PRODUCT_ILLEGAL_ITEMS, "list", new String[]{}); - public static final TradeShop PLUGIN = (TradeShop) Bukkit.getPluginManager().getPlugin("TradeShop"); + public static final TradeShop PLUGIN = TradeShop.getPlugin(); private final String key, path; private final Object defaultValue; @@ -155,12 +155,7 @@ public static Setting findSetting(String search) { static boolean upgrade() { double version = CONFIG_VERSION.getDouble(); Set hasUpgraded = new HashSet<>(); // Uses this instead of a boolean to later replace below ifs with boolean return methods... - ConfigManager configManager = PLUGIN.getSettingManager(); - - // 2.2.2 Changed enable debug from true/false to integer - if (!configManager.getConfig().isInt(ENABLE_DEBUG.path)) { - ENABLE_DEBUG.clearSetting(); - } + ConfigManager configManager = PLUGIN.getVarManager().getSettingManager(); // 2.2.2 Better Sorted/potentially commented config if (version < 1.1) { @@ -293,23 +288,23 @@ public Object getDefaultValue() { } public String getMappedString(String subKey) { - return PLUGIN.getSettingManager().getConfig().getConfigurationSection(getPath()).getString(subKey.toLowerCase().replace("_", "-")); + return PLUGIN.getVarManager().getSettingManager().getConfig().getConfigurationSection(getPath()).getString(subKey.toLowerCase().replace("_", "-")); } public boolean getMappedBoolean(String subKey) { - return PLUGIN.getSettingManager().getConfig().getConfigurationSection(getPath()).getBoolean(subKey.toLowerCase().replace("_", "-")); + return PLUGIN.getVarManager().getSettingManager().getConfig().getConfigurationSection(getPath()).getBoolean(subKey.toLowerCase().replace("_", "-")); } public Object getMappedObject(String subKey) { - return PLUGIN.getSettingManager().getConfig().getConfigurationSection(getPath()).get(subKey.toLowerCase().replace("_", "-")); + return PLUGIN.getVarManager().getSettingManager().getConfig().getConfigurationSection(getPath()).get(subKey.toLowerCase().replace("_", "-")); } public String getPostComment() { - return PLUGIN.getLanguage().getPostComment(Language.LangSection.SETTING, Language.LangSubSection.VALUES, path); + return PLUGIN.getVarManager().getLanguage().getPostComment(Language.LangSection.SETTING, Language.LangSubSection.VALUES, path); } public String getPreComment() { - return PLUGIN.getLanguage().getPreComment(Language.LangSection.SETTING, Language.LangSubSection.VALUES, path); + return PLUGIN.getVarManager().getLanguage().getPreComment(Language.LangSection.SETTING, Language.LangSubSection.VALUES, path); } public SettingSection getSection() { @@ -345,7 +340,7 @@ public String getFileString() { StringBuilder keyOutput = new StringBuilder(); if (!getPreComment().isEmpty()) { - keyOutput.append(section.getSectionLead()).append("# ").append(PLUGIN.getSettingManager().fixCommentNewLines(section.getSectionLead(), getPreComment())).append("\n"); + keyOutput.append(section.getSectionLead()).append("# ").append(PLUGIN.getVarManager().getSettingManager().fixCommentNewLines(section.getSectionLead(), getPreComment())).append("\n"); } if (defaultValue instanceof Map) { @@ -359,50 +354,54 @@ public String getFileString() { if (getPostComment().equals(" ") || getPostComment().equals("\n")) keyOutput.append(getPostComment()).append("\n"); else - keyOutput.append(section.getSectionLead()).append("# ").append(PLUGIN.getSettingManager().fixCommentNewLines(section.getSectionLead(), getPostComment())).append("\n"); + keyOutput.append(section.getSectionLead()).append("# ").append(PLUGIN.getVarManager().getSettingManager().fixCommentNewLines(section.getSectionLead(), getPostComment())).append("\n"); } return keyOutput.toString(); } public Map getAsMap() { - return PLUGIN.getSettingManager().getConfig().getConfigurationSection(getPath()).getValues(true); + return PLUGIN.getVarManager().getSettingManager().getConfig().getConfigurationSection(getPath()).getValues(true); } public void setValue(Object obj) { - PLUGIN.getSettingManager().getConfig().set(getPath(), obj); + PLUGIN.getVarManager().getSettingManager().getConfig().set(getPath(), obj); } public void setMappedValue(String subKey, Object obj) { String newNode = getPath() + "." + subKey; - PLUGIN.getSettingManager().getConfig().set(newNode, obj); + PLUGIN.getVarManager().getSettingManager().getConfig().set(newNode, obj); } public void clearSetting() { - PLUGIN.getSettingManager().getConfig().set(getPath(), null); + setValue(null); + } + + public void resetSetting() { + setValue(getDefaultValue()); } public Object getSetting() { - return PLUGIN.getSettingManager().getConfig().get(getPath()); + return PLUGIN.getVarManager().getSettingManager().getConfig().get(getPath()); } public String getString() { - return PLUGIN.getSettingManager().getConfig().getString(getPath()); + return PLUGIN.getVarManager().getSettingManager().getConfig().getString(getPath()); } public List getStringList() { - return PLUGIN.getSettingManager().getConfig().getStringList(getPath()); + return PLUGIN.getVarManager().getSettingManager().getConfig().getStringList(getPath()); } public int getInt() { - return PLUGIN.getSettingManager().getConfig().getInt(getPath()); + return PLUGIN.getVarManager().getSettingManager().getConfig().getInt(getPath()); } public double getDouble() { - return PLUGIN.getSettingManager().getConfig().getDouble(getPath()); + return PLUGIN.getVarManager().getSettingManager().getConfig().getDouble(getPath()); } public boolean getBoolean() { - return PLUGIN.getSettingManager().getConfig().getBoolean(getPath()); + return PLUGIN.getVarManager().getSettingManager().getConfig().getBoolean(getPath()); } } \ No newline at end of file diff --git a/src/main/java/org/shanerx/tradeshop/data/storage/DataStorage.java b/src/main/java/org/shanerx/tradeshop/data/storage/DataStorage.java index cb96f13c..50441db1 100644 --- a/src/main/java/org/shanerx/tradeshop/data/storage/DataStorage.java +++ b/src/main/java/org/shanerx/tradeshop/data/storage/DataStorage.java @@ -36,16 +36,15 @@ import org.bukkit.World; import org.bukkit.inventory.ItemStack; import org.shanerx.tradeshop.TradeShop; -import org.shanerx.tradeshop.data.storage.Json.JsonLinkageConfiguration; -import org.shanerx.tradeshop.data.storage.Json.JsonPlayerConfiguration; -import org.shanerx.tradeshop.data.storage.Json.JsonShopConfiguration; +import org.shanerx.tradeshop.data.storage.Json.JsonLinkageData; +import org.shanerx.tradeshop.data.storage.Json.JsonPlayerData; +import org.shanerx.tradeshop.data.storage.Json.JsonShopData; import org.shanerx.tradeshop.item.ShopItemSide; import org.shanerx.tradeshop.player.PlayerSetting; import org.shanerx.tradeshop.shop.Shop; import org.shanerx.tradeshop.shop.ShopStatus; import org.shanerx.tradeshop.shoplocation.ShopChunk; import org.shanerx.tradeshop.shoplocation.ShopLocation; -import org.shanerx.tradeshop.utils.Utils; import org.shanerx.tradeshop.utils.debug.DebugLevels; import java.io.File; @@ -53,7 +52,6 @@ import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.ArrayList; -import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -63,10 +61,9 @@ import java.util.logging.Level; import java.util.stream.Collectors; -public class DataStorage extends Utils { +public class DataStorage { private transient DataType dataType; - public final Map saving; private final String BROKEN_JSON_START = "}(.*[\"\\w:])"; private final Cache linkCache = CacheBuilder.newBuilder() @@ -83,7 +80,6 @@ public class DataStorage extends Utils { .build(); public DataStorage(DataType dataType) { - saving = new HashMap<>(); reload(dataType); } @@ -102,9 +98,9 @@ public boolean validate() { //Check for err files Bukkit.getServer().getWorlds().forEach((w) -> { - File[] list = JsonShopConfiguration.getFilesInFolder(w.getName()); - if (list != null && list.length > 0) { - errFiles.addAll(Arrays.stream(list).filter((f) -> FilenameUtils.getExtension(f.getName()).toLowerCase().contains("err")).collect(Collectors.toList())); + List list = JsonShopData.getFilesInFolder(w.getName()); + if (!list.isEmpty()) { + errFiles.addAll(list.stream().filter((f) -> FilenameUtils.getExtension(f.getName()).toLowerCase().contains("err")).collect(Collectors.toList())); } }); @@ -112,9 +108,9 @@ public boolean validate() { //Check for and correct malformed files Bukkit.getServer().getWorlds().forEach((w) -> { - File[] list = JsonShopConfiguration.getFilesInFolder(w.getName()); - if (list != null && list.length > 0) { - Arrays.stream(list).forEach((f) -> { + List list = JsonShopData.getFilesInFolder(w.getName()); + if (!list.isEmpty()) { + list.forEach((f) -> { try { String fileStr = FileUtils.readFileToString(f, StandardCharsets.UTF_8), correctedString = fileStr.split(BROKEN_JSON_START)[0]; @@ -130,8 +126,6 @@ public boolean validate() { } }); - TradeShop.getPlugin().getDebugger().log("FLATFILE Malformed Files Found: " + correctedFiles.size(), DebugLevels.DATA_ERROR); - //Write corrected malformed files if (correctedFiles.size() > 0) { correctedFiles.forEach((k, v) -> { @@ -151,11 +145,11 @@ public boolean validate() { TradeShop.getPlugin().getDebugger().log("Removing empty player files... ", DebugLevels.DATA_VERIFICATION); - File[] playerFiles = JsonPlayerConfiguration.getAllPlayers(); + List playerFiles = JsonPlayerData.getAllPlayers(); if (playerFiles != null) { List deletedResults = new ArrayList<>(); Map failedResults = new HashMap<>(); - Arrays.stream(playerFiles).forEach((file) -> { + playerFiles.forEach((file) -> { if (file.isFile() && file.length() == 0) { try { file.delete(); @@ -166,8 +160,13 @@ public boolean validate() { } }); - TradeShop.getPlugin().getDebugger().log("Empty files deleted: " + deletedResults.size(), DebugLevels.DATA_VERIFICATION); - TradeShop.getPlugin().getDebugger().log("# of empty player files that couldn't be deleted: " + failedResults.size() + (failedResults.size() > 0 ? ("\nFailed Deletion results: \n" + failedResults.entrySet().stream().map((entry) -> entry.getKey() + ": " + entry.getValue().getMessage()).collect(Collectors.joining("\n"))) : "\n"), DebugLevels.DATA_ERROR); + if (deletedResults.size() != 0) + TradeShop.getPlugin().getDebugger().log("Empty files deleted: " + deletedResults.size(), DebugLevels.DATA_VERIFICATION); + if (failedResults.size() != 0) + TradeShop.getPlugin().getDebugger().log("# of empty player files that couldn't be deleted: " + + failedResults.size() + + (failedResults.size() > 0 ? ("\nFailed Deletion results: \n" + failedResults.entrySet().stream().map((entry) -> entry.getKey() + ": " + entry.getValue().getMessage()).collect(Collectors.joining("\n"))) : "\n") + , DebugLevels.DATA_ERROR); } return errFiles.size() < 1; @@ -176,50 +175,47 @@ public boolean validate() { } public Shop loadShopFromSign(ShopLocation sign) { - Shop cached = shopCache.getIfPresent(sign.serialize()); - return cached != null ? cached : getShopConfiguration(sign.getChunk()).load(sign); + if (sign == null) return null; + Shop cached = shopCache.getIfPresent(sign.toString()); + return cached != null ? cached : getShopData(sign.getChunk()).load(sign); } public Shop loadShopFromStorage(ShopLocation chest) { - return loadShopFromSign(getLinkageConfiguration(chest.getWorld()).getLinkedShop(chest)); + return loadShopFromSign(getLinkageData(chest.getWorld()).getLinkedShop(chest)); } public void saveShop(Shop shop) { - shopCache.put(shop.getShopLocationAsSL().serialize(), shop); - getShopConfiguration(shop.getShopLocation().getChunk()).save(shop); + shopCache.put(shop.getShopLocationAsSL().toString(), shop); + getShopData(shop.getShopLocation().getChunk()).save(shop); } public void removeShop(Shop shop) { - shopCache.invalidate(shop.getShopLocationAsSL().serialize()); - getShopConfiguration(shop.getShopLocation().getChunk()).remove(shop.getShopLocationAsSL()); - getLinkageConfiguration(shop.getShopLocationAsSL().getWorld()).removeShop(shop.getShopLocationAsSL()); + shopCache.invalidate(shop.getShopLocationAsSL().toString()); + getShopData(shop.getShopLocation().getChunk()).remove(shop.getShopLocationAsSL()); + getLinkageData(shop.getShopLocationAsSL().getWorld()).removeShop(shop.getShopLocationAsSL()); } public int getShopCountInChunk(Chunk chunk) { - return getShopConfiguration(chunk).size(); + return getShopData(chunk).size(); } public List getMatchingShopsInChunk(ChunkSnapshot chunk, boolean inStock, List desiredCosts, List desiredProducts) { List matchingShops = new ArrayList<>(); - ShopChunk shopChunk = new ShopChunk(chunk); - if (chunkExists(shopChunk)) { - ShopConfiguration config = getShopConfiguration(shopChunk); + ShopConfiguration config = getShopData(new ShopChunk(chunk)); - config.list().forEach((shopLoc) -> { - Shop shop = config.loadASync(shopLoc); + config.list().forEach((shopLoc) -> { + Shop shop = config.loadASync(shopLoc); - if ((desiredCosts != null && shop.isMissingSideItems(ShopItemSide.COST, desiredCosts)) || - (desiredProducts != null && shop.isMissingSideItems(ShopItemSide.PRODUCT, desiredProducts))) - return; //Ignore any shops that don't have a matching product/cost + if ((desiredCosts != null && shop.isMissingSideItems(ShopItemSide.COST, desiredCosts)) || + (desiredProducts != null && shop.isMissingSideItems(ShopItemSide.PRODUCT, desiredProducts))) + return; //Ignore any shops that don't have a matching product/cost - if (!inStock || shop.getStatus().equals(ShopStatus.OPEN)) { - matchingShops.add(shop); - } - }); + if (!inStock || shop.getStatus().equals(ShopStatus.OPEN)) { + matchingShops.add(shop); + } + }); - TradeShop.getPlugin().getDebugger().log(" --- _G_M_ --- " + Arrays.toString(matchingShops.stream().map(shop -> shop.getShopLocationAsSL().serialize()).toArray(String[]::new)), DebugLevels.DATA_ERROR); - } return matchingShops; } @@ -233,8 +229,8 @@ public int getShopCountInWorld(World world) { File folder = new File(TradeShop.getPlugin().getDataFolder().getAbsolutePath() + File.separator + "Data" + File.separator + worldName); if (folder.exists() && folder.listFiles() != null) { for (File file : folder.listFiles()) { - if (file.getName().contains(worldName)) - count.addAndGet(new JsonShopConfiguration(ShopChunk.deserialize(file.getName().replace(".json", ""))).size()); + if (file.getName().contains(worldName) && file.getName().endsWith(".json")) + count.addAndGet(new JsonShopData(ShopChunk.deserialize(file.getName().replace(".json", ""))).size()); } } break; @@ -247,7 +243,7 @@ public int getShopCountInWorld(World world) { } public PlayerSetting loadPlayer(UUID uuid) { - PlayerSetting playerSetting = playerCache.getIfPresent(uuid) != null ? playerCache.getIfPresent(uuid) : getPlayerConfiguration(uuid).load(); + PlayerSetting playerSetting = playerCache.getIfPresent(uuid) != null ? playerCache.getIfPresent(uuid) : getPlayerData(uuid).load(); //If playerSetting data not find create new and return return playerSetting != null ? playerSetting : new PlayerSetting(uuid); @@ -255,57 +251,61 @@ public PlayerSetting loadPlayer(UUID uuid) { public void savePlayer(PlayerSetting playerSetting) { playerCache.put(playerSetting.getUuid(), playerSetting); - getPlayerConfiguration(playerSetting.getUuid()).save(playerSetting); + getPlayerData(playerSetting.getUuid()).save(playerSetting); } public void removePlayer(PlayerSetting playerSetting) { playerCache.invalidate(playerSetting.getUuid()); - getPlayerConfiguration(playerSetting.getUuid()).remove(); + getPlayerData(playerSetting.getUuid()).remove(); } public ShopLocation getChestLinkage(ShopLocation chestLocation) { - return getLinkageConfiguration(chestLocation.getWorld()).getLinkedShop(chestLocation); + return getLinkageData(chestLocation.getWorld()).getLinkedShop(chestLocation); } public void addChestLinkage(ShopLocation chestLocation, ShopLocation shopLocation) { if (Bukkit.isPrimaryThread() && getChestLinkage(chestLocation) == null) - getLinkageConfiguration(chestLocation.getWorld()).add(chestLocation, shopLocation); + getLinkageData(chestLocation.getWorld()).add(chestLocation, shopLocation); } public void removeChestLinkage(ShopLocation chestLocation) { - getLinkageConfiguration(chestLocation.getWorld()).removeChest(chestLocation); + getLinkageData(chestLocation.getWorld()).removeChest(chestLocation); } - protected PlayerConfiguration getPlayerConfiguration(UUID uuid) { + protected PlayerConfiguration getPlayerData(UUID uuid) { if (dataType == DataType.FLATFILE) { - return new JsonPlayerConfiguration(uuid); + return new JsonPlayerData(uuid); } throw new NotImplementedException("Data storage type " + dataType + " has not been implemented yet."); } - protected ShopConfiguration getShopConfiguration(Chunk chunk) { - return getShopConfiguration(new ShopChunk(chunk)); + protected ShopConfiguration getShopData(Chunk chunk) { + return getShopData(new ShopChunk(chunk)); } - protected ShopConfiguration getShopConfiguration(ShopChunk chunk) { + private final Map chunkDataCache = new HashMap<>(); + protected ShopConfiguration getShopData(ShopChunk chunk) { if (dataType == DataType.FLATFILE) { - return new JsonShopConfiguration(chunk); + String serializedChunk = chunk.serialize(); + if (chunkDataCache.containsKey(serializedChunk)) + return chunkDataCache.get(serializedChunk); + JsonShopData data = new JsonShopData(chunk); + chunkDataCache.put(serializedChunk, data); + return new JsonShopData(chunk); } + throw new NotImplementedException("Data storage type " + dataType + " has not been implemented yet."); } - protected boolean chunkExists(ShopChunk chunk) { - if (dataType == DataType.FLATFILE) { - return JsonShopConfiguration.doesConfigExist(chunk); - } - throw new NotImplementedException("Data storage type " + dataType + " has not been implemented yet."); + public void dropShopData(ShopChunk chunk) { + chunkDataCache.remove(chunk.serialize()); } - protected LinkageConfiguration getLinkageConfiguration(World w) { + protected LinkageConfiguration getLinkageData(World w) { if (linkCache.getIfPresent(w) == null) { if (dataType == DataType.FLATFILE) { - linkCache.put(w, new JsonLinkageConfiguration(w)); + linkCache.put(w, new JsonLinkageData(w)); } } @@ -315,5 +315,13 @@ protected LinkageConfiguration getLinkageConfiguration(World w) { throw new NotImplementedException("Data storage type " + dataType + " has not been implemented yet."); } + + public void ensureFinalSave() { + // for onDisable !!! + if (dataType == DataType.FLATFILE) { + JsonShopData.SaveThreadMaster.getInstance().saveEverythingNow(); + } + // SQLITE will have an analogous branch + } } diff --git a/src/main/java/org/shanerx/tradeshop/data/storage/Json/JsonConfiguration.java b/src/main/java/org/shanerx/tradeshop/data/storage/Json/JsonConfiguration.java index 66f52955..f37342e8 100644 --- a/src/main/java/org/shanerx/tradeshop/data/storage/Json/JsonConfiguration.java +++ b/src/main/java/org/shanerx/tradeshop/data/storage/Json/JsonConfiguration.java @@ -25,28 +25,18 @@ package org.shanerx.tradeshop.data.storage.Json; -import com.google.gson.JsonObject; -import com.google.gson.JsonParser; -import com.google.gson.JsonSyntaxException; +import de.leonhard.storage.Json; +import de.leonhard.storage.util.FileUtils; import org.shanerx.tradeshop.TradeShop; -import org.shanerx.tradeshop.utils.Utils; -import org.shanerx.tradeshop.utils.debug.DebugLevels; -import org.shanerx.tradeshop.utils.gsonprocessing.GsonProcessor; import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; -import java.nio.file.Files; -import java.util.logging.Level; +import java.util.List; -class JsonConfiguration extends Utils { - protected final GsonProcessor gson; - protected File file, pathFile; - protected JsonObject jsonObj; +class JsonConfiguration extends Json { + //protected static final Map fileCache = new HashMap<>(); protected final TradeShop PLUGIN = TradeShop.getPlugin(); + protected final String fileKey; /** * Creates a JsonConfiguration object assisting with managing JSON data @@ -55,88 +45,41 @@ class JsonConfiguration extends Utils { * @param fileName name of the file to load without extension */ protected JsonConfiguration(String folderFromData, String fileName) { - this.gson = new GsonProcessor(); - this.pathFile = getPath(folderFromData); - this.file = getFile(folderFromData, fileName); + super(new File(getPath(folderFromData), fileName + ".json")); + fileKey = folderFromData + ":" + fileName; - buildFilePath(); loadFile(); } - public static File getFile(String folderFromData, String fileName) { - return new File(getPath(folderFromData).getPath() + File.separator + fileName + ".json"); - } + public static JsonConfiguration getJsonConfiguration(String folderFromData, String fileName) { + String key = folderFromData + ":" + fileName; - public static File getPath(String folderFromData) { - return new File(TradeShop.getPlugin().getDataFolder().getAbsolutePath() + File.separator + "Data" + File.separator + folderFromData); - } + /*if (fileCache.containsKey(key)) { + return fileCache.get(key); + }*/ - private void buildFilePath() { - try { - pathFile.mkdirs(); - file.createNewFile(); - } catch (IOException e) { - PLUGIN.getLogger().log(Level.SEVERE, "Could not create " + file.getName() + " file! Data may be lost!", e); - } + return new JsonConfiguration(folderFromData, fileName); } - public static void jsonSyntaxError(File file, Exception e) { - String errStr = ""; - - try { - errStr = new String(Files.readAllBytes(file.toPath())); - } catch (IOException ex) { - TradeShop.getPlugin().getLogger().log(Level.SEVERE, "Could not read " + file.getName() + " file! ERR", e); - } - - File err = new File(file.getPath() + File.separator + file.getName().replace(".json", ".err")); - - try { - FileWriter fileWriter = new FileWriter(err); - fileWriter.write(e.toString()); - fileWriter.append("\n\n--------------------------------------------------------------------------------------\n\n"); - fileWriter.append(errStr); - fileWriter.flush(); - fileWriter.close(); - } catch (IOException ex) { - TradeShop.getPlugin().getLogger().log(Level.SEVERE, "Could not save " + file.getName() + " file! Writing err to console.", e); - TradeShop.getPlugin().getLogger().log(Level.SEVERE, e + "\n\n--------------------------------------------------------------------------------------\n\n" + errStr, e); - } + public static String getPath(String folderFromData) { + return TradeShop.getPlugin().getDataFolder().getAbsolutePath() + File.separator + "Data" + File.separator + folderFromData; } - public static File[] getFilesInFolder(String folderFromData) { - File dir = getPath(folderFromData); - TradeShop.getPlugin().getVarManager().getDebugger().log("reading file list from " + dir.getAbsolutePath(), DebugLevels.DATA_VERIFICATION); - return dir.listFiles(); + public static List getFilesInFolder(String folderFromData) { + return FileUtils.listFiles(new File(getPath(folderFromData)), "json"); } protected void loadFile() { - try { - jsonObj = JsonParser.parseReader(new FileReader(file)).getAsJsonObject(); - - } catch (FileNotFoundException e) { - PLUGIN.getLogger().log(Level.SEVERE, "Could not load " + file.getName() + " file! Data may be lost!", e); - } catch (IllegalStateException e) { - jsonObj = new JsonObject(); - } catch (JsonSyntaxException e) { - PLUGIN.getLogger().log(Level.SEVERE, "Could not load " + file.getName() + " file due to malformed Json! \n Please send the .err file with the same name to the TradeShop Devs. \n\nTradeShop will now disable, please remove/fix any err files before restarting the plugin.", e); - - jsonSyntaxError(file, e); - } + forceReload(); + //fileCache.put(fileKey, this); } protected void saveFile() { - final String str = gson.toJson(jsonObj); - if (!str.isEmpty()) { - try { - FileWriter fileWriter = new FileWriter(this.file); - fileWriter.write(str); - fileWriter.flush(); - fileWriter.close(); - } catch (IOException e) { - PLUGIN.getLogger().log(Level.SEVERE, "Could not save " + this.file.getName() + " file! Data may be lost!", e); - } + if (!file.exists()) create(); + try { + write(); + } catch (Exception e) { + e.printStackTrace(); } - } } diff --git a/src/main/java/org/shanerx/tradeshop/data/storage/Json/JsonLinkageConfiguration.java b/src/main/java/org/shanerx/tradeshop/data/storage/Json/JsonLinkageData.java similarity index 71% rename from src/main/java/org/shanerx/tradeshop/data/storage/Json/JsonLinkageConfiguration.java rename to src/main/java/org/shanerx/tradeshop/data/storage/Json/JsonLinkageData.java index c7678d73..da16a74e 100644 --- a/src/main/java/org/shanerx/tradeshop/data/storage/Json/JsonLinkageConfiguration.java +++ b/src/main/java/org/shanerx/tradeshop/data/storage/Json/JsonLinkageData.java @@ -25,40 +25,35 @@ package org.shanerx.tradeshop.data.storage.Json; -import com.google.gson.reflect.TypeToken; import org.bukkit.World; import org.shanerx.tradeshop.data.storage.LinkageConfiguration; -import java.util.HashMap; import java.util.Map; -public class JsonLinkageConfiguration extends JsonConfiguration implements LinkageConfiguration { +public class JsonLinkageData extends JsonConfiguration implements LinkageConfiguration { - Map linkageData; + Map linkageData; - public JsonLinkageConfiguration(World world) { + public JsonLinkageData(World world) { super(world.getName(), "chest_linkage"); load(); } @Override public void load() { - linkageData = gson.fromJson(jsonObj.get("linkage_data"), new TypeToken>() { - }.getType()); - - if (linkageData == null) - linkageData = new HashMap<>(); + loadFile(); + linkageData = getMapParameterized("linkage_data"); } @Override - public Map getLinkageData() { + public Map getLinkageData() { return linkageData; } @Override public void save() { - jsonObj.add("linkage_data", gson.toJsonTree(linkageData)); - + if (linkageData == null) load(); + set("linkage_data", linkageData); saveFile(); } } diff --git a/src/main/java/org/shanerx/tradeshop/data/storage/Json/JsonPlayerConfiguration.java b/src/main/java/org/shanerx/tradeshop/data/storage/Json/JsonPlayerData.java similarity index 69% rename from src/main/java/org/shanerx/tradeshop/data/storage/Json/JsonPlayerConfiguration.java rename to src/main/java/org/shanerx/tradeshop/data/storage/Json/JsonPlayerData.java index 236d8138..b29c3564 100644 --- a/src/main/java/org/shanerx/tradeshop/data/storage/Json/JsonPlayerConfiguration.java +++ b/src/main/java/org/shanerx/tradeshop/data/storage/Json/JsonPlayerData.java @@ -25,57 +25,53 @@ package org.shanerx.tradeshop.data.storage.Json; -import com.google.gson.reflect.TypeToken; import org.shanerx.tradeshop.data.storage.PlayerConfiguration; import org.shanerx.tradeshop.player.PlayerSetting; import java.io.File; -import java.util.Map; +import java.util.List; import java.util.UUID; -public class JsonPlayerConfiguration extends JsonConfiguration implements PlayerConfiguration { +public class JsonPlayerData extends JsonConfiguration implements PlayerConfiguration { private final transient UUID playerUUID; private transient PlayerSetting playerSetting; private static final String playerFolder = "Players"; - public JsonPlayerConfiguration(UUID uuid) { + public JsonPlayerData(UUID uuid) { super(playerFolder, uuid.toString()); playerUUID = uuid; } + public static List getAllPlayers() { + return getFilesInFolder(playerFolder); + } + @Override public void save(PlayerSetting playerSetting) { this.playerSetting = playerSetting; - jsonObj.add(playerSetting.getUuid().toString(), gson.toJsonTree(playerSetting)); + set(playerSetting.getUuid().toString(), playerSetting.serialize()); saveFile(); } @Override public PlayerSetting load() { - if (jsonObj.has("data")) { - playerSetting = new PlayerSetting(playerUUID, gson.fromJson(jsonObj.get("data"), new TypeToken>() { - }.getType())); - jsonObj.remove("data"); - saveFile(); - } else { - playerSetting = gson.fromJson(jsonObj.get(playerUUID.toString()), PlayerSetting.class); + playerSetting = PlayerSetting.deserialize(getMapParameterized(playerUUID.toString())); + + if (playerSetting == null) { + playerSetting = new PlayerSetting(playerUUID); + save(playerSetting); } - if (playerSetting != null) - playerSetting.load(); + playerSetting.load(); return playerSetting; } @Override public void remove() { - file.delete(); - } - - public static File[] getAllPlayers() { - return getFilesInFolder(playerFolder); + super.remove(playerUUID.toString()); } } diff --git a/src/main/java/org/shanerx/tradeshop/data/storage/Json/JsonShopConfiguration.java b/src/main/java/org/shanerx/tradeshop/data/storage/Json/JsonShopConfiguration.java deleted file mode 100644 index 614f9876..00000000 --- a/src/main/java/org/shanerx/tradeshop/data/storage/Json/JsonShopConfiguration.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - * - * Copyright (c) 2016-2023 - * SparklingComet @ http://shanerx.org - * KillerOfPie @ http://killerofpie.github.io - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * NOTICE: All modifications made by others to the source code belong - * to the respective contributor. No contributor should be held liable for - * any damages of any kind, whether be material or moral, which were - * caused by their contribution(s) to the project. See the full License for more information. - * - */ - -package org.shanerx.tradeshop.data.storage.Json; - -import com.google.common.collect.Sets; -import com.google.gson.JsonElement; -import org.bukkit.Bukkit; -import org.shanerx.tradeshop.TradeShop; -import org.shanerx.tradeshop.data.storage.ShopConfiguration; -import org.shanerx.tradeshop.shop.Shop; -import org.shanerx.tradeshop.shoplocation.ShopChunk; -import org.shanerx.tradeshop.shoplocation.ShopLocation; -import org.shanerx.tradeshop.utils.debug.DebugLevels; - -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.logging.Level; - -public class JsonShopConfiguration extends JsonConfiguration implements ShopConfiguration { - - private final ShopChunk chunk; - - public JsonShopConfiguration(ShopChunk chunk) { - super(chunk.getWorldName(), chunk.serialize()); - this.chunk = chunk; - } - - public static boolean doesConfigExist(ShopChunk chunk) { - return getFile(chunk.getWorldName(), chunk.serialize()).exists(); - } - - @Override - public void save(Shop shop) { - jsonObj.add(shop.getShopLocationAsSL().serialize(), gson.toJsonTree(shop)); - - saveFile(); - } - - @Override - public void remove(ShopLocation loc) { - if (jsonObj.has(loc.serialize())) - jsonObj.remove(loc.serialize()); - - saveFile(); - } - - @Override - public Shop load(ShopLocation loc) { - Shop shop = loadASync(loc); - - if (shop == null) - return null; - - shop.fixAfterLoad(); - return shop; - } - - @Override - public Shop loadASync(ShopLocation loc) { - String locStr = loc.serialize(); - Shop shop = null; - - if (!jsonObj.has(locStr)) return null; - - try { - shop = gson.fromJson(jsonObj.get(locStr), Shop.class); - shop.aSyncFix(); - } catch (IllegalArgumentException iAe) { - iAe.printStackTrace(); - remove(loc); - } - - return shop; - } - - @Override - public List list() { - List shopsInFile = new ArrayList<>(); - jsonObj.keySet().forEach(str -> shopsInFile.add(ShopLocation.deserialize(str))); - return shopsInFile; - } - - @Override - public int size() { - return jsonObj.size(); - } - - @Override - protected void saveFile() { - if (!PLUGIN.getDataStorage().saving.containsKey(file)) { - final String str = gson.toJson(jsonObj); - PLUGIN.getDataStorage().saving.put(file, str); - if (!str.isEmpty()) { - Bukkit.getScheduler().runTaskAsynchronously(TradeShop.getPlugin(), () -> { - try { - FileWriter fileWriter = new FileWriter(this.file); - fileWriter.write(str); - fileWriter.flush(); - fileWriter.close(); - } catch (IOException e) { - PLUGIN.getLogger().log(Level.SEVERE, "Could not save " + this.file.getName() + " file! Data may be lost!", e); - } - PLUGIN.getDataStorage().saving.remove(this.file); - }); - } - } - } - - @Override - protected void loadFile() { - if (!this.file.exists()) { - // If could not find file try with old separators - String oldFile = file.getPath() + File.separator + chunk.serialize().replace(";;", "_") + ".json"; - if (new File(oldFile).exists()) - new File(oldFile).renameTo(file); - } - - super.loadFile(); - - for (Map.Entry entry : Sets.newHashSet(jsonObj.entrySet())) { - if (entry.getKey().contains("l_")) { - jsonObj.add(ShopLocation.deserialize(entry.getKey()).serialize(), entry.getValue()); - jsonObj.remove(entry.getKey()); - } - } - } -} diff --git a/src/main/java/org/shanerx/tradeshop/data/storage/Json/JsonShopData.java b/src/main/java/org/shanerx/tradeshop/data/storage/Json/JsonShopData.java new file mode 100644 index 00000000..d13fb883 --- /dev/null +++ b/src/main/java/org/shanerx/tradeshop/data/storage/Json/JsonShopData.java @@ -0,0 +1,262 @@ +/* + * + * Copyright (c) 2016-2023 + * SparklingComet @ http://shanerx.org + * KillerOfPie @ http://killerofpie.github.io + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * NOTICE: All modifications made by others to the source code belong + * to the respective contributor. No contributor should be held liable for + * any damages of any kind, whether be material or moral, which were + * caused by their contribution(s) to the project. See the full License for more information. + * + */ + +package org.shanerx.tradeshop.data.storage.Json; + +import lombok.Getter; +import org.bukkit.scheduler.BukkitRunnable; +import org.jetbrains.annotations.NotNull; +import org.shanerx.tradeshop.TradeShop; +import org.shanerx.tradeshop.data.config.Setting; +import org.shanerx.tradeshop.data.storage.ShopConfiguration; +import org.shanerx.tradeshop.shop.Shop; +import org.shanerx.tradeshop.shoplocation.ShopChunk; +import org.shanerx.tradeshop.shoplocation.ShopLocation; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentSkipListSet; + +public class JsonShopData extends JsonConfiguration implements ShopConfiguration { + + private final ShopChunk chunk; + private Map chunkMap; + + public JsonShopData(ShopChunk chunk) { + super(chunk.getWorldName(), chunk.serialize()); + this.chunk = chunk; + } + + + @Override + public void save(Shop shop) { + set(shop.getShopLocationAsSL().toString(), shop.serialize()); + saveFile(); + } + + @Override + public void remove(ShopLocation loc) { + remove(loc.toString()); + } + + @Override + public Shop load(ShopLocation loc) { + Shop shop = loadASync(loc); + + if (shop == null) + return null; + + shop.fixAfterLoad(); + return shop; + } + + @Override + public Shop loadASync(ShopLocation loc) { + String locStr = loc.toString(); + if (!fileData.containsKey(locStr)) + return null; + + Shop shop = Shop.deserialize(getSection(locStr)); + + shop.aSyncFix(); + return shop; + } + + @Override + public List list() { + List shopsInFile = new ArrayList<>(); + keySet().forEach(str -> shopsInFile.add(ShopLocation.deserialize(str))); + return shopsInFile; + } + + @Override + public int size() { + return keySet().size(); + } + + @Override + protected void saveFile() { + SaveThreadMaster.getInstance().enqueue(this); + } + + @Override + protected void loadFile() { + + if (!this.file.isFile()) { + // If could not find file try with old separators + String oldFile = file.getPath() + File.separator + chunk.serialize().replace(";;", "_") + ".json"; + if (new File(oldFile).isFile()) new File(oldFile).renameTo(file); + } + + String data = ""; + + try { + for (Map.Entry entry : readToMap().entrySet()) { + if (entry.getKey().contains("l_")) { + set(ShopLocation.deserialize(entry.getKey()).toString(), entry.getValue()); + remove(entry.getKey()); + } + } + } catch (IOException ex) { + ex.printStackTrace(); + } + } + + public static class SaveOperation implements Comparable { + + @Getter + private final JsonConfiguration jsonConfig; + private final long time; + + SaveOperation(JsonConfiguration jsonConfig) { + this.jsonConfig = jsonConfig; + this.time = System.currentTimeMillis(); + } + + @Override + public int compareTo(@NotNull SaveOperation so) { + if (!this.jsonConfig.getFile().exists() || (this.jsonConfig.getFile().isFile() != so.jsonConfig.getFile().isFile())) { + return -1; + } + + try { + if (Files.isSameFile(this.jsonConfig.getFile().toPath(), so.jsonConfig.getFile().toPath())) return 0; + } catch (IOException e) { + throw new RuntimeException(e); + } + + if (this.time <= so.time) return -1; + return 1; + } + + @Override + public int hashCode() { + return jsonConfig.getFile().hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof SaveOperation)) return false; + return hashCode() == obj.hashCode(); + } + } + + public static class SaveThreadMaster { + private static SaveThreadMaster singleton; + + private final ConcurrentSkipListSet saveQueue; + private final Set runningTasks; + + private final int maxThreads; + + private SaveThreadMaster() { + if (singleton != null) { + throw new UnsupportedOperationException("Attempting to create further instance of singleton class SaveThreadMaster!"); + } + + saveQueue = new ConcurrentSkipListSet<>(); + runningTasks = Collections.newSetFromMap(new ConcurrentHashMap<>()); + maxThreads = Math.max(0, Setting.MAX_SAVE_THREADS.getInt()); + + singleton = this; + } + + public static SaveThreadMaster getInstance() { + if (singleton == null) { + return new SaveThreadMaster(); + } + return singleton; + } + + private SaveTask makeRunnable() { + return new SaveTask(); + } + + + synchronized void enqueue(JsonConfiguration jsonConfig) { + SaveOperation op = new SaveOperation(jsonConfig); + saveQueue.remove(op); // removes ops with a similar file + saveQueue.add(op); + + if (maxThreads == 0) { + makeRunnable().run(); + } else if (runningTasks.size() < maxThreads) { + makeRunnable().runTaskAsynchronously(TradeShop.getPlugin()); + } + } + + private synchronized SaveOperation pollNext() { + return saveQueue.pollFirst(); + } + + public void saveEverythingNow() { + if (saveQueue.isEmpty()) return; + for (int i = runningTasks.size(); i < maxThreads; ++i) { + makeRunnable().runTaskAsynchronously(TradeShop.getPlugin()); + } + } + } + + static class SaveTask extends BukkitRunnable { + private final SaveThreadMaster master; + + SaveTask() { + master = SaveThreadMaster.getInstance(); + } + + @Override + public void run() { + master.runningTasks.add(this); + SaveOperation op; + + while ((op = master.pollNext()) != null) { + File file = op.jsonConfig.getFile(); + synchronized (file) { + if (op.jsonConfig.keySet().isEmpty()) { + file.delete(); + continue; + } + + op.jsonConfig.saveFile(); + } + } + + // task dies now: + master.runningTasks.remove(this); + } + + @Override + public int hashCode() { + return master.maxThreads == 0 ? 0 : super.getTaskId(); + } + } +} diff --git a/src/main/java/org/shanerx/tradeshop/data/storage/LinkageConfiguration.java b/src/main/java/org/shanerx/tradeshop/data/storage/LinkageConfiguration.java index 376d5bc2..7a44fef4 100644 --- a/src/main/java/org/shanerx/tradeshop/data/storage/LinkageConfiguration.java +++ b/src/main/java/org/shanerx/tradeshop/data/storage/LinkageConfiguration.java @@ -38,11 +38,11 @@ public interface LinkageConfiguration { void load(); - Map getLinkageData(); + Map getLinkageData(); default ShopLocation getLinkedShop(ShopLocation chestLocation) { - String loc = chestLocation.serialize(); - return getLinkageData().containsKey(loc) ? ShopLocation.deserialize(getLinkageData().get(chestLocation.serialize())) : null; + String loc = chestLocation.toString(); + return getLinkageData().containsKey(loc) ? ShopLocation.deserialize(getLinkageData().get(chestLocation.toString()).toString()) : null; } default int size() { @@ -50,10 +50,10 @@ default int size() { } default void addLinkage(ShopLocation chestLocation, ShopLocation shopLocation) { - if (getLinkageData().containsKey(chestLocation.serialize())) - getLinkageData().replace(chestLocation.serialize(), shopLocation.serialize()); + if (getLinkageData().containsKey(chestLocation.toString())) + getLinkageData().replace(chestLocation.toString(), shopLocation.toString()); else - getLinkageData().put(chestLocation.serialize(), shopLocation.serialize()); + getLinkageData().put(chestLocation.toString(), shopLocation.toString()); } default void add(ShopLocation chestLocation, ShopLocation shopLocation) { @@ -73,7 +73,7 @@ default void removeChest(ShopLocation chestLocation) { default void removeShop(ShopLocation shopLocation) { List removeChests = new ArrayList<>(); - String shopLoc = shopLocation.serialize(); + String shopLoc = shopLocation.toString(); getLinkageData().forEach((key, value) -> { if (value.equals(shopLoc)) diff --git a/src/main/java/org/shanerx/tradeshop/item/IllegalItemList.java b/src/main/java/org/shanerx/tradeshop/item/IllegalItemList.java index 8623baa4..43fdcc0a 100644 --- a/src/main/java/org/shanerx/tradeshop/item/IllegalItemList.java +++ b/src/main/java/org/shanerx/tradeshop/item/IllegalItemList.java @@ -27,14 +27,13 @@ import org.bukkit.Material; import org.shanerx.tradeshop.TradeShop; -import org.shanerx.tradeshop.utils.Utils; import org.shanerx.tradeshop.utils.debug.DebugLevels; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -public class IllegalItemList extends Utils { +public class IllegalItemList { private ListType type; private ArrayList list; diff --git a/src/main/java/org/shanerx/tradeshop/item/ShopItemStack.java b/src/main/java/org/shanerx/tradeshop/item/ShopItemStack.java index 9ed2c73b..a80a6941 100644 --- a/src/main/java/org/shanerx/tradeshop/item/ShopItemStack.java +++ b/src/main/java/org/shanerx/tradeshop/item/ShopItemStack.java @@ -25,9 +25,11 @@ package org.shanerx.tradeshop.item; +import com.bergerkiller.bukkit.common.config.JsonSerializer; import com.google.common.collect.Lists; import com.google.gson.annotations.Expose; import com.google.gson.annotations.SerializedName; +import de.leonhard.storage.sections.FlatFileSection; import net.md_5.bungee.api.ChatColor; import org.apache.commons.lang.WordUtils; import org.bukkit.FireworkEffect; @@ -47,20 +49,21 @@ import org.shanerx.tradeshop.utils.debug.DebugLevels; import org.shanerx.tradeshop.utils.gsonprocessing.GsonProcessor; import org.shanerx.tradeshop.utils.objects.ObjectHolder; +import org.shanerx.tradeshop.utils.simplix.serializers.ConfSerSerializer; import org.yaml.snakeyaml.external.biz.base64Coder.Base64Coder; import java.io.ByteArrayInputStream; import java.io.IOException; -import java.io.Serializable; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import java.util.Objects; -public class ShopItemStack implements Serializable, Cloneable { +public class ShopItemStack implements Cloneable { - @Expose + @Expose(serialize = false) private ItemStack itemStack; + private String itemStackString; private transient Debug debugger; @Expose(serialize = false) @@ -70,20 +73,53 @@ public class ShopItemStack implements Serializable, Cloneable { @SerializedName(value = "itemSettings", alternate = "shopSettings") private Map> itemSettings; + /** + * Create a ShopItemStack with a Base64 encoded {@link ItemStack} and default item Settings. + * + * @param itemStack Bukkit ItemStack object to be used + * @deprecated Constructors for ShopItemStack are being depreciated in favor of {@link ShopItemStackBuilder} + */ + @Deprecated public ShopItemStack(ItemStack itemStack) { this(itemStack, new HashMap<>()); } - public ShopItemStack(ItemStack itemStack, HashMap> itemSettings) { + /** + * Create a ShopItemStack with an {@link ItemStack} and Map containing item Settings. + * @deprecated + * Constructors for ShopItemStack are being depreciated in favor of {@link ShopItemStackBuilder} + * + * @param itemStack Bukkit ItemStack object to be used + * @param itemSettings Map of ShopItemStackSettingKeys and ObjectHolders + */ + @Deprecated + public ShopItemStack(ItemStack itemStack, Map> itemSettings) { this.itemStack = itemStack; this.itemSettings = itemSettings; buildMap(); } + /** + * Create a ShopItemStack with a Base64 encoded {@link ItemStack} and default item Settings. + * @deprecated + * Constructors for ShopItemStack are being depreciated in favor of {@link ShopItemStackBuilder} + * + * @param itemStackB64 Base64 encoded ItemStack + */ + @Deprecated public ShopItemStack(String itemStackB64) { this(itemStackB64, new HashMap<>()); } + /** + * Create a ShopItemStack with a Base64 encoded {@link ItemStack} and Map containing item Settings. + * @deprecated + * Constructors for ShopItemStack are being depreciated in favor of {@link ShopItemStackBuilder} + * + * @param itemStackB64 Base64 encoded ItemStack + * @param itemSettings Map of ShopItemStackSettingKeys and ObjectHolders + */ + @Deprecated public ShopItemStack(String itemStackB64, HashMap> itemSettings) { this.itemStackB64 = itemStackB64; this.itemSettings = new HashMap<>(); @@ -91,10 +127,33 @@ public ShopItemStack(String itemStackB64, HashMap> itemS itemSettings.forEach((key, value) -> this.itemSettings.put(ShopItemStackSettingKeys.match(key), value)); buildMap(); - loadLegacyData(); + try { + fixLoadedData(); + } catch (JsonSerializer.JsonSyntaxException e) { + itemStack = null; + itemSettings = null; + } } - //Re-added for backwards compatibility + /** + * Re-added for backwards compatibility + * Create a ShopItemStack with a Base64 encoded {@link ItemStack} and argument for each setting. + * @deprecated + * Constructors for ShopItemStack are being depreciated in favor of {@link ShopItemStackBuilder} + * + * @param itemStackB64 Base64 encoded ItemStack + * @param compareDurability Compare Durability + * @param compareEnchantments Compare Enchantments + * @param compareName Compare Name + * @param compareLore Compare Lore + * @param compareCustomModelData Compare Custom Model Data + * @param compareItemFlags Compare Item Flags + * @param compareUnbreakable Compare Unbreakable + * @param compareAttributeModifier Compare Attribute Modifier + * @param compareBookAuthor Compare Book Author + * @param compareBookPages Compare Book Pages + * @param compareShulkerInventory Compare Shulker Inventory + */ @Deprecated public ShopItemStack(String itemStackB64, int compareDurability, boolean compareEnchantments, boolean compareName, boolean compareLore, boolean compareCustomModelData, @@ -117,18 +176,49 @@ public ShopItemStack(String itemStackB64, int compareDurability, boolean compare itemSettings.putIfAbsent(ShopItemStackSettingKeys.COMPARE_ENCHANTMENTS, new ObjectHolder<>(compareEnchantments)); buildMap(); - loadLegacyData(); + try { + fixLoadedData(); + } catch (JsonSerializer.JsonSyntaxException e) { + itemStack = null; + itemSettings = null; + } } - public static ShopItemStack deserialize(String serialized) { - ShopItemStack item = new GsonProcessor().fromJson(serialized, ShopItemStack.class); - item.loadLegacyData(); - item.buildMap(); - return item; + public static ShopItemStack deserialize(FlatFileSection serialized) { + ShopItemStackBuilder item = new ShopItemStackBuilder(); + + Map> settings = new HashMap<>(); + + for (String key : serialized.keySet()) { + switch (key) { + case "itemStackString": + item.setItemStack(ConfSerSerializer.deserializeItemStack(serialized.getMapParameterized(key))); + break; + case "itemSettings": + case "shopSettings": + Map> temp = serialized.getMapParameterized(key); + temp.forEach((k, v) -> settings.put(ShopItemStackSettingKeys.valueOf(k), ObjectHolder.deserialize(v))); + item.setItemSettings(settings); + break; + case "itemStackB64": + item.setItemStackB64(serialized.getString(key)); + break; + } + } + + return item.build(); } - public String serialize() { - return new GsonProcessor().toJson(this); + public Map serialize() { + HashMap map = new HashMap<>(); + Map settings = new HashMap<>(); + itemSettings.forEach((key, value) -> settings.put(key.getConfigName(), value.serialize())); + + map.put("itemStackString", ConfSerSerializer.serialize(itemStack)); + map.put("itemSettings", settings); + if (itemStackB64 != null && !itemStackB64.isEmpty()) map.put("itemStackB64", itemStackB64); + + return map; } public ObjectHolder getShopSetting(ShopItemStackSettingKeys key) { @@ -470,7 +560,12 @@ public boolean isSimilar(ItemStack toCompare) { public ItemStack getItemStack() { if (itemStack == null) - loadLegacyData(); + try { + fixLoadedData(); + } catch (JsonSerializer.JsonSyntaxException e) { + itemStack = null; + itemSettings = null; + } return itemStack; } @@ -521,14 +616,94 @@ public String getStateString(ObjectHolder stateSetting) { @Override public String toString() { - return new GsonProcessor().toJson(this); + return serialize().toString(); } /** * Sets the objects {@link ItemStack} from its Base64. */ - private void loadLegacyData() { - if (itemStack == null && hasBase64()) { + private void fixLoadedData() throws JsonSerializer.JsonSyntaxException { + if (itemStack == null) { + if (hasBase64()) { + try { + ByteArrayInputStream inputStream = new ByteArrayInputStream(Base64Coder.decodeLines(itemStackB64)); + BukkitObjectInputStream dataInput = new BukkitObjectInputStream(inputStream); + + // Read the serialized inventory + itemStack = new ItemStack((ItemStack) dataInput.readObject()); + + dataInput.close(); + } catch (ClassNotFoundException | IOException e) { + itemStack = null; + } + } else if (itemStackString != null && !itemStackString.isEmpty()) { + itemStack = GsonProcessor.fromJsonToItemStack(itemStackString); + } + } + + } + + public String toConsoleText() { + return serialize().toString(); + } +} + +class ShopItemStackBuilder { + private ItemStack itemStack = null; + private Map> itemSettings = null; + private String itemStackB64 = "", itemStackString = ""; + + ShopItemStackBuilder() { + } + + ShopItemStackBuilder(ItemStack itm) { + itemStack = itm; + } + + ShopItemStackBuilder(String json) { + itemStackString = json; + } + + ShopItemStackBuilder setItemStack(ItemStack itemStack) { + this.itemStack = itemStack; + return this; + } + + ShopItemStackBuilder setItemSettings(Map> itemSettings) { + this.itemSettings = itemSettings; + return this; + } + + ShopItemStackBuilder setItemStackB64(String itemStackB64) { + this.itemStackB64 = itemStackB64; + return this; + } + + ShopItemStackBuilder setItemStackString(String itemStackString) { + this.itemStackString = itemStackString; + return this; + } + + ShopItemStack build() { + processLoadedData(); + + return itemStack == null ? null : new ShopItemStack(itemStack, itemSettings); + } + + /** + * Verifies that the objects {@link ItemStack} is appropriately set. + */ + private void processLoadedData() { + processB64(); + processJSON(); + + if (itemSettings == null) { + itemSettings = ShopItemStackSettingKeys.getDefaultSettings(); + } + } + + private void processB64() { + if (itemStack == null && !itemStackB64.isEmpty()) { try { ByteArrayInputStream inputStream = new ByteArrayInputStream(Base64Coder.decodeLines(itemStackB64)); BukkitObjectInputStream dataInput = new BukkitObjectInputStream(inputStream); @@ -543,7 +718,13 @@ private void loadLegacyData() { } } - public String toConsoleText() { - return new GsonProcessor().toJson(this); + private void processJSON() { + if (itemStack == null && itemStackString != null && !itemStackString.isEmpty()) { + try { + itemStack = GsonProcessor.fromJsonToItemStack(itemStackString); + } catch (JsonSerializer.JsonSyntaxException e) { + itemStack = null; + } + } } } \ No newline at end of file diff --git a/src/main/java/org/shanerx/tradeshop/item/ShopItemStackSettingKeys.java b/src/main/java/org/shanerx/tradeshop/item/ShopItemStackSettingKeys.java index a3cdfcd3..cac12dc0 100644 --- a/src/main/java/org/shanerx/tradeshop/item/ShopItemStackSettingKeys.java +++ b/src/main/java/org/shanerx/tradeshop/item/ShopItemStackSettingKeys.java @@ -31,8 +31,10 @@ import org.shanerx.tradeshop.data.config.Setting; import org.shanerx.tradeshop.utils.objects.ObjectHolder; +import java.lang.reflect.Type; import java.util.HashMap; import java.util.Map; +import java.util.stream.Stream; public enum ShopItemStackSettingKeys { @@ -65,18 +67,36 @@ public enum ShopItemStackSettingKeys { public static Map getDefaultConfigMap() { Map configMap = new HashMap<>(); - for (ShopItemStackSettingKeys value : values()) { - String key = value.getConfigName(); - Map subConfigMap = new HashMap<>(); - subConfigMap.put(defaultKey, value.preConfigDefault); - subConfigMap.put(userEditableKey, true); + Stream.of(values()).forEach(key -> configMap.put(key.getKey(String.class), key.getSubConfigMap())); - configMap.put(key, subConfigMap); - } return configMap; } + public static Map> getDefaultSettings() { + Map> defaultMap = new HashMap<>(); + + Stream.of(values()).forEach(key -> defaultMap.put(key.getKey(ShopItemStackSettingKeys.class), key.getDefaultValue())); + + return defaultMap; + } + + private Map getSubConfigMap() { + Map subConfigMap = new HashMap<>(); + subConfigMap.put(defaultKey, preConfigDefault); + subConfigMap.put(userEditableKey, true); + return subConfigMap; + } + + private T getKey(Type T) { + if (T.equals(ShopItemStackSettingKeys.class)) { + return (T) this; + } else if (T.equals(String.class)) { + return (T) getConfigName(); + } + return null; + } + public String makeReadable() { return WordUtils.capitalizeFully(name().replace("_", " ")); diff --git a/src/main/java/org/shanerx/tradeshop/player/JoinEventListener.java b/src/main/java/org/shanerx/tradeshop/player/JoinEventListener.java index b8f967c2..5d384df6 100644 --- a/src/main/java/org/shanerx/tradeshop/player/JoinEventListener.java +++ b/src/main/java/org/shanerx/tradeshop/player/JoinEventListener.java @@ -32,11 +32,10 @@ import org.bukkit.event.player.PlayerJoinEvent; import org.shanerx.tradeshop.TradeShop; import org.shanerx.tradeshop.data.config.Message; -import org.shanerx.tradeshop.utils.Utils; import org.shanerx.tradeshop.utils.versionmanagement.Updater; import org.shanerx.tradeshop.utils.versionmanagement.Version; -public class JoinEventListener extends Utils implements Listener { +public class JoinEventListener implements Listener { private final TradeShop plugin; diff --git a/src/main/java/org/shanerx/tradeshop/player/Permissions.java b/src/main/java/org/shanerx/tradeshop/player/Permissions.java index 3dd63867..211f5a02 100644 --- a/src/main/java/org/shanerx/tradeshop/player/Permissions.java +++ b/src/main/java/org/shanerx/tradeshop/player/Permissions.java @@ -60,7 +60,7 @@ public enum Permissions { NONE("", PermissionDefault.TRUE); private final static TradeShop plugin = (TradeShop) Bukkit.getPluginManager().getPlugin("TradeShop"); - private final Utils utils = new Utils(); + private final transient Utils utils = new Utils(); private final String key; private final PermissionDefault defaultState; private final String description; diff --git a/src/main/java/org/shanerx/tradeshop/player/PlayerSetting.java b/src/main/java/org/shanerx/tradeshop/player/PlayerSetting.java index 0fb1b334..9557e197 100644 --- a/src/main/java/org/shanerx/tradeshop/player/PlayerSetting.java +++ b/src/main/java/org/shanerx/tradeshop/player/PlayerSetting.java @@ -30,6 +30,8 @@ import de.themoep.inventorygui.GuiPageElement; import de.themoep.inventorygui.InventoryGui; import de.themoep.inventorygui.StaticGuiElement; +import lombok.Getter; +import lombok.Setter; import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.inventory.ItemStack; @@ -39,22 +41,29 @@ import org.shanerx.tradeshop.shoplocation.IllegalWorldException; import org.shanerx.tradeshop.shoplocation.ShopLocation; import org.shanerx.tradeshop.utils.Utils; -import org.shanerx.tradeshop.utils.gsonprocessing.GsonProcessor; -import java.io.Serializable; +import java.util.HashMap; import java.util.HashSet; +import java.util.List; import java.util.Map; import java.util.Set; import java.util.UUID; -public class PlayerSetting implements Serializable { +public class PlayerSetting { - private transient UUID uuid; - private final String uuidString; + @Getter private final Set ownedShops; + private final String uuidString; + @Getter private final Set staffShops; + @Getter + private transient UUID uuid; + @Getter + @Setter private boolean showInvolvedStatus, adminEnabled = true; + @Setter + @Getter private int multi = Setting.MULTI_TRADE_DEFAULT.getInt(); private transient Utils utils = new Utils(); @@ -81,44 +90,60 @@ public PlayerSetting(UUID playerUUID) { load(); } - public static PlayerSetting deserialize(String serialized) { - PlayerSetting playerSetting = new GsonProcessor().fromJson(serialized, PlayerSetting.class); - playerSetting.load(); - return playerSetting; - } - - public boolean isAdminEnabled() { - return adminEnabled; - } + public static PlayerSetting deserialize(Map serialized) { + if (!serialized.containsKey("uuidString")) return null; //TODO: Add error message (Player UUID is null) + + UUID plUUID = UUID.fromString(serialized.get("uuidString").toString()); + PlayerSetting playerSetting = new PlayerSetting(plUUID); + + for (Map.Entry entry : serialized.entrySet()) { + switch (entry.getKey()) { + case "ownedShops": + playerSetting.ownedShops.addAll((List) entry.getValue()); + break; + case "staffShops": + playerSetting.staffShops.addAll((List) entry.getValue()); + break; + case "showInvolvedStatus": + playerSetting.showInvolvedStatus = (boolean) entry.getValue(); + break; + case "adminEnabled": + playerSetting.adminEnabled = (boolean) entry.getValue(); + break; + case "multi": + playerSetting.multi = (int) entry.getValue(); + break; + } + } - public void setAdminEnabled(boolean adminEnabled) { - this.adminEnabled = adminEnabled; - } - public int getMulti() { - return multi; + return playerSetting; } - public void setMulti(int multi) { - this.multi = multi; - } + public Map serialize() { + HashMap data = new HashMap<>(); + data.put("uuidString", uuidString); + data.put("ownedShops", ownedShops); + data.put("staffShops", staffShops); + data.put("showInvolvedStatus", showInvolvedStatus); + data.put("adminEnabled", adminEnabled); + data.put("multi", multi); - public Set getOwnedShops() { - return ownedShops; + return data; } public void addShop(Shop shop) { if (shop.getOwner().getUUID().equals(uuid) && - !ownedShops.contains(shop.getShopLocationAsSL().serialize())) - ownedShops.add(shop.getShopLocationAsSL().serialize()); + !ownedShops.contains(shop.getShopLocationAsSL().toString())) + ownedShops.add(shop.getShopLocationAsSL().toString()); else if (shop.getUsersUUID(ShopRole.MANAGER, ShopRole.MEMBER).contains(uuid) && - !ownedShops.contains(shop.getShopLocationAsSL().serialize())) - staffShops.add(shop.getShopLocationAsSL().serialize()); + !ownedShops.contains(shop.getShopLocationAsSL().toString())) + staffShops.add(shop.getShopLocationAsSL().toString()); } public void removeShop(Shop shop) { - ownedShops.remove(shop.getShopLocationAsSL().serialize()); - staffShops.remove(shop.getShopLocationAsSL().serialize()); + ownedShops.remove(shop.getShopLocationAsSL().toString()); + staffShops.remove(shop.getShopLocationAsSL().toString()); } public void removeShop(String shop) { @@ -134,30 +159,18 @@ public void updateShop(Shop shop) { } - public UUID getUuid() { - return uuid; - } - - public Set getStaffShops() { - return staffShops; - } - public void load() { if (uuid == null) uuid = UUID.fromString(uuidString); if (multi > Setting.MULTI_TRADE_MAX.getInt()) multi = Setting.MULTI_TRADE_MAX.getInt(); utils = new Utils(); } - public String serialize() { - return new GsonProcessor().toJson(this); - } - public String getInvolvedStatusesString() { Set nullShops = new HashSet<>(); StringBuilder sb = new StringBuilder(); sb.append("&eStatus of your shops: \n"); sb.append("&eShop Role &f| &eType &f| &eAvailable Trades &f| &eLocation &f| &eInventory Status\n&b"); - if (getOwnedShops().size() > 0) { + if (!getOwnedShops().isEmpty()) { getOwnedShops().forEach(s -> { try { Shop shop = TradeShop.getPlugin().getDataStorage().loadShopFromSign(ShopLocation.deserialize(s)); @@ -175,7 +188,7 @@ public String getInvolvedStatusesString() { } }); } - if (getStaffShops().size() > 0) { + if (!getStaffShops().isEmpty()) { getStaffShops().forEach(s -> { try { Shop shop = TradeShop.getPlugin().getDataStorage().loadShopFromSign(ShopLocation.deserialize(s)); @@ -204,7 +217,7 @@ public InventoryGui getInvolvedStatusesInventory() { Set nullShops = new HashSet<>(); InventoryGui gui = new InventoryGui(TradeShop.getPlugin(), Bukkit.getOfflinePlayer(uuid).getName() + "'s Shops", new String[]{"ggggggggg", "ggggggggg", " fp ln "}); GuiElementGroup group = new GuiElementGroup('g'); - if (getOwnedShops().size() > 0) { + if (!getOwnedShops().isEmpty()) { getOwnedShops().forEach(s -> { try { Shop shop = TradeShop.getPlugin().getDataStorage().loadShopFromSign(ShopLocation.deserialize(s)); @@ -230,7 +243,7 @@ public InventoryGui getInvolvedStatusesInventory() { } }); } - if (getStaffShops().size() > 0) { + if (!getStaffShops().isEmpty()) { getStaffShops().forEach(s -> { try { Shop shop = TradeShop.getPlugin().getDataStorage().loadShopFromSign(ShopLocation.deserialize(s)); @@ -283,7 +296,4 @@ public boolean showInvolvedStatus() { return showInvolvedStatus; } - public void setShowInvolvedStatus(boolean showInvolvedStatus) { - this.showInvolvedStatus = showInvolvedStatus; - } } diff --git a/src/main/java/org/shanerx/tradeshop/player/ShopUser.java b/src/main/java/org/shanerx/tradeshop/player/ShopUser.java index b71d6185..71d3be3f 100644 --- a/src/main/java/org/shanerx/tradeshop/player/ShopUser.java +++ b/src/main/java/org/shanerx/tradeshop/player/ShopUser.java @@ -26,7 +26,14 @@ package org.shanerx.tradeshop.player; import com.google.gson.annotations.SerializedName; -import org.bukkit.*; +import lombok.Getter; +import lombok.Setter; +import org.bukkit.Bukkit; +import org.bukkit.ChunkSnapshot; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.OfflinePlayer; +import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.block.Sign; import org.bukkit.entity.Player; @@ -40,18 +47,24 @@ import org.shanerx.tradeshop.shop.ShopChest; import org.shanerx.tradeshop.shop.ShopType; import org.shanerx.tradeshop.shoplocation.ShopLocation; -import org.shanerx.tradeshop.utils.gsonprocessing.GsonProcessor; -import java.io.Serializable; -import java.util.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; import java.util.stream.Collectors; @SuppressWarnings("unused") -public class ShopUser implements Serializable { +public class ShopUser { @SerializedName("player") private final String playerUUID; private transient OfflinePlayer player; + @Getter + @Setter private ShopRole role; public ShopUser(OfflinePlayer player, ShopRole role) { @@ -64,10 +77,17 @@ public ShopUser(UUID pUUID, ShopRole role) { this.role = role; } - public static ShopUser deserialize(String serialized) { - ShopUser shopUser = new GsonProcessor().fromJson(serialized, ShopUser.class); - shopUser.player = Bukkit.getOfflinePlayer(UUID.fromString(shopUser.playerUUID)); - return shopUser; + public static ShopUser deserialize(Map serialized) { + return new ShopUser(UUID.fromString((String) serialized.get("player")), ShopRole.valueOf((String) serialized.get("role"))); + } + + public Map serialize() { + Map map = new HashMap<>(); + + map.put("player", playerUUID); + map.put("role", role.name()); + + return map; } /** @@ -177,14 +197,6 @@ public UUID getUUID() { return getPlayer().getUniqueId(); } - public ShopRole getRole() { - return role; - } - - public void setRole(ShopRole newRole) { - role = newRole; - } - public String getName() { return getPlayer().getName(); } @@ -195,10 +207,6 @@ private void fix() { } } - public String serialize() { - return new GsonProcessor().toJson(this); - } - public ItemStack getHead() { ItemStack userHead = new ItemStack(Material.PLAYER_HEAD); SkullMeta userMeta = (SkullMeta) userHead.getItemMeta(); diff --git a/src/main/java/org/shanerx/tradeshop/shop/Shop.java b/src/main/java/org/shanerx/tradeshop/shop/Shop.java index 89982c75..de3ee023 100644 --- a/src/main/java/org/shanerx/tradeshop/shop/Shop.java +++ b/src/main/java/org/shanerx/tradeshop/shop/Shop.java @@ -25,6 +25,8 @@ package org.shanerx.tradeshop.shop; +import de.leonhard.storage.sections.FlatFileSection; +import lombok.Getter; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Location; @@ -46,11 +48,9 @@ import org.shanerx.tradeshop.shoplocation.ShopLocation; import org.shanerx.tradeshop.utils.Utils; import org.shanerx.tradeshop.utils.debug.DebugLevels; -import org.shanerx.tradeshop.utils.gsonprocessing.GsonProcessor; import org.shanerx.tradeshop.utils.objects.ObjectHolder; import org.shanerx.tradeshop.utils.objects.Tuple; -import java.io.Serializable; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -62,18 +62,32 @@ import java.util.UUID; import java.util.stream.Collectors; -public class Shop implements Serializable { +public class Shop { private final ShopLocation shopLoc; private transient TradeShop plugin = TradeShop.getPlugin(); private ShopUser owner; private Set managers, members; + /** + * -- GETTER -- + * Returns the type of the shop + * + * @return list of managers as ShopUser + */ + @Getter private ShopType shopType; private List product, cost; private ShopLocation chestLoc; private transient Utils utils = new Utils(); private ShopStatus status = ShopStatus.INCOMPLETE; private Map> shopSettings; + /** + * -- GETTER -- + * Returns the amount of trades the shop could do when last accessed + * + * @return amount of trades the shop can do + */ + @Getter private int availableTrades = 0; private transient boolean aSync = false; @@ -145,19 +159,6 @@ public Shop(Location location, ShopType shopType, ShopUser owner) { this(new Tuple<>(location, null), shopType, owner, new Tuple<>(null, null), new Tuple<>(null, null)); } - /** - * Deserializes the object to Json using Gson - * - * @param serialized Shop GSON to be deserialized - * @return Shop object from file - */ - public static Shop deserialize(String serialized) { - Shop shop = new GsonProcessor().fromJson(serialized, Shop.class); - shop.fixAfterLoad(); - - return shop; - } - /** * Loads a shop from file and returns the Shop object * @@ -216,15 +217,6 @@ public Location getShopLocation() { return getShopLocationAsSL().getLocation(); } - /** - * Returns the type of the shop - * - * @return list of managers as ShopUser - */ - public ShopType getShopType() { - return shopType; - } - /** * Sets the shops type * @@ -238,12 +230,60 @@ public void setShopType(ShopType newType) { } /** - * Returns the amount of trades the shop could do when last accessed + * Deserializes the object to Json using Gson * - * @return amount of trades the shop can do + * @param data Shop Map to be deserialized from file data + * @return Shop object from file */ - public int getAvailableTrades() { - return availableTrades; + public static Shop deserialize(FlatFileSection data) { + Shop shop = new Shop(ShopLocation.deserialize(data.getMapParameterized("shopLoc")).getLocation(), + ShopType.valueOf(data.getString("shopType")), + ShopUser.deserialize(data.getMapParameterized("owner"))); + + StringBuilder dataRemaining = new StringBuilder(); + + for (String key : data.keySet()) { + switch (key) { + case "shopLoc": + case "shopType": + case "owner": + break; // Already used so skip + case "managers": + shop.managers = new HashSet<>(data.getSerializableList(key, UUID.class)); + break; + case "members": + shop.members = new HashSet<>(data.getSerializableList(key, UUID.class)); + break; + case "product": + data.keySet(key).forEach((itmKey) -> shop.addSideItem(ShopItemSide.PRODUCT, ShopItemStack.deserialize(data.getSection(itmKey)))); + break; + case "cost": + data.keySet(key).forEach((itmKey) -> shop.addSideItem(ShopItemSide.COST, ShopItemStack.deserialize(data.getSection(itmKey)))); + break; + case "chestLoc": + shop.chestLoc = ShopLocation.deserialize(data.get(key).toString()); + break; + case "status": + shop.status = ShopStatus.valueOf(data.get(key).toString()); + break; + case "shopSettings": + shop.shopSettings = data.getMapParameterized(key); + data.remove(key); + break; + case "availableTrades": + shop.availableTrades = (int) data.get(key); + break; + default: + dataRemaining.append(key).append(": ").append(data.get(key)).append("\n"); + break; + } + } + + if (dataRemaining.length() > 0) { + TradeShop.getPlugin().getVarManager().getDebugger().log("Shop (" + shop.shopLoc + ") deserialized completed with data remaining: \n" + dataRemaining, DebugLevels.DATA_ERROR); + } + + return shop; } /** @@ -251,8 +291,28 @@ public int getAvailableTrades() { * * @return serialized string */ - public String serialize() { - return new GsonProcessor().toJson(this); + public Map serialize() { + Map map = new HashMap<>(); + Map> settings = new HashMap<>(); + ArrayList> products = new ArrayList<>(), costs = new ArrayList<>(); + + product.forEach(item -> products.add(item.serialize())); + cost.forEach(item -> costs.add(item.serialize())); + shopSettings.forEach((key, value) -> settings.put(key.getConfigKey(), value)); + + map.put("shopLoc", shopLoc.serialize()); + map.put("owner", owner.serialize()); + map.put("managers", managers); + map.put("members", members); + map.put("shopType", shopType.name()); + map.put("product", products); + map.put("cost", costs); + map.put("chestLoc", chestLoc.serialize()); + map.put("status", status.toString()); + map.put("shopSettings", settings); + map.put("availableTrades", availableTrades); + + return map; } /** @@ -277,13 +337,12 @@ public ShopLocation getInventoryLocationAsSL() { * Fixes values and objects after loading or creating a Shop */ public void fixAfterLoad() { - aSyncFix(); aSync = false; shopLoc.stringToWorld(); if (!getShopType().isITrade()) { - if (chestLoc == null) { + if (chestLoc == null && getShopLocation() != null) { chestLoc = new ShopLocation(new Utils().findShopChest(getShopLocation().getBlock()).getLocation()); } chestLoc.stringToWorld(); @@ -292,6 +351,8 @@ public void fixAfterLoad() { plugin.getDataStorage().addChestLinkage(chestLoc, shopLoc); } + aFixup(); + if (getShopSign() != null) updateSign(); } @@ -301,6 +362,10 @@ public void fixAfterLoad() { */ public void aSyncFix() { aSync = true; + aFixup(); + } + + private void aFixup() { if (utils == null) utils = new Utils(); if (plugin == null) plugin = TradeShop.getPlugin(); @@ -319,10 +384,10 @@ public String toDebug() { StringBuilder sb = new StringBuilder(); sb.append("Shop Debug: \n"); sb.append("Shop Chunk: ").append(new ShopChunk(shopLoc.getChunk()).serialize()).append("\n"); - sb.append("Sign Location: ").append(shopLoc.serialize()).append("\n"); + sb.append("Sign Location: ").append(shopLoc).append("\n"); sb.append("Shop Type: ").append((isMissingItems() ? Setting.SHOP_INCOMPLETE_COLOUR : Setting.SHOP_GOOD_COLOUR).getString()).append(shopType.toHeader()).append("\n"); sb.append("Shop Status: ").append(status.getLine()).append("\n"); - sb.append("Storage Location: ").append(hasStorage() ? getInventoryLocationAsSL().serialize() : "N/A").append("\n"); + sb.append("Storage Location: ").append(hasStorage() ? getInventoryLocationAsSL().toString() : "N/A").append("\n"); sb.append("Storage Type: ").append(hasStorage() ? getStorage().getType().toString() : "N/A").append("\n"); sb.append("Owner: ").append(owner.getName()).append(" | ").append(owner.getUUID()).append("\n"); sb.append("Managers: ").append(managers.isEmpty() ? "N/A" : managers.size()).append("\n"); @@ -1145,15 +1210,16 @@ public boolean isSideValid(ShopItemSide side) { * * @param side Side to be updated * @param updatedItemList list to set updatedItemList to + * @param save2disk whether or not to save to disk */ - public void updateSide(ShopItemSide side, List updatedItemList) { + public void updateSide(ShopItemSide side, List updatedItemList, boolean save2disk) { if (!getShopType().isITrade() && chestLoc != null) updatedItemList.removeIf(item -> item.getItemStack().getType().toString().endsWith("SHULKER_BOX") && getInventoryLocation().getBlock().getType().toString().endsWith("SHULKER_BOX")); if (side.equals(ShopItemSide.PRODUCT)) product = updatedItemList; else cost = updatedItemList; - saveShop(); + if (save2disk) saveShop(); updateSign(); } @@ -1164,7 +1230,7 @@ public void updateSide(ShopItemSide side, List updatedItemList) { * @param updatedItem Item to be updated at the specified index and side * @param index index of the item t be updated */ - public void updateSideItem(ShopItemSide side, ShopItemStack updatedItem, int index) { + public void updateSideItem(ShopItemSide side, ShopItemStack updatedItem, int index, boolean save2disk) { if (!getShopType().isITrade() && chestLoc != null && updatedItem.getItemStack().getType().toString().endsWith("SHULKER_BOX") && @@ -1173,7 +1239,7 @@ public void updateSideItem(ShopItemSide side, ShopItemStack updatedItem, int ind (side.equals(ShopItemSide.PRODUCT) ? product : cost).set(index, updatedItem); - saveShop(); + if (save2disk) saveShop(); updateSign(); } diff --git a/src/main/java/org/shanerx/tradeshop/shop/ShopChest.java b/src/main/java/org/shanerx/tradeshop/shop/ShopChest.java index dcc21fe4..7c2d5602 100644 --- a/src/main/java/org/shanerx/tradeshop/shop/ShopChest.java +++ b/src/main/java/org/shanerx/tradeshop/shop/ShopChest.java @@ -44,7 +44,7 @@ import java.util.List; import java.util.UUID; -public class ShopChest extends Utils { +public class ShopChest { private final static TradeShop PLUGIN = TradeShop.getPlugin(); private final Location loc; @@ -160,7 +160,7 @@ public Inventory getInventory() { public boolean hasStock(List itemToCheck) { if (isEmpty()) return false; - return itemToCheck.size() > 0 && getItems(getInventory().getStorageContents(), itemToCheck, 1).get(0) != null; + return itemToCheck.size() > 0 && new Utils().getItems(getInventory().getStorageContents(), itemToCheck, 1).get(0) != null; } public boolean isEmpty() { diff --git a/src/main/java/org/shanerx/tradeshop/shop/ShopSign.java b/src/main/java/org/shanerx/tradeshop/shop/ShopSign.java index 586a1041..e6347da2 100644 --- a/src/main/java/org/shanerx/tradeshop/shop/ShopSign.java +++ b/src/main/java/org/shanerx/tradeshop/shop/ShopSign.java @@ -27,7 +27,6 @@ import org.bukkit.Material; import org.shanerx.tradeshop.TradeShop; -import org.shanerx.tradeshop.utils.Utils; import org.shanerx.tradeshop.utils.debug.DebugLevels; import org.shanerx.tradeshop.utils.versionmanagement.Version; @@ -113,7 +112,7 @@ public String getDefaultColour() { } } -public class ShopSign extends Utils { +public class ShopSign { private final Version version = TradeShop.getPlugin().getVersion(); private final ArrayList signTypes = new ArrayList<>(); diff --git a/src/main/java/org/shanerx/tradeshop/shop/ShopStorage.java b/src/main/java/org/shanerx/tradeshop/shop/ShopStorage.java index 83673df4..19079bec 100644 --- a/src/main/java/org/shanerx/tradeshop/shop/ShopStorage.java +++ b/src/main/java/org/shanerx/tradeshop/shop/ShopStorage.java @@ -28,7 +28,6 @@ import com.google.common.collect.Lists; import org.bukkit.Material; import org.shanerx.tradeshop.TradeShop; -import org.shanerx.tradeshop.utils.Utils; import org.shanerx.tradeshop.utils.debug.DebugLevels; import org.shanerx.tradeshop.utils.versionmanagement.Version; @@ -37,7 +36,7 @@ import java.util.HashMap; import java.util.List; -public class ShopStorage extends Utils { +public class ShopStorage { private final Version version = TradeShop.getPlugin().getVersion(); private final HashMap storageTypes = new HashMap<>(); diff --git a/src/main/java/org/shanerx/tradeshop/shop/ShopType.java b/src/main/java/org/shanerx/tradeshop/shop/ShopType.java index e7db6da4..247e05cd 100644 --- a/src/main/java/org/shanerx/tradeshop/shop/ShopType.java +++ b/src/main/java/org/shanerx/tradeshop/shop/ShopType.java @@ -25,6 +25,7 @@ package org.shanerx.tradeshop.shop; +import com.bergerkiller.bukkit.common.config.JsonSerializer; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.block.Block; @@ -35,10 +36,8 @@ import org.shanerx.tradeshop.player.Permissions; import org.shanerx.tradeshop.utils.gsonprocessing.GsonProcessor; -import java.io.Serializable; - -public enum ShopType implements Serializable { +public enum ShopType { TRADE(Permissions.CREATE), @@ -78,7 +77,12 @@ public static ShopType getType(Sign s) { } public static ShopType deserialize(String serialized) { - return new GsonProcessor().fromJson(serialized, ShopType.class); + try { + return GsonProcessor.fromJson(serialized, ShopType.class); + } catch (JsonSerializer.JsonSyntaxException ex) { + ex.printStackTrace(); + } + return null; } @Override @@ -101,7 +105,7 @@ public boolean checkPerm(Player pl) { } public String serialize() { - return new GsonProcessor().toJson(this); + return GsonProcessor.toJson(this); } public boolean isTrade() { diff --git a/src/main/java/org/shanerx/tradeshop/shop/listeners/ChunkUnloadListener.java b/src/main/java/org/shanerx/tradeshop/shop/listeners/ChunkUnloadListener.java new file mode 100644 index 00000000..aa78b0a7 --- /dev/null +++ b/src/main/java/org/shanerx/tradeshop/shop/listeners/ChunkUnloadListener.java @@ -0,0 +1,22 @@ +package org.shanerx.tradeshop.shop.listeners; + +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.world.ChunkUnloadEvent; +import org.shanerx.tradeshop.TradeShop; +import org.shanerx.tradeshop.shoplocation.ShopChunk; + +public class ChunkUnloadListener implements Listener { + + private TradeShop plugin; + + public ChunkUnloadListener(TradeShop plugin) { + this.plugin = plugin; + } + + @EventHandler + public void onChunkUnload(ChunkUnloadEvent e) { + ShopChunk shopChunk = new ShopChunk(e.getChunk()); + TradeShop.getPlugin().getVarManager().getDataStorage().dropShopData(shopChunk); + } +} diff --git a/src/main/java/org/shanerx/tradeshop/shop/listeners/ShopCreateListener.java b/src/main/java/org/shanerx/tradeshop/shop/listeners/ShopCreateListener.java index 67401cda..8d3a72ce 100644 --- a/src/main/java/org/shanerx/tradeshop/shop/listeners/ShopCreateListener.java +++ b/src/main/java/org/shanerx/tradeshop/shop/listeners/ShopCreateListener.java @@ -43,7 +43,7 @@ import org.shanerx.tradeshop.utils.objects.ObjectHolder; @SuppressWarnings("unused") -public class ShopCreateListener extends Utils implements Listener { +public class ShopCreateListener implements Listener { @EventHandler(priority = EventPriority.HIGHEST, ignoreCancelled = true) public void onSignChange(SignChangeEvent event) { @@ -68,13 +68,13 @@ public void onSignChange(SignChangeEvent event) { // Required as the createShop method needs to make sure the first line is blank for commands to avoid overwriting existing shops shopSign.setLine(0, ""); - Shop shop = createShop(shopSign, p, shopType, lineCheck(ShopItemSide.COST, event.getLine(2)), lineCheck(ShopItemSide.PRODUCT, event.getLine(1)), event); + Shop shop = new Utils().createShop(shopSign, p, shopType, lineCheck(ShopItemSide.COST, event.getLine(2)), lineCheck(ShopItemSide.PRODUCT, event.getLine(1)), event); if (shop != null) { return; } - failedSignReset(event, shopType); + new Utils().failedSignReset(event, shopType); } private ItemStack lineCheck(ShopItemSide side, String line) { diff --git a/src/main/java/org/shanerx/tradeshop/shop/listeners/ShopProtectionListener.java b/src/main/java/org/shanerx/tradeshop/shop/listeners/ShopProtectionListener.java index 903fe6b1..2eaba767 100644 --- a/src/main/java/org/shanerx/tradeshop/shop/listeners/ShopProtectionListener.java +++ b/src/main/java/org/shanerx/tradeshop/shop/listeners/ShopProtectionListener.java @@ -64,7 +64,7 @@ import java.util.Iterator; import java.util.List; -public class ShopProtectionListener extends Utils implements Listener { +public class ShopProtectionListener implements Listener { private final TradeShop plugin; @@ -118,6 +118,12 @@ public void onInventoryMoveItem(InventoryMoveItemEvent event) { Shop shop = plugin.getDataStorage().loadShopFromStorage(new ShopLocation(invBlock.getLocation())); + if (shop == null) { + plugin.getListManager().addSkippableHopper(event.getInitiator().getLocation(), false); + plugin.getDebugger().log("Protection Shop Null Catch for \n " + event.getInitiator().getLocation(), DebugLevels.PROTECTION); + return; + } + boolean isForbidden = !(fromHopper ? shop.getShopSetting(ShopSettingKeys.HOPPER_IMPORT).asBoolean() : shop.getShopSetting(ShopSettingKeys.HOPPER_EXPORT).asBoolean()); if (isForbidden) { event.setCancelled(true); @@ -126,7 +132,7 @@ public void onInventoryMoveItem(InventoryMoveItemEvent event) { } plugin.getDebugger().log("ShopProtectionListener: Triggered > " + (fromHopper ? "FROM_HOPPER" : "TO_HOPPER"), DebugLevels.PROTECTION); - plugin.getDebugger().log("ShopProtectionListener: Shop Location as SL > " + shop.getInventoryLocationAsSL().serialize(), DebugLevels.PROTECTION); + plugin.getDebugger().log("ShopProtectionListener: Shop Location as SL > " + shop.getInventoryLocationAsSL().toString(), DebugLevels.PROTECTION); plugin.getDebugger().log("ShopProtectionListener: checked hopper setting > " + shop.getShopType().name() + "SHOP_HOPPER_EXPORT", DebugLevels.PROTECTION); HopperShopAccessEvent hopperEvent = new HopperShopAccessEvent( shop, @@ -143,7 +149,7 @@ public void onInventoryMoveItem(InventoryMoveItemEvent event) { //plugin.getListManager().addSkippableShop(event.getInitiator().getLocation(), hopperEvent.isForbidden()); if (!hopperEvent.isForbidden()) { - scheduleShopDelayUpdate("ShopProtectionListener#onInventoryMoveItem", shop, 2L); + new Utils().scheduleShopDelayUpdate("ShopProtectionListener#onInventoryMoveItem", shop, 2L); } } @@ -321,7 +327,7 @@ public void onBlockPlace(BlockPlaceEvent event) { if (!plugin.getListManager().isInventory(block)) return; - Sign shopSign = findShopSign(block); + Sign shopSign = new Utils().findShopSign(block); if (shopSign == null) return; diff --git a/src/main/java/org/shanerx/tradeshop/shop/listeners/ShopRestockListener.java b/src/main/java/org/shanerx/tradeshop/shop/listeners/ShopRestockListener.java index 5a396572..fe41010b 100644 --- a/src/main/java/org/shanerx/tradeshop/shop/listeners/ShopRestockListener.java +++ b/src/main/java/org/shanerx/tradeshop/shop/listeners/ShopRestockListener.java @@ -34,7 +34,7 @@ import org.shanerx.tradeshop.shop.ShopChest; import org.shanerx.tradeshop.utils.Utils; -public class ShopRestockListener extends Utils implements Listener { +public class ShopRestockListener implements Listener { private final TradeShop plugin; @@ -52,7 +52,7 @@ public void onInventoryClose(InventoryCloseEvent event) { if (shop != null) { shop.updateSign(); shop.saveShop(); - scheduleShopDelayUpdate("ShopRestockListener#onInventoryClose", shop, 10L); + new Utils().scheduleShopDelayUpdate("ShopRestockListener#onInventoryClose", shop, 10L); } } } diff --git a/src/main/java/org/shanerx/tradeshop/shop/listeners/ShopTradeListener.java b/src/main/java/org/shanerx/tradeshop/shop/listeners/ShopTradeListener.java index b4ec85ac..3773a020 100644 --- a/src/main/java/org/shanerx/tradeshop/shop/listeners/ShopTradeListener.java +++ b/src/main/java/org/shanerx/tradeshop/shop/listeners/ShopTradeListener.java @@ -60,13 +60,12 @@ import java.util.List; import java.util.Map; -public class ShopTradeListener extends Utils implements Listener { +public class ShopTradeListener implements Listener { private final TradeShop PLUGIN = TradeShop.getPlugin(); @EventHandler(priority = EventPriority.LOW, ignoreCancelled = true) public void onBlockInteract(PlayerInteractEvent e) { - if (e.useInteractedBlock().equals(Event.Result.DENY) || e.isCancelled()) return; @@ -87,7 +86,7 @@ public void onBlockInteract(PlayerInteractEvent e) { shop = PLUGIN.getDataStorage().loadShopFromSign(new ShopLocation(s.getLocation())); if (shop == null) { - String[] lines = failedSignLines(type); + String[] lines = new Utils().failedSignLines(type); for (int line = 0; line < 4; line++) { s.setLine(line, lines[line]); } @@ -100,9 +99,8 @@ public void onBlockInteract(PlayerInteractEvent e) { Bukkit.getPluginManager().callEvent(preEvent); if (preEvent.isCancelled()) return; - shop = preEvent.getShop(); //Sets shop to events shop so any changes made in preEvent are carried back - shop.updateSide(ShopItemSide.COST, preEvent.getCost()); - shop.updateSide(ShopItemSide.PRODUCT, preEvent.getProduct()); + shop.updateSide(ShopItemSide.COST, preEvent.getCost(), false); + shop.updateSide(ShopItemSide.PRODUCT, preEvent.getProduct(), false); boolean doBiTradeAlternate = shop.getShopType().isBiTrade() && preEvent.isAction(Action.LEFT_CLICK_BLOCK); @@ -137,7 +135,7 @@ public void onBlockInteract(PlayerInteractEvent e) { } if (shop.hasSide(ShopItemSide.PRODUCT)) { - List searchResult = getItems(shop.getChestAsSC().getInventory().getStorageContents(), shop.getSideList(ShopItemSide.PRODUCT, doBiTradeAlternate), multiplier); + List searchResult = new Utils().getItems(shop.getChestAsSC().getInventory().getStorageContents(), shop.getSideList(ShopItemSide.PRODUCT, doBiTradeAlternate), multiplier); Message.SHOP_INSUFFICIENT_ITEMS.sendItemMultiLineMessage(buyer, Collections.singletonMap(Variable.MISSING_ITEMS, searchResult)); } return; @@ -152,7 +150,7 @@ public void onBlockInteract(PlayerInteractEvent e) { e.setCancelled(true); shop = PLUGIN.getDataStorage().loadShopFromSign(new ShopLocation(s.getLocation())); - Tuple> canExchangeResult = canExchangeAll(shop, buyer.getInventory(), multiplier, e.getAction()); + Tuple> canExchangeResult = new Utils().canExchangeAll(shop, buyer.getInventory(), multiplier, e.getAction()); PLUGIN.getDebugger().log("ExchangeResult " + canExchangeResult.getLeft(), DebugLevels.TRADE); switch (canExchangeResult.getLeft()) { @@ -201,7 +199,7 @@ public void onBlockInteract(PlayerInteractEvent e) { private Tuple, List> tradeAllItems(Shop shop, int multiplier, PlayerInteractEvent event, Player buyer) { Action action = event.getAction(); - List costItems = createBadList(), productItems = createBadList(); // Start with Bad lists so that in the event of failure at least one list has to have null at 0 + List costItems = new Utils().createBadList(), productItems = new Utils().createBadList(); // Start with Bad lists so that in the event of failure at least one list has to have null at 0 Inventory shopInventory = shop.hasStorage() ? shop.getChestAsSC().getInventory() : null; Inventory playerInventory = buyer.getInventory(); @@ -220,7 +218,7 @@ private Tuple, List> tradeAllItems(Shop shop, int mul //Method to find Cost items in player inventory and add to cost array if (useCost) { - costItems = getItems(playerInventory.getStorageContents(), shop.getSideList(ShopItemSide.COST, isBi), multiplier); + costItems = new Utils().getItems(playerInventory.getStorageContents(), shop.getSideList(ShopItemSide.COST, isBi), multiplier); if (costItems.get(0) == null) { ItemStack item = costItems.get(1); Message.INSUFFICIENT_ITEMS.sendItemMultiLineMessage(buyer, Collections.singletonMap(Variable.MISSING_ITEMS, costItems)); @@ -239,7 +237,7 @@ private Tuple, List> tradeAllItems(Shop shop, int mul } //Method to find Product items in shop inventory and add to product array - productItems = getItems(shopInventory.getStorageContents(), shop.getSideList(ShopItemSide.PRODUCT, isBi), multiplier); + productItems = new Utils().getItems(shopInventory.getStorageContents(), shop.getSideList(ShopItemSide.PRODUCT, isBi), multiplier); if (productItems.get(0) == null) { ItemStack item = productItems.get(1); shop.updateStatus(); @@ -269,13 +267,13 @@ private Tuple, List> tradeAllItems(Shop shop, int mul if (useCost) { //For loop to put cost items in shop inventory for (ItemStack item : costItems) { - addItemToInventory(shopInventory, item.clone()); + new Utils().addItemToInventory(shopInventory, item.clone()); } } //For loop to put product items in player inventory for (ItemStack item : productItems) { - addItemToInventory(playerInventory, item.clone()); + new Utils().addItemToInventory(playerInventory, item.clone()); } PLUGIN.getDebugger().log("ShopTradeListener > tradeAll > end-productItems: " + productItems, DebugLevels.TRADE); diff --git a/src/main/java/org/shanerx/tradeshop/shoplocation/ShopChunk.java b/src/main/java/org/shanerx/tradeshop/shoplocation/ShopChunk.java index 94b7c3e2..da79001b 100644 --- a/src/main/java/org/shanerx/tradeshop/shoplocation/ShopChunk.java +++ b/src/main/java/org/shanerx/tradeshop/shoplocation/ShopChunk.java @@ -30,9 +30,7 @@ import org.bukkit.ChunkSnapshot; import org.bukkit.World; -import java.io.Serializable; - -public class ShopChunk implements Serializable { +public class ShopChunk { private final String div = ";;", worldName; diff --git a/src/main/java/org/shanerx/tradeshop/shoplocation/ShopLocation.java b/src/main/java/org/shanerx/tradeshop/shoplocation/ShopLocation.java index 9930f539..6a432201 100644 --- a/src/main/java/org/shanerx/tradeshop/shoplocation/ShopLocation.java +++ b/src/main/java/org/shanerx/tradeshop/shoplocation/ShopLocation.java @@ -29,19 +29,27 @@ import org.bukkit.Chunk; import org.bukkit.Location; import org.bukkit.World; +import org.shanerx.tradeshop.utils.objects.ObjectHolder; -import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; -public class ShopLocation implements Serializable { +public class ShopLocation { final private String div = "::"; private final String worldName; - private final double x; - private final double y; - private final double z; + private final int x, y, z; private transient World world; public ShopLocation(World w, double x, double y, double z) { + this.world = w; + this.worldName = w.getName(); + this.x = (int) x; + this.y = (int) y; + this.z = (int) z; + } + + public ShopLocation(World w, int x, int y, int z) { this.world = w; this.worldName = w.getName(); this.x = x; @@ -52,33 +60,57 @@ public ShopLocation(World w, double x, double y, double z) { public ShopLocation(Location loc) { this.world = loc.getWorld(); this.worldName = loc.getWorld().getName(); - this.x = loc.getX(); - this.y = loc.getY(); - this.z = loc.getZ(); + this.x = loc.getBlockX(); + this.y = loc.getBlockY(); + this.z = loc.getBlockZ(); } public static ShopLocation deserialize(String loc) { if (loc.startsWith("l")) { String[] locA = loc.contains("::") ? loc.split("::") : loc.split("_"); //Keep same as div - double x = Double.parseDouble(locA[2]), y = Double.parseDouble(locA[3]), z = Double.parseDouble(locA[4]); + ObjectHolder x = new ObjectHolder<>(locA[2]), y = new ObjectHolder<>(locA[3]), z = new ObjectHolder<>(locA[4]); World world = Bukkit.getWorld(locA[1]); if (world == null) world = Bukkit.getWorld(locA[1].replace("-", "_")); if (world == null) { - throw new IllegalWorldException("Cannot find world " + locA[1], new WorldlessLocation(x, y, z)); + throw new IllegalWorldException("Cannot find world " + locA[1], new WorldlessLocation(x.asDouble(), y.asDouble(), z.asDouble())); + // Not to maintainer: do NOT remove this artificial error, it is supposed to be caught elsewhere + // (Temporary fix for metadata world renaming bug until metadata is removed entirely) + } + + return new ShopLocation(world, x.asInteger(), y.asInteger(), z.asInteger()); + } + + return null; + } + + public static ShopLocation deserialize(Map loc) { + if (loc.containsKey("world") && loc.containsKey("x") && loc.containsKey("y") && loc.containsKey("z")) { + World world = Bukkit.getWorld(loc.get("world").toString()); + if (world == null) + world = Bukkit.getWorld(loc.get("world").toString().replace("-", "_")); + if (world == null) { + throw new IllegalWorldException("Cannot find world " + loc.get("world"), new WorldlessLocation(Double.parseDouble(loc.get("x").toString()), Double.parseDouble(loc.get("y").toString()), Double.parseDouble(loc.get("z").toString()))); // Not to maintainer: do NOT remove this artificial error, it is supposed to be caught elsewhere // (Temporary fix for metadata world renaming bug until metadata is removed entirely) } - return new ShopLocation(world, x, y, z); + return new ShopLocation(world, Double.parseDouble(loc.get("x").toString()), Double.parseDouble(loc.get("y").toString()), Double.parseDouble(loc.get("z").toString())); } return null; } - public String serialize() { - return "l" + div + worldName + div + x + div + y + div + z; + public Map serialize() { + Map map = new HashMap<>(); + map.put("world", worldName); + map.put("x", x); + map.put("y", y); + map.put("z", z); + map.put("div", div); + + return map; } public World getWorld() { @@ -121,6 +153,6 @@ public String toString() { } public String toString(boolean includeWorld) { - return (includeWorld ? "World:" + worldName + " " : "") + "X:" + x + " Y:" + y + " Z:" + z; + return "l" + div + (includeWorld ? worldName + div : "") + x + div + y + div + z; } } \ No newline at end of file diff --git a/src/main/java/org/shanerx/tradeshop/utils/Utils.java b/src/main/java/org/shanerx/tradeshop/utils/Utils.java index 3991a206..192c37fe 100644 --- a/src/main/java/org/shanerx/tradeshop/utils/Utils.java +++ b/src/main/java/org/shanerx/tradeshop/utils/Utils.java @@ -75,10 +75,10 @@ */ public class Utils { - private final UUID KOPUUID = UUID.fromString("daf79be7-bc1d-47d3-9896-f97b8d4cea7d"); - private final UUID LORIUUID = UUID.fromString("e296bc43-2972-4111-9843-48fc32302fd4"); - private final TradeShop PLUGIN = TradeShop.getPlugin(); - protected PluginDescriptionFile pdf = PLUGIN.getDescription(); + private final transient UUID KOPUUID = UUID.fromString("daf79be7-bc1d-47d3-9896-f97b8d4cea7d"); + private final transient UUID LORIUUID = UUID.fromString("e296bc43-2972-4111-9843-48fc32302fd4"); + private final transient TradeShop PLUGIN = TradeShop.getPlugin(); + protected transient PluginDescriptionFile pdf = PLUGIN.getDescription(); public Utils() { } @@ -92,7 +92,7 @@ public UUID[] getMakers() { * * @return the name. */ - protected String getPluginName() { + public String getPluginName() { return pdf.getName(); } @@ -514,14 +514,14 @@ public Shop createShop(Sign shopSign, Player creator, ShopType shopType, ItemSta } Map permittedLimits = Maps.filterEntries(PLUGIN.getListManager().getLimitPermissions(), (entry) -> creator.hasPermission(entry.getKey())); - int limit; - if (permittedLimits.containsValue(-1)) { - limit = -1; - } else if (Setting.SUM_PER_PLAYER_LIMIT.getBoolean()) { - limit = permittedLimits.values().stream().mapToInt(Integer::intValue).sum(); - } else { - OptionalInt oInt = permittedLimits.values().stream().mapToInt(Integer::intValue).max(); - limit = oInt.isPresent() ? oInt.getAsInt() : 0; + OptionalInt oMaxInt = permittedLimits.values().stream().mapToInt(Integer::intValue).reduce(Integer::max), //process max value + oSumInt = permittedLimits.values().stream().mapToInt(Integer::intValue).reduce(Integer::sum); //process sum value + int limit = -1; // set default value to -1 + + if (permittedLimits.size() > 0 && !permittedLimits.containsValue(-1)) { //If the player has set permissions and does not have an unlimited permission(-1) + limit = Setting.SUM_PER_PLAYER_LIMIT.getBoolean() ? //set based on config setting + oSumInt.getAsInt() : // set to sum if enabled + oMaxInt.getAsInt(); //set to max if disabled } final int OWNED_SHOPS = PLUGIN.getDataStorage().loadPlayer(owner.getUUID()).getOwnedShops().size(); @@ -537,13 +537,13 @@ public Shop createShop(Sign shopSign, Player creator, ShopType shopType, ItemSta Shop shop; Block chest = findShopChest(shopSign.getBlock()); - if (!shopType.isITrade()) { if (ShopChest.isShopChest(chest)) { shopChest = new ShopChest(chest.getLocation()); } else { shopChest = new ShopChest(chest, creator.getUniqueId(), shopSign.getLocation()); } + if (!shopType.isITrade()) { if (shopChest.hasOwner() && !shopChest.getOwner().equals(owner.getUUID())) { Message.NO_SHOP_PERMISSION.sendMessage(creator); return null; @@ -750,7 +750,7 @@ public boolean textToBool(String check) { } public void scheduleShopDelayUpdate(String cause, Shop shop, Long delay) { - PLUGIN.getDebugger().log("Shop delay update caused by " + cause + ": " + shop.getShopLocationAsSL().serialize(), DebugLevels.PROTECTION); + PLUGIN.getDebugger().log("Shop delay update caused by " + cause + ": " + shop.getShopLocationAsSL().toString(), DebugLevels.PROTECTION); Bukkit.getScheduler().scheduleSyncDelayedTask(PLUGIN, () -> { shop.updateFullTradeCount(); shop.updateSign(); diff --git a/src/main/java/org/shanerx/tradeshop/utils/debug/Debug.java b/src/main/java/org/shanerx/tradeshop/utils/debug/Debug.java index c28557b1..ce45a61a 100644 --- a/src/main/java/org/shanerx/tradeshop/utils/debug/Debug.java +++ b/src/main/java/org/shanerx/tradeshop/utils/debug/Debug.java @@ -42,9 +42,9 @@ public Debug() { } public static Debug findDebugger() { - final TradeShop plugin = ((TradeShop) Bukkit.getPluginManager().getPlugin("TradeShop")); + final TradeShop plugin = TradeShop.getPlugin(); if (plugin != null) { - return plugin.getDebugger(); + return plugin.getVarManager().getDebugger(); } else { return new Debug(); } @@ -69,14 +69,32 @@ public void reload() { } } - public void log(String message, DebugLevels level) { + public void log(String message, DebugLevels level, String positionalNote) { + StringBuilder messageBuilder = new StringBuilder(); + if (level.getPosition() > 0 && decimalDebugLevel <= 0) { + return; + } + + if (level.getPosition() > 0 && binaryDebugLevel.charAt(level.getPosition() - 1) == '1') { - Bukkit.getLogger().log(level.getLogLevel(), PREFIX.replace("%level%", level.getPrefix()) + message); + message = PREFIX.replace("%level%", level.getPrefix()) + message; } else if (level == DebugLevels.DISABLED) { - Bukkit.getLogger().log(level.getLogLevel(), PREFIX.replace(" Debug%level%", "") + message); + message = PREFIX.replaceAll("( Debug.%level%)", "(D) ") + message; } else if (level.getPosition() < 0) { - Bukkit.getLogger().log(level.getLogLevel(), PREFIX.replace("%level%", level.getPrefix()) + message); + message = PREFIX.replace("%level%", level.getPrefix()) + message; + } + + if (positionalNote != null && !positionalNote.isEmpty()) { + messageBuilder.append("{ ").append(positionalNote).append(" }\n"); } + + messageBuilder.append(message); + + Bukkit.getLogger().log(level.getLogLevel(), messageBuilder.toString()); + } + + public void log(String message, DebugLevels level) { + log(message, level, null); } public String getFormattedPrefix(DebugLevels debugLevel) { diff --git a/src/main/java/org/shanerx/tradeshop/utils/debug/DebugLevels.java b/src/main/java/org/shanerx/tradeshop/utils/debug/DebugLevels.java index 250b3fbb..0b7a6a00 100644 --- a/src/main/java/org/shanerx/tradeshop/utils/debug/DebugLevels.java +++ b/src/main/java/org/shanerx/tradeshop/utils/debug/DebugLevels.java @@ -25,6 +25,7 @@ package org.shanerx.tradeshop.utils.debug; +import java.util.Optional; import java.util.logging.Level; public enum DebugLevels { @@ -46,8 +47,9 @@ public enum DebugLevels { SQLITE(12, Level.INFO), // 2048 GSON(13, Level.INFO), // 4096 DATA_VERIFICATION(14, Level.INFO), // 8192 - FIND_COMMAND(15, Level.INFO) // 16384 - + FIND_COMMAND(15, Level.INFO), // 16384 + JSON_SAVING(16, Level.INFO), // 32768 + JSON_LOADING(17, Level.INFO) // 65536 ; @@ -88,4 +90,16 @@ public String getPrefix() { return " - " + name(); } + public static Optional match(String desiredLevel) { + Optional ret = Optional.empty(); + for (DebugLevels level : values()) { + if (level.name().replaceAll("\\w", "").equalsIgnoreCase(desiredLevel)) { + ret = Optional.of(level); + break; + } + } + + return ret; + } + } \ No newline at end of file diff --git a/src/main/java/org/shanerx/tradeshop/utils/gsonprocessing/GsonProcessor.java b/src/main/java/org/shanerx/tradeshop/utils/gsonprocessing/GsonProcessor.java index fd3370ee..13cbf8b7 100644 --- a/src/main/java/org/shanerx/tradeshop/utils/gsonprocessing/GsonProcessor.java +++ b/src/main/java/org/shanerx/tradeshop/utils/gsonprocessing/GsonProcessor.java @@ -25,52 +25,142 @@ package org.shanerx.tradeshop.utils.gsonprocessing; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; -import com.google.gson.JsonElement; -import com.google.gson.JsonSyntaxException; -import org.bukkit.configuration.serialization.ConfigurationSerializable; -import org.shanerx.tradeshop.utils.gsonprocessing.typeadapters.ConfigurationSerializableAdapter; +import com.bergerkiller.bukkit.common.config.JsonSerializer; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import org.bukkit.inventory.ItemStack; +import org.shanerx.tradeshop.item.ShopItemStack; +import org.shanerx.tradeshop.item.ShopItemStackSettingKeys; +import org.shanerx.tradeshop.player.ShopUser; +import org.shanerx.tradeshop.shop.Shop; +import org.shanerx.tradeshop.shop.ShopSettingKeys; +import org.shanerx.tradeshop.shop.ShopStatus; +import org.shanerx.tradeshop.shop.ShopType; +import org.shanerx.tradeshop.shoplocation.ShopLocation; +import org.shanerx.tradeshop.utils.objects.ObjectHolder; +import org.shanerx.tradeshop.utils.objects.Tuple; -import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.UUID; public class GsonProcessor { - private final Gson globalGson; + private static final JsonSerializer jsonSerializer = new JsonSerializer(); - public GsonProcessor(boolean doPrettyPrinting) { - GsonBuilder gsonBuilder = new GsonBuilder() - .disableHtmlEscaping() - .serializeNulls() - .enableComplexMapKeySerialization() - .setLenient() - .registerTypeHierarchyAdapter(ConfigurationSerializable.class, new ConfigurationSerializableAdapter()); + public static ItemStack fromJsonToItemStack(String json) throws JsonSerializer.JsonSyntaxException { + return jsonSerializer.fromJsonToItemStack(json); + } + + @SuppressWarnings("unchecked") + public static Map jsonToMap(String json) throws JsonSerializer.JsonSyntaxException { + return jsonSerializer.fromJson(json, Map.class); + } - if (doPrettyPrinting) gsonBuilder.setPrettyPrinting(); + @SuppressWarnings("unchecked") + public static T fromJson(JsonObject json, Class type) throws JsonSerializer.JsonSyntaxException { + if (type.equals(Shop.class) && (json.has("product") || json.has("cost"))) { + return (T) jsonToShop(json); + } - globalGson = gsonBuilder.create(); + return jsonSerializer.fromJson(json.toString(), type); } - public GsonProcessor() { - this(true); + public static T fromJson(String json, Class type) throws JsonSerializer.JsonSyntaxException { + if (type.equals(Shop.class)) { + return fromJson(stringToJsonObject(json), type); + } + + return jsonSerializer.fromJson(json, type); } - public T fromJson(String json, Class classOfT) throws JsonSyntaxException { - return globalGson.fromJson(json, (Type) classOfT); + public static String itemStackToJson(ItemStack item) { + return jsonSerializer.itemStackToJson(item); } - public T fromJson(JsonElement json, Type typeOfT) throws JsonSyntaxException { - return globalGson.fromJson(json, typeOfT); + public static String mapToJson(Map map) { + return jsonSerializer.mapToJson(map); } - public String toJson(Object src) { - return globalGson.toJson(src, src.getClass()); + public static String toJson(Object value) { + return jsonSerializer.toJson(value); } - public JsonElement toJsonTree(Object src) { - return globalGson.toJsonTree(src, src.getClass()); + public static JsonObject stringToJsonObject(String json) throws JsonSerializer.JsonSyntaxException { + return jsonSerializer.fromJson(json, JsonObject.class); } - public Gson getGlobalGson() { - return globalGson; + public static Shop jsonToShop(JsonObject json) { + Shop shop; + + try { + ShopLocation shopLoc = fromJson(json.get("shopLoc").getAsString(), ShopLocation.class), + chestLoc = fromJson(json.get("chestLoc").getAsString(), ShopLocation.class); + ShopUser owner = fromJson(json.get("owner").getAsString(), ShopUser.class); + ShopStatus shopStatus = fromJson(json.get("shopStatus").getAsString(), ShopStatus.class); + Map> shopSettings = new HashMap<>(); + List managers = fromJsonInJsonArray(json.getAsJsonArray("managers"), UUID.class), + members = fromJsonInJsonArray(json.getAsJsonArray("members"), UUID.class); + ShopType shopType = fromJson(json.get("shopType").getAsString(), ShopType.class); + + HashSet users = new HashSet<>(Objects.nonNull(managers) ? managers : Collections.emptySet()); + + jsonToMap(json.get("shopSettings").getAsString()).forEach((key, oh) -> shopSettings.put(ShopSettingKeys.valueOf(key), (ObjectHolder) oh)); + + List product = fromJsonInJsonArrayToShopItemstackList(json.getAsJsonArray("product")), + cost = fromJsonInJsonArrayToShopItemstackList(json.getAsJsonArray("cost")); + + shop = new Shop(new Tuple<>(shopLoc.getLocation(), + chestLoc.getLocation()), + shopType, + owner, + new Tuple<>( + new HashSet<>(Objects.nonNull(managers) ? managers : Collections.emptyList()), + new HashSet<>(Objects.nonNull(members) ? members : Collections.emptyList()) + ), + fromJsonInJsonArrayToShopItemstackList(json.getAsJsonArray("product")), + fromJsonInJsonArrayToShopItemstackList(json.getAsJsonArray("cost"))); + shop.setShopSettings(shopSettings); + shop.setStatus(shopStatus); + + } catch (JsonSerializer.JsonSyntaxException | NullPointerException e) { + return null; + } + + return shop; + } + + private static List fromJsonInJsonArray(JsonArray json, Class type) { + List ret = new ArrayList<>(); + new ArrayList<>(json.asList()).forEach((jsonElement) -> { + try { + ret.add(fromJson(jsonElement.getAsString(), type)); + } catch (JsonSerializer.JsonSyntaxException ignored) { + } + }); + ret.remove(null); + + return ret.isEmpty() ? null : ret; + } + + private static List fromJsonInJsonArrayToShopItemstackList(JsonArray json) { + List ret = new ArrayList<>(); + Map> shopItemStackSettings = new HashMap<>(); + new ArrayList<>(json.asList()).forEach((jsonElement) -> { + JsonObject jsonItem = jsonElement.getAsJsonObject(); + shopItemStackSettings.clear(); + try { + jsonToMap(jsonItem.get("itemSettings").getAsString()).forEach((key, oh) -> shopItemStackSettings.put(ShopItemStackSettingKeys.valueOf(key), (ObjectHolder) oh)); + ret.add(new ShopItemStack(fromJsonToItemStack(jsonItem.get("itemStackString").getAsString()), shopItemStackSettings)); + } catch (JsonSerializer.JsonSyntaxException ignored) { + } + }); + ret.remove(null); + + return ret.isEmpty() ? null : ret; } } diff --git a/src/main/java/org/shanerx/tradeshop/utils/logging/transactionlogging/TransactionLogger.java b/src/main/java/org/shanerx/tradeshop/utils/logging/transactionlogging/TransactionLogger.java index c71f394b..7dce4f09 100644 --- a/src/main/java/org/shanerx/tradeshop/utils/logging/transactionlogging/TransactionLogger.java +++ b/src/main/java/org/shanerx/tradeshop/utils/logging/transactionlogging/TransactionLogger.java @@ -26,8 +26,6 @@ package org.shanerx.tradeshop.utils.logging.transactionlogging; import com.google.common.io.Files; -import com.google.gson.Gson; -import com.google.gson.JsonObject; import org.bukkit.inventory.ItemStack; import org.shanerx.tradeshop.TradeShop; import org.shanerx.tradeshop.data.config.Setting; @@ -40,13 +38,9 @@ import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; -import java.nio.charset.StandardCharsets; import java.text.SimpleDateFormat; -import java.util.Base64; import java.util.Date; import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; public class TransactionLogger { @@ -126,29 +120,14 @@ public void logTransaction(PlayerSuccessfulTradeEvent event) { } private String getItemListAsString(List itemList) { - try { - final Gson gson = new GsonProcessor(false).getGlobalGson(); - JsonObject jsonObj = new JsonObject(); + //try { + String[] itemArray = new String[itemList.size()]; for (int i = 0; i < itemList.size(); i++) { - JsonObject temp = gson.toJsonTree(new ItemStack(itemList.get(i))).getAsJsonObject(); - - // remove unneeded tags - if (temp.has("meta")) { - JsonObject tempMeta = temp.getAsJsonObject("meta"); - tempMeta.remove("placeableKeys"); - tempMeta.remove("destroyableKeys"); - - if (tempMeta.has("persistentDataContainer")) { - JsonObject tempPerData = tempMeta.getAsJsonObject("persistentDataContainer"); - tempPerData.remove("registry"); - tempPerData.remove("adapterContext"); - } - } - - jsonObj.add("Item #" + i, temp); + itemArray[i] = GsonProcessor.itemStackToJson(new ItemStack(itemList.get(i))); } - String ret = gson.toJson(jsonObj); + /* + String ret = gson.toJson(jsonObj); Matcher m = Pattern.compile("(/).+( [\\[{])").matcher(ret); @@ -181,7 +160,7 @@ private String getItemListAsString(List itemList) { } } - /* + *//* // Replaces get rid of " that break the json output // Remove " from :"{ ret = ret.replace(":\"{", ":{"); @@ -197,7 +176,7 @@ private String getItemListAsString(List itemList) { ret = ret.replace("}\"}", "}}"); // Replace empty "" with "unknown" ret = ret.replace("{\"\",", "["); - */ + *//* return ret // Remove " from :"{ @@ -216,10 +195,14 @@ private String getItemListAsString(List itemList) { .replace("}\"}", "}}") // Replace empty "" with "unknown" .replace("\"\",", ""); + */ + return GsonProcessor.toJson(itemArray); + /* } catch (Exception e) { e.printStackTrace(); return "Error: " + Base64.getEncoder().encodeToString(e.getStackTrace().toString().getBytes(StandardCharsets.UTF_8)); } + */ } private String getFileTimeString() { diff --git a/src/main/java/org/shanerx/tradeshop/utils/management/ListManager.java b/src/main/java/org/shanerx/tradeshop/utils/management/ListManager.java index 6bc33031..dfbdb221 100644 --- a/src/main/java/org/shanerx/tradeshop/utils/management/ListManager.java +++ b/src/main/java/org/shanerx/tradeshop/utils/management/ListManager.java @@ -40,7 +40,6 @@ import org.shanerx.tradeshop.item.NonObtainableMaterials; import org.shanerx.tradeshop.item.ShopItemSide; import org.shanerx.tradeshop.shop.ShopStorage; -import org.shanerx.tradeshop.utils.Utils; import org.shanerx.tradeshop.utils.debug.DebugLevels; import org.shanerx.tradeshop.utils.objects.ObjectHolder; import org.shanerx.tradeshop.utils.relativedirection.RelativeDirection; @@ -54,7 +53,7 @@ import java.util.concurrent.TimeUnit; @SuppressWarnings("unused") -public class ListManager extends Utils { +public class ListManager { private final IllegalItemList globalList = new IllegalItemList(IllegalItemList.ListType.DISABLED, new ArrayList<>()); private final IllegalItemList costList = new IllegalItemList(IllegalItemList.ListType.DISABLED, new ArrayList<>()); diff --git a/src/main/java/org/shanerx/tradeshop/utils/objects/ObjectHolder.java b/src/main/java/org/shanerx/tradeshop/utils/objects/ObjectHolder.java index 7f6a31f2..31593be6 100644 --- a/src/main/java/org/shanerx/tradeshop/utils/objects/ObjectHolder.java +++ b/src/main/java/org/shanerx/tradeshop/utils/objects/ObjectHolder.java @@ -28,7 +28,10 @@ import com.google.gson.annotations.SerializedName; import org.bukkit.Material; +import java.util.Collections; +import java.util.List; import java.util.Map; +import java.util.Optional; public class ObjectHolder { @@ -39,10 +42,22 @@ public ObjectHolder(Type obj) { this.obj = obj; } + public static ObjectHolder deserialize(Map serialized) { + return new ObjectHolder<>(serialized.get("obj")); + } + + public Map serialize() { + return Collections.singletonMap("obj", obj); + } + public Type getObject() { return obj; } + public boolean isNull() { + return obj == null; + } + public boolean isBoolean() { return obj != null && obj instanceof Boolean; } @@ -115,6 +130,21 @@ public Map asMap() { return null; } + public boolean isList() { + return !isNull() && obj instanceof List; + } + + public Optional> asStringList() { + Optional> ret = Optional.empty(); + if (isList()) { + try { + ret = Optional.of((List) obj); + } catch (ClassCastException ignored) { + } + } + return ret; + } + public boolean canBeMaterial() { return asMaterial() != null; } diff --git a/src/main/java/org/shanerx/tradeshop/utils/objects/Tuple.java b/src/main/java/org/shanerx/tradeshop/utils/objects/Tuple.java index 269f4dfd..17a4cb84 100644 --- a/src/main/java/org/shanerx/tradeshop/utils/objects/Tuple.java +++ b/src/main/java/org/shanerx/tradeshop/utils/objects/Tuple.java @@ -26,11 +26,11 @@ package org.shanerx.tradeshop.utils.objects; import com.google.gson.annotations.SerializedName; -import org.shanerx.tradeshop.utils.gsonprocessing.GsonProcessor; -import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; -public class Tuple implements Serializable { +public class Tuple { @SerializedName("right") private R r; @@ -58,12 +58,16 @@ public L getLeft() { return l; } - public String serialize() { - return new GsonProcessor().toJson(this); + public Map serialize() { + Map map = new HashMap<>(); + map.put("L", l); + map.put("R", r); + + return map; } @Override public String toString() { - return serialize(); + return serialize().toString(); } } \ No newline at end of file diff --git a/src/main/java/org/shanerx/tradeshop/utils/simplix/serializers/ConfSerSerializer.java b/src/main/java/org/shanerx/tradeshop/utils/simplix/serializers/ConfSerSerializer.java new file mode 100644 index 00000000..a9757e9d --- /dev/null +++ b/src/main/java/org/shanerx/tradeshop/utils/simplix/serializers/ConfSerSerializer.java @@ -0,0 +1,55 @@ +/* + * + * Copyright (c) 2016-2023 + * SparklingComet @ http://shanerx.org + * KillerOfPie @ http://killerofpie.github.io + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * NOTICE: All modifications made by others to the source code belong + * to the respective contributor. No contributor should be held liable for + * any damages of any kind, whether be material or moral, which were + * caused by their contribution(s) to the project. See the full License for more information. + * + */ + +package org.shanerx.tradeshop.utils.simplix.serializers; + +import org.bukkit.configuration.serialization.ConfigurationSerializable; +import org.bukkit.configuration.serialization.ConfigurationSerialization; +import org.bukkit.inventory.ItemStack; + +import java.util.LinkedHashMap; +import java.util.Map; + +public class ConfSerSerializer { + public static ItemStack deserializeItemStack(Map map) { + return (ItemStack) ConfigurationSerialization.deserializeObject(map, ItemStack.class); + } + + public static Map serialize(ConfigurationSerializable configurationSerializable) { + return toMap(configurationSerializable); + } + + public static Map toMap(ConfigurationSerializable src) { + Map map = new LinkedHashMap<>(src.serialize()); + + map.forEach((k, v) -> { + if (v instanceof ConfigurationSerializable) { + map.replace(k, toMap((ConfigurationSerializable) v)); + } + }); + + return map; + } +} diff --git a/src/main/java/org/shanerx/tradeshop/utils/versionmanagement/Updater.java b/src/main/java/org/shanerx/tradeshop/utils/versionmanagement/Updater.java index a77edeae..25eb3d70 100644 --- a/src/main/java/org/shanerx/tradeshop/utils/versionmanagement/Updater.java +++ b/src/main/java/org/shanerx/tradeshop/utils/versionmanagement/Updater.java @@ -31,9 +31,13 @@ import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.MalformedURLException; +import java.net.URISyntaxException; import java.net.URL; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.logging.Level; import java.util.logging.Logger; +import org.shanerx.tradeshop.TradeShop; public class Updater { @@ -85,6 +89,19 @@ public String getVersionComponent(SemVer semver) { public BuildType getBuildType() { return build; } + + public String buildNumberSuffix() { + try { + Path path = Paths.get(TradeShop.class.getProtectionDomain().getCodeSource().getLocation().toURI()); + String name = path.getFileName().toString(); + if (!name.matches(".+\\d+.jar$")) return ""; + String buildNum = name.substring(name.length() - 7, name.length() - 4); + return " build " + buildNum; + } catch (URISyntaxException e) { + e.printStackTrace(); + } + return ""; + } public RelationalStatus checkCurrentVersion() { try { @@ -106,11 +123,11 @@ public RelationalStatus checkCurrentVersion() { log.log(Level.WARNING, "[Updater] +------------------------------------------------+"); in.close(); return RelationalStatus.BEHIND; - } else if (rs == RelationalStatus.AHEAD) { + } else if (rs == RelationalStatus.AHEAD || getVersion().endsWith("DEV")) { log.log(Level.WARNING, "[Updater] +-----------------------------------------------------+"); log.log(Level.WARNING, "[Updater] You are running a developmental version of " + pdf.getName() + "!"); log.log(Level.WARNING, "[Updater] Most recent stable version: " + inputLine); - log.log(Level.WARNING, "[Updater] Current version: " + getVersion()); + log.log(Level.WARNING, "[Updater] Current version: " + getVersion() + buildNumberSuffix()); log.log(Level.WARNING, "[Updater] Please notice that the build may contain critical bugs!"); log.log(Level.WARNING, "[Updater] +-----------------------------------------------------+"); in.close(); diff --git a/src/main/resources/Lang/en-us.yml b/src/main/resources/Lang/en-us.yml index 95ac9e1f..8e8c0749 100644 --- a/src/main/resources/Lang/en-us.yml +++ b/src/main/resources/Lang/en-us.yml @@ -47,6 +47,8 @@ setting: system-options: data-storage-type: pre-comment: "How would you like your servers data stored? (FLATFILE, SQLITE)" + max-save-threads: + pre-comment: "Max. number of additional subthreads to spawn. For the best performance, take into account how many cores you have.\n Set to 0 to save everything in the main thread (not recommended unless you experience issues with data saving)." enable-debug: pre-comment: "What debug code should be run. This will add significant amounts of spam to the console/log, generally not used unless requested by Devs" check-updates: diff --git a/src/main/resources/settings.yml b/src/main/resources/settings.yml index a104f1ef..602b5f4b 100644 --- a/src/main/resources/settings.yml +++ b/src/main/resources/settings.yml @@ -9,6 +9,9 @@ config-version: 1.2 system-options: # How would you like your servers data stored? (FLATFILE) data-storage-type: FLATFILE + # Max. number of additional subthreads to spawn. For the best performance, take into account how many cores you have. + # Set to 0 to save everything in the main thread (not recommended unless you experience issues with data saving). + max-save-threads: 3 # What debug code should be run. This will add significant amounts of spam to the console/log, generally not used unless requested by Devs enable-debug: 0 # Should we check for updates when the server starts