These files were loaded only by their own test_*_parity.gd and never by the runtime (transitively checked, incl. client_phase_integration_system). Removes 76 manifest implementation/evidence references across 18 contracts; contract docs get a note that conclusions based on them are void. Live systems kept: chest, consumable, item_attr, metin_socket, whisper_chat. Full headless suite: no new failures (7 failing + 5 headless-hanging render tests are identical before the deletion). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
18 KiB
social.chat_text_tail
Scope
审计公聊、队伍/公会/喊话频道、无 VID 系统消息、私聊收发和私聊窗口、忽略名单、聊天气泡、名字/公会/称号/等级尾标以及尾标的寿命、排布和死亡清理。对比重点是当前端是否复现 40250 的消息类型分支、服务器事件来源、私聊状态机、文本颜色/过滤/表情副作用、尾标覆盖规则和渲染布局;本地有同名 helper 或能显示文本不等于实现统一。
Reference call chain
UserInterface/PythonNetworkStreamPhaseGame.cppRecvChatPacket校验聊天类型;CHAT_TYPE_COMMAND进入ServerCommand,不进入普通聊天和聊天尾标。- 有 VID 时,普通/队伍/公会/喊话/客户端私聊从
"名字: "后取正文,执行表情解析、跨帝国文字转换和辱骂过滤;角色不存在时直接忽略;除CHAT_TYPE_SHOUT外注册CPythonTextTail::RegisterChatTail,PC 消息再进入CPythonChat::AppendChat。 - 无 VID 时,NOTICE/BIG_NOTICE 分别进入
BINARY_SetTipMessage/BINARY_SetBigMessage,系统和喊话按专门分支处理,不是简单追加到同一聊天列表。 RecvWhisperPacket将 mode、发送者和文本交给OnRecvWhisper/错误/系统回调;私聊历史、按钮、闪烁和忽略名单由CPythonChat、uiwhisper.py和game.py联动。
UserInterface/PythonNetworkStreamCommand.cppServerCommand作为CHAT_TYPE_COMMAND的二次命令总线,解析 cube、observer、StoneDetect、stamina、mobile、gift、情感动作和dig_motion,并把副作用交给 UI、角色或效果管理器;命令不进入普通聊天尾标。
UserInterface/PythonChat.cpp/PythonChat.h- 普通聊天维护共享聊天行队列和多个 chat set,支持 view/edit/log 三种布局、滚动步长、最大行数、延迟追加、按频道颜色和清理。
- 40250 颜色是 talking 白、info 淡红、notice/big notice 淡黄、party 青白、guild 淡紫、command/shout 青绿、whisper 绿色;私聊 mode 包含 chat、not-exist、target-blocked、sender-blocked、error、GM 和 system。
AppendWhisper按目标名维护独立会话;IgnoreCharacter/IsIgnoreCharacter只对目标名切换黑名单;InitWhisper/MakeWhisperButton恢复已有会话。
UserInterface/PythonTextTail.cpp/InstanceBaseEffect.cppRegisterChatTail和RegisterInfoTail共用每 VID 一条尾标;聊天尾标为白色、bNameFlag=true,信息尾标为淡红、bNameFlag=false,新消息覆盖旧消息并重置now + 5000ms。- 聊天气泡会强制显示角色名字,并把名字尾标移动到气泡下方 17px;公会名、称号、等级按实际字体度量排在名字两侧/上下;角色死亡时
DetachTextTail。 - 公会名只在 guild id 非零时创建,名称查询失败回退
Noname;称号/等级受EnablePKTitle、alignment grade、level 和挂马高度影响。
Client/Eternexus/root/game.py/uiwhisper.pyOnRecvWhisper按官方 whisper mode 分流到AppendWhisper、系统错误文本和界面RecvWhisper通知;聊天输入、好友/目标板和独立私聊窗口都能打开同一目标会话。- 私聊窗口发送只有网络请求成功后才应关闭/追加本地回显;忽略按钮通过
/ignore <name>与服务端/客户端状态同步。
Current call chain
EntityStore::mut_chat、mut_whisper和 parser 已保存GC_CHAT/GC_WHISPER为 chat queue;M2Client发出chat、whisper_received信号,基础 classic 动态包布局和长度限制存在;GC_WHISPER缺少固定 type/name 字段时会拒绝,不再静默吞包。project/ui/chat_ui.gd只有四个本地 tab(全部/私聊/系统/战斗),按 GodotRichTextLabel重建整段文本;公共输入支持普通、公会、队伍、喊话和/w,但普通/喊话发送失败没有统一错误回显,私聊窗口也无视client.whisper()返回值而立即本地回显并关闭。- 当前入站私聊
_on_whisper已按 40250 区分0=CHAT、1=NOT_EXIST、2=TARGET_BLOCKED、3=SENDER_BLOCKED、4=ERROR、5=GM、0xFF=SYSTEM;1..4 的空文本会生成本地化错误兜底文案。live 会话已接入,颜色/字体和服务端错误正文仍未完整闭环。 project/whisper_chat_system.gd实现了独立的本地 conversation/最小化/闪烁/忽略 helper,ChatUI.setup现在把它接入M2Client.whisper_received;live 私聊仍没有完整的独立窗口历史渲染、任务栏按钮、ignore 命令和发送结果状态。project/chat_tail.gd已复现单 VID 覆盖、5000ms 生命周期、聊天/信息颜色和名字跟随规则;project/net_world.gd用Label3D气泡、名字和子标签实现,死亡/过期会清理节点。project/text_tail.gd、text_tail_arrange.gd、name_tail_layout.gd已实现部分颜色、称号、等级、公会名、挂马高度和像素近似排布;但运行时仍是 Godot billboard/估算字符宽度,不是 40250 的CGraphicText实际字体度量和CPythonTextTail渲染对象。ClassicParser::on_gc(GC_CHAT)现按 40250 先拒绝非法 chat type,并在非系统消息的 VID 不存在于EntityStore时消费但不产生 chat event;liveproject/net_world.gd::_on_chat仍没有复现表情解析、跨帝国转换、辱骂过滤和无 VID NOTICE/BIG_NOTICE 专用 UI。
Branch matrix
| 场景 | 40250 | 当前端 | 结论 |
|---|---|---|---|
| 普通/队伍/公会聊天 | 解析类型、角色和前缀,过滤/表情后写聊天行,必要时注册气泡 | 基础 GC_CHAT queue、UI tab 和气泡存在 |
PARTIAL:过滤/表情/未知实体/真实显示布局缺失 |
| 喊话 | 公共聊天颜色和公共区显示,不能注册角色聊天尾标 | 当前写入公共 tab;ChatTail 也能保留,但 net_world 连接路径未证明按 ref 排除 |
PARTIAL |
| 无 VID INFO/NOTICE/BIG_NOTICE | 专用 tip/big notice 分支,按类型显示 | 统一塞入 System/All RichTextLabel,没有专用 tip/big notice |
GAP |
| COMMAND | 进入 ServerCommand,不显示普通聊天/气泡 |
native 有部分 command 解析;非已识别 command 仍缺完整 side effect 矩阵 | PARTIAL |
| 表情/帝国文字/辱骂过滤 | 先解析表情或转换/过滤,再显示文本/动画 | 有发送表情 token,但没有入站 ParseEmoticon、帝国转换和辱骂过滤链 |
GAP |
| 私聊正常收发 | mode/name/text 进入独立目标会话,按钮/历史/通知联动 | packet queue、独立输入和 live conversation 接入存在;窗口历史/按钮/通知仍不完整 | PARTIAL |
| 私聊错误/GM/system mode | 0..5/0xFF 具有不同错误/字体/颜色和通知 | mode 数值与错误/GM/system 分支已对齐;颜色、字体和 live 通知仍不等价 | PARTIAL |
| 忽略目标 | IgnoreCharacter 按名称切换,收到私聊不进入会话并有服务端 ignore 命令 |
live ChatUI 收到普通/GM 私聊前经过会话 ignore 判断;仍无 UI 忽略按钮/服务端命令连接 | PARTIAL |
| 聊天气泡 | 每 VID 单槽覆盖,白/淡红,5000ms,聊天气泡强显名字并上移名字 17px | 单槽、颜色、生命周期和本地布局 helper 存在 | PARTIAL:实际字体/屏幕投影/已知实体和资源表现不同 |
| 名字/称号/等级/公会名 | 由角色同步、alignment/guild/item/挂马更新,死亡 detach,真实字体度量排布 | 快照+Label3D 子标签和近似字符宽度存在 | PARTIAL:权威更新源和渲染度量不完全同链 |
| 换图/重连/死亡/重复消息 | CPythonChat/TextTail 清理与重新注册,旧会话状态按客户端生命周期处理 | 本地节点过期/死亡清理存在;chat queue、私聊会话和重连恢复未端到端验证 | PARTIAL |
Implementation-equivalence matrix
| 项目 | 状态 | 证据/限制 |
|---|---|---|
| Preconditions | PARTIAL | native 长度/阶段边界存在;缺入站 actor/type/name、ignore、输入门控和真实 UI 状态前置条件 |
| Branch structure | PARTIAL | 普通/私聊/尾标主干和 live ignore 分支存在,但无 VID notice、表情/过滤和完整私聊通知分支 |
| Algorithms/formulas | PARTIAL | 5000ms 生命周期和 17px 名字偏移有静态镜像;频道颜色、前缀、字符宽度、会话/通知算法存在明确差异 |
| State transition order | GAP | 参考是网络回包→过滤/表情/尾标→聊天/窗口/提示;当前 conversation 已随 live signal 更新,但本地回显/窗口通知和服务端结果顺序仍不同 |
| Constants/units | PARTIAL | EChatType 和尾标 5000ms/17px/颜色部分存在;多个公共/私聊颜色与 40250 不同,字体宽度是 7px 估算 |
| Timing/event sources | PARTIAL | 气泡过期和 UI 信号存在;延迟聊天、真实服务器命令、重连/后台通知和私聊闪烁未接通 |
| Resource/data sources | GAP | 40250 使用角色/公会/本地化/字体资源及服务器消息;当前标题本地化可注入但 chat 文本/颜色/宽度多为脚本常量和 Godot 默认字体 |
| Protocol side effects | PARTIAL | classic CG_CHAT/CG_WHISPER 与 GC queue 有;入站类型副作用、SendSequence/错误文案、ignore 命令和 notice/big notice UI 未完整复现 |
| Interruption/failure/cleanup | GAP | 私聊发送失败仍本地显示并关闭;会话/忽略/聊天行重连清理、未知 VID、重复/乱序回包和专用提示清理缺端到端证据 |
Regression evidence
project/chat_test.gd:公共/私聊输入路由、拾取/钓鱼消息、气泡和名字/子标签排布通过;使用 fake client,未验证真实GC_CHAT分支和发送失败。project/chat_tail_test.gd:RegisterChatTail/RegisterInfoTail、单 VID 覆盖和 5000ms 生命周期通过。project/text_tail_test.gd、project/text_tail_arrange_test.gd、project/name_tail_layout_test.gd、project/guild_mark_tail_test.gd:静态颜色、称号/等级、公会名、排列和 guild mark 通过;未验证真实字体资源和 C++ 尾标对象。project/test_whisper_chat_parity.gd:26/26 通过,覆盖会话、闪烁、忽略和历史;project/chat_test.gd另验证 live ChatUI 的普通/GM 入站信号进入同一 conversation。project/chat_mobile_ui_test.gd、project/test_chat_hyperlink_dice_parity.gd:移动聊天窗口、私聊输入和额外链接/dice helper 通过;不能证明 40250 的入站消息分支。build/extension/net_entity_test、build/extension/net_classic_session_test:GC_CHAT/GC_WHISPER 解析和发送包基础通过;session 回归覆盖未知 VID、非法 type、已知 VID 的 chat event 矩阵;project/chat_test.gd另覆盖 whisper mode 1/5/0xFF 的错误、GM、system 显示映射,但仍没有完整 0..5/0xFF live 回调、失败回显和重连测试。
Deep audit round 2026-09-21
Fresh regression results
godot --headless --path project --script chat_test.gd、chat_tail_test.gd、text_tail_test.gd、text_tail_arrange_test.gd:均退出码 0;公共/私聊路由、气泡覆盖、5000ms 生命周期、颜色和尾标排布通过,但使用的是脚本/fake client 与近似字体度量。godot --headless --path project --script name_tail_layout_test.gd、guild_mark_tail_test.gd:均退出码 0;名字/公会标记和尾标布局 helper 通过。godot --headless --path project --script test_whisper_chat_parity.gd:退出码 0,26/26 通过;覆盖独立的WhisperChatSystem会话、闪烁、忽略和历史;chat_test.gd已补 liveChatUI入站网络状态验证。godot --headless --path project --script chat_mobile_ui_test.gd、test_chat_hyperlink_dice_parity.gd:均退出码 0;移动 UI、链接/骰子 helper 通过。build/extension/net_entity_test与build/extension/net_classic_session_test:均退出码 0;GC_CHAT/GC_WHISPER 基础解析和发送包通过,未覆盖完整消息分支矩阵。
Static parity findings
- 40250
RecvWhisperPacket的 mode 是0=CHAT、1=NOT_EXIST、2=TARGET_BLOCKED、3=SENDER_BLOCKED、4=ERROR、5=GM、0xFF=SYSTEM;当前ChatUI::_on_whisper把1显示为系统、2显示为 GM,且其余错误/屏蔽分支没有对应 UI 语义。 - 当前
ChatUI在client.whisper()返回前就本地追加回显并关闭私聊窗口;网络发送失败时仍显示成功,违背 40250 的请求结果驱动状态转换。 WhisperChatSystem已有独立会话/忽略/闪烁实现,liveChatUI现在把普通/GMM2Client.whisper_received接入该状态源;独立窗口渲染、任务栏按钮和服务端 ignore 命令仍未闭环。- 40250
RecvChatPacket对未知 VID 的普通消息直接忽略,并处理表情、跨帝国转换、辱骂过滤以及无 VID 的 NOTICE/BIG_NOTICE 专用提示;当前_on_chat对未知 VID 仍能显示原文,NOTICE/BIG_NOTICE 统一进入 RichTextLabel,未接专用提示和过滤链。 - 40250 聊天气泡/尾标依赖
CGraphicText实际字体、角色/公会/称号/等级权威同步并在死亡时 detach;当前 Label3D/脚本近似布局虽有局部测试,但没有真实字体资源、网络更新和重连/死亡/重复消息端到端证据。
Active command-bus source review
- 本轮逐项核对
PythonNetworkStreamCommand.cpp与当前EntityStore::apply_server_command→M2Client::poll信号链:当前端已经覆盖cube、observer、StoneDetect、stamina、mobile、gift、combo、block mode、lover、password/refine/private-shop 以及 emotion/dig 的主要事件枚举,net_entity_test对其中一组事件通过。 - 仍存在参考语义差异:40250 未识别/参数数量错误命令会走日志或特定 UI 回调;当前端对命令的统一 token/参数校验、效果资源创建、所有 emotion/observer/gift 回调和命令失败清理没有完整矩阵。
ClientCommand()在参考版本本身返回 false,不能把当前端已有 server-command helper 测试解释为完整 GM/命令 parity。
Round conclusion
本轮仍为 PARTIAL:已按 40250 收口 native GC_CHAT 的非法类型/未知 VID 丢弃分支,修正 ChatUI 的 whisper mode 映射与空错误文案兜底,并把 live 普通/GM whisper 接入独立会话和 ignore 判断;窗口通知、NOTICE 分支、表情/过滤/跨帝国文字和真实尾标渲染仍未与 40250 统一。
Active EterLib text-render review
EterLib/GrpText.cpp/GrpTextInstance.cpp/TextBar.cpp/TextTag.cpp以及GrpFontTexture.cpp、GrpMarkInstance.cpp共同负责真实字体资源、字宽/行数/字符位置、光标/描边/颜色、标记和池化对象生命周期;这正是 40250 聊天气泡、名字/公会/称号尾标的渲染基础。- 当前
Label3D、RichTextLabel和脚本宽度估算已覆盖局部可见结果,但没有复用同等字体纹理度量、字符定位、mark 生命周期和资源失败分支。已有布局测试使用 helper/fake client,不能替代真实字体资源与网络角色更新。 - 因此本轮完成上述 EterLib 文本核心静态核对;尾标的单槽/5000ms/17px 行为仍有镜像证据,但渲染资源和清理链不一致,合同继续为
PARTIAL。
Active UserInterface chat and text-tail review
InsultChecker.cpp/h维护可清空/追加的禁词集合,按 locale-aware case-insensitive 比较处理多字节字符;FilterInsult用*替换完整词,IsInsultIn只报告命中,不能用 ASCIIfind近似替代。PythonChatModule.cpp暴露 chat set 的创建、位置/高度/步长/模式、延迟消息、忽略角色、whisper 会话、whisper 清理和 item hyperlink 解析;hyperlink 通过CItemManager查 item 数据,不是只显示原字符串。PythonTextTailModule.cpp的生产顺序是UpdateAllTextTail、UpdateShowingTextTail、RegisterCharacterTextTail、RegisterChatTail/RegisterInfoTail、标题/拾取/排列和投影位置查询;Pick、隐藏/显示和角色删除清理是同一状态机的一部分。- 当前端聊天/尾标 helper 已有局部测试,live ChatUI 已将普通/GM whisper 接入独立会话和 ignore 判断;仍未形成 locale 禁词、多字节边界、chat-set 排列、item hyperlink、未知/删除 VID、投影失败和真实字体资源的同一调用链,已有 Godot 宽度估算和本地文本状态不能证明 40250 等价,合同保持
PARTIAL。
Implementation fix round 2026-09-22
project/ui/chat_ui.gd已按PythonChat.h/game.py修正 whisper mode:1..4作为错误系统消息,5作为 GM,0xFF作为 system;空错误正文使用本地化兜底文案。extension/src/net/classic/classic_parser.cpp已按RecvWhisperPacket的固定头前置条件,将缺少 type/name 的GC_WHISPERbody 从静默成功改为失败;net_classic_session_test增加对应直接 parser 回归。project/chat_test.gd、project/test_whisper_chat_parity.gd、project/chat_mobile_ui_test.gd、project/test_chat_hyperlink_dice_parity.gd与 native session 回归通过;live conversation/ignore 接入已有证据,完整通知/颜色、忽略命令和公共聊天副作用仍未闭环。
Static review evidence
已将 InsultChecker.cpp/h、PythonChatModule.cpp、PythonTextTailModule.cpp 纳入 active source 证据;这些文件对应的过滤、chat-set、whisper、hyperlink、尾标更新和拾取分支仍记录为实现差异或未验证分支。
Status
PARTIAL。当前端已有聊天协议骨架、公共输入、私聊基础发送、聊天气泡和名字尾标的可测试镜像,但并非与 40250 统一实现:live 私聊已接入独立会话,但窗口历史/任务栏通知/服务端 ignore 命令仍未闭环;公共颜色/notice 分支不一致、入站表情/过滤/跨帝国文本缺失,且尾标渲染仍使用 Godot billboard 与宽度估算。本轮已修正 whisper mode 映射、空错误文案、截断 whisper 拒绝逻辑并接通 live conversation/ignore 判断,其他差异继续保持 PARTIAL。
2026-09-22 死代码删除
以下文件只被自身测试引用、运行时从不加载,已删除;本文中以它们为实现或证据的结论作废,相关行为需按 40250 源码单元重新移植:test_chat_hyperlink_dice_parity.gd。