Skip to content

Latest commit

 

History

History
1945 lines (1793 loc) · 348 KB

File metadata and controls

1945 lines (1793 loc) · 348 KB

当前项目状态

源码学习仓库同步记录(2026-09-23):已从可运行的完整工程补入微信小游戏转换器、YooAsset、HybridCLR/WebGL 及旧启动链所需代码依赖;导出目录改为仓库内的 wx-export/,平台 AppID/CDN 保持占位值。补齐依赖后按负责人要求不再做仓库副本的编译或导出验证。该仓库仍缺原游戏部分旧美术,不能据此宣称独立出包已验证。操作边界见 README.md。

🔖 交接快照(2026-09-21 · 新会话请只读这一节)

上一版快照(2026-09-20 的四步结构性收敛)已完成,过程见本文件历史轮次(第 1~90 轮)。以下是当前状态。

目标(当前)

负责人 2026-09-22 宣布:「全部界面的 UI 验收算通过了」,剩余的排行榜等页面由负责人自行调整。 ⇒ UI 适配主线收口,我方停止代改;当前转入"记录 + 护栏 + 可回归校验"状态。下方 §已收口 是本阶段结论。

已完成并验收

表驱动(10 表/49 英雄) · ProfilePage 收口 · BUG-018 玩家名/ID/战力 · BUG-019 部分(品质+立绘表) · BUG-020 购买进度条 · BUG-023② 道具类型语义 · BUG-026 六项(遮罩/红点/提示/底栏/阵容卡/阵容关闭) · BUG-027 三项(客服关闭/邮箱全部删除/排行榜 50 名) · 滚动列表根因修复(撑高+Clamped+顶部对齐,10 页接入) · 大厅窄高比适配(负责人已确认"大厅好了") · BUG-025 方案 C(ClientBoot 置首,构建顺序 ClientBoot → Boot → ClientShell) · 冗余阵容卡清理 · 改名链路死按钮修复 · 个性化交互(选中→确定键替换)+ 演示数据(ClientShow 全开) · 英雄详情等 6 页接入滚动修复 · Pending shipmentCanvas 底栏铺满 · ⭐ UI 适配 第 1+2 批(2026-09-22 负责人复验通过:"修好了"):英雄详情三个技能页签的文字贴图/选中框切换、后退键、等级卡位置、英雄页卡牌列表几何

验证三件套:Logs/verify-compile.ps1(三目标 0 error)· ClientSelfTest(96 项 / 失败 0)· 审计脚本 ui-contract-audit / ui-type-audit / ui-flow-matrix / ui-dead-buttons / ui-layout-audit / ui-adapt-audit{,2}

✅ 已收口:UI 适配(负责人 2026-09-22 决定)

负责人决定:排行榜等剩余页面自己调,且「全部界面的 UI 验收算通过了」。 我方停止代改,转为记录 + 护栏。 完整执行记录见 UI_ADAPT_BACKLOG.md;定稿锚点规则与"已手调值"见 UI_ANCHOR_SIGNOFF.md(§三之二、§三之三)。

已交付并通过验证的部分(可回归):

  • 第 1+2 批:英雄详情 3 个技能页签的选中态皮肤(贴图+底框切换)、后退键、等级卡、英雄页两份卡牌列表几何 —— 负责人亲验"修好了";ui-adapt-audit3 PASS 37/0、selftest-scene-mirror PASS 35/0。
  • 第 4 批 #6 排行榜(列表几何部分):战力榜 Viewport 曾塌成 0×0 ⇒ RectMask2D 失效、内容画到框外; 两份 Content 中锚 + pivot(0,1) 被横向推出;网格对齐 MiddleCenter。均已修(FixRankPageLists() + 菜单 8 + 文本补丁)。
  • 新增只读校验(可随时跑,不会改场景):
    • Logs/rank-resolve-check.ps1 —— 4 条列表几何断言 + 6 条"是否随画布高度漂移"断言
    • Logs/rank-layout-check.ps1 —— 全场景 16 份竖向列表的布局级体检(视口必须有真实面积 / 内容不得宽于视口)
    • Logs/verify-adapt12-offline.ps1 —— 一条命令跑 8 项(编译/审计/自检镜像/引用校验/补丁安全/排行榜/布局/完整性)

已知未闭环项(如实记录,不是"已完成"):

  1. RankPage排行榜 里 6 个节点仍是中锚(Challange/Ballte Mall、Explanation text frame、两份 tips、两个榜单容器) ⇒ 在 1080×1920(画布高 1339 vs 设计 1630)下会整体下移 145.5 单位,即负责人反馈的"标题出框 / 说明框与未上榜位置不对"。 修复已实现并编译通过(FixRankPageStableAnchors(),按 1630 基准回写等效 offset,设计比例下位置不变), 但未写入场景 —— 负责人选择自行调整。
  2. 两个 Viewport 的 sizeDelta 疑似互换:战力榜 (-17,0)、挑战榜 (0,0)(原属挑战榜的值跑到了战力榜)。 战力榜已不塌陷故不会出框,仅右边窄 17 单位。已记入 UI_ANCHOR_SIGNOFF.md §三之三 供负责人核对。
  3. 全场景布局体检仅剩 1 项不合格:ShopPage商店/Product page/展示卡牌Scroll View(视口宽 678.2 < 内容宽 704.9 ⇒ 左右被裁), 对应 backlog #5 商店;#7 邮箱有同源疑点。负责人已宣布验收通过,故未实施。

护栏(防止我这边把负责人的手调拽回去):

  • Logs/apply-rank-text.ps1 默认拒绝写入(exit 5),需显式 -OwnerApproved;-DryRun 仍只读可用。
  • Logs/apply-adapt12-text.ps1 检测到编辑器在跑就拒绝写入(exit 3),且不加 -ForceLayout 不碰任何位置值。
  • 编辑器工具 FixRankPageStableAnchors() 只改"还是中锚"的节点;已是贴顶锚的一律跳过。
  • 审计脚本只断言锚点类型 / 是否贴边,不再断言具体 offset(避免把手调判成失败)。

📌 本轮踩到并已记录的两个 Unity 陷阱(UI_LAYOUT_DEBUG_GUIDE.md §7)

  • 编辑器可能在跑旧编译产物:菜单项存在但方法体是上一版 ⇒ 表现成"点了只改一半"。 判别:比对 Library/ScriptAssemblies/Assembly-CSharp-Editor.dll 与源码时间戳,或直接在 DLL 原始字节里搜 你新写的日志字面量。verify-compile.ps1 绿 ≠ 编辑器 DLL 是新的(它是独立 Roslyn 编译)。 可靠解法:点回 Unity 窗口 / Ctrl+R 等编译完成,或关掉编辑器用批处理 -executeMethod。 另:别在菜单方法里调 AssetDatabase.Refresh() —— 会触发域重载把正在执行的方法打断。
  • 节点名可以字面含斜杠:Challange/Ballte Mall 是一个 GameObject 的名字,不是两级路径 ⇒ Transform.Find("Challange/Ballte Mall") 永远找不到。要用"遍历直接子节点按名字片段匹配"。 见 UI_ADAPT_BACKLOG.md(含分批表与完整执行记录)。

第 1+2 批:✅ 已验收通过(负责人 2026-09-22 亲验:"修好了")。 验证证据:三目标编译 0 error · 静态审计 PASS 37/0 · 自检断言静态镜像 PASS 35/0 · 场景完整性 OK · 文本补丁幂等; 且补丁经历了 Unity 自己的保存往返(09:27 保存后 37/0 依旧成立)⇒ 手写 YAML 补丁被证明有效。

第 4 批 #6(排行榜):✅ 已修复并验证(2026-09-22)。

  • 真根因(实读,非估算):排行榜页里放了两份位置完全相同的列表容器(Challenge List 挑战榜 / Battle Power Ranking 战力榜),由底部两个按钮切换显隐。两份配置不一致:

    1. 战力榜 Viewport 锚点 (0,0)-(0,0) + sizeDelta (0,0) ⇒ 视口塌成 0×0,它的 RectMask2D 什么都裁不住 ⇒ 内容按自家位置画到框外 = 负责人说的"两个 ranking 穿过下方 UI 底框"; 挑战榜那份虽是 (0,0)-(1,1) 但 sizeDelta.x = −17(同样不对)。
    2. 两份 Content 都是中锚 + offset x ≈ 376 而 pivot 是 (0,1) ⇒ 配合运行时贴顶后横向被推出去 = "上方 UI 错位";且 GridLayoutGroup.childAlignment 还是 MiddleCenter(4)(应为 UpperLeft)。
  • 修法:ClientShellStructuralRepair.FixRankPageLists() + 菜单 8. 排行榜列表修复: Viewport 贴满 Scroll View、Content 改左上锚 + offset 归零、网格对齐 UpperLeft。不动尺寸/行高/底栏。

  • 验证:Logs/rank-resolve-check.ps1 → RANK CHECK: OK;ui-adapt-audit3 PASS 37/0; selftest-scene-mirror PASS 35/0;三目标编译 0 error。

  • ⚠️ 本轮最耗时的坑(已记入 UI_LAYOUT_DEBUG_GUIDE.md §7):那个编辑器进程始终没重新编译, 点菜单 8 多次都只跑了旧代码(Content 变了、Viewport 没变)。最终用 批处理(Logs/repair-rank-batch.ps1,必定从源码全新编译)+ 文本补丁(Logs/apply-rank-text.ps1 补唯一漏项) 两条互补手段落地。另:判断"工具到底改没改"要重新解析文件内容,不能只看 mtime。

  • 同源线索(下批用):Logs/rank-layout-check.ps1 新增全场景 16 份竖向列表的布局级体检 (视口必须有真实面积 + 内容不得宽于视口),现只剩 1 份不合格:ShopPage商店/Product page/展示卡牌Scroll View (视口宽 678.2 < 内容宽 704.9 ⇒ 左右被裁)—— 正是 backlog #5 商店「道具卡牌的 Content 有问题」,病根已定位。

  • 第 1 批(P0 回归)· 英雄详情 3 个技能页签 —— 真根因(三层): ① 层级是 Toggle/Background/Checkmark(Checkmark 是 Background 的子节点); ② 技能区/{天赋,秘技,终结技}选中框.png 全工程零引用; ③ 三个底框贴图接错(天赋挂秘技的、秘技挂天赋的且 m_Enabled: 0)。 修法:ClientHeroDetailToggleSkin 按选中段换底框 sprite + 文字恒显;工具写入贴图与绑定;ClientSelfTest 防回归断言。

  • 第 2 批:① 后退Button 改左上锚(中锚在 1339 画布落到 y=-35~26);② leftmiddleCanvas 贴 downCanvas 顶部 (原中锚 y=730~957 与 upCanvas/right 重叠)+ 属性条联动下移;③ 英雄页两份卡牌 Content 改左上锚 (原 offset (-299,503) ⇒ 整列跑到滚动框左外、压住『弹珠』)。负责人复验后又自己微调了这三处的 offset, 已记录进 UI_ANCHOR_SIGNOFF.md §三之二(勿被工具回退)。

  • 负责人下一步(2 步):① 先让编辑器重新导入(点一下 Unity 窗口 / Ctrl+R)—— 本轮实测那个进程的 Library/ScriptAssemblies/Assembly-CSharp.dll 停在 17:43、Assembly-CSharp.csproj 不含新脚本,即内存里还没有这个类型; 导入成功后再进 Play 复验(若仍报缺失脚本,点菜单 Client → 结构修复 → 7. UI 适配 第 1+2 批 即可修好); ② 要跑编辑器内自检时先关编辑器,再跑 powershell -NoProfile -ExecutionPolicy Bypass -File Logs\verify-adapt12.ps1。

  • 不打开 Unity 也能跑的三道校验(全绿):Logs/ui-adapt-audit3.ps1(PASS 37/0)· Logs/selftest-scene-mirror.ps1(ClientSelfTest 场景断言的静态镜像,PASS 35/0)· Logs/check-handoff-refs.ps1(皮肤组件每个引用都指向真实对象/资源,OK)。

  • 静态审计:Logs/ui-adapt-audit3.ps1(只读,退出码可判定)。修复前 PASS 26 / FAIL 11 ⇒ 修复后 PASS 37 / FAIL 0。

  • 自检镜像:Logs/selftest-scene-mirror.ps1(只读)= ClientSelfTest 场景断言的静态等价物,PASS 35 / FAIL 0; 编辑器内的 ClientSelfTest 仍需关掉编辑器后跑(Logs/verify-adapt12.ps1)。

  • ⚠️ 教训(已记入 UI_LAYOUT_DEBUG_GUIDE.md §7):审计脚本不要硬编码 transform fileID —— 本轮第一版把两份卡牌 Content 的 id 写错(268087959 其实是图鉴页),于是英雄页那份漏改; 改用"按真实层级走路径"后才暴露。路径式查找才是可靠做法(C# 工具一直用路径式,所以一直是对的)。

  • 场景写入方式(重要):编辑器当时占着工程、批处理起不来,因此本轮用 Logs/apply-adapt12-text.ps1 把与编辑器工具完全相同的值写进场景 YAML,并用"写入后重新解析 + 逐条断言贴图/锚点 + Logs/check-scene-integrity.ps1 对比 document 集合"三重护栏保证没写坏;编辑器工具仍是权威路径且幂等。

系统性根因(记住这一条)

ClientCanvas 参考 753×1630 + matchWidthOrHeight = 0(按宽)⇒ 宽恒 753、高 = 753×(H/W): 1080×2280→1590 · 1080×2160→1506 · 1080×1920→1339。 ⇒ 横向稳定,纵向全靠贴顶/贴底/拉伸;凡"固定高度或固定纵向位置"的内容在矮画布上必然溢出/被裁/重叠。

必读文档(新会话按序读)

  1. UI_ADAPT_BACKLOG.md —— 11 项反馈 + 分批计划 + 第 1+2 批的完整执行记录(真根因/修法/验证状态)
  2. UI_LAYOUT_DEBUG_GUIDE.md —— 五步排查法 + 现象→锚点嫌疑对照表 + 踩坑清单
  3. UI_ANCHOR_SIGNOFF.md —— 已定稿的锚点规则 + 4 条微调注意事项
  4. BUG_TRACKER.md(BUG-025~BUG-027)· Assets/Client/MODULE.md §18(审计方法)· Assets/Client/UI/HeroDetailPage/MODULE.md(技能页签真实层级)
  5. 移植侧:WEBGL_B0_GATE.md / WEBGL_B1_BUILD.md / WEBGL_B2_DIAGNOSTICS.md / HANDOVER_PLAN.md

操作要点(都是踩过的坑)

  • 跑批处理 Unity 必须先关掉编辑器(否则 HandleProjectAlreadyOpenInAnotherInstance 崩溃,退出码 0x40000015);子进程临时传 ALLUSERSPROFILE=C:\ProgramData
  • 场景节点路径必须带完整前缀 ClientCanvas/PopupLayer/...;中文名在 YAML 里是 \uXXXX 转义(比对前反转义);prefab 实例内部节点静态扫不到;GameObject.Find 找不到未激活对象
  • .ps1 里不要写中文字面量(PowerShell 按 ANSI 读会乱码 ⇒ 用字符码或从文件读); 另注意 $ID 是 PowerShell 内置只读变量(用 $NODEID),且 $arr = @($a + 'x', $b + 'y') 会因逗号优先级被当成一个元素 ⇒ 每个元素要各自加括号
  • 场景改动前先备份到 Logs/ClientShell.before-*.unity.bak;修正要写进幂等的编辑器工具,负责人可点 Client → 结构修复 → 2. 执行结构修复 自行应用
  • Logs/ 下的脚本、日志与 *.unity.bak 都是证据,不要删

🔜 移植任务交接(另开会话专供 —— 先读这一节 + HANDOVER_PLAN.md + TCP_WEBGL_HANDOFF.md)

🔴 2026-09-22 晚 · 移植会话最新状态(新会话先读这一块)

旧决定 D1 = 不动入口(Init.cs 不改、ClientShell 不进 Build Settings)已被 2026-09-22 的实际工作推翻, 但负责人【未】给出长期授权。 📌 授权状态(负责人 2026-09-22 明确口径):本会话对 Init.cs / Boot.unity / 构建清单 / MiniGameConfig.asset 的改动是【经负责人逐次口头许可】进行的;后续任何改动仍需【逐次确认】,不得视为已获长期授权。 ⇒ 新会话若要再动这些文件(含 Init.cs 的场景加载改动),必须先向负责人确认。 可自由改动、无需单独确认的:Logs/ 下的脚本与文档、纯 Markdown 文档。

进度:移植目标 B 的「可构建 / 可启动 / 可操作 / 真实会话」四项全部达成

目标 状态 关键证据
可构建 ✅ 一条命令 8 分钟出包,WXConvertCore.DoExport 返回 SUCCEED
可启动 ✅ 微信开发者工具里进入客户端界面
可操作 ✅ 负责人确认「各界面跳转和功能没问题」
真实会话(TCP) ✅ 网关成功 → TCP建连成功 → 握手成功 → 游客登录成功 → 英雄数据接收并解析成功:英雄=4,英雄组=1 → 成功退出 TCP
真机 ⬜ 未做 首页修复后再推(HANDOVER_PLAN.md §5 B2 矩阵)

✅ 原「唯一阻塞:首页(ClientShell)不显示」已修复并在容器内复验通过(2026-09-22 晚)

根因:ClientShell 不在 YooAsset 寻址清单里 (收集器只收 Assets/HotUpdateResources/*,没有 Assets/Client/*), 而 Init.cs:192 用 YooAssets.LoadSceneAsync(名字) 按地址加载 ⇒ Failed to mapping location to asset path : ClientShell ⇒ 场景没加载。 与 BUG-025 同源("场景在清单外"),只是这次场景在 Build Settings 里、却不在 YooAsset 清单里。

复验证据(负责人导出的微信开发者工具 Console,13,647 行,只读副本本会话已核对): 加载Init → 首个场景:ClientShell → 首个场景加载方式判定:构建清单场景数=2,目标=ClientShell(L2875) → 全文件 0 处 Failed to mapping location to asset path / Failed to load scene(对照修复前) → [配置表] … Hero 可用 49 / 表内 54(L3212)= 客户端组合根已运行 → [ClientProfileNavigationController] ActiveVisualCanvases:count=7,paths=ClientCanvas | ClientCanvas/PagesLayer/MainPage主页/…(L12578)= 首页 UI 已激活 → 资源包初始化成功 + Updated package Version : 2026-09-22-1420(L2494)= YooAsset 走根目录正常 → TCP 六包齐全(网关成功 → TCP建连成功 → 握手成功 → 游客登录成功 → 英雄数据 英雄=4/英雄组=1 → 成功退出) → 无异常、无缺失脚本;运行 84s,卡顿率 3.6%

  • 完整根因 + 两个修复方案对比 → HOME_PAGE_SCENE_FIX_OPTIONS.md
  • 面向非技术同事的解释版 → D:\Users\Administrator\Desktop\notd\首页不显示-根因说明.md
  • TCP 断链的完整分析(已修复,含证据链)→ TCP_NETWORK_BREAK_ROOTCAUSE.md

✅ 负责人 2026-09-22 已选定并授权:方案 A(改用 SceneManager.LoadSceneAsync 加载 ClientShell)。 ✅ 2026-09-22 晚已实施完成(唯一文件 Assets/Main/Init.cs,备份 Logs/Init.cs.before-planA.bak): 新增 LoadFirstSceneAsync(),两处调用点(运行时原 L192 + OnCompleted() 原 L518/编辑器分支)都接入, 内置场景起不来时回落 YooAssets.LoadSceneAsync(原行为逐字保留)。 ⚠️ 交接文档原先只提到 L192,漏了 L518 —— 不改编辑器分支,编辑器里 Play Boot 仍进不去首页。 详细记录与本次 OSS 重传清单 → HOME_PAGE_SCENE_FIX_OPTIONS.md §九 · Logs/webgl-port/OSS_UPLOAD_MANIFEST-planA.txt ✅ 已复验通过(2026-09-22 晚):容器内场景加载成功且首页 UI 已激活(证据见本条上方); 负责人已确认「首页肉眼可见」;OSS 上两个新首包文件(124561790dc5891e…data…br / f646dc49cc019398…wasm…br)实测均 200。 ⚠️ 新发现(已取证,是否修待决策):方案 A 里预留的 首个场景已加载(SceneManager 内置场景) 日志没有打印 (全文件 0 匹配)⇒ Init 协程在 LoadSceneMode.Single 切场景时随 Boot 场景一起被销毁, Init.cs 中"加载后"那段(ApplyWebGLRenderCompatibilityToLoadedCameras() + WebGLFirstScreenDiagnosticsHost)不会执行 (日志中 WebGLFirstScreen 同样 0 匹配)。这是既有设计问题、非方案 A 引入,实测渲染正常; 要修需再次动 Init.cs(按授权口径须负责人逐次确认)。 ✅ A4 已获授权并已实施(2026-09-22 晚):新增 Assets/Main/WebGLPostSceneLoadRunner.cs (跨场景宿主,不声明任何 [SerializeField],避免字段布局不一致导致构建失败), Init.cs 把"加载后"两个动作(相机兼容处理 + 首屏诊断)改为由它在 SceneManager.sceneLoaded 时执行一次; Init 自身生命周期未改(探针仍依赖"Boot 场景会被卸载"这一前提)。 已编译 0 error、已出包 exit=0;构建标识 DATA_FILE_MD5=356e1b81e1be0bb4、CODE_FILE_MD5=2edcf1b6d32ca4ab。 重传清单 → Logs/webgl-port/OSS_UPLOAD_MANIFEST-A4.txt;真机手册 → WEBGL_B2_REALDEVICE.md。 ✅ 已容器复验通过(2026-09-22 晚,负责人 Console 截图): 首个场景已加载(sceneLoaded 事件):ClientShell,模式=Single;由跨场景宿主执行加载后处理。

  • WebGL 渲染兼容性已应用:Client UI Clear Camera / WebGL 渲染兼容性已注册:已检查 1 台相机;后续相机将在 URP 渲染前处理。
  • [WebGL 首屏诊断 1s] scene=ClientShell, loaded=True, resolution=1170x2532, cameras=1, canvases=72, pipeline=Universal Render Pipeline Asset, skybox=Default-Skybox, reflection=none
  • [WebGL 首屏相机 1s] … hdr=False, post=False(说明兼容处理确实生效)。 ⬜ 待留意:本次 Console 计数为 1 error / 20~21 warnings;10s 那条诊断未在截图范围内。 已知非致命项(404 版本探测 / ETC 纹理回退 / 开发阶段上报提示)见 WEBGL_B2_REALDEVICE.md §五,未取证的 error 不当成已知项。

本会话已完成并落地的改动(全部有备份,可回滚)

文件 改动 目的
Assets/Client/Runtime/ClientTcpConnectionProbe.cs 9 个 [SerializeField] 移出 #if UNITY_WEBGL 修构建级根因:字段集在编辑器/播放器不一致 ⇒ script class layout is incompatible
ProjectSettings/EditorBuildSettings.asset 清单改为 Boot(0) → ClientShell(1)(移除 ClientBoot) 回归历史启动链,让 Boot/Init 能加载 HotFix
Assets/Main/Boot.unity ClientStartScene: ClientShell;Default/FallbackHostServer → 新 CDN 首个场景指向客户端
Assets/Main/Init.cs 新增 ClientStartScene 字段 + ResolveFirstSceneName()(默认空 = 原行为 LoginScene) 可配置加载目标,不破坏原逻辑
Assets/WX-WASM-SDK-V2/Editor/MiniGameConfig.asset CDN → .../WebGL/pinball-client 换到干净 CDN 目录
Assets/Client/Runtime/ClientBootLoader.cs 移除探针挂载 + 标注弃用 它已不在启动链
Assets/Client/Editor/ClientWebGLBuildCommand.cs 新增:命令行构建 6 步管线 + 启动链校验 一键出包
Assets/Client/Editor/ClientSelfTest.cs 拆出 RunAllCore()(不结束进程) 供管线内调用

新增的工具与脚本(都在 Logs/webgl-port/)

文件 用途
run-pipeline-2phase.ps1 一键出包:pwsh -File ... -PackageVersion <版本>(两阶段,约 8 分钟)
upload-to-oss.ps1 ossutil 上传(含上传后自检);-DryRun 可只看命令
OSS_UPLOAD_MANIFEST.txt 上传清单,含路径、逐项文件名、自检 URL

(wx-auto/ 自动化探针目录已于 2026-09-22 清理删除,连同 2 个被取代的旧脚本与 17 个空日志;见第 3 条坑。)

⚠️ 本会话踩过、务必记住的坑(下个会话不要再踩)

  1. ClientTcpConnectionProbe 的 [SerializeField] 不能放在 #if UNITY_WEBGL 内。 否则编辑器侧与播放器侧字段布局不一致,Unity 直接拒绝构建: Error building player because script class layout is incompatible between the editor and the player. 字段本身不依赖 WebGL 类型,声明放外面;只把用它们的逻辑放进 #if。
  2. YooAsset 的资源放在 CDN【根目录】,不是 /Assets/。 Init.cs:476-482 → GetRemoteMainURL(fileName) => $"{host}/{fileName}", 而 host = .../WebGL/pinball-client(根)。 那个 /Assets 层级是微信 SDK 首包(webgl.data / wasm / 纹理)用的,与 YooAsset 无关。 → 同一类路径错配本会话踩了两次(先少一层、后多一层,即 BUG-015 与本次)。 教训:上传后必须按客户端实际请求的 URL 逐个自检,不能靠推断。
  3. 不要试图用 miniprogram-automator 读小游戏的 Console。 实测:cli auto --auto-port <port> 能握手成功,但 evaluate / systemInfo / currentPage 全部超时, 且小游戏没有 getConsoleMessages API。已验证为死路,不要再花时间。 (过程产物 Logs/webgl-port/wx-auto/ 已删除,勿重建。另外:用 cli auto 时不要连带 kill 父进程, 会杀掉开发者工具主进程 —— 本会话踩过。)
  4. 微信开发者工具的服务端口开关:设置 → 安全设置 → 服务端口。开着 cli 才能用。 但即使开着,对小游戏也只能握手、不能查数据。
  5. 改 CDN 目录必须同时改两处:MiniGameConfig.asset 的 CDN 与 Boot.unity 的 DefaultHostServer / FallbackHostServer。改完必须重跑转换(game.js 里写死了 DATA_CDN)。
  6. 只调 UI 时,重跑构建后通常只需重传 data.br 一个新文件: 实测连续多次构建 wasm.br 哈希不变(未改 C# 时);改了构建清单或代码 wasm.br 才会变。
  7. edit 工具会剥掉 UTF-8 BOM(CRLF 保留)。改 BOM 文件后要复查并手工补回。
  8. 本机一律用 pwsh(PowerShell 7);5.1 会把无 BOM 的 UTF-8 脚本当 ANSI 读,含中文直接解析失败。

下次开工的第一步

  1. 读本节 + HOME_PAGE_SCENE_FIX_OPTIONS.md §九(方案 A 已实施,并在容器内复验通过);
  2. ✅ 首页阻塞已解除:新 data.br/wasm.br 已上传 OSS 并实测 200,容器 Console 证据见本节;
  3. ✅ 真机已通过(2026-09-22):Android 1080×2400 真机、A4 构建(DATA_FILE_MD5=356e1b81e1be0bb4)。 未开调试被 downloadFile:fail url not in domain list 拦下;开「调试」后资源下载通过 → 首页正常渲染、编队页/新手任务页可跳转、TCP 六包在真机全部走完(英雄=4,英雄组=1)、RT-FPS 50~63 / Jank 0 / Stutter 0.00%、无致命异常。 ⇒ 阶段 B 五项(可构建/可启动/可操作/真实会话/真机)全部达成;实测记录见 WEBGL_B2_REALDEVICE.md §八。
  4. ⬜ 剩余:B2 矩阵深度项(安全区与遮挡、返回栈压测、弱网/断网、后台切回、内存峰值未采集); 以及生产化前置——正式版/体验版必须配合法域名,而裸 IP 的发现服务与网关无法加白,需服务端侧提供 HTTPS 域名(属服务端范围)。
  5. 📖 移植侧总入口(阶段 C):WEBGL_MINIGAME_HANDBOOK.md(环境事实 / 一键出包 / 上传规则 / 容器与真机取证 / 排查表 / 坑清单 / 授权边界); 模块级 → Assets/Main/MODULE.md;缺陷与风险 → BUG_TRACKER.md(BUG-025 已闭环、新增 BUG-028 与 RISK-021); 阶段状态与决策 → DEVELOPMENT_WORKFLOW.md「2026-09-22 移植阶段状态与决策记录」。
  6. ⬜ 待决策(需授权动 Init.cs):是否修「Init 被 Single 模式销毁 ⇒ 加载后诊断/相机兼容处理不执行」;
  7. ⬜ 待确认:UI 后续是否还会频繁调整(决定是否值得上方案 B,换回 UI 热更能力)。

📌 2026-09-20 只读基线仍有效:WEBGL_PORT_BASELINE.md(工作区差异 / 启动链实测 / 编译验证 / TCP 日志证据 / 资源与 OSS 实测 / 风险主次)。 该文件是只读盘点产物,其余内容(UI 收敛进度)由原会话维护,两者不冲突。 三条否定性事实仍然成立,但第 ① 条已被本会话消除: ① ClientShell 没有任何运行时入口 → 已解决(已进 Build Settings,Init.ClientStartScene 指向它;仅剩 YooAsset 寻址问题); ② GameController.StartWebGLLobbyPreview 是死代码(全工程零调用方); ③ WebGL 热更 HotFix.dll.bytes 曾落后——已在本会话重新生成并纳入管线。

按序读这六份:AGENTS.md(§4 是 WebGL/黑屏的取证纪律)→ HANDOVER_PLAN.md(A/B/C 三阶段总纲 + 三层架构目标)→ TCP_WEBGL_HANDOFF.md(TCP 那条路的权威记录) → TCP_NETWORK_BREAK_ROOTCAUSE.md(TCP 断链的完整分析与修复) → HOME_PAGE_SCENE_FIX_OPTIONS.md(首页阻塞:根因 / 方案对比 / §九 实施与复验,已闭环) → WEBGL_MINIGAME_HANDBOOK.md(移植侧总入口) → Assets/Client/MODULE.md。

⚠️ TCP_WEBGL_HANDOFF.md 当前不在工作区(git status 显示 D,即被 git 追踪但工作区已删;不是本会话删的, 也不在本会话的清理范围内)。它是本文件多处引用的 TCP 权威文档,新会话需要它时按下面任一种取:

  • 从 git 恢复:git checkout -- TCP_WEBGL_HANDOFF.md(HEAD 内容 105 行,完整)
  • 或读副本:D:\Users\Administrator\Desktop\notd\TCP_WEBGL_HANDOFF.md(105 行,内容一致)
  • 其它工程副本:D:\unity project\pinball-learning-{code,source,source-clean}\TCP_WEBGL_HANDOFF.md

若要恢复,请先确认它是有意删除的(AGENTS.md §3:不清理负责人已有改动)。

网络:已走通,且有权威文档 —— 不要重新发明

  • 平台 API 是微信 TCPSocket(WXBase.CreateTCPSocket() + OnConnect/OnError/OnClose/OnMessage/Write)—— 不是 WebSocket,因此不需要 TCP-over-WS 网关。
  • TCP_WEBGL_HANDOFF.md 明确记录:历史日志曾证明「网关获取 → TCP 建连 → 握手 → 游客登录 → GetHero 收包解析」全链路跑通;后来被临时改动弄坏了探针。
  • 2026-09-22:该全链路已在微信小游戏容器内再次跑通,六包齐全(见本节「最新状态」表)。修复过程与证据链见 TCP_NETWORK_BREAK_ROOTCAUSE.md。
  • 探针 = Assets/Client/Runtime/ClientTcpConnectionProbe.cs(挂在 Boot.unity 的 Init 对象上,独立验证用,不替代原业务登录流程)。它靠自身 StartPersistentProbe() 迁移到 DontDestroyOnLoad 对象以存活过场景切换。
  • ↔ 探针的反射目标 NetController / SysDefines 在 HotFix 程序集里,而 HotFix 只有 Boot/Init 能加载(Init.cs:216 Assembly.Load)。 ⇒ 因此探针必须与 Init 同场景;任何"绕过 Boot 的客户端独立入口"都会让探针 15 秒超时。这是一条硬约束。
  • ⚠️ 文档明令的硬约束:① 不得再用“直接引用 HotFix 类型”解决反射问题(会复发 IL1005 / 程序集解析失败);② 不得改 IP / 端口 / 服务端 / 账号 / token / YooAsset 基础设施 / 微信 SDK / 项目设置(例外:负责人 2026-09-22 已授权为移植目标修改 MiniGameConfig.asset 的 CDN 与构建清单);③ 没有新日志证据时不得反复改端口、随机改协议字段或宣称成功。
  • 成功判据是带前缀的日志([TCP客户端] …),末尾必须出现“英雄数据接收并解析成功”+“成功退出 TCP”;禁止把“已建连 / 已握手 / 已登录 / 连接关闭”当作整体成功。
  • 收尾流程:run-pipeline-2phase.ps1 → 按 OSS_UPLOAD_MANIFEST.txt 上传(YooAsset 文件放 CDN 根目录)→ 清开发者工具缓存 → 重跑 → 回传完整 [TCP客户端] 日志。

基础设施:已就位(2026-09-20 代理只读清点,勿重复搭)

项 证据
微信 SDK Assets/WX-WASM-SDK-V2(含 Editor/WXConvertCore.cs)
WebGL 资源包 Bundles/WebGL/DefaultPackage 719.5 MB,OSS/CDN 链路已通
热更 HybridCLRData/{Assemblies,HotUpdate,il2cpp,StrippedAOT,LocalIl2cpp…} 有 WebGL 数据
原生插件 工程内已有 .jslib / .wasm
XLua 风险 ≈ 0 WebGLPlugins/ 有完整 Lua 5.3 C 源(能在 WebGL 编译);但 Assets/Lua 只有 7 个文件 / 1.2 KB ⇒ Lua 基本没用,逻辑是 C#

难度评估(依据上述证据,不是猜测)

  • 目标 A「真机主流程跑稳」≈ 1.5 ~ 3 周;目标 B「可提审(全机型 / 弱网 / 性能 / 合规)」≈ A 之后再 2 ~ 4 周。
  • 风险排序:① iOS 真机 WebGL2 / 内存 / 纹理压缩;② 包体与首启下载体验(首包 ≤ 4MB、wasm 走 CDN);③ HybridCLR AOT 泛型补齐(新 API 会冒一次);④ UI 适配(刘海 / 长屏 / 安全区);⑤ 音频解锁 / 触摸 / onShow-onHide。
  • 待负责人回答(直接改工期 ±1 周):那次 TCP 成功是真机还是开发者工具?BUG-009(首屏黑屏 + URP shader)与 BUG-013(app.json 启动页)现在是否真的闭环(tracker 仍标“调查中”,确认后请关闭)。

加载页:UI 侧已备好,只等启动流程接线

  • 新增 Assets/Client/Runtime/ClientLoadingService.cs:Begin(text) / SetProgress(0..1) / SetProgressPercent / SetLoadingText / Complete() / Hide();它显式接管 SystemLayer 开关(该层恒 inactive,而 加载Page 自身 activeSelf=1,一激活就全屏显示)。
  • 接线点 = Assets/Main/Init.cs 的资源下载:OnDownloadProgressUpdateFunction 第 405 行已算出 progress,目前只 Debug.LogError(progress)(每帧刷 error);把注释掉的 EventTrigger 换成 ClientLoadingService.SetProgress(...) 即可。
  • ⚠️ Init.cs 属启动 / 原公司代码边界,UI 会话未动它。
  • 演示入口(Play 模式):菜单 Client/加载页/演示 5 秒加载(走 ClientLoadingService)。

⚠️ 一处架构偏离,需要负责人定(诚实记录) HANDOVER_PLAN.md §3 规定 SystemLayer 承担「Loading / 阻断遮罩 / Toast / Tips」,但 SystemLayer 在场景里恒 inactive;因此 2026-09-20 把全局 Toast 与 ClientSystemFeedback 移到了 ClientCanvas/ToastRoot(否则 Toast 不显示、StartCoroutine 直接报错)。要么按 plan 恢复(让加载/提示流程显式控制 SystemLayer.SetActive),要么修订 plan 把 Toast 归到 ClientCanvas —— 请负责人定,别两边都写。

UI 侧现状(新会话别重做)

  • 已整页验收:HeroPage英雄、FormationPage编队;ShopPage商店 / MailPage邮件 早已模板化。
  • 已验收细节(编队):点卡即切换(自动补编号最小的空位 / 再点移出且不补位 / 满员不加入 / 同队不可重复英雄);队内编号 1..3 显示在选卡上(数字贴图 Assets/Client/UI/HeroDetailPage/Sprites/属性icon/新建文件夹/数字/0..9.png,换 sprite 实现);空槽保留格位、清空卡面;选中点 用 alpha 高亮;确认键 = 确认并返回。
  • 未做 / 阻断:ActivityPage 结构收敛(行为已正确,需一次场景写入)、ProfilePage(真列表无数据源,见 MODULE.md §14)、RankPage 等;元素筛选负责人明确不做。
  • 全局 Toast 已可用;ClientPopupService._maskRoot(弹窗遮罩槽位)仍为空。

📦 配置表来源已确认(2026-09-20,负责人指向 D:\Users\Administrator\Desktop\弹珠配置)

这是什么:游戏权威配置(不是草稿)。excel\1服-弹珠\ 下 20 张 .xlsx(Hero 140 KB、Resources、Skill、Potency、MapCopy、Item、Head、HeadFrame、Badge、Nameplate、Title、Energy、Dan、Coefficient、Monster、MonsterTemplate、PinBallRoom、RandomHero、PotencyLevel、Audios、ServerControl),并为 Client / Server 各生成 4 种产物:Cs(生成类)/ Json(真实数据)/ Lua / Cpp。同目录 弹珠配置\tools 是导出器与协议生成器(jbproto,含 GlobalProtocols.xml、ClientPF.xml 等协议定义与 175 KB 的 ClientPF.cs)。

它解开了哪些此前的"未定义/阻断"

  • MODULE.md §14 关于个人中心真列表的"条数来源 / 拥有规则 / 图标映射 / 排序全部未定义" —— 其实全有定义:Head / HeadFrame / Badge / Nameplate / Title 五张表同一形状:Id / Name / Desc / Sorting(排序)/ ClientShow(前端是否显示)/ NotUnlockedClientShow(未解锁是否显示)/ ResId(美术资源);Head 用字符串 Avatar 代替 ResId。
  • 排行榜精灵表(BUG-019):THero 提供 QualityIcon_3..6、ElementIcon_1..6、CatapultIcon_1..3、Avatar(HeroAvatar_13001)、Portrait1/2(HeroPortrait_13001_c/_d) —— 美术按名字约定,可按名解析,不必手拖数组。
  • 元素筛选:THero.Element 是 int 1..6(不是 "Fire"/"Water")⇒ 编队页那 7 个按钮 = 全 + 6 元素,数量吻合,"映射未定义"这条可解(只差 int↔中文名的顺序确认)。

真实契约 vs 我们前端当前的假设(需对齐)

项 Assets/Client 现状 权威契约
英雄 Id string "hero-001" int(如 13001)
元素 string "Fire"/"Water" int 1..6 + ElementIcon
品质 / 弹射 未用 int 3..6 / int 1..3 + Icon
英雄规模 本地模拟 9 个 Hero.json 54 行,且带 ClientShow 前端可见门
立绘 / 头像 未接 名字约定 HeroAvatar_<id> / `HeroPortrait__c

发现的缺口(已核实)

  1. 工程 Assets/Scripts/Table/ 缺 4 个生成类:TBadge / TNameplate / TPotency / TPotencyLevel —— 配置目录里有,工程里没有;且 TableLoadConfig.TableHelperTypeList 的 17 张清单里也没有它们 ⇒ 徽章 / 铭牌永远没有数据源(这不是"待确认",是缺文件)。
  2. 工程里一个表 JSON 都没有(全 Assets 无 Hero.json 等,也没有 Resources/Table 目录)⇒ TableLoadHelper 走"本地配置表缺失,使用空表继续"分支(TableLoadHelper.cs 第 233~241 行),17 张表全空。当前 ClientShell 场景日志里该警告 0 次,因为表加载挂在启动流程(TableManager / GameController)上,本场景不跑。
  3. 待验证的加载契约:THero 等类把 levelCap / HpBase / Skill … 声明为 JArray,而 JSON 里是字符串("levelCap":"[10,20,30,40,50]")⇒ 加载器必须做转换,否则这条会在接真表时炸。

待负责人定

  • 表的投放:两者(已定,见下「第 50 轮」)
  • 是否补齐那 4 个生成类并加入 TableLoadConfig 清单?(已定:可以)
  • Assets/Client 与表的边界(已定:表驱动)
  • 元素 int 1..6 ↔ 中文名(光/水/土/风/火/暗)的顺序以哪个为准? ← 仍未定

第 50 轮 · 表驱动落地(已执行并验证)

  • 负责人三项决定:表投放 = 两者(本地进包兜底 + OSS config.pkg 热更);Assets/Client = 表驱动;补齐 4 个生成类 = 可以。
  • 补齐/修正工程表类(Assets/Scripts/Table/,均只增不删,因为原项目代码在用):
    • 新增 4 个此前缺失的生成类:TBadge / TNameplate / TPotency / TPotencyLevel(从配置目录拷入,using 规范成工程的 LC.Newtonsoft.Json.Linq),并加入 TableLoadConfig.TableHelperTypeList(原清单 17 张 → 21 张)。
    • THero:补 Portrait1(卡面) / Portrait2(出战位);保留旧 Portrait —— Assets/Scripts/BNRoom/UI/MarbleUI.cs:1148 仍在读它,删掉会破坏原项目编译。
    • THead:补 Desc / Sorting / ClientShow / NotUnlockedClientShow + Avatar(新表以资源名替代整型 ResId),保留 ResId;THeadFrame / TTitle 同样补前四个字段。 ⚠️ 这三个类的工程版本是旧版(只有 Id/Name/ResId),不补就没有 ClientShow/Sorting/NotUnlockedClientShow —— 「表驱动」的过滤与排序规则全依赖它们。
  • 本地表进包:21 张 JSON 落到 Assets/Resources/Table/(合计 174.1 KB)。已确认 Assets/Resources 不在 YooAsset 收集路径里(收集的是 Resources_HotUpdate/ 与 HotUpdateResources/)⇒ 不会产生 BUG-012 那种重复资源地址。
  • Client 侧表驱动:新增 IClientConfigService + ClientConfigModels(ClientHeroConfig / ClientCollectionConfig / ClientCollectionKind)+ TableClientConfigService,并在 ClientServices 暴露 Config。UI 只依赖接口,不直接引用原项目表类型。
    • ⚠️ 实现走反射,不直接引用 HotFix 类型:表类在 HotFix 程序集(Assets/Scripts/HotFix.asmdef),而 Assets/Client 属 Assembly-CSharp。TCP_WEBGL_HANDOFF.md 明确禁止直接引用(会复发 IL1005);且工程里的 HotFix.ref.dll 是上次构建产物,直接引用会读到旧成员(本轮实际踩到:THero 少了 Portrait1/2 导致 23 个编译错误)。
  • 新增只读探针 Assets/Client/Editor/ClientTableProbe.cs(菜单 Client/配置表/打印各表行数 + -executeMethod 两用,全程反射):把每张表的真实行数打出来。它是"表到底加载没有"的唯一可靠入口 —— 底层 TableLoadHelper 缺表时只打一条警告就按空表继续,UI 会安静地什么都不显示。
  • ⚠️ 重大发现:磁盘缓存 config.pkg 优先级高于本地 json。 TableLoadHelper.LoadFromLocalPackage() 先看 {persistentDataPath}/config.pkg,存在就用它,本地 Resources/Table/*.json 只是"没有缓存时"的兜底。 实测:C:\Users\Administrator\AppData\LocalLow\xiaoshi\xiaozhen\config.pkg(2026-09-03,9.3 KB,9/3 WebGL 调试遗留)一直盖着新表 ⇒ 探针只报 THero = 12 行(而非 54)。 已备份到 Logs/config.pkg.bak-20260903 后删除,重跑探针 ⇒ THero = 54 行、21 张表全部可用(0 空表 / 0 缺失)。 含义:只更新本地 json 不会生效,只要还有旧缓存;生产靠 LoadFromNet(ossUrl, md5) 按 md5 覆盖缓存(localPackageMd5_ != remoteMd5 才下载)。小游戏真机同理。
  • 表行数实测(Logs/table-probe-2.log):Hero 54、Resources 256、Potency 68、Skill 33、Audios 29、MapCopy 24、Monster 15、MonsterTemplate 12、HeadFrame 9、Title 9、Item 9、Head 6、Badge 6、Nameplate 5、RandomHero 4、PotencyLevel 3、其余 1 行(Energy/Coefficient/PinBallRoom/ServerControl/Dan)。ClientShow=1 的英雄有 49 个。
  • 验证证据:① Logs/verify-compile-tables3.log Roslyn 三目标 0 error;② Logs/table-probe-2.log 命令行 Unity 全工程编译 0 error(覆盖 HotFix,满足 AGENTS.md 对编译输入改动的要求)+ 21 张表行数;③ 探针 0 次「本地配置表缺失」。
  • ⚠️ 工具盲区(已确认,供后续会话):Logs/verify-compile.ps1 的编译清单取自 Library/Bee/artifacts/*/Assembly-CSharp.rsp,只覆盖 Assembly-CSharp(Assets/Client),Assets/Scripts(HotFix 程序集)不在其中 —— 它引用的是旧 HotFix.ref.dll。所以改 Assets/Scripts 必须用命令行 Unity 编译或表探针那条路验证,否则会看到"改了却不生效"的假象。
  • 下一步(UI 侧,等负责人放行):把 HeroPage / ProfilePage / RankPage 从本地模拟切到 ClientServices.Config(54 英雄、真头像/徽章/称号),玩家状态仍走 IClientDataService;ClientPlayerProfile.EquippedTitleId/EquippedAvatarId 目前是 string,与真实契约的 int Id 不一致,切换时需一并改。
  • 第 50 轮补(诊断要主动出现):ClientServices.InitializeForDevelopment() 里改为立刻触碰一次 _config.IsReady,让配置表在启动时就加载并打印行数。 ⚠️ 首轮负责人 Play 时 Console 什么都没看到 —— 因为 TableClientConfigService 是懒加载,而当时没有任何页面调用 Config,所以 Report() 从未执行。教训:诊断日志不能依赖"有人来查询",否则表加载失败(底层只打一条警告就按空表继续)会毫无线索。已修,Roslyn 三目标 0 error(Logs/verify-compile-eagerconfig2.log)。
  • 第 51 轮 · 发现工程表类与实际配置表「结构漂移」(99 条运行时 FormatException)
    • 负责人 Play 后 Console 出现 99 条 配置表解析出错:System.FormatException。定位到字段级:Skill.json 33 行 × Effect1Subtype/Effect2Subtype/Effect3Subtype(工程类 = int,json = "[]")⇒ 33×3 = 99 ✓ 完全吻合。配置目录的新 TSkill.cs 已把它们改成 JArray,并删除 *SubtypeParameter、新增 *ResId / Attack。
    • 全表漂移普查(固化脚本 Logs/verify-table-drift.ps1,只读可复用):Resources(256 行:SkeletonData 被丢弃,ScaleX/ScaleY/ScaleType/ActionName/AnimationName/BbWidth/BbHeight/Int 恒 0)、RandomHero(Heroid 被丢弃、Weight 恒 0)、Coefficient(SkillBeneficialEffect/SkillNegativeEffect 被丢弃)、MonsterTemplate.Rewards 恒 0。Hero.Portrait / Head.ResId 是本轮刻意保留的兼容字段(预期内)。
    • 修复牵涉战斗代码,本轮未动:Assets/Scripts/BNRoom/Static/GetSkillEffectParameters.cs:48~53 把 Effect1/2/3Subtype 与 *SubtypeParameter 当 int 用,改成 JArray 会破坏战斗技能参数装配 ⇒ 属原公司战斗逻辑,超出授权,需负责人裁决(BUG_TRACKER.md BUG-022 给了三个备选方案)。
    • ⚠️ 我的验证疏漏(已记 BUG_TRACKER.md RISK-019):Logs/table-probe-2.log 里本来就有 99 条 配置表解析出错(含堆栈共 198 行),但我当时只 grep 了 error CS,于是对外报"0 error"—— 报告失真,负责人 Play 时立刻看到。纪律:批处理/Play 之后必须同时扫 Exception 与业务 LogError 关键字(本项目为 配置表解析出错、本地配置表缺失),再下"0 error"结论。
    • 另修:Logs/verify-table-drift.ps1 第一版用 @(管道 | ConvertFrom-Json),在 PowerShell 5.1 下会把顶层 JSON 数组裹成1 个元素,逐字段报告全是 Count/Length/Rank 这类数组自带属性(假数据)—— 已改为正则提取并自检行数(Hero=54、Skill=33)。验证脚本本身写错比没有更糟,本轮已第二次踩到。
  • 第 52 轮 · 按负责人边界重构:Client 自己读表,不再触发全量加载(99 条报错从根上消失)
    • 负责人 2026-09-20 明确边界:只负责 Assets/Client 的实现与平台移植,其余一律不管,除非挡到这两项。
    • 判断:那 99 条来自 TableManager.InitData() 的21 张全量加载,其中 Skill 表 Client 根本不用 ⇒ 属"挡到 Client 验收"(Console 被刷满),因此在 Client 侧隔离,不动战斗代码。
    • 新增 Assets/Client/Runtime/Services/ClientTableSource.cs:客户端自己的读表入口,数据源优先级与游戏一致 —— {persistentDataPath}/config.pkg(远端热更落盘)优先 → Resources/Table/<表名>.json(进包兜底)。pkg 格式为只读复刻(GZip → version:1byte → 反复 [utf8\0][utf8\0];权威实现 TableLoadHelper._parsePackageContent),版本不符/解析失败回退本地并警告一次。
    • TableClientConfigService 重写:改为用 LC.Newtonsoft.Json.Linq(插件 DLL,不属 HotFix)直接解析;不再反射 T*Helper/TableManager,不再触发 21 张全量加载。字段读取全部容错(缺失/类型不符回落默认值,不抛异常)。
    • ClientTableProbe 重写:不再反射 HotFix,改走 ClientTableSource 验证客户端真实路径;菜单更名 Client/配置表/打印客户端配置表行数;日志前缀 [配置表]。
    • 验证(Logs/client-table-probe.log,本次按要求同时扫运行时报错):error CS 0;配置表解析出错 0(原 99);Exception/FormatException/NullReference 0;本地配置表缺失 0。 · Hero = 54 行(ClientShow!=0 的 49 行)、Head 6(1)、HeadFrame 9(3)、Badge 6(1)、Nameplate 5(1)、Title 9(1);汇总 6 张可用 / 0 空 / 0 缺失 / 0 解析失败;数据源 = 本地 Resources/Table(磁盘上已无 config.pkg)。
    • ⚠️ 待负责人确认(数据侧,不是代码问题):按表里的 ClientShow 规则,前端只显示 1 个头像 / 3 个头像框 / 1 个徽章 / 1 个铭牌 / 1 个称号(连 Head 的"默认头像" Id=1 都是 ClientShow=0)。英雄侧 49/54 正常。这像是配置尚未填全,而非规则有误 —— 请确认是要按现数据照做,还是等配置补齐。
    • 影响:BUG-022(表结构漂移)对 Client 已不再有影响(已隔离),仍对战斗侧有效但按边界不在本次范围;BUG-021(旧 config.pkg 覆盖)仍要注意 —— Client 也会优先读落盘 pkg。
  • 第 53 轮 · 按配置对齐客户端(int id 全量切换 + 表驱动落地)
    • 负责人三项决定:id 全改 int(原选项 A)/元素 1..6 = 光/水/土/风/火/暗(按筛选按钮排列)/战力先标待确认。
    • 领域模型:与配置对应的 26 个字段转 int(英雄 / 道具 / 收藏品 / 技能潜能 / 编队槽位 / 卡池奖励 / 奖励道具 / 升级消耗资源)。 服务端不透明标识(订单 / 邮件 / 活动 / 任务 / 公告 / 卡池 / 商品 / 玩家)与美术资源名(IllustrationId/AttributeIconId/QualityId,配置给的就是名字如 QualityIcon_3)保持 string。 对应地,IClientDataService 的相关签名全部改为 int(GetHeroDetail / TryUpgradeHero / TryToggleFormationHero / TrySetFormationSlot / GetShowcaseHeroId / GetEquippedBadgeId …)。
    • 元素:新增 ClientElements(1..6 = 光/水/土/风/火/暗,含 Name / FromName / AllIds);ClientHero.Element(string) → ElementId(int) + ElementName(中文名) + ElementIcon。 已核实 .Element 全工程没有任何调用点(只有一处注释引用),因此改动无回归面。
    • 表驱动落地:LocalClientDataService 里 9 个手写假英雄 → BuildHeroesFromConfig():静态字段来自配置表(名字 / 品质 / 元素 / 星级 / 图标名 / 立绘名),玩家状态本地模拟(拥有 = 前 6 个、等级 = 1、战力 = 0【待确认】)。
    • 收藏品接口:新增 GetOwnedCollectionIds(kind) / GetEquippedCollectionId(kind) / TryEquipCollection(kind, id) —— 列表来自 ClientConfigService.GetCollections(配置 + ClientShow/Sorting),拥有/装备是玩家状态;TrySetEquippedBadge 改为转调它;顺手修掉 GetEquippedBadgeId() 原本错误地返回称号的 bug。
    • ⚠️ 抓到并修掉一个初始化顺序 bug:InitializeForDevelopment() 里 _data 先于 _config 创建,而 IsInitialized => _data != null,导致构造 LocalClientDataService 时守卫为 false ⇒ 现象是"配置能读到 49 个英雄,数据服务却报英雄配置为空"。已改为先建配置服务再建数据服务,并新增 ClientServices.HasConfig 供构造期判断。
    • 验证(Logs/client-config-chain2.log:命令行 Unity 全工程编译 + 探针,按新纪律一并扫了运行时报错): error CS 0 / Exception 0 / 配置表解析出错 0; 英雄列表 = 49 个;首个 = Id 13003 / 蝎子精 / 元素1(光) / 品质3 / 1星 / 拥有=True / 战力=0【战力待确认】; 收藏品:Head 可见1/拥有1/装备10001、HeadFrame 3/2/10002、Badge 1/1/10002、Nameplate 1/1/10001、Title 1/1/10002。
    • 仍未接(下一步):① 英雄详情接 TSkill / TPotency;② 道具/背包接 TItem 并修正 ClientItemType 语义(Type=1 实为货币、Type=2 表里没有);③ ProfilePage 用新的收藏品接口做列表收敛(含场景写入);④ 立绘按名加载(HeroAvatar_* 工程内 0 个、HeroPortrait_* 仅 8 个 ⇒ 缺图,不报错但显示为空)。
  • 第 54 轮 · 修「图鉴仍显示 55/99」与「英雄页只有 6 个」
    • 负责人 Play 反馈:真实英雄名出来了 ✓;但英雄页只显示 6 个、图鉴仍显示 55/99。
    • 55/99 的根因:场景里每个子页各有一套进度文本 —— HeroPage英雄/HeroSubPage/upCanvas/底框Image/{已收集进度, 总英雄数量} 与 HeroPage英雄/GuideSubPage/upCanvas/底框Image/{已收集进度, 总英雄数量}, 两套的设计文案都烘死为 55 与 /99;而 ClientHeroPage 在 Inspector 上只接了一套(_ownedProgressText / _totalHeroCountText 指向 HeroSubPage 那套)⇒ 另一个子页(图鉴)永远停在烘死文案上。 修法:RefreshProgress() 改为按两个子页根节点各自深度查找(FindDeepChild)并两套都写,口径 = 已收集(已拥有英雄数) + 总数("/" + 英雄总数);Inspector 上原槽位保留兼容写入。纯代码,未写场景。
    • 只显示 6 个的根因:英雄子页按既有设计只列已拥有(图鉴列全部、未拥有带锁),而我上一轮的模拟只让 6 个英雄"已拥有"。 改为 SimulatedLockedHeroCount = 3(除最后 3 个外都视为已拥有) ⇒ 英雄子页 46 张、图鉴 46/49,且仍能看到 3 张未拥有的锁态。 ⚠️ 拥有状态属玩家状态,真实值应由服务端下发;这里只是演示模拟。
    • 顺带记录:已收集进度 / 总英雄数量 四个节点都在 prefab 实例里(组件 fileID 是 19 位长 ID,场景内查不到组件文档)—— 这正是"只读工具看不到 prefab 实例内部"的老盲区,故改用运行时代码查找而非 Inspector 接线。
    • 验证:Roslyn 三目标 0 error;命令行 Unity 全工程编译 + 探针见 Logs/client-config-chain3.log。
    • 请 Play 复核:英雄页应显示 46 张;两个子页右上角都应显示 46/49(不再是 55/99)。
  • 第 55 轮 · 卡面名称节点迁移(取消名称底图;范围=全改)
    • 负责人要求:"取消英雄名称的 image,然后调一下 text 的显示",范围 全改(= 改共用的卡prefab,所有引用处一起变)。
    • 机制说明(回答"名称是不是代码写的"):是 —— ClientHeroCard._nameText.text = displayName,_nameText 是序列化字段。 原 prefab 里只有 卡牌名称Image(纯 Image,没有文本子节点),名称 TMP 是修复工具在场景实例里新建的(路径 卡牌名称Image/卡牌名称)⇒ Image 是名称文本的父节点:直接删 Image 会把文本一起删掉、_nameText 静默变 null(名称消失且不报错)。
    • 执行:新增幂等步骤 MigrateCardNameNode()(已挂进 RepairAll,位于 WireHeroCard 之后、CreateGuideSubPage 之前): ① prefab 本体新建 卡牌名称(锚点/尺寸/位置沿用原 Image ⇒ 文字落在原处)→ ② 删 prefab 的 卡牌名称Image → ③ 场景侧把残余 卡牌名称Image 下的文本上提一级(继承 Image 矩形)后删 Image → ④ 对每张 ClientHeroCard 重新接线 _nameText。
    • ⚠️ 实测发现(重要):只改 prefab 不够 —— 第一轮跑完场景里仍有 4 处 卡牌名称Image(FormationPage 编队卡牌-Panel 的 3 张槽位卡 + HeroPage 图鉴子页的模板卡),说明它们并不是该 prefab 的实例、prefab 改动不会传播过去。 ⇒ 第 ③ 步刻意不依赖 prefab 血缘,改为按节点名在全场景处理(已是通用、幂等)。
    • 验证(Logs/repair-namemigrate2.log):error CS 0、配置表解析出错 0;场景 卡牌名称Image = 0(期望 0 ✓)、卡牌名称 = 6;5 张 ClientHeroCard 全部 名称=卡牌名称 ✓;无"卡下没有 卡牌名称"警告 ✓;共 22 处变更。
    • 备份:Logs/角色卡牌Button-final 1.before-namemigrate.prefab.bak、Logs/ClientShell.before-namemigrate.unity.bak、Logs/ClientShell.before-namemigrate2.unity.bak。
    • 顺带加固:WireHeroCardOn() 原来写死 卡牌名称Image 路径找名称节点,找不到就把 _nameText 写成 null(静默失效);已改为整卡子树按名深搜,找不到才回退旧路径创建 ⇒ 以后无论怎么挪节点,RepairAll 都不会冲掉接线。
    • 待确认:名称文本的字号/颜色/对齐/位置是否还要调 —— 当前沿用工具默认(居中、20pt、黑色、raycastTarget=false,矩形 = 原 Image)。
  • 第 56 轮 · 继续接配置:道具 / 技能 / 天赋 / 随机英雄池 进入客户端模型
    • 负责人:"改好了这个,继续其他配置"。
    • 领域模型:新增 ClientItemConfig(道具)、ClientSkillConfig(技能)、ClientPotencyConfig(天赋/潜能)、ClientRandomHeroConfig(卡池); ClientHeroConfig 增 Skills / Potencies(来自 THero.Skill / THero.Potency,即"本英雄的技能/天赋 id 列表")。
    • 接口:IClientConfigService 增 7 个只读查询 —— GetItems / TryGetItem / TryGetSkill / TryGetPotency / GetHeroSkills / GetHeroPotencies / GetRandomHeroPool; TableClientConfigService 全部实现,并新增 ReadIntList 兼容表里两种数组写法(真数组 与 字符串形式 "[10,20,30]")。
    • 探针表清单 6 → 10 张(加 Item / Skill / Potency / RandomHero)。
    • 验证(Logs/client-config-items.log):error CS 0、配置表解析出错 0;Item 9 / Skill 33 / Potency 68 / RandomHero 4 全部读到(汇总 10 张可用 / 0 缺失 / 0 解析失败); 英雄 13003 技能 4 个;首个 = 130011 捣药杵击 / Type1 ✅(表间关联可用); 道具 9 个;首个 = 110001 点数 / Type1 / Item_110001 ✅;随机英雄池 4 条;首条 = 池1 -> 英雄 15001 ✅。
    • ⚠️ 两个数据发现(已记 MODULE.md §15.6,待负责人确认,未确认前不写映射):
      1. 天赋数据只有 4 个英雄填了:13001 玉兔(13 个) / 14001 嫦娥(17) / 14007 唐三藏(17) / 15001 孙悟空(21),id 属 300101/400101/400701/500101 系列; 其余 50 个英雄的 Potency 是占位 [1,2](表里最小 id 是 300101)⇒ 解析为 0 条。客户端已容错(不报错、返回空集合),表现为天赋页无数据 —— 需确认是"数据未填"还是"另一种引用约定(如按行号)"。
      2. 技能 Type ↔ 详情页 天赋 / 秘技 / 终结技 的冲突(无权威依据,未写映射)。 ⚠️ 纠正上一版的误导说法:先前写"54/54 个英雄的技能关联全部可解析"——技术上成立但会误导,真相是 54 个英雄的 Skill 只有 4 种取值,同一"系列"的英雄(16 / 6 / 16 / 16 个)共用同一套技能;天赋同理,只有 4 个"系列首个英雄"填了。 被英雄引用的 16 个技能 = 4 个系列 × Type 1/2/3/4 各一个: Type1 主动攻击(捣药杵击 / 月轮飞击 / 禅杖普度 / 如意金箍棒)、Type2 回复·增益(玉兔灵药 / 月华祝福 / 佛法回复 / 战意昂扬)、 Type3 被动·护体(月华追踪 / 广寒清辉 / 金蝉护体 / 金刚不坏)、Type4 大招(广寒月影 / 皓月当空 / 紧箍咒 / 法天象地)。 另有 17 个技能没有任何英雄引用(Type5×16 + Type6×1 + 999999 占位),描述全是"对敌人造成伤害"、名字是怪物名(火焰追击 / 毒牙毒液 / 蛮牛冲撞 / 九头齐噬…)⇒ 那批属怪物(战斗侧)技能。 ⇒ 冲突 = UI 的 3 个页签 vs 配置的 4 类技能 + 1 个天赋列表:① 数量:4 类要塞进 2 个技能页签,即便 Type4 = 终结技,Type1/2/3 三类也只能挤进「秘技」;② 归属:Type 本身不区分英雄/怪物(靠值域 1~4 / 5~6),映射无法只从 Type 推出;③ 形态:TPotency 是每英雄 13~21 条的列表,页签呈现方式无依据。详见 MODULE.md §15.6。
    • 未做(等答复再动):ClientHeroDetailPage 用真实技能/天赋渲染;ClientItemType 的语义修正(实测 Type=1 是货币、Type=3 是消耗品,Type=2 表里没有,客户端现叫 Material(1)/Equipment(2)/Consumable(3))。
  • 本次会话收尾(2026-09-20 晚)
    • 负责人决定:
      1. 天赋占位 [1,2] ⇒ 空着就行、不要报错(已确认为预期行为,不是缺陷)。客户端当前行为即如此:GetHeroPotencies 静默跳过查不到的 id、返回空集合,不打日志、不抛异常;探针实测 英雄 13003 天赋 0 个 且 error CS 0 / 配置表解析出错 0 / 无异常。已在代码处加注释固化,防止后人当成 bug"修"成按行号取或补默认值。
      2. 技能 Type ↔ 秘技 / 终结技 的对应:负责人在问,明天再定。 未确认前不写映射。
    • 下一步(明天):
      1. 拿到技能 Type 映射后,接 ClientHeroDetailPage 的 秘技 / 终结技 页签(Config.GetHeroSkills(heroId) 已就绪)。
      2. 天赋页签接 Config.GetHeroPotencies(heroId)(4 个英雄有数据、其余按约定显示空态)。
      3. ClientItemType 语义修正(Type=1 货币 / Type=3 消耗品 / Type=2 表内无)—— 方向已获同意,改名与用法待做。
      4. 其余待接:ProfilePage 收藏品列表收敛(需一次场景写入)、立绘按名加载(HeroAvatar_* 工程内 0 个、HeroPortrait_* 仅 8 个 ⇒ 缺图,取不到时显示空、不报错)。
    • 今日产出(可交付状态):Assets/Client 已表驱动—— 10 张客户端表(Hero / Head / HeadFrame / Badge / Nameplate / Title / Item / Skill / Potency / RandomHero)读入客户端模型,48 个英雄真实数据在 Play 中可见,收藏品接口(列表来自表、拥有/装备属玩家状态)可用,卡面名称底图已按要求取消且接线加固。全部经命令行 Unity 全工程编译 + 探针验证(Logs/client-config-chain*.log、Logs/repair-namemigrate2.log)。
  • 第 90 轮 · 大厅窄高比适配(背景黑边 + 两个底栏重叠):根因已确证、修法已编译,待应用
    • 负责人反馈:大厅在 1080×2160 / 1080×1920 上背景左右黑边、CanvasBottomFunction0 与 CanvasBottomFunction1 靠近至重叠;752×1630 ~ 1080×2280 正常。
    • 根因(实测数据,非推断):ClientCanvas 参考 753×1630、matchWidthOrHeight = 0(按宽匹配)⇒ 画布宽恒 753、高 = 753×(H/W): 2.168→1632 ✓ / 2.111→1590 / 2.0→1506 / 1.778→1339。 · MainPage主页/Background 是全屏锚点 ✓ 但 Image.m_PreserveAspect = 1 ⇒ 画布变矮时按高缩放 ⇒ 比 753 窄 ⇒ 左右黑边; · CanvasBottomFunction0 锚点 (0.5,0)(底)而 CanvasBottomFunction1 锚点 (0.5,0.5) + offset -417(中)⇒ 后者随画布中心下压: 高 1630 时二者中心距底 398 / 227(间距 171 ✓);高 1339 时 F1 降到 252.5 ⇒ 半高 97/87.5 ⇒ F0 顶边 324 > F1 底边 165 ⇒ 重叠 ✓ 与"比例越矮越严重"完全吻合。
    • 修法(工具 NormalizeLobbyBackgroundAndBottomBars(),纯锚点机械修正、不动美术尺寸/位置): ① 背景 preserveAspect = false(铺满;若要保比例可改用 AspectRatioFitter.EnvelopeParent 做"覆盖"); ② CanvasBottomFunction1 改底锚、offset 取设计高度等效值 398(=1630/2−417)⇒ 两者都跟底边走,间距恒定。
    • 状态:代码已写好、编译三目标 0 error ✓;备份 Logs/ClientShell.before-lobbyadapt.unity.bak ✓。 ⏸ 场景写入未执行:负责人正在编辑器里,批处理因"工程已打开"中止(HandleProjectAlreadyOpenInAnotherInstance)。 ⇒ 可由负责人一键应用:菜单 Client → 结构修复 → 2. 执行结构修复(幂等,含本修正);或关掉编辑器后由我执行 + 补跑自检。
  • 第 89 轮 · 交付《UI 锚点定稿确认表》—— 19 页可"所见即所得"直接微调
    • 负责人要求:"确定哪些界面的布局锚点已经定好、能所见即所得,我直接微调就完事" ⇒ 交付 UI_ANCHOR_SIGNOFF.md。
    • 内容:21 页逐页定稿状态表(根/背景 · 底栏 · 标题/顶区 · 列表容器 ⇒ 结论)+ 4 条微调注意事项 + 已定稿的 7 条锚点规则 + 复现命令。
    • 结论:19 页 ✅ 可微调 / 2 页 ➖ 未接入(Email Details (Have)/(No));另 Success Receipt Interface 不可达。
    • 4 条注意事项(避免白改):① 面板式弹窗别改成全屏(会盖住下层)② 列表 Content 的高度由运行时撑开(手改高度会被覆盖;改 CellSize/Spacing/Padding 安全)③ 改锚点必须保持全屏拉伸(弹窗遮罩 只改颜色、别改尺寸)④ 卡牌网格保持 UpperLeft。
    • 数据来源:本会话两批只读核查(ui-adapt-audit.ps1 21 页 / ui-adapt-audit2.ps1 15 个标题节点)✓ 可重跑。
    • 本轮无场景/代码改动;编译与自检保持上一轮状态(96/0)。
    • 下一步:负责人按该表逐页微调视觉;遇到具体错位时给页面 + 截图,我做定点修正(流程:定位根因 → 最小改动 → 编译/自检 → 复验)。
  • 第 88 轮 · UI 适配第二批:标题贴顶 / 顶区对齐 —— 无真问题(结构规则已达标)
    • 新增 Logs/ui-adapt-audit2.ps1(只读)→ Logs/ui-adapt-audit2.md:核对 15 个 title/top-bar 节点是否顶部锚定、是否被错挂在 Bottom page function bar 下(后者是历史坑:会随画布高度变化与顶区重叠)。
    • 结果:无真问题 ✓ · 没有任何节点被错挂在底栏下 ✓(历史坑已消除); · 真正的页面标题都已顶部锚定:ShopPage商店/Shopping Mall Title ✓、MailPage邮件/Email Title ✓、ActivityPage活动/task title ✓、Complete Guide Event Page全图鉴活动/task title ✓、ShopPage商店/Top function bar ✓; · 其余报 not top-anchored 的是标题背景框 / 弹窗内部标题 / 装饰节点(如 Shop title background frame、Emial title background frame、RenameDialog/Title、Content_Title)—— 它们本就不需要顶部锚定,是我校验收得太宽(判据假阳性)。
    • 结论:UI 适配的"结构性规则"已全部达标(画布按宽匹配 · 页面根/背景全屏 · 底栏铺满 · 标题贴顶 · 顶区对齐 · 卡牌网格左上 · 竖向列表撑高/Clamped/顶部对齐 · 面板式弹窗豁免)。 剩下的是视觉/间距/字号/美术位置微调(规则⑤明确留给负责人)与你在 Play 里具体点出的某页错位。
    • 建议后续方式:不要再泛查 —— 你指具体页面 + 截图,我按同一套方法做定点修正(每批留证据 + 编译/自检 + 你复验)。
    • 验证:本轮无场景/代码改动(纯核对);编译与自检保持上一轮状态(96/0)。
  • 第 87 轮 · UI 适配开工:逐页布局核查(21 页)+ 首批 2 处修复
    • 新增 Logs/ui-adapt-audit.ps1(只读、纯 ASCII)→ Logs/ui-adapt-audit.md:逐页核对 9 条锚点规则 (根/背景全屏 · 底栏横向铺满 · 列表 childAlignment 是否 MiddleCenter · ContentSizeFitter.verticalFit 是否 Unconstrained),并豁免面板式弹窗(规则⑧)。
    • 核查结果(21 页):绝大多数 OK;真问题 2 处: ① 🔴 Pending shipmentCanvas 底栏没横向铺满(违反规则③)⇒ 不同宽高比设备上底栏宽窄不一; ② 🔴 MailPage邮件 有 2 个列表容器是 Unconstrained ⇒ 我上轮接入滚动修复时漏了邮箱页。 另 3 处(Product Purchase Interface / Purchase Success Page / 联系客服Page 背景"非全屏")是我判据的误报 —— 它们是面板式弹窗,背景不平铺正是负责人确认过的正确做法(规则⑧)。
    • 修复:① 工具新增 NormalizePendingShipmentBar()(只改水平锚点与 offset,高度/竖直位置不变 ⇒ 不跳位)并在步骤里调用; ② ClientMailPage.Show() 接入 ClientScrollFix.FixAll ✓
    • 验证:编译三目标 0 error;Logs/repair-adapt1.log 显示底栏已铺满;自检 96 项 / 失败 0(退出码 0)✓; 审计复跑后 Pending shipmentCanvas 由 ✘ 变 OK(bar=stretched) ✓
    • ⚠️ 审计读的是场景文件:邮箱页仍显示 unfit=2,那是场景里的作者值,运行时已由 ClientScrollFix 修正 ✓(不是遗漏)。
    • 下一步(逐页适配继续):按同一脚本逐页核对剩余规则(标题贴顶 / 顶区对齐 / 网格左上 / 面板式弹窗豁免), 发现问题即用工具做机械性锚点修正(改锚点按世界坐标回写、不跳位),每批后由负责人 Play 复验。
  • 第 86 轮 · BUG-025 方案 C 落地 + 冗余阵容卡已清理 + 全量自检 96/0(首次跑通)
    • ① BUG-025 方案 C 已落地 ✓:新增客户端专用启动场景 Assets/Client/Scenes/ClientBoot.unity(对象 ClientBoot + ClientBootLoader,职责仅 Start() → LoadScene("ClientShell")), 并置首。实测构建顺序 ClientBoot → Boot → ClientShell(原 Boot.unity 保留未动,可随时调整顺序回滚)。 证据:Logs/repair-clientboot.log 的 构建场景顺序(前 5 个):ClientBoot → Boot → ClientShell + ProjectSettings/EditorBuildSettings.asset ✓ ⇒ 移植侧硬阻断解除(导出的包现在能进到客户端 UI)。
    • ② 冗余阵容卡已清理 ✓:工具 RemoveRedundantLineupCards() 删除了我上一轮新建的容器(含 3 张 展示卡牌); 自检诊断确认阵容弹窗内现在恰好是场景既有的 6 张 角色卡牌Button-final ✓(干净)。
    • ⚠️ 过程中的自我更正:第一版清理没生效,因为它是沿 玩家阵容/Content 路径查找、任一环没命中就静默 return(无日志) ✗。 改为"在弹窗内找全部子节点名都是 展示卡牌 的 Content"并每步打日志后才成功 ✓(教训:工具里的提前 return 必须留痕,否则"没做"和"做了但没事可做"分不清)。
    • ③ 自检首次跑通:96 项 / 失败 0,退出码 0 ✓(Logs/self-test.log)。 同时修掉自检里过时的期望:收藏品可见条数已按负责人决定(B)由 1/1/1/3/1 变为 6/6/5/9/9,断言同步更新 ✓
    • 备份:Logs/ClientShell.before-clientboot.unity.bak、Logs/ClientShell.before-cleanup2.unity.bak。
    • 下一步(等负责人):① 按上表命名导出贴图 ⇒ 我接线收藏品/排行榜图标 ② UI 适配(建议单独立项,先出全页问题清单)。
  • 第 85 轮 · BUG-025 选方案 C + 清理冗余阵容卡:代码与工具已就绪,待关编辑器执行场景写入
    • 负责人决策:BUG-025 → 方案 C(新建只做客户端初始化的 ClientBoot 场景并置首);清理上一轮我新建的 3 张冗余阵容卡。
    • 已写好(编译三目标 0 error ✓): · 新增 Assets/Client/Runtime/ClientBootLoader.cs —— 职责极小:Start() 里 SceneManager.LoadScene("ClientShell")(客户端数据由 ClientShell 内的 ClientBootstrap 初始化);不改动原 Boot 场景,只新增入口场景并置首,可随时从构建清单移除回滚。 · 工具新增 EnsureClientBootScene():场景不存在则新建(空场景 + ClientBoot 对象 + ClientBootLoader)并保存;把 ClientBoot 放进 EditorBuildSettings 第 0 位;确保 ClientShell 在清单中;不删不动原 Boot.unity 条目;日志打印前 5 个场景顺序。幂等。 · 工具新增 RemoveRedundantLineupCards():删除 Player lineup/玩家阵容/Content(我上轮新建的容器 + 3 张 展示卡牌); 安全护栏:只有当该容器全部子节点名都以 展示卡牌 开头时才删 —— 场景既有 6 张 角色卡牌Button-final 在别处、不受影响(代码两种名字都收)。幂等。
    • ⏸ 未执行:Unity 编辑器正在运行(跑批处理必须先关它,否则会打断你的操作)⇒ 请关掉编辑器后说一声,我立刻执行 ① 新建 ClientBoot 场景并置首 ② 删除冗余阵容卡 ③ 复核构建清单顺序 + 跑全量自检(96 项)。
    • 备份策略:执行前会备份 ClientShell.unity(Logs/ClientShell.before-clientboot.unity.bak)。
  • 第 84 轮 · 落实负责人第二批决策(个性化交互 + 演示数据 + 其余页滚动修复 + 缺图清单)
    • 负责人决策与落地: · 个性化"演示效果"选 B ⇒ 已把 Head/HeadFrame/Badge/Nameplate/Title 五张表全部行改为 ClientShow: 1 (6/9/6/5/9 = 35 行)⇒ 列表可见条数由 1/1/1/3/1 变为 6/9/6/5/9,未拥有的显示"未解锁"态 ✓ · 个性化「确定键」语义(负责人原话:点条目选中后再点确定键进行替换,而不是返回)⇒ ClientProfilePage 改为 点条目=只选中(高亮 + Toast「已选择…(点确定键替换)」),5 个子界面的 个性化确定键Button(Content_Avatar/Frame/Info/Title/Widget)绑定为确认替换; 未选中时提示"请先选择…";旧的"点击即装备"入口保留为兼容转发 ✓ · 其余列表页接入滚动修复 ⇒ 已接入 英雄 / 商店 / 活动 / 主页展示 / 全图鉴活动 / 英雄详情(各自 Show 调用 ClientScrollFix.FixAll)✓ · 装备(不管数据、有接口就行)· 战力(显示哪个都行)⇒ 不动 ✓;邮件 ⇒ 已结 ✓;未接入页面不做 ⇒ 不再提议 ✓ · 清理我新建的 3 张冗余阵容卡 ⇒ ⏸ 需先关掉你的 Unity 编辑器才能跑批处理删除;仅视觉冗余、当前被隐藏,不清也无功能影响 ✓
    • 缺图清单已产出(写入 BUG_TRACKER.md,负责人已同意提供素材):工程内按命名规范的贴图实测全为 0 (HeroAvatar*/AvatarFrame*/Medal*/Nameplate*/Title_*/AttributeIcon*/Item_*); 而 Assets/Client/UI/切图(11)/** 有中文名原始切图(头像 30 / 头像框 11 / 徽章 7 / 铭牌 14 / 称号 14)。 需要"id ↔ 贴图"的对应(按规则命名导出,或给我一份对照表);另有 Head 表 ResId 字段为空、元素 6(暗)缺图、 属性图标 0 张、排行榜条目 AvatarId/FrameId/BadgeId 全为 0(数据侧) 三处已在清单中标注 ✓
    • 验证:编译三目标 0 error ✓(新增/改动的页面均已纳入);自检仍待补跑(你的编辑器占用中)。
  • 第 83 轮 · 更正上一轮修复的副作用:排行榜整列右移(我只改了竖直方向)
    • 负责人复验:编队/个人中心等其它都通过 ✓;但排行榜所有行整体右移、右边缘被裁掉、左半空着(附截图)。
    • 根因是我的第一版修复:把容器的水平也改成拉伸(anchorMin.x=0/anchorMax.x=1)⇒ 容器宽 = "视口宽 + 作者设定的 sizeDelta.x" ⇒ 远比原本宽 ⇒ 网格居中排布后整列右移并被 Viewport 裁切。
    • 修法:ClientScrollFix 改为只调竖直方向 —— anchorMin/anchorMax/pivot 的 x 一律沿用作者值; 对齐只改竖直分量,水平分量保留(TextAnchor 编码 0..2 = Upper*、3..5 = Middle*、6..8 = Lower* ⇒ (int)value % 3 即水平分量)。
    • 教训(已写入 BUG-027):修布局问题时只改与问题相关的轴;"看起来更标准"的通用写法在作者已调好宽度的页面上会变成副作用 —— 最小改动优先。
    • 验证:编译三目标 0 error ✓;视觉结果待负责人 Play 复验(我不能代替 GUI 验证)。
    • 自检仍未跑(你的编辑器占用中)。其余列表页(英雄/商店/邮箱/活动)仍未接入该修复,等你一句话。
  • 第 82 轮 · 滚动列表根因修复(排行榜/编队"只显示 6 条 + 松手弹回 + 默认不在最上面")
    • 负责人复验:客服弹窗 ✅ 通过、邮箱 ✅ 通过;排行榜仍不行(只显示 6 个、下滑松手被拉回、默认不在最上面),编队 Scroll View 同样; 并推测"估计是 middle center 导致的" —— 推测正确。
    • 场景实测根因(三条叠加,全都是配置而非逻辑): ① ContentSizeFitter.m_VerticalFit: 0(Unconstrained)⇒ 内容不撑高 ⇒ 只显示作者高度那几条,且内容高≈视口高 ⇒ 滚动范围为 0 ⇒ 一滑就回弹; ② ScrollRect.m_MovementType: 1(Elastic)⇒ 松手弹回; ③ GridLayoutGroup.m_ChildAlignment: 4(MiddleCenter)⇒ 内容居中 ⇒ 默认看中间而非顶部。
    • 新增 Assets/Client/Runtime/UI/ClientScrollFix.cs(运行时修正,不写场景/不动美术): 撑高(verticalFit = PreferredSize)+ movementType = Clamped + childAlignment = UpperCenter + 容器顶部锚点/轴心 + 重排后回到顶部; 只处理竖向列表(vertical && !horizontal)。
    • 已接入:ClientRankPage.Show()(两个榜)、ClientFormationPage.Show()、ClientProfilePage.Show()。
    • 未接入(等你确认):英雄 / 商店 / 邮箱 / 活动 等其余列表页大概率同样有问题;工具已备好,接入只是一行调用,为避免复验期引入额外变化先不动。
    • 验证:编译三目标 0 error(新增文件已纳入两个 profile)。 ⚠️ 自检仍未跑(你的编辑器占用中,跑批处理必须先关它)。
  • 第 81 轮 · 负责人首轮验收反馈:3 项逻辑问题已修 + 1 项说明(个性化"删改")+ UI 错位暂缓
    • 负责人结论:大部分逻辑与功能没问题;UI 错位/不适配属意料之中,后续专门改、现在不用管(已记为暂缓项,本轮未做任何排版改动)。
    • ① 客服会话界面点"确定键"或空白处都返回不了上一级 ✅ 已修(两条根因): · 遮罩只被显隐、没有任何点击处理 ⇒ 点空白无反应 —— 这是所有弹窗的共同问题(不只客服页); 已在 ClientPopupService.EnsureMaskClickClosesTop() 运行时给遮罩补 Button(transition=None,不改尺寸/排版)→ 点击 CloseTop(); · 客服弹窗内没有任何关闭键绑定 ⇒ ClientHomePage.BindContactPopupClose() 按常见命名(确定键Button/确定Button/确定/关闭键Button/关闭Button/退出Button)查找并绑定,找不到只记日志;另把 background/底框 绑为"点空白关闭"兜底。
    • ② 排行榜只显示前 5 名,要求前 50 名 ✅ 已修:根因是模拟数据每榜只有 5 条 ⇒ LocalClientDataService.BuildLeaderboard(50, …) 补足到 50 条(前 5 名保留原样例,其余确定性规则、不用随机数,便于复现与自检); ClientRankPage 新增"行容器 + 首行模板",EnsureRankRows() 运行时克隆补足,上限 50(不写场景)。
    • ③ 邮件"全部删除" ✅ 已修(按负责人给的规则"全部领取和已读后才能删,删完显示暂无邮件"): 新增 IClientDataService.TryDeleteAllMails() —— 逐封校验已读+已领取,不满足即拒绝并说明原因;通过则清空 + DataChanged; ClientMailPage.DeleteAll() + 绑定 —— 场景里删除键在 Panel/All delete/Button 下、按钮节点本身叫 Button(名字太通用)⇒ 按父节点 All delete 取子 Button(BindButtonUnder),避免误绑; 删完 Refresh() 走既有空态 ⇒ Default/No emails + "暂无邮件" ✓(场景本来就有该节点)。
    • ④ 解释(非缺陷):个性化页签 5 个子界面"被删改" —— 是我做过的列表收敛(证据 Logs/repair-profilelists.log 53 处变更): 删掉每列预摆的演示项、把模板改名为 xxxItem 并禁用(仅作克隆源),运行时按数据生成;原因是表按 ClientShow 过滤后可见条数为 1/1/1/3/1, 不收敛就会出现"数据 1 条、界面 5 个假条目"。代价:默认演示效果不见了。三个方向待你定(A 保持数据驱动 / B 打开表中更多 ClientShow 行或补模拟数据让界面自动变多 / C 恢复内联演示项,不推荐)。
    • 验证:编译三目标 0 error ✓。 ⚠️ 自检本轮未跑:你的 Unity 编辑器处于打开状态,跑批处理必须先关掉它 ⇒ 为避免打断你的验收,我没有执行;等你关掉编辑器我再补跑(或你直接 Play 复验这三处)。
    • 详见 BUG_TRACKER.md BUG-027。
  • 第 80 轮 · 射线可达性审计(只读):169 个按钮中 4 个无法静态判定,均为 prefab 实例(无真缺口)
    • 新增 Logs/ui-raycast-audit.ps1(只读、纯 ASCII)→ 报告 Logs/ui-raycast-audit.md。 这轮查的是"看着在、点不到"的另一种机制:按钮子树的图是否接收射线(m_RaycastTarget),以及祖先 CanvasGroup.blocksRaycasts 是否被关。
    • 判据:按钮可点 ⇔ 其场景可见子树里至少有一个 m_RaycastTarget=1 的 Graphic(射线命中后向最近的 Button 祖先冒泡);或有祖先 CanvasGroup.m_BlocksRaycasts=0 则直接不可点。
    • 结果:169 个按钮 → 4 个候选,且 4 个的路径全为空 ⇒ 它们正是 prefab 实例根(实例根的 Transform 在场景 YAML 里是 stripped 的,静态解析取不到路径)—— 属已知假阳性类别,没有可执行发现;其余 165 个按钮的子树的都有可接收射线的图 ✓
    • 本轮我自己踩的坑(都在工具里,已修):① 拿 6 位 guid 前缀去比 32 位全 guid ⇒ buttons = 0(静默"零发现",最容易误判成"没问题"); ② 子树遍历遇到 prefab 实例根的无 Transform ⇒ 键为 null 抛异常,已加保护;③ CanvasGroup 改为按字段特征(m_BlocksRaycasts)识别,不再依赖 guid(它来自内置模块、不在包缓存里)。 ⇒ 教训同前:"0 发现"必须先确认工具真的在工作(本轮靠"按钮数=0 与 169 矛盾"发现)。
    • 本轮无任何场景/代码改动(验收期间冻结)。
    • 审计工具矩阵已达 7 个(均只读、可重跑):接线 / 节点契约 / 类型一致性 / 返回关闭闭环 / 死按钮 / 分层排版 / 射线可达。
    • 下一轮(第 24 轮,本目标最后一轮)建议:若无新指令,不再新增边际审计,改为收尾——汇总七份审计结论与待办、刷新 CURRENT_STATE/MODULE/看板,等你验收结果。
  • 第 79 轮 · UI 分层与列表排版核对(只读,验收期间不改动)
    • 新增 Logs/ui-layout-audit.ps1(纯 ASCII,只读)→ 报告 Logs/ui-layout-audit.md,三段:① ClientCanvas 子层与激活态;② 19 个已登记节点的实际父层 / 是否全屏;③ 全部列表容器(Content)的布局组件。
    • 结论:分层与排版均无异常 ✓ · ClientCanvas 子层:PopupLayer[1] / PagesLayer[1] / SystemLayer[0] / ToastRoot[0] —— 唯一异常仍是已知的 SystemLayer 常驻 inactive(RISK-020 待你选 A/B/C); · 19/19 已登记节点都在 PopupLayer ✓(PagesLayer 只放 MainPage主页,与既有结论一致); · 页面根形态:12 个全屏、7 个面板型(Exchange code interface / Historical Order Interface / Pending shipmentCanvas / Player lineup / Product Purchase Interface / 联系客服Page 等)—— 与你此前判定"Player lineup 是面板型、不该全屏拉伸"一致 ✓,不是缺陷; · 31 个列表容器全部具备 GridLayoutGroup + ContentSizeFitter ✓(0 个缺布局组件)⇒ 列表克隆/排版前提齐备。
    • 本轮无任何场景/代码改动(验收期间刻意冻结;跑批处理会关掉你的编辑器、改代码会触发重编译并打断 Play)。
    • 等你验收:清单 UI_ACCEPTANCE_CHECKLIST.md(A~G 七组)。验收通过后我再做排队项(清理我新建的 3 张阵容卡 → 落地你确认的产品项)。
  • 第 78 轮 · 阵容卡根因修复 + 场景接线回归自检 + 交付验收清单(负责人正在验收)
    • ⚠️ 本轮起暂停一切场景写入与代码改动 —— 负责人已开始人工验收;场景写入会让 Unity 重载、代码改动会触发重编译并打断 Play。 后续改动等验收结果再排(已排队项见下)。
    • 🔴 阵容弹窗根因(比原先判断更深):ClientRankPage.CollectLineupCards() 原先只查第一个 Content、且只认 展示卡牌 前缀 —— 而实测阵容弹窗里本来就有 6 张 角色卡牌Button-final(既有列表)⇒ 一张都没被收集(弹窗只有层数/回合数/战力)。 修法(代码):在整个阵容弹窗内按名收集,两种前缀都收;并排除名字含 Scroll 的容器 —— 因为场景里的滚动容器就叫 展示卡牌Scroll View(同以前缀开头),若把它当成一张卡,Refresh(null) 会 SetActive(false) 把整个卡牌区关掉。
    • 自检新增"场景接线回归"(ClientSelfTest.RunSceneWiringChecks):批处理里只读打开 ClientShell.unity(不保存), 用 SerializedObject 断言关键引用与节点:弹窗遮罩、邮件红点、ProfilePage 五类收藏品模板+容器+主页展示、改名链路三按钮节点、 阵容弹窗卡牌与关闭按钮、邮箱一键按钮、BottomFunctionIconView._icon 全部接线。 ⇒ 以后场景/工具被改坏,自检会直接以非 0 退出码报出来,不必等你 Play 才发现。
    • ⚠️ 自检自身踩的两个坑(已修):① 用 GameObject.Find 找节点 —— 它只返回激活对象,而弹窗默认隐藏 ⇒ 误报"节点不存在",已改为根节点深搜(含未激活); ② 断言"阵容卡数"时把 展示卡牌Scroll View 也算成卡 ⇒ 已与代码同一判据(排除 Scroll;卡 = 角色卡牌Button* 或 展示卡牌+数字)。
    • 最终自检:96 项 / 失败 0(Logs/self-test3.log);编译三目标 0 error; 诊断输出确认阵容弹窗内卡牌节点 = 9 个(既有 角色卡牌Button-final ×6 + 本轮新建 展示卡牌1..3)。
    • 交付 UI_ACCEPTANCE_CHECKLIST.md(A~G 七组、每项含步骤/预期/失败回传;含"已知未完成/待决定"与自动基线;附复现命令与"跑批处理前必须先关编辑器"的提醒)。
    • 已排队的改动(等验收后再做):
      1. 清理候选:本轮新建的 展示卡牌1..3 与既有 6 张重复 —— 若 E2/E4 显示正常,则删掉我新建的 3 张(已记入 BUG_TRACKER 待核验清理项,含回滚方式);
      2. E 组若不过,按你回传的 Console/截图定位(阵容卡的等级/星级/立绘走 等级-Text 回退与既有贴图表);
      3. 你确认后落地 个性化确定键 语义、SystemLayer A/B/C、邮件正文 A/B/C 等。
  • 第 77 轮 · 死按钮审计:抓到 5 处"点了没反应"(4 处已修)+ 修掉一个静默失败根因
    • 新增 Logs/ui-dead-buttons.ps1(纯 ASCII,可重跑)→ 报告 Logs/ui-dead-buttons.md。 判据:场景 Button 既没有场景持久事件(m_MethodName),其名字又没出现在任何运行时代码的绑定/查找行里。
    • 实测:场景 169 个按钮,其中 0 个走场景持久事件(全场景仅 3 个 SetActive 持久调用且不在按钮上 —— 按钮一律由代码绑定,符合本工程架构);首轮候选 67 个,复核后确认 5 处真缺口:
      按钮 问题 处置
      Panel_Profile/底框/改名称 改名入口点不开 ✅ 已修(绑定 OpenRenameDialog)
      RenameDialog/ConfirmButton 确认改名没反应 ✅ 已修(绑定 ConfirmRename)
      RenameDialog/CancelButton 取消没反应 ✅ 已修(绑定 CancelRename)
      MailPage/Email come/Panel/All read/All read button 一键领取附件没反应 ✅ 已修(绑定 ClaimAll)
      个性化确定键Button ×6 个性化各分类"确定"无绑定 ⏸ 保留待确认(本实现是"点条目即装备","确定键"的语义属产品规则,不臆造)
    • 🔧 修掉静默失败根因:ClientProfilePage.BindButton 原先用 transform.Find(只查直接子级), 而 改名称 在 Panel_Profile/底框/ 下、确认/取消在 Panel_Profile/RenameDialog/ 下 ⇒ 一个都找不到且不报错。已改为深搜(FindDeep),与其它页面一致 ✓ ClientMailPage 同样新增深搜绑定(含找不到时的明确告警,不再静默)。
    • 不臆造行为(仅记录):邮箱 All delete(IClientDataService 没有删除/批量已读接口 ⇒ 未实现功能);元素筛选按钮(你此前明确本阶段不做);未接入页面内的按钮。
    • 审计工具的假阳性来源(已写入文档):看不到"用序列化字段接的按钮"(_leftButton/_rightButton/_equipmentButtons/_heroTabButton/_addButton 等)⇒ 这些会误报。
    • 验证:编译三目标 0 error;修复后重跑审计,4 个按钮已从候选中消失(67 → 63);自检 70 项 / 失败 0、退出码 0 ✓
    • 已写入 MODULE.md §18.3;本轮无场景写入(改动全在代码层)。
    • 建议 Play 复核:个人中心点 改名称 → 输入框弹出 → 确认 应生效(名称更新 + Toast)、取消 应关闭;邮箱页点 一键 → 附件入包 + Toast。
  • 第 76 轮 · BUG-026 全部处置完毕(负责人"全部授权"+"允许在合适的位置新建")
    • ① 弹窗遮罩/输入阻断 ✅ —— 关键发现:工具里的 EnsurePopupMask() 早就写好了却从未被调用(所以场景里一直没有遮罩节点)。 本轮补上调用 ⇒ 新建 ClientCanvas/PopupLayer/弹窗遮罩(全屏 + raycastTarget、默认隐藏,由 ClientPopupService.ApplyMask 动态维护)+ 接线 _maskRoot ✓
    • ② 邮件红点 ✅ —— 克隆现成 ActivityButton/RedDot → CanvasBottomFunction0/BottomFunctionIcon_Mail/RedDot(默认隐藏)+ 接线 _mailDot ✓
    • ③ 页面提示 ✅(两种情形都查清了): · ClientHomePage 本来就已把提示发给全局 Toast ⇒ 我此前把它列为"真缺口"是误报(已更正); · ClientProfilePage 确实没有 ⇒ 本轮让它实现 IClientFeedbackHost + BindFeedback,ShowNotice 优先走全局 Toast(_notice 仅作兼容回退)✓
    • ④ 底栏图标/文字 ✅(一半)—— BottomFunctionIconView._icon 已接(Bottom1..4/Image);_label 无对应节点(这些节点只有一个 Image 子节点、没有文字,且 Configure 无调用方)⇒ 如实记录,不臆造文字节点 ✓
    • ⑤ 排行榜阵容卡 ✅ —— 在 Player lineup/玩家阵容 下新建 Content(GridLayoutGroup 3 列)+ 3 个共用卡 prefab 实例 展示卡牌1..3(保留 prefab 关联); 该 prefab 已含 卡牌名称/等级-Text/立绘Image/品质Image/品质底框Image/属性图标Image/星级图标Image (1..5) ⇒ 正好覆盖 LineupCardRow 所需 ✓
    • ⑥ 阵容弹窗关闭 ✅ —— Player lineup 右上角新建 关闭Button(克隆自排行榜返回按钮),ClientRankPage.OpenLineup() 绑定 CloseLineup ✓
    • ⚠️ 又更正我一处审计误报:我说"星级图标Image (1..5) 工程内不存在"是错的 —— 共用卡 prefab 本来就有; 误报原因是代码里写的是前缀字面量 "星级图标Image (" + i + ")",而我的比对当时只做全名相等。 已修审计判据(字面量是任一节点名的前缀即算命中)⇒ A 类清单随即变干净 ✓
    • 最终审计状态:A 类无未处理真缺口(只剩编辑器工具的字符串片段、以及已有兜底的 前往获取* 与已加回退的 LV等级); B 类 39 条全部为已解释的非缺口。
    • 验证:编译三目标 0 error;repair-bug026a.log(37 处变更)/repair-bug026b.log(43 处变更)均 error CS 0、异常 0; 自检 70 项 / 失败 0;场景复核 _maskRoot/_mailDot/_icon 非 0,弹窗遮罩、BottomFunctionIcon_Mail/RedDot(均 active=false)、玩家阵容/Content、关闭Button 均存在 ✓
    • 备份:ClientShell.before-bug026a.unity.bak、ClientShell.before-bug026b.unity.bak;Unity 已开回。
    • 建议你 Play 验收:① 打开任一弹窗看遮罩是否挡住下层点击;② 大厅邮件入口是否出现红点(有未读/未领邮件时); ③ 个人中心点未拥有的收藏品 → 应弹 Toast 提示;④ 排行榜点"查看" → 阵容弹窗应有 3 张卡 + 右上角关闭按钮。
  • 第 75 轮 · 页面/弹窗「返回·关闭闭环」核对:闭环基本完整,另发现阵容弹窗无关闭手段
    • 新增 Logs/ui-flow-matrix.ps1(纯 ASCII,中文关键词用字符码构造)→ 报告 Logs/ui-flow-matrix.md: 对 19 个已登记场景节点列出 pageId / 代码引用数 / 是否需要返回·关闭节点。
    • 结论:返回闭环基本完整 ✓ —— 各页返回都绑在 BackoffButton(不是 后退Button),且场景里各页都有该节点: 排行榜 ClientRankPage:80、活动页 ClientActivityPage:298/302、商店 ClientShopPage:401、全图鉴活动 ClientCompleteGuideEventPage:345-347 ✓; 英雄/英雄详情/编队/邮件/个人中心 走 后退Button(工具 BackButtonPaths 5 条)✓;Purchase Success Page 点空白关闭 ✓。
    • 🔴 新发现:Player lineup(玩家阵容)子树里没有任何按钮 ⇒ 打开后关不掉 —— 与它"没有卡牌节点"同源,该弹窗整体未完成。 已并入 BUG-026 缺口清单(新增第 6 项)。
    • ⚠️ 我又踩了同一个坑(第 3 次):脚本里写了中文字面量 '后退'/'关闭',被 PowerShell 按 ANSI 读成乱码 ⇒ 关键词永远匹配不上, 导致首轮结果"所有页面 back=False"与已知事实矛盾(ProfilePage个人中心/后退Button 明明存在)。改为字符码构造 [char]0x540E+[char]0x9000 后结果正确 ✓ ⇒ 结论:.ps1 里一律不得出现非 ASCII 字面量;需要中文就用字符码或从文件读。
    • 审计工具的已知判据盲区(已写入 BUG-026,避免误读):只认 后退/关闭/Backoff,不覆盖 取消键Button 这类业务命名 (例:Product Purchase Interface 实际由 取消键Button 关闭,ClientShopPage:285);prefab 实例内部节点不在场景 YAML 中,可能漏判。
    • 本轮无代码/场景改动(纯静态核对 + 工具)⇒ 无需重新编译。
    • 待授权仍未回复:BUG-026 的 6 项缺口(弹窗遮罩、邮件/公告红点、页面提示、底栏图标文字、排行榜阵容卡、阵容弹窗关闭手段)。
  • 第 74 轮 · UI 类型一致性审计:127 处引用 0 不符(含阳性对照)
    • 新增 Logs/ui-type-audit.ps1(纯 ASCII,可重跑) → 报告 Logs/ui-type-audit.md。 这轮查的是比"有没有接线"更隐蔽的一类:字段声明类型与它引用的场景组件实际类型不一致 —— AGENTS.md §4 明令"文本必须按场景真实组件类型声明",不一致会让引用静默失效(BUG-018 的成因)。
    • 判据:解析客户端每个序列化字段的声明类型(Text / TMP_Text / Image …), 再解析场景里该字段指向的组件 guid(f4688f…=TMP、5f7201…=旧版 UGUI Text、fe87c0…=Image、4e29b1…=Button)后比对。
    • 结果:解析到 107 个声明字段、比对 127 处非空引用 ⇒ 0 处不符 ✓ ⇒ 结论:「文本类型声明与场景不符」这一类只在 BUG-018 出现过一次,且已修复;其余全部正确。
    • ✅ 阳性对照(确认审计不是"0 因为没比较"):同一次运行解析出的被引用组件种类分布为 class1(GameObject) 49、TMP_Text 22、Transform 17、Image 17、Button 12、UGUI_Text 8、其它 2 —— 两类文本都在场,若真有错配必然会被捕获 ✓
    • 已写入 MODULE.md §18.2(工具与判据);本轮无代码/场景改动 ⇒ 无需重新编译。
    • 仍待授权(BUG-026 的 5 项真缺口):弹窗遮罩 _maskRoot、邮件/公告红点、页面提示 _notice、底栏 BottomFunctionIconView._icon/_label(以上都只需指向现成节点)、排行榜阵容卡(需新建或改为不显示)。
    • 下一步(不写场景也能做):继续逐页做契约与健壮性核对;等你授权后再统一接线。
  • 第 73 轮 · UI-only 重启:UI 契约审计系统化(脚本 + 报告)+ 修掉一处潜伏空引用
    • 范围:负责人 2026-09-21 明确 "该任务只负责UI" ⇒ 目标已改为 UI-only(平台移植/WebGL/真机/BUG-009·013·025 不在本任务)。
    • 把 MODULE.md §18 的核对法做成可重跑脚本:新增 Logs/ui-contract-audit.ps1(纯 ASCII,避免 .ps1 被按 ANSI 读坏的旧坑)→ 报告 Logs/ui-contract-audit.md。 两条判据:A 代码里"按名查找"的字面量在**场景 + 全部 prefab(920 个名字)**中都不存在;B 场景里客户端组件的序列化字段为 fileID 0。 结果:A 类真命中 1 处、B 类 40 条(分类见下)。已记 BUG-026。
    • A 类真缺口(1 处):排行榜"查看阵容"弹窗没有卡牌节点 —— ClientRankPage 找 展示卡牌* 及子节点 卡牌名称/LV等级/星级图标Image (1..5), 在全部 498 个 prefab/场景/asset 里 0 命中 ⇒ 弹窗只有 层数/回合数/战力,没有卡牌。 ✅ 已核实不会崩:OpenLineup 按 _lineupCards.Count 循环,列表空即空转。
    • B 类分类(40 条):真缺口 5 项 —— ① ClientPopupService._maskRoot(弹窗无遮罩/无输入阻断) ② ClientHomeRedDotController._mailDot/_noticeDot(邮件/公告红点不显示;活动红点已接 ✓) ③ ClientHomePage._notice/ClientProfilePage._notice(提示文本静默不显示,ClientHomePage.cs:217 已有取证注释) ④ BottomFunctionIconView._icon/_label ×4(底栏图标/文字,目前无调用方) ⑤ 排行榜阵容卡(同 A 类)。 其余全部判定为非缺口(有兜底或本就可选):ClientUiPopup._popupRoot ×18 回退 gameObject、ClientShellController._popupService/_feedback 走 GetComponentInChildren、 ClientHeroPage._heroTabSelected/_guideTabSelected 代码注明可选、ClientHeroCard._teamBadgeNumber 仅编队用、ClientSystemFeedback._toastText 是旧版遗留(TMP 的 _toastLabel 已接)、 ClientMailPage._emptyHint 运行时自补、BUG-020 的两个文本字段刻意留空、BUG-019 四张表缺美术。
    • ✅ 本轮代码修复 1 处(潜伏崩溃):BottomFunctionIconView.Configure 原先没有判空,而 Bottom1..Bottom4 的 _icon/_label 都是 fileID 0 ⇒ 一旦有人调用就空引用抛异常。已改为逐项判空(未接线即跳过),语义不变。 另核实 ClientHomeRedDotController.SetVisible 有判空 ⇒ 红点只是"不显示",不会崩。
    • 证据:编译三目标 0 error;审计脚本可重跑(Logs/ui-contract-audit.ps1 → .md)。
    • 待授权(AGENTS.md §4:不擅自写场景):上述真缺口 1~5 项,全部用现成节点接线即可(唯 ⑤ 需新建或改为不显示); 其中 ① 遮罩、② 红点、③ 提示 属于交互稿明确要求的可见行为,建议优先。
    • 下一步:等负责人授权场景写入(或给出"不做"的取舍);期间可继续做不写场景的 UI 代码健壮性与契约核对。
  • 第 72 轮 · 流程文档同步(AGENTS.md §5/§6 的强制项)+ 消除两处与实况冲突的旧约束
    • DEVELOPMENT_WORKFLOW.md(88 → 162 行): · ⚠️ 更正一处与实况冲突的强制约束:原文写"所有可导航页面必须位于 PagesLayer,弹窗在 PopupLayer,提示/遮罩/加载在 SystemLayer", 但实测:PagesLayer 只有 MainPage主页,其余客户端页面(英雄/编队/个人中心/商店/邮件/排行/活动…)都在 PopupLayer; SystemLayer 恒 inactive、Toast 挂在 ClientCanvas 下 ⇒ 已标注"在 RISK-020 定案前,本行不再作为强制约束"。 · 更正目录树:原文有 Assets/Client/Tests/,实测不存在;已改为 Editor/(含自检套件),并说明"不能直接用 UTF 的 asmdef 原因 + 改 asmdef 属架构变更需授权"。 · 新增 ## 2026-09-20 客户端阶段状态与决策记录(AGENTS.md §5 要求的阶段状态 + 决策记录): ① 本会话已完成项(8 项,各带证据文件);② 未完成/阻断;③ 负责人决策记录 7 条; ④ 待拍板 6 项;⑤ 三条命令行验证入口。
    • PROJECT_OVERVIEW.md:Assets/Client 的状态从"C0 进行中"改为**"已表驱动"(10 张表、收口完成、自检 70 项通过); 并在"启动与资源链路(已核验)"补上与 BUG-025 一致的结论**:该链路只到 LoginScene,ClientShell 既不在构建设置也无人加载 ⇒ 现状构建的 WebGL 包进不到客户端 UI,三方案待选(指向 WEBGL_B0_GATE.md)。
    • 证据:纯文档改动 ⇒ 按 AGENTS.md §3 只做文本核对(行数/章节/关键词已复查); 确认 DEVELOPMENT_WORKFLOW.md 里已无"PagesLayer 强制约束"的现行冲突残留(只剩更正说明里引用的原文)。
    • 结论:桌面侧已无任何可推进项 —— 目标剩余部分(阶段 B 全部、阶段 A 的 3 处定向决策)必须由负责人输入。
  • 第 71 轮 · 客户端纯逻辑自检套件落地(阶段 A3「自动化测试」缺口关闭):70 项全通过
    • 新增 Assets/Client/Editor/ClientSelfTest.cs(菜单 Client/自检/运行全部纯逻辑自检;命令行入口 ClientSelfTest.RunAll)。
    • 先讲一个约束(决定了做法):Assets/Client 没有 asmdef ⇒ 代码在预定义程序集 Assembly-CSharp; 而 asmdef 测试程序集无法引用预定义程序集 ⇒ 不能直接用 Unity Test Framework(除非把客户端整体改成 asmdef = 架构变更,需你授权)。 因此采用 Editor 自检 + 命令行退出码:任一断言失败即以非 0 退出,可直接进构建前门禁 / CI。
    • 覆盖 70 项断言(均为高风险纯逻辑):表加载(英雄可见 49 / 道具 9)、元素映射(1..6 ↔ 光水土风火暗 + 越界不抛)、 道具类型映射(表 Type 只允许 1/3;背包项 ItemType 必须等于表 Type 的映射;**并真的走一遍"一键领取"**再校验)、 说明文本格式化(1→8%、15→9%、20→80%、无分档原样返回)、能力页签归属(页签名/主技能名/条数 12·1·0 + 守恒式:各页签条数之和 = 该英雄天赋表行数 13 ⇒ 无漏归属)、收藏品可见数(1/1/1/3/1 = ProfilePage 验收基准)、 远端 pkg 读取链(自建"3 行 Hero"的 pkg → 断言路径变远端且可见英雄 = 1 → 自删并复位)。
    • ★ 把上一轮手工做的"变异 pkg 验证"变成了自动化回归:日志实测三行 本地 Resources/Table…Hero 可用 49 / 表内 54 → 远端落盘包 config.pkg(1 张表);Hero 可用 1 / 表内 3 → 本地 …49 / 表内 54 ✓ 且安全:若 persistentDataPath/config.pkg 已存在,该项自检直接跳过,绝不覆盖你的数据。
    • 证据:编译三目标 0 error;Logs/self-test.log —— error CS 0 / 异常 0 / 通过 70 项 / 失败 0 项、退出码 0。
    • ⚠️ 首次运行 57 通过 / 6 失败,6 项全是我自己写错的期望值(把 DisplayName 当成主技能名、把英雄天赋表总行数当成各页签条数)。 修正后全通过 —— 这正是自检的价值:它先抓住了写测试的人。留档 Logs/self-test.first-run.log 作对比。
    • ⚠️ 再次遇到 PowerShell 输出管线故障(out-lineoutput 异常,本次变体是 FormatEntryData ... not in the correct sequence), 导致一次 Unity 批处理看起来跑了其实没跑(日志时间戳新但内容是旧的)⇒ 我改成"先移走旧日志再跑"来消除歧义 ✓ 已记入文档。
    • 顺带确认(来自自检日志的 数据源 行):收藏品可见/表内 = 头像 1/6、头像框 3/9、徽章 1/6、铭牌 1/5、称号 1/9 ✓ (这与第 60 轮给你的 Play 预期 1/1/1/3/1 一致)。
    • 下一步:桌面侧已无可推进项(除文档/看板维护)。等你的 6 项决策。
  • 第 70 轮 · ClientItemType 语义修正落地(BUG-023 ② 关闭)+ 发现"装备判定永远失败"的真缺陷
    • 背景:你早前已同意方向("Type=1 货币 / Type=3 消耗品 / Type=2 表内无,改名与用法待做"),本轮落地。
    • 表实测(再确认):Item.json 共 9 行 —— Type=1:点数 / 源晶 / 晶核(货币);Type=3:启迪之星 / 共鸣结晶·绿蓝紫橙红(消耗品);Type=2 0 行。
    • 改动: · 枚举按表对齐:Unknown = 0 / Currency = 1 / Consumable = 3,2 不设成员(表内无该值 ⇒ 语义未定义,不猜); · 5 处硬编码改为表驱动 ResolveItemType(itemId)(邮件附件 / 活动奖励 / 两条奖励循环 / 任务奖励)—— 原先它们写的是 ClientItemType.Material(=1,正是"货币"的值),属语义错位; · 配置层本来就是对的:ClientItemConfig.Type 的注释已写明"1 = 货币、3 = 消耗品;2 表内未出现" ✓ 错只在领域枚举与本地模拟。
    • 🔴 副产物:一个真缺陷 —— 表内没有任何"装备"类型,而 TrySetEquipmentEquipped 依赖 ClientItemType.Equipment(值 2) ⇒ 该判定永远失败(装备功能实际不可用)。为不擅自引入未确认的产品规则,改为显式 IsEquippableItem(item)(当前恒 false)
      • 明确失败原因"装备功能尚未接入(配置表暂无装备类型)",行为与原先完全一致。等负责人确认装备的数据来源(配置表?服务端?)。
    • 验证:编译三目标 0 error;新增 ClientTableProbe.VerifyItemTypeMapping()(菜单 Client/配置表/验证道具类型映射(领取路径)) 真的执行"一键领取邮件附件"(ClaimAllMails)再逐项比对 —— 实测 [验证] 一键领取邮件附件:2 封、入包道具 110004(表 Type=3)ItemType=Consumable 期望=Consumable ✓、 结论行"与配置表完全一致"(Logs/verify-itemtype.log,error CS 0 / 异常 0)。 另在基线探针里加了不变式自检(背包项 ItemType 必须等于表 Type 的映射),Logs/b1-prebuild-baseline2.log 三项全 ✓。
    • ⚠️ 工具坑复现:PowerShell out-lineoutput NullReference 又出现一次(已知问题),重跑同一命令即成功 —— 已在文档里记为已知现象。
    • 下一步:等负责人拍板(构建入口 A/B/C 等 5 项)。本轮是"你已同意方向"的最后一项可落地内容; 之后桌面侧仅剩"保持文档/看板同步",其余都需你的决策或美术资源。
  • 第 69 轮 · 客户端启动阶段判定表(真机日志"卡在哪一步"速查)
    • 取证结论(启动链):场景根节点 = ClientBootstrap + ClientCanvas + EventSystem 平级; ClientCanvas 下为 PopupLayer / PagesLayer / SystemLayer / ToastRoot; 入口组件 = ClientCanvas 上的 ClientShellController + ClientUiNavigator + ClientSystemFeedback + ClientUiClickTracer; 真正的数据初始化在 ClientBootstrap.cs:12-14(ClientServices.InitializeForDevelopment() → [Client] Local development data initialized.)。
    • ⚠️ 重要限制(已写入文档):工程没有 ProjectSettings/MonoManager.asset ⇒ 未配置脚本执行顺序 ⇒ 各 Awake/Start 先后未定义。因此判定表按"哪条标记缺失"使用,不能按"顺序对不对"判断。
    • 7 个启动标记 + 缺失含义(写进 WEBGL_B2_DIAGNOSTICS.md §2.2): [配置表] 数据源:… / [配置表] 其他:道具 N(…) / [Client] Local development data initialized. / [Client] 组合根注入完成:弹窗宿主 N 个,提示宿主 N 个。 / [Client] PopupLayer 收录弹窗:按 pageId 路由 N … / [Client] 从场景自动收录 N 个未登记页面。 / [Client] 导航能力已注入 N 个页面视图,导航观察者 N 个。
    • 典型组合判读:① 一条都没有 ⇒ 场景没加载或卡在 Wasm/资源初始化(走 §3/§4 采集,先别怀疑表或 UI); ② 有"data initialized"无 [配置表] ⇒ 配置服务初始化失败;③ 有数据源但 解析失败>0 ⇒ 表链问题(=真机验证点①); ④ 有组合根/导航标记但无页面数据日志 ⇒ 页面未进入,取 ClientUiTrace 的 导航/弹窗 追踪行。
    • 另记录:运行时关键动作由 ClientUiTrace.Line("导航"/"弹窗"/"追踪", …) 输出,真机采集时要保留这些行(它们是"点不动/关不掉"类问题的证据)。
    • 本轮无代码改动(纯取证 + 文档;按纪律不预先加日志代码)⇒ 无需重新编译。
    • 下一步:等构建入口决策(BUG-025)。桌面侧剩余可做项已不多,主要转为保持文档与看板同步、以及在你给规则后接剩余缺口。
  • 第 68 轮 · 构建前全量基线探针(真机比对基准)+ 顺手验证了 ProfilePage 的 Play 预期
    • 新增 ClientTableProbe.LogFullBaseline()(菜单 Client/配置表/打印构建前全量基线):在既有覆盖之外补上 运行环境 / 玩家状态层 / 各页面数据条数 / 收藏品三层对账(表内可见 · 已拥有 · 使用中),一次跑出可复查的基准。
    • 实测(Logs/b1-prebuild-baseline.log,error CS 0 / 异常 0 / 解析出错 0): · 平台 WindowsEditor、读表路径 本地 Resources/Table、表汇总 可用 10 / 空 0 / 缺失 0 / 解析失败 0、Hero = 54 行(可见 49); · 英雄列表 49 个(首个 13003 蝎子精 / 元素1(光) / 品质3);Stats 页签数 3、普攻 捣药杵击、属性 id1 = 1500; · 玩家 体验玩家 / local-player / 战力 100【待确认】;主页展示与主力英雄均 13003;编队队伍 0/4、当前队伍战力 0;装备弹珠 marble-001; · 背包 3 / 商城 3 / 卡池历史 0;邮件 2 / 任务 2 / 公告 2 / 弹珠 2;排行榜 战力 5 / 挑战 5;活动任务 Newbie 5 + Advanced 5;赛季活动 6; · 收藏品(表内可见/已拥有/使用中):Head 1/1/10001、Badge 1/1/10002、Nameplate 1/1/10001、HeadFrame 3/2/10002、Title 1/1/10002。
    • ★ 顺带验证了第 60 轮给你的 Play 预期:我当时说"收藏品应显示 头像 1 / 徽章 1 / 铭牌 1 / 头像框 3 / 称号 1", 本轮基线正好是 1/1/1/3/1 ✓ —— 说明 Play 验收时列表条数应与此一致。
    • 已写入 WEBGL_B2_DIAGNOSTICS.md §2.1(含复现命令与真机判读须知:不要用"数量不同"直接推断服务端或配置问题)。
    • ⚠️ 我又犯了一次"不查就写":新方法里我猜了枚举成员(ClientLeaderboardKind.Battle、ClientActivityTaskCategory.Seasonal), 编译报 2 个 CS0117。查证后:ClientLeaderboardKind = { BattlePower, Challenge }、活动任务只有 Newbie/Advanced(赛季内容走 GetActivities(),不是任务)。 教训:任何类型/枚举/方法名都要先 grep 定义再写,不允许凭印象拼。
    • 数据层观察(非缺陷,待确认):玩家战力 = 100 而 当前队伍战力 = 0 —— 两者口径不同(前者本地模拟展示值,后者是队伍各槽位英雄战力之和,而英雄战力属服务器下发),展示口径需负责人确认。
    • 下一步:等构建入口决策(BUG-025);桌面侧可继续的是把"客户端启动阶段清单"整理成文档(按纪律不预先加代码)。
  • 第 67 轮 · B1 构建清单 + B2 证据采集清单(两份可直接执行的移植文档)
    • 新增 WEBGL_B1_BUILD.md:前置条件(含"BUG-025 未定则构建无意义"的开工先决)、8 步链路 (① 命令行探针验证 → ② HybridCLR AOT/WebGL 热更 dll(Assets/Editor/HybridCLR/WebGLHotUpdateDllCommand.cs)→ ③ YooAsset 构包 [GUI] → ④ Unity WebGL 构建 [GUI] → ⑤ WX 转换 [GUI](WXEditorWindow/WXConvertCore,产物 webgl/+minigame/、模板 wechat-default)→ ⑥ 开发者工具预览 [GUI] → ⑦ 真机(授权人)→ ⑧ 归档)、逐步校验标准、失败排查表、证据归档命名约定。 明确标注 [GUI] 步骤由负责人执行,代理只备前置与校验。
    • 新增 WEBGL_B2_DIAGNOSTICS.md:按 AGENTS.md §4 纪律只列采集项、不写根因。 · 可用日志通路已确证存在:WX.SetEnableDebug(WX.cs:2294)、WX.GetLogManager(:4507)、WX.GetRealtimeLogManager(:4519)(真机黑屏最有用,可在小程序后台看,不必连线); · 客户端已有日志标签判读表:[配置表] 客户端读表路径… / 汇总:可用 N 张…解析失败 N 张 / 逐表行数 —— 并给出桌面基准(Logs/pkg-verify4-local.log、Hero = 54 行); · BUG-009 8 条采集项(完整 Console≥30s、WebGL2 上下文、资源包初始化成功、[配置表] 段是否存在、全部 Error 原文、缺失 Shader 完整列表、 首屏形态(黑屏/全白/有 UI 无 3D…)、清缓存复采、真机 RealtimeLog); · BUG-013 6 条采集项(game.json/app.json 启动页字段只读、转换日志与产物、加载阶段日志序列、框架 js 与 worker 加载、默认首屏图); · 三个 WebGL 验证点的真机判据与失败时先采什么;真机回归矩阵(按 §5 B2,含记录格式"未测试不能标记通过"); · 最小可回收诊断仅作提案([Boot] N/4 … 阶段标记 + RealtimeLog),等采集结果出来再决定是否加(现在加属无证据的猜测性投入)。
    • 顺带确证(解决 B0 的"待采集"):YooAsset = com.tuyoogame.yooasset 2.1.1,位置 Assets/Main/Yooasset(工程内本地包,故 manifest.json 里没有条目); 已同步更新 WEBGL_B0_GATE.md §4 与 §7 并新增 §9 配套文档索引。 WX 转换器另有确证事实:WXConvertCore.cs 强制 PlayerSettings.WebGL.compressionFormat = Disabled、debugSymbols = true、 导出目录 webgl/ / minigame/、框架文件名 webgl.wasm.framework.unityweb.js、worker webgl.worker.js、默认首屏图 .../images/background.jpg。
    • 本轮无代码/场景改动(纯文档)⇒ 无需重新编译。
    • 下一步:等负责人定 构建入口 A/B/C(BUG-025);期间可继续桌面侧可做的事(例如把客户端启动阶段的日志标签补成一份"阶段清单"以便真机判读 —— 但按纪律不预先加代码)。
  • 第 66 轮 · B0 迁移前门禁:逐条取证,抓到一个硬阻断
    • 新增文档 WEBGL_B0_GATE.md(B0 门禁记录,供移植新会话直接使用):工具链版本与安装位置、WebGL 暴露面、 YooAsset/HybridCLR/XLua 兼容矩阵、首包/分包、真机环境、首次真机三个验证点、待负责人清单、证据索引。
    • 🔴 硬阻断(BUG-025):ProjectSettings/EditorBuildSettings.asset 只有一个场景 Assets/Main/Boot.unity; 全工程没有任何代码加载 ClientShell(只有编辑器工具引用路径常量);Boot.unity 里客户端引用出现次数 0。 ⇒ 按现状构建 WebGL,包内不含客户端场景,运行后永远到不了客户端 UI。 已给三个方案(A 加进清单并置首 / B 在 Boot 后追加加载 / C 新建 ClientBoot 场景),等负责人选。
    • 已留档的工具链事实:Unity 2022.3.57f1c2;URP 14.0.11;TMP 3.0.7;HybridCLR(gitee git 依赖,无版本号,另有 HybridCLRGenerate/); 微信小游戏 SDK com.qq.weixin.minigame 0.1.1(WXSDK,Tuanjie Engine Adapter);XLua 为工程内集成且含 WebGL 适配 Assets/Plugins/WebGL/xlua_webgl.cpp。 WX 转换 GUI 入口在 Assets/WX-WASM-SDK-V2/Editor/(WXEditorWindow / WXConvertCore / WXMultiPackageMergeWindow)。
    • WebGL Player 设置两处风险:stripEngineCode: 0(引擎代码剥离关闭 ⇒ 包体偏大)、webGLCompressionFormat: 2(Disabled); 其余:webGLMemorySize: 256、webGLInitialMemorySize: 32、webGLThreadsSupport: 0(线程关,与小游戏一致 ✓)、apiCompatibilityLevel: 6、allowUnsafeCode: 1。
    • 待采集(不当作结论):Packages/manifest.json 里没有 yooasset 条目,但工程确实在用 YooAsset ⇒ 其实际位置与版本未确证,已标为待采集。
    • 首次真机三个验证点已写入门禁文档:① 表读取链(persistentDataPath/config.pkg + Unity.IO.Compression 解压 + 回落 Resources/Table); ② Span/stackalloc 说明文本格式化;③ Resources/Table 体积(+174 KB)与首包/分包预算。
    • 本轮无代码/场景改动(纯取证与文档)⇒ 无需重新编译。
    • 下一步:等负责人定构建入口;同时可先在桌面侧把 B1 的构建步骤整理成可复现清单(不含上传/发布)。
  • 第 65 轮 · Rank 缺口可做部分已接:排行榜品质 / 立绘查找表 + 更正我自己的数量错误
    • 做了什么:新增结构修复步骤 FillRankVisualTables(),按工程内实际贴图重建 ClientRankPage 的两张查找表: · _qualities = 6 项(id 2..6 → QualityIcon_2..6.png,另加本地模拟占位 id quality-placeholder → QualityIcon_3); · _illustrations = 5 项(id 为英雄号 12001/13001/14001/15001 → HeroPortrait_*.png,另加 illustration-placeholder); · 刻意不填:_avatars(HeroAvatar_*)/_frames(AvatarFrame_*)/_badges(Medal_*)/_attributes(AttributeIcon_*)—— 工程内 0 个贴图,填了只会是空引用。
    • 契约依据(不是猜):ClientConfigModels 注释写明资源名约定 QualityIcon_<Quality>、HeroPortrait_<id>_c|_d; id 取自文件名后缀(AssetDatabase.FindAssets("QualityIcon_ t:Sprite")),因此将来美术补图后重跑一次即自动扩充。
    • 证据:编译三目标 0 error;Logs/repair-rankvisuals.log error CS 0 / 异常 0 / 30 处变更; 场景 YAML 复核:_qualities 6 项、_illustrations 5 项均带 Sprite 引用(fileID 21300000 + guid),其余 4 张表为 [] ✓。
    • ⚠️ 更正我自己的数据错误(第 62 轮):我当时写「QualityIcon_* 20 个 / ElementIcon_* 10 个 / HeroPortrait_* 8 个」—— 实测是 5 / 5 / 4(Get-ChildItem 按 .png 计数)。已同步更正 BUG_TRACKER 与 MODULE.md。 另一个实测发现:ElementIcon_* 只有 _1.._5,元素 6(暗)没有图。
    • 教训:数量类结论必须来自一次明确的计数命令,不能靠印象外推;报告里已写出的数字也要能回溯到命令。
    • 仍未解:_avatars/_frames/_badges/_attributes 四类需美术补图(映射规则已明确:收藏品经 Resources 表得 AvatarFrame_* / Medal_* 等)。
    • 下一步:B0 迁移前门禁(阶段 A 已收口到"等负责人拍板三处"的状态)。
  • 第 64 轮 · ActivityPage 缺口结案:没有缺口(又一条过时记录被推翻)
    • 取证方法与结果(本轮最有价值的产出):把 ClientActivityPage 里所有"按名查找"的字面量抽出来(30+ 个), 逐个到 ActivityPage活动 子树(687 节点)核对 —— 32/32 全部精确命中(含双空格的 Newbie Task Button), 且数量自洽:12 张任务卡(12 × 任务进度条Canvas / 领取+待完成键Button / 进度条 / 已领取icon)、 60 个道具卡面(12 卡 × 5 奖励 × 道具卡面|道具名称|道具数量)、6 张赛季卡(6 × 活动标题|活动日期|红点|热门|标注文本)。 ⇒ UI 与代码的节点契约完全对齐。
    • 数据也是真的:ClientActivityPage 读 ClientServices.Data.GetActivityTasks(category), 而 LocalClientDataService 提供 新手 5 条 + 进阶 5 条 + 6 个赛季活动,并有 TryClaimActivityTask / TryClaimActivity / TryClaimCompleteGuideEvent 完整实现 ✓。
    • 可达:大厅入口 ClientCanvas/PagesLayer/MainPage主页/downCanvas/ActivityButton 存在 ✓, ClientHomePage.BindPrefabNavigation("ActivityButton", ClientHomeDestination.Activity) → ClientUiNavigator 映射到 ClientUiPageId.Activity ✓。
    • 唯一未接:SetSpriteResolver / RegisterSprite(按 image id 取图的解析器)没有任何调用方 ⇒ 领取/待领取标签图标保持模板烘焙图; 与 BUG-023 的"资源标识无解析通路"同源,不是本页缺陷。
    • ⇒ 正确结论:ActivityPage 是已实现、已对齐、已接本地数据、可从大厅抵达的页面;此前"只有结构/待实现"的记录过时。
    • 顺带核实(入口清单):ActivityButton = 1 ✓;TaskButton = 0、NoticeButton = 0 ⇒ 任务页与公告页在场景里没有入口(与"缺失页面显示开发中"一致); HomeDisplayButton / PersonalizeButton = 0(此前已记录,属历史兼容绑定,实际不命中)。
    • 本轮无代码/场景改动(结论是"无缺口")⇒ 无需重新编译。
    • 阶段 A 剩余:Rank 的"品质一类可接"(资源已具备)+ BUG-024 / RISK-020 / BUG-023 三处等负责人拍板,然后进入 B0 门禁。
  • 第 63 轮 · Mail 缺口结案:真实缺口只有一个(详情/状态无文本节点),另更正三条过时记录;看板已建
    • 看板已启用(更正我此前"board_* 工具不可用"的错误结论):工具要求 POSIX 风格路径 /d/unity project/pinball, 传 D:\unity project\pinball 会被拒为"must be an absolute path"。已建 3 个主任务 + 13 个子任务(阶段 A / 阶段 B / 两项 WebGL 降风险改造)。
    • Mail 取证结论(ClientMailPage 组件实例 1008869757): · 可用的:邮件列表走"1 模板 + 运行时克隆"✓,克隆体已绑 SelectMail(index) ✓,ClaimAll / TryClaimMail ✓, 列表项显示 邮件名称(含已读/已领取标记)、日期text、附件 道具卡牌prefab* ✓。 · 真实缺口:_detail(标题+正文+附件)与 _status(领取状态)在场景里 fileID 0, 且全页没有任何可接的目标节点 —— TMP 文本穷举只有列表项内的那几个;Email Title/Canvas/Emial title background frame/Email text 整棵子树没有文本组件(那个叫 Email text 的节点其实是 Image)⇒ 选中邮件看不到正文与状态。
    • ⚠️ 更正本页三条过时记录:① _emptyHint 不是缺口 —— ResolveMissingReferences() 运行时用 Find("Default") 自补 ✓; ② _mailLabels 的 2 槽旧机制已被模板方案取代(代码注释已说明)✓;③ 邮件卡已有点击绑定 ✓。
    • 记档 BUG-024:给出三个方案(A 在现有面板下新增/改造一个 TMP 正文区/B 正文改用已有 Email Details Page 弹窗/C 维持现状只显示列表),等负责人选(不擅自新建 UI 节点)。
    • 本轮无代码/场景改动(缺口属设计层,且 §4 要求不擅自建节点)⇒ 无需重新编译;文档改动已做文本核对。
    • 下一步:ActivityPage 缺口(阶段 A 最后一个未取证页),随后 Rank 的"品质一类可接"与 B0 门禁。
  • 第 62 轮 · 资源映射规则已找到 + 美术盘点(推翻"规则未定义")
    • 发现:Resources 表(256 行)的 Id → SkeletonData 就是"资源 id → 资源名"映射,收藏品 ResId 正是 Resources.Id: Title 51001→Title_51001、HeadFrame 52001→AvatarFrame_52001、Nameplate 53001→Nameplate_53001、Badge 54001→**Medal_54001**(徽章资源名叫 Medal)。
    • 美术盘点(按名搜 Assets,排除 .meta):有 = QualityIcon_*(20) / ElementIcon_*(10) / HeroPortrait_*(部分,实测 8 个); 没有 = HeroAvatar_* / Title_* / AvatarFrame_* / Nameplate_* / Medal_* / Item_* / CatapultIcon_* / AttributeIcon_*。
    • ⇒ BUG-023 ① 与 BUG-019 的阻断原因更正为"部分美术缺资源"(不是"规则未定义"):品质 / 元素 / 立绘可立即接,其余等美术补图或确认走热更包。
    • 另发现一处"接口与 prefab 对不上":卡prefab 有 品质Image / 属性图标Image 节点,但 ClientHeroCard 没有对应字段 ⇒ 卡片要显示品质/元素徽标需加字段 + 接线。
    • BUG-020 已修并验证:_progressFill 已接(场景复核 fileID 1451101832),修复日志 error CS 0 / 异常 0 / 19 处变更。
    • 文档修整:本文件第 57~61 轮的"轮次标题"此前被我插错位置(标题挤在一起、正文交错、顺序倒置),本轮按每轮首条 bullet 的标记重排; 现约定 最新轮次放在最上,新增轮次请插在当前第一条轮次标题之前。
  • 第 61 轮 · 阶段 A 收口:两个"关不掉的弹窗"结案(其中一条是过时记录)
    • 结论(有代码/场景证据): · Purchase Success Page 并不存在"关不掉"问题 —— ClientShopPage 第 233 行 Set(_success, true) 打开它, 第 288 行 BindSuccessDismissHandlers() 在运行时遍历它的全部 Graphic、恢复 raycastTarget 并补 ClientShopCloseOnClick(→ CloseSuccessPage), 注释里写着负责人要求"点击任何地方直接退回购买界面" ⇒ 关闭路径完整 ✓ · Success Receipt Interface 是"死内容":全工程只有结构修复工具里的 LayerMove 引用它, 没有任何运行时代码打开它;根节点没有 Image(无点击区)、子节点也没有 Button ⇒ 既打不开也无从关闭。 ⇒ 它不是可用性阻断项,而是"尚未确定用途的场景残留"(进入条件属产品决策)。记录为待确认,不擅自删除。
    • 因此 MODULE.md §14 与旧总清单里"Purchase Success Page、Success Receipt Interface 交互节点数为 0,打开后无关闭手段"的说法已过时,本轮更正。
    • 取证方法(可复用):① 用脚本把场景组件的 m_Script guid 解析成类型名(区分 TMP/UGUI Text/Image/Button/GraphicRaycaster); ② 用 git/全工程 grep 找"谁打开它";③ 用 ClientShopPage 这类宿主页面的 Bind/BindSuccessDismissHandlers 判断"运行时是否补了点击处理"。
    • 教训(与第 59 轮同源):审计文档里的结论会过时,接手前必须用当前代码/场景复核;本轮与上一轮各发现一条("主页展示有 9 张卡"、"两个弹窗都关不掉")都是过时记录。
    • 下一步:继续阶段 A 的 Shop / Rank / Mail / Activity 缺口(BUG-019 / BUG-020 等)。
  • 第 60 轮 · ProfilePage 收口执行完成(5 个收藏品列表 + 主页展示 + BUG-018),等 Play 验收
    • 工具侧(ClientShellStructuralRepair): ① ListTarget 增 TemplatePrefix —— 实测这些列表的第一项常是"未解锁"节点(徽章未解锁Image (3)), 直接取 items[0] 会把未解锁项当模板;现在按前缀优选(已解锁),并删除除模板外全部内联项。 ② 新增 FindByPathTrimmed 兜底 —— Unity 用单引号包裹带尾空格的节点名(m_Name: 'Panel_Personalize ',真实名字尾部 2 个空格), 把尾空格写进 C# 字面量极易被吃掉,故每段按 Trim() 匹配。 ③ 新增 EnsureProfileShowcase():主页展示容器是空的 ⇒ 用 PrefabUtility.InstantiatePrefab 新建隐藏模板卡(保留 prefab 关联)+ WireHeroCardOn 补组件/接线。 ④ 新增 WireProfileTexts():按路径取 TMP 组件接到 _playerName/_playerId/_combatPower。 ⑤ ListTargets 增 5 条 ProfilePage 收藏品列表(Approved=true,负责人已授权)+ ClientProfilePage 分派分支。
    • 场景写入结果(Logs/repair-profilelists.log,error CS 0 / 异常 0 / 共 53 处变更): · 5 个容器各剩 1 个 inactive 模板:头像Item[0] / 徽章Item[0] / 铭牌Item[0] / 头像框Item[0] / 称号Item[0] ✓ 模板选取正确:徽章已解锁image -> 徽章Item、小铭牌已解锁image -> 铭牌Item、称号已解锁-无image -> 称号Item(没有被未解锁项抢走)✓ · 展示卡Item 已新建(prefab 实例)+ 已挂 ClientHeroCard + _showcaseTemplate/_showcaseRoot 已接线 ✓ · _playerName / _playerId / _combatPower 三条 TMP 文本已接线 ✓;ClientProfilePage 共 15 个字段全部非 0 ✓
    • 代码侧:新增 ClientCollectionItemView(只写控件)/ ClientCollectionList(1 模板 + N 实例,范式与 ClientHeroCardList 一致); ClientProfilePage 重写:TMP 字段类型(BUG-018 根因)+ 5 列表 + 主页展示 + 文本绑定 + 点击装备(未拥有给提示,不报错)。
    • ⚠️ 本轮我造成并已修复的事故:重写 ClientProfilePage 时没读全原文(读取被截断)就整文件覆盖, 丢掉了 BindPageActions / BindButton / CancelRename / ConfirmRename。已从 git diff 恢复原始语义补回。 关键事实:场景里唯一的 UnityEvent 是 3 个 SetActive,没有任何按钮通过场景事件调用这些方法 ⇒ 丢失后表现是"按钮没反应且不报错"。 教训:覆盖整文件前必须完整读取原文件(读取被截断时先取回全文)。
    • 🔍 工具盲区(已记录):prefab 实例根节点的名字存在 PrefabInstance 的 m_Modifications(propertyPath: m_Name)里, 不在 GameObject 文档中 ⇒ 我的场景解析脚本扫不到它(首轮因此误判"展示卡Item 不存在")。判定实例类节点要另查 PrefabInstance 块。
    • 待验收(请 Play 个人中心):5 个收藏品列表应显示 头像 1 / 徽章 1 / 铭牌 1 / 头像框 3 / 称号 1(按 ClientShow 过滤的真实条数),未拥有的显示"未解锁"子节点; 玩家名 / 玩家ID / 战力 应有值(王…/玩家ID: …/战力数值);主页展示应有 1 张卡(点击进"主页展示"页更换)。
    • ⚠️ 已知未接:收藏品图标未解析 —— ResId(整型资源 id)→ Sprite 的映射规则未定义(与 BUG-019 同类阻断),Head 用的 HeroAvatar_* 贴图工程内 0 个; 故当前保持模板图。需要负责人给出映射规则或认定可用贴图后补接。
  • 第 59 轮 · 阶段 A 收口启动:ProfilePage 取证完成 + 两个新组件落地(未写场景)
    • 负责人决定:SystemLayer 先不动,要影响分析(→ 已记 BUG_TRACKER.md RISK-020,含 A/B/C 三方案与推荐 C); ProfilePage 场景写入全部授权(主页展示 + 5 个收藏品列表);BUG-018 可以一起做。
    • ⚠️ 先纠正一处我自己的失实:上一轮我口头说"已记入 RISK-020",实际没有写入文件 —— 本轮已补上(BUG_TRACKER.md 共 373 行)。教训:说了写了就必须真的写。
    • BUG-018 精确定位(含组件类型核对,AGENTS.md §4 要求):场景里这三个文本是 TMP_Text(guid f4688fdb…), 而 ClientProfilePage 把它们声明成了旧版 UnityEngine.UI.Text ⇒ 违反 §4,需改字段类型。节点: · 玩家名 = Panel_Profile/底框/玩家名称Image/Text (TMP) · 玩家ID = Panel_Profile/底框/玩家IDImage/Text (TMP)(另有 downImage/ID卡底框Image/Text (TMP) = ID 卡号码) · 战力 = Panel_Profile/MiddleImage/Panel1/战力底框/Text (TMP)(另有 战力排行Image/Text (TMP))
    • ProfilePage 列表结构取证:Panel_Showcase/展示卡牌Scroll View 1/Viewport/Content = 空容器(0 项); 5 个收藏品容器各自 Content_*/*Scroll View/Viewport/Content,条目名形如 头像已解锁Image (2) / 徽章未解锁Image (1) / 小铭牌已解锁image / 称号已解锁-无image; 每个"已解锁"条目内部已带一个未解锁子节点(头像已解锁Image/头像未解锁Image/Image)⇒ 1 模板 + 切锁子节点即可表达拥有/未拥有。
    • 新增两个组件(编译通过,尚未接场景):Assets/Client/Runtime/UI/ClientCollectionItemView.cs(只写控件:图标/未解锁子节点/使用中标记/点击;值没变不写)、 ClientCollectionList.cs(1 模板 + N 实例,多余的隐藏不销毁;与 ClientHeroCardList 同一范式,且不依赖领域模型)。
    • 已核实不是回归:ProfilePage 下从来没有 角色卡牌Button-final 1(最老备份与当前场景都是 0);ConvergeKnownLists 白名单只有 Shop/Mail/Hero/Formation 四个容器,没碰过 ProfilePage; 审计里"主页展示有 9 张英雄卡"的说法与实场景不符(该容器一直为空)。⇒ 主页展示列表必须新建 1 张隐藏模板卡(已获授权)。
    • 下一步:① 扩展 ListTarget/ConvergeKnownLists 支持 ProfilePage 6 个列表(注意 已解锁image 小写 i 与 称号已解锁-无image 的命名陷阱); ② 改 ClientProfilePage(TMP 字段类型 + 5 列表 + 主页展示 + BUG-018 文本绑定 + 点击装备);③ 编译 → 场景写入 → 探针/场景复核。
  • 第 58 轮 · 两项 WebGL 降风险改造(①②)完成并运行时验证
    • ① ClientTableSource 的 gzip 换成工程同款 Unity.IO.Compression: Assets/Unity.IO.Compression/Unity.IO.Compression.asmdef 未写 autoReferenced: false ⇒ 默认 true,Assembly-CSharp 可直接引用 ✓; 已把 using System.IO.Compression; 换成 using Unity.IO.Compression;(与 TableLoadHelper 同源),消掉"WebGL 下 System.IO.Compression 未验证"这个未知。
    • ② ClientServerPcSession 加平台条件编译:该组件挂在 ClientShell 场景里(guid 出现 1 次)⇒ 不能整体编译掉(会变 Missing Script)。 做法:#if UNITY_WEBGL && !UNITY_EDITOR 下留同名空壳 MonoBehaviour,其余(TcpClient / System.Net.Sockets / Task.Run / 网关反射发现)整段进 #else 不参与编译 ⇒ 小游戏包不再带 PC 网络栈。
    • 验证(Logs/pkg-verify*.log):Roslyn 三目标 0 error,且 WebGL profile 也 0 error(证明引用解析成功 + WebGL 分支走空壳); 命令行 Unity 全工程编译 + 探针 0 error / 0 异常。
    • ★ 额外收获:首次验证了"远端表"整条链。方法(可复用,建议 B 阶段照用): 用 PowerShell 造一个合法 pkg(GZip → [version=1byte] → 反复 [utf8\\0][utf8\\0])放到 {persistentDataPath}\\config.pkg, 并把里面的 Hero 变异成只有 3 行;探针实测 读表路径:远端落盘包 config.pkg(1 张表) + Hero = 3 行 + 英雄列表 = 1 个 ⇒ Unity.IO.Compression 解压、pkg 解析、远端优先、按表回落全部在真实运行时证明有效(不是空内容的弱测试)。删掉 pkg 后再跑 ⇒ 本地 Resources/Table + Hero = 54 行 ✓ 回落正确。
    • ⚠️ 又一次 PowerShell 坑(第 3 次同类):测试夹具用 @(@("Hero", $json)) 会被展平成 ("Hero", $json),导致 $pair[0]="H"、$pair[1]="e" —— 夹具写坏、差点误判成客户端 bug。改用 List[byte] + AddRange 后一次通过。数组展平是本机 PowerShell 的高频陷阱。
    • 下一步:阶段 A 收口 —— ProfilePage 收藏品列表 / Shop·Rank·Mail·Activity 缺口 / 两个无法关闭的弹窗 / SystemLayer 分层定案。
  • 第 57 轮 · 新建 Stats 模块(数值与说明)—— 按负责人架构原则一次到位
    • 负责人原则原话:数据只由权威服务器计算并分发,客户端负责 属性接口、技能/天赋数值接口 与 逻辑说明显示;单独成模块,贴近 MVC,强解耦 / 拓展性强 / 维护方便 / GC 消耗少,且"这是所有代码和设计的原则"。
    • 新增 17 个文件(模块根 Assets/Client/Runtime/Stats/,自带 MODULE.md): Model/(7:属性 id / 属性值 / 能力种类 / 页签 / 能力状态 / 能力条目+页签+英雄能力集,纯 C# 零 UnityEngine 依赖)、 Gateway/(2:IClientStatsGateway 服务端契约 + LocalClientStatsGateway 扮演服务器)、 Service/(3:★ClientAbilitySectionRule 唯一映射点 + 接口 + ClientStatsService)、 Format/(2:说明文本接口 + ClientDescriptionFormatter)、 View/(4:图标解析委托 + 属性行 / 能力条目 / 能力页签三个 View)。
    • 硬约束已落到代码:接口里没有任何"计算"形态的方法;配置表只被 Service / Format / Gateway(扮演服务器时)读取;本地模拟只在 Gateway 里;说明文本只有 Format/ 一个出口,View 不拼字符串。
    • GC:能力集合按英雄建一次原地刷新;属性用复用列表;查询全 for+索引(无 LINQ/无接口 foreach);说明文本 (id,level) 缓存且"无分档时直接返回模板字符串本身";View 值没变不写控件;强化列表对象池;事件用缓存委托并在 Dispose 解除。
    • 验证(Logs/stats-module-probe3.log;Roslyn 三目标 0 error + 命令行 Unity 全工程编译 + 探针):error CS 0 / 配置表解析出错 0 / 异常 0; 3 个页签 = 天赋(玉兔灵药) / 秘技(月华追踪) / 终结技(广寒月影)、普攻 = 捣药杵击; 格式化自检:等级1=…8%…、等级15=…9%…、末段共用后缀(等级20)=…80%…、单个数字不动; 属性(英雄 13003):Hp1500 Atk480 Def160 Spd65 暴击400 暴伤14500; 被动归属自检(13001):天赋 12 条 / 秘技 1 条(秘技强化 描述点名"月华追踪"⇒ 正确归秘技)/ 终结技 0 条。
    • 顺手修掉我自己的一个设计错误:原先 GetHeroSkills / GetHeroPotencies / TryGetHero 只查"前端可见"的英雄, 而"能不能按 id 查定义"与"列表要不要显示它"是两件事 ⇒ 新增 _heroByIdAll(表内全部)与 _heroById(可见)分开。
    • ⚠️ 数据侧发现(待负责人知晓,非代码问题): ① 49 个可见英雄的被动数据全是占位 [1,2],有完整被动数据的 4 个英雄(13001/14001/14007/15001)ClientShow 全为 0 ⇒ 正式数据补齐前,可见英雄的天赋页必然空态(已按"空着、不报错"处理)。 ② 被动 300112 天赋冷却 与 300113 秘技冷却 描述完全相同(都是"天赋技能冷却-1回合",疑似漏改)⇒ 按弱关联判断时 秘技冷却 被兜底归到天赋页。
    • 说明文本格式的实测纠正:分档是每段各自带单位(8%/9%/10%,码点 0038 0025 002F 0039…),不是我原先假设的"只有末段带 %";现已两种都支持。
    • 设计与约定见 Assets/Client/Runtime/Stats/MODULE.md(含目录、MVC 边界、GC 清单、禁止事项、6 条待确认项)。
    • 下一步:接页面(ClientHeroDetailPage 三个页签改成只绑 ClientHeroAbilitySet,属性行绑 GetAttributes);ClientItemType 语义修正。

📋 未验收 / 未实现 / 隐患 总清单(2026-09-20,来源:BUG_TRACKER.md + MODULE.md §14 + 本次只读审计)

A. 未验收通过的页面

页面 / 弹窗 验收 主要缺口
HeroPage英雄 ✅ 已验收 —
HeroDetailPage英雄详情主页 ✅ 已验收(BUG-016 / 017 已关闭) —
FormationPage编队 ✅ 已验收 元素筛选(明确不做)、搜索、查看卡面信息tips 未实现
ShopPage商店 ⛔ 未验收 卡面售价待 Play 核对;购买数量进度条未接线(BUG-020)
ProfilePage个人中心 ⛔ 未验收 玩家名/ID/战力不显示真实数据(BUG-018);个性化 5 个真列表 + 主页展示 9 张卡无数据源(§14)
MailPage邮件 ⛔ 未验收 _detail / _status 未接线;邮件详情无打开逻辑
RankPage排行榜 ⛔ 未验收 6 张精灵表全空(BUG-019)
ActivityPage活动 ⛔ 未验收 行为已正确但结构未收敛(需一次场景写入)
Complete Guide Event Page全图鉴活动 ⛔ 未验收 无实际逻辑
Product Purchase Interface、Purchase Success Page、Success Receipt Interface、Exchange code interface、Historical Order Interface、Pending shipmentCanvas、Email Details Page(Have)/(No)、Player lineup、联系客服Page ⛔ 未验收 多为 routed=0(仅按引用打开);其中 Purchase Success Page / Success Receipt Interface 交互节点数=0,打开后无法关闭

B. 未实现的功能

  1. 整页缺失(有 pageId 路由、场景无页面):扭蛋 / 背包 / 任务 / 公告 / 弹珠 —— 现由首页「开发中」提示兜底;HeroEnhance 连 UI 入口都没有。
  2. ProfilePage 个性化:头像(5) / 徽章(5) / 铭牌(9) / 头像框(2) / 称号(3+3) 五个真列表 + 主页展示 9 张卡 —— IClientDataService 无任何集合 API,ClientItemType 也没有这些分类。
  3. 排行榜:头像/框/徽章/立绘/属性/品质的 id → sprite 映射未定义。
  4. 邮件:详情/状态区无数据;Email Details(Have)/(No) 与 Success Receipt Interface 代码里没有任何打开逻辑。
  5. 购买完成链:Purchase Success Page、Success Receipt Interface 交互节点=0。 2026-09-20 第 61 轮更正:Purchase Success Page 由 ClientShopPage.BindSuccessDismissHandlers() 在运行时补 ClientShopCloseOnClick ⇒ 可关(不是阻断项);Success Receipt Interface 不可达(无任何运行时代码打开),属待确认的场景残留。
  6. 红点系统:邮件/公告红点无节点(全场景只有 ActivityButton/RedDot)。
  7. 加载页:接口已备好(ClientLoadingService),未接入启动流程 —— 归移植会话。
  8. 弹窗遮罩:ClientPopupService._maskRoot 空 ⇒ 不阻断背后点击。
  9. 编队:元素筛选(负责人明确不做)、搜索、查看卡面信息tips。
  10. 英雄详情底部 4 键:BottomFunctionIconView._icon/_label 未接线。

C. 潜在隐患

  • 架构一致性:SystemLayer 恒 inactive,与 HANDOVER_PLAN.md §3(SystemLayer 承担 Loading / 遮罩 / Toast / Tips)冲突;本轮把 Toast 临时挂到 ClientCanvas ⇒ 偏离待负责人裁定。
  • 文档过期:MODULE.md §14 对编队的描述已过期(编队已实现验收、选卡已收敛为 1 模板、_slot/_status 已删),会误导后续会话(AGENTS.md §6 要求同步)。
  • "静默失效"惯犯:全场景 39 个组件带未接线字段,表现是"看着正常、其实是美术占位字" ⇒ 验收极易漏(BUG-018 ~ 020、RISK-015 已记;RISK-016 为良性排除清单)。
  • 本地模拟数据单薄:9 个英雄,无任务 / 公告 / 扭蛋 / 称号等集合 ⇒ 验收覆盖面不足。
  • 工具盲区:只读脚本看不到 prefab 实例内部(历史误判来源);场景中文为转义存储;pwsh 是 PS 5.1 且按 ANSI 读脚本(中文注释会让脚本解析崩)。任务看板 board_* 不可用,进度只能靠本文件。
  • 移植相关:Init.cs 的 Debug.LogError(progress) 每帧刷 error(会淹掉真机日志、妨碍排查黑屏);WebGL 未结项 —— BUG-009(首屏黑屏 + URP shader)、BUG-013(app.json 启动页)调查中,BUG-005/007/008/011/012/014 待验证,BUG-010/015 待重传/重转。
  • 仓库状态:工作区存在大量未提交改动与未跟踪产物(Bundles/WebGL 719 MB 等)⇒ 回滚与交接风险;RISK-014 挂着清理待办。
  • 基础设施已知重复:LitJson 重复程序集(RISK-007)、Timeline AOT 元数据(BUG-008)。

FormationPage 本轮落地(第 38 轮,全部纯代码、未写场景)

  • 数据契约(IClientDataService + LocalClientDataService,本地模拟、可替换):新增 GetFormationTeams() / GetFormationTeamIndex() / TrySwitchFormationTeam(int) / TrySetFormationSlot(int, string) / GetFormationCombatPower(int);新增领域模型 ClientFormationTeam(SlotCount=3、TeamCode、SlotHeroIds)。队伍数 4 与槽位数 3 取自场景节点,非杜撰。旧的单槽 GetFormationHeroId() / TrySetFormationHero() 保留为兼容写法 = 「当前队伍槽位 0」,_formationHeroId 字段已删除(单一数据源,§12.4)。
  • 卡牌管理器(§13):ClientHeroCard.SetTeamSlot(slotNumber, numberSprite=null);ClientHeroCardList.Show(..., Func<T,int> teamSlotOf, onClick) 重载。⚠️ 编号数字 实测是 Image 而非文本,写不了数字,只能换 sprite → 数字贴图来源待确认。
  • 页面接线:ClientFormationPage 由 38 行扩到完整实现 —— 3 槽位、4 队伍(左/右Button + 编组号-Text)、英雄选择列表(ClientHeroCardList)、战力 文本、后退Button;_slot/_status 全部判空。
  • 刻意不实现(映射未定义,避免把猜测当规则):① 元素筛选 全/光/水/土/风/火/暗 与数据侧 Element("Fire"/"Water") 的对应;② 选中点1..4 的当前队伍高亮表现、确认键Button 语义。
  • 场景写入已完成(第 39 轮;负责人授权“自动关和开”,由代理执行):RepairAll 跑了两遍。 第一遍暴露一个顺序 bug:ConvergeKnownLists() 排在卡牌接线之前,收敛先把选卡改名成 编队英雄卡Item、删掉其余 8 张,之后按原名 角色卡牌Button-final* 找就0 张(日志原文: 编队卡牌-Panel 下接线卡牌 9 处 / Scroll View/.../Content 下接线卡牌 0 处)。 修正为「接线在收敛之前」并让匹配器同时认收敛后的模板名(保证幂等)后,第二遍 14 处变更、无删除。
  • 场景文件复核(不信日志,只读解析场景 YAML):ClientHeroCard 全场景 2 → 6 处 (HeroPage 2 + 编队 3 张槽位卡 + 选卡模板 1);模板名 编队英雄卡Item 已改名且已禁用; ClientFormationPage._cardTemplate=fileID 2015043900、_cardListRoot=fileID 302072625,均非 0。
  • 备份:Logs/ClientShell.before-formation-cards.unity.bak、Logs/ClientShell.before-formation-cards-2.unity.bak。
  • ✅ 已整页验收通过(负责人 2026-09-20:“哦牛逼,完美”)。验收确认的效果: 选卡 9 张(含 3 张带锁)参数各异;点卡即切换(自动补最小空位 / 再点移出且不补位 / 满员不加入); 编号 1/2/3 显示在选卡上并随编队动态变化;3 个槽位格位保留(空槽卡面为空); 左/右Button 切 4 支队伍(编组号 01→02…);战力 随队伍变化。
  • ⚠️ 下方“元素筛选/选中点高亮/确认键语义未做”“_slot/_status 待拖拽”等描述, 均已在第 40 / 41 轮处理完毕(详见对应段落)—— 保留原文仅为时序证据,勿据此重做。

第 40 轮(负责人验收反馈 → 立即执行三件)

  • 元素筛选:不做(负责人明确“不实现了”)。已删除 ClientFormationPage.SetElementFilter;ClientHeroPage.SetElementFilter 是既有的空壳,未动。
  • 选中点1..4 高亮:已实现。取证:4 个点是同一贴图、同一颜色(m_Color (1,1,1,1)、raycastTarget=0),工程里没有“选中态”变体 ⇒ 只能按 alpha 区分(_teamDotDimAlpha,默认 0.35,可在 Inspector 调)。另记:4 个点的名字编号与屏幕横坐标相反(选中点1 在最右),代码按“名字编号 = 队伍编号”理解。
  • 确认键Button:已实现 = 确认并返回(_navigation.Back())。理由:本地模拟是即时写入(点卡即存),没有独立“保存”动作;若语义另有要求,改 ConfirmTeam() 一处。
  • _slot / _status:硬阻塞,无法接。取证 —— 编队页只有 3 类文本节点(编组号-Text / 战力 / 卡上的 等级-Text,前两个已各有所属),查看卡面信息tips-Image/Image 无文本子节点;且 SystemLayer 下只有 加载Page,根本没有 Toast 节点 ⇒ ClientSystemFeedback.ShowToast 现在只会打警告。两个字段目前全判空、安全但无可见反馈。待负责人决定:指一个节点 / 批准新建一个文本节点(属新建 UI,需明确批准)/ 直接删掉这两个字段。
  • 本轮 Roslyn 三目标 0 error(Logs/verify-compile-formation3.log)。

第 41 轮(负责人三条要求 → 全部落地;本轮无需场景写入**)**

  • 同队不可重复英雄(数据规则):LocalClientDataService.TrySetFormationSlot 中,若该英雄已在同队其它槽位 ⇒ 返回 false 且不改任何状态,由页面提示。依据负责人“原则上不能选重复的英雄”。(若日后想改成“自动把它从旧槽位移过来”,只改这一段。)
  • 空槽位:改为保留格位、只清空卡面 —— 新增 ClientHeroCard.SetContentVisible(bool),只切子节点、不动本节点。原因:槽位容器带 HorizontalLayoutGroup,隐藏本节点会让其余槽位重排。同时空槽不再显示成“一张未解锁的卡”(不再走 Apply(unlocked:false))。
  • 删除 _slot / _status:连同只服务它们的 Configure(GameObject, Text, Text) 一并删除;SetStatus 改为 Debug.Log("[Client] 编队:…");编辑器工具里那句“请拖入文本节点”的日志同步更正。原因:编队页只有 编组号-Text / 战力 / 卡上 等级-Text(前两个已各有所属),SystemLayer 下也没有 Toast 节点。
  • 本轮 Roslyn 三目标 0 error(Logs/verify-compile-formation6.log)。

第 44 轮(两条路径都能移出 —— 纯代码)

  • 槽位卡也接上同一个 toggle:点槽位卡 = 点选卡上那张编号卡,二者都能把该英雄移出编队 (槽位里既然有人,TryToggleFormationHero 必然走“移出”分支、不补位)。 实现只在 RefreshSlots 里把 onClick 从 null 换成 () => SelectHero(heroId)(捕获的是英雄 id,不是循环变量)。 选卡的 Button 与槽位卡的 Button 场景里本就都有(修复日志:“已有 Button 或未匹配到,跳过”)。
  • Roslyn 三目标 0 error(Logs/verify-compile-slotclick.log)。

第 45 ~ 47 轮(UI 收口:导航死目标 + 全局视觉 Toast —— 代码 + 一次场景写入)

  • 第 45 轮 · 只读普查:全场景内联列表汇总落 Logs/verify-inline-census.txt;ClientUiPopup 注册表显示可按 pageId 路由的弹窗只有 9 个(Profile / Hero / HeroDetail / Shop / Mail / Rank / Activity / Formation / CompleteGuideEvent),其余 10 个仅按引用打开。
  • ⚠️ 我误报过一次,已纠正:曾断言 ClientProfilePage 两个入口“点了没反应”。实测场景里根本没有 HomeDisplayButton / PersonalizeButton 节点,而 BindButton 用直接子节点查找 ⇒ 那两行是从未被调用的死代码;个人中心没有问题(3 面板切换一直由 ClientProfileNavigationController 负责)。教训:看到调用点先查节点是否存在,再下结论。
  • 第 46 轮 · 开发中提示:真正要处理的是 GachaButton / BackpackButton(场景中确实存在、确实会触发导航)。新增 IClientHomeNavigation.CanOpenFromHome(destination)(查弹窗注册表 + PagesLayer 注册表);ClientHomePage.RequestNavigation 先判定再导航,不可达则提示「XXX功能开发中」并返回(顺带不改底部页签选中态)。判定是动态的 —— 以后补页并注册后,提示自动消失、入口自动生效。
  • 第 47 轮 · 全局视觉 Toast(场景写入):取证到两处“只进日志”的根因 —— ClientSystemFeedback._toastRoot 为空(ShowToast 只打警告)+ ClientHomePage._notice 是 fileID 0(ShowNotice 只 Console)。已在 SystemLayer 下新建 ToastRoot + ToastLabel(深色半透明底 + 白字居中、raycastTarget=false 不吞点击、字体沿用 Assets/Resources_HotUpdate/Font/TextMeshPro/Tips SDF.asset、默认隐藏)并接线;ClientHomePage 新增 IClientFeedbackHost,ShowNotice 优先走全局 Toast。
  • 场景复核(读场景文件):ToastRoot / ToastLabel 已存在;ClientSystemFeedback._toastRoot = 832108125、_toastLabel = 1405690691、_toastDuration = 2。备份 Logs/ClientShell.before-toast.unity.bak;批处理 15 处变更、0 错误(Logs/repair-toast.log)。
  • 视觉规格是最小方案(居中偏下 640×104、anchoredPosition (0,-400)、字号 30)—— 按验收意见随时可调,改 EnsureSystemToast() 一处。

第 48 轮(修 Toast 报错:宿主改挂 ClientCanvas —— 场景写入 18 处变更、0 错误)

  • 负责人在 Play 里报错,日志栈指向 ClientSystemFeedback.cs:66(StartCoroutine): Coroutine couldn't be started because the game object is inactive。
  • 根因(我的错):SystemLayer 在场景里恒为 inactive —— 加载Page 的 activeSelf=1 但父层关着,且没有任何代码激活 SystemLayer(ClientLoadingPage 只切自己)。第 47 轮我把 ToastRoot 与 ClientSystemFeedback 都放在该层 ⇒ ① Toast 处于 inactive 层级 根本显示不出来;② 组件自身在 inactive 物体上,协程无法启动。
  • 修法:ClientSystemFeedback 与 ToastRoot / ToastLabel 全部改挂 ClientCanvas(组合根,恒激活);EnsureKernelComponents 的安装位置同步改为 ClientCanvas,并移除 SystemLayer 上的历史残留。幂等 —— EnsureSystemToast() 也会清掉 SystemLayer 下的旧 ToastRoot。
  • 场景复核(读场景文件):ToastRoot -> ClientCanvas/ToastRoot、ToastLabel -> ClientCanvas/ToastRoot/ToastLabel、ClientSystemFeedback 宿主 = ClientCanvas(_toastRoot=1971698340、_toastLabel=1195055596)。备份 Logs/ClientShell.before-toastfix.unity.bak;批处理 Logs/repair-toastfix.log。
  • ⚠️ 顺带发现(未动,待负责人定):既然 SystemLayer 恒 inactive,其中的 加载Page(ClientLoadingPage)也从未运行过(连 Awake 都不会触发)。是“暂时不要加载页”还是“漏了激活”属产品取向,本轮未做任何改动。

第 49 轮(加载页直连入口 + Play 演示入口 —— 纯代码,未写场景)

  • 负责人判断:加载页从没被调用,唯一能想到的用场是「登录成功后下载资源进大厅」的过渡。只读取证证实:ClientLoadingPage 全工程无运行时调用方;钩子其实已在 Assets/Main/Init.cs(downloader.OnDownloadProgressCallback,第 405 行已算出 progress = currentDownloadBytes / totalDownloadBytes),但驱动事件被注释、只剩 Debug.LogError(progress) 每帧刷屏。
  • 新增 Assets/Client/Runtime/ClientLoadingService.cs(命名空间 Pinball.Client):给启动流程一个不依赖 EventCenter 静态事件总线的最小接口 —— Begin(text) / SetProgress(0..1) / SetProgressPercent(0..100) / SetLoadingText / Complete() / Hide() / IsShowing / Reset()。
    • 显式接管 SystemLayer 开关(该层恒 inactive,而 加载Page 自身 activeSelf=1,一激活就全屏显示):Begin() 打开、Hide() 关闭,不让它常开。
    • 找不到加载页 ⇒ 全部 no-op + 只警告一次,绝不抛异常打断启动流程。
    • 解析用 Object.FindObjectOfType<ClientLoadingPage>(true):一次性 + 缓存(因它身处 inactive 层、无法靠自身 Awake 注册),不是每帧轮询,符合 AGENTS.md §4。
    • Complete() 不自动隐藏 —— “满进度停留多久”由调用方决定后调 Hide()(静态类不持协程/计时器,不替产品定停留时长)。
  • 顺带修掉一个既有 bug:ClientLoadingPage.PlayFiveSecondPreview() 只在自身 SetActive(true) 后 StartCoroutine,但父层 inactive ⇒ activeInHierarchy=false ⇒ 协程报同一个错、画面也不出现(Inspector 那个“播放 5 秒加载演示”按钮一直是坏的)。已改为先经 ClientLoadingService.Begin() 打开层;演示结尾补 Hide()(以前显示不出来,所以“演完不收尾”从未暴露)。
  • 新增 Play 模式演示入口(ClientLoadingPageEditor.cs):菜单 Client/加载页/演示 5 秒加载(走 ClientLoadingService) + Inspector 按钮「走 ClientLoadingService 演示」。用 EditorApplication.update 计时、不往场景塞任何对象;它验证的是真实链路(含 SystemLayer 开关),也是启动流程接线的参照实现。
  • Roslyn 三目标 0 error;ClientLoadingService.cs 已进入 Editor 与 WebGL 两个 profile(Logs/verify-compile-loadingdemo.log)。

第 42 轮(测试样本扩充 —— 纯数据,未写场景、未动美术)

  • LocalClientDataService._heroes 由 2 个扩到 9 个(6 已拥有 / 3 未拥有:hero-002 / hero-008 / hero-009),名字 / 元素 / 等级 / 星级 / 战力各不相同,便于看卡面参数差异。立绘沿用模板(选卡的 spriteOf 返回 null),没有任何美术改动。Element 仍用数据侧既有的英文值,界面 光/水/土/风/火/暗 映射仍未定义。
  • 队伍预置:第 1 队 3 槽填满(hero-003/004/005,打开即可看到选卡上的 1/2/3 编号);第 2 队 1 个(hero-006);第 3、4 队留空 —— 便于连续切 4 支队伍观察“编号随编队动态变化”。
  • 已核对不会溢出:编队页 Scroll View/Viewport/Content 与已验收的商店列表组件完全一致(RectTransform + GridLayoutGroup + ContentSizeFitter),9 张卡不会被裁。
  • Roslyn 三目标 0 error(Logs/verify-compile-mockheroes.log)。

第 43 轮(编队点选改为“切换”语义 —— 纯代码,未写场景) 负责人明确的交互,取代原先“先点空位再点卡”:点卡即切换。

  • 不在队中 ⇒ 自动补编号最小的空位(无需先选空位);
  • 已在队中 ⇒ 移出它,其余槽位不补位(编号保持不动),该编号空出;
  • 三个编号都占满 ⇒ 不加入(提示「编队已满(3 个编号都已占用),请先移出一位」);
  • 同时空出 2 个及以上编号时,必须补编号较小的那个 —— 实现从下标 0 顺序找第一个空位,天然满足。 落地:规则本体在 IClientDataService.TryToggleFormationHero(heroId, out slotNumber, out failureReason) + LocalClientDataService 实现;页面 SelectHero 只做提示与刷新。 同时删除页面的 _activeSlot 与 SelectSlot(int)(“先选槽位”整套移除), 并让槽位卡不再承担点击(移出统一由“点选卡上已编号的那张”完成)。 Roslyn 三目标 0 error(Logs/verify-compile-toggle2.log)。 FormationPage编队 取证(第 37 轮,证据 Logs/verify-formationpage.txt)
  • 场景意图(98 个可见节点 + 171 个 prefab 实例):编队卡牌-Panel 3 个槽位卡(含 编队队内编号Image,默认关);页面分栏-Image/Panel 选中点1..4 + 左/右Button + 编组号-Text[01](= 4 队伍);元素属性分类列表-Image 全/光/水/土/风/火/暗 = 7 个筛选;搜索icon-image;战力框(战力文本 99999);查看卡面信息tips-Image;确认键Button;Scroll View/Viewport/Content 9 张英雄卡。
  • 契约只有单个:GetFormationHeroId() / TrySetFormationHero(heroId)(且要求 hero.IsOwned)⇒ 3 槽位 / 4 队伍 / 元素筛选 / 搜索 / 编队战力全无接口。ClientPlayerLineup.Cards 是排行榜打榜阵容(ClientRankPage 在用),不是自己的编队。
  • 场景结构也没就绪:9 张选卡与 3 张槽位卡都没有 ClientHeroCard —— 全场景该组件仅 2 处(HeroPage 的 HeroSubPage prefab 修改 + GuideSubPage 普通节点);且 角色卡牌Button-final 1.prefab 的 卡牌名称Image 没有文本子节点(HeroPage 的 卡牌名称 是 WireHeroCard() 新建的)。⇒ 要让这页的卡显示数据,需与 HeroPage 同款的场景处理。
  • 待办 7 定性:修复工具第 421 行原文「_slot / _status 需要负责人按实际意图拖拽」⇒ 属意图未定,不是漏拖。
  • 本轮仅修一个潜在 NRE:SelectHero 直接解引用 _status(值为 fileID 0),已改为判空(Refresh 本来就有)。 ActivityPage 取证结论(2026-09-20,证据 Logs/verify-inline-lists.txt):子树 687 节点、15 组重名兄弟,全部在 Scroll View 下、全部带 GridLayoutGroup、零 星级图标Image(与待办 4 无冲突)。结构=3 个真列表 + 12 个嵌套列表:新手任务(6× 任务卡prefabs)、进阶任务(6× 任务卡prefabs)、活动任务(6× 活动底框prefabs),且每张任务卡内部还有 5× 道具卡牌prefab 奖励槽。 ⚠️ 但行为已经正确:ClientActivityPage.ApplyTask(第 445 行)用 binding.Root.SetActive(exists) 按 GetActivityTasks() 条数隐藏多余卡片,奖励槽同样按 data.Rewards.Count 隐藏多余项 —— 即“场景烘一批池子 + 运行时隐藏多余”,已满足“实例数恒等于数据条数”。 ⇒ 本轮若做,属纯结构收敛(池子 → “1 模板 + 运行时生成”),不是修 bug;代价是一次不可逆的场景写入,并需新建 2 个列表脚本(卡片列表 + 卡片内嵌套的奖励列表)。种子数据:新手 5 条 / 进阶 5 条 / 每任务 1 个奖励。 仍被阻断:ProfilePage(真列表无数据源,见 MODULE.md §14)。有真缺口的候选:FormationPage(待办 7 _slot/_status 未接线)。

已完成并经负责人验收

专项 结果
全局弹窗遮罩 已撤除;模态改由 ClientPopupService 逐节点屏蔽射线(ApplyModalState,含"栈空即恢复大厅"的安全网)
弹窗层级 / 显隐 根因是嵌套 Canvas 的 overrideSorting(已清零);另修三处同源 bug:ClientUiPopup.Awake 自隐藏、Open 隐藏下层、ShopPage.Show 越权置顶
分辨率适配专项 清除 123 处非根画布 CanvasScaler;matchWidthOrHeight 0.5→0、关 pixelPerfect;13 个全屏型页面根+背景铺满、5 个底栏横向铺满;锚点规范确立(已验收)
列表收敛 ShopPage商店 130→46、MailPage邮件 263→63、HeroPage英雄 190→57(模板模式,均含内联回退)
HeroPage 五步 ① 取证 ② 卡牌脚本解耦(ClientHeroCard / ClientHeroCardList)③ 子界面拆分(HeroSubPage / GuideSubPage)④ 子页切换 + 进度显示 + 页签选中态 ⑤ 详情页只读
HeroPage 接线核对(第 33 轮) 只读场景核对两项待验证均通过;另修掉 BUG-016(前往获取+已满级Button 从未绑定 onClick,已解锁英雄点了没反应);Roslyn 三目标 0 error
详情页根因(第 34 轮) 项 1/项 3 同源:OpenHeroDetail 的 Fallback(HeroDetail) 恒 null ⇒ Show() 从未被调用 ⇒ 只读不生效且 _currentHero 恒 null。已修(ClientPopupService.GetPopup + 导航器解析,BUG-017);顺带默认关闭性能探针([UI追踪][性能] + 场景规模);Roslyn 三目标 0 error

✅ HeroPage 验收明细(2026-09-20 · 整页通过)

  • 页签选中态 —— 切换后只有一个发黄(已解决)。
  • 详情页只读(BUG-017) —— 图鉴页点带锁卡,日志 只读=True,已作用于 5 个按钮;装备槽 4 槽 + 升级按钮点不动。负责人回复:“完美实现”。
  • 只读范围(负责人明确,务必按此口径) —— 仅装备槽 + 升级按钮;天赋 / 秘技 / 终结技三个 Toggle 不受限制,任何时候都能切。早前把三个 Toggle 一并锁住属超范围实现,已撤除。
  • 升级按钮(BUG-016) —— 已解锁英雄可点、有响应。
  • 控制台噪声 —— [UI追踪][性能] 与 187 行“场景规模”统计已默认关闭(ClientUiPerfProbe._enabled = false)。
  • 为复测临时加的状态量日志已按约撤除,未留在定稿代码里。

留档根因(一项缺陷同时造成“只读”与“升级”失效):ClientUiNavigator.OpenHeroDetail 原先用 Fallback(HeroDetail) 取页面节点,而 Fallback 只查 _pageById,该表只收录 ClientUiPage(全场景仅 MainPage主页 一个);弹窗登记在 ClientPopupService._popupById,从不进该表 ⇒ 恒 null ⇒ 提前 return ⇒ Show() 从未被调用(页面能打开,却从不按所点英雄初始化)。已改为向弹窗服务 GetPopup(pageId) 解析。完整证据链见 BUG_TRACKER.md BUG-017。

待办(明确未做 / 状态已更新至第 46 轮)

  1. 列表收敛其余页面:ProfilePage 26 处、ActivityPage 15 处 等。⚠️ 星级图标Image×175 是固定 5 星展示,不得模板化(审计逐页清单里那行“✔ 可安全模板化”是机械判断,以此条为准;审计工具自身在 ClientHierarchyAudit.cs 的说明里也承认它不是列表)。
    • ✅ 已完成并验收:HeroPage英雄、FormationPage编队;ShopPage商店 / MailPage邮件 早已模板化。
    • ProfilePage:被数据源阻断(真列表无任何集合 API,见 MODULE.md §14),暂勿动。
    • ActivityPage:行为已正确(隐藏式池子),做的话属纯结构收敛,需一次不可逆的场景写入。
  2. 商店卡面数字语义 → 已确认:售价,已按此接入 ClientShopPage.ApplyPriceBadge(写入节点 = 道具数量)。待 Play 核对卡面确实显示售价。
    • ⚠️ 我第一版接错了:接到 数量角标。解析 道具卡牌prefab.prefab 才看到它是纯 Image、没有文本(左下角 数量黑底 同)⇒ 写了也不显示。卡上只有 道具名称 / 道具数量 两个文本节点。教训:卡是 prefab 实例时,先读 prefab 源文件再接线,别凭名字猜。
    • ⚠️ 语义由页面决定:奖励 / 邮件场景下 道具数量 表示“数量”(ClientActivityPage 绑它)。本次只动商店。
  3. _TEMP_GuideMarker:创建代码已删(否则幂等的 RepairAll 会把它加回来);场景里的节点按负责人决定“保留不删” —— 勿自行删除。
  4. ClientFormationPage._slot / _status 未接线 → 两个字段已删除(场景内无可用文本节点,提示改走 Console,见第 41 轮)。
  5. 调试诊断待清理 → 已清:ClientUiTrace.Enabled = false 一次性静音(可见性诊断 / 栈快照 / 显隐 / 路由 / 导航 / 点击),并移除 HeroPage 每次刷新的进度日志。调用点全部保留,改回 true 即可复查,无需重新埋点。
  6. board_* 工具不可用(第 33 轮复测确认仍坏):对三种绝对路径写法均报 project_path must be an absolute path ⇒ 工具自身的路径校验缺陷;任务看板始终未建立,本会话以 CURRENT_STATE.md 承担进度记录。
  7. 【下一个大方向】移植微信小游戏 WebGL 环境 + 真机测试(负责人 2026-09-20 提出,预计另开一个新会话) → 权威版已上移到本节顶部「🔜 移植任务交接」(网络事实 / 基础设施证据 / 难度评估 / 加载页接线点 / 架构偏离)。以那一节为准,下面仅保留“调用点”细节,避免两处各写一份(§12.4 单一 owner)。
    • 加载页(ClientLoadingPage)的唯一现实调用点就在这条线上。只读取证(2026-09-20):全工程无任何运行时调用方(只有自身 + Editor 预览按钮 PlayFiveSecondPreview);而 Assets/Main/Init.cs 的资源下载流程钩子已齐: 第 372 行 downloader.OnDownloadProgressCallback = OnDownloadProgressUpdateFunction,第 405 行已算出 progress = currentDownloadBytes / totalDownloadBytes。 ⚠️ 但驱动事件被注释掉了(EventCenter…"更新下载进度" / "下载完成"),且进度是用 Debug.LogError(progress) 打出来的(每帧刷 error,真机日志会被它淹掉)—— 这就是加载页从未被调用的原因。 ⚠️ 前提:加载Page 位于 SystemLayer,而该层恒为 inactive ⇒ 接线时必须由下载流程显式控制 SystemLayer.SetActive(true/false)(加载Page 的 activeSelf 已是 1,一旦激活就会显示,不能常开)。 → 属移植会话范围(Init.cs 是启动/原公司代码边界,本会话未改)。
    • 其它潜在调用点(当前不存在):YooAsset 分包按需下载时的过渡遮罩;若登录与资源下载拆成两段,则再加一个“登录后过渡”。不建议把整屏加载页用于普通网络等待(那是 Toast / 局部遮罩的活)。
    • 移植难度评估(2026-09-20,基于本仓库证据,非猜测):
      • 已具备(不用再担心):WX-WASM-SDK-V2 已导入;Bundles/WebGL 资源包 719.5 MB 已构建、OSS/CDN 链路已走通;HybridCLRData 有 WebGL 热更与 AOT 数据;WebGLPlugins/ 下有完整 Lua 5.3 C 源(Lua 能在 WebGL 编译);原生插件 .jslib/.wasm 已在工程内。
      • XLua 风险≈0:Assets/Lua 只有 7 个文件 / 1.2 KB —— Lua 基本没被使用,游戏逻辑是 C#。
      • 已在追踪的启动链缺陷:BUG-005~BUG-015(首包版本文件 404、SDK 追加 /Assets、AOT 元数据、本地表缺失、资源重复地址、app.json 启动页、首屏黑屏 + URP shader 不支持)。⚠️ BUG-009 / BUG-013 在 tracker 里仍标调查中,需按实际结果复核后再关。
      • 风险排序(越前越容易翻车):① iOS 真机 WebGL2 / 内存 / 纹理压缩兼容;② 网络 —— 微信只有 WebSocket,若服务端是原生 TCP 需网关或协议转换,且粘包 / 心跳 / 断线重连在 WS 下行为不同;③ 包体与首启下载体验(首包 ≤4MB、总包受限、wasm 走 CDN);④ HybridCLR AOT 泛型补齐(新 API 会反复冒一次);⑤ UI 适配(刘海 / 长屏 / 安全区);⑥ 音频解锁、触摸、onShow/onHide 生命周期。
      • 待负责人确认(直接决定工期):TCP 那条路是在真机还是开发者工具/编辑器上打通的?服务端是原生 TCP 还是已有 WS 网关?BUG-009/BUG-013 现在是否真的闭环?
  8. 全局提示缺口 → 已补(第 47 轮):SystemLayer 下已建 ToastRoot + ToastLabel 并接上 ClientSystemFeedback,全局 ShowToast 现在有视觉。主页“开发中”提示已改走它。仍留空的是 ClientPopupService._maskRoot(弹窗遮罩槽位)—— 是否要遮罩由负责人定。

关键约定(权威版见 Assets/Client/MODULE.md)

  • §11 交付与验收:一次一页;负责人 Play 验收后才算完成;场景写入不可逆,写入前先说明并取得确认。
  • §12 诊断纪律:① 排序不由层级单独决定(先查 Canvas.overrideSorting/sortingOrder)② 运行时读数不能当布局事实(以场景/Inspector 为准)③ 沿"谁能改变这个状态"用全局搜索穷举 ④ 验证结果而非调用(接线必须用场景文件核对,日志的非空判断会骗人)。
  • 列表:1 模板 + 运行时生成;实例数恒等于数据条数(不足新建、多余隐藏,防累积)。
  • WYSIWYG:Game 视图锁 753×1630(或同比例 1080×2337)在 Game 视图里调;纵向安全区按最矮档 1080×1920(画布高 1339)设计。
  • 四个坑:再给节点加 CanvasScaler / 勾 Override Sorting / 用世界坐标调位 / 底图硬拉伸(应用 9-slice)。

工作方式(重要)

  • 纯代码改动 → 不关 Unity,只跑 Roslyn 验证 & "D:\unity project\pinball\Logs\verify-compile.ps1" -Profile All,负责人 Ctrl+R 即可。
  • 需要写场景 → 才关 Unity 跑批处理:Unity.exe -batchmode -quit -projectPath 'D:\unity project\pinball' -executeMethod '<类>.<方法>',子进程传 $env:ALLUSERSPROFILE='C:\ProgramData';改大范围前先备份场景(Logs/*.unity.bak)。
  • 结构修复入口:Pinball.Client.Editor.ClientShellStructuralRepair.RepairAll(幂等,白名单 + Approved 验收闸门)。
  • 只读普查:Pinball.Client.Editor.ClientHierarchyAudit.RunAudit → Logs/hierarchy-audit.txt(九节:总览/全局问题/逐页/数据对照/全屏适配/Canvas 布局/顶部锚点扫描/HeroPage 取证/卡牌模板)。
  • 只读场景事实核对(第 33 轮新增,不需要 Unity):& "D:\unity project\pinball\Logs\verify-scene-facts.ps1" → Logs/verify-scene-facts.txt。直接解析 ClientShell.unity 重建节点树,输出目标按钮/Toggle 计数、Animator controller 参数、Button.m_OnClick 持久监听数;Unity 开着也能跑,用于在麻烦负责人 Play 之前先证伪“接线其实没接上”。 ⚠️ 两个坑:①pwsh 实为 Windows PowerShell 5.1,脚本必须纯 ASCII(含中文的 UTF-8 无 BOM 脚本会被按 ANSI 解析而报 Missing closing '}'),中文节点名用 [regex]::Unescape('...\uXXXX...');②场景 YAML 里中文是 \uXXXX 转义,普通文本 grep 搜不到中文节点名。
  • 真实运行时日志(第 34 轮的关键证据源):$env:LOCALAPPDATA\Unity\Editor\Editor.log(UTF-8,PS 5.1 要 Get-Content -Encoding UTF8 再过滤)。⚠️ Debug.Log 里的多行文本会被拆成多行,grep 时别漏续行 —— ClientUiTrace.Click 的 命中层级 / 接收组件 就是续行,漏掉它们就等于没读到证据。用它比对真实时序,可直接判定“某方法到底有没有被调用”,比读代码推断可靠得多。
  • ⚠️ verify-scene-facts.ps1 的盲区:只解析场景 YAML,看不到 prefab 实例内部的组件与名字(HeroSubPage 的英雄卡模板就是 prefab 实例,其 ClientHeroCard 不会被列出)。凡涉及 prefab 实例的结论,必须用运行日志或 Inspector 复核,别据此下断言。
  • 批处理日志统一在 Logs/。

📚 历史记录(逐轮,倒序;保留作证据,新会话可跳过)

当前项目状态

2026-09-20(第三十六轮 · 清小项:待办 5 / 6 / 8):

负责人先选 ActivityPage,但只读取证发现它行为已经正确:ClientActivityPage.ApplyTask 用 binding.Root.SetActive(exists) 按 GetActivityTasks() 条数隐藏多余卡片,奖励槽同样按 data.Rewards.Count 隐藏多余项 ⇒ 已满足“实例数恒等于数据条数”(场景烘池子 + 运行时隐藏)。做的话属纯结构收敛且要动不可逆的场景,遂改先清小项。

① 待办 5 —— 商店卡面角标语义 = 售价(负责人明确)。取证:数量角标 全项目无任何代码引用(纯静态装饰),ClientShopPage 只写 道具名称。全场景 65 个该节点,全在 ActivityPage(60) / MailPage(5);商店卡下那份只读工具看不到(道具卡牌prefab 是 prefab 实例 → 工具盲区),故接线做成容错:Find 深搜(运行时能穿透 prefab 实例)+ 节点自身与子节点都无文本则静默跳过。已接入两条路径(模板 + 内联回退)。 ⚠️ 关键区分:同一张道具卡上的 道具数量 才是“数量”语义(ClientActivityPage 绑的就是它),与 数量角标 是两个不同节点 —— 本次只动商店。

② 待办 6 —— _TEMP_GuideMarker:只删节点没用。RepairAll 是幂等的,只要创建代码还在(第 1290 行)就会把节点重新加回来。已删创建代码块并留注释;场景里那个节点仍在 ClientShell.unity,删除属场景写入,待负责人确认后单独执行。

③ 待办 8 —— 调试诊断已清:全部诊断都走 ClientUiTrace,其 Line/Warn/Click 与 ClientUiClickTracer 都检查总开关 ⇒ Enabled 由 true 改 false 一行静音(可见性诊断 / 栈快照 / 显隐 / 路由 / 导航 / 点击),调用点全部保留,改回 true 即可复查。另移除 ClientHeroPage 每次 RefreshCards 都打的“已解锁 N / 共 M”日志(控制台第二大噪声源)。 至此噪声源清完:[UI追踪][性能]+场景规模(第 34 轮)+ 全部 [UI追踪](本轮)+ 英雄页刷新日志(本轮)。

④ Roslyn 三目标 0 error(Logs/verify-compile-smallitems.log)。

⑤ 工具增强:Logs/verify-scene-facts.ps1 新增「任意页面重名兄弟组扫描」(已函数化,覆盖 ProfilePage + ActivityPage)与「按名查节点全路径 + 分页计数」,证据落 Logs/verify-inline-lists.txt、Logs/verify-node-lookup.txt。

2026-09-20(第三十五轮 · HeroPage 整页验收通过 + 定稿清理):

负责人确认:“可以,完美实现” —— 详情只读(BUG-017 根因修复)与升级按钮(BUG-016)均通过,页签选中态此前已通过。HeroPage(含详情页)整页验收完成,按 §11 记入“已完成并经负责人验收”。

① 只读范围纠正(负责人明确):只读仅作用于装备槽 + 升级按钮;天赋/秘技/终结技三个 Toggle 不受限制,任何时候都可切。此前把三个 Toggle 一并 interactable=false 属超范围实现,已撤除(第三十四轮 ⑦ 已记录)。注意 Assets/Client/MODULE.md 第 254 行的权威表述本来就是“装备栏与升级按钮不可交互” —— 是代码超出了文档约定。

② 定稿清理:为复测临时加的 详情页升级按钮 onClick 已装配:… 状态量日志已删除,未留在定稿代码里。(当时的另一条 升级按钮被点击:hero=… 实际并未写入,故无需处理。)RequestUpgrade / BindControls 已恢复原形,仅保留 BUG-016 的名字回退。

③ Roslyn 三目标 0 error(Logs/verify-compile-final.log)。本页至此无待验证项。

④ 遗留(未做,见待办):其余页面列表收敛、商店角标语义、_TEMP_GuideMarker、ClientFormationPage._slot/_status、调试诊断总清理、board_* 工具缺陷。下一个页面待负责人指定。

一个值得复用的方法论:本轮两次“看起来是 UI 问题”的卡点,最终都靠读真实日志时序(Editor.log)而不是读代码推断定位 —— 一次是 Show() 从未被调用,一次是“日志那次点击发生在修复之前、根本不构成检验”。没读到时序就不要下结论。

2026-09-20(第三十四轮 · 项 1/项 3 同源根因:Show() 从未被调用 + 关掉性能探针):

负责人反馈:项 2(页签选中态)已解决;项 1(详情只读)与项 3(升级按钮)没有。据此按 §12.5“修复完全不产生可观察变化时,先怀疑打在了不参与结果的维度上”停线取证,不再换同类改法试。

① 关掉性能监测日志(负责人要求):ClientUiPerfProbe._enabled 默认 true → false。EnsureDiagnostics 是 AddComponent 运行时补挂、场景里没有该组件(按 guid 核对命中 0 处),故改字段默认值即生效。 顺带:场景规模:活跃 GameObject=… 那 187 行噪声出自同一个 Update 里的 _countSceneScale 分支,一并消失。

② 不再猜,直接读 Editor.log 的真实时序:[1940] 英雄详情只读=False… 出现在场景启动绑定时,而 [2056] 点击图鉴卡 → [2059] Open(HeroDetail) 之后再没有 只读= 日志 ⇒ Show() 没被调用。 (上一轮把这条 False 读成“负责人点的是已解锁英雄”,是误判。教训:日志要连时序一起读;且 Debug.Log 的多行文本会被拆成多行,漏读续行等于没读。)

③ 点击追踪器直接给出被点对象:命中 HeroPage英雄/GuideSubPage/…/英雄卡Item_Instance/Mark(Mark=未解锁遮罩)⇒ 被点的确实是未解锁那张卡,却走成了“已解锁”路径。 同时排除下标错位:ClientHeroCardList.Show 用 int index = i 逐次捕获,unlockedOf(items[i]) 与 onClick(index) 同源同序,实例数恒等于数据条数。

④ 根因(BUG-017):ClientUiNavigator.OpenHeroDetail 在 Open(pageId) 成功后查 Fallback(HeroDetail),而 Fallback 只查 _pageById,该表只收录 ClientUiPage。只读场景核对:全场景仅 1 个 ClientUiPage(PagesLayer/MainPage主页,pageId=0 Home);弹窗登记在 ClientPopupService._popupById,从不进 _pageById ⇒ 恒 null ⇒ 提前 return。 于是未解锁只读不生效(页面停在启动那次 SetReadOnly(false))、_currentHero 恒为 null(升级按钮即便装上 onClick 也会在开头 return)—— 两项一起“没有”,正是同一个所有者缺陷(§12.4)。

⑤ 修法(纯代码,未写场景):ClientPopupService 新增 GetPopup(ClientUiPageId)(注册表归它所有,就该由它回答“pageId 对应哪个节点”);OpenHeroDetail 改为先向弹窗服务取节点再 Show,保留 Fallback 作为兼容路径。另加两条状态量日志(onClick 已装配 / 升级按钮被点击 hero=…)供复测核对,定稿前随待办 8 一起删。Roslyn 三目标 0 error。

⑥ 工具局限(重要):verify-scene-facts.ps1 只解析场景 YAML,看不到 prefab 实例内部的组件与名字(HeroSubPage 的英雄卡模板正是 prefab 实例),一度与日志 英雄卡列表=True 矛盾。不要用工具的“没扫到”去否定运行时的“确实存在”。

⑦ 撤回一处超范围实现(负责人纠正):SetReadOnly 里曾把 天赋/秘技/终结技 三个 Toggle 一并 interactable = false。负责人明确:只读只作用于装备槽与升级按钮,三个 Toggle 任何时候都可切。该三行已撤除(Assets/Client/MODULE.md 第 254 行的权威表述本来就是“装备栏与升级按钮不可交互”,是代码超出了文档约定,不是文档错)。教训:验收条件要以负责人原话为准,别把“我认为更合理”的约束塞进需求。

2026-09-20(第三十三轮 · 两项待验证静态核对通过 + 修掉 BUG-016):

① 新增只读场景核对工具 Logs/verify-scene-facts.ps1 → Logs/verify-scene-facts.txt:直接解析 ClientShell.unity 的 YAML 重建节点树(用 m_Children 还原兄弟顺序、按 Button.cs/Toggle.cs 的 GUID 数组件、读 Animator 的 controller 参数、读 Button.m_OnClick 的 m_MethodName)。不需要 Unity、不写任何文件,Unity 开着也能跑 —— 正好补上 §12“验证结果而非调用”里最缺的一环:在麻烦负责人 Play 之前先证伪“接线其实没接上”。 注意:本机 pwsh 实为 Windows PowerShell 5.1,脚本必须纯 ASCII —— 含中文的 UTF-8 无 BOM 脚本会按 ANSI 解析并报 Missing closing '}';脚本内中文节点名一律用 [regex]::Unescape('...\uXXXX...') 字面量。另外场景 YAML 里中文是 \uXXXX 转义,普通文本 grep 搜不到中文节点名(这也是之前几次“搜不到就以为不存在”的陷阱)。

② 待验证 1(详情只读)静态通过:upCanvas 直接子节点实测为 upImage | 立绘 | left | right | Panel | Panel (1) | 垂直Panel | 卡牌信息Canvas;Panel 内 2 个 Button(Bottom1/Bottom2)、Panel (1) 内 2 个(Bottom3/Bottom4),根下 前往获取+已满级Button 自带 Button ⇒ SetReadOnly 恰好作用于 5 个,与日志期望的 已作用于 5 个按钮(panel=2 / panel(1)=2) 完全吻合。详情页内 3 个 Toggle = 天赋Toggle/秘技Toggle/终结技Toggle。

③ 待验证 2(页签选中态)静态通过:英雄Button/图鉴Button 均 m_Transition=3(Animation);英雄Button.controller / 图鉴Button.controller 各含全部 5 个 trigger(Normal/Highlighted/Pressed/Selected/Disabled,均 m_Type: 9)⇒ DriveTabAnimator 的 ResetTrigger/SetTrigger 全部命中真实参数,不会报 “parameter does not exist”。 ⚠️ 中途误报过一次,已自我推翻:第一版解析器在 m_Type: 行就 break,只读出 1 个参数 Normal,差点把“选中态不可能生效”当结论上报;回到 controller 原文的 m_AnimatorParameters 段核对后推翻 —— 工具本身也要被验证,不能只信工具的输出。

④ 新发现并修掉 BUG-016:同一份场景事实暴露出 前往获取Canvas 全场景 0 个节点,而 EnsureBound 正是从它取容器 ⇒ _upgradeButton 恒为 null ⇒ BindControls 里的 onClick 从不装配,已解锁英雄点该按钮毫无反应(场景侧该按钮 m_MethodName 条目数实测 = 0,确无持久监听)。上一轮只给 SetReadOnly 补了名字回退,漏了这条绑定路径。已在 EnsureBound 补上与 SetReadOnly 同名的回退(同一按钮),纯代码、未写场景,Roslyn 三目标 0 error。

2026-09-20(第三十二轮 · 第 5 步完成:详情页只读):

ClientHeroDetailPage 新增 SetReadOnly(bool) + IsReadOnly,并在 Show(hero, illustration) 里 _currentHero = hero 之后按 hero.IsOwned 自动判定:

SetReadOnly(hero == null || !hero.IsOwned);

放在 Show 里而不是让各调用方自己传 —— 这样任何入口(英雄页 / 图鉴页 / 未来的其它入口)行为天然一致,符合负责人"这是点击卡牌进入详情页的通用逻辑"的要求。

只读影响范围(只动交互,不动视觉/排版/显隐):_equipmentButtons(装备栏槽位,对应 upCanvas/Panel、Panel (1))、_upgradeButton(前往获取+已满级Button,语义是"获取技能/天赋升级材料")、_talentToggle/_secretToggle/_ultimateToggle。 幂等,并在 _upgradeButton 装配之后再套用一次 —— 因为首次 Show 时按钮引用可能尚未装配好。 日志打印 英雄详情只读=?(装备栏 N 个;升级按钮=?),便于核对。

已完成的 HeroPage 五步:① 取证 ② 角色/卡牌脚本解耦(ClientHeroCard/ClientHeroCardList)③ 子界面拆分(HeroSubPage/GuideSubPage)④ 子页切换 + 进度 + 页签 ⑤ 详情只读。 遗留:① 若锁定英雄的装备栏仍可点,看日志里"装备栏 N 个"是否为 0 —— 为 0 说明该列表在别处装配,需再查;② _TEMP_GuideMarker 临时标记待定稿时删除;③ 列表收敛其余页面(内联列表 49 处)仍待推进。

2026-09-20(第三十一轮 · 进度格式修正 + 页签 Animator 驱动 + 网格对齐):

① 卡牌网格对齐已修(场景):HeroSubPage / GuideSubPage 的 Content 上 GridLayoutGroup.childAlignment 由 MiddleCenter → UpperLeft。根因:默认 MiddleCenter,子节点未填满时整组居中,故只有 1 张卡时跑到中间。改后卡片固定在左上第一格(背包式)。负责人已验证网格位置 ✓

② "总英雄数量不显示" = 格式问题,不是节点问题。只读取证(审计【八】新增 DumpTextNode)读出两个文本的原始设计文案: 已收集进度 = '55'、总英雄数量 = '/99'(自带斜杠!) —— 设计意图是 55/99。 而代码写的是 "1" 与 "2",把斜杠覆盖掉了 → 显示成 12,看起来像"总数没显示"。 修复:_totalHeroCountText.text = "/" + 总数。(节点本身 active/白色/字号 26 一切正常,接线也正确 —— 诊断日志此前已证明 值='2' active=True。)

③ 页签选中态改为直接驱动 Animator:负责人确认"只有 pressed 和 selected 是黄色,其余为灰" → 说明用的是 Button 的 Animation 过渡(Unity 标准 trigger:Normal/Highlighted/Pressed/Selected/Disabled)。只设 EventSystem 选中对象不够 —— 被点过的按钮会停在 Pressed 状态,于是两个页签同时呈黄色。现改为 DriveTabAnimator() 显式重置 Pressed/Selected/Normal/Highlighted 后按需 SetTrigger("Selected"|"Normal")。

下一步(第 5 步,负责人已要求执行):ClientHeroDetailPage.SetReadOnly(bool) —— 未解锁英雄进详情时 upCanvas/Panel、Panel (1) 装备栏与 前往获取+已满级Button 不可交互。开工前需先读 ClientHeroDetailPage.cs(该类含 15 个节点引用,不能凭猜改)。

2026-09-20(第三十轮 · 修掉"两条卡牌路径并存"):

负责人反馈:英雄子页有 2 张卡仍显示 锁Image 与 编队队内编号Image;两个页签看起来都是选中态;点任意卡都能进详情但不知有无权限区分。

① 已修(根因,日志确证):[Client] 英雄卡:需要 2 张,容器内既有克隆体 3 个... 是旧方法 EnsureTemplateInstances 的日志 —— 说明第 4 步之后新旧两条路径同时运行。旧路径生成的克隆体从不调用 Apply,因而保留模板默认状态(模板里 锁Image、编队队内编号Image 默认激活)→ 就是那 2 张"带锁和编号的多余卡"。 修复:EnsureBound() 的模板分支不再调用 EnsureTemplateInstances,卡牌统一由 ClientHeroCardList 管理。(纯代码,编译 0 error。) 数据侧经日志确认无误:已解锁 1 / 共 2。

② 待负责人提供信息:两个页签的选中态。已改用 EventSystem.SetSelectedGameObject 驱动 Button 内置 Selected 状态(并删掉了会盖住它的 interactable=false)。但截图显示两个页签都呈黄色底框 —— 需确认:黄色是否本就是 Normal 态?若要可靠表达"当前页签",需知道其 Animator 参数名(bool/trigger)或 clip 名,我直接驱动 Animator。

③ 尚未实现:详情页的未解锁只读(装备栏与 前往获取+已满级Button 不可交互)属第 5 步 ClientHeroDetailPage.SetReadOnly,本轮未做。"点任意卡都能进详情"是符合规格的(未解锁英雄也可进详情,只是只读)。

2026-09-20(第二十九轮 · 页签选中态改用内置机制 + 修掉"静默接线失败"):

① 页签选中态:删掉 interactable 写法,改用 Unity 内置 Selected 负责人截图显示 英雄Button 是 Transition = Animation 且配了 Selected Trigger = Selected —— Unity 的 Button 天生就有 Selected 状态,由 EventSystem.current.SetSelectedGameObject() 驱动。已改为切换子页时把对应按钮设为 EventSystem 当前选中对象,直接播放负责人自己配的动画。 同时删掉上一轮的 interactable = false —— 它会让当前页签进入 Disabled 状态、反而盖掉 Selected 动画(错误做法)。 并说明:_heroTabSelected / _guideTabSelected 是 GameObject 字段,拖 .controller 资源进不去;且根本不需要它们(留空不影响任何逻辑)。

② 修掉一个"静默接线失败"(重要):_ownedProgressText / _totalHeroCountText 的字段类型是 TMP_Text,而我传的是节点的 Transform → 类型不符,Unity 静默拒绝赋值:日志打印"已接线=True",场景里却始终 fileID=0(负责人正是因此看到 Inspector 为 None)。改为传 GetComponent<TMP_Text>() 后修复。 验证方式已改为直接读场景文件(_ownedProgressText fileID=4454792166064425531、_totalHeroCountText fileID=483668028028388863)—— 不再只凭日志里的非空判断。这才是 §12"日志要打印状态量"的完整含义:要验证结果,而不是验证调用。

场景接线现状(读场景文件确认):_heroSubPage/_guideSubPage/_heroTabButton(英雄Button)/_guideTabButton(图鉴Button)/_ownedProgressText/_totalHeroCountText 六项全部非 0 ✓

下一步(第 5 步):ClientHeroDetailPage.SetReadOnly(bool)。

2026-09-20(第二十八轮 · 第 4 步:两个子页打通(代码 + 接线)):

关键发现:ClientHero.IsOwned 就是解锁状态字段(ClientModels.cs L32-41,另有 HeroId/Name/Element/Level/StarLevel/CombatPower)。

代码(三目标 0 error):

  • 新增 OpenHero(ClientHero, Sprite) —— 按对象直接开详情。原因:原 OpenCardByIndex 用 heroes[cardIndex % heroes.Count] 映射全表,而英雄子页只显示已解锁、图鉴子页显示全部,两表长度与顺序不同,共用同一下标必然错位。OpenCardByIndex 改为委托给它,旧入口(SelectOwnedHero/SelectLockedHero)不受影响。
  • RefreshCards() 重写:改用 ClientHeroCardList。英雄页 = 仅 IsOwned;图鉴页 = 全部且按 IsOwned 设锁+遮罩(两者由 ClientHeroCard 同步)。每个子页各自一份"容器 + 模板"的列表实例(复制 GuideSubPage 时其内部也带了模板,互不干扰)。
  • 新增 SwitchSubPage(bool) / ShowHeroSubPage() / ShowGuideSubPage() / ApplySubPageVisibility() / RefreshProgress();OnPageRefresh 里新增 BindTabs()(RemoveListener 再 AddListener,防重复叠加)。
  • 进度写入 已收集进度(已解锁数)/ 总英雄数量(总数)。
  • 页签选中态:_heroTabSelected/_guideTabSelected 留给负责人拖入他自定义的 animation 状态节点(代码只按需显隐),同时用 interactable 表达"当前页签不可再点"。

场景接线(Logs/wire-progress.log,8 处变更):_heroSubPage=HeroSubPage、_guideSubPage=GuideSubPage、_heroTabButton=英雄Button、_guideTabButton=图鉴Button、_ownedProgressText=已收集进度、_totalHeroCountText=总英雄数量。实测两个进度文本均为 TextMeshProUGUI,与字段类型 TMP_Text 一致,故直接接线(未凭猜测声明类型)。

待负责人做:把页签的 animation 状态节点拖到 _heroTabSelected/_guideTabSelected(留空也能跑,只是没有视觉选中态)。 下一步(第 5 步):ClientHeroDetailPage.SetReadOnly(bool) —— 未解锁英雄进详情时,upCanvas/Panel、Panel (1) 装备栏与 前往获取+已满级Button 不可交互;已解锁则全可交互。

2026-09-20(第二十七轮 · 第 3 步:两个子界面已拆开):

Logs/create-guidesub2.log,5 处变更,批处理正常结束: middleCanvas → 重命名为 HeroSubPage(英雄子界面);由它复制出 GuideSubPage(图鉴子界面),并加临时视觉标记 _TEMP_GuideMarker(紫色半透明块 + 文字,定稿时整体删掉)。 场景已备份 Logs/ClientShell.before-guidesub.unity.bak。

过程中踩到并已修复的坑:临时标记最初把 Image 与 TextMeshProUGUI 建在同一 GameObject 上 → 报 Can't add 'TextMeshProUGUI' ... because a 'Image' is already added,抛异常导致批处理中止、场景未保存。已改为 Image 作底、TMP 作子节点(这也是 UI 的标准搭法)。

顺带做了两处"防改名"加固:① WireHeroCard 改为用 FindObjectsOfType<ClientHeroCard> 定位模板,不再依赖路径;② ListTargets 里 HeroPage 的容器路径同步改为 HeroSubPage/MiddleCanvas/...。

遗留(无害):本轮日志有 未找到列表容器,跳过收敛:HeroPage英雄/HeroSubPage/... —— 因为 ConvergeKnownLists 排在改名之前执行,当时节点还叫 middleCanvas;下次运行路径即匹配,无需处理。

下一步(第 4 步):ClientHeroPage 维护"当前子页"(方案 A),HeroButton/GuideButton 选中态驱动 HeroSubPage/GuideSubPage 激活;卡牌生成改用已写好的 ClientHeroCardList;写 已收集进度 / 总英雄数量(路径 HeroSubPage/upCanvas/底框Image/)。英雄页只显示已解锁;图鉴页显示全部并按解锁状态设 锁Image + Mark。

2026-09-20(第二十六轮 · 英雄卡牌解耦:独立脚本 + 模板接线完成):

背景:负责人指出"英雄卡牌的各个接口逻辑应该单独写几个脚本来管理",并确认命名用英文、HeroSubPage/GuideSubPage 方案选 A(ClientHeroPage 维护当前子页,两子页共用同一套卡牌逻辑)。

取证(只读,审计【九】):卡牌模板 英雄卡Item 实测子树含 品质底框Image/品质Image/属性图标Image/卡牌名称Image/立绘Image/LV+等级 image/Lv-Image(inactive)/等级-Text(TMP, inactive)/垂直星星Panel+星级图标Image×5/编队队内编号Image+编号数字/Mark(inactive)/锁Image,根自带 Button。注意:模板里没有任何"名称 Text"节点 —— 而旧代码找的是 卡牌名称 与 Text (TMP),两个都匹配不上,故名称与等级从未被写入(卡面一直是美术占位字)。

负责人确认:① 允许新建一个 TMP 名称节点;② Mark 就是未解锁遮罩,且必须与 锁Image 同步出现/消失;③ 编队队内编号Image 只在 FormationPage编队 显示,其它场合不显示。

新增脚本(纯代码,编译三目标 0 error):

  • Assets/Client/Runtime/UI/ClientHeroCard.cs —— 英雄卡牌的唯一管理者(名称/等级/立绘/锁/遮罩/编队编号/点击)。刻意不依赖 ClientHero,Apply 只收基础类型,便于任何列表复用。内置两条约束:锁与遮罩同步、编队编号默认强制隐藏(仅 SetTeamBadgeVisible 打开)。
  • Assets/Client/Runtime/UI/ClientHeroCardList.cs —— "1 模板 + N 实例"管理器,Show(items, nameOf, levelOf, unlockedOf, spriteOf, onClick)。实例数恒等于数据条数,每次 Show 重新对齐,从根上杜绝 2→4→6 累积。

场景写入(Logs/wire-hero-card.log,5 处变更):在 卡牌名称Image 下新建 TMP 节点 卡牌名称;给 英雄卡Item 挂 ClientHeroCard;接线全部字段 —— 立绘=立绘Image 名称=卡牌名称 等级=等级-Text 锁=锁Image 遮罩=Mark 编队编号=编队队内编号Image Button=有,_levelDecorations=[Lv-Image]。

下一步:第 3 步 —— middleCanvas → HeroSubPage 重命名、复制出 GuideSubPage(含临时视觉标记);随后第 4 步子页切换/页签选中态/进度文本,第 5 步详情页 SetReadOnly。

2026-09-20(第二十五轮 · HeroPage英雄 取证 + 修掉卡牌累积缺陷):

取证结论(Logs/hierarchy-audit.txt 第八节,只读):场景是干净的 —— 卡牌容器 middleCanvas/MiddleCanvas/Canvas/Scroll View/Viewport/Content 子节点=1(仅禁用的 英雄卡Item 模板),全页含"卡牌"的节点只有 1 个。故负责人报告的"4 张 / 6 张"全是运行时累积。 根因(已确证):ClientHeroPage.EnsureTemplateInstances() 只按 _cardBindings.Count < needed 判断、从不清理容器内已生成的克隆体;而 UnbindCards() 会清空 _cardBindings 却不销毁克隆体 → 每进出一次多生成一轮 → 2 → 4 → 6 累加,且旧克隆体点击下标越界(表现为"只有某一张能进详情")。这是第二十四轮收敛引入的缺陷。 修复(纯代码,编译三目标 0 error,无需重启 Unity):改为"清空绑定 → 收集容器内非模板既有克隆体 → 按需复用 → 不足才新建 → 多余隐藏",并输出 需要 N 张 / 既有 M 个 / 已绑定 K 张 便于核对。

另两项取证(待负责人回答):① Background 根下那个已是全屏拉伸((0,0)-(1,1) offset 0),另有同名的 middleCanvas/Background(490×508 居中固定)——"垂直拉伸不够"指哪个未定;② upCanvas 数值合理(锚 (0.5,1)、距顶 26~140),"初次位置不对"疑为首次激活布局未重算(待确认是一瞬恢复还是持续错)。

下一步(负责人已批准):复制 middleCanvas 建图鉴子界面(要有视觉区分、注册进代码、重新命名整理结构),并做 英雄/图鉴 按钮的选中态 + 子界面切换。(Background/upCanvas 两项经负责人微调后已确认"完美"。)

2026-09-20(第二十四轮 · 列表收敛第 3 页 HeroPage英雄 落地):

负责人指示"继续列表收敛",据此打开 ListTargets 中 HeroPage英雄 的验收闸门(Approved: false → true)并执行。Logs/converge-hero.log,共 12 处变更: 删除 7 张内联 角色卡牌Button-final 1 → 保留 1 张重命名为 英雄卡Item 并禁用为克隆源 → 写入 ClientHeroPage._cardTemplate / _cardListRoot。

体检复验:HeroPage英雄 节点 190 → 57、交互节点 22 → 15、根尺寸全屏拉伸 ✔;全场景内联列表 57 → 49 处。 顺带修掉一个真实缺陷:旧 RefreshCards 用 heroes[index % heroes.Count] 取模填充 —— 8 张卡重复显示同样 2 个英雄;模板化后卡片数 = 英雄数,重复消失。AcceptanceNotes 里那条"待批准"的过期说明已同步更新。

已模板化 3 页:ShopPage商店(130→46)、MailPage邮件(263→63)、HeroPage英雄(190→57)。 剩余内联列表 49 处,按体量:ProfilePage个人中心 12、ActivityPage活动 12、FormationPage编队 12、Player lineup 7、RankPage排行榜 2、Email Details Page(Have) 1、HeroDetailPage英雄详情主页 1 等;星级图标Image×175 属固定展示、不得模板化。 注意:HeroPage英雄 的场景写入待负责人在 Unity 里 Play 验收(§11:验收前不标"已完成")。

2026-09-20(第二十三轮 · 分辨率适配专项完成并经负责人验收):负责人确认"改完了,已验收"。本轮专项共落地如下,全部有日志与体检证据:

# 内容 证据
① 清除 123 处非根画布 CanvasScaler(12+111,首轮漏删因两套判定口径不一致) Logs/apply-123.log;体检复验"✓ 无"
② ClientCanvas:matchWidthOrHeight 0.5→0(按宽匹配)、pixelPerfect true→false Logs/apply-123.log
③ 12 个全屏型页面根+背景铺满;5 个底栏横向铺满 Logs/apply-123.log、add-4-pages.log
④ 商店:标题换父级到页面根+贴顶、顶栏贴顶并对齐标题下、底栏铺满、水晶石纵向贴顶 Logs/shop-bars.log、fix-crystal-anchor.log
⑤ 5 处顶部元素纵向贴顶(MailPage/ActivityPage/FormationPage/全图鉴×2) Logs/fix-top5.log
⑥ Player lineup 还原为面板型 + 护栏(只在仍是拉伸态时还原,绝不覆盖负责人的手工尺寸) Logs/restore-player-lineup.log、fix-top5.log
⑦ 顶部区域扫描工具口径修正(名字+锚点+页面已拉伸 三项同时成立;打印真实锚点),复验 ✓ 未发现 Logs/hierarchy-audit.txt 第七节

确立的通用口径:贴哪条边用哪条边的锚;要铺满哪个方向用该方向的拉伸锚;纯背景 (0,0)-(1,1);居中内容不动。WYSIWYG 前提:Game 视图锁 753×1630(或同比例 1080×2337)编辑,且在 Game 视图里调。纵向安全区按最矮档 1080×1920(画布高 1339)设计。 四个会打破 WYSIWYG 的坑:再给节点加 CanvasScaler;勾 Override Sorting;用世界坐标调位置;底图直接拉伸变形(应用 9-slice)。

遗留:① 若背景拉伸后变形,需改 9-slice(待负责人指认节点);② 第 (4) 步列表收敛仍停在 HeroPage英雄 Approved=false 待批;③ 调试诊断(可见性诊断/栈快照/Canvas 链)待稳定后清理;④ 商店卡面"数量角标"语义待确认;⑤ board_* 工具对 D:\unity project\pinball 报 project_path must be an absolute path,看板未建立。

2026-09-20(第二十二轮 · 5 处顶部元素改贴顶 + 扫描口径修好 + 一处"会覆盖负责人改动"的隐患):

① 5 处顶部区域元素改为贴顶锚(Logs/fix-top5.log):MailPage邮件/Email Title、ActivityPage活动/task title、FormationPage编队/页面分栏-Image、全图鉴活动/顶部角色-Image、全图鉴活动/task title。手法同水晶石:只动纵向、横向保持、世界坐标回写。 ② 扫描口径已修正并复验:判定恢复为「页面已全屏拉伸 且 名字像标题/栏 且 锚点仍为中心」三项同时成立;报告行改为打印真实锚点(上一版硬编码 锚=(0.5,0.5) 且漏了锚点检查,产出 15 项假阳性)。修正后复验:✓ 未发现 —— 该类问题已清零。 ③ 修掉一处会覆盖负责人改动的隐患:RestorePlayerLineupRect() 原会无条件把尺寸写回 752×1630,而负责人已把它手动调成正确的 675×1127 —— 每次 RepairAll 都会覆盖掉。现改为只在"仍是拉伸态(锚点 (0,0)-(1,1))"时才还原,绝不强行写尺寸,与尺寸解耦。本轮日志确认护栏生效:未对 Player lineup 做任何还原动作,负责人的 675×1127 未被触碰。

⚠️ 又一则同类教训(与上一轮"尺寸不足以判定类型"配套):幂等的"修复"必须区分"我改坏的"与"负责人手动调的"。仅凭"当前值 != 我期望的值"就写回,会把负责人的手工调整当成待修缺陷。判定应基于结构状态(是否仍是我造成的拉伸态),而不是数值是否等于我记的那个值。

2026-09-20(第二十一轮 · 四页验收 + Player lineup 回滚 + 一条判定教训):

验收结果:Email Details Page(Have)、Email Details Page (No)、Success Receipt Interface 三页通过 ✓;Player lineup(玩家阵容)负责人判定为面板型,不该全屏拉伸 → 已还原。 回滚(Logs/restore-player-lineup.log,3 处变更):Player lineup 从 size=(753,565) 锚=(0,0)-(1,1)(拉伸态)还原为 752×1630 + 中央锚点 (0.5,0.5),并已从 FullScreenPopups 白名单移除(名单内加了注释说明,防止以后再被加回)。

⚠️ 本轮的方法教训(重要):我把 Player lineup 加入拉伸名单,依据只是"尺寸 752×1630 等于参考分辨率"。 这个依据不成立 —— 面板型弹窗也可以恰好等于参考分辨率,类型是设计意图,不能仅凭尺寸推断。 这与 §12 已记的"运行时读数不能当布局事实"是同一类错误:用可观测的近似量替代了需要确认的意图。 今后凡判定"全屏型 / 面板型",一律先问负责人,不自行推断。

扫描口径已修正(少量 A):AppendTopAreaAnchorScan 的判定从几何位置改为名字(title/bar/标题/栏/顶)。原因:多数弹窗体检时未激活、布局未计算,几何判定产出 41 项噪声(连 background 都被误判)。该口径会漏掉名字不像标题的节点(如 Regular store resource exchange - Crystal stones),故只作低噪声起点,兜底靠负责人逐页验收(B 为主)。尚未运行(需关一次 Unity,避免打断验收)。

2026-09-20(第二十轮 · 水晶石兑换条锚点修正):负责人验收 ①②③ 后反馈"除 1080×1920 右上角外都完美",并定位到节点 Regular store resource exchange - Crystal stones。

成因(与商店标题同一类):该节点是 ShopPage商店 直接子节点、尺寸 134×40、锚点为中心锚 (0.5,0.5) → 根改为全屏拉伸后随画布高度漂移。只有 1080×1920 明显,因为 match=0 下画布宽度恒为 753,高度按比例算:1080×1920 → 1339(最矮)、1170×2532 → 1630、1080×2400 → 1673;最矮那档顶部元素被压得最近才暴露。 修复(Logs/fix-crystal-anchor.log,4 处变更):只把纵向锚点改为贴顶 y=1,横向锚点原样保留(避免同时改动左右定位把问题挪到别处),并以世界坐标回写保证视觉不跳。

通用口径(供后续逐页复核):凡"位于顶部区域"却用中心锚的元素,在根拉伸后都会漂 —— 商店已发现两处(Shopping Mall Title、本节点)。建议按此模式扫一遍其余 8 页的顶部区域元素。 纵向安全区设计口径:按最矮档 1339 设计 —— 顶部元素向下偏移 ≤ ~130、底部元素向上偏移 ≤ ~160,中间留 ~1050 给内容。

2026-09-20(第十九轮 · ①②③ 全部执行完毕,分辨率适配根因清除):负责人确认"①②③ 都同意,全部都做"。Logs/apply-123.log,共 134 处变更;场景已备份到 Logs/ClientShell.before-canvas-scaler.unity.bak(5.4MB,可回滚)。

① 非根画布 CanvasScaler 全清:123 处(12+111)。首轮只删 12 处的原因已查明:我的删除用 owner.isRootCanvas 判定,而体检按"非 ClientCanvas 自身"计数 —— 两套口径不一致导致漏删 111。统一口径后补齐。体检复验:✓ 无(根画布之外没有自带 CanvasScaler 的节点)。嵌套 Canvas 本身保留,未改动任何 Pos/Size/锚点。 ② ClientCanvas:matchWidthOrHeight 0.5 → 0(改按宽匹配,参考宽度恒定 753);pixelPerfect true → false。 ③ 9 个全屏型页面根与背景全部改为铺满父级;5 个底栏(Rank/Activity/HeroDetail/Formation/全图鉴)改为底部横向铺满。体检复验:9 页全部 [全屏拉伸] ✓,面板型页面保持固定尺寸(正确)✓。

遗留(新发现):Email Details Page(Have)、Email Details Page (No)、Success Receipt Interface、Player lineup 四页尺寸是 752×1630(等于参考分辨率,即全屏型),但目前仍是固定尺寸 → 同样会露边。它们不在本轮 9 页白名单内,待负责人决定是否一并拉伸。

2026-09-20(第十八轮 · 商店顶/底栏锚点规范化,机械部分完成):负责人确认"标题贴顶、功能栏在标题下方"及分工(我做机械锚点、负责人微调间距)。

结构病因(关键):Shopping Mall Title 实际是 Bottom page function bar 的子节点(Canvas 链证据),继承了"底部锚"父级的运动 → 在 matchWidthOrHeight=0.5(画布高度随比例变化)下与顶部功能栏错位重叠。只改自己的锚点救不了,必须换父级。

已执行(Logs/shop-bars.log,共 6 处变更):① Shopping Mall Title 父级由 Bottom page function bar 移到页面根;② 标题锚点 → 贴顶居中 (0.5,1);③ Top function bar 锚点 → 贴顶居中;④ 功能栏顶边对齐到标题下边缘(位移 140.6,间距留 0,由负责人微调);⑤ Bottom page function bar → 底部横向铺满(原 752 宽 → 1279)。改锚点时以世界坐标回写,保证视觉不跳。加上上一轮:根与 background 已全屏拉伸(共 3 处)。

负责人确认的通用模式(跨分辨率兼容):贴哪条边用哪条边的锚;要铺满哪个方向就用该方向的拉伸锚;纯背景 (0,0)-(1,1);居中内容不动。WYSIWYG 前提:Game 视图锁定到参考比例 753:1630 ≈ 1:2.164(建议 1080×2337),调的是 anchoredPosition / sizeDelta。

下一步:其余 8 页(Mail/Rank/Activity/Hero/HeroDetail/Profile/Formation/全图鉴)。审计已给出各页"边缘锚 + 拉伸锚"计数,但尚未列出中心锚子节点的名字 —— 而"看起来贴边、实际是中心锚"正是本次商店问题的成因,需扩展体检先列出各页直接子节点清单,交负责人确认后再批量执行。

2026-09-20(第十七轮 · 全屏适配:商店首例已改):负责人要求"全部都要改,先改商店"。

事实基线(只读体检,Logs/hierarchy-audit.txt 第五节新增):CanvasScaler = ScaleWithScreenSize,参考 753×1630,matchWidthOrHeight = 0.5(宽高混合匹配,不是按宽) → 比例一变画布参考尺寸宽高都会变,而各弹窗根写成固定尺寸(商店 752×1527、多数页 752×1630)→ 必然露边。参考分辨率恰好等于 MainPage主页 的尺寸,说明这些页当初就是按参考分辨率整屏画的,只是写成了固定尺寸。 体检同时给出安全性依据:各页直接子节点绝大多数是中心锚(改根后位置不变);边缘锚的多为顶/底栏(Bottom page function bar、upCanvas、downCanvas),改根后会贴到真屏幕边缘 —— 属期望行为。仅 5 页各有 1 个拉伸锚子节点需单独复核。

已执行(商店,RepairAll 日志 Logs/stretch-shop.log,批处理退出 0,共 3 处变更): 根 ShopPage商店 752×1527 锚(0.5,0.5) → 铺满父级;background 752×1527 → 铺满父级。 其余子节点(顶/底功能栏、Product page 等)一律未动,底栏会自然贴到屏幕底。 工具已写成通用(StretchFullScreenPopups,白名单 9 个全屏型页面),但本轮由 FullScreenPopupsThisRun 限制为只跑商店,待负责人验收后放开其余 8 页。 面板型弹窗(购买确认/兑换码/联系客服/订单/发货)明确不改,保持居中面板(此前把成功页误判为"缺全屏"已吃过一次亏)。

待确认:① 商店在多种分辨率(1080×1920 / 1080×2400 / 1170×2532)下的表现;② background 那张图能否直接拉伸(不能则需 9-slice 或加可拉伸底色);③ MailPage/后退Button(左中锚)、HeroPage/upCanvas(顶锚)移到真屏幕边是否为预期。

工具问题(待查):board_get/board_revision 对 D:\unity project\pinball、D:/unity project/pinball、D:\unity project 均报 project_path must be an absolute path,看板未能建立。

2026-09-20(第十六轮 · 弹窗层级问题解决 + 复盘固化):负责人确认"完美效果,满意"。本轮把这次反复修复的经验写入 Assets/Client/MODULE.md §12 诊断与修复纪律(下一条目已改为 §13),并同步交接。

本轮实际修复的真根因(两个): ① 层级"跑到商店后面" —— ClientShopPage.BringToFront() 里对 item 的 Canvas 执行了 overrideSorting = true; sortingOrder = ++_nextCanvasSortingOrder;。 overrideSorting=true 的嵌套 Canvas 完全无视层级顺序、只按 sortingOrder 排, 于是商店内部的 Product page(order 1005)与 Activity Mall Page(order 1002) 永远渲染在所有弹窗之上。修复分两处,缺一不可:场景清除这两个节点已存的 overrideSorting=true(工具 ClearNestedCanvasOverride(),体检确认全场景已无该项), 代码删除运行时重新打开它的那段逻辑。这也解释了此前 4 轮改兄弟序号(SetAsLastSibling、 整体重排栈)为何全部无效 —— 那是不参与排序的维度。 ② 成功页"不铺满 + 点任意处不关闭" —— 同一根因:该页根节点上没有任何 Graphic (普查:根组件只有 GraphicRaycaster + ClientUiPopup),矩形其实早已是全屏 ((0,0)-(1,1)、sizeDelta=0)。没有 Graphic 就没有东西铺满屏幕、也没有整屏接点击面。 修复:给根节点补一块全屏 Image(半透明黑 alpha 0.6、raycastTarget=true), 同时解决"视觉覆盖"与"点击接收";配合 BindSuccessDismissHandlers(给页内每个 Graphic 打开 raycastTarget 并挂 ClientShopCloseOnClick)实现点任意处关闭。

复盘要点(已写入 MODULE.md §12):① 排序不由层级单独决定,动手前先打印 Canvas.overrideSorting/sortingOrder;② 运行时读数不能当布局事实(我曾把 Play 中的 rect.rect.size=215.9×2219.1 当作排版事实,误判成功页为"窄竖带"并据此取得授权改动,实际 场景值是居中 752×1527 —— 布局事实以场景/Inspector 为准);③ 沿"谁能改变这个状态"穷举 (用全局搜索列全写入路径,而非改一处试一次);④ 同一所有者原则(显隐与层级只由 ClientPopupService 决定,View 不得自行 SetActive 根节点或改层级 —— 本次三个 bug Awake 自隐藏 / Open 隐藏下层 / Show 越权置顶 同源于"整屏替换"旧语义); ⑤ 反证要当反证(修复完全不产生可观察变化时,先怀疑"打在了不参与该结果的维度上"); ⑥ 日志要打印状态量而非调用成功;⑦ 工作流:纯代码改动不关 Unity(避免每次触发提权 警告打扰负责人),仅场景写入才走关→批处理→重启。

遗留:调试用诊断(可见性诊断 / 栈快照 / Canvas 链)与 _nextCanvasSortingOrder 未使用 的告警仍在,待负责人确认稳定后一并清理;HeroPage英雄 仍停在 Approved=false 待批; ShopPage商店 / MailPage邮件 的验收与第 (4) 步后续页面仍按 §11 逐页推进。

2026-09-20(第十五轮 · 验收要点入报告):页面管线受 §11 验收闸门约束(未验收不得推进下一页),本轮不新增任何未审阅的行为改动,只做一件只读、零运行时风险的事:让普查报告输出 ★ 验收要点。

实现(ClientHierarchyAudit):新增 AcceptanceNotes 表并在 AppendOnePage 输出,内容数据驱动(写清运行时预期卡片数来自哪个数据源),让 Play 验收有客观对照口径而非凭印象:ShopPage商店(按 GetShopListings()=3 生成 3 张、点任意一张应打开购买界面)、MailPage邮件(按 GetMails()=2 生成 2 张、点卡应选中邮件)、HeroPage英雄(待批准;批准前应仍是 8 张内联卡,正是闸门未触发的证据)。编译三目标 0 error。

闸门状态未变:ShopPage商店/MailPage邮件 已写入待验收;HeroPage英雄 Approved=false、场景未写入。本轮同样未写入场景。

阻断点(连续第四轮):第 (4) 步按 §11 约定必须由负责人逐页 Play 验收后才能推进下一页,故以下两项未答复前无法继续:(a) ShopPage商店 / MailPage邮件 的验收结果;(b) HeroPage英雄 是否批准执行场景写入(批准后只需把 ListTargets 中该页 Approved 改 true 再跑一次 RepairAll,约 1 分钟)。目标保持 active。

2026-09-20(第十四轮 · 实现 MODULE.md §6 模态约定,纯代码、未动场景、未推进任何页面):撤掉全局遮罩后,点击穿透的问题重新变成活的——全屏弹窗打开时主页底部图标仍可点,每点一次就往栈上叠一层,正是之前那个"延迟弹出"现象。全局遮罩曾用来堵这个洞,但它会盖住栈顶弹窗(购买界面点不动)且会残留锁死界面,已作废。正解是逐节点屏蔽射线。

实现(ClientPopupService):新增 _allPopups(CollectPopups 时收录全部弹窗,含不参与 pageId 路由的二级弹窗)与 _lobbyRoot(PagesLayer 的第一个子节点=大厅);新增 ApplyModalState() 并在 ApplyMask() 开头调用,逻辑是只有栈顶弹窗可点——其下的弹窗与大厅一律 blocksRaycasts=false;SetRaycastBlocked() 按需补 CanvasGroup 并设置,只加交互组件,不新建 UI 节点、不改任何 rect。追踪日志会打印 [UI追踪][弹窗] 模态 <路径> blocksRaycasts=True/False。编译三目标 0 error。

闸门状态未变:ShopPage商店 / MailPage邮件 已写入待验收;HeroPage英雄 代码就绪但 Approved=false,场景未写入(本轮同样未写入)。全场景内联列表仍为 57 处、HeroPage英雄 仍为 190 节点 / 8 张卡。

下一步(等待负责人):(a) ShopPage商店 / MailPage邮件 的 Play 验收结果;(b) HeroPage英雄 是否批准执行场景写入。收到答复前不推进任何页面。

2026-09-20(第十三轮 · 把验收闸门做成结构):负责人要求"每页做完要说明、验收通过才算通过"。复查时发现一个会绕过该闸门的隐患:HeroPage 一旦登记进 ListTargets,之后任何一次 RepairAll(哪怕是为别的修复而跑)都会顺手删掉它的 7 张内联卡 —— 等于未经确认就执行了场景写入。

修复:ListTarget 增加 Approved 字段作为验收闸门。语义是"登记进白名单 ≠ 允许现在动场景";未验收的页面必须停在 false,ConvergeKnownLists() 会跳过并打印 跳过 X:尚未通过负责人验收(ListTarget.Approved=false)。新增一页的完整流程改为:改代码(含内联回退)→ 编译 → 登记且保持 false → 向负责人说明并取得确认 → 改 true → 跑 RepairAll。

白名单现状:ShopPage商店 true、MailPage邮件 true(二者已执行写入、待 Play 验收);HeroPage英雄 false(代码侧已就绪,场景写入待确认)。

闸门生效验证(只读普查):HeroPage英雄 仍是 190 节点 / 8 张 角色卡牌Button-final 1、全场景内联列表仍是 57 处 —— 与登记前完全一致,证明 Approved=false 确实没有触发任何场景改动。编译三目标 0 error。

下一步(等待负责人):(a) ShopPage商店 / MailPage邮件 的 Play 验收结果;(b) HeroPage英雄 是否执行场景写入(批准后只需把 Approved 改 true 再跑一次 RepairAll)。在收到答复前不再推进任何页面。

2026-09-20(第十二轮 · 负责人要求改变交付节奏:一次一页、说明后验收):负责人明确要求"每做完一个页面都要与我解释,我验收后才算通过",并要求不得跨页批量推进。据此:

  • Assets/Client/MODULE.md 新增 §11「交付与验收流程(负责人强制要求)」:① 不得跨页批量推进;② 每页完成必须书面说明(改了什么/依据/影响节点数/如何验证/遗留风险);③ 负责人在 Unity Play 验收通过后才算完成,验收前只能标"待验收",CURRENT_STATE.md 不得写"已完成";④ 场景写入不可逆,写入前先说明变化并取得确认;⑤ 页内多个子项仍按一页一验收,不反复打断。

当前状态:

  • 待验收:ShopPage商店(130→46 节点)、MailPage邮件(263→63 节点)—— 场景写入已执行,等 Play 验收。
  • 进行中:HeroPage英雄 —— 代码侧已就绪,场景写入尚未执行。已给 ClientHeroPage 加模板支持:_cardTemplate/_cardListRoot 字段、EnsureTemplateInstances()(按 GetHeroes().Count 克隆并建 CardBinding)、RefreshCards() 模板分支(按位取用,不再 % heroes.Count 取模、超出隐藏),并保留内联回退。编译三目标 0 error。尚未登记白名单、尚未跑 RepairAll。

HeroPage英雄 的关键取证:该页 9 个内联容器里只有 1 个是真列表 —— middleCanvas/MiddleCanvas/Canvas/Scroll View/Viewport/Content,角色卡牌Button-final 1 ×8,GridLayoutGroup cell=204x326 固定列数2;其余 8 个都是 星级图标Image ×5(每卡一组 5 星),按约定属固定数量展示、不得模板化。英雄数据仅 2 条,而场景 8 张卡 —— 旧 RefreshCards 用 heroes[index % heroes.Count] 取模填充,所以 8 张卡反复显示同样 2 个英雄;模板化后卡片数 = 英雄数,重复问题一并消失。

2026-09-20(第十一轮 · 第 4 步流程固化 + 白名单约束):本轮对 HeroPage英雄 做动手前前提确认,得出一个必须固化的约束。

发现:ClientHeroPage 确实驱动英雄列表(RefreshCards() 读 ClientServices.Data.GetHeroes() 并遍历 _cardBindings),所以它可以模板化——但必须先给 View 加模板生成代码。若先删场景实例、后改代码,页面会只剩 1 个禁用模板,这是可见的功能回归。

据此把工具改成声明式白名单:新增 ListTarget 结构与 ListTargets 白名单(登记"页面 / 容器路径 / 项前缀 / 模板名 / 模板字段 / 容器字段"),ConvergeKnownLists() 只收敛白名单内的目标,不做"扫描到就收敛"。新增一页 = 先改代码 → 编译 → 登记一行 → 跑 RepairAll。

同步写入 Assets/Client/MODULE.md §7:收敛一页的四步流程(必须按序) —— ①取证(普查数据对照)→ ②校验前提(容器须自带布局组件;星级图标Image 属固定展示不得套用)→ ③先改代码后动场景(含内联回退,否则是功能回归)→ ④登记白名单再执行并用普查核对。已完成项:ShopPage商店(130→46 节点)、MailPage邮件(263→63 节点)。编译三目标 0 error。

下一轮:按四步流程做 HeroPage英雄(9 容器 / 190 节点,英雄数据仅 2 条 → 失配最严重)。先给 ClientHeroPage 加模板生成(含回退),再登记白名单。

2026-09-20(第十轮 · 第 4 步可执行性筛查):在普查工具里新增**"该容器是否有布局组件"判定**(DescribeLayout),因为 ConvergeList 会拒绝无布局组件的容器(否则克隆体叠在同一坐标=改变布局),必须先筛出来才知道哪些能安全模板化。

筛查结论(关键,决定后续路线):剩余 57 个内联列表容器,100% 自带布局组件 → 全部可安全模板化,0 个需要先改布局。按页面:FormationPage编队 12、ProfilePage个人中心 12、ActivityPage活动 12、HeroPage英雄 9、Player lineup 7、RankPage排行榜 2、Email Details Page(Have)/MailPage邮件/HeroDetailPage英雄详情主页 各 1。

这意味着第 4 步不存在"必须先加布局组件"的阻塞,剩余工作是把 ConvergeList 扩展到各容器 + 各页 View 补模板生成逻辑,属可批量推进的机械工作。 注意 星级图标Image×175 是固定 5 星展示、不是列表,不得套用模板化。

进度:全场景内联列表 64 → 57 处;ShopPage商店、MailPage邮件 已完成模板化。编译三目标 0 error。

下一轮:按容器清单推进下一页。优先 HeroPage英雄(9 容器/190 节点,而英雄数据只有 2 条 → 失配最严重、收益最大)。

2026-09-20(第九轮 · 第 4 步第二站 MailPage邮件 模板化落地 + 工具泛化):

先更正上一轮的一处误判:我曾在 CURRENT_STATE 写"MailPage 的邮件卡容器只有 ContentSizeFitter、未见布局组件"——这是错的。实测该容器同时有 ContentSizeFitter 与 GridLayoutGroup;6 张邮件卡的 y 坐标为 -141.5 / -450.12 / -758.74 / -1067.36 / -1375.98 / -1684.6,步长恒为 -308.62(= cell 283 + spacing 25.62)→ 确为布局组件自动排布,模板化同样不改变既有美术与布局尺寸。

工具泛化:把上一轮的一次性方法重构为通用 ConvergeList(containerPath, itemPrefix, templateName, target, templateField, rootField) + ConvergeKnownLists()。新增前提校验:容器若无 GridLayoutGroup/VerticalLayoutGroup/HorizontalLayoutGroup 则拒绝收敛并告警(避免克隆体叠在同一坐标=改变布局)。这条校验是模板化能否安全执行的关键闸门。

MailPage邮件 收敛结果(权威验证,走 Unity 实时对象模型):节点 263 → 63(删掉 5 张邮件卡各自的整棵子树)、交互节点 23 → 8、该页内联列表 7 处 → 1 处。全场景内联列表 63 → 57 处。代码侧 ClientMailPage 新增 ApplyMailCardsFromTemplate()(按 _mails.Count 克隆、为克隆体绑上 SelectMail(index)——场景里的邮件卡此前没有任何点击绑定、超出隐藏、写邮件名),并保留内联回退路径。编译三目标 0 error。

工具语义修正:普查"数据对照"节原先对模板模式会误报 ✘(场景只剩 1 个模板 vs 数据 N)。现 AppendPair 在 nodeCount <= 1 时输出 ✔ 模板模式(场景保留 1 个模板,运行时按数据生成 N 个),并把前缀匹配扩到模板名(道具卡牌/邮件)。

进度:全场景内联列表 64 → 57 处(ShopPage商店 与 MailPage邮件 已完成模板化)。剩余集中在 ProfilePage个人中心(26) / ActivityPage活动(15) / FormationPage编队(14) / HeroPage英雄(9) / Player lineup(7) / RankPage排行榜(2) 等,其中 星级图标Image×175 属固定 5 星展示、不是列表。下一轮按 Logs/list-worklist.md 继续。

2026-09-20(第八轮 · 负责人全权授权 · 第 4 步首个"1 模板 + 运行时生成"落地):负责人明确"全权授权",据此执行了首个列表数据化改造。

前提验证(关键,不可跳过):模板生成要成立,容器必须有布局组件自动排列克隆体,否则原有手工摆位的卡会全部叠在同一坐标——那才是真的改布局。实测 ShopPage商店/Product page/展示卡牌Scroll View/Viewport/Content 自带 GridLayoutGroup(cell 214.2×285.6,固定列数 2),13 张卡原本就是被布局组件排布的 → 改为模板生成不改变既有美术与布局尺寸 ✓

场景侧(ClientShellStructuralRepair.ConvergeShopCardList(),幂等):删除 12 张内联卡 → 保留 1 张重命名为 道具卡牌Item、禁用为克隆源 → 写入 ClientShopPage._cardTemplate 与 _cardListRoot。日志 Logs/converge-shop.log,15 处变更。

代码侧(ClientShopPage):新增 ApplyCardsFromTemplate()(按 _listings.Count 克隆、按下标绑定、超出隐藏、写入 道具名称)与 UseCardTemplate 判定;BindCards()/ApplyCards() 保留内联回退路径,因此场景写入前后都不会出现空窗。

权威验证(Logs/hierarchy-audit.txt,走 Unity 实时对象模型):ShopPage商店 节点数 130 → 46、交互节点 21 → 9、该页内联列表已消失;全场景内联列表 64 → 63 处。编译三目标 0 error。

顺带修正工具缺陷:普查报告的"数据对照"原先硬编码了商城 13 / 邮件 6,收敛后会失真;现改为从场景实时统计(FindExactPath + CountChildrenStartingWith),随收敛自动更新。

本轮新增的数据源基线(LocalClientDataService):商城 3 · 邮件 2 · 英雄 2 · 背包 3 · 任务 2 · 公告 2 · 活动 6 · 弹珠 2 · 排行榜[BattlePower/Challenge] 各 5 · 活动任务[Newbie/Advanced] 各 5。→ 不匹配是系统性的(如 HeroPage英雄 190 节点/9 处内联,数据只有 2 条英雄)。

下一轮:按 Logs/list-worklist.md 推进第 4 步。注意 MailPage邮件 的邮件卡容器只有 ContentSizeFitter、未见布局组件,需先确认其排布方式再决定是否套用模板生成(否则会叠在一起);其余容器(RankPage/ProfilePage 各 Scroll View、任务卡的道具列表)已确认自带 GridLayoutGroup。

2026-09-20(第七轮 · 列表数据化方向确认 + 改造清单产出):负责人确认:"好多 Scroll View 里面的 content 的 prefabs 都是不规范的,后续肯定是要通过数据获取的。"

据此把普查报告归并成可执行清单 Logs/list-worklist.md(12KB / 10 个页面)。归并结论:内联列表 64 个容器 / 约 339 个项对象,但去重后只有 8 种列表项类型 —— 星级图标Image×175(35 容器)、道具卡牌prefab×98(18 容器)、角色卡牌Button-final 1×32(5)、任务卡prefabs×12(2)、角色卡牌Button-final×6、邮件prefab×6、玩家战力排行prefabs×5、玩家排行perfabs×5。改造工作量取决于 8 个模板,而非 64 个容器。

重要区分:星级图标Image 属于固定数量展示(5 星靠显隐表达等级),不是数据列表 —— 保留节点结构、由代码按等级显隐即可;只有项数随数据变化的才是真列表。这条已写入 Assets/Client/MODULE.md §7(含负责人确认语与清单指引)。

每页容器分布:ActivityPage活动 12 个/62 项、FormationPage编队 12/62、ProfilePage个人中心 12/62、HeroPage英雄 9/48、Player lineup 7/36、MailPage邮件 7/36、RankPage排行榜 2/10、ShopPage商店 1/13、HeroDetailPage英雄详情主页 1/5、Email Details Page(Have) 1/5。

2026-09-20(第六轮 · 第 4 步第二站 MailPage邮件 · 代码侧收敛完成):取证——场景 Email come/邮件Scroll View/Viewport/Content 下有 6 张 邮件prefab,而 LocalClientDataService._mails 只有 2 条;旧实现的 _mailLabels 只是个 2 槽数组且在场景里全是空的,_emptyHint/_detail 同样为空 → 既写不进邮件名,也管不了另外 4 张卡的显隐。

已实施(纯代码,未动任何 anchor / sizeDelta / anchoredPosition):ClientMailPage 新增 ResolveCardContainer()(按场景真实路径 Email come/邮件Scroll View/Viewport/Content 定位,Transform.Find 逐级精确名)、ResolveCards()(收集 邮件prefab*,找不到容器时明确告警而非静默)、ResolveMissingReferences()(补齐 _pageRoot;_emptyHint 回退到 Default 节点,不新增任何节点)、ApplyMailCards()(按 _mails.Count 控制显隐 + 写入邮件名,卡数≠邮件数时告警)、SetCardText()(同时兼容 TMP 与旧版 UGUI 文本,按场景实际组件取用,避免用可能有误的序列化字段类型要求绑定)。RefreshLabels() 与 Refresh() 改为走上述路径。编译三目标 0 error。

遗留:_mailLabels(Text[],2 槽)已不再被使用,字段保留以免破坏已序列化数据;_detail 仍为空(场景中语义不明确的 Email Title/.../Email text 是否为详情区未确认),已做空判不会抛异常。邮件详情弹窗 Email Details Page(Have)/(No)、Success Receipt Interface 仍无任何打开逻辑,待负责人确认进入条件与内容。

验收方式:Play → 主页 → 邮件。应看到只有 2 张邮件卡(其余 4 张隐藏)、卡面显示"欢迎来到弹珠世界 / 开发期补偿"并带未读圆点与"附件待领取";Console 有 邮件卡已收集 6 张 与卡数不一致的告警(预期)。

2026-09-20(第五轮 · 第 4 步首站 ShopPage商店 · 代码侧收敛完成):取证先行——LocalClientDataService._shopListings 只有 3 条(shop-card-001..003),而场景里 ShopPage商店/Product page/展示卡牌Scroll View/Viewport/Content 下有 13 张 道具卡牌prefab。旧实现 BindPrefix(_regular, "道具卡牌prefab", OpenListing) 把 13 张全部绑到下标 0..12,而 OpenListing 有 if (index >= _listings.Count) return; → 10 张卡是死区,且表现为"静默无响应"(与 09-20 日志吻合:点第 5、5、3 张无反应,第 2 张才打开购买界面)。同时 RefreshListings() 原本完全不碰卡牌节点,卡面文字从未被写入。

已实施(纯代码,未动任何 anchor / sizeDelta / anchoredPosition):ClientShopPage 新增 BindCards()(按层级顺序显式收集卡牌并逐张按下标绑定)+ ApplyCards()(按数据条数控制显隐、把 _listings[i].DisplayName 写入卡面 道具名称,并在卡牌数与商品数不一致时输出告警)。BindPrefix 一把梭绑定已移除,RefreshListings() 末尾调用 ApplyCards()。编译三目标 0 error。

本轮未做(受目标约束"不改动既有美术与布局尺寸"):① 页面根仍非全屏拉伸(ShopPage商店 锚点 (0.5,0.5)-(0.5,0.5)),需负责人授权后才能改为 (0,0)-(1,1);② 13 张内联卡未删成"1 模板 + 运行时生成"(本轮只做显隐控制,删除实例属场景结构修改,待授权);③ 卡面 数量角标/数量黑底/道具数量 的语义未确认(是售价还是拥有数),未擅自写入。④ 页面根上挂的裸 Image 依赖未改。

验收方式:Play → 主页 → 商店。应看到只有 3 张卡(其余 10 张隐藏)、卡面显示"角色卡牌 1/2/3",点任意一张都能打开购买界面;Console 会输出卡牌数与商品数不一致的告警(这是预期,提示后续改模板生成)。

2026-09-20(第四轮 · 第 3 步完成):重写 Assets/Client/MODULE.md 为强制约定(135 新增 / 14 删除,11 个章节)。原文件已过期(称 ClientShell.unity 为"空场景"、目录描述与实际不符)。新约定覆盖:三层结构(PagesLayer 只放大厅;一级全屏界面标 _pageId 且 _routeByPageId=true;二级弹窗不占 pageId)、弹窗根必须全屏拉伸、命名(XxxPage/Content/List/Item/Button/Image;禁跨页关键词、首尾空格、拼写错误、裸 Image、指数后缀堆叠)、交互(交互节点必须自带命中面;装饰 Graphic 一律 raycastTarget=false,两者均记明"普查现状 0 违规,必须保持的基线")、模态(每页根自带 CanvasGroup 控制 blocksRaycasts;禁止再引入全局遮罩并写明 09-20 的两次故障为据)、列表(只留 1 个禁用模板 + 运行时生成;数量必须与数据条数对应;ContentSizeFitter 需单向拉伸锚点)、深度/规模上限(深度 ≤ 8、节点 ≤ 200)、依赖禁止事项、验证方式(编译三目标 0 error / 层级普查自检 / Play 后筛 [UI追踪] / 场景写入走 RepairAll 且需关 Unity)、待确认项。

每条约定都对应普查中的具体数字(64 处内联列表、22/23 非全屏根、5 处拼写错误、3 处首尾空格、18 处同级同名、ActivityPage活动 687 节点/深度 13 等),便于第 4 步逐页对照验收。

新发现的文档债:Assets/Client/UI/ 下仍有已删页面的子模块文档 —— UI/BackpackPage/MODULE.md(ClientBackpackPage 已于 09-18 删除)、UI/BadgePage/MODULE.md(ClientBadgePage/ClientBadgeButton 已删);UI/PrimaryPages/MODULE.md、UI/MainPage/HomeDisplay/MODULE.md 对应的页面脚本已不再被场景引用。按 AGENTS.md §6 的清理要求,需先记录候选项与依据再决定是否移除,本轮未删除。

治理覆盖检查:Runtime/Runtime/UI/Runtime/Services/Runtime/Domain/Editor/UI/Scenes 均已有 MODULE.md ✓

下一步(第 4 步 · 按页面逐个收敛,一次一页):建议顺序 ShopPage商店(130 节点/深度 8/1 处内联列表 13 张卡/21 交互)→ MailPage邮件(263/12/7 处内联/30 个命名残留)→ RankPage排行榜 → ActivityPage活动(687/13/15 处)→ FormationPage编队 → 其余。每页收敛后由负责人 Play 验收,通过再进下一页。

2026-09-20(第三轮 · 普查报告完成):新增只读工具 Assets/Client/Editor/ClientHierarchyAudit.cs(Menu:Client → 结构修复 → 6. 层级普查报告(只读),批处理 Pinball.Client.Editor.ClientHierarchyAudit.RunAudit),报告落盘 Logs/hierarchy-audit.txt(26.5KB)。该工具不写入场景。

普查结论(2841 个 GameObject):三层结构正确(PagesLayer 1 / PopupLayer 19 / SystemLayer 1)。交互组件 Button=209、Toggle=11、ScrollRect=35、自定义指针处理器宿主=291;Graphic=2559,其中 raycastTarget=true 有 2010。

好消息(前几轮的修复已生效,两项归零):A. 交互节点命中面来自祖先或缺失 = 0;B. 装饰 Graphic 仍参与射线 = 0。

待收敛的结构问题(按规模排序):① 列表在场景内联展开共 64 处(最大项):ProfilePage个人中心 26 处、ActivityPage活动 15 处、FormationPage编队 14 处、HeroPage英雄 9 处、MailPage邮件 7 处、Player lineup 7 处、RankPage排行榜 2 处、HeroDetailPage/ShopPage/Email Details(Have) 各 1 处。典型:MailPage 的 邮件prefab ×6 每个内嵌 道具卡牌prefab ×5(共 30 个节点被判定为跨页复制残留)。② 页面规模失衡:ActivityPage活动 687 节点/深度 13、ProfilePage个人中心 540 节点/深度 11、MailPage邮件 深度 12。③ 22/23 个页面根为非全屏(仅 Purchase Success Page 全屏拉伸)——这是"弹窗没有天然模态边界、才需要外挂遮罩"的量化依据。④ 命名问题:拼写错误 5 处(玩家排行perfabs 应为 prefab)、名字含首尾空格 3 处(Panel_Personalize␣␣、␣Card info2、challenge␣)、同级同名节点 18 处(大量 Image)。⑤ Purchase Success Page 与 Success Receipt Interface 交互节点数为 0 —— 前者全屏拉伸且无任何 Button/自定义指针处理器,打开后没有任何关闭手段(与 09-20 日志中 Open Purchase Success Page 栈深=2 之后从未关闭相互印证);后者同理。

正面发现(应保留的设计):多数二级弹窗根自带 CanvasScaler + GraphicRaycaster,即为独立子 Canvas,天然隔离 Canvas 重建,符合最佳实践;后续约定应固化这一点,而不是把 19 个弹窗摊在同一个 Canvas 下。

下一步(第 3 步):把层级与命名约定写入 Assets/Client/MODULE.md(该文件当前过期,仍称 ClientShell.unity 为空场景)。第 4 步按页面逐个收敛,建议顺序:ShopPage商店 → MailPage邮件 → RankPage排行榜 → ActivityPage活动 → FormationPage编队 → 其余。

2026-09-20(第二轮 · 方向调整):负责人指出"UI 层级不合理",经证据核对成立,决定停止逐点打补丁,转为结构性收敛。 本次会话暴露的 8 条结构问题(均有证据):① 节点名是复制残留不表意(RankPage 内叫 邮件Scroll View、MailPage 邮件内嵌 道具卡牌prefab、玩家排行perfabs 拼写错误);② 容器与视觉不分层,装饰 Image 与交互目标同节点、raycastTarget 默认全开(全场景关掉 479 个);③ 交互节点自身没有命中面,17 个 Button(avatar Mask/Avatar)靠祖先的 Image 接收射线;④ 预制体在场景内大量内联展开(全场景 90 个 道具卡牌prefab 实例,MailPage 单棵子树约 200 对象);⑤ 列表节点与数据不对应(商城 13 张卡 vs 更少的 _listings,多数卡点了无反应);⑥ 弹窗根节点尺寸非全屏(联系客服Page 732×377、ProfilePage 733×1300),没有天然模态边界;⑦ 19 个弹窗同挤一个 Canvas,无排序控制;⑧ 页面由复制粘贴产生(联系客服Page 上同时挂 ClientProfilePage + ClientUiPage)。

已执行的处置:撤除全局弹窗遮罩——上一轮新建的 弹窗遮罩 节点已验证会造成两个新问题:遮罩会盖住栈顶弹窗(Product Purchase Interface 点不动,日志中后续点击全部只命中 弹窗遮罩),以及栈未清空时遮罩残留把整个界面锁死。现已删除该节点并清空 ClientPopupService._maskRoot,RepairAll 中的 EnsurePopupMask 改为 RemovePopupMask。遮罩方案作废,模态改由"每页根自带 CanvasGroup"承担。

新的四步计划(负责人确认):(1) 撤掉遮罩 ✅ 已完成;(2) 产出全量层级普查报告(只读不写场景):每页层级深度、节点数、交互节点及其命中面归属、装饰节点、命名异常、数据-节点对应关系;(3) 把层级与命名约定写入 Assets/Client/MODULE.md(页面根命名;Content/List/Item/Button/Image 命名;交互节点必须自带命中面;装饰 Graphic 一律 raycastTarget=false;每页根自带 CanvasGroup 由它控制模态;列表由数据生成而非场景内联实例);(4) 按页面逐个收敛,一次一页、每页可独立验收,不改动既有美术与布局尺寸。

注意:Assets/Client/MODULE.md 当前仍是过期内容(称 ClientShell.unity 为"空场景"、目录结构描述与实际不符),将在第 (3) 步一并重写。目标 goal-3d2e3b1d 已被改写为新四步计划,但当前处于 paused,模型无权 resume,需负责人在 GUI 恢复。

2026-09-20(续 09-18):① ClientPopupService._popupLayer 自动兜底。 日志证实点商城道具卡后 Product Purchase Interface 确实被打开([UI追踪][弹窗] Open … 栈深=2),但 _popupLayer 为空导致 Open() 末尾的 SetAsLastSibling 被整段跳过,弹窗只能按场景原始兄弟顺序渲染——Product Purchase Interface 是 PopupLayer 第 11 个子节点、ShopPage商店 是第 4 个,于是购买界面被商店盖在后面,视觉上像"点了没反应/回到主页"。日志中 ReturnHome 出现 0 次,导航逻辑本身正常。现 Awake() 在 _popupLayer 为空时取 transform(该组件本就挂在 PopupLayer 上),不再依赖人工拖槽位。09-18 遗留的"商城道具卡未证实"一项就此收口——卡牌 Button 与 BindPrefix(_regular, "道具卡牌prefab", …) 均已生效。

② 全场景射线与显示解耦(负责人明确要求)。 新增 ClientShellStructuralRepair.DecoupleRaycastMenu()(Menu:Client → 结构修复 → 5. 解耦射线与显示(全场景),批处理可用)。规则:自身、或自身到最近 Canvas 之间的任一祖先上存在交互组件(Selectable/ScrollRect/EventTrigger/任何 I*Handler 自定义脚本)→ 保留 raycastTarget;否则关闭。不能按"该节点没 Button 就关"——交互节点的命中面常由子 Image 提供(商城 道具卡牌prefab 根有 Button 但自身无 Graphic,靠子立绘接收射线后冒泡到 Button)。实测:扫描 2559 个 Graphic,关闭 479 个、保留交互区 1993 个;第二次运行关闭 0 个(幂等)。内置命中面自愈:为 17 个"命中面原本挂在祖先上"的交互节点(全部形如 …/avatar Mask/Avatar (Button),Avatar 自身无 Graphic)恢复最近可用射线表面(targetGraphic → 子树首个 Graphic → 最近祖先 Graphic)。最终体检 所有 Button/Toggle 等仍保有可射线表面,0 破损。本操作不修改任何尺寸、锚点、位置与渲染顺序。

③ 诊断指标纠正。 ClientUiClickTracer 原打印 onClick监听数=N,实为 GetPersistentEventCount()(只统计 Inspector 持久监听),运行时 AddListener 永远计为 0 —— 曾误导负责人以为卡牌未绑定。现明确标注为 Inspector持久监听=N(运行时AddListener不在此计数)。

2026-09-18(阶段总结 · 交接):目标——修复非战斗客户端 UI 结构,使 ClientCanvas 的 PagesLayer/PopupLayer/SystemLayer 三层分层真实生效,消除双导航器并行、重复 ClientUiPageId、页面节点缺失/未注册,并把 Assets/Client 向 MVC 收敛。架构基线(负责人确认,优先于 HANDOVER_PLAN §3):PagesLayer 只留 MainPage主页;其余全屏界面全部是 PopupLayer 弹窗;SystemLayer 放 加载Page 与 Toast/遮罩。

执行结果(已落盘并逐项静态复核):PagesLayer=1(仅 MainPage主页 + ClientUiPage(Home));PopupLayer=19(9 个一级全屏界面挂 ClientUiPopup(路由) + 联系客服Page + 9 个二级弹窗(不路由));SystemLayer=1。全场景 ClientUiPage=1、ClientUiPopup=19、ClientHeroDetailPage=1(旧重复实现节点已删,含 64 子节点)、ClientProfilePage=1、ClientPageNavigator=0(类型与组件均已移除)、ClientUiBackButton=13、ClientPopupService/ClientSystemFeedback/ClientShellController/ClientUiClickTracer 各 1。已删 7 个孤儿脚本(ClientGachaPage/ClientMarblePage/ClientNoticePage/ClientBackpackPage/ClientHeroEnhancePage/ClientBadgePage/ClientBadgeButton)并整体废弃两个旧 Editor 工具(ClientShellDirectUpdater/ClientShellUiBuilder)。场景修复统一由 Assets/Client/Editor/ClientShellStructuralRepair.cs 的 RepairAll() 承担,幂等(重复运行只剩幂等项)。

本轮定位并修复的缺陷(均有日志/结构证据):① ClientPopupService 曾实现 IClientNavigationObserver,导航器 TryOpen 打开弹窗后 NotifyObservers 立即触发自身 CloseAll(),导致所有跳转表现为"点了没反应"——已移除该实现,收口职责归导航器 Back/ReturnHome。② ClientProfileNavigationController 原挂在 PagesLayer 且 Bind() 在 Start();ProfilePage个人中心 迁入 PopupLayer 后既是"启动即隐藏的弹窗"(Unity 不调用未激活对象的 Start),又不在其子树内 → 7 条路由全部失联、面板停在场景初始态。现改为挂在 ProfilePage个人中心、Bind() 移入 Awake() 并加 !_bound 兜底、搜索根改用显式 _pageSearchRoot。③ ToggleGroup A 上原本没有 ToggleGroup 组件、3 个顶部 Toggle 的 m_Group 全为 0;且 BindNestedToggles 只在 _pages.Values 内找 5 元组,而那 5 个 Toggle 在 Panel_Personalize/SubTabBar/Image/Panel → 全部未绑定。现按名字识别 + 补挂 ToggleGroup(AllowSwitchOff=false) + 写入 3 个 m_Group + 发现范围改为 SearchRoot。④ 全场景 ClientUiBackButton 实例为 0(旧工具找的是不存在的 ReturnButton,实际节点叫 后退Button/BackoffButton)→ 13 个后退键全部补挂。⑤ Panel_Showcase 的 大铭牌立绘image/铭牌Image 渲染在顶部 Toggle 之上并吞掉点击(日志 EventSystem 命中列表首位即该图);曾误用"改渲染顺序"修复并被负责人否决,现改为恢复原渲染顺序 + 只关闭 3 个装饰节点的 raycastTarget,视觉零变化。⑥ 展示卡牌Scroll View 1 滚不动是两因叠加:Content 锚点双向拉伸 + ContentSizeFitter 两轴均为 Unconstrained(等于不生效)→ 已改为 (0,1)-(1,1)+pivot(0.5,1) 且 VerticalFit=PreferredSize。⑦ 主页底部功能图标改为真实节点名(BottomFunctionIcon_Rank/_Shop/_Mail),MarbleButton 按负责人确认改指向 HeroPage英雄,BottomFunctionIcon 绑定联系客服弹窗。⑧ 7 个"页面 → 已迁出弹窗"的序列化槽位由工具自动写入(ClientShopPage×5、ClientRankPage×1、ClientHomePage×1),页面弹窗显隐改走 IClientPopupService。⑨ ClientBootstrap 原会为全图鉴活动节点重新 AddComponent<ClientUiPage>,迁移后会造成双所有者——已改为纯依赖注入。

验证:独立 Roslyn 全量编译 Assembly-CSharp[Editor]/Assembly-CSharp-Editor[Editor]/Assembly-CSharp[WebGL] 三目标均 0 error(脚本 Logs/verify-compile.ps1)。场景写入走批处理 Pinball.Client.Editor.ClientShellStructuralRepair.RepairAll,逐次日志见 Logs/client-structure-repair*.log。新增诊断设施 ClientUiTrace/ClientUiClickTracer([UI追踪][点击|导航|弹窗|显隐|路由],默认开启,ClientUiTrace.Enabled=false 可静音),已能输出"鼠标点了谁 → 谁接收 → 是否跳转 → 谁改了显隐"的完整证据链。负责人已验收:个人中心(3 主面板 + 5 子 Toggle 互斥、默认子页、后退)通过。

遗留风险 / 待确认(明天优先):① 未实测——商城的 13 张 道具卡牌prefab 已由工具补 Button(ClientShopPage 绑定名同时从场景中不存在的 展示卡牌Button 改为 道具卡牌prefab),但静态解析显示这 13 个 Button 块的 m_GameObject 无法在场景具名对象中定位,推断是 prefab 实例覆盖(未证实)。需负责人 Play → 商店 → 点道具卡实测:能弹购买界面即收口;仍无反应则改为直接给 道具卡牌prefab 预制体资产加 Button**。② ClientPopupService._maskRoot 与 ClientSystemFeedback 的 Toast 槽位仍为空(弹窗不切遮罩 / Toast 只记警告),需负责人指定节点。③ ClientFormationPage._slot/_status 未绑定;编队页完整逻辑(3 槽位/4 队伍/队内编号/详情键)尚未实现。④ Email Details Page(Have)/(No)、Success Receipt Interface 已迁入 PopupLayer 但代码里没有任何打开逻辑(负责人早前也确认"逻辑好像没实现")。⑤ 任务卡无需补 Button(其子树内已有 领取+待完成键Button 且 ClientActivityPage 已绑定 RequestClaim;负责人已确认维持现状)。⑥ BackpackButton 仍会提示 Backpack 未注册(背包页已按负责人要求删除)。⑦ Assets/Client/MODULE.md 已过期(仍称 ClientShell.unity 是空场景),需按 AGENTS.md §6 刷新。⑧ ClientPageNavigator 类型已删,其残留 m_Enabled=0 组件在场景中已移除(计数 0),如后续再见到需复查。下一阶段:S5 逐页 Controller 抽离(ClientServices.Data 调用点需从 View 移出)、S7 IClientDataService 按域拆分并返回快照而非活列表、A3 为 LocalClientDataService 纯规则补自动化测试。

2026-09-16:负责人 Play 验证发现活动列表卡片无法点击;确认现有 活动底框prefabs 根节点只有 Image、没有 Button,而旧绑定仅处理预挂 Button,导致全图鉴入口事件从未注册。ClientActivityPage.BindSeasonalList 现会在运行时为每张现有活动卡补充 Button,以卡片 Image 作为可射线 targetGraphic,关闭默认颜色过渡并绑定对应活动索引;不修改或新增场景 GUI 节点。全图鉴页领取素材捕获同步改为页面激活后的延迟初始化,避免 inactive Animator 产生 Animator is not playing an AnimatorController 警告。独立 Roslyn 全量编译退出码 0;Unity 批处理仍因可见 Editor 占用工程未进入导入,日志 Logs/codex-complete-guide-entry-fix-compile.log。待 Refresh 后复验第一张“全图鉴活动”可点击进入详情页。

2026-09-16:已为现有 ClientCanvas/PagesLayer/Complete Guide Event Page全图鉴活动 接入运行时控制器,未创建、删除或调整 GUI 节点。页面默认隐藏,活动列表首个本地“全图鉴活动”入口经 ClientUiNavigator 打开;左下 BackoffButton 返回活动列表,问号按钮显示初始隐藏的规则弹窗。现有 23 个 Image 均可按枚举槽接收数字图片 ID,6 个 TMP/Legacy 文本均可按枚举槽赋值;进度明确绑定语义正确的 进度条底框 与其子节点 进度条,完成态、领取/待完成素材切换、不可重复领奖和已领取图标复用活动页规则。本地数据服务新增全图鉴活动读取/领奖边界,当前使用 2/2 可领取模拟数据,仅用于演示。Unity 命令行因当前可见 Editor 占用工程未进入导入,日志 Logs/codex-complete-guide-event-compile.log;使用 Unity 现有完整响应文件执行独立 Roslyn 编译退出码 0。待负责人 Refresh 后 Play 验证入口、弹窗、进度、领奖和返回;正式活动期数/规则/奖励、图片 ID→YooAsset、服务端持久化及统一 Tips 仍待确认/接入。

2026-09-15:负责人已在 Unity Play 模式完成加载页人工验收,确认 ClientCanvas/SystemLayer/加载Page 层级正常,一键 5 秒分段加载演示、SmoothDamp 平滑进度追赶和三标点 1→2→3 循环显隐均无问题。本轮标记为“本地加载界面表现闭环完成”;正式 YooAsset/网络加载进度源与数字图片 ID 解析仍待后续接入。

2026-09-15:负责人验证发现一键演示中的插值主要表现为速度差异。原因是旧演示每帧都提交连续线性目标,输入本身已平滑。现将 5 秒演示改为模拟真实加载器的分段检查点(0%、8%、22%、47%、63%、82%、94%、100%),每段只更新一次目标值,由正式 SmoothDamp 逻辑平滑追赶,便于直观验证“消除跳变”而非单纯减速。文本差异检查通过;Unity 命令行仍因当前 Editor 占用工程而未编译,日志 Logs/codex-loading-stepped-preview-compile.log。

2026-09-15:加载进度由直接赋值改为“目标进度 + 显示进度”平滑追赶。SetProgress 只更新 0~1 目标值,单一协程通过 Mathf.SmoothDamp 和 Time.unscaledDeltaTime 更新 Image.fillAmount,默认平滑时间为 0.15 秒;连续到达的分段进度不再瞬间跳变。Begin/Complete 使用立即赋值保证起点和 100% 无拖尾,一键 5 秒演示自动复用该插值逻辑。文本差异检查通过;Unity 命令行编译因当前 Editor 占用同工程未进入编译,日志 Logs/codex-loading-progress-smoothing-compile.log,待现有 Editor Refresh 后验证。

2026-09-15:加载页新增仅 Unity Editor 可用的一键 5 秒演示。进入 Play 后选中 ClientCanvas/SystemLayer/加载Page,可在 ClientLoadingPage Inspector 点击“播放 5 秒加载演示”;演示会显示加载页、用非缩放时间将进度从 0% 推至 100%,同时运行三标点循环,结束停在 100%。演示方法使用 UNITY_EDITOR 条件编译,不进入正式 Player 构建。文本差异和唯一调用点检查通过;Unity 命令行编译因当前 Editor 占用同工程未进入编译,日志 Logs/codex-loading-preview-compile.log,待现有 Editor 执行 Assets > Refresh 后验证 Console。

2026-09-15:负责人复验发现 加载Page 既不在 PagesLayer 也未显示于 SystemLayer。查明为上次手工修改大型 Unity YAML 时只将加载页的 m_Father 指向 SystemLayer,但子列表引用被误写到活动页“已领取icon”下。现已删除误引用,并在 SystemLayer 的 m_Children 中精确写入 加载Page RectTransform;文本检查确认父子双向引用唯一且一致。当前打开的 Editor 需重新打开 ClientShell.unity 以丢弃内存中的旧层级快照后复验。

2026-09-15:已将负责人新制作的 加载Page 从 PagesLayer 迁移至 ClientCanvas/SystemLayer,移除误挂的 ClientUiPage/ClientProfilePage、旧 IClientResourceLoadSource/独立跳动标点逻辑,以及 ClientUiFeedback.SetLoading 旧加载遮罩入口。新 ClientLoadingPage 已绑定背景、Logo、进度底框、进度条、3 个标点和 TMP 加载文本;所有 Image 支持数字 ID 接口,文本支持泛型赋值,进度条按 01 或 0100 从左向右增长,标点按 1→2→3 依次消失后再依次出现。当前打开的 Unity Editor 已对新加载控制器及场景变更自动编译,Tundra build success、运行时和 Editor 程序集均产出;后续删除 ClientUiFeedback 旧入口的小改动已做唯一调用点静态检查,待 Editor 再次 Refresh。独立命令行 Unity 因同工程被 Editor 占用未进入编译,日志 Logs/codex-loading-page-compile.log。待人工 Play 验证进度条和标点时序;正式图片 ID→YooAsset 解析实现仍待接入。

2026-09-14:负责人已完成人工验证,确认 ActivityPage活动 本轮大体逻辑无问题:默认新手页、三页互斥、新手/进阶状态隔离、蓝底黄条进度显示、满进度切换领取态、领奖后显示已领取、奖励卡数量保持及底部页签选择状态均通过当前验收。本轮标记为“本地模拟闭环完成”;真实任务持久化、服务端领奖确认、背包/邮件投递、图片 ID→YooAsset 和统一 Tips 仍待后续接入。

2026-09-14:ActivityPage 任务完成态补充真实素材切换。此前进度满仅设置 Button 可交互,并尝试使用尚未接入的数字图片 ID,因此仍显示场景默认“待完成”。现从既有 领取+待完成键Button.controller 的 Pressed 动画捕获“领取底框/领取”两张 Sprite:未满恢复默认待完成图,满进度立即固定显示领取图,点击成功后仍进入已领取图标状态;后续数字 ID 解析器接入后可覆盖该本地素材兜底。

2026-09-14:负责人复验发现完成任务 1/1 仍只显示蓝色。原因是黄色进度节点虽然已按 100% 宽度更新,但 Canvas 同级绘制顺序使蓝色底框覆盖在其上。源码已明确调整为“蓝色底框在下 → 黄色进度在上 → 进度数字最上层”,不修改场景保存的节点层级。当前源码时间为 18:14,而 Unity Library/ScriptAssemblies/Assembly-CSharp.dll 仍为 18:12,证明打开的 Editor 尚未导入此次源码;命令行实例又因同工程被占用而无法代编译。负责人需在现有 Unity 窗口退出 Play 后执行 Assets > Refresh(或 Ctrl+R),等待 Console 编译完成,再重新 Play 验证。

2026-09-14:根据负责人首轮 ActivityPage 人工验证修正四项行为:场景中命名写反的进度节点已按实际视觉解释为“蓝色 进度条=底框、黄色 进度条底框=实际进度”;奖励数据少于现有道具卡数量时不再隐藏任何 道具卡牌prefab;页面根直接激活时在 OnEnable/Start 强制初始化为新手任务;领奖刷新后恢复当前底部页签 Button 的 EventSystem 选择状态,领奖不再退出页签选择动画。ClientBootstrap 在场景无有效 Camera 时创建仅清屏的运行时 Camera,避免 Game 窗口透出 No cameras rendering,不改变 UI 层级。MSBuild 运行时编译退出码 0;Unity 命令行因当前 Editor 占用工程未进入编译,日志:Logs/codex-activity-page-fixes-compile.log。待负责人重新 Play 验证。

2026-09-14:已按负责人重构后的现有 GUI 重写 ActivityPage活动,并停用 ClientShellDirectUpdater 的旧活动页生成/筛选路径,未创建、删除或调整 UI 节点。进入页面默认显示新手任务;新手/进阶/活动三页互斥,新手与进阶各有 5 条独立数据和独立领奖状态,多出的第 6 个现有卡槽会随无数据自动隐藏。任务说明、当前/总数、从左向右的离散进度条、奖励道具卡、待完成/可领取/已领取状态已接入;未完成按钮无响应,领取成功后领取 Canvas 隐藏、已领取图标显示,同一数据状态不可重复领取。领奖接口显式支持拒绝/处理中/已发放以及背包/邮件投递渠道;活动卡文本、红点、热门标记和图片均有替换接口。运行时和 Editor MSBuild 验证退出码 0;Unity 2022.3.57f1c2 命令行验证因可见 Editor 占用工程而在导入前退出,日志:Logs/codex-activity-page-compile.log。正式服务端持久化、邮件投递规则、图片数字 ID→YooAsset 映射和 Tips 弹窗仍待接入。

2026-09-14:HeroDetailPage英雄详情主页 的旧空引用逻辑已替换为按现有层级运行时绑定。HeroPage 的 8 张既有卡牌均接入点击入口(双击等同连续点击),打开详情时直接传递被点卡牌的 立绘Image.sprite。详情页已提供图片数字 ID、文字、六项属性、立绘左右切换、三页互斥 Toggle、两项升级消耗、材料数量样式、确认升级和装备槽扩展事件接口;默认显示天赋页,Toggle 的 Checkmark 不再被常态自动隐藏。误挂在其它同级页面的旧详情组件会自动停用,不删除其 GUI。开发期本地数据以“养成材料 + 金币”填充两个消耗槽并完成校验/扣除,失败通过 TipRequested 预留弹窗接入。Unity 2022.3.57f1c2 命令行验证因可见 Editor 占用工程而在编译前退出,日志:Logs/codex-hero-detail-logic-compile.log;补充 MSBuild 对 Assembly-CSharp 验证退出码 0。负责人已在 Unity 中完成人工验证并确认无报错,卡牌入口与详情页本轮逻辑验收通过。最终材料配方、装备槽动作、图片 ID→YooAsset 映射和 Tips 样式仍待确认。

2026-09-12:Player lineup 的本地模拟阵容卡牌数量已由 5 扩展为 6,与 展示卡牌Scroll View/Content 的六个既有卡槽(含 展示卡牌plusButton (5))一致;无需调整 UI 节点或布局。命令行 Unity 编译仍因 Editor 占用工程而在脚本编译前退出,日志:Logs/codex-rank-lineup-six-cards-compile.log;待 Editor 自动重编译与人工验证第六张卡牌显示。

2026-09-12:已定位并清理 Assets/Client/animator controller/Battle powerButton.controller 的 Normal 动画片段中的唯一空函数名 Animation Event。该事件会在按钮状态动画播放时触发 AnimationEvent has no function name specified! 并刷屏;删除后不影响 Normal/Highlighted/Pressed/Selected/Disabled 的既有 Sprite 动画与按钮交互。文本检查确认该控制器已无 functionName:;命令行 Unity 验证因 Editor 占用工程未进入导入/编译,日志:Logs/codex-battle-power-animation-event-compile.log,待 Editor 重新导入后确认 Console 不再出现该警告。

2026-09-12:主页实际按钮 BottomFunctionIcon_Rank 已接入既有 ClientHomePage → ClientUiNavigator → RankPage排行榜 导航链;排行榜顶部 Bottom page function bar/BackoffButton 在未打开玩家阵容时改为明确调用 ReturnHome,保证回到主页且清空返回栈。未改动任何 UI 节点、布局或位置。命令行 Unity 编译因当前 Editor 占用工程而在脚本编译前退出,日志:Logs/codex-rank-navigation-compile.log;待 Editor 自动重编译与人工点击验证。

2026-09-12:排行榜旧的三条文本快照模型、GetRankEntries 接口与 ClientShellDirectUpdater 的旧排行榜生成入口已移除,场景中旧组件的已失效序列化字段也已清理。ClientRankPage排行榜 实际节点扫描确认:固定背景区、Battle Power Ranking、Challenge List、Player lineup 均已在场景中;新实现仅通过节点名绑定现有 5 条榜单行与 5 张阵容卡,不改变 Prefab、位置或布局。新增本地模拟的分榜单/玩家阵容/卡牌数据边界,以及头像、头像框、徽章、立绘、属性与品质 Sprite-ID 映射接口。命令行 Unity 编译已按流程执行,但工程正被 Unity Editor 实例占用而在脚本编译前退出;日志:Logs/codex-rank-compile.log。待 Editor 自动重编译或释放工程后重验,并人工点击验证榜单切换、查看阵容、关闭阵容和顶部返回。

2026-09-11:为实习开发学习与成果复盘创建本地 Git 快照提交 840fc330(客户端源码、Lua/WebGL/DLL、场景、预制体、工程配置与治理文档;不含图片、音频、模型、材质、字体、动画和资源包)。推送至配置的 origin 时 GitHub 返回 Repository not found;待负责人提供已创建且当前凭据可访问的仓库地址或授予访问权限后重试。

2026-09-10:按负责人要求关闭商城导航诊断输出但保留脚本。ClientShopNavigationDiagnostics 与返回链路仍在,ClientShopPage.enableNavigationDiagnostics 默认关闭;后续若需复现,仅在该现有组件 Inspector 勾选此字段即可恢复完整 [ClientShop导航诊断] 日志。

2026-09-10:商城回归测试日志已核对通过。[ClientShop导航诊断] 连续四次均显示 PointerDown → PointerUp → 商城后退 onClick 已触发 → shopSelf=False/shopHierarchy=False/home=True,证明主返回按钮、统一导航与主页恢复完整闭环。Event MallButton 空函数名 Animation Event 仅出现于修复前的日志段;当前控制器已无空事件,重新导入后的后续运行记录未再出现该警告。未发现本轮商城运行时代码的异常。

2026-09-10:负责人要求商城主返回按证据诊断,不再猜测。场景树已确认 Product page 只含展示卡牌 Scroll View,之前按“后退Button”绑定的对象均属其它页面;商城实际返回节点为 ShopPage商店/Bottom page function bar/BackoffButton。现已精确绑定该节点,并新增开发期 ClientShopNavigationDiagnostics,记录绑定、PointerDown/Up/Click、Button onClick 及处理前后商城/主页/导航器状态,供 Console 回传定位。另已清除 Event MallButton.controller 的 Pressed 动画中空函数名 Animation Event,消除该警告。待 Unity 自动编译与人工复现日志。

2026-09-10:负责人反馈商城主界面“后退Button”仍无效。已为 Product page 下该按钮及其全部既有可射线子节点添加独立 IPointerClickHandler,不再只依赖可能被通用返回组件重置的 Button.onClick;点击时重置购买态、关闭商城弹层、调用统一导航 ReturnHome,并以直接隐藏商城/激活主页作为导航状态异常时的兜底。待 Unity 自动编译与人工点击验证。

2026-09-10:商城逻辑正在替换为角色卡牌占位商品方案:已移除早期 ClientShopProduct、GetShopProducts 与 TryPurchaseShopProduct,改用可替换的 ClientShopListing、批量购买与已购数量查询接口;本地单价暂定 10 水晶石。ClientShopPage 正在绑定负责人已完成的商城 GUI(常规/活动页、购买弹窗、成功页、兑换码、订单和待发货)。Unity 命令行编译因已有 Unity Editor 占用工程而在脚本编译前退出,日志:Logs/codex-shop-compile.log;尚待 Editor 空闲后重验。

2026-09-10:根据负责人提供的 Unity Console,已删除 ClientShellDirectUpdater 中仍调用旧商城 API 的三个早期编辑器路径(旧商城生成、商品确认生成、核心交互中的商城绑定)。此前 ConfigureDetail、Purchase、Configure 的 4 个 CS1061 阻断错误不再有源码引用;未触碰已完成的商城 GUI。待 Unity 自动重编译后确认 Console 无新错误。

2026-09-10:负责人提供的重编译 Console 只剩 4 个 Editor 警告,均已按来源修正:AddBuildMapUtility 避免遮蔽基类成员、AssetBundleTool 移除已废弃的确定性选项、HybridCLR 自有命令移除不可达旧分支、CodeGuard 修正错误标记为校验器的实际菜单项(第三方目录改动由负责人本次“修警告”请求明确授权)。尚待 Unity 再次完成自动重编译确认无警告。

2026-09-10:负责人反馈主页商城图标无响应。已定位为主页只绑定旧名 ShopButton、而实际节点名为 BottomFunctionIcon_Shop,且 ClientUiNavigator 被禁用导致导航事件无人处理;已补充图标绑定并启用导航器。PC 客户端会话新增 allowPcServerConnection 总开关,ClientShell 配置为 0:自动启动和手动启动都会只输出“客户端开发模式:已屏蔽”,不执行网关、TCP、握手或登录。未删除服务器代码;待 Unity 自动编译及点击验证。

2026-09-10:负责人提供的 Console 剩余 6 条警告已处理:Init.OnCompleted 去除无 await 的 async;ClientTcpConnectionProbe 的仅 WebGL 会话配置改在 UNITY_WEBGL && !UNITY_EDITOR 条件块内声明,避免 PC 编译把其序列化值判为未使用。未改变 WebGL 运行路径或 PC 连接屏蔽开关;待 Unity 自动重编译确认。

2026-09-10:商城层级与交互修正:所有商城页/弹层每次打开都会 SetAsLastSibling,购买成功页的全部现有可射线节点均绑定点击关闭,商城所有同名“后退Button”统一路由至 Back,且返回导航改为全场景查找已启用的 ClientUiNavigator。ClientUiFeedback 的 Toast 会置顶并在 2 秒后自动隐藏;待 Unity 编译及手动点击验证。

2026-09-10:负责人反馈常规商城的展示卡牌 Scroll View 覆盖新弹层。已将商城页面/弹层打开时的提升策略扩展为根 Canvas.overrideSorting = true 与递增 sortingOrder,不再只调整 Transform sibling;因此购买、成功、兑换、订单和待发货会始终高于角色卡牌独立 Canvas。待 Unity 编译与手动验证。

2026-09-10:负责人反馈卡牌无法打开购买页、商城主后退未回主页、兑换码图标/文字无法聚焦。OpenListing 现实时刷新本地商城条目而非依赖进入页时缓存;ClientUiNavigator 新增清空历史的 ReturnHome 并由商城主后退调用;兑换输入框的现有 Image 与 Text (TMP) 增加点击聚焦转发。待 Unity 编译和手动验证。

2026-09-09:已在 PC 与小程序共享的 ClientServerPacketRouter 中将 CLGTDisconnectNtf(模块 1、协议 2)分类为 ClientGtDisconnectNotification,可读协议日志会输出断开码和中文原因(正常通知、超时、踢线、异地登录、维护、与平台/游戏服断连、系统错误、离线挂机等)。PC ClientServerPcSession 收到该包会输出原因;小程序 ClientTcpConnectionProbe 收到该包也会输出原因,且在英雄数据未完成时将其作为失败原因。未改变连接策略或添加自动重连。文本差异检查通过;Unity 命令行编译被当前打开的 Unity Editor 占用,未进入脚本编译,日志为 Logs/codex-disconnect-notification-compile.log。

2026-09-09:PC 协议会话 session-20260909-194125.protocol.log 已验证握手、游客登录(头像/头像框/称号/徽章/铭牌 ID 均已分类输出)及 CLPFGetHeroAck 全部成功,随后接收 CLGTDisconnectNtf(模块 1、协议 2、9 字节)并发生远端强制断开。Editor.log 中“TCP 读取失败”由后台读取线程先收到连接重置、主线程后归档该断开通知的时序造成;本次没有协议解析失败或前置数据丢失证据。原始包文件仍被运行中会话占用,未读取断开通知的具体 code;若需要区分正常断开与踢线/维护,待会话关闭释放文件后再读取或在记录器中增加该协议摘要。

2026-09-09:codex-clientgt-profile-sync-compile.log 已显示 Unity 批处理完成,但其无窗口进程未自行退出并留下 Temp/UnityLockfile,导致 Hub 显示项目仍打开。已确认无桌面 Editor 窗口后,仅结束本次由代理启动的 batchmode 进程并删除其 0 字节临时锁文件;项目锁已释放,未删除项目资源或用户数据。

2026-09-09:已按 D:\Users\Administrator\Desktop\弹珠配置\tools\jbproto\Protocol\ClientGT.lua/.hpp 同步新版 CLGTLoginAck:字段顺序为头像、头像框、称号、徽章、铭牌,后两项替代旧 dan/decorate。项目 ClientGT.cs 的二进制读写已更新;PC 端 GamePlayer 保存五项装扮 ID;小程序 ClientTcpConnectionProbe 按同一顺序读取;ClientServerPacketRouter 的登录摘要会分类输出五项内容 ID,继续隐藏用户 ID、昵称、手机号、令牌和点券。未主动发送登录/装扮业务请求。ClientPF.cs 的协议 3–22 个性化分类保持生效。文本差异检查通过;Unity 2022.3.57f1c2 命令行编译已完成,日志 Logs/codex-clientgt-profile-sync-compile.log 包含 Batchmode quit successfully invoked,未检出 error CS。

2026-09-09:后端同步的 ClientPF.cs 已包含个性化协议:称号、铭牌、徽章、头像、头像框的查询列表及装备/卸下(模块 2、协议 3–22)。ClientServerPacketRouter 已补充分类和脱敏字段摘要:列表记录状态、数量和最多 20 个内容 ID,操作记录对象 ID、装备/卸下动作及回包状态;不会主动发送业务请求。初始检查时工作区未找到新版 ClientGT.cs,后续已由负责人提供的 .lua/.hpp 核对并同步,详见本文件最新记录。Unity 2022.3.57f1c2 命令行编译已完成,日志 Logs/codex-personalization-protocol-compile.log 包含 Batchmode quit successfully invoked,未检出 error CS。

2026-09-09:负责人确认购买数量节点 Purchase quantity 为 TextMeshProUGUI。ClientShopPurchaseQuantityProgress 的数量及端点文字引用已改用 TMP_Text,可直接绑定该文字节点;长期基线已补充 TMP/UGUI 文本引用类型一致性与交互组件挂载位置约束。未改场景或 GUI。Unity 命令行编译再次被已打开的同项目 Unity 实例阻止,未进入脚本编译;日志为 Logs/codex-shop-purchase-tmp-compile.log。

2026-09-09:新增 Assets/Client/Runtime/UI/ClientShopPurchaseQuantityProgress.cs,仅实现商城购买弹窗的数量选择进度条逻辑,未改场景、GUI、商品交易或本地服务。组件可按商品 PurchaseLimit 初始化 0 至最大值的离散挡位;支持减、加、最大值、拖动图标、图标数量/左右端点文字及填充进度同步。Unity 命令行编译被已打开的同项目 Unity 实例阻止,未进入脚本编译;日志为 Logs/codex-shop-purchase-quantity-compile.log。待负责人关闭 Editor 后重跑编译并在 ClientShell 手动绑定现有节点验证。

2026-09-08:负责人反馈 7 页面仍出现叠加;已读取 Editor.log,当前日志只有旧 ClientProfileNavigationBinder 的历史运行记录,没有新 ClientProfileNavigationController 的运行时记录,无法据此判断接管链路。已在新控制器加入临时诊断:启动绑定数量、顶部/底部 Toggle 路由、每次 Navigate/Back,以及 ApplyRoute 后实际激活页面数量。待负责人测试后根据 [ClientProfileNavigationController] 日志继续定位;本次未改 GUI。

2026-09-08:按负责人确认,删除旧的 ClientProfileNavigationBinder,改为 ClientProfileNavigationController 统一管理个人中心、主页展示及个性化 5 个页面,共 7 个互斥路由;顶部 3 个 Toggle 全局切换,个性化底部 5 个 Toggle 从现有持久化目标解析路由,后退使用历史栈。场景只保留一个活动路由,未调整 GUI。Unity 命令行编译仍被其他 Unity 实例占用,日志为 Logs/codex-profile-route-controller-compile.log。

2026-09-08:已根据 C:\Users\Administrator\AppData\Local\Unity\Editor\Editor.log 的真实运行日志修复主页展示后退:ReturnFromShowcase 已收到点击,但个人中心 Toggle 原本就是 True,因此没有触发 Toggle 事件;现在设置 Toggle 后始终显式调用 ShowPage(_profilePage)。临时诊断已移除。Unity 命令行验证仍被其他 Unity 实例占用,日志为 Logs/codex-showcase-back-fix-compile.log。

2026-09-08:已根据 Unity Editor.log 定位主页展示后退问题:按钮持久化回调正常触发,但“个人中心Toggle”原本已为 isOn=True,重复赋值不会触发 onValueChanged,所以页面仍保持主页展示。ReturnFromShowcase 现无论 Toggle 状态如何都会显式执行 ShowPage(_profilePage);临时诊断组件已移除。

2026-09-08:修正主页展示后退与客户端初始页:HomepageDisplayPage主页展示 下现有 后退Button 已在场景中持久化绑定到 PagesLayer 导航绑定器,点击后选中“个人中心Toggle”;场景初始状态改为仅激活 MainPage主页,ProfilePage个人中心 初始关闭,需点击主页 ProfileButton 后才打开。未调整任何 GUI 尺寸、位置、层级或素材。

2026-09-08:按负责人要求不调整主页展示页面任何 GUI 尺寸、位置、层级或素材;仅在 ClientProfileNavigationBinder 中绑定现有 后退Button,点击后选中“个人中心Toggle”并返回个人中心。待 Unity Editor 空闲后进行命令行编译验证。

2026-09-08:已将个人中心导航绑定器挂到 ClientShell/PagesLayer。运行时按现有节点名绑定顶部“个人中心 / 主页展示 / 个性化”3 页;个性化进入时默认显示铭牌,并在 5 个个性化页面切换时刷新各自底部 5 项 ToggleGroup 的现有页面显隐事件。新增 Assets/Client/Runtime/UI/ClientProfileNavigationBinder.cs;Unity 命令行日志为 Logs/codex-profile-navigation-bind-compile.log,本次未取得实际编译结果,日志同时记录 Unity Licensing Client 访问令牌不可用与项目已被其他 Unity 实例占用。

2026-09-08:继续修复 ClientShell 中个人中心相关两组“个人中心 / 主页展示 / 个性化” Toggle 的 Checkmark 常态显隐。两组共 6 个 Toggle 已解除 graphic 自动绑定,保留 isOn、ToggleGroup 与页签切换事件;待 Unity Editor 关闭后完成命令行编译验证。

2026-09-07:修复 ClientShell 中 BadgePage/Panel 的 5 个 Toggle Checkmark 显隐问题。已解除 Toggle graphic 自动绑定,保留各 Toggle 的 isOn 与 onValueChanged;场景中的 Checkmark 节点可常显。Unity 命令行编译因当前 Editor 占用项目未进入编译,证据见 Logs/codex-badge-checkmark-compile.log。

当前短入口(2026-09-04):WebGL/微信 TCP 最小会话探针目标为“HTTP 获取 IP/端口 → TCP 建连 → 握手 → 游客登录 → 完整解析英雄数据 → 仅成功后主动关闭”。固定 device 为 WebGLMiniGameDeviceIdentifierPinballNode(40 位纯英文)。最新微信日志已确认 HTTP、TCP 与握手回包均成功;未进入游客登录的根因是探针附着的 Boot Init 对象在切换 LoginScene 时被卸载。探针现会迁移至独立的跨场景对象,待关闭当前 Unity Editor 后重新编译/同步 HotFix、构建并验证。

  • 更新时间:2026-08-28
  • 当前分支:main
  • 当前阶段:C2「英雄、图鉴与背包」
  • 当前唯一目标:在不影响原街机/战斗、服务端或总架构的前提下,建立可持续开发的微信小程序客户端界面与养成模块基础。

已确认边界

  • 开发范围:养成、英雄/图鉴、背包、商城、邮箱、排行榜、活动、任务、扭蛋、个人中心及本地模拟逻辑。
  • 交互范围权威输入:D:\Users\Administrator\Desktop\J 界面交互草图-弹珠项目-小程序端.pdf。该 PDF 为单页全流程草图;其中已画出的页面、页签、跳转、空态、禁用态、弹窗、筛选与领取反馈属于客户端验收范围。
  • 不开发:战斗/关卡、服务端、支付、账号、总架构;不改造既有 Boot、MainScene、LoginScene 和街机战斗业务。
  • 新功能入口:Assets/Client/Scenes/ClientShell.unity,不加入现有 Build Settings;后续从该场景验证客户端页面。
  • 保留现有 YooAsset、HybridCLR、XLua、URP 和微信 SDK;真实平台接入仅做接口准备。

工作区保护

  • 已提交前的场景、热更新、YooAsset、HybridCLR、项目设置和微信 SDK 差异均视为既有受保护改动,禁止清理、重置、批量暂存或覆盖。
  • 可再生产物(Library/、Logs/、Temp/、.vs/、obj/、*.csproj、*.sln)仅记录为清理候选;本轮未删除。
  • 历史 WebGL/小游戏调试证据保留于 BUG_TRACKER.md、VERSION_HISTORY.md 和 AI_MODEL_UPGRADE.md,不再作为 C0 的阻塞项。

当前检查点

  • 2026-09-02 微信开发者工具自动预览失败,错误为 80051 source size 31013KB exceed max limit 30MB。已检查 D:\Users\Administrator\Desktop\弹珠接入text_1\720\minigame,目录约 30.26 MiB,主要文件为 data-package/*.webgl.data.unityweb.bin.br 约 17.6 MB、wasmcode/*.wasm.br 约 12.0 MB。结论为上传包超限,运行尚未开始,当前日志不能用于判断 UnityWebRequest 或 TCP;需先减少小游戏上传包约 1–2 MB,再继续验证。

  • 2026-09-02 诊断微信日志“请求网关地址后无后续回调”:源码 NetController.cs 已包含 GetIpPortWithUnityWebRequest,但实际小游戏资源 Assets/HotUpdateResources/Dll/WebGL/HotFix.dll.bytes 与 HybridCLRData/HotUpdateDlls/WebGL/HotFix.dll 时间均为 2026-08-28 13:55:15,未包含本次 2026-09-02 的 UnityWebRequest 改动。结论为 HotFix DLL 未重新编译/同步,当前不是 TCP 或 GetHeroReq 问题。待关闭 Unity Editor 后执行 Build/WebGL/Compile And Sync HotFix DLL,再重新生成 WebGL/小游戏资源并清理微信开发者工具旧缓存验证。

  • 2026-09-02 已将 Assets/Main/Boot.unity 中 ClientTcpConnectionProbe.useDirectLocalTest 改为 0,保留 runOnStart=1、useRealGuestLogin=1,下次小游戏启动将从本地直连切换为 GetIpPort → UnityWebRequest 网关发现流程。当前 DefaultQLClient.ServerUrl 仍为局域网 HTTP 地址,开发者工具验证需临时允许未校验合法域名;正式验证前仍需替换为服务端 HTTPS 网关域名。

  • 2026-09-02 已按负责人提供的微信小游戏兼容方案改造 NetController.GetIpPort():WebGL/小游戏分支改为 UnityWebRequest.Post 协程,复用 DefaultQLClient.ServerUrl、ClientGetGateConnectionRequest 的 zone_id、原 QL 参数、MD5 签名及 JSON/XML 解析,成功后继续写入 SysDefines.Ip/Port 并调用原连接回调;PC/Editor 分支仍保留旧 QL 客户端链路。当前网关地址未在仓库新增,小游戏正式验证前需将 DefaultQLClient.ServerUrl 配置为负责人提供的 HTTPS 网关域名,并在微信开发者工具加入 request 合法域名。Unity 批处理日志为 Logs/codex-gateway-uwr-compile.log,已完成脚本编译并显示 Batchmode quit successfully invoked,无本轮 error CS;进程退出状态仍待系统回收确认,尚未进行小游戏人工验证。

  • 2026-09-01 已重写 Assets/Client/Runtime/ClientTcpConnectionProbe.cs 为小程序 TCP 客户端最小会话:连接后按旧协议握手(正确读取 errcode + payload + random_key)、游客登录、登录成功后发送 CLPFGetHeroReq(模块 2、协议 1、空请求体),并解析 CLPFGetHeroAck(模块 2、协议 2)。解析英雄数据已包含新版 CLPFHeroInfo.fight Int64 字段及英雄组数据;默认不发送真实业务协议,需临时开启 useRealGuestLogin。本轮命令行编译因 Unity 2022.3.57f1c2 工程被当前 Editor 占用而未进入编译,日志为 Logs/codex-tcp-client-compile.log;待负责人关闭 Editor 后重试,并在微信开发者工具验证游客登录与 GetHero 响应。

  • 2026-08-31 已新增加载页运行时逻辑:IClientResourceLoadSource 声明可替换的资源进度事件边界,ClientLoadingPage 将进度映射到从左到右的 Image.FillAmount 并显示百分比,ClientLoadingDotsAnimator 以不受 Time.timeScale 影响的协程让 1/2/3 三个加载点依次上移下落并循环。当前脚本已改为自动绑定负责人已有的“加载Page”节点,待挂载验证。

  • 2026-08-31 已新增 ClientTcpConnectionProbe:通过既有 NetController.GetIpPort 获取网关地址,再调用微信 SDK WXBase.CreateTCPSocket 仅验证 TCP 建连,成功后立即关闭,不发送登录或业务协议。因 Assets/Client 属于 Assembly-CSharp,探针已改为反射调用 HotFix 类型,解除 AOT→HotFix 的链接依赖。微信运行日志已证明 Unity 与探针均正常启动;首次探针早于 HotFix 加载而退出,现已改为最多等待 15 秒,待 NetController 就绪后再请求网关。该 C# 改动待负责人关闭当前 Unity Editor 后执行 Unity 批处理编译,并重新构建/转换小游戏验证。

  • 2026-08-31 TCP 探针复测证据:已输出“等待 HotFix 与 NetController 初始化”,但远程版本请求 https://<CDN域名>/1/HotUpdate/NewAB/WebGL/2026-08-28-720/StreamingAssets/yoo/DefaultPackage/PackageManifest_DefaultPackage.version 返回 HTTP 404;本次日志没有网关 IP/端口、TCPSocket.connect、成功或失败回调。结论:当前尚不能判断服务器或 TCP,先修复/绕过该 YooAsset 远程版本文件路径后再验证。

  • 2026-08-31 OSS 路径修复后复测:版本文件、Manifest 与 HotFix DLL 均已下载,StartGame.Start、GameController.Init 完成并进入大厅资源加载。探针仍只输出“等待 HotFix 与 NetController 初始化”;经代码检查,NetController.Instance 为单例基类继承的静态属性,原反射查询缺少 BindingFlags.FlattenHierarchy,已补齐。命令行 Unity 编译再次因负责人 Unity Editor 占用工程被拒绝,日志为 Logs/codex-tcp-probe-compile.log;待关闭 Editor 后重新构建/转换小游戏验证。

  • 2026-08-31 后续导出目录 D:\Users\Administrator\Desktop\弹珠接入text_1\720\minigame 已在 18:22 重新生成,晚于探针修正时间;Boot.unity 中 ClientTcpConnectionProbe.runOnStart: 1。负责人提供的下一份开发者工具日志从运行 18 秒后的插件帧率监控开始,不含任何 Unity 启动段或 [TCP探针] 字样,不能作为 TCP 成功/失败证据;需清空 Console 后重新编译并从启动时采集。

  • 2026-08-31 负责人确认运行中曾出现“[TCP探针] HotFix 已就绪,开始请求网关 IP/端口(HTTP)”。结合 NetController.asyncExecuteWebRequest 的 Task.Run(() => WebClient.Execute(...)) 和 QLWebClient 的 System.Net.HttpWebRequest 实现,当前 TCP 验证的阻塞点已确定为旧 HTTP 网关发现层:Unity WebGL 不支持 System.Net 网络类和线程,故不会进入网关回调及 WXTCPSocket.connect。后续需负责人提供当前网关 HTTP 契约以实现 UnityWebRequest 适配,或提供非仓库化的固定测试主机/端口以跳过网关验证。探针日志已改为不记录真实 IP/端口。

  • 2026-09-01 负责人提供局域网 TCP 测试目标;已为 ClientTcpConnectionProbe 新增不含真实地址的 useDirectLocalTest、directTestHost、directTestPort 本地直连配置。启用后会跳过旧 HTTP 网关,直接调用微信 TCPSocket.connect,成功后立即关闭且不发送业务数据。真实地址仅由负责人临时在 Inspector 输入,禁止保存、提交或写入日志。Unity 批处理 Logs/codex-tcp-probe-direct-compile.log 已出现 Tundra build success,但进程仍处于资源刷新,尚未有最终 Exiting batchmode successfully 退出标记。

  • 2026-09-01 局域网最小 TCP 连通性验证通过:微信开发者工具日志依次出现“使用本地直连测试参数”“已调用微信 TCPSocket.connect”“TCP 建连成功;未发送任何业务数据”“TCP 连接已关闭”。结论仅覆盖开发者工具到当前局域网测试目标的 TCP 建连;不覆盖 HTTP 网关发现、登录/业务协议、真机网络、正式域名白名单或线上服务器。测试完成后必须清空本地直连参数并禁止提交。

  • 2026-09-01 已只读审查旧 TCP 协议:每个包为“小端 4 字节总长度(含长度字段)+ 2 字节模块 ID + 2 字节协议 ID + 正文”;旧心跳请求为模块 1、协议 8,应答为模块 1、协议 9 且携带状态码。但旧连接流程要求先执行握手,握手包含平台、版本及设备标识,不能在未取得服务端确认的情况下假定它无副作用。微信 SDK 已具备二进制 TCPSocket.write 和 onMessage 能力;当前探针仍刻意未注册收包或发送。下一步需服务端负责人书面确认“握手+一次心跳”可用于测试,或提供独立 echo 测试契约(请求字节、期望响应、无副作用保证),然后才可扩展探针进行实际收发验证。

  • 2026-09-01 负责人已明确授权当前服务器的真实登录验证。ClientTcpConnectionProbe 已扩展为仅在“本地直连 + useRealGuestLogin”均开启时执行一次“旧协议握手 → 取得随机密钥 → 旧协议游客登录 → 接收登录响应 → 关闭”的最小链路。地址、token、随机密钥及用户资料均不记录;日志只输出包长度、协议阶段和响应状态。Unity 2022.3.57f1c2 批处理命令已执行,但被当前同版本 Editor 的项目锁阻止,未进入编译;日志为 Logs/codex-tcp-real-login-compile.log。未关闭负责人 Editor,待其在当前 Editor Console 确认无编译错误后进行 WebGL/微信小游戏人工验证。

  • 2026-09-01 微信开发者工具存在高频“request 错误”日志,普通 Console 记录会被刷出缓冲区。探针已增加仅在真实登录测试开启时显示的微信原生结果弹窗,覆盖连接失败、异常数据、无效包、握手拒绝、登录成功/拒绝与登录超时;弹窗不显示地址、token、随机密钥或用户资料。第二次 Unity 2022.3.57f1c2 批处理仍因打开的 Editor 项目锁而未编译,日志为 Logs/codex-tcp-login-modal-compile.log。待当前 Editor 自动编译确认后重新导出小游戏验证。

  • 2026-09-01 已用两个负责人提供的候选端口进行真实登录测试;两次均出现“TCP 建连成功 → 已发送 62 字节旧协议握手 → ECONNRESET”,无握手响应。结论:小游戏的 TCP 建连与二进制发包均已验证;候选端口的服务端在解析/拒绝握手后主动断开,尚未验证登录或收包。探针弹窗已修正为在该状态显示“建连成功后被服务器断开”;当前批处理仍被已打开的 Editor 锁阻断,日志为 Logs/codex-tcp-reset-message-compile.log。不再盲测端口,等待服务端确认网关端口及握手兼容性。

  • 2026-09-03 已重新核对 PC 端 ClientGT.cs、新 ClientPF.cs、ClientPFResponser.cs、NetController.cs 与微信 ClientTcpConnectionProbe.cs:微信当前发送 CLPFGetHeroReq(模块 2、协议 1),按新 CLPFGetHeroAck 顺序读取英雄数组与英雄队伍数组,现有日志已显示获取英雄成功。探针新增可选 logDeviceIdentifier,开启后仅打印设备来源、长度、首尾片段和 SHA-256 指纹,不打印完整设备值。Unity 批处理再次被已打开 Editor 锁阻止,日志为 Logs/codex-tcp-device-log-compile.log;需在当前 Editor 自动编译后导出验证。

  • 2026-09-03 负责人明确授权内网临时查看完整机器码。探针新增默认关闭的 logFullDeviceIdentifier,仅在同时开启设备诊断时打印完整值;测试结束必须关闭并清理临时构建/日志,不得提交或用于正式包。批处理验证日志为 Logs/codex-tcp-full-device-compile.log,当前仍受已打开 Editor 项目锁影响。

  • 2026-09-03 最新微信运行日志显示启动阶段通过 CDN 请求 e112a2cd0d6ade4f.webgl.data.unityweb.bin.br 并返回 404,随后 start game fail: 404;本地新导出文件存在于 D:\Users\Administrator\Desktop\弹珠接入text_1\720\webgl。此前“仅脚本改动无需上传 OSS”的判断不适用于当前 CDN 配置:WebGL 重新导出产生了新的带 hash 数据文件,必须上传该文件(及实际出现 404 的其他 CDN 文件)或清空 CDN 配置改用本地包。

  • 2026-09-03 新日志已无 WebGL 资源 404,且出现 TCP 建连、握手、游客登录、CLPFGetHeroReq 发送及英雄回包解析日志,说明小游戏到服务器的游客 TCP 登录和 GetHero 数据链路已跑通。设备诊断显示 SystemInfo.deviceUniqueIdentifier 返回 n/a(长度 3);探针已修正为将 n/a、unknown、undefined、全零及过短值视为占位值并回退 PlayerPrefs.DeviceId。批处理日志为 Logs/codex-tcp-device-fallback-compile.log,仍因打开 Editor 项目锁未进入编译;待 Editor 自动编译后重新导出验证回退值。

  • 负责人新增长期决定:已有 UI 页面默认只写脚本,不新建 Page、UI 节点,不替换素材或改变 GUI 排版;场景结构修改必须得到明确授权。

  • 已建立客户端目录/模块说明和独立场景;ClientBootstrap 默认注册本地模拟账户、货币、英雄与背包服务,未触碰既有街机启动链或网络层。

  • ClientShell 已切换为“场景可编辑 UI”路径:运行时页面脚本仅负责数据绑定和导航;Assets/Client/Editor/ClientShellUiBuilder.cs 会在编辑器中生成 ClientCanvas、MainPage、ProfilePage、按钮与改名弹窗,避免运行时临时创建 UI。

  • 首次执行 UI 生成工具时,Unity 2022.3.57f1c2 报出内置字体 Arial.ttf 已失效;现已改用其要求的 LegacyRuntime.ttf。该次生成在第一个文字节点前中断,需删除已生成的 ClientCanvas 后重新执行菜单。

  • 场景首次运行曾因 MainPage.OnEnable 早于 ClientBootstrap.Awake 访问本地服务而报错;页面首轮绑定已改为 Start,重新启用页面时才在 OnEnable 刷新,消除了根节点启用顺序依赖。

  • 主页与个人中心使用负责人提供的参考图作为临时构图底图,展示本地名称、ID、战力;主页可进入个人中心,个人中心支持返回与本地改名。未完成入口只显示待开发提示,不进入旧街机页面。

  • 主页展示页已实现本地最小闭环:根据本地英雄拥有状态选择展示立绘、确认后写回 IClientDataService。展示资源位于 UI/HomeDisplay;第二名示例英雄未拥有,选择时应提示锁定。

  • 主页面所有一级入口已由“待开发提示”改为实际导航。英雄和背包页展示本地模拟列表;其余入口先进入统一内容页并保留返回主页,待对应规则/交互稿细节实施后替换为独立页面。

  • 负责人已确认主页面必须由独立可编辑的 Scene 节点构成。生成器已改为不使用 HomeReference.png,改为创建背景、主立绘、头像框、头像、顶部栏、战力栏、编队/弹珠卡、底部导航及独立入口节点;已有旧 Canvas 需由负责人删除后重建。

  • 已定位主页素材未显示的直接证据:复制进工程的 PNG 默认 textureType: 0、spriteMode: 0,LoadAssetAtPath<Sprite> 会得到空对象。生成器现会在首次构建前将 UI/MainPage/Sprites 中的纹理统一设置为单图 Sprite 后再生成节点。

  • 已进入 C2 英雄/图鉴页面:拆分素材已复制至 Assets/Client/UI/HeroPage/Sprites,不使用整张参考图;英雄/图鉴页签、全/火/水/风筛选、已拥有/未拥有示例英雄卡和返回主页已可演示。

  • 英雄详情页已使用 Assets/Client/UI/HeroDetailPage/Sprites 的拆分素材直接写入 ClientShell:HeroDetailPage、背景、战力区、属性区、技能区、文案和返回按钮均为可单独选中的场景节点。点击已拥有英雄会由 ClientPageNavigator 打开详情页,并绑定本地名称、等级、战力;返回会回到英雄页。技能、装备和真实数值仍待确认。

  • 英雄页卡牌视觉已补齐为独立节点:品质框、属性图标、三颗星级和未拥有遮罩/文案均可在 Hierarchy 调整。现有全/火/水/风筛选、已拥有英雄详情入口和未拥有提示保持不变;尚未提供独立英雄立绘,因此继续复用已有的英雄卡素材。

  • 背包页已直接写入 ClientShell:BackpackPage、筛选按钮、材料槽、装备槽、状态文案和返回按钮均为可编辑场景节点。主页底部背包入口进入该页;数据来自 IClientDataService.GetInventory(),支持全部/材料/装备筛选及条目选中提示。背包专用切图、道具名称/图标和出售/合成/装备规则待确认。

  • 负责人已将优先级调整为“先完成主页所有可点击一级界面”。扭蛋、商城、邮箱、排行榜、活动、任务、公告已从统一 FeaturePage 拆成独立的 GachaPage、ShopPage、MailPage、RankPage、ActivityPage、TaskPage、NoticePage 场景根节点;每页有独立标题、状态区和返回主页按钮,并由共享导航控制器分发。当前仅完成本地展示/返回闭环,业务数据和规则待对应资料确认。

  • 客户端 UI 已按统一 Canvas 架构重构:ClientCanvas 是唯一 UI 宿主,包含 PagesLayer、PopupLayer、SystemLayer。现有所有客户端页面根节点已迁入 PagesLayer;ClientUiPageId、ClientUiPage 和 ClientUiNavigator 负责页面标识、生命周期(Enter/Pause/Resume/Exit)与返回栈。旧 ClientPageNavigator 已在 ClientShell 停用,不再参与运行时导航;所有现有返回按钮由 ClientUiBackButton 在运行时接入统一返回栈。

  • 个人中心、主页展示、铭牌、英雄详情已接入新页面栈:个人中心的“主页展示”与“个性化”分别进入展示页和 BadgePage;铭牌页使用 UI/BadgePage/Sprites 中的拆分素材,提供三项选择、预览和本地确认;英雄详情新增元素、星级、拥有状态绑定。真实解锁、装备/技能、铭牌服务器同步仍待确认。

  • 2026-08-28 已针对运行中反馈补强统一导航:主页每次显示都会重新接管所有一级入口(含头像/资料),返回按钮每次启用都会重接 ClientUiNavigator.Back;返回栈因域重载或 Inspector 直接激活而为空时会兜底回到主页。待 Unity Editor 自动重编译后的人工验证与关闭 Editor 后的命令行编译。

  • 2026-08-29 已完成扭蛋与商城页的本地模拟闭环:ClientGachaPool/TryDrawGacha 演示单抽、十连、钻石不足、奖励结果和英雄解锁;ClientShopProduct/TryPurchaseShopProduct 演示商品、余额校验、限购与奖励入背包。ApplyGachaPage、ApplyShopPage 已将二者写入 ClientShell 的 PagesLayer,页面根及其背景、标题、货币、商品/抽取按钮、结果/状态和返回按钮均为可编辑场景节点。正式概率、保底、运营周期、商品价格、限购与货币规则仍待产品确认。

  • 2026-08-29 已完成邮箱页本地模拟闭环:ClientMail、读取和附件领取均通过 IClientDataService 处理;MailPage 可展示未读/已领状态、阅读详情、领取附件、重复领取提示和空列表节点。ApplyMailPage 已将页面节点写入 PagesLayer;真实邮件协议、有效期、批量领取和附件类型仍待产品确认。

  • 2026-08-29 已完成排行榜页本地快照展示:榜单通过 ClientRankEntry/GetRankEntries 提供,页面显示前三名、自己的排名与刷新状态;真实赛季、奖励、跨服与实时刷新待服务端契约。首次 ApplyRankPage 在 Logs/codex-rank-page-apply.log 因未先添加 ClientRankPage 组件出现空引用,已按定位补齐组件创建;重试成功并写入 PagesLayer。

  • 负责人已确认后续无素材页面的视觉实施规则:先按交互草图生成可编辑的完整页面版式骨架,再由负责人替换节点素材;不再使用通用纯色占位页作为页面成品。草图已完成视觉核对,活动、任务与公告等后续页面将沿用其“顶部标题/页签、主体内容卡或列表、状态信息、固定底部操作/返回”的结构。

  • 2026-08-29 已完成活动页本地模拟闭环并按草图结构落地:ClientActivity/TryClaimActivity 支持活动状态、进度、领取成功、进度不足与重复领取;ActivityPage 含标题栏、页签、活动卡、详情面板、领取区和返回入口,均为 PagesLayer 下可替换的场景节点。运营日历、真实活动条件、奖励配置和红点规则待产品/服务端确认。

  • 2026-08-29 已完成任务页本地模拟闭环并按草图结构落地:ClientTask/TryClaimTask 支持任务进度、领取成功、未完成与重复领取;TaskPage 含标题栏、每日/成长页签、任务卡、详情面板、领取区和返回入口,均为 PagesLayer 下可替换的场景节点。日/周重置、真实任务条件、奖励配置和红点规则待产品/服务端确认。

  • 2026-08-29 已完成公告页本地模拟闭环并按草图结构落地:ClientNotice/TryReadNotice 支持公告列表、未读状态、阅读详情和空态;NoticePage 含标题栏、公告列表区、详情区和返回入口,均为 PagesLayer 下可替换的场景节点。真实运营后台、公告有效期、排序与推送规则待产品/服务端确认。

  • 2026-08-29 已完成英雄培养最小闭环:英雄详情新增“培养”入口,HeroEnhancePage 可展示等级、战力、金币/材料消耗并执行 TryUpgradeHero;成功时扣除本地资源、提升英雄及主页战力,覆盖材料不足、金币不足和本地等级上限。正式升级公式、材料类型、等级上限、升星与装备规则待产品确认。

  • 2026-08-29 已补齐背包本地锁定交互:选择材料或装备后可切换锁定/解锁,状态经 TrySetInventoryItemLocked 写回本地数据并显示在条目文本;LockToggleButton 已写入现有 BackpackPage。装备穿戴、出售/分解、批量操作和真实锁定协议待产品/服务端确认。

  • 2026-08-29 已在英雄培养页补齐本地升星:TryStarUpHero 会消耗本地金币与材料、提升星级及英雄/主页战力,并覆盖资源不足与星级上限。StarUpButton 已写入 HeroEnhancePage;正式升星条件、消耗、成功率与星级效果待产品确认。

  • 2026-08-29 已在背包补齐本地装备/卸下:选中演示装备后可装备给本地演示英雄或卸下,锁定装备会被阻止操作;装备状态经 EquippedHeroId 写回并显示在条目中。装备槽位、属性、替换确认与战斗数值影响不在当前授权范围。

  • 2026-08-29 已打通扭蛋与英雄图鉴的本地拥有状态:扭蛋获得第二名英雄后,英雄页会移除锁定遮罩、显示英雄名并允许进入详情;未获得时保持锁定提示。该同步使用同一 IClientDataService 英雄数据,不新增临时状态。

  • TeamButton/GachaButton 作为独立预制体放入 MainPage 后,导航由 ClientHomePage 按 Root 名称在运行时绑定,避免替换预制体导致生成器一次性 Button 回调丢失。

  • 下一检查点:按统一页面架构逐页补齐一级页面已确认交互;新增弹窗统一放入 PopupLayer,全局提示/加载统一放入 SystemLayer,不再新增独立导航器或运行时业务 UI 根。

  • 2026-08-29 缺口盘点:主页的编队与弹珠入口目前复用英雄页,尚未形成独立的编队/弹珠页面;扭蛋缺卡池切换、结果弹窗和历史,商城缺商品详情/确认,邮箱缺批量领取/筛选,活动/任务/公告缺真实页签切换与筛选,英雄/背包缺装备详情/替换确认和养成预览,通用 PopupLayer/SystemLayer 的弹窗、红点、加载尚未实现。后续按当前计划逐项补齐;服务端、支付、战斗、真实运营配置仍不在范围内。

  • 2026-08-29 已完成缺口计划的第一批:主页“编队”与“弹珠”已不再复用英雄页,分别进入 FormationPage 和 MarblePage;前者支持选择已拥有英雄进入单出战槽位,后者支持选择已拥有弹珠装备,均使用 IClientDataService 本地保存状态。队伍人数、编队属性、弹珠战斗效果与真实资源解锁仍待产品/服务端契约。

  • 2026-08-29 已补充扭蛋抽取历史:GetGachaHistory 记录本地抽取次数,GachaPage 显示“暂无抽取记录/已抽取次数”;历史节点已写入页面,卡池切换与结果弹窗仍待完成。

  • 2026-08-29 已实现扭蛋结果弹窗代码:ClientGachaResultPopup 归属 PopupLayer,单抽/十连成功后展示奖励并可关闭;ApplyGachaResultPopupPass 已准备将弹窗节点写入 ClientShell,待 Unity 批处理完成场景写入确认。

  • 2026-08-29 扭蛋结果弹窗已实际写入 ClientShell/ClientCanvas/PopupLayer/GachaResultPopup;正确版本 Unity 2022.3.57f1c2 批处理成功,日志为 Logs/codex-gacha-result-popup-apply-57.log。

  • 2026-08-29 已补充邮箱批量领取与筛选逻辑:IClientDataService.ClaimAllMails、ClientMailPage.ShowAll/ShowUnread/ClaimAll 覆盖全部/未读和一键领取;场景按钮由 ApplyMailBatchAndFilterPass 写入,待 Unity 批处理验证。

  • 2026-08-29 已补充活动/任务“进行中/已领取”筛选逻辑及场景写入器 ApplyActivityTaskFilterPass,待 Unity 批处理验证。

  • 2026-08-29 已完成商城商品详情与二次确认逻辑:首次点击商品只选中并展示价格/奖励,ConfirmPurchase 才执行扣款和入包;ApplyShopConfirmPass 负责写入详情与确认按钮。

  • 2026-08-29 已补充背包道具详情展示:选中材料/装备时显示数量、装备状态及待确认属性说明;ApplyBackpackDetailPass 负责写入详情节点。

  • 2026-08-29 核心本地交互已完成场景落地:ApplyCoreInteractionScenePass 已将商城详情/确认、邮箱全部/未读/一键领取、活动与任务筛选、公告全部/未读、背包详情一次性写入 ClientShell。活动和任务复用现有顶部页签节点并附加按钮回调,不创建覆盖节点。

  • 2026-08-29 已完成 SystemLayer 统一反馈:UiFeedback 包含可编辑的 Toast 与 Loading 节点;商城购买失败/成功及邮箱一键领取接入 Toast。主页的邮件、活动、公告入口已增加 RedDot,由本地数据的未读/可领取状态刷新。

  • 2026-08-29 已补齐核心防误触和养成预览:装备首次点击穿戴只进入确认态,再次点击才执行;英雄培养页显示升级/升星后等级和星级预览。本地演示仅有一件装备,真实多装备替换规则仍待产品配置。

  • 2026-08-29 已实现五个底部导航的选中视觉代码:个人中心/弹珠/主页/背包/活动未选中使用各自 2.png 白色图标,选中使用 1.png 黄色图标,并显示独立 *_SelectedFrame 高亮底框;主页默认选中,跳转与返回主页均会刷新选中项。场景写入入口为 ApplyBottomNavigationSelectionPass。

验证与风险

  • 2026-08-31 已执行 Unity 2022.3.57f1c2 批处理场景写入与编译,日志为 Logs/codex-loading-page-apply.log;退出日志为 Exiting batchmode successfully now!,包含 Tundra build success 和加载页写入成功信息,未检出本轮 error CS 或异常。仍需负责人打开场景进入 Play Mode,手动提供一个实现 IClientResourceLoadSource 的加载器并验证视觉节奏。

  • 铭牌素材首次导入尝试未写入资源:PowerShell 对 Copy-Item -LiteralPath "...\\铭牌\\*" 不解析通配符,报路径不存在;目标 Assets/Client/UI/BadgePage/Sprites 保持为空。已定位为复制命令参数问题,后续仅以明确目录枚举重试。

  • 个人中心/铭牌/英雄详情场景写入首次批处理未执行:Logs/codex-personal-pages-apply.log 报“another Unity instance is running with this project open”。当前有一个由 Hub 启动的主 Unity Editor 及两个其子进程,均不得由自动化结束;素材已复制至 Assets/Client/UI/BadgePage/Sprites,代码尚待该 Editor 关闭后执行 ApplyPersonalCenterPages 编译与场景写入。

  • 负责人关闭 Editor 后,已执行 ClientShellDirectUpdater.ApplyPersonalCenterPages:退出码 0,场景已保存,日志为 Logs/codex-personal-pages-apply-retry.log;日志包含 Tundra build success、个人中心/展示/铭牌/英雄详情写入成功和 Exiting batchmode successfully now!,未检出本轮编译错误或异常。

  • 2026-08-28 已以 Unity 2022.3.57f1c2 批处理执行 ClientShellDirectUpdater.ApplyHeroDetailPage:脚本编译图构建成功,退出码 0,日志为 Logs/codex-hero-detail-apply.log;日志包含 Exiting batchmode successfully now!,未检出本轮 error CS、Exception 或编译失败。既有项目警告仍存在:Assets/Main/Init.cs 的 CS1998、Assets/Editor/AddBuildMapUtility.cs 的 CS0108、旧 AssetBundle API 的 CS0618 与 HybridCLR 编辑器代码的 CS0162。

  • 2026-08-28 已以同一 Unity 批处理执行 ClientShellDirectUpdater.ApplyBackpackPage:退出码 0,场景已保存,日志为 Logs/codex-backpack-apply.log;日志包含 Exiting batchmode successfully now!,未检出本轮 error CS、Exception 或编译失败。

  • 英雄卡视觉增补的首次批处理在 Logs/codex-hero-visual-pass.log 中止:场景加载后 GameObject.Find("HeroPage") 无法找到被禁用的页面根。已定位为 Unity 的活动对象查找限制,改为包含禁用对象的组件查找后再继续;首次命令未写入场景。

  • 修正后已执行 ClientShellDirectUpdater.ApplyHeroVisualPass:退出码 0,场景已保存,日志为 Logs/codex-hero-visual-pass-retry.log;日志包含 Tundra build success 与 Exiting batchmode successfully now!,未检出本轮编译错误或异常。

  • 2026-08-28 已执行 ClientShellDirectUpdater.ApplyPrimaryPages:退出码 0,场景已保存,日志为 Logs/codex-primary-pages-apply.log;日志包含 Tundra build success 与 Exiting batchmode successfully now!,未检出本轮编译错误或异常。

  • 2026-08-28 已执行 ClientShellDirectUpdater.ApplyCanvasUiArchitecture:退出码 0,场景已保存,日志为 Logs/codex-client-ui-architecture.log;日志包含 Tundra build success 与 Exiting batchmode successfully now!,未检出本轮编译错误或异常。

  • 2026-08-28 已在 Editor 释放后以 Unity 2022.3.57f1c2 批处理编译导航修复:退出码 0,日志为 Logs/codex-navigation-fix-compile.log;日志含 Tundra build success 与 Exiting batchmode successfully now!,未检出本轮 error CS、Exception 或编译失败。仍待负责人在 Play Mode 走通头像 → 个人中心 → 主页展示/个性化(铭牌)及返回。

  • 2026-08-29 已以同一 Unity 批处理分别执行 ClientShellDirectUpdater.ApplyGachaPage 与 ApplyShopPage:退出码均为 0,日志为 Logs/codex-gacha-page-apply.log、Logs/codex-shop-page-apply.log;均含 Tundra build success、页面写入成功与 Exiting batchmode successfully now!,未检出本轮 error CS、Exception 或编译失败。

  • 2026-08-29 已以同一 Unity 批处理执行 ClientShellDirectUpdater.ApplyMailPage:退出码 0,日志为 Logs/codex-mail-page-apply.log;包含 Tundra build success、邮箱页面写入成功与 Exiting batchmode successfully now!,未检出本轮 error CS、Exception 或编译失败。

  • 2026-08-29 已以同一 Unity 批处理重试执行 ClientShellDirectUpdater.ApplyRankPage:退出码 0,日志为 Logs/codex-rank-page-apply-retry.log;包含 Tundra build success、排行榜页面写入成功与 Exiting batchmode successfully now!,未检出本轮 error CS、Exception 或编译失败。

  • 2026-08-29 已以同一 Unity 批处理执行 ClientShellDirectUpdater.ApplyActivityPage:退出码 0,日志为 Logs/codex-activity-page-apply.log;包含 Tundra build success、活动页面写入成功与 Exiting batchmode successfully now!,未检出本轮 error CS、Exception 或编译失败。

  • 2026-08-29 已以同一 Unity 批处理执行 ClientShellDirectUpdater.ApplyTaskPage:退出码 0,日志为 Logs/codex-task-page-apply.log;包含 Tundra build success、任务页面写入成功与 Exiting batchmode successfully now!,未检出本轮 error CS、Exception 或编译失败。

  • 2026-08-29 已以同一 Unity 批处理执行 ClientShellDirectUpdater.ApplyNoticePage:退出码 0,日志为 Logs/codex-notice-page-apply.log;包含 Tundra build success、公告页面写入成功与 Exiting batchmode successfully now!,未检出本轮 error CS、Exception 或编译失败。

  • 2026-08-29 已以同一 Unity 批处理执行 ClientShellDirectUpdater.ApplyHeroEnhancePage:退出码 0,日志为 Logs/codex-hero-enhance-page-apply.log;包含 Tundra build success、英雄培养页面与详情入口写入成功及 Exiting batchmode successfully now!,未检出本轮 error CS、Exception 或编译失败。

  • 2026-08-29 已以同一 Unity 批处理执行 ClientShellDirectUpdater.ApplyBackpackInteractionPass:退出码 0,日志为 Logs/codex-backpack-interaction-apply.log;包含 Tundra build success、背包交互节点写入成功及 Exiting batchmode successfully now!,未检出本轮 error CS、Exception 或编译失败。

  • 2026-08-29 已以同一 Unity 批处理编译英雄拥有状态联动:退出码 0,日志为 Logs/codex-hero-ownership-sync-compile.log;包含 Tundra build success 与 Exiting batchmode successfully now!,未检出本轮 error CS、Exception 或编译失败。

  • 2026-08-29 已以同一 Unity 批处理执行 ClientShellDirectUpdater.ApplyHeroEnhanceStarPass:退出码 0,日志为 Logs/codex-hero-enhance-star-apply.log;包含 Tundra build success、英雄培养升星节点写入成功及 Exiting batchmode successfully now!,未检出本轮 error CS、Exception 或编译失败。

  • 2026-08-29 已以同一 Unity 批处理再次执行 ClientShellDirectUpdater.ApplyBackpackInteractionPass 写入装备切换按钮:退出码 0,日志为 Logs/codex-backpack-equip-apply.log;包含 Tundra build success、场景写入成功及 Exiting batchmode successfully now!,未检出本轮 error CS、Exception 或编译失败。

  • 2026-08-29 已以同一 Unity 批处理执行 ClientShellDirectUpdater.ApplyFormationAndMarblePages:退出码 0,日志为 Logs/codex-formation-marble-apply.log;包含 Tundra build success、编队与弹珠页面写入成功及 Exiting batchmode successfully now!,未检出本轮 error CS、Exception 或编译失败。

  • 2026-08-29 扭蛋历史首次编译在 Logs/codex-gacha-history-apply.log 因记录插入错误位置出现 CS0103,已按日志定位修正;重试 Logs/codex-gacha-history-apply-retry.log 退出码 0,场景写入与 Unity 编译通过。

  • 2026-08-29 扭蛋结果弹窗批处理首次启动触发 Unity 资源导入,期间未到达执行方法日志;Unity 进程随后退出但日志无最终退出标记,需在缓存稳定后重新执行并核对 Tundra build success/Exiting batchmode successfully now!。本轮未结束任何负责人 Unity 进程。

  • 2026-08-29 使用正确 Unity 2022.3.57f1c2 完成纯批处理编译,Logs/codex-client-full-compile-57.log 含 Tundra build success 与 Exiting batchmode successfully now!,未检出 error CS。邮箱/活动/任务/公告新增场景控件写入器因 Unity 启动竞争尚未得到独立落盘日志,逻辑代码已进入编译输入,需下一轮在 Unity 空闲时执行对应方法。

  • 2026-08-29 核心交互第二轮纯编译 Logs/codex-core-interaction-compile-2.log 通过;商城/背包场景写入尝试未生成独立日志,不能视为已落盘,需 Unity 空闲后执行 ApplyShopConfirmPass、ApplyBackpackDetailPass、ApplyMailBatchAndFilterPass、ApplyActivityTaskFilterPass、ApplyNoticeFilterPass。

  • 2026-08-29 已用 Unity 2022.3.57f1c2 成功执行核心交互场景写入,Logs/codex-core-interaction-scene-apply.log 含 Tundra build success、节点写入成功及 Exiting batchmode successfully now!;系统反馈与红点写入日志为 Logs/codex-system-feedback-apply.log、Logs/codex-home-red-dot-apply.log,均通过。最终代码编译为 Logs/codex-core-local-final-compile.log,未检出 error CS 或 Exception。

  • 2026-08-29 底部导航选中状态首次写入未执行:Logs/codex-bottom-navigation-selection-apply.log 明确显示 another Unity instance is running with this project open,Unity 在加载工程前退出,未产生场景或编译改动。等待负责人关闭该工程的 Unity Editor 后,仅执行一次 ApplyBottomNavigationSelectionPass 并验证日志;不自动结束负责人的进程。

  • 2026-08-29 负责人关闭 Unity Editor 后已成功执行 ApplyBottomNavigationSelectionPass:Logs/codex-bottom-navigation-selection-apply.log 含 Tundra build success、五个底部导航选中状态写入成功及 Exiting batchmode successfully now!。ProfileButton、MarbleButton、HomeButton、BackpackButton、ActivityButton 均有白色未选中图标、黄色选中图标和可编辑的 *_SelectedFrame 高亮底框。

  • 2026-08-29 已将负责人提供的 D:\Users\Administrator\Desktop\UI\切图(11) 原样复制为独立素材目录 Assets/Client/UI/切图(11),共 358 个 PNG,未覆盖现有页面素材或场景引用。该目录等待 Unity 导入完成后按页面逐项替换;使用单张切图前需设置为 Sprite (2D and UI)。

  • BUG-009 至 BUG-013 和 RISK-010、RISK-011 仍是既有微信/WebGL 调试风险,后续只有接入旧启动/资源链时才按编号恢复。

待确认

  1. 首个优先页面(建议先做大厅/个人中心或英雄/背包)。
  2. UI 适配基线、字体/图标来源、最终美术资源和性能预算。
  3. 养成、装备、货币与奖励的真实数值/规则来源;确认前仅实现可配置的本地示例数据。

2026-09-02 资源清理检查点

  • 已检查微信小游戏导出目录 D:\\Users\\Administrator\\Desktop\\弹珠接入text_1\\720\\minigame:当前源文件总量约 31.73 MB,超过微信 30 MB 上传限制;主要体积来自 data-package 约 17.65 MB 与 wasmcode 约 12.01 MB,不能直接删除。
  • 已反查 Assets/Effects ALL/unity tex/8K.png 的 GUID 701e45d0f28ccd34580e3f64324a7d17,在工程场景、Prefab、脚本、配置中未发现外部引用;已将该 PNG 及其 .meta 从工程移至 D:\\Users\\Administrator\\Desktop\\pinball-resource-quarantine-20260902\\Effects ALL\\unity tex,保留可恢复副本,未直接永久删除。
  • 其他大体积候选(战斗 UI 字体/图集等)仍有明确 Prefab 或 ClientShell 引用,未清理。旧导出包未改变,需重新导出后才能验证体积和运行效果。
  • 2026-09-02 已将 Assets/WX-WASM-SDK-V2/Editor/MiniGameConfig.asset 的 ProjectConf.assetLoadType 固定为 0(CDN)。SDK 会将 game.js 的资源根替换为 CDN/Assets,不再把首资源包放入小游戏包;重新导出前需确认 CDN 对应目录已上传并可公开 HTTPS 访问。
  • 2026-09-02 重新导出验证:minigame 已降至约 15.75 MB,game.js 已生成 DATA_CDN 且 loadDataPackageFromSubpackage: false;data-package 仅保留空占位文件。对当前 CDN 地址探测数据文件返回 404,说明资源尚未上传或路径不匹配,暂不能直接预览验证。
  • 2026-09-02 微信日志进一步确认 CDN 已生效但数据文件返回 404;日志请求文件名为 97be491cfe81277d.webgl.data.unityweb.bin.br,与当前检查到的新导出文件名 a81346d6b223f67d.webgl.data.unityweb.bin.br 不一致,需重新导入最新导出目录或按最新 game.js 的 DATA_FILE_MD5 上传对应文件。
  • 2026-09-02 已完成 2026-08-28-720 的 YooAsset 增量构建;本地输出目录包含一套运行时清单 PackageManifest_DefaultPackage_2026-08-28-720.bytes/.hash 与 PackageManifest_DefaultPackage.version。同目录的 PackageManifest_*.json、BuildReport_*.json、buildlogtep.json 是报告/日志,不作为运行时清单上传。
  • 2026-09-02 OSS 根目录在线探测:PackageManifest_DefaultPackage.version/.bytes/.hash 返回 200,但最新数据文件 97be491cfe81277d.webgl.data.unityweb.bin.br 与 bundle(含 65fe2931113959a247385aecb582299e.bundle)返回 404;说明只更新了清单,仍需上传数据文件和全部 bundle。
  • 2026-09-02 再次探测:PackageManifest_DefaultPackage.version/.bytes/.hash 与最新数据文件 97be491cfe81277d.webgl.data.unityweb.bin.br 已返回 200;65fe2931113959a247385aecb582299e.bundle、a3c400ea8fa068e432ee745022f0711e.bundle、bf71706251bf4132766a28b15d0b446c.bundle 仍返回 404,bundle 尚未全部位于 CDN 根目录。
  • 2026-09-02 更正验证:上述三个 404 哈希属于旧日志,不在当前构建目录,不能作为当前上传判断。当前构建清单中 HotFix bundle 的 FileHash 为 f2f6a09db1e4930193e8b772ff1d8dd1;该 bundle、其他当前构建 bundle 示例、清单和 97be491cfe81277d.webgl.data.unityweb.bin.br 均已从 OSS 根目录返回 200。
  • 2026-09-02 最新微信日志仍请求 c233ed8e38c5d8c785e8244969fba8c7.bundle 并返回 404,随后因 HotFix.NetController 未加载在 15 秒超时。已核对该文件既不在当前 2026-08-28-720 本地输出(47 个 bundle),也不在 OSS;当前本地与 OSS 的 version、manifest bytes、manifest hash 三件套一致,因此优先怀疑微信开发者工具仍使用旧资源缓存或运行时加载了旧清单引用。处理顺序:清除开发者工具全部缓存并重新导入最新 minigame;若仍请求 c233...,需回查生成该旧引用的导出/清单来源,不应伪造或上传本地不存在的 bundle。
  • 2026-09-02 15:43 新日志确认 c233... 对应 assets_hotupdateresources_dll_webgl_mscorlib_dll.bundle。当前构建报告/清单对应的 mscorlib 文件为 26efc0d84c5d4b11e39fb99673983285.bundle,本地和 OSS 均可访问(200,1,165,915 bytes),而 c233... 本地不存在且 OSS 为 404。由此当前运行实例实际使用的是旧清单/缓存引用;无需修改 TCP 或 NetController 代码。若清除缓存并重新导入后仍请求 c233...,应先关闭并重新打开微信开发者工具、删除该项目后从最新 minigame 目录重新导入;在坚持 720 版本时暂不上传伪造文件或改版本号。
  • 2026-09-02 重新导出后复核 D:\Users\Administrator\Desktop\弹珠接入text_1\720\minigame:根目录 game.js 为 8,084 bytes、game.json 为 654 bytes,wasmcode/de4eef4dc8d1d159.webgl.wasm.code.unityweb.wasm.br 为 15,151,684 bytes,已不再是此前的 0/4 字节占位文件;可重新导入微信开发者工具验证。wasmcode/game.js 仍为 0 bytes,暂不作为 wasm 二进制完整性判断依据。
  • 2026-09-02 16:11 新日志确认 wasm 分包已成功下载并编译;当前失败变为 CDN 首包数据 404。导出目录生成的新文件是 D:\Users\Administrator\Desktop\弹珠接入text_1\720\webgl\64e29d07d6223d9d.webgl.data.unityweb.bin.br(18,045,804 bytes),运行时请求同名文件,但 OSS 720 根目录仍只有旧的 97be491cfe81277d.webgl.data.unityweb.bin.br(200),64e29... 返回 404。需将新 64e29... 文件上传到同一 OSS 根目录后再预览;这一步完成前 HotFix/NetController 不会执行。
  • 2026-09-02 随后复核 OSS:64e29d07d6223d9d.webgl.data.unityweb.bin.br 已返回 HTTP 200,Content-Length 18,045,804,说明新导出的首包数据已上传成功。可清除微信开发者工具缓存后重新预览,继续观察 HotFix bundle 与 GetIpPort 日志。
  • 2026-09-02 16:18 新日志确认 wasm 与首包数据均已成功下载/解压,但首包初始化后仍按 720 清单请求旧的 c233ed8e38c5d8c785e8244969fba8c7.bundle(mscorlib)并 404。当前本地 StreamingAssets/构建报告对应 mscorlib 为 26efc0d84c5d4b11e39fb99673983285.bundle,说明重新导出的 data 包与当前 YooAsset bundle 清单未同步;需按“先构建 720 AssetBundle,再导出小游戏,再上传同一批 data、manifest、bundle”的顺序重新生成,不能只替换 OSS data 文件或 TCP 代码。
  • 2026-09-02 重新构建/导出并上传后复核 OSS:当前最新 data 文件 b4b7d574128ba5ce.webgl.data.unityweb.bin.br 返回 200,大小 18,045,937 bytes;3 个运行时清单和当前构建目录全部 47 个 bundle 共 51 个对象均返回 200,无 404。可清除微信开发者工具全部缓存后重新预览,观察是否进入 HotFix 与 NetController。
  • 2026-09-02 16:54 最新预览已使用新 b4b7...data 并完成资源包下载/初始化,但随后仍请求 c233...bundle 404;说明运行时实际加载的 YooAsset 清单仍包含旧 mscorlib 映射,GetIpPort 尚未执行。当前应停止修改网络代码,重新核对“同一批 AssetBundle 构建输出→WebGL 导出→manifest/data 上传”的完整链路,或用新的唯一包版本/路径进行缓存隔离。
  • 2026-09-02 17:37 新日志确认清单已切换到当前 mscorlib 26efc0d84c5d4b11e39fb99673983285,但 bundle 请求路径为 StreamingAssets/yoo/DefaultPackage/<hash>.bundle;此前仅上传 720 根目录 bundle,子路径样例返回 404。需按 WebGL 导出目录保留相对路径,将 D:\Users\Administrator\Desktop\弹珠接入text_1\720\webgl\StreamingAssets\yoo\DefaultPackage\ 下全部 .bundle 上传到 OSS .../2026-08-28-720/StreamingAssets/yoo/DefaultPackage/,清缓存后重试。
  • 2026-09-02 随后复核 OSS 子目录:StreamingAssets/yoo/DefaultPackage/ 下本地对应的 47 个 bundle 全部返回 HTTP 200;其中 mscorlib 26ef... 大小 1,165,915 bytes,HotFix f2f6... 大小 267,636 bytes。资源路径现已完整,下一步只需清缓存并重新预览。
  • 2026-09-02 最新上传复核:当前本地包版本为 2026-08-28-720-r2;OSS 根目录的 PackageManifest_DefaultPackage.version、PackageManifest_DefaultPackage_2026-08-28-720-r2.bytes/.hash 和最新 data 19a66249237aa142.webgl.data.unityweb.bin.br 均返回 HTTP 200,47 个 StreamingAssets/yoo/DefaultPackage/*.bundle 也全部返回 HTTP 200。上传路径与当前运行时请求路径已匹配。
  • 2026-09-02 R3 上传复核:本地版本为 2026-08-28-720-r3;OSS 根目录 version、r3 bytes/hash、最新 data 7a69f3891b08fea6.webgl.data.unityweb.bin.br 均返回 200,大小分别为 17、7226、32、18051766 bytes;StreamingAssets/yoo/DefaultPackage/ 下 47 个 bundle 全部返回 200。R3 文件路径完整,可清缓存后预览握手。
  • 2026-09-02 微信日志已进入真实 TCP:网关发现成功、TCPSocket.connect 成功、握手请求已发送;服务器返回握手状态码 1(无法识别的平台),随后关闭连接。已将 Assets/Scripts/GameLogic/GameController.cs 的 RuntimePlatform.WebGLPlayer 映射为协议平台编号 6;Unity 批处理编译未执行成功,因当前工程已有 Unity 实例占用项目(日志 Logs/codex-platform-webgl-compile.log),未结束负责人进程。
  • 2026-09-03 网络链路现状:微信正式流程使用 NetController.GetIpPort() 的 WebGL UnityWebRequest 获取网关地址,不使用直连测试参数;随后由 ClientTcpConnectionProbe 通过微信 TCPSocket 执行 ClientGT 握手、游客登录,再发送 ClientPF CLPFGetHeroReq(模块 2/协议 1)并解析 CLPFGetHeroAck(模块 2/协议 2)。最新日志已证明网关获取、TCP 建连、游客登录和 GetHero 收包均成功;开发者工具的 SystemInfo.deviceUniqueIdentifier 返回 n/a,探针已回退到 PlayerPrefs.DeviceId,并保留临时设备诊断打印。WebGL 导出产生新 data/wasm hash 时,必须同步上传 OSS;YooAsset 资源本身未变时无需单独重建。
  • 2026-09-03 最新一次设备回退验证:HTTP 网关、TCP 建连、握手及游客登录请求均执行;设备值已回退为 32 位 PlayerPrefs.DeviceId,但登录请求后未收到可识别的 LoginAck,服务器关闭连接,因此没有发送 CLPFGetHeroReq。探针新增收包长度、模块/协议号及关闭阶段日志,用于区分服务器无回包与协议号不匹配;重新导出后需提供该段完整日志。Unity 批处理日志 Logs/codex-tcp-gethero-diagnose-compile.log 仍受打开 Editor 项目锁影响。
  • 2026-09-03 登录回归根因已确认:服务器可接受 WebGL SystemInfo.deviceUniqueIdentifier 原始值 n/a(此前 23 字节游客登录请求后成功进入 GetHero),但切换为 32 位 PlayerPrefs.DeviceId 后登录包变为 63 字节并被服务器关闭。探针默认恢复发送原始值以保持已验证链路;新增 useFallbackDeviceIdentifierForLogin 仅供服务端确认兼容后试用,默认关闭。Unity 批处理日志 Logs/codex-tcp-login-device-compat-compile.log 仍受打开 Editor 项目锁影响。
  • 2026-09-03 已在 PC 端 NetController.SendLoginPlatformReq 发送游客登录前增加临时 device 值及长度日志,用于与微信端对比;未改动登录类型、CA3 加密或协议字段。Unity 批处理验证日志为 Logs/codex-pc-device-log-compile.log,仍受当前打开的 Editor 项目锁影响。测试后应移除该完整 device 日志。
  • 2026-09-03 PC 日志显示成功登录所用 device 为 40 位十六进制;微信使用 32 位 PlayerPrefs.DeviceId 时登录被服务器断开。探针回退逻辑已调整为生成/复用 40 位十六进制 SHA-1 值,旧 32 位缓存自动替换;仍需开启 useFallbackDeviceIdentifierForLogin 后重新导出验证。Unity 批处理日志为 Logs/codex-device-40hex-compile.log,仍受 Editor 项目锁影响。
  • 2026-09-03 服务端日志确认存在游客设备/会话处理:32 位设备值的两次握手后出现 can't find client session ... OnRecv_PFGTLoginAck;PC 40 位设备值返回 errcode:0 并分配用户 ID;WebGL n/a 返回 errcode:0 并分配用户 ID;WebGL 40 位设备值也返回 errcode:0 并分配用户 ID。结论:服务端接受 40 位设备值和 n/a,32 位值不兼容;服务端日志尚未包含对应 GetHeroReq 处理记录,需继续核对登录应答后的连接/英雄请求。
  • 2026-09-03 负责人决定不再使用 n/a 或随机 40 位设备值;微信探针登录设备字段改为固定纯英文字母常量 WebGLMiniGameDeviceIdentifierPinballNode(40 字符、无符号),不再读取 SystemInfo/PlayerPrefs。旧回退开关保留但已标记废弃,不参与设备值生成。Unity 批处理日志为 Logs/codex-fixed-device-compile.log,仍受打开 Editor 项目锁影响;需重新导出并验证固定值登录及 GetHero 收发。 2026-09-03 编译修复:Assets/Client/Runtime/ClientTcpConnectionProbe.cs 原文件存在多处语法截断,导致 CS1622。已恢复为可编译的 TCP 网关/握手/收包最小结构,固定设备值保持不变;完整游客登录与 GetHero 协议发送需在 Unity 编译通过后依据现有 ClientGT/ClientPF 再补回。命令行编译因 Unity 编辑器占用工程未执行到脚本编译,日志 Logs/codex-clienttcp-repair-compile.log。 2026-09-03 已补回握手回包后的游客登录请求及登录成功后的 CLPFGetHeroReq 发送和日志;登录 token 当前为固定设备值的 Base64 占位,需以服务端验证结果确认是否要求 CA3 加密。 2026-09-03 微信日志显示 NetController.GetIpPort 不可用,根因是探针只按 HotFix 程序集查找类型;已改为同时查找 Assembly-CSharp 及所有已加载程序集。需重新 WebGL 构建/转换后验证。 2026-09-03 新日志确认 WebGL IL2CPP 运行时反射仍找不到 NetController。已改为直接调用 NetController.Instance.GetIpPort,并直接读取 SysDefines.Ip/Port,避免裁剪/程序集反射失败。 2026-09-03 修复 SysDefines.Port 为 long 与 TCP API int 的 CS0266,加入 1..int.MaxValue 范围校验后显式转换。 2026-09-03 WebGL UnityLinker 报 Failed to resolve assembly: HotFix,确认直接引用 NetController/SysDefines 会使 Assembly-CSharp 产生 HotFix 编译依赖;已移除直接引用,恢复反射查找并在 NetController 尚未初始化时每秒重试。 2026-09-03 已重建 Assets/Client/Runtime/ClientTcpConnectionProbe.cs:保留 AOT→HotFix 纯反射边界并用单一协程等待 HotFix/网关;握手补齐平台、产品、版本、device、channel、country、language;游客登录改为 CA3Encode(fixedDevice + "," + OpeninstallToken, randomKey) 等价实现;登录应答和 CLPFGetHeroAck 均按 ClientGT.cs/ClientPF.cs 字段顺序、数组上限和包尾完整校验。状态机只在英雄数据成功解析后请求主动关闭,所有 onError、超时、无效包和服务器关闭均输出失败原因。命令行 Unity 编译尝试被已打开的同工程 Editor 项目锁阻止,日志为 Logs/codex-tcp-client-session-compile.log;尚未构建、上传或操作 GUI。 2026-09-08 个人中心七页面互斥导航清理:ClientProfileNavigationController 改为按个性化五按钮在 ToggleGroup 中的固定顺序映射页面,不再读取旧的持久化跳转目标;从 46 个相关顶部/底部 Toggle 移除旧的序列化 GameObject.SetActive 回调,避免旧控制器与新控制器并行打开页面;MainPage主页 默认恢复激活。GUI 节点、层级、尺寸和位置未改动。Unity 2022.3.57f1c2 批处理验证仍被已打开的同工程 Editor 锁阻止,日志为 Logs/codex-profile-route-cleanup-compile.log;需关闭/释放 Editor 后重新编译并运行页面点击回归。 2026-09-08 日志诊断确认旧版控制器存在页面激活重入:ApplyRoute 激活页面时触发 ToggleGroup.OnEnable,ToggleGroup 又触发导航回调,造成递归 ApplyRoute 和 ArgumentOutOfRangeException。已在 ClientProfileNavigationController 增加 _isApplyingRoute 回调抑制,页面切换期间忽略 ToggleGroup 自动初始化事件;日志同时证明七页、21 个顶部 Toggle、25 个底部 Toggle 均已绑定,未绑定数为 0。待负责人重新运行当前脚本后复核。 2026-09-08 根据最新测试日志,顶部 Toggle 在铭牌页可正常返回个人中心,但进入其他个性化页后未观察到后续顶部返回事件;已增加 PagesLayerActiveRoots 诊断,下一次测试将记录所有仍处于 activeInHierarchy 的一级页面根节点,用于区分 GUI 点击未命中与页面内容脱离七页根节点。Unity 批处理再次受现有 Editor 实例占用,未结束负责人进程。 2026-09-08 页面导航重构:ClientProfileNavigationController.ApplyRoute 改为以 PagesLayer 为唯一可见性边界,每次切换先关闭 PagesLayer 下全部一级节点,再只打开目标七页面;这样会同时清理遗留的 MainPage、旧页面和独立包装 Canvas,不再只关闭七页字典中的节点。未修改节点布局和尺寸。Unity 批处理编译日志 Logs/codex-profile-route-global-exclusive-compile.log 仍显示工程被已有 Editor 占用,待 Editor 空闲后验证。 2026-09-08 通过最新日志和场景结构确认第二套运行时导航:ClientCanvas 上的 ClientUiNavigator 仍订阅旧页面事件并调用 ClientUiPage.Enter/Pause/Resume,与新控制器同时改页面状态。已将该场景组件禁用(GUID 6f19541d58330684484d3fd37121ff65),保留脚本供旧编辑器工具引用;新控制器作为唯一运行时页面导航入口。验证日志 Logs/codex-disable-legacy-ui-navigator-compile.log 仍被现有 Unity Editor 项目锁阻止。 2026-09-08 针对负责人最新截图继续收敛页面互斥:运行日志证明当前控制器的 PagesLayer 一级根节点每次只有一个激活,但画面仍存在重叠,说明可能有旧流程留下的重复页面实例或脱离首次页面字典的同名页面。ClientProfileNavigationController 现会扫描当前场景所有位于 PagesLayer 下的 7 个页面实例,切换时先全部关闭,再打开唯一目标;原有关闭 PagesLayer 全部一级子节点的保护仍保留,并新增 AllPageInstancesActive 诊断记录全场景同名页面的实际激活数量。未修改 GUI 尺寸、位置、层级或素材。待负责人重新运行后回传最新 [ClientProfileNavigationController] Bind 中的 allPageInstances 数量和截图;Unity 命令行编译需继续在 Editor 释放后执行。 2026-09-08 最新运行日志已确认 7 个页面实例互斥有效(allPageInstances=7、每次 AllPageInstancesActive:count=1),但负责人截图仍重叠。因此新增 ActiveVisualCanvases 诊断,记录 ClientCanvas 下所有实际启用的 Canvas 路径与排序层级,用于定位页面外 Popup/System 或页面内部独立 Canvas 的第二套显示来源;下一步依据该证据重构唯一显示宿主,不再继续叠加页面 SetActive 补丁。 2026-09-08 交接记录:负责人要求将当前聊天交接到新聊天。当前页面导航事实:ClientProfileNavigationController 日志持续证明 7 个页面互斥,AllPageInstancesActive:count=1;ActiveVisualCanvases 显示的 Canvas 全部位于当前激活页面路径下,例如头像/铭牌页自己的 Scroll View、默认背景和顶部 Toggle,未发现其他 BadgePage 同级页面同时渲染。Hierarchy 截图也显示 5 个 BadgePage 为 PagesLayer 下同级节点,当前头像页内部包含 Background、Canvas、Scroll View、PersonalizeLabel、默认背景+标签Canvas、个人中心/主页展示/个性化(1)。因此剩余“重叠”尚未被证明是页面导航残留,可能是当前页面内部子节点布局/显隐或运行画面未刷新;未在证据不足时关闭这些内部 Canvas。已禁用场景中的旧 ClientUiNavigator,保留旧源码供 Editor 工具引用;顶部/底部旧序列化 SetActive 回调已清理。最近代码文件为 Assets/Client/Runtime/UI/ClientProfileNavigationController.cs,当前 Unity 编译仍被已有 Editor 项目锁阻止,最近日志为 Logs/codex-profile-visual-canvas-compile.log。新聊天应先读取本记录、AGENTS.md、相关 MODULE.md 和最新 Editor.log,再决定是否修改 GUI 子节点。 2026-09-08 新目标:负责人暂停 UI 重叠修复,改为在独立 ClientShell/Client 场景进行服务器数据对接。目标顺序为“建立连接 → 接收原始数据包 → 按模块/协议分类 → 后续再接入各业务接口”,暂不做 UI 展示。已确认不能直接沿用 Boot 的场景生命周期:当前 ClientShell 没有 Boot 初始化链,现有 ClientTcpConnectionProbe 仅在微信 WebGL 分支执行。已新增 Assets/Client/Runtime/Services/ClientServerPacketRouter.cs,按 ClientGT 1/1、1/5 和 ClientPF 2/1、2/2 分类,输出 JSONL 摘要并可保存本地原始包捕获到 Application.persistentDataPath/ClientServerLogs,不写入 UI/业务服务。下一步是增加可替换的 Client 传输适配器:PC 端优先用真实 TCP/网关链路测试,微信端复用同一分类器;不得把真实 token、个人资料或服务端地址写入仓库。当前 Unity 编译仍需在已有 Editor 释放后执行。 2026-09-08 服务器数据对接继续:新增 ClientServerPcSession 作为 ClientShell 的 PC/Editor 传输入口,通过现有 NetController.GetIpPort 反射获取网关,不把地址写入仓库;连接后执行握手、游客登录和 CLPFGetHeroReq,所有收到的完整包统一送入 ClientServerPacketRouter。路由器对 CLPFGetHeroAck 额外记录英雄/英雄组数量,并识别长度异常与截断包;网关发现增加 15 秒超时。ClientShell 已挂载该入口,WebGL 下自动让位给原微信探针,不改 GUI。命令行验证日志为 Logs/codex-client-server-compile.log,仍被已有 Unity Editor 项目锁阻止(HandleProjectAlreadyOpenInAnotherInstance),没有取得脚本编译结果;待负责人重新进入并释放工程后自动重试,编译后等待短暂资源刷新再继续运行验证。 2026-09-08 负责人重新进入 Unity 后,Editor.log 已确认本轮 Assembly-CSharp.dll 编译成功并完成域重载,未发现本轮 error CS;仅有既有未使用字段及旧代码警告。按流程再次执行的命令行验证仍被当前运行的 Unity Editor 拦截,日志为 Logs/codex-client-server-compile-retry.log,原因仍是 HandleProjectAlreadyOpenInAnotherInstance。下一步可直接在已完成编译的 Unity Editor 中运行 ClientShell,观察 [ClientServerPC] 与 [ClientServerData] 日志,并把 Application.persistentDataPath/ClientServerLogs 下的 JSONL 路径/内容回传。 2026-09-08 ClientShell PC 端真实运行验证通过:Editor.log 显示网关解析到临时服务端地址并成功 TCP 建连,发送握手 99 字节、游客登录 71 字节、CLPFGetHeroReq 8 字节;收到并分类 3 个服务端包:模块 1/协议 1 握手应答 17 字节、模块 1/协议 5 登录应答 155 字节、模块 2/协议 2 英雄应答 348 字节。JSONL 记录确认 HeaderValid,英雄数组 4、英雄组数组 1。原始包与摘要已保存到本地 ClientServerLogs,当前目标“连接→收包→分类”闭环完成;下一步再把分类结果映射到可替换的客户端数据接口,暂不接 UI 展示。 2026-09-08 分类可读性增强:ClientServerPacketRouter 现在同时记录发送和接收方向;PC 传输每次发送握手、游客登录或 CLPFGetHeroReq 前均写入分类器。除 JSONL 和原始二进制外,新增同会话 .protocol.log,按序号、方向、协议名、模块/协议号、字节数、状态和安全摘要输出,登录令牌等敏感正文不落盘。此前一次运行仍只有 3 个接收包,是因为旧版本只接收记录;需重新运行 ClientShell 生成包含收发双方的新版协议日志。代码修改后待 Unity 编辑器重新编译验证。 2026-09-08 协议分类继续扩展:路由器通过反射扫描已加载的 CLGT*、CLPF* 类型及其 mid/pid 常量,自动建立完整协议名目录;记录新增 ProtocolName,不再只显示有限枚举。未知或被裁剪的协议仍记录模块/协议号和原始包,不猜测正文。git diff --check 未发现空白错误;命令行验证日志 Logs/codex-client-protocol-catalog-compile.log 仍因 Unity Editor 占用项目而未进入编译。待 Editor 完成本轮自动编译后运行 ClientShell,确认 .protocol.log 中出现双向及完整协议类名。 2026-09-08 可读分类摘要继续增强:握手请求记录平台/产品/版本,登录请求记录登录方式/令牌长度,握手与登录应答记录状态,英雄应答记录英雄 ID、星级、等级、战力和数组数量;设备、渠道、令牌、密钥、昵称、电话等敏感或个人字段不写日志。发送请求已按请求类别分类,不再显示 Unknown。本次命令行日志未生成,说明仍被运行中的 Unity Editor 抢占;待编辑器自动完成本轮编译后重新运行 ClientShell 验证。 2026-09-08 协议日志格式优化:.protocol.log 现在按数据包分隔成多行报告,显示发送/接收、协议类名、协议分类、模块中文用途、协议号、长度、校验和字段摘要;字段摘要自动逐项换行,便于人工阅读。未新增接口绑定或 UI 展示逻辑。代码改动后需重新编译并运行一次 ClientShell 才会生成新格式日志。 2026-09-09 微信端协议日志接入:ClientTcpConnectionProbe 的握手、游客登录、CLPFGetHeroReq 等发送包现在也写入统一 ClientServerPacketRouter,微信收到的完整包继续统一分类;可读分段报告同时写入 ClientServerLogs 并通过 Unity/微信日志输出。未改动 UI 和接口绑定。git diff --check 通过;命令行编译因当前 Unity Editor 占用项目被阻止,日志为 Logs/codex-wechat-readable-packets-compile.log,待 Editor 自动编译后重新导出微信包验证。 2026-09-09 微信端测试目标确认:负责人要求仅验证 Console 中是否能输出与 PC 相同的双向可读协议报告,测试通过后再移除长期 Console 输出;当前已在微信探针的发送路径调用 RecordOutgoing,接收路径调用 Accept,并增加 IL2CPP 协议名兜底。最新命令行编译仍被 Editor 锁阻止,需在 Unity Editor 自动编译完成后重新构建/导出微信包并人工回传 Console。