半夜翻 trending,翻到一个名字很离谱的仓库:katiahayati/lucasartsifier。前半截看着像搞卢卡斯艺术那套格式的,点进去,通篇 Sierra。这期选手就它了。
一句话定调——把 Sierra 老冒险游戏反编译出来做静态分析、自动推导守卫、再编译回去打补丁的卡死终结者。
那批八十年代末的 Sierra 游戏有个通病:走错一步就永久卡死,存档读回来也救不了,只能从头开。它干的事就是把这种死局找出来,往游戏里塞一道守卫,让你压根走不到那儿去。补丁走的是 Sierra 当年发自家 bug 修复用的那套 loose patch 机制,原始文件一个字节不动,补丁文件删了就还原。动别人二十年前的游戏、不碰原件,这是基本礼貌,它懂。
真亮点在它不预设任何标题特定信息。
起始房间、胜利房间、死亡信号、调试标志,全是从游戏自己的代码里扒出来的。LSL2 那次分析,它自己找到起始房间 rm11、胜利房间 [86]、死亡信号 global101 == 1001,还有调试全局变量 [14, 100]。四款游戏的 config 里,那几个覆盖字段全是空的。
这个我服。省掉"每换一款游戏就手搓一份配置"这件事,才是它敢说自己游戏无关的底气。Leisure Suit Larry 2、King's Quest IV、King's Quest VI、Laura Bow 2,同一套引擎,SCI0 一路跨到 SCI1.1,1988 到 1992,全程没用一行游戏特定代码。
流水线本身不玄:二进制反编译成带类型的控制流 AST,扔成 JSON IR,再对这个 AST 做抽象解释,把路径条件拼成一张游戏图,边上挂着守卫、物品获取、物品丢失、寄存器写入。它连房间美术和障碍多边形都要读一遍——有些门是几何的,压根不在脚本里。
它找卡死的判据很锋利:物品在跨越前拿得到,跨越后拿不到,但之后还得用。就这一条模式,把"无限种卡死方式"收缩成一个能判定的问题。接着把游戏图压成强连通分量,也就是能自由漫游的区域,只有它们之间的单向边才可能把人滞留住,问题于是变成有限的。LSL2 里一口气捞出 15 个物品 softlock 加一个析取组。登船是单向跨越,工具顺着就推出哪些东西必须随身带过河。
顺手说个我觉得最有意思的:Spinach Dip 攥在手里过 rm138 是致命的,所以那道守卫带的是负文字——手里有它就不许跨。而且守卫安放的位置,正好是玩家还来得及把东西扔下船的地方。卡在你还守得住规矩的最后一刻。写这玩意的人是真玩过这些游戏的。还有个小的:会把必需品白白浪费掉的死胡同,会被单独中和,弹一句 "Just kidding!" 拦下来,不扣分。
门槛这块得说清楚。分析代码是 Python 3,纯标准库,零第三方依赖,这层舒服得不像话。但装之前你得先编两个工具链出来:一个 C# 写的反编译器,是 sci-tools 的 fork,多吐一份类型化 AST JSON;一个 C++ 写的 SCI 编译器,从 SCICompanion 移植过来在 Linux 上无头跑。后面那个是 GPL 的,混进 MIT 的仓库里,用之前自己留意边界。我认怂,这俩我都没自己编,只把仓库和分析输出摸了一圈,这句先声明在前头。
跑起来是一行:
python3 -m pipeline /path/to/game
加 --report 只分析不写盘,加 --skip-decompile 复用已有的 IR。但这一行的代价全在上游,别被界面清爽骗了。作者自己在 Ubuntu 24.04 容器里从零验过整套流程,测试套件冷启动跑完要 21 分钟。我就停在 report 那一步,没敢让它落地写补丁。
前面说它"游戏无关",这话我说满了,往回撤一点:准确讲,是在这四款 SCI 游戏上没用游戏特定代码。作者自己列的未来工作里,Quest for Glory 那几款还卡在状态爆炸里,打算靠抽象掉玩家属性、战斗和血量消耗品来治,没做完;AGI 引擎那一支更是还没动工。别把"四款"读成"全部"。
还有一条最老实、也是我最想让人看见的:到现在为止,没有任何一款游戏在打完补丁的版本上完成过一次连续通关。KQV 最接近——它的测试计划里每一行都在补丁游戏上玩过,包括终局,过程中还发现、纠正、退役了几个守卫。但也只是最接近。仓库 51 个 star、1 个 fork,冷清,好在 issue 区不像机器人自言自语。
适合谁:做反编译、程序分析、老游戏修复这几条线里任意一条的,都值得点进去看看。它那套"从获胜区域反推守卫条件、再放到还来得及遵守的最后一个时刻"的推导思路,挪到别的有状态空间的地方也不丢人。不适合谁:只想舒舒服服把 King's Quest 通一遍的,别碰,ScummVM 加个存档比这实在。想拿它当通用静态分析框架的也别来,那层抽象解释是贴着 SCI 字节码语义写的,扒不走。
候选池里我给 Quest for Glory 留了个位置,等作者哪天把那口状态爆炸理平了再说。值不值得挂个 star 蹲更新,自己翻两下 README 就有数。