Files
ft/CodexOutput/upserver/Unity重登缺陷-方案与评审.md

47 lines
6.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Unity 实际验收:重登与失败重试缺陷专项方案
日期:2026-09-21。遵循《当前阶段范围裁决-仅最小登录.md》,正式地址固定 http://s101.local:18080/。
## 已复现问题
1. S1:输入 not-an-id 后停留 LoginStage、Authorized=false;点击重试仍提交旧 ID,只有重试按钮,没有可编辑输入框。证据:uloop-invalid-state.json、uloop-invalid-retry-state.json、uloop-invalid-retry-ui.json。
2. S2/S3:101→101→102→101 均能认证进入 FishingStage,但重登后出现三个 Failed to create Sentry 和 TimerManager already exist。证据:uloop-reentry-error-stacks.json。此前“错误为空”仅为早期采样,不能概括重登后的完整阶段。
3. 退出旧身份、Cookie 更换及清空、会话版本增加、旧 Hub 断开已由真实 QuitStage 路径验证。此次不重做认证协议。
## 根因与方案
- PFLoginAct.LoginAsync 仅在首次输入 ID;ReytryDialog 直接重复 userService.Login,无法修正错误输入。仅配置为 {{input}} 时,在重试提交中重新等待 InputID,复用原单次提交门、取消令牌、输入监听清理和进度显隐。固定 ID 和 Agg/真实渠道入口保持原逻辑。
- RootCtx 重建 Container,ActivitySentryManager 静态类型缓存仍在;InitActivitySentryType 认为类型重复直接返回,新容器没有服务注册。以容器实例作为缓存生命周期边界:更换容器时清空类型映射与类型键缓存,同一容器仍拒绝重复注册。发现入口与显式注册入口都先检查当前容器,避免懒加载跳过注册。缓存不含存档,不写玩家数据。
- QuitAct 已取消全部 Timer 任务,但 SubBoostrap 随重登再 Create 时旧常驻 TimerMgr 仍在。取消后调用已有 Timer.Destroy,沿用该方法立即清空静态引用、在 Unity 帧末销毁对象的行为;不改通用计时器机制。
## 修改边界
生产文件仅 PFLoginAct.cs、Activity/Sentry/ActivitySentryManager.cs、QuitAct.cs。测试与证据位于 CodexOutput/upserver。保留其他未提交差异;不改正式地址、服务器、账号映射、KV、俱乐部扩展、PlayFab SDK、渠道链接或存档。不将停止 PlayMode 计为游戏内退出通过。
## 完整评审裁决(实施前)
本轮主会话基于真实调用链完成方案评审,不冒充新的独立 agent 评审。
- 范围:三项均直接阻碍失败重试/退出重登的本阶段验收,属于必要修复,允许按上述边界实施。
- 取消与重入:输入等待沿用 LoginLifetime,重试门在等待前设置;输入完成后再次检查取消;旧重试回调不得开启新输入或认证。
- UI:SimpleDialog 调用回调后关闭自身;输入面板是独立对象,可以等待用户重新提交。固定 ID 不弹输入。
- 容器隔离:类型缓存随当前 GContext.container 变化失效;不保存或复制旧容器实例内的服务,不用重复注册覆盖同一容器。
- 退出顺序:原提前注销、await RT 释放、CancelAllRegisteredTimers 顺序保留,随后销毁 TimerMgr;异常/未授权退出不得清存档。
- 验证:增补实际生产流程提取测试(输入重试、等待中注销、重复按钮),对容器替换及重复注册做真实源文件回归,退出测试断言销毁;Unity 编译后重新执行无效 ID→重试失败→101成功及101→102→101。
- 风险边界:活动订阅和更广泛静态单例不在本次主动重构范围;若仍有新异常,单列证据另行裁决。网络断连和真实渠道 SDK 未测则继续待验收。
裁决:方案评审通过,可以实施;本文件先于生产代码修改落盘。运行结果及限定代码 review 另行记录。
## 补充裁决:退出后 PlayFab 缓存上传保护(实施前)
- 新证据:uloop-fixed-relogin-errors.json。在101同号重登时,UserService.Logout已经ForgetAllCredentials,RootCtx销毁触发PlayFabMgr.OnDestroy→SyncData→UpdateUserData,SDK同步抛出未登录异常。Sentry/Timer旧错误未再出现,但S2暂不能标完整通过。
- 方案:PlayFabMgr.SyncData进入时检查SDK登录状态,未登录直接返回,不轮转/清空待同步缓冲;OnDestroy取消周期任务后保存PlayerPrefs,再走有登录保护的SyncData。UpdateUserDataValue现有按账号LocalData/LastUpdateTime落盘逻辑保持不变。PlayerPrefs.Save写本地已有值,不清空、重置、改账号或新增远端写入。
- 评审:不推迟退出身份失效,不临时恢复旧凭据,不吞掉仍已登录时的上传异常。保护覆盖销毁与周期同步在注销空窗中的调用;保存本地已写入的键。对未登录有待同步数据的路径做队列不变、零远端调用、取消与本地Save回归。
- 开发边界仅新增PlayFabMgr.cs两处保护及CodexOutput测试。属于本轮退出必要兼容,不是启动KV/存档迁移。原有60秒比较策略、网络失败补传、完整存档隔离不在此补丁内,不能宣称保证云端最终一致性。
- 主会话完整差异方案评审结论:通过,允许实施;需要重新编译并复测连续重登。新补丁未经独立agent复审,不沿用旧R1复审冒充。
## 补充裁决:退出后的首页延迟回调(实施前)
- 最终连续回归在同号重登停下,原因是HomePanel.LastShowPanel在等待0.5秒后,通过新的/已拆卸的GContext.container继续找IFaceUIService;旧首页已销毁。证据uloop-final-relogin101-errors.json,前三类异常均未再出现。
- 仅修改HomePanel.LastShowPanel:进入时拒绝已销毁面板,记录当前容器;等待后校验Unity对象仍存在且容器仍为同一实例,才调用原显示逻辑。不更改首页奖励/活动规则、不新增玩法,不用延长测试等待来规避缺陷。
- 评审:符合退出后迟到回调隔离及首页最小保护范围;容器引用仅保存在短异步方法内;原正常面板与同容器路径保持。生产新增边界仅HomePanel.cs这一方法,测试覆盖正常显示、等待中销毁、等待中容器替换。
- 主会话方案完整评审通过,可以实施。所有本轮运行时补丁统一做最后限定review,不冒充已获独立复审。