← 部落格2026-10-04

重編譯是什麼:Marchwind 64 的技術框架

Marchwind 64 不是模擬器,也不是重做的遊戲,而是把原版程式整個翻譯成電腦和手機能直接執行的代碼。這篇介紹靜態重編譯的思路和項目的大致結構。

常有人問:這是基於 N64 模擬器做的嗎?還是相當於把遊戲重做了一遍?兩者都不是。Marchwind 64 用的是靜態重編譯(static recompilation,簡稱 recomp):把原版卡帶裡的程式逐個函式翻譯成 C 代碼,再用現代編譯器編成 Windows、macOS、Linux 和安卓上的原生程式。

模擬器、重做與重編譯

  • 模擬器在你的電腦上假裝是一臺 N64:一邊執行,一邊逐條解釋原版的 MIPS 指令,同時模擬 N64 的處理器、顯示晶片和音訊晶片。遊戲本身原封不動,但每一條指令都要經過這層翻譯。
  • 重做是照著原版重新寫一個遊戲:畫面、規則和劇情都要重新實現,很難做到和原版一模一樣。
  • 重編譯介於兩者之間:遊戲邏輯還是原版的那一份,只是提前翻譯成了本機代碼。戰鬥計算、敵人 AI、事件指令碼、存檔格式都和原版逐條一致;執行時不需要模擬處理器,所以也能在原版程式的邊界上插入新功能。

打個比方:模擬器像同聲傳譯,每句話現場翻;重編譯像把整本書先譯好再出版;重做則是照著原書的故事另寫一本。

從卡帶到原生程式

  1. 找出代碼。 原版程式分成 18 段:1 段常駐記憶體,17 段按需從卡帶裝入(標題、地圖、戰鬥、場間畫面等各有一段,有些段會裝到同一塊記憶體)。我們逐段確定了每段在卡帶裡的位置和執行地址,共 3,407 個函式。
  2. 翻譯成 C。 用開源的 N64Recomp 把每個函式的 MIPS 指令翻譯成等價的 C 代碼,保留原版的記憶體佈局和計算方式。
  3. 替換系統層。 原版程式依賴 N64 的系統庫(執行緒、消息佇列、計時器、手柄、存檔)。N64ModernRuntime 用電腦上的執行緒和檔案實現了這些介面,翻譯出來的代碼不需要知道自己不在 N64 上。
  4. 畫面與聲音。 N64 的畫面由顯示晶片按「顯示列表」繪製。遊戲照舊生成這些顯示列表,由 RT64 用 Direct3D 12、Vulkan 或 Metal 在現代顯示卡上畫出來,寬屏和高畫質貼圖替換也在這一層。音訊晶片上跑的音訊程式同樣被重編譯成本機代碼。
  5. 編譯。 生成的 C 代碼和我們自己的代碼一起,用各平臺的編譯器編成最終程式。

遊戲的圖片、聲音和文本仍然從你自己的 ROM 裡讀取,所以需要自備日版 ROM。

在原版之上加東西

因為原版函式都變成了普通的 C 函式,我們可以在指定的函式前後接管或包裝它們,現在共有 134 處。主要用在:

  • 原生介面。 對白、場間選單、改造、強化部件、存檔、設定等畫面,由我們用 RmlUi 重新繪製,支援中英日三語、高解析度文字和觸屏;遊戲狀態仍由原版代碼管理,原版畫面也可以隨時切回來。
  • 翻譯。 全部臺詞以純文本檔案隨程式附帶,介面和資料文本(人名、機體、武器、精神等)用詞條表管理,執行時按語言替換,玩家也可以自己改。
  • HD 美術。 頭像、背景、地圖、立繪、戰鬥演出等在繪製時替換成高畫質圖,不改遊戲邏輯。
  • 體驗改進。 多存檔欄與自動存檔、快進與跳過、戰鬥演出中止、改鍵、濾鏡與框體、可開關的原版 bug 修正等。
  • 開發工具。 內建的除錯介面可以讓 AI 工具讀取遊戲狀態、按鍵和截圖,方便自動測試和復現問題。

