Skip to content

Hand-placed instances (.pvs)

ForzaTechWorld and streamingApplies toFH6

Everything not placed by a .pgeo rule is in one file per track, Ribbon_00\<track>_00.pvs: prefab sign gantries, viaduct decks and bridges, landmarks, platforms, rocks, the Houdini-generated buildings, roofs, plinths and cables (hda_* folders), the heightfield terrain clusters, distance proxies and the vista backdrops. The executable’s RTTI names the types PVSModelInstance and PVSVisibleModelInstance. Observed

Two files of the install are version 0xA4: brio_00.pvs (42,782,135 bytes) and Stripped\gs\generalsceneassets.pvs (381,229 bytes), which is the header and texture descriptors only. Both read to their last byte under the layout below, every constant holding and every reference (an instance’s transform, parent, gameplay record, frame and LOD rows; a LOD row’s model; a transform’s clip and LOD profile group; a texture key’s descriptor; a clip record’s file) pointing inside what it refers to, on every record. Proven · both files The homespace02 file (82,789 bytes) is version 0x63, a different layout. Observed Counts are those of brio_00.pvs.

Little-endian, in order; every boundary comes from a count in the file and is asserted where the next section starts, with no searching. Observed

Section Content Confidence
header 0x21 bytes: SVPF, u32 0xA4, u32 8, u32 0, u32 0, u8 world (1 when the world sections are present, 0 for the texture-only file), u32 6, a u32 (14,000,000 in Brio, 0 in the general file), u32 0 Proven
megatextures u8 0, 1,476 × 8 B entries, u32, u8 1, then 1,476 × { u32 len, name, u32, u32 } Proven
bounds u32, u32, u32 n (76,907), n × 29 B { u32, u8 (0 or 0xFF), f32 centre[3], f16[4], u16 0, i16 } Proven
gameplay records u32, u32, u32 n (120,225), u32 count (1,079), then { u8 nRoutes, u8 season mask, u16 routes[nRoutes], i32 link, cstring tag } Proven
per-pgeo-id u32 n + i32[n] (mostly −1), u32 n + u8[n] (0xFF or 0x01) Proven
index tables u32 0, u32 k (5), k × { u32 own index, u32 n, i32[n] }; 15,104 entries each in Brio Proven
fixed block 49 bytes, u32 n + n × 8 B, u8 0 Proven
texture descriptors u32 n (48,733 in Brio; 6,807 in the general file) × 56 B Proven
shaders, materials u32 n × { u32 hash, u32 len, path }, twice (46 shaders, 419 materials) Proven
models u32 n (134,330) + u32[n] Proven
cells u32 n (41,106) × 12 B { u32 reference, u32 reference, u8 level, u8[3] = 0 }, see Cells Proven
dependency blocks u32 n (17,560) × { u32 k, k × 8 B } Proven
frames u32 n (5,489) × 48 B: the ModulateConstants table (below) Proven
transforms u32 n (111,452) × 58 B (below) Proven
LOD rows u32 n (593,706) × { u32 model, u32 instance }, sorted by instance; model = brioout.N Proven
LOD profiles u32 groups (155) × { u32 n, n × 50 B }, 2,232 records; see LODs and clusters Proven
instances u32 n (154,254) × 35 B (below) Proven
model bounds u32 0, u32 n (= models, 134,330) × the record below Proven
tail u32 len + brioout, u8[3], 14 animation clip names, u32 0 × 3, u32[3], 48,733 × { u32 key, u32 descriptor } (keys strictly increasing, the descriptors a permutation of the texture descriptors), u8 0, 5 clip files { u64 hash, string path }, 14 clip records { u32 id, u64 file hash, u32[3] }, u32 Proven

The shader and material paths are game:\media\tracks\brio\bin\<name>, where <name> is the Name of the bin.zip asset manifest (bin\ is the archive), on all 465 names. :proven The loose manifest lists the file’s textures, models and instances: its model numbers are the file’s, and every LOD row is named by one of its Instance elements. Proven

The meaning of the index tables, the fixed block, the dependency blocks, the per-pgeo-id tables and the tail’s u32 words is not established: the bytes are read and accounted for. Unknown

PVS transform record58 bytesFH6100% known

Little-endian. Row-vector 3×3 with the scale baked in; apply as p' = p · M + pos, also for the world-baked Houdini pieces, which share one 90°-about-Y record.

ProvenObservedSourcedInferredUnknownNot described
OffsetSizeTypeFieldConfidenceNotes
0x02u16animation clip indexObserved0xFFFF for none; below the number of clip names in the tail
0x22u16clip index repeatProvenequal to the u16 at 0 on all 111,452 transforms
0x41u8no-group flagProven0 when the transform has a LOD profile group, 1 when it has none (byte 56 is 0xFF); both on all 111,452 transforms
0x512f32[3]positionObserved
0x1118f16[9]matrixObserved
0x2316f32[4]tintObservedtint.x is the likely source of INSTANCE_VARIATION (the swatch palette row, read as it is) for hand-placed instances: see Environment, The palette read
0x334u32 = 0zeroProven
0x371u8material variantObservedrow of the Modl variant table
0x381u8LOD profile groupProven0xFF for none; otherwise below the number of LOD profile groups (155)
0x391u8group mirrorProven0 with a LOD profile group, 0xFF without
PVS instance record35 bytesFH683% known
ProvenObservedSourcedInferredUnknownNot described
OffsetSizeTypeFieldConfidenceNotes
0x04u32unknownUnknown
0x42u16flagsObserved0x40 = catalogue copy
0x62u16unknownUnknown
0x84i32transform indexProvenbelow the number of transforms on all 154,254 instances
0xC4i32HLOD parentProven-1 = none, else an instance index
0x101u8HLOD flagProven1 exactly when the HLOD parent is set, else 0xFF
0x112i16gameplay recordProven-1 = none, else an index into the gameplay records
0x134i32 = -1minus oneProven
0x174u32first LOD rowProventhe first row of the instance; the first rows ascend and the rows between them belong to the instance
0x1B6u8[6]band rowsProvenper LOD profile band, the index (counted from the first row) of the LOD row drawn there; 0x7F = nothing
0x212u16frameProvenindex into the frames table

An instance’s models are the LOD rows from its first row to the next instance’s. Proven Model number N is the id of a ChunkMap record of type 4 (a .modelbin, all of them in GeoChunk0): the ids of all 113,868 type-4 records are model numbers below the 134,330 of the file’s list, so the record names the exact file, template and LOD cluster. The other 20,462 model numbers have no entry in the install, and 19,436 of them are used by LOD rows (of the 130,240 model numbers the rows use). Proven · brio_00.pvs and the four chunk maps A checked 1% sample of 1,098 multi-LOD instances shows band k names the row whose model LOD is k (or repeats the previous row) in 1,096; the two others have no LOD0 row (rows LOD1 to LOD4, band 0 points at LOD1). So the model drawn close up is the one named by band 0, not the first row. Observed

Frames (ModulateConstants). A 48-byte record { float4 c0 = (origin xyz, absolute world, 0), float4 c1 = (unit axis A, scale), float4 c2 = (axis B, scale) }; record 0 is all zeros (no modulate). For city buildings A is the facade axis, B is (0, 1, 0), the scales are −1/14 (a 14 m repeat) and the origin is the building centre. A frame is indexed by a .pgeo record’s u16 at +0x3E and by a ribbon instance’s frame. Observed

Model bounds. Each record is an oriented box in model space: u32 k, u32[k], u8, f32 centre[3], f16 half[3], f16 axes[9], u16, u8; a corner is centre + Σ ±half_i × axis_i with axis_i row i of the axes, which are orthonormal on every record (83,025 identity, 51,227 rotated). The vertices of 44,976 of 44,987 shipped models with rotated axes lie inside their oriented box; the other 10 are cable LOD2 and LOD3 files that poke out by at most 5.2 cm (plus ocean_vista). Read as an axis-aligned centre ± half only 4,734 do. The boxes contain every vertex of 113,811 of the 113,823 shipped models that carry them. 78 models carry the empty sentinel (centre 0, half −1, −1, −1). One record is saturated: ocean_vista has half (65504, 375, 65504), the largest finite f16, and its vertices reach 30.8 km past that box. Observed

Of the 111,452 transforms, 2,069 have no LOD profile group, and no instance uses one of them. Proven

Each cell record holds two ChunkMap words of type 12. The second names a .pvsz entry of GeoChunk0; the first is the second’s id plus level × 6,851 (level 1, 2 or 3), and names no entry of the install’s four chunk maps. Proven Each of the 13,702 .pvsz entries is the second word of exactly three records, one per level, and the 41,106 first words are all different. Proven · brio_00.pvs and the four chunk maps What the first word refers to, and what the levels mean, is not established. Unknown

Instances with flag 0x40 (3,483 of the 154,254, each with its transform at exactly (0, 0, 0) Proven; 790 of them 0x44) form the catalogue: unplaced template copies, including all 30 el/ (gpy_el_*, evolving world) instances. 43,491 instances in all sit at the origin; being at the origin is not by itself the catalogue rule. Observed Five instances are the trains: an animation clip index on an identity transform at the origin with gameplay record 64 (route 0), positioned at run time along their clip. Observed

An instance’s gameplay record carries routes, a season mask, a link and a tag; 31,918 of 154,254 instances use one. Observed

  • Routes: 0 (speed cameras, XP boards, danger signs, mascots, trailblazer markers, the trains); 500 to 546 paired with 500; 1, 2, 4, 5, 3335, 8003, 8004. Observed
  • link equals PhysicsDefinitionIndex for the ANIM_CM_* records, matching AnimatedCollisionMeshes.xml; other values occur on physics props (reflectors, chairs, smashable boulders). Observed
  • Tags: ESTATE_ENTRANCE_13, BARN_FIND_NIS_Pao_89, [LEGEND_ISLAND_NORTH_GATE_CLOSED] and _OPEN, [BRIDGE_PILLARS], SPEEDCAMERA_07_LEFT, ANIM_CM_E0001_Ambient_HighSpeedTrain_Front. Observed

The 1,079 records end exactly at the per-pgeo-id table. By kind: route and/or tag 1,040 instances, season mask only 5,526, link only 25,352 (physics props). Observed

Classified from data, whole map, summer: Observed

Rule Data Instances
catalogue copy flags & 0x40 3,483
runtime-positioned animation clip index on an identity transform at the origin 5
heightfield clusters any shipped LOD row in scene/tbheightfield/; see Terrain clusters 23,941
not in the main view the LOD profile group has no pass-2 record (group 19: passes 0, 1, 8, 9) 298 with no shipped model; the other 3,153 group-19 instances are the _cb terrain underlays
distance proxy band 0 row is 0x7F; the proxy replaces its HLOD children further away 5,771: all 5,060 hlod_* (4,761 with an HLOD parent), all 244 autouberlod_*, 361 *_genmesh_lod1
no shipped model no band’s model is in ChunkMap0 7,163
stripped LOD0 band 0’s model is not shipped, a later band’s is 194

Whole map, summer: 110,530 instances draw (spring 110,513, autumn 110,520, winter 112,808). Observed

Backdrops. The 167 vista_* instances (distant mountains in models/vista) and the one ocean_vista (models/water, the sea to the horizon, material Vista_Ocean, family ocean_vista) use LOD profile group 63, whose main-view record draws band 0 from 0 to 65,504 m; nothing in their rows, flags or groups marks them far-only. Their triangles lie around and beyond the playable map: of 17,868 near-view terrain clusters (x −9,216..8,192, z −11,264..10,752), the vista triangles (76,785) overlap 304 and the ocean vista’s (7,021) overlap 71, all at the map’s edge. Observed

Of the 12,283 ribbon instances whose model is also placed by a .pgeo, none lies within 1 mm of such a placement and one within 5 cm: the game draws both lists. Observed

What are the index tables, fixed block, dependency blocks and tail words of the .pvs?

They are read to the last byte and their sizes and constants are known, but what they index or drive is not.