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

洱海月 v0-07-0300 封包解析:ID 675 GCDoubleExpInfo(双倍经验状态回包)

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

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

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

×

GCDoubleExpInfo 是当前版本双倍经验系统的正式状态回包。当前 Game.exe 与当前 Lua 服务端都能确认,这条包固定长度为 20 字节,结构稳定为 5 个连续的 uint32 字段,用来同步剩余可领取小时数、冻结状态、付费双倍剩余时间、总双倍剩余时间和重置时间戳。

当前 Temp_Release_v0-07-0300 的现役查询链已经明确切到:

  • 客户端请求:CGAskDoubleExp(709)
  • 服务端回包:GCDoubleExpInfo(675)

旧版客户端里虽然还保留 CGCheckDoubleExp(985),但当前 Lua 主链实际不再接那条请求。

包信息

项目 内容
封包 ID 675
包名 GCDoubleExpInfo
方向 GC 服务端 -> 客户端
固定包长 20
当前 Lua 协议定义 /home/ubuntu/Game2/services/game/packet.lua
当前 Lua 主要发送点 /home/ubuntu/Game2/services/scene/obj/human.lua
当前请求入口 /home/ubuntu/Game2/services/msgagent.lua、/home/ubuntu/Game2/services/scene/scenecore.lua
上游请求 CGAskDoubleExp
主要作用 向客户端同步当前角色的双倍经验状态

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

GetPacketID()   = 675;
GetPacketSize() = 20;

包体结构

按当前 Game.exe 与当前 Lua 服务端现状,这条包固定为 20 字节。

偏移 长度 字段 类型 含义
0x00 0x04 available_hour uint32 当前还能领取的双倍经验小时数
0x04 0x04 is_lock uint32 双倍经验是否冻结,0=未冻结,1=冻结
0x08 0x04 money_time uint32 当前剩余的付费双倍经验秒数
0x0C 0x04 total_time uint32 当前总双倍经验剩余秒数,现役 Lua 写法为 money_time + free_time
0x10 0x04 rtime uint32 双倍经验周重置或状态参考时间戳

当前 Lua 协议对象里虽然在 ctor() 中残留了一个 unknow_3 = 0,但它没有参与 bis() / bos() 的读写,也不是实际包体字段。当前线上的真实协议字段就是上面这 5 个 uint32。

当前实际行为 / 模式说明

当前版本的双倍经验查询主链非常直接:

  1. 客户端发送空包 CGAskDoubleExp
  2. msgagent.lua 把请求转给场景服 char_ask_double_exp_info
  3. 场景对象 human:send_double_exp_info() 组装 GCDoubleExpInfo
  4. 客户端收到后更新本地双倍经验状态并触发界面刷新

当前 Lua 的字段写法可以直接说明语义:

  • available_hour 来自 self.double_exp_info.available_hour
  • is_lock 来自 self.double_exp_info.is_lock and 1 or 0
  • money_time 来自 math.floor(self.double_exp_info.money_time)
  • total_time 来自 math.floor(self.double_exp_info.money_time) + math.floor(self.double_exp_info.free_time)
  • rtime 直接沿用 self.double_exp_info.rtime

结合当前 script_base.lua 的辅助接口,可以进一步确认:

  • available_hour 表示当前剩余可提取的周双倍经验小时数
  • money_time 是商城或付费来源的双倍经验剩余时间
  • free_time 是免费双倍经验剩余时间,但它不会单独出现在包体中,而是被合并进 total_time
  • rtime 会在周重置逻辑 DEResetWeeklyFreeTime() 中被写成 os.time()

当前客户端 Execute() 没有再做复杂解析,而是把这 5 个 uint32 整体写入本地双倍经验状态,再触发一次界面更新事件。这也说明当前协议重点是“完整覆盖同步当前双倍经验状态”,不是增量更新某一个字段。

