The navmesh that wasn't Inferred
Does Legend of Legaia keep a navmesh - a table of walkable-area records - in RAM? No. The 1700-byte cluster that changes on every area load, which reads plausibly as a table of 24-byte records, is a per-scene scratch buffer the renderer fills with assembled GPU primitive data on scene entry. This page records the falsification, and where the game's real pathing data lives, so nobody re-derives the navmesh reading from the same evidence.
At a glance
- What it is
- A negative finding: the RAM window
0x80108EA4..0x80109550is a renderer scratch buffer, not a navmesh table - Where the real pathing data is
- The per-scene walkability grid (field locomotion), the MAN region boxes, and the tile-board grid for the puzzle mode - table below
- Parser
- none (nothing to parse); reproduction via
mednafen-state extract+scripts/mednafen/pointer-hunt.py - Confidence
- Inferred - zero pointers into the window across three save states; the contents match GP0 packet shapes
Falsified readings across the whole project are collected on do-not-re-walk; this page keeps the full reasoning for the one that looked most like real data.
The decisive test: nothing points at it
A real navmesh table would be consulted through a stable base-pointer cell somewhere in RAM. A pointer-hunt over the full 2 MiB of main RAM, for any u32 pointing into the window, returns zero hits in all three save states (mc1 field, mc2 battle, mc3 field). No overlay slot, SCUS data segment, kernel stack or runtime heap holds the table base. The buffer is consumed by code that knows its address as a compiled-in constant (a MIPS LUI+ADDIU immediate pair inside the renderer), not via indirection.
What the bytes actually are
Three shapes appear across the captures, none matching a record table:
- Repeating constant runs. In the
map01field state, the window holds a uniform u16 sequence (0c 00repeated, then0d 00, then0e 00) with no record structure. - GPU-packet shapes. In the other two states, 12-byte runs mirror the GP0 packet header + RGB-colour + delta-position layout the PSX renderer emits (GP0 packets are the raw draw commands sent to the PlayStation GPU): the canonical TMD primitive flag/mode/code/ilen quartet, RGB colour triplets, and signed byte deltas at the i16 positions.
- Overwritten wholesale. All three states show different shapes at the same offset. Stable per-scene records would persist; a working buffer is refilled on scene entry.
Where the pathing data really lives
| System | Data | Details |
|---|---|---|
| Town / field locomotion + collision | Per-scene walkability tile grid: one byte per 128-unit tile, 4 sub-cell wall bits, reached through a scratchpad base pointer | Field locomotion |
| Puzzle / board minigame | Tile-board grid (cell 2 = wall), installed inline by field-VM op 0x49 | Field/event VM |
| Per-scene region / zone boxes | 18-byte records in the MAN control block, queried by player tile; the payload is a camera preset, not pathing data | Camera-region table |
| Encounter arming | Record pointer in the actor slot +0x94 | Encounter record, world map |
How we know
| Evidence | Instrument | What it shows |
|---|---|---|
| Zero inbound pointers | pointer-hunt.py into-window over three save states | No RAM cell holds the window's base - a table nobody indexes is not a table. |
| Six adjacent pointers | Same hunt widened to 0x80108000..0x8010A000 | Pointers target neighbouring offsets (0x80108398, 0x80108BC8, 0x80108C2C, 0x80108C38) - the sprite-batcher's own structures, not the scratch region. |
| Byte shapes | mednafen-state extract RAM dumps | Contents match GP0 draw-packet layout, and differ wholesale across scenes. |
Reproducing the negative finding
./target/release/mednafen-state extract <mc1.mc1> --start 0x80000000 --end 0x80200000 --out /tmp/ram_mc1.bin
./target/release/mednafen-state extract <mc3.mc3> --start 0x80000000 --end 0x80200000 --out /tmp/ram_mc3.bin
python3 scripts/mednafen/pointer-hunt.py into-window /tmp/ram_mc1.bin \
--target-lo 0x80108EA4 --target-hi 0x80109550 --exclude-self
python3 scripts/mednafen/pointer-hunt.py into-window /tmp/ram_mc3.bin \
--target-lo 0x80108EA4 --target-hi 0x80109550 --exclude-self
Both invocations return zero hits. The narrow bounds match the original navmesh reading; widen to 0x80108000..0x8010A000 to surface the adjacent sprite-batcher pointers.
History: how the navmesh reading arose
The cluster was spotted by diffing two area-load save states: 1700 bytes differed, which is how scene-resident data shows up - but also how any working buffer repopulated on scene entry shows up. A leading id / kind record interpretation fit one state's bytes and broke on the other two. Structural inference from a single diff pair is the trap; the pointer hunt is the test that settles it.