mirror of https://github.com/OpenTTD/OpenTTD.git
Codechange: split off the settings saveload code from the main settings handling logic
This commit is contained in:
parent
25ca6a75bc
commit
7e7a4aad72
|
@ -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
|
||||
|
|
|
@ -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);
|
198
src/settings.cpp
198
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.
|
||||
|
@ -143,16 +151,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
|
||||
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue