sots-re/ghidra/addresses.d
alex 2e935b8491 SV: what writes SvSctOb during a turn -- the script-object event bus
Lane W recovered what the type is; this is what moves it. Nothing in the turn calls a
method on a child script object directly. A driver notifies the root with an integer event
id, the root fans the delivery out to every child, and each delivery is a generic handler
plus one event-specific vtable slot chosen from a 33-entry jump table at 0x007a6480. That
table is what proves the hand-written pairs lane K read in the tail are event deliveries
and not ad-hoc calls, and five of its rows are not in slot order.

Six deliveries in a turn, from five functions, with the ids they send. Three handlers
write the eight leaves that diverged: the slavers' difficulty tier (a three-record stack
table against the frame, and at frame >= 100 the scan runs off the end and stores nothing,
so the tier can never reach 2), the refugees' one-shot latch at turn begin, and the swarm
queen's hives -- registered on the systems whose EggScio equals the SWARM's scenario tag,
which the queen's constructor stores at +0x4 while its own encounter id sits at +0x8.

The hive target turn slips forward by one every turn the spawn gates fail. That single
`inc` is the whole explanation of a field that reads 31 after turn 1 and 32 after turn 2,
which no re-roll can produce on two hives at once.

Corrects combat-done-tail.md: the tail has a FOURTH script-hook site, at 0x007d9820, and
it sends event 0x1c -- the same id ProcessTurn sends, which lane K attributed to that
driver alone.

Two leaves stay blocked, and not on a workload: the refugees' design id needs handle
allocation and data-file instantiation, and the hive target turn needs one MT draw plus
two config constants behind pointers no reference initialises in a form this lane could
follow. Fitting them from a single two-hive observation would have been fitting, not
derivation, so it was not done.

An RNG claim for the next lane to falsify cheaply: lane Z's "residual outside the two turn
drivers is exactly zero" was measured on turns where the hives already existed. Hive
creation draws inside BeginProcessTurn, outside both drivers and before either.

