116 lines
4.9 KiB
Markdown
116 lines
4.9 KiB
Markdown
# OpenRA3
|
|
|
|
A from-scratch, portable re-implementation of **Command & Conquer: Red Alert 3**
|
|
in **C++26** using **C++ modules**, built with **GCC 16**.
|
|
|
|
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.0.1**. 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. There is no renderer yet, so
|
|
the match is observed as a deterministic headless result.
|
|
|
|
```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/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` | `dev` (toolchain) and `deploy` (runtime) targets |
|
|
| `.gitlab-ci.yml` | build → test → package pipeline |
|
|
|
|
## Build
|
|
|
|
The host needs no toolchain: build inside the container.
|
|
|
|
```bash
|
|
docker build --target dev -t openra3-dev:local .
|
|
|
|
docker run --rm -v "$PWD:/work" -w /work openra3-dev:local cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release
|
|
docker run --rm -v "$PWD:/work" -w /work openra3-dev:local cmake --build build -j
|
|
docker run --rm -v "$PWD:/work" -w /work openra3-dev:local ctest --test-dir build --output-on-failure
|
|
```
|
|
|
|
Behind a slow or blocked mirror, pass `--build-arg APT_MIRROR=<url>`.
|
|
|
|
## Running a skirmish
|
|
|
|
```bash
|
|
# list the maps in your install
|
|
docker run --rm -v "/path/to/Red Alert 3:/game:ro" openra3-dev:local \
|
|
./build/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-dev:local \
|
|
./build/bin/openra3 skirmish --game-dir /game --map map_mp_2_feasel4 --seed 7
|
|
```
|
|
|
|
`--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.
|
|
|
|
## 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)).
|