From ddfd4b10c458c00024352b99ffe83b1e60526a80 Mon Sep 17 00:00:00 2001 From: Bukkit/Spigot Date: Thu, 25 Apr 2019 14:24:05 +1000 Subject: [PATCH] Replace ItemTag API with new API that also expands to Tiles and Entities By: Bjarne Koll --- .../main/java/org/bukkit/block/Banner.java | 2 +- .../main/java/org/bukkit/block/Beacon.java | 2 +- .../src/main/java/org/bukkit/block/Bed.java | 2 +- .../src/main/java/org/bukkit/block/Bell.java | 2 +- .../main/java/org/bukkit/block/Campfire.java | 2 +- .../java/org/bukkit/block/CommandBlock.java | 2 +- .../java/org/bukkit/block/Comparator.java | 2 +- .../main/java/org/bukkit/block/Conduit.java | 2 +- .../main/java/org/bukkit/block/Container.java | 2 +- .../org/bukkit/block/CreatureSpawner.java | 2 +- .../org/bukkit/block/DaylightDetector.java | 2 +- .../org/bukkit/block/EnchantingTable.java | 2 +- .../java/org/bukkit/block/EndGateway.java | 2 +- .../java/org/bukkit/block/EnderChest.java | 2 +- .../main/java/org/bukkit/block/Jigsaw.java | 2 +- .../main/java/org/bukkit/block/Jukebox.java | 2 +- .../main/java/org/bukkit/block/Lectern.java | 2 +- .../src/main/java/org/bukkit/block/Sign.java | 2 +- .../src/main/java/org/bukkit/block/Skull.java | 2 +- .../main/java/org/bukkit/block/Structure.java | 2 +- .../main/java/org/bukkit/block/TileState.java | 39 +++++ .../main/java/org/bukkit/entity/Entity.java | 3 +- .../org/bukkit/inventory/meta/ItemMeta.java | 6 +- .../meta/tags/CustomItemTagContainer.java | 5 + .../meta/tags/ItemTagAdapterContext.java | 6 + .../inventory/meta/tags/ItemTagType.java | 4 + .../PersistentDataAdapterContext.java | 18 +++ .../persistence/PersistentDataContainer.java | 141 ++++++++++++++++ .../persistence/PersistentDataHolder.java | 23 +++ .../persistence/PersistentDataType.java | 153 ++++++++++++++++++ 30 files changed, 416 insertions(+), 22 deletions(-) create mode 100644 paper-api/src/main/java/org/bukkit/block/TileState.java create mode 100644 paper-api/src/main/java/org/bukkit/persistence/PersistentDataAdapterContext.java create mode 100644 paper-api/src/main/java/org/bukkit/persistence/PersistentDataContainer.java create mode 100644 paper-api/src/main/java/org/bukkit/persistence/PersistentDataHolder.java create mode 100644 paper-api/src/main/java/org/bukkit/persistence/PersistentDataType.java diff --git a/paper-api/src/main/java/org/bukkit/block/Banner.java b/paper-api/src/main/java/org/bukkit/block/Banner.java index 92fe953ade..e6eb3c04b9 100644 --- a/paper-api/src/main/java/org/bukkit/block/Banner.java +++ b/paper-api/src/main/java/org/bukkit/block/Banner.java @@ -8,7 +8,7 @@ import org.jetbrains.annotations.NotNull; /** * Represents a captured state of a banner. */ -public interface Banner extends BlockState { +public interface Banner extends TileState { /** * Returns the base color for this banner diff --git a/paper-api/src/main/java/org/bukkit/block/Beacon.java b/paper-api/src/main/java/org/bukkit/block/Beacon.java index 8814730bd7..6349fa9da3 100644 --- a/paper-api/src/main/java/org/bukkit/block/Beacon.java +++ b/paper-api/src/main/java/org/bukkit/block/Beacon.java @@ -11,7 +11,7 @@ import org.jetbrains.annotations.Nullable; /** * Represents a captured state of a beacon. */ -public interface Beacon extends BlockState, Lockable, Nameable { +public interface Beacon extends TileState, Lockable, Nameable { /** * Returns the list of players within the beacon's range of effect. diff --git a/paper-api/src/main/java/org/bukkit/block/Bed.java b/paper-api/src/main/java/org/bukkit/block/Bed.java index a2393852e8..f9bd74f9ce 100644 --- a/paper-api/src/main/java/org/bukkit/block/Bed.java +++ b/paper-api/src/main/java/org/bukkit/block/Bed.java @@ -7,4 +7,4 @@ import org.bukkit.material.Colorable; * @deprecated does not provide useful information beyond the material itself */ @Deprecated -public interface Bed extends BlockState, Colorable { } +public interface Bed extends TileState, Colorable { } diff --git a/paper-api/src/main/java/org/bukkit/block/Bell.java b/paper-api/src/main/java/org/bukkit/block/Bell.java index 43f64148a6..6fee356a3f 100644 --- a/paper-api/src/main/java/org/bukkit/block/Bell.java +++ b/paper-api/src/main/java/org/bukkit/block/Bell.java @@ -3,4 +3,4 @@ package org.bukkit.block; /** * Represents a captured state of Bell. */ -public interface Bell extends BlockState { } +public interface Bell extends TileState { } diff --git a/paper-api/src/main/java/org/bukkit/block/Campfire.java b/paper-api/src/main/java/org/bukkit/block/Campfire.java index 1d3584c868..cf71d8eb63 100644 --- a/paper-api/src/main/java/org/bukkit/block/Campfire.java +++ b/paper-api/src/main/java/org/bukkit/block/Campfire.java @@ -7,7 +7,7 @@ import org.jetbrains.annotations.Nullable; /** * Represents a captured state of a campfire. */ -public interface Campfire extends BlockState { +public interface Campfire extends TileState { /** * @see Inventory#getSize() diff --git a/paper-api/src/main/java/org/bukkit/block/CommandBlock.java b/paper-api/src/main/java/org/bukkit/block/CommandBlock.java index b7ee5bc940..372c0bd5a4 100644 --- a/paper-api/src/main/java/org/bukkit/block/CommandBlock.java +++ b/paper-api/src/main/java/org/bukkit/block/CommandBlock.java @@ -6,7 +6,7 @@ import org.jetbrains.annotations.Nullable; /** * Represents a captured state of a command block. */ -public interface CommandBlock extends BlockState { +public interface CommandBlock extends TileState { /** * Gets the command that this CommandBlock will run when powered. diff --git a/paper-api/src/main/java/org/bukkit/block/Comparator.java b/paper-api/src/main/java/org/bukkit/block/Comparator.java index c9acc916d9..6fb4c1a944 100644 --- a/paper-api/src/main/java/org/bukkit/block/Comparator.java +++ b/paper-api/src/main/java/org/bukkit/block/Comparator.java @@ -3,4 +3,4 @@ package org.bukkit.block; /** * Represents a captured state of an on / off comparator. */ -public interface Comparator extends BlockState { } +public interface Comparator extends TileState { } diff --git a/paper-api/src/main/java/org/bukkit/block/Conduit.java b/paper-api/src/main/java/org/bukkit/block/Conduit.java index d889f41b7d..5543165536 100644 --- a/paper-api/src/main/java/org/bukkit/block/Conduit.java +++ b/paper-api/src/main/java/org/bukkit/block/Conduit.java @@ -3,4 +3,4 @@ package org.bukkit.block; /** * Represents a captured state of a conduit. */ -public interface Conduit extends BlockState { } +public interface Conduit extends TileState { } diff --git a/paper-api/src/main/java/org/bukkit/block/Container.java b/paper-api/src/main/java/org/bukkit/block/Container.java index a03bdfd3ac..bc06199f0a 100644 --- a/paper-api/src/main/java/org/bukkit/block/Container.java +++ b/paper-api/src/main/java/org/bukkit/block/Container.java @@ -8,7 +8,7 @@ import org.jetbrains.annotations.NotNull; /** * Represents a captured state of a container block. */ -public interface Container extends BlockState, BlockInventoryHolder, Lockable, Nameable { +public interface Container extends TileState, BlockInventoryHolder, Lockable, Nameable { /** * Gets the inventory of the block represented by this block state. diff --git a/paper-api/src/main/java/org/bukkit/block/CreatureSpawner.java b/paper-api/src/main/java/org/bukkit/block/CreatureSpawner.java index 5773e99ee6..e73fb0ef08 100644 --- a/paper-api/src/main/java/org/bukkit/block/CreatureSpawner.java +++ b/paper-api/src/main/java/org/bukkit/block/CreatureSpawner.java @@ -6,7 +6,7 @@ import org.jetbrains.annotations.NotNull; /** * Represents a captured state of a creature spawner. */ -public interface CreatureSpawner extends BlockState { +public interface CreatureSpawner extends TileState { /** * Get the spawner's creature type. diff --git a/paper-api/src/main/java/org/bukkit/block/DaylightDetector.java b/paper-api/src/main/java/org/bukkit/block/DaylightDetector.java index ea4117ea8d..702ee7fbe0 100644 --- a/paper-api/src/main/java/org/bukkit/block/DaylightDetector.java +++ b/paper-api/src/main/java/org/bukkit/block/DaylightDetector.java @@ -3,4 +3,4 @@ package org.bukkit.block; /** * Represents a captured state of a (possibly inverted) daylight detector. */ -public interface DaylightDetector extends BlockState { } +public interface DaylightDetector extends TileState { } diff --git a/paper-api/src/main/java/org/bukkit/block/EnchantingTable.java b/paper-api/src/main/java/org/bukkit/block/EnchantingTable.java index 9f5aa6c6c5..68b9e034a6 100644 --- a/paper-api/src/main/java/org/bukkit/block/EnchantingTable.java +++ b/paper-api/src/main/java/org/bukkit/block/EnchantingTable.java @@ -5,4 +5,4 @@ import org.bukkit.Nameable; /** * Represents a captured state of an enchanting table. */ -public interface EnchantingTable extends BlockState, Nameable { } +public interface EnchantingTable extends TileState, Nameable { } diff --git a/paper-api/src/main/java/org/bukkit/block/EndGateway.java b/paper-api/src/main/java/org/bukkit/block/EndGateway.java index 4cf5be6ee8..5e76a1cf4b 100644 --- a/paper-api/src/main/java/org/bukkit/block/EndGateway.java +++ b/paper-api/src/main/java/org/bukkit/block/EndGateway.java @@ -6,7 +6,7 @@ import org.jetbrains.annotations.Nullable; /** * Represents a captured state of an end gateway. */ -public interface EndGateway extends BlockState { +public interface EndGateway extends TileState { /** * Gets the location that entities are teleported to when diff --git a/paper-api/src/main/java/org/bukkit/block/EnderChest.java b/paper-api/src/main/java/org/bukkit/block/EnderChest.java index e0eb2560ff..17843e338f 100644 --- a/paper-api/src/main/java/org/bukkit/block/EnderChest.java +++ b/paper-api/src/main/java/org/bukkit/block/EnderChest.java @@ -3,4 +3,4 @@ package org.bukkit.block; /** * Represents a captured state of an ender chest. */ -public interface EnderChest extends BlockState { } +public interface EnderChest extends TileState { } diff --git a/paper-api/src/main/java/org/bukkit/block/Jigsaw.java b/paper-api/src/main/java/org/bukkit/block/Jigsaw.java index b5296e0d9f..02c7fa58ec 100644 --- a/paper-api/src/main/java/org/bukkit/block/Jigsaw.java +++ b/paper-api/src/main/java/org/bukkit/block/Jigsaw.java @@ -3,4 +3,4 @@ package org.bukkit.block; /** * Represents a captured state of a jigsaw. */ -public interface Jigsaw extends BlockState { } +public interface Jigsaw extends TileState { } diff --git a/paper-api/src/main/java/org/bukkit/block/Jukebox.java b/paper-api/src/main/java/org/bukkit/block/Jukebox.java index 1203182f34..363294cff2 100644 --- a/paper-api/src/main/java/org/bukkit/block/Jukebox.java +++ b/paper-api/src/main/java/org/bukkit/block/Jukebox.java @@ -8,7 +8,7 @@ import org.jetbrains.annotations.Nullable; /** * Represents a captured state of a jukebox. */ -public interface Jukebox extends BlockState { +public interface Jukebox extends TileState { /** * Gets the record inserted into the jukebox. diff --git a/paper-api/src/main/java/org/bukkit/block/Lectern.java b/paper-api/src/main/java/org/bukkit/block/Lectern.java index d306604476..78107207b4 100644 --- a/paper-api/src/main/java/org/bukkit/block/Lectern.java +++ b/paper-api/src/main/java/org/bukkit/block/Lectern.java @@ -7,7 +7,7 @@ import org.jetbrains.annotations.NotNull; /** * Represents a captured state of a lectern. */ -public interface Lectern extends BlockState, BlockInventoryHolder { +public interface Lectern extends TileState, BlockInventoryHolder { /** * Get the current lectern page. diff --git a/paper-api/src/main/java/org/bukkit/block/Sign.java b/paper-api/src/main/java/org/bukkit/block/Sign.java index 74db5efcb8..b43e11162d 100644 --- a/paper-api/src/main/java/org/bukkit/block/Sign.java +++ b/paper-api/src/main/java/org/bukkit/block/Sign.java @@ -5,7 +5,7 @@ import org.jetbrains.annotations.NotNull; /** * Represents a captured state of either a SignPost or a WallSign. */ -public interface Sign extends BlockState { +public interface Sign extends TileState { /** * Gets all the lines of text currently on this sign. diff --git a/paper-api/src/main/java/org/bukkit/block/Skull.java b/paper-api/src/main/java/org/bukkit/block/Skull.java index 6325f58380..943d751fb3 100644 --- a/paper-api/src/main/java/org/bukkit/block/Skull.java +++ b/paper-api/src/main/java/org/bukkit/block/Skull.java @@ -11,7 +11,7 @@ import org.jetbrains.annotations.Nullable; /** * Represents a captured state of a skull block. */ -public interface Skull extends BlockState { +public interface Skull extends TileState { /** * Checks to see if the skull has an owner diff --git a/paper-api/src/main/java/org/bukkit/block/Structure.java b/paper-api/src/main/java/org/bukkit/block/Structure.java index d0f1d507ed..dc40069551 100644 --- a/paper-api/src/main/java/org/bukkit/block/Structure.java +++ b/paper-api/src/main/java/org/bukkit/block/Structure.java @@ -11,7 +11,7 @@ import org.jetbrains.annotations.NotNull; * Represents a structure block that can save and load blocks from a file. They * can only be used by OPs, and are not obtainable in survival. */ -public interface Structure extends BlockState { +public interface Structure extends TileState { /** * The name of this structure. diff --git a/paper-api/src/main/java/org/bukkit/block/TileState.java b/paper-api/src/main/java/org/bukkit/block/TileState.java new file mode 100644 index 0000000000..3b10fcc138 --- /dev/null +++ b/paper-api/src/main/java/org/bukkit/block/TileState.java @@ -0,0 +1,39 @@ +package org.bukkit.block; + +import org.bukkit.persistence.PersistentDataContainer; +import org.bukkit.persistence.PersistentDataHolder; +import org.jetbrains.annotations.NotNull; + +/** + * Represents a block state that also hosts a tile entity at the given location. + * + * This interface alone is merely a marker that does not provide any data. + * + * Data about the tile entities is provided by the respective interface for each + * tile entity type. + * + * After modifying the data provided by a TileState, {@link #update()} needs to + * be called to store the data. + */ +public interface TileState extends BlockState, 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. + *

+ * This {@link PersistentDataHolder} is only linked to the snapshot instance + * stored by the {@link BlockState}. + * + * When storing changes on the {@link PersistentDataHolder}, the updated + * content will only be applied to the actual tile entity after one of the + * {@link #update()} methods is called. + * + * @return the custom tag container + */ + @NotNull + @Override + PersistentDataContainer getPersistentDataContainer(); +} diff --git a/paper-api/src/main/java/org/bukkit/entity/Entity.java b/paper-api/src/main/java/org/bukkit/entity/Entity.java index 7fdcedf329..f9460a4876 100644 --- a/paper-api/src/main/java/org/bukkit/entity/Entity.java +++ b/paper-api/src/main/java/org/bukkit/entity/Entity.java @@ -15,6 +15,7 @@ import org.bukkit.event.entity.EntityDamageEvent; import org.bukkit.event.player.PlayerTeleportEvent.TeleportCause; import org.bukkit.material.Directional; import org.bukkit.metadata.Metadatable; +import org.bukkit.persistence.PersistentDataHolder; import org.bukkit.util.BoundingBox; import org.bukkit.util.Vector; import org.jetbrains.annotations.Contract; @@ -24,7 +25,7 @@ import org.jetbrains.annotations.Nullable; /** * Represents a base entity in the world */ -public interface Entity extends Metadatable, CommandSender, Nameable { +public interface Entity extends Metadatable, CommandSender, Nameable, PersistentDataHolder { /** * Gets the entity's current position diff --git a/paper-api/src/main/java/org/bukkit/inventory/meta/ItemMeta.java b/paper-api/src/main/java/org/bukkit/inventory/meta/ItemMeta.java index c103599f5a..435766a3e7 100644 --- a/paper-api/src/main/java/org/bukkit/inventory/meta/ItemMeta.java +++ b/paper-api/src/main/java/org/bukkit/inventory/meta/ItemMeta.java @@ -12,6 +12,7 @@ import org.bukkit.enchantments.Enchantment; import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemFlag; import org.bukkit.inventory.meta.tags.CustomItemTagContainer; +import org.bukkit.persistence.PersistentDataHolder; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -21,7 +22,7 @@ import org.jetbrains.annotations.Nullable; * An implementation will handle the creation and application for ItemMeta. * This class should not be implemented by a plugin in a live environment. */ -public interface ItemMeta extends Cloneable, ConfigurationSerializable { +public interface ItemMeta extends Cloneable, ConfigurationSerializable, PersistentDataHolder { /** * Checks for existence of a display name. @@ -368,8 +369,11 @@ public interface ItemMeta extends Cloneable, ConfigurationSerializable { * These tags can also be modified by the client once in creative mode * * @return the custom tag container + * @deprecated this API part has been replaced by the {@link PersistentDataHolder} API. + * Please use {@link PersistentDataHolder#getPersistentDataContainer()} instead of this. */ @NotNull + @Deprecated CustomItemTagContainer getCustomTagContainer(); /** diff --git a/paper-api/src/main/java/org/bukkit/inventory/meta/tags/CustomItemTagContainer.java b/paper-api/src/main/java/org/bukkit/inventory/meta/tags/CustomItemTagContainer.java index e3b77998f3..f46e2978bd 100644 --- a/paper-api/src/main/java/org/bukkit/inventory/meta/tags/CustomItemTagContainer.java +++ b/paper-api/src/main/java/org/bukkit/inventory/meta/tags/CustomItemTagContainer.java @@ -8,7 +8,12 @@ import org.jetbrains.annotations.Nullable; /** * This interface represents a map like object, capable of storing custom tags * in it. + * + * @deprecated this API part has been replaced by the + * {@link org.bukkit.persistence.PersistentDataHolder} API. Please use + * {@link org.bukkit.persistence.PersistentDataHolder} instead of this. */ +@Deprecated public interface CustomItemTagContainer { /** diff --git a/paper-api/src/main/java/org/bukkit/inventory/meta/tags/ItemTagAdapterContext.java b/paper-api/src/main/java/org/bukkit/inventory/meta/tags/ItemTagAdapterContext.java index 9de37daa32..97e6c96efe 100644 --- a/paper-api/src/main/java/org/bukkit/inventory/meta/tags/ItemTagAdapterContext.java +++ b/paper-api/src/main/java/org/bukkit/inventory/meta/tags/ItemTagAdapterContext.java @@ -1,11 +1,17 @@ package org.bukkit.inventory.meta.tags; +import org.bukkit.persistence.PersistentDataAdapterContext; +import org.bukkit.persistence.PersistentDataHolder; import org.jetbrains.annotations.NotNull; /** * This interface represents the context in which the {@link ItemTagType} can * serialize and deserialize the passed values. + * + * @deprecated this API part has been replaced by {@link PersistentDataHolder}. + * Please use {@link PersistentDataAdapterContext} instead of this. */ +@Deprecated public interface ItemTagAdapterContext { /** diff --git a/paper-api/src/main/java/org/bukkit/inventory/meta/tags/ItemTagType.java b/paper-api/src/main/java/org/bukkit/inventory/meta/tags/ItemTagType.java index eab84fe863..e8bd710f6e 100644 --- a/paper-api/src/main/java/org/bukkit/inventory/meta/tags/ItemTagType.java +++ b/paper-api/src/main/java/org/bukkit/inventory/meta/tags/ItemTagType.java @@ -1,5 +1,6 @@ package org.bukkit.inventory.meta.tags; +import org.bukkit.persistence.PersistentDataType; import org.jetbrains.annotations.NotNull; /** @@ -42,7 +43,10 @@ import org.jetbrains.annotations.NotNull; * * @param the primary object type that is stored in the given tag * @param the retrieved object type when applying this item tag type + * + * @deprecated please use {@link PersistentDataType} as this part of the api is being replaced */ +@Deprecated public interface ItemTagType { /* diff --git a/paper-api/src/main/java/org/bukkit/persistence/PersistentDataAdapterContext.java b/paper-api/src/main/java/org/bukkit/persistence/PersistentDataAdapterContext.java new file mode 100644 index 0000000000..8face93f33 --- /dev/null +++ b/paper-api/src/main/java/org/bukkit/persistence/PersistentDataAdapterContext.java @@ -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(); +} diff --git a/paper-api/src/main/java/org/bukkit/persistence/PersistentDataContainer.java b/paper-api/src/main/java/org/bukkit/persistence/PersistentDataContainer.java new file mode 100644 index 0000000000..05a93aa314 --- /dev/null +++ b/paper-api/src/main/java/org/bukkit/persistence/PersistentDataContainer.java @@ -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. + *

+ * 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 the generic java type of the tag value + * @param 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()} + */ + void set(@NotNull NamespacedKey key, @NotNull PersistentDataType type, @NotNull Z value); + + /** + * Returns if the persistent metadata provider has metadata 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 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. + *

+ * 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 the generic type of the stored primitive + * @param 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 + */ + boolean has(@NotNull NamespacedKey key, @NotNull PersistentDataType 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 the generic type of the stored primitive + * @param 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 + Z get(@NotNull NamespacedKey key, @NotNull PersistentDataType 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 the generic type of the stored primitive + * @param 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 + Z getOrDefault(@NotNull NamespacedKey key, @NotNull PersistentDataType 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(); +} diff --git a/paper-api/src/main/java/org/bukkit/persistence/PersistentDataHolder.java b/paper-api/src/main/java/org/bukkit/persistence/PersistentDataHolder.java new file mode 100644 index 0000000000..80b277cc57 --- /dev/null +++ b/paper-api/src/main/java/org/bukkit/persistence/PersistentDataHolder.java @@ -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(); + +} diff --git a/paper-api/src/main/java/org/bukkit/persistence/PersistentDataType.java b/paper-api/src/main/java/org/bukkit/persistence/PersistentDataType.java new file mode 100644 index 0000000000..a6f8ce3b98 --- /dev/null +++ b/paper-api/src/main/java/org/bukkit/persistence/PersistentDataType.java @@ -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. + *

+ * 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: + *

+ * {@code
+ * public class UUIDTagType implements PersistentDataType {
+ *
+ *         {@literal @Override}
+ *         public Class getPrimitiveType() {
+ *             return byte[].class;
+ *         }
+ *
+ *         {@literal @Override}
+ *         public Class 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);
+ *         }
+ *     }}
+ * + * @param the primary object type that is stored in the given tag + * @param the retrieved object type when applying this tag type + */ +public interface PersistentDataType { + + /* + The primitive one value types. + */ + PersistentDataType BYTE = new PrimitivePersistentDataType<>(Byte.class); + PersistentDataType SHORT = new PrimitivePersistentDataType<>(Short.class); + PersistentDataType INTEGER = new PrimitivePersistentDataType<>(Integer.class); + PersistentDataType LONG = new PrimitivePersistentDataType<>(Long.class); + PersistentDataType FLOAT = new PrimitivePersistentDataType<>(Float.class); + PersistentDataType DOUBLE = new PrimitivePersistentDataType<>(Double.class); + + /* + String. + */ + PersistentDataType STRING = new PrimitivePersistentDataType<>(String.class); + + /* + Primitive Arrays. + */ + PersistentDataType BYTE_ARRAY = new PrimitivePersistentDataType<>(byte[].class); + PersistentDataType INTEGER_ARRAY = new PrimitivePersistentDataType<>(int[].class); + PersistentDataType LONG_ARRAY = new PrimitivePersistentDataType<>(long[].class); + + /* + Nested PersistentDataContainer. + */ + PersistentDataType TAG_CONTAINER = new PrimitivePersistentDataType<>(PersistentDataContainer.class); + + /** + * Returns the primitive data type of this tag. + * + * @return the class + */ + @NotNull + Class getPrimitiveType(); + + /** + * Returns the complex object type the primitive value resembles. + * + * @return the class type + */ + @NotNull + Class 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. + *

+ * This implementation does not add any kind of logic, but is used to + * provide default implementations for the primitive types. + * + * @param the generic type of the primitive objects + */ + class PrimitivePersistentDataType implements PersistentDataType { + + private final Class primitiveType; + + PrimitivePersistentDataType(@NotNull Class primitiveType) { + this.primitiveType = primitiveType; + } + + @NotNull + @Override + public Class getPrimitiveType() { + return primitiveType; + } + + @NotNull + @Override + public Class 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; + } + } +}