找回密码
 registerss
搜索
查看: 23|回复: 0

洱海月 v0-07-0300 封包解析:ID 9032 WGCRetNormalRankList(普通排行榜返回)

[复制链接]
  • 打卡等级:本地老炮
  • 打卡总天数:603
  • 打卡月天数:1
  • 打卡总奖励:600
  • 最近打卡:2026-10-03 06:32:28
Waylee 发表于 2026-4-14 13:38 | 显示全部楼层 |阅读模式 | Google Chrome | Windows 10

马上注册,查看网站隐藏内容!!

您需要 登录 才可以下载或查看,没有账号?registerss

×

WGCRetNormalRankList 是普通排行榜界面的返回包,用于把多个榜单页签、每个榜单的玩家排行数据,以及榜单尾部的领奖状态一起下发给客户端。

包信息

项目 内容
封包 ID 9032
包名 WGCRetNormalRankList
方向 服务端 -> 客户端
对应请求 CGWNormalRankingList (9031)
包体长度 变长
当前作用 返回普通排行榜页签、每个榜单的玩家列表,以及榜单奖励状态

包体结构

包头固定为 23 字节,之后跟随 rank_list_count 个榜单块。Game.exe 的 GetPacketSize() 计算公式为:

23 + Σ(16 + 48 * player_count[i])

其中:

  • 23 是总包头长度。
  • 每个榜单块固定头为 10 字节。
  • 每个玩家条目固定 48 字节。
  • 每个榜单块尾部还有 6 字节奖励状态结构。

总包头结构如下:

偏移 长度 字段 类型 含义
0x00 0x04 rank_list_count uint32 本次返回的榜单数量
0x04 0x04 reserved_u32_1 uint32 客户端会读取,当前 Lua 测试值写死为 11,含义未定
0x08 0x02 reserved_u16_1 uint16 客户端会读取,当前 Lua 测试值写死为 22,含义未定
0x0A 0x04 reserved_u32_2 uint32 客户端会读取,当前 Lua 测试值写死为 33,含义未定
0x0E 0x01 ui_message_type int8 Lua 注释指向 LevelupMessageType,疑似领奖提示或消息类型
0x0F 0x04 cur_rank_type int32 当前选中的榜单类型
0x13 变长 rank_entries rank_entry[rank_list_count] 榜单块数组

单个榜单块的结构如下:

偏移 长度 字段 类型 含义
0x00 0x04 rank_type uint32 榜单类型
0x04 0x01 reserved_flag_1 int8 榜单 UI 控制位,当前 Lua 测试值写 9
0x05 0x01 reserved_flag_2 int8 榜单 UI 控制位,当前 Lua 测试值写 8
0x06 0x04 player_count int32 当前榜单内的玩家数量
0x0A 48 * player_count players rank_player[player_count] 上榜玩家数组
0x0A + 48 * player_count 0x06 reward_info rank_reward_info 榜单尾部奖励状态

单个玩家条目的结构如下:

偏移 长度 字段 类型 含义
0x00 0x04 rank uint32 当前名次
0x04 0x04 rank_time uint32 上榜或结算时间戳,当前 Lua 测试值写 2505112359
0x08 0x04 rank_value uint32 排行值或展示分数,当前 Lua 测试值写 100 + j
0x0C 0x01 reserved_player_flag int8 玩家行 UI 控制位,当前 Lua 测试值写 1
0x0D 0x04 player_guid uint32 玩家 GUID
0x11 0x01 school_id int8 门派/职业 ID
0x12 0x1E player_name char[30] 玩家名,客户端按定长 30 字节读取

榜单尾部奖励状态结构如下:

偏移 长度 字段 类型 含义
0x00 0x01 reward_state int8 Lua 注释对应 nreward
0x01 0x01 reward_insert_flag int8 Lua 注释对应 nInsert
0x02 0x04 reward_index int32 Lua 注释对应 nIndex

当前实际行为

  • 客户端侧 Game.exe 已明确把这条包实现为“变长榜单列表包”,不是固定长度包。
  • 当前服务端请求入口是 request:CGRankingLists(),它只把玩家对象转发给场景服,不读取 CGWNormalRankingList(9031) 的请求体内容。
  • 当前场景服 scenecore:char_ranking_lists() 只是 new() 一个 WGCRetNormalRankList 对象后直接发送,没有查询 .ranking 服务,也没有拼接真实排行榜。
  • 当前实际返回内容全部写死在 /home/ubuntu/Game2/services/game/packet.lua 的 packet.WGCRetNormalRankList.bos() 中:固定返回 4 个榜单,每个榜单固定 10 个玩家,rank_type 直接写成 1..4。
  • 这段 Lua bos() 明显带有调试痕迹,注释里多次写了“需要调试看 UI 表现”“疑似预留数据”。
  • 更关键的是,当前 Lua 拼包并未完全对齐 Game.exe 的正式读取格式:
    • 玩家名当前按 string.len(name) 写出,而客户端固定按 30 字节读取。
    • 榜单尾部奖励状态当前只写了 3 个 char,而客户端固定按 1 + 1 + 4 共 6 字节读取。
  • 因此,当前服务端实现更像普通排行榜 UI 的临时测试桩,不是已经完全打通的正式排行榜协议。

