nms-nbt-manipulation

star 1

直接操作 CompoundTag 讀寫物品、實體、方塊實體的 NBT 資料(Paper NMS + Mojang-mapped)/ Read and write NBT data on items, entities, and block entities via CompoundTag

MrPippi By MrPippi schedule Updated 4/30/2026

name: nms-nbt-manipulation description: "直接操作 CompoundTag 讀寫物品、實體、方塊實體的 NBT 資料(Paper NMS + Mojang-mapped)/ Read and write NBT data on items, entities, and block entities via CompoundTag"

NMS NBT Manipulation / NMS NBT 操作

技能名稱 / Skill Name

nms-nbt-manipulation

目的 / Purpose

透過 NMS CompoundTag 直接讀寫物品、實體、方塊實體的 NBT 資料,繞過 Bukkit PersistentDataContainer API 的限制,實現更底層的持久化與資料操作。

NMS 版本需求 / NMS Version Requirements

  • Paper 1.21 – 1.21.3
  • Paperweight userdev 1.7.2+
  • Mojang mappings(已由 Paper 1.20.5+ 原生支援)

觸發條件 / Triggers

  • 「NBT」「CompoundTag」「NBT 讀寫」「物品 NBT」「實體 NBT」
  • 「nbt manipulation」「compound tag」「item nbt」「entity nbt」「nbt data」
  • 「持久化」「NBT 持久化」「nbt persistence」

輸入參數 / Inputs

參數 範例 說明
package_name com.example.nbt 產出類別所在 package
target item / entity / block 操作目標(物品、實體、方塊實體)
class_name NbtHelper 工具類名稱

輸出產物 / Outputs

  • ItemNbtHelper.java — 物品 NBT 讀寫工具
  • EntityNbtHelper.java — 實體 NBT 讀寫工具
  • NbtSerializer.java(選)— 自定義物件 NBT 序列化工具

Paperweight 建置設定 / Build Setup

參見 Skills/paper-nms/PLATFORM.md。關鍵依賴:

dependencies {
    paperweight.paperDevBundle('1.21.1-R0.1-SNAPSHOT')
}

代碼範本 / Code Template

ItemNbtHelper.java

package com.example.nbt;

import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.item.ItemStack;
import org.bukkit.craftbukkit.v1_21_R1.inventory.CraftItemStack;

import java.util.Optional;

@SuppressWarnings("UnstableApiUsage")
public final class ItemNbtHelper {

    private ItemNbtHelper() {}

    /** 取得物品的 NMS ItemStack 並讀取自定義 NBT 標籤。 */
    public static Optional<String> getString(org.bukkit.inventory.ItemStack item, String key) {
        ItemStack nms = CraftItemStack.asNMSCopy(item);
        CompoundTag tag = nms.getTag();
        if (tag == null || !tag.contains(key)) return Optional.empty();
        return Optional.of(tag.getString(key));
    }

    /** 寫入字串 NBT 並回傳修改後的 Bukkit ItemStack(不可變模式)。 */
    public static org.bukkit.inventory.ItemStack setString(
            org.bukkit.inventory.ItemStack item, String key, String value) {
        ItemStack nms = CraftItemStack.asNMSCopy(item);
        CompoundTag tag = nms.getOrCreateTag();
        tag.putString(key, value);
        return CraftItemStack.asBukkitCopy(nms);
    }

    /** 讀取整數 NBT。 */
    public static int getInt(org.bukkit.inventory.ItemStack item, String key, int def) {
        ItemStack nms = CraftItemStack.asNMSCopy(item);
        CompoundTag tag = nms.getTag();
        return (tag != null && tag.contains(key)) ? tag.getInt(key) : def;
    }

    /** 寫入整數 NBT 並回傳修改後的 Bukkit ItemStack。 */
    public static org.bukkit.inventory.ItemStack setInt(
            org.bukkit.inventory.ItemStack item, String key, int value) {
        ItemStack nms = CraftItemStack.asNMSCopy(item);
        CompoundTag tag = nms.getOrCreateTag();
        tag.putInt(key, value);
        return CraftItemStack.asBukkitCopy(nms);
    }

