Files
ft/CodexOutput/upserver/B3BatchMigration/M2/M2-管理器同生态位替代策略-2026-09-29.md
Liubing\LB 6813da149a feat(upserver): 保存M2客户端KV迁移至本人统计写检查点
保存独立KV用户服务、固定会话存档与原业务接线,以及C3d资料缓存和C3e本人统计写。
保留原PF/AGG路线、业务公式和时序;榜单读取、好友资料、公告、匹配及首场景闸仍待完成。

验证:ServiceHost两条件各33组646断言;Unity CLI Loop编译0错误269警告。
包含相关方案、评审裁决、测试及状态文档。未操作服务器、正式账号或打包。
2026-09-30 19:19:05 +08:00

73 lines
11 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.
# M2:KVMgr与PlayFabMgr同生态位替代策略(主会话意见,待完整方案审查)
日期:2026-09-29。用户要求KVMgr与PlayFabMgr处于同一生态位,考虑先把PlayFabMgr所有函数替代并切换调用,最后处理保护。本意见基于当前源码和[架构复审裁决](M2-架构复审裁决与修复顺序-2026-09-29.md),用于修订R1完整方案;**没有批准代码修改**。
> **2026-09-29 用户纠偏,以下为本文件最新有效顺序**:我先前把管理器迁移与Guard归属、目录移动、生命周期重构放进同一实施批,增加了难以核对的变化;撤回这种混做安排。本阶段以现有行为为基线,逐成员列“旧入口→新入口→调用方→等价/必要差异”,完成存档能力承接和调用迁移。`PlayerKVGameLoadGuard`、现有KV Handle/Owner和旧PF路径在迁移期间保持原行为;不新造Guard、不移动Guard、不搬KVMgr文件、不顺手重写定时器或`Awake`。只有被具体旧调用阻断、且有用例证明的最小兼容改动才能列入迁移白名单。Guard归属、物理分层和代码清理留到迁移完成后的独立优化方案;此前正文中相反的“先归位”“同批生命周期适配”建议不再作为当前实施要求。生产代码仍须等修订后完整方案评审、逐项裁决。
### Guard事实与处理
| 问题 | 已核实事实与本阶段决定 |
|---|---|
| 新KVMgr为何有Guard | **是本次upserver迁移引入的保护**。9月15日前的仓库版本无Guard。9月28日提交`0eb43b2b4`同时新增`PlayerKVGameLoadGuard.cs`、PlayFabMgr旧方法中的Guard调用及四个KV入口;之后B02只是把四个带Guard的入口原样移到KVMgr。此前我只说“搬迁前已有”,遗漏了真正来源,现予纠正。 |
| 旧PlayFabMgr是否有Guard | 原始旧类没有。9月15日的仓库树`f40a816cc`和该文件上一次提交`7a7c1e9f5`均未出现`PlayerKVGameLoadGuard`;当前旧类有11处,全部来自9月28日迁移提交。 |
| 它是否必须存在 | 对原始PlayFabMgr不是必须的,也不是KVMgr天然职责。**当前受控KV加载实现**在31模块`Apply`期间持有它,并用`Violations==0`判副作用;四KV入口的拒绝结果和计数已有验证用例。因此现在直接删除会改变已审加载合同;先保持到迁移完成,再以实际运行/测试证据判断能否移除或换成更小的边界保护,不预设永久保留。 |
| KVMgr调用Guard是否等于反向调用业务Service | 否。Guard实现仅依赖`System`/`Threading`,由加载协调器进入与释放;KVMgr没有调用`UserService`或加载协调器。文件放在`Services/PlayerData`目录造成的层级疑虑是真实设计问题,但目录调整不是迁移前置。 |
“先移植”的验收口径:先实现旧**对外存档能力**在KV路径的对应入口,按业务域替换调用,逐项核对保存结果和旧行为;旧PF专属协议逻辑在切换完成前维持原路径。`CompareDatas`、`Awake`、40秒PF定时器不得未经对照就复制到KVMgr,也不得在同一迁移补丁里悄悄删除;需分别列原触发时机、作用与KV路径的必要替代,评审后作为迁移检查点处理。把PF SDK代码直接改名塞进KVMgr,只会把第二次后端迁移推迟,不算已完成KV替代。读失败/缺键、写拒绝/不确定、原票据确认及固定handle属于新旧后端合同的必要差异,必须在替换相应调用时显式适配;这不是可后置的“优化”。
## 结论与边界
**同一生态位成立,含义是“业务存档入口由KVMgr承接,最终PlayFabMgr运行调用归零”**,不是把旧类逐字复制、保留`Instance`全局当前账号或维持旧返回类型。当前KVMgr只搬了四个显式KV入口,尚未替换旧PF存档调用,之前按B01/B02小段推进没有达到用户期待的管理器完整接管。
`PlayFabMgr.cs`实际上混了存档门面、PF本地与远端合并、定时同步、Unity生命周期、PF SDK发送和Editor测试循环。KVMgr只拥有存档门面;其余能力必须分别归到会话加载/迁移政策、现有KV Owner同步、上层生命周期或测试宿主。目标是**完全替代运行能力与调用,保留旧文件但停用自动执行**,不是要求每个私有函数都有一个KVMgr同名函数。
```mermaid
flowchart LR
B[业务/玩法] -->|旧存档调用:待清零| P[PlayFabMgr]
B -->|显式原handle与结果| K[KVMgr:存档门面]
L[登录/加载/退出Service] -->|发布、撤销原handle| B
L -->|认证/加载阶段| H[KV Handle/Owner]
K -->|读/写/Flush/票据| H
P -->|旧PF分支:切换前保留| PF[PlayFab SDK]
```
## PlayFabMgr方法逐类去向
| 现有成员 | 真正职责 | 替代去向与能否同名 |
|---|---|---|
| `GetLocalData(key): string/null` | 存档键读取 | 已有`KVMgr.ReadKV(handle,key)`,必须保留成功/缺键/失败三态;不能同签名返回null掩盖读错。 |
| `UpdateUserDataValue(key,data,remoteStore): void` | 本地编辑+远端待同步 | 已有`KVMgr.WriteKV(handle,key,data,remoteStore)`,调用方要处理Accepted、拒绝、本地提交不确定及票据;旧void合同不可直接复制。 |
| `SyncDataImmidiate(key,data): Task<bool>` | 单键立即远端提交 | 用同一原handle的`WriteKV`+`FlushKVAsync`+`WaitForKVTicketAsync`观察**该次原票据**;bool不足以表达Unknown/部分确认。消费/领奖须按业务动作收口。 |
| `CompareDatas(remoteDatas,userId)` | PF远端与PlayerPrefs时间戳合并 | 归历史档迁移/正式加载来源政策,不进入KVMgr常规读写API;不能对KV档再做PF式双源合并。 |
| `SyncData`、私有定时循环、`InitBuffer`、`UpdateFaild` | 旧PF缓冲和SDK发送 | 现有KV Owner/Coordinator负责缓存、同步和状态;不复制第二套队列、计时器或PF失败回调。 |
| `Awake`、`OnApplicationPause/Quit`、`OnDestroy` | Unity自动生命周期 | 上层会话Service在登录、暂停、退出时协调Flush/Close;KVMgr保持非MonoBehaviour。全部旧调用迁出后停止创建旧组件。 |
| `Instance`与Editor `Start/StopKVGameplayLoopSync` | 隐式全局入口/受控测试循环 | 正式业务显式传原handle;测试循环继续受Editor许可限制,收口时改测试宿主,不变成KVMgr生产单例。 |
### `CompareDatas`、`Awake`与40秒PF定时器的具体落点
**现状:三者都没有迁走。** `CompareDatas`仍在`Core/PlayFabMgr.cs`,由`Services/UserService.cs::InitData`在PF登录取得`UserData`后调用;它读写按`userId`命名的PlayerPrefs时间戳/本地字典,可能回写PF。`Awake`仍在PlayFabMgr,注册`_instance`、建立5个PF缓冲区并启动40秒`UpdateUserDataValue(CancellationToken)`循环。`SubBoostrap.RegisterServices`仍`AddComponent<PlayFabMgr>()`。KV `PlayerKVSessionOwner.FlushAsync`已能执行一次固定Owner同步,但没有自动40秒调度;`PlayerKVGameLoadCoordinator.Revoke`负责关闭,并不等同“退出前远端Flush确认”。Editor限定玩法还借`PlayFabMgr.StartKVGameplayLoopSync`启动旧计时器。
**逐项审查问题(非预先选定的R1实现):**
1. `CompareDatas`不复制到KVMgr。正常KV登录改走现有`PlayerKVLoginContext.PrepareAsync`读取KV快照→`PlayerKVSaveSchema.Decode`→31模块`PlayerKVGameLoadTransaction.Apply`,由上层`UserService`/加载协调器决定何时发布成功。PF历史档与PlayerPrefs双源合并只属于一次性历史迁移政策:若其他账号确实需要,另列受控`LegacyPlayFabSaveImport`工具/流程,读取原数据、校验目标和备份后导入;未确定政策前保留旧PF分支,不在正常KV登录自动调用CompareDatas。
2. `Awake`目前创建旧单例、缓冲并启动PF循环;迁移方案先列出其实际触发链、KV现存能力和停用旧组件的条件,不在本轮先建新组件。正式切换时必须证明登录、暂停、退出仍有对应行为,再决定是否需要最小接线。
3. 40秒PF定时器目前仍在旧Mgr;先核对KV Owner现有同步触发与实际需求,列定时/暂停/退出的可观察行为和验证条件。不在移植时预设新的定时器或生命周期组件;如果现有能力不能满足切换条件,再单列必要替代并评审。
KVMgr仍只占**存档API**生态位,不反向调用UserService。正式默认启用前,Unity生命周期和Editor测试循环是否仍依赖旧Mgr必须逐项核实并完成替代验收,不能把停用旧组件等同于行为已替代。
现有Roslyn矩阵为224语法候选/81文件,其中`UpdateUserDataValue`164、`GetLocalData`50、`SyncDataImmidiate`2、`CompareDatas`1,其余是旧Mgr内部及SDK调用。数字是语法候选,不是224项独立审批,也不含所有Unity序列化、反射或别名引用。最终须另查组件创建、Prefab/UnityEvent、动态调用与直接PlayFab SDK。
两处`SyncDataImmidiate`分别在钓鱼鱼饵消费和转盘券消费;它们必须跟所属扣费/奖励动作一起验证,不能仅以“新管理器同名方法返回true”证明替换完成。
## 可执行的顺序:先能力,后调用,保护分层处理
1. **一次完整方案评审后,先定KVMgr的存档合同**:保持现有文件位置与单一Guard,明确固定handle来源和`Read/Write/Flush/Wait`如何覆盖旧三个对外存档方法。优先复用四个现成入口;不为了名字相似新增薄转发函数。
2. **在同一实施批按业务域成组替换调用方**:先已关闭B01代表链,然后核心进度及奖励、活动/商业、身份/加载边界;每组列key、首次模型修改、结果处理和回归。可以先把全部管理器能力实现好,再连续替换调用方;不能只做`PlayFabMgr.Instance`→`KVMgr`的文本替换后统一补错。每检查点更新日志,合同内错误直接修复,不按单函数反复审批。
3. **不可后置的最低保护与替换同时生效**:原handle归属/撤销、加载期拒绝、读三态、写Rejected/uncertain、原票据确认、迟到回调旧epoch隔离。否则新调用会把读失败当空档、把未知提交当成功或重复扣费。现有保护优先复用,不新建一套。
4. **可在调用替换后、正式默认切换前收尾的保护**:T08多键部分远端保存检测、差异对账和受控恢复、长期票据容量、历史账号/新账号政策、完整登录/退出组合回归。这些不能延到已经正式启用之后。
5. 全部需要保留的存档业务改用KVMgr且正式路径通过后,令PlayFabMgr的运行引用、组件创建和自动同步归零;直接PF SDK外围依赖另清理,最后才移除包。保留`PlayFabMgr.cs`历史文件按用户目标处理其编译依赖。
**不建议**“一次性实现旧类全部同名函数→全局替换81文件→最后才加任何保护”。它看似减少决策,实际让旧`null/void/bool`隐藏KV错误,并使失败定位横跨业务。可接受的粗粒度是**一份总架构/合同评审+业务域连续实施检查点**,而不是每个调用点各审一次。
下一步在主会话:把此方法去向表和[修复Todo](M2-架构复审裁决与修复顺序-2026-09-29.md)合入R1完整方案,列精确白名单和验收矩阵后送原ZCode审查。固定地址`http://s101.local:18080/`;使用Unity CLI Loop,不使用UnitySkills,暂不打包。