re: the ScriptPhase vtable is 113 slots, and there is a SilphScriptPhaseDemo

RTTI at vtable[-1] names the class .?AVSilphScriptPhase@silph@@ and the
next class's COL at 0x820A8680 terminates the table at 113 entries.
The earlier ">=200 slots" reading used a bad terminator -- scanning for
a non-code word runs straight into the next vtable.  Cross-check: the
147 built-in stubs use 109 distinct slots, min 0 max 110.

The next vtable is .?AVSilphScriptPhaseDemo@silph@@, also 113 slots,
overriding 109 of them with mostly one shared stub -- a cut-down phase.
That explains why sub_822710D0 has two callers: sub_82263408 and
sub_82275800 are the two classes' Update, both slot 111.

Both "unread spawner callers" are placed: sub_82264058 is slot 0 of
SilphScriptPhase and sub_82273910 is slot 0 of the Demo class -- the two
destructors.

Also records a negative: the Stage%02d construction site I proposed last
iteration does not exist (no stage format string among the 43 short %d
strings; no precomputed name hash anywhere), so the stage-index lead
cannot be settled that way.

Docs only; artefacts byte-identical.
This commit is contained in:
Sylpheed RE agent
2026-08-27 10:05:01 +00:00
parent 6213825a2f
commit 044b98dcc4
3 changed files with 95 additions and 5 deletions

View File

@@ -502,6 +502,38 @@ unknown, what evidence exists, and what the first step would be. Move an item in
found this pass, and `grep`ping the extracted disc does not help — the pak names
are hashed, so neither `Stage16` nor `Stage17` appears as a plain token.
* ✅✅🔴 **(2026-08-27) THE VTABLE IS 113 SLOTS, THE CLASS IS
`silph::SilphScriptPhase`, THERE IS A SECOND ONE — and the test I proposed last
iteration does not exist. [structures/isl-builtin-dispatch](structures/isl-builtin-dispatch.md).**
🔴 **Dropped first, honestly:** the plan was to settle the stage-index lead at
the `Stage%02d` construction site. **There isn't one.** The `'%s%02d'` at
`0x820A9C8C` has one xref into a generic string helper; listing *every* short
`%d` string in the image (43) finds no stage pattern; and the `name_hash` of
`Stage_S00…30` / `Stage00…30` / `UnitGroup_S00…30` appears **nowhere as a 4-byte
word**. The executable never builds a stage script name — the mapping is on the
data side. **Do not retry this route.**
**Vtable LENGTH settled: 113 slots (0…112).** The RTTI locator at
`vtable[-1]` = `0x820A84B8` → type descriptor `0x8289CD18` =
**`.?AVSilphScriptPhase@silph@@`**. ⚠️ The earlier "≥200 slots, no non-code word
in the first 200" was a **bad terminator** — the scan ran into the next vtable.
The real terminator is the next class's COL at `0x820A8680`. Independent
cross-check: the 147 built-in stubs use **109 distinct slots, min 0, max 110**
all inside 0…112.
**A SECOND class: `silph::SilphScriptPhaseDemo`** (`0x8289CCC0`), vtable
`0x820A8684`, also 113 slots, **overriding 109 of them** — nearly all pointing at
one shared stub `0x8226C160`. The Demo phase implements almost none of the script
surface, keeping slot 15 → `sub_82391BA8`, slot 111 `Update``sub_82275800`,
slot 112 → `sub_8237EF08`.
🔑 **That closes a loose end from the timers work**: `sub_822710D0` (the
stopwatch advance) has two callers, `sub_82263408` and `sub_82275800` — they are
the two classes' `Update`, same slot 111, base and derived.
**And both "unread spawner callers" are placed**`sub_82264058` is
`SilphScriptPhase` **slot 0** and `sub_82273910` is `SilphScriptPhaseDemo`
**slot 0**: the two scalar deleting destructors, a matched pair rather than two
mysteries. 🟡 Why a destructor reaches the spawner is not read.
🟡 Still open: `X+12`'s domain — the one remaining static handle is another hop,
to whatever the GamePartTask manager passes into `GamePart_MainGame` slot 4.
## ✅✅ SOLVED — the mission freeze was a modal sign-in dialog (2026-08-26)
`XamShowSigninUI` opens a modal dialog and `xeXamDispatchDialog` blocks the