A work in progress decompilation of Sonic Heroes for the Nintendo GameCube.
This is a non-commercial study and preservation project. It is not affiliated with SEGA.
This repository contains no game code, no game assets and no extracted assembly. Some functions are written as inline assembly in the source, which is explained under Status. You need your own legally obtained copy of the game to build it. The project does not produce a playable game and is not a port.
Supported version:
G9SE8P, GameCube, North America (NTSC-U), revision 0
Planned later: G9SP8P (PAL) and G9SJ8P (NTSC-J).
This is a GameCube decompilation. The G9SE8P GameCube machine code, object
layout and artifact hashes are authoritative for every match.
Some corresponding PS2 builds preserve useful symbol metadata. Maintainers may inspect a legally obtained PS2 copy locally to help classify a translation unit as C or C++, recover a symbol name or signature, and understand class or source structure. That evidence is only a cross-platform lead: it must be correlated with the GameCube unit and verified by GameCube objdiff. It cannot establish a GameCube byte match on its own.
The repository does not contain or distribute PS2 disc images, executables, extracted code or complete symbol dumps, and contributors do not need a PS2 copy to work here. Reviewed classifications and the minimum useful evidence are recorded in the repository. See the source-language policy for the workflow, the current migration audit for reviewed decisions, and LEGAL.md for the artifact rules.
The progress badges and generated objdiff report are authoritative; avoid copying percentages into prose because they become stale.
main.dol and all 17 configured REL modules rebuild byte for byte. Their hashes
are stored in config/G9SE8P/build.sha1, and CI verifies all eighteen artifacts
on every change. stage00D is not configured; see the note at the end of
config/G9SE8P/config.yml.
Exact linked artifacts do not mean that every function has been reconstructed as source. Unwritten regions can still be carried through the decompilation build, so source progress must be read from objdiff rather than from the final SHA-1 result alone.
The disc ships no .map file. Names and translation-unit boundaries are argued
from GameCube cross references, private data, alignment and correlated metadata.
PS2 symbols can supply cross-platform names and class evidence, but every
conclusion is checked against the GameCube object. See the
source-language policy and
current audit.
Some SDK units legitimately require inline assembly for instructions with no C form, such as special-purpose-register and cache operations. Generated assembly and all other extracted binary material remain under ignored build/original directories and are never committed.
Reproducing the RELs needed a fix to decomp-toolkit. These RELs reserve an empty
section slot before .text which mwld drops during the partial link, because
nothing lands in it; dtk wrote its section table straight from the object
indices, so every section came out one index low and the header fields shifted
with them. The project therefore pins a
fork carrying that change, tagged
v1.8.3-sh1. It is reported upstream as
encounter/decomp-toolkit#144;
point tools/download_tool.py back at upstream once it lands there.
I use LLMs to help write this decompilation. Nothing goes in unverified: every function has to match the original byte for byte in objdiff, and CI checks the SHA-1 of the built DOL on every push. A function either reproduces the original binary exactly or it does not get marked as matching.
You need Python and ninja on your PATH.
Use native tooling. WSL and msys2 are not needed, and objdiff cannot watch files for automatic rebuilds under WSL.
brew install ninjaInstall ninja from your package manager.
On macOS and Linux, wibo is downloaded automatically to run the original Windows compilers.
Clone the repository:
git clone https://github.com/Jovinull/sonicheroes.gitTurn on the repository hooks once, so a commit that stages game data or build output is refused before it happens:
git config core.hooksPath .githooksPut your copy of the game in orig/G9SE8P/. Either drop the disc image there
(ISO, RVZ, GCM, WBFS, CISO, GCZ, NFS or TGC), or extract the disc with Dolphin
into that folder. If you use a disc image, it can be deleted after the first
build.
Then:
python configure.py
python -m unittest tools.test_check_language_policy
python tools/check_language_policy.py
ninjaThe checksum step verifies main.dol and all 17 configured REL modules.
After the first build there will be an objdiff.json in the project root.
Get objdiff, open project settings and
point Project directory at this repository. It picks up the config on its own.
Pick an object in the sidebar to start diffing. It rebuilds automatically when
you edit source, headers, configure.py, splits.txt or symbols.txt.
See CONTRIBUTING.md.
Game-owned code is C++ by default, while reviewed C boundaries and known C
libraries remain C. Legacy .c paths that already compile with -lang=c++ are
migrated to .cpp in verified batches, not rewritten all at once. Each batch
records its language evidence and must preserve the GameCube object before it is
accepted. The exact policy and migration checklist are in
docs/language-policy.md.
External resources that help with naming functions and structs (community disassemblies, SDK headers, format documentation) are tracked in REFERENCES.md.
See LEGAL.md.
