diff --git a/docs/engine-ctx-reference.md b/docs/engine-ctx-reference.md index fd0b65b..daf71ef 100644 --- a/docs/engine-ctx-reference.md +++ b/docs/engine-ctx-reference.md @@ -99,8 +99,8 @@ Struct `EngineCtx`, size `0xa1000`. Applied to the Ghidra `/v2` image (dispatch- | `0x9c660` | `sys4ini_records` | `void*` | SYS4INI 80-byte record base at embedded FileDB+0x414; record = base + id*0x50 | | `0x9f274` | `mounted_aai_catalogs` | `void*` | base of 256-entry selector-keyed AAI catalog-pointer table inside the embedded FileDB; op 0x143 scans slots 1..255 from +0x9f278 | | `0x9f278` | `mounted_aai_catalog_selector_1` | `void*` | selector-one cell and op 0x143 scan start; subsequent dwords are selector 2..255 | -| `0xa0cc0` | `screen_w` | `int` | screen width (640) | -| `0xa0cc4` | `screen_h` | `int` | screen height (480) | +| `0xa0cc0` | `screen_w` | `int` | logical screen width; constructor/default registry uses 640, then the SYS4INI SCREENX setting overrides it (Himegari 800) | +| `0xa0cc4` | `screen_h` | `int` | logical screen height; constructor/default registry uses 480, then the SYS4INI SCREENY setting overrides it (Himegari 600) | | `0xa0cc8` | `screen_bpp` | `int` | screen bpp (8) | | `0xa0ce4` | `run_state_flags` | `uint` | interpreter run-state flags (bit1 sleeping; 0x8000000 skip/fast-forward) | | `0xa0ce8` | `timed_callback_abort_signal` | `int` | scheduler-polled abort/input signal cleared when op 0xd5 starts; redirects to abort PC when configured | diff --git a/docs/engine-re.md b/docs/engine-re.md index 6d2cc01..3515f03 100644 --- a/docs/engine-re.md +++ b/docs/engine-re.md @@ -146,6 +146,24 @@ decompile `ctx->cur_ctx_index` / `ctx->frame_instruction_word_count` / `ctx->run ## Findings +### Logical screen dimensions come from the SYS4INI settings trailer (resolved 2026-07-24) + +AGE has a compiled fallback, but the shipped game's logical resolution is data-driven. Engine construction +at `0x413860` initializes `EngineCtx.screen_w/screen_h` to `640x480`, and +`engine_settings_register_defaults@0x46be30` independently registers `set:WinX=640` and +`set:WinY=480`. During `engine_load_sys4ini_and_mount_append_catalogs@0x4099f0`, the loader advances past +the archive/file directory and VM-bank metadata into the remaining SYS4INI data, then calls +`engine_apply_sys4ini_settings@0x4056d0`. That routine loads the serialized settings through the engine +settings service and copies `set:WinX`/`set:WinY` into the two context fields before surfaces and the main +window are created. + +The decompressed Himegari SYS4INI trailer explicitly contains `SCREENX=800` and `SCREENY=600`. As an +independent cross-game check, Kamidori's trailer contains `1024x576`. Thus the answer for the logical game +canvas is **SYS4INI per-game data overriding a generic EXE fallback**, not a separately compiled AGE +binary for every resolution. `display:ScreenMode`, `display:FullScreenWidth/Height`, aspect mode, and +related registered settings govern presentation/fullscreen selection separately; they do not redefine the +authored logical canvas. The serialized trailer location is recorded in `sys4-format-notes.md`. + ### ops `0x1a2`/`0x1a3` store and restore shared `SAVE.DAT` integer cells (resolved 2026-07-20) The SCJUMP slice assumed `u00428010` resolved a decision value to a scene. **That premise is wrong**, diff --git a/docs/sys4-format-notes.md b/docs/sys4-format-notes.md index 84856f5..1ae5341 100644 --- a/docs/sys4-format-notes.md +++ b/docs/sys4-format-notes.md @@ -14,6 +14,18 @@ live in `tools/probe_*.py`. > `vm-map/opcodes.toml`. The tag values below (0x71/0x03/0x8F etc.) are the > *opcodes at table targets*: 0x8F=`call`, 0x03=`call-script`, 0x71=`u0041A7B0`. +## SYS4INI directory and per-game settings trailer — CONFIRMED + +`SYS4INI.BIN` is not only the asset catalog. Its `S4IC` LZSS stream begins with the archive names and +80-byte file records documented in `asset-resolution-re.md`, then continues with VM-bank metadata and a +NUL-delimited per-game engine-settings trailer. `tools/parse_sys4ini.py` currently consumes only the +directory prefix. + +The Himegari trailer contains `SCREENX=800` and `SCREENY=600`; Kamidori's independent SYS4INI contains +`SCREENX=1024` and `SCREENY=576`. This establishes the authored logical canvas as per-game data. Native +initialization and the executable's `640x480` fallback are documented in `engine-re.md`; +fullscreen/display-mode settings are a separate concern from these logical dimensions. + ## Header — CONFIRMED Fixed 60-byte (0x3C) header: 8-byte magic + thirteen little-endian u32 fields. diff --git a/tools/parse_sys4ini.py b/tools/parse_sys4ini.py index 995efda..a1eec89 100644 --- a/tools/parse_sys4ini.py +++ b/tools/parse_sys4ini.py @@ -17,7 +17,7 @@ Container format (little-endian x86), signature "S4IC422 " at offset 0: The LZSS stream (GARbro-style: 0x1000 ring buffer, zero-filled, init pos 0xFEE, control bits LSB->MSB, 1=literal, 0=two-byte back-reference: offset=(hi&0xf0)<<4 -| lo, length=3+(hi&0xf)) decompresses to a plain directory: +| lo, length=3+(hi&0xf)) begins with a plain directory: uint32 arc_count { char name[256] } x arc_count archive filenames (DATA1.ALF ..) @@ -26,6 +26,10 @@ control bits LSB->MSB, 1=literal, 0=two-byte back-reference: offset=(hi&0xf0)<<4 uint32 file_number; uint32 offset; uint32 size } x file_count (80 bytes each) +The directory is followed by VM-bank metadata and a per-game engine-settings +trailer. This tool currently emits only the asset directory; see +docs/sys4-format-notes.md for the trailer finding. + Entries whose name is "@" are placeholders and skipped (matches GARbro/exs4alf). Usage: py -3.11 -X utf8 tools/parse_sys4ini.py [--check] diff --git a/vm-map/engine-ctx.toml b/vm-map/engine-ctx.toml index aa70f8e..3b95404 100644 --- a/vm-map/engine-ctx.toml +++ b/vm-map/engine-ctx.toml @@ -476,12 +476,12 @@ note = "selector-one cell and op 0x143 scan start; subsequent dwords are selecto offset = 0xa0cc0 name = "screen_w" type = "int" -note = "screen width (640)" +note = "logical screen width; constructor/default registry uses 640, then the SYS4INI SCREENX setting overrides it (Himegari 800)" [[field]] offset = 0xa0cc4 name = "screen_h" type = "int" -note = "screen height (480)" +note = "logical screen height; constructor/default registry uses 480, then the SYS4INI SCREENY setting overrides it (Himegari 600)" [[field]] offset = 0xa0cc8 name = "screen_bpp"