Implement root reload and title debug launcher

This commit is contained in:
gamer147
2026-07-20 22:32:49 -04:00
parent df17747f63
commit f21a4c06bf
20 changed files with 1151 additions and 56 deletions

View File

@@ -112,8 +112,8 @@ that is one at context construction and cleared only when op `0x9` resets/reload
SYSTEM4 calls `LOGO.BIN` and `OP.BIN` only while that flag is nonzero. The former stubbed-zero output
explained the direct jump to TITLE. LOGO and OP then use the modal movie op
`0x20f` with raw catalog movies `0x335f`/`LOGO.AGF` and `0x3364`/`OP.AGF`; existing `0x236` is the distinct
non-modal, scene-local movie-to-surface path. The VM now models the initial-root flag and clears it at its
existing op-`0x9` lifecycle boundary. Godot resolves a typed raw MPEG asset, reuses the asynchronous decoder
non-modal, scene-local movie-to-surface path. The VM now models the initial-root flag and clears it at the
op-`0x9` whole-stack root-reload boundary. Godot resolves a typed raw MPEG asset, reuses the asynchronous decoder
and retained compositor, and parks the VM until EOF or mouse/Accept/Cancel input. Focused natural-boot tests
prove `LOGO -> OP -> INIT -> TITLE` ordering and exact movie operands. MPEG audio remains explicitly deferred
until the decoder abstraction has an engine-owned synchronized audio/volume contract.
@@ -124,6 +124,15 @@ Replace the single-SC0000-root assumption with an application-owned session that
SYSTEM4's computed `call-script` is the authoritative scene coordinator: child scenes return to that frame,
while globals, the host, and intentional retained state remain owned by the same live VM session.
**Root-reload boundary implemented (2026-07-20).** Ordinary op `0x2` child exits still return to their
calling SYSTEM4 frame. Op `0x9` is the distinct native reset path: it discards the complete active script
stack, clears scene-owned graphics/input/ADV state, cancels deferred SFX starts while preserving active
audio, preserves global banks and process-owned host state, and starts raw script resource zero
(`SYSTEM4.BIN`) at offset zero. The implementation propagates the boundary
through nested calls without running any caller continuation and records the new root frame with
`FrameCause.RootReload`. Native RE and the one intentional history-lifetime exception are documented in
`docs/engine-re.md`; the history backlog remains preserved until its ownership is proven rather than guessed.
Required responsibilities:
- Own global integer/string banks and any proven external/profile state across scenes.
@@ -134,9 +143,97 @@ Required responsibilities:
- Expose deterministic transition evidence: outgoing scene, reason/decision, incoming scene, and state
summary suitable for tests.
Completion evidence: SYSTEM4 reaches a computed child script in one VM, the child returns to SYSTEM4,
selected globals and system-owned state survive, and script-owned boundary cleanup releases scene-local
presentation state.
Completion evidence now present: SYSTEM4 reaches computed child scripts in one VM; ordinary children return
to SYSTEM4; op `0x9` performs a tested whole-stack reload of SYSTEM4; selected globals and process-owned state
survive; and scene-owned presentation/input state is released. Manual validation of a natural gameplay
route through the first `0x9` remains deferred: Himegari's readily accessible return-to-title choice belongs
to the still-unimplemented frontend exit-request policy, while the other known natural paths require later
gameplay, game over, or completion. Do not use TITLE's currently exposed post-`0x1` developer-menu
fallthrough as evidence; native `0x1` is non-returning. See `docs/engine-re.md`.
**Godot debug scene launcher (2026-07-20; implemented and manually validated).** The first version
is deliberately narrower than arbitrary hot swapping:
- Expose an F4-style Godot overlay only while `TITLE.BIN` is the persistent VM's active SYSTEM4 child.
- Resolve the chosen `.BIN` through the existing SYS4 catalog, then ask the VM to return the current TITLE
child frame with the game-authored coordinator writes (`G[0]=1`, `G[0xaba5c]=-1`, `G[0x62ccf]=0`, and
selected packed id in `G[0x699]`) applied on the VM thread.
- Let SYSTEM4 resume at `0x2b0` and execute its real entry wrapper and computed `call-script`; do not replace
the VM root or call the selected scene directly from Godot.
- Disable switching while another scene is active. That scene must reach its own terminal cleanup and then
either return through SYSTEM4's post-child cleanup or execute its genuine op `0x9`. A separate clean
relaunch remains the escape hatch for a stuck/incomplete scene.
The runtime now has a generic debug-only "return this exact active child frame with queued global writes"
request, thread-safe frame-generation/stack reporting, and the distinct `DebugReturned` trace outcome. TITLE
does not park in ADV op `0x72`: its visible menu continuously polls input and executes a 1 ms op-`0xc8` sleep
at `TITLE@0xe5`. The request therefore targets the observed active frame generation and is consumed by the
VM thread at its next completed opcode boundary, before another TITLE opcode can execute. `SignalInput` is
used only if the target happens to be in a real ADV wait, avoiding a stale signal that could advance the
selected child. Synthetic coordinator tests cover both an ADV wait and TITLE's sleep/poll shape, selected-
child dispatch, ordinary SYSTEM4 continuation, stale/ineligible request rejection, and selected-child
op-`0x9` whole-stack propagation.
This launcher would provide the real visible TITLE→selected scene sequence and preserve the coordinator
boundary, but it cannot manufacture valid late-game state. The current direct harness and opcode coverage
suggest early ADV scenes and `DEBUG.BIN` are plausible targets; later scenarios, GAMECLEAR, battle/map, and
profile-dependent scripts may still require progression data or missing opcodes. A startup-only/direct-scene
selector is cheaper, but it is merely a UI for `--scene ... --boot` and provides no transition-lifecycle
evidence. An unrestricted in-process switch would additionally require VM cancellation, task joining,
movie/audio disposal, locator/trace regeneration, and an explicit global-state policy, so it is not a quick
or trustworthy first version.
**Menu population and selection contract.** The runtime SYS4 catalog—not `build/` inventory—is the
source of truth. Himegari currently has 481 unique base-catalog `.BIN` records: 136 `SC####`, 164 `SP*`, 8
`DEBUG*`, 29 initializer-named scripts, and 144 other named scripts. Each menu row keeps the packed resource
id as its identity and carries display name, pack selector, raw index, archive, size, and category; names are
labels rather than keys so future append-pack collisions remain representable. Population should enumerate
base `Catalog.Files` plus every mounted append catalog, exclude placeholders/non-BIN records, and compute
`packed_id = (pack_id << 24) | raw_index` without parsing all scripts up front. The selected script is decoded
and validated only when Launch is pressed; an unsupported decode reports an error and leaves TITLE running.
The currently mounted append pack contributes 39 additional `.BIN` records, so the shipped launcher smoke
test sees 520 distinct packed script ids.
The initial UI groups entries rather than implying every BIN is a standalone scene:
- **Scenario:** `SC####.BIN`, naturally sorted by number.
- **Secondary/event:** `SP*.BIN`, naturally sorted by name and suffix.
- **Debug:** `DEBUG*.BIN`.
- **Other/expert:** every remaining script; the separate **All** filter includes every category. Initializers,
callbacks, data routines, and modal UI scripts may require caller-owned state and may immediately return
or corrupt the live session.
`SYSTEM4.BIN` and `TITLE.BIN` are not launchable in the first version; recursively dispatching either through
SYSTEM4's child slot is not a scene test. Search is case-insensitive over name and hexadecimal/decimal packed
id. The detail pane shows name, category, packed/raw id, archive, size, and the fixed warning that launch uses
the current live global/profile state. Compatibility or opcode-gap badges are deferred until coverage logic
has an engine-owned runtime API; the menu must not parse generated Markdown or call Python tooling.
The implementation should leave one explicit extension point for future test sequences:
`DebugLaunchPreset(label, packed_script_id, extra_global_writes, note)`. Catalog rows use only the four
coordinator writes above; profile-authored presets may later add proven story/progression globals without
turning the menu into a free-form state editor or save backend. Arbitrary PC/offset jumps are out of scope.
**Implementation order.** (1) Add catalog script-entry enumeration with packed ids and unit coverage for
base/append mounts, placeholders, duplicate names across packs, and category/sort/filter behavior. (2) Add a
generic VM debug request targeted at an exact active frame generation; it applies an immutable set of global
writes on the VM thread and returns that child at the next opcode boundary. Test SYSTEM4→TITLE→selected child,
ordinary child return/cleanup continuation, op-`0x9` propagation, TITLE's sleep/poll loop, and stale/ineligible
request rejection. (3) Add the Godot F4 overlay (`PopupPanel`, search/category controls, `ItemList`, detail
pane, Launch/Cancel), consume all overlay input, and enable Launch only for the active `SYSTEM4 > TITLE`
stack. (4) Add a Godot smoke test for catalog population and request wiring, then
manually validate `TITLE -> DEBUG -> 0x9 -> SYSTEM4 -> TITLE` before expanding the selectable categories or
adding presets.
Steps 14 are complete. F4 opens the Godot `PopupPanel` only for the exact active
`SYSTEM4.BIN > TITLE.BIN` stack; search, category filters, packed-id metadata, guarded Launch, and Cancel are
live. `SYSTEM4.BIN` and `TITLE.BIN` remain visible but unlaunchable. While the panel is open, AGE gameplay
input is not forwarded. Launch reparses the selected packed id before queuing any writes. The threaded Godot
selftest constructs the catalog and panel and currently reports 520 unique packed scripts. Manual validation
confirmed `TITLE -> F4 -> DEBUG.BIN`: its four scripted ADV pages at `0xc7`, `0x110`, `0x17b`, and `0x1ed`
were presented, its terminal op `0x9` at `0x1fb` ran, and SYSTEM4 reconstructed the visible TITLE menu. No
launcher/session-lifecycle discrepancy was observed. DEBUG-specific content oddities are not acceptance
failures for this developer route and remain out of scope unless they reproduce in a normal game script.
## Stage B2 — Faithful full boot