Skip to content

公开 API

编译依赖

xml
<repositories><repository><id>jiuwu-releases</id><url>https://repo.crypticlib.com/repository/maven-public/</url></repository></repositories>
<dependency><groupId>emaki.jiuwu.craft</groupId><artifactId>emaki-item-api</artifactId><version>2.7.16</version><scope>provided</scope></dependency>
kotlin
repositories { maven("https://repo.crypticlib.com/repository/maven-public/") }
dependencies { compileOnly("emaki.jiuwu.craft:emaki-item-api:2.7.16") }

仅编译依赖

不要安装、bundle、shade 或 relocate API Jar。runtime 已内嵌未 relocate 的 API 类;重复 ClassLoader 类型会破坏事件和 bridge。

门面与六个入口

先检查 EmakiItemApi.status().usable()。其余非 null 入口是:

  • catalog():定义、别名、身份与套装查询。
  • operations():创建、刷新、套装同步与修复 GUI。
  • repair():禁修标志、经济修复报价与执行。
  • migration()(experimental):管理型文件/库存迁移。
  • extensions():物品层预览 provider 注册。
  • state():物品自定义持久状态的类型化读写。

installuninstallBridge 只属于 runtime;第三方不得调用或实现。

Operations

  • create(id,amount) 在 global-region owner thread 构建并触发可取消的 EmakiItemCreateEvent。监听器可替换结果;取消映射为 FailureKind.CANCELLED
  • refresh / forceRefresh 返回重建后的 stack;实时库存物品须在 holder owner thread。
  • refreshPlayer(player,trigger)refreshEquippedSets(player,trigger) 在玩家 owner thread,compare-before-write 冲突可返回携带实际 ItemRefreshSummaryPartial
  • openRepairGui(player) 返回 EmakiResult<Unit>,玩家 owner thread。

Repair

repair().isDisabledmarkDisabledclearDisabled 管理 durability-disable 标志。quote(Player,ItemStack) 返回 RepairQuoteView;不可负担仍是成功报价且 affordable()==falserepair(Player,ItemStack) 走真实经济修复服务:事件、扣费、补偿、耐久提交和 post actions 都在同一 runtime 流程中。材料修复仍是 GUI/库存事务,没有伪造的简化 API。

Migration

preview(oldId,newId)apply(oldId,newId,replaceReferences,keepAlias) 会同步执行文件系统工作,调用方必须选择非 tick worker;I/O 失败映射为 INTERNAL_ERROR,部分文件已提交时返回 Partial<MigrationOutcome>migrateInventory(Player) 需要玩家 owner thread;migrateAllOnline() 只处理当前线程拥有的在线玩家,Folia 所有权不完整时返回 Partial<Integer>

Extensions

registerLayerPreview(Plugin,ItemLayerPreviewProvider) 返回 owner-scoped registration;关闭 handle 或按 owner 注销。provider 使用克隆的 request/result,不得跨 owner 线程修改实时 stack。

ItemState

state() 是物品自定义持久状态的类型化读写层,字段由 ItemStateKey<T>(namespace + partition + 字段名 + ItemStateType)标识:

  • snapshot(item) 返回不可变的 ItemStateSnapshot:可用 get(key) 取类型化值、contains(key) 判断字段是否存在、repaired() 判断读取时是否顺带修复了元数据。item() 返回克隆件。
  • repair(item) 修复元数据并回读快照。
  • get(item,key) 返回 Optional<T>,类型不匹配时为空。
  • set(item,key,value)add(item,key,amount)remove(item,key) 返回 ItemStateMutation<T>:含 oldValuenewValuedelta,以及 committedchangedclampedrejectedreason,被 clamp 或拒绝都能从返回值判断,不抛异常。

结果语义

无负载成功使用 EmakiResult<Unit>;通用可选负载访问器为 optionalValue()FailureKind 只有 UNAVAILABLENOT_FOUNDINVALID_INPUTREJECTEDCANCELLEDTARGET_OFFLINEWRONG_THREADINTERNAL_ERROR

就绪与 reload

status().ready() 的判据是"定义已加载",不是"组件已构造"。插件启用后组件立即非 null,但定义表在 reload 期间会被重建,因此:

  • reload 窗口内 status()loadingcatalog()operations()repair()migration() 中返回 EmakiResult 的方法一律返回 unavailable()——不是 NOT_FOUND。把 unavailable() 当作"稍后重试",不要当作"该物品不存在"。
  • definitionIds()exists(id)typeIds() 这类纯查询无法表达不可用,reload 期间可能返回陈旧或空结果。需要"定义确实加载好了"再动作时,用 EmakiCoreLibApi.whenReady(plugin, "EmakiItem", callback),不要用空结果反推。
  • 缓存了 EmakiItem 定义的插件,要在每次重载后更新缓存,用 EmakiCoreLibApi.addModuleListener(plugin, "EmakiItem", phase -> ...)LOADING 时失效、READY 时重建。whenReady 只响一次,不适合这个用途。

启动期依赖 EmakiItem 定义的插件应挂 whenReady 而不是在自己的 onEnable 里直接查表:模块加载顺序不保证 EmakiItem 的首次加载先于你的 onEnable。回调只触发一次,且运行线程不保证是 owner thread,触碰玩家或背包前需显式调度。