跳转至

NBT

NBT(Named Binary Tag)是一种二进制级别的数据编码格式,用于在Minecraft中存储结构化数据。在基岩版中,NBT被广泛应用于实体、物品、方块实体、存档等多个方面的数据序列化与反序列化。

概述

NBT最初由Notch为Minecraft Java版设计,后被基岩版沿用并在编码细节上做出了修改。NBT的核心思想是使用一系列带有名称的标签(Tag)来组织数据,每个标签由类型、名称和值三部分构成。标签可以嵌套,从而形成树状的层级结构,用以表达复杂的数据关系。

JSON等文本格式相比,NBT是一种紧凑的二进制格式,读写效率更高,更适合游戏运行时的大量数据存取场景。但也因此,NBT文件无法直接用文本编辑器查看或编辑,通常需要借助专用工具进行操作。

数据类型

NBT定义了以下数据类型,每种类型由一个唯一的类型ID标识:

类型 类型ID 大小 描述
End 0x00 1字节 标记复合标签(Compound Tag)的结束
Byte 0x01 1字节 8位有符号整数
Short 0x02 2字节 16位有符号整数
Int 0x03 4字节 32位有符号整数
Long 0x04 8字节 64位有符号整数
Float 0x05 4字节 32位IEEE 754单精度浮点数
Double 0x06 8字节 64位IEEE 754双精度浮点数
Byte Array 0x07 可变 字节型数组,前缀一个Int表示长度
String 0x08 可变 UTF-8编码字符串,前缀一个Short表示长度
List 0x09 可变 同类型标签的有序列表,前缀一个Byte表示元素类型和一个Int表示长度
Compound 0x0A 可变 由若干具名标签组成的无序集合,以End标签结束
Int Array 0x0B 可变 整型数组,前缀一个Int表示长度
Long Array 0x0C 可变 长整型数组,前缀一个Int表示长度

NBT中不存在专用的布尔类型。布尔值通过Byte类型模拟,1代表真,0代表假。

字节序

基岩版NBT使用小端序(Little-Endian)编码,即多字节数值的低位字节在前、高位字节在后。这与Java版使用的大端序(Big-Endian)相反,是基岩版NBT与Java版NBT之间最主要的差异之一。

此外,基岩版在网络传输场景中使用一种称为网络小端序(Network Little-Endian)的变体编码。在该编码中,Int和Long类型使用可变长整数(VarInt)表示,以减小网络传输的数据量。

文件头

基岩版的部分NBT文件(如 level.dat)在数据正文之前包含一个8字节的文件头(Header)。文件头由两个小端序的32位整数组成:

  1. 第一个整数:存储版本号(在 level.dat中表示存档版本,其他文件中通常为8)。
  2. 第二个整数:NBT数据正文的字节长度(不包括文件头本身的8个字节)。

并非所有NBT文件都包含文件头。例如, .mcstructure结构文件中的NBT数据不包含文件头。

存储位置

NBT在基岩版中应用于多种数据存储场景:

存档数据库

基岩版使用经过修改的Google LevelDB作为存档的底层数据库,配合Zlib压缩。数据库中以下类型的键值对存储NBT数据:

  • 方块实体数据(键标签0x31):存储箱子、告示牌、酿造台等方块实体的状态。
  • 实体数据(键标签0x32):存储世界中所有非玩家实体的状态。
  • 计划刻数据(键标签0x33):存储待执行的计划刻信息。
  • 玩家数据:本地玩家以~local_player为键存储,远程玩家以player_<客户端ID>为键存储。

存档配置文件

level.dat文件存储了世界的全局配置信息,包括世界名称、游戏模式、游戏规则、种子、天气状态等。该文件包含前述8字节文件头。

结构文件

.mcstructure文件使用NBT存储由结构方块导出的建筑结构数据,包括方块布局、方块实体数据和实体数据。该文件不包含文件头。

物品数据

物品在NBT中的常见标签包括:

与Java版NBT的差异

基岩版NBT与Java版NBT在概念上一致,但在以下方面存在差异:

差异 基岩版 Java版
字节序 小端序 大端序
存储方式 LevelDB数据库 区域文件(Region File)
根元素 存在根元素名称(通常为空字符串) 存在根元素名称
网络传输 网络小端序(使用VarInt) 大端序
文件头 部分文件包含8字节文件头 通常使用GZip压缩

编辑注意事项

直接编辑NBT数据存在一定风险。安全的做法是只修改游戏本身能够产生的值,例如修改书与笔的文本内容、物品的显示名称和描述文本等。超出游戏正常范围的修改(如设置超过上限的属性值、写入无效的标签类型等)可能导致数据损坏或游戏行为异常。对于需要自定义交易或自定义掉落等功能,建议优先使用战利品表等数据驱动的方式实现,而非直接修改NBT