Theseus 模组文档
API 参考 / 入口与生命周期

Mod


想先跑起来?

这一页是签名与行为参考。入口接口:先写一个最小模组,再回来看每个回调的边界。直接做一遍:教程 · 第一个模组。

模组入口接口。第三方模组实现它(或其子接口 GameplayMod),通过 info() 提供元信息,并按需覆写生命周期回调。实现类必须有无参构造器:宿主从 jar 加载时用 Class.getDeclaredConstructor().newInstance() 实例化。

方法速览

方法用途
info()返回模组元信息(唯一抽象方法)
loadOrder()声明加载阶段与软依赖;默认 null = INIT、无软依赖
onPreInit(ModContext)注册窗口:唯一允许写注册表的阶段
onInit(ModContext)注册表冻结后的初始化:读配置、订阅事件、建运行期资源
onPostInit(ModContext)全部模组 onInit 完成后的收尾与跨模组交互
onUnload()卸载时释放资源(调用一次)
createConfigScene()提供模组独立配置场景;默认 null = 无配置界面

完整签名

java
public interface Mod {

    ModInfo info();

    default ModLoadOrder loadOrder();

    default void onPreInit(ModContext ctx);

    default void onInit(ModContext ctx);

    default void onPostInit(ModContext ctx);

    default void onUnload();

    default com.seecmd.mod.api.scene.Scene createConfigScene();
}

info()

签名:

java
ModInfo info();

行为:返回不可变的 ModInfo。宿主在注册阶段调用并校验:

宿主也可能在模组列表、状态查询(getModInfo / getRegisteredMods / getActiveMods)时再次调用,因此实现应保持廉价、无副作用。模组 id 同时是数据目录名 data/mods/<id>、资源命名空间与注册键命名空间,务必与 manifest 的 Seecmd-Mod-Id 一致。

示例:

java
@Override
public ModInfo info() {
    return ModInfo.of("hello_mod", "Hello Mod", "1.0.0",
            List.of("YourName"), "我的第一个 Theseus 模组");
}

loadOrder()

签名:

java
default ModLoadOrder loadOrder();

行为:返回 ModLoadOrder,声明激活阶段与软依赖。默认返回 null,等价于 LoadStage.INIT 且无软依赖。该声明只决定同阶段内、每个阶段内部的遍历次序;「何时做」由三段回调表达。loadOrder() 抛异常时宿主按默认值(INIT、无软依赖)处理。硬依赖仍经 ModInfo.dependsOn() 声明,缺失即加载失败。

示例:

java
@Override
public ModLoadOrder loadOrder() {
    return new ModLoadOrder(LoadStage.PRE_INIT, List.of("core_lib"), List.of());
}

onPreInit(ModContext ctx)

签名:

java
default void onPreInit(ModContext ctx);

行为:注册窗口回调,模组加载时最先调用。经 ctx.registries() 注册全部自有内容(见 ModRegistries);此刻注册表开放,全部模组的本回调结束后宿主立即冻结注册表。

示例:

java
@Override
public void onPreInit(ModContext ctx) {
    ctx.registries().collectibles().register(
            RegistryKey.of("hello_mod", "first_note", CollectibleDefinition.class),
            CollectibleDefinition.of("初遇").withBrief("第一次启动模组"));
}

onInit(ModContext ctx)

签名:

java
default void onInit(ModContext ctx);

行为:注册表已冻结、全部模组的 onPreInit 已完成之后调用。用于注册窗口之外的初始化:读配置、建缓存、订阅事件、创建运行期资源、读取其它模组已注册的内容。

示例:

java
@Override
public void onInit(ModContext ctx) {
    boolean showToast = ctx.config().getBool("show_toast", true);
    if (showToast) {
        ctx.notifier().info("Hello Mod 已加载");
    }
    ctx.eventBus().subscribe(TickEvent.class, event -> {
        // 任意场景每帧回调(宿主线程)
    });
}

onPostInit(ModContext ctx)

签名:

java
default void onPostInit(ModContext ctx);

行为:全部模组的 onInit 已完成之后调用。用于发布初始事件、自检、建立跨模组交互、读取自有译文。

示例:

java
@Override
public void onPostInit(ModContext ctx) {
    ctx.getLogger().info("译文:" + ctx.language().get("hello_mod.greeting").orElse("(missing)"));
}

onUnload()

签名:

java
default void onUnload();

行为:模组卸载时调用一次(玩家停用需重启生效,实际发生在退出或注销时)。可覆写以释放资源。异常被宿主隔离,仅记录日志,不阻塞其它模组卸载。宿主随后还会强制关停网络线程池、释放图像句柄,并按模组归属清理事件订阅、能力、跨模组服务、全局快捷键与 UI 定制项;冻结式注册表不撤销。

示例:

java
@Override
public void onUnload() {
    unloading = true;          // 供弹窗重建逻辑判断终止条件
}

createConfigScene()

签名:

java
default com.seecmd.mod.api.scene.Scene createConfigScene();

行为:返回模组的独立配置场景实例;默认 null 表示无配置界面。模组可在菜单中(如 ModList 详情面板按 C)进入该场景。宿主每次进入配置都会调用本方法取得新实例;抛异常时返回 null。

示例:

java
@Override
public com.seecmd.mod.api.scene.Scene createConfigScene() {
    return new MyConfigScene();
}

线程:源码未声明额外线程约束;生命周期回调由宿主在启动线程串行调用。

稳定性:2.0 起冻结:2.x 内只增不破(禁止删签名 / 改签名 / 改语义);破坏性变更只在 major 版本发生且须提供迁移指南与至少一个大版本的弃用期。3.x 内继续只增不破。