Skip to main content

sc4-savegame-format-analysis

Source: OpenSC4 development notes (2026-07/08), from reverse-engineering the savegame City - Big City Tutorial.sc4. The same findings drive the DBPF/savegame loaders in OpenSC4.


SimCity 4 — Savegame Format Analysis

Generated 2026-07-23 by parsing the file directly (scripts run against the uploaded save) and cross-referencing the OpenSC4 codebase plus community documentation. See Sources & confidence for how much to trust each identification.

Revised 2026-08-06 while implementing §4.4. That work parsed the network subfiles of all eight populated saves in Regions/, not just this one, and corrected several identifications this document previously had wrong — see §4.4 and the session log at the end for what changed and why.

Revised again 2026-08-06 while implementing 2D sprite props — the 413 prop occupants in this save that reference no 3D model at all. The format that work decoded lives in the DATs, not the save, so it changes only the prop lines in §3 and §4.3; the decoding itself is in §8.

1. The file at a glance​

File size4,732,755 bytes
ContainerDBPF v1.0, index format 7.0, 179 index entries, 69 hole records
Compression73 subfiles QFS/RefPack-compressed (listed in the DIR subfile)
Distinct subfile types133
Serialized game objects93,499 across 120 classes (per the COM-serializer registry)

City identity (from the region-view subfile, LTEXTs and terrain):

City nameBig City Tutorial (localized in ~20 languages, e.g. Initiation aux grandes villes, Großstadt-Tutorial)
Mayor nameDefacto
Region-view record version1.13
Region tile(2, 7)
City size2×2 km — 128×128 tiles (altitude map 129×129 vertices)
Altitude range30.0 – 394.5 m (water level is 250 m)
PopulationR 22,618 / C 3,727 / I 10,638
Mayor rating35
GUID0x667FC376
Modemayor ("normal")

Headline content counts (all record-parsed from this file):

ContentCountSubfile
Buildings3,427 (60 distinct exemplars)0xA9BD882D
Props69,431 (347 distinct exemplars)0x2977AA47
Flora2,798 (9 distinct exemplars)0xA9C05C85
Lots3,5690xC9BD5D4A
Lot base-texture tiles3,6230xC97F987C
Ground-network tiles (road 1,323 / street 1,873 / rail 139)3,3350xC9C05C6E
Water pipes4830x49C05B9F
Lot foundations2,5100x49C05C8F
Lot retaining walls1,2450x49C05C9F
Simulation data grids (SimGrid layers)1360x49B9E602…60A
Ordinance subfiles~20see §4.6

2. Container-level notes​

  • Standard DBPF 1.0 exactly as already handled by addons/dbpf/DBPF.gd; the engine's QFS decompressor and DIR handling load every subfile in this save without error.
  • Almost every savegame subfile lives in group 0x299B2D1B (121 of 179 entries). The exceptions: LTEXTs (0x6AAEE931/32 name/mayor, 0x4A2482BB thumbnail labels), PNG thumbnails (0x4A2482BB), terrain (0xE98F9525), the region-view record (0xCA027EE1) and a handful of singletons.
  • Savegame records follow SC4's standard serialization: u32 size, u32 CRC, u32 memory address, then a version and class-specific payload. 120 of the 133 types chain cleanly as size-prefixed record arrays (verified while counting the records above).
  • Several network subfiles are absent from this save — network subfile 2 (0xCA16374F, bridges/elevated), the tunnel subfile (0x8A4BD52B), the prebuilt network (0x49C1A034) and the power-line pair (0xC9C05C5D / 0x09C05C6A) — consistent with a flat tutorial city with no bridges, tunnels or long-distance power. Other shipped saves do have them: see §4.4.

3. Implementation status in OpenSC4 (summary)​

Implemented today (15 of the 133 types present): building/prop/flora occupants, lots, lot base textures, terrain altitudes (main map only), region-view stats, PNG thumbnails, LTEXT, the DIR directory, and — as of 2026-08-06 — the whole of §4.4: ground networks, pipes, the network index, lot foundations and retaining walls, plus the power-line and bridge subfiles that occur in other saves. In short: everything the city renderer needs to draw a complete city, and nothing of the simulation.

Prop rendering was completed later the same day. 413 of this save's 69,431 prop occupants reference no 3D model at all — they are 2D sprites, and were being silently dropped; §8 has the format and the fix. The 2,339 props still unplaced are a different problem: they do name an S3D model, but no zoom/rotation variant of it exists in the DATs we load.

Not implemented (present in this save): the item index, zone developer/manager, tract developer, all 136 SimGrid layers, every simulator/manager state blob, budget (departments, line items, taxes), the ~20 ordinances, historical graph data, advice state, and the COM-serializer registry.

Engine scaffolding still unfed: CityView/ClassDefinitions/ (NetGraphNode, NetGraphEdge, NetTile, TransitTile) models a transit-network graph. The §4.4 parsers give it geometry but not connectivity — that needs SC4Path (0x296678F7), which has no parser. Note NeworkGraph.gd (filename typo intentional) is dead and internally inconsistent (tile.networedges vs tile.networkedges); treat it as a sketch, not an API.

Also worth noting: the region UI derives the displayed city name from the filename (RegionCityView.gd:22), while the save carries properly localized name/mayor LTEXTs.

4. Full inventory by category​

Confidence legend: Verified = parsed by this analysis and/or by OpenSC4 code · Documented = well-established community documentation (SC4D wiki, SC4Parser, sc4 npm lib) · Reported = label from the SimsWiki SAVEGAMES table read via search snippets (unverified) · Inferred = deduced here from ID families / structure · Unknown = no identification.

4.1 City identity & metadata​

