CGSplitItem 是客户端请求把一组可堆叠道具拆分成两堆的定长请求包。
当前版本里,这条包会提交来源容器、来源格索引和拆分数量。服务端收到后,会在目标容器中寻找空位,把指定数量复制成新堆,并同步回包 GCSplitItemResult 与原格 GCItemInfo。
包信息
| 项目 |
内容 |
| 封包 ID |
453 |
| 包名 |
CGSplitItem |
| 方向 |
CG 客户端 -> 游戏服 |
| 包长 |
12 |
| 当前 Lua 协议定义 |
/home/ubuntu/Game2/services/game/packet.lua |
| 当前服务端入口 |
/home/ubuntu/Game2/services/msgagent.lua |
| 当前实际处理 |
/home/ubuntu/Game2/services/scene/obj/human.lua 的 split_item() |
| 主要作用 |
请求把一组堆叠道具拆出指定数量到新格子 |
当前 Game.exe 可直接确认:
GetPacketID() = 453;
GetPacketSize() = 12;
Read() = sub_1405C6E20;
Write() = sub_1405C8DC0;
Execute() = sub_140328260;
包体结构
| 偏移 |
长度 |
字段 |
类型 |
含义 |
0x00 |
0x04 |
container |
uint32 |
来源容器类型 |
0x04 |
0x04 |
position |
uint32 |
来源格索引 |
0x08 |
0x04 |
num |
uint32 |
要拆出的数量 |
当前 Lua 定义的容器枚举为:
Container = {
BANK_CON = 0,
BAG_CON = 1,
}
总长度固定为:
4 + 4 + 4 = 12
当前实际行为 / 模式说明
这条包在当前版本里并不是“任意容器通用拆分”,而是“协议支持多个容器,但当前实现主要处理背包拆分”。
当前主链流程如下:
msgagent 收到 CGSplitItem 后,直接转给场景层 char_split_item()
- 场景层再转交角色对象
human:split_item(split)
- 角色对象当前只在:
split.container == packet_def.CGSplitItem.Container.BAG_CON
分支下做实际处理
- 如果来源格没有物品、来源格为空、没有空目标格,当前都会直接回失败
- 如果可以拆分,则调用:
human_item_logic:split_item(container, split.position, split.num, container, empty_index)
在同一个背包容器里生成新堆
- 成功后会发送两条消息:
GCSplitItemResult:告知新堆目标格和结果
GCItemInfo:刷新原来源格的剩余数量
当前实现还有两个值得注意的现状:
BANK_CON = 0 虽然在协议枚举里保留,但 human:split_item() 的 else 分支是空的,当前未正式处理银行拆分
GCSplitItemResult.RESULT_FALSE_NOGRID = 1 虽然在结果枚举里保留,但当前背包拆分逻辑在“没有空格”时仍回 RESULT_FALSE = 0,没有单独走 RESULT_FALSE_NOGRID
服务端落点
- 协议定义:
/home/ubuntu/Game2/services/game/packet.lua
- 请求入口:
/home/ubuntu/Game2/services/msgagent.lua
- 场景转发:
/home/ubuntu/Game2/services/scene/scenecore.lua
- 角色实际处理:
/home/ubuntu/Game2/services/scene/obj/human.lua
- 拆分底层逻辑:
/home/ubuntu/Game2/lualib/human_item_logic.lua
/home/ubuntu/Game2/lualib/item_operator.lua
当前转发链非常直接:
function request:CGSplitItem()
skynet.call(my_scene, "lua", "char_split_item", my_obj_id, self)
end
function scenecore:char_split_item(whos, split)
local obj = self.objs[whos]
obj:split_item(split)
end
关键代码
当前 Lua 协议定义
packet.CGSplitItem = {
xy_id = packet.XYID_CG_SPLIT_ITEM,
Container = {
BANK_CON = 0,
BAG_CON = 1,
},
bis = function(self, buffer)
local stream = bistream.new()
stream:attach(buffer)
self.container = stream:readuint()
self.position = stream:readuint()
self.num = stream:readuint()
end
}
当前角色对象处理
function human:split_item(split)
local msg = packet_def.GCSplitItemResult.new()
msg.container = split.container
if split.container == packet_def.CGSplitItem.Container.BAG_CON then
local container = self:get_prop_bag_container()
local item = container:get_item(split.position)
...
local empty_index = container:get_empty_item_index(item:get_place_bag())
...
local ret = human_item_logic:split_item(container, split.position, split.num, container, empty_index)
if ret then
msg.item = container:get_item(empty_index):copy_raw_data()
msg.result = msg.RESULT.RESULT_SUCCEED
msg.is_null = 0
msg.con_index = empty_index
self.scene:send2client(self, msg)
msg = packet_def.GCItemInfo.new()
msg.bagIndex = split.position
msg.item = item:copy_raw_data()
self.scene:send2client(self, msg)
end
end
end
当前拆分规则
当前底层拆分限制非常明确:
function item_operator:split_item(logparam, src_container, src_index, count, dest_container, dest_index)
local item = src_container:get_item(src_index)
if item:get_lay_count() <= count or count == 0 then
return define.ITEM_OPERATOR_ERROR.ITEMOE_UNKNOW
end
if item:is_empty() then
return define.ITEM_OPERATOR_ERROR.ITEMOE_SOUROPERATOR_EMPTY
end
if item:is_lock() then
return define.ITEM_OPERATOR_ERROR.ITEMOE_SOUROPERATOR_LOCK
end
...
self:set_item_lay_count(dest_container, final_dest_index, count)
self:set_item_lay_count(src_container, src_index, item:get_lay_count() - count)
return define.ITEM_OPERATOR_ERROR.ITEMOE_SUCCESS
end
也就是说,当前版本只有在以下条件满足时才允许拆分:
- 来源格存在物品
- 物品不是空物品
- 物品未锁定
count > 0
count < 当前堆叠数量
- 目标容器存在空格
当前 Game.exe 关键结论
当前客户端包类的读写顺序与 Lua 完全一致:
Read(stream) {
read_u32(container);
read_u32(position);
read_u32(num);
return 1;
}
Write(stream) {
write_u32(container);
write_u32(position);
write_u32(num);
return 1;
}
GetPacketSize() {
return 12;
}
Execute() {
return 2;
}
结论
CGSplitItem 在当前 Temp_Release_v0-07-0300 里的最终结论可以直接收敛为:
- 这是一条固定长度
12 字节的客户端请求包。
- 包体字段只有三个:
- 当前协议枚举保留了
BANK_CON=0 和 BAG_CON=1,但当前 Lua 实际只处理 BAG_CON=1 的背包拆分。
- 当前服务端会在拆分前校验来源格、锁定状态、拆分数量和目标空格。
- 拆分成功后,会同时回:
GCSplitItemResult 用于告知新堆信息
GCItemInfo 用于刷新原格剩余数量
- 当前
Game.exe 与当前 Lua 对这条包的结构判断完全一致,不需要借助旧 Server 才能确定包体。