Files
ft/CodexOutput/upserver/B3BatchMigration/M2/M2-CP2正式接线设计输入与新增阻断-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

8.9 KiB
Raw Blame History

M2 CP2 正式接线设计输入与新增阻断(待完整方案审查)

日期:2026-09-29。继承修订2及 CP1 限定关闭裁决。本文件记录只读源码核查和拟议边界,不是 CP2 编码批准;不得据此改生产代码。正式地址固定 http://s101.local:18080/,Unity 仅 CLI Loop,不用 UnitySkills,暂不打包。

首批账号裁决

用户本轮明确选定“仅已核准且已有 KV 档的账号”,并确认首批名单仅 101、102。因此正式 KV 入口须在认证前核准规范化十进制 ID 为 101/102,认证后再核同一 ID、newCreate == false、现存 KV 档及完整 Schema;任一失败停止并排水关闭,不创建空档、不迁移其他账号历史档、不覆盖未知数据。101/102 的既有受控许可不是正式入口的授权机制;正式清单的来源、变更方式和校验文件须在完整方案中单列。其他账号遇 SaveBackend=kv 应报错停止,不能静默回退到 PF 或为其自动建档。实际正式账号请求/写入仍不在本检查点。

方案选择

方案 结果 裁决方向
A:启动前捕获 backend,KV 分支不创建 PF 组件;同一 Context 的 S101 认证、KV Owner 和 API 租约;加载后发布身份与原 handle 沿用 CP1 原对象/关闭屏障;需完成正式实例准入、网络路由和旧调用审计 推荐作为完整 CP2 方案主体,待审查
B:仍创建 PF 组件但在 Awake 内按 backend 跳过 保留组件引用可掩盖旧调用,生命周期和旧定时器容易复活;不能证明运行引用归零 不采用
C:KV 配置直接调用 Editor 许可循环/验证工厂并开放全部 API 测试专用权限与正式账号混用,路由无边界 不采用

用户本轮选定 CP2 首段验收仅含非 AGG 的正式 Bootstrap→登录→31 模块 Apply→原 handle 交接→退出排水,在进入 FishingStage 前停住;Mail/IAP、业务 API 和公开授权事件先不触发。首场景可运行是下一独立验收门。FishingStage 内还有即时 PF 与 API 调用,见下表,不能让登录成功后自然切场景再靠空引用暴露漏项。AGG 渠道路径仍需独立完整设计;在该设计获批前,AGG 构建的 kv 必须显式拒绝、PF 默认路径维持。此首段仍须完整独立审查,不能仅凭本文件视为获批。