我們自己寫的部分大約是 3.6 萬行 C++(執行時、介面、翻譯、HD、平臺適配),另有約 4 萬行 Python 工具,負責劇情指令碼分析、翻譯流水線、美術打包、測試和發布。

幾個具體例子

對白。 劇情仍由原版的事件指令碼推進:誰說話、說到哪一句、什麼時候等玩家按鍵,都由原版代碼決定。我們在指令碼顯示文字的那一刻讀出這句臺詞的編號和說話人,用這個編號去對應的臺詞檔案裡取當前語言的譯文,再用自帶的 HarmonyOS Sans 字型按高解析度排版繪製。原版的日文字型檔只有幾千個固定字形,這樣做就不受它的限制,也能整句重新斷行、少翻頁。

場間畫面。 原版的整備選單由一張排程表按編號切換各個畫面。我們在排程入口判斷:如果某個畫面已有原生版本,就由新畫面接管輸入和繪製;玩家確定操作時,再把結果交回原版代碼處理。比如改造機體時,扣資金、改數值仍走原版的那一段邏輯,所以價格和上限都和原版一樣。

存檔。 原版的存檔讀寫全部經過同一個函式,一次搬運一段卡帶存檔(SRAM)。我們只把這次搬運轉到別的檔案:32 KiB 的卡帶存檔檔案原樣保留,所以能和 ares、Project64、mupen64plus、RetroArch 等模擬器互相匯入;多出來的存檔欄和自動存檔另存為單獨的檔案,每一份都是原版寫出的同一段位元組,校驗和恢復也照舊由原版代碼完成。

跳過戰鬥演出。 原版本來就能在設定裡關掉戰鬥動畫,關掉時走另一條結算路徑。我們中止演出時,就切回原版這條「不播動畫」的路徑繼續結算,傷害、命中和經驗都與關掉動畫時完全相同,不會因為少跑了幾幀而影響結果。

寬屏。 RT64 可以把 3D 畫面畫得更寬,但遊戲自己的 2D 元素(狀態列、游標、文字框)是按 4:3 擺放的。我們為這些元素逐個設定在寬屏下的位置,讓畫面鋪滿 16:9 時介面依然對齊。

更多 HD 美術的接入方式見HD 美術是怎麼做的。

怎樣確認和原版一致

  • 用模擬器對照。 需要確認原版行為時,我們在 ares 模擬器裡運行同一個 ROM、讀同一份存檔,逐個畫面對比。
  • 先讀代碼再動手。 戰鬥公式、按鍵繫結、隱藏要素等都先從原版代碼裡查清楚並寫成文件,再決定怎麼接入或修正;原版 bug 的修正都做成可以關掉的開關。
  • 自動測試。 約 450 個測試檢查資料匯出、翻譯檔案、介面詞條等;另有離線排版檢查,不開遊戲就能把每個介面在各種語言和螢幕尺寸下排一遍,找出超出框的文字。
  • 自動駕駛遊戲。 通過內建的除錯介面,指令碼或 AI 工具可以啟動遊戲、按鍵、截圖、讀取記憶體狀態,用來復現玩家報告的問題。

還做不到的

重編譯保留了原版的全部邏輯,也就保留了它的節奏:遊戲邏輯固定每秒 30 幀,等待、動畫和滾動都按幀計數,所以沒法簡單改成 60 幀,只能以後在顯示層插幀。同理,凡是原版邏輯決定的事情,比如敵人的行動和戰鬥結果,我們都儘量不碰,只在預設開啟、可以關掉的修正裡調整。

一份代碼,五個平臺

macOS、Windows、Linux、Steam Deck 和安卓用的是同一份代碼,圖形分別走 Metal、Direct3D 12、Vulkan。每次提交都會在 GitHub 上自動構建 Windows、Linux 和安卓版本。

致謝

沒有這些開源項目,就沒有 Marchwind 64:N64Recomp 與 N64ModernRuntime(重編譯與執行時)、RT64(圖形)、RmlUi(介面)、librashader(RetroArch 濾鏡),以及 Zelda 64: Recompiled 等先行項目積累的經驗。項目原始碼以 GPL-3.0 發布在 GitHub。