Mount SYS4 append asset catalogs
This commit is contained in:
@@ -166,7 +166,7 @@ The current Phase-A backend deliberately continues through the extracted-file bo
|
||||
accepts both OGG and WAV and Godot loads the WAV bytes into its fixed SC0000 channel pool. This does not change
|
||||
the scoped VFS plan below: ALF/AAI mounting and in-process asset reads remain a separate foundation track.
|
||||
|
||||
## Runtime asset-VFS track (VFS-A and VFS-C complete 2026-07-11)
|
||||
## Runtime asset-VFS track (VFS-A/B/C complete 2026-07-11)
|
||||
|
||||
The pre-extracted tree and `build/textures/*.BMP` pipeline were a Phase-A bootstrap, not the desired final
|
||||
runtime. The native-compatible target is a read-only virtual filesystem that preserves AGE's translation/mod
|
||||
@@ -194,11 +194,16 @@ store.
|
||||
`call-script` targets through this seam; `ResourceMap` uses the same live catalog. `build/asset-index.json`,
|
||||
`build/asset-sections.json`, `build/callscript-names.json`, and `extracted/` are validation/temporary
|
||||
graphics-audio artifacts, not script-runtime dependencies.
|
||||
2. **AAI append mount.** Parse the installed `APPEND01.AAI` (`S4AC422`) and its paired `APPEND01.ALF` with
|
||||
the same catalog abstractions. First prove whether Himegari joins append records by a separate pack/tag,
|
||||
by name replacement, or by another table selected by the native high-byte-id path; do not invent mount
|
||||
precedence. Validate every parsed append entry against `BinExtractALF.exe` output before exposing it to
|
||||
the runtime.
|
||||
2. **AAI append mount (VFS-B DONE).** `Sys4AssetCatalog` also parses the installed `APPEND01.AAI`
|
||||
(`S4AC422`) and mounts its paired `APPEND01.ALF`. This is a separate selector-keyed catalog, not a
|
||||
filename overlay: AGE scans `*.AAI`, reads the selector at AAI header offset `0x108`, and stores the
|
||||
successfully loaded catalog in `mounted_aai[selector]`. A resource id with a nonzero high byte selects
|
||||
that slot; its low 24 bits index only the selected append table. Installed `APPEND01` is selector 1.
|
||||
Within that catalog the ordinary exact loose-record-name then ALF-range precedence still applies, so the
|
||||
literal `$1$...` names are preserved. A later successfully enumerated AAI with the same selector replaces
|
||||
the earlier pointer in the native loop; no base/append name replacement occurs. Native extracts the
|
||||
selector with arithmetic `SAR 24`; the port rejects sign-bit selectors rather than guessing behavior for
|
||||
ids that would index before AGE's mount table.
|
||||
3. **AGF decoder (VFS-C DONE).** `Age.Engine/Sys4/AgfDecoder.cs` decodes an opened AGF payload directly
|
||||
to a tightly packed, top-down width/height + RGBA8 surface. The MIT-licensed GARbro
|
||||
`ArcFormats/Eushully/ImageAGF.cs` provides a compact reference: `ACGF` (or zero) signature, type 1/2,
|
||||
@@ -246,8 +251,15 @@ Five installed assets spanning raw/compressed metadata and pixel/alpha combinati
|
||||
800×300 with intermediate alpha values, and is inherited in surface slot 17 before SC0000. A windowed
|
||||
page-1 capture with `build/textures/` moved aside showed the translucent textbox edge and bottom-right
|
||||
controls. Texture runtime no longer consults `extracted/` or `build/textures/`; current audio consumers
|
||||
still use extracted OGG/WAV paths by design. APPEND01/AAI, audio migration, and movie `0x236` remain
|
||||
unimplemented by this slice.
|
||||
still use extracted OGG/WAV paths by design. Audio migration and movie `0x236` remain unimplemented.
|
||||
|
||||
VFS-B passes its bounded gates in `Sys4AssetStoreTests`: the installed AAI expands from the LZSS stream at
|
||||
`0x118` (expanded size at `0x110`, packed size at `0x114`) to one `APPEND01.ALF` archive and 81 80-byte
|
||||
records. All records carry selector 1 and literal `$1$` names. The full directory has stable SHA-256
|
||||
`23F0C104A45C099CEFB7D333362716EDE6F20B9EC53E4C3705A8E3A87063708E` over its ordered record fields.
|
||||
The integration gate runs `BinExtractALF.exe` into a disposable directory, compares all 81 names, validates
|
||||
every range and size, and byte-compares all 81 payloads. `Sys4ScriptProvider` resolves a real append script
|
||||
through `0x01xxxxxx`; direct base-name lookup deliberately does not see append records.
|
||||
|
||||
### Deliberate non-goals
|
||||
|
||||
|
||||
@@ -1045,6 +1045,25 @@ includes the scene's own early writes (can exclude by codebase for a pure pre-sc
|
||||
|
||||
---
|
||||
|
||||
### S4AC append catalogs and packed resource ids (2026-07-11)
|
||||
|
||||
`asset_mount_append_catalogs@0x44f120` scans `*.AAI`, constructs `AAIFileDB` objects, and calls
|
||||
`aai_catalog_load@0x401110`. Installed `S4AC422` uses selector `1` at header offset `0x108`, expanded size
|
||||
at `0x110`, packed size at `0x114`, and an LZSS directory stream at `0x118`. The expanded directory is the
|
||||
same archive-count / 256-byte archive-name / file-count / 80-byte-record layout as SYS4INI. Its 81 names are
|
||||
literal `$1$...` basenames in `APPEND01.ALF`.
|
||||
|
||||
After a successful load, the scan writes the catalog pointer to `FileDB+0x3028 + selector*4`; a later
|
||||
successful discovery of the same selector overwrites that slot. `asset_open_indexed_entry@0x44f390` splits
|
||||
nonzero-high-byte ids into `mounted_aai[id >> 24]` and record index `id & 0xffffff`, while high-byte-zero ids
|
||||
stay in the base SYS4 table. `aai_open_indexed_entry@0x401630` then applies the same exact loose basename
|
||||
before indexed ALF fallback as the base path. Thus append selection is explicit pack selection, not filename
|
||||
replacement. The selector extraction is an arithmetic `SAR 24`, so ids whose high byte has its sign bit set
|
||||
index before the mount table rather than slots `0x80..0xff`; the port rejects those selectors instead of
|
||||
inventing unsigned behavior. `/v2` names/comments this mount/load/open chain and is saved.
|
||||
|
||||
---
|
||||
|
||||
## Native walls backlog (targets for this loop)
|
||||
|
||||
- ~~**call-script dispatch**~~ — **SOLVED** (above): `call-script <id>` = raw SYS4INI file index.
|
||||
|
||||
@@ -1050,7 +1050,7 @@ opcode/ctx lint, 481-script decode, RECOVER, and `git diff --check` clean. SC000
|
||||
**85/129 to 87/129 handled (67.4%)**, with 42 GAP ops / 188 GAP instructions. Movie `0x236` and SFX remain
|
||||
separate slices. No implementation commit was made.
|
||||
|
||||
### Foundation track — native asset VFS + ALF/AAI/AGF readers (VFS-A/C DONE; VFS-B PENDING)
|
||||
### Foundation track — native asset VFS + ALF/AAI/AGF readers (VFS-A/B/C DONE)
|
||||
|
||||
This is an optional high-leverage detour before movie `0x236` or SFX. It replaces the Phase-A
|
||||
pre-extracted/pre-converted asset bootstrap with the native loose-override/archive-fallback model and removes
|
||||
@@ -1125,6 +1125,28 @@ Validation: 124/124 engine tests, CLI/Godot builds, Godot threaded selftest, pix
|
||||
assets, and the windowed no-BMP capture. VFS-B APPEND01/AAI, OGG/WAV migration, movie `0x236`, and unrelated
|
||||
opcode work remain separate.
|
||||
|
||||
### VFS-B — APPEND01 AAI mount DONE (2026-07-11)
|
||||
|
||||
`Sys4AssetCatalog.Load` now discovers installed `*.AAI` files beside `SYS4INI.BIN`, parses the `S4AC`
|
||||
directory at its native offsets, and mounts each catalog by the selector stored at header offset `0x108`.
|
||||
For Himegari, `APPEND01.AAI` mounts selector 1, names one `APPEND01.ALF`, and contains 81 records whose
|
||||
literal names all begin `$1$`. `AssetEntry` retains the pack id, `ResolvePacked` applies the evidenced
|
||||
`high byte -> mounted catalog; low 24 bits -> record` rule, and `Sys4ScriptProvider` routes append call ids
|
||||
through the existing `IAssetStore`. Base direct-name lookup remains base-only: append records are not guessed
|
||||
name replacements. The selected catalog still probes the record's exact loose basename before its ALF range.
|
||||
|
||||
Native `/v2` now names/comments the AAI constructor/load/table/open/get chain and
|
||||
`asset_mount_append_catalogs@0x44f120`; `asset_open_indexed_entry@0x44f390` documents the packed-id split.
|
||||
The native scan stores each successful catalog directly into its selector slot, so a later enumerated AAI
|
||||
with the same selector replaces the earlier pointer. Its `SAR 24` selector extraction makes sign-bit high
|
||||
bytes negative table indexes, so the port rejects them rather than inventing `0x80..0xff` behavior. Only
|
||||
selector 1 is installed and exercised here.
|
||||
|
||||
Validation: 127/127 engine tests; stable complete-directory digest; all 81 ranges fit; a disposable
|
||||
`BinExtractALF.exe APPEND01.AAI` extraction matches all 81 names, sizes, and payload bytes; real
|
||||
`$1$SC1260.BIN` loads through its packed id; CLI/Godot builds and threaded `SELFTEST OK`. Audio migration,
|
||||
movie `0x236`, AGF work, and unrelated opcodes were untouched.
|
||||
|
||||
### Phase A — native SC0000 SFX family (`0xb4`/`0xb5`/`0xb6`/`0xc2`/`0xd9`) DONE (2026-07-11)
|
||||
|
||||
Native RE and the matching trace resolve the bounded family. `0xb4(resource,channel)` synchronously loads
|
||||
|
||||
@@ -70,9 +70,9 @@ Three layers, cleanly separated:
|
||||
modders. They share the *format spec* (documented), not code — acceptable for a small, stable
|
||||
container format.
|
||||
- **Native content foundation status (2026-07-11).** VFS-A runtime-parses the base SYS4 catalog and
|
||||
applies loose-first bounded ALF reads; VFS-C decodes AGF directly to platform-neutral RGBA8 and feeds
|
||||
Godot without pre-extracted or pre-converted texture files. APPEND01/AAI mounting and audio-byte consumers
|
||||
remain separate follow-ups.
|
||||
applies loose-first bounded ALF reads; VFS-B mounts selector-keyed S4AC append catalogs and resolves the
|
||||
native high-byte/low-24-bit id split; VFS-C decodes AGF directly to platform-neutral RGBA8 and feeds Godot
|
||||
without pre-extracted or pre-converted texture files. Audio-byte consumers remain a separate follow-up.
|
||||
- **Profile = manifest.** Adding a game = a new profile + its maps. Adding an engine version = a new
|
||||
front-end plugin + profiles that reference it. See §5.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user