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_internal.h Functions and types used internally for the settings configurations. */
10 #ifndef SETTINGS_INTERNAL_H
11 #define SETTINGS_INTERNAL_H
14 #include "saveload/saveload.h"
16 enum SettingFlag
: uint16_t {
18 SF_GUI_0_IS_SPECIAL
= 1 << 0, ///< A value of zero is possible and has a custom string (the one after "strval").
19 SF_GUI_DROPDOWN
= 1 << 2, ///< The value represents a limited number of string-options (internally integer) presented as dropdown.
20 SF_GUI_CURRENCY
= 1 << 3, ///< The number represents money, so when reading value multiply by exchange rate.
21 SF_NETWORK_ONLY
= 1 << 4, ///< This setting only applies to network games.
22 SF_NO_NETWORK
= 1 << 5, ///< This setting does not apply to network games; it may not be changed during the game.
23 SF_NEWGAME_ONLY
= 1 << 6, ///< This setting cannot be changed in a game.
24 SF_SCENEDIT_TOO
= 1 << 7, ///< This setting can be changed in the scenario editor (only makes sense when SF_NEWGAME_ONLY is set).
25 SF_SCENEDIT_ONLY
= 1 << 8, ///< This setting can only be changed in the scenario editor.
26 SF_PER_COMPANY
= 1 << 9, ///< This setting can be different for each company (saved in company struct).
27 SF_NOT_IN_SAVE
= 1 << 10, ///< Do not save with savegame, basically client-based.
28 SF_NOT_IN_CONFIG
= 1 << 11, ///< Do not save to config file.
29 SF_NO_NETWORK_SYNC
= 1 << 12, ///< Do not synchronize over network (but it is saved if SF_NOT_IN_SAVE is not set).
31 DECLARE_ENUM_AS_BIT_SET(SettingFlag
)
34 * A SettingCategory defines a grouping of the settings.
35 * The group #SC_BASIC is intended for settings which also a novice player would like to change and is able to understand.
36 * The group #SC_ADVANCED is intended for settings which an experienced player would like to use. This is the case for most settings.
37 * Finally #SC_EXPERT settings only few people want to see in rare cases.
38 * The grouping is meant to be inclusive, i.e. all settings in #SC_BASIC also will be included
39 * in the set of settings in #SC_ADVANCED. The group #SC_EXPERT contains all settings.
41 enum SettingCategory
{
44 /* Filters for the list */
45 SC_BASIC_LIST
= 1 << 0, ///< Settings displayed in the list of basic settings.
46 SC_ADVANCED_LIST
= 1 << 1, ///< Settings displayed in the list of advanced settings.
47 SC_EXPERT_LIST
= 1 << 2, ///< Settings displayed in the list of expert settings.
49 /* Setting classification */
50 SC_BASIC
= SC_BASIC_LIST
| SC_ADVANCED_LIST
| SC_EXPERT_LIST
, ///< Basic settings are part of all lists.
51 SC_ADVANCED
= SC_ADVANCED_LIST
| SC_EXPERT_LIST
, ///< Advanced settings are part of advanced and expert list.
52 SC_EXPERT
= SC_EXPERT_LIST
, ///< Expert settings can only be seen in the expert list.
58 * Type of settings for filtering.
61 ST_GAME
, ///< Game setting.
62 ST_COMPANY
, ///< Company setting.
63 ST_CLIENT
, ///< Client setting.
65 ST_ALL
, ///< Used in setting filter to match all types.
70 /** Properties of config file settings. */
72 SettingDesc(const SaveLoad
&save
, SettingFlag flags
, bool startup
) :
73 flags(flags
), startup(startup
), save(save
) {}
74 virtual ~SettingDesc() = default;
76 SettingFlag flags
; ///< Handles how a setting would show up in the GUI (text/currency, etc.).
77 bool startup
; ///< Setting has to be loaded directly at startup?.
78 SaveLoad save
; ///< Internal structure (going to savegame, parts to config).
80 bool IsEditable(bool do_command
= false) const;
81 SettingType
GetType() const;
84 * Get the name of this setting.
85 * @return The name of the setting.
87 constexpr const std::string
&GetName() const
89 return this->save
.name
;
93 * Check whether this setting is an integer type setting.
94 * @return True when the underlying type is an integer.
96 virtual bool IsIntSetting() const { return false; }
99 * Check whether this setting is an string type setting.
100 * @return True when the underlying type is a string.
102 virtual bool IsStringSetting() const { return false; }
104 const struct IntSettingDesc
*AsIntSetting() const;
105 const struct StringSettingDesc
*AsStringSetting() const;
108 * Format the value of the setting associated with this object.
109 * @param buf The before of the buffer to format into.
110 * @param last The end of the buffer to format into.
111 * @param object The object the setting is in.
113 virtual std::string
FormatValue(const void *object
) const = 0;
116 * Parse/read the value from the Ini item into the setting associated with this object.
117 * @param item The Ini item with the content of this setting.
118 * @param object The object the setting is in.
120 virtual void ParseValue(const IniItem
*item
, void *object
) const = 0;
123 * Check whether the value in the Ini item is the same as is saved in this setting in the object.
124 * It might be that determining whether the value is the same is way more expensive than just
125 * writing the value. In those cases this function may unconditionally return false even though
126 * the value might be the same as in the Ini item.
127 * @param item The Ini item with the content of this setting.
128 * @param object The object the setting is in.
129 * @return True if the value is definitely the same (might be false when the same).
131 virtual bool IsSameValue(const IniItem
*item
, void *object
) const = 0;
134 * Check whether the value is the same as the default value.
136 * @param object The object the setting is in.
137 * @return true iff the value is the default value.
139 virtual bool IsDefaultValue(void *object
) const = 0;
142 * Reset the setting to its default value.
144 virtual void ResetToDefault(void *object
) const = 0;
147 /** Base integer type, including boolean, settings. Only these are shown in the settings UI. */
148 struct IntSettingDesc
: SettingDesc
{
149 typedef StringID
GetTitleCallback(const IntSettingDesc
&sd
);
150 typedef StringID
GetHelpCallback(const IntSettingDesc
&sd
);
151 typedef void SetValueDParamsCallback(const IntSettingDesc
&sd
, uint first_param
, int32_t value
);
154 * A check to be performed before the setting gets changed. The passed integer may be
155 * changed by the check if that is important, for example to remove some unwanted bit.
156 * The return value denotes whether the value, potentially after the changes,
157 * is allowed to be used/set in the configuration.
158 * @param value The prospective new value for the setting.
159 * @return True when the setting is accepted.
161 typedef bool PreChangeCheck(int32_t &value
);
163 * A callback to denote that a setting has been changed.
164 * @param The new value for the setting.
166 typedef void PostChangeCallback(int32_t value
);
168 * A callback to get the correct default value. For example a default that can be measured in time
169 * units or expressed as a percentage.
170 * @return The correct default value for the setting.
172 typedef int32_t GetDefaultValueCallback();
179 std::enable_if_t
<std::disjunction_v
<std::is_convertible
<Tdef
, int32_t>, std::is_base_of
<StrongTypedefBase
, Tdef
>>, int> = 0,
180 std::enable_if_t
<std::disjunction_v
<std::is_convertible
<Tmin
, int32_t>, std::is_base_of
<StrongTypedefBase
, Tmin
>>, int> = 0,
181 std::enable_if_t
<std::disjunction_v
<std::is_convertible
<Tmax
, uint32_t>, std::is_base_of
<StrongTypedefBase
, Tmax
>>, int> = 0,
182 std::enable_if_t
<std::disjunction_v
<std::is_convertible
<Tinterval
, int32_t>, std::is_base_of
<StrongTypedefBase
, Tinterval
>>, int> = 0
184 IntSettingDesc(const SaveLoad
&save
, SettingFlag flags
, bool startup
, Tdef def
,
185 Tmin min
, Tmax max
, Tinterval interval
, StringID str
, StringID str_help
, StringID str_val
,
186 SettingCategory cat
, PreChangeCheck pre_check
, PostChangeCallback post_callback
,
187 GetTitleCallback get_title_cb
, GetHelpCallback get_help_cb
, SetValueDParamsCallback set_value_dparams_cb
,
188 GetDefaultValueCallback get_def_cb
) :
189 SettingDesc(save
, flags
, startup
),
190 str(str
), str_help(str_help
), str_val(str_val
), cat(cat
), pre_check(pre_check
),
191 post_callback(post_callback
),
192 get_title_cb(get_title_cb
), get_help_cb(get_help_cb
), set_value_dparams_cb(set_value_dparams_cb
),
193 get_def_cb(get_def_cb
) {
194 if constexpr (std::is_base_of_v
<StrongTypedefBase
, Tdef
>) {
195 this->def
= def
.base();
200 if constexpr (std::is_base_of_v
<StrongTypedefBase
, Tmin
>) {
201 this->min
= min
.base();
206 if constexpr (std::is_base_of_v
<StrongTypedefBase
, Tmax
>) {
207 this->max
= max
.base();
212 if constexpr (std::is_base_of_v
<StrongTypedefBase
, Tinterval
>) {
213 this->interval
= interval
.base();
215 this->interval
= interval
;
219 int32_t def
; ///< default value given when none is present
220 int32_t min
; ///< minimum values
221 uint32_t max
; ///< maximum values
222 int32_t interval
; ///< the interval to use between settings in the 'settings' window. If interval is '0' the interval is dynamically determined
223 StringID str
; ///< (translated) string with descriptive text; gui and console
224 StringID str_help
; ///< (Translated) string with help text; gui only.
225 StringID str_val
; ///< (Translated) first string describing the value.
226 SettingCategory cat
; ///< assigned categories of the setting
227 PreChangeCheck
*pre_check
; ///< Callback to check for the validity of the setting.
228 PostChangeCallback
*post_callback
; ///< Callback when the setting has been changed.
229 GetTitleCallback
*get_title_cb
;
230 GetHelpCallback
*get_help_cb
;
231 SetValueDParamsCallback
*set_value_dparams_cb
;
232 GetDefaultValueCallback
*get_def_cb
; ///< Callback to set the correct default value
234 StringID
GetTitle() const;
235 StringID
GetHelp() const;
236 void SetValueDParams(uint first_param
, int32_t value
) const;
239 * Check whether this setting is a boolean type setting.
240 * @return True when the underlying type is an integer.
242 virtual bool IsBoolSetting() const { return false; }
243 bool IsIntSetting() const override
{ return true; }
245 void ChangeValue(const void *object
, int32_t newvalue
) const;
246 void MakeValueValidAndWrite(const void *object
, int32_t value
) const;
248 virtual size_t ParseValue(const char *str
) const;
249 std::string
FormatValue(const void *object
) const override
;
250 void ParseValue(const IniItem
*item
, void *object
) const override
;
251 bool IsSameValue(const IniItem
*item
, void *object
) const override
;
252 bool IsDefaultValue(void *object
) const override
;
253 void ResetToDefault(void *object
) const override
;
254 int32_t Read(const void *object
) const;
257 void MakeValueValid(int32_t &value
) const;
258 void Write(const void *object
, int32_t value
) const;
261 /** Boolean setting. */
262 struct BoolSettingDesc
: IntSettingDesc
{
263 BoolSettingDesc(const SaveLoad
&save
, SettingFlag flags
, bool startup
, bool def
,
264 StringID str
, StringID str_help
, StringID str_val
, SettingCategory cat
,
265 PreChangeCheck pre_check
, PostChangeCallback post_callback
,
266 GetTitleCallback get_title_cb
, GetHelpCallback get_help_cb
, SetValueDParamsCallback set_value_dparams_cb
,
267 GetDefaultValueCallback get_def_cb
) :
268 IntSettingDesc(save
, flags
, startup
, def
? 1 : 0, 0, 1, 0, str
, str_help
, str_val
, cat
,
269 pre_check
, post_callback
, get_title_cb
, get_help_cb
, set_value_dparams_cb
, get_def_cb
) {}
271 static std::optional
<bool> ParseSingleValue(const char *str
);
273 bool IsBoolSetting() const override
{ return true; }
274 size_t ParseValue(const char *str
) const override
;
275 std::string
FormatValue(const void *object
) const override
;
278 /** One of many setting. */
279 struct OneOfManySettingDesc
: IntSettingDesc
{
280 typedef size_t OnConvert(const char *value
); ///< callback prototype for conversion error
282 OneOfManySettingDesc(const SaveLoad
&save
, SettingFlag flags
, bool startup
, int32_t def
,
283 int32_t max
, StringID str
, StringID str_help
, StringID str_val
, SettingCategory cat
,
284 PreChangeCheck pre_check
, PostChangeCallback post_callback
,
285 GetTitleCallback get_title_cb
, GetHelpCallback get_help_cb
, SetValueDParamsCallback set_value_dparams_cb
,
286 GetDefaultValueCallback get_def_cb
, std::initializer_list
<const char *> many
, OnConvert
*many_cnvt
) :
287 IntSettingDesc(save
, flags
, startup
, def
, 0, max
, 0, str
, str_help
, str_val
, cat
,
288 pre_check
, post_callback
, get_title_cb
, get_help_cb
, set_value_dparams_cb
, get_def_cb
), many_cnvt(many_cnvt
)
290 for (auto one
: many
) this->many
.push_back(one
);
293 std::vector
<std::string
> many
; ///< possible values for this type
294 OnConvert
*many_cnvt
; ///< callback procedure when loading value mechanism fails
296 static size_t ParseSingleValue(const char *str
, size_t len
, const std::vector
<std::string
> &many
);
297 std::string
FormatSingleValue(uint id
) const;
299 size_t ParseValue(const char *str
) const override
;
300 std::string
FormatValue(const void *object
) const override
;
303 /** Many of many setting. */
304 struct ManyOfManySettingDesc
: OneOfManySettingDesc
{
305 ManyOfManySettingDesc(const SaveLoad
&save
, SettingFlag flags
, bool startup
,
306 int32_t def
, StringID str
, StringID str_help
, StringID str_val
, SettingCategory cat
,
307 PreChangeCheck pre_check
, PostChangeCallback post_callback
,
308 GetTitleCallback get_title_cb
, GetHelpCallback get_help_cb
, SetValueDParamsCallback set_value_dparams_cb
,
309 GetDefaultValueCallback get_def_cb
, std::initializer_list
<const char *> many
, OnConvert
*many_cnvt
) :
310 OneOfManySettingDesc(save
, flags
, startup
, def
, (1 << many
.size()) - 1, str
, str_help
,
311 str_val
, cat
, pre_check
, post_callback
, get_title_cb
, get_help_cb
, set_value_dparams_cb
, get_def_cb
, many
, many_cnvt
) {}
313 size_t ParseValue(const char *str
) const override
;
314 std::string
FormatValue(const void *object
) const override
;
317 /** String settings. */
318 struct StringSettingDesc
: SettingDesc
{
320 * A check to be performed before the setting gets changed. The passed string may be
321 * changed by the check if that is important, for example to remove unwanted white
322 * space. The return value denotes whether the value, potentially after the changes,
323 * is allowed to be used/set in the configuration.
324 * @param value The prospective new value for the setting.
325 * @return True when the setting is accepted.
327 typedef bool PreChangeCheck(std::string
&value
);
329 * A callback to denote that a setting has been changed.
330 * @param The new value for the setting.
332 typedef void PostChangeCallback(const std::string
&value
);
334 StringSettingDesc(const SaveLoad
&save
, SettingFlag flags
, bool startup
, const char *def
,
335 uint32_t max_length
, PreChangeCheck pre_check
, PostChangeCallback post_callback
) :
336 SettingDesc(save
, flags
, startup
), def(def
== nullptr ? "" : def
), max_length(max_length
),
337 pre_check(pre_check
), post_callback(post_callback
) {}
339 std::string def
; ///< Default value given when none is present
340 uint32_t max_length
; ///< Maximum length of the string, 0 means no maximum length
341 PreChangeCheck
*pre_check
; ///< Callback to check for the validity of the setting.
342 PostChangeCallback
*post_callback
; ///< Callback when the setting has been changed.
344 bool IsStringSetting() const override
{ return true; }
345 void ChangeValue(const void *object
, std::string
&newval
) const;
347 std::string
FormatValue(const void *object
) const override
;
348 void ParseValue(const IniItem
*item
, void *object
) const override
;
349 bool IsSameValue(const IniItem
*item
, void *object
) const override
;
350 bool IsDefaultValue(void *object
) const override
;
351 void ResetToDefault(void *object
) const override
;
352 const std::string
&Read(const void *object
) const;
355 void MakeValueValid(std::string
&str
) const;
356 void Write(const void *object
, const std::string
&str
) const;
359 /** List/array settings. */
360 struct ListSettingDesc
: SettingDesc
{
361 ListSettingDesc(const SaveLoad
&save
, SettingFlag flags
, bool startup
, const char *def
) :
362 SettingDesc(save
, flags
, startup
), def(def
) {}
364 const char *def
; ///< default value given when none is present
366 std::string
FormatValue(const void *object
) const override
;
367 void ParseValue(const IniItem
*item
, void *object
) const override
;
368 bool IsSameValue(const IniItem
*item
, void *object
) const override
;
369 bool IsDefaultValue(void *object
) const override
;
370 void ResetToDefault(void *object
) const override
;
373 /** Placeholder for settings that have been removed, but might still linger in the savegame. */
374 struct NullSettingDesc
: SettingDesc
{
375 NullSettingDesc(const SaveLoad
&save
) :
376 SettingDesc(save
, SF_NOT_IN_CONFIG
, false) {}
378 std::string
FormatValue(const void *) const override
{ NOT_REACHED(); }
379 void ParseValue(const IniItem
*, void *) const override
{ NOT_REACHED(); }
380 bool IsSameValue(const IniItem
*, void *) const override
{ NOT_REACHED(); }
381 bool IsDefaultValue(void *) const override
{ NOT_REACHED(); }
382 void ResetToDefault(void *) const override
{ NOT_REACHED(); }
385 typedef std::variant
<IntSettingDesc
, BoolSettingDesc
, OneOfManySettingDesc
, ManyOfManySettingDesc
, StringSettingDesc
, ListSettingDesc
, NullSettingDesc
> SettingVariant
;
388 * Helper to convert the type of the iterated settings description to a pointer to it.
389 * @param desc The type of the iterator of the value in SettingTable.
390 * @return The actual pointer to SettingDesc.
392 static constexpr const SettingDesc
*GetSettingDesc(const SettingVariant
&desc
)
394 return std::visit([](auto&& arg
) -> const SettingDesc
* { return &arg
; }, desc
);
397 typedef std::span
<const SettingVariant
> SettingTable
;
399 const SettingDesc
*GetSettingFromName(const std::string_view name
);
400 void GetSaveLoadFromSettingTable(SettingTable settings
, std::vector
<SaveLoad
> &saveloads
);
401 bool SetSettingValue(const IntSettingDesc
*sd
, int32_t value
, bool force_newgame
= false);
402 bool SetSettingValue(const StringSettingDesc
*sd
, const std::string value
, bool force_newgame
= false);
404 #endif /* SETTINGS_INTERNAL_H */