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

如何在Minecraft Forge中编辑玩家NBT数据?新手Mod开发遇阻

Minecraft Forge模组开发:无法给玩家添加自定义NBT标签的解决方案

核心问题分析

  • pPlayer.serializeNBT()返回的是玩家NBT的副本对象,修改这个副本后未写回玩家实体,导致修改不会生效。
  • 自定义的NLevelTag未实现Tag接口的必要序列化/反序列化方法,Minecraft无法将其正确转换为可存储的NBT数据。
  • 直接操作整个玩家NBT(serialize/deserialize)风险极高,容易覆盖原生或其他模组的NBT数据,不推荐使用。

正确解决方案

方案1:使用玩家持久化数据容器(官方推荐)

Minecraft提供的PersistentDataContainer是专门用于存储自定义数据的安全容器,不会干扰原生NBT结构:

  1. 定义全局数据键(避免键名冲突):
public static final ResourceLocation NECROMANCY_LEVEL_KEY = new ResourceLocation("necromancy", "level_data");
  1. 修改finishUsingItem方法:
@Override
public ItemStack finishUsingItem(ItemStack stack, Level level, LivingEntity livingEntity) {
    if (livingEntity instanceof Player pPlayer) {
        PersistentDataContainer dataContainer = pPlayer.getPersistentData();
        
        if (!dataContainer.contains(NECROMANCY_LEVEL_KEY, Tag.TAG_COMPOUND)) {
            // 初始化等级数据
            CompoundTag levelTag = new CompoundTag();
            levelTag.putInt("level", 1);
            levelTag.putInt("levelXP", 1); // 对应初始levelUp()后的XP值
            dataContainer.put(NECROMANCY_LEVEL_KEY, levelTag);
        } else {
            // 更新已有数据
            CompoundTag levelTag = dataContainer.getCompound(NECROMANCY_LEVEL_KEY);
            int currentXP = levelTag.getInt("levelXP");
            levelTag.putInt("levelXP", currentXP + 5); // 对应levelUp(5)的效果
        }
    }
    return super.finishUsingItem(stack, level, livingEntity);
}

方案2:修复自定义Tag并正确写回玩家NBT(不推荐)

如果坚持使用自定义Tag,必须让NLevelTag完整实现Tag接口:

  1. 重构NLevelTag类:
public class NLevelTag implements Tag {
    private int level;
    private int levelXP;
    private static final Logger LOGGER = LogUtils.getLogger();

    public NLevelTag(int _level, int _levelXP) {
        this.level = _level;
        this.levelXP = _levelXP;
    }

    // 从CompoundTag读取数据
    public static NLevelTag fromTag(CompoundTag tag) {
        return new NLevelTag(tag.getInt("level"), tag.getInt("levelXP"));
    }

    // 将数据转为CompoundTag
    public CompoundTag toTag() {
        CompoundTag tag = new CompoundTag();
        tag.putInt("level", this.level);
        tag.putInt("levelXP", this.levelXP);
        return tag;
    }

    // 实现Tag接口必要方法
    @Override
    public void write(FriendlyByteBuf buf) {
        buf.writeInt(level);
        buf.writeInt(levelXP);
    }

    @Override
    public byte getId() {
        return Tag.TAG_COMPOUND;
    }

    @Override
    public Tag copy() {
        return new NLevelTag(this.level, this.levelXP);
    }

    // 你的levelUp方法
    public void levelUp() {
        this.levelXP++;
        LOGGER.debug("XP leveled up to " + this.levelXP);
    }

    public void levelUp(int times) {
        for (int i = 0; i < times; i++) {
            levelUp();
        }
    }
}
  1. 修改finishUsingItem方法:
@Override
public ItemStack finishUsingItem(ItemStack stack, Level level, LivingEntity livingEntity) {
    if (livingEntity instanceof Player pPlayer) {
        // 获取玩家NBT副本
        CompoundTag entityNBT = pPlayer.saveWithoutId(new CompoundTag());
        
        if (!entityNBT.contains("necromancy_level", Tag.TAG_COMPOUND)) {
            NLevelTag levelTag = new NLevelTag(1, 0);
            levelTag.levelUp();
            entityNBT.put("necromancy_level", levelTag.toTag());
            pPlayer.load(entityNBT); // 将修改后的NBT写回玩家实体
        } else {
            CompoundTag storedTag = entityNBT.getCompound("necromancy_level");
            NLevelTag levelTag = NLevelTag.fromTag(storedTag);
            levelTag.levelUp(5);
            entityNBT.put("necromancy_level", levelTag.toTag());
            pPlayer.load(entityNBT); // 写回实体
        }
    }
    return super.finishUsingItem(stack, level, livingEntity);
}

关键注意事项

  • 优先使用PersistentDataContainer,这是官方推荐的自定义数据存储方案,避免破坏原生NBT,也降低模组冲突概率。
  • 自定义Tag必须完整实现Tag接口的所有方法,否则无法被Minecraft正确序列化。
  • 操作玩家NBT副本后,必须调用load()方法写回实体,否则修改不会生效。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 20:02:13