2 * This file is part of OpenTTD.
3 * 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.
4 * 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.
5 * 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/>.
8 /** @file settings_sl.cpp Handles the saveload part of the settings. */
10 #include "../stdafx.h"
13 #include "compat/settings_sl_compat.h"
15 #include "../settings_type.h"
16 #include "../settings_table.h"
17 #include "../network/network.h"
20 #include "../safeguards.h"
23 * Prepare for reading and old diff_custom by zero-ing the memory.
25 void PrepareOldDiffCustom()
27 memset(_old_diff_custom
, 0, sizeof(_old_diff_custom
));
31 * Reading of the old diff_custom array and transforming it to the new format.
32 * @param savegame is it read from the config or savegame. In the latter case
33 * we are sure there is an array; in the former case we have
36 void HandleOldDiffCustom(bool savegame
)
38 /* Savegames before v4 didn't have "town_council_tolerance" in savegame yet. */
39 bool has_no_town_council_tolerance
= savegame
&& IsSavegameVersionBefore(SLV_4
);
40 uint options_to_load
= GAME_DIFFICULTY_NUM
- (has_no_town_council_tolerance
? 1 : 0);
43 /* If we did read to old_diff_custom, then at least one value must be non 0. */
44 bool old_diff_custom_used
= false;
45 for (uint i
= 0; i
< options_to_load
&& !old_diff_custom_used
; i
++) {
46 old_diff_custom_used
= (_old_diff_custom
[i
] != 0);
49 if (!old_diff_custom_used
) return;
52 /* Iterate over all the old difficulty settings, and convert the list-value to the new setting. */
54 for (const auto &name
: _old_diff_settings
) {
55 if (has_no_town_council_tolerance
&& name
== "town_council_tolerance") continue;
57 std::string fullname
= "difficulty." + name
;
58 const SettingDesc
*sd
= GetSettingFromName(fullname
);
60 /* Some settings are no longer in use; skip reading those. */
66 int32_t value
= (int32_t)((name
== "max_loan" ? 1000 : 1) * _old_diff_custom
[i
++]);
67 sd
->AsIntSetting()->MakeValueValidAndWrite(savegame
? &_settings_game
: &_settings_newgame
, value
);
72 * Get the SaveLoad description for the SettingTable.
73 * @param settings SettingDesc struct containing all information.
74 * @param is_loading True iff the SaveLoad table is for loading.
75 * @return Vector with SaveLoad entries for the SettingTable.
77 static std::vector
<SaveLoad
> GetSettingsDesc(const SettingTable
&settings
, bool is_loading
)
79 std::vector
<SaveLoad
> saveloads
;
80 for (auto &desc
: settings
) {
81 const SettingDesc
*sd
= GetSettingDesc(desc
);
82 if (sd
->flags
& SF_NOT_IN_SAVE
) continue;
84 if (is_loading
&& (sd
->flags
& SF_NO_NETWORK_SYNC
) && _networking
&& !_network_server
) {
85 if (IsSavegameVersionBefore(SLV_TABLE_CHUNKS
)) {
86 /* We don't want to read this setting, so we do need to skip over it. */
87 saveloads
.push_back({sd
->GetName(), sd
->save
.cmd
, GetVarFileType(sd
->save
.conv
) | SLE_VAR_NULL
, sd
->save
.length
, sd
->save
.version_from
, sd
->save
.version_to
, nullptr, 0, nullptr});
92 saveloads
.push_back(sd
->save
);
99 * Save and load handler for settings
100 * @param settings SettingDesc struct containing all information
101 * @param object can be either nullptr in which case we load global variables or
102 * a pointer to a struct which is getting saved
104 static void LoadSettings(const SettingTable
&settings
, void *object
, const SaveLoadCompatTable
&slct
)
106 const std::vector
<SaveLoad
> slt
= SlCompatTableHeader(GetSettingsDesc(settings
, true), slct
);
108 if (!IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY
) && SlIterateArray() == -1) return;
109 SlObject(object
, slt
);
110 if (!IsSavegameVersionBefore(SLV_RIFF_TO_ARRAY
) && SlIterateArray() != -1) SlErrorCorrupt("Too many settings entries");
112 /* Ensure all IntSettings are valid (min/max could have changed between versions etc). */
113 for (auto &desc
: settings
) {
114 const SettingDesc
*sd
= GetSettingDesc(desc
);
115 if (sd
->flags
& SF_NOT_IN_SAVE
) continue;
116 if ((sd
->flags
& SF_NO_NETWORK_SYNC
) && _networking
&& !_network_server
) continue;
117 if (!SlIsObjectCurrentlyValid(sd
->save
.version_from
, sd
->save
.version_to
)) continue;
119 if (sd
->IsIntSetting()) {
120 const IntSettingDesc
*int_setting
= sd
->AsIntSetting();
121 int_setting
->MakeValueValidAndWrite(object
, int_setting
->Read(object
));
127 * Save and load handler for settings
128 * @param settings SettingDesc struct containing all information
129 * @param object can be either nullptr in which case we load global variables or
130 * a pointer to a struct which is getting saved
132 static void SaveSettings(const SettingTable
&settings
, void *object
)
134 const std::vector
<SaveLoad
> slt
= GetSettingsDesc(settings
, false);
139 SlObject(object
, slt
);
142 struct OPTSChunkHandler
: ChunkHandler
{
143 OPTSChunkHandler() : ChunkHandler('OPTS', CH_READONLY
) {}
145 void Load() const override
147 /* Copy over default setting since some might not get loaded in
148 * a networking environment. This ensures for example that the local
149 * autosave-frequency stays when joining a network-server */
150 PrepareOldDiffCustom();
151 LoadSettings(_old_gameopt_settings
, &_settings_game
, _gameopt_sl_compat
);
152 HandleOldDiffCustom(true);
156 struct PATSChunkHandler
: ChunkHandler
{
157 PATSChunkHandler() : ChunkHandler('PATS', CH_TABLE
) {}
160 * Create a single table with all settings that should be stored/loaded
163 SettingTable
GetSettingTable() const
165 static const SettingTable saveload_settings_tables
[] = {
166 _difficulty_settings
,
171 _pathfinding_settings
,
175 static std::vector
<SettingVariant
> settings_table
;
177 if (settings_table
.empty()) {
178 for (auto &saveload_settings_table
: saveload_settings_tables
) {
179 for (auto &saveload_setting
: saveload_settings_table
) {
180 settings_table
.push_back(saveload_setting
);
185 return settings_table
;
188 void Load() const override
190 const auto settings_table
= this->GetSettingTable();
192 /* Reset all settings to their default, so any settings missing in the savegame
193 * are their default, and not "value of last game". AfterLoad might still fix
194 * up values to become non-default, depending on the saveload version. */
195 for (auto &desc
: settings_table
) {
196 const SettingDesc
*sd
= GetSettingDesc(desc
);
197 if (sd
->flags
& SF_NOT_IN_SAVE
) continue;
198 if ((sd
->flags
& SF_NO_NETWORK_SYNC
) && _networking
&& !_network_server
) continue;
200 sd
->ResetToDefault(&_settings_game
);
203 LoadSettings(settings_table
, &_settings_game
, _settings_sl_compat
);
206 void LoadCheck(size_t) const override
208 LoadSettings(this->GetSettingTable(), &_load_check_data
.settings
, _settings_sl_compat
);
211 void Save() const override
213 SaveSettings(this->GetSettingTable(), &_settings_game
);
217 static const OPTSChunkHandler OPTS
;
218 static const PATSChunkHandler PATS
;
219 static const ChunkHandlerRef setting_chunk_handlers
[] = {
224 extern const ChunkHandlerTable
_setting_chunk_handlers(setting_chunk_handlers
);