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

洱海月 v0-07-0300 封包解析:ID 598 GCBusMove(载具开始移动通知)

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

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

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

×

GCBusMove 是当前项目里用于通知客户端“载具开始沿下一段路径移动”的广播包。它不负责逐帧同步载具当前位置,而是告诉客户端:哪辆载具、当前平面坐标是多少、下一目标点在哪里、应当按什么速度移动。

当前 Temp_Release_v0-07-0300 里,这条协议既保留在 Game.exe,也确实由 /home/ubuntu/Game2/services/scene/obj/bus.lua 发送。Lua 侧只有 bos() 没有 bis(),说明当前主线只把它当作服务端到客户端的单向移动通知包使用。

包信息

项目 内容
封包 ID 598
包名 GCBusMove
方向 GC 服务端 -> 客户端
固定包长 28
当前 Lua 协议定义 已定义,仅 bos()
当前 Lua 发送点 /home/ubuntu/Game2/services/scene/obj/bus.lua
主要作用 通知客户端指定载具从当前坐标开始,朝下一目标点按给定速度移动
相关包 GCNewBus_Move / GCBusStopMove / GCBusAddPassenger / GCBusRemoveAllPassenger

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

GCBusMove
GetPacketID()   = 598;
GetPacketSize() = 28;
Read            = 0x140610790;
Write           = 0x140610810;
Execute thunk   = 0x140610780 -> sub_1403325B0;

包体结构

当前 Game.exe 与 Lua 定义都能确认,这条包是固定 28 字节结构:

偏移 长度 字段 类型 含义
0x00 0x04 m_objID int32 载具对象 ID
0x04 0x04 world_pos_x float 当前平面 X 坐标
0x08 0x04 world_pos_y float 当前平面 Y 坐标
0x0C 0x04 next_pos_x float 下一目标点 X 坐标
0x10 0x04 next_pos_y float 下一目标点 Y 坐标
0x14 0x04 next_pos_z float 下一目标点 Z 坐标
0x18 0x04 speed float 本段移动速度

Lua 序列化顺序与 Game.exe 的 Read() / Write() 完全一致:

Read(stream) {
    read_i32(m_objID);
    read_f32(world_pos_x);
    read_f32(world_pos_y);
    read_f32(next_pos_x);
    read_f32(next_pos_y);
    read_f32(next_pos_z);
    read_f32(speed);
}

当前协议只携带“当前平面坐标” world_pos.x/y,并不包含当前 world_pos.z。也就是说,客户端真正依赖的是“从当前二维起点朝三维目标点移动”的通知,而不是一份完整三维当前位置快照。

当前实际行为

当前项目里,载具移动逻辑落在 /home/ubuntu/Game2/services/scene/obj/bus.lua:

  1. bus:start_patrol() 会根据巡逻路径和往返方向生成 move_path。
  2. 创建出第一段目标点后,立即调用 send_move_to() 广播 GCBusMove。
  3. 载具在 logic_move() 中按速度推进;当跨过当前路径点且后面还有下一段时,会更新自身坐标并再次调用 send_move_to(),通知客户端切换到下一段目标点。
  4. 当最后一个路径点走完后,move_path 被清空,转入 on_arrive_dest()。

这里有一个很重要的现状差异:

  • 当前 Lua 主线没有在 on_arrive_dest() 里发送 GCBusStopMove。
  • 当前实际做法是切换往返方向、让所有乘客下车,然后重新广播 create_new_obj_packet() 生成的 GCNewBus 或 GCNewBus_Move。

因此,GCBusMove 在当前版本里的职责更接近“开始下一段移动”或“切段移动”,而不是“完整移动生命周期通知”。

客户端 Execute() 的行为也比较直接:

  1. 先用 next_pos.x/y 做一次目标位置校验。
  2. 如果目标点非法,会抛出 "ERROR POSITION @ GCBusMoveHandler target"。
  3. 找到对应 m_objID 的客户端对象后,把一个内部移动命令(常量 43)和 next_pos + speed 下发给对象。

这说明客户端收到包后,不是直接把载具瞬移到目标点,而是把它交给本地对象运动系统按目标点与速度继续跑。

服务端落点

当前项目里与这条协议直接相关的落点如下:

  • 协议定义:
    • /home/ubuntu/Game2/services/game/packet.lua
  • 载具巡逻与移动广播:
    • /home/ubuntu/Game2/services/scene/obj/bus.lua
  • 到站后的乘客清理与新对象重发:
    • /home/ubuntu/Game2/services/scene/obj/bus.lua

关键代码

当前 Lua 协议定义

packet.GCBusMove = {
    xy_id = packet.XYID_GC_BUS_MOVE,
    bos = function(self, buffer)
        local stream = bostream.new()
        stream:writeint(self.m_objID)
        stream:writefloat(self.world_pos.x)
        stream:writefloat(self.world_pos.y)
        stream:writefloat(self.next_pos.x)
        stream:writefloat(self.next_pos.y)
        stream:writefloat(self.next_pos.z)
        stream:writefloat(self.speed or 0)
        return stream:get()
    end
}

当前 Lua 发送链

function bus:send_move_to()
    local world_pos = self:get_world_pos()
    local msg = packet_def.GCBusMove.new()
    msg.m_objID = self:get_obj_id()
    msg.world_pos = world_pos
    msg.next_pos = self.move_path[1]
    msg.speed = self:get_speed()
    self:get_scene():broadcast(self, msg, true)
end

function bus:start_patrol()
    local patrol_id = self:get_patrol_id()
    local partol = self:get_scene():get_patrol_path_by_index(patrol_id)
    if partol then
        self.move_path = self:get_athwart_path(partol)
        self:send_move_to()
    end
end

当前到站后的处理方式

function bus:on_arrive_dest()
    self.stop_time_timer = self:get_stop_time()
    local athwart = self:get_athwart()
    if athwart == 0 then
        athwart = 1
    else
        athwart = 0
    end
    self:set_athwart(athwart)
    self:passengers_off()
    local msg = self:create_new_obj_packet()
    self:get_scene():broadcast(self, msg, true)
end

当前 Game.exe 的执行结论

GetPacketID() = 598;
GetPacketSize() = 28;

Execute() {
    validate_target_position(next_pos_x, next_pos_y);
    target = find_object(m_objID);
    if (target) {
        send_move_command_43(target, next_pos_x, next_pos_z, next_pos_y, speed);
    }
    return 2;
}

结论

GCBusMove 在当前 Temp_Release_v0-07-0300 项目里的结论可以直接收敛为:

  1. 这条包的 ID 是 598,固定长度 28。
  2. 包体字段很简单,就是载具对象 ID、当前平面坐标、下一目标点和速度。
  3. 当前 Lua 只在载具开始巡逻或切到下一段路径时广播这条包。
  4. 当前协议不携带当前 world_pos.z,只发 world_pos.x/y 与完整的 next_pos.x/y/z。
  5. 当前客户端收到后会校验目标点,并把移动目标交给本地对象移动系统处理,而不是直接瞬移。
  6. 载具到达巡逻终点时,当前主线并不是发送 GCBusStopMove,而是切换方向、清乘客并重新广播新的对象状态包。

因此,GCBusMove 更适合归类为“载具分段移动启动通知包”,而不是完整的停止/刷新总控包。

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

本版积分规则

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

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

Powered by Discuz! X5.0

© 2001-2026 Discuz! Team.

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