Skip to content

快速开始

本页说明如何构建、部署 Emaki runtime,以及第三方插件如何正确引用 API。API Jar 只是编译依赖,不是服务器插件。

环境要求

项目要求
Java25
服务端Paper / Folia,构建 Paper API 基线为 1.21.8
构建工具Maven,多模块聚合工程
必装基础模块EmakiCoreLib

构建 runtime

在项目根目录执行:

bash
mvn -DskipTests package

默认 reactor 共 22 个模块:14 个 API 模块全部包含(CoreLibApi、ItemApi、StrengthenApi、SkillsApi、AttributeApi、ForgeApi、CookingApi、GemApi、LevelApi、CodexApi、StorageApi、StationApi、AccessoryApi、MobsApi),以及 8 个 runtime(CoreLib、Forge、Strengthen、Cooking、Attribute、Level、Codex、Station)。根目录存在 .key 时会自动激活 private-modules profile,再追加 6 个 runtime:Skills、Gem、Item、Storage、Accessory、Mobs。也可显式运行:

bash
mvn -DskipTests -Pprivate-modules package

插件本体通常位于 Emaki*/target/。只把 EmakiCoreLib-*.jarEmakiForge-*.jar 这类 runtime Jar 放入服务器 plugins/

不要安装或打包 API Jar

emaki-*-api-*.jar 不得放入 plugins/,也不得 shade 或 relocate 到你的插件。每个 Emaki runtime Jar 已内嵌一份未 relocate 的 API 类;重复副本会由不同 ClassLoader 定义为不同类型,导致 Bukkit 事件监听与 API bridge 静默失效。

第三方插件引用 API

所有 API 都发布在:

text
https://repo.crypticlib.com/repository/maven-public/

Maven

下面以 Forge 为例;将 artifactId 和版本替换为后文表格中的目标模块。示例版本按当前 POM 写为 4.7.11

xml
<repositories>
  <repository>
    <id>emaki</id>
    <url>https://repo.crypticlib.com/repository/maven-public/</url>
  </repository>
</repositories>

<dependencies>
  <dependency>
    <groupId>emaki.jiuwu.craft</groupId>
    <artifactId>emaki-forge-api</artifactId>
    <version>4.7.11</version>
    <scope>provided</scope>
  </dependency>
</dependencies>

Gradle Kotlin DSL

kotlin
repositories {
    maven("https://repo.crypticlib.com/repository/maven-public/")
}

dependencies {
    compileOnly("emaki.jiuwu.craft:emaki-forge-api:4.7.11")
}

不要使用 implementationapi、Shadow relocation 或其他会把 API 类复制进产物的配置。

当前 14 对 runtime / API 版本

以下版本来自当前模块 POM。服务器安装 runtime Jar;开发工程仅以 provided / compileOnly 引用 API artifact。.key 私有 profile 只影响 runtime 模块是否参与构建,不改变 API 坐标。

Runtime JarAPI 坐标当前版本API Jar 放进 plugins/
EmakiCoreLib-4.8.1.jaremaki.jiuwu.craft:emaki-corelib-api:4.8.14.8.1
EmakiAttribute-4.7.11.jaremaki.jiuwu.craft:emaki-attribute-api:4.7.114.7.11
EmakiForge-4.7.11.jaremaki.jiuwu.craft:emaki-forge-api:4.7.114.7.11
EmakiStrengthen-4.7.19.jaremaki.jiuwu.craft:emaki-strengthen-api:4.7.194.7.19
EmakiCooking-4.2.9.jaremaki.jiuwu.craft:emaki-cooking-api:4.2.94.2.9
EmakiGem-2.7.15.jaremaki.jiuwu.craft:emaki-gem-api:2.7.152.7.15
EmakiLevel-1.5.8.jaremaki.jiuwu.craft:emaki-level-api:1.5.81.5.8
EmakiSkills-2.7.11.jaremaki.jiuwu.craft:emaki-skills-api:2.7.112.7.11
EmakiItem-2.7.16.jaremaki.jiuwu.craft:emaki-item-api:2.7.162.7.16
EmakiCodex-1.0.5.jaremaki.jiuwu.craft:emaki-codex-api:1.0.51.0.5
EmakiStorage-1.0.6.jaremaki.jiuwu.craft:emaki-storage-api:1.0.61.0.6
EmakiStation-1.0.8.jaremaki.jiuwu.craft:emaki-station-api:1.0.81.0.8
EmakiAccessory-1.0.3.jaremaki.jiuwu.craft:emaki-accessory-api:1.0.31.0.3
EmakiMobs-1.0.6.jaremaki.jiuwu.craft:emaki-mobs-api:1.0.61.0.6

各模块完整公开方法、结果模型、线程要求和事件覆盖请查看对应 docs/modules/<module>/api.mdevents.md

运行时依赖声明

API 编译依赖不会让服务器自动加载对应 runtime。你的 paper-plugin.yml 仍应声明所需插件依赖。例如功能必须依赖 Forge 时使用硬依赖;只是可选联动时使用 soft dependency,并在运行时探测:

java
if (!EmakiForgeApi.status().usable()) {
    // 隐藏 Forge 联动;不要让可选模块拖垮整个插件
    return;
}

API 门面在 bridge 未安装或重载窗口中返回非 null 降级实现:目录通常为空,状态变更返回 EmakiResult 的 unavailable failure。真正完全没有 soft-depend runtime 时,首次加载 API 类也可能发生链接错误;可选集成应把相关类隔离,并在边界捕获 LinkageError | RuntimeException

