传奇服务端脚本死循环 GOTO @宗派经验报错排查与修复方法

来源: 作者: 点击:
报错信息里写得很清楚,问题出在 QFunction 脚本的 @GetExp 触发段,执行了 GOTO @宗派经验 这条命令,而且一秒触发一次。@GetExp 是引擎内置的经验获取触发点,角色每次获得经验都会自动执行这一段。脚本里连续写了三个 goto,其中跳转到 @宗派经验 之后,执行完那一整段逻辑,脚本流程并没有真正切断,又回到了触发入口,再次执行 GOTO,如此反复就形成了闭环。

**GOTO 与 BREAK 的执行逻辑**

要理解为什么会循环,得先搞明白这两个命令的区别。goto 是无条件跳转,跳到指定标签后从那一行开始继续往下执行。执行完标签内的代码后,脚本不会自动停住,还会继续往下走,或者在某些情况下回溯到触发点 。break 的作用是立即终止当前脚本块的执行,执行到 break 之后,后面所有的语句都不会再解析 。

原脚本 @GetExp 段里写了三个 goto,最后才跟一个 break。这个写法的问题在于,前两个 goto 跳出去执行完,如果目标段里没有 break 或者没有把流程彻底断掉,脚本会回到 @GetExp 继续跑,跑到第三个 goto,又跳走,又回来,循环就开始了 。而且三个 goto 连续堆叠本身就容易出问题,引擎在处理多重跳转时,执行顺序和返回逻辑容易混乱 。

**@宗派经验 段本身的问题**

再往下看 @宗派经验 这段脚本,里面做了几件事:从宗主名单里判断当前角色是不是宗主,然后用 GetRandomName 从经验文件里随机取一行名字,用 mov 和 inc 做经验数值的累加,最后用 DelTextList 和 AddTextList 把旧数据删掉、把新数据写进去。

这段逻辑本身没有明显的语法错误,但有一个隐患。GetRandomName 这个命令在文件为空或者读取不到有效行的时候,赋值行为可能不符合预期。有技术文章提到过类似的情况:GetRandomText 在读取到空值的时候,不会把变量清空,而是保留上一次的值 。如果 @宗派经验 被高频触发,前一次读到的名字还留在变量里,下一次读取又拿到同样的旧值,变量内容不变,脚本判断不出“该停了”,就会一直循环下去。解决办法是在使用 GetRandomName 之前,先用 mov 把 S28 清空,比如写一行 `mov S28`,确保每次读取前变量是干净的。

**脚本执行顺序的修正**

@GetExp 段的核心问题是触发机制和跳转逻辑冲突。@GetExp 是经验获取时自动触发的,角色只要在打怪、吃经验丹、做任务,这个触发点就会不断被激活。如果每次激活都无条件跳转到 @宗派经验,而 @宗派经验 内部又没有任何条件判断来阻止重复执行,那这个循环就无法打破 。

修正的思路是在 @GetExp 里加上条件判断,只有满足特定条件时才执行跳转。比如用 CHECKNAMELIST 先判断当前角色是否在宗主名单里,只有宗主角色才需要执行宗派经验的计算逻辑,非宗主角色触发 @GetExp 时直接跳过,不执行 GOTO 。这样一来,大部分角色获得经验时不会触发这段逻辑,循环的压力就小了很多。

另外,@GetExp 里三个 goto 连着写本身就不规范。一个 #ACT 块里最好只用一个 goto 命令,多个跳转容易导致执行顺序错乱 。如果确实需要触发多个不同的逻辑段,应该用条件判断分开处理,或者把它们合并到一个统一的流程节点里,按顺序执行。

**UPGRADEITEMEX 之外的配置检查**

除了脚本本身的逻辑,服务端的配置参数也值得检查一下。在 Mir200 文件夹下的 !Setup.txt 文件里,找到 ScriptGotoCountLimit 这个参数,默认值一般是 10,意思是脚本循环跳转超过 10 次就会被引擎强制中断并报错 。如果脚本确实需要多次循环,可以把这个数值调大一些,比如改成 10000 到 50000 之间,但不能改得太大,否则真遇到死循环的时候,引擎要跑很久才能检测到,期间会持续消耗服务器资源 。

还有一个替代方案是用 delaygoto 代替普通的 goto。delaygoto 的语法是 `delaygoto 时间 @标签`,时间单位是毫秒。比如 `delaygoto 1000 @宗派经验` 表示延迟 1 秒后再跳转 。延迟跳转的好处是给引擎留出了处理时间,不会在同一瞬间反复触发同一个逻辑段,能有效降低死循环的触发概率。

**修正后的脚本结构**

综合以上分析,@GetExp 段应该改成先判断、再跳转、最后用 break 终止的结构。@宗派经验 段需要在 GetRandomName 之前加一行 mov 清空变量,并且确保这段逻辑执行完毕后有明确的终止指令。

如果服务端支持,把普通 goto 换成 delaygoto 是最稳妥的做法。延迟跳转加上条件判断,双保险基本可以杜绝这类死循环报错。修改完成后记得重启 M2 引擎让脚本重新加载,否则改动的效果不会立即生效。