找回密码
 register
搜索
查看: 23|回复: 0

洱海月 工程任务无法进入副本问题修复教程

[复制链接]
  • 打卡等级:本地老炮
  • 打卡总天数:533
  • 打卡月天数:22
  • 打卡总奖励:530
  • 最近打卡:2026-06-24 01:45:59
Waylee 发表于 2026-4-10 01:47 | 显示全部楼层 |阅读模式 | Google Chrome | Windows 10

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

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

×

一、先说结论

这次要修的不是“某一个帮会任务脚本坏了”,而是整套老 Lua4.0 帮会城市任务脚本,迁到当前 Lua5.4 + skynet 服务端之后,副本兼容层没有补完整。

表面现象是:

  1. 接任务正常
  2. 点进入副本也会走逻辑
  3. 但人物就是进不去
  4. 有时还会报这类错误
attempt to compare number with boolean
./lualib/copyscenemanager_core.lua:127: assertion failed!

或者更隐蔽一点:

  1. 不报错
  2. 副本看起来也创建了
  3. 但是角色没有被正常传进去

这类问题最容易误判成:

  1. 客户端没发包
  2. 副本管理器有问题
  3. 某个单独任务脚本写坏了

但这次结合当前正在使用的 Game.exe、当前 Lua 服务端、以及老版本城市任务脚本的实际写法来看,根因非常明确:

不是客户端问题,必须只改服务端。

