diff --git a/packages/host/src/Instance.ts b/packages/host/src/Instance.ts index 755c7364..6e18661f 100644 --- a/packages/host/src/Instance.ts +++ b/packages/host/src/Instance.ts @@ -796,6 +796,7 @@ end`.replace(/\r?\n/g, " "); } else { modPack = await this.sendTo("controller", new lib.ModPackGetRequest(modPackId)); } + this.checkModPackVersion(modPack); this.activeModPack = modPack; const mods = await this._host.fetchMods(modPack.mods.values(), modPack.factorioVersion); @@ -847,6 +848,25 @@ end`.replace(/\r?\n/g, " "); await fs.writeFile(this.path("mods", "mod-settings.dat"), this.activeModPack.toModSettingsDat()); } + /** + * Check that the mod pack does not target a newer Factorio than the server + * + * The mod pack's Factorio version is written into mod-settings.dat and + * Factorio refuses to read it if it is newer than the game. It then + * loads default settings instead, which can corrupt the save. + * + * @throws {lib.RequestError} if the mod pack version is higher than the server version. + */ + checkModPackVersion(modPack: lib.ModPack) { + const serverVersion = this.server.version; + if (serverVersion && modPack.integerFactorioVersion > lib.integerFullVersion(serverVersion)) { + throw new lib.RequestError( + `Mod pack ${modPack.name} is for Factorio ${modPack.factorioVersion} ` + + `which is newer than the Factorio ${serverVersion} this instance runs` + ); + } + } + /** * Prepare instance for starting * diff --git a/test/host/Instance.js b/test/host/Instance.js index 52623700..73e11c1a 100644 --- a/test/host/Instance.js +++ b/test/host/Instance.js @@ -38,6 +38,34 @@ describe("class Instance", function() { }); }); + describe(".checkModPackVersion()", function() { + function modPack(factorioVersion) { + return lib.ModPack.fromJSON({ name: "pack", factorio_version: factorioVersion }); + } + + it("should accept a mod pack for an older or equal Factorio version", function() { + instance.server.version = "1.1.91"; + instance.checkModPackVersion(modPack("1.1")); + instance.checkModPackVersion(modPack("1.1.90")); + instance.checkModPackVersion(modPack("1.1.91")); + }); + + it("should reject a mod pack for a newer Factorio version", function() { + instance.server.version = "1.1.91"; + assert.throws( + () => instance.checkModPackVersion(modPack("1.1.110")), + new lib.RequestError( + "Mod pack pack is for Factorio 1.1.110 which is newer than the Factorio 1.1.91 this instance runs" + ) + ); + assert.throws(() => instance.checkModPackVersion(modPack("2.0")), lib.RequestError); + }); + + it("should skip the check when the server version is unknown", function() { + instance.checkModPackVersion(modPack("2.0")); + }); + }); + describe("._recordPlayerJoin()", function() { it("should add player to playersOnline", function() { instance._recordPlayerJoin("player");