diff --git a/docs/re/structures/ui-screen-runtime.md b/docs/re/structures/ui-screen-runtime.md new file mode 100644 index 00000000..9bbf8d96 --- /dev/null +++ b/docs/re/structures/ui-screen-runtime.md @@ -0,0 +1,87 @@ +# The UI screen object at runtime — found in live guest memory + +**Status:** ✅ `CONFIRMED` for the object's identity and its element array (five +independent field matches against the file, on a running game). 🟡 the remaining +arrays are unidentified. ❔ nothing here settles the paint order — see the +"what this does not answer" section, which is the reason the search happened. + +## How it was found, in one step + +The item class from the emulator-era splash work has vtable **`0x820b30b4`**, and +`sub_823C2990` allocates its objects at **244 bytes** each +([`ui-quad-class-foothold.md`](../ui-quad-class-foothold.md)). A vtable pointer +is a fixed 4-byte value at offset 0 of every instance, so the objects are +findable in the live guest image without a debugger: + +```bash +tools/re-capture/gmem.py find hex:820b30b4 # while the title screen is up +``` + +Seven live objects, at `0xBCD24D88`, `0xBCD25188`, `0xBCD25388`, `0xBCD25488`, +`0xBCD25588`, `0xBCD25688`, `0xBCD26488` — spaced 0x100 apart, consistent with a +244-byte object plus allocator overhead. + +## What they are + +Each object begins with **two** vtable pointers (`0x820b30b4`, `0x820b31a4` — +multiple inheritance) and then a run of `{pointer, count, capacity}` triplets. +The counts identify the objects immediately: + +| object | first triplet's count | which `GP_TITLE` build | +|---|---|---| +| `0xBCD25188` | **7** | builds 0/1 — the loading overlay (7 elements) | +| `0xBCD25388` | **24** | **build 4 — the title (24 elements)** | +| `0xBCD24D88` | **1** | builds 2/3 — the `PRESS Ⓐ BUTTON` bundle (1 element) | + +So the three bundles this project decoded statically are all resident, with the +element counts the files declare — including the two-bundle composition of the +title screen that the draw capture inferred. + +## The element array + +`+0x08` of the screen object is `{ptr, count, capacity}` pointing at an array of +**48-byte entries, one per element, in declaration order**. Verified field-by-file +at five positions on the title build, with no misses: + +| index | file says (build 4) | live memory at `+0x10`/`+0x14` | +|---|---|---| +| 0 | `ptlogo1.t32` pivot (451,50) | 451.0, 50.0 | +| 1 | `ptlogo2.t32` pivot (449,46) | 449.0, 46.0 | +| 6 | `pteff01.t32` pivot (320,160) | 320.0, 160.0 | +| 9 | `ptbase2.t32` pivot (320,180) | 320.0, 180.0 | +| 21 | `ptcopyright.t32` pivot (309,10) | 309.0, 10.0 | + +Entry layout as far as it is read: + +``` ++0x00 u32 pointer (per-element data) ++0x04 u32 0 ++0x08 u32 flags (0x10081021 on element 0) ++0x0C u32 ? ++0x10 f32 pivot X ← the declaration entry's pivot, as a FLOAT ++0x14 f32 pivot Y ++0x18 u32 0 ++0x1C u32 ? ++0x20 u32 pointer } ++0x24 u32 count } the element's KEYFRAMES — 8/8 on elements 0 and 1, ++0x28 u32 capacity } which is exactly their keyframe count in the file ++0x2C u32 ? +``` + +So the pivot and the keyframe group, which this project reads out of the bundle, +are present at runtime in the same order and with the same values. + +## What this does not answer + +**The paint order.** The array is in *declaration* order, and the capture proves +the screen is not painted in that order, so the renderer either walks something +else or sorts. Three more `{ptr,count,capacity}` triplets are present in the +screen object and unidentified — `+0x14` (24 entries of 12 bytes, each +`{ptr,1,1}`, pointing into a densely packed region), `+0x24` (2 entries) and +`+0x30` (24). The `+0x14` one is *not* an index list (its entries are pointers, +not small integers), so the obvious "draw order table" reading is already out. + +**What is better than before:** the question is now a *data* question on a live +structure that can be dumped in seconds, rather than a code-reading exercise. The +next probe is to dump `+0x24` and `+0x30` on the title build and see whether +either is 24 entries in a non-declaration order.