21
Outpost 2 Programming & Development / Progress: ~4.7k decompiles in - here's the map
« Last post by jonathangoorin on April 03, 2026, 02:24:40 AM »What I've done so far: run the decompiler over the shipping binaries and keep one greppable tree of per-function C to hang notes on. It is not pretty source, but it is a floor plan I can extend: search, cross-reference, and attach an indexer to instead of reinventing context every time I sit down.
At a glance
- 4663 translation units across Outpost2.exe, op2ext.dll, and OP2Shell.dll - raw material for search and cross-reference, not pretty code.
- Outpost2.exe also gets an auto subsystem index (game loop, units, UI, saves, ...) against community Tethys VAs and a few other hints.
-- DLLs land in the same export batch as the EXE; the numbered breakdowns below are EXE-only until I fold the DLLs into the same indexer.
Table: Export volume
Why 4277 rows but 3022 "places" on the map?
- The index has 4277 rows, but only 3022 distinct entry points.
-- Many addresses appear twice (e.g. `FUN_...` and a decorated name for the same VA).
- Any percentages below are against those 3022 uniques, not the raw row count.
Table: Mapped vs still fuzzy (EXE)
On the EXE side I have already put a bit more than half of the entry points into a subsystem I can reason about in write-ups; the remainder is still unclassified in my tooling and is the main backlog for me to work through.
Where the names come from
For each address I keep one best row and prefer anything that has a proper Tethys `Class::member` string.
Table: Evidence (% of 3022)
993 of the 3022 uniques (~33%) carry a Tethys symbol on the row I keep - the strongest naming signal in my rollup.
Table: Confidence (same rollup)
What those confidence rows mean for my index: most addresses already sit in a named subsystem; about one in three has a Tethys symbol on the row I keep; low and unclassified overlap, so 1311 addresses (~43%) are still unfinished labeling on my side - expected at this stage, not the end state.
Table: Subsystem heat (row counts, duplicates allowed)
Going forward: fold op2ext.dll and OP2Shell.dll into the same subsystem indexer (the tables above stay EXE-focused until that lands), keep burning down the unclassified tail with more Ghidra time, and grow the parallel notes: markdown per area, VOL / map / saves write-ups, symbol scrapers, and a small pygame map view as a sanity check so I do not drift on tiles.
If a bucket looks wrong or you know a thread that would have saved me a week, I will read it; glad for pointers.
Cheers,
Jonathan
At a glance
- 4663 translation units across Outpost2.exe, op2ext.dll, and OP2Shell.dll - raw material for search and cross-reference, not pretty code.
- Outpost2.exe also gets an auto subsystem index (game loop, units, UI, saves, ...) against community Tethys VAs and a few other hints.
-- DLLs land in the same export batch as the EXE; the numbered breakdowns below are EXE-only until I fold the DLLs into the same indexer.
Table: Export volume
| Binary | `.c` units |
| Outpost2.exe | 4278 |
| op2ext.dll | 173 |
| OP2Shell.dll | 212 |
| Total | 4663 |
Why 4277 rows but 3022 "places" on the map?
- The index has 4277 rows, but only 3022 distinct entry points.
-- Many addresses appear twice (e.g. `FUN_...` and a decorated name for the same VA).
- Any percentages below are against those 3022 uniques, not the raw row count.
Table: Mapped vs still fuzzy (EXE)
| - | Addresses | Share |
| In a named subsystem (units, UI, game loop, ...) | 1711 | 56.6% |
| Only "unclassified" so far | 1311 | 43.4% |
On the EXE side I have already put a bit more than half of the entry points into a subsystem I can reason about in write-ups; the remainder is still unclassified in my tooling and is the main backlog for me to work through.
Where the names come from
For each address I keep one best row and prefer anything that has a proper Tethys `Class::member` string.
Table: Evidence (% of 3022)
| Evidence | Count | % of 3022 |
| Tethys VA table (OPU / headers) | 994 | 32.9% |
| Curated known-address list | 200 | 6.6% |
| HFL-style DAT globals | 161 | 5.3% |
| Heuristic filename | 166 | 5.5% |
| Heuristic content | 150 | 5.0% |
| Keyword scrape | 40 | 1.3% |
| Has a subsystem assignment | 1711 | 56.6% |
| Still default / unclassified | 1311 | 43.4% |
993 of the 3022 uniques (~33%) carry a Tethys symbol on the row I keep - the strongest naming signal in my rollup.
Table: Confidence (same rollup)
| Level | Addresses | Share |
| high | 1194 | 39.5% |
| medium | 471 | 15.6% |
| low | 1357 | 44.9% |
What those confidence rows mean for my index: most addresses already sit in a named subsystem; about one in three has a Tethys symbol on the row I keep; low and unclassified overlap, so 1311 addresses (~43%) are still unfinished labeling on my side - expected at this stage, not the end state.
Table: Subsystem heat (row counts, duplicates allowed)
| Subsystem | Rows |
| units | 794 |
| ui | 392 |
| save_load | 391 |
| scenario | 327 |
| game_loop | 230 |
| map | 210 |
| rendering | 192 |
| sim_tick | 152 |
| unclassified | 1390 |
| networking | 40 |
| research | 49 |
| buildings | 57 |
| audio | 53 |
| Sum | 4277 |
Going forward: fold op2ext.dll and OP2Shell.dll into the same subsystem indexer (the tables above stay EXE-focused until that lands), keep burning down the unclassified tail with more Ghidra time, and grow the parallel notes: markdown per area, VOL / map / saves write-ups, symbol scrapers, and a small pygame map view as a sanity check so I do not drift on tiles.
If a bucket looks wrong or you know a thread that would have saved me a week, I will read it; glad for pointers.
Cheers,
Jonathan

Recent Posts