13 addresses in ghidra/addresses.d/lane-sv.json; validated to a scratch path, merges to
1,204 with no duplicate name. A fourteenth was dropped: this lane reached 0x004271c0
independently and would have filed it as RNG_NextIntInclusive, but addresses.json already
carries it as RNG_NextInt with the same convention and four lanes depend on that name. The
merger only detects duplicate NAMES, so a second name for one address would have merged
silently and forked the vocabulary for the campaign's most-used RNG primitive.
2026-09-08 16:46:44 -04:00
..
lane-a.json A: the AIAgent CD blocks - derivation, addresses, and what stays a hypothesis 2026-09-08 07:33:33 -04:00
lane-a2.json lane A2: the alliance mask read from the bytes, and every ModCount writer 2026-09-08 12:44:30 -04:00
lane-ai1.json lane AI2: the AI's task selection loop, the priority table, and the order-method -> TurnCommands map 2026-09-08 14:43:41 -04:00
lane-ai2.json lane AI2: the AI's task selection loop, the priority table, and the order-method -> TurnCommands map 2026-09-08 14:43:41 -04:00
lane-ai3.json findings: lane AI3 -- the AI stepping order is save player order, and pass 0 writes nothing 2026-09-08 15:29:53 -04:00
lane-ai4.json AI4: what an AI turn emits, and what each command costs in ModCount 2026-09-08 16:27:58 -04:00
lane-b5.json B5: the combat resolver's sub-dispatcher is RETREAT, and it is the largest 2026-09-08 12:00:14 -04:00
lane-b6.json findings: ship construction -- the build queue read byte for byte, and the missing destroyer is the AI's 2026-09-08 14:54:03 -04:00
lane-c3.json lane C3: ComputeOutput on the turn path -- the money ComputeBudget actually sums 2026-09-08 14:50:50 -04:00
lane-d2.json lane D2: the ship-design catalogue -- how designs persist, hull size, and the 0x400 flag 2026-09-08 12:45:36 -04:00
lane-e1.json income-term: the output -> money chain read from the instruction stream; the BnkEl oracle goes 6/25 -> 25/25 2026-09-08 13:49:48 -04:00
lane-e3.json lane E3: ten addresses for the visibility record, and the standalone's new distance 2026-09-08 13:38:57 -04:00
lane-ev.json lane EV: what a turn actually posts, and two corrections to events.md 2026-09-08 15:40:07 -04:00
lane-g2.json board: lane P2 nav classifier; type 2 is the Liir drive, a naming error not a gap 2026-09-08 12:45:27 -04:00
lane-g3.json lane G3: civilian growth read and measured; out[6] is not a repair number 2026-09-08 15:53:08 -04:00
lane-h.json lane H: five live probes, the oracle restored, and a harness perturbation bisected to one hook 2026-09-08 13:53:36 -04:00
lane-i.json lane I: the complete inlined-draw inventory, and the seven RNG entry points 2026-09-08 10:03:33 -04:00
lane-j.json lane J: the combat resolver, read from the instruction stream 2026-09-08 09:37:02 -04:00
lane-k.json lane K: field offsets belong in the offset schema, and off_RNG was already right 2026-09-08 08:48:25 -04:00
lane-n.json lane N: the population -> base-output term, read and live-verified 2026-09-08 12:11:52 -04:00
lane-o.json lane O: 7 purpose-built saves - issued turn commands, node routes, research-roll-pending 2026-09-08 08:35:13 -04:00
lane-p2.json lane P2: the path solver read from the instruction stream, and OrderFleetMove's three failure bits 2026-09-08 12:43:34 -04:00
lane-pl.json lane PL: decompose the /Sim/players residual by mechanism; the bankruptcy protection factor is a float32 2026-09-08 16:36:45 -04:00
lane-q.json lane Q: TurnCommands_v5 reconciled and typed; SAVE_FORMAT section 11 corrected 2026-09-08 09:03:26 -04:00
lane-sv.json SV: what writes SvSctOb during a turn -- the script-object event bus 2026-09-08 16:46:44 -04:00
lane-t.json T: read ServerPlayer::ProcessTurn and StrategyServer::ProcessTurn from the instruction stream 2026-09-08 08:08:36 -04:00
lane-t2.json lane T2: the treaty-turn stamp, and Player.Status's real writer 2026-09-08 14:52:44 -04:00
lane-u.json lane K: StrategyServer::OnAllCombatDone_Tail mapped, 36 phases from the instruction stream 2026-09-08 08:47:08 -04:00
lane-v2.json lane V2: vtable inversion — resolve indirect call edges image-wide 2026-09-08 12:05:05 -04:00
lane-w.json lane W: SvSctOb variant factories; fix the four save_reader.py defects openly 2026-09-08 07:05:09 -04:00
lane-w2.json lane W2: multiplayer Tier 0 played end to end with no server; ModCount/Frame/Status watchpoints; rcex explained 2026-09-08 15:23:52 -04:00
lane-w3.json W3: NVO.TShn's writer trapped live, its gate named, and 158/158 on the corpus 2026-09-08 16:41:09 -04:00
lane-z.json Z: the dominant RNG consumer is trade-raid generation, behind a virtual call 2026-09-08 10:57:12 -04:00
README.md gen_addresses: per-lane fragment dir; duplicate names are a hard error 2026-09-08 05:55:03 -04:00

Per-lane address fragments

addresses.json is a single shared file. When several lanes run concurrently they edit the same lines, and three times on 2026-09-08 one lane's git add swept another's in-flight entries into the wrong commit. Nothing was lost, but authorship and atomicity were.

A lane may instead drop its own file here:

{ "entries": [ { "name": "...", "addr": "0x...", "convention": "...",
                 "prototype": "...", "status": "verified", "source": "findings/..." } ] }

Name it after the lane (lane-d.json). tools/gen_addresses.py merges every fragment in sorted order after addresses.json. A duplicate name across files is a hard error, not last-wins — two lanes disagreeing about an address is exactly the thing we must not paper over.

The integrator folds fragments back into addresses.json once the lane's work is merged.