re: trigger queue layout at phase+272, and a readable pending count
Chasing what makes the phase-1 condition re-evaluate, since the polls do not run continuously. Two method corrections: searching the VM range for '272(rN)' mostly returns VTABLE slot offsets -- 0x82273174 lwz r11,272(r11) is followed by mtctr/bctrl, a virtual call through slot 68, not an access to the phase field. And [phase+272] is not a pointer to a queue but an EMBEDDED container: vt2 (sub_82265DD0) is 'addi r3,r3,272 ; b 0x8226E3B8', passing phase+272 as this. Layout from the push/pop pair (sub_8226E3B8 from built-in 100, sub_8226E220 called every frame from sub_8226D740): +12 list head, +16 current node, +20 element count (zero = empty, tested first by the pop), +24 scratch. The pop returns the record through out-parameters read from node+8: three u32s, a double at +16, another u32 at +24 -- matching the six pointers sub_8226D740 passes in. The actionable part is [phase+272+20], a live pending-trigger count readable from /dev/shm. Watching it alongside [ScriptMission+40] should show when the engine hands the script an event, which is when condition coroutines start -- the thing every phase experiment so far has been blind to. Layout is from disassembly only; not yet verified live.
This commit is contained in:
@@ -230,3 +230,44 @@ facts — the *identifications* (which built-in does what) have held up well.
|
||||
slots, by simulating the constant/stack dataflow of `sub_822FE040`.
|
||||
* Names here are from handler behaviour, not from symbols; `isl.py` prints a bare
|
||||
`builtinN` for anything unread rather than guessing.
|
||||
|
||||
## ✅ The trigger queue at `phase+272` — layout, and a readable pending count
|
||||
|
||||
Chasing what makes the phase-1 condition re-evaluate (the polls do **not** run
|
||||
continuously — see [script-runtime-probe](../script-runtime-probe.md)).
|
||||
|
||||
**Two method corrections first**, because both nearly sent me the wrong way:
|
||||
|
||||
* Searching the VM's address range for `272(rN)` returns mostly **vtable slot
|
||||
offsets**, not accesses to the phase field. `0x82273174 lwz r11,272(r11)` is
|
||||
followed by `mtctr; bctrl` — it is a virtual call through slot 68, nothing to
|
||||
do with `[phase+272]`.
|
||||
* `[phase+272]` is **not a pointer to a queue** — it is an **embedded container**.
|
||||
`vt2` (`sub_82265DD0`) is literally `addi r3,r3,272 ; b 0x8226E3B8`, i.e. it
|
||||
passes `phase+272` as `this` into the push.
|
||||
|
||||
### Container layout, from the push/pop pair
|
||||
|
||||
`sub_8226E3B8` (push, reached from built-in **100**) and `sub_8226E220` (pop,
|
||||
called every frame from `sub_8226D740`):
|
||||
|
||||
| offset in the container | meaning |
|
||||
|---|---|
|
||||
| `+12` | list head/sentinel (`addi r31, r30, 12`) |
|
||||
| `+16` | current node pointer |
|
||||
| `+20` | **element count — zero means empty**; the pop tests it first and returns 0 |
|
||||
| `+24` | scratch: the popped node is stashed here |
|
||||
|
||||
The pop hands the record out through **out-parameters**, reading from
|
||||
`node+8`: `+0`, `+4`, `+8` as `u32`s, `+16` as a `double`, `+24` as another
|
||||
`u32` — which matches `sub_8226D740` passing six pointers into local slots.
|
||||
|
||||
### 🎯 `[phase + 272 + 20]` is a live "pending triggers" counter
|
||||
|
||||
That is the useful part: a single `u32` that says how many triggers are queued,
|
||||
readable from `/dev/shm` with no debugger. Watching it alongside
|
||||
`[ScriptMission+40]` should show **when** the engine hands the script an event —
|
||||
which is exactly the moment the condition coroutines get started, and the thing
|
||||
every phase experiment so far has been blind to.
|
||||
|
||||
**Not yet verified live.** The layout above is read off the disassembly only.
|
||||
|
||||
Reference in New Issue
Block a user