Show HN: 自动检测并修补Sierra游戏中的死局状态
摘要
该工具使用静态分析自动检测并修补经典Sierra冒险游戏中的无法获胜状态,确保游戏保持可玩性,避免死锁。
查看缓存全文
缓存时间: 2026/08/19 07:05
katiahayati/lucasartsifier
来源:https://github.com/katiahayati/lucasartsifier
Sierra 软死锁分析器
针对30年前冒险游戏的静态分析工具
本工具可反编译 Sierra SCI 游戏,通过抽象解释将反编译后的脚本转化为包含受保护的房间转换、物品移动和剧情标记写入的图形结构,自动识别软死锁——即游戏仍可接受输入但胜利条件已悄然无法达成的状态,并生成、验证、编译用于防止此类死锁的保护机制,最终完成安装。
该工具无需预先声明任何游戏信息:起始房间、胜利房间、死亡信号及调试标记均从游戏代码本身自动发现。与 LucasArts 游戏不同,Sierra 游戏可能让你陷入困境。例如在《洛杉矶的防晒霜》中,一旦登上邮轮,你可能在几天后因无法返回而死在木筏上。本工具能自动识别此类陷阱,并在玩家仍可操作的最后时刻阻断导致死锁的关键路径。
已分析并测试四款游戏——《休闲衬衫拉里2》(SCI0,1988)、《国王秘史4》(SCI0,1988)、《国王秘史6》(SCI1.1,1992)和《劳拉·鲍2》(SCI1.1,1992)——使用相同引擎,无需针对特定游戏编写分析代码。
演示
《国王秘史4》补丁版——鲸鱼、夜钟及七处物品滞留点均已添加保护机制:
演示视频:国王秘史4 补丁版
三十秒速览
摘自《休闲衬衫拉里2》实际运行过程(python3 -m pipeline ):
[2] 分析 锚点:起始房间 rm11,胜利房间 [86](自动发现)
死亡信号:global101 == 1001,调试全局变量:[14, 100](推导得出)
101 个房间,27 个强连通分量,40 个门控寄存器
软死锁:15 件物品 + 1 个析取组
- 防晒霜 ...
[3] 推导
rm38 -> rm131:(且(玩家持有:11)(玩家持有:12)(玩家持有:14)(玩家持有:15))
rm57 -> rm58:(且(玩家持有:21)(玩家持有:24)(玩家持有:25)(玩家持有:26))
rm79 -> rm80:(或(玩家持有:30)(玩家持有:31))
rm131 -> rm138:(非(玩家持有:13))
rm63:删除 `(玩家放置:21 -1)`(毛发再生剂)
验证保护模型...
修复 15 + 1 组软死锁;新增软死锁:无
[4] 补丁
编译 117/118 个脚本
script.000 主程序 10790 字节
script.057 rm57 2938 字节
...
完成。build/patch 目录下生成 10 个补丁文件
分析器已识别登船行为为单向通行,推导出必须携带的物品,重新验证保护模型以确保保护机制不会引入新的软死锁,并将修改过的脚本重新编译为 Sierra 自有的松散补丁格式。
注意 rm131 -> rm138:(非(玩家持有:13))——保护机制也支持否定字面量:在 rm138 房间持有菠菜蘸酱会导致死亡,因此解决方案是在玩家仍可丢弃该物品时拒绝通行。本项目认为「要求丢弃已无法丢弃的物品」造成的死墙比游戏漏洞更严重。
若保护机制验证失败或脚本编译出错,整个流程将中止生成任何文件。补丁版游戏可正常运行——该补丁机制正是 Sierra 当年修复漏洞的方式,且原版文件不会被修改(删除补丁文件即可恢复)。
游戏中可设置保护模式:
- 完全保护:阻止所有危险操作
- 轻度保护:首次阻止后允许操作(附带警告)
- 关闭:禁用所有保护
何为软死锁?(或:玩家须知)
部分死亡结局被故意保留——即那些从当前状态仍可避免的死亡。分析通过可达性(而非死亡条件)区分「无法获胜状态」与「可避免死亡」。
在《休闲衬衫拉里2》中,未穿戴完整伪装进入 KGB 海滩会导致死亡。部分伪装部件仅存在于邮轮上,因此分析器禁止在未获取全部伪装时离船。但其余部件可在岛上获取——正位于死亡发生处——故该死亡结局被保留:这是 Sierra 游戏暗示任务目标的方式。正如 Al Lowe 所说:「常存档,早存档!」
当前状态
已完成四款游戏,覆盖引擎两个主要时期(SCI0 1988 → SCI1.1 1992),无需预先声明游戏信息——起始房间、胜利房间、死亡信号及调试标记均从游戏代码推导。
| 游戏 | 引擎 | 状态 | 备注 |
|---|---|---|---|
| 休闲衬衫拉里2(1988) | SCI0 | 已完成并测试 | 菠菜蘸酱:携带即死,故使用否定字面量保护,在仍可丢弃时触发 |
| 国王秘史4(1988) | SCI0 | 已完成并测试 | 实时夜钟机制;鲸鱼——通过仅在可存活状态下激活随机事件进行保护 |
| 国王秘史6(1992) | SCI1.1 | 已完成并测试 | 双结局路径极大增加分析复杂度;对婚礼开始(计时器)设置保护,直到关键物品在手 |
| 劳拉·鲍2(1992) | SCI1.1 | 已完成并测试 | 幕间结构:剧情时钟为寄存器,幕间过渡为单向通行,利用幕间转换拦截器实现保护 |
| 国王秘史5(1990) | SCI1-中间版本 | 进行中(kq5 分支) | 村庄市场:匹配付款与商人以完成全部支付——检测转化为匹配问题 |
简要工作原理
- 反编译:将游戏二进制文件转换为带类型的控制流抽象语法树(JSON IR)
- 抽象解释:解析抽象语法树,组合路径条件生成游戏图:受保护的移动边、物品获取/丢失、寄存器写入。同时读取房间图像(PIC/VIEW)与障碍物多边形(部分门控为几何判定,脚本中无对应代码)
- 简化图结构:提取强连通分量——玩家可自由移动的区域。仅单向边可能导致滞留,使问题复杂度可控
- 识别滞留点:物品在通行前可获取、通行后不可用、后续仍需要
- 推导保护机制:从胜利区域反推目标可达条件,在玩家最后可操作点放置保护。物品消耗型死胡同单独处理,通过「只是开玩笑!」提示阻止浪费关键物品,且不扣分
- 重编译并输出:补丁版游戏可正常运行(如通过 ScummVM 或 DOSBox)
更详细说明见 docs/HOW-IT-WORKS.md;文件架构见 docs/ARCHITECTURE.md;国王秘史6当前状态见 docs/KQ6-STATUS.md;劳拉·鲍2推导日志见 docs/LB2-ORACLE.md。
工具链
步骤 1 和 6 依赖两个现有优秀项目(以无头模式运行):
- 反编译:sci-tools(https://github.com/sluicebox/sci-tools)(sluicebox,MIT 协议)。我们维护的分支(https://github.com/katiahayati/sci-tools)在
.sc源码输出之外增加了第二个输出器:带类型的控制流 JSON 抽象语法树,供分析使用。反编译逻辑本身未修改。 - 编译:SCICompanion(https://github.com/icefallgames/SCICompanion)的脚本编译器(Philip Fortier,GPL-2.0+),已移植为 Linux 无头构建运行——
tools/scicompile/包含小型 CLI 及兼容层,替代 MFC/Windows 界面,调用原始解析器、类浏览器、资源映射和代码生成器(GenerateScriptResource)。供应商树在构建时克隆且不作修改;因 MSVC 专有构建需修补少量文件,所有改动记录于tools/scicompile/BUILD_NOTES.md。
安装
分析部分为纯 Python 3,无任何第三方依赖——src/ 仅导入标准库。需安装的是其驱动的两个外部工具链:反编译器(C#)和 SCI 编译器(C++),均在此从源码构建。
环境要求
sudo apt install python3 git cmake g++ make dotnet-sdk-8.0 # Debian/Ubuntu
| 组件 | 用途 | 验证版本 |
|---|---|---|
| Python 3.12 | 分析与测试(src/) | 3.12.3 |
| .NET SDK 8 | 构建 sci-tools(反编译游戏) | 8.0.129 |
| cmake ≥ 3.16、C++14 编译器、make | 构建 scicompile(重编译补丁脚本) | cmake 3.28.3, g++ 13.3 |
| git | 克隆两个供应商树 | 2.43 |
已在 ubuntu:24.04 容器中全新验证:上述包、两次构建、完整流程运行及游戏无关测试——详见 docs/HOW-IT-WORKS.md 中的日志记录。
一次性构建
git clone https://github.com/katiahayati/lucasartsifier && cd lucasartsifier
# 1. 反编译器:克隆我们的 sci-tools 分支至 vendor/,构建并将游戏反编译至 build/ir
# 同时生成 .sc 源码树和带类型的 JSON 抽象语法树
tools/sci-tools-fork/build.sh /path/to/game
# 2. 编译器:SCICompanion 的无头移植版。源码克隆后不作修改;
# 移植代码位于 tools/scicompile/{compat,patched}
git clone --depth 1 https://github.com/icefallgames/SCICompanion vendor/SCICompanion
cmake -S tools/scicompile -B tools/scicompile/build
cmake --build tools/scicompile/build -j
仅需步骤 1 即可分析游戏(--report);步骤 2 用于将推导的保护机制转为补丁文件。
vendor/ 目录已加入 gitignore——此处不重新分发第三方源码或游戏数据。
运行工具
需自行准备游戏副本(不包含在本仓库中)。以下命令在 src/ 目录下执行:
cd src
python3 -m pipeline /path/to/game # 反编译 -> 分析 -> 推导 -> 生成补丁
python3 -m pipeline /path/to/game --report # 仅分析,不生成文件
python3 -m pipeline /path/to/game --skip-decompile # 复用 build/ir 下的抽象语法树
输出文件位于 build/patch/ 目录:
cp build/patch/script.* /copy/of/game/ # 安装补丁
rm /copy/of/game/script.0* # 恢复原版
松散 script.NNN 文件会覆盖映射资源,因此无需修改 RESOURCE.MAP 和游戏卷文件,删除补丁文件即可完全回退。务必使用游戏副本操作,勿直接修改原始文件。
运行测试
python3 tools/run_tests.py # 完整测试套件(首次全模型冷启动约 21 分钟)
docs/TESTING.md 包含更多说明:为何部分检查故意显示红色、三组回归测试的不同用途、如何在提交前度量改动影响,以及如何在 ScummVM 中无键盘操作下测试补丁版游戏。
目录结构
src/ 分析代码(Python 3,仅标准库)
src/testdata/ 固化测试数据:两套基准 + 监控对
tools/run_tests.py 测试运行器(见 docs/TESTING.md)
tools/drive_scummvm.py 无键盘操作测试补丁版游戏
tools/kq6_panel_probe.py ... 驱动脚本:冷启动 -> 国王秘史6保护控制
tools/sci-tools-fork/ 构建脚本(用于我们的 JSON-IR sci-tools 分支)[C#]
tools/scicompile/ SCICompanion 编译器的无头 Linux 移植版 [C++, GPL-2.0+]
docs/ 工作原理、架构、测试、各游戏状态、许可证
docs/reviews/ 已标记版本的无上下文评审(原文)
docs/archive/ 过时的规划文档(保留测量数据)[见其 README]
vendor/ 构建时克隆,不纳入版本控制(见安装说明)
各游戏配置(src/config.py)仅包含文件系统路径和显示名称——不包含游戏本身信息。起始房间、胜利房间、死亡信号及调试标记均有覆盖字段,但所有游戏均留空——整个流程从游戏代码自动推导这四项信息(见 src/anchors.py)。新游戏无需配置条目——config.by_name() 会自动识别所有反编译后置于 build/sweep// 下的游戏。
未来计划
- 当前未建模必要操作。现有保护机制针对的是「执行某操作所需条件在通行后不再满足且无法获取」的转换。这覆盖了房间边、剧情推进和玩家无法控制的事件(如鲸鱼吞食、夜幕降临、幕间过渡)。但尚未建模「不执行某操作导致后续死亡」的情况,例如《国王秘史5》中需要向猫扔鞋以拯救后续会帮助你的老鼠。
- 《荣耀传说》系列的状态爆炸问题。QFG 游戏内容过于复杂,分析器难以完成处理。推测可通过抽象化玩家属性、战斗和消耗品(口粮等)解决,但相关工作尚未开展。
- SCI1.0 / SCI1-中间版本。已建模 SCI0 和 SCI1.1。《国王秘史5》(中间混合版本)在
kq5分支开发中,已完成大部分。 - 完整端到端测试。四款游戏均已在补丁后广泛测试,但尚未进行完整端到端游玩,可能发现新漏洞。
- **更多游戏!**引擎中无游戏特定代码,但 Sierra 在每款游戏中发布了大量游戏特定代码,因此每个新游戏均需扩展分析逻辑。期望最终可收敛至零改动。
- AGI 游戏。AGI 游戏应纳入支持,但尚未开始相关工作。
许可证
MIT 协议,但 tools/scicompile/ 目录采用 GPL-2.0 或更高版本——因其包含修改过的 SCICompanion 源码并链接其编译器,属于衍生作品。详见 LICENSE、NOTICE 和 docs/LICENSING.md。
基于 sci-tools(https://github.com/sluicebox/sci-tools)(sluicebox,MIT)和 SCICompanion(Philip Fortier,GPL-2.0+)构建。本仓库不包含任何游戏数据。
相似文章
展示 HN:我为 Windows 原生 x64/x86 崩溃构建了一个事后调试器
ForensicDbg 是一个现代化的事后调试器,专为 Windows 原生 x64/x86 崩溃设计,具备集成AI的MCP接口和最先进的用户界面,以实现高效的错误识别和分析。
向 HN 展示:Statewright – 让 AI 智能体更可靠的可视化状态机
Statewright 是一个开源工具,它通过可视化状态机为 AI 智能体实施护栏约束,通过将工具使用限制在特定的工作流阶段,从而提升 GPT 和 Llama 等模型的可靠性。
将NetHack加入我的社区应用,这款38年历史的游戏始终让我措手不及
一位开发者将NetHack加入自己的社区应用,发现了这款38年历史的Roguelike游戏惊人的深度,包括通过Bones文件实现的多人在线模式,以及无数隐蔽的互动方式。
Show HN:Decomp Academy – 学习将 GameCube 游戏反编译为匹配的 C 代码
Decomp Academy 是一个交互式在线平台,教会用户如何通过编写字节匹配的 C 代码,针对 2001 年 MWCC 编译器生成的真实 PowerPC 汇编输出来反编译 GameCube 游戏。
Lean 内核可靠性漏洞 #14576 的事后剖析
对 Lean 内核中一个可靠性漏洞的事后剖析,该漏洞被利用来产生考拉兹猜想的“反证”,并说明了修复方案以及为什么独立的检查器最初也未能发现它。