Theseus 模组文档
API 参考 / judge 包:判定管线

JudgmentAdjuster


想先跑起来?

这一页是签名与行为参考。在计分前改写判定结果。直接做一遍:教程 · 添加判定等级。

判定结果改写钩子:在判定已产生、计分/连击/特效之前介入,可整体替换 JudgeResult。在 onPreInit 内经 ctx.registries().judgmentAdjusters() 注册,多个调整器按注册顺序链式执行,前一个的输出作为后一个的输入。

这是官方唯一的「判定干预」通道;NoteJudgedEvent / ComboBreakEvent 在判定落地后才投递,且不可取消。

方法速览

方法用途
adjust(JudgeResult, GameplayContext)改写本次判定结果,返回新结果

完整签名

java
public interface JudgmentAdjuster {

    JudgeResult adjust(JudgeResult input, GameplayContext ctx);
}

adjust(JudgeResult input, GameplayContext ctx)

签名:

java
JudgeResult adjust(JudgeResult input, GameplayContext ctx);

行为:input 是上一步的判定结果(链首为判定引擎产出的原始结果),ctx 是计分前的游玩状态只读快照。返回改写后的结果;返回 null 表示本调整器不生效——宿主跳过它并限频告警(日志明示 SHALL NOT 返回 null),链用上一步的结果继续。抛异常同样被隔离跳过,链继续,一个坏调整器不影响其它模组。

链按注册顺序执行,每次判定一次(HOLD 起点与终点各一次)。链结束后若最终判定仍是内置 seecmd:none,宿主用 JudgeResults.withJudgment 自动改写为内置 seecmd:miss;自定义判定等级不受此转换影响。

改写 judgeTime() 会触发宿主重录准度分布(撤销旧时刻、按新时刻记账),因此把时间改成 ctx.musicTimeMs() 等值不会出现同一次判定算两次。改写 judgment() 为自定义等级时,内部枚举会回退 NONE,但注册的 JudgmentKindDefinition 仍驱动 scoreValue / accuracyWeight / comboBehavior / isMissKind 与特效颜色。

确定性契约(强制):判定链路(JudgmentAdjuster.adjust / NoteTypeDefinition.onJudge / onJudgeTick)位于可重演路径上——暂停恢复倒带会对过去的时间窗逐帧正向重演,多帧率下同一输入也必须产出同一结果。实现必须:

违反契约的表现是「倒带后判定结果与首演不一致」;宿主无法拦截,属于模组自身缺陷。

示例(把所有 PERFECT 降为 GREAT;内置等级实例在 onPreInit 内取出):

java
private static final ResourceLocation PERFECT = ResourceLocation.of("seecmd", "perfect");
private static final ResourceLocation GREAT = ResourceLocation.of("seecmd", "great");

@Override
public void onPreInit(ModContext ctx) {
    JudgmentKindDefinition perfect = ctx.registries().judgmentKinds().get(PERFECT).orElse(null);
    JudgmentKindDefinition great = ctx.registries().judgmentKinds().get(GREAT).orElse(null);
    ctx.registries().judgmentAdjusters().register(
            RegistryKey.of("my_mod", "perfect_to_great", JudgmentAdjuster.class),
            (input, gameplayCtx) -> input.judgment() == perfect
                    ? JudgeResults.withJudgment(input, great)
                    : input);
}

线程:源码未声明额外线程约束。宿主在判定落地的同一线程(游玩/渲染线程)内同步调用;不要从自有线程调用 adjust。

生命周期阶段:onPreInit 注册;运行期每个音符判定完成后、计分前由宿主按注册顺序调用。

稳定性:2.0 起冻结:2.x 内只增不破(禁止删签名/改签名/改语义)。