aboutsummaryrefslogtreecommitdiffhomepage
path: root/patches/unapplied/server/0256-Implement-an-API-for-CanPlaceOn-and-CanDestroy-NBT-v.patch
diff options
context:
space:
mode:
Diffstat (limited to 'patches/unapplied/server/0256-Implement-an-API-for-CanPlaceOn-and-CanDestroy-NBT-v.patch')
-rw-r--r--patches/unapplied/server/0256-Implement-an-API-for-CanPlaceOn-and-CanDestroy-NBT-v.patch402
1 files changed, 402 insertions, 0 deletions
diff --git a/patches/unapplied/server/0256-Implement-an-API-for-CanPlaceOn-and-CanDestroy-NBT-v.patch b/patches/unapplied/server/0256-Implement-an-API-for-CanPlaceOn-and-CanDestroy-NBT-v.patch
new file mode 100644
index 0000000000..bfabc2cd1e
--- /dev/null
+++ b/patches/unapplied/server/0256-Implement-an-API-for-CanPlaceOn-and-CanDestroy-NBT-v.patch
@@ -0,0 +1,402 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Mark Vainomaa <[email protected]>
+Date: Wed, 12 Sep 2018 18:53:55 +0300
+Subject: [PATCH] Implement an 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 3d749e6d6193878f1b4f288946afcec9461dc8df..e29134181d5b032311fe163b48fbe53f1298c6fd 100644
+--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java
+@@ -84,6 +84,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:
+ *
+@@ -272,6 +278,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 - Implement an 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
+
+ // We store the raw original JSON representation of all text data. See SPIGOT-5063, SPIGOT-5656, SPIGOT-5304
+ private String displayName;
+@@ -285,6 +295,10 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
+ private int hideFlag;
+ private boolean unbreakable;
+ private int damage;
++ // Paper start - Implement an API for CanPlaceOn and CanDestroy NBT values
++ private Set<Namespaced> placeableKeys = Sets.newHashSet();
++ private Set<Namespaced> destroyableKeys = Sets.newHashSet();
++ // Paper end
+
+ private static final Set<String> HANDLED_TAGS = Sets.newHashSet();
+ private static final CraftPersistentDataTypeRegistry DATA_TYPE_REGISTRY = new CraftPersistentDataTypeRegistry();
+@@ -322,6 +336,15 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
+ this.hideFlag = meta.hideFlag;
+ this.unbreakable = meta.unbreakable;
+ this.damage = meta.damage;
++ // Paper start - Implement an 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
+ this.unhandledTags.putAll(meta.unhandledTags);
+ this.persistentDataContainer.putAll(meta.persistentDataContainer.getRaw());
+
+@@ -385,6 +408,31 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
+ this.persistentDataContainer.put(key, compound.get(key).copy());
+ }
+ }
++ // Paper start - Implement an 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.deserializeNamespaced(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.deserializeNamespaced(list.getString(i));
++ if (namespaced == null) {
++ continue;
++ }
++
++ this.placeableKeys.add(namespaced);
++ }
++ }
++ // Paper end
+
+ Set<String> keys = tag.getAllKeys();
+ for (String key : keys) {
+@@ -523,6 +571,34 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
+ this.setDamage(damage);
+ }
+
++ // Paper start - Implement an 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.deserializeNamespaced(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.deserializeNamespaced(canDestroyRaw);
++ if (value == null) {
++ continue;
++ }
++
++ this.destroyableKeys.add(value);
++ }
++ }
++ // Paper end
++
+ String internal = SerializableMeta.getString(map, "internal", true);
+ if (internal != null) {
+ ByteArrayInputStream buf = new ByteArrayInputStream(Base64.getDecoder().decode(internal));
+@@ -651,6 +727,23 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
+ if (this.hasDamage()) {
+ itemTag.putInt(CraftMetaItem.DAMAGE.NBT, this.damage);
+ }
++ // Paper start - Implement an API for CanPlaceOn and CanDestroy NBT values
++ if (hasPlaceableKeys()) {
++ List<String> items = this.placeableKeys.stream()
++ .map(this::serializeNamespaced)
++ .collect(java.util.stream.Collectors.toList());
++
++ itemTag.put(CAN_PLACE_ON.NBT, createNonComponentStringList(items));
++ }
++
++ if (hasDestroyableKeys()) {
++ List<String> items = this.destroyableKeys.stream()
++ .map(this::serializeNamespaced)
++ .collect(java.util.stream.Collectors.toList());
++
++ itemTag.put(CAN_DESTROY.NBT, createNonComponentStringList(items));
++ }
++ // Paper end
+
+ for (Map.Entry<String, Tag> e : this.unhandledTags.entrySet()) {
+ itemTag.put(e.getKey(), e.getValue());
+@@ -667,6 +760,21 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta {
+ }
+ }
+
++ // Paper start
++ static ListTag createNonComponentStringList(List<String> 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
++
+ ListTag createStringList(List<String> list) {
+ if (list == null) {
+ return null;
+@@ -750,7 +858,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
+@@ -1182,7 +1290,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
+ }
+
+ /**
+@@ -1217,6 +1329,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;
+ }
+
+@@ -1241,6 +1357,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);
+@@ -1298,6 +1422,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<String> cerealPlaceable = this.placeableKeys.stream()
++ .map(this::serializeNamespaced)
++ .collect(java.util.stream.Collectors.toList());
++
++ builder.put(CAN_PLACE_ON.BUKKIT, cerealPlaceable);
++ }
++
++ if (this.hasDestroyableKeys()) {
++ List<String> cerealDestroyable = this.destroyableKeys.stream()
++ .map(this::serializeNamespaced)
++ .collect(java.util.stream.Collectors.toList());
++
++ builder.put(CAN_DESTROY.BUKKIT, cerealDestroyable);
++ }
++ // Paper end
+ final Map<String, Tag> internalTags = new HashMap<String, Tag>(this.unhandledTags);
+ this.serializeInternal(internalTags);
+ if (!internalTags.isEmpty()) {
+@@ -1470,6 +1611,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,
+@@ -1499,4 +1642,146 @@ 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<Material> getCanDestroy() {
++ return !hasDestroyableKeys() ? Collections.emptySet() : legacyGetMatsFromKeys(this.destroyableKeys);
++ }
++
++ @Override
++ @SuppressWarnings("deprecation")
++ public void setCanDestroy(Set<Material> canDestroy) {
++ Preconditions.checkArgument(canDestroy != null, "Cannot replace with null set!");
++ legacyClearAndReplaceKeys(this.destroyableKeys, canDestroy);
++ }
++
++ @Override
++ @SuppressWarnings("deprecation")
++ public Set<Material> getCanPlaceOn() {
++ return !hasPlaceableKeys() ? Collections.emptySet() : legacyGetMatsFromKeys(this.placeableKeys);
++ }
++
++ @Override
++ @SuppressWarnings("deprecation")
++ public void setCanPlaceOn(Set<Material> canPlaceOn) {
++ Preconditions.checkArgument(canPlaceOn != null, "Cannot replace with null set!");
++ legacyClearAndReplaceKeys(this.placeableKeys, canPlaceOn);
++ }
++
++ @Override
++ public Set<Namespaced> getDestroyableKeys() {
++ return !hasDestroyableKeys() ? Collections.emptySet() : Sets.newHashSet(this.destroyableKeys);
++ }
++
++ @Override
++ public void setDestroyableKeys(Collection<Namespaced> 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<Namespaced> getPlaceableKeys() {
++ return !hasPlaceableKeys() ? Collections.emptySet() : Sets.newHashSet(this.placeableKeys);
++ }
++
++ @Override
++ public void setPlaceableKeys(Collection<Namespaced> 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<Namespaced> toUpdate, Collection<Material> 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<Material> legacyGetMatsFromKeys(Collection<Namespaced> names) {
++ Set<Material> 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 deserializeNamespaced(String raw) {
++ boolean isTag = raw.length() > 0 && raw.codePointAt(0) == '#';
++ com.mojang.datafixers.util.Either<net.minecraft.commands.arguments.blocks.BlockStateParser.BlockResult, net.minecraft.commands.arguments.blocks.BlockStateParser.TagResult> 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<net.minecraft.world.level.block.Block> 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;
++ }
++
++ // don't DC the player if something slips through somehow
++ Namespaced resource = null;
++ try {
++ if (isTag) {
++ resource = new NamespacedTag(key.getNamespace(), key.getPath());
++ } else {
++ resource = CraftNamespacedKey.fromMinecraft(key);
++ }
++ } catch (IllegalArgumentException ex) {
++ org.bukkit.Bukkit.getLogger().warning("Namespaced resource does not validate: " + key.toString());
++ ex.printStackTrace();
++ }
++
++ return resource;
++ }
++
++ private @Nonnull String serializeNamespaced(Namespaced resource) {
++ return resource.toString();
++ }
++
++ // not a fan of this
++ private boolean ofAcceptableType(Collection<Namespaced> namespacedResources) {
++
++ for (Namespaced resource : namespacedResources) {
++ if (!(resource instanceof org.bukkit.NamespacedKey || resource instanceof com.destroystokyo.paper.NamespacedTag)) {
++ return false;
++ }
++ }
++
++ return true;
++ }
++ // Paper end
+ }