源码证据与必须写入完整方案的合同

  1. 启动捕获:Boostrap.AfterAssetUpdateV2 在已取得 config 后先调用 SubBoostrap.RegisterServices(ctx.gameObject),后调用 AfterAssetUpdate(config,...)。后者当前无条件 AddComponent<PlayFabMgr>()。正式方案应把捕获的 SaveBackend 传给注册入口,在创建组件前分流;只接受精确 playfab/kv,缺省 PF,未知值停止。运行期间配置变更不切换当前组件或身份。Editor 的 PlayerKVGameplayLoop.BeforeBootstrap 属许可流程,不替代正式捕获。
  2. 正式实例与加载:PlayFabUserService() 的 kvControlledInstance=false,而 ResetForKVLoad / ReplaceFromKVDecoded 只接受受控实例或 Editor loop;RejectSaveBackend("kv") 直接拒绝。完整方案必须定义互斥的正式 KV 实例准入,不能把 kvControlledInstance 当成正式标志随意改义;第 31 模块的初始化通知/归一化意图、失败清理和 OnInitData 接收者都要有正式合同。正式登录仅调用 LoadForGameAsync 一次,读取 TryGetCurrentGameHandle(epoch) 得到 CP1 同一原对象;TryAcquireGameHandle 仅由 Coordinator 内部消费。不可再调 LoginApiServerCore 建第二个 S101 会话。
  3. 身份发布:当前 IsLogin 必须有 PF SDK 登录,IsAuthorized 必须 apiSession 认证,ApiPlayerId 取 apiSession.PlayerId,而正式 KV Context 持有的是另一会话。CP2 首段仅在 GameLoaded 后形成内部“已认证且原 handle 已交接”的状态,阶段切换、Mail/IAP 初始化、EvtAPISvrLoginSuccess 和对玩法公开 IsAuthorized 均保持关闭;后续首场景门才一次性发布 InternalId、API PlayerId、CreateTime 和事件。失败/Logout 同步撤销内部状态和 handle,再异步排水;旧 epoch 响应不得恢复身份。UserId 当前代表 PF ID,Mail 缓存和若干埋点会消费它;不得把 S101 十进制 ID 偷换成“PF ID”而不逐调用审计。SetMMTestValue 把 UserId 按十六进制解析并写 PF,KV 分支必须使用已解码 MMTest 且不调用该旧函数。OnYinDunLogin/TapJoy、资料更新及 AGG 头像/关联账号写入须列逐项行为边界。
  4. 工厂与文件:PlayerKVGameLoadCapability 目前只有 UNITY_EDITOR 的 CreateForValidation,其验证 handler 明确拒绝真实传输。需另增正式工厂,从启动捕获的 API 校验恰为 http://s101.local:18080/,使用同一 CookieContainer、三个互不共享且可独立 Dispose 的 auth/KV/lease handler;禁止重用 S101AccountSession 的旧 Cookie 替换流。CacheRoot 必须按账号隔离且路径固定,表快照取已加载的真实 cfg.Tables,不能沿用 Bindings 的硬编码 "kv-loop" 当正式版本。观察超时保持既有范围,Close 失败不得启动新 Context。
  5. 31 模块:PlayerKVGameplayBindings.cs 整文件仅 Editor 编译,Snapshot/Bind 要在 Player 目标可用;LoginStage 的 EventShootingRangeData 注册仅 Editor loop 下存在。需逐模块核 1–31 的容器注册、加载前静止点、Apply 主线程和版本快照;任一缺失失败关闭,不造空对象替代。原 PFLoginAct 登录成功后马上 MailService.Init() 与 iapService.Init();InGameMailService.Init() 在已授权时马上异步 mail/fetch。DevIAPService.Init() 和 AggRTIAPService.Init() 目前只注册实时事件,首批不能以此推断全部购买流程已迁移。
  6. API 借用:CustomServerMgr 的 kvOnly 仅放行两条 __kv_validation,普通 CustomServerPost 直接抛错;PlayerKVAccountLease.SendAsync 也只有这两条验证路径。正式租约应独立于验证路由,先定义确切 (Method, canonical route) 白名单。已核自动请求是 POST mail/fetch;若允许进入 FishingStage,还会由 InitEvent 触发 POST friend/GetInvitedListCount、由 AntiCheatManager.CheckBan 触发 POST anti-cheat/CheckBan;HomePanel 条件触发 POST club/GetSelfClub。这些是候选清单而非完整首场景白名单,其余 Club 路由仅按实际验收场景逐项批准,不能开 club/*。路由不得接受绝对 URL、编码绕过、查询、片段、路径穿越或重定向。绑定期间至 GameLoaded 前不发送普通业务请求;响应返回前后核 SessionVersion、同一租约、epoch、授权与关闭状态;401/403 只撤销当前身份,不重登 PF;Close 排水后才允许新租约。Cookie 旧属性不可把正式 KV Cookie 暴露为可替换流。
  7. 退出和故障:CP1 独立复核未重跑三类 cleanup-failure,也没有 GameLoaded 后 Close 失败的专项用例。CP2 必须注入/验证成功发布后的 Close 故障、旧 handler 无法排水、401/403、迟到响应、同账号新 epoch、切账号、Unity Quit;公开状态先撤销、屏障故障保持阻断,不声称底层资源已释放。卸载/重试/退出均观察同一 Registry;不可用 async void 异常吞掉失败。

审查前仍未解决的硬点

  • 正式核准账号清单如何发放与防止“只改配置就扩大范围”,以及初次 KV 档存在性的无写判定(newCreate=false 本身不充分)。
  • UserId 的全调用点分类:哪些要求 PF 十六进制 ID,哪些只需稳定玩家标识;Mail 缓存键、统计与好友/社团请求不能盲目替换。
  • 登录后初始场景还会发起的所有 API 和 PF 管理器调用;目前只核到下述若干入口,不能推断首个界面已可无错运行。
  • FishingStage.StartAsync 必走 SurveyService 构造(直接 PlayFabMgr.Instance.GetLocalData)、LeadboardData.SetLvData(PlayFab 排行榜调用);还触发上述 Friend/AntiCheat API。SurveyService.GetSurveyMatchlist 又把 UserId 按十六进制解析。进入场景前必须完成这几条业务转换或明确阻断阶段跳转,不能仅空值兜底。非 AGG 的 DevIAPService.GetOrderUnreceived 目前返回空字典,不能据此推断 AGG 支付路径可用。
  • AGG SDK 登录与 S101 账号映射、关联账号归一化、头像写入及埋点键名;在独立方案前保持 KV 显式拒绝。
  • Player 目标原有 _cheatingScore 编译错误的来源和独立修复白名单;正式验收必须 0 错误,不把 Editor 编译等同 Player。

以上硬点任一未在 CP2 完整方案给出可执行合同与测试矩阵,则 CP2 保持待评审,不修改生产代码。最终 CP4/CP5 要核旧 PlayFabMgr 自动执行及运行引用归零、删掉没有正式消费者的迁移接口和闲置实现,给最终流程图;本检查点不提前清理。