物品 API
Baikiruto 的核心物品操作方法,涵盖物品构建、读取、注册和 ID 查询。
方法一览
| 方法 | 返回值 | 说明 |
|---|---|---|
buildItem(itemId: String, context: Map<String, Any?> = emptyMap()) | ItemStack? | 根据物品 ID 构建 ItemStack |
readItem(itemStack: ItemStack) | ItemStream? | 读取 ItemStack 的 Baikiruto 数据 |
getItem(itemId: String) | Item? | 获取物品定义 |
registerItem(item: Item) | Item | 注册自定义物品 |
getItemId(itemStack: ItemStack) | String? | 获取 ItemStack 的物品 ID |
getItemData(itemStack: ItemStack) | Map<String, Any?>? | 获取物品的公共数据 |
getItemUniqueData(itemStack: ItemStack) | Map<String, Any?>? | 获取物品的唯一实例数据 |
构建物品
val api = Baikiruto.api()
// 根据 ID 构建物品
val itemStack = api.buildItem("my_sword")
if (itemStack != null) {
player.inventory.addItem(itemStack)
}
// context 参数可传入 Map 用于动态属性计算(如等级相关的属性)
val contextItem = api.buildItem("level_sword", mapOf("player" to player))
读取物品
val api = Baikiruto.api()
// 读取手持物品
val itemStream = api.readItem(player.inventory.itemInMainHand)
if (itemStream != null) {
println("物品 ID: ${itemStream.itemId}")
}
// 获取物品 ID(简便方法)
val itemId = api.getItemId(player.inventory.itemInMainHand)
if (itemId != null) {
println("这是 Baikiruto 物品: $itemId")
} else {
println("这不是 Baikiruto 物品")
}
获取物品数据
val api = Baikiruto.api()
val item = player.inventory.itemInMainHand
// 获取公共数据(所有同 ID 物品共享)
val data = api.getItemData(item)
data?.forEach { (key, value) ->
println("$key = $value")
}
// 获取唯一实例数据(每个物品实例独有)
val uniqueData = api.getItemUniqueData(item)
uniqueData?.forEach { (key, value) ->
println("唯一数据 $key = $value")
}
获取物品定义
val api = Baikiruto.api()
// 获取物品定义
val item = api.getItem("my_sword")
if (item != null) {
println("物品名称: ${item.id}")
}
注册自定义物品
val api = Baikiruto.api()
// 注册自定义物品
val item = api.registerItem(myItem)
println("已注册物品: ${item.id}")
buildItem 返回的 ItemStack 已经包含了 Baikiruto 的 NBT 标记,可以通过 readItem 或 getItemId 识别。
ItemStream 常用能力
如果你在开发附属插件,buildItem() 适合“直接拿成品”;如果你还要继续改显示、注入运行时数据或决定最终 lore,优先走 api.getItemManager().generateItem(...) 拿到 ItemStream。
| 方法 | 作用 | 适合场景 |
|---|---|---|
setDisplayName(name) | 直接修改当前流里的显示名 | 只改这一次构建结果 |
setLore(lines) | 直接修改当前流里的 lore | 最终阶段临时覆盖当前 ItemStack |
setRuntimeData(key, value) | 写入运行时数据 | 想参与 display / i18n / rebuild 链路 |
snapshotData() | 导出当前 itemId、versionHash、runtimeData | 调试数据流 |
rebuild() / rebuildToItemStack() | 基于当前 runtimeData 重新构建 | 先改数据,再让 Baikiruto 重跑显示链 |
val api = Baikiruto.api()
val stream = api.getItemManager().generateItem(
"demo:sword",
mapOf("player" to player, "sender" to player)
) ?: return
stream.setRuntimeData("extra_damage", 12)
val preview = stream.snapshotData()
println(preview.runtimeData)
val rebuilt = stream.rebuildToItemStack(player)
player.inventory.addItem(rebuilt)
附属插件如何修改物品描述
方案 1:推荐在显示构建阶段注入 item_description
如果目标是“改最终给玩家看的描述”,最稳妥的入口是 ItemReleaseDisplayBuildEvent。这时显示方案已经选好,但 ItemDisplay.build(...) 还没执行,你改的 name / lore 会继续参与后续显示模板、运行时占位符和 NBT 同步。
val api = Baikiruto.api()
val bus = api.getItemEventBus()
bus.subscribe(ItemReleaseDisplayBuildEvent::class.java) { event ->
if (event.itemId != "demo:sword") return@subscribe
event.addLore(
"item_description",
listOf(
"&7附属插件追加的描述",
"&8Owner: {unique.player}"
)
)
}
这里的 item_description 对应默认 display 模板里常见的 <item_description...> 占位符;如果你的 display 使用了别的 key,就改那个 key。
方案 2:在代码里直接写入 runtime lore
如果你是自己调用 generateItem(...) 构建物品,而不是单纯监听事件,推荐直接写 runtimeData["lore"]。这样数据会进入 Baikiruto 的显示链,而不是只改当前 ItemMeta。
val stream = api.getItemManager().generateItem(
"demo:sword",
mapOf("player" to player, "sender" to player)
) ?: return
stream.setRuntimeData(
"lore",
linkedMapOf(
"item_description" to listOf(
"&7开发附属插件时写入的描述",
"&f额外伤害: 12"
)
)
)
val itemStack = stream.toItemStack()
这条链路适合你想让后续 readItem()、rebuild()、更新检测继续理解这份 lore 数据的场景。
方案 3:只想临时覆盖当前结果,就用 setLore(...)
val stream = api.getItemManager().generateItem("demo:sword") ?: return
stream.setLore(listOf("&7临时覆盖 lore"))
val itemStack = stream.toItemStack()
这种写法会立刻修改当前 ItemStream 持有的 ItemStack,但它不是“显示变量”层的数据。如果后面还会经过 display 选择、i18n、重新构建或更新检查,新的 lore 可能会被覆盖。
方案 4:最后一跳强改 ItemStack
ItemReleaseFinalEvent 是最后一道口子,适合你只想在返回玩家前补一条展示文本。但要注意:源码里 ItemStreamTransport.sync() 发生在这个事件之前,所以这里改的是最终 ItemStack,不是 Baikiruto 的 runtimeData 语义层。
想让修改尽量跟随后续 read() / rebuild() / update 继续生效,优先使用 ItemReleaseDisplayBuildEvent 或 setRuntimeData("lore", ...),不要只在 ItemReleaseFinalEvent 里改 ItemMeta。
如果物品配置用了 lore!! / name!!,或者运行时 __locked_display_fields__ 包含 lore / name,setLore(...) 和普通显示覆盖会被拦截。源码仍然会对“锁定值里的占位符”做渲染,但不会接受普通的 lore 覆写。
物品数据流(完整链路)
下面这张图按源码的真实顺序,串起“配置 → 物品流 → 最终 ItemStack → 反向读取”:
items/*.yml + display/*.yml
│
└─ ItemDefinitionLoader.reloadItems()
├─ parseModels()
├─ parseDisplays()
└─ parseItemSection()
├─ 生成 template ItemStack
├─ 合并 model/display/item/components/data/effects/i18n
└─ 产出 DefaultItem(defaultRuntimeData, metas, scripts, eventData)
│
▼
BaikirutoAPI.buildItem() / ItemManager.generateItem()
│
└─ DefaultItem.build(context)
├─ 创建 DefaultItemStream(template.clone(), defaultRuntimeData)
├─ ItemBuildPreEvent
├─ BUILD 脚本
├─ metas.build(stream)
└─ ItemBuildPostEvent
│
▼
ItemStream
│
├─ setRuntimeData()/setLore()/applyMeta()
├─ snapshotData()
└─ toItemStack()
├─ ItemDataMapperFeature.apply()
├─ ItemReleaseEvent
├─ ItemSelectDisplayEvent
├─ ItemReleaseDisplayBuildEvent
├─ applySelectedDisplay()
├─ applyI18nDisplay()
├─ applyRuntimeDisplay()
├─ applyPlaceholderDisplay()
├─ ItemStreamTransport.sync()
│ └─ 写入 NBT: baikiruto.id/version/meta_history/data
├─ VersionAdapter / native feature / skull hook
└─ ItemReleaseFinalEvent
│
▼
成品 ItemStack
│
└─ ItemHandler.read(itemStack)
├─ ItemStreamTransport.read()
└─ DefaultItemStream(itemStack.clone(), payload)
你可以用这张图快速判断应该在哪一层动手:
- 想改“显示变量”并让后续链路继续理解:改
ItemBuildPreEvent、ItemReleaseDisplayBuildEvent或runtimeData - 想临时改当前物品外观:改
setLore(...)/setDisplayName(...) - 想对最终返回给玩家的成品做一次性补丁:改
ItemReleaseFinalEvent.itemStack