Files
ft/CodexOutput/upserver/B3BatchMigration/M2/M2-好友KV资料服务端接口设计-待完整审核-2026-09-30.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

10 KiB
Raw Blame History

好友KV资料服务端接口设计(待完整审核)

2026-09-30。用户授权:好友数据可以从服务器取得,客户端侧可设计接口,这部分由服务端开发修改。本文件是拟实施合同,不是当前线上已有字段的说明。客户端Agent不修改服务器;所有相关内容完整审核通过后才编码。

1. 方案选择与范围

方案 影响 选择
扩展原friend/GetFriendsList,随好友一次返回KV公开资料 保留已有路由、认证和friends字符串数组,新增一个资料字段即可承接原Profile语义 采用
新增独立批量KV公开资料路由 增加一次请求和关系列表/资料的组合步骤,改变原一次取得好友资料的链路 本次不采用
客户端逐个读好友私有KV 已被隔离合同与实测否定 禁止

本次设计只覆盖好友列表中的KV资料,落实LevelB及LastLogin的服务器读取;不将设计范围扩成新的泛化资料管理器。SearchFriend公开资料、等级榜、公告、匹配仍在同一C3c各自范围,不能因本接口定稿声称它们都已通过。

2. 请求合同

POST /friend/GetFriendsList
Content-Type: application/json
Cookie: 当前登录会话(沿现有认证)

{}
  • 服务器从认证会话取得本人UserID,沿原好友关系来源获取本人好友列表。
  • 请求不接受用于选择本人账号的playerId/playFabId/userId,不接受任意目标ID列表;客户端不提供好友私有KV访问凭据。
  • 只投影该原好友集合允许公开的资料,不返回原始NewPlayerDataDic、完整KV或认证数据。
  • 不改原好友关系建立、分页/数量边界和关系结果顺序,不新增好友增删动作。一次客户端请求完成关系和资料取得;服务端可用已有内部能力批量读取,不能回调客户端逐好友取档。

3. 返回合同

外层沿原code/msg/friends;成功仍code=1,friends仍为JSON字符串数组。每个字符串解码后,原PlayFabId/DisplayName/AvatarUrl/Level四字段保留原兼容含义,不改名、不把Level塞入复合分数。本次增加Profile字段,供迁移后的原PF好友消费者使用。

无好友成功:

{"code":1,"msg":"","friends":[]}

一名好友的成功示例(合成说明,不是101/102真实数据):

{
  "code": 1,
  "msg": "",
  "friends": [
    "{\"PlayFabId\":\"102\",\"DisplayName\":\"Angler#102\",\"AvatarUrl\":\"\",\"Level\":12,\"Profile\":{\"DisplayName\":\"Angler#102\",\"AvatarUrl\":\"\",\"Statistics\":[{\"Name\":\"LevelB\",\"Value\":1200034}],\"LastLogin\":\"2026-09-30T01:00:00.0000000Z\"}}"
  ]
}

新增Profile是普通业务DTO,不要求服务器引用PlayFab SDK。包含下列字段:

字段 JSON类型 值的来源与规则
Profile object或null,字段必须出现 可正常取得目标KV公开资料时为对象;已明确目标资料实体不存在时为null。读取超时/服务失败不能伪装null
Profile.DisplayName string或null 对应好友KV的DisplayName;缺键为null,空串保留。客户端沿原GetDefaultName规则处理空昵称,不额外写回KV
Profile.AvatarUrl string或null 对应好友KV的AvatarUrl;缺键为null,不填虚构头像
Profile.Statistics array或null,字段必须出现 当前只投影LevelB。正常完成KV读取后生成数组;无LevelB键则为[]。null仅表示明确不存在统计资料集合,不用于掩盖读取失败
Statistics[].Name string 本次固定LevelB,不将地区统计混入好友全局分数
Statistics[].Value JSON整数(Int32范围) 从该好友KV的LevelB十进制整数字符串解析;不从普通Level/建筑重新计算,不更改原负值等规则
Profile.LastLogin UTC时间字符串或null,字段必须出现 从该好友KV的LastLoginTimeUtc读取,保留真实时刻并以UTC往返格式O返回;缺键为null,不用查询时间或DB时间静默回填

外层四字段用于原接口消费者兼容,新增Profile明确承接KV迁移后的资料来源;客户端本次原PF好友映射读取Profile里的名字/头像/统计/时间,身份取外层PlayFabId。外层Level仍是普通等级,不在本接口改造中顺便修其他消费者或将其当GetPlayLv真实等级的证明。重复的名字/头像字段是保留现有wire兼容所需,不新增第二个持久化副本;服务器不为Profile另存缓存真值。

为什么保留Profile/Statistics两层

原FriendService分别判断Profile==null、Statistics==null,并且“统计集合存在但没有LevelB”会保留好友、分数初始化为0。只加两个nullable平铺字段无法同时表达这些原行为。新增这一资料DTO只服务于FriendService一个实际调用点,保留原形状,可复用现有PF结果模型在客户端内部映射;不新增Provider/管理器或运行开关。

4. 缺值、失败和旧客户端兼容

