Theseus 模组文档
API 参考 / spi 包:游戏模式、谱面扩展与内容

GameModeDefinition


想先跑起来?

这一页是签名与行为参考。改规则不改内核:轨道映射、镜像、输入与覆盖渲染。直接做一遍:教程 · 添加游戏模式。

游戏模式定义对象:把「当前模式要做什么」收敛为一组回调,宿主核心循环不再为每种模式写 if/else,而是把控制权交给当前激活模式的实例。在 onPreInit 用 ctx.registries().gameModes().register(key, def) 注册,注册键(如 mymod:mirror)即模式 id,游玩中可经 GameStateAccess.requestMode("mymod:mirror") 切换。除 displayName() 外所有方法都是安全空操作的默认实现,最小实现只需提供显示名。相关类型:GameModeContext。

方法速览

方法用途
displayName()模式显示名(界面/日志)
onEnter(GameModeContext)模式成为当前激活模式时调用
onUpdate(long, GameModeContext)每个常规游玩更新帧调用
onHandleInput(InputEvent, GameModeContext)输入分发钩子,返回 true 表示吞掉本帧输入
mapLane(int, int)物理轨道 → 判定轨道映射
mirrorsPlayfield()是否左右镜像渲染谱面
onExit(GameModeContext)模式不再激活时调用
renderOverlay(RenderCanvas, GameModeContext)模式激活时每帧的覆盖层渲染

displayName()

签名:

java
String displayName();

行为:返回模式的显示名(如 "镜像")。宿主不把它用于模式匹配或派发,实现应恒定返回同一字符串,供界面/日志自行展示。

示例:

java
@Override
public String displayName() {
    return "镜像";
}

onEnter(GameModeContext ctx)

签名:

java
default void onEnter(GameModeContext ctx);

行为:模式成为当前激活模式时调用一次——游玩场景 onEnter 选定模式后,或 GameStateAccess.requestMode 切换成功后;切换时旧模式的 onExit 先于新模式的本回调。ctx 是宿主复用的快照对象,只在本帧回调内有效。宿主以 try/catch 隔离异常(进场/切换路径静默忽略),但仍应在实现内自行防御。

示例:

java
@Override
public void onEnter(GameModeContext ctx) {
    // 每局重置本模式的自持状态;不要保存 ctx 引用
    enteredAtMs = ctx.musicTimeMs();
}

onUpdate(long musicTimeMs, GameModeContext ctx)

签名:

java
default void onUpdate(long musicTimeMs, GameModeContext ctx);

行为:宿主在每个常规游玩更新帧调用,位置在输入处理之前;暂停、结束与倒带窗口不进入该路径(倒带分支提前返回,只投递 GameplayTickEvent)。musicTimeMs 与本帧 ctx.musicTimeMs() 同值。宿主还可能在当前激活模式不是内置 seecmd:disorder 时,额外对 disorder 模式调用本回调以维持无序机制;自定义模式不会收到这种额外派发。异常被 try/catch 静默忽略。

示例:

java
@Override
public void onUpdate(long musicTimeMs, GameModeContext ctx) {
    if (ctx.isPaused()) {
        return;
    }
    long now = ctx.musicTimeMs();   // 与参数同值
    // 用 now 推进本模式的动画/计时,不要阻塞
}

onHandleInput(InputEvent event, GameModeContext ctx)

签名:

java
default boolean onHandleInput(InputEvent event, GameModeContext ctx);

行为:每次输入分发开始时调用。宿主当前采用轮询式输入,event 恒为 null,实现不得解引用事件对象(需要按键状态请用 InputAccess 能力)。返回 true 表示本帧输入已被模式消费,主循环不再做常规按键判定。该调用点在宿主中没有 try/catch 包裹,抛出异常会向上中断本帧输入处理,务必自行防御。默认实现返回 false。

示例:

java
@Override
public boolean onHandleInput(InputEvent event, GameModeContext ctx) {
    // 轮询式派发:event 恒为 null,不要读取它的字段
    return false;   // false = 交还主循环继续处理
}

mapLane(int lane, int laneCount)

签名:

java
default int mapLane(int lane, int laneCount);

行为:把物理轨道映射为实际判定轨道,默认恒等。lane 为 0 起的物理轨道,laneCount 为本谱面轨道数。宿主在按键判定与「当前按住轨道」计算中应用本映射;单次调用抛异常时回退物理轨道。注意:宿主渲染侧的左右翻转由 mirrorsPlayfield() 驱动,不读取本方法——镜像类模式应同时实现两者(mapLane 返回 laneCount - 1 - lane,并让 mirrorsPlayfield() 返回 true)。

示例:

java
@Override
public int mapLane(int lane, int laneCount) {
    return laneCount - 1 - lane;
}

mirrorsPlayfield()

签名:

java
default boolean mirrorsPlayfield();

行为:返回 true 时宿主每帧把轨道渲染切到镜像模式,左右翻转音符、按键指示器、轨道分隔线等全部轨道元素;默认 false。宿主在渲染路径每帧直接读取,该调用点没有 try/catch 包裹,异常会中断本帧渲染。模式切换即时生效。

示例:

java
@Override
public boolean mirrorsPlayfield() {
    return true;
}

onExit(GameModeContext ctx)

签名:

java
default void onExit(GameModeContext ctx);

行为:模式不再为当前激活模式时调用——切换模式时先于新模式的 onEnter,离开游玩场景时也会对当前模式调用。异常由宿主 try/catch 隔离(场景退出路径记限频日志)。适合释放本局状态、复位经能力接口改过的视觉状态。

示例:

java
@Override
public void onExit(GameModeContext ctx) {
    // 本模式写入的视觉状态应在这里经 GameStateAccess 复位
}

renderOverlay(RenderCanvas canvas, GameModeContext ctx)

签名:

java
default void renderOverlay(RenderCanvas canvas, GameModeContext ctx);

行为:模式激活时每帧调用,层序在原版 HUD 之上、全屏覆盖之下。canvas 是模组唯一绘制入口,坐标系为画布像素。异常由宿主 try/catch 静默忽略,单帧绘制失败不影响游玩。

示例:

java
@Override
public void renderOverlay(RenderCanvas canvas, GameModeContext ctx) {
    canvas.drawText("MIRROR", 16, 32, TextStyle.of(16, Color.WHITE));
}

完整签名

java
public interface GameModeDefinition {

    String displayName();

    default void onEnter(GameModeContext ctx);

    default void onUpdate(long musicTimeMs, GameModeContext ctx);

    default boolean onHandleInput(InputEvent event, GameModeContext ctx);

    default int mapLane(int lane, int laneCount);

    default boolean mirrorsPlayfield();

    default void onExit(GameModeContext ctx);

    default void renderOverlay(RenderCanvas canvas, GameModeContext ctx);
}

线程:源码未声明额外线程约束;宿主在游玩更新与渲染主线程同步调用全部回调,回调内不得阻塞。

生命周期阶段:定义对象在 onPreInit 注册;运行期在进入模式、游玩更新帧、输入处理、渲染帧、退出模式时回调。

稳定性:1.x 内只增不破的承诺在 2.0 兑现破坏一次:@Deprecated 的 overridesJudgment() 已随 删除(幽灵扩展点:宿主从不读取其返回值,判定级接管由 NoteTypeDefinition 的 overridesJudgment + onJudgeTick 与本接口的 onHandleInput 承担)。2.0 内恢复只增不破。