命名二进制标签(NBT)

命名二进制标签(NBT)

NBT 是 Minecraft 早期由 Notch 亲自编写并引入的格式,在整个 Minecraft 代码库中广泛用于数据存储。

规范

NBT 规范与 JSON 类似,但有以下区别:

  • 字节、短整数、长整数和浮点数有各自的类型,分别以 b、s、l 和 f 为后缀,类似 Java 代码中的表示方式。
    • 双精度浮点数也可以带 d 后缀,但并非必需,类似 Java。Java 中整数可用的可选 i 后缀在 NBT 中不允许使用。
    • 后缀不区分大小写,例如 64b 等同于 64B,0.5F 等同于 0.5f。
  • 不存在布尔类型,而是用字节表示:true 为 1b,false 为 0b。
    • 当前实现将所有非零值都视为 true,因此 2b 也会被视为 true。
  • NBT 没有与 null 对应的值。
  • 键两侧的引号可省略。例如 JSON 属性 "duration": 20 在 NBT 中既可写为 duration: 20,也可保留引号。
  • JSON 中的子对象在 NBT 中称为复合标签(compound tag,或简称 compound)。
  • 与 JSON 不同,NBT 列表不能混合不同类型。列表类型由首个元素确定,或由代码指定。
    • 但列表的列表可以包含不同元素类型的子列表。例如,一个列表包含两个子列表,第一个存字符串、第二个存字节,这是允许的。
  • 另有特殊的数组类型,与列表不同,但也使用方括号包围元素,共三种:
    • 字节数组,以 B; 开头,例如 [B;0b,30b]。
    • 整数数组,以 I; 开头,例如 [I;0,-300]。
    • 长整数数组,以 L; 开头,例如 [L;0l,240l]。
  • 列表、数组和复合标签允许尾随逗号。

NBT 文件

Minecraft 大量使用 .nbt 文件,例如数据包中的结构文件。保存一个区域(即一组区块)内容的区域文件(.mca),以及游戏各处使用的 .dat 文件,也都是 NBT 文件。

NBT 文件通常经过 GZip 压缩,属于二进制文件,不能直接编辑。

代码中的 NBT

与 JSON 一样,所有 NBT 对象都属于一个外围对象。先创建它:

CompoundTag tag = new CompoundTag();

现在可以向标签写入数据:

tag.putInt("Color", 0xffffff);
tag.putString("Level", "minecraft:overworld");
tag.putDouble("IAmRunningOutOfIdeasForNamesHere", 1d);

这里有多种辅助方法,例如 putIntArray 除接受 int[] 的标准变体外,还提供接受 List<Integer> 的便捷方法。

也可以从标签读取值:

int color = tag.getInt("Color");
String level = tag.getString("Level");
double d = tag.getDouble("IAmRunningOutOfIdeasForNamesHere");

数值类型不存在时返回 0,字符串不存在时返回 ""。更复杂的类型(列表、数组、复合标签)不存在时会抛出异常。

因此,应该检查标签元素是否存在:

boolean hasColor = tag.contains("Color");
boolean hasColorMoreExplicitly = tag.contains("Color", Tag.TAG_INT);

TAG_INT 常量定义在所有标签类型的父接口 Tag 中。除 CompoundTag 外,大多数标签类型(例如 ByteTag、StringTag)主要供内部使用,不过遇到它们时,可以通过 CompoundTag#get 与 #put 直接操作。

ListTag 是一个明显例外。使用 CompoundTag#getList 获取列表时必须同时指定元素类型。例如,获取字符串列表:

ListTag list = tag.getList("SomeListHere", Tag.TAG_STRING);

创建 ListTag 时也必须指定列表类型:

ListTag list = new ListTag(List.of("Value1", "Value2"), Tag.TAG_STRING);

最后,在一个 CompoundTag 内操作另一个 CompoundTag 时,直接使用 CompoundTag#get 与 #put:

tag.put("Tag", new CompoundTag());
tag.get("Tag");

NBT 的用途

Minecraft 在许多地方使用 NBT,常见例子包括方块实体与实体。

提示 ItemStack 通过数据组件抽象了 NBT 的使用。

另见


来源: NeoForged/Documentation(1.21.1)。中文翻译依据提交 4a680cdd4d15。