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

洱海月 v0-07-0300 封包解析:ID 239 CGUseAbility(生活技能操作请求)

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

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

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

×

CGUseAbility 是客户端向服务端发起生活技能操作的请求包。

包信息

项目 内容
封包 ID 239
包名 CGUseAbility
直接响应 GCAbilityResult
响应 ID 533
附加同步 GCAbilityAction / GCAbilitySucc
附加同步 ID 812 / 70
作用 发起一次生活技能操作,并携带配方、平台对象和材料位信息

包体结构

这条包在当前项目里需要分两层理解:

  • 按当前 Game.exe 类定义,包体长度是 15 字节。
  • 按当前 Lua 服务端主链,实际只读取前 11 字节。

按当前 Game.exe 类结构可先这样记录:

偏移 长度 字段 类型 含义
0x00 0x02 ability uint16 生活技能 ID
0x02 0x04 prescription int32 配方 ID
0x06 0x04 platform_obj_id uint32 辅助平台对象 ID
0x0A 0x01 mat_index uint8 材料背包位
0x0B 0x04 client_flag uint32 当前 Game.exe 额外客户端开关,Lua 主链未读取

当前 Lua 主链真正参与处理的是:

  • ability
  • prescription
  • platform_obj_id
  • mat_index

总长度:

当前 Game.exe:15 字节
当前 Lua 主链有效读取:11 字节

回包结构

GCAbilityResult

这是当前最直接的响应包,用于返回本次能力操作是否允许开始,或中途失败结果。

按当前 Lua 主链结构可按下面理解:

偏移 长度 字段 类型 含义
0x00 0x02 ability uint16 生活技能 ID
0x02 0x04 prescription int32 配方 ID
0x06 0x04 result int32 操作结果码

长度说明:

当前 Lua 主链读写:10 字节
当前 Game.exe GetPacketSize:12 字节

GCAbilityAction

这是当前能力操作开始时的广播包。

偏移 长度 字段 类型 含义
0x00 0x04 m_objID uint32 角色对象 ID
0x04 0x04 logic_count uint32 逻辑计数
0x08 0x02 ability uint16 生活技能 ID
0x0A 0x04 prescription int32 配方 ID
0x0E 0x04 target_obj_id int32 平台对象 ID
0x12 0x01 begin_or_end uint8 开始或结束标记

总长度:

19 字节

GCAbilitySucc

这是当前能力成功产出后的成功通知包。

偏移 长度 字段 类型 含义
0x00 0x02 ability uint16 生活技能 ID
0x02 0x04 prescription int32 配方 ID
0x06 0x04 item_index uint32 产出物品 ID
0x0A 0x01 num uint8 产出数量
0x0B 0x01 padding uint8 当前 Lua 固定补 0

总长度:

12 字节

当前实际行为

  • 当前 msgagent.lua 先处理这条包。
  • 如果 ability 命中 define.COMPOUND_MAT_ITEM_INDEX,服务端会先检查 mat_index 指向的背包位材料是否属于该技能允许的材料。
  • 材料校验不通过时,当前实现只记录 log_char_use_ability_rec 日志并直接返回,不继续进入场景服主链。
  • 正常情况下,请求会进入 scenecore:char_use_ability()。
  • 场景服会先检查角色是否死亡、是否可行动、当前是否忙碌、是否已处于生活技能操作状态。
  • 如果 ability 在配置表里不存在,当前函数会直接 return,不会继续发结果包。
  • 校验通过后,服务端会把本次操作写入 ability_opera,包括技能 ID、配方 ID、平台对象 ID、材料背包位和操作时长。
  • 随后调用 AI 的 push_command_use_ability(),并立即回一个 GCAbilityResult。
  • 如果本次操作正式开始,角色会广播 GCAbilityAction,并把 begin_or_end 设为 1。
  • 当前项目里只看到 begin_or_end = 1 的开始广播,未看到对应的结束广播。
  • 能力完成后,由具体能力脚本决定结果;成功时通常会发 GCAbilitySucc。
  • 当前 character.lua 的失败收尾分支把 msg.result 写成了 msg.resilt,这会导致该分支的 GCAbilityResult 结果字段无法按预期写入。

