+ * Note: This will completely override current item's {@link ItemMeta}.
+ * If you still want to keep the original item's NBT tags, see
+ * {@link #mergeNBT(ItemStack)} and {@link #mergeCustomNBT(ItemStack)}.
+ *
+ * @param item ItemStack that should get the new NBT data
+ */
+ public void applyNBT(ItemStack item) {
+ if (item == null || item.getType() == Material.AIR) {
+ throw new NullPointerException("ItemStack can't be null/Air!");
+ }
+ NBTItem nbti = new NBTItem(new ItemStack(item.getType()));
+ nbti.mergeCompound(this);
+ item.setItemMeta(nbti.getItem().getItemMeta());
+ }
+
+ /**
+ * Merge all NBT tags to the provided ItemStack.
+ *
+ * @param item ItemStack that should get the new NBT data
+ */
+ public void mergeNBT(ItemStack item) {
+ NBTItem nbti = new NBTItem(item);
+ nbti.mergeCompound(this);
+ item.setItemMeta(nbti.getItem().getItemMeta());
+ }
+
+ /**
+ * Merge only custom (non-vanilla) NBT tags to the provided ItemStack.
+ *
+ * @param item ItemStack that should get the new NBT data
+ */
+ public void mergeCustomNBT(ItemStack item) {
+ if (item == null || item.getType() == Material.AIR) {
+ throw new NullPointerException("ItemStack can't be null/Air!");
+ }
+ ItemMeta meta = item.getItemMeta();
+ NBTReflectionUtil.getUnhandledNBTTags(meta).putAll(NBTReflectionUtil.getUnhandledNBTTags(bukkitItem.getItemMeta()));
+ item.setItemMeta(meta);
+ }
+
+
+ /**
+ * True, if the item has any tags now known for this item type.
+ *
+ * @return true when custom tags are present
+ */
+ public boolean hasCustomNbtData() {
+ ItemMeta meta = bukkitItem.getItemMeta();
+ return !NBTReflectionUtil.getUnhandledNBTTags(meta).isEmpty();
+ }
+
+ /**
+ * Remove all custom (non-vanilla) NBT tags from the NBTItem.
+ */
+ public void clearCustomNBT() {
+ ItemMeta meta = bukkitItem.getItemMeta();
+ NBTReflectionUtil.getUnhandledNBTTags(meta).clear();
+ bukkitItem.setItemMeta(meta);
+ }
+
+ /**
+ * @return The modified ItemStack
+ */
+ public ItemStack getItem() {
+ return bukkitItem;
+ }
+
+ protected void setItem(ItemStack item) {
+ bukkitItem = item;
+ }
+
+ /**
+ * This may return true even when the NBT is empty.
+ *
+ * @return Does the ItemStack have a NBTCompound.
+ */
+ public boolean hasNBTData() {
+ return getCompound() != null;
+ }
+
+ /**
+ * Helper method that converts {@link ItemStack} to {@link NBTContainer} with
+ * all it's data like Material, Damage, Amount and Tags.
+ *
+ * @param item
+ * @return Standalone {@link NBTContainer} with the Item's data
+ */
+ public static NBTContainer convertItemtoNBT(ItemStack item) {
+ return NBTReflectionUtil.convertNMSItemtoNBTCompound(ReflectionMethod.ITEMSTACK_NMSCOPY.run(null, item));
+ }
+
+ /**
+ * Helper method to do the inverse to "convertItemtoNBT". Creates an
+ * {@link ItemStack} using the {@link NBTCompound}
+ *
+ * @param comp
+ * @return ItemStack using the {@link NBTCompound}'s data
+ */
+ public static ItemStack convertNBTtoItem(NBTCompound comp) {
+ return (ItemStack) ReflectionMethod.ITEMSTACK_BUKKITMIRROR.run(null,
+ NBTReflectionUtil.convertNBTCompoundtoNMSItem(comp));
+ }
+
+ @Override
+ protected void saveCompound() {
+ if(directApply) {
+ applyNBT(originalSrcStack);
+ }
+ }
+
+}
diff --git a/src/com/pretzel/dev/villagertradelimiter/nms/NBTList.java b/src/com/pretzel/dev/villagertradelimiter/nms/NBTList.java
new file mode 100644
index 0000000..cf6294a
--- /dev/null
+++ b/src/com/pretzel/dev/villagertradelimiter/nms/NBTList.java
@@ -0,0 +1,429 @@
+package com.pretzel.dev.villagertradelimiter.nms;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.NoSuchElementException;
+
+import com.pretzel.dev.villagertradelimiter.nms.utils.MinecraftVersion;
+import com.pretzel.dev.villagertradelimiter.nms.utils.nmsmappings.ReflectionMethod;
+
+/**
+ * Abstract List implementation for ListCompounds
+ *
+ * @author tr7zw
+ *
+ * @param