# M2 C3c 剩余 SDK 接线集中差异与待审方案 状态:**已到必要的集中差异审查点,尚未批准本增量编码。** 本文不是已完成的实现方案:第3节缺失的调用映射必须由审查结论补齐,不能由实施者临时猜测。既有C2d/C3b结论继续有效。 执行方式:当前客户端主会话实施,同批连续开发;不创建并行开发端,不逐功能送审。 目标:KV模式从KV及其既有业务接线取得原SDK提供的数据,业务逻辑保持原样,PF/AGG有效路线保留。 架构:复用KVUserService、IPlayerSaveStore和CustomServerMgr的现有身份/会话。本人存档由原handle操作;跨账号、榜单、好友关系和匹配按其真实服务能力接入。不为这一批新增泛化Provider、管理器、工厂或新开关,不让底层KVMgr依赖好友/UI/榜单业务。 技术:现有Unity C#、Newtonsoft.Json、Unity CLI Loop与ServiceHost离线宿主。 依据:[范围重申与调用清单](M2-KV替代范围重申与剩余SDK接线集中核查-2026-09-30.md)、[已审正式方案](M2-合批正式实施方案-待完整审查-2026-09-29.md)、根AGENTS及用户纯平移裁决。 ## 1. 本次继续执行得出的新结论 1. 历史文档不是完全没有候选接口:`CodexOutput/upserver/服务端契约核查.md:19`记录`POST friend/GetFriendsList`;《客户端与服务端对比分析.md:50》记录`Friends`为JSON字符串数组。它们是历史本地版本分析,**不是当前线上契约证据**;本次没有读取服务器源码。旧集中问题单里“尚不知有无好友路由”的描述应改为“已有历史候选,字段等价性待核”。 2. `friend/SearchFriend`已经有客户端调用与DTO,C3b已验证新ID传递。`SearchFriendReq.PlayFabId`填对方UserID;`SearchFriendResp`包含Code、Msg、Info,Info为BFriendInfo(PlayFabId、DisplayName、AvatarUrl、Level)。可作为对方资料读取候选,不需要另造URL。原搜索UI按`Code > 0`消费。但历史分析提示可能返回Unknown默认资料;C3b响应是合成夹具,不能证明正式响应源自KV或资料具有权威性。 3. `friend/GetHomePage`返回邀请/推荐列表;不拿它当本人/他人完整档案接口。活动`event/GetLeaderboards`也不能当全球/地区等级榜。 4. 公告本次加入同一增量:TileNewsManager有SDK调用,NoticePopupPanel有实际事件发布。其源文件不在原候选白名单中,需要一次纳入明确边界。 ## 2. 已证实不能直接机械替换的差异 | 编号 | 客户端原语义与证据 | 机械替换会造成什么 | 本次裁决 | |---|---|---|---| | D1 好友等级 | FriendService:169-185从Statistics取LevelB;SocialFriends:106-107将value除以/模100000;伙伴邀请:360也除100000 | 普通Level=12直接填value会在好友UI显示等级0;只乘100000又会丢建筑等级及原排序 | 必须拿到等价LevelB,或真实Lv与建筑等级后按原clamp算法计算。历史方案“Level直接映射”不能继续采用 | | D2 好友时间 | FriendService:186存LastLogin;EventPartnerInvitationPanel:361无HasValue检查直接读`.Value`并按时间排序 | 缺时间填null可令符合筛选条件的好友在伙伴邀请列表触发异常;填当前时间/MinValue会改变排序 | 需真实等价时间来源,不能靠更改消费者过滤/默认时间解决。GetActiveFriendCount也使用该字段,但全Scripts检索未发现其调用者,不夸大为已执行链 | | D3 他人资料 | UserService:849-892原GetPlayInfo同步返回同一占位对象,异步更新对象并发布GetClubPlayInfoEvent;GetPlayLv按目标ID取Lv | KV当前缓存未命中返回null/异常,并不等价;直接换成等待网络后显示又改变原时序 | 候选在KVUserService中恢复原占位对象、缓存更新与事件路径;只替换数据读取。先裁决SearchFriend的结果有效性和失败映射 | | D4 等级榜 | 原SetLvData编码等级和建筑等级;GetLeadboardData返回全局/地区前50、位置与资料 | 仅保存本人Lv无法生成其他玩家榜;把活动榜接过来改变业务 | 沿用已审“不新增LevelB冗余键”,补准确的KV聚合读取及原统计更新时点映射,不能简单删除Update统计调用 | | D5 公告/匹配 | 公告读取标题/正文/时间及首项;匹配有创建/3秒轮询/取消/结果 | 空公告或直接MachingEnd(null)只是停用;普通KV写键不能替代多人票据匹配 | 补真实调用映射,保留现有UI和轮询时序;本增量不顺带修原公告异步显示或匹配竞态 | ## 3. 集中审查需要产出的最小裁决 这不是重新询问迁移方向、新ID或邮件流程,也不要求客户端读取服务器源码。审查侧先查已有资料;能直接指出已有调用方式的就给文件/段落,缺事实才列一次外部沟通项。 | 能力 | 已有可用输入 | 需补的准确映射/事实 | |---|---|---| | 他人资料 | 现有SearchFriend请求/DTO、新UserID与同会话FriendRequest | 能否按目标UserID读到KV来源的真实Lv/昵称/头像;Unknown/不存在/请求失败的区分;Info.PlayFabId是否为目标ID。若可复用,给出原GetPlayInfo/GetPlayLv失败形态对应关系 | | 好友列表 | 历史POST friend/GetFriendsList,Cookie身份、Friends字符串数组 | 现行请求体与完整单项格式、成功/失败Code;等价LevelB或Lv+建筑等级、LastLogin的来源。不可批准“Level直接映射”或用假时间补齐 | | 等级榜 | 本人KV已有Lv/InfiniteBuildingData/ContinentCode;原分数算法 | 已有聚合路由/输入/结果(统计名、地区、StartPosition、MaxResultsCount、UserID、分数、位置、资料);聚合读取如何与原更新时点对应,未知地区如何沿已审边界处理 | | 公告 | 原消费者Title/Body/Timestamp和首项选择已定位 | 公告属于全局内容,给实际KV作用域、键或读取入口及发布/排序格式,不能凭名称猜一个私有KV键 | | 匹配 | 原QueueName、GiveUpAfterSeconds、Tier/Map/Group/Details | 新UserID的创建/查询/取消/读结果调用;TicketId、Status、MatchId、成员UserID/属性的对应。保留3秒轮询和原5秒Ready检查,不用伪EntityKey | 只有旧本地文档或成功合成响应时,明确写“候选/待实测”,不要升级为当前线上已确认。用户已允许必要功能测试;已知原普通路由无需逐条再索要审批。缺的是上述数据语义和新调用映射,不是对测试方向的授权。 ## 4. 候选最小文件边界与实施顺序 确定接口后沿当前主会话按下列顺序实施,不拆新批,不更改既有业务消费者: | 文件(Client/Assets/Scripts下) | 仅允许的迁移变化 | |---|---| | Services/KVUserService.cs | GetPlayInfo/GetPlayLv的目标玩家读取、原缓存对象更新和原事件;本人KV资料及认证流程不改 | | Services/FriendService.cs | GetFriendList的KV数据取得及映射,保留async void、过滤、排序、发布顺序和原PF分支 | | Services/FriendModel.cs(新增白名单候选) | 只有现有DTO确实缺少已确认响应字段时补DTO;不重命名现有字段 | | DataCenter/DataCenter.LeadboardData.cs | KV统计/聚合调用及结果映射,保留原分数计算、展示和活动榜 | | Services/TileNewsManager.cs(新增白名单候选) | KV公告读取及原TitleNewsItem结果映射,UI消费者零修改 | | Duel/UI/EventFishingDuelPanel.cs | 同一匹配流程按既有提供方选择接线,KV移除开发性结束路径,PF路线保留 | | CodexOutput/upserver/KVGameLoadTests/ServiceHost/下现有宿主及新增C3RemainingSdkTests.cs | 链接真实生产类,协议夹具和SDK计数;不得把只测夹具当真实生产覆盖 | 不新增生产接口抽象;若实际签名迫使新增层次,必须给具体调用者和复用现有实现不足的理由,由同一次审查裁决。Core/KVMgr、KV底层协议/Guard、HomePanel、场景资产、服务端代码不在本增量边界。未来需要新增URL分类时先审准确路由,不能开放任意请求。 - [x] 完成客户端与历史接口资料核查、具体差异及消费者核对。 - [x] 建立本增量受审hash与静态核查记录;不重写原C2d/C3b封存。 - [ ] 审查逐项补齐第3节映射,明确哪些可立即实施;没有依据的项保持未裁决,不能给空泛整包PASS。 - [ ] 主会话核受审hash、逐条裁决并补全可执行签名/响应映射后,在同批先写对应失败用例,再接线至通过。 - [ ] 两种ServiceHost条件测试及Unity CLI Loop编译;原PF对照和KV零SDK调用计数同时验证。 - [ ] 用正式允许的账号101/102检验已知调用的数据/ID语义,保留脱敏失败供服务端侧处理。正式写入/Play范围按当时明确裁决执行,不混入付费或打包。 - [ ] 全链就绪后恢复已登记冻结,最后一次C4实施复核。 ## 5. 验证要求(随实现执行,本次未运行) 1. 101查102、反向查询及旧会话撤销:结果必须属于目标账号;PF调用计数KV为0,PF对照仍走原实现。 2. 好友Lv=12、建筑=34时原value=1200034;旧好友UI解码12/34、排序不变。缺少建筑/LastLogin不能因解析默认值而伪装测试通过;包含真实伙伴邀请消费者验证时间读取。 3. 他人资料缓存未命中:同步占位返回对象保持引用;异步更新和GetClubPlayInfoEvent遵循原行为。接口失败、不存在、Unknown分别按裁决验证,不写回假资料。 4. 榜单空榜/50人/同分/地区缺失、更新后读取;公告多项顺序、Timestamp、原红点/显示流程,不能拿内存拼榜冒充聚合。 5. 匹配创建失败、等待、Matched、Canceled、取消后的返回;3秒轮询及成员属性解析保持,不顺带加强原竞态行为。 命令:`dotnet run --project CodexOutput/upserver/KVGameLoadTests/ServiceHost/ServiceHost.csproj --no-restore`;另一条件增加`-p:AndroidProbe=true`。Unity只运行`uloop compile --project-path C:/projects/ft/Client --wait-for-domain-reload true`及已核隔离验证。测试需覆盖真实接线,合成HTTP不证明线上KV来源。 ## 6. 给原ZCode的一次性审查指令 先核同目录`M2-C3c剩余SDK差异受审hash.json`的所有项;读取本文及引用方案,只读客户端和已归档文档,禁止读取/改动本地或远程服务器源码。不要重审C2d/C3b已批准同合同内容。 按D1-D5逐条给出:事实是否成立、已有映射文档位置、客户端最小实现裁决与允许文件、仍缺的具体事实。重点反证“Level直接映射”和“LastLogin置空”是否能保留原流程;若不能,禁止以UI修复规避。 报告写`M2-C3c剩余SDK接线独立差异审查-2026-09-30.md`,注明受审清单SHA256、逐项核验数量及仅静态/实际测试的区别。不能用用户已批准KV方向代替对新增接口映射的审查;也不反过来要求用户重答方向问题。报告落盘后由主会话核hash、逐项裁决;一次批准范围内连续执行。 ## 7. 当前停止原因与边界 根AGENTS规定:“修改代码前完成相关方案的完整评审,记录裁决和开发边界。”原正式审查只批准原白名单与方案§2–§7的明确行为;尚未给出这些剩余能力的完整映射,公告及必要DTO又增加文件边界。现在直接编码只能猜字段、丢数据或改业务,违反用户纯平移要求,因此在本增量编码前停在集中审查点。 本次未改生产/测试/配置,未发线上请求,未Play/打包,未向其他会话或人员发送消息。当前需要审查侧给出上述具体裁决,不等于已证明服务器必须新增全部能力。 封存前只读核验:原受审基线叠加C2d后2122项Client文件全部一致;C3b的4项交付与8项证据全部一致,0漂移。见`M2-C3c只读核查记录.json`。本轮没有重跑业务测试;等级除法示例仅用于反证错误映射,不是线上或Unity运行证据。