字段说明

  • ability:本次要执行的生活技能 ID。
  • prescription:本次要使用的配方 ID。
  • platform_obj_id:辅助平台对象 ID,例如工作台、采集点或相关操作对象。
  • mat_index:材料所在背包位。
  • client_flag:当前 Game.exe 额外带出的客户端开关字段;当前 Lua 主链未读取,也未参与当前项目主逻辑。

服务端落点

  • 协议定义:services/game/packet.lua
  • 请求入口:services/msgagent.lua
  • 场景处理:services/scene/scenecore.lua
  • 操作开始广播:services/scene/obj/character.lua
  • 能力执行框架:lualib/abilityenginer.lua
  • 能力实现:services/scene/ability/*.lua
  • 成功结果发送:lualib/script_base.lua

关键代码

当前 Lua 协议定义

packet.CGUseAbility = {
    xy_id = packet.XYID_CG_USEABILITY,
    bis = function(self, buffer)
        local stream = bistream.new()
        stream:attach(buffer)
        self.ability = stream:readushort()
        self.prescription = stream:readint()
        self.platform = stream:readuint()
        self.mat_index = stream:readuchar()
    end
}

当前请求入口与材料校验

function request:CGUseAbility()
    local compound_mat_item_indexs = define.COMPOUND_MAT_ITEM_INDEX[self.ability]
    if compound_mat_item_indexs then
        local baglist = skynet.call(my_scene, "lua", "call_human_function", my_obj_id, "get_item_bag_list")
        local mat = baglist[self.mat_index]
        assert(mat, self.mat_index)
        local item_index = mat.item_index
        if compound_mat_item_indexs[item_index] == nil then
            log_char_use_ability(self, mat)
            return
        end
    end
    skynet.call(my_scene, "lua", "char_use_ability", my_obj_id, self)
end

当前场景服处理

human:reset_ability_opera()
local ability_opera = human:get_ability_opera()
ability_opera.ability_id = use.ability
ability_opera.pres_id = use.prescription
ability_opera.obj = use.platform
ability_opera.max_time = ability["操作时间基数"]
ability_opera.mat_bag_index = use.mat_index

local res = human:get_ai():push_command_use_ability()
local msg = packet_def.GCAbilityResult.new()
msg.ability = use.ability
msg.prescription = use.prescription
msg.result = res or define.OPERATE_RESULT.OR_ERROR
self:send2client(human, msg)

当前开始广播

local msg = packet_def.GCAbilityAction.new()
msg.m_objID = self:get_obj_id()
msg.logic_count = self:get_logic_count()
msg.ability = ability_opera.ability_id
msg.prescription = ability_opera.pres_id
msg.target_obj_id = ability_opera.obj
msg.begin_or_end = 1
self:get_scene():broadcast(self, msg, true)

当前成功结果

local msg = packet_def.GCAbilitySucc.new()
msg.ability = ability_id
msg.prescription = prescription["index"]
msg.item_index = result_id
msg.num = result_num
human:get_scene():send2client(human, msg)

结论

CGUseAbility 本质上就是旧版客户端的生活技能操作请求包。

当前项目里真正要记住的只有六点:

  1. 这条包的 ID 是 239。
  2. 当前 Game.exe 类大小是 15 字节,但 Lua 主链实际只读取前 11 字节。
  3. 当前真正参与业务的核心字段是 ability、prescription、platform_obj_id 和 mat_index。
  4. 直接响应包是 GCAbilityResult,当前 Lua 主链有效结构是 10 字节;附加同步主要是 GCAbilityAction 和 GCAbilitySucc。
  5. 合成类能力会先校验 mat_index 指向的材料是否合法,不合法时当前实现只记日志,不继续处理。
  6. 当前项目里 GCAbilityAction 只看到开始广播,没有看到结束广播;能力收尾失败分支还存在 msg.resilt 拼写错误。
您需要登录后才可以回帖 登录 | registerss

本版积分规则

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

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

Powered by Discuz! X5.0

© 2001-2026 Discuz! Team.

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