NBT实战
这部分会涉及不少英语...
而且玩NBT必须会点英语...因为都是英语词语
英语不好的读者...请自行找个命令群问吧,并且得学好点英语啊23333
阅读树视图(Treeview)
Wiki中以树视图来表达NBT的继承关系(父compound/list与子标签)。
标签左边的图标会标识每个标签的类型(看不清楚的话可以把鼠标放在那图标上面)。
那格式相信已经非常清楚了,然而还是有点需要解释的。
阅读子Compound
首先,大家需要明白一个很重要的事实: Compound是分种类的。
Compound根据子标签的不同,是有不同的"种类"的。我们一般会把常用的compound分类。类别如下(子类别为在父类别加上一些别的标签):
- Entity (实体)
- Mob (生,实体的子类别)
- Projectile (弹射物,实体的子类别)
- Block Entity (动态方块,实体的子类别)
- ...
- Item (物品)
- Block (方块)
- Tag (物品内的Tag)
- Attribute
- ...
我们会在之后的部分简述其中一些标签。
其实命令里的
Data tag
(数据标签)也是有分"种类"的,实体相关的大部分为Entity,物品相关的为Tag,方块相关的为Block
有时候会看到这种See this format (recursive)
(中文为参见这个格式(递归)
)。
这代表里面这个Compound,就是这个部分最"大"的标签(在这个例子中,最大的标签就是Entity data,中文为实体数据)。
那个部分在wiki里其实是这样的
Entity data
id: string ...
Pos: list of 3 TAG_Doubles ...
...
Passengers: list of the data of the entity riding...
see this format (recursive)
我们看最"大"的tag,就是看没有父标签的那个,在这情况就是Entity data
。
有时候也会看见这种:The list of items .... (中文:....物品的列表)
这说明下面的compound为item。
阅读List元素
List元素有两种,分别为有限(且顺序敏感)元素数量及不限制元素数量的。
有限元素的分别有两种写法。第一种就如同上方的HandItems一样,就是List下面有多于一个标签,那些标签必须放在相应的位置。
以HandItems作例子
HandItems:[{id:"minecraft:stone",Count:1b},{id:"minecraft:glass",Count:1b}]
石头就是放在主手,而玻璃就是放在副手。
对于非Compound的有限元素,有时候就会这么写:数字 TAG_<类型>....,说明了元素数量及类型,如:
Motion: 3 TAG_Doubles describing the current dX,dY,dZ velocity of the entity in meters per tick.
这句讲解了List里的元素类型以及用途。而粗体的那三个字就是你要写的元素了。以下是一个例子:
Motion:[1d,2d,3d]
x轴上的速度为1m/s,y轴为2m/s,z轴为3m/s。
不限制元素数量的写法有两种:第一种为在List下面有一个标签,第二种为只写着List of ...
而之后的部分不是种类而是子标签用途。
例子:
1:
2:
Tags: List of custom string data.
这代表了子标签数量不设限制,而子标签次序一般并无影响。
例子:
Passengers:[{id:"minecraft:pig"},{id:"minecraft:armor_stand"}]
Tags:[abc,def,ghjdfs,sfdsfsdf,sadasdsad]
注: 是一般并无影响而不是绝对没有影响。
在Passengers的例子里,如果根实体(被Passengers骑着的实体)为船,那么第一个及第二个实体的位置会有分别。只有一个实体和有两个甚至更多实体的位置也不同。List是无法直接修改指定索引值的标签的。赋值时也无法不覆盖掉原先的所有标签。
阅读数组
其实数组方面和List的不限制元素数量写法也十分相近,就是Array of ...
。
例子:
Colors: Array of integer values corresponding to the primary colors of this firework's explosion...
简单来说就是一堆数字,代表了那烟花的颜色。所以NBT的例子为:
Colors:[I;123,456,789,123,456,789]
1.12后数组有类型分别,分号前的值即代表其类别。
例子1——给予物品
give
命令的功能为给予物品,其格式为
give <玩家> <物品id> [数量] [伤害值] [NBT]
NBT(有时亦作数据标签,其实就是NBT)部分,其base tag为tag。
什么是Base tag呢?其实这是一个概念,说的是这段NBT最外层的Compound是什么。
上面我们说到,Compound也有分为不同种类的。有一些是Entity,一些是Item,一些是Tag。而不同命令使用的NBT也有所不同。
比如是物品类的命令,如give
命令,它们的NBT那里就是物品的额外NBT,其Base tag就是tag
,意思就是最外层的compound类型为tag
。
而tag的(部分)子标签为
tag: compound
└── display:compound
├── Name: 物品名称,string
└── Lore: 物品描述,string的list,每个string代表一行
故此我们命令里的NBT就能这么写:
{display:{Name:"物品名称",Lore:["第一行","第二行"]}}
例子命令:
give @p nether_star 1 0 {display:{Name:"原谅之星",Lore:["爱是一道光","如此美妙"]}}
这命令给予玩家一个下界之星,名称为 原谅之星,描述为 爱是一道光 (下一行)如此美妙。
例子2——物品自定义NBT
只有物品的tag能有这个操作
物品的tag里能够自定义NBT,通过自定义NBT,玩家能够方便的把物品分类并且选择物品的实体/持有物品的实体等。
tag: compound
├── 自定义NBT1: 种类自定
├── 自定义NBT2: 种类自定
├── ...
└── 自定义NBTn: 种类自定
假设我们要给予玩家一些特别的物品,我们需要统一进行检查。(检测有没有持有那类的物品,给予buff或者避免重复给予玩家那类型物品)
如果我们不使用自定义NBT,就需要逐个物品来检查,那就会十分麻烦,故此我们可以使用自定义NBT。
#这是第一类,编程的别问我为啥从1开始数
give @p diamond_axe 1 0 {CustomNBT:1b}
give @p diamond_sword 1 0 {CustomNBT:1b}
#这是第二类
give @p iron_axe 1 0 {CustomNBT:2b}
give @p iron_sword 1 0 {CustomNBT:2b}
这样,比如我们要检查拿着第一类物品的玩家,我们可以通过以下命令:
testfor @p {SelectedItem:{tag:{CustomNBT:1b}}}
相比两条命令(分别检测{SelectedItem:{id:"minecraft:diamond_axe"}}
和{SelectedItem:{id:"minecraft:diamond_sword"}}
)明显方便了许多,而且这只是因为一个种类里的物品比较少:比较多物品的时候能更方便。
提示:NBT里检测id的时候,无论是实体名称、方块id或者是物品id都得写
minecraft:
。检查NBT时,如果是同样精准度的话,我们会使用较少NBT的那个,因为效率会更高。而就物品来说,我们就可以使用自定义NBT,简单方便的进行检查。
高级用法
我们可以用大类小类的方式更有系统的分类,对小游戏地图特别有用。
然而我们不必写很多特殊标签,我们只需要:Compound。
比如说,以上两类都属于工具类别,那么我们就命名这个大类为tools
NBT改为{tools:{CustomNBT:1b}}
及{tools:{CustomNBT:2b}}
假设我们要检测小类,则正常方式也行。如果要检测大类,则可以只写{SelectedItem:{tags:{tools:{}}}}
是不是方便很多呢?2333
例子3——天降补给
生成一个掉落中的方块(Falling block),类型为箱子,里面装着一把剑。
首先我们看看falling_block
的NBT。
falling_block
├──Block: 方块ID。字串。
├──TileEntityData: 方块实体的NBT。
├──Data: 方块的元数据。Byte。
└──Time: 这掉落中的方块的存在时间(单位为游戏刻)。如果设置为0,过了1游戏刻后如果方块发现所处位置的方块id和此实体的方块id不同,就会消失。...(省却了和这部分无关系的描述)。当数值超过600或y坐标=0,这个实体就会消失。Int。
至于箱子(一种方块实体)的NBT就是这样的
chest
└──Items: 箱子内的物品列表。
而物品的格式就是
Item
├──Count: 物品数量。byte。
├──Slot: 物品所处格子编号。byte。
├──Damage: 物品数据值。short。
├──id: 物品id。字串。
└──tag: 物品的其他tag。
首先我们写出这剑的NBT,假设我们希望是一把钻石剑,在箱子的第一格(编号从0开始)。
{Count:1b,Slot:0b,Damage:0s,id:"minecraft:diamond_sword"}
然后编写箱子的NBT(物品列表内的物品就是剑的NBT)
{Items:[{Count:1b,Slot:0b,Damage:0s,id:"minecraft:diamond_sword"}]}
最后编写掉落方块的NBT(TileEntityData
里的就是箱子的NBT)
{Block:"minecraft:chest",Data:0b,Time:1,TileEntityData:{Items:[{Count:1b,Slot:0b,Damage:0s,id:"minecraft:diamond_sword"}]}}
这例子显示了NBT格式是怎么引用别的NBT的。
例子4——小僵尸Boss
首先我们希望Boss的名字叫Boss。这和实体格式有关:
然后如何定义一只小僵尸呢?我们就得看僵尸的NBT。
zombie
└──IsBaby: 僵尸是否婴儿。Byte。
那么僵尸有没有定义名称的NBT呢?看起来是没有的。???
其实僵尸(zombie)是实体(entity)的一个子类,因此僵尸里会继承所有属于实体的tag,比如是CustomName
。
Entity
├──CustomName: 实体的名称。字串。
└──CustomNameVisible: 实体名称是否可见。Byte。
可以这么想,僵尸有的NBT为:
zombie
├── 一切实体的NBT
└── 僵尸独有的NBT
也就是
zombie
├──CustomName
├──CustomNameVisible
├──IsBaby
└──...
好了我们怎么弄一只boss呢?我们可以修改属性,也就是Attribute。然而在僵尸的NBT里看不到Attribute啊!是不是代表没有呢?
不是的,其实僵尸也属于生物(Mob),而Mob就有我们需要的Attribute了。
僵尸的继承体系是:
- entity
- mob
- 怪物monster, 不死类生物 Undead (这里不影响NBT,但影响其行为)
- mob
Mob的格式是这样的:
Mob
├──Attributes: Attributes列表。
│ └┬─ 一个Attribute
│ ├──Name: attribute的名称(我们改血量,写generic.maxHealth)
│ ├──Base: attribute的数值(写30),类型为byte。
│ ├──...
├──Health: 血量(只改maxHealth只会修改最大血量,实际血量还是20)。float。
└──...
所以NBT可以这么写:
{CustomName:Boss,CustomNameVisible:1b,IsBaby:1b,Attributes:[{Name:"generic.maxHealth",Base:30b}],Health:30.0f}
注意: 使用
summon
命令生成实体时我们不是在指定实体的所有标签,我们只是修改特定的标签,其他标签还是会自动赋予的,其中一些会被随机生成。有一些NBT只能在实体生成时设置,生成后就会消失。
样式代码
有时候我们会希望在NBT加入样式代码,来为比如是物品名称或描述加上颜色等样式。
样式代码其实就是§<符号>
,之后的字符根据会加上特定样式。样式决定于§
后的符号,和JSON那些样式类似。也能够混合使用(效果会叠加直至§r
的出现)。
颜色:
特殊样式:
样式代码 | 效果 |
---|---|
§k | 混淆(obfuscated) |
§l | 粗体(bold) |
§m | 删除线(strikethrough) |
§n | 下划线(underline) |
§o | 斜体(italic) |
§r | 重置(reset),即前方样式不会对后方有作用 |
例子:
{CustomName:"§a123456§r"}
{display:{Lore:["§a§l粗体原谅"]}}
然而是无法以正常方式向游戏内输入
§
字符的。
最方便的方式为通过命令函数输入,如果不能使用命令函数的话可以使用牌子点击黑科技,链接:http://www.mcbbs.net/thread-443181-1-1.html
除了NBT以外,其他地方也会使用§
字符代表颜色,比如存档名称、advancement、记分板假名等等。
例子
命令:
give @p nether_star 1 0 {display:{Name:"§a§l爱是一道光",Lore:["如此美妙"]}}
效果:
你们是不是以为如此美妙的部分也是绿色和粗体?不是说好的之后的字符根据会加上特定样式
么?
其实是这样的,那句之后的字符根据会加上特定样式
其实说的是同一个NBT内,比如是Name里面,或者是Lore里面的一个子标签里面。
故此,Lore部分是独立于Name部分的,也不会获得那原谅Buff。
其他
这里会说一些NBT的额外资料。
部分NBT是生成后就会消失的,如UUID,别想着要改了。
部分NBT是只读(Read only)不能修改的,如OnGround这些,而且你修改了也没用。
有时候会看见别人写错类型的,如Item: {id:"minecraft:stone",Count:1}
。
然而其实这并不是错的,这是利用了NBT的型别转换(Type casting),也就是说修改NBT时能自动把类型转为正确类型。(当然,超出了正确类型范围的时候就不会自动转换了)
不过我们并不建议这种写法,因为有很大几率会出现错误,并且在检测NBT的时候不允许使用这种写法。
生物的ActiveEffects不建议直接修改。部分和attribute有关的状态效果需要attribute modifier。故此只声明ActiveEffects是无效的。
生物的Attribute很坑(包括AttributeModifier,比如史莱姆的maxHealth改了也没用...)...建议使用前多测试。
检测生物有没有受到攻击可以检测生物HurtTime
。(function的话可以考虑检测9s
,命令方块的话得+1s,检测10s
。这是由于gameLoopFunction在生物更新后执行。原则上10s
到1s
都可以用于检测,但一般我们都需要即时获取状态。)
别试图检测Float/Double,你往往不要指望恰好能达到你所检测的值...例如检查实体视角时更常见的是使用选择器参数而不是相应NBT。
处理火球的时候记着设置direction。motion对它是没用的,并且不设置direction根本生成不了。
重要!!!
村民的Inventory
设置的时候只会增加物品,不会覆盖。
比如原先有[{id:"minecraft:stone",Count:1b,Damage:0s}]
,我们设置Inventory:[{id:"minecraft:stone",Count:1b,Damage:0s}]
,村民的Inventory NBT会变为[{id:"minecraft:stone",Count:2b,Damage:0s}]
。
假如我们在以上的基础上设置[{id:"minecraft:stone",Count:1b,Damage:1s}]
,村民的Inventory会变为[{id:"minecraft:stone",Count:2b,Damage:0s},{id:"minecraft:stone",Count:1b,Damage:1s}]
。
而且村民的replaceitem
命令中的slot.villager.数字
是基于这个列表里的物品位置的,第一个的数字就是0
,第二个就是1
,如此类推。但实际上在村民的Inventory里是不会有Slot
这个NBT的。我们需要移除物品就只能靠replaceitem
为air
了。replaceitem
为air
之后物品会向前补充那空缺。
幸好这奇奇怪怪的特性不常见...
此特性由Yaossg发现