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

洱海月 v0-07-0300 封包解析:ID 1091 GCCheDiFuLuData(彻地符箓传送点数据同步)

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

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

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

×

GCCheDiFuLuData 是当前 Temp_Release_v0-07-0300 中仍在实际使用的一条变长回包,用来把彻地符箓 / 遁甲书的传送点槽位数据同步给客户端。当前 Lua 主线支持两种发送方式:玩家主动请求 CGAskCheDiFuLuData(1090) 时做一次全量下发;脚本通过 SetCheDiFuLuData() 改写某个槽位时,再补发一次单槽刷新。

结合当前 Game.exe、Lua 协议定义和彻地符箓物品脚本可以确认,这条包真正同步的只有“槽位索引 + 场景 ID + 坐标”。客户端界面里显示的剩余使用次数 count 与初始化标记 init 由物品参数另行提供,不在本包内。

包信息

项目 内容
封包 ID 1091
包名 GCCheDiFuLuData
方向 GC 服务端 -> 客户端
关联请求 CGAskCheDiFuLuData(1090)
包长 2 + 16 * size
当前有效上限 size <= 30,最大 482 字节
当前 Lua 协议定义 已定义
当前 Lua 发送入口 human:send_chedifulu_data(index)
主要作用 同步彻地符箓 30 个槽位中的已配置传送点数据,支持全量同步和单槽刷新

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

GCCheDiFuLuData
GetPacketID()   = 1091;
GetPacketSize() = 16 * size + 2;
Read            = 0x1406169B0;
Write           = 0x140616AA0;
Execute thunk   = 0x1406169A0 -> sub_140080330;

包体结构

这条包是一个“2 字节头 + N 个 16 字节条目”的变长结构。

偏移 长度 字段 类型 含义
0x00 0x01 reserved_1 uchar 保留字节;当前 Lua 默认写 0,当前客户端 Execute() 未消费
0x01 0x01 size uchar 条目数量
0x02 0x10 * size list[size] 结构数组 传送点条目列表

单个条目的线性结构如下:

偏移 长度 字段 类型 含义
+0x00 0x04 index uint32 0 基槽位号,当前有效范围 0..29
+0x04 0x04 sceneid uint32 目标场景 ID
+0x08 0x04 x uint32 目标坐标 X
+0x0C 0x04 y uint32 目标坐标 Y

当前 Game.exe 的读写顺序与 Lua 协议定义一致:

Read(stream) {
    read_u8(reserved_1);
    read_u8(size);
    for (i = 0; i < size && i < 30; ++i) {
        read_u32(index[i]);
        read_u32(sceneid[i]);
        read_u32(x[i]);
        read_u32(y[i]);
    }
}

Write(stream) {
    write_u8(reserved_1);
    write_u8(size);
    for (i = 0; i < size && i < 30; ++i) {
        write_u32(index[i]);
        write_u32(sceneid[i]);
        write_u32(x[i]);
        write_u32(y[i]);
    }
}

需要注意两点:

  1. size 在线路上是 uchar,但当前客户端和服务端实现都把有效槽位数限制在 30。
  2. GetPacketSize() 直接按 size 计算,Read/Write() 则在 30 条时强制截断,所以当前实际使用必须保证 size <= 30。现行 Lua 主链正是按 define.CHEDIFULU_DATA_SIZE = 30 控制的。

当前实际行为

当前版本里,这条包的行为可以收敛为下面几条:

  1. 玩家发送 CGAskCheDiFuLuData 后,msgagent.lua 会转到场景服 char_ask_chedifulu_data(),再由 human:send_chedifulu_data() 组包并下发。
  2. human:send_chedifulu_data() 在不带 index 参数时,会遍历 define.CHEDIFULU_DATA_SIZE = 30 个槽位,把已有配置逐条写入 msg.list,形成一次全量同步。
  3. 脚本接口 SetCheDiFuLuData(selfId, index, sceneid, position) 最终落到 human:set_chedifulu_data();这个函数在写入角色数据后会立刻调用 send_chedifulu_data(index),因此支持单槽刷新。
  4. 当前服务端只同步“已保存的自定义槽位”。如果某个槽位没有记录,物品脚本 893252.lua 会在使用时用默认点位兜底,前四个默认槽位分别是 401(223,225)、402(131,128)、161(13,25)、165(25,108)。
  5. 当前客户端 Execute() 只把每条记录的 index / sceneid / x / y 写入本地彻地符箓缓存;首字节 reserved_1 没有被当前执行链使用。
  6. 客户端界面 Item_DunJiaShu.lua 最终通过 LuaFnGetCheDiFuLuPosInfo() 把槽位显示成“场景名 + 坐标”,但其中的剩余次数 count 与初始化标记 init 来自物品参数,不是 GCCheDiFuLuData 的内容。

另外,当前 Lua 协议定义里的 bis() 存在一个只在“服务端反序列化此 GC 包”时才会暴露的问题:它使用 if i < 30 then 判断,因此只会把前 29 条写入 self.list。不过现行服务端主链只发送这条包,不依赖该 bis() 路径,因此不会影响正常下发。

