Tighten atlas seam annotations for transport and load/save

This commit is contained in:
Jan Petykiewicz 2026-04-14 01:57:02 -07:00
commit aaf9310e62
5 changed files with 299 additions and 120 deletions

View file

@ -89,7 +89,26 @@ The broader map-editor page owner is now bounded through
tighter too: the row pair shown in `Supply Only` and `Production Demand->Supply` is the `+0x08`
supplied-cargo selector, the row pair shown in `Demand Only` and `Production Demand->Supply` is
the `+0x1c` demanded-cargo selector, and the single amount field at `+0x04` is labeled `Annual
Demand:` only in mode `1` but `Annual Supply:` in modes `2/3`. The stronger new runtime-side
Demand:` only in mode `1` but `Annual Supply:` in modes `2/3`. The editor-side token boundary is
narrower now too: `0x004cf910` re-enters the same runtime importer `0x00435630` on entry, then
exact-matches the persisted `+0x08/+0x1c` token strings against visible live cargo names through
`0x005a57cf` while seeding the selector controls. There is still no special marker decode on this
side; unmatched token strings simply leave the selector index at its zero default while the raw
scenario-state strings stay in the recipe-book slab, and `0x004d0040` writes those selected cargo
names back into `+0x08/+0x1c` verbatim rather than normalizing them first. The write-side control
map is tighter now too: `0x59d8` updates the shared production-cap float at `book+0x3ed`,
`0x59d9` opens the rename modal, `0x59da/0x59db` cycle the selected book modulo `12`, and
`0x59de` commits the selected book ordinal. The five line-level write bands are exact in the
same way: `0x5a0a..0x5a0e` write the line-mode dwords at `book+0x3f1+line*0x30`,
`0x5a1e..0x5a22` copy one live cargo name into the supplied-token lane at
`book+0x3f9+line*0x30`, `0x5a32..0x5a36` copy one live cargo name into the demanded-token lane
at `book+0x40d+line*0x30`, and `0x5a50..0x5a54` write the per-line amount float to
`book+0x3f5+line*0x30` after the handler clamps the entered value to `<= 6`. The constructor-side
usage summary is bounded too: it scans the live city-or-region collection at `0x0062bae0`, keeps
only rows whose usage gates `[entry+0x242]` and `[entry+0x2f6]` are live and whose current
recipe ordinal `[entry+0x2f2]` matches the selected book, concatenates up to eight visible names
from `[entry+0x356]` with the separator at `0x005c9f38`, counts the rest, and then formats the
bounded usage summaries from localized ids `508` and `509`. The stronger new runtime-side
result is now a full chain rather than only the importer:
`scenario_state_rebuild_port_warehouse_cargo_recipe_runtime_tables` first imports those same five
lines into one repeated array of identical `0xbc`-byte runtime descriptors with no row-index
@ -120,9 +139,17 @@ The broader map-editor page owner is now bounded through
`[candidate+0x2a]` divided by the descriptor amount, while nonzero mode bypasses that scaling
path and publishes the row amount directly. At that point the candidate import strip is
structurally closed in current local evidence: the local import and rebuild seam is no longer
where the loader reconstructs runtime descriptor or membership tables, but only what the
unresolved supply-marker token family means before those already-grounded candidates are projected
back into live cargo ids. The immediate sibling
where the loader reconstructs runtime descriptor or membership tables. The remaining semantic gap
is narrower instead: current local evidence shows no hidden decode stage for the supply-marker
token family at all. The editor slab preserves unmatched token strings verbatim, the constructor
only reflects selector ordinals for tokens that already exact-match visible live cargo names, and
the importer later writes the exact-matcher result ids straight into the live descriptor lanes,
defaulting failed matches to cargo id `0`. The reset side narrows that further too:
`0x00436d10` only zero-fills the recipe books and reseeds their `# %1` name lane, so those
marker-like token strings are not coming from the built-in reset path. So the open question is
now only what upstream source, if any, authored those marker-like token strings before exact
matching. The
immediate sibling
`structure_candidate_refresh_recipe_runtime_mode_flags_0x78c_0x790` `0x00411ce0`, which for
subtype byte `[candidate+0x32] == 2` scans the imported descriptor strip and derives two compact
post-import flags from mode `0` presence and whether every mode-`0` descriptor keeps at least
@ -141,8 +168,9 @@ The broader map-editor page owner is now bounded through
side is explicit now too: `0x00436d10` is the shared reset-and-rebuild owner beneath startup and
world-entry paths. It zeroes the late scenario-state bands, seeds the fixed year defaults and
chairman-slot rows, rebuilds the two named availability collections at `[state+0x66b2]` and
`[state+0x66b6]`, re-seeds the twelve recipe books at `[state+0x0fe7]` from the fixed template
at `0x005c9f78`, refreshes selected-year state through `0x00409e80`, `0x00433bd0`,
`[state+0x66b6]`, zero-fills the twelve recipe books at `[state+0x0fe7]`, then only reseeds
their per-book name lane from the fixed `# %1` format string at `0x005c9f78` through
`0x0051b700 -> 0x00518de0`, refreshes selected-year state through `0x00409e80`, `0x00433bd0`,
`0x00435603`, and the year-gap scalar helper `0x00434130`, and only then re-enters
`0x00435630`, `0x0041e970`, `0x00412bd0`, and `0x00436af0`. The startup side is tighter now too:
`0x00438890` does not jump straight into one selector-specific file-load branch. It first
@ -250,16 +278,18 @@ The broader map-editor page owner is now bounded through
demand rows preserve string-bearing windows at `line+0x1c`, and the current probe shows those
conservatively as prefixed ASCII previews such as `..Grain`, `..Corn`, `..Livestock`, and
`..Milk`; local `objdump` now grounds `0x0041e9f0` itself as
`cargo_collection_find_entry_by_exact_name`, a direct exact-string walk over the live cargo
collection at `0x0062ba8c`. The importer at `0x00435630` feeds both token lanes through that same
matcher after one conservative in-place cleanup pass: empty strings are replaced with the first
live cargo name, and mode `3` loops until the supplied and demanded token strings no longer
compare equal. By contrast, the imported `supply-marker-entry` rows still feed nonprintable
windows such as `.@...` from `line+0x08` through that same exact matcher, and the resolver path
currently shows no special-case decoding for those marker forms. So the strongest static read is
now: the stem-like demand rows preserve cargo-name text but are skipped because their mode is
zero, while the nonzero imported marker rows are the live descriptor inputs yet likely fail exact
cargo-name resolution unless another upstream transform exists.
`cargo_collection_find_entry_id_by_exact_name`, a direct exact-string walk over the live cargo
collection at `0x0062ba8c` that returns one live cargo entry id or `0`. The importer at
`0x00435630` feeds both token lanes through that same matcher after one conservative in-place
cleanup pass: empty strings are replaced with the first live cargo name, and mode `3` loops
until the supplied and demanded token strings no longer compare equal. By contrast, the imported
`supply-marker-entry` rows still feed nonprintable windows such as `.@...` from `line+0x08`
through that same exact matcher, and the resolver path currently shows no special-case decoding
for those marker forms. So the strongest static read is now: the stem-like demand rows preserve
cargo-name text but are skipped because their mode is zero, while the nonzero imported marker
rows are the live descriptor inputs yet likely fail exact cargo-name resolution unless another
upstream transform exists; when they do fail, the importer writes the returned `0` ids directly
into the runtime descriptor cargo lanes instead of taking any special marker-side fallback path.
The wrapper layer above that query no longer looks like a hiding place for special treatment
either. Local `objdump` now shows `0x00412960` simply summing the two supply-side floats returned
by `0x00412650`, while `0x004129a0` returns the single zero-mode cap-scaled subrow lane directly;

