7.4 KiB
项目审查补充:s101 迁移
日期:2026-09-21。基线 HEAD:f40a816cc,审查对象为当前未提交工作区。按《接手入口.md》继续审查,结合《开发状态.md》《后续实现方案.md》《审查记录.md》《开发日志.md》与最新最小登录收尾评审、验收记录判断现状。
本次仅更新文档,没有移动、迁出或修改业务代码,没有提交、推送、连接正式服或操作玩家数据。审查范围集中于迁移相关认证、HTTP、SignalR、俱乐部调用及现有测试,不代表全项目所有玩法审计。使用 unity-project-scout 核查项目基线:Unity 2022.3.62f2c1,URP 14.0.12、Addressables、HotUpdate 程序集;PlayFab SDK 和异步包仍在 manifest 中。
裁决与开发边界
本批审查结论:有条件通过继续准备 A/B;完整退出安全与业务会话隔离暂不通过;C 存档切换、D SDK 删除仍不放行。
最新最小登录收尾中的 HTTP 代际过滤、SignalR 首连预绑定、订阅释放和旧 RPC 结果过滤已存在,不重复列为未修复。以下三项是当前源码仍需处理的问题,其中 F1 为历史问题复核,F2/F3 为补充证据。
本文件只形成问题裁决和建议,不授权立即改代码。后续先完成具体方案的完整评审并记录文件边界,再实施:F1/F2 限于身份分类及相应 ClubService 调用者;F3 涉及 QuitAct、UserService/渠道 override 与 RT 生命周期,由同一集成人协调。不得全局替换 UserId、改变旧存档命名空间或直接复用 manager 实现 KV 写入。
F1 / P1:俱乐部本人身份仍混用 PlayFab ID(已知,仍未修复)
- 证据:
Client/Assets/Scripts/Services/UserService.cs:452明确UserId = loginResult.PlayFabId;ClubService.cs:232,294,355,436,477,497,507,518,532,545,594的本人playerId仍读取userService.UserId。:311的internalIdToPlayerId也写入旧身份。 - 契约复核:相邻服务端本地源码
LeaderboardAPI/Services/Club/ClubService.cs:176–177,600对 CreateClub/QuitClub 的 playerId 使用PlayerIdUtil.Parse,并按该值查询玩家/会员。这是本地契约证据,不宣称与线上部署版本完全一致。 - 触发与影响:s101 登录成功后调用这些功能,旧 PlayFab 字符串可能不能按十进制解析;即使恰好全是数字,也不等于渠道身份,仍会查询错误的 ID。没有据此宣称线上已发生错误写入。
- 建议:先完成本人、目标玩家及缓存映射的身份清单;本人新 API 使用已认证 ApiPlayerId,未认证不发送;目标 ID 按来源转换,不能替换成本人 ID。保留旧 PF 存档身份。
- 验收要求:模拟本人/目标玩家区分、未认证阻断以及映射缓存;会员变更不得以正式账号写操作代替测试。
F2 / P1:manager 丢弃旧响应后,上层仍会修改俱乐部状态
- 证据:
CustomServerMgr.SendAsync对过期响应、网络失败及 HTTP 失败返回 null。ClubService.cs:298–320的 CreateClub 在 null/空响应时清空myClubInfo并发布状态变化;:480–489的 QuitClub 完全不判断响应,直接退出聊天、清空俱乐部与点赞游标、显示提示并发布状态事件。两者均未像 GetSelfClub 一样检查请求所属 SessionVersion。 - 触发与影响:退出俱乐部请求断网/失败时,本地仍表现为已退出,而服务端可能未变更;若旧调用在会话变更后恢复,则 manager 返回 null 仍不能阻止调用者执行本地副作用。跨账号可见影响取决于服务实例是否复用,但同账号失败误报不依赖该条件。
- 建议:请求前固定会话版本,await 后先过滤失效会话;失败保留原状态,按实际业务响应确认成功后才清理。不能仅将 playerId 改为 ApiPlayerId 后便宣称 A 阶段完成。
- 验收要求:覆盖 CreateClub/QuitClub 的网络失败、HTTP 失败、业务失败和旧响应;断言不清空已知状态、不发成功事件。当前 GetSelfClub 已有版本和 null 保护,不能把它的通过扩大到所有 ClubService 方法。
F3 / P1:退出等待 Hub 释放期间,账号仍然有效
- 证据:
Stages/QuitAct.cs:35–56在销毁 UI、重置配置后,先 awaitrtService.ReleaseAsync();userService.Logout()直到OnStarted的:70–73才执行。UserService.cs:649–659的退出代际递增、HTTP 会话清理及 PF 凭据清除都发生在 Logout 内。RT ReleaseAsync 只立即使 RT 自身失效,然后等待生命周期锁和 Stop/Dispose。 - 触发与影响:当
QuitStage.Logout=true且 Hub 关闭尚未完成时,退出流程已经开始,HTTP 会话版本及登录退出代际却仍旧有效。在途 HTTP 成功可继续返回,当前 401 仍可能触发重登,等待中的登录也未因“开始退出”而失效。已存在的代际保护要等 Logout 真正执行才生效。 - 证据边界:这是源码执行顺序确认的窗口;没有运行 Unity/真实 SDK 复现。现有 RT 测试通过 StopGate 明确覆盖了“ReleaseAsync 尚未完成”,但没有编译实际 QuitAct/UserService,不能证明此窗口安全。
- 建议:专项评审退出入口的顺序:当本次确实要注销时,在第一个网络 await 前使身份和登录任务失效,再可等待地释放连接、清理场景;保留无需注销的退出路径语义,并处理 SessionChanged 与 ReleaseAsync 的协同及重复调用。不是简单删掉 await,也不直接移动代码后跳过评审。
- 验收要求:阻塞 Hub Stop,让旧 HTTP 200/401、API 登录及渠道 SDK 回调分别到达;确认不再更新状态、不重登、不返回登录完成,并验证释放异常时仍能完成必要清理。
本次实际验证与限制
本会话前段已实际执行以下离线命令,均退出 0;用户要求继续审查后未重复运行或增加测试代码:
$env:DOTNET_CLI_HOME='C:/projects/ft/CodexOutput/dotnet-home'
$env:APPDATA='C:/projects/ft/CodexOutput/dotnet-appdata'
dotnet run --project CodexOutput/upserver/MinimalLoginTests/MinimalLoginTests.csproj --verbosity quiet
dotnet run --project CodexOutput/upserver/RealtimeTests/RealtimeTests.csproj --verbosity quiet
- MinimalLoginTests:31 项通过;编译实际 S101AccountSession、CustomServerMgr,未编译实际 UserService/AggUserService/ClubService/QuitAct。
- RealtimeTests:三组输出通过;编译实际 RTService,Hub、事件及引擎环境为替身。将 State 从 Reconnecting 改回 Connected 不等于真实网络自动重连。
git diff --check:退出 0,仅有行尾转换提示。- 本次未执行活动回归生成器、2079 源码编译、Unity 导入/场景、真实 SDK、正式服联调或 KV 写读删。这些既有验收记录仍为历史证据。
文档一致性与下一步
《开发状态.md》顶部已注明最小登录收尾完成,但历史区及《后续实现方案.md》《TODO.md》仍保留“首连/旧401待修复”等旧文字。接手时按最新收尾复审和本补充判断:底层已修复,上层调用者及退出起点仍有缺口;不能重复修复旧问题,也不能据此勾选全游戏隔离通过。
下一批先评审 F1/F2 的身份调用清单与失败语义,再单独评审 F3 退出顺序。B 的生产 Cookie/HttpClient 所有权及失效设计仍需具体化;本批没有检查或放行新的 KV 实现。审查建议的测试尚未实施,不计入通过。