Skip to content

API 与集成

第三方插件通过 emaki-accessory-api 访问 EmakiAccessory。

Maven 坐标

xml
<dependency>
    <groupId>emaki.jiuwu.craft</groupId>
    <artifactId>emaki-accessory-api</artifactId>
    <version>1.0.3</version>
    <scope>provided</scope>
</dependency>

不要把 emaki-accessory-api-*.jar 放进服务器 plugins/。它只是编译期构件。

paper-plugin.yml 里把 EmakiAccessory 声明为依赖:

yaml
dependencies:
  server:
    EmakiAccessory:
      load: BEFORE
      required: false
      join-classpath: true

门面

emaki.jiuwu.craft.accessory.api.EmakiAccessoryApi 是静态门面:

方法说明
status()可用性与身份元数据,返回 CoreLib 的 ApiStatus
catalog()查询层,见下文 AccessoryCatalog
install(Bridge) / uninstall(Bridge)仅供 EmakiAccessory 自身生命周期调用。

访问器永不返回 null。EmakiAccessory 缺失时 catalog 返回空答案,因此调用方不能把 NullPointerException 当作可用性信号。

Bridge 标注 @ApiStatus.NonExtendable,第三方插件不得实现。

没有操作层与扩展层

这是刻意的设计。饰品通过 EmakiAttribute 与 EmakiSkills 各自已有的 owner 作用域扩展点推送贡献,不存在饰品专属的战斗或技能管线给第三方挂钩,因此本模块只暴露查询层。

要影响饰品带来的属性或技能,应当去 EmakiAttribute / EmakiSkills 的对应扩展点,而不是找 EmakiAccessory 要接口。

不要缓存层对象

在使用点解析 catalog(),不要把它存进字段:backing bridge 在 reload 时会被替换

java
// 正确
EmakiAccessoryApi.catalog().parts();

// 错误:reload 后这个引用会指向旧 bridge
private final AccessoryCatalog cached = EmakiAccessoryApi.catalog();

AccessoryCatalog 查询层

标注 @ApiStatus.NonExtendable

方法线程说明
List<AccessoryPartView> parts()任意线程列出所有部位定义。
Optional<AccessoryPartView> part(String partId)任意线程按 id 查部位。
List<String> slotInstanceIds()任意线程列出所有槽位实例 id。
List<String> pageIds()任意线程列出所有饰品页 id,按页顺序。1.0.3 起。
String enabledPage(UUID playerId)该玩家的 owner 线程当前生效页 id;未知或该页当前不可用时返回空字符串。1.0.3 起。
Map<String, EquippedAccessoryView> equipped(UUID playerId)该玩家的 owner 线程该玩家在生效页上装备的饰品,键为槽位实例 id。
Map<String, EquippedAccessoryView> equippedOnPage(UUID playerId, String pageId)该玩家的 owner 线程指定页上存放的饰品。1.0.3 起。
int equippedSetPieces(UUID playerId, String setId)该玩家的 owner 线程该玩家某套装的已装备件数,只统计生效页。

部位、槽位与页 id 查询是配置事实,任何线程都可调用。

玩家查询读取内存会话缓存,必须在该玩家的 owner 线程调用。玩家数据尚未加载完成时返回空结果而不是阻塞——因此空结果不能反推成「这个玩家没戴任何饰品」。

多页语义有三点要注意:

  • equipped() 只报告生效页。要看其他页用 equippedOnPage()
  • 玩家缺少生效页权限时,enabledPage() 返回空字符串、equipped() 返回空 Map,但存储物品不受影响,仍可被玩家取回。
  • equipped() 包含孤儿槽位,方便调用方看到待取回的物品;不需要时用 EquippedAccessoryView#orphaned() 过滤。孤儿槽位不参与套装件数。

这些方法都是纯查询,没有就绪门禁。reload 期间可能读到陈旧数据,需要在 reload 后失效自己的缓存时用 CoreLib 的常驻就绪监听:

java
EmakiCoreLibApi.addModuleListener(myPlugin, "EmakiAccessory", phase -> {
    if (phase == ModuleReadinessPhase.READY) {
        rebuildMyCache();
    }
});

模型类型

emaki.jiuwu.craft.accessory.api.model 包:

AccessoryPartView

java
public record AccessoryPartView(String partId, int count, String displayName, List<String> slotInstanceIds)
成员说明
partId()部位 id。
count()展开出的槽位数,至少为 1。
displayName()MiniMessage 显示名,可能为空字符串。
slotInstanceIds()展开后的槽位实例 id,按序号顺序,格式 <partId>_<序号>,序号从 1 开始。列表不可变。

EquippedAccessoryView

java
public record EquippedAccessoryView(String pageId, String slotInstanceId, String partId, ItemStack item, boolean orphaned)
成员说明
pageId()该饰品所在的页 id。1.0.3 起。
slotInstanceId()槽位实例 id。
partId()所属部位 id;部位已不存在时是原始前缀。
item()存储物品的防御性副本,槽位为空时为 null
orphaned()该槽位是否已不被所属页声明。

item() 每次调用都返回一份克隆,调用方无法通过视图改动存储状态。