Skip to content

refactor(hud): 公共设置改由 Trait 声明式注册,并修复 HUD 缩放失效 - #167

Merged
gaoyu06 merged 1 commit into
mainfrom
refactor/hud-settings-and-scale
Aug 1, 2026
Merged

refactor(hud): 公共设置改由 Trait 声明式注册,并修复 HUD 缩放失效#167
gaoyu06 merged 1 commit into
mainfrom
refactor/hud-settings-and-scale

Conversation

@gaoyu06

@gaoyu06 gaoyu06 commented Jul 31, 2026

Copy link
Copy Markdown
Member

背景

HUD 的公共外观设置由基类 Component.drawRect / drawString 消费,注册却留在子类手写,两边没有任何机制保证一致。这是一个必须手动同步的重复,随时间必然分叉——而且子类手写注册其实零自由度:写不写都不影响行为(基类照读字段),只影响用户能不能在 UI 里看到,纯负担。

实测分叉情况:

现象 实例
注册 0 个却用了 5 个 Keystrokes 的背景色/圆角/间距在 ClickGUI 里看不到也改不了,锁死默认值且不进配置
漏注册但仍生效 ModsList / BlockIndicator 漏了 rounded/roundRadius/fontShadow
重复注册 8 个模块把 rounded 传两次,addSettings 不去重 → 渲染两个一样的开关
反向不一致 Sprint/ToggleSneak/TargetDisplay 不画背景,但 bg 默认 true,开 blur 后糊出一块不存在的背景框

改造后各模块的公共设置数完全由 Trait 决定,不再有分叉(Keystrokes 0→7、ModsList/BlockIndicator 4→6、Sprint/ToggleSneak→2、MiniMap→0)。

主要改动

Trait 声明式注册

InterfaceModule 新增 Trait{BACKGROUND, TEXT, SPACING},由 ModuleManager.init() 在所有模块构造完成后统一调用 registerCommonSettings() 追加。放在末尾是为了保持「模块自有设置在前、公共外观在后」的原有 UI 顺序。

Trait 同时具备行为语义而不只是 UI 语义——Component.hasBackground() 检查 Trait.BACKGROUND,所以无背景模块不会再被画 blur 蒙版。光靠「不注册」解决不了这个问题,因为 bg 字段永远存在且默认 true

修复 scale 失效

22 个组件全部 allowScale = true,滚轮能滚、值会存进配置,但这 4 个的 draw()scale 一次都没出现:

  • Scoreboard / TargetHUD / PlayerDisplay — 绕过 drawRect/drawString 直接调 Rects.*fontManager.sXX,导致 scalebg/rounded/betterFont/fontShadow 全部失效
  • MiniMap — FBO 尺寸与背景贴图未乘 scale

按基类约定(位置偏移由调用方乘 scale,尺寸/字号由基类乘)改回基类路径。两处刻意保留裸绘制:TargetHUD 的血条和玩家头像是内容而非装饰,不应被 Background 开关关掉,仅显式缩放。

其他修复

  • getRealPosition 的 RT/LB/RB 分支用裸 width/height 定位,而 drawRect、hover 检测、拖拽钳制、blur 蒙版都用 width * scale——同一个类里两套约定,放大后的右对齐组件溢出屏幕 width * (scale - 1)
  • ComponentsManager 两处 catch 把异常对象整个丢弃,只打一行固定字符串 × 每秒 60 帧,比不打日志更糟(吞掉了堆栈)。加 ClientLogger.error(String, Throwable) 重载,前 3 次带堆栈、之后按 2 的幂降频,连续失败 60 帧自动禁用组件,并在 catch 里复位 scissor/stencil/blend
  • PotionDisplay 的 scissor 与 Keystrokes 的 stencil 改 try/finally。此前中途抛异常会让 GL_SCISSOR_TEST 一直开着,整个游戏画面被裁到药水条的矩形内
  • InterfaceHandlergetComponent(MiniMap.class) 加 null 检查(该方法按 mod.getClass() == clazz 精确匹配,MiniMap 模块未注册时返回 null 会直接 NPE)

行为变化

  • Sprint/ToggleSneak/TargetDisplay 开启 HUD blur 时不再有多余的背景模糊块
  • 8 个模块的 ClickGUI 里少一个重复的「圆角」开关
  • Keystrokes/ModsList/BlockIndicator 多出若干原本被隐藏的设置项
  • PlayerDisplay 的背景色从硬编码变为可调(构造器里覆盖了默认值,外观不变)

