Files
ft/CodexOutput/upserver/B3BatchMigration/M2/M2-CP2A正式登录与原句柄交接完整方案-待独立审查.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

11 KiB
Raw Blame History

M2 CP2A 正式登录与原句柄交接完整方案(待独立审查)

日期:2026-09-29。依据修订2主会话裁决、CP1限定关闭及用户本轮两项明确选择:首批仅账号 101、102 且已有 KV 档;本检查点只验正式登录与原 handle 交接,在进入首场景前停住。本文是 CP2 的一个完整可独立验证的子边界,尚未获原 ZCode 审查/主会话批准,不能编码。CP2B 首场景、CP3 业务迁移、CP4 旧运行引用清零、CP5 无用代码清理均不因本方案自动通过。

1. 可观察目标和停止点

默认/缺省 SaveBackend=playfab 的启动、登录、Mail/IAP 和进入 FishingStage 行为保持原状。仅 SaveBackend=kv 且非 AGG 目标、账号为 101/102、正式 API 恰为 http://s101.local:18080/ 时,启动前不创建 PlayFabMgr,完成一次 S101 登录、现存 KV 档读取与 31 模块 Apply,返回 CP1 同一原 PlayerKVGameSessionHandle 的内部会话交接检查点。此状态不进入 FishingStage、不初始化 Mail/IAP、不发布 EvtAPISvrLoginSuccess、不开放业务 API 或存档写入 UI。登录失败、无档、新建、Schema 不符、关闭失败均留在登录阶段且撤销身份/句柄,不回退 PF、不自动重试写入。Logout/应用退出同步撤销并登记异步排水;排水失败不准下一次 Context。

该“正式”只表示 Bootstrap/非 Editor 专用工厂/普通登录入口可到达,不表示已发布玩法。首场景的 Survey 构造与排行榜旧 PF 调用、Friend/AntiCheat/Club 路由另见只读清单,本检查点以双重阶段阻断保护,不能靠运行时异常当边界。

2. 精确设计合同

2.1 启动与账号准入

  • Boostrap.AfterAssetUpdateV2 将已加载 config 传入 SubBoostrap.RegisterServices。该方法在任何存档组件创建之前一次捕获精确 playfab/kv,注册不可变 PlayerKVRuntimeSelection。未配置为 PF;其他值在启动处停止,运行期间配置被改不切换当前后端。KV 若为 AGG 目标在启动处明确失败,绝不创建 PF 组件后继续。既有 Editor loop 在 RegisterServices 内稍后才把配置临时设为 kv-loop;正式捕获不得误拒该 Editor 许可流程,其登录分支仍先由原 UNITY_EDITOR && !SERVICE_HOST 入口处理。
  • kv 分支核 API 的规范 URI 字符串恰为 http://s101.local:18080/,只创建必要的 KV 退出生命周期接收者,不创建/唤醒旧 PlayFabMgr。PF 分支组件顺序及旧 Awake 不变。正式入口不读取 Editor permit、claim、备份和 PlayerKVGameplayLoop.Enabled。
  • 在 S101 请求前规范化 CustomID 为无符号十进制正整数的最短字符串,仅 101/102通过;名单为本批受审代码常量,后续扩员必须另审,不从运行时可改配置读取。响应的 PlayerId 必须仍等于请求 ID,NewlyCreated 必须为 false,playerdata/Get 的非空档必须经 31 模块完整 Schema 验证。newCreate=false 单独不算已有档。任一失败撤销关闭;不得创建空档或远端写入。