View file

@ -364,7 +364,9 @@
setup still touches the surrounding callback-table and replay-band fields without ever seeding a
nonzero value into `[transport+0x1778]`, so the local static seam is closed here: no ordinary
constructor, reset, service, or callback-table owner in `RT3.exe` currently writes that sidecar,
and the producer looks upstream of this local cluster.
and the latest full-binary disassembly scan still finds only the `0x595bc0` read while the
neighboring lifecycle fields `[transport+0x177c/+0x1780/+0x1784/+0x178c/+0x17f8]` do show normal
constructor/reset/use sites. The producer therefore still looks upstream of this local cluster.
Beside it, `0x58e200` is the broader callback-table attach or refresh owner:
it seeds one immediate-drain context id, conditionally copies the local name into `[transport+0x04]`,
clears `[transport]`, `[transport+0x48]`, and `[transport+0x1edc]`, stores follow-on callback
@ -736,6 +738,16 @@
validated-cookie event forwarder over callback slot `[transport+0x17f0]`, and `0x597330` is the
validated extended-payload forwarder over `[transport+0x17f4]`; both reuse the same owner
context at `[transport+0x17f8]`. The adjacent staged-route
capacity gate is tighter now too: `0x595d60` is not another live-route opener. It is the
immediate bound-route fast path and capacity gate under `gsi_am_rating`. When the staged
descriptor already matches the current live route through `0x595d00`, it returns straight
through `0x592710`; otherwise it only reuses that same bound-route callback lane when
`numplayers < maxplayers`. `0x595dc0` then uses that result exactly as the already-bound-or-
capacity gate before it clears selector slot `2`, stages route-callback payload through
`0x5958e0`, and only then re-enters route mode `0`. The live-route connect owner is narrower in
the same way: `0x597480` mirrors success into deferred route-status flag `[transport+0x1ed8]`,
and the later mode-`4` branch in `0x595e10` is the place that actually consumes that flag to
choose route mode `1` versus `3`. The adjacent staged-route
callback side is tighter too: `0x595860` is now bounded as the
submit-result handler beneath `0x5958e0`, and the old `[transport+0xac0]` ambiguity there is now
gone. That branch is using the already-grounded third selector-generation counter at `[0xac0]`
@ -985,10 +997,11 @@
`0x005a08f0` is the constructor-side queue bootstrap that opens the queue-owned UDP socket and
clears the active and pending list roots. The grounded
live-route connect path at
`multiplayer_transport_try_connect_live_route` does not currently perform any matching
post-construction patch for `[route+0xa0]`, `[route+0xa4]`, or `[route+0xd4]`, and the higher
route-mode state machine now looks consistent with that, but the owner is tighter than the old
flat mode list. `multiplayer_transport_set_route_mode` first applies one pre-dispatch gate:
`multiplayer_transport_try_connect_live_route` now matches the status-route side on the main
callback seam: after a successful connect it also patches `[route+0xa0]` through
`0x58bc90 -> 0x597330`. The remaining negative boundary is narrower now: current local evidence
still does not show matching post-construction writes to `[route+0xa4]` or `[route+0xd4]`, and
the higher route-mode state machine now looks consistent with that. `multiplayer_transport_set_route_mode` first applies one pre-dispatch gate:
when a bound route still exists at `[this+0x1ec8]`, requested mode `2`, and selector slot `2`
is not active, it submits one bound-route status request through `0x5959e0`. That request itself
is now narrower too: it derives one request token from the current binding through `0x5934c0`,
@ -1035,8 +1048,10 @@
and chooses either the default route id `0x1964` through `0x58cc40` or the binding-specific id
in `[binding+0x30]` through `0x58c9b0`; on the binding-specific path it also clears pending
rebuild cookie `[binding+0x34]` and marks the constructed route live via `[route+0xbc] = 1`,
while the success tail mirrors stored route label `[this+0x9a8]` into `[this+0xb3c]` and clears
live-route mode mask `[this+0xb38]`. The stable
while the success tail mirrors stored route label `[this+0x9a8]` into `[this+0xb3c]`, patches
`[route+0xa0]` through `0x58bc90 -> 0x597330`, and clears live-route mode mask `[this+0xb38]`.
The remaining negative boundary is narrower now: current local evidence still does not show
companion writes to `[route+0xa4]` or `[route+0xd4]` in the grounded live-route connect path. The stable
transitions therefore still switch by releasing route objects or route bindings and rebuilding
route state, not by mutating callback slots in place. The parser behavior is now tighter as well: semicolon lines only dispatch when
`[route+0xd4]` is non-null, and the subtype-`6` raw fallback only dispatches when `[route+0xa4]`

View file

