Files
OpenRA3/docs/ARCHITECTURE.md
EnderTheCoder 26e1934a5d feat(render): SAGE water/ocean shaders, per-user logs, camera & culling
Terrain pass now ports the SAGE water model (Ocean.fx / OpenSAGE Water.frag): a de-gridded procedural wave normal combined with the retail ra3_deepocean flow and ra3_deepocean_nrm bump maps (appended as the last two terrain-atlas layers, no new backend binding), Schlick fresnel, sky reflection + depth-graded refraction, SAGE diffuse/specular lighting, depth-based transparency, and an underwater tint (UnderwaterDeferred.fx). Mirrored across terrain.frag / dx_terrain.hlsl / webgl_terrain_frag.glsl / webgpu_terrain.wgsl.

Also: logs move to the per-user state dir (%LOCALAPPDATA%\\OpenRA3\\logs, else XDG) and archive as openra3.<stamp>.log; the FPS label shows the active backend; middle-drag camera reset; objects and roads below the water plane are culled.
2026-09-30 22:18:08 +08:00

861 lines
40 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Architecture & Master Plan
OpenRA3 is a from-scratch, portable re-implementation of **Command & Conquer:
Red Alert 3** (SAGE 2.0) in **pure C++26** — C++ modules, `import std;`, no
scripting language, no managed runtime, no other programming language anywhere
in the tree. It is built with Clang + libc++ on Linux and cross-compiled to
Windows with llvm-mingw.
This document is two things at once:
1. the **layer architecture** (how the modules sit on top of one another), and
2. the **master plan** — the complete Red Alert 3 feature set decomposed three
levels deep into **Module → Function → Feature**, each tagged with its
implementation status and target milestone.
The decomposition is the contract: every feature RA3 has is either implemented,
being implemented, or explicitly planned here. Nothing is silently dropped.
> **Scope.** Offline only. Single-player campaign, skirmish, Commander's
> Challenge and LAN lockstep — never an online service, matchmaking, EA account
> or GameSpy/Steam integration. The simulation is deterministic and
> self-contained. No game assets or binaries are shipped; the engine reads the
> user's own install at runtime.
---
## 1. Principles
Same five rules as the rest of the tree, restated because the plan is written
against them:
1. **Pure C++.** One language. No Lua, no JS, no C#, no Python at runtime.
Python is allowed *only* in offline build tooling (`tools/`, cmake helper
scripts), never linked into `openra3`.
2. **No raw owning pointers.** Ownership is `std::unique_ptr`; cross-references
are non-owning views (`thing *`, handles, indices).
3. **Portable simulation.** No platform API in the foundation or simulation
layers. All platform concerns live behind `display` / `audio` / `video`.
4. **Determinism.** Anything that can diverge between runs (RNG, iteration
order, float accumulation, hash order) is explicit, seeded and testable.
5. **RE-traceable.** Every structure or constant taken from the retail
`ra3_1.12.game` (image base `0x400000`) or from the GPLv3 SAGE 1.0 reference
cites its origin. No asserted fact without a source.
---
## 2. Layer architecture
Each layer may import the ones below it, never the ones above. The `ra3`
umbrella module re-exports the SDK; applications import `ra3` only.
```
L6 tooling / apps openra3 (CLI) tools/ (offline, Python allowed)
| import ra3
---------------------------------------------------------------------------
v
L5 meta ra3.i18n ra3.mod ra3.net (deferred)
|
L4 match services ra3.match ra3.replay ra3.save
|
L3 presentation ra3.client ── ra3.render ── ra3.audio ── ra3.video
| \ |
| \ v
| ra3.display (backend pick)
| / | \ \
v ra3.ui ra3.vulkan ra3.dx ra3.webgpu / ra3.wasmgl
| (SDL3) (Vulkan) (D3D11/12) (wasm workers)
---------------------------------------------------------------------------
v
L2 simulation ra3.logic ra3.modules ra3.combat ra3.movement
ra3.economy ra3.ai ra3.script ra3.powers ra3.shroud
|
L1 data & assets ra3.data ── ra3.assets ── ra3.map ── ra3.terrain
| |
v v
ra3.fs (BIG4 / RefPack / install)
|
L0 foundation ra3.core (types, math, containers, RNG, message bus)
```
The current concrete modules (`ra3.core`, `ra3.logic`, `ra3.data`,
`ra3.skirmish`, `ra3.fs`, `ra3.map`, `ra3.terrain`, `ra3.models`, `ra3.render`, `ra3.ui.*`,
`ra3.vulkan.*`, `ra3.dx.*`, `ra3.webgpu.*`, `ra3.wasmgl.*`, `ra3.display`, `ra3.game`, `ra3.client`, and the
vendored `ender.log`) are the **seeds** of the
target modules below. `ra3.skirmish` and `ra3.game` will be absorbed into
`ra3.ai` / `ra3.match`; new modules are added as their subsystems are recovered.
### Status legend
| Tag | Meaning |
| --- | --- |
| `[x]` | implemented and tested on `main` |
| `[~]` | partially implemented / works for the happy path |
| `[ ]` | planned, not started |
| `(vX.Y)` | target milestone (see the roll-up in §5) |
| `!!` | needs reverse engineering before it can be built |
| Function tag | Meaning |
| --- | --- |
| `D` | **done** — the function's features are largely present |
| `P` | **partial** — some features present |
---
## 3. Master plan — Module → Function → Feature
### M00 `ra3.core` — foundation vocabulary `[D]`
Mirrors SAGE `GameEngine/Common`. Everything else speaks this.
- **F1 Types & math** `[D]`
- `[x]` `real` (float), `int32`/`uint32`/`uint16`/`uint8`, `bool` aliases
- `[x]` `coord2d` / `coord3d` vectors, dot/cross/length/normalize
- `[x]` `rgb_color` / `argb_color`, packing and lerp
- `[x]` geometry: `segment`, `triangle`, `plane`, ray/segment intersection
- `[ ]` fixed-point helpers for replay-stable accumulation `(v0.4)`
- `[ ]` matrix / quaternion (needed by W3D models) `(v0.6)`
- `[ ]` `KindOf` flag bitset (SAGE object taxonomy) `(v0.4)`
- **F2 Containers** `[D]`
- `[x]` `ascii_string` + `make_name_key` (case-folded hash for data lookup)
- `[x]` intrusive doubly linked list (message stream node layout)
- `[x]` deterministic iteration-order map (insertion-ordered)
- `[ ]` object pool / arena for per-frame allocations `(v0.4)`
- `[ ]` interned string table `(v0.5)`
- **F3 Deterministic RNG** `[D]`
- `[x]` seedable `random` stream (`game_logic` random)
- `[ ]` independent per-player / per-subsystem streams `(v0.4)`
- `[ ]` shuffle / weighted-pick primitives `(v0.4)`
- **F4 Message stream** `[D]`
- `[x]` command bus with retail node layout (`appendMessage` `0x0060c4a0`)
- `[x]` ordered per-frame command drain
- `[ ]` command argument blocks (build/target/waypoint payloads) `(v0.4)`
- `[ ]` network/replay source tagging `(v0.4)`
- **F5 Diagnostics** `[~]`
- `[x]` logging sink + assert macro
- `[ ]` scoped profiling timers, per-subsystem counters `(v0.4)`
- `[ ]` structured crash/report capture `(v0.8)`
- **F6 Serialization primitives** `[~]`
- `[x]` little-endian byte reader/writer
- `[ ]` chunked binary reader/writer with versioning `(v0.5)`
- `[ ]` stable content hashing (replay/desync checks) `(v0.4)`
- **F7 Localization primitives** `[~]` (see M26)
- `[x]` UTF-16 unit access, CSF low-byte `^0xFF` decode
- `[ ]` placeholder substitution, plural/gender rules `(v0.5)`
### M01 `ra3.fs` — containers & install `[D]`
- **F1 BIG archive** `[D]`
- `[x]` `BIG4` header parse (`fileSize` LE, `fileCount`/offsets BE) + name index
- `[x]` payload read on demand (index-only resident memory)
- `[ ]` `BIGF` (RefPack whole-archive) variant `!!` `(v0.5)`
- `[ ]` write support (pack/repack, used by tooling) `(v0.8)`
- **F2 RefPack codec** `[D]`
- `[x]` decode: 2/3/4-byte commands, long-literal, stop opcode
- `[x]` `refpack_output_size` without full decompress
- `[ ]` encode (for tooling round-trips) `(v0.8)`
- **F3 Install locator** `[D]`
- `[x]` `--game-dir` / `$RA3_GAME_DIR` / `C:\Red Alert 3` defaults
- `[ ]` registry / Steam / EA-app discovery `(v0.5)`
- `[ ]` Uprising as an optional content source `(v0.5)`
- **F4 Virtual file system** `[~]`
- `[x]` layered archive mounts (loose files → `*.big`)
- `[ ]` patch/language precedence rules (newest `Lang-*.big` wins) `(v0.5)`
- `[ ]` case-insensitive lookup + path normalisation `(v0.5)`
- **F5 Extraction targets** `[D]`
- `[x]` `openra3 extract` dumps maps/terrain to `assets/`
- `[ ]` full asset dump via `ra3tools` integration as a build target `(v0.5)`
### M02 `ra3.data` — data schema & balance `[P]`
- **F1 Data schema** `[ ]` `!!`
- `[ ]` SAGE INI parser (`#include`, `#define`, inheritance) `(v0.5)`
- `[ ]` XML rule schema
- `[ ]` `.manifest` compiled-blob schema `!!` `(v0.5)`
- **F2 Compiled asset blobs** `[ ]` `!!`
- `[ ]` `global.bin` deserialisation `(v0.5)`
- `[ ]` `static.*.bin` deserialisation `(v0.5)`
- `[ ]` version/dependency validation `(v0.5)`
- **F3 Balance tables** `[~]`
- `[x]` damage types, `ArmorTemplate` percentages
- `[x]` weapon target masks, weapon definitions
- `[x]` unit/structure build costs, times, prerequisites
- `[x]` ore economy constants
- `[ ]` read these from the install instead of pinned constants `(v0.5)`
- **F4 Object definitions** `[ ]`
- `[ ]` `ThingTemplate`/`ObjectTemplate` inheritance graph `(v0.5)`
- `[ ]` module descriptor lists (per-object update/draw module sets)
- `[ ]` `WeaponTemplate`/`ArmorTemplate`/`LocomotorTemplate` stores
- **F5 Faction & player templates** `[~]`
- `[x]` Allied / Soviet / Empire side flags (`2/4/8`), match templates
- `[ ]` commander/sub-commander definitions `(v0.7)`
- `[ ]` build/upgrade unlock trees per faction `(v0.5)`
- **F6 Rules & settings** `[ ]`
- `[ ]` skirmish options (cash, crates, superweapons, speed, limits)
- `[ ]` bonus crate effect table
- `[ ]` AI personality tables
- `[ ]` map-specific rule overrides (`map.ini`)
- **F7 Validation** `[ ]`
- `[ ]` schema diagnostics with source location
- `[ ]` cross-reference integrity (missing templates/refs)
### M03 `ra3.assets` — runtime asset manager `[ ]`
- **F1 Textures** `[~]`
- `[x]` TGA decode (`ra3.render`); 256×256 terrain cells
- `[ ]` DDS / DXT compressed textures `(v0.5)`
- `[ ]` atlas + mip generation, gutter padding (GPU) `[~]`
- `[ ]` async upload / streaming `(v0.6)`
- **F2 Models** `[~]`
- `[x]` compiled `W3DMesh` decode (vertex buffer + D3D9 declaration + triangle list) from the BAB static/worldbuilder stream
- `[x]` embedded DDS textures (DXT1/3/5 + uncompressed RGB) → ARGB
- `[x]` `W3DHierarchy` decode + static bind-pose skinning (bone-space vertices)
- `[ ]` W3D container/hierarchy animation, LOD sets, collision meshes `!!` `(v0.6)`
- **F3 Animation** `[ ]` `!!`
- `[ ]` W3D animation chunks, bone poses `(v0.6)`
- `[ ]` blend trees / transition animations
- **F4 Audio** `[ ]` `!!`
- `[ ]` audio container + codec decode `(v0.7)`
- `[ ]` cue/event tables (unit responses, weapon foley)
- **F5 Fonts & glyphs** `[ ]`
- `[ ]` bitmap/vector font load; CJK coverage `(v0.5)`
- **F6 Asset registry** `[ ]`
- `[ ]` cache with ref counting, eviction `(v0.6)`
- `[ ]` name-key lookup into the data schema
- **F7 UI art (`.apt`)** `[ ]` `!!`
- `[ ]` RA3 interface art decode (HUD/command bar) `(v0.7)`
### M04 `ra3.map` — map catalog & loader `[D]`
- **F1 Catalog** `[D]`
- `[x]` scan `MapsMultiplayer.big` for main map entries
- `[ ]` campaign + challenge map catalog `(v0.7)`
- **F2 Compiled map (`CkMp`)** `[D]`
- `[x]` double unwrap (`BIG4` RefPack → `EAR\0` → RefPack → `CkMp`)
- `[x]` name table + chunk list (`{index,version,size,data}`)
- `[ ]` full typed chunk dispatch for all chunk kinds `(v0.5)`
- **F3 Start positions** `[~]`
- `[x]` `Player_N_Start` waypoint scan → `coord3d`
- `[ ]` `MPPositionList` layout for maps without waypoints `!!` `(v0.5)`
- **F4 Metadata** `[~]`
- `[x]` display names from `gamestrings.csf` (`MAP:<ID>`)
- `[ ]` player count, size, supported game modes `(v0.5)`
- **F5 Map rules** `[ ]`
- `[ ]` `map.ini` override application `(v0.5)`
- **F6 Preview art** `[~]`
- `[x]` `<map>_art.tga` overview decode (`--thumbnail`)
- **F7 Validation & fallback** `[D]`
- `[x]` reject degenerate extractions, fall back to built-in test map
- `[ ]` integrity/version checks with actionable errors `(v0.5)`
### M05 `ra3.terrain` — terrain `[P]`
- **F1 Heightmap** `[D]`
- `[x]` `HeightMapData` v6 (grid, border, `u16` elevations, scale)
- `[ ]` multi-resolution / LOD height sampling `(v0.6)`
- **F2 Blend tiles** `[D]`
- `[x]` `BlendTileData` v27: tile grid, blends/three-way/cliff tables
- `[x]` `BlendDescription` parse; `secondaryTile` decode
- `[x]` retail `Terrain.fx` blend ramp (`blend_factor`, axis flags)
- **F3 Terrain textures** `[D]`
- `[x]` `art\terrain\*.tga` from `Terrain.big` / `Core11.big`
- `[x]` cell atlas with replicated gutter (GPU bleeding fix)
- `[ ]` continuous 32 px / Morton layout (kill residual grid lines) `(v0.4)`
- **F4 Water** `[ ]` `!!`
- `[ ]` water height/type, sea level `(v0.6)`
- `[ ]` animated waves + shoreline blending `(v0.6)`
- `[ ]` shroud-aware water rendering `(v0.6)`
- **F5 Cliffs & roads** `[ ]` `!!`
- `[x]` `CliffTextures` table parsed
- `[ ]` cliff mesh + `CliffTextureMapping` UV remap `(v0.6)`
- `[ ]` roads and bridges (passability + render) `(v0.6)`
- **F6 Terrain lighting** `[ ]`
- `[ ]` per-vertex normals, cell lighting, global light `(v0.6)`
- **F7 Terrain queries** `[~]`
- `[x]` height lookup (render)
- `[ ]` passability grid (ground/naval/amphibious/air) `(v0.4)`
- `[ ]` buildability grid (flatness, slope, water) `(v0.4)`
### M06 `ra3.logic` — simulation core `[P]`
- **F1 Objects & things** `[~]`
- `[x]` `thing` → `object` with pluggable `update_module`s
- `[x]` global object registry with stable ids
- `[ ]` handle/reference system (survives deletion) `(v0.4)`
- `[ ]` object destruction lifecycle + death dispatch `(v0.4)`
- **F2 Players & teams** `[~]`
- `[x]` `player` / `player_list`
- `[x]` money (`std::vector<Money*>`) and power fields
- `[x]` team assignment and relations
- `[ ]` diplomacy matrix, ally vision sharing `(v0.5)`
- **F3 Partition manager** `[~]`
- `[x]` spatial grid, neighborhood queries
- `[ ]` cell-resolution + large-object multi-cell registration `(v0.4)`
- **F4 Game loop** `[~]`
- `[x]` 30 Hz deterministic step with frame counter
- `[x]` `prepare_new_game` / `start_new_game` two-phase start
- `[ ]` per-tick module scheduling with stable ordering `(v0.4)`
- **F5 Commands** `[~]`
- `[x]` `message_stream` bus
- `[ ]` typed commands (build, attack, move, ability, sell, repair) `(v0.4)`
- `[ ]` command validation + feedback (insufficient funds, etc.) `(v0.4)`
- **F6 Determinism** `[~]`
- `[x]` seeded logic random
- `[ ]` replay-hash of state per tick `(v0.4)`
- `[ ]` float determinism policy / fixed-point where required `(v0.4)`
- **F7 Victory / defeat** `[~]`
- `[x]` team-wipe / base-destruction win condition
- `[ ]` surrender, disconnection, timed, objective victories `(v0.5)`
- `[ ]` score / stats accumulation `(v0.8)`
### M07 `ra3.modules` — object update & draw modules `[P]`
- **F1 Module system** `[~]`
- `[x]` update modules attached to objects with a simple order
- `[ ]` module descriptor data-binding (from `ThingTemplate`) `(v0.5)`
- `[ ]` interface queries (get WeaponModule / ContainModule on demand) `(v0.4)`
- **F2 Locomotor** `[ ]`
- `[ ]` movement state machine (idle/moving/attacking) `(v0.4)`
- **F3 Weapon module** `[~]`
- `[x]` simple weapons on units, auto-target + fire
- `[ ]` multi-weapon slots, turret aiming/rotation `(v0.4)`
- `[ ]` reload/clip, deploy/undeploy states `(v0.6)`
- **F4 Contain** `[ ]`
- `[ ]` transport passenger slots, load/unload `(v0.4)`
- `[ ]` garrison of civilian structures `(v0.6)`
- `[ ]` paradrop / airdrop `(v0.6)`
- **F5 Production** `[~]`
- `[x]` pay-as-you-go build queue on a factory
- `[ ]` per-factory queues, rally points, queue reordering `(v0.4)`
- `[ ]` building placement → production handoff `(v0.4)`
- **F6 Power** `[~]`
- `[x]` power production/consumption fields
- `[ ]` brownout/blackout effects on radar + build speed `(v0.4)`
- **F7 Upgrades** `[ ]`
- `[ ]` upgrade research, unlock dependent modules/weapons `(v0.5)`
- **F8 Experience / veterancy** `[ ]`
- `[ ]` XP from kills, ranks (veteran/elite/heroic), bonuses `(v0.6)`
- `[ ]` chevron rendering `(v0.6)`
- **F9 Special abilities** `[~]`
- `[ ]` secondary ability slots with cooldown, target/area types `(v0.6)`
- `[ ]` toggle/instant/targeted ability kinds `(v0.6)`
- **F10 Stealth / disguise / detection** `[ ]`
- `[ ]` stealth states, detection radius, decloak on fire `(v0.6)`
- `[ ]` disguise (spy-like) and detection interaction `(v0.6)`
- **F11 Structure modules** `[~]`
- `[x]` base structures, destruction
- `[ ]` construction/assembly animation, sell, repair `(v0.4)`
- `[ ]` walls/gates if present, defensive structures `(v0.6)`
- **F12 Resource modules** `[~]`
- `[x]` harvester ↔ refinery ore cycle
- `[ ]` ore field spread/depletion, multiple miners, dock queue `(v0.4)`
- **F13 Shroud modules** `[ ]`
- `[ ]` per-object shroud reveal / clearance `(v0.4)`
- **F14 Draw modules** `[ ]`
- `[ ]` model draw, animation, particles, construction ghost, temp effects `(v0.6)`
### M08 `ra3.combat` — weapons, warheads, damage `[P]`
- **F1 Weapons** `[~]`
- `[x]` damage, range, rate of fire, target masks
- `[ ]` clip/burst, scatter, arc, continuous beam `(v0.4)`
- `[ ]` primary vs secondary weapon selection `(v0.4)`
- **F2 Warheads** `[~]`
- `[x]` damage type + armor multiplier resolution
- `[ ]` radius/falloff, affects mask, death type on kill `(v0.4)`
- **F3 Armor** `[~]`
- `[x]` `ArmorTemplate` percentage table
- `[ ]` armor upgrades and per-state armor `(v0.6)`
- **F4 Damage application** `[~]`
- `[x]` damage resolution against armor
- `[ ]` conditional modifiers (from above, in air, moving) `(v0.4)`
- `[ ]` friendly-fire policy, self-damage `(v0.4)`
- **F5 Projectiles** `[ ]`
- `[ ]` ballistic / laser / missile / beam / homing / arcing `(v0.4)`
- `[ ]` projectile draw + impact VFX hook `(v0.6)`
- **F6 Targeting** `[~]`
- `[x]` simple nearest/in-range acquisition
- `[ ]` priority scans (attack-move, guard, force-attack) `(v0.4)`
- `[ ]` re-targeting, leash, target ground `(v0.4)`
- **F7 Special effects** `[ ]`
- `[ ]` EMP/stun, flame/radiation DoT, mind-control, shrink/grow `(v0.7)`
- **F8 Death & corpses** `[ ]`
- `[ ]` death types, wrecks, gibs, salvage, rebuild `(v0.6)`
### M09 `ra3.movement` — locomotion & pathfinding `[ ]`
- **F1 Locomotors** `[ ]`
- `[ ]` ground / air / naval / amphibious / hover / teleport `!!` `(v0.4)`
- `[ ]` turn rates, acceleration, braking, banking `(v0.6)`
- **F2 Pathfinding** `[ ]`
- `[ ]` grid A* over the passability grid `(v0.4)`
- `[ ]` hierarchical / jump-point refinement `(v0.6)`
- `[ ]` dynamic obstacle integration (buildings, units) `(v0.6)`
- **F3 Steering & flocking** `[ ]`
- `[ ]` separation, avoidance, group cohesion `(v0.6)`
- `[ ]` formation slots (line/wedge/box) `(v0.6)`
- **F4 Orders & waypoints** `[~]`
- `[x]` straight-line move toward a target (skirmish)
- `[ ]` waypoint queues, queued orders with shift `(v0.4)`
- `[ ]` guard / patrol / attack-move / stop / scatter `(v0.4)`
- **F5 Collision & crush** `[ ]`
- `[ ]` unit-unit collision, pushing, crush damage `(v0.6)`
- **F6 Naval & amphibious** `[ ]`
- `[ ]` water-only movement, amphibious land↔water transition `!!` `(v0.6)`
- **F7 Transport & airdrop** `[ ]`
- `[ ]` boarding/unloading, airdrop descent `(v0.6)`
### M10 `ra3.economy` — resources, power, construction `[P]`
- **F1 Ore / resource** `[~]`
- `[x]` ore fields and harvester↔refinery cycle
- `[ ]` ore spread/regrowth, depletion, ore density `(v0.4)`
- **F2 Power** `[~]`
- `[x]` power balance fields
- `[ ]` brownout/blackout consequences `(v0.4)`
- **F3 Construction** `[~]`
- `[x]` pay-as-you-go queue, tech prerequisites, build times
- `[ ]` build-radius rules (structures must be in base vicinity) `(v0.4)`
- `[ ]` low-power build-speed penalty `(v0.4)`
- **F4 Placement** `[ ]`
- `[ ]` placement grid, footprint validation, green/red ghost `(v0.4)`
- `[ ]` adjacency bonuses / prerequisite-adjacent structures `(v0.6)`
- **F5 Repair & sell** `[ ]`
- `[ ]` structure repair over time, cost, sell refund `(v0.4)`
- `[ ]` unit repair pads if present `(v0.6)`
- **F6 Rally points** `[ ]`
- `[ ]` factory rally, rally preview, waypoint rally `(v0.6)`
- **F7 Income modifiers** `[ ]`
- `[ ]` bonus crates (cash/units/repair/heal, `random_bonus_crates`) `(v0.5)`
### M11 `ra3.ai` — computer opponents `[P]`
- **F1 Skirmish AI** `[~]`
- `[x]` simple build AI (base, ore, a couple of unit types)
- `[ ]` data-driven build orders per faction `(v0.5)`
- `[ ]` economy management (expand, defend harvesters) `(v0.5)`
- **F2 Attack management** `[~]`
- `[x]` send units at the enemy base
- `[ ]` attack force assembly, waves, retreat/regroup `(v0.5)`
- `[ ]` targeting priorities (harvesters, key structures) `(v0.6)`
- **F3 Team AI / diplomacy** `[ ]`
- `[ ]` allied coordination, shared attacks, base defense `(v0.6)`
- **F4 Difficulty & personalities** `[ ]`
- `[ ]` easy/normal/hard modifiers, AI cheating options `(v0.5)`
- `[ ]` commander personalities (aggressive/turtle/air/naval) `(v0.7)`
- **F5 Scouting** `[ ]`
- `[ ]` exploration, map awareness, threat response `(v0.6)`
- **F6 Superweapon usage** `[ ]`
- `[ ]` AI powers/power targeting `(v0.7)`
- **F7 Script hooks** `[ ]`
- `[ ]` AI cooperation with script triggers (campaign) `(v0.7)`
### M12 `ra3.script` — triggers & missions `[ ]`
- **F1 Trigger system** `[ ]` `!!`
- `[ ]` conditions (elapsed, object in region, destroyed, flag) `(v0.7)`
- `[ ]` actions (spawn, order, reveal, camera, dialog, win/lose) `(v0.7)`
- **F2 Script engine** `[ ]` `!!`
- `[ ]` SAGE script language / mission script parse `(v0.7)`
- `[ ]` timers, counters, flags, per-player state `(v0.7)`
- **F3 Campaign missions** `[ ]`
- `[ ]` mission objectives, sequential phases, briefing `(v0.8)`
- `[ ]` three faction campaigns (Allied/Soviet/Empire) `(v0.8)`
- **F4 Reinforcements & spawns** `[ ]`
- `[ ]` scripted spawns, cinematic units, capture `(v0.8)`
- **F5 Tutorials** `[ ]`
- `[ ]` tutorial message gates, camera lock/unlock actions `(v0.8)`
- **F6 Co-op** `[ ]`
- `[ ]` co-op commander missions `(v0.9)`
### M13 `ra3.powers` — superweapons & support powers `[ ]`
- **F1 Superweapons** `[ ]` `!!`
- `[ ]` Allied Chronosphere `(v0.7)`
- `[ ]` Soviet Vacuum Imploder `(v0.7)`
- `[ ]` Empire Psionic Decimator `(v0.7)`
- `[ ]` charge timer, targeting, ready state, HUD `(v0.7)`
- **F2 Support powers** `[ ]`
- `[ ]` per-faction powers (spy satellite, air support, etc.) `(v0.7)`
- `[ ]` cooldowns, targeting types, cost `(v0.7)`
- **F3 Commander's Challenge powers** `[ ]`
- `[ ]` challenge-mode power loadouts `(v0.8)`
### M14 `ra3.shroud` — fog of war & radar `[ ]`
- **F1 Shroud** `[ ]`
- `[ ]` per-player unexplored grid `(v0.4)`
- **F2 Fog of war** `[ ]`
- `[ ]` explored-but-unseen dimming `(v0.4)`
- **F3 Reveal sources** `[ ]`
- `[ ]` units/structures reveal radius, abilities, spy satellite `(v0.6)`
- **F4 Radar / minimap** `[ ]`
- `[ ]` radar texture, unit blips, radar-offline on low power `(v0.6)`
- **F5 Shroud ↔ logic** `[ ]`
- `[ ]` targetability gating, option for AI to ignore shroud `(v0.4)`
### M15 `ra3.client` — game client & shell `[P]`
- **F1 Game client** `[~]`
- `[x]` `game_client` facade owning the sim, driving the frame loop
- `[ ]` sim/present decoupling, interpolation, catch-up `(v0.6)`
- **F2 Tactical view / camera** `[~]`
- `[x]` controls: wheel zoom, edge scroll, clamped pan, open on player start
- `[x]` camera tuning table (`cameraMinHeight` …) + lock actions
- `[ ]` retail perspective camera, pitch/yaw, FOV (needs 3D terrain) `(v0.6)`
- **F3 Selection** `[ ]`
- `[ ]` click select, drag-box, double-click type select `(v0.6)`
- `[ ]` control groups (Ctrl+N), type filters, select-all-of-type `(v0.6)`
- **F4 Orders** `[ ]`
- `[ ]` contextual right-click orders, force-attack, force-move `(v0.6)`
- `[ ]` order queue with shift, formation move `(v0.6)`
- **F5 Command bar** `[ ]` `!!`
- `[ ]` build/production palettes, ability buttons, portraits `(v0.7)`
- `[ ]` tooltips, cost/time, cooldown sweep, disabled states `(v0.7)`
- **F6 HUD** `[ ]`
- `[x]` minimal match-state overlay (units, start markers)
- `[ ]` resource/power readouts, objectives, notifications `(v0.7)`
- `[ ]` EVA voice announcements hook `(v0.7)`
- **F7 Shell menus** `[~]`
- `[x]` map list by localized name + full render/skirmish options; console fallback
- `[ ]` main menu, skirmish setup, faction/team/color pickers `(v0.7)`
- `[ ]` options (video/audio/keybinds), pause, load/save, credits `(v0.8)`
- **F8 Feedback & cursors** `[ ]`
- `[ ]` action cursor, placement ghost, move/attack markers `(v0.6)`
### M16 `ra3.render` — renderer & RHI `[P]`
- **F1 RHI** `[ ]`
- `[ ]` device/queue/swapchain abstraction over Vulkan `(v0.6)`
- `[ ]` buffers, textures, samplers, descriptor sets, pipelines `(v0.6)`
- `[ ]` `present_terrain` is the seam where this lands today `[~]`
- **F2 Render graph** `[ ]`
- `[ ]` pass scheduling, barriers, transient/aliased resources `(v0.6)`
- **F3 Terrain render** `[~]`
- `[x]` top-down software + GPU heightfield with blend ramp + gutter atlas
- `[ ]` perspective terrain mesh, LOD, cliff `(v0.6)`
- `[x]` water surface in the raymarch: SAGE `Water.frag` port (ocean/river) `[~]`
- **F4 Model render** `[~]`
- `[x]` static map-object triangle soup, world-space, depth-tested over the terrain (Vulkan + software)
- `[x]` bind-pose skinning (bone-space vertices) + ground-decal depth bias
- `[ ]` animated W3D draw, materials, team colors `!!` `(v0.6)`
- `[ ]` shadows, decals, ground marks `(v0.6)`
- **F5 VFX** `[ ]`
- `[ ]` particle systems, beams, muzzle flashes, explosions `(v0.6)`
- `[ ]` shader effect graph (retail `.fxo` parity where feasible) `!!` `(v0.7)`
- **F6 Sky & atmosphere** `[ ]`
- `[ ]` skybox, fog, weather, time-of-day `(v0.7)`
- **F7 HUD render** `[ ]`
- `[ ]` 2D art layer, fonts, minimap/radar texture `(v0.7)`
- **F8 Software renderer** `[D]`
- `[x]` ARGB framebuffer, blit/line/circle/text, TGA decode, BMP encode
- `[x]` map compositing, grid, markers; headless output
- **F9 Post-processing** `[ ]`
- `[x]` underwater tint/fog in the terrain pass (retail `UnderwaterDeferred.fx`) `[~]`
- `[ ]` bloom, color grading, AA, resolution scaling `(v0.7)`
### M16b shader porting status (retail `Data\Shaders.big` → `*.fxo`)
The retail set is **88 compiled effects** (`Core12\shaders\compiled`, duplicated
in `Misc`/`Shaders`; `Core5`/`Core8` ship only `terrain`; plus a 60-byte
`null` stub). OpenRA3 implements the static-map subset only:
- **Ported (approximate stand-ins, shared by all backends):** `Terrain.fx`
(`terrain.*`), the opaque diffuse subset of `BuildingsGeneric.fx` /
`BasicW3D.fx` / `ObjectsGeneric.fx` (`object.*`), and the SAGE water model
`Ocean.fx` (+ `OceanDisplacement`/`OceanNoVertexTexture`/`RiverWater`/
`RiverReflection`/`UnderwaterDeferred`, folded into the `terrain.*` water
branch — see `docs/REVERSE_ENGINEERING.md`). The retail water flow and bump
maps (`art/terrain/ra3_deepocean.tga`, `ra3_deepocean_nrm.tga`) ride as the
last two terrain-atlas layers, so no backend adds a binding.
- **Not ported:** all faction/variant model shaders (`buildings*`, `objects*`,
`basicw3d*`, `defaultw3d*`, `normalmapped`, `tree`/`treesway`), instances/
animation (`infantry*`), particles and beams (`cpuparticle`, `gpuparticle*`,
`swarmparticle`, `laser*`, `lightning`, `fx*`, `tracer`, `trail`,
`connectionline`, `linerenderers`, `stream`, `rain`, `simple*`), shadows and
ground decals (`shadow`, `decal`, `outlines`, `occlusion`, `terraintracks`),
post-processing (`postfx_*`), and the 2D/misc shaders (`render2d`, `video`,
`bootupscreen`, `debug`, `errormissing`, `rotateenvironmentmap`,
`distortingobject`). The shared retail includes `shadowmap.fxh`, `ssao.fxh`,
`macrotexture.fxh`, `gamma.fxh` are likewise absent (`skinning.fxh` is done at
bind pose only).
### M17 `ra3.ui` — platform layer & backends `[D]`
- **F1 Display abstraction** `[D]`
- `[x]` shared primitives + interactive loops + `ui_event` mapping in the base
- `[x]` backends implement primitives only (SDL/Vulkan cannot drift)
- **F2 SDL3 backend** `[D]`
- `[x]` window, streaming-texture blit, input polling
- `[ ]` gamepad support `(v0.8)`
- **F3 Backend selection (`ra3.display`)** `[D]`
- `[x]` preferred backend + ordered fallback (Vulkan / D3D11 / D3D12 / SDL)
- `[x]` in-game Renderer option; report failure for offscreen fallback
- **F4 Input mapping** `[~]`
- `[x]` keyboard/mouse state, modifier masks
- `[ ]` rebindable keybinds, mouse capture, scroll wheel events `(v0.6)`
- **F5 Window modes** `[ ]`
- `[ ]` windowed/fullscreen/borderless, resize, multi-monitor `(v0.6)`
- **F6 Null/headless backend** `[D]`
- `[x]` returns false so the tree builds and runs without SDL3/Vulkan
### M18 `ra3.vulkan` — Vulkan backend `[P]`
- **F1 Device & swapchain** `[~]`
- `[x]` embedded SPIR-V, SDL3 surface, present path
- `[ ]` formal RHI integration (see M16 F1) `(v0.6)`
- **F2 Terrain presentation** `[D]`
- `[x]` GPU heightfield raymarch, mipmapped atlas, gutter, retail blend ramp
- **F3 Materials & pipelines** `[~]`
- `[x]` static-model pipeline (vertex/index buffers, texture array, depth test)
- `[ ]` particle/HUD pipelines `(v0.6)`
- **F4 Null fallback** `[D]`
- `[x]` report failure when no Vulkan loader is present
### M18b `ra3.dx` — Direct3D 11 / 12 backend `[P]`
- **F1 Device & swapchain** `[D]`
- `[x]` SDL3 window → HWND, DXGI flip-model swapchain, resize
- `[x]` runtime HLSL via `d3dcompiler_47` (no build-time shader compiler)
- **F2 2D image path** `[D]`
- `[x]` BGRA scene texture + fullscreen-triangle blit (D3D11/D3D12)
- **F3 Terrain presentation** `[D]`
- `[x]` GPU heightfield raymarch (HLSL port of `terrain.frag`), D3D11 and D3D12
- **F4 Root signatures / PSOs (D3D12)** `[~]`
- `[x]` root constants, descriptor tables, static samplers, barriers
- `[ ]` shared RHI with Vulkan (see M16 F1) `(v0.6)`
- **F5 Null fallback** `[D]`
- `[x]` non-Windows builds link a stub that fails `init`
### M18d `ra3.wasmgl` — SDL-free wasm worker backend `[P]`
- **F1 Device & canvas** `[D]`
- `[x]` Emscripten-only; engine runs on a plain Web Worker, WebGL2 on an
OffscreenCanvas transferred by the page (no SDL, no `PROXY_TO_PTHREAD`)
- `[x]` `specialHTMLTargets['#canvas']` lets `emscripten_webgl_create_context` find
the worker's OffscreenCanvas
- **F2 2D image path** `[D]`
- `[x]` GLSL ES BGRA texture + fullscreen triangle (`.bgra` swizzle)
- **F3 Terrain presentation** `[D]`
- `[x]` GPU heightfield raymarch (GLSL ES), including the `GL_R16`
(`0x822A`) heightmap and `GL_RGBA16` cell textures
- **F4 On-demand assets** `[D]`
- `[x]` `assets.manifest.json` (from `scripts/make_web_manifest.py`) is embedded;
the worker registers every file with `FS.createLazyFile`, so only opened files
are fetched (a map pulls just its map + tiles)
- **F5 Input** `[D]`
- `[x]` page owns DOM listeners and posts events to the worker's exported
`openra3_*` functions (no DOM callbacks in the worker)
- **F6 Null fallback** `[D]`
- `[x]` non-Emscripten builds link a stub that fails `init`
### M18e `ra3.webgpu` — WebGPU wasm backend `[P]`
- **F1 Device & surface** `[D]`
- `[x]` Emscripten `emdawnwebgpu` port (Dawn C++ wrapper); the worker pre-creates
the device (`Module.preinitializedWebGPUDevice`) and a surface is configured on
the transferred OffscreenCanvas
- **F2 WGSL shaders** `[D]`
- `[x]` web WebGPU is WGSL-only, so the scene/terrain shaders are WGSL ports
(the Vulkan SPIR-V blobs cannot be reused); the uniform layout and terrain data
plumbing are shared with Vulkan/WebGL
- **F3 Terrain** `[D]`
- `[x]` GPU heightfield raymarch in WGSL (R16Uint heightmap, RGBA16Uint cell
record, RGBA8 atlas)
- **F4 Selection & fallback** `[D]`
- `[x]` preferred wasm backend; falls back to `ra3.wasmgl` when no adapter is
available
- **F5 Null fallback** `[D]`
- `[x]` non-Emscripten builds link a stub that fails `init`
### M19 `ra3.audio` — audio `[ ]`
- **F1 SFX** `[ ]`
- `[ ]` 3D positional sound from cues/events `(v0.7)`
- **F2 Music** `[ ]`
- `[ ]` streaming music, playlists, combat stingers `(v0.7)`
- **F3 Voice & EVA** `[ ]`
- `[ ]` unit response lines, announcer (EVA) events `(v0.7)`
- **F4 Mixer** `[ ]`
- `[ ]` buses (master/sfx/music/voice), volume, ducking, reverb `(v0.7)`
- **F5 Codecs** `[ ]` `!!`
- `[ ]` decode RA3 audio formats `(v0.7)`
### M20 `ra3.video` — movies & cutscenes `[ ]`
- **F1 Movie playback** `[ ]` `!!`
- `[ ]` intro/briefing/ending video decode + playback `(v0.8)`
- `[ ]` skip, subtitles, aspect handling `(v0.8)`
- **F2 In-engine cutscenes** `[ ]`
- `[ ]` scripted camera + unit animation sequences `(v0.8)`
### M21 `ra3.match` — game setup & match rules `[P]`
- **F1 Game setup** `[~]`
- `[x]` map + two players + seed defaults
- `[ ]` faction/color/team/start-slot selection, AI personalities `(v0.7)`
- **F2 Rules & options** `[ ]`
- `[ ]` starting cash, crates on/off, superweapons on/off, speed, limits `(v0.7)`
- **F3 Match flow** `[~]`
- `[x]` `prepare_new_game` / `start_new_game` split mirroring retail
- `[ ]` loading progress, in-game start countdown `(v0.7)`
- **F4 Factions** `[~]`
- `[x]` Allied / Soviet / Empire player templates
- `[ ]` full faction tech trees and rosters `(v0.5)`
- **F5 Victory & scoring** `[~]`
- `[x]` team-wipe victory
- `[ ]` full victory conditions, post-match score screen `(v0.8)`
### M22 `ra3.replay` — recording & playback `[ ]`
- **F1 Recorder** `[ ]`
- `[ ]` capture command stream + seed + map id per match `(v0.4)`
- **F2 Replay format** `[ ]`
- `[ ]` self-describing header, command log, checksums `(v0.4)`
- `[ ]` compatibility with retail `.RA3Replay` playback `!!` `(v0.9)`
- **F3 Playback** `[ ]`
- `[ ]` deterministic re-simulation, speed control, seek `(v0.4)`
- **F4 Golden replays** `[ ]`
- `[ ]` curated replay corpus as a regression test `(v0.4)`
- **F5 Observer / spectator** `[ ]`
- `[ ]` watch live or recorded matches, fog option `(v0.9)`
### M23 `ra3.save` — save/load & profiles `[ ]`
- **F1 Save / load** `[ ]`
- `[ ]` full simulation state serialization (objects, modules, queues) `(v0.8)`
- `[ ]` versioned saves with migration `(v0.8)`
- **F2 Profiles** `[ ]`
- `[ ]` player profile, stats, progress/unlocks `(v0.8)`
- **F3 Options persistence** `[ ]`
- `[ ]` settings, keybinds, last-used skirmish config `(v0.7)`
- **F4 Checkpoints** `[ ]`
- `[ ]` campaign checkpoint save/restore `(v0.9)`
### M24 `ra3.mod` — data packages `[ ]`
- **F1 Data packages** `[ ]`
- `[ ]` load order, override precedence, loose-file mounting `(v0.8)`
- **F2 Content discovery** `[ ]`
- `[ ]` scan user mod dirs and additional `.big` archives `(v0.8)`
- **F3 Mod validation** `[ ]`
- `[ ]` schema + reference checks, actionable errors `(v0.8)`
### M25 `ra3.net` — LAN lockstep `[ ]` *(deferred, offline-only)*
- **F1 Lockstep** `[ ]`
- `[ ]` deterministic lockstep over LAN, command-exchange only `(v1.0)`
- **F2 Lobby & sync** `[ ]`
- `[ ]` lobby, slot/team assignment, start sync `(v1.0)`
- **F3 Desync detection** `[ ]`
- `[ ]` state-hash comparison, desync report `(v1.0)`
> No online service, matchmaking, EA account or third-party network
> integration — ever. LAN only.
### M26 `ra3.i18n` — localization `[P]`
- **F1 CSF strings** `[~]`
- `[x]` parse `gamestrings.csf` (UTF-16 units, low byte `^0xFF`)
- `[x]` map display-name lookup (`MAP:<ID>`)
- `[ ]` full string-table load for all UI text `(v0.5)`
- **F2 Language selection** `[~]`
- `[x]` newest `Lang-English*.big` wins
- `[ ]` all supported languages, fallback chain `(v0.5)`
- **F3 Fonts & shaping** `[ ]`
- `[ ]` glyph coverage, CJK/RTL shaping where applicable `(v0.6)`
- **F4 Substitution** `[ ]`
- `[ ]` placeholders, numbers, plurals `(v0.5)`
### M27 `apps` — applications `[D]`
- **F1 CLI** `[D]`
- `[x]` `menu` / `menu-preview` / `maps` / `skirmish` / `render` / `extract`
- `[ ]` `replay`, `benchmark`, `validate-data` subcommands `(v0.5)`
- **F2 Extraction pipeline** `[~]`
- `[x]` `extract` → `assets/` (maps, terrain)
- `[ ]` full asset dump (models/textures/audio/movies) as a build target `(v0.5)`
- **F3 Diagnostics** `[ ]`
- `[ ]` headless render/benchmark modes for CI `(v0.4)`
### M28 `tools` — offline tooling `[~]`
*(Python is permitted here; it is never linked into `openra3`.)*
- **F1 Reference fetch** `[D]`
- `[x]` sparse-clone SAGE 1.0 reference into git-ignored `reference/`
- **F2 Ghidra workflow** `[D]`
- `[x]` MCP-driven recovery loop + recovered symbol map (see RE doc)
- `[ ]` automated structure/table extractors `(v0.5)`
- **F3 Format inspectors** `[ ]`
- `[ ]` BIG/RefPack/CkMp/W3D/APT dumpers `(v0.5)`
- **F4 CI & packaging** `[D]`
- `[x]` GitLab CI builds both targets → test → package
---
## 4. Cross-cutting invariants
These hold across **every** module above and are enforced in review:
1. **Language** — runtime code is C++ only. Build tooling may use Python.
2. **Ownership** — no raw owning pointers; `unique_ptr` for ownership, handles or
`thing *` views for references.
3. **Layering** — a module imports only lower layers. `ra3.core` imports no
engine module and no platform API.
4. **Determinism** — RNG, iteration, hashing and float use are explicit and
seedable; the logic step must be bit-reproducible for a given input stream.
5. **RE-traceable** — retail structure/constant changes cite an address in
[`REVERSE_ENGINEERING.md`](REVERSE_ENGINEERING.md).
6. **Offline** — no online service; LAN lockstep (M25) is the only networking,
and only command exchange.
7. **No bundled assets** — game data is read from the user's install; nothing
from it is committed. The tree builds and runs in CI on a built-in test map.
---
## 5. Milestone mapping
The plan rolls up to these releases:
| Milestone | Modules advanced | Delivers |
| --- | --- | --- |
| `v0.3.x` (done) | M00, M01, M04, M05(F1–F3), M06, M07(partial), M08(partial), M10(partial), M16(F3,F8), M17, M18 | minimal deterministic skirmish, real terrain, Vulkan present, menu |
| `v0.4.0` | M05(F4–F7), M06, M07, M08, M09(F1,F2,F4), M14, M22(F1–F4) | real update modules: locomotor, projectiles/warheads, placement, shroud, pathfinding, replay |
| `v0.5.0` | M02, M03, M04(F3,F4), M08, M10(F3,F4), M11(F1,F2), M26 | data-driven content: deserialise `.bin`/`.manifest`, real rosters, maps, strings |
| `v0.6.0` | M03(F1–F3), M07(F4,F6,F8,F14), M09(F2–F7), M16(F1,F2,F4,F5), M18(F3), M15(F1–F4,F8) | full renderer: perspective terrain, W3D models, in-game client + input |
| `v0.7.0` | M13, M15(F5–F7), M19, M11(F4–F6), M20, M21 | HUD/command bar, audio, superweapons, Commander's Challenge |
| `v0.8.0` | M12, M20(F1), M23, M24, M21(F5) | campaigns, cutscenes, save/load, mods |
| `v0.9.0` | M22(F2,F5), M12(F6), M25 | retail replay playback, co-op, LAN lockstep |
| `v1.0.0` | all | feature-complete offline RA3 |
---
## 6. Design rules
The five rules the codebase is held to (restated from §1, with the concrete
consequences that trip people up):
1. **No raw owning pointers.** Ownership is `std::unique_ptr`; the partition
manager and object registry hold non-owning `thing *` views only.
2. **Portable simulation.** No platform APIs in `ra3.core` / simulation
modules. All platform concerns live behind `display`.
3. **Determinism.** Anything that can diverge between runs (random, iteration
order) is explicit and seedable.
4. **RE-traceable.** Where a structure or constant comes from the retail
binary, the address is cited in the comment.
5. **No bundled assets, no online.** Game data is read from the user's install
and never committed; there is no networking or online service.
---
## 7. Where to start
- New to the codebase: read this plan top-to-bottom (§3 is the feature set,
§5 the near-term order of work).
- Picking up a feature: find its **Function** above, take the lowest-numbered
unmet `[ ]` **Feature**, and cite its supporting retail address.
- Reverse engineering a subsystem: follow the loop in
[`REVERSE_ENGINEERING.md`](REVERSE_ENGINEERING.md); the `!!` tags above mark
the functions that still need a recovery pass before they can be built.