package org.shininet.bukkit.itemrenamer.meta; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import org.bukkit.Material; import org.bukkit.inventory.ItemStack; import org.shininet.bukkit.itemrenamer.utils.StackUtils; import com.comphenix.protocol.wrappers.nbt.NbtCompound; import com.comphenix.protocol.wrappers.nbt.NbtFactory; import com.comphenix.protocol.wrappers.nbt.io.NbtBinarySerializer; import com.google.common.base.Preconditions; public abstract class CompoundStore { public static final int PLUGIN_ID = 0x79fe4647; protected ItemStack stack; protected CompoundStore(ItemStack stack) { Preconditions.checkNotNull(stack, "stack cannot be NULL."); this.stack = StackUtils.getCraftItemStack(stack); } /** * Retrieve the item stack where the additional compound will be stored. * @return Item stack where the compound will be stored. */ public ItemStack getStack() { return stack; } /** * Save a given compound to the given item stack. * @param compound - the compound to save. * @return The current item stack. */ public abstract ItemStack saveCompound(NbtCompound compound); /** * Load the saved compound. * @return The saved compound, or NULL. */ public abstract NbtCompound loadCompound(); /** * Retrieve a compound store that saves and loads the compound directly in the NbtCompound tag. * @param stack - the ItemStack whose tag will be used to save and load NbtCompounds. * @param key - the compound key. * @return The compound store. */ public static CompoundStore getNativeStore(ItemStack stack, final String key) { return new CompoundStore(stack) { @Override public ItemStack saveCompound(NbtCompound compound) { getCompound(stack).put(key, compound); return stack; } @Override public NbtCompound loadCompound() { NbtCompound data = getCompound(stack); // Check for our marker if (data.containsKey(key)) { return data.getCompound(key); } else { return null; } } /** * Retrieve the NbtCompound that stores additional data in an ItemStack. * @param stack - the item stack. * @return The additional NbtCompound. */ private NbtCompound getCompound(ItemStack stack) { // It should have been a compound in the API ... return NbtFactory.asCompound(NbtFactory.fromItemTag(stack)); } }; } /** * Retrieve a compound store that saves and loads compounds from invisible data in the display name or lore. * @param stack - the item stack whose display name or lore will be used to load and save data. * @return The compound store. */ @Deprecated public static CompoundStore getItemMetaStore(ItemStack stack) { return new CompoundStore(stack) { // Unique for this kind of store private CharCodeStore encoder = (isNamingItem(stack) || stack.getItemMeta().hasLore()) ? CharCodeFactory.fromLore(PLUGIN_ID, stack) : CharCodeFactory.fromDisplayName(PLUGIN_ID, stack); private NbtBinarySerializer serializer = new NbtBinarySerializer(); @Override public ItemStack saveCompound(NbtCompound compound) { ByteArrayOutputStream store = new ByteArrayOutputStream(); serializer.serialize(compound, new DataOutputStream(store)); encoder.getData().setBytes(store.toByteArray()); encoder.save(); return stack; } @Override public NbtCompound loadCompound() { if (encoder.hasData()) { ByteArrayInputStream input = new ByteArrayInputStream(encoder.getData().getBytes()); // Retrieve the stored NbtCompound return serializer.deserializeCompound(new DataInputStream(input)); } return null; } }; } /** * Determine if the display name of the given item is used to set the name of a mob in any way. * <p> * This includes spawner eggs and naming tags. * @stack - the stack to check. * @return TRUE if it does, FALSE otherwise. */ private static boolean isNamingItem(ItemStack stack) { return stack.getType() == Material.MONSTER_EGG || stack.getType() == Material.MONSTER_EGGS || stack.getType() == Material.NAME_TAG; } }