命名二进制标签(NBT)
NBT 是 Minecraft 早期由 Notch 编写的数据格式,在游戏代码中广泛用于数据存储。
格式规范
NBT 与 JSON 格式类似,但存在一些差别:
- 字节、短整数、长整数和单精度浮点数有独立类型,分别使用
b、s、l、f后缀,形式类似 Java 中的表示法。- 双精度浮点数可选用
d后缀,与 Java 类似。原文另称 Java 整数可选的i后缀在这里不允许使用。 - 后缀不区分大小写,例如
64b与64B相同,0.5F与0.5f相同。
- 双精度浮点数可选用
- 没有布尔类型,而用字节表示:
true为1b,false为0b。- 当前实现将所有非零值视为
true,因此2b也表示真。
- 当前实现将所有非零值视为
- 没有对应
null的值。 - 键两侧的引号可省略。例如 JSON 的
"duration": 20,在 NBT 中可写为duration: 20或"duration": 20。 - JSON 中的子对象在 NBT 中称为复合标签,简称 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> 的便捷重载。
当然,也可以读取标签中的值:
Optional<Integer> color = tag.getInt("Color");
Optional<String> level = tag.getString("Level");
Optional<Double> d = tag.getDouble("IAmRunningOutOfIdeasForNamesHere");
由于无法保证标签存在,返回值用 Optional 包装。基本类型可通过相应的 *Or* 方法指定默认值。ListTag 可通过 getListOrEmpty 返回空列表默认值,CompoundTag 则使用 getCompoundOrEmpty。基本类型数组没有对应的 *Or* 方法。
int color = tag.getIntOr("Color", 0xffffff);
String level = tag.getStringOr("Level", "minecraft:overworld");
double d = tag.getDoubleOr("IAmRunningOutOfIdeasForNamesHere", 1d);
所有标签类型都实现 Tag。除 CompoundTag 外,多数类型主要供内部使用,例如 ByteTag 和 StringTag。需要时,也可以通过 CompoundTag#get 和 #put 直接操作它们。
一个明显例外是 ListTag。它与特定标签类型关联,类型在内部计算,因此操作方式有所不同:
ListTag newList = new ListTag();
// Adds the tags to the list
newList.add(StringTag.valueOf("Value1"));
newList.add(StringTag.valueOf("Value2"));
// Getting the tag
ListTag getList = tag.getListOrEmpty("SomeListHere");
最后,在 CompoundTag 内部直接操作另一个 CompoundTag 时,使用 CompoundTag#get 和 #put:
tag.put("Tag", new CompoundTag());
// Can use regular `get` as well if you want to handle null case instead
tag.getCompoundOrEmpty("Tag");
NBT 的用途
Minecraft 在许多地方使用 NBT。方块实体和实体通过值访问抽象了 NBT 操作,ItemStack 则通过数据组件抽象这些操作。
另见
来源: NeoForged/Documentation(26.1)。中文翻译依据提交
4a680cdd4d15。