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

洱海月 v0-07-0300 封包解析:ID 788 GCExchangeSynchLock(交易锁定状态同步)

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

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

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

×

GCExchangeSynchLock 是当前交易流程里用于同步“锁定/解锁状态”的回包。当前 Game.exe 与当前 Lua 服务端都能确认,这条包固定长度为 5 字节,结构是 1 个 uint16 + 3 个 uint8,用于刷新交易界面上的锁定状态,并在需要时配合 GCExchangeSynchConfirmII 开启或关闭最终确认按钮。

当前版本里,这条包不是独立业务包,而是 CGExchangeSynchLock 请求成功后的状态同步回包。它负责告诉客户端:

  • 本次更新是否同时作用于双方锁定状态
  • 当前更新的是哪一侧锁定标记
  • 最终锁定结果是上锁还是解锁

包信息

项目 内容
封包 ID 788
包名 GCExchangeSynchLock
方向 GC 服务端 -> 客户端
固定包长 5
当前 Lua 协议定义 /home/ubuntu/Game2/services/game/packet.lua
当前 Lua 主要发送点 /home/ubuntu/Game2/services/scene/scenecore.lua
上游请求 CGExchangeSynchLock
配套回包 GCExchangeSynchConfirmII
主要作用 同步交易锁定状态,并驱动客户端刷新锁定标记与确认阶段状态

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

GetPacketID()   = 788;
GetPacketSize() = 5;

包体结构

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

偏移 长度 字段 类型 含义
0x00 0x02 display_hhmm uint16 客户端会按 HH:MM 形式格式化显示的时分字段;当前 Lua 主链未赋值,默认写 0
0x02 0x01 is_both uint8 是否同时更新双方锁定状态,1=同时更新两侧
0x03 0x01 is_my_self uint8 当 is_both=0 时,表示当前更新落在哪一侧;客户端仍保留 1 分支,但当前 Lua 主链未使用
0x04 0x01 is_locked uint8 本次同步后的锁定状态,1=锁定,0=解锁

这 4 个字段里,有两个名字已经在当前 Lua 中做了同步修正:

  • unknow 已按当前 Game.exe 的 HH:MM 格式化行为修正为 display_hhmm
  • is_lockd 已修正为 is_locked

当前实际行为 / 模式说明

当前交易锁定主链如下:

  1. 客户端发送 CGExchangeSynchLock
  2. 场景服 char_exchange_synch_lock() 先做 exchange_certify_each_other() 校验
  3. 根据 lock_my_self 决定本次是锁定还是解锁
  4. 按双方当前交易盒状态,向一侧或双方发送 GCExchangeSynchLock
  5. 当双方都锁定后,再发送 GCExchangeSynchConfirmII(is_enable=1) 开启最终确认
  6. 当任一方解锁后,再发送 GCExchangeSynchConfirmII(is_enable=0) 关闭最终确认

当前 Lua 主链已确认的发送模式只有以下几种:

对方单边锁定

is_both   = 0
is_my_self = 0
is_locked = 1

这表示当前接收者需要把“对方那一侧”的锁定标记切成锁定。

双方同时进入锁定完成状态

is_both   = 1
is_my_self = 0
is_locked = 1

这表示客户端需要把双方锁定标记都切成锁定。紧接着服务端还会下发 GCExchangeSynchConfirmII(is_enable=1),允许进入最终确认阶段。

对方解锁,导致双方锁定关系解除

is_both   = 1
is_my_self = 0
is_locked = 0

这表示客户端需要把双方锁定标记都恢复为未锁定。

对方单边解锁同步

is_both   = 0
is_my_self = 0
is_locked = 0

这表示当前接收者只需要把“对方那一侧”的锁定标记恢复为未锁定。

还有一个当前版本必须单独说明的现状:

  • 当前 Game.exe 的 handler 明确支持 is_my_self = 1 分支,也就是“当 is_both = 0 时只更新自己这一侧的锁定标记”
  • 但当前 Lua 主链没有发送这个分支,现役发送值全部都是 is_my_self = 0

因此,客户端实现比当前 Lua 使用范围更宽,但不能直接把 is_my_self = 1 当成当前服务端一定会发的现役状态。

另一个容易忽略的字段是 display_hhmm:

  • 当前 Game.exe 会把它按 "%0.2d:%0.2d" 格式化
  • 当前 Lua 主链没有为它赋值,所以线上通常写出的是默认 0
  • 也就是客户端最终拿到的显示文本通常是 00:00

