Ticker

tick 与渲染事件;F3 顶替与可见性判定

基本信息

属性 值
路径 com.github.lunatrius.ingameinfo.handler.Ticker
行数 85
实例数 每个连接 1 个(由 TickerManager 创建)

三个事件处理器

1. onRenderGameOverlayEventPre(:20-26)—— 顶掉 F3

if (ConfigurationHandler.showHUD && ConfigurationHandler.replaceDebug
        && event.type == RenderGameOverlayEvent.ElementType.DEBUG) {
    event.setCanceled(true);
}

三个条件同时满足才取消原版 DEBUG 层:

条件 默认值
showHUD true
replaceDebug false
事件类型是 DEBUG —

⚠️ replaceDebug 默认 false —— 所以默认不接管 F3。 本 mod 与 F3 的关系是「可选替换」,不是「F3 增强」。

⚠️ 事件类型是 Pre(RenderGameOverlayEvent.Pre), 所以在原版绘制之前取消,这是能阻止绘制的唯一时机。

2. onClientTick(:28-38)—— 每 tick 逻辑

if (event.phase == TickEvent.Phase.END) {
    this.client.mcProfiler.startSection("ingameinfo");
    if (isRunning()) { this.core.onTickClient(); }
    Tag.releaseResources();
    this.client.mcProfiler.endSection();
}
步骤 说明
startSection("ingameinfo") 挂到 mcProfiler 的 F3 计时里
isRunning() 才调 onTickClient() 见下
Tag.releaseResources() 在 isRunning() 之外 ⚠️ 无条件执行
endSection() 配对

⚠️ Tag.releaseResources() 无条件调用, 即使 HUD 关闭也每 tick 执行。 它会清 TagPlayerPotion 的 potionEffects 缓存等。 HUD 关闭时这是纯浪费(每 tick 20 次/秒)。

⚠️ 只在 Phase.END 处理,Phase.START 被忽略。

3. onRenderGUI(:40-49)—— 绘制

if (event.type == RenderGameOverlayEvent.ElementType.TEXT) {
    this.client.mcProfiler.startSection("ingameinfo");
    if (isRunning()) { this.core.onTickRender(event.resolution); }
    this.client.mcProfiler.endSection();
}

⚠️ 事件类型是 Post,元素类型是 TEXT(聊天框)—— 即本 mod 的 HUD 绘制在原版聊天文本之后, 所以 HUD 文字会盖在聊天消息上。

replaceDebug 开启时,F3 DEBUG 层已被步骤 1 取消, 但 TEXT 层仍在,所以 HUD 显示在原版该显示聊天框的位置。

isRunning 的可见性判定(:51-84)

if (!ConfigurationHandler.showHUD) return false;                        // ①
if (this.client.mcProfiler.profilingEnabled) return true;               // ②
if (ConfigurationHandler.replaceDebug == this.client.gameSettings.showDebugInfo) {  // ③
    if (this.client.gameSettings.hideGUI) return false;                 // ④
    if (!ConfigurationHandler.showOnPlayerList
            && this.client.gameSettings.keyBindPlayerList.getIsKeyPressed()) {       // ⑤
        if (this.client.theWorld != null && this.client.thePlayer != null) {
            final ScoreObjective scoreobjective = this.client.theWorld.getScoreboard().func_96539_a(0);
            final NetHandlerPlayClient handler = this.client.thePlayer.sendQueue;
            if (!this.client.isIntegratedServerRunning() || handler.playerInfoList.size() > 1
                    || scoreobjective != null) return false;
        }
    }
    if (this.client.currentScreen == null) return true;                 // ⑥
    return ConfigurationHandler.showInChat && this.client.currentScreen instanceof GuiChat;  // ⑦
}
return false;                                                           // ⑧
# 判定 含义
① showHUD == false 配置总开关
② profiler 在跑 无条件显示(F3+Shift 的调试计时)
③ replaceDebug == showDebugInfo 状态对齐检查
④ hideGUI(F1 隐藏 GUI) 隐藏
⑤ 按 Tab 且不满足「单人物语」条件 隐藏
⑥ 无 GUI 打开 显示
⑦ 在聊天界面 取决于 showInChat
⑧ ③ 不成立 隐藏

③ 的设计意图(关键)

replaceDebug(配置)与 showDebugInfo(原版 F3 开关)必须相等才显示 HUD。

replaceDebug showDebugInfo 结果
false(默认) false 显示 HUD
false(默认) true(按 F3) 隐藏 HUD
true true 显示 HUD(顶掉原版 F3)
true false 隐藏 HUD

即:HUD 与 F3「互斥接管」 —— 关掉原版 F3 才用自己的,关掉自己的就还回原版 F3。

⚠️ 这个设计有代价:想同时看 F3 和 HUD 做不到, 除非把 showDebugInfo 关掉(此时 F3 已被 replaceDebug 顶掉)。

⚠️ ② 的 profiler 分支在 ③ 之前, 所以「F3 profiling 模式」下 HUD 无条件显示, 不管 replaceDebug 与 showDebugInfo 是否对齐。

⑤ 的「单人物语」判定

按 Tab 打开多人列表时,只有满足全部条件才隐藏 HUD:

条件 含义
isIntegratedServerRunning() 单机
playerInfoList.size() > 1 玩家数 ≤ 1
scoreobjective != null → 不隐藏 记分板有任何目标就保持显示

即:单机 + 只有自己 + 没有记分板时隐藏 HUD, 避免单人游戏时按 Tab 看到自己的 HUD 挡着列表。 func_96539_a(0) 是 Scoreboard.getObjectiveInDisplaySlot(0) 的 SRG 名(未映射),取第 0 槽(sidebar)目标。

两个实例字段(:17-18)

private final Minecraft client = Minecraft.getMinecraft();
private final InGameInfoCore core = InGameInfoCore.INSTANCE;

⚠️ 在构造时取 Minecraft.getMinecraft() 单例。 TickerManager 在 ClientConnectedToServerEvent 时创建本类, 此时 Minecraft 必然已初始化。

相关