Skip to content
This repository has been archived by the owner on Mar 13, 2023. It is now read-only.

Commit

Permalink
Add multiplayer private game setting
Browse files Browse the repository at this point in the history
  • Loading branch information
bmaupin committed Aug 4, 2017
1 parent c67f913 commit abf0e64
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 16 deletions.
31 changes: 17 additions & 14 deletions docs/format.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
| --- | --- | --- | --- |
| 1 | | | |
| | String | Must be `CIV5` | File signature |
| | 32-bit integer | 0x4<br>0x5<br>0x8 | Save game version:<br>4 = 1.0.0<br>5 = 1.0.1<br>8 = 1.0.2 - 1.0.3 |
| | 32-bit integer | 4<br>5<br>8 | Save game version:<br>4 = 1.0.0<br>5 = 1.0.1<br>8 = 1.0.2 - 1.0.3 |
| | String | `1.0.2.13 (341540)`<br>`1.0.3.18 (379995)`<br>`1.0.3.80 (389545)`<br>`1.0.3.142 (395070)`<br>`1.0.3.144 (395131)`<br>`1.0.3.279(130961)` | Civ 5 version |
| | String | `379995`<br>`395131`<br>`403694` | Civ 5 build |
| | String | `CIVILIZATION_IROQUOIS`<br>`CIVILIZATION_MOROCCO` | Player 1 civilization |
Expand All @@ -14,21 +14,24 @@
| | String | `GAMESPEED_STANDARD`<br>`GAMESPEED_QUICK` | Game pace |
| | String | `WORLDSIZE_DUEL`<br>`WORLDSIZE_SMALL` | Map size |
| | String | `Assets\Maps\Continents.lua`<br>`Assets\Maps\Earth_Duel.Civ5Map` | Map |
| 3 | | | Player information |
| 3 | | | Player names |
| 4 | | | Player statuses |
| 8 | | | Civilizations |
| 9 | | | Leaders |
| 14 | | | Climate |
| 18 | | | See notes below |
| 18/19 | | | |
| | 32-bit integer | 0x0<br>0x14a<br>0x1f4 | Max turns |
| 19/20 | | | City states |
| 24/25 | | | Player colours |
| 25/26 | | | Sea level |
| 28/29 | | | |
| | | | Turn timer |
| 19* | | | |
| | 32-bit integer | 0<br>330<br>500 | Max turns |
| 20* | | | City states |
| 23* | | | |
| | Integer | | Turn timer length |
| 25* | | | |
| | | | Player colours |
| | | | Multiplayer private game |
| 26* | | | Sea level |
| 29* | | | |
| | Boolean | | Victory conditions |
| 29/30 | | | Various map and game options |
| 32/33 | | | zlib compressed data starts with 0x789c |
| 30* | | | Various map and game options |
| 33* | | | zlib compressed data starts with 0x789c |

Notes:
---
Expand All @@ -37,7 +40,7 @@ Notes:
`1400 0000 4349 5649 4c49 5a41 5449 4f4e 5f4d 4f52 4f43 434f`
- `1400 0000` = 0x14 (little endian) = 20 bytes
- `4349...` = `CIVILIZATION_MOROCCO` (20 bytes long)
- Savegames contain different number of sections depending on the build/version
- *Savegames contain different number of sections depending on the build/version
- Build 395070 (version 1.0.3.142)+
- Contains 33 sections
- Section 18 is an additional section that contains mostly 0xff
Expand Down Expand Up @@ -81,7 +84,7 @@ References:
- https://gaming.stackexchange.com/a/273907/154341
- Multiplayer turn types
- http://blog.frank-mich.com/civilization-v-how-to-change-turn-type-of-a-started-game/
- Multiplayer lobby public/private
- Multiplayer private/public
- https://github.com/Canardlaquay/Civ5SavePrivate/blob/master/Civ5PrivateSave/Form1.cs
- https://github.com/Renophaston/DefectiveCivSavePrivatizer/blob/master/main.c
- Multiplayer pitboss setting
Expand Down
27 changes: 25 additions & 2 deletions src/__tests__/civ5save.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const NEW_CULTURAL_VICTORY = false;
const NEW_DIPLOMATIC_VICTORY = true;
const NEW_DOMINATION_VICTORY = true;
const NEW_MAX_TURNS = 123;
const NEW_PRIVATE_GAME = false;
const NEW_SAVEGAME_FILENAME = 'New.Civ5Save';
const NEW_SCIENCE_VICTORY = false;
const NEW_TIME_VICTORY = true;
Expand Down Expand Up @@ -83,15 +84,15 @@ test('Get game mode', () => {
expect(savegame101135.gameMode).not.toBeDefined();
expect(savegame101221.gameMode).not.toBeDefined();
expect(savegame10213.gameMode).toBe('singleplayer');
expect(savegame103279.gameMode).toBe('singleplayer');
expect(savegame103279.gameMode).toBe('multiplayer');
});

