Skip to content

feat(render): 修复残影并增加聊天头像显示 - #164

Merged
gaoyu06 merged 10 commits into
FPSMasterTeam:mainfrom
Serendisand:fix/render-perf-stutter
Jul 31, 2026
Merged

feat(render): 修复残影并增加聊天头像显示#164
gaoyu06 merged 10 commits into
FPSMasterTeam:mainfrom
Serendisand:fix/render-perf-stutter

Conversation

@Serendisand

Copy link
Copy Markdown
Contributor

变更内容

  • 修复 Nametags 关闭时仍会拦截原版 nametag 渲染的问题

    • 仅在 LevelTag.using 开启时取消原版 renderLivingLabel
    • 避免模块关闭时仍走自定义 nametag 渲染逻辑
  • 修复 Nametags 文字阴影/残影异常

    • 去掉 nametag 第一遍深度关闭绘制中的 shadow
    • 保留最终显示层的 FontShadow 设置
    • 缓存 mate 图标 ResourceLocation
    • 减少背景颜色重复读取
  • 优化 HUD blur 渲染逻辑

    • 全局 HUD blur 的 stencil 阶段不再完整绘制所有组件
    • 改为只绘制组件背景 mask
    • 避免文字本身参与 blur mask,减少文字残影/错误阴影
    • 降低组件 draw 逻辑每帧重复执行的开销
  • 修复 MotionBlur 旧模式可能污染后续渲染状态的问题

    • 补充 GL attrib/matrix 状态保存与恢复
    • 使用 try/finally 保证异常情况下也能恢复 GL 状态
  • 优化事件总线派发性能

    • 将事件 handler 从反射 Method.invoke 替换为 MethodHandle
    • 降低 tick/render 等高频事件派发开销

@Serendisand Serendisand changed the title fix(render): 修复 HUD/nametag 残影并优化事件派发性能 feat(render): 修复残影并增加聊天头像显示 Jul 28, 2026
@Serendisand

Copy link
Copy Markdown
Contributor Author
316279f0f8d73fe3cf39a67721fa718f 有一点小bug,服务器如果使用了聊天插件,可能会出现头像未正常渲染的bug

@Serendisand
Serendisand marked this pull request as draft July 31, 2026 10:07
@Serendisand

Copy link
Copy Markdown
Contributor Author

修复一下bug

@Serendisand
Serendisand marked this pull request as ready for review July 31, 2026 13:21
@Serendisand
Serendisand marked this pull request as draft July 31, 2026 13:25
@Serendisand
Serendisand marked this pull request as ready for review July 31, 2026 13:26
@Serendisand

Copy link
Copy Markdown
Contributor Author

close #166

聊天头像改为只使用原版皮肤管理器(tab list / 世界实体)已有的纹理,
删除整条 Mojang API 拉取链路:网络 I/O、DynamicTexture 生命周期、
CountDownLatch 跨线程等待与并发限流状态全部移除。

顺带根除:线程池拒绝策略只打日志不抛异常,导致 activeRequests 计数
永久泄漏、两次拒绝后 Mojang 兜底整局失效。

发送者识别:
- 新增 ClickEvent 预检,优先从 /msg|/tell|/w 的 suggest/run command
  中提取发送者,这是比文本启发式高一个量级的置信度信号
- 删除 3 字符最长公共子串模糊匹配,它会把 "Party > Notch" 匹配到
  在线的 Party_Manager
- 修正无分隔符系统消息的匹配方向:有分隔符取最右(跳过 [Guild] Rank
  前缀),无分隔符取最左(否则 "Bob was slain by Alice" 会选中 Alice)
- 词边界判定改为 Unicode 感知,避免 CJK 昵称紧贴正文时误判
- 剥离其他聊天 mod 添加的 [12:34] 时间戳前缀

渲染修复:
- 点击命中:offset 属于未缩放空间,须在除以 chatScale 之前减掉,
  否则聊天缩放 != 1 时点不中链接
- 聊天背景右边界同步内缩,否则面板比设定的聊天宽度更宽
- 换行行映射表改为 FIFO 淘汰,整表清空会抹掉在屏行的头像
- MotionBlur 去掉 glPushAttrib/glPopAttrib,改为通过 GlStateManager
  推回状态;裸 popAttrib 会让驱动状态倒退到缓存背后,使后续
  enableBlend()/color() 被当作命中缓存而跳过
- UFontRenderer.trimString 不再对文本做 NameProtect 过滤,其返回
  长度被 TextField 当作原始串的索引使用
