From dd941cc40a25a4c6217f09c121b891962726f3ee Mon Sep 17 00:00:00 2001 From: Jake Potrebic Date: Sun, 11 Aug 2024 13:51:37 -0700 Subject: [PATCH] Re-add patches for can-place/can-destroy API (#11238) * Re-add patches for can-place/can-destroy API This API is all deprecated for removal and has to be replaced as the structure of it has too radically changed * update patches * add link to MaterialRerouting * Deprecation --------- Co-authored-by: Bjarne Koll --- ...CanPlaceOn-and-CanDestroy-NBT-values.patch | 332 +++++++++++++++ ...CanPlaceOn-and-CanDestroy-NBT-values.patch | 397 ------------------ .../server/0981-Adopt-MaterialRerouting.patch | 6 +- ...CanPlaceOn-and-CanDestroy-NBT-values.patch | 155 +++++++ 4 files changed, 490 insertions(+), 400 deletions(-) create mode 100644 patches/api/0482-Add-an-API-for-CanPlaceOn-and-CanDestroy-NBT-values.patch delete mode 100644 patches/removed/1.20.5/0259-Add-API-for-CanPlaceOn-and-CanDestroy-NBT-values.patch create mode 100644 patches/server/1044-Add-API-for-CanPlaceOn-and-CanDestroy-NBT-values.patch diff --git a/patches/api/0482-Add-an-API-for-CanPlaceOn-and-CanDestroy-NBT-values.patch b/patches/api/0482-Add-an-API-for-CanPlaceOn-and-CanDestroy-NBT-values.patch new file mode 100644 index 0000000000..3dd2df1411 --- /dev/null +++ b/patches/api/0482-Add-an-API-for-CanPlaceOn-and-CanDestroy-NBT-values.patch @@ -0,0 +1,332 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Mark Vainomaa +Date: Wed, 12 Sep 2018 18:53:35 +0300 +Subject: [PATCH] Add an API for CanPlaceOn and CanDestroy NBT values + + +diff --git a/src/main/java/com/destroystokyo/paper/Namespaced.java b/src/main/java/com/destroystokyo/paper/Namespaced.java +new file mode 100644 +index 0000000000000000000000000000000000000000..e708cc48f480e91a60834897e447e4a2fc1244d4 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/Namespaced.java +@@ -0,0 +1,41 @@ ++package com.destroystokyo.paper; ++ ++import org.jetbrains.annotations.NotNull; ++ ++/** ++ * Represents a namespaced resource, see {@link org.bukkit.NamespacedKey} for single elements ++ * or {@link com.destroystokyo.paper.NamespacedTag} for a collection of elements ++ * ++ * Namespaces may only contain lowercase alphanumeric characters, periods, ++ * underscores, and hyphens. ++ *

++ * Keys may only contain lowercase alphanumeric characters, periods, ++ * underscores, hyphens, and forward slashes. ++ *

++ * You should not be implementing this interface yourself, use {@link org.bukkit.NamespacedKey} ++ * or {@link com.destroystokyo.paper.NamespacedTag} as needed instead. ++ */ ++@Deprecated(forRemoval = true, since = "1.20.6") ++public interface Namespaced { ++ /** ++ * Gets the namespace this resource is a part of ++ *

++ * This is contractually obligated to only contain lowercase alphanumeric characters, ++ * periods, underscores, and hyphens. ++ * ++ * @return resource namespace ++ */ ++ @NotNull ++ String getNamespace(); ++ ++ /** ++ * Gets the key corresponding to this resource ++ *

++ * This is contractually obligated to only contain lowercase alphanumeric characters, ++ * periods, underscores, hyphens, and forward slashes. ++ * ++ * @return resource key ++ */ ++ @NotNull ++ String getKey(); ++} +diff --git a/src/main/java/com/destroystokyo/paper/NamespacedTag.java b/src/main/java/com/destroystokyo/paper/NamespacedTag.java +new file mode 100644 +index 0000000000000000000000000000000000000000..c976995a0fceaf0cbddd399906a866747b12a202 +--- /dev/null ++++ b/src/main/java/com/destroystokyo/paper/NamespacedTag.java +@@ -0,0 +1,143 @@ ++package com.destroystokyo.paper; ++ ++import com.google.common.base.Preconditions; ++import java.util.Locale; ++import java.util.UUID; ++import java.util.regex.Pattern; ++import org.bukkit.plugin.Plugin; ++import org.jetbrains.annotations.NotNull; ++ ++/** ++ * Represents a String based key pertaining to a tagged entry. Consists of two components - a namespace ++ * and a key. ++ *

++ * Namespaces may only contain lowercase alphanumeric characters, periods, ++ * underscores, and hyphens. ++ *

++ * Keys may only contain lowercase alphanumeric characters, periods, ++ * underscores, hyphens, and forward slashes. ++ * ++ */ ++// Paper - entire class, based on org.bukkit.NamespacedKey ++@Deprecated(forRemoval = true, since = "1.20.6") ++public final class NamespacedTag implements com.destroystokyo.paper.Namespaced { ++ ++ /** ++ * The namespace representing all inbuilt keys. ++ */ ++ public static final String MINECRAFT = "minecraft"; ++ /** ++ * The namespace representing all keys generated by Bukkit for backwards ++ * compatibility measures. ++ */ ++ public static final String BUKKIT = "bukkit"; ++ // ++ private static final Pattern VALID_NAMESPACE = Pattern.compile("[a-z0-9._-]+"); ++ private static final Pattern VALID_KEY = Pattern.compile("[a-z0-9/._-]+"); ++ // ++ private final String namespace; ++ private final String key; ++ ++ /** ++ * Create a key in a specific namespace. ++ * ++ * @param namespace String representing a grouping of keys ++ * @param key Name for this specific key ++ * @deprecated should never be used by plugins, for internal use only!! ++ */ ++ @Deprecated ++ public NamespacedTag(@NotNull String namespace, @NotNull String key) { ++ Preconditions.checkArgument(namespace != null && VALID_NAMESPACE.matcher(namespace).matches(), "Invalid namespace. Must be [a-z0-9._-]: %s", namespace); ++ Preconditions.checkArgument(key != null && VALID_KEY.matcher(key).matches(), "Invalid key. Must be [a-z0-9/._-]: %s", key); ++ ++ this.namespace = namespace; ++ this.key = key; ++ ++ String string = toString(); ++ Preconditions.checkArgument(string.length() < 256, "NamespacedTag must be less than 256 characters", string); ++ } ++ ++ /** ++ * Create a key in the plugin's namespace. ++ *

++ * Namespaces may only contain lowercase alphanumeric characters, periods, ++ * underscores, and hyphens. ++ *

++ * Keys may only contain lowercase alphanumeric characters, periods, ++ * underscores, hyphens, and forward slashes. ++ * ++ * @param plugin the plugin to use for the namespace ++ * @param key the key to create ++ */ ++ public NamespacedTag(@NotNull Plugin plugin, @NotNull String key) { ++ Preconditions.checkArgument(plugin != null, "Plugin cannot be null"); ++ Preconditions.checkArgument(key != null, "Key cannot be null"); ++ ++ this.namespace = plugin.getName().toLowerCase(Locale.ROOT); ++ this.key = key.toLowerCase().toLowerCase(Locale.ROOT); ++ ++ // Check validity after normalization ++ Preconditions.checkArgument(VALID_NAMESPACE.matcher(this.namespace).matches(), "Invalid namespace. Must be [a-z0-9._-]: %s", this.namespace); ++ Preconditions.checkArgument(VALID_KEY.matcher(this.key).matches(), "Invalid key. Must be [a-z0-9/._-]: %s", this.key); ++ ++ String string = toString(); ++ Preconditions.checkArgument(string.length() < 256, "NamespacedTag must be less than 256 characters (%s)", string); ++ } ++ ++ @NotNull ++ public String getNamespace() { ++ return namespace; ++ } ++ ++ @NotNull ++ public String getKey() { ++ return key; ++ } ++ ++ @Override ++ public int hashCode() { ++ int hash = 7; ++ hash = 47 * hash + this.namespace.hashCode(); ++ hash = 47 * hash + this.key.hashCode(); ++ return hash; ++ } ++ ++ @Override ++ public boolean equals(Object obj) { ++ if (obj == null) { ++ return false; ++ } ++ if (getClass() != obj.getClass()) { ++ return false; ++ } ++ final NamespacedTag other = (NamespacedTag) obj; ++ return this.namespace.equals(other.namespace) && this.key.equals(other.key); ++ } ++ ++ @Override ++ public String toString() { ++ return "#" + this.namespace + ":" + this.key; ++ } ++ ++ /** ++ * Return a new random key in the {@link #BUKKIT} namespace. ++ * ++ * @return new key ++ * @deprecated should never be used by plugins, for internal use only!! ++ */ ++ @Deprecated ++ public static NamespacedTag randomKey() { ++ return new NamespacedTag(BUKKIT, UUID.randomUUID().toString()); ++ } ++ ++ /** ++ * Get a key in the Minecraft namespace. ++ * ++ * @param key the key to use ++ * @return new key in the Minecraft namespace ++ */ ++ @NotNull ++ public static NamespacedTag minecraft(@NotNull String key) { ++ return new NamespacedTag(MINECRAFT, key); ++ } ++} +diff --git a/src/main/java/org/bukkit/NamespacedKey.java b/src/main/java/org/bukkit/NamespacedKey.java +index 7ff6d60deb129e23b2a4d772aee123eb6c0b6433..52a2763773b234c581b2dcc6f0584f8d8b0fbc60 100644 +--- a/src/main/java/org/bukkit/NamespacedKey.java ++++ b/src/main/java/org/bukkit/NamespacedKey.java +@@ -19,7 +19,7 @@ import org.jetbrains.annotations.Nullable; + * underscores, hyphens, and forward slashes. + * + */ +-public final class NamespacedKey implements net.kyori.adventure.key.Key { // Paper - implement Key ++public final class NamespacedKey implements net.kyori.adventure.key.Key, com.destroystokyo.paper.Namespaced { // Paper - implement Key and Namespaced + + /** + * The namespace representing all inbuilt keys. +@@ -121,11 +121,13 @@ public final class NamespacedKey implements net.kyori.adventure.key.Key { // Pap + } + + @NotNull ++ @Override // Paper + public String getNamespace() { + return namespace; + } + + @NotNull ++ @Override // Paper + public String getKey() { + return key; + } +diff --git a/src/main/java/org/bukkit/inventory/meta/ItemMeta.java b/src/main/java/org/bukkit/inventory/meta/ItemMeta.java +index 5d5fcb2720b62e47d47f441032c4de02574b051a..f5541454ba5e508a72c83989c6feaef5406e2535 100644 +--- a/src/main/java/org/bukkit/inventory/meta/ItemMeta.java ++++ b/src/main/java/org/bukkit/inventory/meta/ItemMeta.java +@@ -806,4 +806,98 @@ public interface ItemMeta extends Cloneable, ConfigurationSerializable, Persiste + @SuppressWarnings("javadoc") + @NotNull + ItemMeta clone(); ++ ++ // Paper start - Add an API for can-place-on/can-break adventure mode predicates ++ /** ++ * Gets set of materials what given item can destroy in {@link org.bukkit.GameMode#ADVENTURE} ++ * ++ * @return Set of materials ++ * @deprecated this API is unsupported and will be replaced, its usage may result in data loss related to place/destroy predicates. ++ */ ++ @Deprecated(forRemoval = true, since = "1.14") ++ Set getCanDestroy(); ++ ++ /** ++ * Sets set of materials what given item can destroy in {@link org.bukkit.GameMode#ADVENTURE} ++ * ++ * @param canDestroy Set of materials ++ * @deprecated this API is unsupported and will be replaced, its usage may result in data loss related to place/destroy predicates. ++ */ ++ @Deprecated(forRemoval = true, since = "1.14") ++ void setCanDestroy(Set canDestroy); ++ ++ /** ++ * Gets set of materials where given item can be placed on in {@link org.bukkit.GameMode#ADVENTURE} ++ * ++ * @return Set of materials ++ * @deprecated this API is unsupported and will be replaced, its usage may result in data loss related to place/destroy predicates. ++ */ ++ @Deprecated(forRemoval = true, since = "1.14") ++ Set getCanPlaceOn(); ++ ++ /** ++ * Sets set of materials where given item can be placed on in {@link org.bukkit.GameMode#ADVENTURE} ++ * ++ * @param canPlaceOn Set of materials ++ * @deprecated this API is unsupported and will be replaced, its usage may result in data loss related to place/destroy predicates. ++ */ ++ @Deprecated(forRemoval = true, since = "1.14") ++ void setCanPlaceOn(Set canPlaceOn); ++ ++ /** ++ * Gets the collection of namespaced keys that the item can destroy in {@link org.bukkit.GameMode#ADVENTURE} ++ * ++ * @return Set of {@link com.destroystokyo.paper.Namespaced} ++ * @deprecated this API is unsupported and will be replaced, its usage may result in data loss related to place/destroy predicates. ++ */ ++ @Deprecated(forRemoval = true, since = "1.20.6") ++ @NotNull ++ Set getDestroyableKeys(); ++ ++ /** ++ * Sets the collection of namespaced keys that the item can destroy in {@link org.bukkit.GameMode#ADVENTURE} ++ * ++ * @param canDestroy Collection of {@link com.destroystokyo.paper.Namespaced} ++ * @deprecated this API is unsupported and will be replaced, its usage may result in data loss related to place/destroy predicates. ++ */ ++ @Deprecated(forRemoval = true, since = "1.20.6") ++ void setDestroyableKeys(@NotNull Collection canDestroy); ++ ++ /** ++ * Gets the collection of namespaced keys that the item can be placed on in {@link org.bukkit.GameMode#ADVENTURE} ++ * ++ * @return Set of {@link com.destroystokyo.paper.Namespaced} ++ * @deprecated this API is unsupported and will be replaced, its usage may result in data loss related to place/destroy predicates. ++ */ ++ @NotNull ++ @Deprecated(forRemoval = true, since = "1.20.6") ++ Set getPlaceableKeys(); ++ ++ /** ++ * Sets the set of namespaced keys that the item can be placed on in {@link org.bukkit.GameMode#ADVENTURE} ++ * ++ * @param canPlaceOn Collection of {@link com.destroystokyo.paper.Namespaced} ++ * @deprecated this API is unsupported and will be replaced, its usage may result in data loss related to place/destroy predicates. ++ */ ++ @Deprecated(forRemoval = true, since = "1.20.6") ++ void setPlaceableKeys(@NotNull Collection canPlaceOn); ++ ++ /** ++ * Checks for the existence of any keys that the item can be placed on ++ * ++ * @return true if this item has placeable keys ++ * @deprecated this API is unsupported and will be replaced ++ */ ++ @Deprecated(forRemoval = true, since = "1.20.6") ++ boolean hasPlaceableKeys(); ++ ++ /** ++ * Checks for the existence of any keys that the item can destroy ++ * ++ * @return true if this item has destroyable keys ++ * @deprecated this API is unsupported and will be replaced ++ */ ++ @Deprecated(forRemoval = true, since = "1.20.6") ++ boolean hasDestroyableKeys(); ++ // Paper end - Add an API for can-place-on/can-break adventure mode predicates + } diff --git a/patches/removed/1.20.5/0259-Add-API-for-CanPlaceOn-and-CanDestroy-NBT-values.patch b/patches/removed/1.20.5/0259-Add-API-for-CanPlaceOn-and-CanDestroy-NBT-values.patch deleted file mode 100644 index f179b48bd7..0000000000 --- a/patches/removed/1.20.5/0259-Add-API-for-CanPlaceOn-and-CanDestroy-NBT-values.patch +++ /dev/null @@ -1,397 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Mark Vainomaa -Date: Wed, 12 Sep 2018 18:53:55 +0300 -Subject: [PATCH] Add API for CanPlaceOn and CanDestroy NBT values - - -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java -index 1920cf7ad846f57cd278cb9a72dce03f3d014fbb..7cf1153ae532a9d53ee85b05f77ed74b94cf5fbc 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java -@@ -85,6 +85,12 @@ import org.bukkit.persistence.PersistentDataContainer; - import static org.spigotmc.ValidateUtils.*; - // Spigot end - -+// Paper start -+import com.destroystokyo.paper.Namespaced; -+import com.destroystokyo.paper.NamespacedTag; -+import java.util.Collections; -+// Paper end -+ - /** - * Children must include the following: - * -@@ -273,6 +279,10 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - @Specific(Specific.To.NBT) - static final ItemMetaKey BLOCK_DATA = new ItemMetaKey("BlockStateTag"); - static final ItemMetaKey BUKKIT_CUSTOM_TAG = new ItemMetaKey("PublicBukkitValues"); -+ // Paper start - Add API for CanPlaceOn and CanDestroy NBT values -+ static final ItemMetaKey CAN_DESTROY = new ItemMetaKey("CanDestroy"); -+ static final ItemMetaKey CAN_PLACE_ON = new ItemMetaKey("CanPlaceOn"); -+ // Paper end - Add API for CanPlaceOn and CanDestroy NBT values - - // We store the raw original JSON representation of all text data. See SPIGOT-5063, SPIGOT-5656, SPIGOT-5304 - private String displayName; -@@ -286,6 +296,10 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - private int hideFlag; - private boolean unbreakable; - private int damage; -+ // Paper start - Add API for CanPlaceOn and CanDestroy NBT values -+ private Set placeableKeys = Sets.newHashSet(); -+ private Set destroyableKeys = Sets.newHashSet(); -+ // Paper end - Add API for CanPlaceOn and CanDestroy NBT values - - private static final Set HANDLED_TAGS = Sets.newHashSet(); - private static final CraftPersistentDataTypeRegistry DATA_TYPE_REGISTRY = new CraftPersistentDataTypeRegistry(); -@@ -323,6 +337,15 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - this.hideFlag = meta.hideFlag; - this.unbreakable = meta.unbreakable; - this.damage = meta.damage; -+ // Paper start - Add API for CanPlaceOn and CanDestroy NBT values -+ if (meta.hasPlaceableKeys()) { -+ this.placeableKeys = new java.util.HashSet<>(meta.placeableKeys); -+ } -+ -+ if (meta.hasDestroyableKeys()) { -+ this.destroyableKeys = new java.util.HashSet<>(meta.destroyableKeys); -+ } -+ // Paper end - Add API for CanPlaceOn and CanDestroy NBT values - this.unhandledTags.putAll(meta.unhandledTags); - this.persistentDataContainer.putAll(meta.persistentDataContainer.getRaw()); - -@@ -386,6 +409,31 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - this.persistentDataContainer.put(key, compound.get(key).copy()); - } - } -+ // Paper start - Add API for CanPlaceOn and CanDestroy NBT values -+ if (tag.contains(CAN_DESTROY.NBT)) { -+ ListTag list = tag.getList(CAN_DESTROY.NBT, CraftMagicNumbers.NBT.TAG_STRING); -+ for (int i = 0; i < list.size(); i++) { -+ Namespaced namespaced = this.blockKeyFromString(list.getString(i)); -+ if (namespaced == null) { -+ continue; -+ } -+ -+ this.destroyableKeys.add(namespaced); -+ } -+ } -+ -+ if (tag.contains(CAN_PLACE_ON.NBT)) { -+ ListTag list = tag.getList(CAN_PLACE_ON.NBT, CraftMagicNumbers.NBT.TAG_STRING); -+ for (int i = 0; i < list.size(); i++) { -+ Namespaced namespaced = this.blockKeyFromString(list.getString(i)); -+ if (namespaced == null) { -+ continue; -+ } -+ -+ this.placeableKeys.add(namespaced); -+ } -+ } -+ // Paper end - Add API for CanPlaceOn and CanDestroy NBT values - - Set keys = tag.getAllKeys(); - for (String key : keys) { -@@ -524,6 +572,34 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - this.setDamage(damage); - } - -+ // Paper start - Add API for CanPlaceOn and CanDestroy NBT values -+ Iterable canPlaceOnSerialized = SerializableMeta.getObject(Iterable.class, map, CAN_PLACE_ON.BUKKIT, true); -+ if (canPlaceOnSerialized != null) { -+ for (Object canPlaceOnElement : canPlaceOnSerialized) { -+ String canPlaceOnRaw = (String) canPlaceOnElement; -+ Namespaced value = this.blockKeyFromString(canPlaceOnRaw); -+ if (value == null) { -+ continue; -+ } -+ -+ this.placeableKeys.add(value); -+ } -+ } -+ -+ Iterable canDestroySerialized = SerializableMeta.getObject(Iterable.class, map, CAN_DESTROY.BUKKIT, true); -+ if (canDestroySerialized != null) { -+ for (Object canDestroyElement : canDestroySerialized) { -+ String canDestroyRaw = (String) canDestroyElement; -+ Namespaced value = this.blockKeyFromString(canDestroyRaw); -+ if (value == null) { -+ continue; -+ } -+ -+ this.destroyableKeys.add(value); -+ } -+ } -+ // Paper end - Add API for CanPlaceOn and CanDestroy NBT values -+ - String internal = SerializableMeta.getString(map, "internal", true); - if (internal != null) { - ByteArrayInputStream buf = new ByteArrayInputStream(Base64.getDecoder().decode(internal)); -@@ -652,6 +728,23 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - if (this.hasDamage()) { - itemTag.putInt(CraftMetaItem.DAMAGE.NBT, this.damage); - } -+ // Paper start - Add API for CanPlaceOn and CanDestroy NBT values -+ if (hasPlaceableKeys()) { -+ List items = this.placeableKeys.stream() -+ .map(this::serializeNamespaced) -+ .collect(java.util.stream.Collectors.toList()); -+ -+ itemTag.put(CAN_PLACE_ON.NBT, createNonComponentStringList(items)); -+ } -+ -+ if (hasDestroyableKeys()) { -+ List items = this.destroyableKeys.stream() -+ .map(this::serializeNamespaced) -+ .collect(java.util.stream.Collectors.toList()); -+ -+ itemTag.put(CAN_DESTROY.NBT, createNonComponentStringList(items)); -+ } -+ // Paper end - Add API for CanPlaceOn and CanDestroy NBT values - - for (Map.Entry e : this.unhandledTags.entrySet()) { - itemTag.put(e.getKey(), e.getValue()); -@@ -668,6 +761,21 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - } - } - -+ // Paper start - Add API for CanPlaceOn and CanDestroy NBT values -+ static ListTag createNonComponentStringList(List list) { -+ if (list == null || list.isEmpty()) { -+ return null; -+ } -+ -+ ListTag tagList = new ListTag(); -+ for (String value : list) { -+ tagList.add(StringTag.valueOf(value)); // Paper - NBTTagString.of(String str) -+ } -+ -+ return tagList; -+ } -+ // Paper end - Add API for CanPlaceOn and CanDestroy NBT values -+ - ListTag createStringList(List list) { - if (list == null) { - return null; -@@ -751,7 +859,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - - @Overridden - boolean isEmpty() { -- return !(this.hasDisplayName() || this.hasLocalizedName() || this.hasEnchants() || (this.lore != null) || this.hasCustomModelData() || this.hasBlockData() || this.hasRepairCost() || !this.unhandledTags.isEmpty() || !this.persistentDataContainer.isEmpty() || this.hideFlag != 0 || this.isUnbreakable() || this.hasDamage() || this.hasAttributeModifiers()); -+ return !(this.hasDisplayName() || this.hasLocalizedName() || this.hasEnchants() || (this.lore != null) || this.hasCustomModelData() || this.hasBlockData() || this.hasRepairCost() || !this.unhandledTags.isEmpty() || !this.persistentDataContainer.isEmpty() || this.hideFlag != 0 || this.isUnbreakable() || this.hasDamage() || this.hasAttributeModifiers() || this.hasPlaceableKeys() || this.hasDestroyableKeys()); // Paper - Implement an API for CanPlaceOn and CanDestroy NBT values - } - - // Paper start -@@ -1223,7 +1331,11 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - && (this.hideFlag == that.hideFlag) - && (this.isUnbreakable() == that.isUnbreakable()) - && (this.hasDamage() ? that.hasDamage() && this.damage == that.damage : !that.hasDamage()) -- && (this.version == that.version); -+ && (this.version == that.version) -+ // Paper start - Implement an API for CanPlaceOn and CanDestroy NBT values -+ && (this.hasPlaceableKeys() ? that.hasPlaceableKeys() && this.placeableKeys.equals(that.placeableKeys) : !that.hasPlaceableKeys()) -+ && (this.hasDestroyableKeys() ? that.hasDestroyableKeys() && this.destroyableKeys.equals(that.destroyableKeys) : !that.hasDestroyableKeys()); -+ // Paper end - } - - /** -@@ -1258,6 +1370,10 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - hash = 61 * hash + (this.hasDamage() ? this.damage : 0); - hash = 61 * hash + (this.hasAttributeModifiers() ? this.attributeModifiers.hashCode() : 0); - hash = 61 * hash + this.version; -+ // Paper start - Implement an API for CanPlaceOn and CanDestroy NBT values -+ hash = 61 * hash + (this.hasPlaceableKeys() ? this.placeableKeys.hashCode() : 0); -+ hash = 61 * hash + (this.hasDestroyableKeys() ? this.destroyableKeys.hashCode() : 0); -+ // Paper end - return hash; - } - -@@ -1282,6 +1398,14 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - clone.unbreakable = this.unbreakable; - clone.damage = this.damage; - clone.version = this.version; -+ // Paper start - Implement an API for CanPlaceOn and CanDestroy NBT values -+ if (this.placeableKeys != null) { -+ clone.placeableKeys = Sets.newHashSet(this.placeableKeys); -+ } -+ if (this.destroyableKeys != null) { -+ clone.destroyableKeys = Sets.newHashSet(this.destroyableKeys); -+ } -+ // Paper end - return clone; - } catch (CloneNotSupportedException e) { - throw new Error(e); -@@ -1339,6 +1463,23 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - builder.put(CraftMetaItem.DAMAGE.BUKKIT, this.damage); - } - -+ // Paper start - Implement an API for CanPlaceOn and CanDestroy NBT values -+ if (this.hasPlaceableKeys()) { -+ List cerealPlaceable = this.placeableKeys.stream() -+ .map(this::serializeNamespaced) -+ .collect(java.util.stream.Collectors.toList()); -+ -+ builder.put(CAN_PLACE_ON.BUKKIT, cerealPlaceable); -+ } -+ -+ if (this.hasDestroyableKeys()) { -+ List cerealDestroyable = this.destroyableKeys.stream() -+ .map(this::serializeNamespaced) -+ .collect(java.util.stream.Collectors.toList()); -+ -+ builder.put(CAN_DESTROY.BUKKIT, cerealDestroyable); -+ } -+ // Paper end - final Map internalTags = new HashMap(this.unhandledTags); - this.serializeInternal(internalTags); - if (!internalTags.isEmpty()) { -@@ -1516,6 +1657,8 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - CraftMetaArmorStand.SHOW_ARMS.NBT, - CraftMetaArmorStand.SMALL.NBT, - CraftMetaArmorStand.MARKER.NBT, -+ CAN_DESTROY.NBT, -+ CAN_PLACE_ON.NBT, - // Paper end - CraftMetaCompass.LODESTONE_DIMENSION.NBT, - CraftMetaCompass.LODESTONE_POS.NBT, -@@ -1545,4 +1688,141 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { - } - // Paper end - -+ // Paper start - Implement an API for CanPlaceOn and CanDestroy NBT values -+ @Override -+ @SuppressWarnings("deprecation") -+ public Set getCanDestroy() { -+ return !hasDestroyableKeys() ? Collections.emptySet() : legacyGetMatsFromKeys(this.destroyableKeys); -+ } -+ -+ @Override -+ @SuppressWarnings("deprecation") -+ public void setCanDestroy(Set canDestroy) { -+ Preconditions.checkArgument(canDestroy != null, "Cannot replace with null set!"); -+ legacyClearAndReplaceKeys(this.destroyableKeys, canDestroy); -+ } -+ -+ @Override -+ @SuppressWarnings("deprecation") -+ public Set getCanPlaceOn() { -+ return !hasPlaceableKeys() ? Collections.emptySet() : legacyGetMatsFromKeys(this.placeableKeys); -+ } -+ -+ @Override -+ @SuppressWarnings("deprecation") -+ public void setCanPlaceOn(Set canPlaceOn) { -+ Preconditions.checkArgument(canPlaceOn != null, "Cannot replace with null set!"); -+ legacyClearAndReplaceKeys(this.placeableKeys, canPlaceOn); -+ } -+ -+ @Override -+ public Set getDestroyableKeys() { -+ return !hasDestroyableKeys() ? Collections.emptySet() : Sets.newHashSet(this.destroyableKeys); -+ } -+ -+ @Override -+ public void setDestroyableKeys(Collection canDestroy) { -+ Preconditions.checkArgument(canDestroy != null, "Cannot replace with null collection!"); -+ Preconditions.checkArgument(ofAcceptableType(canDestroy), "Can only use NamespacedKey or NamespacedTag objects!"); -+ this.destroyableKeys.clear(); -+ this.destroyableKeys.addAll(canDestroy); -+ } -+ -+ @Override -+ public Set getPlaceableKeys() { -+ return !hasPlaceableKeys() ? Collections.emptySet() : Sets.newHashSet(this.placeableKeys); -+ } -+ -+ @Override -+ public void setPlaceableKeys(Collection canPlaceOn) { -+ Preconditions.checkArgument(canPlaceOn != null, "Cannot replace with null collection!"); -+ Preconditions.checkArgument(ofAcceptableType(canPlaceOn), "Can only use NamespacedKey or NamespacedTag objects!"); -+ this.placeableKeys.clear(); -+ this.placeableKeys.addAll(canPlaceOn); -+ } -+ -+ @Override -+ public boolean hasPlaceableKeys() { -+ return this.placeableKeys != null && !this.placeableKeys.isEmpty(); -+ } -+ -+ @Override -+ public boolean hasDestroyableKeys() { -+ return this.destroyableKeys != null && !this.destroyableKeys.isEmpty(); -+ } -+ -+ @Deprecated -+ private void legacyClearAndReplaceKeys(Collection toUpdate, Collection beingSet) { -+ if (beingSet.stream().anyMatch(Material::isLegacy)) { -+ throw new IllegalArgumentException("Set must not contain any legacy materials!"); -+ } -+ -+ toUpdate.clear(); -+ toUpdate.addAll(beingSet.stream().map(Material::getKey).collect(java.util.stream.Collectors.toSet())); -+ } -+ -+ @Deprecated -+ private Set legacyGetMatsFromKeys(Collection names) { -+ Set mats = Sets.newHashSet(); -+ for (Namespaced key : names) { -+ if (!(key instanceof org.bukkit.NamespacedKey)) { -+ continue; -+ } -+ -+ Material material = Material.matchMaterial(key.toString(), false); -+ if (material != null) { -+ mats.add(material); -+ } -+ } -+ -+ return mats; -+ } -+ -+ private @Nullable Namespaced blockKeyFromString(String raw) { -+ boolean isTag = !raw.isEmpty() && raw.codePointAt(0) == '#'; -+ com.mojang.datafixers.util.Either result; -+ try { -+ result = net.minecraft.commands.arguments.blocks.BlockStateParser.parseForTesting(net.minecraft.core.registries.BuiltInRegistries.BLOCK.asLookup(), raw, false); -+ } catch (com.mojang.brigadier.exceptions.CommandSyntaxException e) { -+ return null; -+ } -+ -+ net.minecraft.resources.ResourceLocation key = null; -+ if (isTag && result.right().isPresent() && result.right().get().tag() instanceof net.minecraft.core.HolderSet.Named namedSet) { -+ key = namedSet.key().location(); -+ } else if (result.left().isPresent()) { -+ key = net.minecraft.core.registries.BuiltInRegistries.BLOCK.getKey(result.left().get().blockState().getBlock()); -+ } -+ -+ if (key == null) { -+ return null; -+ } -+ -+ try { -+ if (isTag) { -+ return new NamespacedTag(key.getNamespace(), key.getPath()); -+ -+ } -+ return CraftNamespacedKey.fromMinecraft(key); -+ } catch (IllegalArgumentException ignored) { -+ return null; -+ } -+ } -+ -+ private @Nonnull String serializeNamespaced(Namespaced resource) { -+ return resource.toString(); -+ } -+ -+ // not a fan of this -+ private boolean ofAcceptableType(Collection namespacedResources) { -+ -+ for (Namespaced resource : namespacedResources) { -+ if (!(resource instanceof org.bukkit.NamespacedKey || resource instanceof com.destroystokyo.paper.NamespacedTag)) { -+ return false; -+ } -+ } -+ -+ return true; -+ } -+ // Paper end - } diff --git a/patches/server/0981-Adopt-MaterialRerouting.patch b/patches/server/0981-Adopt-MaterialRerouting.patch index acdc787b2c..e6473ef21a 100644 --- a/patches/server/0981-Adopt-MaterialRerouting.patch +++ b/patches/server/0981-Adopt-MaterialRerouting.patch @@ -7,7 +7,7 @@ Adopts the paper-api to the material rerouting infrastructure introduced by upstream. diff --git a/src/main/java/org/bukkit/craftbukkit/legacy/MaterialRerouting.java b/src/main/java/org/bukkit/craftbukkit/legacy/MaterialRerouting.java -index 3ff0f0e34356cee4c510fdd60af723b1c5df156a..9c004e7cb46841d874ab997bf2e3b63ae763aec7 100644 +index 3ff0f0e34356cee4c510fdd60af723b1c5df156a..6cc9d7a9e6d4bfdc27e52fc581b2bb832616f121 100644 --- a/src/main/java/org/bukkit/craftbukkit/legacy/MaterialRerouting.java +++ b/src/main/java/org/bukkit/craftbukkit/legacy/MaterialRerouting.java @@ -600,4 +600,82 @@ public class MaterialRerouting { @@ -74,12 +74,12 @@ index 3ff0f0e34356cee4c510fdd60af723b1c5df156a..9c004e7cb46841d874ab997bf2e3b63a + return com.destroystokyo.paper.event.player.PlayerArmorChangeEvent.SlotType.isEquipable(MaterialRerouting.transformToItemType(material)); + } + -+ // Method added post 1.13, no-op (https://github.com/PaperMC/Paper/pull/1244)1 ++ // Method added post 1.13, no-op (https://github.com/PaperMC/Paper/pull/1244) + public static Material getMaterial(final com.destroystokyo.paper.event.block.AnvilDamagedEvent.DamageState damageState) { + return damageState.getMaterial(); + } + -+ // Method added post 1.13, no-op (https://github.com/PaperMC/Paper/pull/1244)1 ++ // Method added post 1.13, no-op (https://github.com/PaperMC/Paper/pull/1244) + @RerouteStatic("com/destroystokyo/paper/event/block/AnvilDamagedEvent$DamageState") + public static com.destroystokyo.paper.event.block.AnvilDamagedEvent.DamageState getState( + final Material material diff --git a/patches/server/1044-Add-API-for-CanPlaceOn-and-CanDestroy-NBT-values.patch b/patches/server/1044-Add-API-for-CanPlaceOn-and-CanDestroy-NBT-values.patch new file mode 100644 index 0000000000..3ff8343ca9 --- /dev/null +++ b/patches/server/1044-Add-API-for-CanPlaceOn-and-CanDestroy-NBT-values.patch @@ -0,0 +1,155 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Jake Potrebic +Date: Wed, 12 Sep 2018 18:53:55 +0300 +Subject: [PATCH] Add API for CanPlaceOn and CanDestroy NBT values + + +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java +index d5c45cc09b9d60c1650507ad6fedb27246291063..5c45946f54e4b16440c15a9165ef85be43e53c84 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java +@@ -2183,4 +2183,117 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { + } + // Paper end + ++ // Paper start - Add an API for can-place-on/can-break adventure mode predicates ++ @Override ++ public Set getCanDestroy() { ++ return !this.hasDestroyableKeys() ? Collections.emptySet() : convertToLegacyMaterial(this.canBreakPredicates); ++ } ++ ++ @Override ++ public void setCanDestroy(final Set canDestroy) { ++ Preconditions.checkArgument(canDestroy != null, "Cannot replace with null set!"); ++ this.canBreakPredicates = convertFromLegacyMaterial(canDestroy); ++ } ++ ++ @Override ++ public Set getCanPlaceOn() { ++ return !this.hasPlaceableKeys() ? Collections.emptySet() : convertToLegacyMaterial(this.canPlaceOnPredicates); ++ } ++ ++ @Override ++ public void setCanPlaceOn(final Set canPlaceOn) { ++ Preconditions.checkArgument(canPlaceOn != null, "Cannot replace with null set!"); ++ this.canPlaceOnPredicates = convertFromLegacyMaterial(canPlaceOn); ++ } ++ ++ private static List convertFromLegacyMaterial(final Collection materials) { ++ return materials.stream().map(m -> { ++ return net.minecraft.advancements.critereon.BlockPredicate.Builder.block().of(CraftBlockType.bukkitToMinecraft(m)).build(); ++ }).toList(); ++ } ++ ++ private static Set convertToLegacyMaterial(final List predicates) { ++ return predicates.stream() ++ .flatMap(p -> p.blocks().map(net.minecraft.core.HolderSet::stream).orElse(java.util.stream.Stream.empty())) ++ .map(holder -> CraftBlockType.minecraftToBukkit(holder.value())) ++ .collect(java.util.stream.Collectors.toSet()); ++ } ++ ++ @Override ++ public Set getDestroyableKeys() { ++ return !this.hasDestroyableKeys() ? Collections.emptySet() : convertToLegacyNamespaced(this.canBreakPredicates); ++ } ++ ++ @Override ++ public void setDestroyableKeys(final Collection canDestroy) { ++ Preconditions.checkArgument(canDestroy != null, "Cannot replace with null collection!"); ++ Preconditions.checkArgument(ofAcceptableType(canDestroy), "Can only use NamespacedKey or NamespacedTag objects!"); ++ this.canBreakPredicates = convertFromLegacyNamespaced(canDestroy); ++ } ++ ++ @Override ++ public Set getPlaceableKeys() { ++ return !this.hasPlaceableKeys() ? Collections.emptySet() : convertToLegacyNamespaced(this.canPlaceOnPredicates); ++ } ++ ++ @Override ++ public void setPlaceableKeys(final Collection canPlaceOn) { ++ Preconditions.checkArgument(canPlaceOn != null, "Cannot replace with null collection!"); ++ Preconditions.checkArgument(ofAcceptableType(canPlaceOn), "Can only use NamespacedKey or NamespacedTag objects!"); ++ this.canPlaceOnPredicates = convertFromLegacyNamespaced(canPlaceOn); ++ } ++ ++ private static List convertFromLegacyNamespaced(final Collection namespaceds) { ++ final List predicates = new ArrayList<>(); ++ for (final com.destroystokyo.paper.Namespaced namespaced : namespaceds) { ++ if (namespaced instanceof final org.bukkit.NamespacedKey key) { ++ predicates.add(net.minecraft.advancements.critereon.BlockPredicate.Builder.block().of(CraftBlockType.bukkitToMinecraft(Objects.requireNonNull(org.bukkit.Registry.MATERIAL.get(key)))).build()); ++ } else if (namespaced instanceof final com.destroystokyo.paper.NamespacedTag tag) { ++ predicates.add(net.minecraft.advancements.critereon.BlockPredicate.Builder.block().of(net.minecraft.tags.TagKey.create(Registries.BLOCK, ResourceLocation.fromNamespaceAndPath(tag.getNamespace(), tag.getKey()))).build()); ++ } ++ } ++ return predicates; ++ } ++ ++ private static Set convertToLegacyNamespaced(final Collection predicates) { ++ final Set namespaceds = Sets.newHashSet(); ++ for (final net.minecraft.advancements.critereon.BlockPredicate predicate : predicates) { ++ if (predicate.blocks().isEmpty()) { ++ continue; ++ } ++ final net.minecraft.core.HolderSet holders = predicate.blocks().get(); ++ if (holders instanceof final net.minecraft.core.HolderSet.Named named) { ++ namespaceds.add(new com.destroystokyo.paper.NamespacedTag(named.key().location().getNamespace(), named.key().location().getPath())); ++ } else { ++ holders.forEach(h -> { ++ h.unwrapKey().ifPresent(key -> { ++ namespaceds.add(new org.bukkit.NamespacedKey(key.location().getNamespace(), key.location().getPath())); ++ }); ++ }); ++ } ++ } ++ return namespaceds; ++ } ++ ++ @Override ++ public boolean hasPlaceableKeys() { ++ return this.canPlaceOnPredicates != null; ++ } ++ ++ @Override ++ public boolean hasDestroyableKeys() { ++ return this.canBreakPredicates != null; ++ } ++ ++ // not a fan of this ++ private static boolean ofAcceptableType(final Collection namespacedResources) { ++ for (com.destroystokyo.paper.Namespaced resource : namespacedResources) { ++ if (!(resource instanceof org.bukkit.NamespacedKey || resource instanceof com.destroystokyo.paper.NamespacedTag)) { ++ return false; ++ } ++ } ++ ++ return true; ++ } ++ // Paper end - Add an API for can-place-on/can-break adventure mode predicates + } +diff --git a/src/main/java/org/bukkit/craftbukkit/legacy/MaterialRerouting.java b/src/main/java/org/bukkit/craftbukkit/legacy/MaterialRerouting.java +index 6930d0afb230a88aa813b02e4d55c95d3a049688..db8d8e2a07296d62c3097f02b03319e2e1ba9394 100644 +--- a/src/main/java/org/bukkit/craftbukkit/legacy/MaterialRerouting.java ++++ b/src/main/java/org/bukkit/craftbukkit/legacy/MaterialRerouting.java +@@ -690,4 +690,22 @@ public class MaterialRerouting { + return ItemStack.of(material, amount); + } + // Paper end ++ ++ // Paper start - methods added post 1.13, no-op (https://github.com/PaperMC/Paper/pull/1015) ++ public static Set getCanDestroy(final ItemMeta meta) { ++ return meta.getCanDestroy(); ++ } ++ ++ public static void setCanDestroy(final ItemMeta meta, final Set materials) { ++ meta.setCanDestroy(materials); ++ } ++ ++ public static Set getCanPlaceOn(final ItemMeta meta) { ++ return meta.getCanPlaceOn(); ++ } ++ ++ public static void setCanPlaceOn(final ItemMeta meta, final Set materials) { ++ meta.setCanPlaceOn(materials); ++ } ++ // Paper end + }