CGSectOper 是当前版本用于提交武道修行操作的请求包。当前 Lua 服务端会把这条包转到场景服,再由角色对象执行 study_sect(),本质上就是“请求修行指定武道 / 天赋”。
当前 Game.exe 与当前 Lua 服务端都能确认,这条包固定携带两个 uint32 字段。结合当前客户端界面脚本 Player:Lua_AskSectOper(0, g_Talent_Studyup_saveid) 可以进一步确认:第一个字段是操作码,当前界面调用值固定为 0;第二个字段是当前选中的武道 ID,也就是实际用于修行的 talent_id。
包信息
| 项目 |
内容 |
| 封包 ID |
980 |
| 包名 |
CGSectOper |
| 方向 |
CG 客户端 -> 服务端 |
| 固定包长 |
8 |
| 成功后续回包 |
GCSectDetail |
| 失败表现 |
服务端直接提示文本,不额外返回专门错误包 |
| 主要作用 |
提交武道修行请求,提升指定武道等级 |
当前 Game.exe 的虚函数结论为:
GetPacketID() = 980;
GetPacketSize() = 8;
包体结构
按当前 Game.exe 与当前 Lua 服务端现状,这条包固定为 8 字节。
| 偏移 |
长度 |
字段 |
类型 |
含义 |
0x00 |
0x04 |
operation |
uint32 |
操作码;当前客户端界面调用值固定为 0 |
0x04 |
0x04 |
talent_id |
uint32 |
要修行的武道 / 天赋 ID |
当前实际行为 / 模式说明
- 当前 Lua 协议入口
request:CGSectOper() 会把请求直接转给场景服 char_sect_oper()。
- 场景服当前实现只消费
talent_id,并直接调用 obj_me:study_sect(so.talent_id)。
operation 在当前 Lua 主链里没有参与分支判断;结合当前客户端界面脚本,它目前更像是保留的操作码字段。
human:study_sect() 会先调用 check_can_study_sect() 做完整校验,包括:
- 武道 ID 是否存在
- 当前等级是否已满
- 领悟点是否足够
- 前置武道是否已满足
- 武道修行等级是否达到要求
- 同层冲突武道是否已经学习
- 校验通过后,服务端会扣除领悟点、提升对应武道等级,并下发
GCSectDetail 刷新当前武道面板。
- 校验失败时,当前实现主要通过
notify_tips() 直接提示,例如“已点满”“武道领悟点不足”“需先学习前置武道”“不可同时修行”等。
服务端落点
- 协议定义:
/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
- 客户端界面调用参考:
客户端/Interface/Talent_Studyup/Talent_Studyup.lua
关键代码
当前 Lua 协议定义
packet.CGSectOper = {
xy_id = packet.XYID_CG_SECT_OPER,
bis = function(self, buffer)
local stream = bistream.new()
stream:attach(buffer)
self.operation = stream:readuint()
self.talent_id = stream:readuint()
end
}
当前 Lua 请求入口与场景处理
function request:CGSectOper()
skynet.call(my_scene, "lua", "char_sect_oper", my_obj_id, self)
end
function scenecore:char_sect_oper(who, so)
local obj_me = self:get_obj_by_id(who)
obj_me:study_sect(so.talent_id)
end
当前角色修行逻辑
function human:study_sect(talent_id)
if not self:check_can_study_sect(talent_id) then
return
end
local talent = self:get_talent()
local study = self:get_study_talent(talent_id)
local sect_info = configenginer:get_config("sect_info")
sect_info = sect_info[talent_id]
local cost_point = sect_info["消耗"][study.level + 1]
talent.understand_point = talent.understand_point - cost_point
talent.cost_point = (talent.cost_point or 0) + cost_point
study.level = study.level + 1
self:send_talent(0)
end
当前客户端界面调用参考
function Talent_Studyup_Skillup_Up_Clicked()
Player:Lua_AskSectOper(0, g_Talent_Studyup_saveid)
end
当前 Game.exe 的读写与执行结论
GetPacketID() = 980;
GetPacketSize() = 8;
Read(stream) {
read_u32(operation);
read_u32(talent_id);
}
Write(stream) {
write_u32(operation);
write_u32(talent_id);
}
Execute() {
return 2;
}
结论
CGSectOper 的封包 ID 是 980,固定长度 8 字节。
- 包体字段已经可以明确命名为
operation + talent_id,不需要再使用 unknow_x。
- 当前版本真正参与修行逻辑的是
talent_id;operation 在当前 Lua 主链中未被使用,当前客户端界面调用值固定为 0。
- 这条包的实际作用是提交武道修行请求,成功后通过
GCSectDetail 刷新武道面板,失败时主要走直接提示文本。
|