OpenTTD Source 20260311-master-g511d3794ce
settings.cpp
Go to the documentation of this file.
1/*
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 <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
6 */
7
23
24#include "stdafx.h"
25#include <charconv>
27#include "settings_table.h"
28#include "debug.h"
29#include "currency.h"
30#include "network/network.h"
32#include "network/core/config.h"
33#include "command_func.h"
34#include "console_func.h"
35#include "genworld.h"
36#include "string_func.h"
37#include "strings_func.h"
38#include "window_func.h"
39#include "company_func.h"
40#include "rev.h"
41#include "error.h"
42#include "gamelog.h"
43#include "settings_func.h"
44#include "ini_type.h"
45#include "ai/ai_config.hpp"
46#include "game/game_config.hpp"
47#include "newgrf_config.h"
48#include "picker_func.h"
49#include "newgrf_badge_config.h"
50#include "base_media_base.h"
51#include "base_media_graphics.h"
52#include "fios.h"
53#include "fileio_func.h"
54#include "settings_cmd.h"
55
56#include "table/strings.h"
57
58#include "safeguards.h"
59
64std::string _config_file;
65std::string _private_file;
66std::string _secrets_file;
67std::string _favs_file;
68
70
83{
84 static const SettingTable _generic_setting_tables[] = {
85 _difficulty_settings,
86 _economy_settings,
87 _game_settings,
88 _gui_settings,
89 _linkgraph_settings,
90 _locale_settings,
91 _multimedia_settings,
92 _network_settings,
93 _news_display_settings,
94 _pathfinding_settings,
95 _script_settings,
96 _world_settings,
97 };
98 return _generic_setting_tables;
99}
100
106{
107 static const SettingTable _private_setting_tables[] = {
108 _network_private_settings,
109 };
110 return _private_setting_tables;
111}
112
118{
119 static const SettingTable _secrets_setting_tables[] = {
120 _network_secrets_settings,
121 };
122 return _secrets_setting_tables;
123}
124
125using SettingDescProc = void(IniFile &ini, const SettingTable &desc, std::string_view grpname, void *object, bool only_startup);
126using SettingDescProcList = void(IniFile &ini, std::string_view grpname, StringList &list);
127
128static bool IsSignedVarMemType(VarType vt)
129{
130 switch (GetVarMemType(vt)) {
131 case SLE_VAR_I8:
132 case SLE_VAR_I16:
133 case SLE_VAR_I32:
134 case SLE_VAR_I64:
135 return true;
136 }
137 return false;
138}
139
143class ConfigIniFile : public IniFile {
144private:
145 static inline const IniGroupNameList list_group_names = {
146 "bans",
147 "newgrf",
148 "servers",
149 "server_bind_addresses",
150 "server_authorized_keys",
151 "rcon_authorized_keys",
152 "admin_authorized_keys"
153 };
154
155public:
156 ConfigIniFile(const std::string &filename) : IniFile(list_group_names)
157 {
158 this->LoadFromDisk(filename, NO_DIRECTORY);
159 }
160};
161
182
184
191std::optional<uint32_t> OneOfManySettingDesc::ParseSingleValue(std::string_view str, std::span<const std::string_view> many)
192{
193 StringConsumer consumer{str};
194 auto digit = consumer.TryReadIntegerBase<uint32_t>(10);
195 /* check if it's an integer */
196 if (digit.has_value()) return digit;
197
198 auto it = std::ranges::find(many, str);
199 if (it == many.end()) return std::nullopt;
200 return static_cast<uint32_t>(it - many.begin());
201}
202
209std::optional<bool> BoolSettingDesc::ParseSingleValue(std::string_view str)
210{
211 if (str == "true" || str == "on" || str == "1") return true;
212 if (str == "false" || str == "off" || str == "0") return false;
213
214 return std::nullopt;
215}
216
224static std::optional<uint32_t> LookupManyOfMany(std::span<const std::string_view> many, std::string_view str)
225{
226 static const std::string_view separators{" \t|"};
227
228 uint32_t res = 0;
229 StringConsumer consumer{str};
230 while (consumer.AnyBytesLeft()) {
231 /* skip "whitespace" */
232 consumer.SkipUntilCharNotIn(separators);
233
234 std::string_view value = consumer.ReadUntilCharIn(separators);
235 if (value.empty()) break;
236
237 auto r = OneOfManySettingDesc::ParseSingleValue(value, many);
238 if (!r.has_value()) return r;
239
240 SetBit(res, *r); // value found, set it
241 }
242 return res;
243}
244
250static std::optional<std::vector<uint32_t>> ParseIntList(std::string_view str)
251{
252 bool comma = false; // do we accept comma?
253 std::vector<uint32_t> result;
254
255 StringConsumer consumer{str};
256 for (;;) {
258 if (!consumer.AnyBytesLeft()) break;
259 if (comma && consumer.ReadIf(",")) {
260 /* commas are optional, but we only accept one between values */
261 comma = false;
262 continue;
263 }
264 auto v = consumer.TryReadIntegerBase<uint32_t>(10);
265 if (!v.has_value()) return std::nullopt;
266 result.push_back(*v);
267 comma = true;
268 }
269
270 /* If we have read comma but no number after it, fail.
271 * We have read comma when (n != 0) and comma is not allowed */
272 if (!result.empty() && !comma) return std::nullopt;
273
274 return result;
275}
276
285static bool LoadIntList(std::optional<std::string_view> str, void *array, int nelems, VarType type)
286{
287 size_t elem_size = SlVarSize(type);
288 std::byte *p = static_cast<std::byte *>(array);
289 if (!str.has_value()) {
290 std::fill_n(p, nelems * elem_size, static_cast<std::byte>(0));
291 return true;
292 }
293
294 auto opt_items = ParseIntList(*str);
295 if (!opt_items.has_value() || opt_items->size() != (size_t)nelems) return false;
296
297 for (auto item : *opt_items) {
298 WriteValue(p, type, item);
299 p += elem_size;
300 }
301 return true;
302}
303
310std::string ListSettingDesc::FormatValue(const void *object) const
311{
312 const uint8_t *p = static_cast<const uint8_t *>(GetVariableAddress(object, this->save));
313
314 std::string result;
315 for (size_t i = 0; i != this->save.length; i++) {
316 int64_t v;
317 switch (GetVarMemType(this->save.conv)) {
318 case SLE_VAR_BL:
319 case SLE_VAR_I8: v = *(const int8_t *)p; p += 1; break;
320 case SLE_VAR_U8: v = *(const uint8_t *)p; p += 1; break;
321 case SLE_VAR_I16: v = *(const int16_t *)p; p += 2; break;
322 case SLE_VAR_U16: v = *(const uint16_t *)p; p += 2; break;
323 case SLE_VAR_I32: v = *(const int32_t *)p; p += 4; break;
324 case SLE_VAR_U32: v = *(const uint32_t *)p; p += 4; break;
325 default: NOT_REACHED();
326 }
327 if (i != 0) result += ',';
328 format_append(result, "{}", v);
329 }
330 return result;
331}
332
333std::string OneOfManySettingDesc::FormatSingleValue(uint id) const
334{
335 if (id >= this->many.size()) {
336 return fmt::format("{}", id);
337 }
338 return std::string{this->many[id]};
339}
340
341std::string OneOfManySettingDesc::FormatValue(const void *object) const
342{
343 uint id = (uint)this->Read(object);
344 return this->FormatSingleValue(id);
345}
346
347std::string ManyOfManySettingDesc::FormatValue(const void *object) const
348{
349 uint bitmask = (uint)this->Read(object);
350 if (bitmask == 0) {
351 return {};
352 }
353
354 std::string result;
355 for (uint id : SetBitIterator(bitmask)) {
356 if (!result.empty()) result += '|';
357 result += this->FormatSingleValue(id);
358 }
359 return result;
360}
361
367int32_t IntSettingDesc::ParseValue(std::string_view str) const
368{
369 StringConsumer consumer{str};
370 /* The actual settings value might be int32 or uint32. Read as int64 and just cast away the high bits. */
371 auto value = consumer.TryReadIntegerBase<int64_t>(10);
372 if (!value.has_value()) {
373 _settings_error_list.emplace_back(
374 GetEncodedString(STR_CONFIG_ERROR),
375 GetEncodedString(STR_CONFIG_ERROR_INVALID_VALUE, str, this->GetName()));
376 return this->GetDefaultValue();
377 }
378 if (consumer.AnyBytesLeft()) {
379 _settings_error_list.emplace_back(
380 GetEncodedString(STR_CONFIG_ERROR),
381 GetEncodedString(STR_CONFIG_ERROR_TRAILING_CHARACTERS, this->GetName()));
382 }
383 return static_cast<int32_t>(*value);
384}
385
386int32_t OneOfManySettingDesc::ParseValue(std::string_view str) const
387{
389 /* if the first attempt of conversion from string to the appropriate value fails,
390 * look if we have defined a converter from old value to new value. */
391 if (!r.has_value() && this->many_cnvt != nullptr) r = this->many_cnvt(str);
392 if (r.has_value()) return *r; // and here goes converted value
393
394 _settings_error_list.emplace_back(
395 GetEncodedString(STR_CONFIG_ERROR),
396 GetEncodedString(STR_CONFIG_ERROR_INVALID_VALUE, str, this->GetName()));
397 return this->GetDefaultValue();
398}
399
400int32_t ManyOfManySettingDesc::ParseValue(std::string_view str) const
401{
402 auto r = LookupManyOfMany(this->many, str);
403 if (r.has_value()) return *r;
404
405 _settings_error_list.emplace_back(
406 GetEncodedString(STR_CONFIG_ERROR),
407 GetEncodedString(STR_CONFIG_ERROR_INVALID_VALUE, str, this->GetName()));
408 return this->GetDefaultValue();
409}
410
411int32_t BoolSettingDesc::ParseValue(std::string_view str) const
412{
414 if (r.has_value()) return *r;
415
416 _settings_error_list.emplace_back(
417 GetEncodedString(STR_CONFIG_ERROR),
418 GetEncodedString(STR_CONFIG_ERROR_INVALID_VALUE, str, this->GetName()));
419 return this->GetDefaultValue();
420}
421
428{
429 return this->get_title_cb != nullptr ? this->get_title_cb(*this) : this->str;
430}
431
437{
438 return this->get_help_cb != nullptr ? this->get_help_cb(*this) : this->str_help;
439}
440
446std::pair<StringParameter, StringParameter> IntSettingDesc::GetValueParams(int32_t value) const
447{
448 if (this->get_value_params_cb != nullptr) {
449 return this->get_value_params_cb(*this, value);
450 }
451
452 if (this->IsBoolSetting()) {
453 return {value != 0 ? STR_CONFIG_SETTING_ON : STR_CONFIG_SETTING_OFF, {}};
454 }
455
456 if (this->flags.Test(SettingFlag::GuiDropdown)) {
457 auto [min_val, _] = this->GetRange();
458 return {this->str_val - min_val + value, value};
459 }
460
461 return {this->str_val + ((value == 0 && this->flags.Test(SettingFlag::GuiZeroIsSpecial)) ? 1 : 0), value};
462}
463
469{
470 return this->get_def_cb != nullptr ? this->get_def_cb(*this) : this->def;
471}
472
477std::tuple<int32_t, uint32_t> IntSettingDesc::GetRange() const
478{
479 return this->get_range_cb != nullptr ? this->get_range_cb(*this) : std::tuple(this->min, this->max);
480}
481
488void IntSettingDesc::MakeValueValidAndWrite(const void *object, int32_t val) const
489{
490 this->MakeValueValid(val);
491 this->Write(object, val);
492}
493
503void IntSettingDesc::MakeValueValid(int32_t &val) const
504{
505 auto [min_val, max_val] = this->GetRange();
506 /* We need to take special care of the uint32_t type as we receive from the function
507 * a signed integer. While here also bail out on 64-bit settings as those are not
508 * supported. Unsigned 8 and 16-bit variables are safe since they fit into a signed
509 * 32-bit variable
510 * TODO: Support 64-bit settings/variables; requires 64 bit over command protocol! */
511 switch (GetVarMemType(this->save.conv)) {
512 case SLE_VAR_NULL: return;
513 case SLE_VAR_BL:
514 case SLE_VAR_I8:
515 case SLE_VAR_U8:
516 case SLE_VAR_I16:
517 case SLE_VAR_U16:
518 case SLE_VAR_I32: {
519 /* Override the minimum value. No value below this->min, except special value 0 */
520 if (!this->flags.Test(SettingFlag::GuiZeroIsSpecial) || val != 0) {
521 if (!this->flags.Test(SettingFlag::GuiDropdown)) {
522 /* Clamp value-type setting to its valid range */
523 val = Clamp(val, min_val, max_val);
524 } else if (val < min_val || val > static_cast<int32_t>(max_val)) {
525 /* Reset invalid discrete setting (where different values change gameplay) to its default value */
526 val = this->GetDefaultValue();
527 }
528 }
529 break;
530 }
531 case SLE_VAR_U32: {
532 /* Override the minimum value. No value below this->min, except special value 0 */
533 uint32_t uval = static_cast<uint32_t>(val);
534 if (!this->flags.Test(SettingFlag::GuiZeroIsSpecial) || uval != 0) {
535 if (!this->flags.Test(SettingFlag::GuiDropdown)) {
536 /* Clamp value-type setting to its valid range */
537 uval = ClampU(uval, min_val, max_val);
538 } else if (uval < static_cast<uint32_t>(min_val) || uval > max_val) {
539 /* Reset invalid discrete setting to its default value */
540 uval = static_cast<uint32_t>(this->GetDefaultValue());
541 }
542 }
543 val = static_cast<int32_t>(uval);
544 return;
545 }
546 case SLE_VAR_I64:
547 case SLE_VAR_U64:
548 default: NOT_REACHED();
549 }
550}
551
557void IntSettingDesc::Write(const void *object, int32_t val) const
558{
559 void *ptr = GetVariableAddress(object, this->save);
560 WriteValue(ptr, this->save.conv, (int64_t)val);
561}
562
568int32_t IntSettingDesc::Read(const void *object) const
569{
570 void *ptr = GetVariableAddress(object, this->save);
571 return (int32_t)ReadValue(ptr, this->save.conv);
572}
573
581void StringSettingDesc::MakeValueValid(std::string &str) const
582{
583 if (this->max_length == 0 || str.size() < this->max_length) return;
584
585 /* In case a maximum length is imposed by the setting, the length
586 * includes the '\0' termination for network transfer purposes.
587 * Also ensure the string is valid after chopping of some bytes. */
588 str.erase(this->max_length - 1, std::string::npos);
589 StrMakeValidInPlace(str, {});
590}
591
597void StringSettingDesc::Write(const void *object, std::string_view str) const
598{
599 reinterpret_cast<std::string *>(GetVariableAddress(object, this->save))->assign(str);
600}
601
607const std::string &StringSettingDesc::Read(const void *object) const
608{
609 return *reinterpret_cast<std::string *>(GetVariableAddress(object, this->save));
610}
611
621static void IniLoadSettings(IniFile &ini, const SettingTable &settings_table, std::string_view grpname, void *object, bool only_startup)
622{
623 const IniGroup *group;
624 const IniGroup *group_def = ini.GetGroup(grpname);
625
626 for (auto &desc : settings_table) {
627 const SettingDesc *sd = GetSettingDesc(desc);
629 if (sd->startup != only_startup) continue;
630
631 /* For settings.xx.yy load the settings from [xx] yy = ? */
632 std::string s{ sd->GetName() };
633 auto sc = s.find('.');
634 if (sc != std::string::npos) {
635 group = ini.GetGroup(s.substr(0, sc));
636 if (group == nullptr) group = group_def;
637 s = s.substr(sc + 1);
638 } else {
639 group = group_def;
640 }
641
642 const IniItem *item = nullptr;
643 if (group != nullptr) item = group->GetItem(s);
644 if (item == nullptr && group != group_def && group_def != nullptr) {
645 /* For settings.xx.yy load the settings from [settings] yy = ? in case the previous
646 * did not exist (e.g. loading old config files with a [settings] section */
647 item = group_def->GetItem(s);
648 }
649 if (item == nullptr) {
650 /* For settings.xx.zz.yy load the settings from [zz] yy = ? in case the previous
651 * did not exist (e.g. loading old config files with a [yapf] section */
652 sc = s.find('.');
653 if (sc != std::string::npos) {
654 if (group = ini.GetGroup(s.substr(0, sc)); group != nullptr) item = group->GetItem(s.substr(sc + 1));
655 }
656 }
657
658 sd->ParseValue(item, object);
659 }
660}
661
662void IntSettingDesc::ParseValue(const IniItem *item, void *object) const
663{
664 int32_t val = (item != nullptr && item->value.has_value()) ? this->ParseValue(*item->value) : this->GetDefaultValue();
665 this->MakeValueValidAndWrite(object, val);
666}
667
668void StringSettingDesc::ParseValue(const IniItem *item, void *object) const
669{
670 std::string str{(item == nullptr) ? this->def : item->value.value_or("")};
671 this->MakeValueValid(str);
672 this->Write(object, str);
673}
674
675void ListSettingDesc::ParseValue(const IniItem *item, void *object) const
676{
677 std::optional<std::string_view> str;
678 if (item != nullptr) {
679 str = item->value;
680 } else if (!this->def.empty()) {
681 str = this->def;
682 }
683 void *ptr = GetVariableAddress(object, this->save);
684 if (!LoadIntList(str, ptr, this->save.length, GetVarMemType(this->save.conv))) {
685 _settings_error_list.emplace_back(
686 GetEncodedString(STR_CONFIG_ERROR),
687 GetEncodedString(STR_CONFIG_ERROR_ARRAY, this->GetName()));
688
689 /* Use default */
690 LoadIntList(this->def, ptr, this->save.length, GetVarMemType(this->save.conv));
691 }
692}
693
706static void IniSaveSettings(IniFile &ini, const SettingTable &settings_table, std::string_view grpname, void *object, bool)
707{
708 IniGroup *group_def = nullptr, *group;
709
710 for (auto &desc : settings_table) {
711 const SettingDesc *sd = GetSettingDesc(desc);
712 /* If the setting is not saved to the configuration
713 * file, just continue with the next setting */
715 if (sd->flags.Test(SettingFlag::NotInConfig)) continue;
716
717 /* XXX - wtf is this?? (group override?) */
718 std::string s{ sd->GetName() };
719 auto sc = s.find('.');
720 if (sc != std::string::npos) {
721 group = &ini.GetOrCreateGroup(s.substr(0, sc));
722 s = s.substr(sc + 1);
723 } else {
724 if (group_def == nullptr) group_def = &ini.GetOrCreateGroup(grpname);
725 group = group_def;
726 }
727
728 IniItem &item = group->GetOrCreateItem(s);
729
730 if (!item.value.has_value() || !sd->IsSameValue(&item, object)) {
731 /* The value is different, that means we have to write it to the ini */
732 item.value.emplace(sd->FormatValue(object));
733 }
734 }
735}
736
737std::string IntSettingDesc::FormatValue(const void *object) const
738{
739 int64_t i;
740 if (IsSignedVarMemType(this->save.conv)) {
741 i = this->Read(object);
742 } else {
743 i = (uint32_t)this->Read(object);
744 }
745 return fmt::format("{}", i);
746}
747
748std::string BoolSettingDesc::FormatValue(const void *object) const
749{
750 bool val = this->Read(object) != 0;
751 return val ? "true" : "false";
752}
753
754bool IntSettingDesc::IsSameValue(const IniItem *item, void *object) const
755{
756 int32_t item_value = static_cast<int32_t>(this->ParseValue(*item->value));
757 int32_t object_value = this->Read(object);
758 return item_value == object_value;
759}
760
761bool IntSettingDesc::IsDefaultValue(void *object) const
762{
763 int32_t object_value = this->Read(object);
764 return this->GetDefaultValue() == object_value;
765}
766
767void IntSettingDesc::ResetToDefault(void *object) const
768{
769 this->Write(object, this->GetDefaultValue());
770}
771
772std::string StringSettingDesc::FormatValue(const void *object) const
773{
774 const std::string &str = this->Read(object);
775 switch (GetVarMemType(this->save.conv)) {
776 case SLE_VAR_STR: return str;
777
778 case SLE_VAR_STRQ:
779 if (str.empty()) {
780 return str;
781 }
782 return fmt::format("\"{}\"", str);
783
784 default: NOT_REACHED();
785 }
786}
787
788bool StringSettingDesc::IsSameValue(const IniItem *item, void *object) const
789{
790 /* The ini parsing removes the quotes, which are needed to retain the spaces in STRQs,
791 * so those values are always different in the parsed ini item than they should be. */
792 if (GetVarMemType(this->save.conv) == SLE_VAR_STRQ) return false;
793
794 const std::string &str = this->Read(object);
795 return item->value->compare(str) == 0;
796}
797
798bool StringSettingDesc::IsDefaultValue(void *object) const
799{
800 const std::string &str = this->Read(object);
801 return this->def == str;
802}
803
804void StringSettingDesc::ResetToDefault(void *object) const
805{
806 this->Write(object, this->def);
807}
808
809bool ListSettingDesc::IsSameValue(const IniItem *, void *) const
810{
811 /* Checking for equality is way more expensive than just writing the value. */
812 return false;
813}
814
816{
817 /* Defaults of lists are often complicated, and hard to compare. */
818 return false;
819}
820
822{
823 /* Resetting a list to default is not supported. */
824 NOT_REACHED();
825}
826
836static void IniLoadSettingList(IniFile &ini, std::string_view grpname, StringList &list)
837{
838 const IniGroup *group = ini.GetGroup(grpname);
839
840 if (group == nullptr) return;
841
842 list.clear();
843
844 for (const IniItem &item : group->items) {
845 if (!item.name.empty()) list.push_back(item.name);
846 }
847}
848
858static void IniSaveSettingList(IniFile &ini, std::string_view grpname, StringList &list)
859{
860 IniGroup &group = ini.GetOrCreateGroup(grpname);
861 group.Clear();
862
863 for (const auto &iter : list) {
864 group.GetOrCreateItem(iter).SetValue("");
865 }
866}
867
874void IniLoadWindowSettings(IniFile &ini, std::string_view grpname, WindowDesc *desc)
875{
876 IniLoadSettings(ini, _window_settings, grpname, desc, false);
877}
878
885void IniSaveWindowSettings(IniFile &ini, std::string_view grpname, WindowDesc *desc)
886{
887 IniSaveSettings(ini, _window_settings, grpname, desc, false);
888}
889
895bool SettingDesc::IsEditable(bool do_command) const
896{
897 if (!do_command && !this->flags.Test(SettingFlag::NoNetworkSync) && _networking && !_network_server && !this->flags.Test(SettingFlag::PerCompany)) return false;
898 if (do_command && this->flags.Test(SettingFlag::NoNetworkSync)) return false;
899 if (this->flags.Test(SettingFlag::NetworkOnly) && !_networking && _game_mode != GM_MENU) return false;
900 if (this->flags.Test(SettingFlag::NoNetwork) && _networking) return false;
901 if (this->flags.Test(SettingFlag::NewgameOnly) &&
902 (_game_mode == GM_NORMAL ||
903 (_game_mode == GM_EDITOR && !this->flags.Test(SettingFlag::SceneditToo)))) return false;
904 if (this->flags.Test(SettingFlag::SceneditOnly) && _game_mode != GM_EDITOR) return false;
905 return true;
906}
907
913{
914 if (this->flags.Test(SettingFlag::PerCompany)) return ST_COMPANY;
915 return this->flags.Test(SettingFlag::NotInSave) ? ST_CLIENT : ST_GAME;
916}
917
923{
924 assert(this->IsIntSetting());
925 return static_cast<const IntSettingDesc *>(this);
926}
927
933{
934 assert(this->IsStringSetting());
935 return static_cast<const StringSettingDesc *>(this);
936}
937
939void HandleOldDiffCustom(bool savegame);
940
941
943static void ValidateSettings()
944{
945 /* Do not allow a custom sea level with the original land generator. */
946 if (_settings_newgame.game_creation.land_generator == LG_ORIGINAL &&
947 _settings_newgame.difficulty.quantity_sea_lakes == CUSTOM_SEA_LEVEL_NUMBER_DIFFICULTY) {
948 _settings_newgame.difficulty.quantity_sea_lakes = CUSTOM_SEA_LEVEL_MIN_PERCENTAGE;
949 }
950}
951
952static void AILoadConfig(const IniFile &ini, std::string_view grpname)
953{
954 const IniGroup *group = ini.GetGroup(grpname);
955
956 /* Clean any configured AI */
957 for (CompanyID c = CompanyID::Begin(); c < MAX_COMPANIES; ++c) {
959 }
960
961 /* If no group exists, return */
962 if (group == nullptr) return;
963
964 CompanyID c = CompanyID::Begin();
965 for (const IniItem &item : group->items) {
967
968 config->Change(item.name);
969 if (!config->HasScript()) {
970 if (item.name != "none") {
971 Debug(script, 0, "The AI by the name '{}' was no longer found, and removed from the list.", item.name);
972 continue;
973 }
974 }
975 if (item.value.has_value()) config->StringToSettings(*item.value);
976 ++c;
977 if (c >= MAX_COMPANIES) break;
978 }
979}
980
981static void GameLoadConfig(const IniFile &ini, std::string_view grpname)
982{
983 const IniGroup *group = ini.GetGroup(grpname);
984
985 /* Clean any configured GameScript */
987
988 /* If no group exists, return */
989 if (group == nullptr || group->items.empty()) return;
990
991 const IniItem &item = group->items.front();
992
994
995 config->Change(item.name);
996 if (!config->HasScript()) {
997 if (item.name != "none") {
998 Debug(script, 0, "The GameScript by the name '{}' was no longer found, and removed from the list.", item.name);
999 return;
1000 }
1001 }
1002 if (item.value.has_value()) config->StringToSettings(*item.value);
1003}
1004
1010{
1011 if (const IniGroup *group = ini.GetGroup("misc"); group != nullptr) {
1012 /* Load old setting first. */
1013 if (const IniItem *item = group->GetItem("graphicsset"); item != nullptr && item->value) BaseGraphics::ini_data.name = *item->value;
1014 }
1015
1016 if (const IniGroup *group = ini.GetGroup("graphicsset"); group != nullptr) {
1017 /* Load new settings. */
1018 if (const IniItem *item = group->GetItem("name"); item != nullptr && item->value) BaseGraphics::ini_data.name = *item->value;
1019
1020 if (const IniItem *item = group->GetItem("shortname"); item != nullptr && item->value && item->value->size() == 8) {
1021 auto val = ParseInteger<uint32_t>(*item->value, 16);
1022 if (val.has_value()) {
1023 BaseGraphics::ini_data.shortname = std::byteswap<uint32_t>(*val);
1024 } else {
1025 ShowErrorMessage(GetEncodedString(STR_CONFIG_ERROR),
1026 GetEncodedString(STR_CONFIG_ERROR_INVALID_VALUE, *item->value, BaseGraphics::ini_data.name),
1027 WL_CRITICAL);
1028 }
1029 }
1030
1031 if (const IniItem *item = group->GetItem("extra_version"); item != nullptr && item->value) {
1032 auto val = ParseInteger<uint32_t>(*item->value);
1033 if (val.has_value()) {
1034 BaseGraphics::ini_data.extra_version = *val;
1035 } else {
1036 ShowErrorMessage(GetEncodedString(STR_CONFIG_ERROR),
1037 GetEncodedString(STR_CONFIG_ERROR_INVALID_VALUE, *item->value, BaseGraphics::ini_data.name),
1038 WL_CRITICAL);
1039 }
1040 }
1041
1042 if (const IniItem *item = group->GetItem("extra_params"); item != nullptr && item->value) {
1043 auto params = ParseIntList(*item->value);
1044 if (params.has_value()) {
1045 BaseGraphics::ini_data.extra_params = params.value();
1046 } else {
1047 ShowErrorMessage(GetEncodedString(STR_CONFIG_ERROR),
1048 GetEncodedString(STR_CONFIG_ERROR_ARRAY, BaseGraphics::ini_data.name),
1049 WL_CRITICAL);
1050 }
1051 }
1052 }
1053}
1054
1062static GRFConfigList GRFLoadConfig(const IniFile &ini, std::string_view grpname, bool is_static)
1063{
1064 const IniGroup *group = ini.GetGroup(grpname);
1065 GRFConfigList list;
1066
1067 if (group == nullptr) return list;
1068
1069 uint num_grfs = 0;
1070 for (const IniItem &item : group->items) {
1071 std::unique_ptr<GRFConfig> c{};
1072
1073 std::array<uint8_t, 4> grfid_buf;
1074 MD5Hash md5sum;
1075 std::string_view item_name = item.name;
1076 bool has_md5sum = false;
1077
1078 /* Try reading "<grfid>|" and on success, "<md5sum>|". */
1079 auto grfid_pos = item_name.find("|");
1080 if (grfid_pos != std::string_view::npos) {
1081 std::string_view grfid_str = item_name.substr(0, grfid_pos);
1082
1083 if (ConvertHexToBytes(grfid_str, grfid_buf)) {
1084 item_name = item_name.substr(grfid_pos + 1);
1085
1086 auto md5sum_pos = item_name.find("|");
1087 if (md5sum_pos != std::string_view::npos) {
1088 std::string_view md5sum_str = item_name.substr(0, md5sum_pos);
1089
1090 has_md5sum = ConvertHexToBytes(md5sum_str, md5sum);
1091 if (has_md5sum) item_name = item_name.substr(md5sum_pos + 1);
1092 }
1093
1094 uint32_t grfid = grfid_buf[0] | (grfid_buf[1] << 8) | (grfid_buf[2] << 16) | (grfid_buf[3] << 24);
1095 if (has_md5sum) {
1096 const GRFConfig *s = FindGRFConfig(grfid, FGCM_EXACT, &md5sum);
1097 if (s != nullptr) c = std::make_unique<GRFConfig>(*s);
1098 }
1099 if (c == nullptr && !FioCheckFileExists(std::string(item_name), NEWGRF_DIR)) {
1100 const GRFConfig *s = FindGRFConfig(grfid, FGCM_NEWEST_VALID);
1101 if (s != nullptr) c = std::make_unique<GRFConfig>(*s);
1102 }
1103 }
1104 }
1105 std::string filename = std::string(item_name);
1106
1107 if (c == nullptr) c = std::make_unique<GRFConfig>(filename);
1108
1109 /* Parse parameters */
1110 if (item.value.has_value() && !item.value->empty()) {
1111 auto params = ParseIntList(*item.value);
1112 if (params.has_value()) {
1113 c->SetParams(params.value());
1114 } else {
1115 ShowErrorMessage(GetEncodedString(STR_CONFIG_ERROR),
1116 GetEncodedString(STR_CONFIG_ERROR_ARRAY, filename),
1117 WL_CRITICAL);
1118 }
1119 }
1120
1121 /* Check if item is valid */
1122 if (!FillGRFDetails(*c, is_static) || c->flags.Test(GRFConfigFlag::Invalid)) {
1123 StringID reason;
1124 if (c->status == GCS_NOT_FOUND) {
1125 reason = STR_CONFIG_ERROR_INVALID_GRF_NOT_FOUND;
1126 } else if (c->flags.Test(GRFConfigFlag::Unsafe)) {
1127 reason = STR_CONFIG_ERROR_INVALID_GRF_UNSAFE;
1128 } else if (c->flags.Test(GRFConfigFlag::System)) {
1129 reason = STR_CONFIG_ERROR_INVALID_GRF_SYSTEM;
1130 } else if (c->flags.Test(GRFConfigFlag::Invalid)) {
1131 reason = STR_CONFIG_ERROR_INVALID_GRF_INCOMPATIBLE;
1132 } else {
1133 reason = STR_CONFIG_ERROR_INVALID_GRF_UNKNOWN;
1134 }
1135
1136 ShowErrorMessage(GetEncodedString(STR_CONFIG_ERROR),
1137 GetEncodedString(STR_CONFIG_ERROR_INVALID_GRF, filename.empty() ? item.name : filename, reason),
1138 WL_CRITICAL);
1139 continue;
1140 }
1141
1142 /* Check for duplicate GRFID (will also check for duplicate filenames) */
1143 auto found = std::ranges::find_if(list, [&c](const auto &gc) { return gc->ident.grfid == c->ident.grfid; });
1144 if (found != std::end(list)) {
1145 ShowErrorMessage(GetEncodedString(STR_CONFIG_ERROR),
1146 GetEncodedString(STR_CONFIG_ERROR_DUPLICATE_GRFID, c->filename, (*found)->filename),
1147 WL_CRITICAL);
1148 continue;
1149 }
1150
1151 if (is_static) {
1152 /* Mark file as static to avoid saving in savegame. */
1153 c->flags.Set(GRFConfigFlag::Static);
1154 } else if (++num_grfs > NETWORK_MAX_GRF_COUNT) {
1155 /* Check we will not load more non-static NewGRFs than allowed. This could trigger issues for game servers. */
1156 ShowErrorMessage(GetEncodedString(STR_CONFIG_ERROR),
1157 GetEncodedString(STR_NEWGRF_ERROR_TOO_MANY_NEWGRFS_LOADED), WL_CRITICAL);
1158 break;
1159 }
1160
1161 /* Add item to list */
1162 list.push_back(std::move(c));
1163 }
1164
1165 return list;
1166}
1167
1168static IniFileVersion LoadVersionFromConfig(const IniFile &ini)
1169{
1170 const IniGroup *group = ini.GetGroup("version");
1171 if (group == nullptr) return IFV_0;
1172
1173 auto version_number = group->GetItem("ini_version");
1174 /* Older ini-file versions don't have this key yet. */
1175 if (version_number == nullptr || !version_number->value.has_value()) return IFV_0;
1176
1177 uint32_t version = 0;
1178 std::from_chars(version_number->value->data(), version_number->value->data() + version_number->value->size(), version);
1179
1180 return static_cast<IniFileVersion>(version);
1181}
1182
1183static void AISaveConfig(IniFile &ini, std::string_view grpname)
1184{
1185 IniGroup &group = ini.GetOrCreateGroup(grpname);
1186 group.Clear();
1187
1188 for (CompanyID c = CompanyID::Begin(); c < MAX_COMPANIES; ++c) {
1190 std::string name;
1191 std::string value = config->SettingsToString();
1192
1193 if (config->HasScript()) {
1194 name = config->GetName();
1195 } else {
1196 name = "none";
1197 }
1198
1199 group.CreateItem(name).SetValue(value);
1200 }
1201}
1202
1203static void GameSaveConfig(IniFile &ini, std::string_view grpname)
1204{
1205 IniGroup &group = ini.GetOrCreateGroup(grpname);
1206 group.Clear();
1207
1209 std::string name;
1210 std::string value = config->SettingsToString();
1211
1212 if (config->HasScript()) {
1213 name = config->GetName();
1214 } else {
1215 name = "none";
1216 }
1217
1218 group.CreateItem(name).SetValue(value);
1219}
1220
1226{
1227 IniGroup &group = ini.GetOrCreateGroup("version");
1228 group.GetOrCreateItem("version_string").SetValue(_openttd_revision);
1229 group.GetOrCreateItem("version_number").SetValue(fmt::format("{:08X}", _openttd_newgrf_version));
1230 group.GetOrCreateItem("ini_version").SetValue(fmt::format("{}", INIFILE_VERSION));
1231}
1232
1238{
1239 const GraphicsSet *used_set = BaseGraphics::GetUsedSet();
1240 if (used_set == nullptr) return;
1241
1242 IniGroup &group = ini.GetOrCreateGroup("graphicsset");
1243 group.Clear();
1244
1245 group.GetOrCreateItem("name").SetValue(used_set->name);
1246 group.GetOrCreateItem("shortname").SetValue(fmt::format("{:08X}", std::byteswap(used_set->shortname)));
1247
1248 const GRFConfig *extra_cfg = used_set->GetExtraConfig();
1249 if (extra_cfg != nullptr && !extra_cfg->param.empty()) {
1250 group.GetOrCreateItem("extra_version").SetValue(fmt::format("{}", extra_cfg->version));
1251 group.GetOrCreateItem("extra_params").SetValue(GRFBuildParamList(*extra_cfg));
1252 }
1253}
1254
1255/* Save a GRF configuration to the given group name */
1256static void GRFSaveConfig(IniFile &ini, std::string_view grpname, const GRFConfigList &list)
1257{
1258 IniGroup &group = ini.GetOrCreateGroup(grpname);
1259 group.Clear();
1260
1261 for (const auto &c : list) {
1262 std::string key = fmt::format("{:08X}|{}|{}", std::byteswap(c->ident.grfid),
1263 FormatArrayAsHex(c->ident.md5sum), c->filename);
1265 }
1266}
1267
1268/* Common handler for saving/loading variables to the configuration file */
1269static void HandleSettingDescs(IniFile &generic_ini, IniFile &private_ini, IniFile &secrets_ini, SettingDescProc *proc, SettingDescProcList *proc_list, bool only_startup = false)
1270{
1271 proc(generic_ini, _misc_settings, "misc", nullptr, only_startup);
1272#if defined(_WIN32) && !defined(DEDICATED)
1273 proc(generic_ini, _win32_settings, "win32", nullptr, only_startup);
1274#endif /* _WIN32 */
1275
1276 /* The name "patches" is a fallback, as every setting should sets its own group. */
1277
1278 for (auto &table : GenericSettingTables()) {
1279 proc(generic_ini, table, "patches", &_settings_newgame, only_startup);
1280 }
1281 for (auto &table : PrivateSettingTables()) {
1282 proc(private_ini, table, "patches", &_settings_newgame, only_startup);
1283 }
1284 for (auto &table : SecretSettingTables()) {
1285 proc(secrets_ini, table, "patches", &_settings_newgame, only_startup);
1286 }
1287
1288 proc(generic_ini, _currency_settings, "currency", &GetCustomCurrency(), only_startup);
1289 proc(generic_ini, _company_settings, "company", &_settings_client.company, only_startup);
1290
1291 if (!only_startup) {
1292 proc_list(private_ini, "server_bind_addresses", _network_bind_list);
1293 proc_list(private_ini, "servers", _network_host_list);
1294 proc_list(private_ini, "bans", _network_ban_list);
1295 proc_list(private_ini, "server_authorized_keys", _settings_client.network.server_authorized_keys);
1296 proc_list(private_ini, "rcon_authorized_keys", _settings_client.network.rcon_authorized_keys);
1297 proc_list(private_ini, "admin_authorized_keys", _settings_client.network.admin_authorized_keys);
1298 }
1299}
1300
1310static void RemoveEntriesFromIni(IniFile &ini, const SettingTable &table)
1311{
1312 for (auto &desc : table) {
1313 const SettingDesc *sd = GetSettingDesc(desc);
1314
1315 /* For settings.xx.yy load the settings from [xx] yy = ? */
1316 std::string s{ sd->GetName() };
1317 auto sc = s.find('.');
1318 if (sc == std::string::npos) continue;
1319
1320 IniGroup *group = ini.GetGroup(s.substr(0, sc));
1321 if (group == nullptr) continue;
1322 s = s.substr(sc + 1);
1323
1324 group->RemoveItem(s);
1325 }
1326}
1327
1351bool IsConversionNeeded(const ConfigIniFile &ini, const std::string &group, const std::string &old_var, const std::string &new_var, const IniItem **old_item)
1352{
1353 *old_item = nullptr;
1354
1355 const IniGroup *igroup = ini.GetGroup(group);
1356 /* If the group doesn't exist, there is nothing to convert. */
1357 if (igroup == nullptr) return false;
1358
1359 const IniItem *tmp_old_item = igroup->GetItem(old_var);
1360 const IniItem *new_item = igroup->GetItem(new_var);
1361
1362 /* If the old item doesn't exist, there is nothing to convert. */
1363 if (tmp_old_item == nullptr) return false;
1364
1365 /* If the new item exists, it means conversion was already done. We only
1366 * do the conversion the first time, and after that these settings are
1367 * independent. This allows users to freely change between older and
1368 * newer clients without breaking anything. */
1369 if (new_item != nullptr) return false;
1370
1371 *old_item = tmp_old_item;
1372 return true;
1373}
1374
1379void LoadFromConfig(bool startup)
1380{
1381 ConfigIniFile generic_ini(_config_file);
1382 ConfigIniFile private_ini(_private_file);
1383 ConfigIniFile secrets_ini(_secrets_file);
1384 ConfigIniFile favs_ini(_favs_file);
1385
1386 if (!startup) ResetCurrencies(false); // Initialize the array of currencies, without preserving the custom one
1387
1388 IniFileVersion generic_version = LoadVersionFromConfig(generic_ini);
1389
1390 if (startup) {
1391 GraphicsSetLoadConfig(generic_ini);
1392 }
1393
1394 /* Before the split of private/secrets, we have to look in the generic for these settings. */
1395 if (generic_version < IFV_PRIVATE_SECRETS) {
1396 HandleSettingDescs(generic_ini, generic_ini, generic_ini, IniLoadSettings, IniLoadSettingList, startup);
1397 } else {
1398 HandleSettingDescs(generic_ini, private_ini, secrets_ini, IniLoadSettings, IniLoadSettingList, startup);
1399 }
1400
1401 /* Load basic settings only during bootstrap, load other settings not during bootstrap */
1402 if (!startup) {
1403 if (generic_version < IFV_LINKGRAPH_SECONDS) {
1404 _settings_newgame.linkgraph.recalc_interval *= CalendarTime::SECONDS_PER_DAY;
1405 _settings_newgame.linkgraph.recalc_time *= CalendarTime::SECONDS_PER_DAY;
1406 }
1407
1408 /* Move use_relay_service from generic_ini to private_ini. */
1409 if (generic_version < IFV_NETWORK_PRIVATE_SETTINGS) {
1410 const IniGroup *network = generic_ini.GetGroup("network");
1411 if (network != nullptr) {
1412 const IniItem *use_relay_service = network->GetItem("use_relay_service");
1413 if (use_relay_service != nullptr) {
1414 if (use_relay_service->value == "never") {
1415 _settings_client.network.use_relay_service = UseRelayService::Never;
1416 } else if (use_relay_service->value == "ask") {
1417 _settings_client.network.use_relay_service = UseRelayService::Ask;
1418 } else if (use_relay_service->value == "allow") {
1419 _settings_client.network.use_relay_service = UseRelayService::Allow;
1420 }
1421 }
1422 }
1423 }
1424
1425 const IniItem *old_item;
1426
1427 if (generic_version < IFV_GAME_TYPE && IsConversionNeeded(generic_ini, "network", "server_advertise", "server_game_type", &old_item)) {
1428 auto old_value = BoolSettingDesc::ParseSingleValue(*old_item->value);
1429 _settings_client.network.server_game_type = old_value.value_or(false) ? ServerGameType::Public : ServerGameType::Local;
1430 }
1431
1432 if (generic_version < IFV_AUTOSAVE_RENAME && IsConversionNeeded(generic_ini, "gui", "autosave", "autosave_interval", &old_item)) {
1433 static constexpr std::initializer_list<std::string_view> _old_autosave_interval{"off"sv, "monthly"sv, "quarterly"sv, "half year"sv, "yearly"sv};
1434 auto old_value = OneOfManySettingDesc::ParseSingleValue(*old_item->value, _old_autosave_interval).value_or(-1);
1435
1436 switch (old_value) {
1437 case 0: _settings_client.gui.autosave_interval = 0; break;
1438 case 1: _settings_client.gui.autosave_interval = 10; break;
1439 case 2: _settings_client.gui.autosave_interval = 30; break;
1440 case 3: _settings_client.gui.autosave_interval = 60; break;
1441 case 4: _settings_client.gui.autosave_interval = 120; break;
1442 default: break;
1443 }
1444 }
1445
1446 /* Persist the right click close option from older versions. */
1447 if (generic_version < IFV_RIGHT_CLICK_CLOSE && IsConversionNeeded(generic_ini, "gui", "right_mouse_wnd_close", "right_click_wnd_close", &old_item)) {
1448 auto old_value = BoolSettingDesc::ParseSingleValue(*old_item->value);
1449 _settings_client.gui.right_click_wnd_close = old_value.value_or(false) ? RightClickClose::Yes : RightClickClose::No;
1450 }
1451
1452 _grfconfig_newgame = GRFLoadConfig(generic_ini, "newgrf", false);
1453 _grfconfig_static = GRFLoadConfig(generic_ini, "newgrf-static", true);
1454 AILoadConfig(generic_ini, "ai_players");
1455 GameLoadConfig(generic_ini, "game_scripts");
1456 PickerLoadConfig(favs_ini);
1457 BadgeClassLoadConfig(favs_ini);
1458
1460 IniLoadSettings(generic_ini, _old_gameopt_settings, "gameopt", &_settings_newgame, false);
1461 HandleOldDiffCustom(false);
1462
1465
1466 /* Display scheduled errors */
1468 if (FindWindowById(WC_ERRMSG, 0) == nullptr) ShowFirstError();
1469 }
1470}
1471
1474{
1475 ConfigIniFile generic_ini(_config_file);
1476 ConfigIniFile private_ini(_private_file);
1477 ConfigIniFile secrets_ini(_secrets_file);
1478 ConfigIniFile favs_ini(_favs_file);
1479
1480 IniFileVersion generic_version = LoadVersionFromConfig(generic_ini);
1481
1482 /* If we newly create the private/secrets file, add a dummy group on top
1483 * just so we can add a comment before it (that is how IniFile works).
1484 * This to explain what the file is about. After doing it once, never touch
1485 * it again, as otherwise we might be reverting user changes. */
1486 if (IniGroup *group = private_ini.GetGroup("private"); group != nullptr) group->comment = "; This file possibly contains private information which can identify you as person.\n";
1487 if (IniGroup *group = secrets_ini.GetGroup("secrets"); group != nullptr) group->comment = "; Do not share this file with others, not even if they claim to be technical support.\n; This file contains saved passwords and other secrets that should remain private to you!\n";
1488
1489 if (generic_version == IFV_0) {
1490 /* Remove some obsolete groups. These have all been loaded into other groups. */
1491 generic_ini.RemoveGroup("patches");
1492 generic_ini.RemoveGroup("yapf");
1493 generic_ini.RemoveGroup("gameopt");
1494
1495 /* Remove all settings from the generic ini that are now in the private ini. */
1496 generic_ini.RemoveGroup("server_bind_addresses");
1497 generic_ini.RemoveGroup("servers");
1498 generic_ini.RemoveGroup("bans");
1499 for (auto &table : PrivateSettingTables()) {
1500 RemoveEntriesFromIni(generic_ini, table);
1501 }
1502
1503 /* Remove all settings from the generic ini that are now in the secrets ini. */
1504 for (auto &table : SecretSettingTables()) {
1505 RemoveEntriesFromIni(generic_ini, table);
1506 }
1507 }
1508
1509 if (generic_version < IFV_REMOVE_GENERATION_SEED) {
1510 IniGroup *game_creation = generic_ini.GetGroup("game_creation");
1511 if (game_creation != nullptr) {
1512 game_creation->RemoveItem("generation_seed");
1513 }
1514 }
1515
1516 /* These variables are migrated from generic ini to private ini now. */
1517 if (generic_version < IFV_NETWORK_PRIVATE_SETTINGS) {
1518 IniGroup *network = generic_ini.GetGroup("network");
1519 if (network != nullptr) {
1520 network->RemoveItem("use_relay_service");
1521 }
1522 }
1523
1524 HandleSettingDescs(generic_ini, private_ini, secrets_ini, IniSaveSettings, IniSaveSettingList);
1525 GraphicsSetSaveConfig(generic_ini);
1526 GRFSaveConfig(generic_ini, "newgrf", _grfconfig_newgame);
1527 GRFSaveConfig(generic_ini, "newgrf-static", _grfconfig_static);
1528 AISaveConfig(generic_ini, "ai_players");
1529 GameSaveConfig(generic_ini, "game_scripts");
1530 PickerSaveConfig(favs_ini);
1531 BadgeClassSaveConfig(favs_ini);
1532
1533 SaveVersionInConfig(generic_ini);
1534 SaveVersionInConfig(private_ini);
1535 SaveVersionInConfig(secrets_ini);
1536 SaveVersionInConfig(favs_ini);
1537
1538 generic_ini.SaveToDisk(_config_file);
1539 private_ini.SaveToDisk(_private_file);
1540 secrets_ini.SaveToDisk(_secrets_file);
1541 favs_ini.SaveToDisk(_favs_file);
1542}
1543
1549{
1550 StringList list;
1551
1553 for (const IniGroup &group : ini.groups) {
1554 if (group.name.starts_with("preset-")) {
1555 list.push_back(group.name.substr(7));
1556 }
1557 }
1558
1559 return list;
1560}
1561
1568GRFConfigList LoadGRFPresetFromConfig(std::string_view config_name)
1569{
1570 std::string section("preset-");
1571 section += config_name;
1572
1574 GRFConfigList config = GRFLoadConfig(ini, section, false);
1575
1576 return config;
1577}
1578
1585void SaveGRFPresetToConfig(std::string_view config_name, GRFConfigList &config)
1586{
1587 std::string section("preset-");
1588 section += config_name;
1589
1591 GRFSaveConfig(ini, section, config);
1593}
1594
1599void DeleteGRFPresetFromConfig(std::string_view config_name)
1600{
1601 std::string section("preset-");
1602 section += config_name;
1603
1605 ini.RemoveGroup(section);
1607}
1608
1615void IntSettingDesc::ChangeValue(const void *object, int32_t newval) const
1616{
1617 int32_t oldval = this->Read(object);
1618 this->MakeValueValid(newval);
1619 if (this->pre_check != nullptr && !this->pre_check(newval)) return;
1620 if (oldval == newval) return;
1621
1622 this->Write(object, newval);
1623 if (this->post_callback != nullptr) this->post_callback(newval);
1624
1625 if (this->flags.Test(SettingFlag::NoNetwork) || this->flags.Test(SettingFlag::Sandbox)) {
1626 _gamelog.StartAction(GLAT_SETTING);
1627 _gamelog.Setting(this->GetName(), oldval, newval);
1628 _gamelog.StopAction();
1629 }
1630
1633
1634 if (_save_config) SaveToConfig();
1635}
1636
1644static const SettingDesc *GetSettingFromName(std::string_view name, const SettingTable &settings)
1645{
1646 /* First check all full names */
1647 for (auto &desc : settings) {
1648 const SettingDesc *sd = GetSettingDesc(desc);
1649 if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue;
1650 if (sd->GetName() == name) return sd;
1651 }
1652
1653 /* Then check the shortcut variant of the name. */
1654 std::string short_name_suffix = std::string{ "." }.append(name);
1655 for (auto &desc : settings) {
1656 const SettingDesc *sd = GetSettingDesc(desc);
1657 if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue;
1658 if (sd->GetName().ends_with(short_name_suffix)) return sd;
1659 }
1660
1661 return nullptr;
1662}
1663
1669void GetSaveLoadFromSettingTable(SettingTable settings, std::vector<SaveLoad> &saveloads)
1670{
1671 for (auto &desc : settings) {
1672 const SettingDesc *sd = GetSettingDesc(desc);
1673 if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue;
1674 saveloads.push_back(sd->save);
1675 }
1676}
1677
1684{
1685 static const SettingTable saveload_settings_tables[] = {
1686 _difficulty_settings,
1687 _economy_settings,
1688 _game_settings,
1689 _linkgraph_settings,
1690 _locale_settings,
1691 _pathfinding_settings,
1692 _script_settings,
1693 _world_settings,
1694 };
1695 static std::vector<SettingVariant> settings_table;
1696
1697 if (settings_table.empty()) {
1698 for (auto &saveload_settings_table : saveload_settings_tables) {
1699 for (auto &saveload_setting : saveload_settings_table) {
1700 settings_table.push_back(saveload_setting);
1701 }
1702 }
1703 }
1704
1705 return settings_table;
1706}
1707
1714static const SettingDesc *GetCompanySettingFromName(std::string_view name)
1715{
1716 static const std::string_view company_prefix = "company.";
1717 if (name.starts_with(company_prefix)) name.remove_prefix(company_prefix.size());
1718 return GetSettingFromName(name, _company_settings);
1719}
1720
1727const SettingDesc *GetSettingFromName(std::string_view name)
1728{
1729 for (auto &table : GenericSettingTables()) {
1730 auto sd = GetSettingFromName(name, table);
1731 if (sd != nullptr) return sd;
1732 }
1733 for (auto &table : PrivateSettingTables()) {
1734 auto sd = GetSettingFromName(name, table);
1735 if (sd != nullptr) return sd;
1736 }
1737 for (auto &table : SecretSettingTables()) {
1738 auto sd = GetSettingFromName(name, table);
1739 if (sd != nullptr) return sd;
1740 }
1741
1742 return GetCompanySettingFromName(name);
1743}
1744
1750std::vector<const SettingDesc *> GetFilteredSettingCollection(std::function<bool(const SettingDesc &desc)> func)
1751{
1752 std::vector<const SettingDesc *> collection;
1753
1754 for (const auto &table : GenericSettingTables()) {
1755 for (const auto &desc : table) {
1756 const auto sd = GetSettingDesc(desc);
1757 if (!func(*sd)) continue;
1758
1759 collection.push_back(sd);
1760 }
1761 }
1762
1763 return collection;
1764}
1765
1775CommandCost CmdChangeSetting(DoCommandFlags flags, const std::string &name, int32_t value)
1776{
1777 if (name.empty()) return CMD_ERROR;
1778 const SettingDesc *sd = GetSettingFromName(name);
1779
1780 if (sd == nullptr) return CMD_ERROR;
1782 if (!sd->IsIntSetting()) return CMD_ERROR;
1783
1784 if (!sd->IsEditable(true)) return CMD_ERROR;
1785
1786 if (flags.Test(DoCommandFlag::Execute)) {
1787 sd->AsIntSetting()->ChangeValue(&GetGameSettings(), value);
1788 }
1789
1790 return CommandCost();
1791}
1792
1801CommandCost CmdChangeCompanySetting(DoCommandFlags flags, const std::string &name, int32_t value)
1802{
1803 if (name.empty()) return CMD_ERROR;
1804 const SettingDesc *sd = GetCompanySettingFromName(name);
1805
1806 if (sd == nullptr) return CMD_ERROR;
1807 if (!sd->IsIntSetting()) return CMD_ERROR;
1808
1809 if (flags.Test(DoCommandFlag::Execute)) {
1811 }
1812
1813 return CommandCost();
1814}
1815
1823bool SetSettingValue(const IntSettingDesc *sd, int32_t value, bool force_newgame)
1824{
1825 const IntSettingDesc *setting = sd->AsIntSetting();
1826 if (setting->flags.Test(SettingFlag::PerCompany)) {
1827 if (Company::IsValidID(_local_company) && _game_mode != GM_MENU) {
1828 return Command<Commands::ChangeCompanySetting>::Post(setting->GetName(), value);
1829 }
1830
1831 setting->ChangeValue(&_settings_client.company, value);
1832 return true;
1833 }
1834
1835 /* If an item is company-based, we do not send it over the network
1836 * (if any) to change. Also *hack*hack* we update the _newgame version
1837 * of settings because changing a company-based setting in a game also
1838 * changes its defaults. At least that is the convention we have chosen */
1839 if (setting->flags.Test(SettingFlag::NoNetworkSync)) {
1840 if (_game_mode != GM_MENU) {
1841 setting->ChangeValue(&_settings_newgame, value);
1842 }
1843 setting->ChangeValue(&GetGameSettings(), value);
1844 return true;
1845 }
1846
1847 if (force_newgame) {
1848 setting->ChangeValue(&_settings_newgame, value);
1849 return true;
1850 }
1851
1852 /* send non-company-based settings over the network */
1854 return Command<Commands::ChangeSetting>::Post(setting->GetName(), value);
1855 }
1856 return false;
1857}
1858
1863void SetDefaultCompanySettings(CompanyID cid)
1864{
1865 Company *c = Company::Get(cid);
1867 for (auto &desc : _company_settings) {
1868 const IntSettingDesc *int_setting = GetSettingDesc(desc)->AsIntSetting();
1869 int_setting->MakeValueValidAndWrite(&c->settings, int_setting->GetDefaultValue());
1870 }
1871}
1872
1877{
1878 const void *old_object = &Company::Get(_current_company)->settings;
1879 const void *new_object = &_settings_client.company;
1880 for (auto &desc : _company_settings) {
1881 const SettingDesc *sd = GetSettingDesc(desc);
1882 uint32_t old_value = (uint32_t)sd->AsIntSetting()->Read(old_object);
1883 uint32_t new_value = (uint32_t)sd->AsIntSetting()->Read(new_object);
1884 /*
1885 * This is called from a command, and since it contains local configuration information
1886 * that the rest of the clients do not know about, we need to circumvent the normal ::Post
1887 * local command validation and immediately send the command to the server.
1888 */
1889 if (old_value != new_value) Command<Commands::ChangeCompanySetting>::SendNet(STR_NULL, _local_company, sd->GetName(), new_value);
1890 }
1891}
1892
1901bool SetSettingValue(const StringSettingDesc *sd, std::string_view value, bool force_newgame)
1902{
1904
1905 if (GetVarMemType(sd->save.conv) == SLE_VAR_STRQ && value == "(null)") {
1906 value = {};
1907 }
1908
1909 const void *object = (_game_mode == GM_MENU || force_newgame) ? &_settings_newgame : &_settings_game;
1910 sd->AsStringSetting()->ChangeValue(object, std::string{value});
1911 return true;
1912}
1913
1920void StringSettingDesc::ChangeValue(const void *object, std::string &&newval) const
1921{
1922 this->MakeValueValid(newval);
1923 if (this->pre_check != nullptr && !this->pre_check(newval)) return;
1924
1925 this->Write(object, newval);
1926 if (this->post_callback != nullptr) this->post_callback(newval);
1927
1928 if (_save_config) SaveToConfig();
1929}
1930
1931/* Those 2 functions need to be here, else we have to make some stuff non-static
1932 * and besides, it is also better to keep stuff like this at the same place */
1933void IConsoleSetSetting(std::string_view name, std::string_view value, bool force_newgame)
1934{
1935 const SettingDesc *sd = GetSettingFromName(name);
1936 /* Company settings are not in "list_settings", so don't try to modify them. */
1937 if (sd == nullptr || sd->flags.Test(SettingFlag::PerCompany)) {
1938 IConsolePrint(CC_ERROR, "'{}' is an unknown setting.", name);
1939 return;
1940 }
1941
1942 bool success = true;
1943 if (sd->IsStringSetting()) {
1944 success = SetSettingValue(sd->AsStringSetting(), value, force_newgame);
1945 } else if (sd->IsIntSetting()) {
1946 const IntSettingDesc *isd = sd->AsIntSetting();
1947 size_t val = isd->ParseValue(value);
1948 if (!_settings_error_list.empty()) {
1949 IConsolePrint(CC_ERROR, "'{}' is not a valid value for this setting.", value);
1950 _settings_error_list.clear();
1951 return;
1952 }
1953 success = SetSettingValue(isd, (int32_t)val, force_newgame);
1954 }
1955
1956 if (!success) {
1957 if (_network_server) {
1958 IConsolePrint(CC_ERROR, "This command/variable is not available during network games.");
1959 } else {
1960 IConsolePrint(CC_ERROR, "This command/variable is only available to a network server.");
1961 }
1962 }
1963}
1964
1965void IConsoleSetSetting(std::string_view name, int value)
1966{
1967 const SettingDesc *sd = GetSettingFromName(name);
1968 assert(sd != nullptr);
1969 SetSettingValue(sd->AsIntSetting(), value);
1970}
1971
1977void IConsoleGetSetting(std::string_view name, bool force_newgame)
1978{
1979 const SettingDesc *sd = GetSettingFromName(name);
1980 /* Company settings are not in "list_settings", so don't try to read them. */
1981 if (sd == nullptr || sd->flags.Test(SettingFlag::PerCompany)) {
1982 IConsolePrint(CC_ERROR, "'{}' is an unknown setting.", name);
1983 return;
1984 }
1985
1986 const void *object = (_game_mode == GM_MENU || force_newgame) ? &_settings_newgame : &_settings_game;
1987
1988 if (sd->IsStringSetting()) {
1989 IConsolePrint(CC_INFO, "Current value for '{}' is '{}'.", sd->GetName(), sd->AsStringSetting()->Read(object));
1990 } else if (sd->IsIntSetting()) {
1991 std::string value = sd->FormatValue(object);
1992 const IntSettingDesc *int_setting = sd->AsIntSetting();
1993 auto [min_val, max_val] = int_setting->GetRange();
1994 auto def_val = int_setting->GetDefaultValue();
1995 IConsolePrint(CC_INFO, "Current value for '{}' is '{}' (min: {}{}, max: {}, def: {}).",
1996 sd->GetName(), value, sd->flags.Test(SettingFlag::GuiZeroIsSpecial) ? "(0) " : "", min_val, max_val, def_val);
1997 }
1998}
1999
2000static void IConsoleListSettingsTable(const SettingTable &table, std::string_view prefilter)
2001{
2002 for (auto &desc : table) {
2003 const SettingDesc *sd = GetSettingDesc(desc);
2004 if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue;
2005 if (!prefilter.empty() && sd->GetName().find(prefilter) == std::string::npos) continue;
2006 IConsolePrint(CC_DEFAULT, "{} = {}", sd->GetName(), sd->FormatValue(&GetGameSettings()));
2007 }
2008}
2009
2015void IConsoleListSettings(std::string_view prefilter)
2016{
2017 IConsolePrint(CC_HELP, "All settings with their current value:");
2018
2019 for (auto &table : GenericSettingTables()) {
2020 IConsoleListSettingsTable(table, prefilter);
2021 }
2022 for (auto &table : PrivateSettingTables()) {
2023 IConsoleListSettingsTable(table, prefilter);
2024 }
2025 for (auto &table : SecretSettingTables()) {
2026 IConsoleListSettingsTable(table, prefilter);
2027 }
2028
2029 IConsolePrint(CC_HELP, "Use 'setting' command to change a value.");
2030}
2031
2032ScriptConfigSettings::ScriptConfigSettings()
2033{
2034 /* Instantiate here, because unique_ptr needs a complete type. */
2035}
2036
2039{
2040 /* Instantiate here, because unique_ptr needs a complete type. */
2041}
2042
2043ScriptConfigSettings::ScriptConfigSettings(const ScriptConfigSettings &other)
2044{
2045 *this = other;
2046}
2047
2048ScriptConfigSettings &ScriptConfigSettings::operator=(const ScriptConfigSettings &other)
2049{
2050 for (CompanyID c = CompanyID::Begin(); c < MAX_COMPANIES; ++c) {
2051 if (other.ai[c] != nullptr) {
2052 this->ai[c] = std::make_unique<AIConfig>(*other.ai[c]);
2053 }
2054 }
2055 if (other.game != nullptr) {
2056 this->game = std::make_unique<GameConfig>(*other.game);
2057 }
2058 return *this;
2059}
AIConfig stores the configuration settings of every AI.
Generic functions for replacing base data (graphics, sounds).
Generic functions for replacing base graphics data.
constexpr T SetBit(T &x, const uint8_t y)
Set a bit in a variable.
constexpr enable_if_t< is_integral_v< T >, T > byteswap(T x) noexcept
Custom implementation of std::byteswap; remove once we build with C++23.
AI instantion of script configuration.
Definition ai_config.hpp:17
static AIConfig * GetConfig(CompanyID company, ScriptSettingSource source=ScriptSettingSource::Default)
Get the AI configuration of specific company.
Definition ai_config.cpp:20
constexpr bool Test(Tvalue_type value) const
Test if the value-th bit is set.
static const GraphicsSet * GetUsedSet()
Common return value for all commands.
IniFile to store a configuration.
Definition settings.cpp:143
Game script instantion of script configuration.
static GameConfig * GetConfig(ScriptSettingSource source=ScriptSettingSource::Default)
Get the script configuration.
@ ForceNewGame
Get the newgame Script config.
bool HasScript() const
Is this config attached to an Script?
void Change(std::optional< std::string_view > name, int version=-1, bool force_exact_match=false)
Set another Script to be loaded in this slot.
void StringToSettings(std::string_view value)
Convert a string which is stored in the config file or savegames to custom settings of this Script.
const std::string & GetName() const
Get the name of the Script.
std::string SettingsToString() const
Convert the custom settings to a string that can be stored in the config file or savegames.
Parse data from a string / buffer.
std::optional< T > TryReadIntegerBase(int base, bool clamp=false)
Try to read and parse an integer in number 'base', and then advance the reader.
bool AnyBytesLeft() const noexcept
Check whether any bytes left to read.
static const std::string_view WHITESPACE_NO_NEWLINE
ASCII whitespace characters, excluding new-line.
bool ReadIf(std::string_view str)
Check whether the next data matches 'str', and skip it.
void SkipUntilCharNotIn(std::string_view chars)
Skip 8-bit chars, while they are in 'chars', until they are not.
std::string_view ReadUntilCharIn(std::string_view chars)
Read 8-bit chars, while they are not in 'chars', until they are; and advance reader.
Functions related to commands.
static const CommandCost CMD_ERROR
Define a default return value for a failed command.
@ Execute
execute the given command
CompanyID _local_company
Company controlled by the human player at this client. Can also be COMPANY_SPECTATOR.
CompanyID _current_company
Company currently doing an action.
Functions related to companies.
Configuration options of the network stuff.
static const uint NETWORK_MAX_GRF_COUNT
Maximum number of GRFs that can be sent.
Definition config.h:88
void IConsolePrint(TextColour colour_code, const std::string &string)
Handle the printing of text entered into the console or redirected there by any other means.
Definition console.cpp:90
Console functions used outside of the console code.
static const TextColour CC_HELP
Colour for help lines.
static const TextColour CC_INFO
Colour for information lines.
static const TextColour CC_DEFAULT
Default colour of the console.
static const TextColour CC_ERROR
Colour for error lines.
void ResetCurrencies(bool preserve_custom)
Will fill _currency_specs array with default values from origin_currency_specs Called only from newgr...
Definition currency.cpp:163
Functions to handle different currencies.
CurrencySpec & GetCustomCurrency()
Get the custom currency.
Definition currency.h:110
void DebugReconsiderSendRemoteMessages()
Reconsider whether we need to send debug messages to either NetworkAdminConsole or IConsolePrint.
Definition debug.cpp:261
Functions related to debugging.
#define Debug(category, level, format_string,...)
Output a line of debugging information.
Definition debug.h:37
Functions related to errors.
std::list< ErrorMessageData > ErrorList
Define a queue with errors.
Definition error.h:51
void ScheduleErrorMessage(ErrorList &datas)
Schedule a list of errors.
@ WL_CRITICAL
Critical errors, the MessageBox is shown in all cases.
Definition error.h:27
void ShowErrorMessage(EncodedString &&summary_msg, int x, int y, CommandCost &cc)
Display an error message in a window.
void ShowFirstError()
Show the first error of the queue.
bool FioCheckFileExists(std::string_view filename, Subdirectory subdir)
Check whether the given file exists.
Definition fileio.cpp:121
std::string _config_file
Configuration file of OpenTTD.
Definition settings.cpp:64
Functions for standard in/out file operations.
@ NO_DIRECTORY
A path without any base directory.
@ NEWGRF_DIR
Subdirectory for all NewGRFs.
Definition fileio_type.h:97
Declarations for savegames operations.
fluid_settings_t * settings
FluidSynth settings handle.
GameConfig stores the configuration settings of every Game.
Gamelog _gamelog
Gamelog instance.
Definition gamelog.cpp:31
Functions to be called to log fundamental changes to the game.
@ GLAT_SETTING
Setting changed.
Definition gamelog.h:21
Functions related to world/map generation.
@ LG_ORIGINAL
The original landscape generator.
Definition genworld.h:21
static const uint CUSTOM_SEA_LEVEL_NUMBER_DIFFICULTY
Value for custom sea level in difficulty settings.
Definition genworld.h:46
static const uint CUSTOM_SEA_LEVEL_MIN_PERCENTAGE
Minimum percentage a user can specify for custom sea level.
Definition genworld.h:47
Types related to reading/writing '*.ini' files.
constexpr T Clamp(const T a, const T min, const T max)
Clamp a value between an interval.
Definition math_func.hpp:79
constexpr uint ClampU(const uint a, const uint min, const uint max)
Clamp an unsigned integer between an interval.
StringList _network_host_list
The servers we know.
Definition network.cpp:76
bool _networking
are we in networking mode?
Definition network.cpp:67
StringList _network_ban_list
The banned clients.
Definition network.cpp:77
bool _network_server
network-server is active
Definition network.cpp:68
StringList _network_bind_list
The addresses to bind on.
Definition network.cpp:75
Basic functions/variables used all over the place.
Network functions used by other parts of OpenTTD.
@ Public
The game is publicly accessible.
@ Local
Do not communicate with the game coordinator.
void BadgeClassSaveConfig(IniFile &ini)
Save badge column preferences.
void BadgeClassLoadConfig(const IniFile &ini)
Load badge column preferences.
Functions related to NewGRF badge configuration.
GRFConfigList _grfconfig_static
First item in list of static GRF set up.
std::string GRFBuildParamList(const GRFConfig &c)
Build a string containing space separated parameter values.
const GRFConfig * FindGRFConfig(uint32_t grfid, FindGRFConfigMode mode, const MD5Hash *md5sum, uint32_t desired_version)
Find a NewGRF in the scanned list.
GRFConfigList _grfconfig_newgame
First item in list of default GRF set up.
bool FillGRFDetails(GRFConfig &config, bool is_static, Subdirectory subdir)
Find the GRFID of a given grf, and calculate its md5sum.
Functions to find and configure NewGRFs.
@ GCS_NOT_FOUND
GRF file was not found in the local cache.
@ Invalid
GRF is unusable with this version of OpenTTD.
@ Static
GRF file is used statically (can be used in any MP game).
@ System
GRF file is an openttd-internal system grf.
@ Unsafe
GRF file is unsafe for static usage.
@ FGCM_NEWEST_VALID
Find newest Grf, ignoring Grfs with GRFConfigFlag::Invalid set.
@ FGCM_EXACT
Only find Grfs matching md5sum.
Functions/types etc.
void PickerSaveConfig(IniFile &ini)
Save favourites of all registered Pickers to config.
void PickerLoadConfig(const IniFile &ini)
Load favourites of all registered Pickers from config.
Declaration of OTTD revision dependent variables.
A number of safeguards to prevent using unsafe methods.
void WriteValue(void *ptr, VarType conv, int64_t val)
Write the value of a setting.
Definition saveload.cpp:848
int64_t ReadValue(const void *ptr, VarType conv)
Return a signed-long version of the value of a setting.
Definition saveload.cpp:824
@ SLE_VAR_NULL
useful to write zeros in savegame.
Definition saveload.h:691
@ SLE_VAR_STR
string pointer
Definition saveload.h:692
@ SLE_VAR_STRQ
string pointer enclosed in quotes
Definition saveload.h:693
constexpr size_t SlVarSize(VarType type)
Return expect size in bytes of a VarType.
Definition saveload.h:821
void * GetVariableAddress(const void *object, const SaveLoad &sld)
Get the address of the variable.
Definition saveload.h:1343
bool SlIsObjectCurrentlyValid(SaveLoadVersion version_from, SaveLoadVersion version_to)
Checks if some version from/to combination falls within the range of the active savegame version.
Definition saveload.h:1329
constexpr VarType GetVarMemType(VarType type)
Get the NumberType of a setting.
Definition saveload.h:790
static void GraphicsSetLoadConfig(IniFile &ini)
Load BaseGraphics set selection and configuration.
void HandleOldDiffCustom(bool savegame)
Reading of the old diff_custom array and transforming it to the new format.
void SyncCompanySettings()
Sync all company settings in a multiplayer game.
void IniLoadWindowSettings(IniFile &ini, std::string_view grpname, WindowDesc *desc)
Load a WindowDesc from config.
Definition settings.cpp:874
static void RemoveEntriesFromIni(IniFile &ini, const SettingTable &table)
Remove all entries from a settings table from an ini-file.
void SaveGRFPresetToConfig(std::string_view config_name, GRFConfigList &config)
Save a NewGRF configuration with a preset name.
StringList GetGRFPresetList()
Get the list of known NewGrf presets.
static void ValidateSettings()
Checks if any settings are set to incorrect values, and sets them to correct values in that case.
Definition settings.cpp:943
bool IsConversionNeeded(const ConfigIniFile &ini, const std::string &group, const std::string &old_var, const std::string &new_var, const IniItem **old_item)
Check whether a conversion should be done, and based on what old setting information.
void IConsoleGetSetting(std::string_view name, bool force_newgame)
Output value of a specific setting to the console.
std::string _secrets_file
Secrets configuration file of OpenTTD.
Definition settings.cpp:66
static GRFConfigList GRFLoadConfig(const IniFile &ini, std::string_view grpname, bool is_static)
Load a GRF configuration.
std::string _favs_file
Picker favourites configuration file of OpenTTD.
Definition settings.cpp:67
static ErrorList _settings_error_list
Errors while loading minimal settings.
Definition settings.cpp:69
void DeleteGRFPresetFromConfig(std::string_view config_name)
Delete a NewGRF configuration by preset name.
void SetDefaultCompanySettings(CompanyID cid)
Set the company settings for a new company to their default values.
static void IniLoadSettingList(IniFile &ini, std::string_view grpname, StringList &list)
Loads all items from a 'grpname' section into a list The list parameter can be a nullptr pointer,...
Definition settings.cpp:836
std::vector< const SettingDesc * > GetFilteredSettingCollection(std::function< bool(const SettingDesc &desc)> func)
Get a collection of settings matching a custom filter.
void LoadFromConfig(bool startup)
Load the values from the configuration files.
GRFConfigList LoadGRFPresetFromConfig(std::string_view config_name)
Load a NewGRF configuration by preset-name.
bool SetSettingValue(const IntSettingDesc *sd, int32_t value, bool force_newgame)
Top function to save the new value of an element of the Settings struct.
void SaveToConfig()
Save the values to the configuration file.
VehicleDefaultSettings _old_vds
Used for loading default vehicles settings from old savegames.
Definition settings.cpp:63
void PrepareOldDiffCustom()
Prepare for reading and old diff_custom by zero-ing the memory.
static void IniLoadSettings(IniFile &ini, const SettingTable &settings_table, std::string_view grpname, void *object, bool only_startup)
Load values from a group of an IniFile structure into the internal representation.
Definition settings.cpp:621
void GetSaveLoadFromSettingTable(SettingTable settings, std::vector< SaveLoad > &saveloads)
Get the SaveLoad for all settings in the settings table.
static void GraphicsSetSaveConfig(IniFile &ini)
Save BaseGraphics set selection and configuration.
static bool LoadIntList(std::optional< std::string_view > str, void *array, int nelems, VarType type)
Load parsed string-values into an integer-array (intlist).
Definition settings.cpp:285
static std::optional< std::vector< uint32_t > > ParseIntList(std::string_view str)
Parse a string into a vector of uint32s.
Definition settings.cpp:250
GameSettings _settings_game
Game settings of a running game or the scenario editor.
Definition settings.cpp:61
CommandCost CmdChangeCompanySetting(DoCommandFlags flags, const std::string &name, int32_t value)
Change one of the per-company settings.
IniFileVersion
Ini-file versions.
Definition settings.cpp:169
@ IFV_0
0 All versions prior to introduction.
Definition settings.cpp:170
@ IFV_AUTOSAVE_RENAME
5 PR#11143 Renamed values of autosave to be in minutes.
Definition settings.cpp:176
@ IFV_LINKGRAPH_SECONDS
3 PR#10610 Store linkgraph update intervals in seconds instead of days.
Definition settings.cpp:173
@ IFV_REMOVE_GENERATION_SEED
7 PR#11927 Remove "generation_seed" from configuration.
Definition settings.cpp:178
@ IFV_MAX_VERSION
Highest possible ini-file version.
Definition settings.cpp:180
@ IFV_NETWORK_PRIVATE_SETTINGS
4 PR#10762 Move use_relay_service to private settings.
Definition settings.cpp:174
@ IFV_GAME_TYPE
2 PR#9515 Convert server_advertise to server_game_type.
Definition settings.cpp:172
@ IFV_RIGHT_CLICK_CLOSE
6 PR#10204 Add alternative right click to close windows setting.
Definition settings.cpp:177
@ IFV_PRIVATE_SECRETS
1 PR#9298 Moving of settings from openttd.cfg to private.cfg / secrets.cfg.
Definition settings.cpp:171
SettingTable GetSaveLoadSettingTable()
Create a single table with all settings that should be stored/loaded in the savegame.
void IConsoleListSettings(std::string_view prefilter)
List all settings and their value to the console.
static void IniSaveSettingList(IniFile &ini, std::string_view grpname, StringList &list)
Saves all items from a list into the 'grpname' section The list parameter can be a nullptr pointer,...
Definition settings.cpp:858
const uint16_t INIFILE_VERSION
Current ini-file version of OpenTTD.
Definition settings.cpp:183
static void IniSaveSettings(IniFile &ini, const SettingTable &settings_table, std::string_view grpname, void *object, bool)
Save the values of settings to the inifile.
Definition settings.cpp:706
static auto & SecretSettingTables()
List of all the secrets setting tables.
Definition settings.cpp:117
std::string _private_file
Private configuration file of OpenTTD.
Definition settings.cpp:65
GameSettings _settings_newgame
Game settings for new games (updated from the intro screen).
Definition settings.cpp:62
static auto & PrivateSettingTables()
List of all the private setting tables.
Definition settings.cpp:105
static void SaveVersionInConfig(IniFile &ini)
Save the version of OpenTTD to the ini file.
static std::optional< uint32_t > LookupManyOfMany(std::span< const std::string_view > many, std::string_view str)
Find the set-integer value MANYofMANY type in a string.
Definition settings.cpp:224
static const SettingDesc * GetSettingFromName(std::string_view name, const SettingTable &settings)
Given a name of setting, return a setting description from the table.
static auto & GenericSettingTables()
List of all the generic setting tables.
Definition settings.cpp:82
void IniSaveWindowSettings(IniFile &ini, std::string_view grpname, WindowDesc *desc)
Save a WindowDesc to config.
Definition settings.cpp:885
static const SettingDesc * GetCompanySettingFromName(std::string_view name)
Given a name of setting, return a company setting description of it.
CommandCost CmdChangeSetting(DoCommandFlags flags, const std::string &name, int32_t value)
Network-safe changing of settings (server-only).
ClientSettings _settings_client
The current settings for this game.
Definition settings.cpp:60
Command definitions related to settings.
Functions related to setting/changing the settings.
@ NotInSave
Do not save with savegame, basically client-based.
@ Sandbox
This setting is a sandbox setting.
@ SceneditOnly
This setting can only be changed in the scenario editor.
@ PerCompany
This setting can be different for each company (saved in company struct).
@ NewgameOnly
This setting cannot be changed in a game.
@ GuiZeroIsSpecial
A value of zero is possible and has a custom string (the one after "strval").
@ NoNetwork
This setting does not apply to network games; it may not be changed during the game.
@ NotInConfig
Do not save to config file.
@ GuiDropdown
The value represents a limited number of string-options (internally integer) presented as dropdown.
@ SceneditToo
This setting can be changed in the scenario editor (only makes sense when SettingFlag::NewgameOnly is...
@ NoNetworkSync
Do not synchronize over network (but it is saved if SettingFlag::NotInSave is not set).
@ NetworkOnly
This setting only applies to network games.
SettingType
Type of settings for filtering.
@ ST_CLIENT
Client setting.
@ ST_GAME
Game setting.
@ ST_COMPANY
Company setting.
static constexpr const SettingDesc * GetSettingDesc(const SettingVariant &desc)
Helper to convert the type of the iterated settings description to a pointer to it.
Definition of the configuration tables of the settings.
GameSettings & GetGameSettings()
Get the settings-object applicable for the current situation: the newgame settings when we're in the ...
Definition of base types and functions in a cross-platform compatible way.
bool ConvertHexToBytes(std::string_view hex, std::span< uint8_t > bytes)
Convert a hex-string to a byte-array, while validating it was actually hex.
Definition string.cpp:572
void StrMakeValidInPlace(char *str, StringValidationSettings settings)
Scans the string for invalid characters and replaces them with a question mark '?
Definition string.cpp:157
std::string FormatArrayAsHex(std::span< const uint8_t > data)
Format a byte array into a continuous hex string.
Definition string.cpp:77
Parse strings.
static std::optional< T > ParseInteger(std::string_view arg, int base=10, bool clamp=false)
Change a string into its number representation.
Functions related to low-level strings.
std::vector< std::string > StringList
Type for a list of strings.
Definition string_type.h:60
EncodedString GetEncodedString(StringID str)
Encode a string with no parameters into an encoded string.
Definition strings.cpp:90
Functions related to OTTD's strings.
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
Class to backup a specific variable and restore it upon destruction of this object to prevent stack v...
std::string name
The name of the base set.
uint32_t shortname
Four letter short variant of the name.
std::string FormatValue(const void *object) const override
Format the value of the setting associated with this object.
Definition settings.cpp:748
static std::optional< bool > ParseSingleValue(std::string_view str)
Find whether a string was a boolean true or a boolean false.
Definition settings.cpp:209
int32_t ParseValue(std::string_view str) const override
Convert a string representation (external) of an integer-like setting to an integer.
Definition settings.cpp:411
All settings that are only important for the local client.
CompanySettings settings
settings specific for each company
Information about GRF, used in the game and (part of it) in savegames.
uint32_t version
NOSAVE: Version a NewGRF can set so only the newest NewGRF is shown.
std::vector< uint32_t > param
GRF parameters.
All settings together for the game.
All data of a graphics set.
Ini file that supports both loading and saving.
Definition ini_type.h:87
bool SaveToDisk(const std::string &filename)
Save the Ini file's data to the disk.
Definition ini.cpp:42
IniFile(const IniGroupNameList &list_group_names={})
Create a new ini file with given group names.
Definition ini.cpp:33
A group within an ini file.
Definition ini_type.h:34
const IniItem * GetItem(std::string_view name) const
Get the item with the given name.
Definition ini_load.cpp:50
std::string comment
comment for group
Definition ini_type.h:38
void Clear()
Clear all items in the group.
Definition ini_load.cpp:96
void RemoveItem(std::string_view name)
Remove the item with the given name.
Definition ini_load.cpp:88
std::string name
name of group
Definition ini_type.h:37
IniItem & CreateItem(std::string_view name)
Create an item with the given name.
Definition ini_load.cpp:79
IniItem & GetOrCreateItem(std::string_view name)
Get the item with the given name, and if it doesn't exist create a new item.
Definition ini_load.cpp:64
std::list< IniItem > items
all items in the group
Definition ini_type.h:35
A single "line" in an ini file.
Definition ini_type.h:23
std::optional< std::string > value
The value of this item.
Definition ini_type.h:25
std::string name
The name of this item.
Definition ini_type.h:24
void SetValue(std::string_view value)
Replace the current value with another value.
Definition ini_load.cpp:30
std::list< IniGroup > groups
all groups in the ini
Definition ini_type.h:53
void RemoveGroup(std::string_view name)
Remove the group with the given name.
Definition ini_load.cpp:173
const IniGroup * GetGroup(std::string_view name) const
Get the group with the given name.
Definition ini_load.cpp:117
void LoadFromDisk(std::string_view filename, Subdirectory subdir)
Load the Ini file's data from the disk.
Definition ini_load.cpp:184
IniGroup & GetOrCreateGroup(std::string_view name)
Get the group with the given name, and if it doesn't exist create a new group.
Definition ini_load.cpp:145
Base integer type, including boolean, settings.
StringID str_help
(Translated) string with help text; gui only.
StringID str_val
(Translated) first string describing the value.
void MakeValueValid(int32_t &value) const
Make the value valid given the limitations of this setting.
Definition settings.cpp:503
void ResetToDefault(void *object) const override
Reset the setting to its default value.
Definition settings.cpp:767
std::string FormatValue(const void *object) const override
Format the value of the setting associated with this object.
Definition settings.cpp:737
int32_t def
default value given when none is present
std::tuple< int32_t, uint32_t > GetRange() const
Get the min/max range for the setting.
Definition settings.cpp:477
StringID GetTitle() const
Get the title of the setting.
Definition settings.cpp:427
void ChangeValue(const void *object, int32_t newvalue) const
Handle changing a value.
uint32_t max
maximum values
GetDefaultValueCallback * get_def_cb
Callback to set the correct default value.
bool IsSameValue(const IniItem *item, void *object) const override
Check whether the value in the Ini item is the same as is saved in this setting in the object.
Definition settings.cpp:754
int32_t min
minimum values
PreChangeCheck * pre_check
Callback to check for the validity of the setting.
int32_t GetDefaultValue() const
Get the default value of the setting.
Definition settings.cpp:468
void Write(const void *object, int32_t value) const
Set the value of a setting.
Definition settings.cpp:557
StringID GetHelp() const
Get the help text of the setting.
Definition settings.cpp:436
virtual bool IsBoolSetting() const
Check whether this setting is a boolean type setting.
PostChangeCallback * post_callback
Callback when the setting has been changed.
StringID str
(translated) string with descriptive text; gui and console
void MakeValueValidAndWrite(const void *object, int32_t value) const
Make the value valid and then write it to the setting.
Definition settings.cpp:488
std::pair< StringParameter, StringParameter > GetValueParams(int32_t value) const
Get parameters for drawing the value of the setting.
Definition settings.cpp:446
int32_t Read(const void *object) const
Read the integer from the the actual setting.
Definition settings.cpp:568
virtual int32_t ParseValue(std::string_view str) const
Convert a string representation (external) of an integer-like setting to an integer.
Definition settings.cpp:367
bool IsDefaultValue(void *object) const override
Check whether the value is the same as the default value.
Definition settings.cpp:761
void ParseValue(const IniItem *item, void *object) const override
Parse/read the value from the Ini item into the setting associated with this object.
Definition settings.cpp:675
void ResetToDefault(void *object) const override
Reset the setting to its default value.
Definition settings.cpp:821
bool IsSameValue(const IniItem *item, void *object) const override
Check whether the value in the Ini item is the same as is saved in this setting in the object.
Definition settings.cpp:809
std::string_view def
default value given when none is present
std::string FormatValue(const void *object) const override
Convert a list to a string representation.
Definition settings.cpp:310
bool IsDefaultValue(void *object) const override
Check whether the value is the same as the default value.
Definition settings.cpp:815
int32_t ParseValue(std::string_view str) const override
Convert a string representation (external) of an integer-like setting to an integer.
Definition settings.cpp:400
std::string FormatValue(const void *object) const override
Format the value of the setting associated with this object.
Definition settings.cpp:347
OnConvert * many_cnvt
callback procedure when loading value mechanism fails
std::string FormatValue(const void *object) const override
Format the value of the setting associated with this object.
Definition settings.cpp:341
static std::optional< uint32_t > ParseSingleValue(std::string_view str, std::span< const std::string_view > many)
Find the index value of a ONEofMANY type in a string.
Definition settings.cpp:191
std::vector< std::string_view > many
possible values for this type
int32_t ParseValue(std::string_view str) const override
Convert a string representation (external) of an integer-like setting to an integer.
Definition settings.cpp:386
static Company * Get(auto index)
SaveLoadVersion version_to
Save/load the variable before this savegame version.
Definition saveload.h:762
VarType conv
Type of the variable to be saved; this field combines both FileVarType and MemVarType.
Definition saveload.h:759
SaveLoadVersion version_from
Save/load the variable starting from this savegame version.
Definition saveload.h:761
Container for AI and Game script configuration.
std::unique_ptr< class GameConfig > game
settings for gamescript
TypedIndexContainer< std::array< std::unique_ptr< class AIConfig >, MAX_COMPANIES >, CompanyID > ai
settings per company
~ScriptConfigSettings()
Needs to be manually defined due to incomplete definition of types in the header.
Iterable ensemble of each set bit in a value.
Properties of config file settings.
virtual void ParseValue(const IniItem *item, void *object) const =0
Parse/read the value from the Ini item into the setting associated with this object.
bool IsEditable(bool do_command=false) const
Check whether the setting is editable in the current gamemode.
Definition settings.cpp:895
SettingFlags flags
Handles how a setting would show up in the GUI (text/currency, etc.).
virtual bool IsStringSetting() const
Check whether this setting is an string type setting.
SettingType GetType() const
Return the type of the setting.
Definition settings.cpp:912
constexpr const std::string & GetName() const
Get the name of this setting.
bool startup
Setting has to be loaded directly at startup?.
virtual std::string FormatValue(const void *object) const =0
Format the value of the setting associated with this object.
const struct StringSettingDesc * AsStringSetting() const
Get the setting description of this setting as a string setting.
Definition settings.cpp:932
virtual bool IsSameValue(const IniItem *item, void *object) const =0
Check whether the value in the Ini item is the same as is saved in this setting in the object.
SaveLoad save
Internal structure (going to savegame, parts to config).
virtual bool IsIntSetting() const
Check whether this setting is an integer type setting.
const struct IntSettingDesc * AsIntSetting() const
Get the setting description of this setting as an integer setting.
Definition settings.cpp:922
String settings.
const std::string & Read(const void *object) const
Read the string from the the actual setting.
Definition settings.cpp:607
std::string_view def
Default value given when none is present.
void Write(const void *object, std::string_view str) const
Write a string to the actual setting.
Definition settings.cpp:597
uint32_t max_length
Maximum length of the string, 0 means no maximum length.
PreChangeCheck * pre_check
Callback to check for the validity of the setting.
void ChangeValue(const void *object, std::string &&newval) const
Handle changing a string value.
void MakeValueValid(std::string &str) const
Make the value valid given the limitations of this setting.
Definition settings.cpp:581
bool IsSameValue(const IniItem *item, void *object) const override
Check whether the value in the Ini item is the same as is saved in this setting in the object.
Definition settings.cpp:788
bool IsDefaultValue(void *object) const override
Check whether the value is the same as the default value.
Definition settings.cpp:798
PostChangeCallback * post_callback
Callback when the setting has been changed.
void ResetToDefault(void *object) const override
Reset the setting to its default value.
Definition settings.cpp:804
std::string FormatValue(const void *object) const override
Format the value of the setting associated with this object.
Definition settings.cpp:772
void ParseValue(const IniItem *item, void *object) const override
Parse/read the value from the Ini item into the setting associated with this object.
Definition settings.cpp:668
Default settings for vehicles.
High level window description.
Definition window_gui.h:168
void SetWindowClassesDirty(WindowClass cls)
Mark all windows of a particular class as dirty (in need of repainting).
Definition window.cpp:3229
Window * FindWindowById(WindowClass cls, WindowNumber number)
Find a window by its class and window number.
Definition window.cpp:1166
Window functions not directly related to making/drawing windows.
@ WC_ERRMSG
Error message; Window numbers:
@ WC_CHEATS
Cheat window; Window numbers:
@ WC_GAME_OPTIONS
Game options window; Window numbers: