summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBjarne Koll <LynxPlay101@gmail.com>2018-12-01 20:25:24 +1100
committermd_5 <git@md-5.net>2018-12-01 20:26:50 +1100
commite08005992786cff58eff69abd055a6e76499046e (patch)
tree296cb66c4bd38abd933c8ccd4ec8cb9cd4a2cb4d
parent0c1d258bb8185c39ce12c816a826973e94939b0e (diff)
downloadbukkit-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
-rw-r--r--src/main/java/org/bukkit/inventory/meta/ItemMeta.java17
-rw-r--r--src/main/java/org/bukkit/inventory/meta/tags/CustomItemTagContainer.java102
-rw-r--r--src/main/java/org/bukkit/inventory/meta/tags/ItemTagAdapterContext.java15
-rw-r--r--src/main/java/org/bukkit/inventory/meta/tags/ItemTagType.java143
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;
+ }
+ }
+}