Documentation progress
This commit is contained in:
parent
7f935809b6
commit
5f22a8e2fd
13 changed files with 307 additions and 13 deletions
75
docs/map-renderer-shared-scene-data.md
Normal file
75
docs/map-renderer-shared-scene-data.md
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
# Map Renderer Shared Scene Data
|
||||
|
||||
The map-viewer originally embedded a large amount of game-level data into every per-map `scene.json`. The first obvious duplication was `shapeDefinitions`, but the real repeated payload was larger: the same catalog-derived shape metadata, sprite metadata, and atlas packing output were being rebuilt and reserialized for each map.
|
||||
|
||||
The current layout moves that shared data to per-logical-game reference payloads and keeps per-map scenes focused on actual level content.
|
||||
|
||||
## What Was Repeated Per Map
|
||||
|
||||
- `shapeDefinitions[]` was repeated in every map scene even though each definition is derived from logical game data, not map-local state.
|
||||
- `shapeDefinitions[].catalogEntry`, `catalogOverrides`, and `tableFallback` were repeated anywhere the same shape appeared.
|
||||
- `sprites[]` metadata was repeated per map even though sprite records are also game-level assets.
|
||||
- Atlas packing output was effectively repeated per map because each map serialized or referenced its own local atlas build even when the packed sprite set overlapped heavily with other maps from the same logical game.
|
||||
- `metadata.gameLabel` repeated catalog data that the viewer can recover from the selected game entry.
|
||||
- `metadata.usage.tableAddress`, `metadata.usage.entryCount`, and `metadata.usage.baseMaps` repeated mission-table data already available through the shared `mission-map-data.json` cache.
|
||||
- `metadata.usage.game` and `metadata.usage.map` duplicated `metadata.game` and `metadata.map`.
|
||||
|
||||
## What Changed
|
||||
|
||||
- Build-cache output now stays under `.cache`.
|
||||
- Shared reference payloads are built once per logical game under `.cache/reference-data/<referenceId>/`.
|
||||
- Static export copies those already-built shared payloads into:
|
||||
- `map_renderer/site/data/reference-data/<referenceId>.json`
|
||||
- `map_renderer/site/data/reference-atlases/<referenceId>/atlas-*.png`
|
||||
- Per-map `scene.json` files now carry map-specific scene data plus a compact `references` block:
|
||||
- `references.referenceId`
|
||||
- `references.atlasIds[]`
|
||||
- `references.spriteIds[]`
|
||||
- `references.shapeDefinitionIds[]`
|
||||
- The shared reference payload now contains the full game-level asset metadata needed to hydrate compact scenes:
|
||||
- `shapeDefinitions[]`
|
||||
- `sprites[]`
|
||||
- `atlases[]`
|
||||
- Static export no longer writes per-map atlas copies.
|
||||
- Dynamic loading now reuses the same per-game shared references and shared atlas files instead of treating atlas generation as map-local output.
|
||||
- `metadata.gameLabel` is no longer serialized into static map scenes; the viewer rehydrates it from the selected catalog entry.
|
||||
- Mission-table fields already present in `mission-map-data.json` are no longer duplicated into each static map scene usage block.
|
||||
|
||||
## Why This Split Is Safe
|
||||
|
||||
- `buildShapeDefinition(...)` depends only on game-level inputs, not map-local state.
|
||||
- Sprite metadata and atlas placement are functions of the logical game's referenced asset set, so they can be cached once and reused across maps.
|
||||
- Items already reference shapes indirectly through `shapeDefId`, so map scenes only need the referenced ids, not inline copies of the full definitions.
|
||||
- Catalog edits are already scoped per logical game (`remorse`, `regret`), so the shared reference payload matches the existing catalog model.
|
||||
- Versioned releases like `remorse`, `remorse-101`, `remorse-demo`, and `remorse-jp` already share a logical catalog id, so they also share the same reference payload.
|
||||
|
||||
## Measured Duplication Before The Change
|
||||
|
||||
From the earlier generated static site:
|
||||
|
||||
- `remorse`: about 10.08 MB of serialized shape-definition JSON repeated across 63 maps
|
||||
- `remorse-101`: about 10.08 MB repeated across 63 maps
|
||||
- `remorse-jp`: about 10.08 MB repeated across 63 maps
|
||||
- `regret`: about 6.13 MB repeated across 38 maps
|
||||
|
||||
Those totals only covered serialized `shapeDefinitions`. They did not include the repeated sprite metadata, atlas duplication, or the extra metadata duplication removed from static map scenes.
|
||||
|
||||
## New Layout
|
||||
|
||||
- Per-map scene: map-specific items, bounds, map source, scene summaries, and compact references only.
|
||||
- Per-game reference data: shape definitions, sprite metadata, atlas metadata, catalog-derived names and flags, and dtable fallbacks.
|
||||
- Shared atlas images: one atlas set per logical game, copied from `.cache/reference-data/<referenceId>/` into the static site only during explicit export.
|
||||
- Global caches that remain global: `mission-map-data.json`, `npc-spawner-data.json`, and the CSV catalog exports.
|
||||
|
||||
## Cache And Export Behavior
|
||||
|
||||
- `npm run build-cache` without `--game` or `--map` clears `.cache` first and rebuilds from scratch.
|
||||
- `build-cache` can warm multiple logical games in parallel via `--threads=`.
|
||||
- `--threads=0` means auto, `--threads=-1` forces serial execution, and a positive value caps worker concurrency.
|
||||
- Dynamic scene builds first try to reuse shared per-game reference data and only rebuild that global data when the fingerprint is stale or the required referenced ids are missing.
|
||||
- Static export clears `site` and then copies the already-built shared reference data out of `.cache` instead of regenerating separate per-map atlas payloads.
|
||||
|
||||
## Notes
|
||||
|
||||
- Dynamic and static loading remain backward-compatible because the viewer accepts both older inline scenes and the newer compact reference-based scenes.
|
||||
- The scene JSON download button in the viewer still exports the fully hydrated in-memory scene, which remains useful for inspection even though the on-disk static representation is compact.
|
||||
|
|
@ -38,5 +38,7 @@ The tooltip now exposes generalized metadata for editor/helper objects instead o
|
|||
|
||||
- Add dedicated filters or list views for helper subfamilies such as invisible walls, camera markers, light bridges, and placeholder cubes.
|
||||
- Add shape-family frequency summaries so repeated helper markers can be audited across a map.
|
||||
- Decode more shape-specific field semantics for unresolved editor objects like `0x04B1`, `0x0011`, `0x04C9`, `0x04CA`, and `0x04E3`.
|
||||
- Find the No Regret replacement for the Remorse `0x024F` monster-egg workflow instead of assuming the same shape is reused.
|
||||
- Decode more shape-specific field semantics for the still-unresolved editor objects, especially the remaining non-promoted invisible-wall, camera/helper, and music-controller families, and keep folding any new results back into the dedicated USECODE-link note.
|
||||
- Find the No Regret replacement for the Remorse `0x024F` monster-egg workflow instead of assuming the same shape is reused.
|
||||
|
||||
`0x04B1` now has a stable `CMD_LINK -> TRIGGER.slot_20` viewer target, and `0x04E3` is already promoted as `SKILLBOX::equip`, so they no longer belong in the unresolved editor-object bucket here.
|
||||
|
|
@ -73,6 +73,21 @@ ScummVM's generic egg intrinsics expose:
|
|||
|
||||
So family `4` eggs use `mapNum` as their generic egg id in the engine interface.
|
||||
|
||||
Current Crusader viewer work now closes one additional family-4 detail for the `0x0011` placements used as usecode-trigger eggs:
|
||||
|
||||
- `quality & 0xFF` is the subtype selector for the authored family-4 usecode class.
|
||||
- The runtime resolves that class as `0x0900 + QLo`.
|
||||
- The currently verified authored subtype sets are:
|
||||
- Remorse: `QLo 0, 1, 2, 13` -> `TRIGEGG`, `ONCEEGG`, `FLOOR1`, `MISS1EGG`
|
||||
- Regret: `QLo 0, 1, 2, 5, 8, 10, 13, 24` -> `TRIGEGG`, `ONCEEGG`, `FLOOR1`, `MHATCHER`, `CHANGER`, `DOOREGG`, `MISS1`, `VIDEOEGG`
|
||||
- `npcNum` does not behave like a DTABLE row here.
|
||||
- `xRange = (npcNum >> 4) & 0x0f`
|
||||
- `yRange = npcNum & 0x0f`
|
||||
- Crusader multiplies those range nibbles by `64` world units.
|
||||
- The runtime trigger check also uses a `+/-48` Z window.
|
||||
|
||||
That is why the renderer now treats `0x0011` as a proximity/usecode-trigger egg with a projected footprint overlay, a subtype-aware USECODE landing point, and only the narrower local-arrow rules that are actually justified by the recovered subtype body.
|
||||
|
||||
### Monster eggs
|
||||
|
||||
ScummVM's monster egg accessor exposes:
|
||||
|
|
@ -422,18 +437,18 @@ What helps in the editor:
|
|||
- show the `mapNum`/`mapArray` byte in hex because it behaves like a flag lane selector here
|
||||
- describe the four resulting trigger lanes explicitly
|
||||
|
||||
### `0x04F8` frame `0`: door death helper
|
||||
### `0x04F8` frame `0`: destroyable-door helper
|
||||
|
||||
This shape still lacks a clean No Remorse class label in the recovered tables, but the door-side behavior is already concrete enough to expose in the editor.
|
||||
|
||||
- `DOOR.slot_23` iterates nearby `shape=0x04F8` items after the door damage/crush path
|
||||
- `DOOR.slot_23` iterates nearby `shape=0x04F8` items after the door damage path
|
||||
- it matches them by `Item.getQLo(deathBox) == Item.getQLo(arg_06)`
|
||||
- it dispatches `TRIGGER.slot_20` on lane `0` when `Item.getMapArray(deathBox) == 0`
|
||||
- otherwise it dispatches the `0x80`-offset lane
|
||||
|
||||
Current best read:
|
||||
|
||||
- `0x04F8` is a door-side death or crush trigger helper
|
||||
- `0x04F8` is a door-side helper that lets authored doors become destroyable and then forward into trigger logic
|
||||
- `QLo` is the local door/link key
|
||||
- the map-array byte chooses the normal trigger lane versus the `+0x80` variant
|
||||
|
||||
|
|
@ -728,7 +743,7 @@ That overlay is intentionally narrower than the existing verified teleport/eleva
|
|||
|
||||
- `ALARMHAT (0x0561) -> nearby 0x04D0` helpers, using the recovered local alarm scan behavior
|
||||
- `STEAMBOX (0x0500) -> nearby steam-family targets`, matched by shared `QLo`
|
||||
- `0x04F8 -> nearby door-family targets`, matched by shared `QLo` and local placement
|
||||
- `0x04F8 -> nearby destroyable door-family targets`, matched by shared `QLo` and local placement
|
||||
- `BRO_BOOT (0x04FE) -> nearby SPANEL targets`, matched by shared `QLo`
|
||||
- `PANELNS (0x00A1)`, `CARD_NS (0x031D)`, and `SPANEL (0x03AA) -> nearby 0x04B1` controller helpers when they share the same local `QLo`
|
||||
- `BOX_EW (0x0080) frame 0 -> nearby 0x04B1` controller helpers when they share the same local `QLo`
|
||||
|
|
|
|||
|
|
@ -207,10 +207,10 @@ Examples:
|
|||
## Remaining Uncertainty
|
||||
|
||||
- This note closes where the `0x04D0` NPC list lives and how to recover names, but it does not yet prove every gameplay path that can instantiate those DTABLE rows.
|
||||
- `0x04B1` has strong trigger/link evidence but still needs a fuller write-up tying its item fields to specific map-editing behavior.
|
||||
- `0x04B1` now has a stable map-viewer USECODE landing point (`CMD_LINK -> TRIGGER.slot_20`), but it still needs a fuller write-up tying its item fields to specific map-editing behavior.
|
||||
- `0x0011` is still only partially characterized here; it is clearly in the egg/editor lane, but its relationship to `npcNum` remains unresolved.
|
||||
- Shape `0x04D0` still uses the `MONSTER` usecode class in the old disassembly corpus, so there is still room to document how that script/controller layer cooperates with the DTABLE-backed actor creation path.
|
||||
|
||||
## TODO
|
||||
|
||||
- Do a deeper pass on `0x04B1` and `0x0011` so the raw `npcNum` field can be documented more precisely without overfitting DTABLE assumptions.
|
||||
- Do a deeper pass on `0x04B1` and `0x0011` so the raw `npcNum` field and the `CMD_LINK` linkage fields can be documented more precisely without overfitting DTABLE assumptions.
|
||||
196
docs/map_renderer/trigger-usecode-links.md
Normal file
196
docs/map_renderer/trigger-usecode-links.md
Normal file
|
|
@ -0,0 +1,196 @@
|
|||
# Map Viewer Object -> USECODE Links
|
||||
|
||||
This note records the current evidence-backed USECODE targets surfaced by the map viewer for pinned editor/controller objects and a small set of non-editor gameplay objects with verified active usecode lanes.
|
||||
|
||||
The implementation uses extracted `class_event_index.tsv` results plus existing controller notes rather than filename guesses. The viewer resolves an exact `{ className, slot / eventNameHint }` pair against the generated usecode cache index and then opens the matching pseudocode body in the USECODE tab.
|
||||
|
||||
## Stable Viewer Targets
|
||||
|
||||
| Shape / class | Viewer target | Why this body is the right inspection point |
|
||||
|---|---|---|
|
||||
| `BOX_EW` (`0x0080`) | `BOX_EW::use` (`slot 0x01`) | Recovered switch body that dispatches the local `QLo` link into `TRIGGER.slot_20`. |
|
||||
| `0x0011` family-4 usecode egg | Dynamic per `QLo`: `TRIGEGG::hatch`, `ONCEEGG::hatch`, `FLOOR1::enterFastArea`, `MHATCHER::hatch`, `DOOREGG::hatch`, and other authored subtype bodies | The runtime resolves family-4 egg classes as `0x0900 + QLo`, so the viewer now opens the exact subtype-selected body instead of treating every `0x0011` as one generic placeholder. |
|
||||
| `MONITNS` (`0x0102`) | `MONITNS::use` (`slot 0x01`) | Existing gameplay notes tie shape `258` / `0x0102` to a live monitor/computer-adjacent use handler, making it a strong non-editor first-view script target. |
|
||||
| `MONITEW` (`0x0165`) | `MONITEW::use` (`slot 0x01`) | Disasm crosswalks shape `0x0165` to the east-west monitor variant, which keeps the same live computer-adjacent use handler family. |
|
||||
| `PANELNS` (`0x00A1`) | `PANELNS::use` (`slot 0x01`) | Verified panel-switch wrapper for the same nearby trigger-helper chain. |
|
||||
| `NPCTRIG` (`0x0363`) | `NPCTRIG::equip` (`slot 0x0A`) | Crosswalked shape/class match; the compact slot-`0x0A` body is still the strongest active-event frontier for this trigger family. |
|
||||
| `CRUZTRIG` (`0x0365`) | `CRUZTRIG::gotHit` (`slot 0x06`) | Disasm crosswalks shape `0x0365` to CRUZTRIG, and `gotHit` is the recovered live body for this trigger/helper family. |
|
||||
| `VMAIL` (`0x0367`) | `VMAIL::slot_0a` (`slot 0x0A`) | Disasm crosswalks shape `0x0367` to VMAIL; slot `0x0A` is the active helper body even though its final semantic label is still weaker than the slot number. |
|
||||
| `CARD_NS` (`0x031D`) | `CARD_NS::use` (`slot 0x01`) | Thin wrapper into the downstream `SWITCH` / `TRIGGER` path. Regret also exposes `cast`, but `use` remains the stable first inspection point. |
|
||||
| `SPANEL` (`0x03AA`) | `SPANEL::use` (`slot 0x01`) | Same local `QLo`-keyed switch/controller family as `PANELNS` and `CARD_NS`. |
|
||||
| `FASTSKIL` (`0x0120`) | `FASTSKIL::enterFastArea` (`slot 0x0F`) | Difficulty-gated trigger router, including the verified `QLo`, `QLo + 1`, and `QLo + 2` remap lane. |
|
||||
| `SKILLBOX` (`0x04E3`) | `SKILLBOX::equip` (`slot 0x0A`) | Corpus-backed skill-gated controller body; this is the active recovered lane, not `enterFastArea`. |
|
||||
| `CHEST_NS` (`0x054F`) | `CHEST_NS::use` (`slot 0x01`) | The live chest-open handler runs the animation/audio path and the same general FREE-backed content-spawn flow as the east-west chest family. |
|
||||
| `CHEST_EW` (`0x0550`) | `CHEST_EW::use` (`slot 0x01`) | The live chest-open handler runs the animation/audio path and a FREE-backed content-spawn flow, making it a useful general gameplay object target even though it is not editor-centric. |
|
||||
| `EVENT` (`0x0361`) | `EVENT::equip` (`slot 0x0A`) | Large multiplexer body used by the generic event-controller family. |
|
||||
| `NPC_SPAWNER_04D0` (`0x04D0`, frame `0`) | `MONSTER::enterFastArea` (`slot 0x0F`) | Frame-0 spawners participate in the verified MONSTER auto-enter-area lane when map bit `0x08` is clear, so this is now the right first inspection point for authored 0x04D0 placements. |
|
||||
| `TIMER` (`0x04C9`) | `TIMER::enterFastArea` (`slot 0x0F`) | Fast-area timer helper; the first active body arms slot `0x20` from qHi enter/leave flags and the packed `mapNum:npcNum` delay payload. |
|
||||
| `SPECIAL` (`0x04CA`) | `SPECIAL::enterFastArea` (`slot 0x0F`) | Fast-area phase helper; the active entry body reads `mapNum` / `npcNum` as phase bytes and `qHi` as the delay byte before fanning out through `TRIGGER.slot_20` and `SPECIAL.slot_21`. |
|
||||
| `TRIGPAD` (`0x04CD`) | `TRIGPAD::gotHit` (`slot 0x06`) | Occupancy/surface-gated trigger-pad logic lives in the recovered `gotHit` body. |
|
||||
| `NPC_ONLY` (`0x0366`) | `NPC_ONLY::gotHit` (`slot 0x06`) | Active hit-driven helper lane from the extracted class/event table. |
|
||||
| `FLAMEBOX` (`0x0403`) | `FLAMEBOX::equip` (`slot 0x0A`) | Recovered flame-controller body scans nearby flame helper shapes by shared `QLo` and can swap helper markers into live flame actors. |
|
||||
| `SFXTRIG` (`0x04E2`) | `SFXTRIG::slot_0a` (`slot 0x0A`) | Disasm crosswalks shape `0x04E2` to the compact event-bearing SFXTRIG helper; slot `0x0A` is the stable active body even though a precise semantic label is still weaker than the slot number. |
|
||||
| `DEATHBOX` (`0x04E7`) | `DEATHBOX::slot_0a` (`slot 0x0A`) | The recovered helper body matches death-link `QLo` and forwards NPC death events into `TRIGGER` lanes, so opening the helper body is now more useful than leaving the shape unmapped. |
|
||||
| `BRO_BOOT` (`0x04FE`) | `BRO_BOOT::enterFastArea` (`slot 0x0F`) | Verified helper body scans nearby `SPANEL` items by shared `QLo`, applies ITEM control slots, and runs the boot animation loop. |
|
||||
| `STEAMBOX_HAZARD_CONTROLLER` (`0x0500`) | `STEAMBOX::equip` (`slot 0x0A`) | Recovered hazard-controller body matches nearby steam helpers by shared `QLo` and routes them through event `0` / `1` control lanes. |
|
||||
| `ALARMHAT` (`0x0561`) | `ALARMHAT::equip` (`slot 0x0A`) | Local alarm scan that walks nearby `0x04D0` helper items. |
|
||||
| `ALRMTRIG` (`0x0581`) | `ALRMTRIG::equip` (`slot 0x0A`) | Alert relay that selects `TRIGGER` lanes from map-array and world-alert state. |
|
||||
| `CMD_LINK` (`0x04B1`, `TRIGGER`) | `TRIGGER::slot_20` (`slot 0x20`) | High-slot fan-out entry used by nearby controller families; the named low event slots are empty here, so the viewer jumps straight to the first verified active high slot. |
|
||||
|
||||
## Current Rule For `TRIGGER`
|
||||
|
||||
`TRIGGER` is the one intentional special case.
|
||||
|
||||
The extracted class/event tables show no active named slots in the `0x00..0x1f` range for `TRIGGER`, but they do show populated higher slots `0x20..0x2b`. Existing renderer notes and exported pseudocode both point to `TRIGGER.slot_20` as the shared entry that nearby controller shapes keep spawning when they match on local `QLo` or phase lane.
|
||||
|
||||
That is why the viewer opens `TRIGGER.slot_20` for pinned `0x04B1` helpers instead of trying to invent a named event label that the corpus does not support.
|
||||
|
||||
`TRIGGER.slot_20` is still not fully decoded. The current body is the right landing point for inspection, but several loose or nearly empty branches remain in the recovered pseudocode, especially in the `local_04 == 1`, `local_04 == 2`, and parts of the `local_04 == 3` fan-out.
|
||||
|
||||
## Practical Result In The Viewer
|
||||
|
||||
- Pinned controller objects and the small set of promoted gameplay objects now expose a `USECODE` action in the tooltip.
|
||||
- The action switches the workspace to the USECODE tab.
|
||||
- The USECODE viewer resolves the exact class/slot target against the generated cache index instead of relying on fuzzy filename search.
|
||||
- `0x0011` usecode-trigger eggs now decode their `npcNum` nibble-packed X/Y ranges, resolve `QLo` into the authored family-4 class, open the matching subtype body in the USECODE tab, and draw arrows only for the narrower subtype families whose local target scans are actually recovered.
|
||||
|
||||
`0x04F8` remains intentionally outside the `USECODE` target list for now. The current evidence says it is a destroyable-door helper scanned by `DOOR.slot_23`, not a proven standalone usecode class the viewer should open directly.
|
||||
|
||||
## Newly Decoded Field Notes
|
||||
|
||||
### `0x0011` usecode-trigger egg
|
||||
|
||||
- The active exported family-4 `0x0011` records are proximity/usecode-trigger eggs, not DTABLE NPC spawners.
|
||||
- `mapNum` remains the egg id.
|
||||
- `quality & 0xFF` is the subtype selector for this family.
|
||||
- The runtime resolves the usecode class as `0x0900 + QLo`.
|
||||
- Current authored subtype sets are:
|
||||
- Remorse: `0, 1, 2, 13` -> `TRIGEGG`, `ONCEEGG`, `FLOOR1`, `MISS1EGG`
|
||||
- Regret: `0, 1, 2, 5, 8, 10, 13, 24` -> `TRIGEGG`, `ONCEEGG`, `FLOOR1`, `MHATCHER`, `CHANGER`, `DOOREGG`, `MISS1`, `VIDEOEGG`
|
||||
- `npcNum` packs `xRange = high nibble` and `yRange = low nibble`.
|
||||
- Crusader multiplies each nibble by `64` world units and uses a `+/-48` Z window for the trigger test.
|
||||
- `TRIGEGG` and `ONCEEGG` route into `TRIGGER.slot_20` on hatch/unhatch, so the renderer now draws local arrows to nearby `0x04B1` helpers by shared `QLo`.
|
||||
- Regret `MHATCHER` scans nearby frame-0 `0x04D0` helpers whose `QLo` matches the egg id in `mapNum`, so the renderer now draws that local helper lane too.
|
||||
- Regret `DOOREGG` scans nearby family-1 door objects whose `QLo` matches the egg id in `mapNum`, so the renderer now exposes that local door lane.
|
||||
- `FLOOR1`, `CHANGER`, `MISS1*`, and `VIDEOEGG` remain subtype-aware in the tooltip and USECODE target, but they do not yet justify a generic local-arrow rule.
|
||||
|
||||
### `0x04C9 TIMER`
|
||||
|
||||
- The disasm corpus identifies usecode class `1225` as `TIMER`.
|
||||
- `enterFastArea` and `leaveFastArea` only arm the worker lane; `TIMER.slot_20` performs the wait loop and then fans out into `TRIGGER.slot_20` with phases `0x80` or `0x81`.
|
||||
- `mapNum:npcNum` pack the base timer payload as a 16-bit tick count.
|
||||
- `qHi >> 5` selects one of the trim percentages `0, 10, 25, 40, 50, 60, 75, 90`, and the worker subtracts that percentage from the packed delay before waiting.
|
||||
- The low `qHi` bits act as control flags: bit `0` controls repeat-vs-clear, bit `1` arms on enter-fast-area, bit `2` arms on leave-fast-area, while bits `3` and `4` steer later routing branches inside the worker.
|
||||
|
||||
### `0x04CA SPECIAL`
|
||||
|
||||
- The disasm corpus identifies usecode class `1226` as `SPECIAL`.
|
||||
- `enterFastArea` / `leaveFastArea` use `mapNum` and `npcNum` as small phase/control bytes rather than DTABLE rows.
|
||||
- `qHi` acts as the delay byte used by `SPECIAL.slot_21`, while `QLo` remains the local link byte.
|
||||
- `SPECIAL.slot_21` can temporarily add `3` to `QLo`, route through `TRIGGER.slot_20`, then restore the original `QLo`.
|
||||
- This is enough evidence to promote `SPECIAL::enterFastArea` as the stable first-view body even though some higher-phase cases still live deeper in slot `0x21`.
|
||||
|
||||
### `0x04B1 CMD_LINK`
|
||||
|
||||
- `QLo` is the local link id.
|
||||
- `QHi` low three bits choose subcommand `0..6`, and the upper five bits carry the subcommand argument.
|
||||
- `mapNum` low bits decode mode, item-targeting flag, phase lane, and low-priority behavior.
|
||||
- `mapNum` high bits plus `npcNum` build the 11-bit target code used for exact-shape matching or family sentinels.
|
||||
- `nextItem` still appears in authored records, but this pass did not recover a stable standalone semantic for it beyond the existing TRIGGER fan-out path.
|
||||
|
||||
## Editor Catalog Sweep
|
||||
|
||||
The viewer catalog currently marks 39 Remorse shapes and 48 Regret shapes as `editor` objects. The tables below record which entries already have a viewer integration target and which still need examination before they should grow a `USECODE` link.
|
||||
|
||||
### Shared Editor Objects
|
||||
|
||||
| Shape | Catalog name | Status |
|
||||
|---|---|---|
|
||||
| `0x0011` | `(unnamed)` | Integrated: dynamic family-4 USECODE target from `QLo`, plus local arrows for the recovered `TRIGEGG` / `ONCEEGG`, `MHATCHER`, and `DOOREGG` lanes. |
|
||||
| `0x0060` | `INVISIBLE_WALL_UW` | Needs examination for usecode-link integration |
|
||||
| `0x0061` | `INVISIBLE_WALL_NS` | Needs examination for usecode-link integration |
|
||||
| `0x0062` | `INVISIBLE_WALL_EW` | Needs examination for usecode-link integration |
|
||||
| `0x00f1` | `BROKEN_OVERLAY` | Needs examination for usecode-link integration |
|
||||
| `0x0120` | `FASTSKIL` | Integrated: `FASTSKIL::enterFastArea` |
|
||||
| `0x017d` | `PLACEHOLDER_KEY_CUBE` | Needs examination for usecode-link integration |
|
||||
| `0x0193` | `SPECIAL_FIRE_WALL` | Needs examination for usecode-link integration |
|
||||
| `0x01b0` | `LIGHT_BRIDGE_V` | Needs examination for usecode-link integration |
|
||||
| `0x01b1` | `LIGHT_BRIDGE_H` | Needs examination for usecode-link integration |
|
||||
| `0x0200` | `NUMBERS` | Needs examination for usecode-link integration |
|
||||
| `0x0361` | `EVENT` | Integrated: `EVENT::equip` |
|
||||
| `0x0403` | `FLAMEBOX` | Integrated: `FLAMEBOX::equip` |
|
||||
| `0x04b1` | `CMD_LINK` | Integrated: `TRIGGER::slot_20` |
|
||||
| `0x04c9` | `TIMER` | Integrated: `TIMER::enterFastArea` |
|
||||
| `0x04ca` | `SPECIAL` | Integrated: `SPECIAL::enterFastArea` |
|
||||
| `0x04d0` | `NPC_SPAWNER_04D0` | Integrated: `MONSTER::enterFastArea` for frame-0 placements |
|
||||
| `0x04e2` | `SFXTRIG` | Integrated: `SFXTRIG::slot_0a` |
|
||||
| `0x04e3` | `SKILLBOX` | Integrated: `SKILLBOX::equip` |
|
||||
| `0x04e7` | `DEATHBOX` | Integrated: `DEATHBOX::slot_0a` |
|
||||
| `0x04fe` | `BRO_BOOT` | Integrated: `BRO_BOOT::enterFastArea` |
|
||||
| `0x0561` | `ALARMHAT` | Integrated: `ALARMHAT::equip` |
|
||||
| `0x0500` | `STEAMBOX_HAZARD_CONTROLLER` | Integrated: `STEAMBOX::equip` |
|
||||
| `0x0581` | `ALRMTRIG` | Integrated: `ALRMTRIG::equip` |
|
||||
| `0x05a0` | `HIDENSEEKR` | Needs examination for usecode-link integration |
|
||||
| `0x05a1` | `DOOMSDAY_COUNTER` | Needs examination for usecode-link integration |
|
||||
| `0x05b2` | `MUSIC_CONTROLLER_05B2` | Needs examination for usecode-link integration |
|
||||
| `0x05b3` | `MUSIC_CONTROLLER_05B3` | Needs examination for usecode-link integration |
|
||||
| `0x05b4` | `MUSIC_CONTROLLER_05B4` | Needs examination for usecode-link integration |
|
||||
| `0x05b5` | `MUSIC_CONTROLLER_05B5` | Needs examination for usecode-link integration |
|
||||
| `0x05b6` | `MUSIC_CONTROLLER_05B6` | Needs examination for usecode-link integration |
|
||||
| `0x05b7` | `MUSIC_CONTROLLER_05B7` | Needs examination for usecode-link integration |
|
||||
| `0x05b8` | `MUSIC_CONTROLLER_05B8` | Needs examination for usecode-link integration |
|
||||
| `0x05b9` | `MUSIC_CONTROLLER_05B9` | Needs examination for usecode-link integration |
|
||||
| `0x05ba` | `MUSIC_CONTROLLER_05BA` | Needs examination for usecode-link integration |
|
||||
| `0x05bb` | `MUSIC_CONTROLLER_05BB` | Needs examination for usecode-link integration |
|
||||
| `0x05bc` | `MUSIC_CONTROLLER_05BC` | Needs examination for usecode-link integration |
|
||||
| `0x05bd` | `MUSIC_CONTROLLER_05BD` | Needs examination for usecode-link integration |
|
||||
| `0x05be` | `MUSIC_CONTROLLER_05BE` | Needs examination for usecode-link integration |
|
||||
|
||||
### Remorse-Only Editor Objects
|
||||
|
||||
No currently unresolved Remorse-only editor rows remain in this note after the `NPCTRIG` crosswalk promotion.
|
||||
|
||||
### Regret-Only Editor Objects
|
||||
|
||||
| Shape | Catalog name | Status |
|
||||
|---|---|---|
|
||||
| `0x00cf` | `HAND` | Needs examination for usecode-link integration |
|
||||
| `0x01d6` | `MUTANT_HOOK_CONTROL` | Needs examination for usecode-link integration |
|
||||
| `0x0451` | `GIMP_DISPENSER` | Needs examination for usecode-link integration |
|
||||
| `0x0510` | `SECRET_DOOR_POST` | Needs examination for usecode-link integration |
|
||||
| `0x0548` | `SECRET_DOOR_SWITCH` | Needs examination for usecode-link integration |
|
||||
| `0x056d` | `STEAM_COLLISION_SWITCH` | Needs examination for usecode-link integration |
|
||||
| `0x05ae` | `VOLCANO_CONTROLLER` | Needs examination for usecode-link integration |
|
||||
| `0x05df` | `PRESSURE_BARRIER_V` | Needs examination for usecode-link integration |
|
||||
| `0x05e0` | `PRESSURE_BARRIER_H` | Needs examination for usecode-link integration |
|
||||
| `0x05e1` | `PRESSURE_BARRIER_SWITCH` | Needs examination for usecode-link integration |
|
||||
|
||||
## Remaining Steps
|
||||
|
||||
The next map-viewer USECODE passes should stay evidence-backed and prioritize items that either still appear as generic editor placeholders in the catalogs or already have partial reverse-engineering notes that are not yet promoted into the viewer.
|
||||
|
||||
### Highest Priority
|
||||
|
||||
1. Extend the `0x0011` subtype table beyond the currently promoted `TRIGEGG` / `ONCEEGG`, `FLOOR1`, `MHATCHER`, `DOOREGG`, `MISS1*`, and `VIDEOEGG` lanes only when the recovered pseudocode justifies a reusable viewer target or arrow rule.
|
||||
2. Do the `SURCAMNS` / `SURCAMEW` placement crosswalk so the renderer can decide whether placed `0x04c6` / `0x04de` objects deserve a direct USECODE jump or should remain callback-holder-only families.
|
||||
3. Finish the remaining `CMD_LINK` field write-up: the current tooltip now decodes `quality`, `mapNum`, and `npcNum`, but `nextItem` still lacks a stable standalone semantic beyond appearing in authored controller records.
|
||||
|
||||
### Catalog And Viewer Cleanup
|
||||
|
||||
1. Sweep the remaining shared editor/controller shapes in the catalog table and promote the next solid names instead of leaving `(unnamed)` placeholders where the disasm or extracted corpus already gives a stable class anchor.
|
||||
2. Revisit the `0x05b2`-`0x05be` music-controller cluster and decide whether those shapes belong in the USECODE viewer backlog, a scene-audio note, or both.
|
||||
3. Recheck the Regret-only controller shapes (`HAND`, `MUTANT_HOOK_CONTROL`, `GIMP_DISPENSER`, `SECRET_DOOR_*`, `STEAM_COLLISION_SWITCH`, `VOLCANO_CONTROLLER`, `PRESSURE_BARRIER_*`) against the extracted class/event table before adding any direct links.
|
||||
|
||||
### Gameplay Coverage Extensions
|
||||
|
||||
1. Verify whether non-frame-0 `0x04d0` placements have a second stable inspection target or should stay documented as paired/helper states only.
|
||||
2. Revisit helper families that already have partial notes but no viewer promotion yet, especially the invisible-wall/editor-wall lane and any camera/helper markers that forward into event-trigger classes rather than acting as pure geometry.
|
||||
3. When a family differs by game, keep the stable cross-game viewer target by default and only add game-specific fallback event names after the extracted corpus proves the divergence.
|
||||
|
||||
### Validation Rules For Future Passes
|
||||
|
||||
1. Keep renames grounded in a direct shape/class crosswalk, exported body evidence, or an existing note with clear provenance.
|
||||
2. After each promotion, rerun the renderer cache build and update this note's sweep tables in the same batch so the backlog stays current.
|
||||
3. Do not promote callback-holder families like `SURCAMNS` / `SURCAMEW` as ordinary active-event objects unless the placed-shape behavior is established, not just the class name.
|
||||
|
||||
Current limitation: if a future build changes the active body for a class in one game only, the viewer still prefers the stable cross-game target above and only uses explicit fallback event names where already justified by the extracted corpus.
|
||||
|
|
@ -813,4 +813,10 @@ That gets to a reversible editor sooner than waiting for a full semantic VM reco
|
|||
- **Regression Coverage:**: Added a focused renderer-side regression script at [scripts/test-usecode-structuring.mjs](k:/ghidra/crusader_map_viewer/map_renderer/scripts/test-usecode-structuring.mjs) to guard one equality-based selector case and one counted-loop case.
|
||||
- **Next Steps:**: Rebuild a fresh renderer usecode cache and inspect representative families like `BART`, `_BOOT`, and `EVENT` for any remaining cases where other compare producers still leak VM-oriented phrasing.
|
||||
|
||||
If you want, I can (a) implement the comparison/operand polarity fix next, (b) run the unit tests and a fresh corpus sweep, and (c) open a PR-ready commit with these doc and code updates.
|
||||
## **Recent Renderer Work (2026-04-01)**
|
||||
|
||||
- **Root Cause Closed:**: `TRIGGER.slot_20` was still falling back to labeled blocks in the map-viewer JS renderer because the full structurer did not preserve outer exit labels across nested regions, did not lift raw `foreach_list ... -> exit` iterator loops, and only recognized bare one-line `return;` blocks as return exits.
|
||||
- **Renderer Fixes:**: [src/lib/usecode-decompiler.js](k:/ghidra/crusader_map_viewer/map_renderer/src/lib/usecode-decompiler.js) now propagates enclosing exit labels through nested structured regions, lifts raw `foreach_list` / `foreach_slist` loops into structured `while (true)` bodies, and treats comment-prefixed cleanup-plus-return blocks such as `/* free_local_list */` + `return;` as real return targets for control-flow recovery.
|
||||
- **Readability Impact:**: The remorse cache file [TRIGGER/slot_20_slot_20.txt](k:/ghidra/crusader_map_viewer/map_renderer/.cache/usecode/remorse/EUSECODE/pseudocode/TRIGGER/slot_20_slot_20.txt) now renders as one structured function: the initial phase/setup lane is straight-line `if/else`, the middle search fan-out is structured nested conditionals, the nearby `0x04B1` scan is a real `for item in nearby_items(...)` loop, and the follow-up low-priority trigger worklist is a structured fixed-point `while (1)` loop rather than detached `block_XXXX` labels.
|
||||
- **Regression Coverage:**: [scripts/test-usecode-structuring.mjs](k:/ghidra/crusader_map_viewer/map_renderer/scripts/test-usecode-structuring.mjs) now covers three additional generic structuring cases and one real-data regression that decodes `STATIC/EUSECODE.FLX`, rebuilds the live `TRIGGER.slot_20` IR, and asserts that the rendered pseudocode no longer falls back to block labels or `goto block_...` jumps.
|
||||
- **Binary / Ghidra Impact:**: This pass tightened renderer-side control-flow recovery only. It did not add a new compiled-side VM decode, so no new Ghidra rename or comment was applied in `CRUSADER.EXE` during this batch.
|
||||
Loading…
Add table
Add a link
Reference in a new issue