OpenTTD Source 20260711-master-g3fb3006dff
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_func.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 (vt.mem) {
131 case VarMemType::I8:
132 case VarMemType::I16:
133 case VarMemType::I32:
134 case VarMemType::I64:
135 return true;
136
137 default:
138 return false;
139 }
140}
141
145class ConfigIniFile : public IniFile {
146private:
147 static inline const IniGroupNameList list_group_names = {
148 "bans",
149 "newgrf",
150 "servers",
151 "server_bind_addresses",
152 "server_authorized_keys",
153 "rcon_authorized_keys",
154 "admin_authorized_keys"
155 };
156
157public:
158 ConfigIniFile(const std::string &filename) : IniFile(list_group_names)
159 {
160 this->LoadFromDisk(filename, Subdirectory::None);
161 }
162};
163
185
187
196std::optional<int32_t> IntSettingDesc::ParseSingleValue(std::string_view str, int32_t min, uint32_t max)
197{
198 StringConsumer consumer{str};
199 /* The actual settings value might be int32 or uint32. Read as int64 and just cast away the high bits. */
200 auto value = consumer.TryReadIntegerBase<int64_t>(10);
201 /* check if it's an integer */
202 if (!value.has_value()) return std::nullopt;
203
204 if (value < min || value > max) {
205 return std::nullopt;
206 }
207 return value;
208}
209
216std::optional<uint32_t> OneOfManySettingDesc::ParseSingleValue(std::string_view str, std::span<const std::string_view> many)
217{
218 StringConsumer consumer{str};
219 auto digit = consumer.TryReadIntegerBase<uint32_t>(10);
220 /* check if it's an integer */
221 if (digit.has_value()) return digit;
222
223 auto it = std::ranges::find(many, str);
224 if (it == many.end()) return std::nullopt;
225 return static_cast<uint32_t>(it - many.begin());
226}
227
234std::optional<bool> BoolSettingDesc::ParseSingleValue(std::string_view str)
235{
236 if (str == "true" || str == "on" || str == "1") return true;
237 if (str == "false" || str == "off" || str == "0") return false;
238
239 return std::nullopt;
240}
241
249static std::optional<uint32_t> LookupManyOfMany(std::span<const std::string_view> many, std::string_view str)
250{
251 static const std::string_view separators{" \t|"};
252
253 uint32_t res = 0;
254 StringConsumer consumer{str};
255 while (consumer.AnyBytesLeft()) {
256 /* skip "whitespace" */
257 consumer.SkipUntilCharNotIn(separators);
258
259 std::string_view value = consumer.ReadUntilCharIn(separators);
260 if (value.empty()) break;
261
262 auto r = OneOfManySettingDesc::ParseSingleValue(value, many);
263 if (!r.has_value()) return r;
264
265 SetBit(res, *r); // value found, set it
266 }
267 return res;
268}
269
275static std::optional<std::vector<uint32_t>> ParseIntList(std::string_view str)
276{
277 bool comma = false; // do we accept comma?
278 std::vector<uint32_t> result;
279
280 StringConsumer consumer{str};
281 for (;;) {
283 if (!consumer.AnyBytesLeft()) break;
284 if (comma && consumer.ReadIf(",")) {
285 /* commas are optional, but we only accept one between values */
286 comma = false;
287 continue;
288 }
289 auto v = consumer.TryReadIntegerBase<uint32_t>(10);
290 if (!v.has_value()) return std::nullopt;
291 result.push_back(*v);
292 comma = true;
293 }
294
295 /* If we have read comma but no number after it, fail.
296 * We have read comma when (n != 0) and comma is not allowed */
297 if (!result.empty() && !comma) return std::nullopt;
298
299 return result;
300}
301
310static bool LoadIntList(std::optional<std::string_view> str, void *array, int nelems, VarMemType type)
311{
312 size_t elem_size = SlVarSize(type);
313 std::byte *p = static_cast<std::byte *>(array);
314 if (!str.has_value()) {
315 std::fill_n(p, nelems * elem_size, static_cast<std::byte>(0));
316 return true;
317 }
318
319 auto opt_items = ParseIntList(*str);
320 if (!opt_items.has_value() || opt_items->size() != (size_t)nelems) return false;
321
322 for (auto item : *opt_items) {
323 WriteValue(p, type, item);
324 p += elem_size;
325 }
326 return true;
327}
328
335std::string ListSettingDesc::FormatValue(const void *object) const
336{
337 const uint8_t *p = static_cast<const uint8_t *>(GetVariableAddress(object, this->save));
338
339 std::string result;
340 for (size_t i = 0; i != this->save.length; i++) {
341 int64_t v;
342 switch (this->save.conv.mem) {
343 case VarMemType::Bool:
344 case VarMemType::I8: v = *(const int8_t *)p; p += 1; break;
345 case VarMemType::U8: v = *(const uint8_t *)p; p += 1; break;
346 case VarMemType::I16: v = *(const int16_t *)p; p += 2; break;
347 case VarMemType::U16: v = *(const uint16_t *)p; p += 2; break;
348 case VarMemType::I32: v = *(const int32_t *)p; p += 4; break;
349 case VarMemType::U32: v = *(const uint32_t *)p; p += 4; break;
350 default: NOT_REACHED();
351 }
352 if (i != 0) result += ',';
353 format_append(result, "{}", v);
354 }
355 return result;
356}
357
358std::string OneOfManySettingDesc::FormatSingleValue(uint id) const
359{
360 if (id >= this->many.size()) {
361 return fmt::format("{}", id);
362 }
363 return std::string{this->many[id]};
364}
365
366std::string OneOfManySettingDesc::FormatValue(const void *object) const
367{
368 uint id = (uint)this->Read(object);
369 return this->FormatSingleValue(id);
370}
371
372std::string ManyOfManySettingDesc::FormatValue(const void *object) const
373{
374 uint bitmask = (uint)this->Read(object);
375 if (bitmask == 0) {
376 return {};
377 }
378
379 std::string result;
380 for (uint id : SetBitIterator(bitmask)) {
381 if (!result.empty()) result += '|';
382 result += this->FormatSingleValue(id);
383 }
384 return result;
385}
386
392int32_t IntSettingDesc::ParseValue(std::string_view str) const
393{
394 StringConsumer consumer{str};
395 /* The actual settings value might be int32 or uint32. Read as int64 and just cast away the high bits. */
396 auto value = consumer.TryReadIntegerBase<int64_t>(10);
397 if (!value.has_value()) {
398 _settings_error_list.emplace_back(
399 GetEncodedString(STR_CONFIG_ERROR),
400 GetEncodedString(STR_CONFIG_ERROR_INVALID_VALUE, str, this->GetName()));
401 return this->GetDefaultValue();
402 }
403 if (consumer.AnyBytesLeft()) {
404 _settings_error_list.emplace_back(
405 GetEncodedString(STR_CONFIG_ERROR),
406 GetEncodedString(STR_CONFIG_ERROR_TRAILING_CHARACTERS, this->GetName()));
407 }
408 return static_cast<int32_t>(*value);
409}
410
411int32_t OneOfManySettingDesc::ParseValue(std::string_view str) const
412{
414 /* if the first attempt of conversion from string to the appropriate value fails,
415 * look if we have defined a converter from old value to new value. */
416 if (!r.has_value() && this->many_cnvt != nullptr) r = this->many_cnvt(str);
417 if (r.has_value()) return *r; // and here goes converted value
418
419 _settings_error_list.emplace_back(
420 GetEncodedString(STR_CONFIG_ERROR),
421 GetEncodedString(STR_CONFIG_ERROR_INVALID_VALUE, str, this->GetName()));
422 return this->GetDefaultValue();
423}
424
425int32_t ManyOfManySettingDesc::ParseValue(std::string_view str) const
426{
427 auto r = LookupManyOfMany(this->many, str);
428 if (r.has_value()) return *r;
429
430 _settings_error_list.emplace_back(
431 GetEncodedString(STR_CONFIG_ERROR),
432 GetEncodedString(STR_CONFIG_ERROR_INVALID_VALUE, str, this->GetName()));
433 return this->GetDefaultValue();
434}
435
436int32_t BoolSettingDesc::ParseValue(std::string_view str) const
437{
439 if (r.has_value()) return *r;
440
441 _settings_error_list.emplace_back(
442 GetEncodedString(STR_CONFIG_ERROR),
443 GetEncodedString(STR_CONFIG_ERROR_INVALID_VALUE, str, this->GetName()));
444 return this->GetDefaultValue();
445}
446
453{
454 return this->get_title_cb != nullptr ? this->get_title_cb(*this) : this->str;
455}
456
462{
463 return this->get_help_cb != nullptr ? this->get_help_cb(*this) : this->str_help;
464}
465
471std::pair<StringParameter, StringParameter> IntSettingDesc::GetValueParams(int32_t value) const
472{
473 if (this->get_value_params_cb != nullptr) {
474 return this->get_value_params_cb(*this, value);
475 }
476
477 if (this->IsBoolSetting()) {
478 return {value != 0 ? STR_CONFIG_SETTING_ON : STR_CONFIG_SETTING_OFF, {}};
479 }
480
481 if (this->flags.Test(SettingFlag::GuiDropdown)) {
482 auto [min_val, _] = this->GetRange();
483 return {this->str_val - min_val + value, value};
484 }
485
486 return {this->str_val + ((value == 0 && this->flags.Test(SettingFlag::GuiZeroIsSpecial)) ? 1 : 0), value};
487}
488
494{
495 return this->get_def_cb != nullptr ? this->get_def_cb(*this) : this->def;
496}
497
502std::tuple<int32_t, uint32_t> IntSettingDesc::GetRange() const
503{
504 return this->get_range_cb != nullptr ? this->get_range_cb(*this) : std::tuple(this->min, this->max);
505}
506
513void IntSettingDesc::MakeValueValidAndWrite(const void *object, int32_t val) const
514{
515 this->MakeValueValid(val);
516 this->Write(object, val);
517}
518
528void IntSettingDesc::MakeValueValid(int32_t &val) const
529{
530 auto [min_val, max_val] = this->GetRange();
531 /* We need to take special care of the uint32_t type as we receive from the function
532 * a signed integer. While here also bail out on 64-bit settings as those are not
533 * supported. Unsigned 8 and 16-bit variables are safe since they fit into a signed
534 * 32-bit variable
535 * TODO: Support 64-bit settings/variables; requires 64 bit over command protocol! */
536 switch (this->save.conv.mem) {
537 case VarMemType::Null: return;
538 case VarMemType::Bool:
539 case VarMemType::I8:
540 case VarMemType::U8:
541 case VarMemType::I16:
542 case VarMemType::U16:
543 case VarMemType::I32: {
544 /* Override the minimum value. No value below this->min, except special value 0 */
545 if (!this->flags.Test(SettingFlag::GuiZeroIsSpecial) || val != 0) {
546 if (!this->flags.Test(SettingFlag::GuiDropdown)) {
547 /* Clamp value-type setting to its valid range */
548 val = Clamp(val, min_val, max_val);
549 } else if (val < min_val || val > static_cast<int32_t>(max_val)) {
550 /* Reset invalid discrete setting (where different values change gameplay) to its default value */
551 val = this->GetDefaultValue();
552 }
553 }
554 break;
555 }
556 case VarMemType::U32: {
557 /* Override the minimum value. No value below this->min, except special value 0 */
558 uint32_t uval = static_cast<uint32_t>(val);
559 if (!this->flags.Test(SettingFlag::GuiZeroIsSpecial) || uval != 0) {
560 if (!this->flags.Test(SettingFlag::GuiDropdown)) {
561 /* Clamp value-type setting to its valid range */
562 uval = ClampU(uval, min_val, max_val);
563 } else if (uval < static_cast<uint32_t>(min_val) || uval > max_val) {
564 /* Reset invalid discrete setting to its default value */
565 uval = static_cast<uint32_t>(this->GetDefaultValue());
566 }
567 }
568 val = static_cast<int32_t>(uval);
569 return;
570 }
571 case VarMemType::I64:
572 case VarMemType::U64:
573 default: NOT_REACHED();
574 }
575}
576
582void IntSettingDesc::Write(const void *object, int32_t val) const
583{
584 void *ptr = GetVariableAddress(object, this->save);
585 WriteValue(ptr, this->save.conv.mem, static_cast<int64_t>(val));
586}
587
593int32_t IntSettingDesc::Read(const void *object) const
594{
595 void *ptr = GetVariableAddress(object, this->save);
596 return static_cast<int32_t>(ReadValue(ptr, this->save.conv.mem));
597}
598
606void StringSettingDesc::MakeValueValid(std::string &str) const
607{
608 if (this->max_length == 0 || str.size() < this->max_length) return;
609
610 /* In case a maximum length is imposed by the setting, the length
611 * includes the '\0' termination for network transfer purposes.
612 * Also ensure the string is valid after chopping of some bytes. */
613 str.erase(this->max_length - 1, std::string::npos);
614 StrMakeValidInPlace(str, {});
615}
616
622void StringSettingDesc::Write(const void *object, std::string_view str) const
623{
624 reinterpret_cast<std::string *>(GetVariableAddress(object, this->save))->assign(str);
625}
626
632const std::string &StringSettingDesc::Read(const void *object) const
633{
634 return *reinterpret_cast<std::string *>(GetVariableAddress(object, this->save));
635}
636
646static void IniLoadSettings(IniFile &ini, const SettingTable &settings_table, std::string_view grpname, void *object, bool only_startup)
647{
648 const IniGroup *group;
649 const IniGroup *group_def = ini.GetGroup(grpname);
650
651 for (auto &desc : settings_table) {
652 const SettingDesc *sd = GetSettingDesc(desc);
654 if (sd->startup != only_startup) continue;
655
656 /* For settings.xx.yy load the settings from [xx] yy = ? */
657 std::string s{ sd->GetName() };
658 auto sc = s.find('.');
659 if (sc != std::string::npos) {
660 group = ini.GetGroup(s.substr(0, sc));
661 if (group == nullptr) group = group_def;
662 s = s.substr(sc + 1);
663 } else {
664 group = group_def;
665 }
666
667 const IniItem *item = nullptr;
668 if (group != nullptr) item = group->GetItem(s);
669 if (item == nullptr && group != group_def && group_def != nullptr) {
670 /* For settings.xx.yy load the settings from [settings] yy = ? in case the previous
671 * did not exist (e.g. loading old config files with a [settings] section */
672 item = group_def->GetItem(s);
673 }
674 if (item == nullptr) {
675 /* For settings.xx.zz.yy load the settings from [zz] yy = ? in case the previous
676 * did not exist (e.g. loading old config files with a [yapf] section */
677 sc = s.find('.');
678 if (sc != std::string::npos) {
679 if (group = ini.GetGroup(s.substr(0, sc)); group != nullptr) item = group->GetItem(s.substr(sc + 1));
680 }
681 }
682
683 sd->ParseValue(item, object);
684 }
685}
686
687void IntSettingDesc::ParseValue(const IniItem *item, void *object) const
688{
689 int32_t val = (item != nullptr && item->value.has_value()) ? this->ParseValue(*item->value) : this->GetDefaultValue();
690 this->MakeValueValidAndWrite(object, val);
691}
692
693void StringSettingDesc::ParseValue(const IniItem *item, void *object) const
694{
695 std::string str{(item == nullptr) ? this->def : item->value.value_or("")};
696 this->MakeValueValid(str);
697 this->Write(object, str);
698}
699
700void ListSettingDesc::ParseValue(const IniItem *item, void *object) const
701{
702 std::optional<std::string_view> str;
703 if (item != nullptr) {
704 str = item->value;
705 } else if (!this->def.empty()) {
706 str = this->def;
707 }
708 void *ptr = GetVariableAddress(object, this->save);
709 if (!LoadIntList(str, ptr, this->save.length, this->save.conv.mem)) {
710 _settings_error_list.emplace_back(
711 GetEncodedString(STR_CONFIG_ERROR),
712 GetEncodedString(STR_CONFIG_ERROR_ARRAY, this->GetName()));
713
714 /* Use default */
715 LoadIntList(this->def, ptr, this->save.length, this->save.conv.mem);
716 }
717}
718
731static void IniSaveSettings(IniFile &ini, const SettingTable &settings_table, std::string_view grpname, void *object, bool)
732{
733 IniGroup *group_def = nullptr, *group;
734
735 for (auto &desc : settings_table) {
736 const SettingDesc *sd = GetSettingDesc(desc);
737 /* If the setting is not saved to the configuration
738 * file, just continue with the next setting */
740 if (sd->flags.Test(SettingFlag::NotInConfig)) continue;
741
742 /* XXX - wtf is this?? (group override?) */
743 std::string s{ sd->GetName() };
744 auto sc = s.find('.');
745 if (sc != std::string::npos) {
746 group = &ini.GetOrCreateGroup(s.substr(0, sc));
747 s = s.substr(sc + 1);
748 } else {
749 if (group_def == nullptr) group_def = &ini.GetOrCreateGroup(grpname);
750 group = group_def;
751 }
752
753 IniItem &item = group->GetOrCreateItem(s);
754
755 if (!item.value.has_value() || !sd->IsSameValue(&item, object)) {
756 /* The value is different, that means we have to write it to the ini */
757 item.value.emplace(sd->FormatValue(object));
758 }
759 }
760}
761
762std::string IntSettingDesc::FormatValue(const void *object) const
763{
764 int64_t i;
765 if (IsSignedVarMemType(this->save.conv)) {
766 i = this->Read(object);
767 } else {
768 i = (uint32_t)this->Read(object);
769 }
770 return fmt::format("{}", i);
771}
772
773std::string BoolSettingDesc::FormatValue(const void *object) const
774{
775 bool val = this->Read(object) != 0;
776 return val ? "true" : "false";
777}
778
779bool IntSettingDesc::IsSameValue(const IniItem *item, void *object) const
780{
781 int32_t item_value = static_cast<int32_t>(this->ParseValue(*item->value));
782 int32_t object_value = this->Read(object);
783 return item_value == object_value;
784}
785
786bool IntSettingDesc::IsDefaultValue(void *object) const
787{
788 int32_t object_value = this->Read(object);
789 return this->GetDefaultValue() == object_value;
790}
791
792void IntSettingDesc::ResetToDefault(void *object) const
793{
794 this->Write(object, this->GetDefaultValue());
795}
796
797std::string StringSettingDesc::FormatValue(const void *object) const
798{
799 const std::string &str = this->Read(object);
800 switch (this->save.conv.mem) {
801 case VarMemType::Str: return str;
802
803 case VarMemType::StrQ:
804 if (str.empty()) {
805 return str;
806 }
807 return fmt::format("\"{}\"", str);
808
809 default: NOT_REACHED();
810 }
811}
812
813bool StringSettingDesc::IsSameValue(const IniItem *item, void *object) const
814{
815 /* The ini parsing removes the quotes, which are needed to retain the spaces in STRQs,
816 * so those values are always different in the parsed ini item than they should be. */
817 if (this->save.conv.mem == VarMemType::StrQ) return false;
818
819 const std::string &str = this->Read(object);
820 return item->value->compare(str) == 0;
821}
822
823bool StringSettingDesc::IsDefaultValue(void *object) const
824{
825 const std::string &str = this->Read(object);
826 return this->def == str;
827}
828
829void StringSettingDesc::ResetToDefault(void *object) const
830{
831 this->Write(object, this->def);
832}
833
834bool ListSettingDesc::IsSameValue(const IniItem *, void *) const
835{
836 /* Checking for equality is way more expensive than just writing the value. */
837 return false;
838}
839
841{
842 /* Defaults of lists are often complicated, and hard to compare. */
843 return false;
844}
845
847{
848 /* Resetting a list to default is not supported. */
849 NOT_REACHED();
850}
851
861static void IniLoadSettingList(IniFile &ini, std::string_view grpname, StringList &list)
862{
863 const IniGroup *group = ini.GetGroup(grpname);
864
865 if (group == nullptr) return;
866
867 list.clear();
868
869 for (const IniItem &item : group->items) {
870 if (!item.name.empty()) list.push_back(item.name);
871 }
872}
873
883static void IniSaveSettingList(IniFile &ini, std::string_view grpname, StringList &list)
884{
885 IniGroup &group = ini.GetOrCreateGroup(grpname);
886 group.Clear();
887
888 for (const auto &iter : list) {
889 group.GetOrCreateItem(iter).SetValue("");
890 }
891}
892
899void IniLoadWindowSettings(IniFile &ini, std::string_view grpname, WindowDesc *desc)
900{
901 IniLoadSettings(ini, _window_settings, grpname, desc, false);
902}
903
910void IniSaveWindowSettings(IniFile &ini, std::string_view grpname, WindowDesc *desc)
911{
912 IniSaveSettings(ini, _window_settings, grpname, desc, false);
913}
914
920bool SettingDesc::IsEditable(bool do_command) const
921{
922 if (!do_command && !this->flags.Test(SettingFlag::NoNetworkSync) && _networking && !_network_server && !this->flags.Test(SettingFlag::PerCompany)) return false;
923 if (do_command && this->flags.Test(SettingFlag::NoNetworkSync)) return false;
924 if (this->flags.Test(SettingFlag::NetworkOnly) && !_networking && _game_mode != GameMode::Menu) return false;
925 if (this->flags.Test(SettingFlag::NoNetwork) && _networking) return false;
926 if (this->flags.Test(SettingFlag::NewgameOnly) &&
927 (_game_mode == GameMode::Normal ||
928 (_game_mode == GameMode::Editor && !this->flags.Test(SettingFlag::SceneditToo)))) return false;
929 if (this->flags.Test(SettingFlag::SceneditOnly) && _game_mode != GameMode::Editor) return false;
930 return true;
931}
932
938{
939 if (this->flags.Test(SettingFlag::PerCompany)) return ST_COMPANY;
940 return this->flags.Test(SettingFlag::NotInSave) ? ST_CLIENT : ST_GAME;
941}
942
948{
949 assert(this->IsIntSetting());
950 return static_cast<const IntSettingDesc *>(this);
951}
952
958{
959 assert(this->IsStringSetting());
960 return static_cast<const StringSettingDesc *>(this);
961}
962
964void HandleOldDiffCustom(bool savegame);
965
966
968static void ValidateSettings()
969{
970 /* Do not allow a custom sea level with the original land generator. */
971 if (_settings_newgame.game_creation.land_generator == LG_ORIGINAL &&
972 _settings_newgame.difficulty.quantity_sea_lakes == CUSTOM_SEA_LEVEL_NUMBER_DIFFICULTY) {
973 _settings_newgame.difficulty.quantity_sea_lakes = CUSTOM_SEA_LEVEL_MIN_PERCENTAGE;
974 }
975}
976
977static void AILoadConfig(const IniFile &ini, std::string_view grpname)
978{
979 const IniGroup *group = ini.GetGroup(grpname);
980
981 /* Clean any configured AI */
982 for (CompanyID c = CompanyID::Begin(); c < MAX_COMPANIES; ++c) {
984 }
985
986 /* If no group exists, return */
987 if (group == nullptr) return;
988
989 CompanyID c = CompanyID::Begin();
990 for (const IniItem &item : group->items) {
992
993 config->Change(item.name);
994 if (!config->HasScript()) {
995 if (item.name != "none") {
996 Debug(script, 0, "The AI by the name '{}' was no longer found, and removed from the list.", item.name);
997 continue;
998 }
999 }
1000 if (item.value.has_value()) config->StringToSettings(*item.value);
1001 ++c;
1002 if (c >= MAX_COMPANIES) break;
1003 }
1004}
1005
1006static void GameLoadConfig(const IniFile &ini, std::string_view grpname)
1007{
1008 const IniGroup *group = ini.GetGroup(grpname);
1009
1010 /* Clean any configured GameScript */
1012
1013 /* If no group exists, return */
1014 if (group == nullptr || group->items.empty()) return;
1015
1016 const IniItem &item = group->items.front();
1017
1019
1020 config->Change(item.name);
1021 if (!config->HasScript()) {
1022 if (item.name != "none") {
1023 Debug(script, 0, "The GameScript by the name '{}' was no longer found, and removed from the list.", item.name);
1024 return;
1025 }
1026 }
1027 if (item.value.has_value()) config->StringToSettings(*item.value);
1028}
1029
1035{
1036 if (const IniGroup *group = ini.GetGroup("misc"); group != nullptr) {
1037 /* Load old setting first. */
1038 if (const IniItem *item = group->GetItem("graphicsset"); item != nullptr && item->value) BaseGraphics::ini_data.name = *item->value;
1039 }
1040
1041 if (const IniGroup *group = ini.GetGroup("graphicsset"); group != nullptr) {
1042 /* Load new settings. */
1043 if (const IniItem *item = group->GetItem("name"); item != nullptr && item->value) BaseGraphics::ini_data.name = *item->value;
1044
1045 if (const IniItem *item = group->GetItem("shortname"); item != nullptr && item->value && item->value->size() == 8) {
1046 auto val = ParseInteger<uint32_t>(*item->value, 16);
1047 if (val.has_value()) {
1048 BaseGraphics::ini_data.shortname = std::byteswap<uint32_t>(*val);
1049 } else {
1050 ShowErrorMessage(GetEncodedString(STR_CONFIG_ERROR),
1051 GetEncodedString(STR_CONFIG_ERROR_INVALID_VALUE, *item->value, BaseGraphics::ini_data.name),
1053 }
1054 }
1055
1056 if (const IniItem *item = group->GetItem("extra_version"); item != nullptr && item->value) {
1057 auto val = ParseInteger<uint32_t>(*item->value);
1058 if (val.has_value()) {
1059 BaseGraphics::ini_data.extra_version = *val;
1060 } else {
1061 ShowErrorMessage(GetEncodedString(STR_CONFIG_ERROR),
1062 GetEncodedString(STR_CONFIG_ERROR_INVALID_VALUE, *item->value, BaseGraphics::ini_data.name),
1064 }
1065 }
1066
1067 if (const IniItem *item = group->GetItem("extra_params"); item != nullptr && item->value) {
1068 auto params = ParseIntList(*item->value);
1069 if (params.has_value()) {
1070 BaseGraphics::ini_data.extra_params = params.value();
1071 } else {
1072 ShowErrorMessage(GetEncodedString(STR_CONFIG_ERROR),
1073 GetEncodedString(STR_CONFIG_ERROR_ARRAY, BaseGraphics::ini_data.name),
1075 }
1076 }
1077 }
1078}
1079
1087static GRFConfigList GRFLoadConfig(const IniFile &ini, std::string_view grpname, bool is_static)
1088{
1089 const IniGroup *group = ini.GetGroup(grpname);
1090 GRFConfigList list;
1091
1092 if (group == nullptr) return list;
1093
1094 uint num_grfs = 0;
1095 for (const IniItem &item : group->items) {
1096 std::unique_ptr<GRFConfig> c{};
1097
1098 std::array<uint8_t, 4> grfid_buf;
1099 MD5Hash md5sum;
1100 std::string_view item_name = item.name;
1101 bool has_md5sum = false;
1102
1103 /* Try reading "<grfid>|" and on success, "<md5sum>|". */
1104 auto grfid_pos = item_name.find("|");
1105 if (grfid_pos != std::string_view::npos) {
1106 std::string_view grfid_str = item_name.substr(0, grfid_pos);
1107
1108 if (ConvertHexToBytes(grfid_str, grfid_buf)) {
1109 item_name = item_name.substr(grfid_pos + 1);
1110
1111 auto md5sum_pos = item_name.find("|");
1112 if (md5sum_pos != std::string_view::npos) {
1113 std::string_view md5sum_str = item_name.substr(0, md5sum_pos);
1114
1115 has_md5sum = ConvertHexToBytes(md5sum_str, md5sum);
1116 if (has_md5sum) item_name = item_name.substr(md5sum_pos + 1);
1117 }
1118
1119 GrfID grfid = grfid_buf[0] | (grfid_buf[1] << 8) | (grfid_buf[2] << 16) | (grfid_buf[3] << 24);
1120 if (has_md5sum) {
1121 const GRFConfig *s = FindGRFConfig(grfid, FindGRFConfigMode::Exact, &md5sum);
1122 if (s != nullptr) c = std::make_unique<GRFConfig>(*s);
1123 }
1124 if (c == nullptr && !FioCheckFileExists(std::string(item_name), Subdirectory::NewGrf)) {
1126 if (s != nullptr) c = std::make_unique<GRFConfig>(*s);
1127 }
1128 }
1129 }
1130 std::string filename = std::string(item_name);
1131
1132 if (c == nullptr) c = std::make_unique<GRFConfig>(filename);
1133
1134 /* Parse parameters */
1135 if (item.value.has_value() && !item.value->empty()) {
1136 auto params = ParseIntList(*item.value);
1137 if (params.has_value()) {
1138 c->SetParams(params.value());
1139 } else {
1140 ShowErrorMessage(GetEncodedString(STR_CONFIG_ERROR),
1141 GetEncodedString(STR_CONFIG_ERROR_ARRAY, filename),
1143 }
1144 }
1145
1146 /* Check if item is valid */
1147 if (!FillGRFDetails(*c, is_static) || c->flags.Test(GRFConfigFlag::Invalid)) {
1148 StringID reason;
1149 if (c->status == GRFStatus::NotFound) {
1150 reason = STR_CONFIG_ERROR_INVALID_GRF_NOT_FOUND;
1151 } else if (c->flags.Test(GRFConfigFlag::Unsafe)) {
1152 reason = STR_CONFIG_ERROR_INVALID_GRF_UNSAFE;
1153 } else if (c->flags.Test(GRFConfigFlag::System)) {
1154 reason = STR_CONFIG_ERROR_INVALID_GRF_SYSTEM;
1155 } else if (c->flags.Test(GRFConfigFlag::Invalid)) {
1156 reason = STR_CONFIG_ERROR_INVALID_GRF_INCOMPATIBLE;
1157 } else {
1158 reason = STR_CONFIG_ERROR_INVALID_GRF_UNKNOWN;
1159 }
1160
1161 ShowErrorMessage(GetEncodedString(STR_CONFIG_ERROR),
1162 GetEncodedString(STR_CONFIG_ERROR_INVALID_GRF, filename.empty() ? item.name : filename, reason),
1164 continue;
1165 }
1166
1167 /* Check for duplicate GRFID (will also check for duplicate filenames) */
1168 auto found = std::ranges::find_if(list, [&c](const auto &gc) { return gc->ident.grfid == c->ident.grfid; });
1169 if (found != std::end(list)) {
1170 ShowErrorMessage(GetEncodedString(STR_CONFIG_ERROR),
1171 GetEncodedString(STR_CONFIG_ERROR_DUPLICATE_GRFID, c->filename, (*found)->filename),
1173 continue;
1174 }
1175
1176 if (is_static) {
1177 /* Mark file as static to avoid saving in savegame. */
1178 c->flags.Set(GRFConfigFlag::Static);
1179 } else if (++num_grfs > NETWORK_MAX_GRF_COUNT) {
1180 /* Check we will not load more non-static NewGRFs than allowed. This could trigger issues for game servers. */
1181 ShowErrorMessage(GetEncodedString(STR_CONFIG_ERROR),
1182 GetEncodedString(STR_NEWGRF_ERROR_TOO_MANY_NEWGRFS_LOADED), WarningLevel::Critical);
1183 break;
1184 }
1185
1186 /* Add item to list */
1187 list.push_back(std::move(c));
1188 }
1189
1190 return list;
1191}
1192
1193static IniFileVersion LoadVersionFromConfig(const IniFile &ini)
1194{
1195 const IniGroup *group = ini.GetGroup("version");
1196 if (group == nullptr) return IFV_0;
1197
1198 auto version_number = group->GetItem("ini_version");
1199 /* Older ini-file versions don't have this key yet. */
1200 if (version_number == nullptr || !version_number->value.has_value()) return IFV_0;
1201
1202 uint32_t version = 0;
1203 std::from_chars(version_number->value->data(), version_number->value->data() + version_number->value->size(), version);
1204
1205 return static_cast<IniFileVersion>(version);
1206}
1207
1208static void AISaveConfig(IniFile &ini, std::string_view grpname)
1209{
1210 IniGroup &group = ini.GetOrCreateGroup(grpname);
1211 group.Clear();
1212
1213 for (CompanyID c = CompanyID::Begin(); c < MAX_COMPANIES; ++c) {
1215 std::string name;
1216 std::string value = config->SettingsToString();
1217
1218 if (config->HasScript()) {
1219 name = config->GetName();
1220 } else {
1221 name = "none";
1222 }
1223
1224 group.CreateItem(name).SetValue(value);
1225 }
1226}
1227
1228static void GameSaveConfig(IniFile &ini, std::string_view grpname)
1229{
1230 IniGroup &group = ini.GetOrCreateGroup(grpname);
1231 group.Clear();
1232
1234 std::string name;
1235 std::string value = config->SettingsToString();
1236
1237 if (config->HasScript()) {
1238 name = config->GetName();
1239 } else {
1240 name = "none";
1241 }
1242
1243 group.CreateItem(name).SetValue(value);
1244}
1245
1251{
1252 IniGroup &group = ini.GetOrCreateGroup("version");
1253 group.GetOrCreateItem("version_string").SetValue(_openttd_revision);
1254 group.GetOrCreateItem("version_number").SetValue(fmt::format("{:08X}", _openttd_newgrf_version));
1255 group.GetOrCreateItem("ini_version").SetValue(fmt::format("{}", INIFILE_VERSION));
1256}
1257
1263{
1264 const GraphicsSet *used_set = BaseGraphics::GetUsedSet();
1265 if (used_set == nullptr) return;
1266
1267 IniGroup &group = ini.GetOrCreateGroup("graphicsset");
1268 group.Clear();
1269
1270 group.GetOrCreateItem("name").SetValue(used_set->name);
1271 group.GetOrCreateItem("shortname").SetValue(fmt::format("{:08X}", std::byteswap(used_set->shortname)));
1272
1273 const GRFConfig *extra_cfg = used_set->GetExtraConfig();
1274 if (extra_cfg != nullptr && !extra_cfg->param.empty()) {
1275 group.GetOrCreateItem("extra_version").SetValue(fmt::format("{}", extra_cfg->version));
1276 group.GetOrCreateItem("extra_params").SetValue(GRFBuildParamList(*extra_cfg));
1277 }
1278}
1279
1280/* Save a GRF configuration to the given group name */
1281static void GRFSaveConfig(IniFile &ini, std::string_view grpname, const GRFConfigList &list)
1282{
1283 IniGroup &group = ini.GetOrCreateGroup(grpname);
1284 group.Clear();
1285
1286 for (const auto &c : list) {
1287 std::string key = fmt::format("{:08X}|{}|{}", std::byteswap(c->ident.grfid),
1288 FormatArrayAsHex(c->ident.md5sum), c->filename);
1290 }
1291}
1292
1293/* Common handler for saving/loading variables to the configuration file */
1294static void HandleSettingDescs(IniFile &generic_ini, IniFile &private_ini, IniFile &secrets_ini, SettingDescProc *proc, SettingDescProcList *proc_list, bool only_startup = false)
1295{
1296 proc(generic_ini, _misc_settings, "misc", nullptr, only_startup);
1297#if defined(_WIN32) && !defined(DEDICATED)
1298 proc(generic_ini, _win32_settings, "win32", nullptr, only_startup);
1299#endif /* _WIN32 */
1300
1301 /* The name "patches" is a fallback, as every setting should sets its own group. */
1302
1303 for (auto &table : GenericSettingTables()) {
1304 proc(generic_ini, table, "patches", &_settings_newgame, only_startup);
1305 }
1306 for (auto &table : PrivateSettingTables()) {
1307 proc(private_ini, table, "patches", &_settings_newgame, only_startup);
1308 }
1309 for (auto &table : SecretSettingTables()) {
1310 proc(secrets_ini, table, "patches", &_settings_newgame, only_startup);
1311 }
1312
1313 proc(generic_ini, _currency_settings, "currency", &GetCustomCurrency(), only_startup);
1314 proc(generic_ini, _company_settings, "company", &_settings_client.company, only_startup);
1315
1316 if (!only_startup) {
1317 proc_list(private_ini, "server_bind_addresses", _network_bind_list);
1318 proc_list(private_ini, "servers", _network_host_list);
1319 proc_list(private_ini, "bans", _network_ban_list);
1320 proc_list(private_ini, "server_authorized_keys", _settings_client.network.server_authorized_keys);
1321 proc_list(private_ini, "rcon_authorized_keys", _settings_client.network.rcon_authorized_keys);
1322 proc_list(private_ini, "admin_authorized_keys", _settings_client.network.admin_authorized_keys);
1323 }
1324}
1325
1335static void RemoveEntriesFromIni(IniFile &ini, const SettingTable &table)
1336{
1337 for (auto &desc : table) {
1338 const SettingDesc *sd = GetSettingDesc(desc);
1339
1340 /* For settings.xx.yy load the settings from [xx] yy = ? */
1341 std::string s{ sd->GetName() };
1342 auto sc = s.find('.');
1343 if (sc == std::string::npos) continue;
1344
1345 IniGroup *group = ini.GetGroup(s.substr(0, sc));
1346 if (group == nullptr) continue;
1347 s = s.substr(sc + 1);
1348
1349 group->RemoveItem(s);
1350 }
1351}
1352
1376bool IsConversionNeeded(const ConfigIniFile &ini, const std::string &group, const std::string &old_var, const std::string &new_var, const IniItem **old_item)
1377{
1378 *old_item = nullptr;
1379
1380 const IniGroup *igroup = ini.GetGroup(group);
1381 /* If the group doesn't exist, there is nothing to convert. */
1382 if (igroup == nullptr) return false;
1383
1384 const IniItem *tmp_old_item = igroup->GetItem(old_var);
1385 const IniItem *new_item = igroup->GetItem(new_var);
1386
1387 /* If the old item doesn't exist, there is nothing to convert. */
1388 if (tmp_old_item == nullptr) return false;
1389
1390 /* If the new item exists, it means conversion was already done. We only
1391 * do the conversion the first time, and after that these settings are
1392 * independent. This allows users to freely change between older and
1393 * newer clients without breaking anything. */
1394 if (new_item != nullptr) return false;
1395
1396 *old_item = tmp_old_item;
1397 return true;
1398}
1399
1404void LoadFromConfig(bool startup)
1405{
1406 ConfigIniFile generic_ini(_config_file);
1407 ConfigIniFile private_ini(_private_file);
1408 ConfigIniFile secrets_ini(_secrets_file);
1409 ConfigIniFile favs_ini(_favs_file);
1410
1411 if (!startup) ResetCurrencies(false); // Initialize the array of currencies, without preserving the custom one
1412
1413 IniFileVersion generic_version = LoadVersionFromConfig(generic_ini);
1414
1415 if (startup) {
1416 GraphicsSetLoadConfig(generic_ini);
1417 }
1418
1419 /* Before the split of private/secrets, we have to look in the generic for these settings. */
1420 if (generic_version < IFV_PRIVATE_SECRETS) {
1421 HandleSettingDescs(generic_ini, generic_ini, generic_ini, IniLoadSettings, IniLoadSettingList, startup);
1422 } else {
1423 HandleSettingDescs(generic_ini, private_ini, secrets_ini, IniLoadSettings, IniLoadSettingList, startup);
1424 }
1425
1426 /* Load basic settings only during bootstrap, load other settings not during bootstrap */
1427 if (!startup) {
1428 if (generic_version < IFV_LINKGRAPH_SECONDS) {
1429 _settings_newgame.linkgraph.recalc_interval *= CalendarTime::SECONDS_PER_DAY;
1430 _settings_newgame.linkgraph.recalc_time *= CalendarTime::SECONDS_PER_DAY;
1431 }
1432
1433 /* Move use_relay_service from generic_ini to private_ini. */
1434 if (generic_version < IFV_NETWORK_PRIVATE_SETTINGS) {
1435 const IniGroup *network = generic_ini.GetGroup("network");
1436 if (network != nullptr) {
1437 const IniItem *use_relay_service = network->GetItem("use_relay_service");
1438 if (use_relay_service != nullptr) {
1439 if (use_relay_service->value == "never") {
1440 _settings_client.network.use_relay_service = UseRelayService::Never;
1441 } else if (use_relay_service->value == "ask") {
1442 _settings_client.network.use_relay_service = UseRelayService::Ask;
1443 } else if (use_relay_service->value == "allow") {
1444 _settings_client.network.use_relay_service = UseRelayService::Allow;
1445 }
1446 }
1447 }
1448 }
1449
1450 const IniItem *old_item;
1451
1452 if (generic_version < IFV_GAME_TYPE && IsConversionNeeded(generic_ini, "network", "server_advertise", "server_game_type", &old_item)) {
1453 auto old_value = BoolSettingDesc::ParseSingleValue(*old_item->value);
1454 _settings_client.network.server_game_type = old_value.value_or(false) ? ServerGameType::Public : ServerGameType::Local;
1455 }
1456
1457 if (generic_version < IFV_AUTOSAVE_RENAME && IsConversionNeeded(generic_ini, "gui", "autosave", "autosave_interval", &old_item)) {
1458 static constexpr std::initializer_list<std::string_view> _old_autosave_interval{"off"sv, "monthly"sv, "quarterly"sv, "half year"sv, "yearly"sv};
1459 auto old_value = OneOfManySettingDesc::ParseSingleValue(*old_item->value, _old_autosave_interval).value_or(-1);
1460
1461 switch (old_value) {
1462 case 0: _settings_client.gui.autosave_interval = 0; break;
1463 case 1: _settings_client.gui.autosave_interval = 10; break;
1464 case 2: _settings_client.gui.autosave_interval = 30; break;
1465 case 3: _settings_client.gui.autosave_interval = 60; break;
1466 case 4: _settings_client.gui.autosave_interval = 120; break;
1467 default: break;
1468 }
1469 }
1470
1471 /* Persist the right click close option from older versions. */
1472 if (generic_version < IFV_RIGHT_CLICK_CLOSE && IsConversionNeeded(generic_ini, "gui", "right_mouse_wnd_close", "right_click_wnd_close", &old_item)) {
1473 auto old_value = BoolSettingDesc::ParseSingleValue(*old_item->value);
1474 _settings_client.gui.right_click_wnd_close = old_value.value_or(false) ? RightClickClose::Yes : RightClickClose::No;
1475 }
1476
1477 if (generic_version < IFV_DEFAULT_RAIL_ROAD && IsConversionNeeded(generic_ini, "gui", "default_rail_type", "default_rail_road_type", &old_item)) {
1478 auto old_value = IntSettingDesc::ParseSingleValue(*old_item->value, 0, 2);
1479 _settings_client.gui.default_rail_road_type = static_cast<DefaultRailRoadType>(old_value.value_or(0));
1480 }
1481
1482 _grfconfig_newgame = GRFLoadConfig(generic_ini, "newgrf", false);
1483 _grfconfig_static = GRFLoadConfig(generic_ini, "newgrf-static", true);
1484 AILoadConfig(generic_ini, "ai_players");
1485 GameLoadConfig(generic_ini, "game_scripts");
1486 PickerLoadConfig(favs_ini);
1487 BadgeClassLoadConfig(favs_ini);
1488
1490 IniLoadSettings(generic_ini, _old_gameopt_settings, "gameopt", &_settings_newgame, false);
1491 HandleOldDiffCustom(false);
1492
1495
1496 /* Display scheduled errors */
1498 if (FindWindowById(WindowClass::ErrorMessage, 0) == nullptr) ShowFirstError();
1499 }
1500}
1501
1504{
1505 ConfigIniFile generic_ini(_config_file);
1506 ConfigIniFile private_ini(_private_file);
1507 ConfigIniFile secrets_ini(_secrets_file);
1508 ConfigIniFile favs_ini(_favs_file);
1509
1510 IniFileVersion generic_version = LoadVersionFromConfig(generic_ini);
1511
1512 /* If we newly create the private/secrets file, add a dummy group on top
1513 * just so we can add a comment before it (that is how IniFile works).
1514 * This to explain what the file is about. After doing it once, never touch
1515 * it again, as otherwise we might be reverting user changes. */
1516 if (IniGroup *group = private_ini.GetGroup("private"); group != nullptr) group->comment = "; This file possibly contains private information which can identify you as person.\n";
1517 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";
1518
1519 if (generic_version == IFV_0) {
1520 /* Remove some obsolete groups. These have all been loaded into other groups. */
1521 generic_ini.RemoveGroup("patches");
1522 generic_ini.RemoveGroup("yapf");
1523 generic_ini.RemoveGroup("gameopt");
1524
1525 /* Remove all settings from the generic ini that are now in the private ini. */
1526 generic_ini.RemoveGroup("server_bind_addresses");
1527 generic_ini.RemoveGroup("servers");
1528 generic_ini.RemoveGroup("bans");
1529 for (auto &table : PrivateSettingTables()) {
1530 RemoveEntriesFromIni(generic_ini, table);
1531 }
1532
1533 /* Remove all settings from the generic ini that are now in the secrets ini. */
1534 for (auto &table : SecretSettingTables()) {
1535 RemoveEntriesFromIni(generic_ini, table);
1536 }
1537 }
1538
1539 if (generic_version < IFV_REMOVE_GENERATION_SEED) {
1540 IniGroup *game_creation = generic_ini.GetGroup("game_creation");
1541 if (game_creation != nullptr) {
1542 game_creation->RemoveItem("generation_seed");
1543 }
1544 }
1545
1546 /* These variables are migrated from generic ini to private ini now. */
1547 if (generic_version < IFV_NETWORK_PRIVATE_SETTINGS) {
1548 IniGroup *network = generic_ini.GetGroup("network");
1549 if (network != nullptr) {
1550 network->RemoveItem("use_relay_service");
1551 }
1552 }
1553
1554 HandleSettingDescs(generic_ini, private_ini, secrets_ini, IniSaveSettings, IniSaveSettingList);
1555 GraphicsSetSaveConfig(generic_ini);
1556 GRFSaveConfig(generic_ini, "newgrf", _grfconfig_newgame);
1557 GRFSaveConfig(generic_ini, "newgrf-static", _grfconfig_static);
1558 AISaveConfig(generic_ini, "ai_players");
1559 GameSaveConfig(generic_ini, "game_scripts");
1560 PickerSaveConfig(favs_ini);
1561 BadgeClassSaveConfig(favs_ini);
1562
1563 SaveVersionInConfig(generic_ini);
1564 SaveVersionInConfig(private_ini);
1565 SaveVersionInConfig(secrets_ini);
1566 SaveVersionInConfig(favs_ini);
1567
1568 generic_ini.SaveToDisk(_config_file);
1569 private_ini.SaveToDisk(_private_file);
1570 secrets_ini.SaveToDisk(_secrets_file);
1571 favs_ini.SaveToDisk(_favs_file);
1572}
1573
1579{
1580 StringList list;
1581
1583 for (const IniGroup &group : ini.groups) {
1584 if (group.name.starts_with("preset-")) {
1585 list.push_back(group.name.substr(7));
1586 }
1587 }
1588
1589 return list;
1590}
1591
1598GRFConfigList LoadGRFPresetFromConfig(std::string_view config_name)
1599{
1600 std::string section("preset-");
1601 section += config_name;
1602
1604 GRFConfigList config = GRFLoadConfig(ini, section, false);
1605
1606 return config;
1607}
1608
1615void SaveGRFPresetToConfig(std::string_view config_name, GRFConfigList &config)
1616{
1617 std::string section("preset-");
1618 section += config_name;
1619
1621 GRFSaveConfig(ini, section, config);
1623}
1624
1629void DeleteGRFPresetFromConfig(std::string_view config_name)
1630{
1631 std::string section("preset-");
1632 section += config_name;
1633
1635 ini.RemoveGroup(section);
1637}
1638
1645void IntSettingDesc::ChangeValue(const void *object, int32_t newval) const
1646{
1647 int32_t oldval = this->Read(object);
1648 this->MakeValueValid(newval);
1649 if (this->pre_check != nullptr && !this->pre_check(newval)) return;
1650 if (oldval == newval) return;
1651
1652 this->Write(object, newval);
1653 if (this->post_callback != nullptr) this->post_callback(newval);
1654
1655 if (this->flags.Test(SettingFlag::NoNetwork) || this->flags.Test(SettingFlag::Sandbox)) {
1657 _gamelog.Setting(this->GetName(), oldval, newval);
1658 _gamelog.StopAction();
1659 }
1660
1661 SetWindowClassesDirty(WindowClass::GameOptions);
1662 if (this->flags.Test(SettingFlag::Sandbox)) SetWindowClassesDirty(WindowClass::Cheat);
1663
1664 if (_save_config) SaveToConfig();
1665}
1666
1674static const SettingDesc *GetSettingFromName(std::string_view name, const SettingTable &settings)
1675{
1676 /* First check all full names */
1677 for (auto &desc : settings) {
1678 const SettingDesc *sd = GetSettingDesc(desc);
1679 if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue;
1680 if (sd->GetName() == name) return sd;
1681 }
1682
1683 /* Then check the shortcut variant of the name. */
1684 std::string short_name_suffix = std::string{ "." }.append(name);
1685 for (auto &desc : settings) {
1686 const SettingDesc *sd = GetSettingDesc(desc);
1687 if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue;
1688 if (sd->GetName().ends_with(short_name_suffix)) return sd;
1689 }
1690
1691 return nullptr;
1692}
1693
1699void GetSaveLoadFromSettingTable(SettingTable settings, std::vector<SaveLoad> &saveloads)
1700{
1701 for (auto &desc : settings) {
1702 const SettingDesc *sd = GetSettingDesc(desc);
1703 if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue;
1704 saveloads.push_back(sd->save);
1705 }
1706}
1707
1714{
1715 static const SettingTable saveload_settings_tables[] = {
1716 _difficulty_settings,
1717 _economy_settings,
1718 _game_settings,
1719 _linkgraph_settings,
1720 _locale_settings,
1721 _pathfinding_settings,
1722 _script_settings,
1723 _world_settings,
1724 };
1725 static std::vector<SettingVariant> settings_table;
1726
1727 if (settings_table.empty()) {
1728 for (auto &saveload_settings_table : saveload_settings_tables) {
1729 for (auto &saveload_setting : saveload_settings_table) {
1730 settings_table.push_back(saveload_setting);
1731 }
1732 }
1733 }
1734
1735 return settings_table;
1736}
1737
1744static const SettingDesc *GetCompanySettingFromName(std::string_view name)
1745{
1746 static const std::string_view company_prefix = "company.";
1747 if (name.starts_with(company_prefix)) name.remove_prefix(company_prefix.size());
1748 return GetSettingFromName(name, _company_settings);
1749}
1750
1757const SettingDesc *GetSettingFromName(std::string_view name)
1758{
1759 for (auto &table : GenericSettingTables()) {
1760 auto sd = GetSettingFromName(name, table);
1761 if (sd != nullptr) return sd;
1762 }
1763 for (auto &table : PrivateSettingTables()) {
1764 auto sd = GetSettingFromName(name, table);
1765 if (sd != nullptr) return sd;
1766 }
1767 for (auto &table : SecretSettingTables()) {
1768 auto sd = GetSettingFromName(name, table);
1769 if (sd != nullptr) return sd;
1770 }
1771
1772 return GetCompanySettingFromName(name);
1773}
1774
1780std::vector<const SettingDesc *> GetFilteredSettingCollection(std::function<bool(const SettingDesc &desc)> func)
1781{
1782 std::vector<const SettingDesc *> collection;
1783
1784 for (const auto &table : GenericSettingTables()) {
1785 for (const auto &desc : table) {
1786 const auto sd = GetSettingDesc(desc);
1787 if (!func(*sd)) continue;
1788
1789 collection.push_back(sd);
1790 }
1791 }
1792
1793 return collection;
1794}
1795
1805CommandCost CmdChangeSetting(DoCommandFlags flags, const std::string &name, int32_t value)
1806{
1807 if (name.empty()) return CMD_ERROR;
1808 const SettingDesc *sd = GetSettingFromName(name);
1809
1810 if (sd == nullptr) return CMD_ERROR;
1812 if (!sd->IsIntSetting()) return CMD_ERROR;
1813
1814 if (!sd->IsEditable(true)) return CMD_ERROR;
1815
1816 if (flags.Test(DoCommandFlag::Execute)) {
1817 sd->AsIntSetting()->ChangeValue(&GetGameSettings(), value);
1818 }
1819
1820 return CommandCost();
1821}
1822
1831CommandCost CmdChangeCompanySetting(DoCommandFlags flags, const std::string &name, int32_t value)
1832{
1833 if (name.empty()) return CMD_ERROR;
1834 const SettingDesc *sd = GetCompanySettingFromName(name);
1835
1836 if (sd == nullptr) return CMD_ERROR;
1837 if (!sd->IsIntSetting()) return CMD_ERROR;
1838
1839 if (flags.Test(DoCommandFlag::Execute)) {
1841 }
1842
1843 return CommandCost();
1844}
1845
1853bool SetSettingValue(const IntSettingDesc *sd, int32_t value, bool force_newgame)
1854{
1855 const IntSettingDesc *setting = sd->AsIntSetting();
1856 if (setting->flags.Test(SettingFlag::PerCompany)) {
1857 if (Company::IsValidID(_local_company) && _game_mode != GameMode::Menu) {
1858 return Command<Commands::ChangeCompanySetting>::Post(setting->GetName(), value);
1859 }
1860
1861 setting->ChangeValue(&_settings_client.company, value);
1862 return true;
1863 }
1864
1865 /* If an item is company-based, we do not send it over the network
1866 * (if any) to change. Also *hack*hack* we update the _newgame version
1867 * of settings because changing a company-based setting in a game also
1868 * changes its defaults. At least that is the convention we have chosen */
1869 if (setting->flags.Test(SettingFlag::NoNetworkSync)) {
1870 if (_game_mode != GameMode::Menu) {
1871 setting->ChangeValue(&_settings_newgame, value);
1872 }
1873 setting->ChangeValue(&GetGameSettings(), value);
1874 return true;
1875 }
1876
1877 if (force_newgame) {
1878 setting->ChangeValue(&_settings_newgame, value);
1879 return true;
1880 }
1881
1882 /* send non-company-based settings over the network */
1884 return Command<Commands::ChangeSetting>::Post(setting->GetName(), value);
1885 }
1886 return false;
1887}
1888
1893void SetDefaultCompanySettings(CompanyID cid)
1894{
1895 Company *c = Company::Get(cid);
1897 for (auto &desc : _company_settings) {
1898 const IntSettingDesc *int_setting = GetSettingDesc(desc)->AsIntSetting();
1899 int_setting->MakeValueValidAndWrite(&c->settings, int_setting->GetDefaultValue());
1900 }
1901}
1902
1907{
1908 const void *old_object = &Company::Get(_current_company)->settings;
1909 const void *new_object = &_settings_client.company;
1910 for (auto &desc : _company_settings) {
1911 const SettingDesc *sd = GetSettingDesc(desc);
1912 uint32_t old_value = (uint32_t)sd->AsIntSetting()->Read(old_object);
1913 uint32_t new_value = (uint32_t)sd->AsIntSetting()->Read(new_object);
1914 /*
1915 * This is called from a command, and since it contains local configuration information
1916 * that the rest of the clients do not know about, we need to circumvent the normal ::Post
1917 * local command validation and immediately send the command to the server.
1918 */
1919 if (old_value != new_value) Command<Commands::ChangeCompanySetting>::SendNet(STR_NULL, _local_company, sd->GetName(), new_value);
1920 }
1921}
1922
1931bool SetSettingValue(const StringSettingDesc *sd, std::string_view value, bool force_newgame)
1932{
1934
1935 if (sd->save.conv.mem == VarMemType::StrQ && value == "(null)") {
1936 value = {};
1937 }
1938
1939 const void *object = (_game_mode == GameMode::Menu || force_newgame) ? &_settings_newgame : &_settings_game;
1940 sd->AsStringSetting()->ChangeValue(object, std::string{value});
1941 return true;
1942}
1943
1950void StringSettingDesc::ChangeValue(const void *object, std::string &&newval) const
1951{
1952 this->MakeValueValid(newval);
1953 if (this->pre_check != nullptr && !this->pre_check(newval)) return;
1954
1955 this->Write(object, newval);
1956 if (this->post_callback != nullptr) this->post_callback(newval);
1957
1958 if (_save_config) SaveToConfig();
1959}
1960
1961/* Those 2 functions need to be here, else we have to make some stuff non-static
1962 * and besides, it is also better to keep stuff like this at the same place */
1963void IConsoleSetSetting(std::string_view name, std::string_view value, bool force_newgame)
1964{
1965 const SettingDesc *sd = GetSettingFromName(name);
1966 /* Company settings are not in "list_settings", so don't try to modify them. */
1967 if (sd == nullptr || sd->flags.Test(SettingFlag::PerCompany)) {
1968 IConsolePrint(CC_ERROR, "'{}' is an unknown setting.", name);
1969 return;
1970 }
1971
1972 bool success = true;
1973 if (sd->IsStringSetting()) {
1974 success = SetSettingValue(sd->AsStringSetting(), value, force_newgame);
1975 } else if (sd->IsIntSetting()) {
1976 const IntSettingDesc *isd = sd->AsIntSetting();
1977 size_t val = isd->ParseValue(value);
1978 if (!_settings_error_list.empty()) {
1979 IConsolePrint(CC_ERROR, "'{}' is not a valid value for this setting.", value);
1980 _settings_error_list.clear();
1981 return;
1982 }
1983 success = SetSettingValue(isd, (int32_t)val, force_newgame);
1984 }
1985
1986 if (!success) {
1987 if (_network_server) {
1988 IConsolePrint(CC_ERROR, "This command/variable is not available during network games.");
1989 } else {
1990 IConsolePrint(CC_ERROR, "This command/variable is only available to a network server.");
1991 }
1992 }
1993}
1994
1995void IConsoleSetSetting(std::string_view name, int value)
1996{
1997 const SettingDesc *sd = GetSettingFromName(name);
1998 assert(sd != nullptr);
1999 SetSettingValue(sd->AsIntSetting(), value);
2000}
2001
2007void IConsoleGetSetting(std::string_view name, bool force_newgame)
2008{
2009 const SettingDesc *sd = GetSettingFromName(name);
2010 /* Company settings are not in "list_settings", so don't try to read them. */
2011 if (sd == nullptr || sd->flags.Test(SettingFlag::PerCompany)) {
2012 IConsolePrint(CC_ERROR, "'{}' is an unknown setting.", name);
2013 return;
2014 }
2015
2016 const void *object = (_game_mode == GameMode::Menu || force_newgame) ? &_settings_newgame : &_settings_game;
2017
2018 if (sd->IsStringSetting()) {
2019 IConsolePrint(CC_INFO, "Current value for '{}' is '{}'.", sd->GetName(), sd->AsStringSetting()->Read(object));
2020 } else if (sd->IsIntSetting()) {
2021 std::string value = sd->FormatValue(object);
2022 const IntSettingDesc *int_setting = sd->AsIntSetting();
2023 auto [min_val, max_val] = int_setting->GetRange();
2024 auto def_val = int_setting->GetDefaultValue();
2025 IConsolePrint(CC_INFO, "Current value for '{}' is '{}' (min: {}{}, max: {}, def: {}).",
2026 sd->GetName(), value, sd->flags.Test(SettingFlag::GuiZeroIsSpecial) ? "(0) " : "", min_val, max_val, def_val);
2027 }
2028}
2029
2030static void IConsoleListSettingsTable(const SettingTable &table, std::string_view prefilter)
2031{
2032 for (auto &desc : table) {
2033 const SettingDesc *sd = GetSettingDesc(desc);
2034 if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue;
2035 if (!prefilter.empty() && sd->GetName().find(prefilter) == std::string::npos) continue;
2036 IConsolePrint(CC_DEFAULT, "{} = {}", sd->GetName(), sd->FormatValue(&GetGameSettings()));
2037 }
2038}
2039
2045void IConsoleListSettings(std::string_view prefilter)
2046{
2047 IConsolePrint(CC_HELP, "All settings with their current value:");
2048
2049 for (auto &table : GenericSettingTables()) {
2050 IConsoleListSettingsTable(table, prefilter);
2051 }
2052 for (auto &table : PrivateSettingTables()) {
2053 IConsoleListSettingsTable(table, prefilter);
2054 }
2055 for (auto &table : SecretSettingTables()) {
2056 IConsoleListSettingsTable(table, prefilter);
2057 }
2058
2059 IConsolePrint(CC_HELP, "Use 'setting' command to change a value.");
2060}
2061
2062ScriptConfigSettings::ScriptConfigSettings()
2063{
2064 /* Instantiate here, because unique_ptr needs a complete type. */
2065}
2066
2069{
2070 /* Instantiate here, because unique_ptr needs a complete type. */
2071}
2072
2073ScriptConfigSettings::ScriptConfigSettings(const ScriptConfigSettings &other)
2074{
2075 *this = other;
2076}
2077
2078ScriptConfigSettings &ScriptConfigSettings::operator=(const ScriptConfigSettings &other)
2079{
2080 for (CompanyID c = CompanyID::Begin(); c < MAX_COMPANIES; ++c) {
2081 if (other.ai[c] != nullptr) {
2082 this->ai[c] = std::make_unique<AIConfig>(*other.ai[c]);
2083 }
2084 }
2085 if (other.game != nullptr) {
2086 this->game = std::make_unique<GameConfig>(*other.game);
2087 }
2088 return *this;
2089}
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:145
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
EnumBitSet< DoCommandFlag, uint16_t > DoCommandFlags
Bitset of DoCommandFlag elements.
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(ExtendedTextColour 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 newg...
Definition currency.cpp:162
Functions to handle different currencies.
CurrencySpec & GetCustomCurrency()
Get the custom currency.
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.
@ 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:123
std::string _config_file
Configuration file of OpenTTD.
Definition settings.cpp:64
Functions for standard in/out file operations.
@ NewGrf
Subdirectory for all NewGRFs.
Definition fileio_type.h:97
@ None
A path without any base directory.
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.
@ Setting
Setting changed.
Definition gamelog.h:22
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.
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.
const GRFConfig * FindGRFConfig(GrfID grfid, FindGRFConfigMode mode, const MD5Hash *md5sum, uint32_t desired_version)
Find a NewGRF in the scanned list.
Functions to find and configure NewGRFs.
@ NotFound
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.
@ Exact
Only find Grfs matching md5sum.
@ NewestValid
Find newest Grf, ignoring Grfs with GRFConfigFlag::Invalid set.
uint32_t GrfID
The unique identifier of a NewGRF.
Definition newgrf_type.h:15
@ Editor
In the scenario editor.
Definition openttd.h:21
@ Normal
Playing a game.
Definition openttd.h:20
@ Menu
In the main menu.
Definition openttd.h:19
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, VarMemType conv, int64_t val)
Write the value of a setting.
Definition saveload.cpp:896
int64_t ReadValue(const void *ptr, VarMemType conv)
Return a signed-long version of the value of a setting.
Definition saveload.cpp:872
VarMemType
The types/structures of data we have in memory.
Definition saveload.h:676
@ U64
A 64 bit unsigned int.
Definition saveload.h:686
@ I8
A 8 bit signed int.
Definition saveload.h:679
@ U8
A 8 bit unsigned int.
Definition saveload.h:680
@ StrQ
string pointer enclosed in quotes
Definition saveload.h:689
@ Null
useful to write zeros in savegame.
Definition saveload.h:687
@ I16
A 16 bit signed int.
Definition saveload.h:681
@ Bool
A boolean value.
Definition saveload.h:678
@ U32
A 32 bit unsigned int.
Definition saveload.h:684
@ I32
A 32 bit signed int.
Definition saveload.h:683
@ I64
A 64 bit signed int.
Definition saveload.h:685
@ Str
string pointer
Definition saveload.h:688
@ U16
A 16 bit unsigned int.
Definition saveload.h:682
void * GetVariableAddress(const void *object, const SaveLoad &sld)
Get the address of the variable.
Definition saveload.h:1319
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:1305
constexpr size_t SlVarSize(VarMemType type)
Return expect size in bytes of a VarType.
Definition saveload.h:819
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.
static bool LoadIntList(std::optional< std::string_view > str, void *array, int nelems, VarMemType type)
Load parsed string-values into an integer-array (intlist).
Definition settings.cpp:310
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:899
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:968
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:861
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:646
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 std::optional< std::vector< uint32_t > > ParseIntList(std::string_view str)
Parse a string into a vector of uint32s.
Definition settings.cpp:275
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:171
@ IFV_0
0 All versions prior to introduction.
Definition settings.cpp:172
@ IFV_AUTOSAVE_RENAME
5 PR#11143 Renamed values of autosave to be in minutes.
Definition settings.cpp:178
@ IFV_LINKGRAPH_SECONDS
3 PR#10610 Store linkgraph update intervals in seconds instead of days.
Definition settings.cpp:175
@ IFV_REMOVE_GENERATION_SEED
7 PR#11927 Remove "generation_seed" from configuration.
Definition settings.cpp:180
@ IFV_MAX_VERSION
Highest possible ini-file version.
Definition settings.cpp:183
@ IFV_NETWORK_PRIVATE_SETTINGS
4 PR#10762 Move use_relay_service to private settings.
Definition settings.cpp:176
@ IFV_DEFAULT_RAIL_ROAD
8 PR#15585 Update default rail type setting to support road and tram tiles
Definition settings.cpp:181
@ IFV_GAME_TYPE
2 PR#9515 Convert server_advertise to server_game_type.
Definition settings.cpp:174
@ IFV_RIGHT_CLICK_CLOSE
6 PR#10204 Add alternative right click to close windows setting.
Definition settings.cpp:179
@ IFV_PRIVATE_SECRETS
1 PR#9298 Moving of settings from openttd.cfg to private.cfg / secrets.cfg.
Definition settings.cpp:173
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:883
const uint16_t INIFILE_VERSION
Current ini-file version of OpenTTD.
Definition settings.cpp:186
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:731
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:249
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:910
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 ...
DefaultRailRoadType
How to select the default rail/road types.
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:61
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:773
static std::optional< bool > ParseSingleValue(std::string_view str)
Find whether a string was a boolean true or a boolean false.
Definition settings.cpp:234
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:436
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.
static std::optional< int32_t > ParseSingleValue(std::string_view str, int32_t min, uint32_t max)
Find whether a string was a valid int setting.
Definition settings.cpp:196
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:528
void ResetToDefault(void *object) const override
Reset the setting to its default value.
Definition settings.cpp:792
std::string FormatValue(const void *object) const override
Format the value of the setting associated with this object.
Definition settings.cpp:762
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:502
StringID GetTitle() const
Get the title of the setting.
Definition settings.cpp:452
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:779
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:493
void Write(const void *object, int32_t value) const
Set the value of a setting.
Definition settings.cpp:582
StringID GetHelp() const
Get the help text of the setting.
Definition settings.cpp:461
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:513
std::pair< StringParameter, StringParameter > GetValueParams(int32_t value) const
Get parameters for drawing the value of the setting.
Definition settings.cpp:471
int32_t Read(const void *object) const
Read the integer from the the actual setting.
Definition settings.cpp:593
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:392
bool IsDefaultValue(void *object) const override
Check whether the value is the same as the default value.
Definition settings.cpp:786
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:700
void ResetToDefault(void *object) const override
Reset the setting to its default value.
Definition settings.cpp:846
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:834
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:335
bool IsDefaultValue(void *object) const override
Check whether the value is the same as the default value.
Definition settings.cpp:840
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:425
std::string FormatValue(const void *object) const override
Format the value of the setting associated with this object.
Definition settings.cpp:372
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:366
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:216
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:411
static Company * Get(auto index)
SaveLoadVersion version_to
Save/load the variable before this savegame version.
Definition saveload.h:793
VarType conv
Type of the variable to be saved; this field combines both FileVarType and MemVarType.
Definition saveload.h:790
SaveLoadVersion version_from
Save/load the variable starting from this savegame version.
Definition saveload.h:792
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:920
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:937
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:957
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:947
String settings.
const std::string & Read(const void *object) const
Read the string from the the actual setting.
Definition settings.cpp:632
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:622
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:606
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:813
bool IsDefaultValue(void *object) const override
Check whether the value is the same as the default value.
Definition settings.cpp:823
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:829
std::string FormatValue(const void *object) const override
Format the value of the setting associated with this object.
Definition settings.cpp:797
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:693
Container of a variable's characteristics about a variable's storage.
Definition saveload.h:695
VarMemType mem
The way of storing data in memory.
Definition saveload.h:697
Default settings for vehicles.
High level window description.
Definition window_gui.h:172
void SetWindowClassesDirty(WindowClass cls)
Mark all windows of a particular class as dirty (in need of repainting).
Definition window.cpp:3223
Window * FindWindowById(WindowClass cls, WindowNumber number)
Find a window by its class and window number.
Definition window.cpp:1158
Window functions not directly related to making/drawing windows.