GCStallBuy 是摆摊购买成功后的结果通知包。当前 Game.exe 与当前 Lua 服务端都能确认,这条包固定长度 35 字节,成功成交后会同时发给买家和摊主,用来同步成交对象、目标槽位、摊位序列号、摊位币种、成交价与税后实收金额。失败分支不会发送这条包,而是改走 GCStallError。
包信息
| 项目 |
内容 |
| 封包 ID |
799 |
| 包名 |
GCStallBuy |
| 方向 |
Server -> Client |
| 对应请求 |
CGStallBuy |
| 对应请求 ID |
792 |
| 包长模式 |
固定长度 |
| 包长 |
35 |
| 作用 |
通知摆摊购买成功,并同步买家或摊主界面的成交结果 |
包体结构
| 偏移 |
长度 |
字段 |
类型 |
含义 |
0x00 |
0x04 |
stall_obj_id |
int32 |
摊主角色 obj_id,客户端据此区分“我买了别人摊位”还是“我的摊位被买走” |
0x04 |
0x08 |
item_guid |
bytes[8] |
道具 GUID;购买道具时有效,内部结构为 world(1) + server(1) + mask(2) + series(4) |
0x0C |
0x08 |
pet_guid |
bytes[8] |
珍兽 GUID;购买珍兽时有效 |
0x14 |
0x04 |
serial |
uint32 |
摊位该槽位成交后的最新序列号,用于客户端刷新缓存一致性 |
0x18 |
0x01 |
to_index |
uint8 |
成交后在目标容器中的落点槽位 |
0x19 |
0x01 |
to_type |
uint8 |
目标容器类型;当前现役值仅见 1=背包道具、3=珍兽栏 |
0x1A |
0x01 |
is_yuanbao_stall |
uint8 |
是否为元宝摊位,0=金币摊位,1=元宝摊位 |
0x1B |
0x04 |
cost |
uint32 |
买家本次成交实际支付金额 |
0x1F |
0x04 |
profit |
uint32 |
摊主本次成交税后实收金额 |
当前实际行为
- 当前
Game.exe 的 GetPacketID() 固定返回 799。
- 当前
Game.exe 的 GetPacketSize() 固定返回 35。
- 当前
Game.exe 的 Read() / Write() 顺序与当前 Lua packet.GCStallBuy 一致,字段顺序固定为:
stall_obj_id
item_guid
pet_guid
serial
to_index
to_type
is_yuanbao_stall
cost
profit
- 当前
msgagent 仅在普通场景 scene_type == 0 时转入 /home/ubuntu/Game2/services/scene/scenecore.lua 的 char_stall_buy()。
- 当前 Lua 只在成交成功时构造
GCStallBuy;库存变化、背包空间不足、金额不足、摊位副本过期等失败分支都改发 GCStallError。
- 当前 Lua 的成交成功分支会把同一份
GCStallBuy 同时发给买家和摊主:
- 买道具成功时写
to_type = 1
- 买珍兽成功时写
to_type = 3
cost = need_money
profit = floor(need_money * (1 - trade_tax / 100))
is_yuanbao_stall = stall_box:get_is_yuanbao_stall() and 1 or 0
- 当前
Game.exe 的 Execute() 明确只处理 to_type == 1 或 to_type == 3,并且 is_yuanbao_stall 只接受 0/1 两种值;其他值不会进入现役更新分支。
- 当
stall_obj_id 等于客户端当前打开的他人摊位 obj_id 时,客户端把这条包视为“我购买别人摊位成功”:
to_type == 1 时把摊位中的道具移动到自己背包 to_index
to_type == 3 时把摊位中的珍兽移动到自己珍兽栏 to_index
- 同时清空对方摊位对应格、价格和旧序列号
- 当
stall_obj_id 等于自己角色的 ServerID 时,客户端把这条包视为“我的摊位物品被别人买走”:
to_type == 1 时从自己的摊位和背包里移除已售道具
to_type == 3 时从自己的摊位和珍兽列表里移除已售珍兽
- 同样会刷新摊位槽位价格与最新序列号
cost 与 profit 在当前客户端主要用于成交提示文案,实际扣钱和加钱动作已经在服务端完成。
老源码可作为参考:旧工程残留 Common/Packets/GCStallBuy.h/.cpp 里只有 stall_obj_id / item_guid / pet_guid / serial / to_index / to_type 六段字段,总长 26 字节。当前 Game.exe 已明确扩展出 is_yuanbao_stall / cost / profit 三段尾部字段,因此旧头文件不能直接视为当前版本最终结构。
服务端落点
- 协议定义:
/home/ubuntu/Game2/services/game/packet.lua
- 请求入口:
/home/ubuntu/Game2/services/msgagent.lua
- 主场景处理:
/home/ubuntu/Game2/services/scene/scenecore.lua
- 热更副本:
/home/ubuntu/Game2/services/scripts/scene.lua
关键代码
当前 Lua 协议定义
packet.GCStallBuy = {
xy_id = packet.XYID_GC_STALL_BUY,
bis = function(self, buffer)
local stream = bistream.new()
stream:attach(buffer)
self.m_objID = stream:readint()
self.item_guid = packet.ItemGUID.new()
self.item_guid:bis(stream)
self.pet_guid = packet.PetGUID.new()
self.pet_guid:bis(stream)
self.serial = stream:readuint()
self.to_index = stream:readuchar()
self.to_type = stream:readuchar()
self.is_yuanbao_stall = stream:readuchar()
self.cost = stream:readuint()
self.profit = stream:readuint()
end,
bos = function(self)
local stream = bostream.new()
stream:writeint(self.m_objID)
packet.ItemGUID.bos(self.item_guid, stream)
packet.PetGUID.bos(self.pet_guid, stream)
stream:writeuint(self.serial)
stream:writeuchar(self.to_index)
stream:writeuchar(self.to_type)
stream:writeuchar(self.is_yuanbao_stall or 0)
stream:writeuint(self.cost)
stream:writeuint(self.profit)
return stream:get()
end
}
当前 Lua 发送逻辑
msg.to_type = 1
msg.item_guid = sb.item_guid
msg.pet_guid = sb.pet_guid
msg.serial = stall_box:get_serial_by_index(index)
msg.to_index = dest_index
msg.is_yuanbao_stall = stall_box:get_is_yuanbao_stall() and 1 or 0
msg.cost = need_money
msg.profit = profit
self:send2client(obj, msg)
self:send2client(stall_human, msg)
当前 Game.exe 结论
GetPacketID() = 799;
GetPacketSize() = 35;
Read(stream) {
stall_obj_id = read_i32();
item_guid = read_bytes(8);
pet_guid = read_bytes(8);
serial = read_u32();
to_index = read_u8();
to_type = read_u8();
is_yuanbao_stall = read_u8();
cost = read_u32();
profit = read_u32();
}
Execute() {
if (stall_obj_id == current_open_other_stall_obj_id) {
// 购买他人摊位成功,更新自己的背包或珍兽栏
} else if (stall_obj_id == my_server_id) {
// 自己摊位的货物被卖出,更新自己的摊位与库存
}
return 2;
}
结论
GCStallBuy(799) 在 Temp_Release_v0-07-0300 中是摆摊购买成功后的固定 35 字节结果包,不是旧 26 字节头文件可以直接覆盖的历史结构。当前版本最终应以当前 Game.exe 和当前 Lua 为准:to_type 现役只处理 1=背包道具、3=珍兽栏,新增尾部字段 is_yuanbao_stall / cost / profit 分别负责同步摊位币种、买家成交金额和摊主税后实收。当前服务端已经按实际摊位类型写入 is_yuanbao_stall,因此客户端的金币摊位与元宝摊位提示分支也能与现状保持一致。
|