未验证

MiniMap 模块在 ModuleManager 里是注释掉的状态(// modules.add(new MiniMap())),其 scale 改动为机械修改,未经实机验证。

后续

HUD blur 的 stencil mask 几何问题(drawBlurMask 假设背景是位于 (rX-2, rY) 的单个矩形,对 Keystrokes/ArmorDisplay 等多矩形组件不成立,且因 width/heightdraw() 内赋值而恒差一帧)留待下一个 PR,需要引入 measure() 阶段并让组件声明背景几何。

🤖 Generated with Claude Code

HUD 的公共外观设置(Background/Round/RoundRadius/BackgroundColor/BetterFont/
FontShadow/Spacing)由基类 Component.drawRect / drawString 消费,注册却留在
子类手写,两边没有任何机制保证一致,结果严重分叉:

- Keystrokes 一个都没注册,但组件实际读了其中 5 个 —— 背景色、圆角、间距
  在 ClickGUI 里既看不到也改不了,永远锁死默认值且不进配置文件
- ModsList / BlockIndicator 漏注册 rounded / roundRadius / fontShadow,同样不可见
- 8 个模块把 rounded 传了两次,而 addSettings 不去重 —— ClickGUI 渲染两个
  一模一样的开关,指向同一个值
- Sprint / ToggleSneak / TargetDisplay 不画背景,但 bg 字段默认 true,
  开启 blur 后会在文字后面糊出一块它们根本没画的背景框,用户无从关闭

现在 InterfaceModule 用 Trait(BACKGROUND/TEXT/SPACING) 声明能力,由
ModuleManager.init() 在所有模块构造完成后统一调用 registerCommonSettings()
追加(放在末尾以保持「模块自有设置在前、公共外观在后」的原有 UI 顺序)。
Trait 同时具备行为语义:Component.hasBackground() 检查 Trait.BACKGROUND,
所以无背景模块不会再被画 blur 蒙版。addSettings 改为按引用去重。

修复 scale 失效:22 个组件全部 allowScale=true,滚轮能滚、值会存进配置,
但这 4 个的 draw() 里 scale 一次都没出现 ——

- Scoreboard / TargetHUD / PlayerDisplay 绕过 drawRect/drawString 直接调
  Rects.* 和 fontManager.sXX,导致 scale 及 bg/rounded/betterFont/fontShadow
  全部失效。改回基类绘制路径,位置偏移按约定显式乘 scale
- MiniMap 的 FBO 尺寸与背景贴图未乘 scale
- PlayerDisplay 原本硬编码 Color(0,0,0,60),改用 backgroundColor 的同时在
  构造器里覆盖该设置的默认值,外观不变但可调
- TargetHUD 的血条与头像保持裸绘制(它们是内容不是装饰,不应被 Background
  开关关掉),仅显式缩放

其他修复:

- getRealPosition 的 RT/LB/RB 分支用裸 width/height 定位,而 drawRect、hover
  检测、拖拽钳制、blur 蒙版都用 width*scale —— 同一个类里两套约定,放大后的
  右对齐组件会溢出屏幕 width*(scale-1)
- ComponentsManager 两处 catch 把异常对象整个丢弃,只打一行固定字符串 ×
  每秒 60 帧。加 ClientLogger.error(String, Throwable) 重载,前 3 次带堆栈、
  之后按 2 的幂降频,连续失败 60 帧自动禁用该组件,并在 catch 里复位
  scissor/stencil/blend 防止污染后续渲染
- PotionDisplay 的 scissor 与 Keystrokes 的 stencil 改 try/finally。此前中途
  抛异常会让 GL_SCISSOR_TEST 一直开着,整个游戏画面被裁到药水条的矩形内
- InterfaceHandler 对 getComponent(MiniMap.class) 加 null 检查,MiniMap 模块
  未注册时该调用返回 null 会直接 NPE

Co-Authored-By: Claude <noreply@anthropic.com>
@gaoyu06
gaoyu06 merged commit 99ab873 into main Aug 1, 2026
2 checks passed
@gaoyu06
gaoyu06 deleted the refactor/hud-settings-and-scale branch August 1, 2026 04:22
@gaoyu06
gaoyu06 restored the refactor/hud-settings-and-scale branch August 1, 2026 04:25
@gaoyu06
gaoyu06 deleted the refactor/hud-settings-and-scale branch August 1, 2026 04:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant