保存独立KV用户服务、固定会话存档与原业务接线,以及C3d资料缓存和C3e本人统计写。 保留原PF/AGG路线、业务公式和时序;榜单读取、好友资料、公告、匹配及首场景闸仍待完成。 验证:ServiceHost两条件各33组646断言;Unity CLI Loop编译0错误269警告。 包含相关方案、评审裁决、测试及状态文档。未操作服务器、正式账号或打包。
10 KiB
好友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:
- KV用户调用原FriendRequest("GetFriendsList", 空对象);PF/AGG原SDK分支保持。
- 校验外层成功、friends类型及每个Profile字段是否存在,逐项解析原JSON字符串;禁止把不兼容响应当空好友成功。
- 映射外层PlayFabId到FriendPlayFabId,Profile各字段到原PlayerProfileModel/Statistics;不调用PF SDK获取缺失值。
- 随后沿原FriendService消费段:两项null跳过、自身排除、默认名、统计查找、SetPlayInfo、排序、名次、事件和AGG计数。async void、错误处理和UI消费者不改。
不修改AddFriend/AcceptFriend/DeleteFriend/SearchFriend普通请求,不删除这些业务接口中的目标ID。GetPlayInfo/GetPlayLv完整远端替代仍需对应资料接口合同,本次不以局部缓存修复先行编码。
7. 服务端交付与联合验收
服务端开发负责当前线上仓库的关系查询、内部按好友UserID读取KV、上述公开字段投影、错误响应及部署。客户端Agent只提供设计与后续客户端接线,不修改D:/ft/server/N3-Server或远程服务端代码。
请服务端开发及审核侧一次核对本拟合同,返回实际实现版本及以下脱敏样例:
- 两个有效好友、无好友、Profile不存在、Statistics=null、LevelB缺键、时间缺键;旧关系和顺序保留。
- LevelB=1200034在原UI解码12/34;不同值按原客户端规则排序,服务端不另分配好友名次。
- 字符串LevelB和UTC时间损坏、单项KV超时、关系查询失败、401/403,不返回假空列表或部分成功。
- 本人KV写确认后好友查询返回该统计和时间;101/102互查目标身份正确。测试不改变正式等级/奖励,只在已审授权范围使用真实流程或隔离夹具。
- 原四字段消费者兼容、迁移后的真实FriendService/伙伴邀请消费者、KV分支SDK计数0、原PF对照。
本方案的待审差异明确为:新增Profile公开DTO、缺值映射、请求级错误映射、时间阶段语义。用户授权设计不等于已审核通过;纳入同一C3c完整评审,不能局部开工。本轮仅文档,无服务端或客户端源码修改、无线上请求。