diff --git a/src/main/java/de/epiceric/shopchest/nms/ShulkerBoxMeta.java b/src/main/java/de/epiceric/shopchest/nms/ShulkerBoxMeta.java new file mode 100644 index 0000000..cb6b18e --- /dev/null +++ b/src/main/java/de/epiceric/shopchest/nms/ShulkerBoxMeta.java @@ -0,0 +1,106 @@ +package de.epiceric.shopchest.nms; + +import de.epiceric.shopchest.ShopChest; +import de.epiceric.shopchest.utils.Utils; +import org.bukkit.inventory.ItemStack; + +import java.lang.reflect.InvocationTargetException; +import java.util.HashMap; +import java.util.Map; + +public class ShulkerBoxMeta { + + public static Map getContents(ItemStack shulkerBox) { + try { + Class craftItemStackClass = Utils.getCraftClass("inventory.CraftItemStack"); + + if (craftItemStackClass == null) { + ShopChest.getInstance().debug("Failed to get NBTContents: Could not find CraftItemStack class"); + return null; + } + + Object nmsStack = craftItemStackClass.getMethod("asNMSCopy", ItemStack.class).invoke(null, shulkerBox); + if (nmsStack == null) { + ShopChest.getInstance().debug("Failed to get NBTContents: asNMSCopy returned null"); + return null; + } + + Object hasTag = nmsStack.getClass().getMethod("hasTag").invoke(nmsStack); + if (hasTag == null || !(hasTag instanceof Boolean)) { + ShopChest.getInstance().debug("Failed to get NBTContents: hasTag returned null"); + return null; + } + + if (!(boolean) hasTag) { + ShopChest.getInstance().debug("Failed to get NBTContents: ItemStack has no tag"); + return null; + } + + Object nbtTagCompound = nmsStack.getClass().getMethod("getTag").invoke(nmsStack); + if (nbtTagCompound == null) { + ShopChest.getInstance().debug("Failed to get NBTContents: getTag returned null"); + return null; + } + + Object blockEntityTagObject = nbtTagCompound.getClass().getMethod("getCompound", String.class).invoke(nbtTagCompound, "BlockEntityTag"); + if (blockEntityTagObject == null) { + ShopChest.getInstance().debug("Failed to get NBTContents: getCompound returned null"); + return null; + } + + Object itemsObject = blockEntityTagObject.getClass().getMethod("getList", String.class, int.class).invoke(blockEntityTagObject, "Items", 10); + if (itemsObject == null) { + ShopChest.getInstance().debug("Failed to get NBTContents: getList returned null"); + return null; + } + + Object sizeObject = itemsObject.getClass().getMethod("size").invoke(itemsObject); + if (sizeObject == null) { + ShopChest.getInstance().debug("Failed to get NBTContents: size returned null or not an integer"); + return null; + } + + int size = (Integer) sizeObject; + + Map contentSlots = new HashMap<>(); + + for (int i = 0; i < size; i++) { + Object itemTag = itemsObject.getClass().getMethod("get", int.class).invoke(itemsObject, i); + if (itemTag == null) { + ShopChest.getInstance().debug("Failed to get NBTContents: get returned null"); + continue; + } + + Object nmsStack2 = nmsStack.getClass().getConstructor(nbtTagCompound.getClass()).newInstance(itemTag); + if (nmsStack2 == null) { + ShopChest.getInstance().debug("Failed to get NBTContents: Could not instantiate ItemStack with compound"); + continue; + } + + Object slotObject = itemTag.getClass().getMethod("getInt", String.class).invoke(itemTag, "Slot"); + if (slotObject == null || !(slotObject instanceof Integer)) { + ShopChest.getInstance().debug("Failed to get NBTContents: getInt returned null or not an integer"); + continue; + } + + Object itemStack = craftItemStackClass.getMethod("asBukkitCopy", nmsStack2.getClass()).invoke(null, nmsStack2); + if (itemStack == null || !(itemStack instanceof ItemStack)) { + ShopChest.getInstance().debug("Failed to get NBTContents: asBukkitCopy returned null or not an ItemStack"); + continue; + } + + contentSlots.put((Integer) slotObject, (ItemStack) itemStack); + } + + return contentSlots; + + } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | InstantiationException e) { + ShopChest.getInstance().getLogger().severe("Failed to get NBTContents with reflection"); + ShopChest.getInstance().debug("Failed to get NBTContents with reflection"); + ShopChest.getInstance().debug(e); + } + + return null; + } + +} diff --git a/src/main/java/de/epiceric/shopchest/utils/Utils.java b/src/main/java/de/epiceric/shopchest/utils/Utils.java index d351e0f..ccbfaf6 100644 --- a/src/main/java/de/epiceric/shopchest/utils/Utils.java +++ b/src/main/java/de/epiceric/shopchest/utils/Utils.java @@ -1,7 +1,9 @@ package de.epiceric.shopchest.utils; +import com.google.common.collect.ImmutableList; import de.epiceric.shopchest.ShopChest; import de.epiceric.shopchest.nms.CustomBookMeta; +import de.epiceric.shopchest.nms.ShulkerBoxMeta; import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.configuration.InvalidConfigurationException; @@ -19,9 +21,29 @@ import java.lang.reflect.InvocationTargetException; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.HashMap; +import java.util.Map; public class Utils { + private static final ImmutableList SHULKER_BOX_MATERIALS = new ImmutableList.Builder() + .add(Material.BLACK_SHULKER_BOX) + .add(Material.BLUE_SHULKER_BOX) + .add(Material.BROWN_SHULKER_BOX) + .add(Material.CYAN_SHULKER_BOX) + .add(Material.GRAY_SHULKER_BOX) + .add(Material.GREEN_SHULKER_BOX) + .add(Material.LIGHT_BLUE_SHULKER_BOX) + .add(Material.LIME_SHULKER_BOX) + .add(Material.MAGENTA_SHULKER_BOX) + .add(Material.ORANGE_SHULKER_BOX) + .add(Material.PINK_SHULKER_BOX) + .add(Material.PURPLE_SHULKER_BOX) + .add(Material.RED_SHULKER_BOX) + .add(Material.SILVER_SHULKER_BOX) + .add(Material.WHITE_SHULKER_BOX) + .add(Material.YELLOW_SHULKER_BOX) + .build(); + /** * Check if two items are similar to each other * @param itemStack1 The first item @@ -82,6 +104,13 @@ public class Utils { if (bsMeta1.hasBlockState()) similar &= (bsMeta1.getBlockState().equals(bsMeta2.getBlockState())); + if (getMajorVersion() >= 11 && SHULKER_BOX_MATERIALS.contains(itemStack1.getType())) { + Map contents1 = ShulkerBoxMeta.getContents(itemStack1); + Map contents2 = ShulkerBoxMeta.getContents(itemStack2); + + if (contents1 != null) similar &= contents1.equals(contents2); + } + } else if (itemMeta1 instanceof BookMeta) { BookMeta bookMeta1 = (BookMeta) itemMeta1; BookMeta bookMeta2 = (BookMeta) itemMeta2;