Files
ft/CodexOutput/upserver/B3BatchMigration/M2/M2-双提供方用户服务切换与KV独立实现约束-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

7.8 KiB
Raw Blame History

M2:保留 PlayFab 并新增独立 KV 实现的双提供方切换约束

日期:2026-09-29。用户最新裁决,覆盖此前“最终删除 PlayFabUserService”的错误记录:原 PlayFab 路线必须保留;另写独立的 KV 路线;用一个明确的启动开关选择 PlayFab 或 KV。不得把“移植完成”解释为删除 PlayFabUserService、PlayFabMgr 或 PlayFab SDK。此文供开发 Agent 接手和编制完整方案,不是当前批次扩大代码白名单的批准。

全局简洁性规则在 M2 的应用

遵守项目根目录的 AGENTS.md:在满足已确认功能、正确性和必要安全边界的前提下,抽象越简单明了越好。双提供方方案先比较“复用现有接口并做最小拆分”与新增层次的成本;每新增接口、适配器、管理器或状态,都要指出不可省的职责和实际调用者。不要为了看起来对称而复制 PlayFabUserService、额外包裹 KVMgr 或叠加第二套开关/Guard。确有安全或生命周期约束时应保留并说明,不能以简化为由删掉必要保护。

目标调用关系

游戏业务 / 登录入口
    ↓ 提供方无关的用户与存档契约
启动时选择提供方(PlayFab 或 KV;一次会话内不热换)
    ├─ PlayFabUserService + PlayFabMgr → PlayFab Client SDK(保留、可启用)
    └─ 独立 KV 用户服务 + KV 存档入口 → KV 会话 / 业务 API(新增)

开关需有单一、可观察的选择结果,并在创建用户服务、存档实例及登录前冻结;不能在已登录或已有存档实例时改后端,不能在 KV 失败时静默回退 PlayFab。现有 SaveBackend / PlayerKVRuntimeSelection 可作为设计输入,最终开关语义和 DI 注册须经完整评审确定。PlayFab 路线和 KV 路线均须可分别启动与回归。

当前代码与应处理的边界

位置 当前事实 目标
Services/UserService.cs PlayFabUserService : IUserService 承载原 PlayFab 登录;IUserService 含 EntityKey、playFabId 等 PlayFab 语义。 保留原类与原功能;抽出真正共用的身份、资料、授权契约。PlayFab 专属能力留在 PlayFab 专属接口/实现,KV 不伪造 PlayFab ID 或 EntityKey。
Services/UserService.KVLoad.cs、UserService.KVGameplayLoop.cs KV 编排目前接入 PlayFabUserService partial,属于迁移过渡。 经评审后将 KV 登录、Coordinator、原 handle、生命周期与普通业务请求迁入独立 KV 实现或其组合组件;不继承 PlayFabUserService,不把旧类复制一份。清理旧类中迁移后闲置的 KV 分支,但保留其 PlayFab 路线。
Stages/LoginStage.cs、PFLoginAct.cs 当前 DI 注册 PlayFabUserService/AGG 子类,登录入口又读取具体旧类的 KV 状态。 按冻结开关注册相应实现,登录入口经中立结果/会话契约消费;去掉 KV 对旧具体类型的下转,保留 PlayFab 模式的合法依赖。
Core/PlayFabMgr.cs 与 Core/KVMgr.cs 前者旧存档缓存/同步直接调用 PlayFabClientAPI;后者通过 PlayerKVGameSessionHandle 操作 KV。 两条提供方路径并存;业务逐步改依赖中立存档入口或提供方适配层,PlayFab 模式仍可调用原同步能力,KV 模式只用原 KV handle,不启动旧 PF 定时同步。
PlayerKVGameplayBindings.cs 31 模块绑定仍要求 PlayFabUserService。 抽离 KV 加载接收/身份状态所需的窄契约,保持 Apply、Guard、epoch、失败回滚原合同;PlayFab 模式功能不回归。
AggUserService.cs AGG 当前继承 PlayFabUserService。 保留现有 PlayFab/AGG 通道;KV 是否覆盖 AGG 需另行评审,不能因新增 KV 服务自动改变渠道行为。

