Skip to content

PGZP minizip archives

ForzaTechArchives and filesApplies toFH6

A Forza Horizon 6 track keeps its world (every model, placement table and track texture) in four GeoChunk archives, GeoChunk0.minizip to GeoChunk3.minizip, in the track’s folder under media\Tracks. The format is not a ZIP: the entries have no names inside the archive, only an index, a position and a compression method. The names and the resource types come from companion text and binary files beside the archives. Observed

This page describes the Tokyo track Brio, the only track measured, as Steam build 25588841 ships it. Every statement marked Proven was checked on all four of its GeoChunks: every entry read by a reader that refuses any value the layout below does not allow, and compared field by field with ForzaTools’ reading of the same files. Proven

Chunk Size Entries Holds Confidence
GeoChunk0 39,724,802,048 bytes 411,013 every model, every .pgeo placement file and .pb texture (each with at least its lowest quality tier), terrain cluster models Observed
GeoChunk1 3,573,829,632 bytes 3,065 no .modelbin; its other contents (the models, placements and .pb textures are in chunks 0 to 2) are not described separately Unknown
GeoChunk2 49,414,393,856 bytes 79,840 higher quality tiers of textures, including the largest terrain cell maps (mainmap q5) and the top.dxt near-field layer files Observed
GeoChunk3 4,762,284,032 bytes 1,476 only the highest-resolution builtmegatexture records (the .hq* files) Observed

No path appears in two chunks. Observed Only GeoChunk0 holds .modelbin files. Observed

PGZP header32 bytesFH688% known

Little-endian. The folder index follows at 0x20.

ProvenObservedSourcedInferredUnknownNot described
OffsetSizeTypeFieldConfidenceNotes
0x04char[4] = PGZPmagicProven
0x44u32 = 101versionProvenFH5 shipped 100 and 101 per ForzaTools; the FH6 chunks are 101
0x84u32 = 0x20folder index offsetProven
0xC4u32entry countProven411,013 / 3,065 / 79,840 / 1,476 for chunks 0 to 3
0x104u32folder countProven81,657 / 3,065 / 79,840 / 1,476
0x144u32 = 512entries per sub-chunkProven
0x184u32sub-chunk countProvenceil(entry count / 512): 803 / 6 / 156 / 3
0x1C4u32 = 0reservedUnknown0 in all four chunks

After the header comes the folder index: one u32 per folder, the index of the folder’s first entry, then one more u32, the entry count. A folder’s entries run from its value to the next, so the entries of a folder are consecutive and the values never go down; no folder is empty. A zero u32 pads the list to a multiple of 8 bytes (chunks 2 and 3). Proven Then come the sub-chunks, and right after the directory (the end of the list below) the first entry’s data. Proven

Each sub-chunk is a u64 absolute data start followed by the records of its entries: 512, the last sub-chunk the rest. Every sub-chunk’s first entry has relative offset 0. Proven One more 12-byte record ends the list: its data offset, relative to the last sub-chunk’s data start, is where the last entry’s data ends, and its other fields are 0. Proven

PGZP entry12 bytesFH6100% known

Preceded in each sub-chunk by a u64 absolute data start. Little-endian.

ProvenObservedSourcedInferredUnknownNot described
OffsetSizeTypeFieldConfidenceNotes
0x04u32relative data offsetProvenabsolute offset = sub-chunk data start + this; a multiple of 4 for every entry
0x44u32uncompressed sizeProven
0x82u16flagsProvenversion 101: method = flags & 0x0FFF, padding = flags >> 12 (0 to 3 in FH6). Version 100 (per ForzaTools): flags & 0x3FFF and flags >> 14
0xA2u16folderProventhe low 16 bits of the entry's folder number (its folder by the folder index): chunks 0 and 2 have more than 65,536 folders, and the field wraps

An entry’s stored bytes run from its offset to the next entry’s offset (for the last entry, the end the closing record gives), less its padding: the padding is the 0 to 3 bytes that bring the next entry to a multiple of 4. A stored entry’s stored bytes are exactly its uncompressed size. Proven After the last entry’s data the file is zero bytes up to a multiple of 4,096. Proven

