A map record is an Entity::MakeMessage (MUNGA/ENTITY3.h): classToCreate, owningPlayerID, resourceID, instanceFlags, localOrigin. The origin ends the 76-byte case, which puts classToCreate at +28, resourceID at +40 and instanceFlags at +44. I had been reading +44. That is instanceFlags, and it is 524 on every scenery record - and 524 happens to be cn3's GaugeImage. So every track resolved to cn3 repeated a few hundred times, consistently and wrongly, and every conclusion drawn from that followed: the "one wall bar with a gate", the ticks, the claim that the LOD machinery is never exercised. The id at +40 varies per placement. The tracks use cn1, cn3, cn4, cn5, cn7, br1, br3, ft1, cq1, cq2, md3, md4, the pits, and the score zones sc50/sc50a/sc500a that gave the amber boxes at each end. A record names the model's Model List; the GaugeImage is filed under the same model name, so the name is the join - and models with no gauge image (oao, snAwork, pz1) are skipped here exactly as DrawStatic skips them. Found by following the map loader: InterestManager::LoadMapStream reads the stream as MakeMessages and names the map entity classes, one of which is 95 in these records - CulturalIconClassID.
Regenerating the reference pages
docs/vtv-presets.html and docs/tracks.html are generated from
assets/RP411/RPL4.RES, the gauge config, and the console's RPConfig.xml.
Both are committed, so this is only needed when the resource file changes.
Both need a resource listing from the original tool, which is the authority for resource ids — the directory can be walked in file order, but the ids have holes (this file leaves 53 and 56 unassigned) so the walk has to be aligned against the listing:
Release\RPL4TOOL.exe -l assets\RP411\RPL4.RES > listing.txt # ends in _getch(); close it
python tools\pages\extract_presets.py vtv.json listing.txt
python tools\pages\build_page.py vtv.json docs\vtv-presets.html
python tools\pages\build_tracks.py listing.txt docs\tracks.html
RPL4TOOL finishes with _getch() (RP_L4/RPL4TOOL.cpp), so with stdout
redirected it writes the whole listing and then waits for a keypress —
close it once the file stops growing.
What each reads
| script | reads | writes |
|---|---|---|
extract_presets.py |
RES, L4GAUGE.CFG, tools/console-config/RPConfig.xml, listing |
vtv.json |
build_page.py |
vtv.json, GAUGE/s*.pcc silhouettes |
docs/vtv-presets.html |
build_tracks.py |
RES, listing, RPConfig.xml, RPL4FE.cpp catalogs, tracks.css/js/tpl |
docs/tracks.html |
build_tracks.py reads the front end's own kMaps / kFootballMaps arrays
so the page cannot claim a track is offered when the menu does not offer it.
Two formats worth knowing
Control mappings. A vehicle's ControlsMappings List holds the resource
ids of its L4 and Thrustmaster streams. Streams are named plainly, so
there is nothing in a stream saying whose it is — resolve by id, never by
which vehicle name sits nearest in the file. Records are 24 bytes and carry
their own mode mask; bits 3–8 are ModePreset1..6.
Map instances. 76-byte records: class id at +0, position at +48, unit quaternion at +60. A few records are longer, so resync on an unexpected class id rather than trusting the stride. The quaternion doubles as a checksum — a mis-read almost never produces a unit one.