并且这次不是只改一个文件就完事,而是要补两层:

  1. lualib/script_base.lua
  2. services/scripts/event/city/*.lua

当前这一套 city 目录里,一共是 49 个独立 Lua 文件,不是再靠 module.lua 或聚合脚本兜底,所以兼容代码必须同步进这些单文件里。


二、问题现象

这次排查期间,出现过三种典型表现。

1. 布尔值和数字比较直接炸掉

attempt to compare number with boolean

比如:

if IsHaveMission(sceneId, selfId, missionId) > 0 then

老城市脚本默认 IsHaveMission() 返回的是 1/0
但当前底层实际返回的是 true/false
结果就是脚本里一旦写了 > 0== 0<= 0 这种判断,就会直接炸。

2. 副本创建时断在 Copyscenemanager

日志类似:

./lualib/copyscenemanager_core.lua:127: assertion failed!

这不是副本管理器本身坏了,而是旧脚本调用 LuaFnCreateCopyScene(sceneId) 的方式太老,传进去的配置字段不完整。

当前副本管理器至少要拿到这些关键字段:

  1. conf.sn
  2. conf.source
  3. conf.params[1]

老脚本没补这些字段时,就会直接断言。

3. 副本创建成功,但人物不进去

这个最坑,因为它不一定报错。

根因是老脚本里大量使用的是旧版 NewWorld 调用方式:

NewWorld(sceneId, selfId, destSceneId, x, y, clientRes)

但当前底层实际接口是:

script_base:NewWorld(selfId, dest_scene_id, sn, x, y, client_res)

也就是说:

  1. 旧脚本传的是“源场景ID + 自己ID + 目标场景ID”
  2. 新底层要的是“自己ID + 目标场景ID + 副本SN”

如果不做兼容转换,就会出现:

  1. 副本场景可能已经分配出来了
  2. 角色却没有正确保存副本 SN
  3. 最终看起来像“点了没反应”

三、根因拆解

这次真正缺的,是旧帮会城市脚本到新服务端之间的四个兼容点。

1. IsHaveMission() 返回值类型不兼容

老脚本按 1/0 写逻辑。
当前底层返回布尔值。
所以所有任务判断都会不稳定。

2. LuaFnCreateCopyScene() 没补副本配置

旧脚本传参过于简化。
当前副本管理器需要 sn / source / params[1]
这一步不补,副本创建链路就会断。

3. NewWorld() 旧签名没有做兼容封装

副本场景创建出来后,旧脚本还是拿旧接口传送。
当前底层没法自动猜出副本 sn,所以人物不会被正确送进去。

4. LuaFnIsCanDoScriptLogic() / LuaFnIsObjValid() 也有 1/0 兼容问题

很多副本脚本在 OnCopySceneReady、组队成员遍历、传送判断时,都写了这种条件:

if LuaFnIsCanDoScriptLogic(sceneId, leaderObjId) ~= 1 then
    return
end

如果底层直接回布尔值,旧脚本会把正常对象也误判成异常状态,于是提前 return

所以这次修复不是“加一个判断”那么简单,而是要把旧城市脚本依赖的运行时环境补完整。


四、第一处修改:修 script_base.luaLuaFnCreateCopyScene

文件:

/home/ubuntu/Game2/lualib/script_base.lua

LuaFnCreateCopyScene 改成下面这样:

function script_base:LuaFnCreateCopyScene(config)
    assert(type(config) == "table", type(config))
    config.params = config.params or {}
    if config.params[1] == nil then
        config.params[1] = self.script_id
    end
    if config.sn == nil then
        config.sn = self:LuaFnGenCopySceneSN()
    end
    config.source = skynet.self()
    local dest_scene_id = skynet.call(".Copyscenemanager", "lua", "select", config)
    return dest_scene_id
end

这段代码的作用很直接:

  1. 保证 config 必须是表
  2. 自动补 params
  3. 自动补 params[1] = self.script_id
  4. 自动补副本 sn
  5. 自动补 source = skynet.self()

这样老城市脚本只要把配置表拼出来,就能正常交给当前副本管理器。

这里要特别注意一件事:

不要再沿用那种只传一个 sceneId 然后让底层自己猜全部配置的思路。
当前这套服务端不是那个时代的运行模型了,副本配置必须明确补齐。


五、第二处修改:在 event/city/*.lua 里补 get_copy_scene_config

文件范围:

/home/ubuntu/Game2/services/scripts/event/city/*.lua

这次不是只改 ecity_0102eliminatethieves.lua 一个文件。
而是所有 city 目录下的独立脚本,都要带这个兼容方法。

以任意一个城市任务脚本为模板,比如:

/home/ubuntu/Game2/services/scripts/event/city/ecity_0102eliminatethieves.lua

加入或改成下面这样:

***付费内容***

这段代码解决的是“旧脚本能描述副本,但描述得不完整”的问题。

重点补了这些字段:

  1. sn
  2. params
  3. params[1]
  4. client_res

其中 client_res 很关键。
因为当前客户端切场景时,需要匹配正确的场景资源编号。
副本能创建出来,不代表客户端一定能正常接收和展示。


六、第三处修改:给旧版 NewWorld 调用方式做兼容

还是同一个范围:

/home/ubuntu/Game2/services/scripts/event/city/*.lua

在脚本环境表里,把 NewWorld 这段兼容进去:

CallScriptFunction = function(target_script_id, func_name, ...)
    return current_script():call_city_script(target_script_id, func_name, ...)
end,
NewWorld = function(scene_id, self_id, dest_scene_id, x, y, client_res)
    local script = current_script()
    local target_scene_id = tonumber(dest_scene_id) or dest_scene_id
    local sn
    if type(target_scene_id) == "number" and target_scene_id >= define.COPY_SCENE_BEGIN then
        sn = script:call_base("LuaFnGetCopySceneData_Sn", target_scene_id)
        if sn == define.INVAILD_ID then
            sn = nil
        end
    end
    return script:call_base("NewWorld", self_id, target_scene_id, sn, x, y, client_res)
end,
LuaFnTryRecieveItem = function(...)
    return current_script():call_base("TryRecieveItem", ...)
end,

这段兼容层解决的是“老脚本还在按老签名传送”的问题。

核心逻辑是:

  1. 先拿到老脚本传进来的 dest_scene_id
  2. 判断它是不是副本场景
  3. 如果是副本场景,就再通过 LuaFnGetCopySceneData_Sn 找到它对应的 sn
  4. 最后再按当前底层真正需要的签名调用:
script:call_base("NewWorld", self_id, target_scene_id, sn, x, y, client_res)

如果不做这层转换,很多帮会任务副本会表现成:

  1. 副本分配成功
  2. 任务逻辑继续跑
  3. 玩家却不进副本

七、第四处修改:把布尔返回值统一转回旧脚本习惯的 1/0

这一块同样在:

/home/ubuntu/Game2/services/scripts/event/city/*.lua

1. 先修 LuaFnIsCanDoScriptLogicLuaFnIsObjValid

把这两段兼容进去:

LuaFnIsCanDoScriptLogic = function(...)
    local result = current_script():call_base("LuaFnIsCanDoScriptLogic", ...)
    return result and 1 or 0
end,
LuaFnIsObjValid = function(...)
    local result = current_script():call_base("LuaFnIsObjValid", ...)
    return result and 1 or 0
end,

这样旧脚本里这些判断才能恢复正常:

if LuaFnIsCanDoScriptLogic(sceneId, leaderObjId) ~= 1 then
    return
end

if LuaFnIsObjValid(sceneId, mems[i]) == 1 then
    ...
end

2. 再修 IsHaveMission

setmetatable(env, { __index = function(_, key) ... end }) 这一层里,把 IsHaveMission 的结果统一转成 1/0

local result = script_base[key](script, table.unpack(args))
if key == "IsHaveMission" then
    return result and 1 or 0
end
return result

这一步非常关键。

因为老帮会任务脚本里到处都是这种写法:

if IsHaveMission(sceneId, selfId, missionId) > 0 then
if IsHaveMission(sceneId, selfId, missionId) == 0 then
if IsHaveMission(sceneId, selfId, missionId) <= 0 then

如果你只修副本创建,不修这里,就会继续出现:

attempt to compare number with boolean

八、为什么这次必须批量同步到全部 city 文件

很多人会想先只修一个,比如:

ecity_0102eliminatethieves.lua

这样做只能把“某一个任务”修通,后面换另一个帮会任务时还是会继续炸。

原因很简单:

  1. 当前 services/scripts/event/city 目录已经不是老式共享模块结构
  2. 现在是 49 个独立 Lua 文件 各自内嵌运行环境
  3. 兼容层不在公共 module.lua 里自动继承

所以正确做法不是“修一个任务文件试试”,而是把下面这些兼容段同步到全部城市任务脚本:

  1. get_copy_scene_config
  2. NewWorld 旧签名兼容
  3. LuaFnIsCanDoScriptLogic 返回值兼容
  4. LuaFnIsObjValid 返回值兼容
  5. IsHaveMission 返回值兼容

如果你的正式服目录结构和这次一样,那么最终要上传的是:

/home/ubuntu/Game2/lualib/script_base.lua
/home/ubuntu/Game2/services/scripts/event/city/*.lua

也就是说:

  1. script_base.lua 1 个文件
  2. event/city 目录下 49 个 Lua 文件

九、建议的上传清单

这次修复如果你要往正式服发,按下面这个清单最稳:

必传

ubuntu/Game2/lualib/script_base.lua
ubuntu/Game2/services/scripts/event/city/*.lua

不需要上传

客户端任何文件

这次问题的根因在服务端兼容层,不在客户端。
所以博客里也建议明确写一句:

以当前 Game.exe 为准,禁止改客户端,只修服务端。


十、测试清单

这次修完以后,我建议至少做下面几组测试。

1. 基础进入副本测试

  1. 接一个帮会任务
  2. 点进入副本
  3. 确认角色是否真正切进副本地图
  4. 确认不是只创建了副本但人物留在原场景

2. 队伍进入测试

  1. 组队接任务
  2. 由队长发起进入副本
  3. 确认队员是否也能正常进入
  4. 确认不会卡在 LuaFnIsCanDoScriptLogic ~= 1

3. 任务状态判断测试

  1. 接任务后点击进入
  2. 放弃任务后再点进入
  3. 观察 IsHaveMission 判断是否正常
  4. 确认不再出现 attempt to compare number with boolean
付费看帖
剩余 8% 内容需要支付 66.00 金币 后可完整阅读
支持付费阅读,激励作者创作更好的作品。
您需要登录后才可以回帖 登录 | register

本版积分规则

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

GMT+8, 2026-6-24 05:30 , Processed in 0.061049 second(s), 26 queries .

Powered by Discuz! X5.0

© 2001-2026 Discuz! Team.

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