Use universal packed resource resolution
This commit is contained in:
@@ -54,8 +54,9 @@ highest-risk area of the port. This doc is the steering state; it feeds the A2b
|
||||
all 13206 `offset+size` fit inside their real `.ALF`; 837 name-matched files → 0 size mismatches.
|
||||
`files[]` preserves directory order (feeds step 2's order-correlation). Re-run:
|
||||
`py -3.11 -X utf8 tools/parse_sys4ini.py --check`. (Ref: asmodean's `exs4alf` / GARbro Eushully `ArcALF.cs`.)
|
||||
2. **Resolve `resource_id → asset file`.** **NATIVE RULE CONFIRMED IN GHIDRA (2026-07-21): resource
|
||||
operands are universal packed SYS4INI/AAI ids. There is no scene-relative path or fallback.**
|
||||
2. **Resolve `resource_id → asset file`.** **NATIVE RULE CONFIRMED IN GHIDRA AND IMPLEMENTED
|
||||
(2026-07-21): resource operands are universal packed SYS4INI/AAI ids. There is no scene-relative path
|
||||
or fallback.**
|
||||
|
||||
`asset_catalog_parse_base_tables@0x44e7e0` creates one flat base entry array in serialized SYS4INI
|
||||
order. `asset_open_indexed_entry@0x44f390` receives the operand unchanged. If its high byte is zero,
|
||||
@@ -80,7 +81,7 @@ highest-risk area of the port. This doc is the steering state; it feeds the A2b
|
||||
correlation and the strong `file_number == position - group_start` pattern remain useful evidence about
|
||||
catalog construction/order, but they do not describe runtime resolution. SC0000 starting at zero hid
|
||||
the mistake, while later large ids often fell outside the invented scene range and happened to reach the
|
||||
port's raw fallback. Low raw ids used from later scripts can instead be silently misresolved today.
|
||||
port's former raw fallback. Low raw ids used from later scripts could instead be silently misresolved.
|
||||
`tools/resolve_asset.py` and `build/asset-sections.json` are therefore correlation/manifest-inventory
|
||||
diagnostics only; they must not drive runtime lookup.
|
||||
|
||||
@@ -144,9 +145,10 @@ rendering what the executed bytecode + the map produce (never a hardcoded image)
|
||||
|
||||
## Status
|
||||
|
||||
A2b-background: **steps 1–3 landed, but step 2's resolver must be corrected.** Step 1 =
|
||||
`build/asset-index.json`. Step 2 originally normalized through inferred per-scene sections; native RE now
|
||||
proves runtime operands are already universal packed ids. `tools/resolve_asset.py` and
|
||||
A2b-background: **steps 1–3 landed; step 2's packed resolver was corrected 2026-07-21.** Step 1 =
|
||||
`build/asset-index.json`. Step 2 originally normalized through inferred per-scene sections; native RE proved
|
||||
runtime operands are already universal packed ids, and every typed runtime facade now uses that contract.
|
||||
`tools/resolve_asset.py` and
|
||||
`build/asset-sections.json` remain grouping/correlation diagnostics, not runtime inputs. Step 3 = **first-pass
|
||||
render** (ResourceMap + GodotAdvHost texture ops → TextureRect compositing): the full-screen event-CG
|
||||
layer renders end-to-end from the bytecode. Remaining (next chunk): the **graphics geometry/blend
|
||||
@@ -214,12 +216,14 @@ scene-local numeric addressing mode.
|
||||
on-disk `BinExtractALF.exe` are validation references; the Kelebek repository exposes no clear license,
|
||||
so its code should not be copied without clarification. The focused `LzssDecoder` is shared with
|
||||
`Sys4AssetCatalog`; raw and compressed information/pixel/ACIF sections use the same bounded primitive.
|
||||
4. **Runtime consumers (packed-id correction pending).** Script loading and SFX already use
|
||||
`ResolvePacked`. Texture/voice/non-modal movie facades still contain the disproven scene-first/raw-fallback
|
||||
compatibility layer and must be switched to the same typed packed lookup. Godot caches decoded RGBA
|
||||
surfaces by catalog identity and supplies synchronous dimensions to opcode `0x208`; it no longer reads
|
||||
`build/textures/*.BMP`. BGM remains direct-name. Extraction, grouping, and conversion tools remain
|
||||
diagnostics.
|
||||
4. **Runtime consumers (packed-id correction complete 2026-07-21).** Script loading, textures, voice,
|
||||
SFX, cursors, and modal/non-modal movies all select through `ResolvePacked` before type filtering. The VM
|
||||
retains bytecode operands unchanged instead of asking the host for scene normalization. Godot caches
|
||||
decoded RGBA and movie identities by the full packed id, preserving AAI selectors rather than colliding
|
||||
with equal low indexes in the base catalog. It supplies synchronous dimensions to opcode `0x208` and no
|
||||
longer reads `build/textures/*.BMP`. BGM remains direct-name. Focused regressions cover SC0010's low
|
||||
`0x21` texture and `0x120..0x122` voices plus append-pack identity. Extraction, grouping, and conversion
|
||||
tools remain diagnostics.
|
||||
|
||||
### Acceptance gates
|
||||
|
||||
@@ -352,7 +356,7 @@ corpus is `LOGO.BIN (0x335f,42,4)`, `OP.BIN (0x3364,42,4)`, and
|
||||
Native `0x20f` also arms modal run-state `0x2000`; unlike `0x236`, these six-instruction wrapper scripts
|
||||
depend on the movie service itself to park until EOF/input cancellation before they release surface 42.
|
||||
|
||||
`ResourceMap.ResolveRawMovie` currently supplies that typed universal lookup, while `ReadMovie` remains the MPEG
|
||||
`ResourceMap.ResolveMovie` supplies that typed universal lookup, while `ReadMovie` remains the MPEG
|
||||
signature gate. `IHost.PlayModalMovieToSurface` is distinct from the non-modal call for lifecycle only: Godot
|
||||
reuses the asynchronous DirectShow frame decoder and retained compositor but parks the VM thread until EOF
|
||||
or mouse/Accept/Cancel input. The wrapper's following release then tears down the completed/cancelled movie.
|
||||
|
||||
@@ -2119,9 +2119,11 @@ open raw entry `0x21` (`SO013A.AGF`); adding SC0010's catalog position `0x11e` i
|
||||
`COL0023.OGG`. Its `play-voice 0x120/0x121/0x122` operands directly select
|
||||
`LILA1414/LILB0053/LILC0054.OGG`, whose SC0010-local file numbers are 2/3/4. The catalog grouping relation
|
||||
is therefore `absolute id = group start + file_number`; the compiler has already performed that addition.
|
||||
The port's scene-first compatibility resolver inverted this relationship and must be replaced by typed
|
||||
`ResolvePacked` lookup for texture, voice, and movie consumers. Ghidra `/v2` renames the catalog parser and
|
||||
entry-name helper, corrects the opener/caller comments, and is saved.
|
||||
The port's former scene-first compatibility resolver inverted this relationship. On 2026-07-21 it was
|
||||
replaced by typed `ResolvePacked` lookup for texture, voice, and both movie consumers; the VM now preserves
|
||||
the operand unchanged and Godot cache/movie identities retain the complete packed selector. SC0010 low-id
|
||||
and installed append-pack regressions cover the two failure modes. Ghidra `/v2` renames the catalog parser
|
||||
and entry-name helper, corrects the opener/caller comments, and is saved.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -619,7 +619,7 @@ This is a target-pixel operation, not retained-object teardown. It invokes IDire
|
||||
- **grounding:** source=investigation, confidence=high
|
||||
- **evidence:** Ghidra /v2: op_0x20f_play_modal_movie_to_surface@0x422e50 shares the movie-object allocation, DirectShow graph open, audio-route, and volume setup used by 0x236, then calls movie_start_modal_playback@0x463280, ORs EngineCtx+0xa0ce4 with 0x2000, and marks movie presentation dirty. The main loop and window procedure special-case run-state 0x2000. Corpus has exactly three sites: LOGO (0x335f,42,4), OP (0x3364,42,4), and ED (0x3324,42,dynamic flags). Those ids are universal raw SYS4INI indexes for MPEG-pack LOGO.AGF, OP.AGF, and ED.AGF; each script releases its surface only after 0x20f resumes.
|
||||
|
||||
Implemented through IHost.PlayModalMovieToSurface. Its operand uses the same native universal packed-id catalog contract as 0x236; the separate host call exists for modal wait/cancel lifecycle, not a different resolver. ResourceMap must retain MPEG signature validation in ReadMovie. Godot reuses the asynchronous decoder/retained-surface compositor, parks only the VM thread until EOF, and treats mouse click or Accept/Cancel input as completion before wrapper cleanup releases the decoder. MPEG audio remains a separate backend/audio-clock contract.
|
||||
Implemented through IHost.PlayModalMovieToSurface. Its operand uses the same native universal packed-id catalog contract as 0x236; the separate host call exists for modal wait/cancel lifecycle, not a different resolver. ResourceMap.ResolveMovie selects through ResolvePacked and retains MPEG signature validation in ReadMovie. Godot reuses the asynchronous decoder/retained-surface compositor, parks only the VM thread until EOF, and treats mouse click or Accept/Cancel input as completion before wrapper cleanup releases the decoder. MPEG audio remains a separate backend/audio-clock contract.
|
||||
|
||||
### 0x212 `set-gfx-field64` (set-gfx-field64, argc 2)
|
||||
- **summary:** 0x212 (obj_idx)(val) — handler gfx_op_0x212_set_field64 @0x4230c0: obj=[ctx+0x14d54 + obj_idx*4]; if obj: *(obj+0x64)=val. The generic instruction length is 5 dwords. See docs/engine-re.md gfx op-contract table.
|
||||
@@ -749,7 +749,7 @@ Implemented through IHost.PlayModalMovieToSurface. Its operand uses the same nat
|
||||
- **grounding:** source=investigation, confidence=high
|
||||
- **evidence:** Ghidra /v2 op_0x236_play_movie_to_surface@0x423ee0 fetches operand 1 and passes it unchanged to movie_to_texture_open_asset_graph@0x463e20, which passes it unchanged to asset_open_indexed_entry@0x44f390. The opener directly indexes the flat base table or selected AAI table and has no scene input. SC0000 native operand capture and exact 0x13c8->0x13d1 trace prove nonblocking behavior. BTL's live 0x2b21 site supplies 0x2af1/0x2af5/0x2bca/0x2bd8/0x2bde, the exact base entries MVB001/MVB004/MVB914/MVB958/MVB955.
|
||||
|
||||
The handler requires an existing destination texture, allocates/reuses a 0x478-byte movie-to-texture object for the surface, opens operand 1 through the native universal packed-id reader, builds FilterGraph/IGraphBuilder/IMediaControl/IMediaPosition/IMediaEvent/IBasicAudio, and presents bottom-up RGB samples through the movie texture renderer. Operand 3 selects movie/sound routing policy: bits 0x10000/0x20000/0x40000/0x80000 force sound route 0/1/2/3, otherwise set:DependMovieSound is used; SC0000's low value 2 is retained as native movie mode state. Operand 4 is the movie sync/device mask. Static layer preparation after 0x236 does not terminate the retained movie; 0x21c services it through EOF and subsequent surface cleanup stops/detaches it. The port should type-check the selected packed record as MPEG but must not add a scene base or scene-first fallback.
|
||||
The handler requires an existing destination texture, allocates/reuses a 0x478-byte movie-to-texture object for the surface, opens operand 1 through the native universal packed-id reader, builds FilterGraph/IGraphBuilder/IMediaControl/IMediaPosition/IMediaEvent/IBasicAudio, and presents bottom-up RGB samples through the movie texture renderer. Operand 3 selects movie/sound routing policy: bits 0x10000/0x20000/0x40000/0x80000 force sound route 0/1/2/3, otherwise set:DependMovieSound is used; SC0000's low value 2 is retained as native movie mode state. Operand 4 is the movie sync/device mask. Static layer preparation after 0x236 does not terminate the retained movie; 0x21c services it through EOF and subsequent surface cleanup stops/detaches it. The port type-checks the selected ResolvePacked record as MPEG without adding a scene base or fallback.
|
||||
|
||||
### 0x238 `set-anim-clock` (set-anim-clock, argc 1)
|
||||
- **summary:** (duration) — set the GLOBAL animation clock: native ctx+0x51b78=0 (elapsed), +0x51b7c=duration. The generic instruction length is 3 dwords. NON-BLOCKING: only configures; the render loop advances it and interpolates all animating objects. SC0000 opening @0x123bd/@0x13858. Handler 0x4240e0; Kelebek VA 0x422390 is drift.
|
||||
|
||||
@@ -561,20 +561,23 @@ Focused regressions cover exact dispatch, signed edge cases, string aliasing, cl
|
||||
movie polling, animation reset suppression, delayed voice operands, paired clipping, overlap, and colorkey
|
||||
transparency. Manual DEBUGMAP acceptance reached player combat and exposed the next concrete frontier:
|
||||
combat-effect movies do not play. The resolver/decoder diagnosis is canonical in
|
||||
`docs/asset-resolution-re.md`; fix that bounded movie path before proceeding to enemy-turn/end-turn breadth.
|
||||
`docs/asset-resolution-re.md`; packed resolution is now corrected, with manual BTL validation and the
|
||||
separate decoder decision remaining before enemy-turn/end-turn breadth.
|
||||
|
||||
**Combat-effect movie gap diagnosed; native resolver generalized; implementation pending.** BTL's
|
||||
**Universal packed resource resolver implemented; combat movie validation pending.** BTL's
|
||||
`0x236@0x2b21` consumes universal packed MVB ids, exactly as texture, voice, script-load, and modal-movie
|
||||
consumers do. Native Ghidra analysis shows that none of those paths applies an SC section base or fallback;
|
||||
the port's scene-first compatibility resolver is therefore generally wrong, not merely incomplete for BTL.
|
||||
the port's former scene-first compatibility resolver was therefore generally wrong, not merely incomplete for BTL.
|
||||
That explains each `movie unresolved BTL:...` warning and the secondary attempt to decode MPEG-backed
|
||||
`MVB914.AGF` as a still image. A packed-catalog decoder probe also found a separate backend wall: the current
|
||||
DirectShow graph handles `MVB914` (400x400) but rejects the reached 280x352 MVB001/MVB004/MVB955/MVB958
|
||||
assets with `0x80040217`. Broader samples tie current compatibility to 16-aligned display widths, while 125
|
||||
installed MVB assets use 280x352. The next bounded slice is to replace typed texture, voice, and movie
|
||||
consumers with universal packed resolution and regress SC0010's low texture/voice ids plus BTL effects.
|
||||
The existing portable-decoder seam and a software fallback for 280x352 effects remain the following,
|
||||
separate step, with destination dimensions and failed-movie identity preserved correctly.
|
||||
installed MVB assets use 280x352. Texture, voice, and both movie consumers now use universal packed
|
||||
resolution; VM surface state and Godot caches retain the full selector. Focused tests prove SC0010's low
|
||||
texture/voice ids and append-pack identity; 302 engine tests, a zero-warning Godot build, and threaded
|
||||
selftest pass. **NEXT:** manually re-enter combat and confirm the BTL ids now resolve into the movie backend.
|
||||
The expected remaining failures are the known 280x352 DirectShow graphs; defer decoder replacement until
|
||||
that resolver-only acceptance check, preserving destination dimensions and failed-movie identity afterward.
|
||||
|
||||
**Mutable-surface fill/blend regression corrected.** The first visual recheck exposed BUNKI's menu interior
|
||||
as transparent. SYSTEM4 creates 800x600 surface 3 and fills it opaque white through `0x20b`; the metadata-only
|
||||
|
||||
Reference in New Issue
Block a user