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 客户端处理逻辑直接确认。