diff options
author | Bjarne Koll <LynxPlay101@gmail.com> | 2018-12-01 20:25:24 +1100 |
---|---|---|
committer | md_5 <git@md-5.net> | 2018-12-01 20:26:50 +1100 |
commit | e08005992786cff58eff69abd055a6e76499046e (patch) | |
tree | 296cb66c4bd38abd933c8ccd4ec8cb9cd4a2cb4d | |
parent | 0c1d258bb8185c39ce12c816a826973e94939b0e (diff) | |
download | bukkit-e08005992786cff58eff69abd055a6e76499046e.tar bukkit-e08005992786cff58eff69abd055a6e76499046e.tar.gz bukkit-e08005992786cff58eff69abd055a6e76499046e.tar.lz bukkit-e08005992786cff58eff69abd055a6e76499046e.tar.xz bukkit-e08005992786cff58eff69abd055a6e76499046e.zip |
SPIGOT-4347: Add API to allow storing arbitrary values on ItemStacks
4 files changed, 277 insertions, 0 deletions
diff --git a/src/main/java/org/bukkit/inventory/meta/ItemMeta.java b/src/main/java/org/bukkit/inventory/meta/ItemMeta.java index 031400b3..64b68b1a 100644 --- a/src/main/java/org/bukkit/inventory/meta/ItemMeta.java +++ b/src/main/java/org/bukkit/inventory/meta/ItemMeta.java @@ -12,6 +12,7 @@ import org.bukkit.configuration.serialization.ConfigurationSerializable; import org.bukkit.enchantments.Enchantment; import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemFlag; +import org.bukkit.inventory.meta.tags.CustomItemTagContainer; /** * This type represents the storage mechanism for auxiliary item data. @@ -314,6 +315,22 @@ public interface ItemMeta extends Cloneable, ConfigurationSerializable { */ boolean removeAttributeModifier(Attribute attribute, AttributeModifier modifier); + /** + * Returns a public custom tag container capable of storing tags on the + * item. + * + * Those tags will be sent to the client with all of their content, so the + * client is capable of reading them. This will result in the player seeing + * a NBT Tag notification on the item. + * + * These tags can also be modified by the client once in creative mode + * + * @return the custom tag container + * @deprecated draft API + */ + @Deprecated + CustomItemTagContainer getCustomTagContainer(); + @SuppressWarnings("javadoc") ItemMeta clone(); } diff --git a/src/main/java/org/bukkit/inventory/meta/tags/CustomItemTagContainer.java b/src/main/java/org/bukkit/inventory/meta/tags/CustomItemTagContainer.java new file mode 100644 index 00000000..f80dd85d --- /dev/null +++ b/src/main/java/org/bukkit/inventory/meta/tags/CustomItemTagContainer.java @@ -0,0 +1,102 @@ +package org.bukkit.inventory.meta.tags; + +import org.bukkit.NamespacedKey; +import org.bukkit.inventory.meta.ItemMeta; + +/** + * This interface represents a map like object, capable of storing custom tags + * in it. + */ +public interface CustomItemTagContainer { + + /** + * Stores a custom value on the {@link ItemMeta}. + * + * This API cannot be used to manipulate minecraft tags, as the values will + * be stored using your namespace. This method will override any existing + * value the meta may have stored under the provided key. + * + * @param key the key this value will be stored under + * @param type the type this item tag uses + * @param value the value stored in the tag + * @param <T> the generic java type of the tag value + * @param <Z> the generic type of the object to store + * @throws NullPointerException if the key is null + * @throws NullPointerException if the type is null + * @throws NullPointerException if the value is null. Removing a custom tag + * should be done using {@link #removeCustomTag(org.bukkit.NamespacedKey)} + * @throws IllegalArgumentException if no suitable adapter will be found for + * the {@link ItemTagType#getPrimitiveType()} + */ + <T, Z> void setCustomTag(NamespacedKey key, ItemTagType<T, Z> type, Z value); + + /** + * Returns if the item meta has a custom tag registered matching the + * provided parameters. + * + * This method will only return if the found value has the same primitive + * data type as the provided key. + * + * Storing a value using a custom {@link ItemTagType} implementation will + * not store the complex data type. Therefore storing a UUID (by storing a + * byte[]) will match hasCustomTag("key" , {@link ItemTagType#BYTE_ARRAY}). + * Likewise a stored byte[] will always match your UUID {@link ItemTagType} + * even if it is not 16 bytes long. + * + * This method is only usable for custom object keys. Overwriting existing + * tags, like the the display name, will not work as the values are stored + * using your namespace. + * + * @param key the key the value is stored under + * @param type the type which primitive storage type has to match the value + * @param <T> the generic type of the stored primitive + * @param <Z> the generic type of the eventually created complex object + * @return if a value + * @throws NullPointerException if the key to look up is null + * @throws NullPointerException if the type to cast the found object to is + * null + */ + <T, Z> boolean hasCustomTag(NamespacedKey key, ItemTagType<T, Z> type); + + /** + * Returns the custom tag's value that is stored on the item. + * + * @param key the key to look up in the custom tag map + * @param type the type the value must have and will be casted to + * @param <T> the generic type of the stored primitive + * @param <Z> the generic type of the eventually created complex object + * @return the value or {@code null} if no value was mapped under the given + * value + * @throws NullPointerException if the key to look up is null + * @throws NullPointerException if the type to cast the found object to is + * null + * @throws IllegalArgumentException if the value exists under the given key, + * but cannot be access using the given type + * @throws IllegalArgumentException if no suitable adapter will be found for + * the {@link ItemTagType#getPrimitiveType()} + */ + <T, Z> Z getCustomTag(NamespacedKey key, ItemTagType<T, Z> type); + + /** + * Removes a custom key from the item meta. + * + * @param key the key + * @throws NullPointerException if the provided key is null + */ + void removeCustomTag(NamespacedKey key); + + /** + * Returns if the container instance is empty, therefore has no entries + * inside it. + * + * @return the boolean + */ + boolean isEmpty(); + + /** + * Returns the adapter context this tag container uses. + * + * @return the tag context + */ + ItemTagAdapterContext getAdapterContext(); +} diff --git a/src/main/java/org/bukkit/inventory/meta/tags/ItemTagAdapterContext.java b/src/main/java/org/bukkit/inventory/meta/tags/ItemTagAdapterContext.java new file mode 100644 index 00000000..348fa65f --- /dev/null +++ b/src/main/java/org/bukkit/inventory/meta/tags/ItemTagAdapterContext.java @@ -0,0 +1,15 @@ +package org.bukkit.inventory.meta.tags; + +/** + * This interface represents the context in which the {@link ItemTagType} can + * serialize and deserialize the passed values. + */ +public interface ItemTagAdapterContext { + + /** + * Creates a new and empty tag container instance. + * + * @return the fresh container instance + */ + CustomItemTagContainer newTagContainer(); +} diff --git a/src/main/java/org/bukkit/inventory/meta/tags/ItemTagType.java b/src/main/java/org/bukkit/inventory/meta/tags/ItemTagType.java new file mode 100644 index 00000000..f8a09010 --- /dev/null +++ b/src/main/java/org/bukkit/inventory/meta/tags/ItemTagType.java @@ -0,0 +1,143 @@ +package org.bukkit.inventory.meta.tags; + +/** + * This class represents an enum with a generic content type. It defines the + * types a custom item tag can have. + * <p> + * This interface can be used to create your own custom {@link ItemTagType} with + * different complex types. This may be useful for the likes of a + * UUIDItemTagType: + * <pre> + * <code>{@code + * public class UUIDItemTagType implements ItemTagType<byte[], UUID> { + * + * {@literal @Override} + * public Class<byte[]> getPrimitiveType() { + * return byte[].class; + * } + * + * {@literal @Override} + * public Class<UUID> getComplexType() { + * return UUID.class; + * } + * + * {@literal @Override} + * public byte[] toPrimitive(UUID complex, ItemTagAdapterContext context) { + * ByteBuffer bb = ByteBuffer.wrap(new byte[16]); + * bb.putLong(complex.getMostSignificantBits()); + * bb.putLong(complex.getLeastSignificantBits()); + * return bb.array(); + * } + * + * {@literal @Override} + * public UUID fromPrimitive(byte[] primitive, ItemTagAdapterContext context) { + * ByteBuffer bb = ByteBuffer.wrap(primitive); + * long firstLong = bb.getLong(); + * long secondLong = bb.getLong(); + * return new UUID(firstLong, secondLong); + * } + * }}</code></pre> + * + * @param <T> the primary object type that is stored in the given tag + * @param <Z> the retrieved object type when applying this item tag type + */ +public interface ItemTagType<T, Z> { + + /* + The primitive one value types. + */ + ItemTagType<Byte, Byte> BYTE = new PrimitiveTagType<>(Byte.class); + ItemTagType<Short, Short> SHORT = new PrimitiveTagType<>(Short.class); + ItemTagType<Integer, Integer> INTEGER = new PrimitiveTagType<>(Integer.class); + ItemTagType<Long, Long> LONG = new PrimitiveTagType<>(Long.class); + ItemTagType<Float, Float> FLOAT = new PrimitiveTagType<>(Float.class); + ItemTagType<Double, Double> DOUBLE = new PrimitiveTagType<>(Double.class); + + /* + String. + */ + ItemTagType<String, String> STRING = new PrimitiveTagType<>(String.class); + + /* + Primitive Arrays. + */ + ItemTagType<byte[], byte[]> BYTE_ARRAY = new PrimitiveTagType<>(byte[].class); + ItemTagType<int[], int[]> INTEGER_ARRAY = new PrimitiveTagType<>(int[].class); + ItemTagType<long[], long[]> LONG_ARRAY = new PrimitiveTagType<>(long[].class); + + /* + Nested TagContainer. + */ + ItemTagType<CustomItemTagContainer, CustomItemTagContainer> TAG_CONTAINER = new PrimitiveTagType<>(CustomItemTagContainer.class); + + /** + * Returns the primitive data type of this tag. + * + * @return the class + */ + Class<T> getPrimitiveType(); + + /** + * Returns the complex object type the primitive value resembles. + * + * @return the class type + */ + Class<Z> getComplexType(); + + /** + * Returns the primitive data that resembles the complex object passed to + * this method. + * + * @param complex the complex object instance + * @param context the context this operation is running in + * @return the primitive value + */ + T toPrimitive(Z complex, ItemTagAdapterContext context); + + /** + * Creates a complex object based of the passed primitive value + * + * @param primitive the primitive value + * @param context the context this operation is running in + * @return the complex object instance + */ + Z fromPrimitive(T primitive, ItemTagAdapterContext context); + + /** + * A default implementation that simply exists to pass on the retrieved or + * inserted value to the next layer. + * + * This implementation does not add any kind of logic, but is used to + * provide default implementations for the primitive types. + * + * @param <T> the generic type of the primitive objects + */ + class PrimitiveTagType<T> implements ItemTagType<T, T> { + + private final Class<T> primitiveType; + + PrimitiveTagType(Class<T> primitiveType) { + this.primitiveType = primitiveType; + } + + @Override + public Class<T> getPrimitiveType() { + return primitiveType; + } + + @Override + public Class<T> getComplexType() { + return primitiveType; + } + + @Override + public T toPrimitive(T complex, ItemTagAdapterContext context) { + return complex; + } + + @Override + public T fromPrimitive(T primitive, ItemTagAdapterContext context) { + return primitive; + } + } +} |