服务端落点

  • /home/ubuntu/Game2/services/msgagent.lua
    request:CGRankingLists() 收到排行榜请求后,直接调用场景服的 char_ranking_lists。
  • /home/ubuntu/Game2/services/scene/scenecore.lua
    scenecore:char_ranking_lists(selfId) 仅创建 WGCRetNormalRankList 并发送给客户端。
  • /home/ubuntu/Game2/services/game/packet.lua
    packet.WGCRetNormalRankList.bos() 负责真正序列化整包,当前内容全部为硬编码测试值。
  • /home/ubuntu/Game2/lualib/iostream.lua
    bostream:write(data, len) 会严格写入固定长度字节,因此当前玩家名长度和奖励尾结构的写法是否匹配客户端格式,完全取决于 bos() 传入的长度。

关键代码

当前服务端发送链路很短:

function request:CGRankingLists()
    skynet.call(my_scene, "lua", "char_ranking_lists", my_obj_id, self)
end

function scenecore:char_ranking_lists(selfId)
    local ret = packet_def.WGCRetNormalRankList.new()
    self:send2client(selfId, ret)
end

当前 Lua 里真正下发的排行榜内容全部来自 bos() 的硬编码测试数据:

local nCurCount = 4
stream:writeuint(nCurCount)
stream:writeuint(11)
stream:writeshort(22)
stream:writeuint(33)
stream:writechar(1)
stream:writeint(1)
stream:writeuint(44)

for i = 1, nCurCount do
    stream:writeuint(i)
    stream:writechar(9)
    stream:writechar(8)
    stream:writeint(10)
    ...
end

Game.exe 中 WGCRetNormalRankList 的读取逻辑可还原为:

read_u32(rank_list_count);
read_u32(reserved_u32_1);
read_u16(reserved_u16_1);
read_u32(reserved_u32_2);
read_i8(ui_message_type);
read_u32(cur_rank_type);
read_u32(reserved_u32_3);

for (i = 0; i < rank_list_count; ++i) {
    read_u32(rank_type);
    read_i8(reserved_flag_1);
    read_i8(reserved_flag_2);
    read_i32(player_count);

    for (j = 0; j < player_count; ++j) {
        read_u32(rank);
        read_u32(rank_time);
        read_u32(rank_value);
        read_i8(reserved_player_flag);
        read_u32(player_guid);
        read_i8(school_id);
        read_fixed_string(player_name, 30);
    }

    read_i8(reward_state);
    read_i8(reward_insert_flag);
    read_i32(reward_index);
}

GetPacketID()   = 9032;
GetPacketSize() = 23 + Σ(16 + 48 * player_count[i]);

客户端对子结构的长度要求也很明确:

rank_entry_size    = 10 + 48 * player_count;
reward_info_size   = 6;
player_name_length = 30;

结论

WGCRetNormalRankList(9032) 在当前版本里是“普通排行榜界面的返回包”,正式协议形态已经能从 Game.exe 明确还原为变长结构。

但当前服务端实现并不是正式排行榜数据链路,而是一个明显的测试桩:

  1. 请求侧没有消费 9031 的真实请求参数。
  2. 场景服没有查询 .ranking,只发送一个空对象。
  3. 所有榜单内容都在 packet.lua 里硬编码。
  4. Lua 现有 bos() 还没有完全按客户端正式格式写满玩家名和奖励尾字段。

如果后续要把这条协议改成可正式使用的排行榜回包,优先应以 Game.exe 当前的变长读包格式为准,而不是继续沿用现在这份临时测试写法。

您需要登录后才可以回帖 登录 | registerss

本版积分规则

QQ|手机版|雪舞知识库 ( 浙ICP备15015590号-1 | 萌ICP备20232229号|浙公网安备33048102000118号 )|天天打卡

GMT+8, 2026-10-4 11:26 , Processed in 0.065227 second(s), 26 queries .

Powered by Discuz! X5.0

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表