使用 LLM 讀取 68000 組語將 1993 年 Amiga 遊戲移植到 Godot
TL;DR
Claude Fable 5 成功將 1993 年的 Amiga 遊戲 Babylonian Twins 移植到 Godot 4,自動翻譯了原始的 68000 組語(72,758 行)以及後來 2010 年的 C++ 引擎(34,000 行)。AI 重建了無文件檔案格式,重現了與原始完全相同的二進位檔案,並暴露了數十年來從未被發現的錯誤。
為什麼這個實驗很重要
作者想測試現代的 LLM 是否能理解從未出現在訓練資料中的無文件 68k 組語。透過將完整的 Amiga 原始碼、素材和建置工具提供給 Claude,作者可以將 AI 生成的移植版與原始二進位檔案進行逐位元組的比較,為 LLM 在底層逆向工程任務上提供具體的基準。
步驟 1 – 在一小時內移植 2010 年的 C++ 引擎
- 結果: 在 21 分鐘內建構了一個可遊玩的 Godot 專案,重現了整個 34k 行的 C++ 程式碼庫。
- 關鍵見解: AI 保留了原始的固定 tick 邏輯(60 Hz),並 沒有 用 Godot 的
CharacterBody2D取代自訂的移動程式碼。保留手寫的碰撞常式避免了細微的物理差異。 - 技術說明: 原始遊戲使用了乘法阻力係數(每個 tick
velocity.x *= 0.85)。因為原始版本以 50 Hz 運行,相同的常數在 60 Hz 下會感覺不對。AI 將兩個 tick 速率分開處理,保留了原始的感覺。
步驟 2 – 自動重建 68000 組語
- 結果: Claude 重建了 1993 年的原始碼,用
vasm組譯,並產生了與發布的 Amiga 磁片 位元組完全相同 的二進位檔案。 - 運作方式: 模型編寫了一個前處理過程,以彌合 ASM-One 和
vasm之間的方言差異(例如cmp #4,d0編碼),並生成了一個腳本來修復因 2008 年傳輸而損壞的檔案名稱映射。 org處理: AI 發現原始版本使用手動記憶體佈局(org $6a000)而沒有連結器。它正確地重現了該佈局,除了一個ds.b 800區塊,因為 ASM-One 的「skip」語意不同;AI 最初輸出了 800 個零位元組,將後續資料偏移了 944 位元組。這個錯誤在重建的 demo 渲染出錯誤的圖形時被發現。- 變數區域差異: 大約有 108 位元組的差異,因為發布的二進位檔案是運行後 RAM 的快照,而全新的組譯則將這些變數留為零。AI 解釋說程式碼在讀取這些變數之前會先寫入它們,因此這種差異是無害的。
解碼無文件格式
關卡地圖
- 關卡載入器包含 1,652 行無文件的 68000 程式碼。AI 透過追蹤繪圖常式並提取寬度/高度常數,推斷出了瓷磚網格格式(無標頭,壓縮區塊)。
- 它重新生成了所有五個關卡,將它們渲染為 PNG,並與作者 2020 年的螢幕截圖進行了像素級的比較。兩個不匹配之處(天空漸層和水色循環)被追溯到遺失的 copper-list 資料,AI 隨後將其補上。
地圖格子屬性
- 每個 16 位元的格子封裝了一個 6 位元的屬性、一個 bank-select 位元和一個 8 位元的瓷磚索引。AI 透過分析繪圖迴圈(遮罩低位元組)和碰撞常式(遮罩高位元)發現了屬性位元。它重建了完整的屬性表,包括實心地面、可攀爬的瓷磚、傷害代碼、門和致死區域。
物件表
- 物件按畫面儲存在自訂表中。AI 識別了標記(
$1111= 空畫面,$2222= 死亡物件)並解碼了行為偏移量,例如hiddenwallR-lrb。然後它將所有物件座標轉換為世界空間,並根據渲染的地圖進行了驗證。
Copper-list 天空漸層
- 天空顏色由 copper list 生成,它寫入了一系列顏色字組(例如
dc.w $09FF,$09EF,…)。AI 提取了關卡 2 的 24 字漸層,將其渲染為垂直條紋,並在初始建構省略它後將其重新加入移植版。
Sprite-sheet 歧義
- Amiga 的 sprite 以平面位元平面的方式儲存。AI 在工作表大小(
frames * width * height * 2 * 5)中檢測到了歧義,並要求作者澄清。正確的解釋是兩個堆疊的行,每個方向一行,AI 隨後對其進行了解碼。
步驟 3 – 將原版作為來賓嵌入現代建構中
- 在一個晚上,AI 加入了一個「來賓」模式,在 Godot 執行檔內以 50 Hz 啟動 1993 年的遊戲,當玩家返回現代版本時切換回 60 Hz。
- 所有素材(PNG, WAV, JSON)由 Python 腳本一次性提取;行為在 GDScript 中重新實作。
- 最終的 Steam 發布版提供了現代遊戲,加上 原始的 Amiga 版本作為第二個啟動選項。
AI 驅動的移植發現的錯誤
| 錯誤 | 原始症狀 | AI 生成的修復 |
|---|---|---|
| 守衛推擊範圍 | 關卡 2 中高處平台上的守衛將玩家推過了堅固的岩石。 | 恢復了遺失的上限檢查(cmp.w #4,d4; bpl Sg.Far)。 |
| 隱藏門瓷磚 | 門顯示為空曠的天空,因為它們是由執行時程式碼繪製的,而不是儲存在地圖中。 | 將執行時門繪製常式加入移植版。 |
| 彈跳床物理 | 在現代建構中跳躍感覺太高。 | 發現 2010 年 iOS 建構中的按住跳躍旗標導致了按下時釋放的不匹配;修正了 Godot 中的輸入處理。 |
| Sprite-sheet 方向 | AI 最初鏡像了雙胞胎的面向方向。 | 澄清了原始工作表包含兩行(左/右)並保持了正確的方向。 |
| 遺失的天空漸層 | 第一次重建渲染了平坦的天空。 | 重新加入了 copper-list 顏色表,消除了像素差異警告。 |
由 LLM 自動化的發布工作流程
- AI 生成了命令列旗標(
--level,--pose,--drive,--probe,--screenshot)以實現無頭測試和腳本化遊戲過程。 - 它產生了所有所需商店解析度的螢幕截圖,以每種語言啟動遊戲,並使用真實字體擷取了遊戲內字幕。
- 商店元資料(標題、描述、圖示)被自動填寫;Steam 的 Web 儀表板只需要手動登入。 | 評論從 Google Play 被抓取、解析,任何回報錯誤的評論(例如一星的「cant get through door on level one」)都被提出以便立即修復。
社群反應(精選 HN 評論)
mattjoyce: 「我下載了一個 ZX81 記憶體傾印並要求 Claude 用 Go 重建它。它搞定了。」 – 突顯了 LLM 在復古運算考古學上的廣泛潛力。
hedgehog: 「讓 Claude 為類似的移植匯出工程指南會很有趣。」 – 建議工作流程本身可以成為可重複使用的藍圖。
robviren: 「過去那些非標準、取巧的程式碼數量,在今天感覺是不可能碰觸的複雜。」 – 強調了 AI 如何彌合 30 年的知識差距。
coder-pm: 「你有沒有在 UAE 中用相同的輸入對移植版和原版進行過測試?」 – 指出了一個有價值的未來驗證步驟;作者確認進行了逐像素的差異檢查。
這對未來的復古移植意味著什麼
- 可行性: LLM 可以讀取無文件的 68k 組語,重建遺失的格式,並在最少的人工指導下產生忠實的現代移植版。
- 速度: 整個流程——從原始碼匯入到可運行的 Godot 建構——耗時約 5 小時 的連續 AI 執行,遠快於手動重寫所需的時間。
- 保存: 位元組相同的重建保證了原始遊戲可以被歸檔、研究,並在現代硬體上執行而不失真實性。
- 錯誤發現: 自動化的逆向工程發現了潛伏三十年未被察覺的錯誤,展示了超越單純程式碼翻譯的實際好處。
去哪裡玩這些遊戲
- 原始 1993 Amiga 版本: 在 itch.io 上的免費磁片映像檔(使用 FS-UAE, WinUAE 或真實硬體執行)。
- 決定版: 可在 iOS、Android 和(2026 年秋季)Steam 上取得,1993 年的版本作為次要啟動選項捆綁在一起。
該移植由在 Claude Code 中運行的 Claude Fable 5 驅動;作者提供了筆記、儲存庫和原始二進位檔案,AI 生成了這篇文章的初稿,隨後被逐行編輯。
Sources
相關
- 專案
- Dispatch
- Dispatch
- Dispatch
- Dispatch