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
当前实际行为 / 模式说明
当前交易锁定主链如下:
- 客户端发送
CGExchangeSynchLock
- 场景服
char_exchange_synch_lock() 先做 exchange_certify_each_other() 校验
- 根据
lock_my_self 决定本次是锁定还是解锁
- 按双方当前交易盒状态,向一侧或双方发送
GCExchangeSynchLock
- 当双方都锁定后,再发送
GCExchangeSynchConfirmII(is_enable=1) 开启最终确认
- 当任一方解锁后,再发送
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 文本后参与后续提示逻辑。
结论
GCExchangeSynchLock 的封包 ID 是 788,固定长度 5 字节。
- 当前
Game.exe 与当前 Lua 一致确认,包体结构为 display_hhmm:uint16 + is_both:uint8 + is_my_self:uint8 + is_locked:uint8。
- 当前 Lua 主链里,这条包主要用于同步“对方锁定/解锁”以及“双方同时锁定/同时解锁”两类状态。
- 当前客户端仍支持
is_my_self = 1 的单边自侧更新分支,但当前 Lua 主链没有发送证据。
- 当前 Lua 已把明显不准确的字段名同步修正为
display_hhmm 与 is_locked,并通过语法校验。