世界加载检测
基本信息
| 属性 | 值 |
|---|---|
| 文件 | net/sxmaa/headlessnh/mixins/early/WorldRendererMixin.java |
| 目标类 | net.minecraft.client.renderer.WorldRenderer |
| 注入点 | updateRenderer @RETURN |
| Mixin 集 | NOTIFY_OF_FINISHED_WORLD_LOAD(EARLY,排除 Angelica) |
| 文件 | net/sxmaa/headlessnh/mixins/late/CeleritasWorldRendererMixin.java |
| 目标类 | com.gtnewhorizons.angelica.rendering.celeritas.CeleritasWorldRenderer(@Pseudo) |
| 注入点 | drawChunkLayer @RETURN(@Dynamic) |
| Mixin 集 | NOTIFY_OF_FINISHED_WORLD_LOAD_ANGELICA(LATE,要求 Angelica) |
这两个 Mixin 是一对互斥替代实现,负责告诉 IntegrationTestController 「世界已进入」。它们不判断加载是否完成,只在渲染循环的每帧回调 onWorldLoaded(),由后者按 stage 决定行为。
为什么分两个
WorldRendererMixin 挂在原版 WorldRenderer.updateRenderer 上。Angelica 用 Celeritas 接管了区块渲染,原版的调用点不再可靠,所以启用 Angelica 时由 Mixins.java 的 addExcludedMod / addRequiredMod 换成 Celeritas 版本。同一时刻只会加载其中一个。
CeleritasWorldRendererMixin 标了 @Pseudo + @Dynamic + remap = false:Celeritas 不在编译期 classpath 上,这样即使 Angelica 缺席也不会导致 Mixin 应用失败。
onWorldLoaded() 的分支
onWorldLoaded() 每帧被调用,内部先做 mc == null || mc.theWorld == null 早退,然后:
isActive() 为真(未设 headlessnh.active):不驱动菜单,只在每次世界加载都写 headlessnh.marker.worldloaded 标记。源码注释写明这是「保持原有行为」。
isActive() 为假(自动化真正在跑):mc.thePlayer == null 时早退(玩家还没进世界),然后按 stage:
MULTIPLAYER:serverLoadHandled保证只处理一次,调度disconnectAndAdvance(serverJoinSettleMillis(), markerServerLoadedName(), gateServerLoadedName())。SINGLEPLAYER:额外要求mc.isSingleplayer()为真才算数——源码注释解释这是因为多人服务器还在拆除时,渲染帧可能带着stage == SINGLEPLAYER触发。处理后立即stage = Stage.DONE。DONE:无操作。
disconnectAndAdvance 的顺序
IntegrationTestController 里的 disconnectAndAdvance 在新线程上按固定顺序执行:Thread.sleep(settleMillis) → 写 marker → Thread.sleep(markerCooldownMillis()) → 等 gate(awaitGate 返回 false 表示已超时失败,直接 return)→ 投递主线程任务:置 teardownRequested = true、直接 displayGuiScreen(new GuiIngameMenu())、最后才把 stage 翻成 SINGLEPLAYER。
[!NOTE] 用
new GuiIngameMenu()而不是ingameMenu.displayInGameMenu(),源码注释说明是因为前者在前台已有界面时会被忽略。teardownRequested标志则让 MinecraftMixin 的暂停菜单分支知道这个菜单是自己开的、应当点「返回游戏」而不是关掉。
相关条目
- MinecraftMixin - 暂停菜单分支如何消费
teardownRequested - Stage 状态机 - stage 翻转与单人世界判定
- Marker 与 Gate 文件 - marker 已存在会抛异常