docs+tools: screen_children.py, validated; the third paint order is blocked on input
screen_children.py walks every resident screen object (vtable 0x820b30b4), reads the element array at +0x08 and the child array at +0x30, and prints the paint permutation with each pivot. Validated in one run off the live title: it reproduces BOTH previously measured orders character-for-character - the splash [0,2,4,6,1,3,5] and the 24-element title permutation - so the next screen it is pointed at can be trusted. The screen that matters was not reached. GP_DIALOG DIFFICULTY carries exactly one primitive and would say whether the game paints it first or last, which is the bit that decides where primitives belong. But (A) does not advance the title screen at holds of 0.10, 0.25 or 0.40s, and neither does START, with the pad verified end to end: pad.py writes /tmp/xenia_pad.txt, the emulator runs with --hid=file --pad_file pointing at it, and the mtime updates on every press. The title is unambiguously the interactive one - PRESS (A) BUTTON is rendered. Recorded as a blocker rather than worked around. Next step is specific: boot with the emulator stdout kept and read the [RE-INPUT] IsUIActive log already present on the canary branch, which would say whether the keystroke is being swallowed emulator-side.
This commit is contained in:
@@ -117,6 +117,18 @@ See [`structures/ui-composable-bundles.md`](structures/ui-composable-bundles.md)
|
||||
screen carrying exactly one primitive — the `GP_DIALOG` DIFFICULTY box, which
|
||||
is reachable from the main menu, would say whether its dim is first or last.
|
||||
This is a runtime child-list read, so it is an emulator item, not a static one.
|
||||
🔴 **ATTEMPTED 2026-08-19 and BLOCKED.** The reader
|
||||
(`tools/re-capture/screen_children.py`) is written and validated — it
|
||||
reproduces both known permutations character-for-character off the live title.
|
||||
The screen could not be reached: **Ⓐ does not advance the title screen** at any
|
||||
hold from 0.10 s to 0.40 s, nor does START, with the pad verified end to end.
|
||||
Two harness bugs were found and fixed on the way (`--audio` is not a cvar and
|
||||
broke eight boot scripts; `vgamepad` no longer exists but `skip_intro.sh`
|
||||
still called it, pressing nothing while exiting 0). Neither unblocks the title.
|
||||
Next step: boot with the emulator's stdout **kept** and check the
|
||||
`[RE-INPUT] XamInputGetKeystrokeEx swallowed by IsUIActive` log already in the
|
||||
canary branch. See
|
||||
[`ui-paint-order-third-permutation.md`](ui-paint-order-third-permutation.md).
|
||||
* ❔ **Blend mode.** Everything is straight alpha-over. The near-white flash
|
||||
quads (`0xf0ffffff`) and coloured ones (`0x60ff0000`) may be additive. The
|
||||
title capture cannot separate the two — its resting elements are all
|
||||
|
||||
98
docs/re/ui-paint-order-third-permutation.md
Normal file
98
docs/re/ui-paint-order-third-permutation.md
Normal file
@@ -0,0 +1,98 @@
|
||||
# A third measured paint order — tool built and validated, screen not reached
|
||||
|
||||
**Status:** ✅ the reader works and is `CONFIRMED` against both previously
|
||||
measured screens. 🔴 **BLOCKED** on the emulator: Ⓐ does not advance the title
|
||||
screen, so `GP_DIALOG`'s DIFFICULTY box — the screen that would answer the
|
||||
question — was never reached. Two harness bugs were found and fixed on the way.
|
||||
|
||||
## Why a third permutation
|
||||
|
||||
Drawing the `.prm` primitives is implemented and measurably right on the title,
|
||||
but it is off by default because **nothing derives where a primitive paints**
|
||||
([`structures/ui-prm-primitives.md`](structures/ui-prm-primitives.md)). A
|
||||
primitive has no `T8aD` header, hence no layer key, and the two screens read off
|
||||
the running game disagree about the answer: the splash paints its primitive
|
||||
first, the title paints one at slot 4 and another last.
|
||||
|
||||
`GP_DIALOG`'s DIFFICULTY box carries **exactly one** primitive, `pceff00.prm`, a
|
||||
50 % black dim. Whether the game paints it first (dimming what is behind the
|
||||
dialog) or last (dimming the dialog too) is a single bit that would discriminate
|
||||
between the candidate rules. It is reachable from the main menu: NEW GAME.
|
||||
|
||||
## The reader
|
||||
|
||||
`tools/re-capture/screen_children.py` walks every resident screen object
|
||||
(vtable `0x820b30b4`), reads the element array at `+0x08` (48-byte records,
|
||||
declaration order) and the child array at `+0x30` (pointers to those records,
|
||||
**paint** order), and prints the permutation with each element's pivot — which is
|
||||
what identifies the build in the file.
|
||||
|
||||
**Validated against both known-good screens in one run, off the live title:**
|
||||
|
||||
```
|
||||
== object 0xbcd25288: 7 elements, 7 children
|
||||
pivots: 0:(640,360) 1:(250,36) 2:(260,46) 3:(120,44) 4:(130,55) 5:(194,68) 6:(204,78)
|
||||
paint order: [0, 2, 4, 6, 1, 3, 5]
|
||||
|
||||
== object 0xbcd25488: 24 elements, 24 children
|
||||
paint order: [9, 11, 12, 10, 13, 6, 20, 19, 14, 15, 18, 16, 17, 0, 2, 4, 7, 1, 3, 5, 22, 23, 21, 8]
|
||||
```
|
||||
|
||||
Both are **character-for-character** what
|
||||
[`structures/ui-screen-runtime.md`](structures/ui-screen-runtime.md) recorded
|
||||
from the hand-driven read. So the next screen this is pointed at can be trusted.
|
||||
|
||||
## Two harness bugs found on the way
|
||||
|
||||
Both fail in ways that look like the *game* misbehaving.
|
||||
|
||||
**`--audio` is not a cvar**, and eight boot scripts passed it. Xenia calls
|
||||
`ShowSimpleMessageBox` from `ParseLaunchArguments`, *before* logging is
|
||||
initialised, so the symptom is a 10×10 window, an empty log, no guest memory, and
|
||||
a dialog blocking on `XIfEvent` forever — which reads as a hang deep in the
|
||||
emulator. `run-canary`'s own header documents this trap; the scripts predate it.
|
||||
Fixed in all eight, and the boot now reaches the title.
|
||||
|
||||
**`vgamepad` no longer exists.** The uinput pad was replaced by the `--hid=file`
|
||||
driver plus `pad.py`, but `skip_intro.sh` still called `vgamepad tap A 250`. The
|
||||
script runs without `set -e`, so the call failed silently and the title branch
|
||||
pressed **nothing** while still `exit 0` — reporting "TITLE → A" with the game
|
||||
sitting on the title. Now presses through `pad.py` and exits 6 if that fails.
|
||||
|
||||
That second bug looked like it would explain the standing "Ⓐ at the title works
|
||||
about half the time" note. **It does not.** See below.
|
||||
|
||||
## 🔴 The blocker: Ⓐ does not advance the title
|
||||
|
||||
With the pad verified end to end — `pad.py` writes `/tmp/xenia_pad.txt`, the
|
||||
emulator was launched with `--hid=file --pad_file=/tmp/xenia_pad.txt`, and the
|
||||
file's mtime updates on every press — the title screen does not advance:
|
||||
|
||||
| press | hold | result |
|
||||
|---|---|---|
|
||||
| Ⓐ ×2 | 0.10 s | still title |
|
||||
| Ⓐ | 0.25 s | still title |
|
||||
| Ⓐ ×5 | 0.40 s | still title |
|
||||
| START | 0.30 s | still title |
|
||||
|
||||
The screen is unambiguously the interactive one — PRESS Ⓐ BUTTON is rendered
|
||||
([capture](captures/title-with-press-a-live.png)). So the input path is wired and
|
||||
the game is waiting for a press it never sees.
|
||||
|
||||
The most likely suspect is already instrumented but was not captured this run:
|
||||
the `[RE-INPUT] XamInputGetKeystrokeEx swallowed by IsUIActive` log added to
|
||||
`xam_input.cc` on the canary branch. `boot_menu.sh` sends the emulator's stdout
|
||||
to `/dev/null`, so nothing was recorded. **That is the first step next time:**
|
||||
boot with stdout kept and check whether the keystroke is being swallowed, which
|
||||
would make this an emulator-side bug rather than a game-side one.
|
||||
|
||||
## What is not settled
|
||||
|
||||
* 🔴 The third permutation itself. The tool is ready; the screen is not reachable.
|
||||
* ❔ Whether Ⓐ ever worked at this title screen, or whether the "half the time"
|
||||
note was always the silent `vgamepad` failure plus chance. The `vgamepad` bug
|
||||
is now excluded, and the title still does not advance, so something else is
|
||||
wrong.
|
||||
* ❔ Only **one** screen object was resident at the moment the main menu was
|
||||
believed to be up (the splash), where the title has seven. Unexplained, and
|
||||
possibly a symptom of the same thing — the menu may never have loaded.
|
||||
Reference in New Issue
Block a user