2.2 三传输与原对象交接

  • 给 PlayerKVGameLoadCapability 增正式工厂,保留 CreateForValidation 原签名和 Editor-only 限制。正式工厂从上述已捕获地址和 Application.persistentDataPath 形成根路径;PlayerKVCacheIdentity 已按 API 指纹和 PlayerId 隔离,不再自造第二层账号目录。cfg.Tables 必须在 SubBoostrap.AfterAssetUpdate 注册完成后才取快照;Bindings 对正式路径接受明确的本地 decoder 版本令牌,Editor 默认 kv-loop 不变。版本令牌仅校验本进程快照一致,不能冒充服务端 Schema 协议版本。
  • 正式 auth、KV、account lease 各自有独立 HttpClientHandler,共享同一个 CookieContainer,AllowAutoRedirect=false,所有权只转交一次;工厂先验证三者不共享,再允许认证发送。正式 handler 不能走 CreateForValidation 的“拒绝真实传输”构造;测试替身不能经 Editor permit 混入正式运行。任何部分构造失败逐个 Dispose,失败保留为关闭屏障。
  • 正常 PlayFabUserService 在捕获的 KV 模式下获得一次性的正式加载准入;当前 kvControlledInstance 专属验证语义保持,不能简单改为 true。Coordinator 的 unstarted 前置必须在正式模式检查无旧 PF 实例、未发布 InternalId、尚无前一会话,并继续在 Apply 前复核。第 31 模块 ResetForKVLoad/ReplaceFromKVDecoded 仅在正式加载窗口内允许,已公开账号/其他后端/第二次 Apply 全拒。非 AGG 身份快照使用 channel=none、空 Linked、NewlyCreated=false,服务端 NewlyCreated 仍须独立拒绝。使用 LoadForGameAsync 共用 CP1 主体;TryAcquireGameHandle 仍只由 Coordinator 调用,UserService 按返回 epoch 调 TryGetCurrentGameHandle 一次并保持同一对象。CP1 三接口均有真实消费者,不另造全局 handle、缓存、同步器或 PF 同名转发。
  • CustomServerMgr 增正式租约绑定/清除,但 CP2A 的 API 业务路由集合为空;绑定时立即废弃旧空闲 transport,Cookie 不对外提供新 jar,任何 CustomServerPost 在 KV 模式仍显式拒绝。正式认证只有 Context 内那一次 S101AccountSession.LoginAsync;绝不调 LoginApiServerCore 建第二会话。租约和 handle 都由同一 Context/epoch 关闭。CP2B 才对 mail/fetch 等逐条路由补审;不能在 CP2A 偷开 club/* 或所有 POST。

2.3 登录状态、阶段闸与关闭

  • PlayFabUserService.LoginWithBackend 在原 Editor loop 优先分支之后,用启动捕获选择正式 KV 分支,不走 LoginPlayFab、SetMMTestValue(其十六进制 PF UserId 解析及 PF 写入均不适用)、LoginApiServerCore、TapJoy、YinDun PF 资料路径。构造函数已有的 EvtAPISvrUnauthorized 订阅在 KV 模式不得执行“PF 已登录则重登 S101”的旧回调。正式加载通知不得调用未审 OnInitData 订阅者;无订阅或唯一经受审登记的接收者才可通过。31 模块 Apply 后仅产生内部 KVHandoffReady(epoch, originalHandle),不将 S101 十进制 ID 写成 PF UserId,不宣布 IsLogin/IsAuthorized 或发布 API 登录成功事件;这些公开状态留 CP2B 随首场景和业务调用一起评审。调用方可取得非权威历史结果,但旧 epoch 不能重新查询“当前账号”换 Owner。
  • PFLoginAct 的 rtService.WaitForAPISvrLogin() 在 KV 首段也不注册(该订阅会一直等尚未发布的事件),收到 KV 内部成功状态后停止加载进度,在登录阶段保留可识别的“准备完成/暂不进入游戏”结果,不调用 MailService.Init、iapService.Init、Unload。LoginStage.RequestNextAct 再按捕获模式双重阻断转入 FishingStage,防止后续 UI 误调用 Unload 绕开。PF 分支完全不变;KV 加载失败不得进入原无限重试/改 ID 对话,应显示失败并要求显式重启或登出,保持关闭屏障。此检查点的用户界面文案不暴露 handle、Cookie 或内部存储细节。
  • Logout、应用退出/销毁对 KV 分支先同步清内部 ready、账号、handle 和 epoch,再调用 Coordinator.Revoke/Registry 排水;不调用 PF 忘凭据/旧缓冲同步。Close 异常保持阻断状态,不能在故障后创建下一个 Context。后台回调按请求时捕获的 ID/epoch/原句柄判定,旧响应绝不重新发布;不可在锁内 await。

3. CP2A 精确生产白名单候选

文件 只允许的变化
Client/Assets/Scripts/AOTScripts/Boostrap.cs、Client/Assets/Scripts/SubBoostrap.cs 传入/捕获配置,PF/KV 组件创建分流与 KV 退出钩子
新 Client/Assets/Scripts/Services/PlayerData/PlayerKVRuntimeSelection.cs(含 .meta) 不可变 backend/固定 API/101、102 准入;不持有 Cookie/handle
Client/Assets/Scripts/Services/PlayerData/PlayerKVControlledLoadCapability.cs、PlayerKVLoginContext.cs、PlayerKVGameLoadCoordinator.cs 正式三 handler 工厂与既有档门;Context/Coordinator 如确需身份/epoch 检查仅增加受限入口,保留 CP1 与验证旧合同
Client/Assets/Scripts/Services/PlayerData/PlayerKVGameplayBindings.cs、Client/Assets/Scripts/Stages/LoginStage.cs 同一 31 模块绑定进入 Player 编译、补实际注册、双重阶段闸;Editor loop 路径不变
Client/Assets/Scripts/Services/UserService.cs、UserService.KVLoad.cs、Client/Assets/Scripts/Stages/PFLoginAct.cs 正式非 AGG 登录窗口、内部交接与明确停留、Logout;PF 分支不变
Client/Assets/Scripts/Core/CustomServerMgr.cs 正式租约绑定/清除与空业务路由拒绝;验证两路由原义不变
新 Client/Assets/Scripts/Services/PlayerData/PlayerKVRuntimeLifetime.cs(含 .meta) 若现有根对象生命周期没有合适位置,仅负责 KV 撤销/登记排水,不另造定时器

不在白名单:PlayFabMgr.cs、KVMgr.cs 四入口/Guard 方法体、AggUserService、FishingStage/Survey/Leaderboard、业务 API/活动/商店、Editor permit/受控循环、实际账号配置或数据文件。若实现证明某白名单项多余,删除它;若必须动白名单外文件,先补方案与独立审查。测试宿主可新增 CP2A 合成测试,不借真实 101/102 操作来填单测空白。

4. 验收矩阵和停手条件

类别 必须验证
PF 不回归 缺省及明确 PF 的 Bootstrap、旧组件、PF 登录、Mail/IAP、阶段跳转行为;Editor 旧 loop 与 CP1/B02 回归
KV 准入 未知 backend、AGG KV、地址不符、100/103、非规范数字、101/102 新建/空档/Schema 不符全部零业务写且不入场景
成功交接 合成 101/102:仅一次 account/Login、一次 KV 开启、31 模块、原对象同一 OwnerInstanceId/epoch;Guard 释放后内部读取可用,公开玩法仍关闭;无 PF 组件/凭据/旧40秒循环
竞态与关闭 加载中取消/Logout、Apply/notify 失败、同账号新 epoch、旧登录回包、GameLoaded 后 Close 故障、handler Dispose 故障、退出注册与观察;失败后无旧对象再发布
网络 三 handler 同 jar 不同实例、重定向拒绝、业务路由全拒、无旧 Cookie 替换;没有正式地址请求或账号写入的合成测试
目标编译 Editor 与 Player 目标均 0 错误;历史 _cheatingScore 另列来源/最小修复审查,不把已有错误算通过;Unity 自动化仅 CLI Loop,不打包

只有原 ZCode 对整个 CP2A 及白名单作独立方案审查、主会话先复核受审 hash 再逐条裁决后,才能修改生产代码。CP2A 实施完还须批末独立实施复核;其关闭只表示登录与原 handle 交接,不启用首场景。CP2B 完成首场景/路由与身份发布后,CP3–CP5 继续逐域迁移并最终删除闲置实现。现有工作树全部保留。