2026-04-06 01:11:06 -07:00
|
|
|
# Multiplayer
|
|
|
|
|
|
|
|
|
|
Primary atlas source:
|
|
|
|
|
|
|
|
|
|
- [control-loop-atlas.md#multiplayer-session-and-transport-flow](/home/jan/projects/rrt/docs/control-loop-atlas.md#multiplayer-session-and-transport-flow)
|
|
|
|
|
|
|
|
|
|
Current grounded owners:
|
|
|
|
|
|
|
|
|
|
- `multiplayer_window_init_globals`
|
|
|
|
|
- `multiplayer_window_service_loop`
|
|
|
|
|
- `multiplayer_register_session_event_callbacks`
|
|
|
|
|
- `multiplayer_dispatch_requested_action`
|
|
|
|
|
- `multiplayer_preview_dataset_service_frame`
|
|
|
|
|
- `multiplayer_transport_service_frame`
|
|
|
|
|
- `multiplayer_transport_service_worker_once`
|
|
|
|
|
- `multiplayer_transport_service_route_callback_tables`
|
|
|
|
|
- `multiplayer_transport_service_status_and_live_routes`
|
|
|
|
|
|
|
|
|
|
Current bounded state blocks:
|
|
|
|
|
|
|
|
|
|
- session globals at `0x006d40d0`
|
|
|
|
|
- active session-event transport at `0x006cd970`
|
|
|
|
|
- preview dataset at `0x006cd8d8`
|
|
|
|
|
- Multiplayer window backing block at `0x006d1270`
|
|
|
|
|
- selector-view store rooted at `[transport+0xab4]`
|
|
|
|
|
|
|
|
|
|
What this note is for:
|
|
|
|
|
|
|
|
|
|
- Multiplayer window and preview-dataset ownership
|
|
|
|
|
- Session-event transport routing
|
|
|
|
|
- GameSpy-facing callback and live-route semantics
|
|
|
|
|
- Selector-view refresh, retry, and probe state
|
|
|
|
|
|
2026-04-08 16:31:33 -07:00
|
|
|
Latest local closure:
|
2026-04-06 01:11:06 -07:00
|
|
|
|
2026-04-08 16:31:33 -07:00
|
|
|
- The remaining multiplayer branch is narrower now:
|
2026-04-06 20:34:16 -07:00
|
|
|
the status-route callback vector is bounded through selector-text or averaged-sample publication,
|
|
|
|
|
control-id-list seeding, scalar-query forwarding, and the validated cookie or extended-payload
|
|
|
|
|
callbacks. The selector-view sidecar is tighter too: `[entry+0x80]` now reads as the averaged
|
|
|
|
|
millisecond probe sample and `[entry+0x54]` as the displayed version/build companion integer from
|
|
|
|
|
the local `X...X|%d` marker family. Separately, the route-callback side now has its own compact
|
|
|
|
|
GameSpy-style server or route descriptor family with primary and optional secondary endpoint
|
|
|
|
|
tuples plus keyed fields like `hostname`, `gamever`, `numplayers`, and `numservers`, feeding the
|
|
|
|
|
route-binding compatibility gate. The compact decode owners are tighter too: `0x5907d0` is now
|
|
|
|
|
the allocate-and-append lane for self-consistent compact payloads, while `0x590d00` is the keyed
|
|
|
|
|
upsert-by-primary-endpoint lane that reuses an existing descriptor when one already matches and
|
|
|
|
|
then notifies the transport owner callback. The route-callback-table runtime above that decode
|
|
|
|
|
path is tighter too: `0x5905e0` now constructs one transport-owned callback-table block,
|
|
|
|
|
`0x5906f0` tears down the decoded schema dictionary rooted at `[this+0x08]`, `0x590540/0x5905a0`
|
|
|
|
|
acquire and release refcounted shared schema strings through the global pool, and `0x5908c0`
|
|
|
|
|
now reads as the live receive/decode state machine serviced by `0x591290` in table states `2/3`.
|
2026-04-08 16:31:33 -07:00
|
|
|
The owner-callback mode split above that runtime is tighter now too: mode `0` comes from the
|
|
|
|
|
generic append-notify lane `0x590370`, mode `1` from compact upsert `0x590d00`, mode `2` from
|
|
|
|
|
generic remove-notify `0x590430`, and modes `6/5/3` from the receive/decode state machine
|
|
|
|
|
`0x5908c0`.
|
2026-04-06 20:34:16 -07:00
|
|
|
The higher transport bring-up split is tighter too: `0x596090` now clearly constructs
|
|
|
|
|
`[transport+0xba4]` through `0x5905e0` with owner callback `0x595a40`, then seeds the local
|
|
|
|
|
field-cache family `[transport+0x1724]` through `0x5a08f0` with helper `0x595b60`, and then
|
|
|
|
|
constructs `[transport+0x1164]` through the same `0x5905e0` path but with owner callback
|
|
|
|
|
`0x595bc0`.
|
|
|
|
|
The live-route lifecycle above it is tighter too: `0x590740` now cleanly resets one table's live
|
|
|
|
|
route plus decode-side runtime without destroying the outer object, `0x5907a0` is the broader
|
|
|
|
|
destroy path that also releases the active descriptor collection, `0x590ed0` opens the route
|
|
|
|
|
handle into `[this+0x4a0]`, stages the initial outbound request, and seeds state `3` plus the
|
|
|
|
|
receive buffer, `0x5911e0` is the state-`2/3` socket-service wrapper above `0x5908c0`,
|
|
|
|
|
`0x5912c0` is the one-shot send-with-reopen-retry helper, and `0x590ea0` is the shared
|
|
|
|
|
disconnect publication and reset tail. The recurring service helper `0x591290` is tighter too:
|
|
|
|
|
it now first clears the staged intrusive descriptor list through `0x590490` before entering the
|
|
|
|
|
state-driven seed-or-receive branch. The upstream openers are tighter now too: `0x5962e0` is the
|
|
|
|
|
field-subscription route-table owner above `[transport+0xba4]`, while `0x596530` is the
|
|
|
|
|
`gsi_am_rating` reopen path above `[transport+0x18bc]`. On that latter branch, `0x590dc0` is now
|
|
|
|
|
bounded as the state-`0` raw-endpoint seed pass over the live route handle, repeatedly pulling
|
|
|
|
|
endpoint tuples through `0x58bc7e` record type `0x1f3` before stamping descriptor flag byte
|
|
|
|
|
`0x15` with `0x11`. That makes the remaining flag-bit question much narrower too: current
|
|
|
|
|
evidence now supports reading byte-`0x15` bit `0x1` as a primary-endpoint-seed or endpoint-only
|
|
|
|
|
source marker. In the `gsi_am_rating` dispatcher, clear-bit descriptors can take the richer
|
|
|
|
|
direct transition lane, while set-bit descriptors are pushed through the queued enrichment path
|
|
|
|
|
and later still suppress that direct transition even when the ready bit is present.
|
|
|
|
|
The adjacent capacity-descriptor side is tighter too: `0x595bc0` no longer reads as a vague
|
|
|
|
|
progress helper. Mode `0` is now clearly the live publish lane, and it lines up with the generic
|
|
|
|
|
descriptor append-notify owner callback at `0x590370`: it samples `hostname`,
|
|
|
|
|
`numwaiting`, `maxwaiting`, `numservers`, and `numplayers` from the current descriptor before
|
|
|
|
|
publishing an opcode-`2` descriptor block, while still carrying three cached side scalars from
|
|
|
|
|
the local capacity sidecar at `[transport+0x1778]`. That sidecar is tighter now too: current
|
|
|
|
|
evidence says it behaves as one cached pointer into the transient work-record family at
|
|
|
|
|
`[transport+0x1780]`, because every meaningful branch in `0x595bc0` reads the same
|
|
|
|
|
`+0x0c/+0x10/+0x18` metadata triplet and the replay modes later consume the pointer through
|
|
|
|
|
`0x5933a0`. The negative result is stronger too: local text-side xrefs still show no direct
|
|
|
|
|
store to `[transport+0x1778]`, and a wider sweep also failed to show any obvious `lea`-based
|
2026-04-08 16:31:33 -07:00
|
|
|
replay-band writer. The owned request lifecycle now tightens that further too:
|
|
|
|
|
`0x593330/0x593370/0x593380/0x5934e0/0x5933a0` fully own `[transport+0x1780]`, `0x1784`, and
|
|
|
|
|
`0x1788`, while still leaving `[transport+0x1778]` outside that family; the neighboring active
|
|
|
|
|
opcode reset path `0x5929a0` also only targets `[transport+0x17fc]`. Constructor and teardown
|
|
|
|
|
passes around `0x596090/0x5961b0/0x5962e0` tighten that negative result further: those owners
|
|
|
|
|
seed or clear the neighboring replay-band fields while still leaving `[transport+0x1778]`
|
|
|
|
|
untouched. A full-binary literal-offset sweep tightens it further still: the only direct
|
|
|
|
|
`0x1778` hit in `RT3.exe` is the read in `0x595bc0`. One nearby ambiguity is now closed too: the
|
|
|
|
|
mode-`5` mirror path in `0x595a40` and `0x595e10` does not seed `[transport+0x1778]`; it writes
|
|
|
|
|
`[transport+0x54]` and mirrors the same staged route companion dword only into queue-side slot
|
|
|
|
|
`[transport+0x1724+0x24]` through `0x005a0940`. So the sidecar writer remains upstream of this
|
|
|
|
|
leaf capacity publisher. The
|
2026-04-06 20:34:16 -07:00
|
|
|
payload split is tighter too:
|
|
|
|
|
`0x592ae0` now grounds opcode `2` as a seven-dword descriptor payload with an owned string slot
|
|
|
|
|
at `+0x08`, so live mode supplies a populated payload while modes `3` and `5` deliberately
|
|
|
|
|
enqueue an all-zero payload and reuse only the sidecar metadata in the wrapper. Those two modes
|
|
|
|
|
are tighter now too: they are not generic replay guesses, they are the live receive-state owner
|
|
|
|
|
callbacks emitted by `0x5911e0 -> 0x5908c0`. So they are best read as delayed metadata replays
|
2026-04-08 16:31:33 -07:00
|
|
|
over one cached work record, not over a standalone custom cache object. The capacity owner split
|
|
|
|
|
itself is tighter now too: `0x595bc0` only does real work for modes
|
|
|
|
|
`0`, `3`, and `5`; the upstream table still delivers modes `1`, `2`, and `6`, but those are
|
|
|
|
|
explicit no-ops in the capacity leaf. So the callback-owner edge is now effectively closed: the
|
|
|
|
|
route-callback table feeds the capacity publisher only through the live append lane and the two
|
|
|
|
|
replay lanes, while the remaining missing piece is still the upstream sidecar producer, not the
|
|
|
|
|
owner-mode wiring. The producer side is tighter now too: callback-table attach,
|
2026-04-06 20:34:16 -07:00
|
|
|
bound-route requests, selector-text route requests, and the type-`9` text fastpath all stage
|
|
|
|
|
that same `+0x0c/+0x10/+0x18` triplet through `0x5934e0`, so the capacity replay sidecar is
|
|
|
|
|
clearly reusing one broader transport work-record family. The generic owner-callback split above that family is tighter now
|
|
|
|
|
too: `0x590370` is the shared append-notify lane in mode `0`, while `0x590430` is the distinct
|
|
|
|
|
remove-notify-and-stage lane in mode `2`. So `0x595bc0` only owns the live append-style publish
|
|
|
|
|
path plus delayed replay modes `3/5`, not the remove path. The neighboring transient work queue
|
|
|
|
|
is tighter too:
|
|
|
|
|
`0x593330/0x593370/0x593380` now bound `[transport+0x1780]` as a real construct/clear/destroy
|
|
|
|
|
collection owner, while `0x5933a0`, `0x5934e0`, and `0x593570` now ground the remove, allocate,
|
|
|
|
|
and completion side over that same family. The small sibling `0x593400` is tighter too: it is a
|
|
|
|
|
pure uniqueness predicate over work-record field `+0x0c`. Its caller is tighter now too:
|
|
|
|
|
`0x58d720` is an immediate-drain quiescence gate over one transport context id, using
|
|
|
|
|
`0x593400` for the queued work family at `[transport+0x1780]` and `0x592970` for the active
|
|
|
|
|
opcode-record collection at `[transport+0x17fc]`. The strongest current read is that
|
|
|
|
|
`0x5934c0` seeds that shared drain context id first, then the transport copies it into queued
|
|
|
|
|
work field `+0x0c` and active opcode-record field `+0x14` before the immediate-drain roots wait
|
|
|
|
|
on one shared disappearance test rather than one vague “drain until something settles” loop. The
|
|
|
|
|
currently grounded roots are `0x58df20`, the neighboring formatted selector-text publish path at
|
|
|
|
|
`0x58dfb0`, and callback-table registration at `0x58e200`. The callback-table attach side now
|
|
|
|
|
has a tighter active-opcode owner stack too: `0x5927b0` services and retires one active opcode
|
|
|
|
|
record, `0x592800` performs the broader context-or-idle retirement sweep, `0x5929a0` removes
|
|
|
|
|
active records by opcode type, and `0x5929f0` removes only opcode-`3` field-snapshot records
|
|
|
|
|
keyed by the subscribed callback-pair payload. That also corrects `0x595b80`: its final cleanup
|
|
|
|
|
is not a queued field-snapshot drain, but an active opcode-type-`3` purge beneath the field
|
|
|
|
|
cache reset.
|
|
|
|
|
The adjacent route-callback descriptor-table lifecycle is tighter too: `0x590410` now grounds
|
|
|
|
|
`[table+0x5bc]` as a real staged intrusive descriptor-list head, `0x590430` is the generic
|
|
|
|
|
remove-notify-and-stage path, `0x590490` releases that staged list, and `0x5904d0` releases the
|
|
|
|
|
active descriptor collection before tearing the staged list down. That also tightens
|
|
|
|
|
`0x5962e0`: its earlier “release active descriptors” step is now explicitly this same
|
|
|
|
|
`0x5904d0` family, not a vague collection clear.
|
|
|
|
|
The callback-table attach side now
|
|
|
|
|
constrains the same work-record metadata family a little further too: `0x593650` deliberately
|
2026-04-08 16:31:33 -07:00
|
|
|
duplicates its first caller metadata dword into both work fields `+0x0c` and `+0x10`, while
|
|
|
|
|
carrying the second caller metadata dword in `+0x18`. The lower opcode wrappers are tighter now
|
|
|
|
|
too: `0x592a40` turned out not to be the real 0x08-byte binding leaf at all, but the explicit
|
|
|
|
|
opcode-`1` trigger wrapper whose constructor is a no-op and whose active-side service is
|
|
|
|
|
`0x5913c0`. The real lower binding leaf is `0x592c40`, which builds the local `0x08`-byte
|
|
|
|
|
payload later deep-copied by the explicit opcode-`5` family `0x591540/0x591570/0x591580`. The
|
|
|
|
|
earlier opcode-`4` reading was just the table-indexing mistake: `0x5928a0` multiplies the pushed
|
|
|
|
|
selector by `0x10`, so selector `4` lands on the row at `0x5e2044`, not the row at `0x5e2034`.
|
|
|
|
|
So
|
|
|
|
|
the replay-side triplet is still a broader transport callback-wrapper family, not one fixed
|
|
|
|
|
route-only tuple. The type-`9` text fastpath confirms the same split from the other side too:
|
|
|
|
|
`0x593d00` only emits the follow-on callback lane when work field `+0x10` is nonnull, and then
|
|
|
|
|
forwards `(+0x10, +0x18, +0x0c)` into `0x593170` as callback function, callback companion, and
|
|
|
|
|
trailing drain context.
|
2026-04-06 20:34:16 -07:00
|
|
|
The nearby field-subscription side is tighter too: `0x592b50` now clearly uses
|
|
|
|
|
`[transport+0x1774]` as a cached progress percentage under the `[transport+0xba4]` callback
|
|
|
|
|
table, and `0x5962e0` seeds that percentage to `1` just before the first immediate mode-`3`
|
|
|
|
|
snapshot. The nearby route-callback-table lifecycle is tighter now too: `0x596090` seeds
|
|
|
|
|
`[transport+0xba0]` as the callback-plumbing enable latch, clears staged payload slot
|
|
|
|
|
`[transport+0xb50]`, and constructs the three owner branches rooted at `[transport+0xba4]`,
|
2026-04-08 16:31:33 -07:00
|
|
|
`[transport+0x1164]`, and `[transport+0x18bc]`; `0x596210` is the recurring service sweep over
|
|
|
|
|
those same three tables plus the local field-cache and queued-descriptor families; `0x596060`
|
|
|
|
|
is the explicit `gsi_am_rating` reset; and `0x596530` is the reopen-from-stored-label sibling
|
|
|
|
|
above that same am-rating table. The matching local cleanup is tighter too: `0x5962c0` is the
|
|
|
|
|
explicit staged route-callback payload clear on `[transport+0xb50]`, while `0x595ce0` now
|
|
|
|
|
clearly resets only the capacity-descriptor route callback table at `[transport+0x1164]`, not
|
|
|
|
|
the field-subscription table at `[transport+0xba4]`. The only meaningful gap left on the
|
|
|
|
|
capacity side is no longer a local writer search. The carried
|
|
|
|
|
sidecar fields are no longer anonymous: current evidence now says they are just the same cached
|
|
|
|
|
callback-wrapper triplet reused by other work-record families, namely drain context id `+0x0c`,
|
|
|
|
|
callback function `+0x10`, and callback companion `+0x18`. The negative result is stronger now
|
|
|
|
|
too: the neighboring replay-band fields `[transport+0x176c]`, `[transport+0x1770]`,
|
|
|
|
|
`[transport+0x1774]`, `[transport+0x177c]`, `[transport+0x1780]`, and `[transport+0x1784]` all
|
|
|
|
|
have direct local lifecycle owners, but `[transport+0x1778]` still only appears as the single
|
|
|
|
|
read in `0x595bc0`; even the broader callback-owner lifecycle now skips it while touching those
|
|
|
|
|
neighbors, including bring-up `0x596090`, recurring service `0x596210`, am-rating reset/reopen
|
|
|
|
|
`0x596060/0x596530`, teardown `0x5961b0`, and field-subscription open `0x5962e0`. The
|
|
|
|
|
constructor now closes that negative result further: `0x58dc50` bulk-zeroes the full transport
|
|
|
|
|
body and still never seeds `[transport+0x1778]` before later explicit neighbor initialization.
|
|
|
|
|
So this edge is now locally closed: no writer is grounded anywhere in `RT3.exe`, and the
|
|
|
|
|
remaining staging path is best read as an upstream callback or worker handoff rather than one
|
|
|
|
|
missing ordinary field store in the local text cluster. The callback-binding family at
|
|
|
|
|
`0x5934e0 -> 0x593650 -> 0x58f2f0` now gives the cleanest local boundary for that claim:
|
|
|
|
|
RT3 stages and later consumes the shared work-record metadata triplet, but the sidecar itself
|
|
|
|
|
still appears only as a borrowed cached pointer at `0x595bc0`, never as a locally seeded
|
|
|
|
|
replay-band field.
|
2026-04-06 21:36:19 -07:00
|
|
|
One adjacent staged-route callback is
|
2026-04-06 20:34:16 -07:00
|
|
|
tighter now too: `0x595860` is the submit-result handler below
|
|
|
|
|
`0x5958e0`, using the already-grounded third selector-generation counter at `[transport+0xac0]`
|
|
|
|
|
plus the target at `[transport+0xb48]` to choose whether staged route-callback traffic can
|
|
|
|
|
advance the route-mode state machine from mode `2` into `3` and later `4`. The counter beneath
|
|
|
|
|
that decision is tighter too: `0x594e30` now reads as a selector-view entry counter for slot `2`
|
|
|
|
|
flag bit `0x20`, optionally filtered by the current transport name buffer. The selector-view
|
|
|
|
|
mutation side beneath that callback family is tighter too: `0x594a30` is now the direct keyed
|
|
|
|
|
store remover, `0x594fb0` clears one selector-slot ownership pointer plus its slot-local flag
|
|
|
|
|
dword and drops the whole entry when no slots remain, `0x595010` rekeys one selector-view entry
|
|
|
|
|
under a new name while preserving the `0x40..` runtime band, and callback root `0x59f9c0` is now
|
|
|
|
|
bounded as the lane that clears one named selector-view slot, publishes callback slot `18`, and
|
|
|
|
|
can still re-enter the route-mode setter from the same slot-`2` state and generation gates. The
|
|
|
|
|
next adjacent callback roots are tighter now too: `0x5950a0` clears one selector slot from every
|
|
|
|
|
selector-view entry in the keyed store, `0x59fab0` is the rename or relabel sibling above
|
|
|
|
|
`0x595010`, `0x59faf0` updates one selector slot's fixed sample-text buffer and refreshes the
|
|
|
|
|
active selector object when present, and `0x59fb60` replaces one selector slot's name set,
|
|
|
|
|
requests the default profile-key bundle for that slot, and publishes callback slot `20`. Slot
|
|
|
|
|
`16` is tighter now too: current grounded caller `0x59f440` forwards the staged route-callback
|
|
|
|
|
payload handle from `[transport+0xb50]` through `0x592ea0` just before route mode `5`. The last
|
|
|
|
|
adjacent callback root in that block is tighter now too: `0x59fbd0` is the built-in
|
|
|
|
|
per-slot profile-key query sibling. It resolves the caller selector name into one slot index,
|
|
|
|
|
forwards the caller trio into `0x596b90`, and then publishes callback slot `28`; that lower
|
|
|
|
|
helper indexes one slot-specific built-in string pair from `[transport+0x189c]` and
|
|
|
|
|
`[transport+0x18ac]`, reuses the generic per-key handler `0x596970`, and only republishes slot
|
|
|
|
|
`28` when that lower query path succeeds.
|
|
|
|
|
The compact-header side is tighter too: `0x58fe20` and `0x58ff20` now show that compact payloads
|
|
|
|
|
always carry the primary IPv4 dword and that header bit `0x10` only gates whether the primary
|
|
|
|
|
port word is inline or inherited from the owner default port. The variable tails are tighter too:
|
|
|
|
|
`0x58fe90` now validates the `0x40` inline keyed-property vector against the owner schema, and
|
|
|
|
|
`0x58fe50` validates the signed-`0x80` trailing string-pair tail before decode. `0x58ff60` then
|
|
|
|
|
grounds bit `0x02` as the inline secondary IPv4 dword branch, bit `0x20` as the paired
|
|
|
|
|
secondary-port word branch with owner-port fallback, bit `0x08` as one still-unresolved
|
|
|
|
|
auxiliary inline dword stored at `[descriptor+0x10]`, bit `0x40` as one inline keyed-property
|
|
|
|
|
vector decoded through the property-store writers, and signed bit `0x80` as one trailing
|
|
|
|
|
string-pair tail. The descriptor-state side is tighter too: queue insertion now cleanly splits
|
|
|
|
|
pending tags `0x4/0x8` from serviced-ready bits `0x1/0x2`, and the `gsi_am_rating` lane now
|
|
|
|
|
separates direct primary-endpoint handling from queued-descriptor handling. Current evidence now
|
|
|
|
|
also says byte `[descriptor+0x14]` is not queue-only: `0x58ff60` can also OR in bit `0x1` after
|
|
|
|
|
the inline keyed-property vector and bit `0x2` after the signed string-pair tail. Byte
|
|
|
|
|
`[descriptor+0x15]` bit `0x1` is source-side too, not queue-generated: it is explicitly seeded
|
|
|
|
|
by the primary-endpoint refresh path and preserved by the compact descriptor decode path before
|
|
|
|
|
the transport later uses it in the `gsi_am_rating` lane both to choose direct-vs-queued handling
|
|
|
|
|
and to suppress the direct `0x595dc0` transition even after ready bit `0x2` is present. The
|
|
|
|
|
descriptor body is tighter too: `[descriptor+0x20]` is now the intrusive next-link used by the
|
|
|
|
|
transport-owned primary-endpoint list, and `[descriptor+0x1c]` is now the special numeric scalar
|
|
|
|
|
behind the current `queryid`/`ping` fallback pair. The compact-only auxiliary dword at
|
|
|
|
|
`[descriptor+0x10]` is tighter in a different way: a local xref scan now shows it being preserved
|
|
|
|
|
by later generic preservation helpers such as
|
|
|
|
|
`generic_record_0x1c_deep_copy_with_owned_string_at_0x08` `0x591410` and the callback-marshaling
|
|
|
|
|
wrappers `0x591480` and `0x591510`, but still no dedicated semantic reader has been recovered.
|
|
|
|
|
So the main remaining uncertainty is the exact higher-level meaning of header bit
|
|
|
|
|
`[descriptor+0x15] & 0x1`, plus whether `[descriptor+0x10]` ever matters outside that
|
2026-04-06 20:36:20 -07:00
|
|
|
preservation path. The route-mode setter is clearer too: `0x595650` now reads as a compact
|
|
|
|
|
state machine over the transport-owned route tables, where mode `0` splits the `gsi_am_rating`
|
|
|
|
|
branch into direct primary-endpoint handling versus queued insertion, mode `1` adds the ready-bit
|
|
|
|
|
gate and the same queued fallback, mode `2` removes pending descriptors from the queued family,
|
|
|
|
|
mode `3` forces mode `2` when the primary-endpoint table is empty, mode `4` updates the deferred
|
|
|
|
|
route-status state around `[this+0x1ed4]` and `[this+0x1ed8]`, and mode `5` copies the staged
|
2026-04-08 16:31:33 -07:00
|
|
|
route companion dword at `[this+0x490]` into `[this+0x54]` while mirroring that value into
|
|
|
|
|
queue-side slot `[this+0x1724+0x24]` through `0x005a0940`. The route-event dispatcher side is cleaner too:
|
2026-04-06 20:34:16 -07:00
|
|
|
the mode-`5` tails in both callback families do not copy a descriptor-local field. They mirror the
|
2026-04-08 16:31:33 -07:00
|
|
|
transport-staged companion dword at `[this+0x490]` into `[this+0x54]` and that same queue-side
|
|
|
|
|
slot instead, not into `[this+0x1778]`. The `gsi_am_rating` maintenance lane is tighter now too: it sorts the
|
2026-04-06 20:34:16 -07:00
|
|
|
primary-endpoint descriptor table through `0x590310` in mode `1` with key `gsi_am_rating`, then
|
|
|
|
|
selects the new head through `0x590480` rather than treating the table as pure insertion order.
|