Kzeroko KTM2

命运天平 API

注册选项与效果、评估草稿,并提交服务器权威命运天平档案。

更新于 2026/9/27 10 分钟阅读

FateBalanceAPI 是命运天平注册、查询和服务器验证提交的公共门面。定义属于公共端内容,供预览与验证共用;效果单独注册,由运行时统一协调。

入口

使用 net.kzeroko.isekaiexpansion.api.fatebalance.FateBalanceAPI。门面委托给 internal.fatebalance;当前作为门面参数或返回值公开的注册器、不可变定义、结果记录和效果接口仍位于该内部包,不应直接调用注册表或服务。

通过 FateBalanceEntrypoint 注册公共内容。初始化先安装内置分类和内容,再调用附属模组入口,最后安装效果分发器。某个入口抛出运行时异常会记录日志并继续下一个;该入口此前成功的注册不会回滚。

常见用法

注册选项和效果

在附属模组已有的 fabric.mod.json 中加入:

{
  "entrypoints": {
    "isekaiexpansion:fate_balance": ["example.addon.ExampleFateBalance"]
  }
}
字段类型默认值作用
entrypointsobject缺省Fabric 入口映射,与已有入口合并。
entrypoints.isekaiexpansion:fate_balancearray<string>缺省实现 FateBalanceEntrypoint 的完整类名,在公共端注册。

示例添加选项及乘算经验效果,翻译键由标识符派生:

public final class ExampleFateBalance implements FateBalanceEntrypoint {
    @Override
    public void register(FateBalanceRegistrar registrar) {
        Identifier choice = new Identifier("example", "quick_learner");
        registrar.registerChoice(FateBalanceChoice.builder(
                choice, FateBalancePolarity.BLESSING, 2)
                .category(FateBalanceSystem.MENTAL_CATEGORY_ID)
                .tags("experience")
                .build());
        registrar.registerEffect(choice, FateBalanceEffects.experience(1.1, 1.1));
    }
}

仅注册选项不会自动产生游戏效果。由所属系统自行计算的机制,也可以在计算处使用 FateBalanceAPI.isSelected(player, choiceId)。

评估和提交

评估不会保存档案。可信服务器代码可以通过与网络请求相同的验证提交:

static FateBalanceCommitResult applyProfile(
        ServerPlayerEntity player, Collection<Identifier> choices) {
    return FateBalanceAPI.commit(player, choices);
}

检查 success()、evaluation() 和可空的 problem()。拒绝结果提供首个问题,完整评估保留全部问题。提交服务没有“确认后禁止编辑”的锁或权限判断,调用方负责决定何时允许修改。重复提交相同的已确认集合会成功,但不再同步或触发变化事件。

注册预设和规则

FateBalancePreset.builder(id) 支持 nameKey、choices(可变参数或集合)、order、availableWhen。默认选项为空、排序 0、始终可用,名称键为 fate_balance_preset.<namespace>.<path-with-dots>。注册时不验证选项 ID 或点数平衡;预设提供可编辑草稿。

FateBalanceRule 接收玩家、不可变的选项/注册快照、基础点数、祝福消耗、负担收益与剩余点数。返回 FateBalanceProblem 列表,不应修改玩家。空列表引用和空项被忽略,运行时异常加入 SERVER_ERROR。内置负担上限本身也是注册规则。

方法一览

门面方法

方法端 / 阶段返回或修改
registrar()公共初始化提供下列注册方法的注册器。
registerCategory(category)公共初始化添加分类。
registerChoice(choice)公共初始化添加不可变选项。
registerEffect(choiceId, effect)公共初始化追加效果,同一选项允许多个效果。
registerPreset(preset)公共初始化添加可编辑起始档案。
registerRule(id, rule)公共初始化添加验证规则。
categories()、choices()、presets()初始化后双端按排序值、标识符文本排序的不可变列表。
findCategory(id)、findChoice(id)双端Optional 查询结果,拒绝空 ID。
evaluate(player, selections)玩家所属游戏线程不可变评估,玩家必填。
commit(serverPlayer, selections)服务器线程重新评估,替换并同步有效档案,再触发变化事件。
selections(player)玩家所属游戏线程当前不可变集合,可能含存档中的未知 ID。
isSelected(player, id)玩家所属游戏线程查询是否选中,不验证可用性。
isConfirmed(player)玩家所属游戏线程已保存的确认标志。
maxPoints()双端配置起始点数限制到 0–64,默认配置为 10。
maxBurdenPoints()双端内置上限 6。

注册写入使用同步锁并发布不可变快照。分类、选项、预设、规则的 ID 重复会抛出异常;效果则追加。注册时不检查效果 ID、分类、前置或冲突目标是否存在。这不是数据包重载注册表。

选项构建器约定

输入默认值验证与含义
builder(id, polarity, points)必填ID/极性非空,点数须为 1–64,否则异常。BLESSING 消耗,BURDEN 提供点数。
nameKey、descriptionKeyfate_balance.<namespace>.<path-with-dots>,描述再加 .description覆盖键不得为空白,ID 路径中的斜杠转为点号。
categoryisekaiexpansion:fate_balance/generalID 非空,此处不检查是否存在。
severitySTANDARDMINOR、STANDARD、MAJOR,非空;仅为表现元数据,不乘算点数。
iconItemnull物品注册ID;缓存GUI模型图像,缺失或空气物品以纸张代替。
order0任意整数,较小值在前。
requires、conflictsWith空可变参数/集合并去重;忽略空容器,拒绝空项;构建时拒绝自引用。
exclusiveGroupnull可选分组 ID,同时选中多个组成员会冲突。
tags空忽略空/空白项,去首尾空白、转小写并去重。
availableWhen(predicate, reasonKey)始终可用,无原因谓词非空,空白原因转 null;评估时异常视为不可用。