@ -144,17 +144,23 @@ The same brush strip is tighter now too:
records into the existing fixed-record/news lanes at `0x006cea4c` and `0x004337c0` rather than
through a separate hidden journal family.
before that later world and shell reactivation tail, `world_entry_transition_and_runtime_bringup`
runs one distinct post-bundle status and runtime refresh phase that posts progress ids `0x196`
and `0x197` through `0x005193f0/0x00540120` with paired `0x004834e0` follow-ons, refreshes the
live event collection at `0x0062be18` through
`scenario_event_collection_refresh_runtime_records_from_packed_state` `0x00433130`, rebuilds the
scenario-side port-or-warehouse cargo recipe runtime tables through `0x00435630`, and then runs
the named-candidate availability preseed through `0x00437743`. That preseed lane is tighter now
too: it walks the live candidate pool at `0x0062b268` in reverse, forces one override bit `0`
whenever the candidate availability word `[candidate+0xba/+0xbb]` is already nonzero, derives the
remaining zero-word subtype cases from the local `2 xor [candidate+0x32]` parity check, and only
skips those subtype-derived rows when the copied stage counter from `0x00620e94` is nonzero
before re-entering `0x00434f20` on the candidate stem at `[candidate+0x04]`. The event-side
runs two separate recipe-runtime rebuild moments rather than one monolithic import step. The
earlier call at `0x00443ebc` fires immediately after the named candidate-availability collection
at `[world+0x66b2]` has been restored from fixed `0x22`-byte rows and before the neighboring
candidate filter/count rebuilds `0x00412c10/0x00412bd0` plus the year-derived follow-ons
`0x00434130/0x00436af0`. The later call at `0x00444ac1` sits inside the explicit `0x197`
checkpoint after `world_publish_shell_controller_progress_scalar_from_year_thresholds_or_selector_overrides`
`0x004354a0` and the territory-side sweep `0x00487de0`, and only then falls through into the
named-candidate availability preseed `0x00437737` plus the later candidate-filter refresh
`0x00412c10`. The post-bundle status and runtime refresh phase around those checkpoints still
posts progress ids `0x196` and `0x197` through `0x005193f0/0x00540120` with paired `0x004834e0`
follow-ons, and refreshes the live event collection at `0x0062be18` through
`scenario_event_collection_refresh_runtime_records_from_packed_state` `0x00433130`. That preseed
lane is tighter now too: it walks the live candidate pool at `0x0062b268` in reverse, forces one
override bit `0` whenever the candidate availability word `[candidate+0xba/+0xbb]` is already
nonzero, derives the remaining zero-word subtype cases from the local `2 xor [candidate+0x32]`
parity check, and only skips those subtype-derived rows when the copied stage counter from
`0x00620e94` is nonzero before re-entering `0x00434f20` on the candidate stem at `[candidate+0x04]`. The event-side
`.smp` bridge is
tighter now too: the save-side companion `0x00433060` opens chunk `0x4e99`, writes version dword
`0x3e9`, first walks the live event collection through
@ -201,7 +207,7 @@ The same brush strip is tighter now too:
writes the standalone runtime condition-row chain plus the four grouped runtime-effect row chains
into the packed stream. The recipe rebuild lane itself is
tighter now too: `0x00435630` resolves both token lanes through the exact live cargo-name matcher
`cargo_collection_find_entry_by_exact_name` `0x0041e9f0`, fills empty token strings from the
`cargo_collection_find_entry_id_by_exact_name` `0x0041e9f0`, fills empty token strings from the
first live cargo entry before that match, and in mode `3` keeps reseeding the primary lane from
that same first live cargo name until the primary and subordinate strings no longer compare equal
through `0x005a57cf`. The importer-side bridge is tighter now too: each of the twelve recipe
@ -210,15 +216,44 @@ The same brush strip is tighter now too:
the paired runtime count lane beside the imported `0xbc` descriptor strip. The five runtime
slots are zeroed and seeded with fixed year-window defaults before any nonzero-mode line is
imported, and each nonzero line amount is normalized to at least `1.0` before the mode `1/3`
direct primary half and mode `2/3` one-row subordinate half are populated. Mode `2` copies the
normalized line amount into `[desc+0x48]`, while mode `3` overwrites that same subordinate amount
with literal `1.0` after the token-divergence loop succeeds.
direct primary half and mode `2/3` one-row subordinate half are populated. The matcher return
value is explicit now too: `0x0041e9f0` returns one live cargo entry id or `0`, and the importer
writes that value straight into `[desc+0x1c]` and `[desc+0x44]` without any post-match failure
guard. The editor-side `Port/Warehouse Cargos` page is tighter in the same way: its constructor
`0x004cf910` exact-matches the persisted `+0x08/+0x1c` token strings against visible live cargo
names only to seed selector indices, leaves unmatched strings at the zero-selector default, and
separately derives the bounded usage summaries `508/509` by scanning the live city-or-region
collection for rows whose current recipe ordinal `[entry+0x2f2]` matches the selected book. The
paired handler `0x004d0040` then writes the selected cargo names back into those token slots
verbatim. That handler is tighter now too: `0x59d8` is the top-level shared production-cap field
and writes `book+0x3ed` after clamping the parsed value to `<= 8`; `0x59d9` only opens the
rename modal over the current `0x3c`-byte book-name span; `0x59da/0x59db` cycle the selected
recipe book backward or forward modulo `12`; and `0x59de` commits the selected book ordinal into
`0x006cffa4`. The five per-line write bands are now exact too: `0x5a0a..0x5a0e` write the mode
dwords at `book+0x3f1+line*0x30`, `0x5a1e..0x5a22` copy one live cargo name into the supplied
token lane at `book+0x3f9+line*0x30`, `0x5a32..0x5a36` copy one live cargo name into the
demanded token lane at `book+0x40d+line*0x30`, and `0x5a50..0x5a54` write the per-line amount
float to `book+0x3f5+line*0x30` after clamping the parsed value to `<= 6`.
So the stronger current boundary is now explicit on both sides: there is still no special marker
decode before import, and unmatched token strings simply survive in scenario state until
`0x0041e9f0` returns cargo id `0`.
Mode `2` copies the normalized line amount into `[desc+0x48]`, while mode `3` overwrites
that same subordinate amount with literal `1.0` after the token-divergence loop succeeds.
After the full twelve-book sweep the helper explicitly re-enters
`structure_candidate_collection_rebuild_runtime_records_from_scenario_state` `0x00412d70` when
the live candidate collection exists. That keeps the strongest current static split narrow and
concrete: mode-zero demand rows can still preserve readable cargo-name text in the saved recipe
books, but only the nonzero imported rows reach the live `0xbc` descriptor array, and the
unresolved supply-marker forms still have no special decode path before the exact matcher runs.
books, but only the nonzero imported rows reach the live `0xbc` descriptor array. The remaining
supply-marker gap is now narrower too: current local evidence shows no special decode path at
all before exact-name resolution. The editor-side page only reflects selector ordinals when the
persisted token strings already match visible live cargo names, and the importer itself writes
the exact-match result ids straight into `[desc+0x1c]` and `[desc+0x44]`, defaulting failed
matches to cargo id `0`. The reset side narrows that authorship question further too:
`0x00436d10` only zero-fills the recipe books and reseeds their `# %1` name lane, so those
marker-like token strings are not coming from the built-in reset template. So the open question
is now only what upstream source, if any, authored those marker-like token strings before exact
matching, not whether one hidden runtime decode stage still sits between the saved recipe books
and the live descriptor arrays.
The first grounded consumer beneath that import bridge is tighter now too:
`structure_candidate_query_cargo_runtime_summary_channels` `0x00412650` lazily stamps the current
scenario year into `[candidate+0x788]`, rebuilds four banks across both mode banks `0/1`, and
@ -331,8 +366,11 @@ The same brush strip is tighter now too:
symmetrically. The surrounding `.smp` lane is tighter too: at version `>= 0x3f1` the save path
also writes the late world-status block at `[world+0x66be]` through chunk ids `0x2ee0/0x2ee1`,
and the restore path reads that same pair back while older bundles clear the compatibility tail
at `[world+0x6987]`; both sides also copy the raw twelve `0x4e1` recipe books at
`[world+0x0fe7]` directly into or out of the bundle before the wider world-cell loops. One
at `[world+0x6987]`; both sides also preserve the same twelve `0x4e1` recipe books at
`[world+0x0fe7]` as one exact `cap dword + 0x3d-byte header + five repeated line tuples`
structure, where each repeated `0x30`-byte line is serialized field-by-field as mode dword
`+0x00`, annual amount float `+0x04`, supplied-token window `+0x08`, and demanded-token window
`+0x1c` before the wider world-cell loops continue. One
serializer-side negative boundary is explicit now too: after the save path emits the six-dword
economic tuning band at `[world+0x0be2..+0x0bf6]`, it spends its next large loops on per-cell
world-grid, overlay-mask, sidecar-plane, and secondary-raster bit serialization and only then
@ -356,7 +394,7 @@ The same brush strip is tighter now too:
`0x005069c6`, which now makes this whole slot cluster look like broader runtime consumers of
scenario special conditions rather than one startup-only mode enum. That startup-side consumer
split is tighter now too: inside the localized `Computing Transportation and Pricing...` bring-up
lane, `world_preseed_named_candidate_availability_records_from_live_pool` `0x00437743` only runs
lane, `world_preseed_named_candidate_availability_records_from_live_pool` `0x00437737` only runs
before global stage counter `0x00620e94` reaches `0x26ad`, reverse-walks the live candidate pool,
and seeds the scenario-side named availability table through `0x00434f20` with one override bit
derived directly from current live candidate state. Any nonzero availability pair
@ -365,13 +403,22 @@ The same brush strip is tighter now too:
branch and only skips those subtype-driven cases when the copied stage counter is already nonzero.
The same startup strip then flows into `world_seed_default_chairman_profile_slots` `0x004377a0`,
which compacts the 16 staged chairman slot records at `[world+0x69d8]`, writes the first-pass
selector bytes into `[profile+0x87+i]`, and only after that materializes the named-profile rows
through `0x00476140`. So the save-derived special-condition band no longer sits beside anonymous
startup glue: the bring-up path now has one concrete candidate-availability mirror at
`0x00437743`, one concrete chairman-slot selector seeding pass at `0x004377a0`, and then the
economy burst `0x00437b20`, whose own loop count is now tighter than before because a nonzero
`[world+0x4af7]` forces the chunk count to literal `0x150` instead of leaving the shell-side
`[0x006cec74+0x178]` count in control. One file-side anchor is now tighter too: the checked
selector bytes into `[profile+0x87+i]`, allocates one fresh persona-record id for each nonzero
selector, and only after that materializes the named-profile rows through `0x00476140`. The
neighboring materializer `world_build_chairman_profile_slot_records` `0x00437220` is tighter now
too: it first rebuilds one local `0x29`-byte occupied-persona mask from the two `0x48`-byte
staging records rooted at `[world+0x69db]`, optionally waits on the multiplayer preview owner at
`0x006cd8d8`, then resolves selector `0` through the first unused persona ordinal in
`[world+0x6987]` while selectors `<0x64` map to `selector-1` and selectors `0x64+` map to the
later-opponent range. That same pass copies the staged tuning dword from `[slot+0x04]` into
`[profile+0x154/+0x158]`, can clear or set `[profile+0x293]` on the multiplayer-preview side
path, and finally seeds `[world+0x25]` plus `[world+0x21]` from the resolved first profile row.
So the save-derived special-condition band no longer sits beside anonymous startup glue: the
bring-up path now has one concrete candidate-availability mirror at `0x00437737`, one concrete
chairman-slot selector seeding pass at `0x004377a0`, one concrete chairman-profile materializer
at `0x00437220`, and then the economy burst `0x00437b20`, whose own loop count is now tighter
than before because a nonzero `[world+0x4af7]` forces the chunk count to literal `0x150` instead
of leaving the shell-side `[0x006cec74+0x178]` count in control. One file-side anchor is now tighter too: the checked
classic and 1.05 `gmp/gms/gmx` corpus does expose the same aligned
`0x0d64..0x0e2c` `50`-dword band as the grounded `.smp` runtime save or restore copy into
`[world+0x4a7f..+0x4b43]`, but most checked file families only populate a sparse subset of that
@ -444,7 +491,17 @@ The same brush strip is tighter now too:
`[world+0x4c74]` `Auto-Show Grade During Track Lay`, `0x0f5d` maps to `[world+0x4c78]`
`Starting Building Density Level`, `0x0f61` maps to `[world+0x4c7c]` `Building Density Growth`,
`0x0f65` maps to grounded dword `[world+0x4c80]` `leftover simulation time accumulator`, and
`0x0f6d` maps to byte `[world+0x4c88]` `selected-year lane snapshot`. The next later grounded
`0x0f6d` maps to byte `[world+0x4c88]` `selected-year lane snapshot`. The write-side owner strip
for the two building-density fields is explicit now too: the editor page
`0x004ca910/0x004cb9f0` still owns the ordinary three-state UI path, but the tiny helper family
`0x004cba34/0x004cba43/0x004cba56/0x004cba69/0x004cba78` also gives direct and fixed-preset
writes into `[world+0x4c78]` and `[world+0x4c7c]`, with hard-wired low/high helpers for the same
saved density modes. The selected-year snapshot lane is narrower now too: both
`world_set_outcome_mode_and_copy_cheat_win_or_loss_status_text` `0x004367c0` and the nonzero
outcome branch inside `world_apply_compact_runtime_effect_record_to_resolved_targets`
`0x00431b20` copy current absolute calendar counter `[world+0x15]` into `[world+0x4c88]`, and
the periodic year-step branch at `0x0040a280` later compares the absolute delta between those two
lanes against one fixed threshold before it reasserts world flag `[world+0x4d]`. The next later grounded
field after that is no longer best read as a dword either: `0x0f71` is the first byte of the
cheat-toggled scenario-lock trio rooted at `[world+0x4c8c..+0x4c8e]`, not the start of one
independently grounded 4-byte scalar. Current runtime-side evidence only gives one narrower
@ -477,9 +534,19 @@ The same brush strip is tighter now too:
A second byte-oriented neighborhood immediately after that now has the same kind of split rather
than a clean restored-field mirror. The earlier grounded anchors in that band all stay zero in
the checked 1.05 saves: exact file offset `0x0f87` maps to selected-year bucket companion scalar
`[world+0x4ca2]`, while `0x0f93` and `0x0f97` map to the two startup-dispatch reset-owned bands
`[world+0x4ca2]`, while `0x0f93` and `0x0f97` map to the two startup-owned dwords
`[world+0x4cae]` and `[world+0x4cb2]`, and the local corpus leaves all three exact dword starts
zeroed. The same is true for the later exact byte-owned policy lanes: file offsets `0x0f78`,
zeroed. Those two later dwords are tighter now in lifecycle even though their user-facing meaning
is still open: the startup-runtime pre-dispatch helper
`world_runtime_reset_startup_dispatch_state_bands` `0x004336d0` clears both before
`shell_active_mode_run_profile_startup_and_load_dispatch` `0x00438890`, the broader
scenario-state reset owner `0x00436d10` clears them again with the rest of the late save-visible
cluster, and the post-fast-forward selected-year tail around `0x00437120` clears them one more
time alongside the shell presenter cache band `[0x006d4024+0x11425a..+0x114276]`. Local static
evidence still does not show any non-clear readers or nonzero writers for `[world+0x4cae]` or
`[world+0x4cb2]`, so the safest current read is still structural: they are startup and reload
lifecycle dwords, not yet another grounded policy or simulation lane. The same is true for the
later exact byte-owned policy lanes: file offsets `0x0f78`,
`0x0f7c`, `0x0f7d`, and `0x0f7e` map cleanly to grounded byte fields `[world+0x4c93]` and
`[world+0x4c97..+0x4c99]`: the linked-site removal follow-on gate plus the three editor
locomotives-page policy bytes `All Steam Locos Avail.`, `All Diesel Locos Avail.`, and `All
@ -512,9 +579,12 @@ The same brush strip is tighter now too:
`[world+0x0be6/+0x0bea/+0x0bee/+0x0bf2]` to `0x3c75c28f`, and seeds `[world+0x0bf6]` to
`0x3ba3d70a` before the later selected-year and candidate refresh path runs. The recipe-side
reset is explicit in the same way: after zeroing exactly `0xea3` dwords rooted at
`[world+0x0fe7]`, the same owner repopulates all twelve `0x4e1`-byte books from the fixed
template table at `0x005c9f78`, using generated ordinal strings `1..12` as the per-book name
lane before later runtime recipe projection re-enters `0x00435630`. That
`[world+0x0fe7]`, the same owner does not preload one full recipe-book payload table. Instead it
seeds only the per-book name lane from the fixed format string `# %1` at `0x005c9f78`, using
generated ordinal strings `1..12` through `0x0051b700 -> 0x00518de0`, before later runtime
recipe projection re-enters `0x00435630`. That means the reset path itself does not author any
default line modes, amounts, or cargo-token strings in the later `book+0x3ed/+0x3f1` payload.
That
same reset owner is now the strongest current live bridge over the whole later pre-recipe
plateau:
after clearing `[world+0x4cc2..+0x4d02]` it rebuilds the named candidate and locomotive
@ -526,8 +596,20 @@ The same brush strip is tighter now too:
by era-policy and named-availability gates. So the aligned scalar
plateau `0x0fa7..0x0fe7` now has a stronger boundary than “some bytes before the recipe books”:
it is the later save-side neighbor immediately in front of a reset-and-rebuild band whose
downstream consumers are already grounded. The local layout seam is therefore closed even though
we still do not have live semantic names for most of the plateau dwords themselves. The
downstream consumers are already grounded. Local operand-side evidence is negative in a useful
way too: after the bulk clear at `0x00436d10`, the current binary does not expose direct
literal-offset reads or writes for the first dwords in `[world+0x4cc2..]`, so the opening slice
of that plateau is currently better treated as one save-visible late-state family with a grounded
reset owner than as a hidden cluster of missed per-field seams. The local layout seam is
therefore closed at the current evidence level even though we still do not have live semantic
names for most of the plateau dwords themselves. The adjacent startup-side special-case gate is
bounded now too: `0x00436c70` is not another generic late-state scalar helper. It is one
hard-coded tutorial-signature predicate that only returns true when selector `0x10` is paired
with the `384x448` map-size check, a live city count of `0x41`, first city name
`Italy - North`, the current shell-side file/scenario root satisfying `0x4331e0 == 0x16`, and
row `7` subtype byte `0x6`; the neighboring string table points at `Tutorial_2.gmp`. So this
branch belongs with the startup/load special-case gates beside the reset owner, not with the
unresolved per-dword semantics of the `0x4cc2..` plateau itself. The
serializer-side evidence now sharpens that same boundary too: current local disassembly of
`0x00446240` writes the leading six-dword tuning band, then falls into the world-grid and
secondary-raster loops, and only after those loops jumps straight to `[world+0x0fe7]` for the
@ -572,9 +654,11 @@ The same brush strip is tighter now too:
label. The editor and runtime bridge is tighter now too: the shell-side
economic tuning owner `0x004ca980/0x004cadf0` writes the visible slider values directly into
`[world+0x0be2/+0x0be6/+0x0bea/+0x0bee/+0x0bf2/+0x0bf6]` and mirrors the first lane into
`[world+0x0bde]`; the `.smp` save/load pair persists that same six-dword band; the post-load
generation pipeline `0x004384d0` reseeds `[world+0x0bde]` from `[world+0x0be2]` before its early
setup passes; and `world_region_query_projected_structure_count_scalar_by_category` `0x004234e0`
`[world+0x0bde]`; the write path is asymmetric too, because lane `0` uses its dedicated divisor
at `0x005c85d8` while the trailing five lanes share the centered `(value-0xce)/0x005c87f8`
path. The `.smp` save/load pair persists that same six-dword band; the post-load generation
pipeline `0x004384d0` reseeds `[world+0x0bde]` from `[world+0x0be2]` before its early setup
passes; and `world_region_query_projected_structure_count_scalar_by_category` `0x004234e0`
consumes `[world+0x0bde]` as one global multiplier on both its live-region and fallback
projected-structure branches. The editor-side read path is explicit on the same seam:
`map_editor_economic_cost_panel_refresh_preview_curve_and_numeric_rows` `0x004caaf0` reads the
@ -604,12 +688,13 @@ The same brush strip is tighter now too:
and the checked map/save pairs `Alternate USA.gmp -> Autosave.gms`, `Southern Pacific.gmp ->
p.gms`, and `Spanish Mainline.gmp -> g.gms` preserve that rooted block byte-for-byte in the
sampled local corpus. The current probe therefore treats it as preserved scenario payload rather
than save-only runtime drift and only reports per-book signatures: a coarse head kind over the
pre-line region, the raw `book+0x3ed` annual-production dword, and one raw summary for each of
the five fixed `0x30`-byte cargo lines beginning at `book+0x3f1`: coarse line kind, raw mode
dword, raw annual-amount dword, and the raw supplied/demanded cargo-token dwords at `+0x08` and
`+0x1c`. That is enough to separate zero, `0xcd`-filled, and mixed books or lines without
overstating line semantics beyond the grounded editor/runtime ownership already documented below.
than save-only runtime drift and reports the same structural shape the `.smp` owners use: one
`book+0x3ed` annual-production dword, one `0x3d`-byte book header, and five repeated
`0x30`-byte cargo-line tuples rooted at `book+0x3f1`, each with mode dword `+0x00`,
annual-amount dword `+0x04`, supplied-token dword window `+0x08`, and demanded-token dword
window `+0x1c`. That is enough to separate zero, `0xcd`-filled, and mixed books or lines
without overstating line semantics beyond the grounded editor/runtime ownership already
documented below.
Local
corpus clustering now makes the remaining split more specific. The base 1.05 save family
(`Autosave.gms`, `nom.gms`) shares a narrow tail-heavy subset with stable relative offsets
@ -794,7 +879,7 @@ The same brush strip is tighter now too:
classic staged-profile band already exposed. The strongest structural read is therefore that the
entire `0x6a70..0x73c0` catalog region is shared verbatim between `Alternate USA.gmp` and the
derived `Autosave.gms`, not rebuilt independently during save. Combined with the earlier
grounded record-layout work under `0x00437743`, `0x00434ea0`, and `0x00434f20`, the current
grounded record-layout work under `0x00437737`, `0x00434ea0`, and `0x00434f20`, the current
safest semantic read is that this shared catalog is the bundled source form of the scenario-side
named candidate-availability table later mirrored into `[state+0x66b2]`, with each entry's
trailing dword now reading as the same availability override bit later copied into
@ -819,8 +904,9 @@ The same brush strip is tighter now too:
seeds the fixed year defaults and chairman-slot rows, reseeds the same six-dword economic-tuning
band later serialized at `0x00446240`, restored at `0x00446d40`, and edited through
`0x004ca980/0x004caaf0/0x004cadf0`, rebuilds the two named-availability collections at
`[state+0x66b2]` and `[state+0x66b6]`, re-seeds the twelve recipe books from the fixed template
at `0x005c9f78`, refreshes selected-year state through `0x00409e80`,
`[state+0x66b2]` and `[state+0x66b6]`, zero-fills the twelve recipe books at `[state+0x0fe7]`,
then only re-seeds their per-book name lane from the fixed `# %1` format string at `0x005c9f78`,
refreshes selected-year state through `0x00409e80`,
`0x00433bd0`, `0x00435603`, and the year-gap scalar helper `0x00434130`, and only then
re-enters `0x00435630`, `0x0041e970`, `0x00412bd0`, and `0x00436af0`. The loader-side coverage
around world entry is tighter now too. `0x00443a50` does not just “restore the late profile
@ -832,8 +918,12 @@ The same brush strip is tighter now too:
restores `[profile+0x77]` into the selected-year lanes, reruns
`0x00409e80`, `0x00433bd0`, `0x00435603`, `0x00444dc5`, `0x0041e970`, `0x00412bd0`,
`0x00434130`, and `0x00436af0`, and only then rehydrates `[world+0x66b2]`, `[world+0x66b6]`,
and the later locomotive override refresh `0x00461e00`. The loader-side coverage is tighter now
too:
and the later locomotive override refresh `0x00461e00`. That named-availability restore split is
tighter now too: the candidate side keeps only rows whose copied names survive the built-in stem
rejects and still resolve into the live candidate pool, with no later fallback preseed if that
validated pass stays empty, while the locomotive side bulk-reinserts its fixed `0x41`-byte rows
raw and only then falls back to `0x004350b0` if the collection is still empty. The loader-side
coverage is tighter now too:
the same table parser now
attaches both to the common-save bridge payload and directly to the fixed source range in
`.gmp` files and the non-common `rt3-105-scenario-save` / `rt3-105-alt-save` branches. That
@ -847,8 +937,22 @@ The same brush strip is tighter now too:
available. The header lanes just ahead of the table vary coherently with those scenario
branches too: `Alternate USA` carries `header_word_0 = 0x10000000`, `Southern Pacific`
carries `0x00000000`, and `Spanish Mainline` carries `0xcdcdcdcd`, while the structural
fields from `header_word_2` onward remain stable (`0x332e`, `0x1`, `0x22`, `0x44`, `0x43`)
and the 9-byte footer still decodes as `0x32dc`, `0x3714`, `0x00` in all three checked maps.
fields from `header_word_2` onward remain stable in a fuller fixed-record strip:
`0x332e`, `0x1`, `0x22`, `0x2`, `0x2`, then the observed capacity/count pair (`0x44`, `0x43`
in the checked save-side probe), followed by `0x0`, `0x1`; the 9-byte footer still decodes as
`0x32dc`, `0x3714`, `0x00` in all three checked maps. The runtime-side support family is now
explicit enough to narrow that strip further without overclaiming ownership: the shared indexed
collection constructor `0x00518570` and growth helper `0x00517f90` really do seed the same
collection-shape header family at `[this+0x04/+0x08/+0x0c/+0x10/+0x14/+0x18]` before the live
payload slab, tombstone bitset, and auxiliary link bands are materialized at
`[this+0x30/+0x34/+0x3c..+0x44]`. So the file-side prefix now reads more like one source-side
fixed-record table header than a random magic run: the stable `0x1/0x22/0x2/0x2/0x44/0x43`
lanes align much better with one fixed-record flag plus one record-stride/growth/bound/count
family than with direct availability payload. The gap is narrower now too: the later named-
availability runtime save path does use the shared serializer `0x00517d90` on the non-`.smp`
package branch, but the `.smp` path still writes direct counted fixed-row runs instead. So the
file table still is not proven to be a byte-for-byte dump of one single runtime
indexed-collection body with tombstone and auxiliary-band tails across every save family.
A wider corpus scan over the visible `.gmp`/`.gms` files makes those two anonymous header
lanes less mysterious too: the parser currently sees only three stable
`(header_word_0, header_word_1)` pairs across 79 files with this table shape, namely
@ -856,12 +960,21 @@ The same brush strip is tighter now too:
`(0xcdcdcdcd, 0xcdcdcdcd)`. The zero-availability count varies widely underneath the first and
third pairs (`0..56` under the zero pair, `14..67` under the `0xcdcdcdcd` pair), so those two
lanes no longer look like counts or direct availability payload; the safest current read is
that they are coarse scenario-family or source-template markers above the stable
`0x332e/0x22/0x44/0x43` table header, with `0xcdcdcdcd` still plausibly acting as one reused
filler or sentinel lane rather than a meaningful numeric threshold. Current exported
that they are coarse scenario-family or source-template markers above the stable fixed-record
header strip `0x332e/0x1/0x22/0x2/0x2/(capacity)/(count)/0x0/0x1`, with `0xcdcdcdcd` still
plausibly acting as one reused filler or sentinel lane rather than a meaningful numeric
threshold. Current exported
disassembly notes still do not ground one direct loader-side or editor-side consumer of
`header_word_0` or `header_word_1` themselves, so that family-marker read remains an
inference from corpus structure rather than a named field assignment.
inference from corpus structure rather than a named field assignment. The save-side runtime
serializers now sharpen that boundary differently, though: the direct `.smp` path still emits
the named candidate and locomotive availability families as direct counted fixed-row runs, while
the non-`.smp` package-save prelude does call the shared indexed-collection serializer
`indexed_collection_serialize_header_and_live_entry_payload_band` `0x00517d90` on those same two
runtime collections before continuing into the later tagged-save families. So the anonymous
file-side `header_word_0/1` pair is no longer excluded by the package-save branch alone, but it
is still not directly explained by the `.smp` save family or by one grounded loader-side field
owner for those two words themselves.
The new loader-side compare command makes the save-copy claim sharper too: for the checked
pairs `Alternate USA.gmp -> Autosave.gms`, `Southern Pacific.gmp -> p.gms`, and
`Spanish Mainline.gmp -> g.gms`, the parsed candidate-availability table contents now match
@ -886,8 +999,10 @@ The same brush strip is tighter now too:
generic database opener; it is the early package-save prelude that seeds stage/progress globals
`0x00620e94/0x0062bec8/0x0062becc/0x0062bed0`, opens one `0x30d40` bundle, and then serializes
the first direct save band in fixed order: chunks `0x32c8/0x32c9`, the late world-status block
`[world+0x66be]`, the direct counted named-availability collections `[world+0x66b2]` and
`[world+0x66b6]`, chunk `0x32dc`, the staged `0x108` profile block under `0x3714/0x3715`, then
`[world+0x66be]`, the shared indexed-collection serializer `0x00517d90` over candidate named-
availability collection `[world+0x66b2]`, chunk `0x32dc`, the staged `0x108` profile block
under `0x3714/0x3715`, the same shared serializer over locomotive named-availability collection
`[world+0x66b6]` under `0x32dd`, then
`world_serialize_runtime_grid_and_secondary_raster_tables_into_bundle` `0x00449520` for the
early world-grid/core-raster band under chunk families `0x2ee2..0x2f44`, then
`aux_candidate_collection_serialize_records_into_bundle_payload` `0x00416a70` for the direct
@ -1005,15 +1120,19 @@ The same brush strip is tighter now too:
`0x22`-byte candidate-name-plus-dword records, and inserts only the rows whose copied names
survive both fixed built-in stem rejects `0x005c8f94/0x005c8e4c` and then resolve back into the
live candidate pool `0x0062b268` through `0x00412b70`; the rejected rows are discarded instead of
blindly restoring stale candidate names. The same loader then clears and repopulates
`[world+0x66b6]` from one counted run of fixed `0x41`-byte locomotive-name-plus-dword records.
After those direct named-availability restores it preserves the older empty-collection fallback
for locomotives by re-entering
blindly restoring stale candidate names, and there is no later candidate-side fallback preseed
if that validated pass stays empty. The same loader then clears and repopulates `[world+0x66b6]`
from one counted run of fixed `0x41`-byte locomotive-name-plus-dword records without the
candidate-side reject-or-resolve filter. After that raw locomotive restore it preserves the older
empty-collection fallback by re-entering
`scenario_state_upsert_named_locomotive_availability_record_and_refresh_runtime_usage`
`0x004350b0` only when `[world+0x66b6]` stayed empty. The startup and restore-side preseed
callers are tighter now too: the common startup lane at `0x00438d6b` and the `.smp` restore
fallback at `0x004478ea` both resolve one linked era name through `0x00461c80` and then upsert
it with literal availability bit `1`, matching the later live-pool sweep inside `0x00461eab`.
The restore-side condition is explicit now too: `0x004478ea` only runs after the direct counted
`0x41`-byte restore left `[world+0x66b6]` empty, so this is a true empty-collection fallback
rather than a second unconditional load pass.
The same `.smp` loader then brackets the
live event collection at `0x0062be18` with chunk ids `0x4e21/0x4e22` and delegates the per-event
packed-state restore to `scenario_event_collection_refresh_runtime_records_from_packed_state`
@ -1088,7 +1207,7 @@ The same brush strip is tighter now too:
neighboring named-candidate bridge is now aligned with that same save/load pattern too: the
scenario-side named candidate-availability table at `[world+0x66b2]` is another counted fixed
record run, the `.smp` restore path only keeps rows whose names still resolve into the live
candidate pool, and the later post-load preseed `0x00437743` plus
candidate pool, and the later post-load preseed `0x00437737` plus
`scenario_state_upsert_named_candidate_availability_record_and_refresh_runtime_filters`
`0x00434f20` mirror that filtered table back into `[candidate+0x7ac]` across the live candidate
pool. The

