From 70df1c3a1bbfc091211e01badc4a44727afc44c6 Mon Sep 17 00:00:00 2001 From: Sylpheed RE agent Date: Thu, 27 Aug 2026 08:14:24 +0000 Subject: [PATCH] re: the kind-1 trigger condition is the same test with a pre-filter -- mechanism read end to end sub_8226DC80 turns out to be sub_8226DAF8's twin. Diffing them 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), leaving the route point in [r31+112/120/128]; * index [phase+324] by payload+0 and require rec+100 != 0; * copy the two 3-double vectors out of the unit record. They part at index 65. Kind 0 calls vtable slot 60 immediately. Kind 1 instead computes an inline point-to-point distance first -- three fsub against the route point, fmul plus two fmadd, fsqrt -- and rejects when it exceeds f31, the same radius: 8226DDC4 fsqrt f0, f0 8226DDC8 fcmpu cr6, f0, f31 8226DDCC bc 4, gt, return-0 8226DDE8 lwz r11, 60(r11) ; then the SAME slot 60 8226DDF0 bcctrl So both trigger kinds run the identical point-to-segment test; kind 1 only adds a cheap early-out against the same radius, and per the drain it does not spawn. Diffing the two functions rather than reading the second one cost one query and made the relationship obvious -- the same move that resolved the six ISL branch handlers. All artefacts regenerate byte-identical; documentation only. What remains on triggers 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. --- docs/re/BACKLOG.md | 14 ++++++++++ docs/re/structures/isl-trigger-node.md | 38 ++++++++++++++++++++++++-- 2 files changed, 50 insertions(+), 2 deletions(-) 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).