Skip to content

API 与集成

EmakiCodexApi 是 EmakiCodex 对第三方插件开放的静态 API 门面。第三方插件只需要把 emaki-codex-api 作为编译依赖;运行时由服务器中安装的 EmakiCodex 插件本体提供实现。

服务器服主只安装 EmakiCodex-*.jar,不要把 emaki-codex-api-*.jar 放进 plugins/

Maven 依赖

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

如果你的插件通过 Maven 构建,请确保运行服务器时已安装同版本或更高版本的 EmakiCodex 插件本体。

Gradle 依赖

kotlin
dependencies {
    compileOnly("emaki.jiuwu.craft:emaki-codex-api:1.0.0")
}

可用性检查

java
import emaki.jiuwu.craft.codex.api.EmakiCodexApi;

if (!EmakiCodexApi.available() || !EmakiCodexApi.isReady()) {
    return;
}

available() 表示 Codex API bridge 已安装;isReady() 表示插件已启用并完成初始化。

也可以使用迁移辅助类:

java
import emaki.jiuwu.craft.codex.api.EmakiCodexApiProvider;

if (EmakiCodexApiProvider.available()) {
    EmakiCodexApiProvider.requireAvailable();
}

EmakiCodexApiProvider 只用于可用性检查;不要把它当成实例服务入口。

授予节点

java
import java.util.UUID;
import emaki.jiuwu.craft.codex.api.EmakiCodexApi;

UUID playerId = player.getUniqueId();
boolean changed = EmakiCodexApi.grantAdvancement(playerId, "example/first_step");

if (!changed) {
    // 玩家不在线、调用线程不持有该玩家归属、节点未注册,或玩家已经完成该节点。
}

同步方法要求调用线程已经持有目标玩家的线程归属;不满足时直接返回 false。不确定归属时请使用下方的异步重载。

advancementId 支持两种写法:

写法示例
短写example/first_step
完整 keyemakicodex:example/first_step

授予节点会奖励内部 codex criterion。节点首次完成时,会触发原版完成链路,并执行该节点配置的 actions.complete

撤销节点

java
import java.util.UUID;
import emaki.jiuwu.craft.codex.api.EmakiCodexApi;

UUID playerId = player.getUniqueId();
boolean changed = EmakiCodexApi.revokeAdvancement(playerId, "example/first_step");

if (!changed) {
    // 玩家不在线、调用线程不持有该玩家归属、节点未注册,或玩家尚未完成该节点。
}

撤销只处理已注册的 Codex 节点;不会删除配置文件,也不会移除服务器注册表中的 Advancement 定义。

异步写入

grantAdvancement / revokeAdvancement 要求调用方已经持有目标玩家的线程归属。如果你不确定当前线程是否拥有该玩家,改用异步重载,由 EmakiCodex 负责调度到正确的 owner 线程:

java
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import emaki.jiuwu.craft.codex.api.EmakiCodexApi;

CompletableFuture<Boolean> future =
        EmakiCodexApi.grantAdvancementAsync(playerId, "example/first_step");

future.thenAccept(changed -> {
    // 回调线程不保证是主线程;接触 Bukkit 状态前请自行调度。
});
方法返回值说明
grantAdvancementAsync(UUID, String)CompletableFuture<Boolean>异步授予节点。API 不可用时返回已完成的 false
revokeAdvancementAsync(UUID, String)CompletableFuture<Boolean>异步撤销节点。API 不可用时返回已完成的 false

这两个方法不承诺切换线程:目标玩家离线、API 不可用或调度失败时,返回的 future 可能已经完成。回调中若需要操作 Bukkit / Paper / Folia 状态,必须自行调度到对应 owner 线程。

版本与插件名

java
String version = EmakiCodexApi.apiVersion();
String pluginName = EmakiCodexApi.pluginName();

当 API 不可用时,这两个方法返回空字符串。

集成边界

  • API 只暴露静态门面,不暴露 AdvancementService、loader、listener 或配置 parser。
  • API 方法面向在线玩家 UUID;离线玩家不会被加载或改写。
  • 如果要在配置动作链中授予节点,优先使用 CoreLib 动作;如果是第三方插件代码集成,再使用 EmakiCodexApi
  • 如果需要在玩家客户端刷新坐标化成就树,当前公开 API 不提供 resync 方法;可在 CoreLib Action 中调用 codex_resync_advancement