From 3cb9843f23af86ae99dc922679f84a17529d7bb3 Mon Sep 17 00:00:00 2001 From: Hornwitser Date: Thu, 30 Jun 2022 01:03:29 +0200 Subject: [PATCH] Add player online autosave pool Add separate autosave pool for autosaves that have had players online since the previous autosave. --- docs/configuration.md | 13 +++++++++++++ packages/lib/config/definitions.js | 8 ++++++++ packages/slave/src/Instance.js | 25 ++++++++++++++++++++++++- 3 files changed, 45 insertions(+), 1 deletion(-) diff --git a/docs/configuration.md b/docs/configuration.md index aab55e1f..a99c37fb 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -271,6 +271,19 @@ If null a random secure password is generated and used each time the instance st Defaults to null. +### player_online_autosave_slots + +Keeps a separate pool for autosaves where at least on player has been online since the previous autosave was done. +This requires regular autosaving to be enabled and will rename autosaves to `_autosave_poN.zip` (where N is a slot number) whenever a player has been online for that save. +The slot numbers start at 1, are incremented by 1 after each autosave that is renamed and reset back to 1 whenever this value is exceeded. +Note that this value should be set to a higher value than the value of `autosave_slots` in `factorio.settings`. +Useful for preventing the loss of all progress when nobody is around on always online servers with auto pause disabled. + +If 0 no autosave renaming takes place. + +Defaults to 5. + + ### factorio.enable_save_patching Whether to use save patching or not. diff --git a/packages/lib/config/definitions.js b/packages/lib/config/definitions.js index 35e28eb8..e713f48f 100644 --- a/packages/lib/config/definitions.js +++ b/packages/lib/config/definitions.js @@ -265,6 +265,14 @@ FactorioGroup.define({ type: "string", optional: true, }); +FactorioGroup.define({ + name: "player_online_autosave_slots", + description: + "Rename autosaves where players have been online since the previous autosave into a separate autosave " + + "pool with this many slots. Requires autosaves to be enabled to work. Set to 0 to disable.", + type: "number", + initial_value: 5, +}); FactorioGroup.define({ name: "enable_save_patching", description: "Patch saves with Lua code. Required for Clusterio integrations, lua modules, and most plugins.", diff --git a/packages/slave/src/Instance.js b/packages/slave/src/Instance.js index 8c71e2ba..062a7017 100644 --- a/packages/slave/src/Instance.js +++ b/packages/slave/src/Instance.js @@ -283,6 +283,8 @@ class Instance extends libLink.Link { */ this.playersOnline = new Set(); this._playerCheckInterval = null; + this._hadPlayersOnline = false; + this._playerAutosaveSlot = 1; } _watchPlayerJoinsByChat() { @@ -364,6 +366,7 @@ class Instance extends libLink.Link { let stats = this.playerStats.get(name); stats.lastLeaveAt = Date.now(); stats.onlineTimeMs += stats.lastLeaveAt - stats.lastJoinAt; + this._hadPlayersOnline = true; let event = { instance_id: this.id, @@ -428,6 +431,22 @@ class Instance extends libLink.Link { async _autosave(name) { let stat = await fs.stat(this.path("saves", `${name}.zip`)); instanceFactorioAutosaveSize.labels(String(this.id)).set(stat.size); + + if ( + this.config.get("factorio.player_online_autosave_slots") > 0 + && (this._hadPlayersOnline || this.playersOnline.size) + ) { + if (this._playerAutosaveSlot > this.config.get("factorio.player_online_autosave_slots")) { + this._playerAutosaveSlot = 1; + } + await fs.rename( + this.path("saves", `${name}.zip`), + this.path("saves", `_autosave_po${this._playerAutosaveSlot}.zip`), + ); + this._playerAutosaveSlot += 1; + this._hadPlayersOnline = false; + } + await this.sendSaveListUpdate(); } @@ -498,10 +517,14 @@ class Instance extends libLink.Link { throw err; } this.playerStats = new Map(stats["players"]); + this._playerAutosaveSlot = stats["player_autosave_slot"] || 1; } async _saveStats() { - let content = JSON.stringify({ players: [...this.playerStats] }, null, 4); + let content = JSON.stringify({ + players: [...this.playerStats], + player_autosave_slot: this._playerAutosaveSlot, + }, null, 4); await libFileOps.safeOutputFile(this.path("instance-stats.json"), content); }