- 高密度字体路径的阴影偏移补齐为 actualDensityScale,此前传半值,
  逆缩放后回落到 0.5px,正是像素对齐改动要消除的偏移

Co-Authored-By: Claude <noreply@anthropic.com>
@gaoyu06

gaoyu06 commented Jul 31, 2026

Copy link
Copy Markdown
Member

Review 结果与后续修复

对本 PR 做了一轮多角度审查,发现的问题已在 42384b1 中修复,并在本地 1.8.9 客户端连服实测通过。

已修复

聊天头像识别

  • 移除 Mojang API 兜底整条链路。头像改为只用原版皮肤管理器(tab list / 世界实体)已有的纹理,聊天渲染路径不再有网络 I/O 和 DynamicTexture 生命周期管理。这也顺带根除了一个隐患:线程池拒绝策略只打日志不抛异常,导致 activeRequests 计数永久泄漏,两次拒绝后 Mojang 兜底整局失效。
  • 新增 ClickEvent 预检,优先从 /msg|/tell|/w <name> 的 suggest/run command 提取发送者。原版聊天装饰器和多数聊天插件会专门在发送者名字那一段挂这个事件,置信度远高于文本启发式。
  • 删除 3 字符最长公共子串模糊匹配。原实现会把 Party > Notch: hi 匹配到在线的 Party_Manager
  • 修正无分隔符系统消息的匹配方向:有分隔符取最右(跳过 [Guild] Rank 前缀),无分隔符取最左。原先一律取最右,会让 Bob was slain by Alice 挂上 Alice 的头像。
  • 词边界判定改为 Unicode 感知,避免 CJK 昵称紧贴正文时被误判成独立 token。
  • 剥离其他聊天 mod 添加的 [12:34] 时间戳前缀,否则发送者不再位于行首,分隔符锚定会退化。
  • 换行行映射表由「满 512 整表 clear」改为 FIFO 淘汰。整表清空会抹掉仍在屏幕上的行的头像,只留下空的头像栏位。

渲染

  • 聊天点击命中:translate(2 + offset) 发生在 scale(g,g) 之前,offset 属于未缩放空间,必须在除以 chatScale 之前减掉。原实现在聊天缩放 ≠ 1 时点不中链接。
  • 聊天背景右边界同步内缩,否则面板比设定的聊天宽度更宽。
  • MotionBlur 去掉 glPushAttrib/glPopAttrib,改为通过 GlStateManager 推回状态。OpenGlHelper.glBlendFuncbindFramebufferTexture 绕过了 GlStateManager 的缓存,裸 popAttrib 会让驱动状态倒退到缓存背后,使后续 enableBlend()/color() 被当作命中缓存而跳过。
  • UFontRenderer.trimString 不再对文本做 NameProtect 过滤。其返回长度被 TextField 当作原始串的索引使用,过滤会改变长度导致光标错位。
  • 高密度字体路径的阴影偏移补齐为 actualDensityScale。此前传半值,逆缩放后回落到 0.5px,正是 74602d1 把默认值从 0.5 改成 1.0 时要消除的偏移,改默认值时漏了这一处。

遗留项(建议另开 PR)

HUD blur 的 stencil mask 几何不通用。Component.drawBlurMask 假设「组件背景 = 位于 (rX-2, rY, width, height) 的单个矩形」,但:

  • KeystrokesComponent 画在 (x, y) 而非 (x-2, y),差 2px
  • ArmorDisplayComponent 画的是若干独立 16×16 小块,不是一个包围盒,blur 会从缝隙透出
  • width/heightdraw() 内部赋值,而 mask 跑在 draw() 之前,恒差一帧;组件首帧 width == 0 会被直接跳过

正解是让组件自己声明背景形状,让 mask 与实绘共用同一份几何,而不是由 mask 侧猜测。这需要改动所有组件,适合单独一个 PR。

补充

PR 描述只覆盖了渲染修复部分,没有提到 671 行的 ChatAvatarCache、新增的 ChatAvatars 模块、全局字体阴影偏移改动和 MainMenu 的 Android 分支——这些占了改动量的大部分。合并时建议在 squash commit message 里补全。

另:审查中曾就 LevelTag 第一遍绘制去掉 FontShadow 提出疑问,经复核该改动是正确的——第一遍是深度关闭的暗色透视底衬,给它叠阴影正是残影来源,真正可见的第二遍完整保留了 FontShadow 分支。此条撤回。

🤖 Generated with Claude Code

@gaoyu06
gaoyu06 merged commit 420e193 into FPSMasterTeam:main Jul 31, 2026
2 checks passed
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.

2 participants