zeldaret/tp and the pursuit of a byte-identical Twilight Princess build
Decompilation of The Legend of Zelda: Twilight Princess
At a glance
- What is it?
- zeldaret/tp reconstructs The Legend of Zelda: Twilight Princess in C++ across ten named retail targets, aiming at binaries identical to the originals rather than at a playable port. Every build starts from a disc image the user supplies and a short chain of python3 and ninja steps.
- Who is it for?
- Adopt zeldaret/tp if you own the disc and want the game's own logic in readable C++ to study, patch or rebuild yourself later. Walk away if your goal is a playable Twilight Princess on new hardware today: the project rules out a port outright, and a build only becomes checkable once the initial compile succeeds and objdiff.json appears in the project root.
- Can I use it commercially?
- Yes. CC0-1.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 122 days ago.
- What is it written in?
- Mainly C++, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Byte matching instead of a port, in one C++ tree
The bar this project sets is narrow and unusual: reconstruct game code in C++ so that the result compiles back into a binary identical to the original. That goal differs sharply from reimplementing the game, and the difference shapes every step that follows. A reimplementation only has to behave the same way. Here, functions, data layouts and call order have to line up with the shipped object code, so progress is measured by a byte comparison rather than by whether the game runs.
Scope is drawn just as tightly. The README states that the project is not, and will not, produce a port to PC or any other platform, and that the repository contains no game assets or assembly whatsoever. A copy of the game is a precondition rather than an optional extra, and nothing inside the repository removes that requirement. For an engineer, the practical reading is simple: this is a reverse-engineering workbench for one specific retail disc, not a game engine and not a compatibility layer.
One C++ codebase, ten retail targets, conditional compilation
Every entry in the version list is a shipping retail disc, and all of them come out of the same tree. GameCube is covered by GZ2E01 for North America, GZ2P01 for Europe and Australia, and GZ2J01 for Japan. Wii adds RZDE01_00 at revision 0, RZDE01_02 at revision 2, RZDP01 for Europe and Australia, RZDJ01 for Japan, and DZDE01, the North American kiosk demo. 2 more targets sit on the Nvidia Shield in China: Shield, plus ShieldD, its debug version.
Region is not a branch you check out. The default build targets GZ2E01 and reads its disc image from `orig/GZ2E01`, while any other target is selected with the `--version` option of `configure.py` followed by a rebuild. Since all versions are built from the same codebase using conditional compilation, a contributor working on one region shares every data structure and control-flow decision with the other 9, which cuts both ways: a fix confirmed on one version can break another, and a match found on the kiosk demo may reveal nothing about the retail disc.
Getting a first build: clone, configure, compile
4 tools are needed, 3 of them mandatory: git, ninja and python3, with clang-format optional. On macOS the install step is short.
brew install ninjaWindows users are pointed at native tooling, asked to put Python and ninja on `%PATH%` (the Store link resolves to `python-311`), and given a pip shortcut for the build tool.
pip install ninjaLinux asks for the same prebuilt ninja package, after which wibo is downloaded and used automatically. Then come 3 steps, each a single command. Clone the repository.
git clone https://github.com/zeldaret/tp.gitCopy your own disc image to `orig/GZ2E01` in one of the 8 supported formats: ISO (GCM), RVZ, WIA, WBFS, CISO, NFS, GCZ or TGC. After the initial build the image can be deleted to save space. Configure the project.
python configure.pyFinally compile.
ninjaThe top level of the clone hints at the layout: source under `src/`, headers under `include/`, per-version settings in `config/`, bundled libraries in `libs/`, helper programs in `tools/`, generated docs driven by a `Doxyfile`, and an `orig/` directory that is yours to fill.
wibo replaces a Windows toolchain on macOS and Linux
On both macOS and Linux the build downloads and uses wibo, described as a minimal 32-bit Windows binary wrapper. The README does not explain what wibo is invoked for, and there is no documented way to skip it, so treat it as a fixed part of the toolchain rather than an optional helper. What it buys shows in what you do not have to install: no spare Windows machine, no virtual machine, no Wine prefix on the path to a first set of objects.
Windows takes the opposite route. The project asks for native tooling and states that WSL or msys2 are not required, with Python and ninja added to `%PATH%`. Running under WSL anyway is permitted, and the build still completes, but what you give up is the automatic rebuild loop in objdiff, a cost that only becomes visible once a first build has succeeded.
Ten listed targets, four shields visible at the top
Count the version list and you get ten targets. Count the badge row above it and you get four: GZ2E01, GZ2P01, GZ2J01 and ShieldD. The remainder, RZDE01_00, RZDE01_02, RZDP01, RZDJ01, DZDE01 and Shield, survive only inside a commented-out HTML block in the page source. A reader scanning the project therefore sees progress badges for 3 GameCube regions plus one Shield debug build, and sees nothing at all for 6 targets that `configure.py` will still build when asked.
That gap says nothing about buildability, and it does not contradict the surrounding text so much as it undercuts its front page. Detail lives elsewhere: the shields resolve to decomp.dev/zeldaret/tp, and the project separately points to zsrtp.link, where a progress page, a contribution guide and an about page are linked. If you need a realistic read on how much work a Wii or retail Shield target represents, the repository front page is the wrong page to read it from.
What 'completely matching' leaves out, and where the work stands
The opening paragraph carries a tension worth unpacking. It says the code for the GameCube builds is completely matching, then adds that not every Translation Unit has been linked yet. Both halves describe different objects. A translation unit is one compiled module, so a codebase can be reconstructed instruction by instruction while the final link still fails to place every piece. The same paragraph says work continues by aligning the Debug version and getting the Wii targets to match, which is the plain reason only the GameCube entries carry visible badges.
Two further facts are easy to miss. The last push was on 2026-06-23, and the repository has no GitHub releases at all, so the commit log is the only place activity shows up. On reuse, the root LICENSE.md file records a CC0 dedication, which attaches no conditions to people who want to read, rebuild or modify the reconstructed C++ source.
objdiff turns each rebuilt object into a byte comparison
Verification depends on a separate desktop application, encounter/objdiff, and it only comes into play once a first build succeeds. At that point an `objdiff.json` file appears in the project root. Point the application's Project directory at the clone and the configuration loads automatically; selecting an object from the left sidebar then shows exactly where your bytes differ from the original.
The loop closes itself from there. Changes to source files, to headers, or to `configure.py`, `splits.txt` and `symbols.txt` trigger a rebuild without anyone touching the terminal, and that is what turns matching from a batch grind into an incremental one. Those notifications are the piece WSL cannot deliver, which is the concrete reason the project steers Windows contributors away from it. The uncomfortable corollary is that a new contributor has no shortcut: to learn how close a specific object is, build the target, open the diff view and read it.
Editorial conclusion
Adopt zeldaret/tp if you own the disc and want the game's own logic in readable C++ to study, patch or rebuild yourself later. Walk away if your goal is a playable Twilight Princess on new hardware today: the project rules out a port outright, and a build only becomes checkable once the initial compile succeeds and objdiff.json appears in the project root. Look at the shields for your own region before installing a toolchain, since 6 of the ten listed versions show no badge at all and the commit log is the only dated record.
Frequently asked questions
Does zeldaret/tp produce a PC port of Twilight Princess?
No. The project states that it is not, and will not, produce a port to PC or any other platform, because it is a decompilation of the original game code that can be compiled back into a binary identical to the original. It is a research codebase, not a launcher.
What must I provide before zeldaret/tp will build?
Your own copy of the game's disc image, placed at `orig/GZ2E01` in ISO (GCM), RVZ, WIA, WBFS, CISO, NFS, GCZ or TGC format, along with git, ninja and python3. The repository ships no game assets or assembly, and clang-format is optional. The image can be deleted once the initial build finishes.
Which Twilight Princess versions can zeldaret/tp target?
Ten retail targets are listed: GZ2E01, GZ2P01 and GZ2J01 on GameCube, RZDE01_00, RZDE01_02, RZDP01, RZDJ01 and DZDE01 on Wii, and Shield and ShieldD on the Nvidia Shield in China. GZ2E01 is the default; any other one is selected with the `--version` option of `configure.py` before building.
Why does objdiff stop rebuilding automatically on Windows?
Under WSL, objdiff cannot get the filesystem notifications it relies on for automatic rebuilds. The project states that native tooling is wanted on Windows and that WSL or msys2 are not required, so the automatic half of the diff loop is the reason to build natively.
How do new contributors get started with zeldaret/tp?
Once the build requirements are working, the project points contributors to its Discord server and to a contribution guide hosted at zsrtp.link/contribute. Progress for each target is tracked through decomp.dev badges, and the project links a progress page at zsrtp.link/progress.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/zeldaret-tp)Was this useful?