Delegate ItemStack (#10852)
This commit is contained in:
parent
27a9efdca5
commit
70f3730d25
7 changed files with 1599 additions and 8 deletions
|
@ -19,3 +19,55 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
|
|||
this.flicker = flicker;
|
||||
this.trail = trail;
|
||||
this.colors = colors;
|
||||
diff --git a/src/main/java/org/bukkit/inventory/meta/Damageable.java b/src/main/java/org/bukkit/inventory/meta/Damageable.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/org/bukkit/inventory/meta/Damageable.java
|
||||
+++ b/src/main/java/org/bukkit/inventory/meta/Damageable.java
|
||||
@@ -0,0 +0,0 @@ import org.jetbrains.annotations.Nullable;
|
||||
public interface Damageable extends ItemMeta {
|
||||
|
||||
/**
|
||||
- * Checks to see if this item has damage
|
||||
+ * Checks to see if this item has damage greater than 0.
|
||||
*
|
||||
- * @return true if this has damage
|
||||
+ * @return true if this has damage > 0
|
||||
*/
|
||||
boolean hasDamage();
|
||||
|
||||
/**
|
||||
* Gets the damage
|
||||
+ * <p>
|
||||
+ * Call {@link #hasDamageValue()} to be sure
|
||||
+ * a damage value is set.
|
||||
*
|
||||
* @return the damage
|
||||
*/
|
||||
@@ -0,0 +0,0 @@ public interface Damageable extends ItemMeta {
|
||||
* Sets the damage
|
||||
*
|
||||
* @param damage item damage
|
||||
+ * @see #resetDamage() to reset and clear the damage data component
|
||||
*/
|
||||
void setDamage(int damage);
|
||||
|
||||
+ // Paper start
|
||||
+ /**
|
||||
+ * Checks if any damage value, including 0,
|
||||
+ * is set on this meta.
|
||||
+ *
|
||||
+ * @return true if any value is set
|
||||
+ */
|
||||
+ boolean hasDamageValue();
|
||||
+
|
||||
+ /**
|
||||
+ * Clears the damage component from the meta. Differs
|
||||
+ * from {@code setDamage(0)} in that it removes the component
|
||||
+ * instead of adding the component with a value of 0.
|
||||
+ */
|
||||
+ void resetDamage();
|
||||
+ // Paper end
|
||||
+
|
||||
/**
|
||||
* Checks to see if this item has a maximum amount of damage.
|
||||
*
|
||||
|
|
|
@ -0,0 +1,434 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jake Potrebic <jake.m.potrebic@gmail.com>
|
||||
Date: Wed, 12 Jun 2024 10:29:30 -0700
|
||||
Subject: [PATCH] Make a PDC view accessible directly from ItemStack
|
||||
|
||||
|
||||
diff --git a/src/main/java/io/papermc/paper/persistence/PersistentDataContainerView.java b/src/main/java/io/papermc/paper/persistence/PersistentDataContainerView.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/persistence/PersistentDataContainerView.java
|
||||
@@ -0,0 +0,0 @@
|
||||
+package io.papermc.paper.persistence;
|
||||
+
|
||||
+import java.util.Set;
|
||||
+import org.bukkit.NamespacedKey;
|
||||
+import org.bukkit.persistence.PersistentDataAdapterContext;
|
||||
+import org.bukkit.persistence.PersistentDataContainer;
|
||||
+import org.bukkit.persistence.PersistentDataHolder;
|
||||
+import org.bukkit.persistence.PersistentDataType;
|
||||
+import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
+import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
+import org.jetbrains.annotations.ApiStatus;
|
||||
+
|
||||
+/**
|
||||
+ * This represents a view of a persistent data container. No
|
||||
+ * methods on this interface mutate the container.
|
||||
+ * @see PersistentDataContainer
|
||||
+ */
|
||||
+@ApiStatus.NonExtendable
|
||||
+public interface PersistentDataContainerView {
|
||||
+
|
||||
+ /**
|
||||
+ * Returns if the persistent metadata provider has metadata registered
|
||||
+ * matching the provided parameters.
|
||||
+ * <p>
|
||||
+ * This method will only return true 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 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 the primative stored value has to match
|
||||
+ * @param <P> the generic type of the stored primitive
|
||||
+ * @param <C> the generic type of the eventually created complex object
|
||||
+ *
|
||||
+ * @return if a value with the provided key and type exists
|
||||
+ *
|
||||
+ * @throws IllegalArgumentException if the key to look up is null
|
||||
+ * @throws IllegalArgumentException if the type to cast the found object to is
|
||||
+ * null
|
||||
+ */
|
||||
+ <P, C> boolean has(@NonNull NamespacedKey key, @NonNull PersistentDataType<P, C> type);
|
||||
+
|
||||
+ /**
|
||||
+ * Returns if the persistent metadata provider has metadata registered matching
|
||||
+ * the provided parameters.
|
||||
+ * <p>
|
||||
+ * This method will return true as long as a value with the given key exists,
|
||||
+ * regardless of its type.
|
||||
+ * <p>
|
||||
+ * This method is only usable for custom object keys. Overwriting existing tags,
|
||||
+ * like the display name, will not work as the values are stored using your
|
||||
+ * namespace.
|
||||
+ *
|
||||
+ * @param key the key the value is stored under
|
||||
+ *
|
||||
+ * @return if a value with the provided key exists
|
||||
+ *
|
||||
+ * @throws IllegalArgumentException if the key to look up is null
|
||||
+ */
|
||||
+ boolean has(@NonNull NamespacedKey key);
|
||||
+
|
||||
+ /**
|
||||
+ * 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 <P> the generic type of the stored primitive
|
||||
+ * @param <C> 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 IllegalArgumentException if the key to look up is null
|
||||
+ * @throws IllegalArgumentException if the type to cast the found object to is
|
||||
+ * null
|
||||
+ * @throws IllegalArgumentException if a value exists under the given key,
|
||||
+ * but cannot be accessed using the given type
|
||||
+ * @throws IllegalArgumentException if no suitable adapter was found for
|
||||
+ * the {@link
|
||||
+ * PersistentDataType#getPrimitiveType()}
|
||||
+ */
|
||||
+ <P, C> @Nullable C get(@NonNull NamespacedKey key, @NonNull PersistentDataType<P, C> 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 <P> the generic type of the stored primitive
|
||||
+ * @param <C> the generic type of the eventually created complex object
|
||||
+ *
|
||||
+ * @return the value or the default value if no value was mapped under the
|
||||
+ * given key
|
||||
+ *
|
||||
+ * @throws IllegalArgumentException if the key to look up is null
|
||||
+ * @throws IllegalArgumentException if the type to cast the found object to is
|
||||
+ * null
|
||||
+ * @throws IllegalArgumentException if a value exists under the given key,
|
||||
+ * but cannot be accessed using the given type
|
||||
+ * @throws IllegalArgumentException if no suitable adapter was found for
|
||||
+ * the {@link PersistentDataType#getPrimitiveType()}
|
||||
+ */
|
||||
+ <P, C> @NonNull C getOrDefault(@NonNull NamespacedKey key, @NonNull PersistentDataType<P, C> type, @NonNull C defaultValue);
|
||||
+
|
||||
+ /**
|
||||
+ * Get the set of keys present on this {@link PersistentDataContainer}
|
||||
+ * instance.
|
||||
+ *
|
||||
+ * Any changes made to the returned set will not be reflected on the
|
||||
+ * instance.
|
||||
+ *
|
||||
+ * @return the key set
|
||||
+ */
|
||||
+ @NonNull Set<NamespacedKey> getKeys();
|
||||
+
|
||||
+ /**
|
||||
+ * Returns if the container instance is empty, therefore has no entries
|
||||
+ * inside it.
|
||||
+ *
|
||||
+ * @return the boolean
|
||||
+ */
|
||||
+ boolean isEmpty();
|
||||
+
|
||||
+ /**
|
||||
+ * Copies all values from this {@link PersistentDataContainer} to the provided
|
||||
+ * container.
|
||||
+ * <p>
|
||||
+ * This method only copies custom object keys. Existing tags, like the display
|
||||
+ * name, will not be copied as the values are stored using your namespace.
|
||||
+ *
|
||||
+ * @param other the container to copy to
|
||||
+ * @param replace whether to replace any matching values in the target container
|
||||
+ *
|
||||
+ * @throws IllegalArgumentException if the other container is null
|
||||
+ */
|
||||
+ void copyTo(@NonNull PersistentDataContainer other, boolean replace);
|
||||
+
|
||||
+ /**
|
||||
+ * Returns the adapter context this tag container uses.
|
||||
+ *
|
||||
+ * @return the tag context
|
||||
+ */
|
||||
+ @NonNull PersistentDataAdapterContext getAdapterContext();
|
||||
+
|
||||
+ /**
|
||||
+ * Serialize this {@link PersistentDataContainer} instance to a
|
||||
+ * byte array.
|
||||
+ *
|
||||
+ * @return a binary representation of this container
|
||||
+ * @throws java.io.IOException if we fail to write this container to a byte array
|
||||
+ */
|
||||
+ byte @NonNull [] serializeToBytes() throws java.io.IOException;
|
||||
+}
|
||||
diff --git a/src/main/java/io/papermc/paper/persistence/PersistentDataViewHolder.java b/src/main/java/io/papermc/paper/persistence/PersistentDataViewHolder.java
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
|
||||
--- /dev/null
|
||||
+++ b/src/main/java/io/papermc/paper/persistence/PersistentDataViewHolder.java
|
||||
@@ -0,0 +0,0 @@
|
||||
+package io.papermc.paper.persistence;
|
||||
+
|
||||
+import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
+import org.jetbrains.annotations.ApiStatus;
|
||||
+
|
||||
+/**
|
||||
+ * The {@link PersistentDataViewHolder} interface defines an object that can view
|
||||
+ * custom persistent data on it.
|
||||
+ */
|
||||
+@ApiStatus.NonExtendable
|
||||
+public interface PersistentDataViewHolder {
|
||||
+
|
||||
+ /**
|
||||
+ * Returns a custom tag container view capable of viewing tags on the object.
|
||||
+ * <p>
|
||||
+ * Note that the tags stored on this container are all stored under their
|
||||
+ * own custom namespace therefore modifying default tags using this
|
||||
+ * {@link PersistentDataViewHolder} is impossible.
|
||||
+ *
|
||||
+ * @return the persistent data container view
|
||||
+ */
|
||||
+ @NonNull PersistentDataContainerView getPersistentDataContainer();
|
||||
+}
|
||||
diff --git a/src/main/java/org/bukkit/inventory/ItemStack.java b/src/main/java/org/bukkit/inventory/ItemStack.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/org/bukkit/inventory/ItemStack.java
|
||||
+++ b/src/main/java/org/bukkit/inventory/ItemStack.java
|
||||
@@ -0,0 +0,0 @@ import org.jetbrains.annotations.Nullable;
|
||||
* use this class to encapsulate Materials for which {@link Material#isItem()}
|
||||
* returns false.</b>
|
||||
*/
|
||||
-public class ItemStack implements Cloneable, ConfigurationSerializable, Translatable, net.kyori.adventure.text.event.HoverEventSource<net.kyori.adventure.text.event.HoverEvent.ShowItem>, net.kyori.adventure.translation.Translatable { // Paper
|
||||
+public class ItemStack implements Cloneable, ConfigurationSerializable, Translatable, net.kyori.adventure.text.event.HoverEventSource<net.kyori.adventure.text.event.HoverEvent.ShowItem>, net.kyori.adventure.translation.Translatable, io.papermc.paper.persistence.PersistentDataViewHolder { // Paper
|
||||
private ItemStack craftDelegate; // Paper - always delegate to server-backed stack
|
||||
private MaterialData data = null;
|
||||
|
||||
@@ -0,0 +0,0 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat
|
||||
}
|
||||
// Paper end
|
||||
|
||||
+ // Paper start - pdc
|
||||
+ @Override
|
||||
+ public io.papermc.paper.persistence.@NotNull PersistentDataContainerView getPersistentDataContainer() {
|
||||
+ return this.craftDelegate.getPersistentDataContainer();
|
||||
+ }
|
||||
+ // Paper end - pdc
|
||||
+
|
||||
@Utility
|
||||
protected ItemStack() {}
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/persistence/PersistentDataContainer.java b/src/main/java/org/bukkit/persistence/PersistentDataContainer.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/org/bukkit/persistence/PersistentDataContainer.java
|
||||
+++ b/src/main/java/org/bukkit/persistence/PersistentDataContainer.java
|
||||
@@ -0,0 +0,0 @@ import org.jetbrains.annotations.Nullable;
|
||||
* This interface represents a map like object, capable of storing custom tags
|
||||
* in it.
|
||||
*/
|
||||
-public interface PersistentDataContainer {
|
||||
+public interface PersistentDataContainer extends io.papermc.paper.persistence.PersistentDataContainerView { // Paper - split up view and mutable
|
||||
|
||||
/**
|
||||
* Stores a metadata value on the {@link PersistentDataHolder} instance.
|
||||
@@ -0,0 +0,0 @@ public interface PersistentDataContainer {
|
||||
* the {@link PersistentDataType#getPrimitiveType()}
|
||||
*/
|
||||
<P, C> void set(@NotNull NamespacedKey key, @NotNull PersistentDataType<P, C> type, @NotNull C value);
|
||||
-
|
||||
- /**
|
||||
- * Returns if the persistent metadata provider has metadata registered
|
||||
- * matching the provided parameters.
|
||||
- * <p>
|
||||
- * This method will only return true 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 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 the primative stored value has to match
|
||||
- * @param <P> the generic type of the stored primitive
|
||||
- * @param <C> the generic type of the eventually created complex object
|
||||
- *
|
||||
- * @return if a value with the provided key and type exists
|
||||
- *
|
||||
- * @throws IllegalArgumentException if the key to look up is null
|
||||
- * @throws IllegalArgumentException if the type to cast the found object to is
|
||||
- * null
|
||||
- */
|
||||
- <P, C> boolean has(@NotNull NamespacedKey key, @NotNull PersistentDataType<P, C> type);
|
||||
-
|
||||
- /**
|
||||
- * Returns if the persistent metadata provider has metadata registered matching
|
||||
- * the provided parameters.
|
||||
- * <p>
|
||||
- * This method will return true as long as a value with the given key exists,
|
||||
- * regardless of its type.
|
||||
- * <p>
|
||||
- * This method is only usable for custom object keys. Overwriting existing tags,
|
||||
- * like the display name, will not work as the values are stored using your
|
||||
- * namespace.
|
||||
- *
|
||||
- * @param key the key the value is stored under
|
||||
- *
|
||||
- * @return if a value with the provided key exists
|
||||
- *
|
||||
- * @throws IllegalArgumentException if the key to look up is null
|
||||
- */
|
||||
- boolean has(@NotNull NamespacedKey key);
|
||||
-
|
||||
- /**
|
||||
- * 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 <P> the generic type of the stored primitive
|
||||
- * @param <C> 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 IllegalArgumentException if the key to look up is null
|
||||
- * @throws IllegalArgumentException if the type to cast the found object to is
|
||||
- * null
|
||||
- * @throws IllegalArgumentException if a value exists under the given key,
|
||||
- * but cannot be accessed using the given type
|
||||
- * @throws IllegalArgumentException if no suitable adapter was found for
|
||||
- * the {@link
|
||||
- * PersistentDataType#getPrimitiveType()}
|
||||
- */
|
||||
- @Nullable
|
||||
- <P, C> C get(@NotNull NamespacedKey key, @NotNull PersistentDataType<P, C> 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 <P> the generic type of the stored primitive
|
||||
- * @param <C> the generic type of the eventually created complex object
|
||||
- *
|
||||
- * @return the value or the default value if no value was mapped under the
|
||||
- * given key
|
||||
- *
|
||||
- * @throws IllegalArgumentException if the key to look up is null
|
||||
- * @throws IllegalArgumentException if the type to cast the found object to is
|
||||
- * null
|
||||
- * @throws IllegalArgumentException if a value exists under the given key,
|
||||
- * but cannot be accessed using the given type
|
||||
- * @throws IllegalArgumentException if no suitable adapter was found for
|
||||
- * the {@link PersistentDataType#getPrimitiveType()}
|
||||
- */
|
||||
- @NotNull
|
||||
- <P, C> C getOrDefault(@NotNull NamespacedKey key, @NotNull PersistentDataType<P, C> type, @NotNull C defaultValue);
|
||||
-
|
||||
- /**
|
||||
- * Get the set of keys present on this {@link PersistentDataContainer}
|
||||
- * instance.
|
||||
- *
|
||||
- * Any changes made to the returned set will not be reflected on the
|
||||
- * instance.
|
||||
- *
|
||||
- * @return the key set
|
||||
- */
|
||||
- @NotNull
|
||||
- Set<NamespacedKey> getKeys();
|
||||
+ // Paper - move to PersistentDataContainerView
|
||||
|
||||
/**
|
||||
* Removes a custom key from the {@link PersistentDataHolder} instance.
|
||||
@@ -0,0 +0,0 @@ public interface PersistentDataContainer {
|
||||
* @throws IllegalArgumentException 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();
|
||||
-
|
||||
- /**
|
||||
- * Copies all values from this {@link PersistentDataContainer} to the provided
|
||||
- * container.
|
||||
- * <p>
|
||||
- * This method only copies custom object keys. Existing tags, like the display
|
||||
- * name, will not be copied as the values are stored using your namespace.
|
||||
- *
|
||||
- * @param other the container to copy to
|
||||
- * @param replace whether to replace any matching values in the target container
|
||||
- *
|
||||
- * @throws IllegalArgumentException if the other container is null
|
||||
- */
|
||||
- void copyTo(@NotNull PersistentDataContainer other, boolean replace);
|
||||
-
|
||||
- /**
|
||||
- * Returns the adapter context this tag container uses.
|
||||
- *
|
||||
- * @return the tag context
|
||||
- */
|
||||
- @NotNull
|
||||
- PersistentDataAdapterContext getAdapterContext();
|
||||
+ // Paper - move to PersistentDataContainerView
|
||||
|
||||
// Paper start - byte array serialization
|
||||
- /**
|
||||
- * Serialize this {@link PersistentDataContainer} instance to a
|
||||
- * byte array.
|
||||
- *
|
||||
- * @return a binary representation of this container
|
||||
- * @throws java.io.IOException if we fail to write this container to a byte array
|
||||
- */
|
||||
- byte @NotNull [] serializeToBytes() throws java.io.IOException;
|
||||
-
|
||||
+ // Paper - move to PersistentDataContainerView
|
||||
/**
|
||||
* Read values from a serialised byte array into this
|
||||
* {@link PersistentDataContainer} instance.
|
||||
diff --git a/src/main/java/org/bukkit/persistence/PersistentDataHolder.java b/src/main/java/org/bukkit/persistence/PersistentDataHolder.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/org/bukkit/persistence/PersistentDataHolder.java
|
||||
+++ b/src/main/java/org/bukkit/persistence/PersistentDataHolder.java
|
||||
@@ -0,0 +0,0 @@ import org.jetbrains.annotations.NotNull;
|
||||
/**
|
||||
* The {@link PersistentDataHolder} interface defines an object that can store
|
||||
* custom persistent meta data on it.
|
||||
+ * <p>Prefer using {@link io.papermc.paper.persistence.PersistentDataViewHolder} for read-only operations
|
||||
+ * as it covers more types.</p>
|
||||
*/
|
||||
-public interface PersistentDataHolder {
|
||||
+public interface PersistentDataHolder extends io.papermc.paper.persistence.PersistentDataViewHolder { // Paper
|
||||
|
||||
/**
|
||||
* Returns a custom tag container capable of storing tags on the object.
|
472
patches/api/Proxy-ItemStack-to-CraftItemStack.patch
Normal file
472
patches/api/Proxy-ItemStack-to-CraftItemStack.patch
Normal file
|
@ -0,0 +1,472 @@
|
|||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jake Potrebic <jake.m.potrebic@gmail.com>
|
||||
Date: Tue, 14 May 2024 11:57:51 -0700
|
||||
Subject: [PATCH] Proxy ItemStack to CraftItemStack
|
||||
|
||||
|
||||
diff --git a/src/main/java/org/bukkit/UnsafeValues.java b/src/main/java/org/bukkit/UnsafeValues.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/org/bukkit/UnsafeValues.java
|
||||
+++ b/src/main/java/org/bukkit/UnsafeValues.java
|
||||
@@ -0,0 +0,0 @@ public interface UnsafeValues {
|
||||
@NotNull java.util.List<net.kyori.adventure.text.Component> computeTooltipLines(@NotNull ItemStack itemStack, @NotNull io.papermc.paper.inventory.tooltip.TooltipContext tooltipContext, @Nullable org.bukkit.entity.Player player); // Paper - expose itemstack tooltip lines
|
||||
|
||||
<A extends Keyed, M> io.papermc.paper.registry.tag.@Nullable Tag<A> getTag(io.papermc.paper.registry.tag.@NotNull TagKey<A> tagKey); // Paper - hack to get tags for non-server backed registries
|
||||
+
|
||||
+ ItemStack createEmptyStack(); // Paper - proxy ItemStack
|
||||
}
|
||||
diff --git a/src/main/java/org/bukkit/inventory/ItemStack.java b/src/main/java/org/bukkit/inventory/ItemStack.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/main/java/org/bukkit/inventory/ItemStack.java
|
||||
+++ b/src/main/java/org/bukkit/inventory/ItemStack.java
|
||||
@@ -0,0 +0,0 @@ import org.jetbrains.annotations.Nullable;
|
||||
* returns false.</b>
|
||||
*/
|
||||
public class ItemStack implements Cloneable, ConfigurationSerializable, Translatable, net.kyori.adventure.text.event.HoverEventSource<net.kyori.adventure.text.event.HoverEvent.ShowItem>, net.kyori.adventure.translation.Translatable { // Paper
|
||||
- private Material type = Material.AIR;
|
||||
- private int amount = 0;
|
||||
+ private ItemStack craftDelegate; // Paper - always delegate to server-backed stack
|
||||
private MaterialData data = null;
|
||||
- private ItemMeta meta;
|
||||
+
|
||||
+ // Paper start - add static factory methods
|
||||
+ /**
|
||||
+ * Creates an itemstack with the specified item type and a count of 1.
|
||||
+ *
|
||||
+ * @param type the item type to use
|
||||
+ * @return a new itemstack
|
||||
+ * @throws IllegalArgumentException if the Material provided is not an item ({@link Material#isItem()})
|
||||
+ */
|
||||
+ @org.jetbrains.annotations.Contract(value = "_ -> new", pure = true)
|
||||
+ public static @NotNull ItemStack of(final @NotNull Material type) {
|
||||
+ return of(type, 1);
|
||||
+ }
|
||||
+
|
||||
+ /**
|
||||
+ * Creates an itemstack with the specified item type and count.
|
||||
+ *
|
||||
+ * @param type the item type to use
|
||||
+ * @param amount the count of items in the stack
|
||||
+ * @return a new itemstack
|
||||
+ * @throws IllegalArgumentException if the Material provided is not an item ({@link Material#isItem()})
|
||||
+ * @throws IllegalArgumentException if the amount is less than 1
|
||||
+ */
|
||||
+ @org.jetbrains.annotations.Contract(value = "_, _ -> new", pure = true)
|
||||
+ public static @NotNull ItemStack of(final @NotNull Material type, final int amount) {
|
||||
+ Preconditions.checkArgument(type.asItemType() != null, type + " isn't an item");
|
||||
+ Preconditions.checkArgument(amount > 0, "amount must be greater than 0");
|
||||
+ return java.util.Objects.requireNonNull(type.asItemType(), type + " is not an item").createItemStack(amount); // Paper - delegate
|
||||
+ }
|
||||
+ // Paper end
|
||||
|
||||
@Utility
|
||||
protected ItemStack() {}
|
||||
@@ -0,0 +0,0 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat
|
||||
* {@link Material#isItem()} returns false.</b>
|
||||
*
|
||||
* @param type item material
|
||||
+ * @apiNote use {@link #of(Material)}
|
||||
+ * @see #of(Material)
|
||||
*/
|
||||
+ @org.jetbrains.annotations.ApiStatus.Obsolete(since = "1.21") // Paper
|
||||
public ItemStack(@NotNull final Material type) {
|
||||
this(type, 1);
|
||||
}
|
||||
@@ -0,0 +0,0 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat
|
||||
*
|
||||
* @param type item material
|
||||
* @param amount stack size
|
||||
+ * @apiNote Use {@link #of(Material, int)}
|
||||
+ * @see #of(Material, int)
|
||||
*/
|
||||
+ @org.jetbrains.annotations.ApiStatus.Obsolete(since = "1.21") // Paper
|
||||
public ItemStack(@NotNull final Material type, final int amount) {
|
||||
this(type, amount, (short) 0);
|
||||
}
|
||||
@@ -0,0 +0,0 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat
|
||||
type = Bukkit.getUnsafe().fromLegacy(new MaterialData(type, data == null ? (byte) damage : data), true);
|
||||
}
|
||||
}
|
||||
- this.type = type;
|
||||
- this.amount = amount;
|
||||
+ this.craftDelegate = ItemStack.of(type, amount); // Paper - create delegate
|
||||
if (damage != 0) {
|
||||
setDurability(damage);
|
||||
}
|
||||
@@ -0,0 +0,0 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat
|
||||
* @param stack the stack to copy
|
||||
* @throws IllegalArgumentException if the specified stack is null or
|
||||
* returns an item meta not created by the item factory
|
||||
+ * @apiNote Use {@link #clone()}
|
||||
+ * @see #clone()
|
||||
*/
|
||||
+ @org.jetbrains.annotations.ApiStatus.Obsolete(since = "1.21") // Paper
|
||||
public ItemStack(@NotNull final ItemStack stack) throws IllegalArgumentException {
|
||||
Preconditions.checkArgument(stack != null, "Cannot copy null stack");
|
||||
- this.type = stack.getType();
|
||||
- this.amount = stack.getAmount();
|
||||
- if (this.type.isLegacy()) {
|
||||
+ this.craftDelegate = stack.clone(); // Paper - delegate
|
||||
+ if (stack.getType().isLegacy()) {
|
||||
this.data = stack.getData();
|
||||
}
|
||||
- if (stack.hasItemMeta()) {
|
||||
- setItemMeta0(stack.getItemMeta(), type);
|
||||
- }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -0,0 +0,0 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat
|
||||
*
|
||||
* @return Type of the items in this stack
|
||||
*/
|
||||
- @Utility
|
||||
@NotNull
|
||||
public Material getType() {
|
||||
- return type;
|
||||
+ return this.craftDelegate.getType(); // Paper - delegate
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -0,0 +0,0 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat
|
||||
* Using this method in ItemStacks passed in events will result in undefined behavior.
|
||||
* @see ItemStack#withType(Material)
|
||||
*/
|
||||
- @Utility
|
||||
@Deprecated // Paper
|
||||
public void setType(@NotNull Material type) {
|
||||
Preconditions.checkArgument(type != null, "Material cannot be null");
|
||||
- this.type = type;
|
||||
- if (this.meta != null) {
|
||||
- this.meta = Bukkit.getItemFactory().asMetaFor(meta, type);
|
||||
- }
|
||||
- if (type.isLegacy()) {
|
||||
- createData((byte) 0);
|
||||
- } else {
|
||||
- this.data = null;
|
||||
- }
|
||||
+ this.craftDelegate.setType(type); // Paper - delegate
|
||||
}
|
||||
// Paper start
|
||||
/**
|
||||
@@ -0,0 +0,0 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat
|
||||
@NotNull
|
||||
@org.jetbrains.annotations.Contract(value = "_ -> new", pure = true)
|
||||
public ItemStack withType(@NotNull Material type) {
|
||||
- ItemStack itemStack = new ItemStack(type, this.amount);
|
||||
- if (this.hasItemMeta()) {
|
||||
- itemStack.setItemMeta(this.getItemMeta());
|
||||
- }
|
||||
-
|
||||
- return itemStack;
|
||||
+ return this.craftDelegate.withType(type); // Paper - delegate
|
||||
}
|
||||
// Paper end
|
||||
|
||||
@@ -0,0 +0,0 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat
|
||||
* @return Amount of items in this stack
|
||||
*/
|
||||
public int getAmount() {
|
||||
- return amount;
|
||||
+ return this.craftDelegate.getAmount(); // Paper - delegate
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -0,0 +0,0 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat
|
||||
* @param amount New amount of items in this stack
|
||||
*/
|
||||
public void setAmount(int amount) {
|
||||
- this.amount = amount;
|
||||
+ this.craftDelegate.setAmount(amount); // Paper - delegate
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -0,0 +0,0 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat
|
||||
*/
|
||||
@Deprecated
|
||||
public void setDurability(final short durability) {
|
||||
- ItemMeta meta = getItemMeta();
|
||||
- if (meta != null) {
|
||||
- ((Damageable) meta).setDamage(durability);
|
||||
- setItemMeta(meta);
|
||||
- }
|
||||
+ this.craftDelegate.setDurability(durability); // Paper - delegate
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -0,0 +0,0 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat
|
||||
*/
|
||||
@Deprecated
|
||||
public short getDurability() {
|
||||
- ItemMeta meta = getItemMeta();
|
||||
- return (meta == null) ? 0 : (short) ((Damageable) meta).getDamage();
|
||||
+ return this.craftDelegate.getDurability(); // Paper - delegate
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -0,0 +0,0 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat
|
||||
*
|
||||
* @return The maximum you can stack this item to.
|
||||
*/
|
||||
- @Utility
|
||||
public int getMaxStackSize() {
|
||||
- if (meta != null && meta.hasMaxStackSize()) {
|
||||
- return meta.getMaxStackSize();
|
||||
- }
|
||||
-
|
||||
- return getType().getMaxStackSize();
|
||||
+ return this.craftDelegate.getMaxStackSize(); // Paper - delegate
|
||||
}
|
||||
|
||||
private void createData(final byte data) {
|
||||
- this.data = type.getNewData(data);
|
||||
+ this.data = this.craftDelegate.getType().getNewData(data); // Paper
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -0,0 +0,0 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat
|
||||
}
|
||||
|
||||
@Override
|
||||
- @Utility
|
||||
public boolean equals(Object obj) {
|
||||
- if (this == obj) {
|
||||
- return true;
|
||||
- }
|
||||
- if (!(obj instanceof ItemStack)) {
|
||||
- return false;
|
||||
- }
|
||||
-
|
||||
- ItemStack stack = (ItemStack) obj;
|
||||
- return getAmount() == stack.getAmount() && isSimilar(stack);
|
||||
+ return this.craftDelegate.equals(obj); // Paper - delegate
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -0,0 +0,0 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat
|
||||
* @param stack the item stack to compare to
|
||||
* @return true if the two stacks are equal, ignoring the amount
|
||||
*/
|
||||
- @Utility
|
||||
public boolean isSimilar(@Nullable ItemStack stack) {
|
||||
- if (stack == null) {
|
||||
- return false;
|
||||
- }
|
||||
- if (stack == this) {
|
||||
- return true;
|
||||
- }
|
||||
- Material comparisonType = (this.type.isLegacy()) ? Bukkit.getUnsafe().fromLegacy(this.getData(), true) : this.type; // This may be called from legacy item stacks, try to get the right material
|
||||
- return comparisonType == stack.getType() && /* getDurability() == stack.getDurability() && */hasItemMeta() == stack.hasItemMeta() && (hasItemMeta() ? Bukkit.getItemFactory().equals(getItemMeta(), stack.getItemMeta()) : true); // Paper - remove redundant item durability check
|
||||
+ return this.craftDelegate.isSimilar(stack); // Paper - delegate
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ItemStack clone() {
|
||||
- try {
|
||||
- ItemStack itemStack = (ItemStack) super.clone();
|
||||
-
|
||||
- if (this.meta != null) {
|
||||
- itemStack.meta = this.meta.clone();
|
||||
- }
|
||||
-
|
||||
- if (this.data != null) {
|
||||
- itemStack.data = this.data.clone();
|
||||
- }
|
||||
-
|
||||
- return itemStack;
|
||||
- } catch (CloneNotSupportedException e) {
|
||||
- throw new Error(e);
|
||||
- }
|
||||
+ return this.craftDelegate.clone(); // Paper - delegate
|
||||
}
|
||||
|
||||
@Override
|
||||
- @Utility
|
||||
public int hashCode() {
|
||||
- int hash = 1;
|
||||
-
|
||||
- hash = hash * 31 + getType().hashCode();
|
||||
- hash = hash * 31 + getAmount();
|
||||
- hash = hash * 31 + (getDurability() & 0xffff);
|
||||
- hash = hash * 31 + (hasItemMeta() ? (meta == null ? getItemMeta().hashCode() : meta.hashCode()) : 0);
|
||||
-
|
||||
- return hash;
|
||||
+ return this.craftDelegate.hashCode(); // Paper - delegate
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -0,0 +0,0 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat
|
||||
* @return True if this has the given enchantment
|
||||
*/
|
||||
public boolean containsEnchantment(@NotNull Enchantment ench) {
|
||||
- return meta == null ? false : meta.hasEnchant(ench);
|
||||
+ return this.craftDelegate.containsEnchantment(ench); // Paper - delegate
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -0,0 +0,0 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat
|
||||
* @return Level of the enchantment, or 0
|
||||
*/
|
||||
public int getEnchantmentLevel(@NotNull Enchantment ench) {
|
||||
- return meta == null ? 0 : meta.getEnchantLevel(ench);
|
||||
+ return this.craftDelegate.getEnchantmentLevel(ench); // Paper - delegate
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -0,0 +0,0 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat
|
||||
*/
|
||||
@NotNull
|
||||
public Map<Enchantment, Integer> getEnchantments() {
|
||||
- return meta == null ? ImmutableMap.<Enchantment, Integer>of() : meta.getEnchants();
|
||||
+ return this.craftDelegate.getEnchantments(); // Paper - delegate
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -0,0 +0,0 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat
|
||||
* @param level Level of the enchantment
|
||||
*/
|
||||
public void addUnsafeEnchantment(@NotNull Enchantment ench, int level) {
|
||||
- ItemMeta itemMeta = (meta == null ? meta = Bukkit.getItemFactory().getItemMeta(type) : meta);
|
||||
- if (itemMeta != null) {
|
||||
- itemMeta.addEnchant(ench, level, true);
|
||||
- }
|
||||
+ this.craftDelegate.addUnsafeEnchantment(ench, level); // Paper - delegate
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -0,0 +0,0 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat
|
||||
* @return Previous level, or 0
|
||||
*/
|
||||
public int removeEnchantment(@NotNull Enchantment ench) {
|
||||
- int level = getEnchantmentLevel(ench);
|
||||
- if (level == 0 || meta == null) {
|
||||
- return level;
|
||||
- }
|
||||
- meta.removeEnchant(ench);
|
||||
- return level;
|
||||
+ return this.craftDelegate.removeEnchantment(ench); // Paper - delegate
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all enchantments on this ItemStack.
|
||||
*/
|
||||
public void removeEnchantments() {
|
||||
- if (meta == null) {
|
||||
- return;
|
||||
- }
|
||||
-
|
||||
- meta.removeEnchantments();
|
||||
+ this.craftDelegate.removeEnchantments(); // Paper - delegate
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -0,0 +0,0 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat
|
||||
*/
|
||||
@UndefinedNullability // Paper
|
||||
public ItemMeta getItemMeta() {
|
||||
- return this.meta == null ? Bukkit.getItemFactory().getItemMeta(this.type) : this.meta.clone();
|
||||
+ return this.craftDelegate.getItemMeta(); // Paper - delegate
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -0,0 +0,0 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat
|
||||
* @return Returns true if some meta data has been set for this item
|
||||
*/
|
||||
public boolean hasItemMeta() {
|
||||
- return !Bukkit.getItemFactory().equals(meta, null);
|
||||
+ return this.craftDelegate.hasItemMeta(); // Paper - delegate
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -0,0 +0,0 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat
|
||||
* the {@link ItemFactory}
|
||||
*/
|
||||
public boolean setItemMeta(@Nullable ItemMeta itemMeta) {
|
||||
- return setItemMeta0(itemMeta, type);
|
||||
+ return this.craftDelegate.setItemMeta(itemMeta); // Paper - delegate
|
||||
}
|
||||
|
||||
- /*
|
||||
- * Cannot be overridden, so it's safe for constructor call
|
||||
- */
|
||||
- private boolean setItemMeta0(@Nullable ItemMeta itemMeta, @NotNull Material material) {
|
||||
- if (itemMeta == null) {
|
||||
- this.meta = null;
|
||||
- return true;
|
||||
- }
|
||||
- if (!Bukkit.getItemFactory().isApplicable(itemMeta, material)) {
|
||||
- return false;
|
||||
- }
|
||||
- this.meta = Bukkit.getItemFactory().asMetaFor(itemMeta, material);
|
||||
-
|
||||
- if (this.meta == itemMeta) {
|
||||
- this.meta = itemMeta.clone();
|
||||
- }
|
||||
-
|
||||
- return true;
|
||||
- }
|
||||
+ // Paper - delegate
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
@@ -0,0 +0,0 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat
|
||||
}
|
||||
|
||||
public int getMaxItemUseDuration(@NotNull final org.bukkit.entity.LivingEntity entity) {
|
||||
- if (type == null || type == Material.AIR || !type.isItem()) {
|
||||
- return 0;
|
||||
- }
|
||||
- // Requires access to NMS
|
||||
- return ensureServerConversions().getMaxItemUseDuration(entity);
|
||||
+ return this.craftDelegate.getMaxItemUseDuration(entity); // Paper - delegate
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -0,0 +0,0 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat
|
||||
*/
|
||||
@NotNull
|
||||
public static ItemStack empty() {
|
||||
- return new ItemStack();
|
||||
+ //noinspection deprecation
|
||||
+ return Bukkit.getUnsafe().createEmptyStack(); // Paper - proxy ItemStack
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -0,0 +0,0 @@ public class ItemStack implements Cloneable, ConfigurationSerializable, Translat
|
||||
* it is either air or the stack has a size of 0.
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
- return type.isAir() || amount <= 0;
|
||||
+ return this.craftDelegate.isEmpty(); // Paper - delegate
|
||||
}
|
||||
// Paper end
|
||||
// Paper start - expose itemstack tooltip lines
|
||||
diff --git a/src/test/java/org/bukkit/configuration/ConfigurationSectionTest.java b/src/test/java/org/bukkit/configuration/ConfigurationSectionTest.java
|
||||
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
|
||||
--- a/src/test/java/org/bukkit/configuration/ConfigurationSectionTest.java
|
||||
+++ b/src/test/java/org/bukkit/configuration/ConfigurationSectionTest.java
|
||||
@@ -0,0 +0,0 @@ public abstract class ConfigurationSectionTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
+ @org.junit.jupiter.api.Disabled("ItemStack can't exist without the Server, test moved to server")
|
||||
public void testGetItemStack_String() {
|
||||
ConfigurationSection section = getConfigurationSection();
|
||||
String key = "exists";
|
||||
@@ -0,0 +0,0 @@ public abstract class ConfigurationSectionTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
+ @org.junit.jupiter.api.Disabled("ItemStack can't exist without the Server, test moved to server")
|
||||
public void testGetItemStack_String_ItemStack() {
|
||||
ConfigurationSection section = getConfigurationSection();
|
||||
String key = "exists";
|
||||
@@ -0,0 +0,0 @@ public abstract class ConfigurationSectionTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
+ @org.junit.jupiter.api.Disabled("ItemStack can't exist without the Server, test moved to server")
|
||||
public void testIsItemStack() {
|
||||
ConfigurationSection section = getConfigurationSection();
|
||||
String key = "exists";
|
Loading…
Add table
Add a link
Reference in a new issue