EmakiResult 最小处理方式

不要把 null、空集合、0 或 false 同时解释为“业务结果”和“插件缺失”。结果型操作使用 EmakiResult<T>

java
if (result.isFailure()) {
    handleFailure(result.failureKind(), result.reasonKey());
} else {
    result.optionalValue().ifPresent(value -> handleValue(value, result.isPartial(), result.reasonKey()));
}

EmakiResult<Unit> 表示无负载成功;optionalValue() 是统一的可选负载访问器。FailureKind 当前精确包括 UNAVAILABLENOT_FOUNDINVALID_INPUTREJECTEDCANCELLEDTARGET_OFFLINEWRONG_THREADINTERNAL_ERROR。业务拒绝、事件取消、模块未安装和线程错误应分别处理。

等待模块就绪

模块加载顺序不保证你的 onEnable 晚于目标模块的首次数据加载。不要在自己的 onEnable 里直接查目标模块的表,改为挂就绪回调:

java
EmakiCoreLibApi.whenReady(this, "EmakiItem", () -> {
    // 此时 EmakiItem 的定义已加载
    buildMyIndex();
});
  • 回调只执行一次。目标模块 reload 会重新经历 not-ready → ready,但不会重放已触发的回调。需要跟随每次 reload 用 addModuleListener(见下节),不要在回调内重新注册——那会无限递归直至 StackOverflowError
  • moduleName 传字面量(如 "EmakiItem"),不要引用目标模块 API jar 里的常量。
  • 返回值是可关闭的 ReadinessRegistration;目标模块已就绪时回调同步执行并返回 inactive 句柄。
  • 回调线程是把模块标记为就绪的那个线程,不保证是 Bukkit owner thread。触碰玩家、背包、世界或 GUI 前先用 EmakiCoreLibApi.scheduling() 调度。
  • 只想"没就绪就跳过"时用 EmakiCoreLibApi.isModuleReady(name) 轮询即可。

reload 窗口内目标模块的 status()loading,返回 EmakiResult 的方法返回 unavailable();而 SetListboolean 这类纯查询无法表达不可用,可能返回陈旧或空结果。不要把空结果当成"该条目不存在"。

监听模块重载

缓存了其他模块内容的插件,需要在对方重载时失效并重建缓存。whenReady 只响一次,用 addModuleListener

java
EmakiCoreLibApi.addModuleListener(this, "EmakiItem", phase -> {
    switch (phase) {
        case LOADING, ABSENT -> myCache.invalidate();
        case READY -> myCache.rebuild();
    }
});
  • 三个相位:LOADING(开始替换数据,失效缓存)、READY(数据可用,重建缓存,首次加载与每次 reload 都触发)、ABSENT(模块已停用)。
  • 常驻,直到句柄关闭。同一 owner 对同一模块重复注册是替换而非追加。
  • 注册时若模块已就绪,不会立即回调;需要当前状态就查 isModuleReady
  • 线程约束同 whenReady:运行在发布状态的线程上,不保证是 owner thread。
  • 只提供"知道重载发生了",不提供让第三方触发别的模块重载的入口。

完整相位表与时序边界见 docs/modules/corelib/api.md

Folia 与线程

  • 玩家、实体、背包或持有物品的操作通常要求对应 entity-owner thread。
  • 方块/位置操作要求 location/region owner thread。
  • global scheduler 不等于任意玩家 owner thread。
  • 返回 CompletableFuture 只表示可以异步提交;future completion callback 不保证 Bukkit 安全线程。
  • 错误线程时,公开写 API 应返回 FailureKind.WRONG_THREAD,调用方应通过 CoreLib scheduling() 或平台 scheduler 正确调度。

推荐安装顺序

  1. EmakiCoreLib:所有业务模块的基础 runtime。
  2. EmakiAttribute:需要属性、资源或战斗联动时安装。
  3. 装备线:EmakiItem、EmakiForge、EmakiStrengthen、EmakiGem。
  4. 成长/玩法线:EmakiLevel、EmakiSkills、EmakiCooking、EmakiCodex、EmakiStorage。
  5. 按模块配置选择 PlaceholderAPI、Vault/ExcellentEconomy、MythicMobs、CraftEngine、ItemsAdder 等软依赖。

实际加载顺序以各模块 paper-plugin.yml 为准。CoreLib 是基础依赖;软依赖缺失时应只关闭对应桥接能力。

首次启动检查

  1. 只将需要的 runtime Jar 放入 plugins/
  2. 启动服务器,等待生成默认配置。
  3. 停服或确认没有玩家正在操作相关系统后修改 plugins/Emaki*/ 配置。
  4. 重启,先处理控制台最早出现的加载错误。
  5. 逐模块验证 GUI、命令、配置重载和外部依赖桥接。
  6. 第三方插件启动时记录各 API 的 status(),但不要调用 runtime 生命周期专用的 installuninstall 或实现 Bridge

装备技能 PDC 契约

EquipmentSkillPdcCodec 位于 emaki-skills-apiemaki.jiuwu.craft.skills.api.pdc 包。它是独立的低层 PDC 协议工具,不代表 EmakiSkills runtime 已就绪;Item、Forge、Gem、Strengthen 的内部嵌入/relocate 策略也不改变第三方插件必须使用 compileOnly 的规则。