test('Get player 1 civilization', () => {
expect(savegame10017.player1Civilization).toBe('CIVILIZATION_PERSIA');
expect(savegame101135.player1Civilization).toBe('CIVILIZATION_ARABIA');
expect(savegame101221.player1Civilization).toBe('CIVILIZATION_FRANCE');
expect(savegame10213.player1Civilization).toBe('CIVILIZATION_SPAIN');
expect(savegame103279.player1Civilization).toBe('CIVILIZATION_MOROCCO');
expect(savegame103279.player1Civilization).toBe('CIVILIZATION_DENMARK');
});

test('Get difficulty', () => {
Expand Down Expand Up @@ -163,6 +164,27 @@ test('Set max turns', () => {
expect(savegame103279.maxTurns).toBe(NEW_MAX_TURNS);
});

test('Get privateGame', () => {
expect(savegame10017.privateGame).toBe(false);
expect(savegame101135.privateGame).toBe(false);
expect(savegame101221.privateGame).toBe(false);
expect(savegame10213.privateGame).toBe(false);
expect(savegame103279.privateGame).toBe(true);
});

test('Set private game', () => {
savegame10017.privateGame = NEW_PRIVATE_GAME;
savegame101135.privateGame = NEW_PRIVATE_GAME;
savegame101221.privateGame = NEW_PRIVATE_GAME;
savegame10213.privateGame = NEW_PRIVATE_GAME;
savegame103279.privateGame = NEW_PRIVATE_GAME;
expect(savegame10017.privateGame).toBe(NEW_PRIVATE_GAME);
expect(savegame101135.privateGame).toBe(NEW_PRIVATE_GAME);
expect(savegame101221.privateGame).toBe(NEW_PRIVATE_GAME);
expect(savegame10213.privateGame).toBe(NEW_PRIVATE_GAME);
expect(savegame103279.privateGame).toBe(NEW_PRIVATE_GAME);
});

test('Get time victory', () => {
expect(savegame10017.timeVictory).toBe(true);
expect(savegame101135.timeVictory).toBe(true);
Expand Down Expand Up @@ -273,6 +295,7 @@ test('Save to file', async () => {
let newSavegame = await Civ5Save.fromFile(newSavegameFile);

expect(newSavegame.maxTurns).toBe(NEW_MAX_TURNS);
expect(newSavegame.privateGame).toBe(NEW_PRIVATE_GAME);
expect(newSavegame.timeVictory).toBe(NEW_TIME_VICTORY);
expect(newSavegame.scienceVictory).toBe(NEW_SCIENCE_VICTORY);
expect(newSavegame.dominationVictory).toBe(NEW_DOMINATION_VICTORY);
Expand Down
Binary file modified src/__tests__/resources/1.0.3.279.Civ5Save
Binary file not shown.
17 changes: 17 additions & 0 deletions src/civ5save.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ export default class Civ5Save {
let sectionOffsets = this._getSectionOffsets();

for (let propertyName in Civ5SavePropertyDefinitions) {
// Player colours is a variable length list of strings so we'll skip it for now
if (propertyName === 'playerColours') {
continue;
}

// Make propertyDefinition a copy; otherwise it will modify the property for every instance of the Civ5Save class
let propertyDefinition = Object.assign({}, Civ5SavePropertyDefinitions[propertyName]);

Expand All @@ -70,6 +75,10 @@ export default class Civ5Save {
break;
}

// Workaround for private game since the previous property doesn't have a predictable length
} else if (propertyName === 'privateGame') {
propertyByteOffset = sectionOffsets[propertySection].start - 10;

} else {
propertyByteOffset = sectionOffsets[propertySection - 1].start + propertyDefinition.byteOffsetInSection;
}
Expand Down Expand Up @@ -235,6 +244,14 @@ export default class Civ5Save {
this._properties['maxTurns'].value = newValue;
}

get privateGame() {
return this._returnPropertyIfDefined('privateGame');
}

set privateGame(newValue) {
this._properties['privateGame'].value = newValue;
}

get timeVictory() {
return this._returnPropertyIfDefined('timeVictory');
}
Expand Down
22 changes: 22 additions & 0 deletions src/civ5saveproperties.json
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,28 @@
},
"type": "int32"
},
"playerColours": {
"_comment": "Starting with build 310700 this is a list of strings. Before that it's a list bytes. Seems like it can have 63 or 64 items.",
"byteOffsetInSection": 0,
"length": null,
"sectionByBuild": {
"98650": 23,
"262623": 24,
"395070": 25
},
"type": "strings"
},
"privateGame": {
"_comment": "https://github.com/Canardlaquay/Civ5SavePrivate",
"byteOffsetInSection": null,
"length": 1,
"sectionByBuild": {
"98650": 23,
"262623": 24,
"395070": 25
},
"type": "bool"
},
"section29Timer1": {
"byteOffsetInSection": 269,
"length": null,
Expand Down

0 comments on commit abf0e64

Please sign in to comment.