From 70589a6263d1e616d47ca7147e6a528ead8d01b5 Mon Sep 17 00:00:00 2001 From: "Kristian S. Stangeland" Date: Mon, 7 Jan 2013 23:39:16 +0100 Subject: [PATCH] Added the ability to read NBT ItemStack tags. --- .../protocol/wrappers/nbt/NbtCompound.java | 133 +++++++++++++++++- .../protocol/wrappers/nbt/NbtFactory.java | 69 +++++++++ .../protocol/wrappers/nbt/NbtList.java | 1 + 3 files changed, 197 insertions(+), 6 deletions(-) diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/nbt/NbtCompound.java b/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/nbt/NbtCompound.java index 3481cee8..e59110d4 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/nbt/NbtCompound.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/nbt/NbtCompound.java @@ -72,6 +72,15 @@ public class NbtCompound implements NbtWrapper>>, Iterabl container.setName(name); } + /** + * Determine if an entry with the given key exists or not. + * @param key - the key to lookup. + * @return TRUE if an entry with the given key exists, FALSE otherwise. + */ + public boolean containsKey(String key) { + return getValue().containsKey(key); + } + /** * Retrieve a Set view of the keys of each entry in this compound. * @return The keys of each entry. @@ -118,17 +127,36 @@ public class NbtCompound implements NbtWrapper>>, Iterabl /** * Retrieve the value of a given entry. * @param key - key of the entry to retrieve. - * @return The value of this entry. + * @return The value of this entry, or NULL if not found. */ @SuppressWarnings("unchecked") public NbtBase getValue(String key) { return (NbtBase) getValue().get(key); } + /** + * Retrieve a value by its key, or assign and return a new NBT element if it doesn't exist. + * @param key - the key of the entry to find or create. + * @param type - the NBT element we will create if not found. + * @return The value that was retrieved or just created. + */ + public NbtBase getValueOrDefault(String key, NbtType type) { + NbtBase nbt = getValue(key); + + // Create or get a compound + if (nbt == null) + put(nbt = NbtFactory.ofType(type, key)); + else if (nbt.getType() != type) + throw new IllegalArgumentException("Cannot get tag " + nbt + ": Not a " + type); + + return nbt; + } + /** * Retrieve a value, or throw an exception. * @param key - the key to retrieve. * @return The value of the entry. + * @throws IllegalArgumentException If the key doesn't exist. */ private NbtBase getValueExact(String key) { NbtBase value = getValue(key); @@ -159,11 +187,21 @@ public class NbtCompound implements NbtWrapper>>, Iterabl * Retrieve the string value of an entry identified by a given key. * @param key - the key of the entry. * @return The string value of the entry. + * @throws IllegalArgumentException If the key doesn't exist. */ public String getString(String key) { return (String) getValueExact(key).getValue(); } + /** + * Retrieve the string value of an existing entry, or from a new default entry if it doesn't exist. + * @param key - the key of the entry. + * @return The value that was retrieved or just created. + */ + public String getStringOrDefault(String key) { + return (String) getValueOrDefault(key, NbtType.TAG_STRING).getValue(); + } + /** * Associate a NBT string value with the given key. * @param key - the key and NBT name. @@ -179,11 +217,21 @@ public class NbtCompound implements NbtWrapper>>, Iterabl * Retrieve the byte value of an entry identified by a given key. * @param key - the key of the entry. * @return The byte value of the entry. + * @throws IllegalArgumentException If the key doesn't exist. */ - public Byte getByte(String key) { + public byte getByte(String key) { return (Byte) getValueExact(key).getValue(); } + /** + * Retrieve the byte value of an existing entry, or from a new default entry if it doesn't exist. + * @param key - the key of the entry. + * @return The value that was retrieved or just created. + */ + public byte getByteOrDefault(String key) { + return (Byte) getValueOrDefault(key, NbtType.TAG_BYTE).getValue(); + } + /** * Associate a NBT byte value with the given key. * @param key - the key and NBT name. @@ -199,11 +247,21 @@ public class NbtCompound implements NbtWrapper>>, Iterabl * Retrieve the short value of an entry identified by a given key. * @param key - the key of the entry. * @return The short value of the entry. + * @throws IllegalArgumentException If the key doesn't exist. */ public Short getShort(String key) { return (Short) getValueExact(key).getValue(); } + /** + * Retrieve the short value of an existing entry, or from a new default entry if it doesn't exist. + * @param key - the key of the entry. + * @return The value that was retrieved or just created. + */ + public short getShortOrDefault(String key) { + return (Short) getValueOrDefault(key, NbtType.TAG_SHORT).getValue(); + } + /** * Associate a NBT short value with the given key. * @param key - the key and NBT name. @@ -219,11 +277,21 @@ public class NbtCompound implements NbtWrapper>>, Iterabl * Retrieve the integer value of an entry identified by a given key. * @param key - the key of the entry. * @return The integer value of the entry. + * @throws IllegalArgumentException If the key doesn't exist. */ - public Integer getInteger(String key) { + public int getInteger(String key) { return (Integer) getValueExact(key).getValue(); } + /** + * Retrieve the integer value of an existing entry, or from a new default entry if it doesn't exist. + * @param key - the key of the entry. + * @return The value that was retrieved or just created. + */ + public int getIntegerOrDefault(String key) { + return (Integer) getValueOrDefault(key, NbtType.TAG_INT).getValue(); + } + /** * Associate a NBT integer value with the given key. * @param key - the key and NBT name. @@ -239,11 +307,21 @@ public class NbtCompound implements NbtWrapper>>, Iterabl * Retrieve the long value of an entry identified by a given key. * @param key - the key of the entry. * @return The long value of the entry. + * @throws IllegalArgumentException If the key doesn't exist. */ - public Long getLong(String key) { + public long getLong(String key) { return (Long) getValueExact(key).getValue(); } + /** + * Retrieve the long value of an existing entry, or from a new default entry if it doesn't exist. + * @param key - the key of the entry. + * @return The value that was retrieved or just created. + */ + public long getLongOrDefault(String key) { + return (Long) getValueOrDefault(key, NbtType.TAG_LONG).getValue(); + } + /** * Associate a NBT long value with the given key. * @param key - the key and NBT name. @@ -259,11 +337,21 @@ public class NbtCompound implements NbtWrapper>>, Iterabl * Retrieve the float value of an entry identified by a given key. * @param key - the key of the entry. * @return The float value of the entry. + * @throws IllegalArgumentException If the key doesn't exist. */ - public Float getFloat(String key) { + public float getFloat(String key) { return (Float) getValueExact(key).getValue(); } + /** + * Retrieve the float value of an existing entry, or from a new default entry if it doesn't exist. + * @param key - the key of the entry. + * @return The value that was retrieved or just created. + */ + public float getFloatOrDefault(String key) { + return (Float) getValueOrDefault(key, NbtType.TAG_FLOAT).getValue(); + } + /** * Associate a NBT float value with the given key. * @param key - the key and NBT name. @@ -279,11 +367,21 @@ public class NbtCompound implements NbtWrapper>>, Iterabl * Retrieve the double value of an entry identified by a given key. * @param key - the key of the entry. * @return The double value of the entry. + * @throws IllegalArgumentException If the key doesn't exist. */ - public Double getDouble(String key) { + public double getDouble(String key) { return (Double) getValueExact(key).getValue(); } + /** + * Retrieve the double value of an existing entry, or from a new default entry if it doesn't exist. + * @param key - the key of the entry. + * @return The value that was retrieved or just created. + */ + public double getDoubleOrDefault(String key) { + return (Double) getValueOrDefault(key, NbtType.TAG_DOUBlE).getValue(); + } + /** * Associate a NBT double value with the given key. * @param key - the key and NBT name. @@ -299,6 +397,7 @@ public class NbtCompound implements NbtWrapper>>, Iterabl * Retrieve the byte array value of an entry identified by a given key. * @param key - the key of the entry. * @return The byte array value of the entry. + * @throws IllegalArgumentException If the key doesn't exist. */ public byte[] getByteArray(String key) { return (byte[]) getValueExact(key).getValue(); @@ -319,6 +418,7 @@ public class NbtCompound implements NbtWrapper>>, Iterabl * Retrieve the integer array value of an entry identified by a given key. * @param key - the key of the entry. * @return The integer array value of the entry. + * @throws IllegalArgumentException If the key doesn't exist. */ public int[] getIntegerArray(String key) { return (int[]) getValueExact(key).getValue(); @@ -339,12 +439,22 @@ public class NbtCompound implements NbtWrapper>>, Iterabl * Retrieve the compound (map) value of an entry identified by a given key. * @param key - the key of the entry. * @return The compound value of the entry. + * @throws IllegalArgumentException If the key doesn't exist. */ @SuppressWarnings("rawtypes") public NbtCompound getCompound(String key) { return (NbtCompound) ((NbtBase) getValueExact(key)); } + /** + * Retrieve a compound (map) value by its key, or create a new compound if it doesn't exist. + * @param key - the key of the entry to find or create. + * @return The compound value that was retrieved or just created. + */ + public NbtCompound getCompoundOrDefault(String key) { + return (NbtCompound) getValueOrDefault(key, NbtType.TAG_COMPOUND); + } + /** * Associate a NBT compound with its name as key. * @param compound - the compound value. @@ -359,12 +469,23 @@ public class NbtCompound implements NbtWrapper>>, Iterabl * Retrieve the NBT list value of an entry identified by a given key. * @param key - the key of the entry. * @return The NBT list value of the entry. + * @throws IllegalArgumentException If the key doesn't exist. */ @SuppressWarnings({"unchecked", "rawtypes"}) public NbtList getList(String key) { return (NbtList) getValueExact(key); } + /** + * Retrieve a NBT list value by its key, or create a new list if it doesn't exist. + * @param key - the key of the entry to find or create. + * @return The compound value that was retrieved or just created. + */ + @SuppressWarnings("unchecked") + public NbtList getListOrDefault(String key) { + return (NbtList) getValueOrDefault(key, NbtType.TAG_LIST); + } + /** * Associate a NBT list with the given key. * @param list - the list value. diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/nbt/NbtFactory.java b/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/nbt/NbtFactory.java index cbf66f62..0223c011 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/nbt/NbtFactory.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/nbt/NbtFactory.java @@ -7,9 +7,13 @@ import java.util.Collection; import java.util.List; import java.util.Map; +import org.bukkit.inventory.ItemStack; + import com.comphenix.protocol.reflect.FieldAccessException; import com.comphenix.protocol.reflect.FuzzyReflection; +import com.comphenix.protocol.reflect.StructureModifier; import com.comphenix.protocol.utility.MinecraftReflection; +import com.comphenix.protocol.wrappers.BukkitConverters; /** * Factory methods for creating NBT elements, lists and compounds. @@ -24,6 +28,39 @@ public class NbtFactory { private static Method methodWrite; private static Method methodLoad; + // Item stack trickery + private static StructureModifier itemStackModifier; + + /** + * Attempt to cast this wrapper as a compund. + * @return This instance as a compound. + * @throws UnsupportedOperationException If this is not a compound. + */ + public static NbtCompound asCompound(NbtWrapper wrapper) { + if (wrapper instanceof NbtCompound) + return (NbtCompound) wrapper; + else if (wrapper != null) + throw new UnsupportedOperationException( + "Cannot cast a " + wrapper.getClass() + "( " + wrapper.getType() + ") to TAG_COMPUND."); + else + throw new IllegalArgumentException("Wrapper cannot be NULL."); + } + + /** + * Attempt to cast this wrapper as a list. + * @return This instance as a list. + * @throws UnsupportedOperationException If this is not a list. + */ + public static NbtList asList(NbtWrapper wrapper) { + if (wrapper instanceof NbtList) + return (NbtList) wrapper; + else if (wrapper != null) + throw new UnsupportedOperationException( + "Cannot cast a " + wrapper.getClass() + "( " + wrapper.getType() + ") to TAG_LIST."); + else + throw new IllegalArgumentException("Wrapper cannot be NULL."); + } + /** * Get a NBT wrapper from a NBT base. * @param base - the base class. @@ -62,7 +99,39 @@ public class NbtFactory { } } } + + /** + * Construct a wrapper for an NBT tag stored (in memory) in an item stack. + *

+ * The item stack must be a wrapper for a CraftItemStack. Use + * {@link MinecraftReflection#getBukkitItemStack(ItemStack)} if not. + * @param stack - the item stack. + * @return A wrapper for its NBT tag. + */ + public static NbtWrapper fromItemStack(ItemStack stack) { + if (!MinecraftReflection.isCraftItemStack(stack)) + throw new IllegalArgumentException("Stack must be a CraftItemStack."); + Object nmsStack = MinecraftReflection.getMinecraftItemStack(stack); + + if (itemStackModifier == null) { + itemStackModifier = new StructureModifier(nmsStack.getClass(), Object.class, false); + } + + // Use the first and best NBT tag + StructureModifier> modifier = itemStackModifier. + withTarget(nmsStack). + withType(MinecraftReflection.getNBTBaseClass(), BukkitConverters.getNbtConverter()); + NbtWrapper result = modifier.read(0); + + // Create the tag if it doesn't exist + if (result == null) { + result = NbtFactory.ofCompound("tag"); + modifier.write(0, result); + } + return result; + } + /** * Initialize a NBT wrapper. * @param handle - the underlying net.minecraft.server object to wrap. diff --git a/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/nbt/NbtList.java b/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/nbt/NbtList.java index ac1c0946..f3162187 100644 --- a/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/nbt/NbtList.java +++ b/ProtocolLib/src/main/java/com/comphenix/protocol/wrappers/nbt/NbtList.java @@ -300,6 +300,7 @@ public class NbtList implements NbtWrapper>>, Iterabl @Override public String toString() { + // Essentially JSON StringBuilder builder = new StringBuilder(); builder.append("{\"name\": \"" + getName() + "\", \"value\": [");