diff --git a/src/main/java/org/shanerx/tradeshop/commands/commandrunners/WhatCommand.java b/src/main/java/org/shanerx/tradeshop/commands/commandrunners/WhatCommand.java index f2f38752..a1699523 100644 --- a/src/main/java/org/shanerx/tradeshop/commands/commandrunners/WhatCommand.java +++ b/src/main/java/org/shanerx/tradeshop/commands/commandrunners/WhatCommand.java @@ -61,6 +61,9 @@ public void what() { if (shop == null) return; + shop.updateFullTradeCount(); + shop.updateSign(); + if (!Permissions.hasPermission(pSender, Permissions.INFO)) { command.sendMessage(Message.NO_COMMAND_PERMISSION.getPrefixed()); return; diff --git a/src/main/java/org/shanerx/tradeshop/data/config/ConfigManager.java b/src/main/java/org/shanerx/tradeshop/data/config/ConfigManager.java index 563e5fed..8eab75e8 100644 --- a/src/main/java/org/shanerx/tradeshop/data/config/ConfigManager.java +++ b/src/main/java/org/shanerx/tradeshop/data/config/ConfigManager.java @@ -185,14 +185,14 @@ public void save() { switch (configType) { case CONFIG: - Arrays.stream(SettingSection.values()).sorted(new CompareSettingSections()).forEach((section) -> outputMap.put(section.getPath(), section.getFileString())); - Arrays.stream(Setting.values()).forEach((setting) -> outputMap.put(setting.getSection().getPath(), - outputMap.getOrDefault(setting.getSection().getPath(), "") + setting.getFileString())); + Arrays.stream(SettingSection.values()).sorted(new CompareSettingSections()).forEach((section) -> outputMap.put(section.getPath().toLowerCase().replace("_", "-"), section.getFileString())); + Arrays.stream(Setting.values()).forEach((setting) -> outputMap.put(setting.getSection().getPath().toLowerCase().replace("_", "-"), + outputMap.getOrDefault(setting.getSection().getPath().toLowerCase().replace("_", "-"), "") + setting.getFileString())); break; case MESSAGES: - Arrays.stream(MessageSection.values()).sorted(new CompareMessageSections()).forEach((section) -> outputMap.put(section.getPath(), section.getFileString())); - Arrays.stream(Message.values()).forEach((message) -> outputMap.put(message.getSection().getPath(), - outputMap.getOrDefault(message.getSection().getPath(), "") + message.getFileString())); + Arrays.stream(MessageSection.values()).sorted(new CompareMessageSections()).forEach((section) -> outputMap.put(section.getPath().toLowerCase().replace("_", "-"), section.getFileString())); + Arrays.stream(Message.values()).forEach((message) -> outputMap.put(message.getSection().getPath().toLowerCase().replace("_", "-"), + outputMap.getOrDefault(message.getSection().getPath().toLowerCase().replace("_", "-"), "") + message.getFileString())); break; } @@ -213,9 +213,10 @@ public void save() { } private boolean addKeyValue(String node, Object value) { + node = node.toLowerCase().replace("_", "-"); if (value instanceof Map) { for (Map.Entry entry : ((Map) value).entrySet()) { - String newNode = node + "." + entry.getKey().toString(); + String newNode = node + "." + entry.getKey().toString().toLowerCase().replace("_", "-"); if (config.get(newNode) == null || (config.get(newNode) != null && config.get(newNode).toString().isEmpty())) { config.set(newNode, entry.getValue().toString()); return true; 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 3b6d5c0c..3b39c1c7 100644 --- a/src/main/java/org/shanerx/tradeshop/data/config/Setting.java +++ b/src/main/java/org/shanerx/tradeshop/data/config/Setting.java @@ -279,15 +279,15 @@ public Object getDefaultValue() { } public String getMappedString(String subKey) { - return PLUGIN.getSettingManager().getConfig().getConfigurationSection(getPath()).getString(subKey.replace("_", "-")); + return PLUGIN.getSettingManager().getConfig().getConfigurationSection(getPath()).getString(subKey.toLowerCase().replace("_", "-")); } public boolean getMappedBoolean(String subKey) { - return PLUGIN.getSettingManager().getConfig().getConfigurationSection(getPath()).getBoolean(subKey.replace("_", "-")); + return PLUGIN.getSettingManager().getConfig().getConfigurationSection(getPath()).getBoolean(subKey.toLowerCase().replace("_", "-")); } public Object getMappedObject(String subKey) { - return PLUGIN.getSettingManager().getConfig().getConfigurationSection(getPath()).get(subKey.replace("_", "-")); + return PLUGIN.getSettingManager().getConfig().getConfigurationSection(getPath()).get(subKey.toLowerCase().replace("_", "-")); } public String getPostComment() { diff --git a/src/main/java/org/shanerx/tradeshop/item/ShopItemStack.java b/src/main/java/org/shanerx/tradeshop/item/ShopItemStack.java index 83aa1052..c8e9b38f 100644 --- a/src/main/java/org/shanerx/tradeshop/item/ShopItemStack.java +++ b/src/main/java/org/shanerx/tradeshop/item/ShopItemStack.java @@ -28,6 +28,7 @@ import com.google.common.collect.Lists; import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import com.google.gson.annotations.SerializedName; import net.md_5.bungee.api.ChatColor; import org.apache.commons.lang.WordUtils; import org.bukkit.FireworkEffect; @@ -65,32 +66,30 @@ public class ShopItemStack implements Serializable, Cloneable { private String itemStackB64; + @SerializedName(value = "itemSettings", alternate = "shopSettings") private Map> itemSettings; public ShopItemStack(ItemStack itemStack) { - this.itemStack = itemStack; - itemSettings = new HashMap<>(); - buildMap(); - toBase64(); + this(itemStack, new HashMap<>()); } - public ShopItemStack(ItemStack itemStack, HashMap> settingMap) { + public ShopItemStack(ItemStack itemStack, HashMap> itemSettings) { this.itemStack = itemStack; - this.itemSettings = settingMap; + this.itemSettings = itemSettings; buildMap(); toBase64(); } public ShopItemStack(String itemStackB64) { - this.itemStackB64 = itemStackB64; - itemSettings = new HashMap<>(); - buildMap(); - fromBase64(); + this(itemStackB64, new HashMap<>()); } - public ShopItemStack(String itemStackB64, HashMap> settingMap) { + public ShopItemStack(String itemStackB64, HashMap> itemSettings) { this.itemStackB64 = itemStackB64; - this.itemSettings = settingMap; + this.itemSettings = new HashMap<>(); + + itemSettings.forEach((key, value) -> this.itemSettings.put(ShopItemStackSettingKeys.match(key), value)); + buildMap(); fromBase64(); } @@ -125,6 +124,10 @@ public Map> getItemSettings() { return itemSettings; } + public String serialize() { + return new Gson().toJson(this); + } + public static ShopItemStack deserialize(String serialized) { ShopItemStack item = new Gson().fromJson(serialized, ShopItemStack.class); item.fromBase64(); @@ -555,10 +558,6 @@ public String getStateString(ObjectHolder stateSetting) { } } - public String serialize() { - return new Gson().toJson(this); - } - @Override public String toString() { return "ShopItemStack{" + @@ -613,5 +612,4 @@ private void fromBase64() { public String toConsoleText() { return new GsonBuilder().setPrettyPrinting().create().toJson(this); } - } \ 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 6f10f7fd..fb8fb88a 100644 --- a/src/main/java/org/shanerx/tradeshop/item/ShopItemStackSettingKeys.java +++ b/src/main/java/org/shanerx/tradeshop/item/ShopItemStackSettingKeys.java @@ -97,4 +97,8 @@ public boolean isUserEditable() { public String getConfigName() { return name().toLowerCase().replace("_", "-"); } + + public static ShopItemStackSettingKeys match(String name) { + return valueOf(name.toUpperCase().replace("-", "_")); + } } diff --git a/src/main/java/org/shanerx/tradeshop/shop/Shop.java b/src/main/java/org/shanerx/tradeshop/shop/Shop.java index 2e7593bb..bdc1c9e8 100644 --- a/src/main/java/org/shanerx/tradeshop/shop/Shop.java +++ b/src/main/java/org/shanerx/tradeshop/shop/Shop.java @@ -27,7 +27,9 @@ import com.google.gson.Gson; import org.bukkit.Bukkit; +import org.bukkit.ChatColor; import org.bukkit.Location; +import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.BlockState; import org.bukkit.block.Container; @@ -52,6 +54,7 @@ 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.Set; @@ -271,7 +274,7 @@ public ShopLocation getInventoryLocationAsSL() { } /** - * Fixes values that cannot be serialized after loading + * Fixes values and objects after loading or creating a Shop */ public void fixAfterLoad() { if (utils == null) @@ -286,6 +289,9 @@ public void fixAfterLoad() { setShopSettings(); + fixSide(ShopItemSide.COST); + fixSide(ShopItemSide.PRODUCT); + if (getShopSign() != null) updateSign(); } @@ -415,36 +421,17 @@ private String[] updateSignLines(String defaultColour) { if (product.isEmpty()) { signLines[1] = ""; } else if (product.size() == 1) { - StringBuilder sb = new StringBuilder(); - - ShopItemStack item = product.get(0); - - sb.append(item.getItemStack().getAmount()); - sb.append(" "); - - sb.append(item.getCleanItemName()); - - signLines[1] = utils.colorize(defaultColour + sb.substring(0, Math.min(sb.length(), 15))); - + signLines[1] = itemLineFormatter(defaultColour, String.valueOf(product.get(0).getItemStack().getAmount()), " ", product.get(0).getCleanItemName()); } else { - signLines[1] = utils.colorize(defaultColour + Setting.MULTIPLE_ITEMS_ON_SIGN.getString().replace("%amount%", "")); - } + signLines[1] = itemLineFormatter(defaultColour, Setting.MULTIPLE_ITEMS_ON_SIGN.getString().replace("%amount%", "")); + } if (cost.isEmpty()) { signLines[2] = ""; } else if (cost.size() == 1) { - StringBuilder sb = new StringBuilder(); - - ShopItemStack item = cost.get(0); - - sb.append(item.getItemStack().getAmount()); - sb.append(" "); - - sb.append(item.getCleanItemName()); - - signLines[2] = utils.colorize(defaultColour + sb.substring(0, Math.min(sb.length(), 15))); + signLines[2] = itemLineFormatter(defaultColour, String.valueOf(cost.get(0).getItemStack().getAmount()), " ", cost.get(0).getCleanItemName()); } else { - signLines[2] = utils.colorize(defaultColour + Setting.MULTIPLE_ITEMS_ON_SIGN.getString()); + signLines[2] = itemLineFormatter(defaultColour, Setting.MULTIPLE_ITEMS_ON_SIGN.getString().replace("%amount%", "")); } updateStatus(); @@ -459,6 +446,18 @@ private String[] updateSignLines(String defaultColour) { return signLines; } + private String itemLineFormatter(String defaultColour, String... strings) { + StringBuilder sb = new StringBuilder(); + + for (String s : strings) { + sb.append(s); + } + + String colorFix = ChatColor.stripColor(utils.colorize(sb.toString())); + + return utils.colorize(defaultColour + colorFix.substring(0, Math.min(colorFix.length(), 15))); + } + /** * Returns the shops inventory as a BlockState * @@ -955,6 +954,34 @@ private void purgeFromUserFiles() { //region Item Management - Methods for adding/deleting/updating/viewing Cost and Product lists //------------------------------------------------------------------------------------------------------------------ + /** + * Checks if shop has a bade side and fixes if necessary + */ + public void fixSide(ShopItemSide side) { + List ogItems = (side.equals(ShopItemSide.PRODUCT) ? product : cost); + + Set matSet = new HashSet<>(); + + ogItems.forEach((item) -> matSet.add(item.getItemStack().getType())); + + + if (ogItems.size() > 1 && ogItems.size() != matSet.size()) { + List scrapList = new ArrayList<>(ogItems); + (side.equals(ShopItemSide.PRODUCT) ? product : cost).clear(); + + ogItems.forEach((item) -> { + while (scrapList.contains(item)) { + addSideItem(side, item); + scrapList.remove(scrapList.lastIndexOf(item)); + } + }); + + updateFullTradeCount(); + updateSign(); + saveShop(); + } + } + /** * Checks if shop has items on specified side * @@ -1065,42 +1092,24 @@ public void setSideItems(ShopItemSide side, ItemStack newItem) { addSideItem(side, newItem); } - /** - * Attempts to fix the side of the trade in cases where an error was found. - * - * @param side Side of the trade to fix - */ - public void fixSide(ShopItemSide side) { - getSide(side).clear(); - try { - getSideItemStacks(side).forEach((item) -> { - if (item != null) addSideItem(side, item); - }); - } catch (NullPointerException ignored) { - getSide(side).clear(); - } - } - /** * Adds more items to the specified side * - * @param side Side to add items to - * @param newItem ItemStack to be added + * @param side Side to add items to + * @param newShopItem ShopItemStack to be added */ - public void addSideItem(ShopItemSide side, ItemStack newItem) { - if (utils.isIllegal(side, newItem.getType())) + public void addSideItem(ShopItemSide side, ShopItemStack newShopItem) { + if (utils.isIllegal(side, newShopItem.getItemStack().getType())) return; - ///* Added stacks are not separated and are added ontop of existing similar stacks - ShopItemStack toAddShopItemStack = new ShopItemStack(newItem); int toRemoveShopItemStack = -1; for (int i = 0; i < getSide(side).size(); i++) { - if (getSideList(side).get(i).getItemStack().getType().equals(newItem.getType()) && getSideList(side).get(i).isSimilar(newItem)) { + if (getSideList(side).get(i).getItemStack().getType().equals(newShopItem.getItemStack().getType()) && getSideList(side).get(i).isSimilar(newShopItem.getItemStack())) { toRemoveShopItemStack = i; - toAddShopItemStack = getSideList(side).get(i).clone(); - toAddShopItemStack.setAmount(getSideList(side).get(i).getAmount() + newItem.getAmount()); + newShopItem = getSideList(side).get(i).clone(); + newShopItem.setAmount(getSideList(side).get(i).getAmount() + newShopItem.getItemStack().getAmount()); break; } } @@ -1108,7 +1117,7 @@ public void addSideItem(ShopItemSide side, ItemStack newItem) { if (toRemoveShopItemStack > -1) getSide(side).remove(toRemoveShopItemStack); - getSide(side).add(toAddShopItemStack); + getSide(side).add(newShopItem); //*/ @@ -1119,11 +1128,21 @@ public void addSideItem(ShopItemSide side, ItemStack newItem) { updateSign(); } + /** + * Adds more items to the specified side + * + * @param side Side to add items to + * @param newItem ItemStack to be added + */ + public void addSideItem(ShopItemSide side, ItemStack newItem) { + addSideItem(side, new ShopItemStack(newItem)); + } + /** * Checks if the shop has sufficient stock to make a trade on specified side */ public boolean hasSideStock(ShopItemSide side) { - return !shopType.isITrade() && hasSide(side) && getChestAsSC() != null && getChestAsSC().hasStock(side, getSideList(side)); + return !shopType.isITrade() && hasSide(side) && getChestAsSC() != null && getChestAsSC().hasStock(getSideList(side)); } /** diff --git a/src/main/java/org/shanerx/tradeshop/shop/ShopChest.java b/src/main/java/org/shanerx/tradeshop/shop/ShopChest.java index 6c727fca..45a8bed4 100644 --- a/src/main/java/org/shanerx/tradeshop/shop/ShopChest.java +++ b/src/main/java/org/shanerx/tradeshop/shop/ShopChest.java @@ -39,7 +39,6 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.persistence.PersistentDataType; import org.shanerx.tradeshop.TradeShop; -import org.shanerx.tradeshop.item.ShopItemSide; import org.shanerx.tradeshop.item.ShopItemStack; import org.shanerx.tradeshop.shoplocation.IllegalWorldException; import org.shanerx.tradeshop.shoplocation.ShopLocation; @@ -209,13 +208,8 @@ public Inventory getInventory() { return null; } - public boolean hasStock(ShopItemSide side, List itemToCheck) { - List result = getItems(getInventory().getStorageContents(), itemToCheck, 1); - if (result.get(0) == null && result.size() == 1) { - getShop().fixSide(side); - } - - return itemToCheck.size() > 0 && result.get(0) != null; + public boolean hasStock(List itemToCheck) { + return itemToCheck.size() > 0 && getItems(getInventory().getStorageContents(), itemToCheck, 1).get(0) != null; } public void loadFromName() { 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 106f73be..00f6ab02 100644 --- a/src/main/java/org/shanerx/tradeshop/shop/listeners/ShopTradeListener.java +++ b/src/main/java/org/shanerx/tradeshop/shop/listeners/ShopTradeListener.java @@ -53,6 +53,7 @@ import org.shanerx.tradeshop.shop.ShopType; import org.shanerx.tradeshop.shoplocation.ShopLocation; import org.shanerx.tradeshop.utils.Utils; +import org.shanerx.tradeshop.utils.debug.DebugLevels; import org.shanerx.tradeshop.utils.objects.Tuple; import java.util.Collections; @@ -159,6 +160,7 @@ public void onBlockInteract(PlayerInteractEvent e) { Tuple> canExchangeResult = canExchangeAll(shop, buyer.getInventory(), multiplier, e.getAction()); + PLUGIN.getDebugger().log("ExchangeResult " + canExchangeResult.getLeft(), DebugLevels.DATA_ERROR); switch (canExchangeResult.getLeft()) { case SHOP_NO_PRODUCT: Message.SHOP_INSUFFICIENT_ITEMS.sendItemMultiLineMessage(buyer, Collections.singletonMap(Variable.MISSING_ITEMS, canExchangeResult.getRight())); @@ -188,6 +190,8 @@ public void onBlockInteract(PlayerInteractEvent e) { tradedItems.put(Variable.GIVEN_LINES, tradeReturn.getRight()); tradedItems.put(Variable.RECEIVED_LINES, tradeReturn.getLeft()); + PLUGIN.getDebugger().log("ShopTradeListener > tradedItems: " + tradedItems, DebugLevels.TRADE); + if (tradeReturn.getLeft().get(0) == null && tradeReturn.getRight().get(0) == null) { Message.FAILED_TRADE.sendMessage(buyer); @@ -227,6 +231,7 @@ private Tuple, List> tradeAllItems(Shop shop, int mul if (costItems.get(0) == null) { ItemStack item = costItems.get(1); Message.INSUFFICIENT_ITEMS.sendItemMultiLineMessage(buyer, Collections.singletonMap(Variable.MISSING_ITEMS, costItems)); + PLUGIN.getDebugger().log("tradeAllItems", DebugLevels.DATA_ERROR); return new Tuple<>(productItems, costItems); } } else { @@ -253,30 +258,36 @@ private Tuple, List> tradeAllItems(Shop shop, int mul return new Tuple<>(productItems, costItems); // Failed Trade } + PLUGIN.getDebugger().log("ShopTradeListener > tradeAll > preMove-productItems: " + productItems, DebugLevels.TRADE); + PLUGIN.getDebugger().log("ShopTradeListener > tradeAll > preMove-costItems: " + costItems, DebugLevels.TRADE); + if (useCost) { //For loop to remove cost items from player inventory for (ItemStack item : costItems) { - playerInventory.removeItem(item); + playerInventory.removeItem(item.clone()); } } //For loop to remove product items from shop inventory for (ItemStack item : productItems) { - shopInventory.removeItem(item); + shopInventory.removeItem(item.clone()); } if (useCost) { //For loop to put cost items in shop inventory for (ItemStack item : costItems) { - shopInventory.addItem(item); + addItemToInventory(shopInventory, item.clone()); } } //For loop to put product items in player inventory for (ItemStack item : productItems) { - playerInventory.addItem(item); + addItemToInventory(playerInventory, item.clone()); } + PLUGIN.getDebugger().log("ShopTradeListener > tradeAll > end-productItems: " + productItems, DebugLevels.TRADE); + PLUGIN.getDebugger().log("ShopTradeListener > tradeAll > end-costItems: " + costItems, DebugLevels.TRADE); + Bukkit.getPluginManager().callEvent(new PlayerSuccessfulTradeEvent(buyer, costItems, productItems, shop, event.getClickedBlock(), event.getBlockFace())); PLUGIN.getMetricsManager().addTrade(); diff --git a/src/main/java/org/shanerx/tradeshop/utils/Utils.java b/src/main/java/org/shanerx/tradeshop/utils/Utils.java index 4d937dfb..c9a3600c 100644 --- a/src/main/java/org/shanerx/tradeshop/utils/Utils.java +++ b/src/main/java/org/shanerx/tradeshop/utils/Utils.java @@ -415,7 +415,7 @@ public Tuple> canExchangeAll(Shop shop, Inventor if (costItems.size() > 0) { //For loop to put cost items in shop inventory for (ItemStack item : costItems) { - if (!shopInventory.addItem(item).isEmpty()) { + if (!addItemToInventory(shopInventory, item).isEmpty()) { return new Tuple<>(ExchangeStatus.SHOP_NO_SPACE, createBadList()); } } @@ -423,7 +423,7 @@ public Tuple> canExchangeAll(Shop shop, Inventor //For loop to put product items in player inventory for (ItemStack item : productItems) { - if (!playerInventory.addItem(item).isEmpty()) { + if (!addItemToInventory(playerInventory, item).isEmpty()) { return new Tuple<>(ExchangeStatus.PLAYER_NO_SPACE, createBadList()); } } @@ -591,16 +591,12 @@ public List getItems(ItemStack[] storageContents, List for (ItemStack storageItem : storage.keySet()) { if (item.isSimilar(storageItem)) { int taken; - try { - taken = megaMin(storage.get(storageItem), count, storageItem.getMaxStackSize()); + taken = megaMin(storage.get(storageItem), count); - if (found.putIfAbsent(item.getItemStack(), taken) != null) - found.put(item.getItemStack(), storage.get(storageItem) + taken); + if (found.putIfAbsent(item.getItemStack(), taken) != null) + found.put(item.getItemStack(), storage.get(storageItem) + taken); - storage.put(storageItem, storage.get(storageItem) - taken); - } catch (NullPointerException ignored) { - return createBadList(); - } + storage.put(storageItem, storage.get(storageItem) - taken); ItemStack goodItem = storageItem; goodItem.setAmount(taken); @@ -627,11 +623,25 @@ public List getItems(ItemStack[] storageContents, List return currentCount != totalCount ? bad : good; } + /** + * Attempts to add an ItemStack to an Inventory while splitting it with its max stack size as a maximum + * + * @param inv Inventory to attempt to add the ItemStack to + * @param item ItemStack to be added to the ivnentory + * @return smallest integer + */ + public Map addItemToInventory(Inventory inv, ItemStack item) { + int maxStack = inv.getMaxStackSize(); + inv.setMaxStackSize(item.getMaxStackSize()); + Map result = inv.addItem(item); + inv.setMaxStackSize(maxStack); + return result; + } + /** * Returns the smallest integer passed to it * * @param values list of integers to compare against each other - * * @return smallest integer */ public int megaMin(int... values) { 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 95a01c69..cc695d02 100644 --- a/src/main/java/org/shanerx/tradeshop/utils/objects/ObjectHolder.java +++ b/src/main/java/org/shanerx/tradeshop/utils/objects/ObjectHolder.java @@ -25,8 +25,11 @@ package org.shanerx.tradeshop.utils.objects; +import com.google.gson.annotations.SerializedName; + public class ObjectHolder { + @SerializedName(value = "value", alternate = "obj") private final Type obj; public ObjectHolder(Type obj) {