From 4691102616d86c6ac283f9c2f6d79e6709d7dc97 Mon Sep 17 00:00:00 2001 From: CraftBukkit/Spigot Date: Wed, 29 May 2024 06:53:59 +1000 Subject: [PATCH] #1405: Add a tool component to ItemMeta By: 2008Choco Also-by: md_5 --- .../inventory/CraftItemFactory.java | 3 + .../craftbukkit/inventory/CraftMetaItem.java | 48 ++- .../components/CraftToolComponent.java | 333 ++++++++++++++++++ .../craftbukkit/legacy/MaterialRerouting.java | 22 ++ .../org/bukkit/craftbukkit/tag/CraftTag.java | 2 +- 5 files changed, 406 insertions(+), 2 deletions(-) create mode 100644 paper-server/src/main/java/org/bukkit/craftbukkit/inventory/components/CraftToolComponent.java diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java index 2470d4dbe1..10a0e392e8 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftItemFactory.java @@ -19,6 +19,7 @@ import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.entity.CraftEntity; import org.bukkit.craftbukkit.entity.CraftEntityType; import org.bukkit.craftbukkit.inventory.components.CraftFoodComponent; +import org.bukkit.craftbukkit.inventory.components.CraftToolComponent; import org.bukkit.craftbukkit.util.CraftLegacy; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; @@ -36,6 +37,8 @@ public final class CraftItemFactory implements ItemFactory { ConfigurationSerialization.registerClass(SerializableMeta.class); ConfigurationSerialization.registerClass(CraftFoodComponent.class); ConfigurationSerialization.registerClass(CraftFoodComponent.CraftFoodEffect.class); + ConfigurationSerialization.registerClass(CraftToolComponent.class); + ConfigurationSerialization.registerClass(CraftToolComponent.CraftToolRule.class); } private CraftItemFactory() { 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 bbca839ea8..a122128cd8 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 @@ -67,6 +67,7 @@ import net.minecraft.world.item.component.CustomData; import net.minecraft.world.item.component.CustomModelData; import net.minecraft.world.item.component.ItemAttributeModifiers; import net.minecraft.world.item.component.ItemLore; +import net.minecraft.world.item.component.Tool; import net.minecraft.world.item.component.Unbreakable; import net.minecraft.world.item.enchantment.ItemEnchantments; import net.minecraft.world.level.block.state.IBlockData; @@ -85,6 +86,7 @@ import org.bukkit.craftbukkit.block.data.CraftBlockData; import org.bukkit.craftbukkit.enchantments.CraftEnchantment; import org.bukkit.craftbukkit.inventory.CraftMetaItem.ItemMetaKey.Specific; import org.bukkit.craftbukkit.inventory.components.CraftFoodComponent; +import org.bukkit.craftbukkit.inventory.components.CraftToolComponent; import org.bukkit.craftbukkit.inventory.tags.DeprecatedCustomTagContainer; import org.bukkit.craftbukkit.persistence.CraftPersistentDataContainer; import org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry; @@ -100,6 +102,7 @@ import org.bukkit.inventory.meta.Damageable; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.inventory.meta.Repairable; import org.bukkit.inventory.meta.components.FoodComponent; +import org.bukkit.inventory.meta.components.ToolComponent; import org.bukkit.inventory.meta.tags.CustomItemTagContainer; import org.bukkit.persistence.PersistentDataContainer; @@ -221,6 +224,8 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { @Specific(Specific.To.NBT) static final ItemMetaKeyType FOOD = new ItemMetaKeyType<>(DataComponents.FOOD, "food"); @Specific(Specific.To.NBT) + static final ItemMetaKeyType TOOL = new ItemMetaKeyType<>(DataComponents.TOOL, "tool"); + @Specific(Specific.To.NBT) static final ItemMetaKeyType DAMAGE = new ItemMetaKeyType<>(DataComponents.DAMAGE, "Damage"); @Specific(Specific.To.NBT) static final ItemMetaKeyType MAX_DAMAGE = new ItemMetaKeyType<>(DataComponents.MAX_DAMAGE, "max-damage"); @@ -249,6 +254,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { private Integer maxStackSize; private ItemRarity rarity; private CraftFoodComponent food; + private CraftToolComponent tool; private int damage; private Integer maxDamage; @@ -295,6 +301,9 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { if (meta.hasFood()) { this.food = new CraftFoodComponent(meta.food); } + if (meta.hasTool()) { + this.tool = new CraftToolComponent(meta.tool); + } this.damage = meta.damage; this.maxDamage = meta.maxDamage; this.unhandledTags = meta.unhandledTags; @@ -373,6 +382,9 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { getOrEmpty(tag, FOOD).ifPresent((foodInfo) -> { food = new CraftFoodComponent(foodInfo); }); + getOrEmpty(tag, TOOL).ifPresent((toolInfo) -> { + tool = new CraftToolComponent(toolInfo); + }); getOrEmpty(tag, DAMAGE).ifPresent((i) -> { damage = i; }); @@ -551,6 +563,11 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { setFood(food); } + CraftToolComponent tool = SerializableMeta.getObject(CraftToolComponent.class, map, TOOL.BUKKIT, true); + if (tool != null) { + setTool(tool); + } + Integer damage = SerializableMeta.getObject(Integer.class, map, DAMAGE.BUKKIT, true); if (damage != null) { setDamage(damage); @@ -779,6 +796,10 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { itemTag.put(FOOD, food.getHandle()); } + if (hasTool()) { + itemTag.put(TOOL, tool.getHandle()); + } + if (hasDamage()) { itemTag.put(DAMAGE, damage); } @@ -861,7 +882,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { @Overridden boolean isEmpty() { - return !(hasDisplayName() || hasItemName() || hasLocalizedName() || hasEnchants() || (lore != null) || hasCustomModelData() || hasBlockData() || hasRepairCost() || !unhandledTags.build().isEmpty() || !persistentDataContainer.isEmpty() || hideFlag != 0 || isHideTooltip() || isUnbreakable() || hasEnchantmentGlintOverride() || isFireResistant() || hasMaxStackSize() || hasRarity() || hasFood() || hasDamage() || hasMaxDamage() || hasAttributeModifiers() || customTag != null); + return !(hasDisplayName() || hasItemName() || hasLocalizedName() || hasEnchants() || (lore != null) || hasCustomModelData() || hasBlockData() || hasRepairCost() || !unhandledTags.build().isEmpty() || !persistentDataContainer.isEmpty() || hideFlag != 0 || isHideTooltip() || isUnbreakable() || hasEnchantmentGlintOverride() || isFireResistant() || hasMaxStackSize() || hasRarity() || hasFood() || hasTool() || hasDamage() || hasMaxDamage() || hasAttributeModifiers() || customTag != null); } @Override @@ -1174,6 +1195,21 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { this.food = (food == null) ? null : new CraftFoodComponent((CraftFoodComponent) food); } + @Override + public boolean hasTool() { + return this.tool != null; + } + + @Override + public ToolComponent getTool() { + return (this.hasTool()) ? new CraftToolComponent(this.tool) : new CraftToolComponent(new Tool(Collections.emptyList(), 1.0F, 0)); + } + + @Override + public void setTool(ToolComponent tool) { + this.tool = (tool == null) ? null : new CraftToolComponent((CraftToolComponent) tool); + } + @Override public boolean hasAttributeModifiers() { return attributeModifiers != null && !attributeModifiers.isEmpty(); @@ -1425,6 +1461,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { && (this.hasMaxStackSize() ? that.hasMaxStackSize() && this.maxStackSize.equals(that.maxStackSize) : !that.hasMaxStackSize()) && (this.rarity == that.rarity) && (this.hasFood() ? that.hasFood() && this.food.equals(that.food) : !that.hasFood()) + && (this.hasTool() ? that.hasTool() && this.tool.equals(that.tool) : !that.hasTool()) && (this.hasDamage() ? that.hasDamage() && this.damage == that.damage : !that.hasDamage()) && (this.hasMaxDamage() ? that.hasMaxDamage() && this.maxDamage.equals(that.maxDamage) : !that.hasMaxDamage()) && (this.version == that.version); @@ -1466,6 +1503,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { hash = 61 * hash + (hasMaxStackSize() ? this.maxStackSize.hashCode() : 0); hash = 61 * hash + (hasRarity() ? this.rarity.hashCode() : 0); hash = 61 * hash + (hasFood() ? this.food.hashCode() : 0); + hash = 61 * hash + (hasTool() ? this.tool.hashCode() : 0); hash = 61 * hash + (hasDamage() ? this.damage : 0); hash = 61 * hash + (hasMaxDamage() ? 1231 : 1237); hash = 61 * hash + (hasAttributeModifiers() ? this.attributeModifiers.hashCode() : 0); @@ -1503,6 +1541,9 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { if (this.hasFood()) { clone.food = new CraftFoodComponent(food); } + if (this.hasTool()) { + clone.tool = new CraftToolComponent(tool); + } clone.damage = this.damage; clone.maxDamage = this.maxDamage; clone.version = this.version; @@ -1591,6 +1632,10 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { builder.put(FOOD.BUKKIT, food); } + if (hasTool()) { + builder.put(TOOL.BUKKIT, tool); + } + if (hasDamage()) { builder.put(DAMAGE.BUKKIT, damage); } @@ -1757,6 +1802,7 @@ class CraftMetaItem implements ItemMeta, Damageable, Repairable, BlockDataMeta { MAX_STACK_SIZE.TYPE, RARITY.TYPE, FOOD.TYPE, + TOOL.TYPE, DAMAGE.TYPE, MAX_DAMAGE.TYPE, CUSTOM_DATA.TYPE, diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/components/CraftToolComponent.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/components/CraftToolComponent.java new file mode 100644 index 0000000000..7f6afd69f7 --- /dev/null +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/components/CraftToolComponent.java @@ -0,0 +1,333 @@ +package org.bukkit.craftbukkit.inventory.components; + +import com.google.common.base.Preconditions; +import com.google.common.collect.ImmutableList; +import java.util.ArrayList; +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.stream.Collectors; +import net.minecraft.core.Holder; +import net.minecraft.core.HolderSet; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.core.registries.Registries; +import net.minecraft.resources.MinecraftKey; +import net.minecraft.tags.TagKey; +import net.minecraft.world.item.component.Tool; +import net.minecraft.world.level.block.Block; +import org.bukkit.Material; +import org.bukkit.Tag; +import org.bukkit.configuration.serialization.SerializableAs; +import org.bukkit.craftbukkit.block.CraftBlockType; +import org.bukkit.craftbukkit.inventory.SerializableMeta; +import org.bukkit.craftbukkit.tag.CraftBlockTag; +import org.bukkit.inventory.meta.components.ToolComponent; + +@SerializableAs("Tool") +public final class CraftToolComponent implements ToolComponent { + + private Tool handle; + + public CraftToolComponent(Tool tool) { + this.handle = tool; + } + + public CraftToolComponent(CraftToolComponent tool) { + this.handle = tool.handle; + } + + public CraftToolComponent(Map map) { + Float speed = SerializableMeta.getObject(Float.class, map, "default-mining-speed", false); + Integer damage = SerializableMeta.getObject(Integer.class, map, "damage-per-block", false); + + ImmutableList.Builder rules = ImmutableList.builder(); + Iterable rawRuleList = SerializableMeta.getObject(Iterable.class, map, "rules", true); + if (rawRuleList != null) { + for (Object obj : rawRuleList) { + Preconditions.checkArgument(obj instanceof ToolRule, "Object (%s) in rule list is not valid", obj.getClass()); + + CraftToolRule rule = new CraftToolRule((ToolRule) obj); + if (rule.handle.blocks().size() > 0) { + rules.add(rule); + } + } + } + + this.handle = new Tool(rules.build().stream().map(CraftToolRule::new).map(CraftToolRule::getHandle).toList(), speed, damage); + } + + @Override + public Map serialize() { + Map result = new LinkedHashMap<>(); + result.put("default-mining-speed", getDefaultMiningSpeed()); + result.put("damage-per-block", getDamagePerBlock()); + result.put("rules", getRules()); + return result; + } + + public Tool getHandle() { + return handle; + } + + @Override + public float getDefaultMiningSpeed() { + return handle.defaultMiningSpeed(); + } + + @Override + public void setDefaultMiningSpeed(float speed) { + handle = new Tool(handle.rules(), speed, handle.damagePerBlock()); + } + + @Override + public int getDamagePerBlock() { + return handle.damagePerBlock(); + } + + @Override + public void setDamagePerBlock(int damage) { + Preconditions.checkArgument(damage >= 0, "damage must be >= 0, was %d", damage); + handle = new Tool(handle.rules(), handle.defaultMiningSpeed(), damage); + } + + @Override + public List getRules() { + return handle.rules().stream().map(CraftToolRule::new).collect(Collectors.toList()); + } + + @Override + public void setRules(List rules) { + Preconditions.checkArgument(rules != null, "rules must not be null"); + handle = new Tool(rules.stream().map(CraftToolRule::new).map(CraftToolRule::getHandle).toList(), handle.defaultMiningSpeed(), handle.damagePerBlock()); + } + + @Override + public ToolRule addRule(Material block, Float speed, Boolean correctForDrops) { + Preconditions.checkArgument(block != null, "block must not be null"); + Preconditions.checkArgument(block.isBlock(), "block must be a block type, given %s", block.getKey()); + + Holder.c nmsBlock = CraftBlockType.bukkitToMinecraft(block).builtInRegistryHolder(); + return addRule(HolderSet.direct(nmsBlock), speed, correctForDrops); + } + + @Override + public ToolRule addRule(Collection blocks, Float speed, Boolean correctForDrops) { + List> nmsBlocks = new ArrayList<>(blocks.size()); + + for (Material material : blocks) { + Preconditions.checkArgument(material.isBlock(), "blocks contains non-block type: %s", material.getKey()); + nmsBlocks.add(CraftBlockType.bukkitToMinecraft(material).builtInRegistryHolder()); + } + + return addRule(HolderSet.direct(nmsBlocks), speed, correctForDrops); + } + + @Override + public ToolRule addRule(Tag tag, Float speed, Boolean correctForDrops) { + Preconditions.checkArgument(tag instanceof CraftBlockTag, "tag must be a block tag"); + return addRule(((CraftBlockTag) tag).getHandle(), speed, correctForDrops); + } + + private ToolRule addRule(HolderSet blocks, Float speed, Boolean correctForDrops) { + Tool.a rule = new Tool.a(blocks, Optional.ofNullable(speed), Optional.ofNullable(correctForDrops)); + + List rules = new ArrayList<>(handle.rules().size() + 1); + rules.addAll(handle.rules()); + rules.add(rule); + + handle = new Tool(rules, handle.defaultMiningSpeed(), handle.damagePerBlock()); + return new CraftToolRule(rule); + } + + @Override + public boolean removeRule(ToolRule rule) { + Preconditions.checkArgument(rule != null, "rule must not be null"); + + List rules = new ArrayList<>(handle.rules()); + boolean removed = rules.remove(((CraftToolRule) rule).handle); + handle = new Tool(rules, handle.defaultMiningSpeed(), handle.damagePerBlock()); + + return removed; + } + + @Override + public int hashCode() { + int hash = 7; + hash = 73 * hash + Objects.hashCode(this.handle); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final CraftToolComponent other = (CraftToolComponent) obj; + return Objects.equals(this.handle, other.handle); + } + + @Override + public String toString() { + return "CraftToolComponent{" + "handle=" + handle + '}'; + } + + @SerializableAs("ToolRule") + public static class CraftToolRule implements ToolRule { + + private Tool.a handle; + + public CraftToolRule(Tool.a handle) { + this.handle = handle; + } + + public CraftToolRule(ToolRule bukkit) { + Tool.a toCopy = ((CraftToolRule) bukkit).handle; + this.handle = new Tool.a(toCopy.blocks(), toCopy.speed(), toCopy.correctForDrops()); + } + + public CraftToolRule(Map map) { + Float speed = SerializableMeta.getObject(Float.class, map, "speed", false); + Boolean correct = SerializableMeta.getObject(Boolean.class, map, "correct-for-drops", false); + + HolderSet blocks = null; + Object blocksObject = SerializableMeta.getObject(Object.class, map, "blocks", false); + if (blocksObject instanceof String blocksString && blocksString.startsWith("#")) { // Tag + blocksString = blocksString.substring(1); + MinecraftKey key = MinecraftKey.tryParse(blocksString); + if (key != null) { + blocks = BuiltInRegistries.BLOCK.getTag(TagKey.create(Registries.BLOCK, key)).orElse(null); + } + } else if (blocksObject instanceof List blocksList) { // List of blocks + List> blockHolders = new ArrayList<>(blocksList.size()); + + for (Object entry : blocksList) { + MinecraftKey key = MinecraftKey.tryParse(entry.toString()); + if (key == null) { + continue; + } + + BuiltInRegistries.BLOCK.getHolder(key).ifPresent(blockHolders::add); + } + + blocks = HolderSet.direct(blockHolders); + } else { + throw new IllegalArgumentException("blocks" + "(" + blocksObject + ") is not a valid String or List"); + } + + if (blocks == null) { + blocks = HolderSet.empty(); + } + + this.handle = new Tool.a(blocks, Optional.ofNullable(speed), Optional.ofNullable(correct)); + } + + @Override + public Map serialize() { + Map result = new LinkedHashMap<>(); + + handle.blocks().unwrap() + .ifLeft(key -> result.put("blocks", "#" + key.location().toString())) // Tag + .ifRight(blocks -> result.put("blocks", blocks.stream().map((block) -> block.unwrapKey().orElseThrow().location().toString()).toList())); // List of blocks + + Float speed = getSpeed(); + if (speed != null) { + result.put("speed", speed); + } + + Boolean correct = isCorrectForDrops(); + if (correct != null) { + result.put("correct-for-drops", correct); + } + + return result; + } + + public Tool.a getHandle() { + return handle; + } + + @Override + public Collection getBlocks() { + return handle.blocks().stream().map(Holder::value).map(CraftBlockType::minecraftToBukkit).collect(Collectors.toList()); + } + + @Override + public void setBlocks(Material block) { + Preconditions.checkArgument(block != null, "block must not be null"); + Preconditions.checkArgument(block.isBlock(), "block must be a block type, given %s", block.getKey()); + handle = new Tool.a(HolderSet.direct(CraftBlockType.bukkitToMinecraft(block).builtInRegistryHolder()), handle.speed(), handle.correctForDrops()); + } + + @Override + public void setBlocks(Collection blocks) { + Preconditions.checkArgument(blocks != null, "blocks must not be null"); + for (Material material : blocks) { + Preconditions.checkArgument(material.isBlock(), "blocks contains non-block type: %s", material.getKey()); + } + + handle = new Tool.a(HolderSet.direct((List) blocks.stream().map(CraftBlockType::bukkitToMinecraft).map(Block::builtInRegistryHolder).collect(Collectors.toList())), handle.speed(), handle.correctForDrops()); + } + + @Override + public void setBlocks(Tag tag) { + Preconditions.checkArgument(tag instanceof CraftBlockTag, "tag must be a block tag"); + handle = new Tool.a(((CraftBlockTag) tag).getHandle(), handle.speed(), handle.correctForDrops()); + } + + @Override + public Float getSpeed() { + return handle.speed().orElse(null); + } + + @Override + public void setSpeed(Float speed) { + handle = new Tool.a(handle.blocks(), Optional.ofNullable(speed), handle.correctForDrops()); + } + + @Override + public Boolean isCorrectForDrops() { + return handle.correctForDrops().orElse(null); + } + + @Override + public void setCorrectForDrops(Boolean correct) { + handle = new Tool.a(handle.blocks(), handle.speed(), Optional.ofNullable(correct)); + } + + @Override + public int hashCode() { + int hash = 5; + hash = 97 * hash + Objects.hashCode(this.handle); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final CraftToolRule other = (CraftToolRule) obj; + return Objects.equals(this.handle, other.handle); + } + + @Override + public String toString() { + return "CraftToolRule{" + "handle=" + handle + '}'; + } + } +} 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 8f70fb8767..4a7876798d 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 @@ -1,5 +1,6 @@ package org.bukkit.craftbukkit.legacy; +import java.util.Collection; import java.util.EnumMap; import java.util.HashMap; import java.util.List; @@ -60,6 +61,7 @@ import org.bukkit.inventory.ShapelessRecipe; import org.bukkit.inventory.StonecuttingRecipe; import org.bukkit.inventory.meta.BlockDataMeta; import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.inventory.meta.components.ToolComponent; import org.bukkit.material.MaterialData; import org.bukkit.packs.DataPackManager; import org.bukkit.scoreboard.Criteria; @@ -578,4 +580,24 @@ public class MaterialRerouting { public static FallingBlock spawnFallingBlock(World world, Location location, Material material, byte data) { return world.spawnFallingBlock(location, CraftBlockData.fromData(CraftMagicNumbers.getBlock(material, data))); } + + public static ToolComponent.ToolRule addRule(ToolComponent toolComponent, Material block, Float speed, Boolean correctForDrops) { + return toolComponent.addRule(transformToBlockType(block), speed, correctForDrops); + } + + public static ToolComponent.ToolRule addRule(ToolComponent toolComponent, Collection blocks, Float speed, Boolean correctForDrops) { + return toolComponent.addRule(blocks.stream().map(MaterialRerouting::transformToBlockType).collect(Collectors.toList()), speed, correctForDrops); + } + + public static Collection getBlocks(ToolComponent.ToolRule toolRule, @InjectPluginVersion ApiVersion version) { + return toolRule.getBlocks().stream().map(val -> transformFromBlockType(val, version)).toList(); + } + + public static void setBlocks(ToolComponent.ToolRule toolRule, Material block) { + toolRule.setBlocks(transformToBlockType(block)); + } + + public static void setBlocks(ToolComponent.ToolRule toolRule, Collection blocks) { + toolRule.setBlocks(blocks.stream().map(MaterialRerouting::transformToBlockType).toList()); + } } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/tag/CraftTag.java b/paper-server/src/main/java/org/bukkit/craftbukkit/tag/CraftTag.java index d6a4e60449..7bb7162027 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/tag/CraftTag.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/tag/CraftTag.java @@ -21,7 +21,7 @@ public abstract class CraftTag implements Tag { this.handle = registry.getTag(this.tag).orElseThrow(); } - protected HolderSet.Named getHandle() { + public HolderSet.Named getHandle() { return handle; }