FateBalanceCategory 要求 ID 非空、名称键非空白,排序不限。FateBalancePair.register 增加双向冲突,检查 ID 不同且构建器 ID/极性匹配,然后依次注册祝福、负担和可选效果。后续注册失败时不保证原子性。

验证与持久化

选择集合可为空引用(空档案),空 ID 和重复项会忽略。评估最多保留 128 个唯一 ID,超出则加入 TOO_MANY_CHOICES。检查未知/不可用选项、缺失前置、冲突、互斥组及负余额。剩余点数为 base + burden − blessing,允许保留正余额;内置规则拒绝超过 6 的负担收益。

问题类型为 UNKNOWN_CHOICE、UNAVAILABLE、MISSING_REQUIREMENT、CONFLICT、EXCLUSIVE_GROUP、NEGATIVE_BALANCE、CUSTOM、TOO_MANY_CHOICES、SERVER_ERROR。对称冲突/互斥组按排序后的对象 ID 和问题元数据去重。自定义消息键在线路传输中上限为 192 字符,构造器不检查该长度。

存储字段类型默认值约定
selectionslist<string>空只读取前 128 项,跳过错误标识符并去重,不检查注册存在性;写入按标识符字典序排列。
confirmedbooleanfalse首次有效提交设为 true,空档案也可以确认。
revisionint0读取时负值限制为 0;每次有变化的有效提交递增。

玩家组件自动同步并在重生时复制。读取 NBT 不会按变更后的内容/配置重新评估。有效替换先同步,再发变化事件。监听器异常在保存后记录,不会回滚。管理员重放命令 /ise charactercreate 会清空选择与确认状态并同步,再以空的当前集合触发同一个变化事件,因此所有效果都会按未启用重新协调。

提交包只发送标识符意图。声明数量为负或超过 128 会拒绝,解码最多读取 128 个 ID。服务器重新评估并返回成功标志及可选问题,权威档案状态另由组件同步。

效果生命周期

钩子或工厂约定
reconcile(serverPlayer, active)幂等地应用或移除自有状态,默认无操作。命谱变化协调前后ID,登录和重生协调全部已注册效果。
experienceMultiplier(player, reason)默认1;协调器只接收LOOT与QUEST。乘积限制在0–4,非有限值恢复1,奖励取整且不为负。COMBAT跳过全部效果。
dailyLootCapMultiplier(player)默认1,所选倍率相乘并使用相同范围。
foodComfortBonus(player, stack)默认0;只对正基础值累加带正负号的加值,限制在整数范围。
mealRepetitionMultiplier(player), sleepComfortMultiplier(player)默认1;乘积限制在0–4,非有限值恢复1。
FateBalanceEffects.attributes(modifiers...)至少一个非空修饰;用固定UUID管理社交属性临时修饰。
experience(loot, quest), dailyLootCap(multiplier)工厂倍率须为0–4内的有限值。
foodTaste(meals, restrictive)非空物品标签。普通口味:匹配食物+4;限制性口味:其他食物−3。
mealRepetition(multiplier), sleepComfort(multiplier)工厂倍率须为0–4内的有限值。

FateBalanceAPI.foodComfort(player, stack, base)应用饮食加值;玩家为null时返回基础值。mealRepetitionMultiplier(player)与sleepComfortMultiplier(player)要求已有玩家,并查询所选效果。组件初始化后,在玩家所属游戏线程调用,双端均可读取。

每日上限在每秒以及命谱变化、登录、重生事件后协调。协调器分别追踪家园战斗上限与命运天平战利品上限,使用当前等级的IsekaiCore默认值,等级至少为1。某上限最后一项修饰移除后,该上限单独恢复一次。两条路径都不清除已消耗经验,战利品特质不能刷新战斗额度。

经验使用ICPlayerExpEvents.MODIFY_GRANT;异界扩展的XpRewardLogic与TypeBLevelPotion直接调用PLAYER_LEVELER.addExperience并绕过该事件。同一命途内按效果注册顺序执行,不逐项隔离异常,也不保证跨命途顺序。

图标合成

iconItem解析物品GUI模型。FateBalanceItemIcons在Minecraft渲染线程通过ModernUiCapture生成64 × 64像素静态图,使用独立颜色与深度目标并恢复渲染状态。ModernUI在UI线程上传位图,作为普通图像合成;滚动、祖先裁剪、透明度与模态层级都由Canvas处理。模型图标不是实时动画预览。

缓存最多128项。视图持有图像副本,脱离窗口时释放。资源重载会清空缓存并刷新已挂载视图,捕获失败时使用默认纹理。验证床、平面物品与自定义模型在滚动和确认浮层中的显示。

事件

FateBalanceEvents.PROFILE_CHANGED 在同步后提供服务器玩家和不可变的前后集合。监听器按顺序执行,不可取消。服务捕获整个事件调用的异常,因此某监听器抛错可能阻止后续监听器,但提交仍报告成功。需要登录/重生恢复的效果应使用 registerEffect。

线程与生命周期

在公共初始化阶段为双端注册相同定义。可用性和自定义验证会同时用于客户端预览和服务器评估,必须兼容双端。ModernUI 桥接会先把评估调度到 Minecraft 客户端线程,再把结果返回 UI 线程;直接调用门面不会自动调度。

提交和效果修改须在服务器线程,且玩家/组件已经存在。注册快照安全不代表任意线程都能安全访问玩家或世界;谓词和规则评估应保持无副作用。

相关页面