diff --git a/src/main/java/com/Acrobot/Breeze/Utils/MaterialUtil.java b/src/main/java/com/Acrobot/Breeze/Utils/MaterialUtil.java index 427fda7e..4fe62d9c 100644 --- a/src/main/java/com/Acrobot/Breeze/Utils/MaterialUtil.java +++ b/src/main/java/com/Acrobot/Breeze/Utils/MaterialUtil.java @@ -11,17 +11,22 @@ import info.somethingodd.OddItem.OddItem; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Material; +import org.bukkit.configuration.file.YamlConstructor; +import org.bukkit.configuration.file.YamlRepresenter; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.meta.BookMeta; import org.bukkit.inventory.meta.Damageable; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.plugin.Plugin; import org.json.simple.JSONObject; +import org.yaml.snakeyaml.DumperOptions; +import org.yaml.snakeyaml.Yaml; +import org.yaml.snakeyaml.nodes.Tag; import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.Map; import java.util.logging.Level; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -49,6 +54,14 @@ public class MaterialUtil { private static final SimpleCache MATERIAL_CACHE = new SimpleCache<>(Properties.CACHE_SIZE); + private static final Yaml YAML = new Yaml(new YamlBukkitConstructor(), new YamlRepresenter(), new DumperOptions()); + + private static class YamlBukkitConstructor extends YamlConstructor { + public YamlBukkitConstructor() { + this.yamlConstructors.put(new Tag(Tag.PREFIX + "org.bukkit.inventory.ItemStack"), yamlConstructors.get(Tag.MAP)); + } + } + /** * Checks if the itemStack is empty or null * @@ -76,14 +89,33 @@ public class MaterialUtil { // Additional checks as serialisation and de-serialisation might lead to different item meta // This would only be done if the items share the same item meta type so it shouldn't be too inefficient - // Special check for books as their pages might change when serialising (See SPIGOT-3206) + // Special check for books as their pages might change when serialising (See SPIGOT-3206 and ChestShop#250) // Special check for explorer maps/every item with a localised name (See SPIGOT-4672) - return one.getType() == two.getType() - && one.getDurability() == two.getDurability() - && one.getData().equals(two.getData()) - && one.hasItemMeta() && two.hasItemMeta() - && one.getItemMeta().getClass() == two.getItemMeta().getClass() - && one.getItemMeta().serialize().equals(two.getItemMeta().serialize()); + if (one.getType() != two.getType() + || one.getDurability() != two.getDurability() + || !one.getData().equals(two.getData()) + || !(one.hasItemMeta() && two.hasItemMeta()) + || one.getItemMeta().getClass() != two.getItemMeta().getClass()) { + return false; + } + Map oneSerMeta = one.getItemMeta().serialize(); + Map twoSerMeta = two.getItemMeta().serialize(); + if (oneSerMeta.equals(twoSerMeta)) { + return true; + } + + // Try to use same parsing as the YAML dumper in the ItemDatabase when generating the code as the last resort + ItemStack oneDumped = YAML.loadAs(YAML.dump(one), ItemStack.class); + if (oneDumped.isSimilar(two) || oneDumped.getItemMeta().serialize().equals(twoSerMeta)) { + return true; + } + + ItemStack twoDumped = YAML.loadAs(YAML.dump(two), ItemStack.class); + if (oneDumped.isSimilar(twoDumped) || oneDumped.getItemMeta().serialize().equals(twoDumped.getItemMeta().serialize())) { + return true; + } + + return false; } /** diff --git a/src/main/java/com/Acrobot/ChestShop/Metadata/ItemDatabase.java b/src/main/java/com/Acrobot/ChestShop/Metadata/ItemDatabase.java index 6ad1c583..dadcba3b 100644 --- a/src/main/java/com/Acrobot/ChestShop/Metadata/ItemDatabase.java +++ b/src/main/java/com/Acrobot/ChestShop/Metadata/ItemDatabase.java @@ -139,20 +139,19 @@ public class ItemDatabase { clone.setAmount(1); clone.setDurability((short) 0); - String code = Base64.encodeObject(yaml.dump(clone)); - Item itemEntity = itemDao.queryBuilder().where().eq("code", code).queryForFirst(); - - if (itemEntity != null) { - return Base62.encode(itemEntity.getId()); + String dumped = yaml.dump(clone); + ItemStack loadedItem = yaml.loadAs(dumped, ItemStack.class); + if (!loadedItem.isSimilar(item)) { + dumped = yaml.dump(loadedItem); } + String code = Base64.encodeObject(dumped); - itemEntity = new Item(code); - - itemDao.create(itemEntity); - - int id = itemEntity.getId(); - - return Base62.encode(id); + Item itemEntity = itemDao.queryBuilder().where().eq("code", code).queryForFirst(); + if (itemEntity == null) { + itemEntity = new Item(code); + itemDao.create(itemEntity); + } + return Base62.encode(itemEntity.getId()); } catch (SQLException e) { e.printStackTrace(); } catch (IOException e) {