src/Civ5SavePropertyDefinitions.js
export default {
'fileSignature': {
'byteOffsetInSection': 0,
'length': 4,
'sectionByBuild': {
'98650': 1
},
'type': 'string',
// Game build is a later property and not yet defined, so the section will need to be determined without it
getSection() {
return 1;
}
},
'saveGameVersion': {
'byteOffsetInSection': 4,
'length': 4,
'sectionByBuild': {
'98650': 1
},
'type': 'int',
// Game build is a later property and not yet defined, so the section will need to be determined without it
getSection() {
return 1;
}
},
// This property is updated if the game is saved with a newer version of Civ 5
'gameVersion': {
'byteOffsetInSection': 8,
'length': null,
'sectionByBuild': {
'230620': 1
},
'type': 'string',
// Game build is a later property and not yet defined, so the section will need to be determined without it
getSection(saveGameVersion) {
if (saveGameVersion >= 7) {
return 1;
} else {
return null;
}
}
},
// This property is updated if the game is saved with a newer version of Civ 5. The build of Civ 5 that was originally
// used when the save file was created is stored later, after gameOptionsMap.
'gameBuild': {
'byteOffsetInSection': null,
'length': null,
'sectionByBuild': {
'230620': 1
},
'type': 'string',
// Game build is not yet defined, so the section will need to be determined without it
getSection(saveGameVersion) {
if (saveGameVersion >= 7) {
return 1;
} else {
return null;
}
}
},
'currentTurn': {
'byteOffsetInSection': null,
'length': 4,
'sectionByBuild': {
'98650': 1
},
'type': 'int'
},
// This property exists in all versions but only seems to gain significance around build 230620
'gameMode': {
'byteOffsetInSection': null,
'length': 1,
'sectionByBuild': {
'98650': 1
},
'type': 'int',
'values': [
'Single player',
'Multiplayer',
'Hotseat'
]
},
'player1Civilization': {
'byteOffsetInSection': null,
'length': null,
'sectionByBuild': {
'98650': 1
},
'type': 'string'
},
'difficulty': {
'byteOffsetInSection': null,
'length': null,
'sectionByBuild': {
'98650': 1
},
'type': 'string'
},
'startingEra': {
'byteOffsetInSection': null,
'length': null,
'sectionByBuild': {
'98650': 1
},
'type': 'string'
},
'currentEra': {
'byteOffsetInSection': null,
'length': null,
'sectionByBuild': {
'98650': 1
},
'type': 'string'
},
'gamePace': {
'byteOffsetInSection': null,
'length': null,
'sectionByBuild': {
'98650': 1
},
'type': 'string'
},
'mapSize': {
'byteOffsetInSection': null,
'length': null,
'sectionByBuild': {
'98650': 1
},
'type': 'string'
},
// The map file appears multiple times; I have no idea why (see section19Map)
'mapFile': {
'byteOffsetInSection': null,
'length': null,
'sectionByBuild': {
'98650': 1
},
'type': 'string'
},
'enabledDLC': {
'byteOffsetInSection': null,
'length': null,
'sectionByBuild': {
'98650': 1
},
'type': 'dlcStringArray'
},
'enabledMods': {
'byteOffsetInSection': null,
'length': null,
'sectionByBuild': {
'98650': 1
},
'type': 'modsStringArray'
},
// Players after the first player marked as none seem to be superfluous
// See SlotStatus in the SDK: CvGameCoreSource/CvGameCoreDLLUtil/include/CvEnums.h
'playerStatuses': {
'byteOffsetInSection': 4,
// Length is number of items, not bytes
'length': 64,
'sectionByBuild': {
'98650': 4
},
'type': 'intArray',
'values': [
'',
'AI',
'Dead',
'Human',
'None'
]
},
// Starting with build 310700 this is a list of strings. Before that I'm not sure if it's a list of bytes or not there
// at all
'playerCivilizations': {
'byteOffsetInSection': 4,
// Length is number of items, not bytes
'length': 64,
'sectionByBuild': {
'310700': 8
},
'type': 'stringArray'
},
// This seems to be very rare (https://github.com/bmaupin/civ5save-editor/issues/6)
'section19SkipPlayer1Leader': {
'byteOffsetInSection': 4,
'length': null,
'sectionByBuild': {
'98650': 17,
'262623': 18,
'395070': 19
},
'type': 'string'
},
'section19Skip1': {
'byteOffsetInSection': null,
'length': 252,
'sectionByBuild': {
'98650': 17,
'262623': 18,
'395070': 19
},
'type': 'bytes'
},
// This is rare but seems to contain the full path to the save file, e.g.
// C:\Users\Username\Documents\My Games\Sid Meier's Civilization 5\Saves\multi\auto\AutoSave_0310 AD-2030.Civ5Save
'section19SkipSavePath': {
'byteOffsetInSection': null,
'length': null,
'sectionByBuild': {
'98650': 17,
'262623': 18,
'395070': 19
},
'type': 'string'
},
// This appears to contain the current OS username
'section19SkipUsername': {
'byteOffsetInSection': null,
'length': null,
'sectionByBuild': {
'98650': 17,
'262623': 18,
'395070': 19
},
'type': 'string'
},
'section19Skip2': {
'byteOffsetInSection': null,
'length': 7,
'sectionByBuild': {
'98650': 17,
'262623': 18,
'395070': 19
},
'type': 'bytes'
},
'section19Map': {
'byteOffsetInSection': null,
'length': null,
'sectionByBuild': {
'98650': 17,
'262623': 18,
'395070': 19
},
'type': 'string'
},
'section19Skip3': {
'byteOffsetInSection': null,
'length': 4,
'sectionByBuild': {
'98650': 17,
'262623': 18,
'395070': 19
},
'type': 'bytes'
},
// https://gaming.stackexchange.com/a/273907/154341
'maxTurns': {
'byteOffsetInSection': null,
'length': 4,
'sectionByBuild': {
'98650': 17,
'262623': 18,
'395070': 19
},
'type': 'int'
},
// This seems to be the second place in the file with player names
'playerNames2': {
'byteOffsetInSection': 4,
// Length is number of items, not bytes
'length': 64,
'sectionByBuild': {
'98650': 21,
'262623': 22,
'395070': 23
},
'type': 'stringArray'
},
'section23Skip1': {
'byteOffsetInSection': null,
'length': 4,
'sectionByBuild': {
'98650': 21,
'262623': 22,
'395070': 23
},
'type': 'int'
},
// https://steamcommunity.com/app/8930/discussions/0/864973761026018000/#c619568192863618582
'turnTimerLength': {
'byteOffsetInSection': null,
'length': 4,
'sectionByBuild': {
'98650': 21,
'262623': 22,
'395070': 23
},
'type': 'int'
},
'playerColours': {
'byteOffsetInSection': 4,
// Length is number of items, not bytes
'length': 64,
// This is technically incorrect; before build 310700 this property exists, but it's a list of bytes instead of a
// list of strings, and there isn't much value in adding the extra complexity for old save games. For reference, the
// correct values are:
// '98650': 23,
// '262623': 24,
// '395070': 25
'sectionByBuild': {
'310700': 24,
'395070': 25
},
'type': 'stringArray'
},
// https://github.com/Canardlaquay/Civ5SavePrivate
'privateGame': {
'byteOffsetInSection': null,
'length': 1,
// As with playerColours, this is technically incorrect, but there isn't much value in implementing this for older
// games because 1. it would require implementing playerColours and 2. it's only relevant for multiplayer games,
// however logic for identifying multiplayer games before build 230620 hasn't been implemented (see gameMode)
'sectionByBuild': {
'310700': 24,
'395070': 25
},
'type': 'bool'
},
'section29Skip1': {
'byteOffsetInSection': 4,
'length': null,
'sectionByBuild': {
'98650': 27,
'262623': 28,
'395070': 29
},
'type': 'bytes',
getLength(enabledDLC, enabledMods) {
let length = 265;
if (enabledMods.includes('(1) Community Patch')) {
// Account for 0xDEADBEEF and mod version number (https://github.com/LoneGazebo/Community-Patch-DLL/blob/72137235dbab0c78d0c65a4b2ea33bad85b9ef61/CvGameCoreDLL_Expansion2/CustomMods.h#L1334)
length += 8;
}
return length;
}
},
'section29Timer1': {
'byteOffsetInSection': null,
'length': null,
'sectionByBuild': {
'98650': 27,
'262623': 28,
'395070': 29
},
'type': 'string'
},
'section29Skip2': {
'byteOffsetInSection': null,
'length': 12,
'sectionByBuild': {
'98650': 27,
'262623': 28,
'395070': 29
},
'type': 'bytes'
},
'section29TurnTimer': {
'byteOffsetInSection': null,
'length': null,
'sectionByBuild': {
'98650': 27,
'262623': 28,
'395070': 29
},
'type': 'string'
},
'section29TxtKeyTurnTimer': {
'byteOffsetInSection': null,
'length': null,
'sectionByBuild': {
'98650': 27,
'262623': 28,
'395070': 29
},
'type': 'string'
},
'section29Timer2': {
'byteOffsetInSection': null,
'length': null,
'sectionByBuild': {
'98650': 27,
'262623': 28,
'395070': 29
},
'type': 'string'
},
'section29Skip3': {
'byteOffsetInSection': null,
'length': 25,
'sectionByBuild': {
'98650': 27,
'262623': 28,
'395070': 29
},
'type': 'bytes'
},
// https://gaming.stackexchange.com/a/273907/154341
'timeVictory': {
'byteOffsetInSection': null,
'length': 1,
'sectionByBuild': {
'98650': 27,
'262623': 28,
'395070': 29
},
'type': 'bool'
},
// https://gaming.stackexchange.com/a/273907/154341
'scienceVictory': {
'byteOffsetInSection': null,
'length': 1,
'sectionByBuild': {
'98650': 27,
'262623': 28,
'395070': 29
},
'type': 'bool'
},
// https://gaming.stackexchange.com/a/273907/154341
'dominationVictory': {
'byteOffsetInSection': null,
'length': 1,
'sectionByBuild': {
'98650': 27,
'262623': 28,
'395070': 29
},
'type': 'bool'
},
// https://gaming.stackexchange.com/a/273907/154341
'culturalVictory': {
'byteOffsetInSection': null,
'length': 1,
'sectionByBuild': {
'98650': 27,
'262623': 28,
'395070': 29
},
'type': 'bool'
},
// https://gaming.stackexchange.com/a/273907/154341
'diplomaticVictory': {
'byteOffsetInSection': null,
'length': 1,
'sectionByBuild': {
'98650': 27,
'262623': 28,
'395070': 29
},
'type': 'bool'
},
'section30Skip1': {
'byteOffsetInSection': 4,
'length': null,
'sectionByBuild': {
'98650': 28,
'262623': 29,
'395070': 30
},
'type': 'bytes',
getLength(enabledDLC, enabledMods) {
let length = 72;
if (enabledDLC.includes('Expansion - Gods and Kings') || enabledDLC.includes('Expansion - Brave New World')) {
length += 4;
}
if (enabledMods.includes('(1) Community Patch')) {
// Account for 0xDEADBEEF and mod version number (https://github.com/LoneGazebo/Community-Patch-DLL/blob/72137235dbab0c78d0c65a4b2ea33bad85b9ef61/CvGameCoreDLL_Expansion2/CustomMods.h#L1334)
length += 8;
}
return length;
}
},
'section30MapSize1': {
'byteOffsetInSection': null,
'length': null,
'sectionByBuild': {
'98650': 28,
'262623': 29,
'395070': 30
},
'type': 'string'
},
'section30TxtKeyMapHelp': {
'byteOffsetInSection': null,
'length': null,
'sectionByBuild': {
'98650': 28,
'262623': 29,
'395070': 30
},
'type': 'string'
},
'section30Skip2': {
'byteOffsetInSection': null,
'length': 8,
'sectionByBuild': {
'98650': 28,
'262623': 29,
'395070': 30
},
'type': 'bytes'
},
'section30MapSize2': {
'byteOffsetInSection': null,
'length': null,
'sectionByBuild': {
'98650': 28,
'262623': 29,
'395070': 30
},
'type': 'string'
},
'section30TxtKeyMapSize': {
'byteOffsetInSection': null,
'length': null,
'sectionByBuild': {
'98650': 28,
'262623': 29,
'395070': 30
},
'type': 'string'
},
'section30MapSize3': {
'byteOffsetInSection': null,
'length': null,
'sectionByBuild': {
'98650': 28,
'262623': 29,
'395070': 30
},
'type': 'string'
},
// A bunch of map properties which differ based on the map size, 4 bytes per property
// See CvWorldInfo::readFrom in the SDK: CvGameCoreSource/CvGameCoreDLL_Expansion2/CvInfos.cpp for the order of values
// See steamassets/assets/dlc/expansion2/gameplay/xml/gameinfo/civ5worlds.xml for values based on map size
'worldInfo': {
'byteOffsetInSection': null,
'length': null,
'sectionByBuild': {
'98650': 28,
'262623': 29,
'395070': 30
},
'type': 'bytes',
getLength(enabledDLC, enabledMods) {
let length = 72;
if (enabledDLC.includes('Expansion - Brave New World')) {
// Brave New World added MaxActiveReligions and NumCitiesTechCostMod
length += 8;
} else if (enabledDLC.includes('Expansion - Gods and Kings')) {
// Gods and Kings added MaxActiveReligions
length += 4;
}
// Community Patch adds multiple new properties
// See CvWorldInfo::readFrom in https://github.com/LoneGazebo/Community-Patch-DLL/blob/master/CvGameCoreDLL_Expansion2/CvInfos.cpp
if (enabledMods.includes('(1) Community Patch')) {
length += 20;
}
return length;
}
},
// This is where a large chunk of game options are stored
// (http://civilization.wikia.com/wiki/Module:Data/Civ5/BNW/GameOptions)
'gameOptionsMap': {
'byteOffsetInSection': null,
'length': null,
'sectionByBuild': {
'98650': 28,
'262623': 29,
'395070': 30
},
'type': 'stringToBoolMap'
}
};