重载生命周期

基本信息

属性 值
入口 MineTweakerImplementationAPI.reload()(MineTweakerImplementationAPI.java:634-701)
触发点 1 服务器启动 onServerStart(MineTweakerImplementationAPI.java:610-613)
触发点 2 /minetweaker 重载指令
触发点 3 客户端建连 onClientAboutToConnect(MineTweakerMod.java:181-188)
生命周期钩子 3 个(onRollbackEvent / onReloadEvent / onPostReload)
钩子可从脚本调用 否 —— MineTweakerImplementationAPI 全文 0 个 ZenScript 注解
脚本分发 platform.distributeScripts(...),受 sendScriptsOnReloading 控制

五个阶段

reload() 的执行顺序(MineTweakerImplementationAPI.java:634-701):

# 动作 源码行
1 blockInfoPlayers.clear() —— 清空方块信息监听者缓存 :635
2 logger.clear() + events.clear() —— 清日志与全部事件订阅 :637-638
3 若 server != null,重新挂上内置的登录/登出监听 LISTEN_LOGIN / LISTEN_LOGOUT :640-643
4 MineTweakerAPI.tweaker.rollback() —— 逆序撤销上次全部动作 :645
5 发布 ONROLLBACK :646
6 若 server != null 且未注册过 minetweaker 指令,则注册 /minetweaker(别名 mt / crafttweaker / ct,OP 限定) :648-688
7 发布 ONRELOAD :691
8 MineTweakerAPI.tweaker.load() —— 重新加载脚本 :693
9 若 server != null,platform.distributeScripts(tweaker.getScriptData()) :695-697
10 发布 ONPOSTRELOAD :699

三个钩子的语义:

钩子 注册方法 发布行 典型用途
ONROLLBACK onRollbackEvent(:593-594) :646 释放脚本占用的外部资源
ONRELOAD onReloadEvent(:597-598) :691 读取即将生效的新状态
ONPOSTRELOAD onPostReload(:601-602) :699 依赖配方已就绪的收尾工作

三个钩子共用同一个空载体类 ReloadEvent(MineTweakerImplementationAPI.java:730-731),签名均为 (IEventHandler<ReloadEvent>) → IEventHandle。三个 EventList 字段声明在 :60-62。

限制:钩子仅 Java 可见

MineTweakerImplementationAPI.java 全文 @ZenMethod / @ZenClass 出现次数为 0(grep -nE '@ZenMethod|@ZenClass' src/main/java/minetweaker/MineTweakerImplementationAPI.java 无输出)。因此脚本里没有 events.onReload(...) 这类调用;这三个钩子只能由 Java 侧模组注册。同理 ReloadEvent 自身也没有 @ZenClass,即便拿到实例脚本也无类型可用。

步骤 3 的内置监听

LISTEN_LOGIN / LISTEN_LOGOUT 是 1.7.10 侧的固定监听器(MineTweakerImplementationAPI.java:641-642),用于把脚本数据推给玩家。它们在每次 reload() 后被重新挂上,因为上一步 events.clear() 已清空所有订阅。

步骤 6 的分发与配置

distributeScripts 实现(mc1710/MCPlatformFunctions.java:32-36):

public void distributeScripts(byte[] data) {
    if (MineTweakerConfig.sendScriptsOnReloading)
        MineTweakerMod.NETWORK.sendToAll(new MineTweakerLoadScriptsPacket(data));
}

sendScriptsOnReloading 默认 true(MineTweakerConfig.java:31-35)。关闭后 /minetweaker 重载不会把新脚本推给客户端,客户端将继续用登录时收到的旧脚本。

客户端侧接收由 MineTweakerLoadScriptsHandler 处理,额外要求 MineTweakerAPI.server == null(即当前不在单机/集成服里)且 handleLoadScripts 为 true(network/MineTweakerLoadScriptsHandler.java:24),然后换成 ScriptProviderMemory 并 reload()。

登录时的首次分发

与重载分发独立:FMLEventHandler.onPlayerLoggedIn 在玩家是 EntityPlayerMP 且 sendLoadScripts 为 true 时单发一个 MineTweakerLoadScriptsPacket(FMLEventHandler.java:41-51)。sendLoadScripts 默认 true(MineTweakerConfig.java:29-30)。

antiStuck 与重复加载

MineTweakerMod 用 loaded 标志 + antiStuck 配置决定重连时是否跳过重载(MineTweakerMod.java:174-178、:185-187):

场景 loaded == false loaded == true
antiStuck == false(配置默认) onServerStart(srv) → 完整重载 完整重载
antiStuck == true onServerStart(srv) → 完整重载 只赋值 MineTweakerAPI.server = srv,跳过重载

客户端侧同理:antiStuck 为 true 且已加载过时,onClientAboutToConnect 直接 return(MineTweakerMod.java:185)。

注意一处不一致:MineTweakerConfig.java:12 的字段初始值把 antiStuck 写成 true,但 load() 里 config.getBoolean("antiStuck", "core", false, ...) 的默认参数是 false(MineTweakerConfig.java:42-46)。由于 load() 在预初始化期必定执行并覆写全部 6 个字段(MineTweakerMod.java:134-135),字段初始值 true 是死代码,实际默认行为由 cfg 默认参数 false 决定。配置文件首次生成时写入的是 false。

相关条目