psx map standalone exporter
This commit is contained in:
parent
a9153546ae
commit
2f243976b6
16 changed files with 3254 additions and 5 deletions
|
|
@ -101,6 +101,51 @@ Those counts are now historical rather than current for the focused `map 104` ex
|
|||
- The immediate export-side blocker was config: `psx-remorse` was excluded from static export even though the prebuilt catalog/build-manager path already supports multi-map PSX scenes.
|
||||
- The renderer config now includes `psx-remorse` in static export so full PSX exports can surface the full processed map set instead of dropping the version entirely.
|
||||
|
||||
## Live MCP Follow-Up (2026-04-13): Main-Visible Palette-Token Submit Normalization
|
||||
|
||||
- Scope for this focused pass: exact submit-flag packing and pre-submit normalization centered on `psx_draw_main_visible_object` (`0x80041458`), wrapper context in `psx_lset_world_frame_wrapper` (`0x80031f0c`) and `psx_draw_world_visible_passes` (`0x80041378`), with submitter override gates at `0x80044e10` and `0x80044eb8`.
|
||||
- Main-visible now has instruction-level confirmation for flag packing at the call sites (`0x800415c0` / `0x800415e0`):
|
||||
- `a3 = (obj_flags & 0x0002) | token_hi`
|
||||
- `token_hi` is normalized earlier as `source_palette_word & 0xFF00` at `0x80041590`.
|
||||
- Exact palette-token carriage for this lane is therefore bits `15:8` of submit flags (`token = flags >> 8`). Low nibble bits remain non-palette control bits.
|
||||
- Submitter override gate behavior is now explicitly aligned across image-table and sprite submitters:
|
||||
- gate expression is `(flags & ~0xF) != 0` (equivalent to `(flags & 0xfffffff0) != 0`)
|
||||
- because world callers only contribute `obj_flags&0x0002` plus token high byte, bit `0x0002` alone does not trigger override; nonzero token high byte is the effective palette-override activator.
|
||||
- Non-obvious normalization outcome for exporter logic: no additional wrapper-stage or no-op-hook mutation exists before `0x80041458` submits; palette-relevant normalization is local to main-visible draw and consists of high-byte extraction only.
|
||||
|
||||
Conservative live-artifact updates applied in Ghidra for this pass:
|
||||
|
||||
- nearby helper renames:
|
||||
- `0x8003a3b0 -> psx_world_draw_tint_fade_step`
|
||||
- `0x80038f10 -> psx_noop_frame_hook_38f10`
|
||||
- `0x80044018 -> psx_noop_frame_hook_44018`
|
||||
- targeted decompiler comments:
|
||||
- `0x80041590` (token high-byte normalization)
|
||||
- `0x800415c0` (final submit-flag packing)
|
||||
- `0x80044e10` / `0x80044eb8` (shared override gate and token indexing)
|
||||
- `0x80031f34` / `0x80031f3c` (wrapper no-op hooks do not mutate submit flags)
|
||||
|
||||
## Live MCP Follow-Up (2026-04-13): World Draw Pass + CLUT Routing Refresh
|
||||
|
||||
- Scope for this focused pass: live `SLUS_002.68` world draw and submitter routing at `0x80041378`, `0x80041458`, `0x80041144`, `0x80044bdc`, and `0x80044e9c`, plus CLUT table lanes `0x800a9f48` and `0x800a9f66`.
|
||||
- World draw pass ordering remains fixed and explicit: stage-1 main-visible sorted slice first, then stage-2 special-visible queue, then HUD/overlay.
|
||||
- Stage-1 and stage-2 world lanes still share submitter dispatch by bound resource kind (`kind==5` image-table submitter, otherwise sprite submitter).
|
||||
- Palette-token handling remains lane-split and exporter-critical: main-visible injects authored high-byte palette token into submit flags; special-visible does not.
|
||||
- CLUT override gate remains shared (`submit_flags & 0xfffffff0`), but CLUT table resolution still branches by submitter/resource-format lane:
|
||||
- `psx_image_table_submit_frame`: high-byte token selects `psx_clut_override_table_by_palette_token[token]`, otherwise default bank CLUT.
|
||||
- `psx_sprite_resource_submit_frame`: format-2 lane follows override table path; non-format-2 lane remaps token through bank CLUT indexing.
|
||||
- Nearby anonymous helper cleanup in the same draw wrapper lane:
|
||||
- `0x8002e534 -> psx_marker_channel_runtime_get_u16_86`
|
||||
- `0x8002eee8 -> psx_marker_channel_runtime_get_u16_84`
|
||||
|
||||
Conservative live-artifact updates applied in Ghidra for this pass:
|
||||
|
||||
- `0x80041378`: decompiler comment clarifying stage-1 -> stage-2 -> HUD order.
|
||||
- `0x800415c0`: decompiler comment clarifying main-visible authored token injection before image-table submit.
|
||||
- `0x800412dc`: decompiler comment clarifying special-visible omits authored high-byte token injection.
|
||||
- `0x80044ed0`: decompiler comment clarifying image-table CLUT override-table path.
|
||||
- `0x80044e5c`: decompiler comment clarifying sprite default bank-CLUT path when override gate is inactive.
|
||||
|
||||
## Live MCP Follow-Up (2026-04-12): Wall-Family Split Failure Mode
|
||||
|
||||
- Scope for this focused pass: live `SLUS_002.68` around the wall-heavy generic family band (`0x003e..0x004f`) and exporter donor-heavy bundles (`0x0008b48c`, `0x00085c40`).
|
||||
|
|
@ -143,9 +188,220 @@ Conservative live-artifact updates applied in Ghidra for this pass:
|
|||
- `0x80044e10`: comment clarifying sprite submit override gate and token-0 fallthrough.
|
||||
- `0x80044eb8`: comment clarifying image-table override keying behavior.
|
||||
|
||||
## Live MCP Follow-Up (2026-04-13): Selector Install, Transition Selection, and Final Latch Closure
|
||||
|
||||
- Scope for this focused pass: selector-install and post-construction reselection chain centered on `psx_object_select_state_script` (`0x800260e8`), `psx_object_advance_state_script` (`0x80025d68`), `psx_object_select_state_from_transition_table` (`0x8001bca0`), `psx_type42_transition_selector_tick` (`0x80018578`), and delayed type-4 reselection around `0x8002906c`.
|
||||
- `psx_object_select_state_script` is confirmed as install-only in exporter terms: it writes selector `obj+0x9e`, seeds state-script cursor (`obj+0x8c/0x90`), and does not write final visible frame token.
|
||||
- Final visible frame/state token is latched in `psx_object_advance_state_script` where current script word is copied to `obj+0x94`; projection/draw lanes consume this live token.
|
||||
- Transition-table selection remains two-stage and row-driven: transition code from `psx_type_transition_mode_policy_rows` (`0x80063a00`) selects selector base from `psx_type_transition_selector_rows` (`0x80063b4c`), then `psx_object_select_state_script` installs selector.
|
||||
- In that transition path, runtime flag mutation is narrow and explicit: selector logic toggles `obj+0x1c` bit `0x0002` only; broad authored lane bits such as `0x0020` are not synthesized by this function.
|
||||
- `psx_type42_transition_selector_tick` adds an early pre-latch gate before reseat/turn-driven selector dispatch: object must be within view margin and pass the object-lane `obj+0x1c & 0x0020` condition. Selector updates there still occur before the later `obj+0x94` latch point.
|
||||
- The unresolved `FUN_8002906c` path is now closed by symbol state in live Ghidra: `0x8002906c` is `psx_type4_reselect_motion_state`, reached from `psx_type4_update_delayed_interaction` (`0x80029dac`) when delayed countdown reaches trigger. This is a post-construction reselection lane, not constructor-side initial bind.
|
||||
|
||||
Exporter-facing implication from executable evidence:
|
||||
|
||||
- A standalone JS exporter should treat selector install (`obj+0x9e`) and final latch (`obj+0x94`) as distinct channels.
|
||||
- Transition-table and type-`0x0042` reselection may alter pre-latch selector/runtime flag state without directly proving final frame token at draw time.
|
||||
- Cohort split logic should therefore prioritize latched `obj+0x94` capture (or strong proxy) over authored selector or transition slot alone.
|
||||
|
||||
Conservative live-artifact updates applied in Ghidra for this pass:
|
||||
|
||||
- `0x800260e8`: comment clarifying install-only selector semantics and no direct `obj+0x94` write.
|
||||
- `0x80025d68`: comment clarifying final frame/state latch into `obj+0x94`.
|
||||
- `0x8001bca0`: comment clarifying two-stage transition-row lookup and `0x0002`-only bit toggle scope.
|
||||
- `0x80018578`: comment clarifying type-`0x0042` pre-latch gate and reseat ordering.
|
||||
- `0x8002906c`: comment clarifying delayed post-construction reselection role.
|
||||
- `0x80029dac`: comment clarifying delayed countdown trigger into post-construction reselection.
|
||||
|
||||
## Live MCP Follow-Up (2026-04-13): Authored Family Descriptor Convergence and Constructor Bind Closure
|
||||
|
||||
- Scope for this focused pass: authored section-0 family dispatch and constructor bind semantics on active `SLUS_002.68` at `psx_dispatch_section0_dispatch_roots` (`0x800256b0`), `psx_dispatch_section0_constructor_placements` (`0x800258cc`), `psx_object_create_simple_record` (`0x800249f4`), `psx_object_create_compound_record` (`0x80024eec`), and descriptor row `0x800626f8`.
|
||||
- Section-0 root and constructor-placement records are now reconfirmed as one convergence lane for unresolved families (`0x0042`, `0x0049`, `0x0055..0x0063`): both dispatch through descriptor slot0 and converge on row `0x800626f8` callback `0x80013618`.
|
||||
- Descriptor row role at `0x800626f8` is now explicitly preserved in disassembly comments as:
|
||||
- slot0 `0x80013618` (`psx_spawn_compound_record_advance_state_once`)
|
||||
- slot1 `0x80013688` (`psx_object_refresh_main_visible_and_cleanup`)
|
||||
- slot2 `0x800254c8` (`psx_object_release_to_free_list`)
|
||||
- Constructor bind semantics are now restated at function entry for exporter extraction:
|
||||
- simple path copies authored route word `record+0x10 -> obj+0x1c`
|
||||
- compound path copies authored route word `record+0x0A -> obj+0x1c`
|
||||
- both read active art header from `DAT_800758d8[type]`
|
||||
- both reuse `DAT_800758c8[type]` for kind-5 resources and otherwise build per-instance resource.
|
||||
- Practical exporter consequence: authored-family divergence should continue to be modeled post-constructor (state/policy/route/latch channels), not as a section-0 descriptor callback split.
|
||||
|
||||
Conservative live-artifact updates applied in Ghidra for this pass:
|
||||
|
||||
- `0x80031c34`: `FUN_80031c34` renamed to `psx_spawn_type0b_compound_burst_for_active_object_sweep`.
|
||||
- `0x800256b0`: decompiler comment clarifying root-dispatch descriptor convergence.
|
||||
- `0x800258cc`: decompiler comment clarifying constructor-placement descriptor convergence.
|
||||
- `0x800249f4`: decompiler comment clarifying simple constructor route-word copy and art-bind/cache split.
|
||||
- `0x80024eec`: decompiler comment clarifying compound constructor route-word copy and art-bind/cache split.
|
||||
- `0x800626f8`: disassembly comment clarifying shared descriptor-row slot mapping.
|
||||
|
||||
## Live MCP Follow-Up (2026-04-13): Source-Record Palette Token Provenance (`obj+0xa0`) and Region00 12-byte Fit
|
||||
|
||||
- Scope for this focused pass: live `SLUS_002.68` constructor/source-pointer storage and world main-visible token read at `0x80024b50`, `0x80025048`, `0x800258cc`, and `0x80041458`.
|
||||
- Main-visible draw token read is now source-exact and band-split:
|
||||
- for `0x003e..0x00ab`: token high byte from `(*(obj+0xa0)+0x06) & 0xff00`
|
||||
- for `>=0x00ac`: token high byte from `(*(obj+0xa0)+0x0c) & 0xff00`
|
||||
- Constructor storage of `obj+0xa0` is now instruction-explicit in both create paths:
|
||||
- simple record path writes source pointer at `0x80024b50`
|
||||
- compound/region00 path writes source pointer at `0x80025048`
|
||||
- Section0 constructor-placement dispatch (`0x800258cc`) steps records by `+0x0c`, confirming region00-style authored records are 12 bytes in this lane.
|
||||
- For currently visible unresolved families in this workflow (`0x0042`, `0x0049`, `0x0055..0x0063`), type band is `<0x00ac`, so main-visible token read uses source offset `+0x06` only; this offset is inside 12-byte records and is therefore a usable authored palette-token carrier.
|
||||
- Consequence for exporter assumptions: treating region00 12-byte records as inherently unable to carry palette override bits is incorrect for these current families; only the `>=0x00ac` `+0x0c` read requires a longer source layout.
|
||||
|
||||
Conservative live-artifact updates applied in Ghidra for this pass:
|
||||
|
||||
- `0x80027f38`: `FUN_80027f38` renamed to `psx_alloc_runtime_snapshot_record_payload`.
|
||||
- `0x80024b50`: decompiler comment clarifying simple-path `obj+0xa0` source-record pointer storage and later main-visible `+0x06/+0x0c` token reads.
|
||||
- `0x80025048`: decompiler comment clarifying compound-path `obj+0xa0` storage and 12-byte-record compatibility with `<0x00ac` `+0x06` token read.
|
||||
- `0x8004156c`: decompiler comment clarifying the exact type-band split and source offsets used for main-visible palette-token injection.
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. Trace the remaining high-volume band `0x0055..0x0063` in Ghidra with the same question used for `0x0042`: why does `DAT_800758d8` stay zero-sized while visible art still exists at runtime?
|
||||
2. Use `map 104` as the primary regression target and dump its remaining fallback type/state/lane distribution before doing any broader heuristic expansion.
|
||||
3. 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.
|
||||
4. Keep the `DAT_800758d4` work on the bounds side unless a family-specific caller proves otherwise; this pass did not reopen that conclusion.
|
||||
4. Keep the `DAT_800758d4` work on the bounds side unless a family-specific caller proves otherwise; this pass did not reopen that conclusion.
|
||||
|
||||
## Live MCP Follow-Up (2026-04-13): Art Payload Decode Semantics For Standalone Exporters
|
||||
|
||||
- Scope for this focused pass: active PSX `SLUS_002.68` type-4/type-5 install and submit corridor centered on `psx_resource_bind_single_image_vram_slot` (`0x800444e4`), `image_bundle_load_to_vram` (`0x80044614`), `sprite_rle_decode_rows` (`0x80045264`), and frame-geometry helpers (`0x80045014`, `0x800450a8`, `0x8004513c`, `0x800451d0`).
|
||||
- Kind-4 decode lane is now extractor-explicit: single-image descriptors bind one VRAM slot and preserve descriptor width/height/format/payload metadata in the runtime resource; this is the minimal schema a standalone decoder must mirror before frame submission.
|
||||
- Kind-5 decode lane is now exporter-explicit: bundle install builds a runtime frame table (`0x10` stride), allocates frame VRAM slots, and uploads either raw rows or RLE-decoded rows depending on frame flag bit0.
|
||||
- RLE semantics are now pinned in live comments: positive control repeats a byte value, negative control copies literal run bytes, and zero terminates each row. This is the required offline decode contract for compressed WDL image payloads.
|
||||
- Geometry extraction rule is now explicit for offline export: width/height/origin come from kind-specific frame schemas (`0x14` stride kind-4 descriptor rows versus `0x10` stride kind-5 runtime rows), not from visibility-lane flags.
|
||||
|
||||
Conservative live-artifact updates applied in Ghidra for this pass:
|
||||
|
||||
- Renames:
|
||||
- `0x80045440` -> `psx_ui_image_bundle_get_frame_payload`
|
||||
- `0x800455d4` -> `psx_ui_image_bundle_draw_temp_vram_frame`
|
||||
- `0x80045d78` -> `psx_ui_image_bundle_draw_temp_vram_frame_static`
|
||||
- Decompiler comments:
|
||||
- `0x800444e4` (kind-4 single-image bind semantics)
|
||||
- `0x80044614` (kind-5 bundle upload table and raw-vs-RLE branch)
|
||||
- `0x80045264` (row-RLE decode contract for offline tools)
|
||||
- `0x80045014`, `0x800450a8`, `0x8004513c`, `0x800451d0` (kind-split frame geometry schema for exporter parity)
|
||||
|
||||
## Live MCP Follow-Up (2026-04-13): Loader Bundle Install, Stream Runtime Banks, and Inflate Lane
|
||||
|
||||
- Scope for this focused pass: `wdl_resource_bundle_load_by_index` (`0x80039444`), `psx_stream_install_type_runtime_banks` (`0x80038f18`), `psx_install_type_state_script_component_extents_banks` (`0x8003917c`), `psx_install_type_art_active_header_and_built_resource` (`0x80045ffc`), detached-stream installer (`0x80040768`), and compressed-state inflate (`0x8003b00c`).
|
||||
- `psx_stream_install_type_runtime_banks` now has exporter-relevant record layout closure: each streamed type entry begins with a fixed `0x14` header `(type_id, state_size, component_size, extents_size, active_art_header_size)` before payload bytes.
|
||||
- Stream-lane install behavior is now role-split and explicit:
|
||||
- installs state/script, component, and extents pointers into `DAT_800758cc/d0/d4`
|
||||
- clears `DAT_800758c8[type]` (`psx_type_art_built_resource_bank`) to null
|
||||
- installs only raw active-header pointer into `DAT_800758d8[type]` when `active_art_header_size != 0`.
|
||||
- Practical consequence for standalone exporters: stream-runtime-bank lane seeds metadata/header pointers only; built drawable resources are resolved in the separate WDL art installer (`psx_install_type_art_active_header_and_built_resource`) through kind-4 bind and kind-5 image-table build.
|
||||
- `wdl_resource_bundle_load_by_index` is now preserved as a multi-pass install sequence with two art/state waves, section-pack pointer install, detached runtime-stream install, optional compressed-state inflate, and only then root-record dispatch.
|
||||
- Compressed-state lane remains pre-dispatch and persistent-state-gated: `psx_lzss_unpack_into_level_buffer` inflates a `0x3e00` block into `psx_level_decompressed_state_buffer` before runtime-header apply and root replay; a zero backref token terminates decode.
|
||||
- Detached runtime-stream blob install (`0x80040768`) is now extraction-structured: header carries three leading lengths, then two 9-entry size arrays, then tail-transfer length used for SPU upload and sequence/VAB setup.
|
||||
|
||||
Conservative live-artifact updates applied in Ghidra for this pass:
|
||||
|
||||
- Renames:
|
||||
- `0x8002b6b8` -> `psx_level_heap_push_cursor_mark`
|
||||
- `0x8002b6e0` -> `psx_level_heap_pop_cursor_mark`
|
||||
- `0x80024720` -> `psx_level_runtime_node_pool_init_0x32`
|
||||
- Decompiler comments:
|
||||
- `0x80038f18` (stream runtime-bank install role split and built-resource clear)
|
||||
- `0x80040768` (detached runtime-stream blob format/install semantics)
|
||||
- `0x8003b00c` (compressed-state inflate role, size lane, and termination)
|
||||
- `0x80024720` (0x32-node cyclic runtime-node pool initialization)
|
||||
|
||||
## Live MCP Follow-Up (2026-04-13): Late Art-Bank Dual Feed and Constructor `0x58` Raw-Header Fast Path
|
||||
|
||||
- Scope for this focused pass: `wdl_resource_bundle_load_by_index` (`0x80039444`), late write sites `0x8003977c` / `0x80039a64`, `psx_install_type_art_active_header_and_built_resource` (`0x80045ffc`), `psx_create_image_resource_from_descriptor` (`0x80044434`), constructors `0x80024ab4` / `0x80024fac`, and sibling packed-stream helper `psx_stream_install_type_runtime_banks` (`0x80038f18`).
|
||||
- `wdl_resource_bundle_load_by_index` does not leave `DAT_800758d8` from one monolithic late art bank. For each WDL pass (`SPEC_A.WDL` first, selected `LSET*.WDL` second), it performs two distinct art-facing installs:
|
||||
- an earlier art-install blob (`header` field used as `local_a0`) that calls `psx_install_type_art_active_header_and_built_resource`
|
||||
- a later header-only override blob (`header` field used as `local_98`) whose `8`-byte rows write raw active-header pointers directly into `DAT_800758d8[type]`
|
||||
- The earlier art-install blob is now role-exact but still only medium confidence for raw standalone parsing:
|
||||
- `psx_install_type_art_active_header_and_built_resource` first stores the incoming header pointer to `DAT_800758d8[type]`
|
||||
- it then resolves kind `4` versus kind `5` resource build and writes the materialized resource to `DAT_800758c8[type]`
|
||||
- it finally mirrors that built resource pointer back into `DAT_800758d8[type]`
|
||||
- practical consequence: this pass is an install/build lane, not the final raw-header state seen by constructors after load completes
|
||||
- The later header-only override blob is the safer standalone parsing target and now has a tighter in-memory schema:
|
||||
- blob header begins with `count` and a directory offset
|
||||
- payload base is `blob + 0x08`
|
||||
- directory rows are `8` bytes each and are consumed as `(active_header_size, type_id)`
|
||||
- when `active_header_size != 0`, loader stores the current payload cursor to `DAT_800758d8[type]`
|
||||
- when `active_header_size == 0`, loader clears `DAT_800758d8[type]`
|
||||
- payload cursor then advances by `active_header_size`
|
||||
- Constructor-side reuse closure is now disassembly-backed and corrects an older decompiler-shaped reading: both constructors branch on `*(DAT_800758d8[type]) == 0x58`, not on `kind == 5`.
|
||||
- `0x80024b0c`: simple constructor raw-header fast path
|
||||
- `0x80025004`: compound constructor raw-header fast path
|
||||
- when the first dword is `0x58`, constructors treat `DAT_800758d8[type]` as a raw active header and reuse `DAT_800758c8[type]` instead of calling `psx_create_image_resource_from_descriptor`
|
||||
- `psx_create_image_resource_from_descriptor` remains the per-instance fallback builder for descriptors that do not arrive on that raw-header fast path. Its role did not change, but the exact condition for constructor reuse is now narrower and stronger.
|
||||
- `psx_stream_install_type_runtime_banks` still matters as a sibling negative-evidence lane: it proves there is a separate packed per-type bank format with a fixed `0x14` entry header `(type_id, state_size, component_size, extents_size, active_art_header_size)`. That stream format should not be conflated with the later `8`-byte header-only override blob used by `wdl_resource_bundle_load_by_index`.
|
||||
|
||||
Candidate standalone raw-schema read after this pass:
|
||||
|
||||
- High confidence: the late header-only override blob is the final post-load source that leaves raw `0x58`-byte active headers in `DAT_800758d8`, and its row walk is `8`-byte `(size,type)` with payloads packed immediately after the blob header.
|
||||
- Medium confidence: those `0x58`-byte active headers are the right standalone parser target for executable-faithful direct art binding because constructors discriminate on `0x58` and then reuse `DAT_800758c8`.
|
||||
- Low to medium confidence: the earlier art-install blob also feeds the same type lane, but its raw on-disk row encoding is still unresolved for standalone parsing because the runtime walk consumes pointer-like aux entries without an intervening relocation helper.
|
||||
|
||||
Conservative live-artifact updates applied in Ghidra for this pass:
|
||||
|
||||
- Decompiler comments:
|
||||
- `0x8003977c` (late header-only override writes raw active-header pointers)
|
||||
- `0x80039a64` (map-local repeat of the same override lane)
|
||||
- `0x800460d4` (built-resource mirror into `DAT_800758d8` is later overwritten by header-only pass)
|
||||
- `0x80024b0c` (simple constructor `0x58` raw-header fast path)
|
||||
- `0x80025004` (compound constructor `0x58` raw-header fast path)
|
||||
|
||||
## Live MCP Follow-Up (2026-04-13): Visibility Routing, Stage Lane Choice, and Main-Visible Ordering
|
||||
|
||||
- Scope for this focused pass: active PSX `SLUS_002.68` around `psx_object_integrate_motion_and_route_visible` (`0x800131a8`), neighboring player/object update corridor (`0x8001263c..0x80013688`), and main-visible ordering helpers centered on `0x8002be6c`, `0x8002c89c`, `0x8002ca74`, `0x8002d778`, and `0x8002e064`.
|
||||
- Route split is now pinned as object-local in executable terms: `psx_object_integrate_motion_and_route_visible` chooses stage-2 only when `type==4` or `obj+0x1c` has bit `0x0400`; otherwise it remains in stage-1 main-visible projection/sort lane.
|
||||
- In the same function, policy table reads (`DAT_800675f8[type]`) are downstream gating and ordering controls, not lane selectors. The key stage route decision remains the object-local `0x0400` branch.
|
||||
- Main-visible ordering is now graph-explicit: `psx_main_visible_order_compare_pair_for_graph` computes relation codes from projected extents and policy bits, `psx_main_visible_order_graph_link_new_object` records edges, and `psx_main_visible_list_sort_range` resolves a dependency-eligible ordered slice while unlinking conflicts.
|
||||
- Stage-1 ordering is therefore not a simple distance sort. It is a dependency-graph sort with policy-biased tie resolution, and that graph order feeds the main-visible draw lane.
|
||||
|
||||
Conservative live-artifact updates applied in Ghidra for this pass:
|
||||
|
||||
- Renames:
|
||||
- `0x8002cd60` -> `psx_main_visible_order_graph_release_node`
|
||||
- `0x8002ce38` -> `psx_main_visible_order_graph_compact_nodes`
|
||||
- `0x8002cf3c` -> `psx_main_visible_order_graph_reset_node_slot`
|
||||
- `0x8002cfb0` -> `psx_main_visible_order_graph_swap_node_slots`
|
||||
- Decompiler comments:
|
||||
- `0x800131a8` (stage-1 vs stage-2 route split for exporter lane choice)
|
||||
- `0x8002be6c` (pair-order relation semantics and policy bit role)
|
||||
- `0x8002d778` (dependency-aware main-visible sort behavior)
|
||||
- `0x8002cd60` (node release semantics)
|
||||
- `0x8002ce38` (node compaction/prune semantics)
|
||||
- `0x8002cf3c` (node slot reset semantics)
|
||||
- `0x8002cfb0` (node slot swap semantics during compaction)
|
||||
|
||||
Exporter-facing implication from executable evidence:
|
||||
|
||||
- A standalone JS exporter should keep route lane and order phase separate in diagnostics and matching:
|
||||
- lane selection key: `type==4 || (obj+0x1c & 0x0400)`
|
||||
- stage-1 ordering key family: graph relation codes plus policy-adjusted compare/unlink behavior
|
||||
- Flattening stage-1 order to simple Y/depth or ignoring graph edge pruning will diverge from executable main-visible draw order even when lane choice is correct.
|
||||
|
||||
## Live MCP Follow-Up (2026-04-13): Kind-4/Kind-5 Palette Selection Field Closure
|
||||
|
||||
- Scope for this focused pass: active PSX `SLUS_002.68` around `psx_resource_bind_single_image_vram_slot` (`0x800444e4`), `image_bundle_load_to_vram` (`0x80044614`), and submitters `psx_sprite_resource_submit_frame` (`0x80044bdc`) / `psx_image_table_submit_frame` (`0x80044e9c`) with lane callers in `psx_draw_main_visible_object` (`0x80041458`) and `psx_draw_special_visible_queue` (`0x80041144`).
|
||||
- Default CLUT source for both kind-4 and kind-5 remains resource field `resource+0x08`, seeded from descriptor/bundle header `+0x14` during bind.
|
||||
- No additional per-frame resource header field in the `0x800444e4/0x80044614` bind corridor directly selects CLUT index at submit time; frame-table records in this corridor drive geometry/payload upload, not palette-bank selection.
|
||||
- One additional resource header field does materially affect palette-routing semantics: resource format (`resource+0x04`, sourced from header `+0x10`) changes sprite override behavior.
|
||||
- format `== 2`: override token uses `psx_clut_override_table_by_palette_token[token]` directly.
|
||||
- format `!= 2`: override token is remapped as a bank-table row key in `psx_clut_table_by_resource_bank` (`(token<<4)` halfword lane).
|
||||
- Submit high-byte token source remains draw-lane/object-authored, not resource-header-local:
|
||||
- main-visible may inject authored high byte (`source+0x06` for `0x003e..0x00ab`, `source+0x0c` for `>=0x00ac`).
|
||||
- special-visible does not inject authored high byte.
|
||||
|
||||
Conservative live-artifact updates applied in Ghidra for this pass:
|
||||
|
||||
- Decompiler comments:
|
||||
- `0x800444e4` (kind-4 default palette-bank seed from header `+0x14`)
|
||||
- `0x80044614` (kind-5 default palette-bank seed and format-2 `+0x10` offset behavior)
|
||||
- `0x80044bdc` (sprite submit default/override CLUT resolution split)
|
||||
- `0x80044e9c` (image-table submit default/override CLUT resolution)
|
||||
|
||||
Exporter-facing implication from executable evidence:
|
||||
|
||||
- Standalone palette selection should treat header `+0x14` as the default bank key only.
|
||||
- Additional CLUT selection must come from runtime submit flags (lane/object authored token), with sprite format-aware override routing.
|
||||
- Do not infer palette index from frame-table width/height/origin/offset fields in the bind/upload helpers; those fields are geometry/payload metadata, not CLUT selectors.
|
||||
|
|
@ -426,7 +426,7 @@ Functions and globals inspected in this pass:
|
|||
- `psx_lzss_unpack_into_level_buffer` (`0x8003b00c`, renamed this pass)
|
||||
- `psx_lzss_pack_level_buffer` (`0x8003aba8`, renamed this pass)
|
||||
- `psx_load_type_state_banks` (`0x8003917c`)
|
||||
- `psx_cache_type_art_descriptor_and_resource` (`0x80045ffc`)
|
||||
- `psx_install_type_art_active_header_and_built_resource` (`0x80045ffc`)
|
||||
- section-0 authored dispatch:
|
||||
- `psx_dispatch_section0_dispatch_roots` (`0x800256b0`)
|
||||
- `psx_dispatch_section0_constructor_placements` (`0x800258cc`)
|
||||
|
|
@ -603,7 +603,7 @@ Functions/data inspected in this pass:
|
|||
- `psx_object_select_state_from_transition_table`
|
||||
- `psx_object_integrate_motion_and_route_visible`
|
||||
- `psx_draw_main_visible_object`
|
||||
- `psx_cache_type_art_descriptor_and_resource`
|
||||
- `psx_install_type_art_active_header_and_built_resource`
|
||||
- `psx_level_post_load_runtime_reset`
|
||||
- `psx_section0_dispatch_root_seed_marker_channel_table`
|
||||
|
||||
|
|
@ -1033,7 +1033,7 @@ The resource creation/submission lane is now explicit enough to treat as stable
|
|||
|
||||
### Creation and per-type cache
|
||||
|
||||
- `psx_cache_type_art_descriptor_and_resource` (`0x80045ffc`) stores the per-type descriptor at `DAT_800758d8[type]` and materialized drawable resource at `DAT_800758c8[type]`.
|
||||
- `psx_install_type_art_active_header_and_built_resource` (`0x80045ffc`) first stores the incoming active header at `DAT_800758d8[type]`, then materializes and caches the drawable resource at `DAT_800758c8[type]`, and temporarily mirrors that built resource back into `DAT_800758d8[type]` until the later header-only override stream restores raw `0x58`-byte headers.
|
||||
- Exact kind branch in this cache helper:
|
||||
- `0x80046048`: `kind == 4` -> `psx_resource_bind_single_image_vram_slot` (`0x800444e4`)
|
||||
- `0x80046054`: `kind == 5` -> allocate bundle wrapper and call `image_bundle_load_to_vram` (`0x80044614`)
|
||||
|
|
|
|||
|
|
@ -36,6 +36,20 @@ Extractor-relevant clarified schema in this pass:
|
|||
- `psx_lzss_pack_level_buffer` is the save-side counterpart (caller `0x80049890`) and repacks the same level-state lane, confirming this blob family is persistent runtime substrate rather than a direct authored placement stream.
|
||||
- `psx_load_type_state_banks` installs per-type runtime payload pointers into `psx_type_state_script_bank` / `psx_type_simple_component_bank` / `psx_type_companion_extents_bank`; constructors consume `psx_type_simple_component_bank[type]` at `0x80024c60` to seed object behavior program fields.
|
||||
|
||||
## 2026-04-13 Live Subordinate Section Deltas
|
||||
|
||||
Live MCP pass on active `SLUS_002.68` tightened the first genuinely concrete subordinate-section read for the still-unresolved level bundle lanes:
|
||||
|
||||
- `psx_apply_deferred_control_command` reads both `psx_ctor_placement_section_ptr` (`DAT_80067938`) and `psx_level_section_pack_base` (`DAT_80067838`).
|
||||
- The function treats constructor-placement-adjacent data as an index lane: it reads a `u16` from `(psx_ctor_placement_section_ptr - 2) + index*2`, multiplies it by `8`, and then walks `8`-byte rows from `psx_level_section_pack_base + index*8` until a row with `bit15` set in the leading halfword terminates the chain.
|
||||
- Those `8`-byte rows are not renderer-facing floor cells. They are consumed as deferred world/control mutation records and are fanned out into both `psx_apply_deferred_control_to_dispatch_roots` and `psx_apply_deferred_control_to_live_objects`, where they mutate authored root records and already-instantiated live objects by type/id and small state bytes.
|
||||
- Adjacent subordinate lane `psx_control_opcode_stream_table` (`DAT_80067840`) is also now tighter: `psx_control_assign_opcode_stream_by_index` reads it as a pointer/offset table for nested control opcode streams and transition/state-machine setup, not as geometry.
|
||||
|
||||
Practical consequence for region-02 work:
|
||||
|
||||
- At least part of the broad "missing map" hypothesis for this area is now closed in the negative direction. The subordinate slices installed from the level section pack are already proven to include deferred control/event infrastructure and opcode-stream pointers, not just hidden floor or wall placement tables.
|
||||
- For `LSET1/L0.WDL`, the raw `post_audio_region_02` leading bytes also reinforce that read: the region begins with mixed/high-entropy payload rather than a clean count-prefixed offset table or plausible direct `0x0c` placement rows. Current safest read is that region `02` is a mixed resource/control payload zone that must be split into smaller typed sub-lanes before any floor-specific decode claim is credible.
|
||||
|
||||
## 2026-04-12 Live Section-0 Descriptor Dispatch Deltas
|
||||
|
||||
Live MCP pass on active `SLUS_002.68` tightened section-0 record-family dispatch evidence for unresolved graphics-heavy types.
|
||||
|
|
|
|||
|
|
@ -739,7 +739,7 @@ Exporter status after the next renderer pass:
|
|||
|
||||
Next decoded runtime layers from the constructor pass:
|
||||
|
||||
- `DAT_800758d8` is the per-type art/template bank, not the missing whole-map substrate. `wdl_resource_bundle_load_by_index` populates it from an `8`-byte descriptor table, and both `FUN_800249f4` and `FUN_80024eec` consume it before calling `FUN_80044434` through the loader-side helper path.
|
||||
- `DAT_800758d8` is the per-type active-art-header bank, not the missing whole-map substrate. `wdl_resource_bundle_load_by_index` feeds it from two distinct late art-facing sections per WDL pass: an earlier build/install lane and a later `8`-byte header-only override lane. The later override is what leaves raw `0x58`-byte active headers in `DAT_800758d8`, and both constructors consume that final state before deciding whether to reuse `DAT_800758c8` or call `FUN_80044434`.
|
||||
- `DAT_800758d0` is a per-type companion/component bank for the simpler constructor family. `FUN_800249f4` copies the resolved pointer from that bank into the local object payload at `obj->8->[0,4]`, so this looks like a per-type component/template block rather than a top-level placement stream.
|
||||
- `DAT_800758cc` is a per-type offset-table bank for the compound constructor family. `FUN_80024eec` stores it at `obj+0x88`, and `FUN_800260e8` later indexes it with the placement byte at `record+0x08` to resolve a state/offset subrecord into `obj+0x8c/0x90`.
|
||||
- `DAT_800758d4` is another per-type companion bank for the compound constructor family. `FUN_80024eec` stores it at `obj+0x84`, and `FUN_8002841c` queries it later using the object's `+0x94` selector, so it behaves like a variant table or companion lookup rather than raw map geometry.
|
||||
|
|
|
|||
22
docs/psx/vram-dump-bundle-grounding.md
Normal file
22
docs/psx/vram-dump-bundle-grounding.md
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
# PSX VRAM Dump Bundle Grounding
|
||||
|
||||
## Scope
|
||||
|
||||
- Active dump-grounding target: `binary/Crusader - No Remorse (USA) GPU RAM 2.bin`
|
||||
- Immediate goal: keep a short evidence log for bundle ids that are visibly present in live PSX VRAM so bundle export/palette work can stay anchored to known runtime art.
|
||||
|
||||
## Known Bundles
|
||||
|
||||
- `bundle_00b3158`: chest NE, appears in the dump
|
||||
- `bundle_0011ad4c`: generator, appears in the dump
|
||||
- `bundle_0015b80`: part of a console, appears in the dump
|
||||
|
||||
## Current Palette Rule
|
||||
|
||||
- For dump-grounded `mode 1` bundle export, prefer the live GPU RAM CLUT slice at row `0xF0`, `x=0..255`, treated as one contiguous `256`-entry palette.
|
||||
- This is the same rule already recorded in `docs/psx/psx.md` for the verified cabinet console family and is now the first palette source to test before falling back to WDL-local palette heuristics.
|
||||
|
||||
## Follow-Up
|
||||
|
||||
- Map these absolute bundle ids back to extracted `out/psx_wdl_disc/.../sprite_bundles` directories when their owning WDL/region is identified.
|
||||
- Add matching framebuffer/VRAM crop evidence here as specific bundles are confirmed.
|
||||
Loading…
Add table
Add a link
Reference in a new issue