From 460991ecf4fbeca2c0f8c39874b39a0885d6f67d Mon Sep 17 00:00:00 2001 From: Loïc Guilloux Date: Sat, 17 Jul 2021 12:48:35 +0200 Subject: Feature: Persistant rotation of numbered auto/netsave after restart (#9397) It was always starting from 0 on openttd restart. Now the most recent auto/netsave number will be used as a base to generate the next filename. --- src/fios.cpp | 57 ++++++++++++++++++++++++++++++++++++++++++ src/fios.h | 12 +++++++++ src/network/network_client.cpp | 4 +-- src/openttd.cpp | 2 +- src/saveload/saveload.cpp | 17 +++---------- src/saveload/saveload.h | 3 ++- 6 files changed, 77 insertions(+), 18 deletions(-) diff --git a/src/fios.cpp b/src/fios.cpp index c59bcfb21..0491c1e51 100644 --- a/src/fios.cpp +++ b/src/fios.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #ifndef _WIN32 # include @@ -745,3 +746,59 @@ void ScanScenarios() { _scanner.Scan(true); } + +/** + * Constructs FiosNumberedSaveName. Initial number is the most recent save, or -1 if not found. + * @param prefix The prefix to use to generate a filename. +*/ +FiosNumberedSaveName::FiosNumberedSaveName(const std::string &prefix) : prefix(prefix), number(-1) +{ + static std::optional _autosave_path; + if (!_autosave_path) _autosave_path = FioFindDirectory(AUTOSAVE_DIR); + + static std::string _prefix; ///< Static as the lambda needs access to it. + + /* Callback for FiosFileScanner. */ + static fios_getlist_callback_proc *proc = [](SaveLoadOperation fop, const std::string &file, const char *ext, char *title, const char *last) { + if (strcasecmp(ext, ".sav") == 0 && StrStartsWith(file, _prefix)) return FIOS_TYPE_FILE; + return FIOS_TYPE_INVALID; + }; + + /* Prefix to check in the callback. */ + _prefix = *_autosave_path + this->prefix; + + /* Get the save list. */ + FileList list; + FiosFileScanner scanner(SLO_SAVE, proc, list); + scanner.Scan(".sav", _autosave_path->c_str(), false); + + /* Find the number for the most recent save, if any. */ + if (list.begin() != list.end()) { + SortingBits order = _savegame_sort_order; + _savegame_sort_order = SORT_BY_DATE | SORT_DESCENDING; + std::sort(list.begin(), list.end()); + _savegame_sort_order = order; + + std::string_view name = list.begin()->title; + std::from_chars(name.data() + this->prefix.size(), name.data() + name.size(), this->number); + } +} + +/** + * Generate a savegame name and number according to _settings_client.gui.max_num_autosaves. + * @return A filename in format ".sav". +*/ +std::string FiosNumberedSaveName::Filename() +{ + if (++this->number >= _settings_client.gui.max_num_autosaves) this->number = 0; + return fmt::format("{}{}.sav", this->prefix, this->number); +} + +/** + * Generate an extension for a savegame name. + * @return An extension in format "-.sav". +*/ +std::string FiosNumberedSaveName::Extension() +{ + return fmt::format("-{}.sav", this->prefix); +} diff --git a/src/fios.h b/src/fios.h index 34504d5e0..c0e516297 100644 --- a/src/fios.h +++ b/src/fios.h @@ -125,4 +125,16 @@ std::string FiosMakeSavegameName(const char *name); FiosType FiosGetSavegameListCallback(SaveLoadOperation fop, const std::string &file, const char *ext, char *title, const char *last); +/** + * A savegame name automatically numbered. + */ +struct FiosNumberedSaveName { + FiosNumberedSaveName(const std::string &prefix); + std::string Filename(); + std::string Extension(); +private: + std::string prefix; + int number; +}; + #endif /* FIOS_H */ diff --git a/src/network/network_client.cpp b/src/network/network_client.cpp index 9f08062f3..d38437cc1 100644 --- a/src/network/network_client.cpp +++ b/src/network/network_client.cpp @@ -132,8 +132,8 @@ struct PacketReader : LoadFilter { */ void ClientNetworkEmergencySave() { - static int _netsave_ctr = 0; - DoAutoOrNetsave(_netsave_ctr, true); + static FiosNumberedSaveName _netsave_ctr("netsave"); + DoAutoOrNetsave(_netsave_ctr); } diff --git a/src/openttd.cpp b/src/openttd.cpp index 711df58c4..0ea1fa75d 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -1393,7 +1393,7 @@ void StateGameLoop() */ static void DoAutosave() { - static int _autosave_ctr = 0; + static FiosNumberedSaveName _autosave_ctr("autosave"); DoAutoOrNetsave(_autosave_ctr); } diff --git a/src/saveload/saveload.cpp b/src/saveload/saveload.cpp index d771bf526..c8a1a0d29 100644 --- a/src/saveload/saveload.cpp +++ b/src/saveload/saveload.cpp @@ -3328,26 +3328,15 @@ SaveOrLoadResult SaveOrLoad(const std::string &filename, SaveLoadOperation fop, * @param counter A reference to the counter variable to be used for rotating the file name. * @param netsave Indicates if this is a regular autosave or a netsave. */ -void DoAutoOrNetsave(int &counter, bool netsave) +void DoAutoOrNetsave(FiosNumberedSaveName &counter) { char buf[MAX_PATH]; if (_settings_client.gui.keep_all_autosave) { GenerateDefaultSaveName(buf, lastof(buf)); - if (!netsave) { - strecat(buf, ".sav", lastof(buf)); - } else { - strecat(buf, "-netsave.sav", lastof(buf)); - } + strecat(buf, counter.Extension().c_str(), lastof(buf)); } else { - /* Generate a savegame name and number according to _settings_client.gui.max_num_autosaves. */ - if (!netsave) { - seprintf(buf, lastof(buf), "autosave%d.sav", counter); - } else { - seprintf(buf, lastof(buf), "netsave%d.sav", counter); - } - - if (++counter >= _settings_client.gui.max_num_autosaves) counter = 0; + strecpy(buf, counter.Filename().c_str(), lastof(buf)); } Debug(sl, 2, "Autosaving to '{}'", buf); diff --git a/src/saveload/saveload.h b/src/saveload/saveload.h index d79bc1416..3047cbfd8 100644 --- a/src/saveload/saveload.h +++ b/src/saveload/saveload.h @@ -11,6 +11,7 @@ #define SAVELOAD_H #include "../fileio_type.h" +#include "../fios.h" #include "../strings_type.h" #include "../core/span_type.hpp" #include @@ -381,7 +382,7 @@ void WaitTillSaved(); void ProcessAsyncSaveFinish(); void DoExitSave(); -void DoAutoOrNetsave(int &counter, bool netsave = false); +void DoAutoOrNetsave(FiosNumberedSaveName &counter); SaveOrLoadResult SaveWithFilter(struct SaveFilter *writer, bool threaded); SaveOrLoadResult LoadWithFilter(struct LoadFilter *reader); -- cgit v1.2.3-70-g09d2