findings/subsystems/population-growth.md -- ServerSystem::GrowCivilianPops 0x00754220 read byte for byte, its whole chain, and Ship::RepairCost 0x00815180. The headline is a correction to the brief's premise. The pass is NOT gated on imperial carrying capacity. The whole system's civilian delta is clamped to 20,000,000 -- POPTYPE[1]+0x08, an int64 literal in the executable -- and on both reference pairs that clamp decides the value: the uncapped delta is 7.5x it and the capacity headroom 25x it. The imperial capacity is pinned at exactly Size x 1e8 from the corpus alone, by two independent behaviours of one colony across three turns, with no data files. Two boundary corrections, both of the rule-17 shape. GrowCivilianPops is a loop over group types whose back edge lies outside every decompiler `if`, so it reads as straight-line code if you stop at the first `ret`; its real end is 0x00754b59. MaxPopGeneric ends at 0x0074a6cd, so the 0x0074a6d0 that lanes N and E1 both cite for the capacity-surplus pair is a different function. A table correction with teeth: InitPopTypeTable never writes the group ceiling at +0x28/+0x2c. The CRT static initialiser at 0x009abe20 does, to INT64_MAX, and nothing else touches it -- so the clamp that reads it is always a no-op. A reader who opens only the obvious initialiser sees zero there and would cap every carrying capacity in the game at nothing. Lane N's whole table is otherwise reproduced independently from the six-register fxch rotation. output-turn-path.md: out[6] is NOT the ship-repair demand. 0x007460b0 sums 0x0081f8c0, which gates on the design's carried-population bit and computes GroupIncome over the ship's own Population -- so it is the income of population carried in slaver and colony hulls, a slot the engine already had under a name nobody had connected to it. Corrected in place, with lane-c3.json's three unread stubs superseded by lane-g3.json's read entries. Ship::RepairCost is unexercised on the corpus and that is a measurement, not an absence (rule 20): the independent colony keeps a ten-ship fleet in orbit over Koa'Vo on both reference pairs and its Sav closes exactly with the demand taken as zero, which it could not do if any hull had a cost. Engine side: sots-engine wip/growth ed6602e -- reference pair 78 -> 81 closed, 0 regressed; pair 2 36 -> 39 closed, 0 regressed. |
||
|---|---|---|
| campaign | ||
| findings | ||
| ghidra | ||
| guides | ||
| notes | ||
| objects | ||
| scripts | ||
| tools | ||
| verify | ||
| .gitignore | ||
| README.md | ||
sots-re
Reverse-engineering worklog for Sword of the Stars (2006, SOTS1) — the 32-bit DX9 original + expansions. The nitty-gritty: static/dynamic analysis notes, Ghidra & ReVa scripts, function/struct maps, D3D9 call traces, decomp progress, findings.
Where this runs
Analysis lab on spicy (PVE, 192.168.3.201):
- CT111
sots-re— Linux workspace: Ghidra + headless ReVa server, radare2/rizin/cutter, binwalk. Hosts the Samba share and this repo's working tree at/srv/re-lab/notes. - VM140
sots-re-win10— Win10 runtime + dynamic analysis (x64dbg, Cheat Engine, RenderDoc/apitrace, DXVK→CPU-Vulkan for GPU-less rendering).
Infra (guests, storage, network, share, ReVa endpoint) is documented from the
system-maintainer POV in trikilli → services/re-lab.md. This repo is everything else.
Layout
findings/— the running findings log (append-only), one file per subsystem.ghidra/— exported scripts, data-type archives, struct definitions.traces/— D3D9 / Win32 API call captures + analysis.scripts/— helper tooling (loaders, extractors, parsers).notes/— session notes, scratch, hypotheses.
Ownership / legality
Game binaries come from the owner's own GOG/Steam copy. RE is for personal
interoperability, bug-fixing, and preservation. Binaries themselves are not committed
here (see .gitignore) — they live on the lab's Samba share /srv/re-lab/samples.
Campaign (how this repo is run)
A 4-agent crew (defined in ~/.claude/agents/re-*.md) runs the exploration:
re-quartermaster (backlog + board) → re-analyst (maps via ReVa) →
re-verifier (proves vs real data; old-vs-new differential once reimpl starts) →
re-scribe (files the note, links it, commits).
campaign/board.md— live status board (start here).- Live tracking = Forgejo issues on
alex/sots-re(labelsstatus/*are the kanban columns;type/*,conf/*).campaign/board.mdis the editable mirror — publish withscripts/forgejo_campaign.py bootstrap(needsFORGEJO_TOKEN). campaign/backlog.md— prioritized target queue.campaign/open-questions.md— unresolved threads.findings/_template.md— the record format every finding follows.findings/{objects,control-flow,subsystems}/— the growing engine map.verify/{parsers,traces,harness,results}/— validation: struct parsers now, golden-trace replay + shim compare-mode for reimplementation.ghidra/— exported scripts + datatype archives.
Approach & north star: findings/00-strategy.md. Binary facts: findings/01-fingerprint.md.
Sibling repo
alex/sots-engine — the from-scratch engine source (clean-room, public-capable). This repo keeps the
evidence + planning for both; binary facts cross over only via ghidra/addresses.json → tools/gen_addresses.py.
guides/re-windows-2000s-howto.md— annotated bibliography + how-to for RE of mid-2000s MSVC/DX9 Windows games, with our-experience call-outs.