Type IDBytesRecordsIdentificationConfidenceOpenSC4 status
0xCA027EDB6,675—Region-view city stats (location, size, RCI population, rating, GUID, mode)VerifiedImplemented — SC4ReadRegionalCity.gd; used by Region UI and City.gd
0x8A2482B9 (4 instances)125,0724 filesPNG images — region-view thumbnails of the city (4 mip sizes)VerifiedImplemented — RegionCityView.gd via ImageSubfile
0x2026960B (40 instances)1,13640 filesLTEXT strings — localized city name (G=6AAEE931) and mayor name (G=6AAEE932) in ~20 languages; 'Temp.png' labels (G=4A2482BB)VerifiedParser implemented (LTEXTSubfile.gd) but savegame instances unused — Region UI takes the name from the filename instead
0xE86B1EEF1,168—DIR / DBDF compressed-file directoryVerifiedImplemented — DBPF.gd/DBDF.gd
0x499B23FE972—COM serializer registry — list of every serialized class + object count (verified: 120 classes, 93,499 objects)VerifiedNot implemented

4.2 Terrain​

Type IDBytesRecordsIdentificationConfidenceOpenSC4 status
0xA9DD6FF4 (5 instances)68,6545 filescSTETerrain altitude maps (main 129×129 vertex grid + four 129-float city-edge strips at I=0x64–0x67)VerifiedPartially implemented — cSTETerrain__SaveAltitudes.gd reads only I=1 (main map); edge strips unused
0xE98F9525221Unidentified 22-byte singleton; its type ID equals the group ID used by the cSTETerrain subfiles — likely terrain-engine stateInferredNot implemented

4.3 Occupants, lots & ground textures (the rendered city)​

Type IDBytesRecordsIdentificationConfidenceOpenSC4 status
0xA9BD882D282,1273,427Building occupant subfileVerifiedImplemented — BuildingSubfile.gd, rendered by City.gd load_buildings()
0x2977AA476,200,59269,431Prop occupant subfileVerifiedImplemented — PropSubfile.gd, load_props(). 66,679 draw as S3D models, 413 as 2D sprites (§8), 2,339 unresolved (S3D variant absent from the loaded DATs)
0xA9C05C85218,2442,798Flora occupant subfileVerifiedImplemented — FloraSubfile.gd, load_flora()
0xC9BD5D4A1,086,5793,569Lot subfile (tile rect, zoning, wealth)VerifiedImplemented (data-only) — LotSubfile.gd, load_lots()
0xC97F987C431,7813,623Lot base-texture subfileVerifiedImplemented — LotBaseTextureSubfile.gd, load_lot_textures()
0x2977AA4926,888262Unidentified — ID adjacent to the prop subfile (0x2977AA47); plausibly timed/conditional prop state 262 recordsInferredNot implemented

4.4 Transport & utility networks​

Revised 2026-08-06. The identifications in this section were previously wrong for three of the five type IDs, and two further subfiles were missing entirely. The corrected table below was established by parsing every record of all eight populated saves in Regions/ byte-exactly (bytes consumed == declared record size, zero failures) and cross-checking the cSC4* class registry in sebamarynissen/sc4. What was wrong: 0x49C05B9F is pipes, not the prebuilt network (that is 0x49C1A034, which appears in no shipped save); 0x49C05C9F and 0x49C05C8F are lot decoration, not networks at all.

Type IDClassBytesRecordsIdentificationConfidenceOpenSC4 status
0xC9C05C6EcSC4NetworkOccupant781,5203,335Ground network occupants — one record per tile of road, street, avenue, one-way road, dirt road and railVerifiedImplemented — NetworkSubfile.gd, rendered by City.load_networks()
0x6A0F82B2cSC4TrafficNetworkMap2,519,2511Network index — city tile → network occupant, spanning every network subfileVerified (header + reference table)Implemented — NetworkIndexSubfile.gd; per-entry payload still undecoded, see below
0x49C05B9FcSC4PipeOccupant338,292483Water pipes (was mislabelled "prebuilt network")VerifiedImplemented — PipeSubfile.gd, hidden underground layer
0x49C05C9FcSC4LotRetainingWallOccupant129,4801,245Lot retaining walls (was mislabelled "pipe subfile") — lot decoration, not a networkVerifiedImplemented — LotStructureSubfile.gd
0x49C05C8FcSC4FoundationOccupant205,8202,510Lot foundations (was "unidentified ≈ subway?") — lot decoration, not a networkVerifiedImplemented — LotStructureSubfile.gd

Two further network subfiles exist in the save format and were absent from this section. Neither occurs in Big City Tutorial, but both occur in other shipped saves:

Type IDClassIdentificationOpenSC4 status
0xC9C05C5DcSC4PowerLineOccupantPower-line spans; 85-byte records naming the two pylons a span runs between, by memory addressImplemented — PowerLineSubfile.gd
0x09C05C6AcSC4PowerPoleOccupantThe pylons themselves; carry an Exemplar TGI and so an S3D modelImplemented — PowerLineSubfile.gd (head only; ~1.4 KB per-span tail undecoded)
0xCA16374Fnetwork subfile 2Bridge / elevated deck tiles. Only in Timbuktu/City - Rush Hour Tutorial.sc4 (16 records)Implemented — BridgeNetworkSubfile.gd (head only; ~390-byte tail incl. pillars undecoded)
0x49C1A034cSC4NetworkOccupantWithPreBuiltModelThe real prebuilt network (highway interchanges). Present in no shipped saveNot implemented, nothing to test against
0x8A4BD52BcSC4NetworkTunnelOccupantTunnels. Present in no shipped saveNot implemented, nothing to test against

The key structural finding. A ground-network record does not need the RUL tile-shape rules to be evaluated. SC4 resolved them when the tile was built and saved the answer: each record carries its four deck corners with position, texture coordinate and baked lighting colour, plus the already-chosen texture id. Rendering is therefore a direct read — which is why sloped roads, diagonals and level crossings came out right without touching RULSubfile.gd. Verified layout:

u32 size, u32 crc, u32 mem, u16 major(8), u16 minor(4)
u16 zot, u8 ?, u8 appearance (bit 0 = present in city, bit 6 = burnt)
u32 0xC772BF98 family marker, constant
tract: u8 minX, minZ, maxX, maxZ, u16 xTractSize, zTractSize
u32 sgpropCount + sgprops[]
u32 GID, u32 TID, u32 IID all zero on ground networks
u8 ?
f32 position x, y, z metres, tile centre
4 x vertex { f32 x,y,z,u,v; u8 r,g,b,a } 24 bytes each, odd-aligned
u32 textureId FSH family; high byte = network family per RULSubfile.gd
u8 wealthTexture
u32 baseTexture FSH family for the sidewalk/ground underneath
u8 orientation
u8 x2 ?
u8 crossingCount-1
crossings[] { u8 networkType, west, north, east, south }
u32 wallCount + walls[] { u32 texture, vertex }
bbox: 6 f32 grouped BY AXIS (minX, maxX, minY, maxY, minZ, maxZ)
u32 constructionStates, u32 alternatePathId, 3 x u32 ?, u64 demolishingCosts

networkType: 0 Road · 1 Rail · 2 Maxis El Highway · 3 Street · 4 Pipe · 5 Powerline · 6 Avenue · 7 Subway · 8 Light Rail · 9 Monorail · 10 One-Way Road · 11 Dirt Road.

Textures resolve at TGI (0x7AB50E44, 0x1ABE787D, textureId + zoom) for zoom 0..4 — the same scheme TransitTiles.gd already used. All 36 distinct texture ids in Big City Tutorial resolve with all five zoom variants present.

Foundations and retaining walls store a placement block that no community parser documents. It was decoded here as f32 x, y, z, size_x, height, size_z (metres), at record offset 0x38 for foundations and 0x48 for walls. Evidence: 100% of the 1,245 walls and 2,510 foundations in Big City Tutorial then have their centre on a lot-covered tile (the x/z transpose gives ~55%), and the median of y − terrain altitude is exactly 0.00 m. Their exemplars carry no model for most records — instead a five-entry list of FSH zoom variants plus the world size one repeat covers (0x295961F2/0x295961F3 for walls, 0x68FCFF37/0xC911EDA0 for foundations), i.e. SC4 stretches a texture over a box. A minority carry an RKT1 S3D model instead.

What is still undecoded. The network index's per-entry payload: between consecutive {tile_number, mem, subfile_type} triples sits a variable-length block nobody has decoded, and SC4Parser's own attempt cannot keep the cursor aligned. NetworkIndexSubfile.gd resynchronises by scanning for the next triple instead, which recovers exactly the declared reference count in every populated save. What tile_number means is also open — it is not a row-major tile index (both that and its transpose match only about half the entries against the actual tile coordinates of the ground-network records).

4.5 Simulation grids (data views)​

Type IDBytesRecordsIdentificationConfidenceOpenSC4 status
0x49B9E602298,46646SimGridUint8 — 46 simulation data grids (record header verified: own-type, dataId, dims)VerifiedNot implemented
0x49B9E60320,7555SimGridSint8 — 5 simulation data grids (record header verified: own-type, dataId, dims)VerifiedNot implemented
0x49B9E60456,78127SimGridUint16 — 27 simulation data grids (record header verified: own-type, dataId, dims)VerifiedNot implemented
0x49B9E605168,03339SimGridSint16 — 39 simulation data grids (record header verified: own-type, dataId, dims)VerifiedNot implemented
0x49B9E60665,5911SimGridUint32 — 1 simulation data grids (record header verified: own-type, dataId, dims)VerifiedNot implemented
0x49B9E60A624,60618SimGridFloat32 — 18 simulation data grids (record header verified: own-type, dataId, dims)VerifiedNot implemented

4.6 Ordinances​