服务端落点

  • 协议定义:
    • /home/ubuntu/Game2/services/game/packet.lua
  • 请求入口:
    • /home/ubuntu/Game2/services/msgagent.lua
  • 交易锁定处理:
    • /home/ubuntu/Game2/services/scene/scenecore.lua

当前真正发送 GCExchangeSynchLock 的逻辑全部集中在 scenecore:char_exchange_synch_lock(),并且与交易盒状态切换、can_conform 开关以及 GCExchangeSynchConfirmII 紧密绑定。

关键代码

当前 Lua 协议定义

packet.GCExchangeSynchLock = {
    xy_id = packet.XYID_GC_EXCHANGE_SYNCH_LOCK,
    bis = function(self, buffer)
        local stream = bistream.new()
        stream:attach(buffer)
        self.display_hhmm = stream:readushort()
        self.is_both = stream:readuchar()
        self.is_my_self = stream:readuchar()
        self.is_locked = stream:readuchar()
    end,
    bos = function(self)
        local stream = bostream.new()
        stream:writeushort(self.display_hhmm or 0)
        stream:writeuchar(self.is_both)
        stream:writeuchar(self.is_my_self)
        stream:writeuchar(self.is_locked)
        return stream:get()
    end
}

当前 Lua 发送链

if es.lock_my_self == 1 then
    my_exchange_box:lock()
    if tar_exchange_box:get_is_lock() then
        my_exchange_box:set_can_conform(true)
        tar_exchange_box:set_can_conform(true)

        my_exchange_box:set_status(my_exchange_box.STATUS.EXCHANGE_WAIT_FOR_CONFIRM)
        tar_exchange_box:set_status(tar_exchange_box.STATUS.EXCHANGE_WAIT_FOR_CONFIRM)

        local msg = packet_def.GCExchangeSynchLock.new()
        msg.is_both = 1
        msg.is_my_self = 0
        msg.is_locked = 1
        self:send2client(obj_tar, msg)
        ...
    else
        local msg = packet_def.GCExchangeSynchLock.new()
        msg.is_both = 0
        msg.is_my_self = 0
        msg.is_locked = 1
        self:send2client(obj_tar, msg)
    end
end
if tar_exchange_box:get_is_lock() then
    tar_exchange_box:unlock()

    local msg = packet_def.GCExchangeSynchLock.new()
    msg.is_both = 1
    msg.is_my_self = 0
    msg.is_locked = 0
    self:send2client(obj_tar, msg)

    msg = packet_def.GCExchangeSynchLock.new()
    msg.is_both = 0
    msg.is_my_self = 0
    msg.is_locked = 0
    self:send2client(obj_me, msg)
end

当前 Game.exe 的读写结论

Read(stream) {
    read_u16(display_hhmm);
    read_u8(is_both);
    read_u8(is_my_self);
    read_u8(is_locked);
    return 1;
}

Write(stream) {
    write_u16(display_hhmm);
    write_u8(is_both);
    write_u8(is_my_self);
    write_u8(is_locked);
    return 1;
}

当前 Game.exe 的执行结论

Execute(packet) {
    if (is_both) {
        SetSelfLockFlag(is_locked);
        SetPeerLockFlag(is_locked);
    } else if (is_my_self) {
        SetSelfLockFlag(is_locked);
    } else {
        SetPeerLockFlag(is_locked);
    }

    NotifyUiEvent(162);
    FormatTime("%0.2d:%0.2d", display_hhmm);
    MaybeShowExchangeTip(display_hhmm);
    return 2;
}

这里的 SetSelfLockFlag、SetPeerLockFlag、MaybeShowExchangeTip 是按当前 Execute() 实际行为做的语义化整理:客户端确实会根据 is_both / is_my_self / is_locked 来更新两侧锁定标记,并把前 2 字节格式化成 HH:MM 文本后参与后续提示逻辑。

结论

  1. GCExchangeSynchLock 的封包 ID 是 788,固定长度 5 字节。
  2. 当前 Game.exe 与当前 Lua 一致确认,包体结构为 display_hhmm:uint16 + is_both:uint8 + is_my_self:uint8 + is_locked:uint8。
  3. 当前 Lua 主链里,这条包主要用于同步“对方锁定/解锁”以及“双方同时锁定/同时解锁”两类状态。
  4. 当前客户端仍支持 is_my_self = 1 的单边自侧更新分支,但当前 Lua 主链没有发送证据。
  5. 当前 Lua 已把明显不准确的字段名同步修正为 display_hhmm 与 is_locked,并通过语法校验。
您需要登录后才可以回帖 登录 | registerss

本版积分规则

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

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

Powered by Discuz! X5.0

© 2001-2026 Discuz! Team.

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