《自由与荣耀》录像回放错误问题探究
综述
最近在做《自由与荣耀》的任务关打法演示录像,发现录像回放错误的问题确实很严重。
所谓录像回放错误,就是指游戏录像回放时未能正确还原此前你打的这局游戏的过程。例如本来一局你赢的游戏,录像回放时却变成是你输了。
《自由与荣耀》的录像文件记录了两部分信息。第一部分是随机数种子,它是一个整数。由随机数种子可以产生一系列的随机数,在游戏中用于几率的判定。例如在某局游戏中,电脑 AI 的兵工厂在 1 级技术时有 70% 几率造火龙坦克、有 30% 几率造密集雨,这种随机性都是由随机数决定。在回放录像时,通过随机数种子就能准确还原此前游戏中用过的随机数,保证电脑兵工厂每次随机造的东西都与当时游戏中一致。
第二部分记录了玩家的所有控制命令,例如选中单位、建造、移动、攻击等命令。这些命令在录像回放时都会被准确地还原。
按照预想,如果录像回放时能够正确加载战役的初始信息,并能够准确还原所有控制命令的话,那么就能够正确还原此前这局游戏的全部过程。但我们发现,《自由与荣耀》的录像回放功能不像《自由与荣耀Ⅱ》那样稳定,在任务关的录像回放中经常会出错,尤其是机器人方第 3、6、7、8 关和人类方第 10 关。
而且同一个录像文件,也不是一定就会回放报错的。你多试几次,它也可能会有一次就突然能正确回放了。
这个 BUG 目前应该是最复杂的,目前作者通过逆向分析游戏代码,也不能完全准确地判断 BUG 出现的原因、以至进行修复。目前只能说:录像报错问题,可能是任务关 AI 的 BUG 引起的。
Verify Failed 报错
在洪恩红字原版 V1.2 中,当执行一条控制命令时,游戏当前场景下的校验值与录像文件中记录的值不相等时,会出现如图所示的报错:

在洪恩版 V1.6.2 中,仍然会进行校验,但检测到错误时不会输出错误信息。
那么校验值是怎么计算的呢?
在每次玩家进行控制操作时,游戏会根据当前所有单位的位置,来计算一个校验和。这里的所有单位,不仅包括每个玩家的全部单位,也包括所有的晶矿和野外的树木、建筑等。《自由与荣耀》中每个单位都有三维坐标 (x, y, h)。游戏会分别计算所有单位的 x 坐标之和、y 坐标之和、h 坐标之和,再计算这三者的平方和,再开根号。即:

在一局游戏结束时,上述校验和会与对应的控制命令一起,记录在游戏录像文件 Juliet.pcs 中。回放录像时,每次执行游戏控制命令时,游戏会计算当前游戏场景下的校验和,与录像中记录的数值对比。例如上图中当前游戏场景下的校验和是 207864.250000,录像文件中记录的校验和是 207861.203125,出现了不一致,因此会报 Verify Failed 错误。
通过校验和的计算公式可以看出,一旦游戏中出现 Verify Failed 错误,就表示当前录像回放的游戏场景下至少有 1 个单位的位置坐标与此前游戏中的数值不同,或者当前游戏场景下的单位无法与此前游戏中的单位一一对应。
揪出罪魁祸首
机器人第 3 关时录像回放报错最频繁的一关,而且当游戏开始的 1.3 秒以内就会报错。
为了揪出罪魁祸首,作者把游戏放慢 125 倍,这样游戏基本时间单位 tick 就会拉长到 5 秒。然后进入机器人第 3 关,保证每 5 秒内都双击一次探测器,这样生成的录像文件中每 tick 都会有游戏控制命令。
接着我们回放录像,因为每 tick 都有控制命令,所以每 tick 也都会计算校验和,我们也就能够找出第一个存在校验和不一致的 tick 了。实测是游戏中的第 32 个 tick(即正常游戏的第 1.24 秒 ~ 1.28 秒)就会报 Verify Failed,也就是说在这时候就出现了第一个位置坐标与此前游戏中不一致的单位。
为了找出这个单位,作者至少要有一次错误回放和一次正确回放,然后到 tick = 32 的时间点,去记录游戏中全部 190 个单位的 x、y、h 坐标,然后进行对比。这个过程非常枯燥,而且遇到了一些麻烦,那就是 OllyDbg 下运行的游戏,录像全部正确回放,这可能与 OllyDbg 下游戏性能较低有关。后来在 Cheat Engine 下运行游戏,录像是有时正确回放,有时出错的,这才能够记录到错误回放中的单位坐标。
最终确定,是一个 VDragon (火龙突击坦克)的坐标发生了不一致:

然后我们回到游戏中,找到这辆火龙突击坦克,它就是蓝色电脑右下角基地中,最南边的那辆火龙坦克。
正确回放录像时,tick = 32 时这辆火龙坦克的位置:

错误回放录像时,tick = 32 时这辆火龙坦克的位置。看一下地上草的位置就能看出,比起正确回放时,坦克位置更靠左边一些,而且坦克炮口指向的位置也不同:

别看只是一辆坦克的位置出现差别。由于蝴蝶效应,由最初的小的差异,不断影响更多事件,产生更多差异(例如火龙坦克位置不同,导致附近工程车摆下采矿器的位置不同),最后差异越来越多,最终可能导致整个录像的剧情被完全改变。
深入追踪
虽然 Verify Failed 报错最初是在 tick = 32 的时间点,但实际最早产生不一致的时间点要比这还早得多。
早在 tick = 9 时,电脑 AI 就会命令这辆火龙坦克进行移动,但是前进的目的地就已经出现了不一致,因此你能看到坦克炮口朝向不同。
在 Verify Failed 之前,这个坦克就已经开始朝着不同的目的地前进了。但最开始的那一段路径还是一致的,后面路径出现分支的时候,才会导致坦克的位置坐标出现不一致,导致 Verify Failed。
深入追踪,电脑给火龙坦克下移动命令,涉及源代码是在 AIComputer2.cpp,也就是任务关的 AI。所以这个 BUG 是存在于任务关,不一定会影响多人游戏。
那更进一步,我还要问:为什么电脑会给火龙坦克的命令无法保证一致呢?
我追踪到最后,是涉及战场的黑雾问题。所谓黑雾,就是小地图上全黑的地方。例如蜘蛛是不能往全黑地方跳跃,雷达站和核弹基地也是不能往全黑地方进行轰炸和投放核弹。
在机器人第 3 关,录像正常回放和错误回放时,电脑 AI 对于某个坐标是否存在黑雾这件事情判断存在差别,导致了 AI 命令这辆火龙坦克前进的目的地位置出现不同。
这个 BUG 目前也只能追踪到这里了,很难修复。