This repository has been archived on 2026-09-16. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
Syplheed-Reborn/docs/re/menu-state-in-memory.md
Sylpheed RE agent 534da24658 re: find the menu screen id and cursor in guest memory
Menu navigation here has always been screenshot-driven, which is unusable under
--gpu=null -- the only configuration where the game does not hit the
software-rasterizer freeze.  Without a memory signal, the one backend that runs
is the one that cannot be steered.

Snapshotting 0x82800000+3 MB at each menu of a rendered run and keeping the
4-byte words that differ between screens and hold small integers leaves exactly
four of 786 432.  One has the property that matters -- it changes on a screen
transition and holds steady when only the highlight moves:

    0x828A690C  screen id     1 title, 3 main menu, 4 extras
    0x828F38AC  menu cursor   (second copy at 0x828F38BC)
    0x828F37B4  per-menu value

Verified on a fresh --gpu=null run with no display at all, driving the same keys
blind: title 1/2/12, main menu 3/4/45, after 4x down 3/12/45, extras 4/14/49 --
4/4 exact against the rendered run, across two runs and two GPU backends.  That
is the check that matters, since this corpus has already had to mark one runtime
address run-dependent.

tools/re-capture/menu_state.py reads them; `menu_state.py watch` prints on
change.

Open: the rest of the sequence into a mission.  Blind driving reached extras
(screen 4) and a further A did not move it, so MISSION SELECT needs a cursor
move first.  Screen ids beyond 4 are unmapped, and the rendered run freezes on
entering that screen -- so map ids up to the freeze, then step blind past it.
2026-08-26 18:21:04 +00:00

56 lines
2.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# The menu's screen id and cursor, in guest memory
**✅ Found and verified 2026-08-26.** Menu navigation in this corpus has always
been driven by screenshots. That is unusable under `--gpu=null`, which is the
only configuration where the game does not hit the software-rasterizer freeze
([`mission-freeze-heap-exhaustion.md`](mission-freeze-heap-exhaustion.md)) — so
without a memory signal, the one backend that runs is the one that cannot be
steered.
## The words
| address | meaning |
|---|---|
| **`0x828A690C`** | **screen id**`1` title, `3` main menu, `4` extras |
| **`0x828F38AC`** | **menu cursor** (a second copy at `0x828F38BC`) |
| `0x828F37B4` | tracks the screen, distinct value per menu |
## How they were found
Snapshot `0x82800000` + 3 MB at each menu of a **rendered** run, then keep the
4-byte words that (a) differ between screens and (b) hold small integer values.
Of 786 432 words, exactly **four** qualified — and one of them,
`0x828A690C`, has the property that matters: it changes on a screen *transition*
and stays put when only the highlight moves.
screen: title -> main menu -> (4x down) -> extras
828a690c: 1 -> 3 -> 3 -> 4 <- screen id
828f38ac: 2 -> 4 -> 12 -> 14 <- cursor moves with the highlight
828f37b4: 12 -> 45 -> 45 -> 49
## ✅ Verified against a second run on a different GPU backend
The values were then read on a fresh `--gpu=null` run — **no display at all**
while driving the same key sequence blind:
| step | rendered (lavapipe) | blind (`--gpu=null`) |
|---|---|---|
| title | 1 / 2 / 12 | **1 / 2 / 12** |
| main menu | 3 / 4 / 45 | **3 / 4 / 45** |
| after 4× down | 3 / 12 / 45 | **3 / 12 / 45** |
| extras | 4 / 14 / 49 | **4 / 14 / 49** |
**4 / 4 exact**, across two runs and two backends. That is the check that matters:
the words are not run-dependent, unlike the OB counter address this corpus had to
mark run-dependent earlier.
`tools/re-capture/menu_state.py` reads them (`menu_state.py watch` polls and
prints on change).
❔ Still open: the rest of the sequence into a **mission**. Blind driving reached
`extras` (screen 4) and a further Ⓐ did not move it — `4 / 14 / 49` twice — so
MISSION SELECT needs a cursor move first. The screen ids beyond 4 are unmapped;
the same snapshot-and-diff method extends to them, but it must be done on a
rendered run, and the rendered run **freezes on entering that screen**. The way
through is to map the ids up to the freeze and step blind past it.