CGExchangeApplyI 是旧版客户端里用于向目标玩家发起交易申请的请求包。当前 Game.exe 与当前 Lua 服务端都能确认,这条包固定为 8 字节,包体由两个 int32 字段组成,分别表示交易目标对象 ID 与目标 GUID。
包信息
| 项目 |
内容 |
| 封包 ID |
125 |
| 包名 |
CGExchangeApplyI |
| 方向 |
Client -> Server |
| 固定包长 |
8 |
| 相关回包 |
GCExchangeApplyI |
| 相关回包 ID |
69 |
| 作用 |
向指定目标玩家发起交易申请 |
当前 Game.exe 的虚函数结论为:
GetPacketID() = 125;
GetPacketSize() = 8;
Execute() = 2;
包体结构
当前 Game.exe 已直接确认这条包按 4 + 4 顺序读写;当前 Lua 协议与交易申请回包链路也能对齐出字段语义。
| 偏移 |
长度 |
字段 |
类型 |
含义 |
0x00 |
0x04 |
target_obj_id |
int32 |
目标玩家当前场景对象 ID |
0x04 |
0x04 |
target_guid |
int32 |
目标玩家 GUID |
当前实际行为 / 模式说明
- 当前
Game.exe 中,CGExchangeApplyI::Read() / Write() 都固定处理两个 int32:
target_obj_id
target_guid
- 当前 Lua 请求入口
request:CGExchangeApplyI() 在进场景服前会先做两层校验:
- 检查角色存档版本号是否与当前在线数据一致
- 检查二级密码是否已解锁
- 如果存档版本号异常,当前版本会记录
log_save_lv_change 日志,并提示玩家重新登录后再交易。
- 进入场景服后,
char_exchange_apply_I() 会按 target_obj_id 找目标对象,并依次检查:
- 当前场景是否为死亡场景
- 双骑交易配对是否合法
- 当前交易有效性校验是否通过
- 目标是否开启拒绝交易
- 发起方是否已在交易中
- 目标方是否已在交易中
- 全部通过后,服务端不会立刻建立交易框,而是先向目标玩家发送
GCExchangeApplyI(69),把发起方信息带过去:
source_oid
source_guid
source_name
source_level
- 当前 Lua 场景主链实际使用的是
target_obj_id;target_guid 在现行场景处理里没有继续参与校验。
服务端落点
- 协议定义:
/home/ubuntu/Game2/services/game/packet.lua
- 请求入口:
/home/ubuntu/Game2/services/msgagent.lua
- 场景处理:
/home/ubuntu/Game2/services/scene/scenecore.lua
关键代码
当前 Lua 协议定义
packet.CGExchangeApplyI = {
xy_id = packet.XYID_CG_EXCHANGE_APPLY_I,
ctor = function(self)
self.target_obj_id = 0
self.target_guid = 0
end,
bis = function(self, buffer)
local stream = bistream.new()
stream:attach(buffer)
self.target_obj_id = stream:readint()
self.target_guid = stream:readint()
end
}
当前 Lua 请求入口
function request:CGExchangeApplyI()
local my_data = ma_func:get_my_data()
if not my_data then
return
end
local guid = my_data.attrib.guid
local save_lv,game_agent = skynet.call(".gamed", "lua", "check_save_lv", guid)
if not save_lv or save_lv ~= my_data.game_flag.save_lv then
...
ma_func:notify_tips("角色数据异常,请重新登陆游戏再进行操作。")
return
end
if not ma_func:is_minor_password_is_unlock() then
ma_func:send_operate_result_msg(define.OPERATE_RESULT.OR_NEED_UNLOCKMINORPASSWORD)
return
end
skynet.call(my_scene, "lua", "char_exchange_apply_I", my_obj_id, self)
end
当前 Lua 场景处理
function scenecore:char_exchange_apply_I(who, ea)
local obj_me = self:get_obj_by_id(who)
if not obj_me then
return
end
...
local obj_tar = self:get_obj_by_id(ea.target_obj_id)
if not obj_tar then
return
end
...
local msg = packet_def.GCExchangeApplyI.new()
msg.source_oid = obj_me:get_obj_id()
msg.source_guid = obj_me:get_guid()
msg.source_name = obj_me:get_name()
msg.source_level = obj_me:get_level()
self:send2client(obj_tar, msg)
end
当前 Game.exe 的读写结论
Read(stream) {
read_i32(target_obj_id);
read_i32(target_guid);
}
Write(stream) {
write_i32(target_obj_id);
write_i32(target_guid);
}
结论
CGExchangeApplyI 在当前旧版项目中的结论可以直接概括为:
- 这条包的封包 ID 是
125。
- 它是固定
8 字节请求包,结构为 target_obj_id + target_guid。
- 当前请求入口会先做存档版本号校验和二级密码解锁校验。
- 当前场景服主要按
target_obj_id 定位交易目标,并完成一系列交易前置检查。
- 校验通过后,服务端会向目标玩家下发
GCExchangeApplyI(69),通知其收到交易申请。
|