mirror of
https://github.com/PaperMC/Paper.git
synced 2025-01-08 03:22:19 +01:00
SPIGOT-4347: Add API to allow storing arbitrary values on ItemStacks
By: Bjarne Koll <LynxPlay101@gmail.com>
This commit is contained in:
parent
4d2079401c
commit
fe1baedce4
4 changed files with 277 additions and 0 deletions
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue