diff --git a/docs/re/BACKLOG.md b/docs/re/BACKLOG.md index 74135f91..326c9385 100644 --- a/docs/re/BACKLOG.md +++ b/docs/re/BACKLOG.md @@ -204,6 +204,20 @@ unknown, what evidence exists, and what the first step would be. Move an item in corpus insists on proving. 🟡 Still unread: `sub_8226DC80` (kind 1) entirely, and slot 60 past the `t < 0` rejection. +* ✅ **(2026-08-27) THE TRIGGER MECHANISM IS READ END TO END — the kind-1 condition + is the SAME test with a pre-filter. [structures/isl-trigger-node](structures/isl-trigger-node.md).** + `sub_8226DC80` is `sub_8226DAF8`'s twin: diffing instruction by instruction, 33 of + the first 86 differ and **every difference before index 65 is a register rename or a + branch target**. Both resolve the route name (`sub_8217FA08` → `sub_823012D8`), + index `[phase+324]` by `payload+0`, require `rec+100 != 0`, and copy the two 3-double + vectors out of the unit record. Then kind 0 calls vtable slot 60 directly, while + **kind 1 first computes an INLINE point-to-point distance** (three `fsub` against the + route point, `fmul` + two `fmadd`, `fsqrt`) and **returns 0 if it exceeds `f31`, the + same radius** — before calling **the same slot 60**. So both kinds run the identical + point-to-segment test; kind 1 only adds a cheap early-out and does not spawn. + ▶️ Trigger work remaining is peripheral: which unit-record fields A and B are, slot + 60 past the `t < 0` rejection, `payload+8`, and the kind-1 path in the drain. + ## ✅✅ SOLVED — the mission freeze was a modal sign-in dialog (2026-08-26) `XamShowSigninUI` opens a modal dialog and `xeXamDispatchDialog` blocks the diff --git a/docs/re/structures/isl-trigger-node.md b/docs/re/structures/isl-trigger-node.md index f0bd5f4c..88b9975d 100644 --- a/docs/re/structures/isl-trigger-node.md +++ b/docs/re/structures/isl-trigger-node.md @@ -248,13 +248,47 @@ two positions; a previous/current pair would make this the standard frame-rate-robust waypoint test, and that is exactly the kind of tidy reading this corpus makes itself prove. Not proven here. +## ✅ The kind-1 condition is the SAME test with a cheap pre-filter + +`sub_8226DC80` turns out to be `sub_8226DAF8`'s twin. Diffing them instruction +by instruction: of the first 86, 33 differ — and every difference before index 65 +is a register rename or a branch target. Both do exactly the same thing up to +that point: + +* resolve the route name (`sub_8217FA08` → `sub_823012D8`), leaving the route + point in `[r31+112/120/128]`; +* index `[phase+324]` by `payload+0`, require `rec+100 != 0`; +* copy the two 3-double vectors out of the unit record. + +Then they part: + +| | kind 0 — `sub_8226DAF8` | kind 1 — `sub_8226DC80` | +|---|---|---| +| next | calls vtable slot 60 straight away | **inline distance first** | +| | | `fsub` ×3 against the route point, `fmul` + 2 `fmadd`, `fsqrt` | +| | | `fcmpu` vs `f31`; **if > the radius, return 0** | +| then | — | **calls the same vtable slot 60** | + +``` +8226DDC4 fsqrt f0, f0 +8226DDC8 fcmpu cr6, f0, f31 ; f31 = the node's double, the radius +8226DDCC bc 4, gt, return-0 ; too far -> reject without the segment test +8226DDD0 lwz r11, 0(r30) +8226DDE8 lwz r11, 60(r11) ; the SAME slot 60 +8226DDF0 bcctrl +``` + +**So both trigger kinds run the identical point-to-segment test.** Kind 1 adds a +point-to-point early-out against the same radius and, per the drain, does not +spawn. The trigger mechanism is now read end to end. + ## 🟡 Not settled * ~~What the drain actually spawns.~~ ✅ Resolved above: built-in 19's nodes carry a real routine offset at `+28`. * ~~Whether `+24` selects between the two node kinds~~ ✅ It does — see above. -* ~~What the kind-0 condition tests~~ ✅ Read above. **`sub_8226DC80` (kind 1) is - still unread entirely.** +* ~~What the kind-0 condition tests~~ ✅ Read. ~~`sub_8226DC80` (kind 1)~~ ✅ Read — + the same test with an inline distance pre-filter. * **Which unit-record fields A and B are** — `rec+64/72/80` vs `rec+32/40/48`. * **The rest of slot 60** past the `t < 0` rejection (a second constant at `0x820B0000+25192` is loaded next).