Bukkit API物品名称/LORE设置后NBT冗余格式问题的替代方案咨询
解决方案:Bukkit物品NBT冗余格式标签问题
针对使用ItemMeta#setDisplayName()/setLore()后NBT出现italic: false等冗余标签导致物品比对失败的问题,以下是几种无需切换到Adventure库的解决方法:
1. 手动清理冗余NBT标签
直接操作物品的NBT结构,移除那些默认添加的、值为false的格式标签。可以借助Spigot提供的SpigotItemMeta来直接访问和修改显示名称/LORE的NBT标签:
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.SpigotItemMeta; import net.minecraft.nbt.CompoundTag; import java.util.List; // 清理单个物品显示名称的冗余格式标签 public void cleanDisplayNameNBT(ItemStack item) { if (!item.hasItemMeta()) return; SpigotItemMeta spigotMeta = (SpigotItemMeta) item.getItemMeta(); CompoundTag displayNameTag = spigotMeta.getDisplayNameTag(); if (displayNameTag != null) { // 移除所有值为false的冗余格式标签 String[] redundantTags = {"italic", "obfuscated", "bold", "strikethrough", "underlined"}; for (String tag : redundantTags) { if (displayNameTag.getBoolean(tag) == false) { displayNameTag.remove(tag); } } spigotMeta.setDisplayNameTag(displayNameTag); item.setItemMeta(spigotMeta); } } // 清理LORE的冗余标签 public void cleanLoreNBT(ItemStack item) { if (!item.hasItemMeta()) return; SpigotItemMeta spigotMeta = (SpigotItemMeta) item.getItemMeta(); List<CompoundTag> loreTags = spigotMeta.getLoreTags(); if (loreTags == null || loreTags.isEmpty()) return; for (CompoundTag loreTag : loreTags) { String[] redundantTags = {"italic", "obfuscated", "bold", "strikethrough", "underlined"}; for (String tag : redundantTags) { if (loreTag.getBoolean(tag) == false) { loreTag.remove(tag); } } } spigotMeta.setLoreTags(loreTags); item.setItemMeta(spigotMeta); }
2. 自定义物品比对逻辑
绕过完整NBT比对,只校验物品的核心属性:物品类型、显示名称的纯文本内容、LORE纯文本、附魔、耐久等关键信息,从根源上避免冗余标签的干扰。
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.ChatColor; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; public boolean isMatchingItem(ItemStack a, ItemStack b) { if (a == null || b == null) return a == b; // 比对物品基础类型 if (!a.getType().equals(b.getType())) return false; // 比对显示名称(去除所有颜色和格式代码) String nameA = getRawDisplayName(a.getItemMeta()); String nameB = getRawDisplayName(b.getItemMeta()); if (!Objects.equals(nameA, nameB)) return false; // 比对LORE内容(同样去除格式代码) List<String> loreA = getRawLore(a.getItemMeta()); List<String> loreB = getRawLore(b.getItemMeta()); if (!Objects.equals(loreA, loreB)) return false; // 按需添加其他核心属性比对:附魔、耐久、自定义持久化数据等 return a.getDurability() == b.getDurability() && Objects.equals(a.getEnchantments(), b.getEnchantments()); } private String getRawDisplayName(ItemMeta meta) { if (meta == null || !meta.hasDisplayName()) return null; return ChatColor.stripColor(meta.getDisplayName()); } private List<String> getRawLore(ItemMeta meta) { if (meta == null || !meta.hasLore()) return null; return meta.getLore().stream().map(ChatColor::stripColor).collect(Collectors.toList()); }
3. 反射适配Spigot序列化逻辑(风险较高)
针对Spigot序列化时默认添加false格式标签的问题,可以通过反射修改内部序列化类的行为,避免生成冗余标签。但这种方法依赖Spigot的内部实现,版本更新后可能失效,需谨慎使用:
import net.md_5.bungee.chat.ComponentSerializer; import java.lang.reflect.Method; // 示例:修改ComponentSerializer的序列化逻辑,不输出false格式属性 public void fixSpigotSerialization() { try { Class<?> serializerClass = Class.forName("net.md_5.bungee.chat.ComponentSerializer"); Method serializeMethod = serializerClass.getDeclaredMethod("serialize", net.md_5.bungee.api.chat.BaseComponent[].class); serializeMethod.setAccessible(true); // 具体实现需参考对应版本的Spigot/BungeeCord源码,替换原有序列化逻辑 // 此处仅提供思路,实际代码需根据版本调整 } catch (Exception e) { e.printStackTrace(); } }
内容的提问来源于stack exchange,提问作者JavaPro123
相关产品推荐
相关产品推荐

