KubeJS NBT 数据操作(物品 / 实体 / 方块的"隐藏数据")¶
原文:原创教程(ぴよまる)
NBT(Named Binary Tag,命名二进制标签)是 Minecraft 里给物品、实体、方块实体挂附加数据的方式——附魔、自定义名称、箱子里的物品、玩家的存档……底层全是 NBT。这篇讲 KubeJS 6.x(1.20.1)里怎么读写 NBT,以及带 NBT 的物品、配方、实体操作。
1. NBT 长什么样¶
NBT 就是一层层 键: 值 包起来的数据,用 {} 表示一组(CompoundTag),[] 表示列表(ListTag):
// 这是一把"锋利 III 的钻石剑"的 NBT(游戏里实际存的格式)
// Enchantments 是一个"列表",列表里每个元素又是一组数据 {}
// id 是附魔 ID 字符串,lvl 是等级(3s 的 s 表示 short 短整数)
// display 是一组数据,Name 是物品显示名(用 JSON 文本格式)
{
Enchantments: [{ id: "minecraft:sharpness", lvl: 3s }],
display: { Name: '{"text":"神器"}' }
}
💡 类型后缀:
3s短整数、3L长整数、3.0f浮点、3.0d双精度。整数不写后缀默认是 int。字符串不用后缀。布尔是true/false。
2. 读取物品的 NBT¶
2.1 判断有没有 NBT + 读整个 NBT¶
ItemEvents.rightClicked(event => { // 监听"玩家右键使用物品"事件
let item = event.item // 拿到被使用的物品对象
if (item.hasNBT()) { // hasNBT():判断这个物品身上有没有 NBT 数据(true/false)
let nbt = item.nbt // 取出物品的 NBT 数据(对象),没有 NBT 时可能是 null
console.log(nbt) // 打印到日志(logs/server.log)
}
})
2.2 读具体的值(get 系列)¶
ItemEvents.rightClicked(event => { // 监听"玩家右键使用物品"事件
let nbt = event.item.nbt // 拿到物品的 NBT 数据(对象)
if (!nbt) return // 没有 NBT 就提前结束(return 后面的代码不执行)
// 读不同类型的数据,方法名都是 get + 类型
nbt.getString('name') // 读字符串:返回 "我的剑" 这样的值
nbt.getInt('level') // 读整数:返回 5 这样的值
nbt.getBoolean('locked') // 读布尔:返回 true 或 false
nbt.getDouble('damage') // 读小数:返回 3.5 这样的值
nbt.getList('items', 10) // 读列表:返回一个数组(10 是元素类型,通常写 10 就行)
nbt.getCompound('data') // 读嵌套的一组数据:返回一个 NBT 对象
})
2.3 检查有没有某个键(contains)¶
ItemEvents.rightClicked(event => { // 监听"玩家右键使用物品"事件
let nbt = event.item.nbt // 拿到物品的 NBT 数据(对象)
if (nbt && nbt.contains('level')) { // contains('键名'):判断 NBT 里有没有这个键
event.player.tell('这把武器有等级标签!') // 有就告诉玩家
}
})
⚠️ 注意顺序:先
item.hasNBT()或判断nbt != null,再调nbt.getXxx(),否则没 NBT 时会报错。
3. 写入 / 修改物品 NBT¶
3.1 put 系列(推荐)¶
ItemEvents.rightClicked(event => { // 监听"玩家右键使用物品"事件
let nbt = event.item.nbt // 拿到物品的 NBT 数据(对象)
if (!nbt) return // 没有 NBT 就提前结束
nbt.putString('owner', event.player.username) // 写入字符串:记录"这把武器的拥有者"
nbt.putInt('kills', 0) // 写入整数:击杀数先归零
nbt.putBoolean('locked', true) // 写入布尔:标记"已锁定"
nbt.putDouble('power', 2.5) // 写入小数
event.player.tell('已写入标签!') // 提示玩家
})
3.2 直接当对象赋值(KubeJS 支持)¶
ItemEvents.rightClicked(event => { // 监听"玩家右键使用物品"事件
let nbt = event.item.nbt // 拿到物品的 NBT 数据(对象)
if (!nbt) return // 没有 NBT 就提前结束
nbt.owner = event.player.username // 直接点属性赋值:等价于 putString('owner', ...)
nbt.kills = 0 // 等价于 putInt('kills', 0)
nbt.locked = true // 等价于 putBoolean('locked', true)
})
3.3 删除键 / 清空 NBT¶
ItemEvents.rightClicked(event => { // 监听"玩家右键使用物品"事件
let nbt = event.item.nbt // 拿到物品的 NBT 数据(对象)
if (!nbt) return // 没有 NBT 就提前结束
nbt.remove('kills') // 删除 NBT 里的"kills"这个键
event.item.removeNBT() // removeNBT():把物品的 NBT 全部清空(物品变回"干净"状态)
})
4. 创建"带 NBT"的物品¶
4.1 Item.of(物品ID, NBT文本)¶
// Item.of 的第二个参数可以直接写 NBT 文本(和游戏里 /give 的写法一样)
// 生成一把"锋利 III 的钻石剑"
let sword = Item.of('minecraft:diamond_sword', '{Enchantments:[{id:"minecraft:sharpness",lvl:3s}]}')
// 生成一个写着自定义名的苹果
let apple = Item.of('minecraft:apple', '{display:{Name:\'{"text":"幸运苹果"}\'}}')
4.2 发给玩家 / 掉落¶
ItemEvents.rightClicked(event => { // 监听"玩家右键使用物品"事件
if (event.item.id === 'kubejs:give_sword') { // 判断:用的是一个"发剑器"物品
// 生成带附魔的钻石剑,发给玩家
let sword = Item.of('minecraft:diamond_sword', '{Enchantments:[{id:"minecraft:sharpness",lvl:3s}]}')
event.player.give(sword) // give():把物品给玩家(物品放进背包)
}
})
4.3 withNBT:给现有物品加 NBT(返回新物品)¶
// withNBT() 不修改原物品,而是返回一个"带上 NBT 的新物品"
// 用法 1:传一个 NBT 对象
let stick = Item.of('minecraft:stick') // 先做一根普通木棍
let marked = stick.withNBT({ owner: 'pyz' }) // 返回一根带 owner=pyz 标签的木棍
// 用法 2:传 NBT 文本
let marked2 = stick.withNBT('{owner:"pyz"}') // 效果同上
5. 配方里的 NBT¶
5.1 移除"产出特定 NBT"的配方¶
ServerEvents.recipes(event => { // 监听"配方"事件,用来增删改合成配方
// 删除所有"合成结果是附魔书"的配方
event.remove({ output: { item: 'minecraft:enchanted_book' } })
})
5.2 合成出带 NBT 的物品(输出带 NBT)¶
ServerEvents.recipes(event => { // 监听"配方"事件
// 合成结果直接写 Item.of + NBT 文本,合出来就是带附魔的剑
event.shaped(Item.of('minecraft:diamond_sword', '{Enchantments:[{id:"minecraft:sharpness",lvl:3s}]}'), [
' A ', // 合成表第一行:中间是 A(空格是空位)
' A ', // 第二行:中间是 A
' B ' // 第三行:中间是 B(摆出来就是一把剑的形状)
], {
A: 'minecraft:diamond', // A = 钻石
B: 'minecraft:stick' // B = 木棍
}).id('kubejs:enchanted_sword') // 配方 ID,方便以后删除
})
5.3 用"带 NBT 的材料"做输入(精确匹配)¶
ServerEvents.recipes(event => { // 监听"配方"事件
// 输入材料写 Item.of + NBT 文本:只有"带这个 NBT 的木棍"才能参与合成
event.shapeless('minecraft:stone', [ // shapeless:无序合成(不要求摆放位置)
Item.of('minecraft:stick', '{owner:"pyz"}') // 必须是一根 owner 是 pyz 的木棍
])
})
5.4 匹配时忽略 NBT(ignoreNBT / weakNBT)¶
ServerEvents.recipes(event => { // 监听"配方"事件
// 默认 KubeJS 的物品匹配(Ingredient)会看 NBT;想"不管 NBT 只看物品 ID"时用这两个方法:
event.remove({
output: {
item: Ingredient.of('minecraft:enchanted_book').ignoreNBT() // ignoreNBT():匹配时忽略 NBT
}
})
// weakNBT() 和 ignoreNBT() 效果类似:只比较物品 ID 和数量,不比较 NBT
Ingredient.of('minecraft:stick').weakNBT()
})
6. 实体 / 玩家的 NBT¶
6.1 实体的完整 NBT(getFullNBT / setFullNBT / mergeFullNBT)¶
EntityEvents.spawned(event => { // 监听"实体生成"事件(世界上出现实体时触发)
let entity = event.entity // 拿到生成的实体
let fullNbt = entity.getFullNBT() // 读取实体的完整 NBT(位置、血量、AI 开关等全在里面)
fullNbt.putString('CustomName', '超级僵尸') // 给实体改自定义名
entity.setFullNBT(fullNbt) // setFullNBT():把改好的 NBT 整个写回实体
// mergeFullNBT():把一部分 NBT 合并进实体(只改传进去的键,不动的键保留原样)
entity.mergeFullNBT({ Health: 100.0f }) // 只改血量,其他数据不动
})
6.2 persistentData:玩家的"永久存档"就是 NBT¶
// persistentData 本质是 NBT 的友好封装:能存数字/字符串/布尔/数组/对象,重启不丢
PlayerEvents.loggedIn(event => { // 监听"玩家登录"事件
let data = event.player.persistentData // 玩家的永久存档数据(对象)
data.joinCount = (data.joinCount || 0) + 1 // 登录次数 +1(没记录过就当 0)
event.player.tell('这是你第 ' + data.joinCount + ' 次登录!') // 告诉玩家
})
💡 persistentData 存进去的就是 NBT:
data.kills = 5等价于往玩家 NBT 里写kills: 5。
7. 常用 NBT 速查表¶
| 想做什么 | 写法 |
|---|---|
| 判断物品有没有 NBT | item.hasNBT() |
| 取物品 NBT | item.nbt |
| 读字符串 | nbt.getString('键') |
| 读整数 | nbt.getInt('键') |
| 读布尔 | nbt.getBoolean('键') |
| 读小数 | nbt.getDouble('键') |
| 读列表 | nbt.getList('键', 10) |
| 读嵌套数据 | nbt.getCompound('键') |
| 有没有某个键 | nbt.contains('键') |
| 写字符串 | nbt.putString('键', '值') |
| 写整数 | nbt.putInt('键', 值) |
| 写布尔 | nbt.putBoolean('键', 值) |
| 写小数 | nbt.putDouble('键', 值) |
| 直接赋值 | nbt.键 = 值 |
| 删一个键 | nbt.remove('键') |
| 清空 NBT | item.removeNBT() |
| 做带 NBT 的物品 | Item.of('id', '{...}') |
| 给现有物品加 NBT | item.withNBT({...}) 或 item.withNBT('{...}') |
| 实体的完整 NBT | entity.getFullNBT() / entity.setFullNBT(nbt) |
| 只改部分 NBT | entity.mergeFullNBT({...}) |
| 玩家/实体/方块永久存档 | xxx.persistentData |
| 匹配时忽略 NBT | Ingredient.of('id').ignoreNBT() |
💡 记忆口诀:读用
getXxx('键')、写用putXxx('键', 值)、判断用contains('键');物品的 NBT 挂在item.nbt上,实体的完整 NBT 用getFullNBT(),想省事直接用persistentData当普通对象存。
本文为 KubeJS 1.20.1 中文文档原创篇目,配套 NBT 字面量格式参考 Minecraft Wiki「物品格式(1.20.5 前)」。