找回密码
 registerss
搜索
查看: 24|回复: 0

洱海月 v0-07-0300 封包解析:ID 415 CGRelation(关系系统总请求包)

[复制链接]
  • 打卡等级:本地老炮
  • 打卡总天数:603
  • 打卡月天数:1
  • 打卡总奖励:600
  • 最近打卡:2026-10-03 06:32:28
Waylee 发表于 2026-4-12 18:13 | 显示全部楼层 |阅读模式 | Google Chrome | Windows 10

马上注册,查看网站隐藏内容!!

您需要 登录 才可以下载或查看,没有账号?registerss

×

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 主链里是:
    • 1~4:好友分组
    • 5:黑名单
    • 6:仇人
  • 当前分组容量限制是:
    • 好友总列表最多 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;
}

结论

这条包在当前旧版项目里要记住七点:

  1. CGRelation 的封包 ID 是 415,它不是单一结构包,而是按 type 分流的关系系统总入口。
  2. 当前 Game.exe 明确确认了这条包的长度规则,当前 Lua 主链实际接入的核心请求类型是 1 / 2 / 4 / 6 / 8 / 9 / 13。
  3. 当前 type=1 用于拉取自己的关系列表;请求后会收到关系列表和在线好友列表两类 GCRelation 回包。
  4. 当前 type=2 用于查询关系详情;Lua 查询时优先按名字走世界服查人。
  5. 当前 type=4 / 6 用于加好友或临时好友转正;当前 type=5 虽然有结构,但 Lua 主链没有实现。
  6. 当前 type=8 用于分组迁移,分组语义是 1~4=好友组、5=黑名单、6=仇人,并带容量和特殊关系限制。
  7. 当前 type=13 用于修改心情,成功后会同步更新角色自身心情并回发新的心情内容。
您需要登录后才可以回帖 登录 | registerss

本版积分规则

QQ|手机版|雪舞知识库 ( 浙ICP备15015590号-1 | 萌ICP备20232229号|浙公网安备33048102000118号 )|天天打卡

GMT+8, 2026-10-4 11:26 , Processed in 0.071488 second(s), 25 queries .

Powered by Discuz! X5.0

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表