Method Compression Where Confidence
0 stored GeoChunks Proven
8 raw DEFLATE (RFC 1951) GeoChunk0 only Proven
31 raw LZ4 block; the payload starts with an LZ4 token byte (F0 30 = 15 + 48 literals) GeoChunks; not in ForzaTools’ FH5 table Proven
21 XMemCompress LZX platform zips per ForzaTechStudio; no entry of the 9,076 zips of the FH6 install uses it Sourced · ForzaTechStudio
22 deflate wrapped in TFIT encryption platform zips (29,250 entries in 1,085 of the install’s 9,076 zips), not GeoChunks Observed
Chunk Stored DEFLATE LZ4 Confidence
GeoChunk0 115,773 14,041 281,199 Proven
GeoChunk1 710 0 2,355 Proven
GeoChunk2 31,427 0 48,413 Proven
GeoChunk3 1,137 0 339 Proven

Every entry of the four chunks decodes to exactly its uncompressed size with every stored byte used: no DEFLATE stream or LZ4 block ends early or leaves bytes over. Proven 1,800 entries (200 of each method of each chunk, spread evenly) decode to the same bytes in ForzaTools (stored and DEFLATE entries) and K4os.Compression.LZ4 (LZ4 entries). Observed ForzaTools never sets the closing record’s offset, so the size it gives the last entry of GeoChunk0 (a compressed one) wraps and it cannot read that entry. Proven

Both sit beside the chunks, one pair per chunk. Observed

ChunkMapN.dat is exactly 4 × entry count bytes: one little-endian u32 per entry, the resource type in the top byte and a 24-bit id below it (type << 24 | id). Proven Over the 495,394 records of the four chunk maps no (type, id) pair repeats, so a record’s whole u32 names one entry of the track. Proven Placement files name models and visibility lists by this word (Hand-placed instances).

Type Resource Type Resource
0 .pgeo placement file 14 .dds
1 .phys 15 .hkx (Havok)
2 placeholder 16 .zip
3 .owb 17 .mtxmoddxt near-field splat map
4 .modelbin 18 .dxt
5 .pb texture 19 .mtp grass clutter map
7 .gr2 20 pack
8 .tz trigger zone 22 .gipack
9 .soundscape 24 .hqdxt
10 .bank 25 streaming cell
11 .lightblock 26 .tdft
12 .pvsz per-cell visibility list 27 .fvt
28 .predeform

All the type names are Observed from the extensions of the paths the contents file gives for each type. A model is named in other files by 4 << 24 | id and a texture by PVSTextureIndex << 4 | (quality − 1). Observed

ChunkContentsMiniZipN.txt is ASCII with one line per entry in entry order, each ended by CR LF, in one of two forms: <PREZIPPED>d:\...\zipcache\pc\<path>|<folder>, the entry’s path on the machine that built the archive, or a bare generated name and its folder, __04965.pvsz|30579 or __tz00021.tz|14717. Proven GeoChunk0 has 14,041 bare lines (13,702 .pvsz, 339 .tz); the other chunks have none. Proven The number after the last | is the entry’s whole folder number, the one the folder index gives (not its 16-bit field). Proven

Beside the chunks sit the files below. They are named here and described on the pages that use them. Observed

File Holds Described in
ChunkAssign*.dat, Duplication_*.dat, TransHints_*.dat, Compensation.dat streaming assignment data Unknown
bin.zip shaders, DXIL permutations, 1,676 material files (419 parent materials × summer, spring, autumn, winter), AssetManifest.xml Asset manifests, Material files, Shader containers
AssetManifest.xml the loose manifest of textures, models and instances Asset manifests
Ribbon_00\ brio_00.pvs (hand-placed instances) and the instance template libraries Hand-placed instances, Template libraries
trackroutes\*.nt plain XML track locators Coordinates and cells
triggerzones\tz_oceanparams\ the ocean preset zones Water

The shared engine textures live outside the track, in media\_library\TexturesPG\*.zip (.swatchbin), and more track textures in media\Stripped\gs\swatchbins.zip (.pb: festival banners and flags, some distance-level textures). Observed

What do the ChunkAssign, Duplication, TransHints and Compensation files contain?

They are present beside the chunks and were not read.

What do the ids of the ChunkMap records number?

The ids of type 4 (models) and type 12 (.pvsz) are named by the hand-placed instance file; what the ids of the other types count is not established.