diff options
-rw-r--r-- | src/saveload/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/saveload/settings_sl.cpp | 178 | ||||
-rw-r--r-- | src/settings.cpp | 198 | ||||
-rw-r--r-- | src/settings_internal.h | 10 |
4 files changed, 204 insertions, 183 deletions
diff --git a/src/saveload/CMakeLists.txt b/src/saveload/CMakeLists.txt index 5f83309a4..32bcc57ac 100644 --- a/src/saveload/CMakeLists.txt +++ b/src/saveload/CMakeLists.txt @@ -33,6 +33,7 @@ add_files( saveload.h saveload_filter.h saveload_internal.h + settings_sl.cpp signs_sl.cpp station_sl.cpp storage_sl.cpp diff --git a/src/saveload/settings_sl.cpp b/src/saveload/settings_sl.cpp new file mode 100644 index 000000000..2097d8645 --- /dev/null +++ b/src/saveload/settings_sl.cpp @@ -0,0 +1,178 @@ +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>. + */ + +/** @file settings_sl.cpp Handles the saveload part of the settings. */ + +#include "../stdafx.h" + +#include "saveload.h" +#include "compat/settings_sl_compat.h" + +#include "../settings_type.h" +#include "../settings_table.h" +#include "../network/network.h" +#include "../fios.h" + +#include "../safeguards.h" + +/** + * Prepare for reading and old diff_custom by zero-ing the memory. + */ +void PrepareOldDiffCustom() +{ + memset(_old_diff_custom, 0, sizeof(_old_diff_custom)); +} + +/** + * Reading of the old diff_custom array and transforming it to the new format. + * @param savegame is it read from the config or savegame. In the latter case + * we are sure there is an array; in the former case we have + * to check that. + */ +void HandleOldDiffCustom(bool savegame) +{ + /* Savegames before v4 didn't have "town_council_tolerance" in savegame yet. */ + bool has_no_town_council_tolerance = savegame && IsSavegameVersionBefore(SLV_4); + uint options_to_load = GAME_DIFFICULTY_NUM - (has_no_town_council_tolerance ? 1 : 0); + + if (!savegame) { + /* If we did read to old_diff_custom, then at least one value must be non 0. */ + bool old_diff_custom_used = false; + for (uint i = 0; i < options_to_load && !old_diff_custom_used; i++) { + old_diff_custom_used = (_old_diff_custom[i] != 0); + } + + if (!old_diff_custom_used) return; + } + + /* Iterate over all the old difficulty settings, and convert the list-value to the new setting. */ + uint i = 0; + for (const auto &name : _old_diff_settings) { + if (has_no_town_council_tolerance && name == "town_council_tolerance") continue; + + std::string fullname = "difficulty." + name; + const SettingDesc *sd = GetSettingFromName(fullname); + + /* Some settings are no longer in use; skip reading those. */ + if (sd == nullptr) { + i++; + continue; + } + + int32 value = (int32)((name == "max_loan" ? 1000 : 1) * _old_diff_custom[i++]); + sd->AsIntSetting()->MakeValueValidAndWrite(savegame ? &_settings_game : &_settings_newgame, value); + } +} + +/** + * Get the SaveLoad description for the SettingTable. + * @param settings SettingDesc struct containing all information. + * @param is_loading True iff the SaveLoad table is for loading. + * @return Vector with SaveLoad entries for the SettingTable. + */ +static std::vector<SaveLoad> GetSettingsDesc(const SettingTable &settings, bool is_loading) +{ + std::vector<SaveLoad> saveloads; + for (auto &desc : settings) { + const SettingDesc *sd = GetSettingDesc(desc); + if (sd->flags & SF_NOT_IN_SAVE) continue; + + if (is_loading && (sd->flags & SF_NO_NETWORK_SYNC) && _networking && !_network_server) { + if (IsSavegameVersionBefore(SLV_TABLE_CHUNKS)) { + /* We don't want to read this setting, so we do need to skip over it. */ + saveloads.push_back({sd->name, sd->save.cmd, GetVarFileType(sd->save.conv) | SLE_VAR_NULL, sd->save.length, sd->save.version_from, sd->save.version_to, 0, nullptr, 0, nullptr}); + } + continue; + } + + SaveLoad sv = sd->save; + /* Replace the name with the actual name of the setting. */ + if (!sd->name.empty()) sv.name = sd->name; + saveloads.push_back(sv); + } + + return saveloads; +} + +/** + * Save and load handler for settings + * @param settings SettingDesc struct containing all information + * @param object can be either nullptr in which case we load global variables or + * a pointer to a struct which is getting saved + */ +static void LoadSettings(const SettingTable &settings, void *object, const SaveLoadCompatTable &slct) +{ + const std::vector<SaveLoad> slt = SlCompatTableHeader(GetSettingsDesc(settings, true), slct); + + if (!IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY) && SlIterateArray() == -1) return; + SlObject(object, slt); + if (!IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY) && SlIterateArray() != -1) SlErrorCorrupt("Too many settings entries"); + + /* Ensure all IntSettings are valid (min/max could have changed between versions etc). */ + for (auto &desc : settings) { + const SettingDesc *sd = GetSettingDesc(desc); + if (sd->flags & SF_NOT_IN_SAVE) continue; + if ((sd->flags & SF_NO_NETWORK_SYNC) && _networking && !_network_server) continue; + if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue; + + if (sd->IsIntSetting()) { + const IntSettingDesc *int_setting = sd->AsIntSetting(); + int_setting->MakeValueValidAndWrite(object, int_setting->Read(object)); + } + } +} + +/** + * Save and load handler for settings + * @param settings SettingDesc struct containing all information + * @param object can be either nullptr in which case we load global variables or + * a pointer to a struct which is getting saved + */ +static void SaveSettings(const SettingTable &settings, void *object) +{ + const std::vector<SaveLoad> slt = GetSettingsDesc(settings, false); + + SlTableHeader(slt); + + SlSetArrayIndex(0); + SlObject(object, slt); +} + +static void Load_OPTS() +{ + /* Copy over default setting since some might not get loaded in + * a networking environment. This ensures for example that the local + * autosave-frequency stays when joining a network-server */ + PrepareOldDiffCustom(); + LoadSettings(_gameopt_settings, &_settings_game, _gameopt_sl_compat); + HandleOldDiffCustom(true); +} + +static void Load_PATS() +{ + /* 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(_settings, &_settings_game, _settings_sl_compat); +} + +static void Check_PATS() +{ + LoadSettings(_settings, &_load_check_data.settings, _settings_sl_compat); +} + +static void Save_PATS() +{ + SaveSettings(_settings, &_settings_game); +} + +static const ChunkHandler setting_chunk_handlers[] = { + { 'OPTS', nullptr, Load_OPTS, nullptr, nullptr, CH_READONLY }, + { 'PATS', Save_PATS, Load_PATS, nullptr, Check_PATS, CH_TABLE }, +}; + +extern const ChunkHandlerTable _setting_chunk_handlers(setting_chunk_handlers); diff --git a/src/settings.cpp b/src/settings.cpp index a2ab8ae33..e3741c235 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -44,8 +44,6 @@ #include "fios.h" #include "fileio_func.h" -#include "saveload/compat/settings_sl_compat.h" - #include "table/strings.h" #include "safeguards.h" @@ -105,7 +103,17 @@ static auto &SecretSettingTables() typedef void SettingDescProc(IniFile &ini, const SettingTable &desc, const char *grpname, void *object, bool only_startup); typedef void SettingDescProcList(IniFile &ini, const char *grpname, StringList &list); -static bool IsSignedVarMemType(VarType vt); +static bool IsSignedVarMemType(VarType vt) +{ + switch (GetVarMemType(vt)) { + case SLE_VAR_I8: + case SLE_VAR_I16: + case SLE_VAR_I32: + case SLE_VAR_I64: + return true; + } + return false; +} /** * IniFile to store a configuration. @@ -144,16 +152,6 @@ enum IniFileVersion : uint32 { const uint16 INIFILE_VERSION = (IniFileVersion)(IFV_MAX_VERSION - 1); ///< Current ini-file version of OpenTTD. /** - * Helper to convert the type of the iterated settings description to a pointer to it. - * @param desc The type of the iterator of the value in SettingTable. - * @return The actual pointer to SettingDesc. - */ -static constexpr const SettingDesc *GetSettingDesc(const SettingVariant &desc) -{ - return std::visit([](auto&& arg) -> const SettingDesc * { return &arg; }, desc); -} - -/** * Find the index value of a ONEofMANY type in a string separated by | * @param str the current value of the setting for which a value needs found * @param len length of the string @@ -832,6 +830,10 @@ const StringSettingDesc *SettingDesc::AsStringSetting() const return static_cast<const StringSettingDesc *>(this); } +void PrepareOldDiffCustom(); +void HandleOldDiffCustom(bool savegame); + + /** Checks if any settings are set to incorrect values, and sets them to correct values in that case. */ static void ValidateSettings() { @@ -842,55 +844,6 @@ static void ValidateSettings() } } -/** - * Prepare for reading and old diff_custom by zero-ing the memory. - */ -static void PrepareOldDiffCustom() -{ - memset(_old_diff_custom, 0, sizeof(_old_diff_custom)); -} - -/** - * Reading of the old diff_custom array and transforming it to the new format. - * @param savegame is it read from the config or savegame. In the latter case - * we are sure there is an array; in the former case we have - * to check that. - */ -static void HandleOldDiffCustom(bool savegame) -{ - /* Savegames before v4 didn't have "town_council_tolerance" in savegame yet. */ - bool has_no_town_council_tolerance = savegame && IsSavegameVersionBefore(SLV_4); - uint options_to_load = GAME_DIFFICULTY_NUM - (has_no_town_council_tolerance ? 1 : 0); - - if (!savegame) { - /* If we did read to old_diff_custom, then at least one value must be non 0. */ - bool old_diff_custom_used = false; - for (uint i = 0; i < options_to_load && !old_diff_custom_used; i++) { - old_diff_custom_used = (_old_diff_custom[i] != 0); - } - - if (!old_diff_custom_used) return; - } - - /* Iterate over all the old difficulty settings, and convert the list-value to the new setting. */ - uint i = 0; - for (const auto &name : _old_diff_settings) { - if (has_no_town_council_tolerance && name == "town_council_tolerance") continue; - - std::string fullname = "difficulty." + name; - const SettingDesc *sd = GetSettingFromName(fullname); - - /* Some settings are no longer in use; skip reading those. */ - if (sd == nullptr) { - i++; - continue; - } - - int32 value = (int32)((name == "max_loan" ? 1000 : 1) * _old_diff_custom[i++]); - sd->AsIntSetting()->MakeValueValidAndWrite(savegame ? &_settings_game : &_settings_newgame, value); - } -} - static void AILoadConfig(IniFile &ini, const char *grpname) { IniGroup *group = ini.GetGroup(grpname); @@ -1751,124 +1704,3 @@ void IConsoleListSettings(const char *prefilter) IConsolePrint(CC_HELP, "Use 'setting' command to change a value."); } - -/** - * Get the SaveLoad description for the SettingTable. - * @param settings SettingDesc struct containing all information. - * @param is_loading True iff the SaveLoad table is for loading. - * @return Vector with SaveLoad entries for the SettingTable. - */ -static std::vector<SaveLoad> GetSettingsDesc(const SettingTable &settings, bool is_loading) -{ - std::vector<SaveLoad> saveloads; - for (auto &desc : settings) { - const SettingDesc *sd = GetSettingDesc(desc); - if (sd->flags & SF_NOT_IN_SAVE) continue; - - if (is_loading && (sd->flags & SF_NO_NETWORK_SYNC) && _networking && !_network_server) { - if (IsSavegameVersionBefore(SLV_TABLE_CHUNKS)) { - /* We don't want to read this setting, so we do need to skip over it. */ - saveloads.push_back({sd->name, sd->save.cmd, GetVarFileType(sd->save.conv) | SLE_VAR_NULL, sd->save.length, sd->save.version_from, sd->save.version_to, 0, nullptr, 0, nullptr}); - } - continue; - } - - SaveLoad sv = sd->save; - /* Replace the name with the actual name of the setting. */ - if (!sd->name.empty()) sv.name = sd->name; - saveloads.push_back(sv); - } - - return saveloads; -} - -/** - * Save and load handler for settings - * @param settings SettingDesc struct containing all information - * @param object can be either nullptr in which case we load global variables or - * a pointer to a struct which is getting saved - */ -static void LoadSettings(const SettingTable &settings, void *object, const SaveLoadCompatTable &slct) -{ - const std::vector<SaveLoad> slt = SlCompatTableHeader(GetSettingsDesc(settings, true), slct); - - if (!IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY) && SlIterateArray() == -1) return; - SlObject(object, slt); - if (!IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY) && SlIterateArray() != -1) SlErrorCorrupt("Too many settings entries"); - - /* Ensure all IntSettings are valid (min/max could have changed between versions etc). */ - for (auto &desc : settings) { - const SettingDesc *sd = GetSettingDesc(desc); - if (sd->flags & SF_NOT_IN_SAVE) continue; - if ((sd->flags & SF_NO_NETWORK_SYNC) && _networking && !_network_server) continue; - if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue; - - if (sd->IsIntSetting()) { - const IntSettingDesc *int_setting = sd->AsIntSetting(); - int_setting->MakeValueValidAndWrite(object, int_setting->Read(object)); - } - } -} - -/** - * Save and load handler for settings - * @param settings SettingDesc struct containing all information - * @param object can be either nullptr in which case we load global variables or - * a pointer to a struct which is getting saved - */ -static void SaveSettings(const SettingTable &settings, void *object) -{ - const std::vector<SaveLoad> slt = GetSettingsDesc(settings, false); - - SlTableHeader(slt); - - SlSetArrayIndex(0); - SlObject(object, slt); -} - -static void Load_OPTS() -{ - /* Copy over default setting since some might not get loaded in - * a networking environment. This ensures for example that the local - * autosave-frequency stays when joining a network-server */ - PrepareOldDiffCustom(); - LoadSettings(_gameopt_settings, &_settings_game, _gameopt_sl_compat); - HandleOldDiffCustom(true); -} - -static void Load_PATS() -{ - /* 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(_settings, &_settings_game, _settings_sl_compat); -} - -static void Check_PATS() -{ - LoadSettings(_settings, &_load_check_data.settings, _settings_sl_compat); -} - -static void Save_PATS() -{ - SaveSettings(_settings, &_settings_game); -} - -static const ChunkHandler setting_chunk_handlers[] = { - { 'OPTS', nullptr, Load_OPTS, nullptr, nullptr, CH_READONLY }, - { 'PATS', Save_PATS, Load_PATS, nullptr, Check_PATS, CH_TABLE }, -}; - -extern const ChunkHandlerTable _setting_chunk_handlers(setting_chunk_handlers); - -static bool IsSignedVarMemType(VarType vt) -{ - switch (GetVarMemType(vt)) { - case SLE_VAR_I8: - case SLE_VAR_I16: - case SLE_VAR_I32: - case SLE_VAR_I64: - return true; - } - return false; -} diff --git a/src/settings_internal.h b/src/settings_internal.h index 0e6637a5b..304f1393a 100644 --- a/src/settings_internal.h +++ b/src/settings_internal.h @@ -302,6 +302,16 @@ struct NullSettingDesc : SettingDesc { typedef std::variant<IntSettingDesc, BoolSettingDesc, OneOfManySettingDesc, ManyOfManySettingDesc, StringSettingDesc, ListSettingDesc, NullSettingDesc> SettingVariant; +/** + * Helper to convert the type of the iterated settings description to a pointer to it. + * @param desc The type of the iterator of the value in SettingTable. + * @return The actual pointer to SettingDesc. + */ +static constexpr const SettingDesc *GetSettingDesc(const SettingVariant &desc) +{ + return std::visit([](auto&& arg) -> const SettingDesc * { return &arg; }, desc); +} + const SettingDesc *GetSettingFromName(const std::string_view name); void GetSettingSaveLoadByPrefix(const std::string_view prefix, std::vector<SaveLoad> &saveloads); bool SetSettingValue(const IntSettingDesc *sd, int32 value, bool force_newgame = false); |