找回密码
 registerss
搜索

洱海月 v0-07-0300 封包解析:ID 453 CGSplitItem(堆叠道具拆分请求)

[复制链接]
Waylee 发表于 2026-4-13 15:25 | 显示全部楼层 |阅读模式 | Google Chrome | Windows 10

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

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

×

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

当前实际行为 / 模式说明

这条包在当前版本里并不是“任意容器通用拆分”,而是“协议支持多个容器,但当前实现主要处理背包拆分”。

当前主链流程如下:

  1. msgagent 收到 CGSplitItem 后,直接转给场景层 char_split_item()
  2. 场景层再转交角色对象 human:split_item(split)
  3. 角色对象当前只在:
    • split.container == packet_def.CGSplitItem.Container.BAG_CON

分支下做实际处理

  1. 如果来源格没有物品、来源格为空、没有空目标格,当前都会直接回失败
  2. 如果可以拆分,则调用:
human_item_logic:split_item(container, split.position, split.num, container, empty_index)

在同一个背包容器里生成新堆

  1. 成功后会发送两条消息:
    • 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 里的最终结论可以直接收敛为:

  1. 这是一条固定长度 12 字节的客户端请求包。
  2. 包体字段只有三个:
    • container
    • position
    • num
  3. 当前协议枚举保留了 BANK_CON=0 和 BAG_CON=1,但当前 Lua 实际只处理 BAG_CON=1 的背包拆分。
  4. 当前服务端会在拆分前校验来源格、锁定状态、拆分数量和目标空格。
  5. 拆分成功后,会同时回:
    • GCSplitItemResult 用于告知新堆信息
    • GCItemInfo 用于刷新原格剩余数量
  6. 当前 Game.exe 与当前 Lua 对这条包的结构判断完全一致,不需要借助旧 Server 才能确定包体。
您需要登录后才可以回帖 登录 | registerss

本版积分规则

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

GMT+8, 2026-10-24 13:56 , Processed in 0.029647 second(s), 26 queries .

Powered by Discuz! X5.0

© 2001-2026 Discuz! Team.

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