保存独立KV用户服务、固定会话存档与原业务接线,以及C3d资料缓存和C3e本人统计写。 保留原PF/AGG路线、业务公式和时序;榜单读取、好友资料、公告、匹配及首场景闸仍待完成。 验证:ServiceHost两条件各33组646断言;Unity CLI Loop编译0错误269警告。 包含相关方案、评审裁决、测试及状态文档。未操作服务器、正式账号或打包。
8.9 KiB
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 默认路径维持。此首段仍须完整独立审查,不能仅凭本文件视为获批。
源码证据与必须写入完整方案的合同
- 启动捕获:
Boostrap.AfterAssetUpdateV2在已取得config后先调用SubBoostrap.RegisterServices(ctx.gameObject),后调用AfterAssetUpdate(config,...)。后者当前无条件AddComponent<PlayFabMgr>()。正式方案应把捕获的SaveBackend传给注册入口,在创建组件前分流;只接受精确playfab/kv,缺省 PF,未知值停止。运行期间配置变更不切换当前组件或身份。Editor 的PlayerKVGameplayLoop.BeforeBootstrap属许可流程,不替代正式捕获。 - 正式实例与加载:
PlayFabUserService()的kvControlledInstance=false,而ResetForKVLoad/ReplaceFromKVDecoded只接受受控实例或 Editor loop;RejectSaveBackend("kv")直接拒绝。完整方案必须定义互斥的正式 KV 实例准入,不能把kvControlledInstance当成正式标志随意改义;第 31 模块的初始化通知/归一化意图、失败清理和OnInitData接收者都要有正式合同。正式登录仅调用LoadForGameAsync一次,读取TryGetCurrentGameHandle(epoch)得到 CP1 同一原对象;TryAcquireGameHandle仅由 Coordinator 内部消费。不可再调LoginApiServerCore建第二个 S101 会话。 - 身份发布:当前
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 头像/关联账号写入须列逐项行为边界。 - 工厂与文件:
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。 - 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()目前只注册实时事件,首批不能以此推断全部购买流程已迁移。 - 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 暴露为可替换流。 - 退出和故障: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 自动执行及运行引用归零、删掉没有正式消费者的迁移接口和闲置实现,给最终流程图;本检查点不提前清理。