--- title: NBT深度解析 category: NBT深度解析 mentions: - ConsoleTerm - SmokeyStack - ThomasOrs tags: - 专家 --- # NBT深度解析 NBT(命名二进制标签)是一种二进制层级的编码格式,正如你熟悉的基于文本层级的JSON格式。因此我们可以用JSON格式举例说明,你可能也注意到Minecraft本身在命令中使用JSON来表示NBT(如Java版命令或简化的基岩版命令`/give`、`/replaceitem`)。详见[NBT命令](/wiki/commands/nbt-commands)。本文将深入解析NBT的运作原理、读取方式以及`Minecraft BE`如何应用它,其详细程度远超你在命令中接触的NBT表象。 ## NBT标签与数据类型 与JSON类似,NBT具备类型识别系统。例如JSON通过`{}`符号识别复合对象,通过`"`识别字符串。要理解NBT,需要掌握复合对象的起始标记和各类型的读取方式。 NBT基于二进制操作,最小单位为8位字节。各类型占用固定字节数,不存在半字节情况。注意类型名称可能有不同叫法,但二进制标识符(ID)始终由1字节表示。 | 名称 | 二进制ID | 二进制大小 | 描述 | | :----------------: | -------: | :--------------- | :------------------------------------------------------------------------------------------------------------------------------- | | 字节 | 0x01 | 1字节(8位) | 单字节类型 | | Int16(短整型) | 0x02 | 2字节(16位) | 双字节类型 | | Int32(整型) | 0x03 | 4字节(32位) | 四字节类型 | | Int64(长整型) | 0x04 | 8字节(64位) | 八字节类型 | | 浮点 | 0x05 | 4字节(32位) | 常规精度浮点数 | | 双精度 | 0x06 | 8字节(64位) | 高精度浮点数 | | 字符串 | 0x08 | 预定义长度 | UTF-8编码文本,前接2字节长度标识 | | 列表 | 0x09 | 预定义长度 | 元素类型统一,前接4字节元素数量 | | 复合标签 | 0x0A (10)| 未定义长度 | 通过遍历键值对读取,直到遇到结束标记 | | 复合标签结束标记 | 0x00 | 0字节 | 仅作为复合标签结束标识 | | 字节列表 | 0x07 | 预定义长度 | 基岩版不常用 | | 整型列表 | 0x0B (11)| 预定义长度 | 基岩版不常用 | | 长整型列表 | 0x0C (12)| 预定义长度 | 基岩版不常用 | 注意NBT没有布尔类型,需用字节类型的1/0表示true/false。 ## NBT标签读写方法 所有数值类型按字节长度读取,基岩版采用[小端序](#小端序)编码,与Java版的大端序相反。 ### 类型读取 始终读取1字节确定后续数据类型。 ### 数值读取 根据类型确定字节数(如类型3读取4字节)。所有数值使用[小端序](#小端序)处理。 ### 字符串读取 先读取2字节长度标识(Int16),再按对应字节数读取UTF-8编码内容。 ### 列表读取 1. 读取列表元素类型(1字节) 2. 读取元素数量(Int32,4字节) 3. 按数量循环读取元素 注意:字节列表/整型列表/长整型列表的读取方式不同 ### 复合标签读取 1. 读取类型标记: - 0x00:结束读取 - 其他类型:继续读取键值对 2. 读取键名字符串 3. 读取对应类型值 ## 基岩版NBT文件解析 注意文件开头的[基岩版NBT文件头](#基岩版nbt文件头),如`.mcstructure`文件无此头而`level.dat`有。根元素需作为匿名属性处理(即使键名为空)。 ::: code-group ```json [.mcstructure示例] "":{ "format_version":1, "size":[],//... "structure":{},//... "structure_world_origin":[]//.. } ``` ::: :::warning 此示例表明即使根元素键名通常为空,仍需进行读取操作。 ::: ## NBT写入规范 写入流程与读取逆向操作,需先掌握读取原理。 ## 基岩版NBT文件头 包含两个4字节数值: 1. 固定值8(0x08000000) 2. NBT结构体字节数(不含头部的8字节) 示例: - `08 00 00 00` - `bf 00 00 00` - <固定值8> ## 小端序 数字按字节逆序存储的编码方式: - Int16 `0x5a72` → 字节数组 `[0x72, 0x5a]` - Int64 `0x11223344aabbccdd` → 存储为 `dd cc bb aa 44 33 22 11` 读取时反向转换即可还原数值。单字节类型不受影响。