CModels and Clipmaps
Asset brain · Engine Integration · SModels · Transient Zones
Status
The Game-Test PDB and Replay database support a named loader chain for clipMap static-model collision records. Replay's corresponding postload route is only partly visible: the source list postloader is exact, but its Replay work is inside a parent-owned code region whose instructions are missing from the SQLite export. Runtime cleanup has an exact DB_ReleaseClipMap body match and a stored Replay WorldCollision_RemoveClipMap row, but the source MAP label is an overload-ambiguous candidate. These parser, postload, and runtime cleanup edges are separate evidence paths; they do not yet prove a complete serialized or runtime CModel layout.
Build identities and evidence boundary
- Game-Test source:
E:\1-game-test\1-game_test.exe, SHA-256269D6137A465DA9D5F5DF68961000D683B9A868FDE5E7800743177C05D059E99; source PDB/MAP evidence is indexed by the Atlas database. - Replay target:
E:\IW8\Builds\1.20-replay\game_dx12_ship_replay.exe, SHA-25668FB1CBCB2924182724004039DE55A4C50152BB6561803C4898B7930B38132F0. - Replay analysis database:
game_dx12_ship_replay.exe.sqlite; the program MD5 recorded by this database is1C238FE327F2ECC3B0DB924C5B425439. This is the database's program MD5, not the executable hash.
Verified loader path: clipMap to static-model collision records
Game-Test Load_clipMap_t (ID 21575)
-> Load_StaticModelCollisionModelList (ID 21538; PDB)
-> 24-byte list record and optional nested model array
-> Load_StaticModelCollisionModel (ID 21536; PDB), 40-byte loop stride
-> script-string name
-> PhysicsAssetPtr
-> XModelDetailCollisionPtr
-> optional 0x1C-byte collision-instance entries
Replay Load_clipMap_t (ID 20057)
-> q_Load_StaticModelCollisionModelList (ID 20052; live SQLite name)
-> same observed 24-byte list-record and 40-byte array roles
-> q_Load_StaticModelCollisionModel (ID 20051; live SQLite name)
-> string, physics-pointer, detail-collision-pointer, and optional instance routes
The source functions are exact PDB rows: Load_StaticModelCollisionModelList at RVA 0x7FBC30 (187 bytes) and Load_StaticModelCollisionModel at 0x7FB950 (252 bytes). Source Load_clipMap_t ID 21575 calls the list helper at 0x7FF186; the list helper calls the child at 0x7FBCC5. In Replay, root ID 20057 at RVA 0xE0FD30 calls list ID 20052 at 0xE0FDFF; the list calls ID 20051 at 0xE0E44E inside the 40-byte-record loop.
The current Replay SQLite rows were checked read-only: ID 20052 is q_Load_StaticModelCollisionModelList, RVA 0xE0E3C0, size 180; ID 20051 is q_Load_StaticModelCollisionModel, RVA 0xE0E2C0, size 245; ID 20057 remains Load_clipMap_t, size 729. Both target extents match the reported Replay .pdata coverage. Source extents are 187 and 252 bytes. Keep those per-build differences and the q prefixes; the correspondences establish function roles, not shared member offsets or a portable serialized ABI. The nested PhysicsAsset helper is itself q-prefixed, which makes that sub-edge less independent.
Evidence: loader-list report, loader-child report, and paired-route observation manifest.
StaticModels CollisionTile shape and unload routes
This StaticModels collision-tile lifecycle is additional runtime-side evidence. Keep it separate from the clipMap_t static-model collision-record parser above: the current reports do not join their records or layouts.
| Replay row | Exact source PDB anchor | Paired route and status |
|---|---|---|
ID 39071 q_StaticModels_AddCollisionTile, RVA 0x139D000, size 480 |
StaticModels_AddCollisionTile ID 63639, RVA 0x1715300, source .pdata 440 bytes |
DB_CreateCollisionTileAsset source/Replay parent bodies match in normalized form; the fourth direct call resolves through source and Replay thunks to the named source body and target row. Child body similarity is very low and source void versus Replay inferred __int64 differs, so q is retained. |
ID 39074 q_StaticModels_CreateCollisionTileShapes, RVA 0x139D680, SQLite size 1471 |
StaticModels_CreateCollisionTileShapes ID 63649, RVA 0x17164E0, source PDB/.pdata 2338 bytes |
ID 39071 passes its original input in RCX to ID 39074. The source parent similarly passes the CollisionTile input to its exact PDB shape builder. Source uses a per-shape helper twice; Replay appears to consolidate shape creation. Replay .pdata totals 1477 bytes, six beyond the stored row size; preserve SQLite size and prototype. |
ID 39075 q_StaticModels_DestroyClipmapShapes, RVA 0x139DC50, size 170 |
StaticModels_DestroyClipmapShapes ID 63655, RVA 0x1717050, PDB/.pdata 244 bytes |
Source/Replay DB_ReleaseClipMap parent bodies match; their first call routes through paired StaticModels_RemoveClipMap wrappers and thence to the source PDB body / Replay ID 39075. Child bodies differ substantially; q retained. |
ID 39097 q_StaticModels_TransientZoneUnloadingMain, RVA 0x139ED90, size 210 |
StaticModels_TransientZoneUnloadingMain ID 63695, RVA 0x171B400, PDB/.pdata 228 bytes |
Both bodies show a zone-index-shaped cleanup path and reach the shape-destruction route; Replay has one indexed incoming caller and body similarity is low. The source bool and Replay char/prototype details are not assumed equivalent; q retained. |
The name mappings are useful for locating collision-tile creation, shape-building, clipmap cleanup, and zone-unload entry points. They do not establish a shared CollisionTile struct, serialized layout, ABI, physics-world identity, or that this path consumes the clipMap static-collision records described above. In particular, the source StaticModels_CreateCollisionTileShapes has another caller, while a corresponding Replay caller is not indexed; Replay's helper split may differ.
Evidence: AddCollisionTile route and apply manifest; shape-builder route and apply manifest; clipmap-shape destroy route and apply manifest; transient-zone unload route and apply manifest.
Postload path: source exact, Replay boundary held
On Game-Test, exact PDB ID 22263 Postload_StaticModelCollisionModelList (RVA 0x8234D0, size 287) is called by Postload_clipMap_t ID 22301 at 0x8272C7. The source helper handles the 0x18-byte list record, resolves/allocates the model array, advances by 40 bytes per model, and calls source Postload_StaticModelCollisionModel.
Replay currently stores ID 20153 at RVA 0xE17A60 as q_Postload_clipMap_t, size 727. Its optional list-processing region is represented as a jump-out in the SQLite export. The report locates a parent-owned .pdata interval [0xE17B2F,0xE17BDC) (173 bytes); after that interval the root calls q_Postload_MapEntsPtr at 0xE17BFF. No separately indexed Replay helper or direct call edge proves that the hidden region is the source static-model list routine. Treat inline postload parsing as a plausible explanation, not a completed Replay mapping. Do not rename ID 20153 or attach the source list name to another target row on this evidence.
A separate sibling parser is better mapped: Replay ID 20130 is currently q_Postload_MapTriggers, RVA 0xE151C0, size 834, with three incoming indexed parents including ID 20153. It postloads trigger collections and has a physics-pointer child route. This proves a trigger-collection postload edge from clipMap, not the static-model collision-list postloader and not the runtime consumer for its PhysicsAsset references.
Evidence: static-model list postload hold and MapTriggers postload report.
Runtime collision lifecycle: cleanup evidence is separate
A paired DB_ReleaseClipMap parent is strong build-to-build evidence: the Game-Test source candidate at RVA 0xC06C70 and Replay ID 24635 at RVA 0xF60000 both have 55-byte extents and identical normalized instruction streams. The live Replay row is named DB_ReleaseClipMap; its callgraph has five outgoing indexed calls, one targeting stored Replay row ID 40587 at RVA 0x1491860, currently named WorldCollision_RemoveClipMap (50 bytes). The incoming callgraph census for ID 40587 shows DB_ReleaseClipMap as its indexed direct caller.
The target removal body and the selected source MAP candidate both access offsets +0xB8 (4-byte operand) and +0xC0 (8-byte operand). This supports a corresponding field-access path during a clipMap removal/cleanup route. The source candidate is only the largest same-name/module Atlas match and overloads may exist; the Replay function label is a stored-name hypothesis, not an exact PDB identity. The call route does not establish what those fields mean, that they are the static-model collision records, or the full object layout. It is runtime cleanup evidence, not proof of the loader-to-runtime dataflow.
Evidence: clipmap physics evidence manifest, field-access paths, and call/thunk routes.
Holds and next discriminators
- Decode Replay parent-owned interval
[0xE17B2F,0xE17BDC)with IDA chunk ownership and instruction bytes. Check for the 0x18-byte list, 40-byte model loop, and per-record postload child calls before pairing it with source ID 22263. - Resolve source overload ownership for
WorldCollision_RemoveClipMap; then independently verify the Replay row's callers and target body before treating that spelling as a semantic name. - Trace the PhysicsAsset pointer from loaded/postloaded collision records into the runtime registration/use path. Current evidence shows parser child calls and a separate clipMap cleanup route, but no direct edge joining those stages.
- Keep source offsets, Replay offsets, record strides, and complete CModel/clipMap types build-specific until each target field is independently confirmed.
- Replay IDs 20146–20148 remain generic for the trigger/collision postload sibling family: shared physics-child calls do not overcome stride/member-offset conflicts with source
Postload_TriggerModelandPostload_cmodel_tcandidates.
See the postload collision/trigger hold for that competing source/target analysis.