这次记录一个很典型、也很容易被误判成客户端界面问题的老坑:帮会城市里建立商业路线时,输入某个帮会 ID 后,系统总提示“与该帮会的商线已经存在”,可实际上这个目标帮会明明还没建过商线。
一开始看上去像是客户端 SetCommerceNet 界面没刷新,或者商业路线列表包发错了。但真正把链路走完后,根因其实在服务端收包结构上。
技术员:雪舞
一、问题现象
线上测试时,出现了下面这种情况:
- 帮会
2 建立到帮会 0 的商业路线,成功
- 继续建立到帮会
1,却提示“与该帮会的商线已经存在”
- 但通过服务端调试接口直接创建时,
0 和 1 两条商线都能成功建立
这说明一件事:
- 服务端核心建商线逻辑本身没坏
- 出问题的是客户端发来的目标帮会 ID,服务端很可能没读对
二、排查思路
这次排查分成了两段:
1. 先确认服务端逻辑是否正常
直接调用 .Dynamicscenemanager 的调试接口测试,结果能连续成功创建多条商线,说明 apply_city_road_opt() 没问题。
2. 再确认客户端到服务端的请求包是否被正确解析
重点检查了服务端的城市操作请求结构 CGWPacket_CityOpt,最终发现这里的字段偏移不对。
问题文件在这里:
\home\ubuntu\Game2\services\game\packet.lua
三、根因分析
服务端原本的 CGWPacket_CityOpt.bis() 是这样读的:
***付费内容***
表面上看没问题,但和 Game.exe 实际发包结构对照后发现:
- 前两个
uchar 后面还有 2 字节保留位
m_TargetGuildID 后面也还有 2 字节保留位
也就是说,服务端少读了两次保留字段,导致后面所有字段整体错位。
这就是为什么会出现这种诡异现象:
- 你输入的是帮会
1
- 服务端实际读出来的
m_TargetGuildID 却可能还是 0
- 如果之前已经和
0 建过商线,就会误提示“商线已存在”
四、最终修复写法
最终修复后的代码如下,直接替换 CGWPacket_CityOpt 的 bis 即可:
***付费内容***
对应位置:
\home\ubuntu\Game2\services\game\packet.lua
五、为什么这个改法最稳
这个修法稳的原因很简单:
- 不改客户端
- 不碰商业路线核心业务逻辑
- 只修正服务端对客户端请求包的解析结构
- 属于标准的协议对齐修复
换句话说,这不是绕路处理,也不是打补丁兜底,而是把服务端收包恢复到和客户端协议一致的正确状态。
六、修复后效果
修复并完整重启服务端后,商业路线建立恢复正常:
- 可以先建立到帮会
0
- 再建立到帮会
1
- 不会再错误提示“与该帮会的商线已经存在”
如果需要验证当前帮会的商线数据,可以用控制台执行:
bash nc.sh 6002
call .Dynamicscenemanager "get_city_road_debug_by_guild", 2
正常情况下会看到类似:
road_count:2
[1]guild=0 ...
[2]guild=1 ...
七、补充说明
还有个现象容易一起被问到:
- 如果输入的目标帮会 ID 和自己帮会 ID 一样
- 界面会“没反应”,也不弹提示
这个不是本次服务端 bug 没修好,而是 Game.exe 在本地发包前就先拦截掉了,所以服务端根本收不到请求。
服务端虽然也有这层校验,但这条校验只有在请求真正发到服务端后才会触发:
if target_guild_id == guild.id then
return { err = "same_target_guild", tips = "不能和自己的帮会建立商线" }
end
所以这部分结论是:
- 规则上,本来就不允许和自己帮会建商线
- 现象上没提示,是客户端本地静默拦截
- 在“不改客户端”的前提下,这个交互提示没法只靠服务端补出来
八、结语
这类问题最容易踩的坑,就是看到界面显示异常就先怀疑回包,其实很多时候真正出错的是请求包字段错位,尤其是这种老协议、老客户端、服务端重写或迁移过的项目里最常见。
这次商业路线的问题,本质上就是一个典型的协议解析偏移错误。把 CGWPacket_CityOpt 结构对齐后,整个功能就恢复正常了。
剩余 31% 内容需要支付 66.00
金币 后可完整阅读
支持付费阅读,激励作者创作更好的作品。
|