Stage 状态机
基本信息
| 属性 | 值 |
|---|---|
| 实现类 | net.sxmaa.headlessnh.IntegrationTestController |
| 内部枚举 | Mode(公开)、Stage(私有) |
| 状态字段 | private static volatile Stage stage |
Mode 与 Stage 的关系
Mode 由三个 system property 决定,是公开 API(IntegrationTestController.mode()):
| 属性 | Mode |
|---|---|
headlessnh.singleplayer=true |
SINGLEPLAYER |
headlessnh.combined=true |
COMBINED |
| 都不设 | NONE |
[!WARNING] 判定顺序是
combined先于singleplayer。两个都设时COMBINED胜出,SINGLEPLAYER被静默忽略。
Stage 是私有枚举,只有三个值,它才是真正驱动流程的状态:
| Mode | 初始 Stage |
|---|---|
MULTIPLAYER / COMBINED |
MULTIPLAYER |
SINGLEPLAYER |
SINGLEPLAYER |
NONE |
DONE |
[!NOTE]
Mode.MULTIPLAYER这个枚举值在mode()里永远不会返回——多人流程是由combined触发的,返回值同样是COMBINED。switch (mode())里的case MULTIPLAYER, COMBINED合并分支因此是等价的。
推进流程
SINGLEPLAYER ──────────────────────────────► DONE
MULTIPLAYER ──► SINGLEPLAYER ──────────────► DONE
MULTIPLAYER 阶段:进入多人世界 → 稳定 headlessnh.delay.serverjoin(默认 7500 ms)→ 写 .serverloaded.headlessnh → 等 headlessnh.gate.serverloaded → 打开 GuiIngameMenu 并按按钮 1「返回游戏」触发拆除 → stage = SINGLEPLAYER。
SINGLEPLAYER 阶段:进入单人世界 → 稳定 headlessnh.delay.singleplayer(默认 7500 ms)→ 写 .worldloaded.headlessnh → 等 headlessnh.gate.worldloaded → 拆除 → stage = DONE。
stage 在 disconnectAndAdvance 的拆除动作之后才翻转成 SINGLEPLAYER,源码注释说明这是为了防止服务器世界还在卸载时渲染帧就发出单人世界 marker。
三个「各只触发一次」的一次性标志
MinecraftMixin 用 @Unique 布尔位保证每个界面只被自动点击一次,重试时按需复位:
| 字段 | 守护的界面 | 复位时机 |
|---|---|---|
menuMultiplayerTriggered |
GuiMainMenu 的多人按钮 |
连接失败重试时 |
menuSingleplayerTriggered |
GuiMainMenu 的单人按钮 |
从不 |
headlessNH$triggeredWorldSelection |
GuiSelectWorld |
从不 |
headlessNH$triggeredWorldCreation |
GuiCreateWorld |
从不 |
headlessNH$triggeredMultiplayer |
GuiMultiplayer |
断开时与直连一并复位 |
headlessNH$triggeredDirectConnect |
GuiScreenServerList |
断开时与多人一并复位 |
连接失败重试
onConnectionFailed() 在 GuiDisconnected 出现 1000 ms 后调用:未超过 headlessnh.connectRetries(默认 5)时只递增计数、复位多人/直连标志并 WARN 日志,流程由回到主菜单的 displayGuiScreen(new GuiMainMenu()) 重新驱动;超限则 fail("could not connect to server after N attempts"),其中 N = connectFailures - 1。
[!NOTE] 失败上限是
connectFailures <= connectRetryLimit()才重试,所以实际重试次数是 5 次、日志里报的 N 是 4,两者相差 1 属于源码写法。
相关条目
- Marker 与 Gate 文件 - 各阶段写出的标记文件
- System Properties - 全部属性与默认值
- MinecraftMixin - 一次性标志的持有者