Type IDBytesRecordsIdentificationConfidenceOpenSC4 status
0x02BF1DFA2711Ordinance subfile (one subfile per ordinance; SC4D "Ordinance Subfiles" family)DocumentedNot implemented
0x42BF1E183371Ordinance subfile (one subfile per ordinance; SC4D "Ordinance Subfiles" family)DocumentedNot implemented
0x62BF1DAA2591Ordinance subfile (one subfile per ordinance; SC4D "Ordinance Subfiles" family)DocumentedNot implemented
0x62BF1DB92661Ordinance subfile (one subfile per ordinance; SC4D "Ordinance Subfiles" family)DocumentedNot implemented
0xA2BF1DDC2341Ordinance subfile (one subfile per ordinance; SC4D "Ordinance Subfiles" family)DocumentedNot implemented
0xA2BF1DE52411Ordinance subfile (one subfile per ordinance; SC4D "Ordinance Subfiles" family)DocumentedNot implemented
0xA2BF1E432481Ordinance subfile (one subfile per ordinance; SC4D "Ordinance Subfiles" family)DocumentedNot implemented
0xC2BF1DC52021Ordinance subfile (one subfile per ordinance; SC4D "Ordinance Subfiles" family)DocumentedNot implemented
0xC2BF1E042611Ordinance subfile (one subfile per ordinance; SC4D "Ordinance Subfiles" family)DocumentedNot implemented
0x22F6E80C2441Ordinance subfile (one subfile per ordinance; SC4D "Ordinance Subfiles" family)DocumentedNot implemented
0x22F6E81B2361Ordinance subfile (one subfile per ordinance; SC4D "Ordinance Subfiles" family)DocumentedNot implemented
0x62F6E7CF2221Ordinance subfile (one subfile per ordinance; SC4D "Ordinance Subfiles" family)DocumentedNot implemented
0xC2F6E81F2621Ordinance subfile (one subfile per ordinance; SC4D "Ordinance Subfiles" family)DocumentedNot implemented
0x00D0723D2441Ordinance subfile (one subfile per ordinance; SC4D "Ordinance Subfiles" family)DocumentedNot implemented
0x40D072362261Ordinance subfile (one subfile per ordinance; SC4D "Ordinance Subfiles" family)DocumentedNot implemented
0xA0D071293021Ordinance subfile (one subfile per ordinance; SC4D "Ordinance Subfiles" family)DocumentedNot implemented
0xE0D0722E2711Ordinance subfile (one subfile per ordinance; SC4D "Ordinance Subfiles" family)DocumentedNot implemented
0xE0D072332751Ordinance subfile (one subfile per ordinance; SC4D "Ordinance Subfiles" family)DocumentedNot implemented
0x815B4CEF2561Likely ordinance subfile (same size/shape/group as the ordinance family; would bring the count to vanilla's 20)InferredNot implemented
0x82B9999B2151Likely ordinance subfile (same size/shape/group as the ordinance family; would bring the count to vanilla's 20)InferredNot implemented

4.7 Budget & economy​

Type IDBytesRecordsIdentificationConfidenceOpenSC4 status
0xAA313C9F2,15925Budget: line-item subfileDocumentedNot implemented
0xE990BFFC1,64718Budget: department-budget subfileDocumentedNot implemented
0xE9A6CD3B24,6481Taxes (SimsWiki)ReportedNot implemented
0x6990C1AA1,858,6541"Sims to jobs match" — commute/demand matching data (SimsWiki label) single 1.86 MB record — 2nd-largest blob in the saveReportedNot implemented
0x89EFA536146,2181Historical data / graph data (SimsWiki: mostly decoded)ReportedNot implemented

4.8 Development & zoning managers​

Type IDBytesRecordsIdentificationConfidenceOpenSC4 status
0x098F964D873,9781Item index subfile — spatial index (quad-tree) of every occupantDocumentedNot implemented
0x498F9B0193,1341Zone developer subfile — per-tile zoning/developer mapDocumentedNot implemented
0x298F9B2D7911Zone managerDocumentedNot implemented
0x2990C1E5911Tract developerDocumentedNot implemented
0x0990C07520,4351Plumbing simulator stateDocumentedNot implemented

4.9 Advisors & mayor view​

Type IDBytesRecordsIdentificationConfidenceOpenSC4 status
0x6A9335DE57,6721,068Advice / advisor state (SimsWiki)ReportedNot implemented
0x89C48F4747,0671Mayor-view city data (SimsWiki)ReportedNot implemented
0x8990C0658,5641Water-pollution simulator state (SimsWiki label)ReportedNot implemented

4.10 Simulator / manager state blobs and other unidentified subfiles​

Nearly all of these are singleton records in group 0x299B2D1B whose type IDs sit in the same numeric families as the identified simulator classes above. The community has never published decodings for most of them; sizes and record counts below are still useful as a fingerprint for future reverse-engineering. The Objs column is the object count the save's own COM-serializer registry (0x499B23FE) reports for that class.

Type IDBytesRecordsObjsNote
0x2990C1BC66,10911cSC4 simulator/manager ID family (undecoded)
0x0990C00541,69411cSC4 simulator/manager ID family (undecoded)
0x8A09F5F436,438663663
0x8A91E7E033,284——
0x4A1DBBBF28,42055
0xA990BFE027,45211cSC4 simulator/manager ID family (undecoded)
0x6B70EFAD15,228282282
0x8990C12D11,658174174cSC4 simulator/manager ID family (undecoded)
0x4A232DA89,4809292
0xC990C0348,31411cSC4 simulator/manager ID family (undecoded)
0xEAC937B47,46522
0x0BF606A55,68911
0x0A134F245,4731313
0x0A4134814,76811
0x8BE3753B4,2667979
0x2A5F877D3,77711
0xAA371C323,2705959
0xCA2C2A2F2,97911
0x8A22BEBE2,6913939
0xE990BE012,49911cSC4 simulator/manager ID family (undecoded)
0x2990BFF22,30611cSC4 simulator/manager ID family (undecoded)
0x4BE372CD2,05611
0x4A1628C51,7491818
0xEA19E8251,60911
0x6A3848DB1,5602626
0x4A3AD3E11,33211
0x6A5F87551,16511
0xAA5292D71,05511
0x8990BE7A1,03311cSC4 simulator/manager ID family (undecoded)
0xEA09D4AE96511
0x8990C09A87311cSC4 simulator/manager ID family (undecoded)
0x896E75AF83733
0x0990C1387441212cSC4 simulator/manager ID family (undecoded)
0x6A1628BA62777
0x8990C37259911cSC4 simulator/manager ID family (undecoded)
0xCA14CA0349511
0x4990C01346411cSC4 simulator/manager ID family (undecoded)
0x6A26D0492781010
0xA990C08E20211cSC4 simulator/manager ID family (undecoded)
0x4A0DD61619811
0xA98F9D3B18811cSC4 simulator/manager ID family (undecoded)
0x2990C05A17611cSC4 simulator/manager ID family (undecoded)
0x6990C04F16011cSC4 simulator/manager ID family (undecoded)
0x0990BDD813011cSC4 simulator/manager ID family (undecoded)
0xA9C741B312211cSC4 simulator/manager ID family (undecoded)
0xC990C0A412211cSC4 simulator/manager ID family (undecoded)
0xC98F9D4A9411cSC4 simulator/manager ID family (undecoded)
0xE9C622D85811cSC4 simulator/manager ID family (undecoded)
0xA98F9D285211cSC4 simulator/manager ID family (undecoded)
0xC9C628EC5011cSC4 simulator/manager ID family (undecoded)
0xC98F9D174411cSC4 simulator/manager ID family (undecoded)
0xE990C18E4411cSC4 simulator/manager ID family (undecoded)
0xE990C0453911cSC4 simulator/manager ID family (undecoded)
0x2990C1423911cSC4 simulator/manager ID family (undecoded)
0x299062C03811cSC4 simulator/manager ID family (undecoded)
0xA7E7F9293811
0xA9C8647C38——cSC4 simulator/manager ID family (undecoded)
0x4990BD933411cSC4 simulator/manager ID family (undecoded)
0x8990C0803111cSC4 simulator/manager ID family (undecoded)
0xA990BD103011cSC4 simulator/manager ID family (undecoded)
0x89D9B9EE26——
0x8A91E7E326——
0xAA2049A12411
0xEA230A282411
0xAA3836FB2311
0xAA3FE6BC2211
0xEAD4BA362011
0x0BB143811911
0x0B7D45E018——
0xC9B84E101511
0x0990C38A1411cSC4 simulator/manager ID family (undecoded)
0x4A1B664E1411
0xA990C0221411cSC4 simulator/manager ID family (undecoded)
0x89C499861211cSC4 simulator/manager ID family (undecoded)
0x49DD6F4C12——
0xEA3FF4F54——

5. What implementing the rest would unlock​

Done — network subfiles (§4.4), 2026-08-06. Ground networks, pipes, the network index, lot foundations and retaining walls all load and render, as do the power-line and bridge subfiles that appear in other saves. What it did not unlock, contrary to what the previous version of this list assumed: the CityView/ClassDefinitions/ graph classes still have no input. A graph needs connectivity, and these subfiles carry only geometry — the connectivity lives in SC4Path, now item 1 below.

Done — 2D sprite props (§8), 2026-08-06. Every prop occupant in this save that has artwork in the DATs now draws. What remains on the prop side is not a format gap: 2,339 occupants name an S3D model whose zoom/rotation variant is missing from the six DATs the loader opens, which is a question of which files we load, not of parsing.

Remaining, ordered by likely value to OpenSC4:

  1. SC4Path (0x296678F7) — the per-tile vehicle paths. This is now the single missing piece between "the network is drawn" and "the network is a graph": it would feed TransitTile.set_tile_paths() (a stub returning {}) and thence NetworkGraph, and it is the prerequisite for any traffic simulation or route display. Note it is a DAT type, not a savegame type — the paths live in the game's own data files, keyed per network piece.
  2. SimGrids (§4.5) — the record header is fully decoded (this analysis parses all 136 layers cleanly: own type id, dataId, resolution, dims at fixed offsets, 55-byte header). They power every data-view overlay (pollution, land value, crime, traffic…). A generic SimGridSubfile would be a small, high-leverage parser.
  3. Zone developer / item index (§4.8) — per-tile zoning enables a zoning overlay and is needed before any simulation work.
  4. Region-view completeness — use the localized LTEXT city name (G=0x6AAEE931) instead of the filename; decode the fields still marked unknown in SC4ReadRegionalCity.gd.
  5. Budget/ordinances/graphs (§4.6–4.7) — only needed once simulation or UI panels exist.
  6. Terrain edge strips (0xA9DD6FF4 I=0x64–0x67) — four 129-float strips, almost certainly the neighbour-city edge altitudes used for cross-city edge matching.

6. Sources & confidence​

  • This file itself — every byte count, record count, grid dimension, string and the COM-serializer table above were parsed directly from the uploaded save with throwaway Python scripts (DBPF index + QFS decompression matching addons/dbpf/).
  • OpenSC4 source — addons/dbpf/*.gd, City.gd, SC4ReadRegionalCity.gd, cSTETerrain__SaveAltitudes.gd, tools/dat_dump.py.
  • SC4D Encyclopaedia (Savegame, Network Subfiles, Ordinance Subfiles pages) and SimsWiki SAVEGAMES — still unreachable as of 2026-08-06 (both return HTTP 403 to any client, browser user-agent or not). Labels marked Reported came from search-result snippets quoting those pages and should be re-checked if the sites ever come back.
  • Killeroo/SC4Parser and sebamarynissen/sc4 — community savegame parsers. Both ARE reachable via raw.githubusercontent.com, which the 2026-07-23 pass did not realise; fetching their source directly is how the §4.4 layouts were established. sc4's src/core/cpp-classes.ts in particular is a type-ID → cSC4* class-name registry and is the fastest way to identify an unknown savegame type. Caveat: neither library is authoritative. SC4Parser's NetworkTile1 mislabels the four 24-byte vertices as three positions plus padding, and sc4's bridge class documents a version-3 layout that does not match the version-2.3 records in the shipped save. Treat both as leads to verify, not truth.

Standard of proof used in the 2026-08-06 revision. A layout was only accepted when a parser written to it consumed exactly the declared record size for every record — not a sample — in every populated save (eight of them). Where that test cannot apply, an independent check was required: foundation and wall placement was confirmed by 100% of centres landing on lot-covered tiles and a median y − terrain of exactly 0.00 m; network-index recovery by the recovered reference count equalling the declared count in all eight cities.

Anything marked Unknown here is, to the best of available community knowledge, genuinely undecoded — SC4's savegame has never been fully reverse-engineered.

7. Session log — 2026-08-06​

Implementing §4.4. Recorded because several findings are not recoverable from the code alone.

Identifications corrected. Three of §4.4's five type IDs were wrong and two subfiles were missing entirely; the table in §4.4 has the detail. The error to learn from: the 2026-07-23 pass inferred 0x49C05B9F/0x49C05C8F/0x49C05C9F from ID adjacency — they sit in the same numeric family as known network types — and adjacency turned out to mean nothing. Two of the three are lot decoration. Record size and shape (700 vs 104 vs 82 bytes; presence of an Exemplar TGI) would have separated them immediately.

Newly decoded.

  • Ground-network record layout, byte-exact — see §4.4. The load-bearing discovery is that SC4 saves the resolved tile: four vertices with position, UV and baked lighting colour, plus the chosen texture id. The RUL tables never need to be evaluated to draw a saved city.
  • Foundation / retaining-wall placement block: f32 x, y, z, size_x, height, size_z.
  • Power lines are two cross-referencing subfiles, spans (0xC9C05C5D) and pylons (0x09C05C6A), joined by memory address. Every span in all five cities that have them names exactly two pylons and both resolve.
  • Pipes lie a median 10.34 m below the terrain surface (range −6.5 to −25.5 m across the 483 records). Consequence for rendering: they cannot be shown by making geometry visible, only by an x-ray pass — see the engine notes below.

Still undecoded after this session. The network index's per-entry payload and the meaning of its tile_number; the ~1.4 KB tail of a power-pole record; the ~390-byte tail of a bridge record (which holds pillar placement, so bridge pillars do not render); the orientation high bit set on 36 ground-network tiles, probably a diagonal-flip flag.

Engine-side findings worth keeping. These bit during this work and are easy to hit again:

  • Network quads must clear the lot base textures, which sit at 0.015 + 0.004 * (priority & 7) — up to 0.043 world units. Anything lifted below that gets buried by a high-priority lot apron, most visibly at intersections.
  • Per-tile quads whose UVs span the full 0..1 of their texture need texture_repeat = false. With the default repeat, edge pixels filter against the texture's opposite edge and leave a hairline seam along every tile boundary.
  • Do not put these quads in the transparent pass. TRANSPARENCY_ALPHA sorts per-object with no depth write, which let lot aprons and the network's own base layer overdraw the road surface; level-crossing tiles vanished entirely. TRANSPARENCY_ALPHA_SCISSOR keeps them in the opaque pass where depth sorting is real.
  • The water shader in City.tscn computed NORMAL as PROJECTION_MATRIX * VIEW_MATRIX * MODEL_MATRIX * vec4(noisenormal, 0). Godot wants NORMAL in view space and a projection matrix is not a valid transform for a direction; the diffuse term collapsed and all water rendered black with only the additive wave highlights showing. Fixed by dropping PROJECTION_MATRIX. Unrelated to networks, but it had been masking the map's water since before this work — a "floating terrain fragment" beyond the map edge turned out to be ordinary land across a bay of invisible water.
  • Water tint still comes from a single texel: texture(watertexture, vec3(vec2(0.0, 0.0), zoom)) paints the whole ocean with the top-left pixel of a 256×256 texture. Sampling with real UVs is a one-line change nobody has made yet.

8. Session log — 2026-08-06 (second pass): 2D sprite props​

Strictly this is a DAT format, not a savegame one; it is recorded here because the save is what leads you to it, and because Core.class_dict had both of its types registered as null — there was no parser to read the code for.

The gap. ExemplarSubfile.get_all_model_refs() finds a prop's model by scanning property values for the S3D type marker 0x5AD0E817. Six prop exemplars used by this save contain no such triple, because they are not 3D objects at all. Every one of their 413 occurrences was counted as "without a resolvable model" and dropped:

Exemplar (G=0xC977C536)InstancesWhat it is
0x28F50000 AStreet1x1x11_stoplightPole_28F333traffic light, orthogonal
0x29E20000 AStreet1x1x11_stoplightPoleDiag_29E29traffic light, diagonal
0x29F00000 / 0x29ED0000 / 0x29EF0000 ARW2x2x5_animatedBallons31balloon bunches on the car lots
0x29C20000 Amill4x2x4_exploritorium_29C20animated crowd of sims

ATC (0x29A5D1EC) — the animation header, reached from the exemplar's ResourceKeyType0 (0x27812820). Group is PROPS_ANIM (0x2A2458F9) for props, NONPROPS_ANIM (0x49A593E7) for everything else. Always exactly 48 bytes, twelve little-endian u32s:

u32Meaning
00x29A5D1EC, own type
1–3FSH type/group/instance — the sprite sheet
40x09ADCD75, AVP type
5AVP group
6–10one AVP instance id per zoom 0–4; 0 where the prop is not drawn at that zoom
11animation rate

Slots 6–10 being per zoom is the load-bearing discovery, and it is verifiable rather than inferred: the filled slots match the exemplar's AppearanceZoomsFlag (0x0ABFC024) bitmask exactly — 0b11100 on the traffic lights, whose filled slots are 2, 3 and 4. Across SimCity_1.dat's 1,084 ATCs only three fill patterns occur at all: zooms {3,4} (1,003 of them), {2,3,4} (79) and all five (2).

AVP (0x09ADCD75) — one zoom's frame table. A 0x24-byte header, verified constant across all 2,253 AVPs in SimCity_1.dat: own type, frame count, two u32 1s, four zero u32s, then the frame count repeated. Frame counts are only ever 8, 4 or 1. Then eight bytes per frame:

ByteMeaning
0page — which FSH directory entry holds this frame
1always 8, in all 15,777 frames
2–3u16 pixel offset of the frame's top-left corner within that page
4–5width, height
6–7anchor x, y — signed int8

Two traps here. The page byte matters because an animation FSH is not one image but up to ~70 directory entries, each a 256×256 DXT1/DXT3 page; FSHSubfile was overwriting self.img per entry and keeping only the last, so multi-page sheets were unreachable. And the offset is a pixel index within its page, so the corner is (offset % 256, offset / 256) — 16 bits covers 256×256 exactly, which is precisely why the page needs a byte of its own.

The anchors really are signed: 9 of the 15,777 frames anchor left of their own rectangle and 2 above it. Read unsigned, those sprites land hundreds of pixels away. No frame is wider than 127 or taller than 126, so the sign costs nothing.

Pixels to world units. A billboard needs a scale and nothing in the ATC/AVP/FSH chain states one. It is recoverable from the S3D data instead: sprites and S3D impostor textures come out of the same pre-renderer, and an S3D vertex carries both a world position and a UV. Least-squares fitting world position -> UV × texture size over ~700 building models per zoom gives the full 2×3 world→screen-pixel matrix. Its row norms, median over the fits, are pixels per 16 m tile:

zoom01234
px per tile6.44912.57624.96556.170112.147

Two things fall out of that fit and are the reason to trust it. The matrix's two rows have equal norm to better than 0.1% — the projection is conformal in the camera plane, which is what makes a single scalar enough to size a billboard. And the matrix independently reproduces SC4's camera: u_x / u_z = 2.4166 ≈ tan 67.5°, and the vertical-to-horizontal ratio is sin 45° at zooms 3–4 and sin 50° at zoom 2 — the azimuth and per-zoom elevations CameraAnchor3D.gd already hardcodes, arrived at from completely independent data. Note the ladder is not a clean ×2: 24.965 → 56.170 is ×2.25. That is measured, not derived; do not "correct" it.

Traffic-light frames are rotations, not signal phases. The stoplight exemplars set "States as Frames" (0x4A70D491), which is easy to read as red/amber/green. It is not: extracting the four zoom-4 frames side by side shows two back views of the pole and two front views with the green lamp lit — they are the four view rotations, the sprite equivalent of an S3D model's four baked rotation variants. So the frame index uses the same expression _place_occupants uses to pick a rotation variant. Whatever drives actual lamp cycling is not in this chain; the exemplar's ResourceKeyTypeMisc (0x27812920) names a second ATC (0x2B2D0000, which does exist, with its own AVPs and FSH) that was not investigated.

Engine-side findings worth keeping.

  • Sprites are camera-facing billboards with vertices emitted relative to the anchor pixel, so the anchor lands on the terrain at the occupant's position. Anything that centres the quad instead leaves poles floating or buried.
  • TRANSPARENCY_ALPHA_SCISSOR, for the same reason §7 gives for network quads — the transparent pass has no depth write and sprites would sort wrongly against buildings.
  • Sprites are hidden at zooms whose ATC slot is empty, as SC4 does, rather than falling back to a coarser zoom's art. At zoom 0 a traffic light is 4 px wide and would be sub-pixel noise on 362 draw calls. Verified by counting lit-lamp pixels down the zoom ladder: 86, 22, 3, 0 at camera zooms 6, 4, 3, 2 — the last being the first unauthored zoom.

Still open. The rate field's unit (read as 1/30 s ticks per frame, which puts the balloons at 0.7 s and the crowd at 1.0 s per frame — plausible, unverified); AVP header u32s 2 and 3, always 1; the second stoplight ATC at 0x2B2D0000; and whether SC4 ever drives a sprite's frame from simulation state, which is what real red/amber/green cycling would require.

Appendix A — SimGrid layer inventory (dataIds)​

All 136 grids parse with the 55-byte header size, crc, mem, u16 major, u8, u32 ownType, u32 dataId, u32 ?, u32 ?, u32 xSize, u32 zSize, u32 0, f32 16.0, f32 0.0625 followed by raw cell data. Grid resolutions in this save: 128×128 (1 tile/cell), 64×64, 32×32, 16×16. DataIds are the game's GUIDs for each data layer (power, pollution, land value, crime, traffic…); mapping dataId → layer name still needs to be pulled from the data-view exemplars in SimCity_*.dat.

SimGridUint8 (0x49B9E602, 46 grids): 0x49D5BC86 (128x128), 0x49D5BBA1 (128x128), 0x49D5BB8C (128x128), 0x49D5B8F9 (64x64), 0x49D5BCB7 (128x128), 0x49D5BCA6 (128x128), 0x49D5BC96 (128x128), 0x69D5C303 (32x32), 0xAA8E1DC1 (32x32), 0x8A8DF4B6 (32x32), 0xCA8E449E (32x32), 0xAA8DF4BD (32x32), 0x8A8DF4C4 (32x32), 0xAA8DF4D4 (32x32), 0x69D5C30D (32x32), 0xAA8E1DE4 (32x32), 0x8A8DF6FC (32x32), 0x69D5C317 (32x32), 0x89D5BB39 (64x64), 0x49D5B953 (128x128), 0x49D5B964 (128x128), 0x89D5BB51 (64x64), 0x01003110 (32x32), 0x01001010 (32x32), 0x01001020 (32x32), 0x01004300 (32x32), 0x01001030 (32x32), 0x01003120 (32x32), 0x01003130 (32x32), 0x01004100 (32x32), 0x01003320 (32x32), 0x01003330 (32x32), 0x01004200 (32x32), 0x01004400 (32x32), 0x69D5C402 (128x128), 0x89D5B6EF (128x128), 0x69D5C3BF (128x128), 0xCABD2925 (32x32), 0x89D5B788 (128x128), 0x2A5BA1B3 (64x64), 0x49D5BBB9 (64x64), 0x89D5B895 (64x64), 0x49D5B678 (128x128), 0xCABD2926 (32x32), 0x69D5C424 (128x128), 0x89D5C3A2 (128x128)

SimGridSint8 (0x49B9E603, 5 grids): 0x69D5B600 (32x32), 0x69D5B604 (32x32), 0x69D5B605 (32x32), 0x49D5B607 (32x32), 0x41800000 (128x128)

SimGridUint16 (0x49B9E604, 27 grids): 0x69D5C2A0 (32x32), 0x69D5C2A1 (32x32), 0x69D5C2A2 (32x32), 0x05003110 (32x32), 0x06003110 (32x32), 0x05001010 (32x32), 0x06001010 (32x32), 0x05001020 (32x32), 0x06001020 (32x32), 0x05004300 (32x32), 0x06004300 (32x32), 0x05001030 (32x32), 0x06001030 (32x32), 0x05003120 (32x32), 0x06003120 (32x32), 0x05003130 (32x32), 0x06003130 (32x32), 0x05004100 (32x32), 0x06004100 (32x32), 0x05003320 (32x32), 0x06003320 (32x32), 0x05003330 (32x32), 0x06003330 (32x32), 0x05004200 (32x32), 0x06004200 (32x32), 0x05004400 (32x32), 0x06004400 (32x32)

SimGridSint16 (0x49B9E605, 39 grids): 0x49D5B602 (32x32), 0x2A674CA5 (32x32), 0x8A674CAF (32x32), 0x00000000 (32x32), 0x8A416368 (32x32), 0x89D5B91A (64x64), 0x02003110 (32x32), 0x03003110 (32x32), 0x02001010 (32x32), 0x03001010 (32x32), 0x02001020 (32x32), 0x03001020 (32x32), 0x02004300 (32x32), 0x03004300 (32x32), 0x02001030 (32x32), 0x03001030 (32x32), 0x02003120 (32x32), 0x03003120 (32x32), 0x02003130 (32x32), 0x03003130 (32x32), 0x02004100 (32x32), 0x03004100 (32x32), 0x02003320 (32x32), 0x03003320 (32x32), 0x02003330 (32x32), 0x03003330 (32x32), 0x02004200 (32x32), 0x03004200 (32x32), 0x02004400 (32x32), 0x03004400 (32x32), 0x89D5BBF2 (64x64), 0x49D5BBCE (64x64), 0x49D5BC41 (64x64), 0x89D5BBF3 (64x64), 0x49D5BC42 (128x128), 0x49D5BC43 (64x64), 0x89D5BBF1 (64x64), 0x89D5BBF0 (64x64), 0x49D5BC40 (64x64)

SimGridUint32 (0x49B9E606, 1 grids): 0x69D5C42D (128x128)

SimGridFloat32 (0x49B9E60A, 18 grids): 0x69D5C324 (32x32), 0x69D5C330 (32x32), 0x69D5C2D0 (32x32), 0x69D5C2D1 (32x32), 0x69D5C2D2 (32x32), 0x69D5C2E0 (32x32), 0x69D5C2E1 (32x32), 0x69D5C2E2 (32x32), 0x49D5BB6F (16x16), 0x69D5C3E2 (128x128), 0x69D5C3E5 (128x128), 0x69D5C3E3 (128x128), 0x69D5C3E1 (128x128), 0x69D5C3AC (128x128), 0x69D5C3E0 (128x128), 0x69D5C3FA (128x128), 0x69D5C40E (128x128), 0x69D5C3E4 (128x128)

Appendix B — COM-serializer registry (0x499B23FE)​

The save's own manifest: 120 serialized classes, 93,499 objects total. Types not listed in §4 appear in Appendix A/§4.10. Format: u32 version(1), u32 count(120), u32 totalObjects, then (u32 typeId, u32 objectCount) × 120 — alignment verified against this save.

Type IDObjectsType IDObjectsType IDObjects
0x00D0723D10x4A1B664E10xA990BFE01
0x02BF1DFA10x4A1DBBBF50xA990C0221
0x098F964D10x4A232DA8920xA990C08E1
0x0990BDD810x4A3AD3E110xA9BD882D3,427
0x0990C00510x4BE372CD10xA9C05C852,798
0x0990C07510x62BF1DAA10xA9C741B31
0x0990C138120x62BF1DB910xAA2049A11
0x0990C38A10x62F6E7CF10xAA313C9F25
0x0A134F24130x6990C04F10xAA371C3259
0x0A41348110x6990C1AA10xAA3836FB1
0x0BB1438110x6A0F82B210xAA3FE6BC1
0x0BF606A510x6A1628BA70xAA5292D71
0x22F6E80C10x6A26D049100xC2BF1DC51
0x22F6E81B10x6A3848DB260xC2BF1E041
0x2977AA4769,4310x6A5F875510xC2F6E81F1
0x2977AA492620x6A9335DE1,0680xC97F987C3,623
0x298F9B2D10x6B70EFAD2820xC98F9D171
0x299062C010x815B4CEF10xC98F9D4A1
0x2990BFF210x82B9999B10xC990C0341
0x2990C05A10x896E75AF30xC990C0A41
0x2990C14210x8990BE7A10xC9B84E101
0x2990C1BC10x8990C06510xC9BD5D4A3,569
0x2990C1E510x8990C08010xC9C05C6E3,335
0x2A5F877D10x8990C09A10xC9C628EC1
0x40D0723610x8990C12D1740xCA14CA031
0x42BF1E1810x8990C37210xCA2C2A2F1
0x498F9B0110x89C48F4710xE0D0722E1
0x4990BD9310x89C4998610xE0D072331
0x4990C01310x89EFA53610xE98F95251
0x49B9E602460x8A09F5F46630xE990BE011
0x49B9E60350x8A22BEBE390xE990BFFC18
0x49B9E604270x8BE3753B790xE990C0451
0x49B9E605390xA0D0712910xE990C18E1
0x49B9E60610xA2BF1DDC10xE9A6CD3B1
0x49B9E60A180xA2BF1DE510xE9C622D81
0x49C05B9F4830xA2BF1E4310xEA09D4AE1
0x49C05C8F2,5100xA7E7F92910xEA19E8251
0x49C05C9F1,2450xA98F9D2810xEA230A281
0x4A0DD61610xA98F9D3B10xEAC937B42
0x4A1628C5180xA990BD1010xEAD4BA361

Appendix C — LTEXT strings in the save​

Localized city name (G=0x6AAEE931) / mayor name (G=0x6AAEE932) pairs — English, French, German, Italian, Spanish, Dutch, Scandinavian languages, Japanese, Korean, Chinese (trad./simpl.), Thai, Polish, Portuguese and more (instances 0x01–0x14, 0x23), e.g. "Big City Tutorial"/"Defacto", "Initiation aux grandes villes"/"De facto", "Großstadt-Tutorial"/"Defacto", "Tutorial "Una grande città""/"De Facto". Four more LTEXTs (G=0x4A2482BB, alongside the four PNG thumbnails) all read "Temp.png".