package org.shininet.bukkit.itemrenamer; import java.util.EnumSet; import java.util.Set; import org.bukkit.Material; import org.bukkit.inventory.ItemStack; import org.shininet.bukkit.itemrenamer.utils.StackUtils; import com.comphenix.protocol.utility.MinecraftReflection; import com.comphenix.protocol.wrappers.nbt.NbtCompound; import com.comphenix.protocol.wrappers.nbt.NbtFactory; /** * Represents a serialization method for storing ItemStacks in compounds. * * @author Kristian * */ public class SerializeItemStack { /** * Represents the different fields that we may save. * @author Kristian */ public enum StackField { ID("id"), COUNT("count"), DAMAGE("damage"), TAG("tag"); /** * The NBT key for this particular field. */ private final String nbt; private StackField(String nbt) { this.nbt = nbt; } } // Which fields will be saved private Set<StackField> fields = EnumSet.allOf(StackField.class); /** * Save the given item stack as a NBT compound. * <p> * Only certain fields will be saved. * @param stack - the item stack. * @return The NBT compound. */ public NbtCompound save(ItemStack stack) { NbtCompound result = NbtFactory.ofCompound(""); NbtCompound data = getData(stack); if (fields.contains(StackField.ID)) result.put("id", (short) stack.getTypeId()); if (fields.contains(StackField.COUNT)) result.put("count", (byte) stack.getAmount()); if (fields.contains(StackField.DAMAGE)) result.put("damage", (short) stack.getDurability()); if (fields.contains(StackField.TAG) && data != null) { result.put("tag", data); } return result; } private NbtCompound getData(ItemStack stack) { if (stack.getType() != Material.AIR) { return (NbtCompound) NbtFactory.fromItemTag(StackUtils.getCraftItemStack(stack)); } return null; } /** * Load the given saved item stack. * @param savedStack - the saved item stack. * @return The item stack. */ public ItemStack load(NbtCompound savedStack) { ItemStack destination = MinecraftReflection.getBukkitItemStack(new ItemStack(Material.STONE)); loadInto(destination, savedStack, true); return destination; } /** * Load the given saved item stack into another stack. * <p> * Only certain fields will be loaded. * @param stack - the destination CraftItemStack. * @param savedStack - the saved item stack. */ public void loadInto(ItemStack stack, NbtCompound savedStack) { loadInto(stack, savedStack, false); } /** * Load the given saved item stack into another stack. * <p> * Only certain fields will be loaded. * @param stack - the destination CraftItemStack. * @param savedStack - the saved item stack. * @param ignoreMissing - whether or not to ignore missing keys. */ public void loadInto(ItemStack stack, NbtCompound savedStack, boolean ignoreMissing) { if (!MinecraftReflection.isCraftItemStack(stack)) throw new IllegalArgumentException("Stack must be a CraftItemStack, but was " + stack); if (loadKey(StackField.ID, savedStack, ignoreMissing)) stack.setTypeId(savedStack.getShort("id")); if (loadKey(StackField.COUNT, savedStack, ignoreMissing)) stack.setAmount(savedStack.getByte("count")); if (loadKey(StackField.DAMAGE, savedStack, ignoreMissing)) stack.setDurability(savedStack.getShort("damage")); if (fields.contains(StackField.TAG) && savedStack.containsKey("tag")) { NbtFactory.setItemTag(stack, savedStack.getCompound("tag")); } else { NbtFactory.setItemTag(stack, null); } } private boolean loadKey(StackField field, NbtCompound savedStack, boolean ignoreMissing) { if (fields.contains(field)) { if (ignoreMissing) return savedStack.containsKey(field.nbt); return true; } return false; } /** * Determine if the serializer is saving or loading a given field. * @param field - the field to save or load. * @return TRUE if it is, FALSE otherwise. */ public boolean hasField(StackField field) { return fields.contains(field); } /** * Add a given field for saving or loading. * @param field - the field to add. * @return TRUE if the field was added, FALSE otherwise. */ public boolean addField(StackField field) { return fields.add(field); } /** * Remove a given field from being saved or loaded. * @param field - the field. * @return TRUE if the field was removed, FALSE otherwise. */ public boolean removeField(StackField field) { return fields.remove(field); } }