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

洱海月 v0-07-0300 封包解析:ID 168 CGRemoveGem(装备摘除宝石请求)

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

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

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

×

CGRemoveGem 是旧版客户端用于“从普通装备上摘除指定孔位宝石”的请求包。当前 Temp_Release_v0-07-0300 的 Lua 服务端已经真实接入这条协议,请求入口位于 /home/ubuntu/Game2/services/msgagent.lua 的 request:CGRemoveGem(),实际处理落到场景服 /home/ubuntu/Game2/services/scene/scenecore.lua 的 char_remove_gem()。

这条包是固定 3 字节小包,分别表示:

  • 要摘除的宝石孔位
  • 被操作装备的背包格
  • 摘除符材料的背包格

时装拆宝石并不走这条包,而是另一条独立协议 CGRemoveDressGem。

包信息

项目 内容
封包 ID 168
包名 CGRemoveGem
方向 CG 客户端 -> 游戏服
固定包长 3
直接回包 GCRemoveGemResult
回包 ID 384
当前 Lua 协议定义 /home/ubuntu/Game2/services/game/packet.lua
当前 Lua 请求入口 /home/ubuntu/Game2/services/msgagent.lua
当前场景服处理 /home/ubuntu/Game2/services/scene/scenecore.lua
主要作用 从普通装备指定孔位摘除宝石,并返还宝石物品

当前 Game.exe 的虚函数结论为:

CGRemoveGem
GetPacketID()   = 168;
GetPacketSize() = 3;
Read            = 0x1405CA4F0;
Write           = 0x1405C8D50;
Execute thunk   = 0x1405C8D40 -> sub_140328250;

GCRemoveGemResult
GetPacketID()   = 384;
GetPacketSize() = 8;
Read            = 0x14060ADC0;
Write           = 0x1405C84B0;
Execute thunk   = 0x1406081C0 -> sub_140336C00;

包体结构

偏移 长度 字段 类型 含义
0x00 0x01 gem_index uint8 要摘除的宝石孔位,客户端使用 0 起始索引
0x01 0x01 equip_index uint8 被操作装备所在背包格
0x02 0x01 mat_index uint8 摘除符材料所在背包格

当前实际行为 / 模式说明

  • 客户端普通拆宝石界面 SplitGem.lua、四孔拆宝石界面 SplitGem_Four.lua、新版拆宝石界面 SplitGemEx.lua,最终都会调用同一套 Lua 绑定:
LifeAbility:Do_SeparateGem(equip_pos, gem_slot, material_pos)
  • 当前 Game.exe 的 LUA:LifeAbility Do_SeparateGem 会先校验 3 个参数都为数字,再把这三个参数写入 CGRemoveGem。
  • 当前普通拆宝石流程的 Lua 服务端会把 gem_index 转成 gem_location = gem_index + 1,因为服务端装备宝石列表是 Lua 的 1 起始数组。
  • 场景服当前会依次校验:
    • 装备与材料是否可操作,是否处于交易 / 锁定状态
    • 目标孔位是否真的存在宝石,且宝石 ID 合法
    • 摘除符是否与目标宝石等级匹配
    • 材料栏是否至少预留 1 个空位
    • 装备部位是否允许执行普通摘除
  • 当前普通装备摘除不支持以下装备位:
    • 坐骑
    • 随身包裹
    • 材料箱
    • 时装
    • 灵武相关部位
    • 其他被 char_remove_gem() 明确排除的部位
  • 校验全部通过后,服务端会先扣除 1 个摘除符,再调用 equip:get_equip_data():remove_gem(gem_location) 执行摘除。
  • 摘除成功后,服务端会把宝石作为独立物品重新创建到材料栏,并额外发送一条 GCItemInfo 同步更新后的装备数据。

关联回包结构

GCRemoveGemResult 是这条包的直接结果包,固定长度 8 字节。

偏移 长度 字段 类型 含义
0x00 0x04 result uint32 摘除结果码
0x04 0x04 gem_item_id uint32 摘除成功后返还的宝石物品 ID;失败时通常为 0

这里第二个字段在当前 Lua 旧代码里原先叫 gem_index,但当前证据已经可以明确确认它不是“格子索引”:

  • 当前 Lua 场景服实际写入的是 gem_item:get_index()
  • 当前 Game.exe 的 GCRemoveGemResultHandler 也会把该字段当成“物品模板 ID”去查询宝石名称并拼接成功提示

因此,这个字段更准确的命名应为 gem_item_id。

当前结果码说明

当前客户端 GCRemoveGemResultHandler.cpp 能明确识别以下结果码文本:

