From 9c97eeb5971a01290e1d8247968583fb0c6bb048 Mon Sep 17 00:00:00 2001 From: Bastiaan <17990055+bbassie@users.noreply.github.com> Date: Sat, 12 Sep 2026 02:53:45 +0200 Subject: [PATCH] Refuse mod packs for a newer Factorio than the instance runs (#1015) The mod pack's Factorio version ends up in mod-settings.dat. Factorio refuses to read that file when the version is newer than the game and falls back to default settings, which can wreck the save. Check the versions in syncMods before touching the mods folder. Closes #1006 Co-authored-by: Claude Fable 5.1 --- packages/host/src/Instance.ts | 20 ++++++++++++++++++++ test/host/Instance.js | 28 ++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) 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");