NBT 格式
NBT, 全称Named Binary Tag, 是一种二进制文件格式, 用作储存Minecraft的游戏资料。
这类型档案的后缀一般为.dat(MC文件里, 其他软件的.dat文件用的绝对是别的格式...)
要打开NBT档案, 一般需要特殊软件/库, 以下有一个普遍认为比较好的软件, 及一个python的nbt库
- NBTExplorer 一个挺常用的软件。
- python nbt库 注意, 这个库导入的时候需要写 import nbt.nbt 而不是nbt。
当然, 我们这是浅谈命令, 自然不是说NBT文件格式了...
命令里的NBT, 讲的是是另外一种格式, 在下面会详细说明。
命令里的NBT能够修改实体(玩家除外)、方块的某些属性, 也能够检查实体(包括玩家)、方块的某些属性是否符合要求。
每个标签的格式如下:
标签名称:值(list里的标签没有标签名称, 只有值)
每个标签之间用逗号(,)相隔,比如
{NoGravity:1b,Invisible:1b}
NoGravity:1b就是一个标签,而NoGravity就是标签的名称,1b就是其值
Invisible:1b就是另一个标签,Invisible就是标签的名称,1b就是其值
数值类
TAG_Byte
例子:1b
这个是代表什么呢?这个是用作储存数值用的。它能够储存的数值范围为-128 至 127。这个除了能够储存数值之外,它也能够储存Boolean值(True/False),这个时候它的范围为0 (False)和1 (True)。
使用的时候需要注意一点,当你用在检测的指令上(比如testfor和scoreboard),数值后需要补上b字来指明它那个数值是Byte
TAG_Short
例子:1s
这个也是储存数值用,数值的范围为-32,768 至 32,767。
使用的时候需要注意一点,当你用在检测的指令上(比如testfor和scoreboard),数值后需要补上s字来指明它那个数值是Short
TAG_Int
例子:1
这个也是储存数值用,数值的范围为-2,147,483,648 至 2,147,483,647。
使用的时候需要注意一点,就是数值后不能补上i字
TAG_Long
例子:0l
这个也是储存数值用,数值的范围为-9,223,372,036,854,775,808 至 9,223,372,036,854,775,807。
使用的时候需要注意一点,当你用在检测的指令上(比如testfor和scoreboard),数值后需要补上l字来指明它那个数值是Long
TAG_Float
例子:1.0f
只有这个和Double可以储存小数。其最大值也比long大得多,然而它的精确度会随着数值的大小而变化(绝对值越大,它的精确度就越小)。
数值后需要补上f字来指明它那个数值是float
TAG_Double
例子:1d
只有这个和Float可以储存小数。其最大值也比long大得多,然而它的精确度会随着数值的大小而变化(绝对值越大,它的精确度就越小)。
如果你的数值里有小数点,那么就默认为double,可以不写d字在数值之后,然而如果没有小数点,就需要写d在数值后面以标明是double。
当你用在检测的指令上(比如testfor和scoreboard),数值后需要补上d字来指明它那个数值是double
TAG_Int_Array
例子:[123,456]
这个看上去和TAG_List相近,然而它们之间的分别挺大的。
- Int_Array只能储存Int,不能储存其他数值
- Int_Array检测的时候是检测整个数值的,而List检测的时候可以只检测某个子标签,比如玩家手上有一个烟花,这个时候玩家的NBT应该是
(Colors就是一个Int_Array){SelectedItem:{tag:{Fireworks:{Explosions:[{Type:1b,Colors:[7599255,62976]}]}}}}
如果我们只是把Colors:[7599255,62976]换为Colors:[7599255]
它的结果是不符合的(因为Colors括号里的是其数值而不是其子标签)
字符
TAG_String
例子:
- "armor_stand"
- armor_stand
这个类型可以储存字串, 不一定需要""包围。
然而要小心,如果字串内有,
号就需要用"把整个字串括住(也有一个例外情况,比如是command:entitydata @e {Fire:20b,Air:20s},这样便不用""括住,因为那个逗号是在另外一个{}里面)。
字串需要转义
转义的方法是:每个\符号前方要加上一个\符号,"符号之间的每个"符号前方也要加上一个\符号
所以"""
转义后会变成"\""
,再转义会变成"\\\""
,再转义就会变成"\\\\\\\""
以下是一些合法的字符串例子:
- "" (空的字符串)
- a (字符串为a)
- "1" (如果那字符串可能被解析为别的类型, 则需要加上"")
- 123456789123456789123546789 (这数值太大, 超出int的最大上限, 因此会被解析为字串)
- {ab,cd} (因为,在{}里面。逗号在{}和[]里面则不需要理会, 然而在()里面则没用)
\\"\\"
(字符串为\"\"
, "符号由于不是在另外一组""里, 因此不需要特别转义)"\\\"\\\""
(和上方的字符串等价, 因为"符号在另外一组"符号里, 因此需要转义)
母标签类
List和Compound可以互相堆叠, 然而堆叠层数不能超过512层...
TAG_List
这个是一个母标签的类型,它的子标签的类型全部都是相同的丶没有标签名称并且会被一个[]括住。
例子:
Items:[{id:"minecraft:stone",Count:1b},{id:"minecraft:glass",Count:1b}]
Items就是一个List类型的NBT,而{id:"minecraft:stone",Count:1b}和{id:"minecraft:glass",Count:1b}就是其子标签(id和Count并不算是其子标签!!!),在这个例子里,其子标签的类型就是Compound。
这个类型相当特别,你可以检测其中的一/几个子标签,比如你检测Items:[{id:"minecraft:glass",Count:1b}],它的输出是成功的。
然而,当你更改List的子标签时,它会把所有的子标签更新(覆盖)。比如说你用blockdata把那个箱子的NBT更改为Items:[{id:"minecraft:glass",Count:2b}],那个箱子里的石头会被删除。
(如果你用entitydata得到他的NBT,你应该会看见类似的东西: 标签名:[0:值1,1:值2,2:值3]之类的东西,其实那个0/1/2就是个编号,大可以忽略它,因为你不能只改变某个编号的值,也不能只探测某个特定编号的值)
注意: 检查[0,0,0]和检查[0]基本上是没有分别的。因为list检查的时候是不会检查位置的, 而是检查有没有该值。因此[0,0,0]只是检查三遍有没有0, 和检查一遍有没有0结果是一样的。
此外, 检测[]就能检测空list标签(一旦里面有任何子标签, 则不会成功)
TAG_Compound
例子:{id:"ArmorStand"}
这个也是一个母标签的类型,其子标签需要用{}括住,并且需要有标签名称。比如Riding:{id:"ArmorStand",CustomName:"AS1",Riding:{id:"ArmorStand",CustomName:"AS2"}}。
注意, 标签名称、子标签也可以有多余空格, 比如 { abcd : cdefg }。
命令执行时会自动清除那些空格, 上方的例子就和{abcd:cdefg}等价。
你能够只检测/修改Compound里的一个子标签, 只需要填写它们的名称就可以了。
然而这也代表了你无法删除Compound里的任何标签。
Compound和List的最大分别(在NBT里)是List无法透过命令独立变更其中的子标签的值,而Compound则可以。
获取方块/实体(非玩家)NBT
实体
我们可以透过
/entitydata <指定的实体> {}
来得到那个实体的NBT
比如
/entitydata @e[c=1,type=!Player] {}
方块
我们可以透过
/blockdata <x> <y> <z> {}
来得到其NBT
比如
/blockdata ~ ~-1 ~ {}
那个输出会有一行"The data tag did not change:",然后就是那些NBT
当然,在聊天栏看是比较辛苦的,我们可以把这个命令放在命令方块里激活,然后ctrl a 那个输出栏,然后再ctrl c复制那个输出,之后放在一个你觉得方便的文字编辑器那里,比如记事本等
阅读NBT文档
使用NBT, 我们需要知道那标签的用途以及格式。
而描述标签的用途和格式的文件, 就是NBT文档了。
本教程里会提供一些NBT的文档。
然而版本更新后, 本教程里的文档或许会不够详尽, 那时候就需要到wiki查阅了。
wiki链接:
NBT树状图简介
树状图格式如下:
- 母标签a
- 母标签b
- 子标签c
- 子标签d
- 子标签e
- 母标签b
b和e就是a的子标签。c和d就是b的子标签。
一般来说树状图标签前面会有一个图标, 代表该标签的类型。
把鼠标放在上方就能查看其类型了(看得多了也能直接从图标查看其类型)。
Compound
如果那个母标签的类型是compound,那么它的子标签就是它能够包括的标签
- Pose
- Body
- x-角度
- y-角度
- z-角度
- LeftArm
- x-角度
- y-角度
- z-角度
- RightArm
- x-角度
- y-角度
- z-角度
- LeftLeg
- x-角度
- y-角度
- z-角度
- RightLeg
- x-角度
- y-角度
- z-角度
- Head
- x-角度
- y-角度
- z-角度
- Body
以命令NBT的写法(缩排和分行是为了方便阅读, 实际上命令是不会有分行和缩排的。而且也没必要写那么多, 对compound来说), 就是
Pose:{
Body:[<x角度>d,<y角度>d,<z角度>d],
LeftArm:[<x角度>d,<y角度>d,<z角度>d],
RightArm:[<x角度>d,<y角度>d,<z角度>d],
LeftLeg:[<x角度>d,<y角度>d,<z角度>d],
RightLeg:[<x角度>d,<y角度>d,<z角度>d],
Head:[<x角度>d,<y角度>d,<z角度>d]
}
List
对于List来说, 有两种情况。
固定子标签
- Head
- x-角度
- y-角度
- z-角度
这里就是一个例子。
Head:[a,b,c]
a代表x角度, b代表y角度, c代表z角度
里面不同位置的子标签有不同含义
不固定子标签
- Tags
- a tag(一个标签)
NBT: Tags:["一个标签","第二个标签","第三个标签"]
每次看见a xxxx(一个 xxx),就代表里面子标签的数量是不固定的, 而且子标签的顺序不是太重要(船的Passengers除外, 那牵涉到实体的位置)
特殊NBT种类
认读的nbt
就是只能检测, 修改了没用的nbt。
例子: OnGround
未必存在的nbt
当不需要它的时候, 它未必存在(事实上很多nbt都是这样)
例子: 物品的Slot标签
只能在出生时设定的nbt
就是出生后或许会消失, 或许修改后没用的nbt
例子: Passengers, UUIDLeast, UUIDMost, id
常见格式
实体格式
- 一个compound
- id: 实体id, 决定实体种类, 如minecraft:ArmorStand
- ...(其他tag)
例子:
{id:"minecraft:ArmorStand",NoGravity:1b}
物品格式
- 一个compound
- id: 物品id, 决定物品种类, 如minecraft:diamond_sword
- Count: 物品数量
- Slot: 所在物品栏id, 可能不存在
- Damage: 物品损伤值/数据值, 默认为0
- tag: 物品的其他nbt标签, 里面可能有: display, ench等
例子:
{id:minecraft:diamond_sword,Count:1b,Damage:0s,tag:{display:{Name:"sword"}}}
母标签 Base Tag
在命令里, 我们或许会使用base tag这个词。而在wiki是看不到这个词的, 这是我们定义来方便说明NBT的。
Base tag就是代表该NBT的母标签。我们为不同NBT的母标签根据用途定义名称。
比如说, Count的base tag就是item, ench的base tag就是tag, 如此类推。
详细可以看JSON文件, 里面的格式如下
- <base tag名称>
- type, tag类型(如果是<base tag名称>, 则代表是compound, 内容则见该base tag)
- subtype, 子tag类型, 如果tag类型是list则会出现
- count, 子tag数量, 如果是0则代表不限制, 如果tag类型是list则会出现
自定义NBT
物品的tag里的nbt可以自定义。
透过自定义nbt, 玩家可以简单地识别特殊物品, 无论该物品在玩家手上还是在掉落物的状态。
自定义nbt需要严格跟从nbt格式, 需要定义其类型, 如test:1b
详细可见: http://www.mcbbs.net/thread-463290-1-1.html