Replace ItemTag API with new API that also expands to Tiles and Entities

By: Bjarne Koll <LynxPlay101@gmail.com>
This commit is contained in:
Bukkit/Spigot
2019-04-25 14:24:05 +10:00
parent 3209bcbf56
commit ddfd4b10c4
30 changed files with 416 additions and 22 deletions

View File

@@ -0,0 +1,18 @@
package org.bukkit.persistence;
import org.jetbrains.annotations.NotNull;
/**
* This interface represents the context in which the {@link PersistentDataType} can
* serialize and deserialize the passed values.
*/
public interface PersistentDataAdapterContext {
/**
* Creates a new and empty meta container instance.
*
* @return the fresh container instance
*/
@NotNull
PersistentDataContainer newPersistentDataContainer();
}

View File

@@ -0,0 +1,141 @@
package org.bukkit.persistence;
import org.bukkit.NamespacedKey;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* This interface represents a map like object, capable of storing custom tags
* in it.
*/
public interface PersistentDataContainer {
/**
* Stores a metadata value on the {@link PersistentDataHolder} instance.
* <p>
* This API cannot be used to manipulate minecraft data, as the values will
* be stored using your namespace. This method will override any existing
* value the {@link PersistentDataHolder} may have stored under the provided
* key.
*
* @param key the key this value will be stored under
* @param type the type this 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 tag should
* be done using {@link #remove(NamespacedKey)}
* @throws IllegalArgumentException if no suitable adapter will be found for
* the {@link PersistentDataType#getPrimitiveType()}
*/
<T, Z> void set(@NotNull NamespacedKey key, @NotNull PersistentDataType<T, Z> type, @NotNull Z value);
/**
* Returns if the persistent metadata provider has metadata registered
* matching the provided parameters.
* <p>
* This method will only return if the found value has the same primitive
* data type as the provided key.
* <p>
* Storing a value using a custom {@link PersistentDataType} implementation
* will not store the complex data type. Therefore storing a UUID (by
* storing a byte[]) will match has("key" ,
* {@link PersistentDataType#BYTE_ARRAY}). Likewise a stored byte[] will
* always match your UUID {@link PersistentDataType} even if it is not 16
* bytes long.
* <p>
* 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 has(@NotNull NamespacedKey key, @NotNull PersistentDataType<T, Z> type);
/**
* Returns the metadata value that is stored on the
* {@link PersistentDataHolder} instance.
*
* @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
* PersistentDataType#getPrimitiveType()}
*/
@Nullable
<T, Z> Z get(@NotNull NamespacedKey key, @NotNull PersistentDataType<T, Z> type);
/**
* Returns the metadata value that is stored on the
* {@link PersistentDataHolder} instance. If the value does not exist in the
* container, the default value provided is returned.
*
* @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 defaultValue the default value to return if no value was found for
* the provided key
* @param <T> the generic type of the stored primitive
* @param <Z> the generic type of the eventually created complex object
*
* @return the value or the default value 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 PersistentDataType#getPrimitiveType()}
*/
@NotNull
<T, Z> Z getOrDefault(@NotNull NamespacedKey key, @NotNull PersistentDataType<T, Z> type, @NotNull Z defaultValue);
/**
* Removes a custom key from the {@link PersistentDataHolder} instance.
*
* @param key the key
*
* @throws NullPointerException if the provided key is null
*/
void remove(@NotNull 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
*/
@NotNull
PersistentDataAdapterContext getAdapterContext();
}

View File

@@ -0,0 +1,23 @@
package org.bukkit.persistence;
import org.jetbrains.annotations.NotNull;
/**
* The {@link PersistentDataHolder} interface defines an object that can store
* custom persistent meta data on it.
*/
public interface PersistentDataHolder {
/**
* Returns a custom tag container capable of storing tags on the object.
*
* Note that the tags stored on this container are all stored under their
* own custom namespace therefore modifying default tags using this
* {@link PersistentDataHolder} is impossible.
*
* @return the persistent metadata container
*/
@NotNull
PersistentDataContainer getPersistentDataContainer();
}

View File

@@ -0,0 +1,153 @@
package org.bukkit.persistence;
import org.jetbrains.annotations.NotNull;
/**
* This class represents an enum with a generic content type. It defines the
* types a custom tag can have.
* <p>
* This interface can be used to create your own custom
* {@link PersistentDataType} with different complex types. This may be useful
* for the likes of a UUIDTagType:
* <pre>
* <code>{@code
* public class UUIDTagType implements PersistentDataType<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, PersistentDataAdapterContext 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, PersistentDataAdapterContext 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 tag type
*/
public interface PersistentDataType<T, Z> {
/*
The primitive one value types.
*/
PersistentDataType<Byte, Byte> BYTE = new PrimitivePersistentDataType<>(Byte.class);
PersistentDataType<Short, Short> SHORT = new PrimitivePersistentDataType<>(Short.class);
PersistentDataType<Integer, Integer> INTEGER = new PrimitivePersistentDataType<>(Integer.class);
PersistentDataType<Long, Long> LONG = new PrimitivePersistentDataType<>(Long.class);
PersistentDataType<Float, Float> FLOAT = new PrimitivePersistentDataType<>(Float.class);
PersistentDataType<Double, Double> DOUBLE = new PrimitivePersistentDataType<>(Double.class);
/*
String.
*/
PersistentDataType<String, String> STRING = new PrimitivePersistentDataType<>(String.class);
/*
Primitive Arrays.
*/
PersistentDataType<byte[], byte[]> BYTE_ARRAY = new PrimitivePersistentDataType<>(byte[].class);
PersistentDataType<int[], int[]> INTEGER_ARRAY = new PrimitivePersistentDataType<>(int[].class);
PersistentDataType<long[], long[]> LONG_ARRAY = new PrimitivePersistentDataType<>(long[].class);
/*
Nested PersistentDataContainer.
*/
PersistentDataType<PersistentDataContainer, PersistentDataContainer> TAG_CONTAINER = new PrimitivePersistentDataType<>(PersistentDataContainer.class);
/**
* Returns the primitive data type of this tag.
*
* @return the class
*/
@NotNull
Class<T> getPrimitiveType();
/**
* Returns the complex object type the primitive value resembles.
*
* @return the class type
*/
@NotNull
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
*/
@NotNull
T toPrimitive(@NotNull Z complex, @NotNull PersistentDataAdapterContext 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
*/
@NotNull
Z fromPrimitive(@NotNull T primitive, @NotNull PersistentDataAdapterContext context);
/**
* A default implementation that simply exists to pass on the retrieved or
* inserted value to the next layer.
* <p>
* 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 PrimitivePersistentDataType<T> implements PersistentDataType<T, T> {
private final Class<T> primitiveType;
PrimitivePersistentDataType(@NotNull Class<T> primitiveType) {
this.primitiveType = primitiveType;
}
@NotNull
@Override
public Class<T> getPrimitiveType() {
return primitiveType;
}
@NotNull
@Override
public Class<T> getComplexType() {
return primitiveType;
}
@NotNull
@Override
public T toPrimitive(@NotNull T complex, @NotNull PersistentDataAdapterContext context) {
return complex;
}
@NotNull
@Override
public T fromPrimitive(@NotNull T primitive, @NotNull PersistentDataAdapterContext context) {
return primitive;
}
}
}