CGCGWPacket 是当前版本里承载帮会城市、帮会宣战、同盟踢人等功能的复合请求包。它不是固定业务单包,而是由 type(uint8) + payload_length(uint32) + payload 组成的总包头,再按 type 分发到不同子结构。
包信息
| 项目 |
内容 |
| 封包 ID |
508 |
| 包名 |
CGCGWPacket |
| 方向 |
CG 客户端 -> 游戏服 |
| 包长规则 |
动态包长,5 + payload_length |
| 当前 Lua 状态 |
现役协议;msgagent 已接入多个 type 分支 |
| 专用回包 |
无专用回包;按分支可能返回 GCWGCPacket 或提示消息 |
| 作用 |
承载帮会城市申请/查询/操作、同盟踢人、帮会宣战等复合请求 |
当前 Game.exe 可确认:
CGCGWPacket::GetPacketID() = 508;
CGCGWPacket::GetPacketSize() = payload_length + 5;
CGCGWPacket::Read() = read(type, 1) + read(payload_length, 4) + read(payload, payload_length);
CGCGWPacket::Write() = write(type, 1) + write(payload_length, 4) + write(payload, payload_length);
CGCGWPacket::Execute() = 0;
包体结构
总包头固定为 1 + 4 字节,后面紧跟 payload_length 指定的子载荷。以下偏移都以 payload 起始位置为基准。
总包头
| 偏移 |
长度 |
字段 |
类型 |
含义 |
0x00 |
0x01 |
type |
uint8 |
复合请求类型 |
0x01 |
0x04 |
payload_length |
uint32 |
子载荷长度 |
0x05 |
n |
payload |
bytes[n] |
按 type 解释的子结构 |
type = 1 城市申请,payload_length = 40
| 偏移 |
长度 |
字段 |
类型 |
含义 |
0x00 |
0x04 |
city_enter_group |
uint32 |
城市入驻目标组 |
0x04 |
0x04 |
guid |
int32 |
客户端附带的角色标识,当前 Lua 不消费 |
0x08 |
0x04 |
reserved_1 |
int32 |
当前客户端填 0,Lua 不消费 |
0x0C |
0x1A |
name |
char[26] |
城市名 |
0x26 |
0x02 |
padding_1 |
bytes[2] |
客户端尾部补零,当前 Lua 未读取 |
type = 2 城市信息查询,payload_length = 4
| 偏移 |
长度 |
字段 |
类型 |
含义 |
0x00 |
0x02 |
scene_id |
int16 |
查询场景或兼容占位值 |
0x02 |
0x01 |
m_Type |
uint8 |
查询类别 |
0x03 |
0x01 |
m_BldIdx |
uint8 |
建筑索引 |
当前 Lua 已接入的查询类别:
m_Type = 1:城市基础/管理信息
m_Type = 2:研究基础信息
m_Type = 3:研究详情
m_Type = 4:城市商店信息
m_Type = 5:商线列表
当前客户端部分基础查询仍会发 m_Type = 0,Lua 在 guild_city_ask_info() 中会把 scene_id > 0 且 m_BldIdx = 0 的分支归一化成 m_Type = 1。
type = 3 且 payload_length = 34,野外帮战申请
| 偏移 |
长度 |
字段 |
类型 |
含义 |
0x00 |
0x20 |
reserved_1 |
bytes[32] |
当前 Lua 与服务端主逻辑均未消费的前置数据 |
0x20 |
0x02 |
tar_guild_id |
int16 |
目标帮会 ID |
type = 3 且 payload_length = 52,城市操作
| 偏移 |
长度 |
字段 |
类型 |
含义 |
0x00 |
0x01 |
m_Opt |
uint8 |
操作类型 |
0x01 |
0x01 |
m_BuildIdx |
uint8 |
建筑索引 |
0x02 |
0x02 |
m_Reserved |
uint16 |
保留字段 |
0x04 |
0x04 |
m_ItemIdx |
uint32 |
配方/商品/条目索引 |
0x08 |
0x04 |
m_PriceMoney |
uint32 |
金币价格字段 |
0x0C |
0x04 |
m_Money |
uint32 |
金币字段 |
0x10 |
0x04 |
m_TicketValue |
uint32 |
票券值字段 |
0x14 |
0x04 |
m_uSourceSceneID |
uint32 |
来源场景 ID |
0x18 |
0x04 |
m_uProductValue |
uint32 |
产出值字段 |
0x1C |
0x04 |
m_Serial |
uint32 |
序号字段 |
0x20 |
0x02 |
m_TargetGuildID |
int16 |
目标帮会 ID |
0x22 |
0x02 |
m_TargetReserved |
int16 |
目标保留字段 |
0x24 |
0x04 |
m_PriceTicketValue |
uint32 |
票券价格字段 |
0x28 |
0x08 |
m_ItemGUID |
bytes[8] |
物品 GUID 原始字节 |
0x30 |
0x04 |
m_CurrencyType |
int32 |
货币类型 |
当前 Lua 已接入的 m_Opt:
1:建筑升级
2:取消当前建造
4:新建建筑
5:建筑降级
6:拆除建筑
7:研究
8:取消研究
10:城市商店购买
11:城市商店交货
12:创建商线
13:取消商线
type = 7 同盟踢人,payload_length = 4
| 偏移 |
长度 |
字段 |
类型 |
含义 |
0x00 |
0x02 |
reserved_1 |
int16 |
客户端 GuildLeague::FireGuild 第一参数,当前 Lua 未消费 |
0x02 |
0x02 |
kick_guild_id |
int16 |
被踢出的帮会 ID |
type = 11 帮会宣战,payload_length = 8
| 偏移 |
长度 |
字段 |
类型 |
含义 |
0x00 |
0x04 |
initiate_or_accept |
uint32 |
当前 Lua 使用 0=发起宣战、1=接受宣战 |
0x04 |
0x02 |
my_guild_id |
int16 |
当前帮会 ID |
0x06 |
0x02 |
tar_guild_id |
int16 |
目标帮会 ID |
type = 12 帮会城市整数参数请求,payload_length = 2
| 偏移 |
长度 |
字段 |
类型 |
含义 |
0x00 |
0x02 |
guild_id |
int16 |
当前客户端直接写入的帮会 ID;Lua 分支未读取,转而重新从场景取值 |
当前 Game.exe 里还能看到未被现役 Lua 主链接入的旧分支,例如:
type = 4,payload_length = 28
type = 6,payload_length = 112
当前实际行为
type = 1:提交城市申请。msgagent 会先检查角色是否满足占城条件,再补写当前会话的 guild_id,最后调用 .Guildmanager:city_apply();成功后扣除占城消耗。
type = 2:查询帮会城市信息。请求会转给 .Dynamicscenemanager:guild_city_ask_info(),结果再拆成一个或多个 GCWGCPacket 回给客户端。
type = 3 且为 city_opt:城市操作主分支。m_Opt = 11 走场景服 agent_command_guild_city_shop_sell(),其余操作走 .Dynamicscenemanager:guild_city_opt()。
type = 3 且为 guild_wild_war:野外帮战宣战。服务端先检查本帮扩张值是否达到 100,再调用 .Guildmanager:guild_wild_war()。
type = 7:同盟踢人。当前 Game.exe 真实子载荷是 int16 + int16,但现役 Lua 分支仍按原始字节处理,只取 self.data[3] 作为 kick_guild_id 传给 ma_guild:guild_league_kick()。
type = 11:帮会宣战/应战。请求直接转给 .Guildmanager:guild_war()。
type = 12:请求帮会城市整数参数。当前 Lua 会重新获取当前帮会 ID,调用 .Guildmanager:get_guild_int_nums(),成功后回发 GCWGCPacket(type=12)。
- 其他
type:当前 Lua 只会把原始字节读入 self.data,msgagent 没有现役处理分支。
服务端落点
- 协议定义:
/home/ubuntu/Game2/services/game/packet.lua
- 请求入口:
/home/ubuntu/Game2/services/msgagent.lua
- 帮会模块:
/home/ubuntu/Game2/msgagent_module/ma_guild.lua
- 城市查询/操作:
/home/ubuntu/Game2/lualib/dynamicscenemanager_core.lua
- 帮会/同盟/宣战处理:
/home/ubuntu/Game2/services/guild/guildmanager_core.lua
- 场景服特殊处理:
/home/ubuntu/Game2/services/scene/scenecore.lua
关键代码
当前 Game.exe 总包读写
__int64 __fastcall CGCGWPacket_Read(__int64 packet, __int64 stream)
{
read(stream, packet + 24, 1);
read(stream, packet + 28, 4);
read(stream, packet + 32, *(unsigned int *)(packet + 28));
return 1;
}
__int64 __fastcall CGCGWPacket_Write(__int64 packet, __int64 stream)
{
write(stream, packet + 24, 1);
write(stream, packet + 28, 4);
write(stream, packet + 32, *(unsigned int *)(packet + 28));
return 1;
}
当前 Lua 总包解析
packet.CGCGWPacket = {
xy_id = packet.XYID_CG_CGW_PACKET,
bis = function(self, buffer)
local stream = bistream.new()
stream:attach(buffer)
self.type = stream:readuchar()
local len = stream:readuint()
if self.type == 1 then
self.city_apply = packet.CGWPacket_CityApply.new()
self.city_apply:bis(stream)
elseif self.type == 2 then
self.city_ask_info = packet.CGWPacket_CityAskInfo.new()
self.city_ask_info:bis(stream)
elseif self.type == 3 then
if len == 0x22 then
self.guild_wild_war = packet.CGWPacket_GuildWildWar.new()
self.guild_wild_war:bis(stream)
else
self.city_opt = packet.CGWPacket_CityOpt.new()
self.city_opt:bis(stream)
end
elseif self.type == 11 then
self.guild_war = packet.CGWPacket_GuildWar.new()
self.guild_war:bis(stream)
else
self.data = {}
for i = 1, len do
self.data[i] = stream:readuchar()
end
end
end
}
当前 Lua 请求分发
function request:CGCGWPacket()
local my_guid = ma_func:get_guid()
if self.type == 1 then
...
result = skynet.call(".Guildmanager", "lua", "city_apply", my_guid, city_apply)
elseif self.type == 2 then
...
local ok, result = pcall(skynet.call, ".Dynamicscenemanager", "lua", "guild_city_ask_info", my_guid, guild_id, self.city_ask_info)
...
elseif self.type == 3 then
if self.city_opt then
...
local ok, result = pcall(skynet.call, ".Dynamicscenemanager", "lua", "guild_city_opt", my_guid, guild_id, self.city_opt)
...
else
...
skynet.call(".Guildmanager", "lua", "guild_wild_war", my_guid, self.guild_wild_war)
end
elseif self.type == 7 then
local kick_guild_id = self.data[3]
ma_func:guild_league_kick(kick_guild_id)
elseif self.type == 11 then
skynet.call(".Guildmanager", "lua", "guild_war", my_guid, self.guild_war)
elseif self.type == 12 then
...
local msg = packet_def.GCWGCPacket.new()
msg.type = 12
msg.wgc_int_nums = params
Net:send(msg)
end
end
当前客户端可确认的 type = 7 与 type = 12 发包
// GuildLeague::FireGuild(parameter1, parameter2)
word payload[0] = parameter1;
word payload[1] = parameter2;
type = 7;
payload_length = 4;
// ConfraternityCount
word payload[0] = current_guild_id;
type = 12;
payload_length = 2;
结论
CGCGWPacket(508) 是一个复合请求总包,真正的包长规则是 5 + payload_length,不是固定长度。
- 当前 Lua 主链实际接入的是
type = 1/2/3/7/11/12 六类业务,其中 type = 3 又按 payload_length 拆成 34 字节的野外帮战申请和 52 字节的城市操作。
type = 7 与 type = 12 已能从当前 Game.exe 明确确认出真实子载荷,分别是 int16 + int16 与单个 int16;其中 type = 7 的现役 Lua 仍只取到了第二个 int16 的低字节。
- 当前城市查询与城市操作分支不会回单一专用结果包,而是按返回内容拆成多个
GCWGCPacket 子包回给客户端。
Game.exe 里还能看到 type = 4、type = 6 等旧分支,但当前 Lua msgagent 没有现役处理逻辑,不应当作当前服务端稳定功能使用。