.srl / .zsr — Per-Sector Sound Regions & Zones
Traced live via GhidraMCP against FarCry2_server. Covers the container/attribution level — exact
per-sector size, owning manager class, and grid indexing are confirmed; the internal record layout
within each sector's blob is not (see Unknowns).
Two of the three files found alongside .sdat in every world sector (see .sdat's sibling-files
note for the original hash-list discovery — 14,964 of
each across the install, matching the sector count exactly): generated\worldsectors\sectorN.srl and
generated\worldsectors\zonesectorN.zsr.
What the acronyms mean
Both extensions are exported by name-obvious functions on CFCXEditorDocument (the map editor's own
export driver, same class family that writes .sdat — see ExportSDAT there):
.srl= "Sound Region Layer" — written byExportSoundRegionLayer(0x08cb1930)..zsr= "Zone Sector" — written byExportZones(0x08cb42a0-ish, caller ofCZoneLogicManager::GetSectorData).
Container: none — a raw, fixed-size per-sector memory dump
Unlike .sdat (a real chunked container with a header, metadata block, and record array — see
.sdat), both of these are dead simple: a single fixed-size raw block per sector, written
with no header and no framing at all.
// ExportSoundRegionLayer, one call per sector (x, y each 0..7):
void* data = CAmbianceManager::GetSectorData(x, y); // this+0xb8, a grid of block pointers
file.Write(data, 0x400 /* = 1024 bytes, exact */);
// ExportZones, one call per sector (x, y each 0..7):
void* data = CZoneLogicManager::GetSectorData(x, y); // this+0xdc, a grid of block pointers
file.Write(data, 0x1000 /* = 4096 bytes, exact */);
.srlis exactly 1024 bytes, always.CAmbianceManager::GetSectorDataindexes a grid of pre-allocated block pointers atthis+0xb8byy * gridWidth + x— no per-sector size variation..zsris exactly 4096 bytes, always.CZoneLogicManager::GetSectorDataindexes a similar grid atthis+0xdc, but — unlike ambiance — with an origin offset subtracted from both coordinates (this+0xf4/this+0xf6), meaning the zone grid isn't guaranteed to start at world sector(0,0).- Both confirm the same 8×8-sectors-per-level grid used everywhere else in this engine.
What's semantically inside each block
Neither format's raw on-disk bytes were decoded field-by-field, but the class families that own this data give strong content-type context:
.srl (ambiance/sound regions) — a rich, time-of-day-driven soundscape system:
SSoundRegion (the base record), SSoundRegionLevel (a volume/intensity level, sortable via
SSoundRegionLevelSort), SSoundRegionTimeEntry/SSoundRegionTimeTrack (time-scheduled sound events,
sortable via SSoundRegionTimeSort), SSoundRegionTimeRandomFx/SSoundRegionRandomFx/
SSoundRegionRandomFxSound (randomized ambient one-shots), SSoundRegionVirtualName (a named
sound-bank reference), SSoundRegionTrackSetVolume (a volume-control track event) —
SSoundRegionManager is the owning collection type.
.zsr (gameplay zones) — CZoneLogicRegion : CBasicRegionEntity is the per-zone record, which
self-registers into CZoneRegionManager::AddRegion on construction and default-initializes three
floats to 1.0 (offsets +0xe4/+0xe8/+0xec — plausibly an RGB tint or a scale/intensity triple, not
confirmed). CZoneInfoComponent is the entity-side hook (an IEntityTask-style component, same pattern
as every other per-entity capability documented in Engine
Architecture) that presumably lets a placed entity define or
query which zone it's in.
Unknowns
- The actual on-disk record layout for either format.
SSoundRegioncontains astd::stringmember (a name/virtual-name field) — a runtime C++ object with a heap pointer can't survive a directmemcpy-to-disk-and-back round trip, so the raw 1024-byte.srlblob is very unlikely to be a literal array of liveSSoundRegionobjects. Either there's a separate, flattened POD structure this data gets serialized to/from (not yet located), orCAmbianceManager's per-sector block holds something simpler than the full runtime record set and the richerSSoundRegion*family is reconstructed elsewhere at load time. Not resolved. - Whether
.zsr'sCZoneLogicRegionrecords serialize any more directly —CBasicRegionEntity's own fields weren't traced. - The exact meaning of
CZoneLogicRegion's three default-1.0floats. - Whether either file has any internal structure (record count, per-record size prefix) or is purely a fixed-layout struct array with a size implied entirely by the constant 1024/4096-byte total.