CGRelation 是旧版客户端里的关系系统总请求包。当前 Game.exe 可以确认它是“type 分流”的可变包,当前 Lua 服务端则把好友列表、关系详情、加好友、分组迁移、删除关系、修改心情等入口都挂在这一个 PacketID 下。
包信息
| 项目 |
内容 |
| 封包 ID |
415 |
| 包名 |
CGRelation |
| 相关回包 |
GCRelation |
| 相关回包 ID |
434 |
| 作用 |
按 type 提交关系系统请求,包括关系列表、关系详情、加好友、分组迁移、删除关系、修改心情 |
包体结构
固定头
| 偏移 |
长度 |
字段 |
类型 |
含义 |
0x00 |
0x01 |
type |
uint8 |
关系请求子类型 |
当前 Lua 已接入的主要子类型
type |
请求名 |
当前 Game.exe 长度 |
当前 Lua 是否接入 |
1 |
REQ_RELATIONLIST |
1 |
是 |
2 |
REQ_RELATIONINFO |
name_len + 8 |
是 |
4 |
REQ_ADDFRIEND |
name_len + 10 |
是 |
5 |
REQ_ADDTOBLACKLIST |
name_len + 9 |
否 |
6 |
REQ_TEMPFRIEND_TO_FRIEND |
name_len + 10 |
是 |
8 |
REQ_TRANSITION |
7 |
是 |
9 |
REQ_DELFRIEND |
5 |
是 |
13 |
REQ_MODIFYMOOD |
mood_len + 2 |
是 |
type = 1 关系列表请求
type = 1 时,附加参数长度为 0,只有固定头。
| 偏移 |
长度 |
字段 |
类型 |
含义 |
0x00 |
0x01 |
type |
uint8 |
1=REQ_RELATIONLIST |
type = 2 关系详情查询
| 偏移 |
长度 |
字段 |
类型 |
含义 |
0x00 |
0x01 |
type |
uint8 |
2=REQ_RELATIONINFO |
0x01 |
0x04 |
target_guid |
int32 |
目标角色 GUID |
0x05 |
0x01 |
name_len |
uint8 |
名字长度 |
0x06 |
name_len |
name |
char[n] |
目标名字 |
0x06 + name_len |
0x02 |
reserved_short |
int16 |
当前 Lua 未直接使用的尾部短整型 |
type = 4 / 6 添加关系或临时好友转正
| 偏移 |
长度 |
字段 |
类型 |
含义 |
0x00 |
0x01 |
type |
uint8 |
4=REQ_ADDFRIEND,6=REQ_TEMPFRIEND_TO_FRIEND |
0x01 |
0x04 |
target_guid |
int32 |
目标角色 GUID |
0x05 |
0x02 |
reserved_short |
int16 |
当前 Lua 未直接使用的中间短整型 |
0x07 |
0x01 |
name_len |
uint8 |
名字长度 |
0x08 |
name_len |
name |
char[n] |
目标名字 |
0x08 + name_len |
0x01 |
relation_type |
int8 |
目标关系类型 |
0x09 + name_len |
0x01 |
group |
int8 |
目标分组 |
type = 8 分组迁移
| 偏移 |
长度 |
字段 |
类型 |
含义 |
0x00 |
0x01 |
type |
uint8 |
8=REQ_TRANSITION |
0x01 |
0x04 |
target_guid |
int32 |
目标角色 GUID |
0x05 |
0x01 |
from_group |
int8 |
原分组 ID |
0x06 |
0x01 |
to_group |
int8 |
目标分组 ID |
type = 9 删除关系
| 偏移 |
长度 |
字段 |
类型 |
含义 |
0x00 |
0x01 |
type |
uint8 |
9=REQ_DELFRIEND |
0x01 |
0x04 |
target_guid |
int32 |
待删除关系对象 GUID |
type = 13 修改心情
| 偏移 |
长度 |
字段 |
类型 |
含义 |
0x00 |
0x01 |
type |
uint8 |
13=REQ_MODIFYMOOD |
0x01 |
0x01 |
mood_len |
uint8 |
心情文本长度 |
0x02 |
mood_len |
mood |
char[n] |
新心情文本 |
当前实际行为 / 模式说明
- 当前
Game.exe 中,CGRelation::GetPacketID() 返回 415。
- 当前
Game.exe 的 Execute() 对客户端侧是空处理,直接返回 2。
- 当前
Game.exe 的 GetPacketSize() 明确按 type 分支计算长度:
type=1:1
type=2:name_len + 8
type=3 / 0x0F:name_len + 4
type=4 / 6 / 0x18:name_len + 10
type=5 / 7:name_len + 9
type=8:7
type=9 / 0x0A / 0x17 / 0x19 / 0x1A / 0x23 / 0x24 / 0x25 / 0x26:5
type=13:mood_len + 2
type=0x1D / 0x1E:text_len + 6
- 当前 Lua 协议层能读取的主要分支是:
1
2
3
4
5
6
7
8
9
10
13
15
23
24
25
26
29
30
- 但当前 Lua 业务主链实际只显式处理这些请求类型:
1:发送自己的关系列表
2:查询关系详情
4:添加关系
6:临时好友转正式好友
8:分组迁移
9:删除关系
13:修改心情
- 当前
type=5 虽然在 packet.lua 与 Game.exe 中都有独立结构,但 ma_relation:CGRelation() 里没有实际实现。
- 当前关系分组语义在 Lua 主链里是:
- 当前分组容量限制是:
- 好友总列表最多
0x50=80
- 黑名单最多
0x0A=10
- 仇人列表最多
0x0A=10
- 当前
type=8 分组迁移会额外校验:
- 目标组容量是否已满
- 配偶 / 师傅 / 徒弟 / 结拜不能直接转入黑名单
- 当前
type=4 在 Lua 里除了普通加好友,还被内部复用为“加仇人”入口:
CMD.relation_on_be_human_kill() 会构造 type=4
- 并把
relation_type 设为 RELATION_TYPE_ENEMIES
group 设为 "enemy"
- 当前回包现状也都走
GCRelation(434),主要返回类型如下:
type=1 请求后,先回 GCRelation type=1 关系列表,再回 GCRelation type=13 在线好友列表
type=2 请求后,成功回 GCRelation type=2,拿不到可返回对象时回 GCRelation type=0x1A
type=4 / 6 成功后回 GCRelation type=5
type=8 成功后回 GCRelation type=9
type=9 成功后回 GCRelation type=10
type=13 成功后回 GCRelation type=16
- 当前世界服会为关系系统提供这些协作能力:
get_player_info
get_player_info_by_name
get_online_users_in_list
notify_friend_be_add
notify_friend_be_del
notify_friends_online
notify_friends_offline
服务端落点
- 协议定义:
/home/ubuntu/Game2/services/game/packet.lua
- 请求入口:
/home/ubuntu/Game2/services/msgagent.lua
- 关系主逻辑:
/home/ubuntu/Game2/msgagent_module/ma_relation.lua
- 世界服协作:
/home/ubuntu/Game2/services/world/worldcore.lua
关键代码
当前 Lua 协议定义
packet.CGRelation = {
xy_id = packet.XYID_CG_RELATION,
ctor = function(self)
self.type = 0
self.request_relation_info = {}
end,
bis = function(self, buffer)
local stream = bistream.new()
stream:attach(buffer)
self.type = stream:readuchar()
if self.type == 2 then
self.request_relation_info.guid = stream:readint()
local len = stream:readuchar()
...
self.request_relation_info.unknow_1 = stream:readshort()
elseif self.type == 4 or self.type == 6 or self.type == 0x18 then
self.request_relation_info.guid = stream:readint()
self.request_relation_info.unknow_2 = stream:readshort()
local len = stream:readuchar()
...
self.request_relation_info.relation_type = stream:readchar()
self.request_relation_info.group = stream:readchar()
elseif self.type == 8 then
self.request_relation_info.guid = stream:readint()
self.request_relation_info.from = stream:readchar()
self.request_relation_info.to = stream:readchar()
elseif self.type == 9 or self.type == 0xA or self.type == 0x17 or self.type == 0x19 or self.type == 0x1A then
self.request_relation_info.guid = stream:readint()
elseif self.type == 0xd then
local len = stream:readuchar()
...
end
end
}
当前 Lua 请求分发
function request:CGRelation()
ma_func:CGRelation(self)
end
function ma_relation:CGRelation(packet)
local msg = packet_def.GCRelation.new()
if packet.type == 1 then
self:send_my_relation_list(packet)
elseif packet.type == 2 then
local relation_info = self:get_relation_info(packet)
if relation_info then
msg.type = packet.type
msg.relation_info = relation_info
else
msg.type = 0x1A
end
self:send2client(msg)
elseif packet.type == 4 then
local ret, relation_info = self:add_relation_info(packet)
if ret then
msg.type = ret
msg.relation_info = relation_info
self:send2client(msg)
end
elseif packet.type == 9 or packet.type == 23 then
msg.type = 10
local del_relation = self:del_relation(packet)
msg.del_relation = del_relation
self:send2client(msg)
skynet.send(".world", "lua", "notify_friend_be_del", del_relation.guid, self.my_guid, del_relation.relation_type)
elseif packet.type == 8 then
msg.type = 9
local relation_guid_uchar_uchar = self:change_relation_group(packet)
...
elseif packet.type == 13 then
msg.type = 16
self.my_data.relation.mood = packet.request_relation_info.mood
skynet.call(self.my_scene, "lua", "call_human_function", self.my_obj_id, "set_mood", self.my_data.relation.mood)
msg.new_mood = { mood = self.my_data.relation.mood }
self:send2client(msg)
end
end
当前 Lua 世界服协作
function worldcore:get_player_info(guid)
...
end
function worldcore:get_player_info_by_name(name)
...
end
function worldcore:get_online_users_in_list(list)
...
end
function worldcore:notify_friend_be_add(guid, tar_guid, relation_type)
...
end
function worldcore:notify_friend_be_del(guid, tar_guid, relation_type)
...
end
当前 Game.exe 的读写与执行结论
GetPacketID() = 415;
GetPacketSize() {
switch (type) {
case 1: return 1;
case 2: return name_len + 8;
case 3:
case 0x0F: return name_len + 4;
case 4:
case 6:
case 0x18: return name_len + 10;
case 5:
case 7: return name_len + 9;
case 8: return 7;
case 9:
case 0x0A:
case 0x17:
case 0x19:
case 0x1A:
case 0x23:
case 0x24:
case 0x25:
case 0x26: return 5;
case 0x0D: return mood_len + 2;
case 0x1D:
case 0x1E: return text_len + 6;
default: return 0;
}
}
Read(stream) {
read_u8(type);
switch (type) {
case 2:
read_i32(target_guid);
read_u8(name_len);
read_bytes(name, name_len);
read_i16(reserved_short);
break;
case 4:
case 6:
case 0x18:
read_i32(target_guid);
read_i16(reserved_short);
read_u8(name_len);
read_bytes(name, name_len);
read_i8(relation_type);
read_i8(group);
break;
case 8:
read_i32(target_guid);
read_i8(from_group);
read_i8(to_group);
break;
case 9:
case 0x0A:
case 0x17:
case 0x19:
case 0x1A:
read_i32(target_guid);
break;
case 13:
read_u8(mood_len);
read_bytes(mood, mood_len);
break;
}
}
Write(stream) { ...same order... }
Execute() {
return 2;
}
结论
这条包在当前旧版项目里要记住七点:
CGRelation 的封包 ID 是 415,它不是单一结构包,而是按 type 分流的关系系统总入口。
- 当前
Game.exe 明确确认了这条包的长度规则,当前 Lua 主链实际接入的核心请求类型是 1 / 2 / 4 / 6 / 8 / 9 / 13。
- 当前
type=1 用于拉取自己的关系列表;请求后会收到关系列表和在线好友列表两类 GCRelation 回包。
- 当前
type=2 用于查询关系详情;Lua 查询时优先按名字走世界服查人。
- 当前
type=4 / 6 用于加好友或临时好友转正;当前 type=5 虽然有结构,但 Lua 主链没有实现。
- 当前
type=8 用于分组迁移,分组语义是 1~4=好友组、5=黑名单、6=仇人,并带容量和特殊关系限制。
- 当前
type=13 用于修改心情,成功后会同步更新角色自身心情并回发新的心情内容。