8.9 KiB
客户端与 N3-Server-CN 对比分析
更新说明:服务端 a3d3faa 已补齐通用玩家 KV Get/Set/Delete,本文未找到KV的结论已过期;最新接口及兼容差异见《KV更新复核.md》。
进一步核查修正:friend/GetHomePage仅返回社交列表,不能作为本人资料恢复接口。当前开发方案、资料来源限制及评审裁决见《客户端迁移详细修改方案.md》。
日期:2026-09-15。客户端 feat/upserver / f40a816cc,加已批准的 SignalR 选项修改;服务端本地 main / 696fc8c。分析以当前源码为准,不代表远端部署版本已经核对。此次只分析及更新文档。
一、结论
服务端已实现渠道十进制身份、Cookie 登录、自建 SignalR 和好友列表;它尚不能在当前检出中完整替代客户端使用的全部 PlayFab 功能。优先打通账号和实时连接,再补齐 KV 契约及外围依赖,最后删除 SDK。
二、核心接口对照
| 项目 | 客户端当前实现 | 服务端当前实现 | 差异与处理 |
|---|---|---|---|
| API 地址 | DebugConfig 和 CustomServerMgr 缺省指向旧 IP:5292;本地配置可覆盖 | 用户指定 s101.local:18080,根路径/时间接口已可达 | 地址及生效配置仍需修改;本次仅 SignalR 选项已改 |
| 身份来源 | AggUserService 将渠道 ID 放在 CustomId;随后 PlayFab 登录生成 hex UserId | PlayerIdUtil 使用 long.Parse,拒绝负值 | UserId 应来自渠道 ID;不能对旧 hex 做进制转换代替身份迁移 |
| 登录路由 | POST account/Login,发送 playerId/playerProfile | 同一路由;playerProfile 可选 | 路由基本一致,主要差异是身份语义与初始化数据 |
| 登录返回 | 只读 state/internalId,LoginApiServer 为 async void | 成功返回 state=0、internalId、createTime、svrTime、newCreate,签发 Cookie | await 业务登录,失败不返回 Done;专用 DTO 接收并映射时间/新账号标志 |
| 登录附带资料 | PlayFab 返回 UserData、昵称、头像、地区、创建/上次登录时间、EntityToken | LoginResp 无 KV、昵称头像、地区、上次登录时间和实体令牌 | 逐项指定新来源;不能删掉 PlayFab 调用后用空值继续初始化 |
| KV 读取 | PlayFab 登录 InfoResultPayload.UserData,CompareDatas 后 LoadPlayerData | 当前检出未找到通用 KV 读取路由,登录也不带存档 | 需要确定 KV 服务/分支;不能用服务器 players 表代替游戏存档 |
| KV 写入 | UpdateUserData,字符串键值、LastUpdated、本地缓存、批量及立即同步 | 当前检出未找到等价通用写入路由 | 定义批量读写、时间/版本、失败重试、跨玩家读取权限后实施 |
| SignalR | /gamehub,业务登录事件触发,复用 CookieContainer | /gamehub RequireAuthorization,用户标识来自 Cookie | 认证与路径一致,已添加 SkipNegotiation+WebSockets;仍需实际登录验证 |
注:服务端模型属性 InternalId/CreateTime 采用默认 MVC JSON 命名策略;客户端的 internalId 不能仅凭 C# 属性大小写判为不兼容。最终用真实响应或契约测试确认。
三、登录顺序必须调整
旧顺序:渠道身份 → PlayFab 登录/资料/KV → 初始化玩法 → 异步发业务登录 → 提前返回 Done。
建议新顺序:渠道身份 → 等待 account/Login 并确认 state → 保存会话/内部 ID/服务时间 → 获取完整玩家资料与 KV → 初始化玩法 → 返回 Done。
API 授权成功事件与游戏数据就绪要明确分开:SignalR 可以在拿到 Cookie 后建立连接,但消费玩法消息的代码需要在数据就绪后执行,或在此期间缓存消息。实施方案需核查所有 EvtAPISvrLoginSuccess 订阅者再确定事件时序。
首次登录建议不上传尚未恢复的等级/昵称等默认资料:服务端 AccountService 每次登录都会把非空 playerProfile 写回 DBPlayer,客户端默认数据可能覆盖已有资料。先取资料/存档,再按明确字段更新。服务端 GetHomePage 可作为资料查询候选,需核对响应是否覆盖登录初始化所需字段。
四、KV 需要的契约
PlayFabMgr 不只是本地缓存。它负责远端记录与本地值合并,再供大量玩法加载;服务端的 DBPlayer 只有账号资料,Redis 的玩法状态也不能证明存在可供客户端调用的通用 KV API。
必须明确:
- 读写路径、鉴权方式、全量/指定 key 读取及响应模型。
- 空存档与请求失败的区分;字符串值、每 key 更新时间/版本。
- 并发策略、写入确认与重试、批量大小限制。
- 当前 Public UserData 中哪些允许其他玩家读取,哪些只能当前账号访问。
- 全新区服是否沿用服务端文档“不迁移旧 PlayFab 存量”决策;本地旧缓存也不能混入新渠道账号。
现有队列还有可靠性缺口:SyncData 在请求确认前轮换缓冲,失败仅记日志;改造时应保留未确认批次并防止旧重试覆盖新值。立即同步与批量同步也必须有明确先后规则。
五、删除 SDK 的外围依赖
| 功能 | 客户端依赖 | 服务端可用能力 | 判断 |
|---|---|---|---|
| 好友列表 | PlayFab GetFriendsList,读取 Profile.Statistics/LastLogin | POST friend/GetFriendsList;Friends 为每项已序列化的 JSON 字符串 | 可适配,需两层解析;PlayerInfo 给 Level,不给 Statistics/LastLogin,在线时长展示需另定来源 |
| 玩家资料 | GetPlayerProfile、UpdateAvatarUrl、UpdateUserTitleDisplayName | account/UpdateProfile、friend/GetHomePage | 有候选;需核对读取/失败语义,不能保持原“先 PlayFab 后业务”双写 |
| 地区与语言 | PlayFab Locations、SetProfileLanguage | 登录响应未提供 | 明确渠道/本地设置/服务端字段的责任,不编造地区 |
| 等级/地区排行榜 | UpdatePlayerStatistics、GetLeaderboard,LevelB 等统计名 | event/GetLeaderboards、event/UpdateScore | 已有的是活动排行榜,不能直接当作全球/地区等级榜替代 |
| 公告 | GetTitleNews | 本次控制器检索未找到等价公告端点 | 契约缺口;不能用空列表假装迁移完成 |
| 对战匹配 | Create/Get/CancelMatchmakingTicket、GetMatch,依赖 EntityKey | duel/DuelRT 负责对战实时请求 | 对战同步不等于票据匹配,需要等价匹配服务或经评审的玩法切换 |
| 账号工具 | PlayFabTools 用渠道 ID 再登录 PlayFab 查资料 | 服务端渠道身份/玩家查询 | 删除这条旧映射,具体替代查询需核实 |
六、易遗漏的客户端兼容问题
- FriendService.cs:375:邀请码把 ID 当 hex 转整数;应核对编码和解码的整个链路。
- SurveyService.cs:56:用户尾号筛选按 hex 转换,会改变十进制渠道用户分组。
- DinggingSceneData.cs:94:随机种子按 hex 转换;迁移后需要明确可复现规则,避免既有玩法结果突变。
- UserService.cs:140:默认名使用 id[0..5];服务端允许较短数字 ID,不能默认长度至少为 5。
- RTService:连接前注册的订阅进入 _cachedEvents,但刷新仅挂在 Reconnected;首次 StartAsync 成功没有刷新调用。从控制流看存在首连漏订阅风险,需回归测试验证,不属于已批准的两项选项修改。
- Logout 当前只清 PlayFab 凭据和字段,业务 Cookie 生命周期需在迁移方案中一并处理。
七、建议实施顺序与评审裁决
- API 地址与现有本地覆盖项修改,验证实际生效;SignalR 两项配置已经落地。
- 完成十进制账号登录方案:响应 DTO、await、时间/资料来源、Cookie、失败处理和所有 ID 依赖点。
- 确认 KV 契约;无契约前不替换存档初始化,不直接删除 SDK。
- 迁移好友等有明确替代接口的功能;逐项解决公告、排行、匹配缺口。
- 清理 SDK 包、类型、程序集和热更新引用,执行编译及回归。
- 用专用账号验证登录、KV 写后读与重新登录、SignalR 无 negotiate 且可调用 Test/接收推送/重连。
裁决:SignalR 选项子集实现与服务端方向一致;全量去 SDK 方案仍有 KV 和外围能力缺口,暂不放行。地址/登录可分别形成限定边界的开发批次,但账号登录成功不能冒充完整游戏登录验收。
源码入口
- 客户端:Client/Assets/Scripts/Services/{UserService,AggUserService,FriendService,RTService,SurveyService,TileNewsManager}.cs
- 客户端:Client/Assets/Scripts/Core/PlayFabMgr.cs、Client/Assets/Scripts/DataCenter/DataCenter.LeadboardData.cs、Client/Assets/Scripts/Duel/UI/EventFishingDuelPanel.cs
- 服务端:LeaderboardAPI/Controllers/{AccountApi,FriendApi,EventLeaderboardApi,DuelApi}.cs、LeaderboardAPI/Program.cs
- 服务端:LeaderboardBLL/Models/AccountModel.cs、LeaderboardBLL/Utils/PlayerIdUtil.cs、LeaderboardBLL/Services/PlayerInfo/{AccountService,PlayerInfoCacheService}.cs、LeaderboardBLL/Services/Friend/NewFriendService.cs