5.8 KiB
5.8 KiB
PSX Art-Binding Recovery
Scope
- Active target: retail PlayStation
SLUS_002.68feeding the renderer-local cache pipeline inCrusader-Map-Viewer/map_renderer. - Goal of this pass: stop treating the current unreadable PSX output as a renderer-only problem and measure whether placeholders are mainly caused by extraction-time art binding failures.
- This note records the first pragmatic recovery pass that replaces large placeholder bands with real bundle-backed art while keeping the result auditable in exported scene metadata.
Root Cause Summary
- The current unreadable output was primarily an extraction-side problem, not a front-end draw bug.
- Before this pass, the built
.cache/scene-cache/psx-remorseset carried58,262fallback placeholders versus only1,714bundle-mapped items. - The fallback concentration was overwhelmingly in
section0_constructor_placements(94.5%of fallback items), not in the smallersection0_dispatch_rootsfamily. - The hottest unresolved types were
0x0042,0x0041,0x0047,0x0045,0x003f,0x004b,0x0046,0x0044,0x0048, and0x004a. - Those types already appeared in the exported
DAT_800758d8art-template layer in many maps, but almost all of their rows wereblockSize = 0and therefore had no direct payload dwords to match against bundle offsets. - The neighboring state banks were still populated:
DAT_800758cccarried valid script tables for the same types, whileDAT_800758d0stayed empty for this family andDAT_800758d4remained on the runtime-bounds side. - That combination strongly suggests inherited or aliased presentation for these constructor-placement families rather than a literal absence of art.
Implemented Recovery Rule
The cache builder now resolves PSX art in three stages instead of dropping directly from "no direct DAT_800758d8 payload" to a placeholder:
- Use the direct non-zero
DAT_800758d8row when a type has a real local template payload and bundle match. - If the type lives in the unresolved zero-block constructor-placement family, look for a same-map donor type whose
DAT_800758ccscript blob is identical and whoseDAT_800758d8row resolves to a real bundle. - If no exact script-signature donor exists, fall back to the nearest resolved same-map donor inside the current constructor-placement family band (
0x003e..0x0064).
The exporter keeps this explicit instead of pretending the rule is fully solved:
mappingSourcenow records whether the art came from a direct template, acc-signature-donor:xxxx, or ageneric-family-donor:xxxxpath.templateTypeIdanddonorTypeIdare preserved in exportedmapSourcerows.- The unresolved type still uses its own
DAT_800758ccselector-to-frame map; only the bundle source is borrowed.
Measured Effect
Two measured rebuilds mattered in this pass.
First donor pass
- Added donor reuse for the original generic family band.
- Totals moved from
58,262fallback /1,714bundle-mapped to37,054fallback /22,922bundle-mapped.
Representative maps:
map 0:1078 / 111->340 / 849map 9:664 / 111->197 / 578map 43:707 / 97->196 / 608map 64:1194 / 161->736 / 619map 104:909 / 93->894 / 108
Extended donor band
- Extended the same heuristic through the next zero-block constructor-placement band up to
0x0064. - Final measured totals after rebuild:
25,038fallback /34,938bundle-mapped.
Representative maps after the extended pass:
map 0:66fallback /1123bundle-mappedmap 9:42fallback /733bundle-mappedmap 43:9fallback /795bundle-mappedmap 64:160fallback /1195bundle-mappedmap 104:866fallback /136bundle-mapped
So the first practical conclusion is straightforward: the exporter was the main blocker for most maps, and a constrained donor heuristic can replace a large fraction of placeholders with real graphics without touching the viewer runtime.
Remaining Unresolved Mass
- The cache is still not fully closed.
25,038fallback items remain across62maps. - The remaining fallback distribution is still concentrated in
section0_constructor_placements. - Current top fallback-heavy types after the donor pass are
0x0042,0x005a,0x005b,0x005c,0x0047,0x0059,0x005d,0x005e,0x0062, and0x0063. 0x0042remains the single largest unresolved type even after the heuristic pass.map 104is the most obvious current outlier: it still sits at866fallback items versus only136bundle-mapped items, so the next recovery pass should treat it as the best stress case rather than relying only on the now-mostly-readable early maps.
Practical Interpretation
- The donor heuristic is good enough to prove that many placeholders were caused by missing extraction-time inheritance logic.
- It is not strong enough to count as the final executable-backed rule for the unresolved families.
- The remaining gap still sits where the earlier Ghidra work already pointed: somewhere between the constructor-side art/resource creation lane and the live post-spawn state/resource/frame reselection path.
Next Steps
- Trace the remaining high-volume band
0x0055..0x0063in Ghidra with the same question used for0x0042: why doesDAT_800758d8stay zero-sized while visible art still exists at runtime? - Use
map 104as the primary regression target and dump its remaining fallback type/state/lane distribution before doing any broader heuristic expansion. - Compare unresolved zero-block types against nearby resolved donor types at the constructor/resource level, not only at the script-signature level, so borrowed bundles can be replaced with an executable-backed alias rule.
- Keep the
DAT_800758d4work on the bounds side unless a family-specific caller proves otherwise; this pass did not reopen that conclusion.