FWIW here's the original 68k SimCity "Classic" (open source Micropolis) save function, which I've long since cleaned up and put in byte swapping to make it portable to SPARC and x86, but yes it is just writing out some big buffers of memory with a function that now swaps bytes:

https://github.com/SimHacker/micropolis/blob/master/Micropol...

Here's some original SimCity 2000 Mac code that saves the city into Mac resources (not the flat part of the file, but the Mac resource fork) -- CompGameWrite actually does some simple run length compression of the raw memory:

Boolean DoSave(short VolNum,Byte *name){
long count,CountTotal;
short i,j,filnum;
short x, y;
Byte *SaveText[] = {"\pGame Saved As:",NIL,NIL};
FInfo info;
Byte *NotCity[] = {
"\pSimCity 2000ª will not save over a non-city file.",
"\pTry to save again using a different name.",
NIL,
};

if (name[0]>20) name[0] = 20;

#ifndef DEBUG
if (GetFInfo(name,VolNum,&info)==0 && info.fdType!=CITYTYPE_ID) {
MessageDialog(NotCity);
return FALSE;
}
#endif

if (FSOpen(name,VolNum,&filnum)!=noErr) {
if (GameError(Create(name,VolNum,APPLICATION_ID,CITYTYPE_ID))) return FALSE;
if (GameError(FSOpen(name,VolNum,&filnum))) return FALSE;
}

if (!WriteHeader(filnum,0L)) return FALSE;
WriteLength = 4; // includes 'SCDH' but not header

//*** Write ***
if (!MiscWrite(filnum)) return FALSE;
if (!GameWrite(filnum,'ALTM',(Ptr)AltMap[0])) return FALSE;

if (!CompGameWrite(filnum,'XTER',(Ptr)TerrainMap[0])) return FALSE;
if (!CompGameWrite(filnum,'XBLD',(Ptr)BuildMap[0])) return FALSE;
if (!CompGameWrite(filnum,'XZON',(Ptr)ZoneMap[0])) return FALSE;
if (!CompGameWrite(filnum,'XUND',(Ptr)UnderMap[0])) return FALSE;

if (!CompGameWrite(filnum,'XTXT',(Ptr)TextMap[0])) return FALSE;
if (!CompGameWrite(filnum,'XLAB',(Ptr)LabelArray)) return FALSE;
if (!CompGameWrite(filnum,'XMIC',(Ptr)MicroRecord)) return FALSE;
if (!CompGameWrite(filnum,'XTHG',(Ptr)ThingList)) return FALSE;
if (!CompGameWrite(filnum,'XBIT',(Ptr)BitsMap[0])) return FALSE;

if (!CompGameWrite(filnum,'XTRF',(Ptr)TrafficMap[0])) return FALSE;
if (!CompGameWrite(filnum,'XPLT',(Ptr)PolluteMap[0])) return FALSE;
if (!CompGameWrite(filnum,'XVAL',(Ptr)ValueMap[0])) return FALSE;
if (!CompGameWrite(filnum,'XCRM',(Ptr)CrimeMap[0])) return FALSE;

if (!CompGameWrite(filnum,'XPLC',(Ptr)PoliceMap[0])) return FALSE;
if (!CompGameWrite(filnum,'XFIR',(Ptr)FireMap[0])) return FALSE;
if (!CompGameWrite(filnum,'XPOP',(Ptr)PopMap[0])) return FALSE;
if (!CompGameWrite(filnum,'XROG',(Ptr)ROGMap[0])) return FALSE;

if (!CompGameWrite(filnum,'XGRP',(Ptr)GraphData[0])) return FALSE;

//*** Close ***
WriteHeader(filnum,WriteLength);
GameError(SetEOF(filnum,WriteLength+8)); // 8 bytes for file header
GameError(FSClose(filnum));
GameError(FlushVol(NIL,VolNum));

BlockMove(name,CityStr,21);
DateCashTitle();
FilVolNum = VolNum;

//*** SUCCESS! ***
SaveText[1] = CityStr;
MessageDialog(SaveText);
return TRUE;
}

And here's the Mac SimEarth save function, which looks like it just write out raw uncompressed memory -- the Mac memory manager has a GetPtrSize function that (obviously) tells you the size of the memory allocated for a pointer:

DoSave(VolNum,name)
int VolNum;
Str255 name;
{
long count,CountTotal;
int i,FilNum;

if (EqualString(name,"\pSimEarth",FALSE,TRUE)) {
MessageDialog( "\pERROR!!",
"\pThe name 'SimEarth' is reserved",
"\pfor this application.",1);
return;
}

if (FSOpen(name,VolNum,&FilNum)) {
if (GAIAError(Create(name,VolNum,'MYCR','SAVE'))) return;
if (GAIAError(FSOpen(name,VolNum,&FilNum))) return;
}
else if (GAIAError(SetFPos(FilNum,fsFromStart,0L))) {
GAIAError(FSClose(FilNum));
return;
}

/**Write**/
CountTotal = (count=GetPtrSize(Map[0]));
if (GAIAError(FSWrite(FilNum,&count,Map[0]))) return;

CountTotal += (count=GetPtrSize(Life[0]));
if (GAIAError(FSWrite(FilNum,&count,Life[0]))) return;

CountTotal += (count=GetPtrSize(OcTempMap[0]));
if (GAIAError(FSWrite(FilNum,&count,OcTempMap[0]))) return;

CountTotal += (count=GetPtrSize(OcCurrentMap[0]));
if (GAIAError(FSWrite(FilNum,&count,OcCurrentMap[0]))) return;

CountTotal += (count=GetPtrSize(DriftMap[0]));
if (GAIAError(FSWrite(FilNum,&count,DriftMap[0]))) return;

CountTotal += (count=GetPtrSize(EventMap[0]));
if (GAIAError(FSWrite(FilNum,&count,EventMap[0]))) return;

CountTotal += (count=GetPtrSize(SAirTempMap[0]));
if (GAIAError(FSWrite(FilNum,&count,SAirTempMap[0]))) return;

CountTotal += (count=GetPtrSize(SCloudDensity[0]));
if (GAIAError(FSWrite(FilNum,&count,SCloudDensity[0]))) return;

CountTotal += (count=GetPtrSize(SAirCurrentMap[0]));
if (GAIAError(FSWrite(FilNum,&count,SAirCurrentMap[0]))) return;

PutParameters();
CountTotal += (count=GetPtrSize(MiscHis));
if (GAIAError(FSWrite(FilNum,&count,MiscHis))) return;

/**Close**/
GAIAError(SetEOF(FilNum,CountTotal));
GAIAError(FSClose(FilNum));
GAIAError(FlushVol(NIL,VolNum));

BlockMove(name,EwinStr,256);
SetWTitle(editWindow,EwinStr);
MessageDialog("\pSave Complete:",EwinStr,"",1);
EnableItem(GetMHandle(301),3); /* Save */
FilVolNum = VolNum;
}