    /** 移除指定 NBT 鍵。 */
    public static org.bukkit.inventory.ItemStack removeKey(
            org.bukkit.inventory.ItemStack item, String key) {
        ItemStack nms = CraftItemStack.asNMSCopy(item);
        CompoundTag tag = nms.getTag();
        if (tag != null) tag.remove(key);
        return CraftItemStack.asBukkitCopy(nms);
    }

    /** 檢查是否含有指定鍵。 */
    public static boolean hasKey(org.bukkit.inventory.ItemStack item, String key) {
        ItemStack nms = CraftItemStack.asNMSCopy(item);
        CompoundTag tag = nms.getTag();
        return tag != null && tag.contains(key);
    }
}

EntityNbtHelper.java

package com.example.nbt;

import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.entity.Entity;
import org.bukkit.craftbukkit.v1_21_R1.entity.CraftEntity;

@SuppressWarnings("UnstableApiUsage")
public final class EntityNbtHelper {

    private EntityNbtHelper() {}

    /**
     * 讀取實體的完整 NBT CompoundTag(含位置、速度、自定義資料等)。
     * 必須在主執行緒呼叫。
     */
    public static CompoundTag getTag(org.bukkit.entity.Entity entity) {
        Entity nms = ((CraftEntity) entity).getHandle();
        CompoundTag tag = new CompoundTag();
        nms.save(tag);
        return tag;
    }

    /** 讀取實體自定義 tag(custom_name, Tags 等之外的自定義鍵)。 */
    public static String getString(org.bukkit.entity.Entity entity, String key, String def) {
        CompoundTag tag = getTag(entity);
        return tag.contains(key) ? tag.getString(key) : def;
    }

    /**
     * 將 CompoundTag 合併回實體(load/merge)。
     * 必須在主執行緒呼叫,且不可覆寫 UUID/位置。
     */
    public static void mergeTag(org.bukkit.entity.Entity entity, CompoundTag patch) {
        Entity nms = ((CraftEntity) entity).getHandle();
        CompoundTag current = new CompoundTag();
        nms.save(current);
        current.merge(patch);
        nms.load(current);
    }
}

NbtSerializer.java(自定義物件序列化範例)

package com.example.nbt;

import net.minecraft.nbt.CompoundTag;

/** 示範如何將自定義物件序列化/反序列化為 CompoundTag。 */
public final class NbtSerializer {

    private NbtSerializer() {}

    public record PlayerData(String name, int level, double exp) {}

    public static CompoundTag serialize(PlayerData data) {
        CompoundTag tag = new CompoundTag();
        tag.putString("name", data.name());
        tag.putInt("level", data.level());
        tag.putDouble("exp", data.exp());
        return tag;
    }

    public static PlayerData deserialize(CompoundTag tag) {
        return new PlayerData(
            tag.getString("name"),
            tag.getInt("level"),
            tag.getDouble("exp")
        );
    }
}

推薦目錄結構 / Recommended Directory Structure

src/main/java/com/example/
├── MyNmsPlugin.java
└── nbt/
    ├── ItemNbtHelper.java
    ├── EntityNbtHelper.java
    └── NbtSerializer.java

執行緒安全注意事項 / Thread Safety

  • ItemNbtHelper 的方法操作 NMS Copy(不修改原物件),可在任何執行緒呼叫
  • ⚠️ EntityNbtHelper.getTag() / mergeTag() 存取實體狀態,必須在主執行緒呼叫
  • ⚠️ nms.save() / nms.load() 不執行緒安全,確保在 Bukkit scheduler 內呼叫
  • 詳見 Skills/_shared/nms-threading.md

失敗回退 / Fallback

錯誤 原因 解法
getTag() 回傳 null 物品無自定義 NBT 改用 getOrCreateTag()
資料合併後實體行為異常 load() 覆寫了位置/UUID 合併前從 patch 移除 PosUUID
ClassCastException: CraftEntity 外掛替換實體實作 改用 nms-reflection-bridge 取得 handle
NBT 鍵消失(重載後) 未使用 PersistentDataContainer 若需跨重啟持久化,改用 PDC 或 SQL
Install via CLI
npx skills add https://github.com/MrPippi/MJP-Claude-Skills --skill nms-nbt-manipulation
Repository Details
star Stars 1
call_split Forks 0
navigation Branch main
article Path SKILL.md
More from Creator