# M2:PlayFabMgr 存档能力迁至 KVMgr,先移植后优化(修订1,待独立审查) 日期:2026-09-29。状态:**方案送审稿,不批准生产代码**。本方案承接用户确认的流程图和“先完成移植、再据证据优化”的顺序。实施前须由原 ZCode 审查会话完整审查;主会话复算受审 hash、逐条裁决并写明批准白名单。后续业务批仍需各自完整调用矩阵和方案审查;本稿的总体路线通过不等于授权修改全部 81 个文件。 ## 1. 目标、当前事实和路线选择 目标是在保留 `PlayFabMgr.cs` 历史文件的前提下,让需要保留的业务存档入口和正式运行调用最终由 KVMgr/KV 承接,旧管理器的运行调用、组件自动执行与 PF 存档发送归零;直接 PF SDK 外围依赖另列清理,最后再考虑移包。正式地址固定 `http://s101.local:18080/`。使用 Unity CLI Loop,不用 UnitySkills,暂不打包。 已关闭的 B02 仅将 `ReadKV/WriteKV/FlushKVAsync/WaitForKVTicketAsync` 四个固定 handle 入口从旧类等价迁入 `Core/KVMgr.cs`,并非旧管理器的全量替代。现行扫描为 224 个语法候选/81 文件:164 个 `UpdateUserDataValue`、50 个 `GetLocalData`、2 个 `SyncDataImmidiate`、1 个 `CompareDatas` 及 7 个内部/SDK 候选。它不是完成率或可机械替换的行数;逐项依据为 `M2-当前调用矩阵-待核证.json`。 历史核证:9 月 15 日仓库树 `f40a816cc` 中的旧管理器没有 Guard;9 月 28 日 upserver 提交 `0eb43b2b4` 才加入 Guard 实现和旧方法检查,B02 原样搬迁带 Guard 的四个 KV 入口。它是迁移新增的保护,不是旧 PF 业务语义。迁移期先保留当前 Guard 类、入口检查、计数与错误返回,完成后单独判断是否可以删减。 | 路线 | 裁定理由 | |---|---| | **选用:KV 能力承接+按业务动作迁调用** | 每个旧入口有明确新合同;业务公式与 UI 时序仅做必要适配,错误可定位。 | | 直接把整份 PlayFabMgr 复制改名成 KVMgr | 新类仍依赖 PF SDK、PlayerPrefs 合档和旧定时队列;不能实现 KV 后端替代,还需第二次迁移。 | | 全局文本替换类名,最后统一补保护 | 旧 `string/null`、`void`、`bool` 无法表达 KV 读错、写拒绝和远端 Unknown,扣费/领奖可能误判。 | ## 2. 职责和调用数据流 ```mermaid flowchart LR B[玩法/业务 Service] -->|原账号固定 handle、key、值| K[KVMgr:读、写、Flush、原票据观察] L[登录/加载/退出 Service] -->|成功 Apply 后发布;撤销时清除| B L -->|进入/释放受控加载门| G[当前 Guard] K -->|现行拒绝检查暂保留| G K --> H[GameSessionHandle/Owner/缓存/同步] H --> S[s101 KV] P[PlayFabMgr 历史文件] -.待所有运行引用清零.-> X[停止组件自动执行] ``` KVMgr 只提供存档入口,不登录、决定账号、枚举场景组件、调用 UserService 或管理第二套缓存。调用方持有登录会话发布的**原 handle**;关闭或同账号新 epoch 后原 handle 不得重新指向新 Owner。`PlayerKVAccountLease` 是账号网络租约,不可冒充存档 handle。 现行 `PlayerKVGameLoadCoordinator.LoadAsync` 是**验证路径**:它在 `Apply` 成功后仍持有 Guard,`LoadedForValidation` 也要求 Guard 存在;四个 KVMgr 方法在此期间均会被拒绝。因此不得把 `LoadKVForValidationAsync` 简单改名并开放给正式玩法。Editor 限定玩法已经验证另一时序:Guard 覆盖 `Apply`,成功后释放,随后发布固定 handle。正式路径需要借鉴这个**时序**,但不能直接沿用 Editor 许可、测试 bridge 或 PF 登录回退。这一项是可写玩法的必需迁移适配,不是 Guard 类优化。独立审查须重点裁决以下最小方案:保留验证路径原行为;为正式加载增加明确模式/入口,成功 `Prepare→Decode→31模块Apply` 且通知完成、身份/epoch 有效后,释放该次 Guard,再一次性发布同一原 handle;失败只 Revoke/Close,不发布。不得让“Guard 仍持有但写调用绕过它”成为修补办法。正式句柄的受控出口只能由当前 `PlayerKVLoginContext`/协调器按身份、epoch、关闭状态给出,不能用全局单例查询或泄漏历史 `Prepare` 结果。若这套分流必须大量复制现有验证代码,审查应判定需要重做本节,不得在实施中临场扩写。 ## 3. 旧成员逐项去向与必要差异 | 旧成员/行为 | 本次迁移验收口径 | |---|---| | `GetLocalData(key): string/null` | `KVMgr.ReadKV(originalHandle,key)`;分别处理存在值、合法缺键和读取失败。调用点不得把失败伪装成空档或默认数值。 | | `UpdateUserDataValue(key,value,remoteStore): void` | `KVMgr.WriteKV(originalHandle,...)`;本地 Accepted 与远端 Confirmed 分开。无消费的状态标记可按已审 B01 合同处理;发奖/扣费必须归入所属业务动作。 | | `SyncDataImmidiate(key,value): Task` | 同一原 handle 的 Write→Flush→**该次原票据**观察;现有两处分别归钓鱼鱼饵和转盘券消费批。Unknown 不当成功或自动重试。 | | `CompareDatas` | PF 远端与 PlayerPrefs 时间戳合档只用于旧 PF/受控历史迁移;正常 KV 登录使用现有 Prepare→Decode→Apply。保留旧路径直至登录来源政策审定,不复制 PF 合档算法到 KVMgr。 | | `InitBuffer/SyncData/UpdateFaild/40秒PF循环` | 对照现有 KV Owner 的缓存/同步行为和正式运行触发。先保留旧 PF 路径;停用前核对定时、暂停、退出是否有等效触发与失败可见性。不得照搬第二套 PF 队列。 | | `Awake/OnApplicationPause/Quit/OnDestroy/Instance` | 先核现有触发链;在全部存档调用及退出接线验证后停止 `SubBoostrap` 创建旧组件。是否需要最小生命周期接线以真实缺口为准,不预先新增通用适配框架。 | | Editor `Start/StopKVGameplayLoopSync` | 继续受原许可和测试宿主限制;正式运行不可引用这些方法。旧组件停用前需保证测试入口有单独去向。 | ## 4. 连续实施检查点与边界 **CP0 审查与基线。** 冻结本稿、224项矩阵和本批源码 hash;原 ZCode 审查总体路线、Guard 时序、正式 handle 出口和首批白名单。主会话逐条裁决后写出确切批准范围。B02 44 项冻结交付和 B01 关闭证据只读复用;不清理当前用户未提交的场景、字体与其他源码修改。 **CP1 正式会话前置。** 在批准文件中建立 Player 构建可用的 31 模块绑定/快照、正式身份/加载入口和原 handle 交接;受控验证工厂仍只限验证。Guard 只在加载副作用敏感窗口阻断,正式成功发布前退出;失败/撤销清除绑定并等待既有 Close 屏障。不得更改 Guard 类和 KVMgr 四入口方法体。此阶段先用合成 transport、旧/新 epoch 和 Apply 失败验证,不切默认 KV、不运行真实账号。 **CP2 管理器对外能力与首批接线。** 复用四入口,针对旧三类对外存档调用明确调用方结果适配;优先复用 B01 已关闭的通知/俱乐部状态作为代表链,不重写其业务计算。每一组记录旧 key、最早内存变化、原 handle 来源、失败停止点、旧回调行为、对应测试。若需要 KVMgr 新方法,必须是确实无法由四入口表达的存档能力且先经白名单审查;不能增加旧 PF 同签名的假成功转发。 **CP3 业务域连续迁移。** 按核心进度及奖励、活动商业及延迟回调、身份及加载边界三个较大业务域推进,不按 224 行逐项审批。每域形成可审的调用/上游/源文件白名单及验收矩阵后一次完整审查,再连续实施并在检查点记日志。消费与发奖链同一业务动作验收;数值公式、随机展开和 UI 顺序无证据不改。原 PF 分支保持可用直到对应域完成,不能同一动作混用两个后端写同一档。 **CP4 旧管理器停止运行。** 核对语法调用、别名/反射/Prefab/UnityEvent、组件创建、测试入口、定时和生命周期;在正式 KV 组合验证与账号/历史数据政策通过前,不停用旧组件或全局切默认。调用归零以后,旧 `PlayFabMgr.cs` 保留为历史文件,另处理它及外围的 PF SDK 编译依赖,再考虑移包。 **CP5 验收后优化。** 独立评估迁移时新增 Guard 是否还需要全局静态 owner、现有计数和当前目录位置。只有发现具体冗余/层级/并发问题并完成单独方案评审,才删除、缩小或移动 Guard/KVMgr;不把优化混入 CP1–4 的行为迁移补丁。 ## 5. 首批源文件候选与明确排除 首批**待审候选**仅限以下职责所在文件,最终以独立审查和主会话白名单为准:`Core/KVMgr.cs`(原则上只核对,不改四方法)、`Services/PlayerData/PlayerKVLoginContext.cs`(受控原 handle 出口)、`Services/PlayerData/PlayerKVGameLoadCoordinator.cs`(正式/验证时序)、`Services/PlayerData/PlayerKVControlledLoadCapability.cs`(正式工厂与验证工厂隔离)、`Services/PlayerData/PlayerKVGameplayBindings.cs`(Player 构建 31 模块绑定可用性)、`Services/UserService.KVLoad.cs` 与 `Services/UserService.cs`(正式登录发布、撤销和初始接线),以及 B01 原八文件中确有正式接线需要的最小改动。`SubBoostrap.cs` 只在停用旧组件检查点有证据且方案审查后纳入,不在首批先改。测试可在 `CodexOutput/upserver/B3BatchMigration/M2Tests/` 独立宿主和固定 Unity Editor 验证入口进行,禁止复制一套生产存档算法。 本稿**尚未批准这些候选文件编码**。CP1 精确签名、生产工厂配置来源、B01 首批需要修改的确切行、全部失败分支和源码白名单必须由独立审查裁决为充分,主会话随后形成批准版;若不充分,修订本稿再审。后续 81 文件不因本稿通过而自动获批。 ## 6. 验收矩阵与停止条件 | 编号 | 必须证明的行为 | |---|---| | V01 | Guard 覆盖 Prepare/Decode/31模块 Apply 副作用窗口;Apply 失败或通知失败不发布原 handle;正式成功后 Guard 已退出且固定 handle 可读写。验证路径原 Guard 语义保持。 | | V02 | 同账号新 epoch、跨账号重登、Logout/Close/取消后的旧 handle 读写与迟到回调均拒绝,不写入新 Owner;Close 失败不绕过屏障。 | | V03 | 存在值/空串/缺键/读失败四种情形不会合并;写拒绝、本地 Accepted、远端 Confirmed/Unknown 不冒充彼此。 | | V04 | 两处立即消费调用各按原票据确认,失败/Unknown 不重复扣费、不自动补发;多键部分保存问题仍按 T08 作为默认切换前置。 | | V05 | B01 已读/提示状态、31模块加载、B02 四入口/Guard、登录与退出回归保持;编译含 Editor、`SERVICE_HOST`、Player 目标条件,Unity CLI Loop 0 新错误。 | | V06 | 默认切换前有账号政策、历史档、连续普通玩法、退出后重新登录恢复及旧 PF 引用归零报告;没有正式接口写入授权时只跑合成 transport。 | 任一白名单外修改、Guard 类/四入口检查语义变化、把 PF SDK 发送塞进 KVMgr、需要全局当前账号、无法证明正式 handle 的撤销、或业务动作新增扣费/奖励重试,立即停止该检查点并修订方案交审。合同内实现错误可在已批准边界内修复、记录首败与回归,不逐函数重复申请。每个检查点更新 `开发日志.md`、入口与 TODO。暂不访问真实 101/102 档,不打包。