result 当前客户端文本键 说明
0 GCRemoveGemResult_Success_Obtain 摘除成功,并根据 gem_item_id 显示获得的宝石名
1 GCRemoveGemResult_NO_ITEM 客户端兼容的缺少材料类错误
2 GCRemoveGemResult_ERROR_GEMINDEX 宝石孔位错误
3 GCRemoveGemResult_NO_GEM 指定孔位没有宝石
4 GCRemoveGemResult_INVALID_EQUIP 装备非法
5 GCRemoveGemResult_TOO_LARGE_GEMINDEX 宝石孔位越界
6 GCRemoveGemResult_UNKNOW_ERROR 未知错误
7 GCRemoveGemResult_BAG_FULL 背包或材料栏空间不足
9 GCRemoveGemResult_REMOVE_FORTH 与四孔拆宝石相关的兼容提示

当前 Lua 主链下,普通装备 char_remove_gem() 实际最常见的回包结果是:

  • 0:成功,gem_item_id 为返还宝石物品 ID
  • 7:返还宝石入包失败

如果 remove_gem() 执行后孔位仍未清空,当前 Lua 只会提示“宝石摘除失败。”,不会再补发成功回包。

服务端落点

这条包在当前项目中的关键位置如下:

  • 协议定义:
    • /home/ubuntu/Game2/services/game/packet.lua
  • 请求入口:
    • /home/ubuntu/Game2/services/msgagent.lua
  • 场景服处理:
    • /home/ubuntu/Game2/services/scene/scenecore.lua
  • 客户端普通拆宝石界面:
    • 客户端/Interface/SplitGem/SplitGem.lua
  • 客户端四孔拆宝石界面:
    • 客户端/Interface/SplitGem_Four/SplitGem_Four.lua
  • 客户端新版拆宝石界面:
    • 客户端/Interface/SplitGemEx/SplitGemEx.lua

关键代码

当前 Lua 协议定义

packet.CGRemoveGem = {
    xy_id = packet.XYID_CG_REMOVE_GEM,
    bis = function(self, buffer)
        local stream = bistream.new()
        stream:attach(buffer)
        self.gem_index = stream:readuchar()
        self.equip_index = stream:readuchar()
        self.mat_index = stream:readuchar()
    end,
}

当前 Lua 请求入口与场景服处理

function request:CGRemoveGem()
    skynet.call(my_scene, "lua", "char_remove_gem", my_obj_id, self)
end

function scenecore:char_remove_gem(me, removetab)
    local equip_index = removetab.equip_index
    local mat_index = removetab.mat_index
    local gem_location = removetab.gem_index + 1
    ...
end

当前客户端真实发送入口

普通拆宝石界面和四孔拆宝石界面都会把“装备格、孔位、材料格”传给 Do_SeparateGem:

LifeAbility:Do_SeparateGem(EQUIP_QUALITY, GEM_SELECTED - 1, CHARM_QUALITY)
LifeAbility:Do_SeparateGem(EQUIP_QUALITY, GEM_SELECTED_FOUR - 1, CHARM_QUALITY)
LifeAbility:Do_SeparateGem(g_SplitGemEx_Equip_pos, g_SplitGemEx_Selected - 1, g_SplitGemEx_Material_pos)

当前 Game.exe 的 Do_SeparateGem 结论

Game.exe 中的 LUA:LifeAbility Do_SeparateGem 当前可以直接确认 3 个参数的来源:

equip_pos    = lua_tonumber(L, 2);
gem_index    = lua_tonumber(L, 3);
material_pos = lua_tonumber(L, 4);

随后构造 CGRemoveGem 并发包;这与当前 Lua 协议层整理出的 gem_index + equip_index + mat_index 三字段模型是对得上的。

当前 GCRemoveGemResult 处理结论

当前 Game.exe 的 GCRemoveGemResultHandler 已经可以明确确认:

  • result != 0 时,会按结果码映射到 GCRemoveGemResult_NO_ITEM / NO_GEM / BAG_FULL ... 等文本键
  • result == 0 时,会把第二个字段当成物品 ID 去查询宝石名称,并显示 GCRemoveGemResult_Success_Obtain

这也是当前把第二个字段命名为 gem_item_id 的直接依据。

结论

CGRemoveGem 在 Temp_Release_v0-07-0300 中已经可以明确归类为“普通装备摘除宝石请求包”:

  • 固定包长 3
  • 包体字段为 gem_index、equip_index、mat_index
  • gem_index 使用客户端 0 起始孔位编号
  • 时装摘除宝石不走这条包,而是另一条 CGRemoveDressGem

配套回包 GCRemoveGemResult 的结构也已经能定准:

  • result:uint32
  • gem_item_id:uint32

其中 gem_item_id 是摘除成功后返还的宝石物品 ID,不是格子索引。这个命名已经可以依据当前 Lua 场景服实际写法与当前 Game.exe 客户端处理逻辑直接确认。

您需要登录后才可以回帖 登录 | registerss

本版积分规则

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

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

Powered by Discuz! X5.0

© 2001-2026 Discuz! Team.

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