You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Bukkit中如何为ItemStack设置自定义ID以支持附魔物品告示牌商店功能

代码错误原因与修复方案

现有代码的核心错误点

  • 恢复数据时错误调用createSection:你在restoreData方法里用config.createSection("eco.sell.aFirstItem")会直接覆盖已存在的配置节点,导致之前保存的数据全部被清空,自然读不到有效数据,应该调用getConfigurationSection读取已有的节点。
  • 附魔存储的key不匹配:保存时你把附魔列表存在meta.enchant(单数),恢复时读取的是meta.enchants(复数),key完全不一致,会读取到空列表,附魔数据加载失败。
  • 未把修改后的ItemMeta写回ItemStack:你获取ItemMeta修改了显示名称后,没有调用item.setItemMeta(meta),修改的名称不会生效。
  • 配置保存逻辑不完整:save()方法仅在物品有ItemMeta时才会调用,无附魔、无自定义名称的普通物品数据不会被持久化到配置文件。
  • 空指针风险:未校验附魔名称是否合法、字符串拆分结果是否符合预期、自定义名称是否为空,特殊情况下会触发空指针或数组越界。
  • (可选兼容问题)player.getItemInHand()是低版本API,高版本Bukkit/Spigot已废弃,建议替换为player.getInventory().getItemInMainHand()。

修复后的代码

保存物品代码

public static void saveItem(Player player){
    ItemStack item = player.getInventory().getItemInMainHand();
    // 先移除旧节点再创建新的,避免残留旧数据
    config.set("eco.sell.aFirstItem", null);
    ConfigurationSection configToEdit = config.createSection("eco.sell.aFirstItem");
    configToEdit.set("type", item.getType().name());
    configToEdit.set("amount", item.getAmount());
    if(item.hasItemMeta()){
        ItemMeta meta = item.getItemMeta();
        // 仅当有自定义名称时存储,避免存null
        if(meta.hasDisplayName()){
            configToEdit.set("meta.name", meta.getDisplayName());
        }
        List<String> enchants = new ArrayList<>();
        meta.getEnchants().forEach((en, lvl) -> enchants.add(en.getName() + ":" + lvl));
        configToEdit.set("meta.enchants", enchants); // 统一用复数key
    }
    // 不管有没有meta都保存配置
    save();
}

恢复物品代码

public static void restoreData(Player player){
    // 读取已有的配置节点,不要创建新节点
    ConfigurationSection configToEdit = config.getConfigurationSection("eco.sell.aFirstItem");
    if(configToEdit == null){
        player.sendMessage("没有找到可恢复的物品数据");
        return;
    }
    ItemStack item = new ItemStack(Material.valueOf(configToEdit.getString("type")), configToEdit.getInt("amount")); 
    ItemMeta meta = item.getItemMeta();
    if(configToEdit.contains("meta")) {
        player.sendMessage("Contains( Meta )");
        // 仅当存储了名称时设置
        if(configToEdit.contains("meta.name")){
            meta.setDisplayName(configToEdit.getString("meta.name"));
        }
        List<String> enchants = configToEdit.getStringList("meta.enchants"); 
        enchants.forEach(line -> {
            String[] split = line.split(":"); 
            if(split.length < 2) return;
            Enchantment enchant = Enchantment.getByName(split[0]);
            if(enchant == null) return;
            int level;
            try {
                level = Integer.parseInt(split[1]);
            } catch (NumberFormatException e) {
                return;
            }
            meta.addEnchant(enchant, level, true); // 附魔加在meta上更规范,true表示绕过等级限制
        });
    }
    // 把修改后的meta写回物品
    item.setItemMeta(meta);
    player.getInventory().addItem(item);
    player.updateInventory();
}

自定义物品ID的实现建议

不需要写入lore,更推荐用Spigot提供的PersistentDataContainer存储自定义ID,属于物品的隐藏属性,玩家看不到也无法普通修改,示例如下:

// 写入自定义ID
NamespacedKey key = new NamespacedKey(你的插件实例, "custom_item_id");
meta.getPersistentDataContainer().set(key, PersistentDataType.STRING, "你的自定义ID");

// 读取自定义ID
String customId = meta.getPersistentDataContainer().get(key, PersistentDataType.STRING);

如果是低于1.14的低版本服务端,才考虑用带特殊前缀的隐藏lore存储。

内容的提问来源于stack exchange,提问作者chaniloko

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 12:18:01