服务端落点

  • 协议定义:
    /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/define.lua
  • 脚本通用接口:
    /home/ubuntu/Game2/lualib/script_base.lua
  • 彻地符箓物品逻辑与默认点位:
    /home/ubuntu/Game2/services/scripts/obj/commonitem/893252.lua

关键代码

当前 Lua 协议定义

packet.GCCheDiFuLuData = {
    ctor = function(self)
        self.unknow_1 = 0
        self.size = 0
        self.list = {}
    end,
    bis = function(self, buffer)
        local stream = bistream.new()
        stream:attach(buffer)
        self.unknow_1 = stream:readuchar()
        self.size = stream:readuchar()
        if self.size > 0 then
            for i = 1, self.size do
                if i < 30 then
                    local l = {}
                    l.index = stream:readuint()
                    l.sceneid = stream:readuint()
                    l.x = stream:readuint()
                    l.y = stream:readuint()
                    table.insert(self.list, l)
                end
            end
        end
    end,
    bos = function(self)
        local stream = bostream.new()
        stream:writeuchar(self.unknow_1)
        stream:writeuchar(self.size)
        for i = 1, self.size do
            local l = self.list[i] or { index = 0, sceneid = 0, x = 0, y = 0 }
            stream:writeuint(l.index)
            stream:writeuint(l.sceneid)
            stream:writeuint(l.x)
            stream:writeuint(l.y)
        end
        return stream:get()
    end
}

当前请求与发送链

function request:CGAskCheDiFuLuData()
    skynet.call(my_scene, "lua", "char_ask_chedifulu_data", my_obj_id, self)
end

function scenecore:char_ask_chedifulu_data(my_obj_id)
    local obj_me = self:get_obj_by_id(my_obj_id)
    obj_me:send_chedifulu_data()
end
function human:send_chedifulu_data(index)
    self.chedifulu_data = self.chedifulu_data or {}
    local msg = packet_def.GCCheDiFuLuData.new()
    msg.list = {}
    if index then
        local data = self.chedifulu_data[index]
        if data then
            local l = {}
            l.index = tonumber(index)
            l.sceneid = data.sceneid
            l.x = data.x
            l.y = data.y
            table.insert(msg.list, l)
        end
    else
        for i = 1, define.CHEDIFULU_DATA_SIZE do
            local data = self.chedifulu_data[tostring(i - 1)]
            if data then
                local l = {}
                l.index = i - 1
                l.sceneid = data.sceneid
                l.x = data.x
                l.y = data.y
                table.insert(msg.list, l)
            end
        end
    end
    msg.size = #msg.list
    self:get_scene():send2client(self, msg)
end

脚本改单槽位时会立即触发回包

function script_base:SetCheDiFuLuData(selfId, index, sceneid, position)
    local human = self.scene:get_obj_by_id(selfId)
    human:set_chedifulu_data(index, sceneid, position)
end

function human:set_chedifulu_data(index, sceneid, position)
    self.chedifulu_data = self.chedifulu_data or {}
    index = tostring(index)
    self.chedifulu_data[index] = {
        sceneid = sceneid,
        x = math.ceil(position.x),
        y = math.ceil(position.y),
    }
    self:send_chedifulu_data(index)
end

彻地符箓默认点位

local default_transports = {
    ["0"] = { sceneid = 401, x = 223, y = 225},
    ["1"] = { sceneid = 402, x = 131, y = 128},
    ["2"] = { sceneid = 161, x = 13, y = 25},
    ["3"] = { sceneid = 165, x = 25, y = 108},
}

当前 Game.exe 的执行结论

GetPacketSize() = 16 * size + 2;

Execute() {
    for (i = 0; i < size && i < 30; ++i) {
        if (index[i] <= 29) {
            client_update_chedifulu_slot(index[i], sceneid[i], x[i], y[i]);
        }
    }
    return 2;
}

结论

GCCheDiFuLuData(1091) 在当前 Temp_Release_v0-07-0300 里的定位已经比较明确:

  1. 它是当前版本实际启用的“彻地符箓传送点数据同步包”。
  2. 包体为 reserved_1 + size + list[size],每条记录固定 16 字节,内容是 index / sceneid / x / y。
  3. 当前有效槽位上限是 30,索引使用 0 基编号。
  4. 服务端既支持玩家主动请求后的全量同步,也支持脚本改写单槽位后的单条刷新。
  5. 当前客户端执行链只消费条目列表本身,不使用首字节 reserved_1。
  6. 彻地符箓的剩余次数、初始化状态与默认点位策略并不由本包完整承载,而是分别来自物品参数和物品脚本兜底逻辑。

因此,把 GCCheDiFuLuData 归类为“彻地符箓 / 遁甲书传送点槽位同步包”是符合当前版本实际行为的。

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

本版积分规则

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

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

Powered by Discuz! X5.0

© 2001-2026 Discuz! Team.

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