aoe3-decomp logo: crossed sabers over a cogwheel in a laurel wreath

aoe3-decomp

Age of Empires III: The Asian Dynasties, decompiled back to C++ that compiles to the original game's exact machine code, and ported to native macOS from that same source.

Progress

Every number below is counted from the repository's main branch. A function only counts as matched when recompiling its source reproduces the original bytes, and review checks that again before it merges.

2,891
functions matched
8.3% of the 35,006 functions in the game executable
357
translation units started
of 1,088 recovered source files
251
near misses kept as stubs
Written, but not yet byte-identical. Each records why it misses, so the next attempt starts there.
460
pull requests merged
Each one is recompiled and mutation-tested before it lands.

Counted 2026-10-26 at commit main.

What a matching decompile is

The game shipped as a compiled Windows program, age3y.exe. We write C++ by hand, function by function, and compile it with the same compiler the game was built with: Microsoft Visual C++ .NET 2003 (7.1, cl 13.10.3077), run natively on macOS. A function is matched when the compiler turns our source into exactly the instructions in the original executable.

1. Read

Analysis tools recover each function's machine code, the classes it uses and the source file it came from.

2. Write

An agent writes plain C++03 that this 2003-era compiler accepts, using real names from the game's own debug strings where they exist.

3. Match

A custom comparer checks the compiled result against the original, instruction for instruction.

4. Prove it

Review recompiles every function and plants a deliberate one-token bug, which has to break the match. Only then does it merge.

The macOS port

The matched source is the ground truth, and the port never changes it. It works the way an emulator layer does, by replacing what the game calls instead of the game itself. The game asks for Direct3D 9, Win32 windows, DirectSound and so on; on a Mac, those calls are answered by new code that speaks Metal, SDL3 and Core Text. The same source still compiles to the original bytes for Windows.

LayerWhat it replacesStatus
Direct3D 9 on MetalThe game's renderer device, its resources and render states, plus shader translation for every shader model the game uses (vs/ps 1.1 to 3.0)on main
Win32 on SDL3Windows, the message pump, input, timers, files, the registry, threads and synchronisationon main
GDI text on Core TextFonts, glyph rasterisation, text drawing and bitmap blits for the game's UI texton main
DirectSound on miniaudioSound buffers, 3D positional audio and the game's EQ filteron main
Memory allocatorThe game's Rockall heapon main
64-bit builds of game codeLayout checks that assume 32-bit pointers, so the game's own files can compile for arm64next
Bink video on FFmpegThe ten functions the game imports from binkw32.dll, with a decoder and a blit layer behind themon main
D3DX9 shader compilersThe assembler, disassembler, HLSL compiler and effect compiler the game calls through D3DX9, written in-housein review
Voice streaming, networkDirectShow and socketsplanned

Every layer has its own tests: pixel-exact rendering checks, sample-exact audio mixes and thread stress tests under sanitizers. Each also has planted-bug checks that the tests must catch.

Running the original on macOS: the static-recompilation bridge

The decompile is not finished, so the port cannot yet be built from matched source alone. The bridge fills the gap. A translator reads the x86 code of your own copy of the game on your own machine, writes it out as C, and compiles that for Apple Silicon. The result runs on the Mac platform layers above, so the original game's code is already executing on macOS while the matched source grows underneath it.

Generated on your machine

The translated C comes from your game files and stays in your build folder. It is never committed to the repository or distributed.

The bridge is temporary

Each translated function is replaced by matched source as the decompile reaches it. When the decompile completes, the bridge goes away.

The platform layers are permanent

Metal, SDL3, Core Text and the audio layer carry over unchanged to the finished native build.

The authentic build is untouched

The bridge never feeds the matching build, never edits matched source, and nothing is patched or bypassed. The rules are in the design decision.

Milestones so far