条件 服务端拟合同 客户端原语义
正常有效资料 Profile对象、Statistics含真实LevelB、真实时间 原过滤/降序/名次/事件流程
目标资料实体确认不存在 保留关系项,Profile=null 沿原Profile==null跳过,不由服务端偷偷删除好友关系
统计集合明确不存在 Profile.Statistics=null 沿原Statistics==null跳过
有效KV读取完成但没有LevelB键 Statistics=[] 沿原查找循环保留value=0;这是原逻辑,不新增Level=1或Level×100000兜底
没有LastLoginTimeUtc键 LastLogin=null,好友不因时间缺失被过滤 保留原Nullable值;伙伴邀请原.Value异常风险仍存在,不能声称此账号已通关
有键但LevelB/时间格式损坏,或某好友KV读取失败 本次请求失败;建议HTTP500,外层code=0、friends=null、msg为非敏感错误类别 按原SDK请求失败记错/返回null,不发布伪空列表;不返回部分成功掩盖无法判定的数据
原关系服务的业务失败 保留原失败HTTP/业务码,不改成code=1 客户端成功条件必须code=1;其他结果走原失败映射
认证失效 原401/403认证处理保持 沿原CustomServerMgr会话处理,不改登录流程
旧服务端只返回四字段,没有Profile字段 这表示新合同尚未部署,不能解码成“Profile=null”假装成功 映射前检查字段存在性,记录协议不匹配;不把整张好友表静默清空

新失败响应示例:{"code":0,"msg":"KV_PROFILE_READ_FAILED","friends":null},配HTTP500;格式损坏类别为KV_PROFILE_DATA_INVALID。此为待审设计,不宣称线上已有该错误码。沿原失败语义处理,不增加客户端重试或新的用户业务流程。

旧客户端忽略新增Profile;原四字段类型和friends字符串数组不变。服务端在上线前需验证真实旧调用者能忽略新增字段。不得通过新增客户端多重开关兼容不完整部署,也不复活开发冻结作为产品行为。

5. 数据生成、缓存与时间边界

  • LevelB仍由本人客户端在原SetLvData触发点计算和写本人KV;服务端读取已保存统计,不在好友请求里按当前等级重算。全球/地区统计写合同另与聚合侧对齐。
  • LastLoginTimeUtc已由本人客户端每日初始化后按现有流程保存。本接口只读取、不更新该键;本人的旧时间仍先用于每日刷新。
  • 此阶段遵循用户先存KV的方向;返回语义明确为该键保存的登录时刻,不声称它覆盖所有“认证成功但首场景尚未完成”的登录。这个与PF元数据更新时点的阶段差异须由同一次C3c完整审查明确记录,不擅自改本人写入时点消除差异。
  • 当前101/102缺LevelB和LastLoginTimeUtc,不能把它们当“正常完整资料”验收样例。字段缺失测试可以使用;正常路径须在已审本人写入完成后再联调验证,测试夹具不得冒充正式结果。
  • 新增Profile不以原四字段资料缓存替代KV读取;本次设计不新增缓存层。若服务器复用现有缓存,必须保持与已确认KV写入的可见性一致,并在联调报告给出实际结果,不能仅返回旧缓存的level=1推导LevelB。

6. 客户端接线候选(审核通过后执行)

仅FriendService.cs.GetFriendList的数据获取前段及必要的FriendModel.cs响应DTO:

  1. KV用户调用原FriendRequest("GetFriendsList", 空对象);PF/AGG原SDK分支保持。
  2. 校验外层成功、friends类型及每个Profile字段是否存在,逐项解析原JSON字符串;禁止把不兼容响应当空好友成功。
  3. 映射外层PlayFabId到FriendPlayFabId,Profile各字段到原PlayerProfileModel/Statistics;不调用PF SDK获取缺失值。
  4. 随后沿原FriendService消费段:两项null跳过、自身排除、默认名、统计查找、SetPlayInfo、排序、名次、事件和AGG计数。async void、错误处理和UI消费者不改。

不修改AddFriend/AcceptFriend/DeleteFriend/SearchFriend普通请求,不删除这些业务接口中的目标ID。GetPlayInfo/GetPlayLv完整远端替代仍需对应资料接口合同,本次不以局部缓存修复先行编码。

7. 服务端交付与联合验收

服务端开发负责当前线上仓库的关系查询、内部按好友UserID读取KV、上述公开字段投影、错误响应及部署。客户端Agent只提供设计与后续客户端接线,不修改D:/ft/server/N3-Server或远程服务端代码。

请服务端开发及审核侧一次核对本拟合同,返回实际实现版本及以下脱敏样例:

  1. 两个有效好友、无好友、Profile不存在、Statistics=null、LevelB缺键、时间缺键;旧关系和顺序保留。
  2. LevelB=1200034在原UI解码12/34;不同值按原客户端规则排序,服务端不另分配好友名次。
  3. 字符串LevelB和UTC时间损坏、单项KV超时、关系查询失败、401/403,不返回假空列表或部分成功。
  4. 本人KV写确认后好友查询返回该统计和时间;101/102互查目标身份正确。测试不改变正式等级/奖励,只在已审授权范围使用真实流程或隔离夹具。
  5. 原四字段消费者兼容、迁移后的真实FriendService/伙伴邀请消费者、KV分支SDK计数0、原PF对照。

本方案的待审差异明确为:新增Profile公开DTO、缺值映射、请求级错误映射、时间阶段语义。用户授权设计不等于已审核通过;纳入同一C3c完整评审,不能局部开工。本轮仅文档,无服务端或客户端源码修改、无线上请求。