diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java index 630986f20d..01ea7cdedd 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java @@ -2521,4 +2521,119 @@ 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) { + final net.minecraft.core.Registry blockRegistry = net.minecraft.server.MinecraftServer.getServer().registryAccess().lookupOrThrow(net.minecraft.core.registries.Registries.BLOCK); + return materials.stream().map(m -> { + return net.minecraft.advancements.critereon.BlockPredicate.Builder.block().of(blockRegistry, 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<>(); + final net.minecraft.core.Registry blockRegistry = net.minecraft.server.MinecraftServer.getServer().registryAccess().lookupOrThrow(net.minecraft.core.registries.Registries.BLOCK); + 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(blockRegistry, 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(blockRegistry, 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/paper-server/src/main/java/org/bukkit/craftbukkit/legacy/MaterialRerouting.java b/paper-server/src/main/java/org/bukkit/craftbukkit/legacy/MaterialRerouting.java index 6930d0afb2..db8d8e2a07 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/legacy/MaterialRerouting.java +++ b/paper-server/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 }