# OpenRA3 A from-scratch, portable re-implementation of **Command & Conquer: Red Alert 3** in **C++26** using **C++ modules** and `import std;`, built with **Clang** for both **Linux** and **Windows**. Red Alert 3 runs SAGE 2.0. EA never released that engine's C++ source, but it did open-source the closely related SAGE 1.0 engine as [`electronicarts/CnC_Generals_Zero_Hour`](https://github.com/electronicarts/CnC_Generals_Zero_Hour) (GPLv3). OpenRA3 uses that tree as the architectural reference and reconstructs the RA3-specific behaviour by decompiling the retail `ra3_1.12.game` binary with Ghidra. > OpenRA3 ships **no game assets or binaries**. You must own Red Alert 3. The > engine reads your own local installation at runtime; nothing from it is ever > copied into this repository. Command & Conquer and Red Alert are trademarks of > Electronic Arts; this project is unaffiliated with and unsupported by EA. ## Status OpenRA3 is at **v0.2.0**. The engine compiles and runs headless, and a **minimal skirmish** is playable: it reads a real multiplayer map out of your install, recovers the player start waypoints, and simulates two sides earning credits, training units and fighting until one base falls. The map and match state can be **rendered** to a window (SDL3) or to an image. The whole tree builds for **Linux** (clang + libc++) and cross-compiles to **Windows** (`openra3.exe` + `SDL3.dll`) with llvm-mingw — both using C++26 modules and `import std;`. ```text $ openra3 skirmish --game-dir "/game" --map map_mp_2_feasel4 OpenRA3 skirmish map=map_mp_2_feasel4 source=archive:map_mp_2_feasel4 seed=1 start positions: P0 (1338, 1940) P1 (1291, 1404) result: decided winner=0 frames=3397 (113.2 s) P0 Commander Allied money= 129 units=19 kills=21 losses=3 P1 AI Soviet money= 840 units= 0 kills=3 losses=21 ``` ## Offline only OpenRA3 implements **offline skirmish and, eventually, LAN/single-player**. There is deliberately **no online mode**: no EA account, no online service, no matchmaking, no GameSpy/Steam integration, and no networking in the simulation. The match loop is deterministic and self-contained so it can be replayed and tested without any external service. ## Assets The engine reads the retail game from your local install: - default path `C:\Red Alert 3`, or `--game-dir DIR`, or `$RA3_GAME_DIR`; - `Data\MapsMultiplayer.big` is read for the map catalog; - maps are unpacked from `BIG4` + RefPack and their start waypoints recovered. **No game data is committed or distributed.** `reference/` (the GPLv3 Generals source) and any extracted assets are git-ignored; `tools/fetch_reference.sh` fetches the former on demand. Without an install, the engine falls back to a built-in test map so the project still builds and runs in CI. ## Layout | Path | Purpose | | --- | --- | | `src/core/ra3.core.cppm` | fundamental types, math, strings, random, message stream | | `src/logic/ra3.logic.cppm` | objects, players, teams, spatial partition, game loop | | `src/client/ra3.client.cppm` | display abstraction + client facade / frame loop | | `src/game/ra3.game.cppm` | RA3 sides, player templates, skirmish defaults | | `src/fs/ra3.fs.cppm` | `BIG4` archives, RefPack codec, local install locator | | `src/map/ra3.map.cppm` | map catalog, `EAR`/RefPack unwrap, start waypoints | | `src/skirmish/ra3.skirmish.cppm` | units, economy, AI, combat, win condition | | `src/render/ra3.render.cppm` | ARGB framebuffer, TGA decode, BMP encode, map compositing | | `src/ui/ra3.ui.*.cppm` | SDL3 window viewer (null backend when SDL3 is absent) | | `src/ra3.cppm` | umbrella module re-exporting the SDK | | `apps/openra3/main.cpp` | `maps` / `skirmish` CLI | | `tests/ra3_tests.cpp` | smoke tests (run via `ctest`) | | `tools/` | reference fetch + Ghidra-driven reconstruction helpers | | `docs/` | architecture, reverse-engineering notes, roadmap | | `Dockerfile` | Linux build image (`dev` toolchain + `deploy` runtime) | | `Dockerfile.win` | isolated Windows cross-build image (llvm-mingw + SDL3 MinGW) | | `cmake/toolchains/` | `llvm-mingw-x86_64.cmake` cross toolchain | | `scripts/` | `build-linux.sh` / `build-windows.sh` one-shot builders | | `.gitlab-ci.yml` | build both targets → test → package pipeline | ## Why Clang + `import std;` The engine never `#include`s the standard library: every module does `import std;`. CMake's support for that (`CXX_MODULE_STD`) works today with Clang + libc++. Linux uses the distro clang (LLVM 21); Windows cross-compiles with [llvm-mingw](https://github.com/mstorsjo/llvm-mingw) (clang 23 + libc++ + the libc++ `std` module). The two toolchains live in **separate images** so their compilers and standard libraries never interfere. ## Build The host needs no toolchain: each target builds inside its own image. ```bash # Linux -> build/linux/bin/openra3 scripts/build-linux.sh # Windows -> build/windows/bin/openra3.exe (+ SDL3.dll) scripts/build-windows.sh ``` Or drive Docker directly: ```bash docker build --target dev -t openra3-linux:local . docker run --rm -v "$PWD:/work" -w /work openra3-linux:local \ cmake -S . -B build/linux -G Ninja -DCMAKE_BUILD_TYPE=Release docker run --rm -v "$PWD:/work" -w /work openra3-linux:local cmake --build build/linux -j docker run --rm -v "$PWD:/work" -w /work openra3-linux:local ctest --test-dir build/linux --output-on-failure docker build -f Dockerfile.win --target dev -t openra3-windows:local . docker run --rm -v "$PWD:/work" -w /work openra3-windows:local \ cmake -S . -B build/windows -G Ninja \ -DCMAKE_TOOLCHAIN_FILE=cmake/toolchains/llvm-mingw-x86_64.cmake \ -DCMAKE_BUILD_TYPE=Release docker run --rm -v "$PWD:/work" -w /work openra3-windows:local cmake --build build/windows -j ``` Behind a slow or blocked mirror, pass `--build-arg APT_MIRROR=`. ## Running a skirmish ```bash # list the maps in your install docker run --rm -v "/path/to/Red Alert 3:/game:ro" openra3-linux:local \ /work/build/linux/bin/openra3 maps --game-dir /game # play a headless skirmish on a real map docker run --rm -v "/path/to/Red Alert 3:/game:ro" openra3-linux:local \ /work/build/linux/bin/openra3 skirmish --game-dir /game --map map_mp_2_feasel4 --seed 7 ``` The Windows build is a native `openra3.exe` — copy it next to `SDL3.dll` and run it from `cmd`/PowerShell, e.g. `openra3.exe skirmish --game-dir "C:\Red Alert 3"`. `--frames N` caps the simulation length (default 15 minutes of game time at 30 Hz). The result is deterministic for a given map and seed. ## Rendering the map The renderer draws the map's own overview art, a world grid and the match state (start markers in yellow, player 0 in blue, player 1 in red). **Offscreen image** (works anywhere, no display needed): ```bash docker run --rm -v "/path/to/Red Alert 3:/game:ro" -v "$PWD/out:/out" openra3-linux:local \ /work/build/linux/bin/openra3 render --game-dir /game --map map_mp_2_feasel4 --out /out/map.bmp ``` On Windows the same command runs natively: `openra3.exe render --game-dir "C:\Red Alert 3" --map map_mp_2_feasel4` opens an SDL3 window. **Interactive window** (SDL3; drag to pan, wheel to zoom, Esc to quit). In a container you need an X server on the host — on Windows run [VcXsrv](https://sourceforge.net/projects/vcxsrv/) and launch it with "Disable access control", then: ```bash docker run --rm -v "/path/to/Red Alert 3:/game:ro" -e DISPLAY=host.docker.internal:0.0 \ openra3-linux:local /work/build/linux/bin/openra3 render --game-dir /game --map map_mp_2_feasel4 ``` If no display is available the viewer falls back to writing `openra3_view.bmp`. The unit overlay uses an approximate world scale (`--world-size`, default 5120); exact calibration from the map's heightmap is on the roadmap. ## Reverse engineering The reconstruction is driven by Ghidra against the retail binary. See [`docs/REVERSE_ENGINEERING.md`](docs/REVERSE_ENGINEERING.md) for the workflow and the recovered symbol map, and [`tools/`](tools/) for the helpers. ## License Project code: GPLv3, matching the `CnC_Generals_Zero_Hour` reference (see [`LICENSE`](LICENSE)).