命名二进制标签(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。