From 8f22066b9a66b0cd2cce08ccc224b49864823eb0 Mon Sep 17 00:00:00 2001 From: Patric Stout Date: Sat, 2 Mar 2024 16:05:43 +0100 Subject: [PATCH] Fix #12147: reset all saved settings to their default before loading a game (#12210) --- src/saveload/settings_sl.cpp | 18 ++++++++++++++---- src/settings.cpp | 16 ++++++++++++++++ src/settings_internal.h | 9 +++++++++ 3 files changed, 39 insertions(+), 4 deletions(-) diff --git a/src/saveload/settings_sl.cpp b/src/saveload/settings_sl.cpp index ab8f5cec28..987344f952 100644 --- a/src/saveload/settings_sl.cpp +++ b/src/saveload/settings_sl.cpp @@ -187,10 +187,20 @@ struct PATSChunkHandler : ChunkHandler { void Load() const override { - /* Copy over default setting since some might not get loaded in - * a networking environment. This ensures for example that the local - * currency setting stays when joining a network-server */ - LoadSettings(this->GetSettingTable(), &_settings_game, _settings_sl_compat); + const auto settings_table = this->GetSettingTable(); + + /* Reset all settings to their default, so any settings missing in the savegame + * are their default, and not "value of last game". AfterLoad might still fix + * up values to become non-default, depending on the saveload version. */ + for (auto &desc : settings_table) { + const SettingDesc *sd = GetSettingDesc(desc); + if (sd->flags & SF_NOT_IN_SAVE) continue; + if ((sd->flags & SF_NO_NETWORK_SYNC) && _networking && !_network_server) continue; + + sd->ResetToDefault(&_settings_game); + } + + LoadSettings(settings_table, &_settings_game, _settings_sl_compat); } void LoadCheck(size_t) const override diff --git a/src/settings.cpp b/src/settings.cpp index 5200b2394c..0fc581443e 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -768,6 +768,11 @@ bool IntSettingDesc::IsDefaultValue(void *object) const return this->def == object_value; } +void IntSettingDesc::ResetToDefault(void *object) const +{ + this->Write(object, this->def); +} + std::string StringSettingDesc::FormatValue(const void *object) const { const std::string &str = this->Read(object); @@ -800,6 +805,11 @@ bool StringSettingDesc::IsDefaultValue(void *object) const return this->def == str; } +void StringSettingDesc::ResetToDefault(void *object) const +{ + this->Write(object, this->def); +} + bool ListSettingDesc::IsSameValue(const IniItem *, void *) const { /* Checking for equality is way more expensive than just writing the value. */ @@ -812,6 +822,12 @@ bool ListSettingDesc::IsDefaultValue(void *) const return false; } +void ListSettingDesc::ResetToDefault(void *) const +{ + /* Resetting a list to default is not supported. */ + NOT_REACHED(); +} + /** * Loads all items from a 'grpname' section into a list * The list parameter can be a nullptr pointer, in this case nothing will be diff --git a/src/settings_internal.h b/src/settings_internal.h index f74127a8ae..177d00a324 100644 --- a/src/settings_internal.h +++ b/src/settings_internal.h @@ -137,6 +137,11 @@ struct SettingDesc { * @return true iff the value is the default value. */ virtual bool IsDefaultValue(void *object) const = 0; + + /** + * Reset the setting to its default value. + */ + virtual void ResetToDefault(void *object) const = 0; }; /** Base integer type, including boolean, settings. Only these are shown in the settings UI. */ @@ -236,6 +241,7 @@ struct IntSettingDesc : SettingDesc { void ParseValue(const IniItem *item, void *object) const override; bool IsSameValue(const IniItem *item, void *object) const override; bool IsDefaultValue(void *object) const override; + void ResetToDefault(void *object) const override; int32_t Read(const void *object) const; private: @@ -332,6 +338,7 @@ struct StringSettingDesc : SettingDesc { void ParseValue(const IniItem *item, void *object) const override; bool IsSameValue(const IniItem *item, void *object) const override; bool IsDefaultValue(void *object) const override; + void ResetToDefault(void *object) const override; const std::string &Read(const void *object) const; private: @@ -350,6 +357,7 @@ struct ListSettingDesc : SettingDesc { void ParseValue(const IniItem *item, void *object) const override; bool IsSameValue(const IniItem *item, void *object) const override; bool IsDefaultValue(void *object) const override; + void ResetToDefault(void *object) const override; }; /** Placeholder for settings that have been removed, but might still linger in the savegame. */ @@ -361,6 +369,7 @@ struct NullSettingDesc : SettingDesc { void ParseValue(const IniItem *, void *) const override { NOT_REACHED(); } bool IsSameValue(const IniItem *, void *) const override { NOT_REACHED(); } bool IsDefaultValue(void *) const override { NOT_REACHED(); } + void ResetToDefault(void *) const override { NOT_REACHED(); } }; typedef std::variant SettingVariant;