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

洱海月 v0-07-0300 封包解析:ID 386 CGAskMail(邮件查询请求)

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

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

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

×

CGAskMail 是旧版客户端用于查询邮件状态与拉取邮件内容的请求包。当前 Temp_Release_v0-07-0300 的 Lua 服务端已经真实接入这条协议,请求入口位于 /home/ubuntu/Game2/services/msgagent.lua 的 request:CGAskMail();包体虽然只有 1 个字节,但 m_askType 会直接决定这是“登录检查邮件数量”还是“拉取邮件正文”。

当前实现里,CGAskMail 不是空包,而是一个明确的 uint8 请求。

包信息

项目 内容
封包 ID 386
包名 CGAskMail
方向 CG 客户端 -> 游戏服
固定包长 1
请求字段 m_askType:uint8
直接回包 GCNotifyMail / GCMail
回包 ID 633 / 273
回包包长 1 / 动态
当前 Lua 协议定义 /home/ubuntu/Game2/services/game/packet.lua
当前 Lua 请求入口 /home/ubuntu/Game2/services/msgagent.lua
当前邮件枚举定义 /home/ubuntu/Game2/lualib/define.lua
主要作用 登录时同步邮件数量,或主动拉取邮件正文

当前 Game.exe 的虚函数结论为:

CGAskMail
GetPacketID()   = 386;
GetPacketSize() = 1;
Read            = 1 byte at (this + 24);   // m_askType
Write           = 1 byte at (this + 24);   // m_askType
Execute thunk   = 0x1405C7E80 -> sub_140328980;

GCNotifyMail
GetPacketID()   = 633;
GetPacketSize() = 1;

GCMail
GetPacketID()   = 273;
GetPacketSize() = dynamic;

包体结构

CGAskMail 是固定 1 字节请求包。

偏移 长度 字段 类型 含义
0x00 0x01 m_askType uint8 邮件查询模式;0 表示登录检查邮件数量,1 表示请求邮件正文

当前枚举定义如下:

define.ASK_TYPE =
{
    ASK_TYPE_LOGIN = 0,
    ASK_TYPE_MAIL = 1,
}

当前实际行为 / 模式说明

  • m_askType = 0 对应 ASK_TYPE_LOGIN:
    • 服务端调用 get_db_mail_list() 统计当前角色可见邮件数。
    • 返回 GCNotifyMail,只同步 m_MailCount,不下发正文。
    • 客户端侧 InfoBrowser.lua、MainMenuBar.lua 会通过 DataPool:GetMailNumber() 驱动邮件提示与界面刷新。
  • m_askType = 1 对应 ASK_TYPE_MAIL:
    • 服务端构造 GCMail。
    • 当前 Lua 主链每次只把 mail_list[1] 放进回包。
    • 发送前会立即执行 delete_mail(mail_list[1]),把这封邮件从角色数据库记录里删除。
    • count 当前只会是 0 或 1。
    • leave_count 表示本次未下发、仍留在列表中的剩余邮件数。
  • get_db_mail_list() 会先过滤脚本邮件:
    • MAIL_TYPE_SCRIPT = 2 的邮件不会原样发给客户端。
    • 当前实现会先调用 execute_script_mail(mail),并同步删除该邮件。
    • 真正进入 GCNotifyMail / GCMail 的,是普通邮件、系统邮件等可展示邮件。
  • 当前 Game.exe 的 GCMail::Execute 还能确认一个显示行为:
    • 当邮件 flag == 1,客户端会按系统邮件处理,发件人显示会替换成 SYSTEM_MAIL。

关联回包结构

GCNotifyMail

GCNotifyMail 是固定 1 字节回包,只用于同步当前邮件数量。

偏移 长度 字段 类型 含义
0x00 0x01 m_MailCount uint8 当前可见邮件数量

GCMail

GCMail 是变长回包。协议层最多可写 0x14 封邮件,但当前 Lua 主链每次只下发 0 或 1 封。

GCMail 包头与尾部

偏移 长度 字段 类型 含义
0x00 0x01 count uint8 本次实际下发的邮件数量;当前实现只会是 0 或 1
变长尾部 0x01 leave_count uint8 本次未下发、仍剩余的邮件数量

单封邮件结构

以下偏移以“单封邮件条目起始位置”为基准;由于 source、dest、content 都是变长字符串,后续字段偏移随长度动态变化。

偏移 长度 字段 类型 含义
+0x00 0x04 guid int32 邮件标识
+0x04 0x01 source_len uint8 发件人字符串长度
+0x05 source_len source char[n] 发件人显示名
+0x05 + source_len 0x04 portrait_id int32 发件人头像 ID
+0x09 + source_len 0x04 related_guid int32 当前 Lua 写包时与前一个 guid 相同;现阶段可视为重复写出的邮件关联标识,语义不宜过度定死
+0x0D + source_len 0x01 dest_len uint8 收件人字符串长度
+0x0E + source_len dest_len dest char[n] 收件人显示名
+0x0E + source_len + dest_len 0x02 content_len uint16 正文长度
+0x10 + source_len + dest_len content_len content char[n] 邮件正文
+0x10 + source_len + dest_len + content_len 0x04 flag uint32 邮件类型 / 标志
+0x14 + source_len + dest_len + content_len 0x04 create_time uint32 创建时间
条件追加 0x14 param_1 ~ param_5 int32[5] 仅在 flag == 2 时额外写出

