公开 API
编译依赖
<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-forge-api</artifactId>
<version>4.7.11</version><scope>provided</scope>
</dependency>repositories { maven("https://repo.crypticlib.com/repository/maven-public/") }
dependencies { compileOnly("emaki.jiuwu.craft:emaki-forge-api:4.7.11") }仅编译依赖
不要把 API Jar 放入 plugins/,也不要 bundle、shade 或 relocate。EmakiForge-4.7.11.jar 已内嵌未 relocate 的 API 类;重复 ClassLoader 类型会破坏 Bukkit 事件与静态 bridge。
门面与真实分层
先检查 EmakiForgeApi.status().usable()。catalog()、operations()、extensions() 永不返回 null;不可用时返回空查询、unavailable 结果或空扩展层。
catalog():配方、材料、匹配、校验、接受状态。operations():程序化锻造、GUI、配方书和物品刷新。extensions():当前为空的保留实验层,不存在可注册扩展点。
install、uninstall 和 Bridge 只属于 runtime 生命周期;第三方不得调用、实现或代理。
Catalog
recipes()、recipe(String)、materialById(String)、materialByItem(ItemStack) 与 accepting() 可读加载后的不可变定义;实时物品须遵守其 holder owner thread。matchRecipe(Player, ForgeInputs) 与 validate(Player, String, ForgeInputs) 需要玩家 owner thread。validate 的业务不通过仍是 Success(ForgeValidation),应检查 allowed()。
实验性 previewResult(Player, String, ForgeInputs) 也要求玩家 owner thread;它只构建当前预览,不执行配置动作、不消耗输入、不写入历史且不交付物品。实验性 mastery(Player, String) 读取玩家该配方已持久化的成功锻造次数;当前会话数据尚未加载时返回 UNAVAILABLE,不会伪造为 0。
程序化锻造
CompletableFuture<EmakiResult<ForgeOutcome>> future =
EmakiForgeApi.operations().forgeAsync(player, recipeId, inputs);forgeAsync 可从任意线程提交,runtime 会把所有玩家/Bukkit 阶段调度到玩家 owner thread。ForgeInputs 是调用方预先保留的分离 escrow 快照:target、blueprints、requiredMaterials、optionalMaterials 均防御性复制。API 不会扫描或扣除玩家任意库存槽;调用方必须在 future 期间锁住实物,并在成功时提交 escrow、失败时释放。
ForgeOutcome 只在结果物品已交付且 commit boundary 已跨越后产生,包含 recipeId、克隆的 resultItem、quality 与 multiplier。普通摇点失败、验证拒绝、事件取消、不可用和执行错误由外层 EmakiResult 表示。取消 future 不能回滚已经越过交付提交点的尝试。
其他 Operations
openForgeGui(Player[, recipeId])、openRecipeBook(Player, page)、viewingRecipeBook(Player):玩家 owner thread。refreshItem(ItemStack):holder owner thread;非锻造物品返回Partial。refreshPlayer(Player):刷新库存、护甲、副手与光标,玩家 owner thread。
结果语义
无负载成功使用 EmakiResult<Unit>,不是 Void。读取可选负载使用 optionalValue();Success/Partial 记录本身的直接访问器仍是 value()。FailureKind 精确为:UNAVAILABLE、NOT_FOUND、INVALID_INPUT、REJECTED、CANCELLED、TARGET_OFFLINE、WRONG_THREAD、INTERNAL_ERROR。