diff options
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.patch | 402 |
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 + } |