跳到主要内容

物品 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 标记,可以通过 readItemgetItemId 识别。

ItemStream 常用能力

如果你在开发附属插件,buildItem() 适合“直接拿成品”;如果你还要继续改显示、注入运行时数据或决定最终 lore,优先走 api.getItemManager().generateItem(...) 拿到 ItemStream

方法作用适合场景
setDisplayName(name)直接修改当前流里的显示名只改这一次构建结果
setLore(lines)直接修改当前流里的 lore最终阶段临时覆盖当前 ItemStack
setRuntimeData(key, value)写入运行时数据想参与 display / i18n / rebuild 链路
snapshotData()导出当前 itemIdversionHashruntimeData调试数据流
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 继续生效,优先使用 ItemReleaseDisplayBuildEventsetRuntimeData("lore", ...),不要只在 ItemReleaseFinalEvent 里改 ItemMeta

注意

如果物品配置用了 lore!! / name!!,或者运行时 __locked_display_fields__ 包含 lore / namesetLore(...) 和普通显示覆盖会被拦截。源码仍然会对“锁定值里的占位符”做渲染,但不会接受普通的 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)

你可以用这张图快速判断应该在哪一层动手:

  • 想改“显示变量”并让后续链路继续理解:改 ItemBuildPreEventItemReleaseDisplayBuildEventruntimeData
  • 想临时改当前物品外观:改 setLore(...) / setDisplayName(...)
  • 想对最终返回给玩家的成品做一次性补丁:改 ItemReleaseFinalEvent.itemStack