DateMilestoneStatusLinks
2026-10-26Feasibility shown: all 35,184 functions of the executable translate to C and link as one arm64 program, and nine real functions pass over 200,000 checks against a reference.reached#635, spike log
2026-10-2799.98% of functions translate (35,176 of 35,184), including SSE/SSE2 and exception-handling cleanup code. Instruction forms are tested against a hand-written reference and a CPU emulator.reached#659, #670, #743
2026-10-26Boots through the C runtime start-up: heap, locks, thread-local storage, command line, environment and locale.reached#688, boot 1
2026-10-26Runs every static initializer and enters WinMain.reached#710, boot 2
2026-10-26Opens the game's archives, parses its XML, then creates and shows the main window and paints the splash screen.reached#727, boot 3
2026-10-27Passes the game's own licence check. Its registration library runs unmodified, and Steam's own install step (the installscript.vdf that ships with a Steam copy) is applied to the port's own registry, so the game finds its registration exactly as it does on Windows. Nothing is bypassed or patched.reached#734, #742, #746, install log
2026-10-27The game's licence-agreement dialog appears as a native macOS dialog with a scrolling text box. Accepting is the player's choice; no automated run accepts it.reached#744, #751, #750
2026-10-27Hardware detection: the game's own detection library runs as translated code and reads a model of the system's display and sound devices, with the display identity coming from the Metal layer.reached#750, detection log

A full map of the start-up path, step by step, is in the start-up note (#766). Boot time on the bridge fell from 1.65 s to 0.50 s of CPU after a dispatch cache (#762).

The platform pieces behind it

PieceStateLinks
Direct3D 9 on MetalThe renderer, the shader-model 1 to 3 translator and the guest-facing COM proxies are on main and linked into the bridge's build. The game has not created its device yet, so no frame is drawn through Metal.#288, #355, #698
In-house HLSL compilerThe D3DX9 shader assembler, disassembler, HLSL compiler and effect compiler are written and in review.#765
Sound and inputDirectSound 8 and DirectInput 8 proxies for the translated code are on main, tested with scripted sequences. They are not wired into the boot yet.#760, #757
Bink videoThe ten binkw32.dll functions run on FFmpeg's Bink decoder with a blit layer, on main. They are not bound into the boot yet, so intro videos are still skipped.#759

Next

Intro video

Bind the game's Bink imports to the video layer so the intro movies play.

Main menu

Create the Direct3D device on Metal, wire in sound and input, and load the first models and menu.

A Mods button

A prototype that adds a Mods button to the menu through recompilation hooks, as part of a separate modded build. The authentic build never loads it. Designed in task-mods-design.

Everything here is counted from merged pull requests and the project's research logs. Items marked in review are not on main yet.

Where it's going

Link the original

Enough matched code to link a Windows build of the game from source.

Prove behaviour

Replay recorded games and check the rebuilt game behaves exactly like the original.

First frame on Metal

The game's real data drawn on a Mac through the port layers.

Playable on macOS

A native Apple Silicon build you can play a skirmish in. A Windows x64 / Direct3D 12 build follows.

The long-term vision

Once the game runs natively, the plan is to build on top of it without touching the faithful version. The byte-identical rebuild stays exactly as it is, and a separate modded build adds three things:

A mod layer

A documented, versioned modding interface that is as extensive as possible: units, civilisations, techs, UI, maps, AI, camera and scripting. Its scope is set by reference mods modelled on the kinds of mods people love for the other Age of Empires games.

An in-game mod browser

Browse, install and update mods from many authors without leaving the game, signed in with an AoE3 decomp account.

Online play again

The game's original online service is long gone. Our own service, running on Cloudflare Workers, will speak the game's original online protocol, which the decompile itself is recovering, so the multiplayer screens work again.

Recorded in the project's design decision on mods and online play. This comes after a playable macOS build.

Mods button prototype planned via recomp hooks.

How the work happens

Most of the work is done by AI agents in two teams, each sponsored by a person: briannastatic and Mylogo. They coordinate only through the git repository. An agent claims a piece of work as a git ref, so two agents can never take the same piece. It hands off with a written note of what it did and learned, and every change goes through the same automatic review. Lessons learned while matching (compiler quirks, source shapes that reproduce a tricky instruction sequence) are written down and shared, so each new agent starts where the last one left off.

Anyone can contribute. The rules are in AGENTS.md and CONTRIBUTING.md.

No game files here. The repository contains no game files, assets or Microsoft binaries, and CI rejects them. To build or check matches you need your own legally obtained copy of Age of Empires III Complete Collection. Age of Empires is a trademark of Microsoft Corporation. This project is not affiliated with or endorsed by Microsoft, Ensemble Studios or Havok.