服务端落点

  • 协议定义:
    • /home/ubuntu/Game2/services/game/packet.lua
  • 请求入口:
    • /home/ubuntu/Game2/services/msgagent.lua
  • 场景转发:
    • /home/ubuntu/Game2/services/scene/scenecore.lua
  • 状态发送:
    • /home/ubuntu/Game2/services/scene/obj/human.lua
  • 双倍经验辅助逻辑:
    • /home/ubuntu/Game2/lualib/script_base.lua

当前发送入口非常明确,scenecore:char_ask_double_exp_info() 只做一件事,就是调用角色对象的 send_double_exp_info()。因此这条包在现役版本里没有多级包装或中转变形,协议字段可以直接按 Lua 发送值理解。

关键代码

当前 Lua 协议定义

packet.GCDoubleExpInfo = {
    xy_id = packet.XYID_GC_DOUBLE_EXP_INFO,
    bis = function(self, buffer)
        local stream = bistream.new()
        stream:attach(buffer)
        self.available_hour = stream:readuint()
        self.is_lock = stream:readuint()
        self.money_time = stream:readuint()
        self.total_time = stream:readuint()
        self.rtime = stream:readuint()
    end,
    bos = function(self)
        local stream = bostream.new()
        stream:writeuint(self.available_hour)
        stream:writeuint(self.is_lock)
        stream:writeuint(self.money_time)
        stream:writeuint(self.total_time)
        stream:writeuint(self.rtime)
        return stream:get()
    end
}

当前 Lua 发送链

function scenecore:char_ask_double_exp_info(who)
    local obj = self.objs[who]
    obj:send_double_exp_info()
end
function human:send_double_exp_info()
    local msg = packet_def.GCDoubleExpInfo.new()
    msg.available_hour = self.double_exp_info.available_hour
    msg.is_lock = self.double_exp_info.is_lock and 1 or 0
    msg.money_time = math.floor(self.double_exp_info.money_time)
    msg.total_time = math.floor(self.double_exp_info.money_time) + math.floor(self.double_exp_info.free_time)
    msg.rtime = self.double_exp_info.rtime
    self:get_scene():send2client(self, msg)
end

当前 Game.exe 的读写结论

Read(stream) {
    read_u32(available_hour);
    read_u32(is_lock);
    read_u32(money_time);
    read_u32(total_time);
    read_u32(rtime);
    return 1;
}

Write(stream) {
    write_u32(available_hour);
    write_u32(is_lock);
    write_u32(money_time);
    write_u32(total_time);
    write_u32(rtime);
    return 1;
}

当前 Game.exe 的执行结论

Execute(packet) {
    ClientDoubleExp.available_hour = packet.available_hour;
    ClientDoubleExp.is_lock        = packet.is_lock;
    ClientDoubleExp.money_time     = packet.money_time;
    ClientDoubleExp.total_time     = packet.total_time;
    ClientDoubleExp.rtime          = packet.rtime;
    NotifyUiEvent(368);
    return 2;
}

这里的状态名是按当前 Execute() 实际行为做的语义化整理:客户端确实会把包内这 5 个值按顺序写入本地状态,再触发一次双倍经验界面刷新事件。

结论

  1. GCDoubleExpInfo 的封包 ID 是 675,固定长度 20 字节。
  2. 当前 Game.exe 与当前 Lua 一致确认,包体就是 5 个连续的 uint32 字段。
  3. 当前字段名可以直接确定为 available_hour、is_lock、money_time、total_time、rtime,不需要再保留 unknow_x。
  4. 当前现役查询链是 CGAskDoubleExp -> GCDoubleExpInfo,而不是旧的 CGCheckDoubleExp。
  5. total_time 在当前 Lua 里等于 money_time + free_time,因此它代表客户端展示使用的总双倍经验剩余时间。
您需要登录后才可以回帖 登录 | registerss

本版积分规则

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

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

Powered by Discuz! X5.0

© 2001-2026 Discuz! Team.

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