View file

@ -26,7 +26,7 @@
helper inside the larger post-load generation pipeline `world_run_post_load_generation_pipeline`
at `0x004384d0` under the `Seeding Economy...` phase rather than under the ordinary player-facing
speed buttons. That setup pipeline is now clearer at the progress-banner level too: on the fuller
setup path it first runs one preliminary named-candidate availability prepass through `0x00437743`
setup path it first runs one preliminary named-candidate availability prepass through `0x00437737`
before any visible progress banner is posted. One startup-side selector edge is tighter now too:
`shell_active_mode_run_profile_startup_and_load_dispatch` `0x00438890` reaches an early
selector-`2` branch at `0x00438a66..0x00438c00` that refreshes one support-family type-`7`
@ -40,9 +40,10 @@
`structure_candidate_collection_run_post_load_local_service_setup_phase` `0x0041ea50`, and the conditional region pair
`world_region_collection_seed_default_regions` `0x00421b60` plus
`world_region_collection_refresh_neighbor_and_profile_bands` `0x00420f30`. One save-load-side
status-stack strip is now tighter too: `0x004422d0/0x00442330` push and pop the same four shell
dwords `[0x006cec74+0x140/+0x13c/+0x138/+0x144]` plus startup byte `[0x006cec78+0x4c74]`
through the local stack `0x0062be90` with depth `0x0062bedc`, and the paired wrappers
status-stack strip is now tighter too: `0x004422d0/0x00442330` push and pop the low bytes of the
same four shell lanes `[0x006cec74+0x140/+0x13c/+0x138/+0x144]` plus startup byte
`[0x006cec78+0x4c74]` through the local stack `0x0062be90` with depth `0x0062bedc`, and the
paired wrappers
`0x004423a0/0x004423d0` bracket that same band while also servicing the live TrackLay.win and
StationPlace.win tool objects through `0x0050e070`, `0x00507a50`, `0x0050a530`, and
`0x0050e1e0`. The live `.smp` serializer uses the higher pair, while `world_entry_transition_and_runtime_bringup`
@ -1186,13 +1187,13 @@
it then posts id `321` `Seeding Economy...` for `simulation_run_chunked_fast_forward_burst`
`0x00437b20`; only after those setup-side gates does the code post id `319`
`Setting up Players and Companies...`. That `319` lane is no longer just a shell-state placeholder: its
earlier hidden prepass is tighter now too: `0x00437743` is the scenario-side named
earlier hidden prepass is tighter now too: `0x00437737` is the scenario-side named
candidate-availability seeding pass over the live candidate pool `0x0062b268`, feeding the
override collection at `[state+0x66b2]` through `0x00434f20` before any visible banner is posted.
That grounded write path is narrower than the static file evidence, though: the startup reset
helper `world_runtime_reset_startup_dispatch_state_bands` `0x004336d0` explicitly clears
`[state+0x66b2]` before the dispatch path begins, and the current exported write-side callers
we can name after that reset are still just the live-pool preseed `0x00437743`, the sibling
we can name after that reset are still just the live-pool preseed `0x00437737`, the sibling
startup lane `0x00436ad7`, and the editor-side `Industry (Overall)` toggle handler
`0x004cf430` through `0x00434f20`. So while the fixed `0x6a70..0x73c0` candidate-availability
block is now well grounded as bundled map/save source data, a direct bulk-import path from that
@ -1479,8 +1480,10 @@
The editor-side help text cluster around ids `2433..2437` is no longer floating either: current
grounded map-editor code now has a live economic tuning family beside the chairman-slot panel.
`map_editor_economic_cost_slider_panel_construct` `0x004cadf0` binds six slider controls through
`map_editor_economic_cost_slider_dispatch` `0x004ca980` into the scenario-state float block
`[0x006cec78+0x0be2..0x0bf6]`, while the surrounding descriptor table at `0x00611c70..0x00612220`
`map_editor_economic_cost_slider_dispatch` `0x004ca980`, which now grounds as the real writer for
the scenario-state float block `[0x006cec78+0x0be2..0x0bf6]`: lane `0` uses one dedicated scale
divisor, the trailing five lanes share the centered `(value-0xce)` path, and the helper mirrors
lane `0` into `[state+0x0bde]`. The surrounding descriptor table at `0x00611c70..0x00612220`
pairs that wider editor lane with localized fields `Prime Rate`, `Merger Premium`, and `Build
Stations Cost` through `Steam Engine Cost` plus the comparison or help texts `2433..2437`. The
broader shell-state master flag at `[0x006cec74+0x68]` still sits above the remaining post-load
@ -2007,9 +2010,10 @@ Current evidence grounds the shell-controller-backed input and frame path as the
`.smp` serializer `world_runtime_serialize_smp_bundle` `0x00446240` does the same thing through
`0x446271` and `0x446d09` around its bundle-write and fixed status-publish span. The exact
save/load-side status stack under those spans is tighter now too: `0x004422d0/0x00442330` push
and pop shell dwords `[0x006cec74+0x140/+0x13c/+0x138/+0x144]` plus startup byte
`[0x006cec78+0x4c74]` through `0x0062be90`, while `0x004423a0/0x004423d0` layer the same band
under active TrackLay.win and StationPlace.win service. The per-frame tail is
and pop the low bytes of shell lanes `[0x006cec74+0x140/+0x13c/+0x138/+0x144]` plus startup byte
`[0x006cec78+0x4c74]` through `0x0062be90`, with the restore side sign-extending the first three
shell bytes and zero-extending the fourth before rewriting the wider dwords; `0x004423a0/0x004423d0`
layer the same band under active TrackLay.win and StationPlace.win service. The per-frame tail is
tighter now too: `0x0054f5b0` queues one 12-dword shell-input event record into the rotating
ring at `[input+0x128]`; `0x0054f6a0` and `0x0054f6b0` are the two neighboring fixed-value
seeders for shared phase scalar `0x00d93850` used by shell-side branches `0x00538b72`,