实施顺序与验收

  1. 先按既有审查白名单收口当前 CP2B-T 批次。后续新增双提供方方案须完整评审,明确开关、契约拆分、DI、账号与业务玩家身份、31 模块、AGG、异常/退出/旧 epoch 处理、场景和 Prefab 绑定,再逐项裁决开发边界后编码。
  2. 建立独立 KV 用户实现及其 KV 存档路径;保持 PlayFab 实现可运行。各批迁移业务调用时同时验证 PlayFab 与 KV 两侧的读写、身份、失败及退出行为,不以空实现或临时冻结冒充完成。
  3. 最终通关前按临时门控清单解除开发期跳过路径,核两种开关模式的完整业务链、重启恢复及安全边界;只清理迁移后闲置的过渡实现,不删除仍供 PlayFab 模式使用的类、SDK、注册和资源。
  4. PlayerKV* 命名按既有用户裁决,在整体移植完成后另批处理。Core/KVMgr.cs → Services/PlayerData 的物理层级反向依赖另行纠偏,不因双提供方方案自动认定已解决。

验收标准:一个启动开关可明确启用原 PlayFab 路线或独立 KV 路线;二者互不串用凭据、存档与运行时实例;PlayFab 旧功能回归通过,KV 全链通过,KV 不再依赖 PlayFabUserService 的具体类型或 PlayFab SDK,且迁移期保护门在最终通关前按清单销账。正式地址、101/102 当前准入和服务器代码边界遵守既有裁决。

项目结束前必须逐项确认的边界(当前均未验收)

以下项目必须由最终实现、调用图、双模式运行证据和审查裁决逐项销账;不能因本文已写下目标就标记通过。

  • PlayFab 路线保留:开关选择 PlayFab 时,PlayFabUserService 仍负责其登录/资料,PlayFabMgr 仍负责旧存档缓存与同步,并直接使用 PlayFabClientAPI;其余 PlayFab SDK 调用按原功能保留。确认原渠道、场景、Prefab、DI 注册及代表性业务回归,而不是只证明能编译。
  • KV 路线独立:开关选择 KV 时,使用独立的 KV 用户服务和基于原 PlayerKVGameSessionHandle 的 KV 存档路径;不得借 PlayFabUserService 实例、PlayFabMgr 活动实例或 PlayFab SDK 凭据完成 KV 业务。当前 KV partial 与旧类绑定应有经评审的抽离结果。
  • 开关只有一处决策:启动阶段明确选择并冻结提供方;用户服务、存档、账号会话、普通请求和场景入口得到一致选择。登录后不得热切换,也不得因 KV 错误静默落到 PlayFab;失败时保持可解释的错误和可恢复边界。
  • 业务依赖可读:业务层依赖中立且语义明确的用户/存档契约,提供方专属类型留在各自实现或适配层;核 IUserService 中的 EntityKey、playFabId、UserId 语义,PFLoginAct 的具体类型下转,以及 31 模块绑定。不能为了共用接口给 KV 伪造 PlayFab 身份。
  • 抽象简洁性:逐项说明最终保留的接口、适配器、管理器和状态各自的实际调用者与不可省职责;合并重复开关、重复状态和无消费者的包装层。用真实调用图确认业务流程能直接读懂,复杂性只来自已确认的功能或必要保护。
  • 会话与写入隔离:分别核两模式的登录、授权、读写、同步/票据、退出、暂停恢复、重启恢复、过期凭据和旧 epoch 回调;确认 KV 的 Guard/原 handle 租约与 PlayFab 的原同步路径不会交叉执行或串档。
  • 渠道和临时路径清账:明确 AGG 与其他渠道各自支持哪种提供方;按临时门控清单恢复为开发方便而冻结/忽略的功能。只清理无消费者的过渡 KV 分支与闲置实现,不能误删仍供 PlayFab 模式使用的代码和资源。
  • 最终证据与裁决:输出两种开关设置的真实最终调用流程图、覆盖上述项目的测试/运行证据和未覆盖范围;完成独立复核与主会话逐项裁决后,才可将双提供方边界标记为通过并结束项目。