如何在Spigot插件中设置物品的CanPlaceOn NBT属性?

2026-05-07 17:401阅读0评论SEO问题
  • 内容介绍
  • 文章标签
  • 相关推荐

本文共计656个文字,预计阅读时间需要3分钟。

如何在Spigot插件中设置物品的CanPlaceOn NBT属性?

原文:

在Spigot开发中,CanPlaceOn 是一个关键的NBT标签,用于指定某物品仅允许被放置在特定方块上(例如只允许放在石头或橡木板上),同时是实现冒险模式(Adventure Mode)下受控放置行为的核心机制。遗憾的是,Bukkit/Spigot 的公共API 并未暴露对CanPlaceOn等高级NBT结构的直接操作接口——这意味着你无法通过ItemMeta或PersistentDataContainer(1.16+)原生设置该标签。

因此,必须借助NMS(Net Minecraft Server)层进行底层NBT操作。以下是兼容 Spigot 1.16.5 至 1.20.x 的通用实现方案(以1.19.4为例,其他版本需微调NMS类路径):

✅ 正确实现步骤(以1.19.4为例)

import net.minecraft.nbt.NBTTagList; import net.minecraft.nbt.NBTTagString; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.block.Block; import org.bukkit.craftbukkit.v1_19_R3.inventory.CraftItemStack; import org.bukkit.Material; import org.bukkit.inventory.ItemStack; public static ItemStack createPlaceableItem(Material material, String... validBlocks) { // 1. 创建Bukkit ItemStack ItemStack bukkitStack = new ItemStack(material, 1); // 2. 转为NMS ItemStack(CraftItemStack) net.minecraft.world.item.ItemStack nmsStack = CraftItemStack.asNMSCopy(bukkitStack); // 3. 获取/创建TagCompound net.minecraft.nbt.NBTTagCompound tag = nmsStack.hasTag() ? nmsStack.getTag() : new net.minecraft.nbt.NBTTagCompound(); // 4. 构建CanPlaceOn列表:每个元素为"minecraft:stone"格式的字符串NBT NBTTagList canPlaceOn = new NBTTagList(); for (String blockId : validBlocks) { // 自动补全命名空间前缀(如传入"stone" → "minecraft:stone") String fullId = blockId.contains(":") ? blockId : "minecraft:" + blockId; canPlaceOn.add(NBTTagString.a(fullId)); } // 5. 写入到tag["CanPlaceOn"] tag.set("CanPlaceOn", canPlaceOn); nmsStack.setTag(tag); // 6. 转回Bukkit ItemStack并返回 return CraftItemStack.asBukkitCopy(nmsStack); }

⚠️ 使用示例与注意事项

// 示例:创建只能放在石头、圆石和橡木板上的金块 ItemStack goldenBlock = createPlaceableItem( Material.GOLD_BLOCK, "stone", "cobblestone", "oak_planks" ); player.getInventory().addItem(goldenBlock);

  • 版本适配关键:NMS类名随Minecraft版本变化(如v1_19_R3对应1.19.4)。请根据目标服务端版本修改CraftItemStack和NMS包路径(可通过ServerVersion工具类自动判断)。
  • 方块ID格式:务必使用注册名(registry name),如"minecraft:deepslate"而非"DEEPSLATE";大小写敏感。
  • 安全边界:CanPlaceOn仅影响放置权限检查,不替代方块逻辑(如红石更新、重力等仍由方块自身处理)。
  • 性能提示:NMS操作开销极小,但应避免在高频事件(如PlayerMoveEvent)中反复调用。

✅ 替代方案(低版本兼容性更强)

若需支持1.12–1.15,可改用反射访问ItemStack内部tag字段(稳定性略低,但无需编译时依赖NMS);而1.20.5+推荐结合net.minecraft.nbt新模块化结构优化。

标签:Go

本文共计656个文字,预计阅读时间需要3分钟。

如何在Spigot插件中设置物品的CanPlaceOn NBT属性?

原文:

在Spigot开发中,CanPlaceOn 是一个关键的NBT标签,用于指定某物品仅允许被放置在特定方块上(例如只允许放在石头或橡木板上),同时是实现冒险模式(Adventure Mode)下受控放置行为的核心机制。遗憾的是,Bukkit/Spigot 的公共API 并未暴露对CanPlaceOn等高级NBT结构的直接操作接口——这意味着你无法通过ItemMeta或PersistentDataContainer(1.16+)原生设置该标签。

因此,必须借助NMS(Net Minecraft Server)层进行底层NBT操作。以下是兼容 Spigot 1.16.5 至 1.20.x 的通用实现方案(以1.19.4为例,其他版本需微调NMS类路径):

✅ 正确实现步骤(以1.19.4为例)

import net.minecraft.nbt.NBTTagList; import net.minecraft.nbt.NBTTagString; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.block.Block; import org.bukkit.craftbukkit.v1_19_R3.inventory.CraftItemStack; import org.bukkit.Material; import org.bukkit.inventory.ItemStack; public static ItemStack createPlaceableItem(Material material, String... validBlocks) { // 1. 创建Bukkit ItemStack ItemStack bukkitStack = new ItemStack(material, 1); // 2. 转为NMS ItemStack(CraftItemStack) net.minecraft.world.item.ItemStack nmsStack = CraftItemStack.asNMSCopy(bukkitStack); // 3. 获取/创建TagCompound net.minecraft.nbt.NBTTagCompound tag = nmsStack.hasTag() ? nmsStack.getTag() : new net.minecraft.nbt.NBTTagCompound(); // 4. 构建CanPlaceOn列表:每个元素为"minecraft:stone"格式的字符串NBT NBTTagList canPlaceOn = new NBTTagList(); for (String blockId : validBlocks) { // 自动补全命名空间前缀(如传入"stone" → "minecraft:stone") String fullId = blockId.contains(":") ? blockId : "minecraft:" + blockId; canPlaceOn.add(NBTTagString.a(fullId)); } // 5. 写入到tag["CanPlaceOn"] tag.set("CanPlaceOn", canPlaceOn); nmsStack.setTag(tag); // 6. 转回Bukkit ItemStack并返回 return CraftItemStack.asBukkitCopy(nmsStack); }

⚠️ 使用示例与注意事项

// 示例:创建只能放在石头、圆石和橡木板上的金块 ItemStack goldenBlock = createPlaceableItem( Material.GOLD_BLOCK, "stone", "cobblestone", "oak_planks" ); player.getInventory().addItem(goldenBlock);

  • 版本适配关键:NMS类名随Minecraft版本变化(如v1_19_R3对应1.19.4)。请根据目标服务端版本修改CraftItemStack和NMS包路径(可通过ServerVersion工具类自动判断)。
  • 方块ID格式:务必使用注册名(registry name),如"minecraft:deepslate"而非"DEEPSLATE";大小写敏感。
  • 安全边界:CanPlaceOn仅影响放置权限检查,不替代方块逻辑(如红石更新、重力等仍由方块自身处理)。
  • 性能提示:NMS操作开销极小,但应避免在高频事件(如PlayerMoveEvent)中反复调用。

✅ 替代方案(低版本兼容性更强)

若需支持1.12–1.15,可改用反射访问ItemStack内部tag字段(稳定性略低,但无需编译时依赖NMS);而1.20.5+推荐结合net.minecraft.nbt新模块化结构优化。

标签:Go