当前邮件类型定义如下:

define.MAIL_TYPE =
{
    MAIL_TYPE_NORMAL  = 0,
    MAIL_TYPE_SYSTEM  = 1,
    MAIL_TYPE_SCRIPT  = 2,
    MAIL_TYPE_NORMAL2 = 3,
}

需要注意的是,GCMail 写包层虽然保留了 flag == 2 时附带 param_1 ~ param_5 的分支,但当前 get_db_mail_list() 会先执行并删除脚本邮件,因此当前主链通常不会把这段脚本邮件结构真正发给客户端。

服务端落点

这条包在当前项目中的关键位置如下:

  • 协议定义:
    • /home/ubuntu/Game2/services/game/packet.lua
  • 请求入口 / 邮件主逻辑:
    • /home/ubuntu/Game2/services/msgagent.lua
  • 邮件与请求类型枚举:
    • /home/ubuntu/Game2/lualib/define.lua
  • 客户端邮件数量提示界面:
    • 客户端/Interface/InfoBrowser/InfoBrowser.lua
    • 客户端/Interface/MainMenuBar/MainMenuBar.lua

关键代码

当前 Lua 协议定义

packet.CGAskMail = {
    xy_id = packet.XYID_CG_ASK_MAIL,
    new = function(o)
        o = o or {}
        setmetatable(o, {__index = packet.CGAskMail})
        o:ctor()
        return o
    end,
    ctor = function(self) self.m_askType = 0 end,
    bis = function(self, buffer)
        local stream = bistream.new()
        stream:attach(buffer)
        self.m_askType = stream:readuchar()
    end
}

当前 Lua 请求处理

function request:CGAskMail()
    local mail_list = get_db_mail_list()
    if self.m_askType == define.ASK_TYPE.ASK_TYPE_LOGIN then
        local msg = packet_def.GCNotifyMail.new()
        msg.m_MailCount = #mail_list
        Net:send(msg)
    else
        local msg = packet_def.GCMail.new()
        if #mail_list > 0 then
            table.insert(msg.mails, mail_list[1])
            delete_mail(mail_list[1])
            msg.count = 1
        else
            msg.count = 0
        end
        msg.leave_count = #mail_list - #msg.mails
        Net:send(msg)
    end
end

当前 Lua 邮件来源过滤

local function get_db_mail_list()
    local response = skynet.call(".char_db", "lua", "findOne", ...)
    local mail_list = response.mail_list or {}
    local common_mail_list = {}
    for i = #mail_list, 1, -1 do
        local mail = mail_list[i]
        if mail.flag == define.MAIL_TYPE.MAIL_TYPE_SCRIPT then
            execute_script_mail(mail)
        else
            table.insert(common_mail_list, mail)
        end
    end
    return common_mail_list
end

当前 Game.exe 读写结论

CGAskMail 在当前客户端里的结构非常直接:

Read :
    read(this + 24, 1);   // m_askType

Write:
    write(this + 24, 1);  // m_askType

GetPacketSize() = 1;

GCMail 的当前 Lua 写包顺序则可以概括为:

writeuchar(count);
repeat each mail:
    writeint(guid);
    writeuchar(source_len);
    write(source, source_len);
    writeint(portrait_id);
    writeint(related_guid);
    writeuchar(dest_len);
    write(dest, dest_len);
    writeushort(content_len);
    write(content, content_len);
    writeuint(flag);
    writeuint(create_time);
    if (flag == 2) write 5 * int32 params;
writeuchar(leave_count);

结论

CGAskMail 在 Temp_Release_v0-07-0300 里已经可以明确收敛为一个“邮件查询模式请求包”:

  • 它不是空包,而是固定 1 字节 m_askType。
  • ASK_TYPE_LOGIN = 0 时,只回 GCNotifyMail 同步邮件数量。
  • ASK_TYPE_MAIL = 1 时,回 GCMail 拉取邮件正文。
  • 当前 Lua 主链每次只下发 1 封普通/系统邮件,并在发送前立即删除该邮件记录。
  • leave_count 用于表示尚未继续下发的剩余邮件数量。

因此,这条协议的核心重点不在复杂包体,而在 m_askType 控制出的两种工作模式,以及当前 Lua 邮件队列“单封取出、立即删除、剩余数量继续轮询”的实际行为。

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

本版积分规则

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

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

Powered by Discuz! X5.0

© 2001-2026 Discuz! Team.

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