扩展名不会告诉你原理图格式——33 个 .schematic 文件里有 31 个是别的格式
五种格式,四种不同的方块打包方式,而 .schematic 这个扩展名被其中两种共用。实测 33 个 .schematic 文件里有 31 个其实是 MCEdit 格式。嗅探 NBT 根节点比相信文件名更可靠,本文附实测数据。
市面上流通的原理图格式有五种,而文件名只是提示,不是事实。 这里的查看器通过查看文件内部来判断它是什么,这样做是有实测依据的。
五种格式,五个扩展名
| 扩展名 | 格式 |
|---|---|
.nbt | 原版结构 |
.schem | Sponge |
.schematic | Sponge——默认 |
.litematic | Litematica |
.mcstructure | 基岩版 |
问题出在 .schematic 这一行。这个扩展名被 经典 MCEdit 格式和 Sponge 格式共用,而改文件名的人要么不知道,要么不在乎。
在一个真实语料库上统计:33 个 .schematic 文件中,31 个是 MCEdit,一个是原版结构,一个是 Litematica。也就是说,按扩展名默认猜测,几乎全都猜错,还有两个文件根本算不上 .schematic——只是名字起错了。
解决办法是嗅探 NBT 根节点,让文件实际是什么胜过它叫什么:
- 有
Regions键 → Litematica - 同时有
palette和blocks→ 原版结构 - 否则做 MCEdit 形状检测,再退回按扩展名判断
同一种方块的四种打包方式
这些格式的差别不是表面功夫。每种都以真正不同的方式存储方块数据,而每种选择都有其后果:
原版 .nbt——列表。 每个保存的位置一条记录,各自指向一个调色板索引。空气和其他方块一样被存储;只有结构空位被略去,所以空心建筑只有在保存前把内部挖成结构空位才省空间。
Sponge .schem——varint 流。 调色板索引以可变宽度整数打包:每字节七位有效载荷,最高位置位表示继续。小调色板每方块一字节;调色板超过 127 项时,高索引开始占两字节。紧凑,但自描述。
MCEdit .schematic——扁平字节数组。 每方块一字节,所以最多 256 种方块类型——正因如此它才有一个可选的 AddBlocks 副数组,每方块加一个半字节的四位 id,使 id 达到 4,095。这是方块状态出现之前的遗留数字 id 格式:它的 id 是数字,当 Schematica 写入 SchematicaMapping 复合标签时通过它解析,否则通过原版 1.12 的 id 表解析。
Litematica .litematic——位打包长整型。 索引以每项恰好 max(2, bits needed for the palette) 位打包,低位在前,一项可能横跨两个长整型的边界。5 项调色板每方块用 3 位;300 项调色板用 9 位。
2 位这个下限很重要:即使只有两种方块的调色板,每项也不会压缩到 2 位以下,所以单色建筑并没有数学上看起来那么小。
基岩版是小端序
.mcstructure 在更底层的地方与众不同:基岩版写入小端序 NBT,而所有 Java 格式都写大端序。这在进行任何格式解析之前就已确定——用错误的字节序读取字节,你得到的不是错误的结构,而是根本无法解析的乱码。
实际意义
如果某个原理图在某个地方打不开,第一个问题不是“文件是不是损坏了”,而是“这个文件是不是它名字所说的东西”。从下载页面拿到的 .schematic 更可能是 MCEdit 而不是 Sponge,而一个相信扩展名的工具会拒绝一个完全正常的文件。
而在比较同一个建筑的两次导出时,体积差异主要在于编码而非内容——一个挖空成结构空位的原版 .nbt 和一个位打包的 .litematic 解决的是不同的问题。