N64 에뮬레이터 기반인지, 아니면 게임을 리메이크한 것인지 하는 질문을 자주 받습니다. 둘 다 아닙니다. Marchwind 64는 정적 리컴파일(recomp)을 사용합니다. 원본 카트리지에 든 프로그램을 함수 단위로 C로 옮기고, 이를 최신 컴파일러가 Windows, macOS, Linux, Android용 네이티브 프로그램으로 만듭니다.
에뮬레이션, 리메이크, 리컴파일
- 에뮬레이터는 컴퓨터를 N64인 것처럼 꾸밉니다. 게임이 실행되는 동안 원본 MIPS 명령을 하나씩 해석하고 N64의 프로세서, 그래픽 칩, 오디오 칩을 흉내 냅니다. 게임 자체는 그대로지만 모든 명령이 그 계층을 거칩니다.
- 리메이크는 원작을 바탕으로 새 게임을 만드는 것입니다. 그래픽, 규칙, 스토리를 모두 다시 구현하기 때문에 원작과 똑같이 맞추기가 어렵습니다.
- 리컴파일은 그 중간에 있습니다. 게임 로직은 원작 그대로이고, 미리 네이티브 코드로 옮겨 둡니다. 전투 계산, 적 AI, 이벤트 스크립트, 세이브 형식은 원작과 똑같이 동작하고, 실행 중에 프로세서를 흉내 낼 필요가 없으며, 원본 함수의 경계에 새 기능을 붙일 수 있습니다.
비유하자면 에뮬레이터는 말하는 대로 한 문장씩 옮기는 동시통역사이고, 리컴파일은 인쇄하기 전에 책 전체를 번역하는 것이며, 리메이크는 같은 이야기로 새 책을 쓰는 것입니다.
카트리지에서 네이티브 프로그램까지
- 코드 찾기. 원본 프로그램은 18개 부분으로 되어 있습니다. 하나는 메모리에 상주하고, 17개는 필요할 때 카트리지에서 불러옵니다(타이틀, 맵, 전투, 인터미션 화면 등이며, 일부는 같은 메모리를 나눠 씁니다). 각 부분이 카트리지의 어디에 있고 어디에서 실행되는지 알아냈습니다. 모두 3,407개 함수입니다.
- C로 옮기기. 오픈 소스 N64Recomp가 각 함수의 MIPS 명령을 원본의 메모리 배치와 연산을 유지한 채 동등한 C로 바꿉니다.
- 시스템 계층 교체. 원본 프로그램은 N64의 시스템 라이브러리(스레드, 메시지 큐, 타이머, 컨트롤러, 세이브)에 의존합니다. N64ModernRuntime이 이를 컴퓨터의 스레드와 파일로 구현하므로, 옮겨진 코드는 자신이 N64 위에 있지 않다는 것을 알 필요가 없습니다.
- 그래픽과 사운드. N64는 그래픽 칩에 보내는 “디스플레이 리스트”로 화면을 그립니다. 게임은 여전히 이것을 만들고, RT64가 Direct3D 12, Vulkan, Metal로 최신 GPU에서 그립니다. 와이드스크린과 HD 텍스처 교체도 여기서 이루어집니다. 오디오 칩에서 돌던 오디오 프로그램도 네이티브 코드로 리컴파일됩니다.
- 컴파일. 생성된 C와 제가 작성한 코드를 플랫폼별로 함께 컴파일합니다.
게임의 이미지, 사운드, 텍스트는 여전히 사용자 본인의 ROM에서 읽어 옵니다. 그래서 일본판 ROM을 직접 준비해야 합니다.
원작 위에 쌓아 올리기
원본 함수가 이제 평범한 C 함수가 되었으므로 특정 함수를 대체하거나 감쌀 수 있습니다. 현재 그런 곳이 134군데 있습니다. 용도는 다음과 같습니다.
- 네이티브 화면. 대사, 인터미션 메뉴, 개조, 강화파츠, 세이브, 설정을 RmlUi로 다시 그려서 중국어, 영어, 일본어로, 고해상도 글자와 터치 지원을 갖추었습니다. 게임 상태는 여전히 원본 코드가 관리하며, 스위치 하나로 원본 화면으로 돌아갈 수 있습니다.
- 번역. 모든 대사는 일반 텍스트 파일로 제공되고, 인터페이스와 데이터 텍스트(인물, 기체, 무기, 정신 커맨드의 이름)는 용어표에서 가져와 실행 중에 언어별로 바꿔 넣습니다. 플레이어도 직접 수정할 수 있습니다.
- HD 그래픽. 초상화, 배경, 맵, 기체 일러스트, 전투 애니메이션을 그려지는 시점에 고해상도 그림으로 교체하며, 게임 로직은 건드리지 않습니다.
- 편의 기능. 세이브 슬롯과 자동 저장, 빨리 넘기기와 건너뛰기, 전투 애니메이션 중단, 키 재설정, 필터와 테두리, 켜고 끌 수 있는 원작 버그 수정.
- 개발 도구. 내장 디버그 인터페이스로 AI 도구가 게임 상태를 읽고, 버튼을 누르고, 스크린숏을 찍을 수 있어서 자동 테스트와 문제 재현에 쓰입니다.
제가 작성한 부분은 약 36,000줄의 C++(런타임, 화면, 번역, HD, 플랫폼 지원)와 스크립트 분석, 번역 파이프라인, 그래픽 패키징, 테스트, 릴리스를 위한 약 40,000줄의 Python 도구입니다.
몇 가지 예
대사. 스토리는 여전히 원본 이벤트 스크립트가 진행합니다. 누가 말할지, 다음에 어떤 대사가 올지, 언제 버튼 입력을 기다릴지는 모두 원본 코드가 정합니다. 스크립트가 대사를 표시하는 순간 그 대사의 번호와 화자를 읽고, 대사 파일에서 그 번호로 현재 언어의 번역을 가져와 내장된 HarmonyOS Sans 글꼴로 고해상도로 배치합니다. 원본 일본어 글꼴은 고정된 글자 수천 개뿐이지만, 이 방식이라면 거기에 얽매이지 않고 대사 전체를 다시 줄바꿈해서 넘겨야 할 페이지 수를 줄일 수 있습니다.
인터미션 화면. 시나리오 사이의 원본 메뉴는 분기 표를 통해 화면을 전환합니다. 그 진입점에서 해당 화면에 네이티브 버전이 있는지 확인하고, 있으면 새 화면이 입력과 그리기를 넘겨받으며, 플레이어가 결정하면 결과를 원본 코드에 돌려줍니다. 예를 들어 기체를 개조할 때 자금을 쓰고 능력치를 올리는 것은 여전히 원본 루틴이 하므로, 가격과 상한이 원작과 같습니다.
세이브. 원작의 세이브 읽기와 쓰기는 모두 카트리지 세이브 메모리(SRAM)의 블록을 옮기는 함수 하나를 거칩니다. 저는 그 전송 대상만 다른 파일로 돌립니다. 32 KiB 카트리지 세이브는 그대로 유지되므로 ares, Project64, mupen64plus, RetroArch 같은 에뮬레이터와 세이브를 주고받을 수 있습니다. 추가 슬롯과 자동 저장은 별도 파일이며, 각각 원작이 쓰는 것과 같은 바이트로 되어 있어 원본 코드가 확인하고 복원합니다.
전투 애니메이션 건너뛰기. 원작에도 설정에서 전투 애니메이션을 끄는 기능이 있고, 그러면 다른 경로로 전투를 처리합니다. 플레이어가 애니메이션을 중단하면 원작의 그 “애니메이션 없음” 경로로 전환하므로, 피해, 명중, 경험치는 애니메이션을 껐을 때와 정확히 같고 건너뛴 프레임은 아무것도 바꾸지 않습니다.
와이드스크린. RT64는 3D 장면을 더 넓게 그릴 수 있지만, 게임 자체의 2D 요소(상태 표시줄, 커서, 텍스트 상자)는 4:3에 맞춰 배치되어 있습니다. 그 요소들에 각각 와이드스크린용 위치를 주어서, 화면이 16:9를 가득 채워도 인터페이스가 어긋나지 않게 했습니다.
HD 그래픽을 넣는 방식은 HD 그래픽 제작기를 참고하세요.
원작과 비교하기
- 에뮬레이터를 기준으로. 원작이 어떻게 동작하는지 알아야 할 때는 같은 ROM과 같은 세이브를 ares 에뮬레이터에서 실행해 화면 단위로 비교합니다.
- 먼저 코드를 읽기. 전투 공식, 조작, 숨겨진 요소는 원본 코드에서 알아내고 문서로 남긴 다음에 어떻게 끼워 넣거나 고칠지 정합니다. 원작 버그 수정은 끌 수 있는 스위치입니다.
- 자동 테스트. 약 450개의 테스트가 데이터 내보내기, 번역 파일, 인터페이스 텍스트를 확인하고, 오프라인 레이아웃 검사가 게임을 실행하지 않고 모든 화면을 모든 언어와 화면 크기로 배치해 넘치는 글자를 찾아냅니다.
- 게임 자동 조작. 내장 디버그 인터페이스를 통해 스크립트와 AI 도구가 게임을 시작하고, 버튼을 누르고, 스크린숏을 찍고, 메모리를 읽을 수 있습니다. 플레이어가 제보한 문제도 이렇게 재현합니다.
(아직) 할 수 없는 것
리컴파일은 원작의 로직을 모두 유지하며, 그 속도도 함께 유지합니다. 게임 로직은 초당 30프레임으로 고정되어 돌아가고 모든 대기, 애니메이션, 스크롤을 프레임 단위로 세기 때문에 단순히 60으로 바꿀 수 없습니다. 그러려면 나중에 화면 표시 쪽에서 프레임을 보간해야 합니다. 마찬가지로 적의 행동이나 전투 결과처럼 원작 로직이 정하는 것은, 기본으로 켜져 있고 끌 수 있는 수정을 빼면 건드리지 않습니다.
하나의 코드베이스, 다섯 플랫폼
macOS, Windows, Linux, Steam Deck, Android가 하나의 코드베이스를 공유하며, Metal, Direct3D 12, Vulkan으로 그립니다. 모든 커밋은 GitHub에서 Windows, Linux, Android용으로 자동 빌드됩니다.
감사의 말
Marchwind 64는 다음 오픈 소스 프로젝트가 없었다면 존재할 수 없었습니다. N64Recomp와 N64ModernRuntime(리컴파일과 런타임), RT64(그래픽), RmlUi(인터페이스), librashader(RetroArch 필터), 그리고 Zelda 64: Recompiled 같은 앞선 프로젝트들의 경험입니다. 프로젝트의 소스는 GPL-3.0으로 GitHub에 있습니다.