OpenTTD Source 20260206-master-g4d4e37dbf1
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
82{
83 static const SettingTable _generic_setting_tables[] = {
84 _difficulty_settings,
85 _economy_settings,
86 _game_settings,
87 _gui_settings,
88 _linkgraph_settings,
89 _locale_settings,
90 _multimedia_settings,
91 _network_settings,
92 _news_display_settings,
93 _pathfinding_settings,
94 _script_settings,
95 _world_settings,
96 };
97 return _generic_setting_tables;
98}
99
104{
105 static const SettingTable _private_setting_tables[] = {
106 _network_private_settings,
107 };
108 return _private_setting_tables;
109}
110
115{
116 static const SettingTable _secrets_setting_tables[] = {
117 _network_secrets_settings,
118 };
119 return _secrets_setting_tables;
120}
121
122using SettingDescProc = void(IniFile &ini, const SettingTable &desc, std::string_view grpname, void *object, bool only_startup);
123using SettingDescProcList = void(IniFile &ini, std::string_view grpname, StringList &list);
124
125static bool IsSignedVarMemType(VarType vt)
126{
127 switch (GetVarMemType(vt)) {
128 case SLE_VAR_I8:
129 case SLE_VAR_I16:
130 case SLE_VAR_I32:
131 case SLE_VAR_I64:
132 return true;
133 }
134 return false;
135}
136
140class ConfigIniFile : public IniFile {
141private:
142 static inline const IniGroupNameList list_group_names = {
143 "bans",
144 "newgrf",
145 "servers",
146 "server_bind_addresses",
147 "server_authorized_keys",
148 "rcon_authorized_keys",
149 "admin_authorized_keys"
150 };
151
152public:
153 ConfigIniFile(const std::string &filename) : IniFile(list_group_names)
154 {
155 this->LoadFromDisk(filename, NO_DIRECTORY);
156 }
157};
158
179
181
188std::optional<uint32_t> OneOfManySettingDesc::ParseSingleValue(std::string_view str, std::span<const std::string_view> many)
189{
190 StringConsumer consumer{str};
191 auto digit = consumer.TryReadIntegerBase<uint32_t>(10);
192 /* check if it's an integer */
193 if (digit.has_value()) return digit;
194
195 auto it = std::ranges::find(many, str);
196 if (it == many.end()) return std::nullopt;
197 return static_cast<uint32_t>(it - many.begin());
198}
199
206std::optional<bool> BoolSettingDesc::ParseSingleValue(std::string_view str)
207{
208 if (str == "true" || str == "on" || str == "1") return true;
209 if (str == "false" || str == "off" || str == "0") return false;
210
211 return std::nullopt;
212}
213
221static std::optional<uint32_t> LookupManyOfMany(std::span<const std::string_view> many, std::string_view str)
222{
223 static const std::string_view separators{" \t|"};
224
225 uint32_t res = 0;
226 StringConsumer consumer{str};
227 while (consumer.AnyBytesLeft()) {
228 /* skip "whitespace" */
229 consumer.SkipUntilCharNotIn(separators);
230
231 std::string_view value = consumer.ReadUntilCharIn(separators);
232 if (value.empty()) break;
233
234 auto r = OneOfManySettingDesc::ParseSingleValue(value, many);
235 if (!r.has_value()) return r;
236
237 SetBit(res, *r); // value found, set it
238 }
239 return res;
240}
241
247static std::optional<std::vector<uint32_t>> ParseIntList(std::string_view str)
248{
249 bool comma = false; // do we accept comma?
250 std::vector<uint32_t> result;
251
252 StringConsumer consumer{str};
253 for (;;) {
255 if (!consumer.AnyBytesLeft()) break;
256 if (comma && consumer.ReadIf(",")) {
257 /* commas are optional, but we only accept one between values */
258 comma = false;
259 continue;
260 }
261 auto v = consumer.TryReadIntegerBase<uint32_t>(10);
262 if (!v.has_value()) return std::nullopt;
263 result.push_back(*v);
264 comma = true;
265 }
266
267 /* If we have read comma but no number after it, fail.
268 * We have read comma when (n != 0) and comma is not allowed */
269 if (!result.empty() && !comma) return std::nullopt;
270
271 return result;
272}
273
282static bool LoadIntList(std::optional<std::string_view> str, void *array, int nelems, VarType type)
283{
284 size_t elem_size = SlVarSize(type);
285 std::byte *p = static_cast<std::byte *>(array);
286 if (!str.has_value()) {
287 std::fill_n(p, nelems * elem_size, static_cast<std::byte>(0));
288 return true;
289 }
290
291 auto opt_items = ParseIntList(*str);
292 if (!opt_items.has_value() || opt_items->size() != (size_t)nelems) return false;
293
294 for (auto item : *opt_items) {
295 WriteValue(p, type, item);
296 p += elem_size;
297 }
298 return true;
299}
300
307std::string ListSettingDesc::FormatValue(const void *object) const
308{
309 const uint8_t *p = static_cast<const uint8_t *>(GetVariableAddress(object, this->save));
310
311 std::string result;
312 for (size_t i = 0; i != this->save.length; i++) {
313 int64_t v;
314 switch (GetVarMemType(this->save.conv)) {
315 case SLE_VAR_BL:
316 case SLE_VAR_I8: v = *(const int8_t *)p; p += 1; break;
317 case SLE_VAR_U8: v = *(const uint8_t *)p; p += 1; break;
318 case SLE_VAR_I16: v = *(const int16_t *)p; p += 2; break;
319 case SLE_VAR_U16: v = *(const uint16_t *)p; p += 2; break;
320 case SLE_VAR_I32: v = *(const int32_t *)p; p += 4; break;
321 case SLE_VAR_U32: v = *(const uint32_t *)p; p += 4; break;
322 default: NOT_REACHED();
323 }
324 if (i != 0) result += ',';
325 format_append(result, "{}", v);
326 }
327 return result;
328}
329
330std::string OneOfManySettingDesc::FormatSingleValue(uint id) const
331{
332 if (id >= this->many.size()) {
333 return fmt::format("{}", id);
334 }
335 return std::string{this->many[id]};
336}
337
338std::string OneOfManySettingDesc::FormatValue(const void *object) const
339{
340 uint id = (uint)this->Read(object);
341 return this->FormatSingleValue(id);
342}
343
344std::string ManyOfManySettingDesc::FormatValue(const void *object) const
345{
346 uint bitmask = (uint)this->Read(object);
347 if (bitmask == 0) {
348 return {};
349 }
350
351 std::string result;
352 for (uint id : SetBitIterator(bitmask)) {
353 if (!result.empty()) result += '|';
354 result += this->FormatSingleValue(id);
355 }
356 return result;
357}
358
364int32_t IntSettingDesc::ParseValue(std::string_view str) const
365{
366 StringConsumer consumer{str};
367 /* The actual settings value might be int32 or uint32. Read as int64 and just cast away the high bits. */
368 auto value = consumer.TryReadIntegerBase<int64_t>(10);
369 if (!value.has_value()) {
370 _settings_error_list.emplace_back(
371 GetEncodedString(STR_CONFIG_ERROR),
372 GetEncodedString(STR_CONFIG_ERROR_INVALID_VALUE, str, this->GetName()));
373 return this->GetDefaultValue();
374 }
375 if (consumer.AnyBytesLeft()) {
376 _settings_error_list.emplace_back(
377 GetEncodedString(STR_CONFIG_ERROR),
378 GetEncodedString(STR_CONFIG_ERROR_TRAILING_CHARACTERS, this->GetName()));
379 }
380 return static_cast<int32_t>(*value);
381}
382
383int32_t OneOfManySettingDesc::ParseValue(std::string_view str) const
384{
386 /* if the first attempt of conversion from string to the appropriate value fails,
387 * look if we have defined a converter from old value to new value. */
388 if (!r.has_value() && this->many_cnvt != nullptr) r = this->many_cnvt(str);
389 if (r.has_value()) return *r; // and here goes converted value
390
391 _settings_error_list.emplace_back(
392 GetEncodedString(STR_CONFIG_ERROR),
393 GetEncodedString(STR_CONFIG_ERROR_INVALID_VALUE, str, this->GetName()));
394 return this->GetDefaultValue();
395}
396
397int32_t ManyOfManySettingDesc::ParseValue(std::string_view str) const
398{
399 auto r = LookupManyOfMany(this->many, str);
400 if (r.has_value()) return *r;
401
402 _settings_error_list.emplace_back(
403 GetEncodedString(STR_CONFIG_ERROR),
404 GetEncodedString(STR_CONFIG_ERROR_INVALID_VALUE, str, this->GetName()));
405 return this->GetDefaultValue();
406}
407
408int32_t BoolSettingDesc::ParseValue(std::string_view str) const
409{
411 if (r.has_value()) return *r;
412
413 _settings_error_list.emplace_back(
414 GetEncodedString(STR_CONFIG_ERROR),
415 GetEncodedString(STR_CONFIG_ERROR_INVALID_VALUE, str, this->GetName()));
416 return this->GetDefaultValue();
417}
418
425{
426 return this->get_title_cb != nullptr ? this->get_title_cb(*this) : this->str;
427}
428
434{
435 return this->get_help_cb != nullptr ? this->get_help_cb(*this) : this->str_help;
436}
437
442std::pair<StringParameter, StringParameter> IntSettingDesc::GetValueParams(int32_t value) const
443{
444 if (this->get_value_params_cb != nullptr) {
445 return this->get_value_params_cb(*this, value);
446 }
447
448 if (this->IsBoolSetting()) {
449 return {value != 0 ? STR_CONFIG_SETTING_ON : STR_CONFIG_SETTING_OFF, {}};
450 }
451
452 if (this->flags.Test(SettingFlag::GuiDropdown)) {
453 auto [min_val, _] = this->GetRange();
454 return {this->str_val - min_val + value, value};
455 }
456
457 return {this->str_val + ((value == 0 && this->flags.Test(SettingFlag::GuiZeroIsSpecial)) ? 1 : 0), value};
458}
459
465{
466 return this->get_def_cb != nullptr ? this->get_def_cb(*this) : this->def;
467}
468
473std::tuple<int32_t, uint32_t> IntSettingDesc::GetRange() const
474{
475 return this->get_range_cb != nullptr ? this->get_range_cb(*this) : std::tuple(this->min, this->max);
476}
477
484void IntSettingDesc::MakeValueValidAndWrite(const void *object, int32_t val) const
485{
486 this->MakeValueValid(val);
487 this->Write(object, val);
488}
489
499void IntSettingDesc::MakeValueValid(int32_t &val) const
500{
501 auto [min_val, max_val] = this->GetRange();
502 /* We need to take special care of the uint32_t type as we receive from the function
503 * a signed integer. While here also bail out on 64-bit settings as those are not
504 * supported. Unsigned 8 and 16-bit variables are safe since they fit into a signed
505 * 32-bit variable
506 * TODO: Support 64-bit settings/variables; requires 64 bit over command protocol! */
507 switch (GetVarMemType(this->save.conv)) {
508 case SLE_VAR_NULL: return;
509 case SLE_VAR_BL:
510 case SLE_VAR_I8:
511 case SLE_VAR_U8:
512 case SLE_VAR_I16:
513 case SLE_VAR_U16:
514 case SLE_VAR_I32: {
515 /* Override the minimum value. No value below this->min, except special value 0 */
516 if (!this->flags.Test(SettingFlag::GuiZeroIsSpecial) || val != 0) {
517 if (!this->flags.Test(SettingFlag::GuiDropdown)) {
518 /* Clamp value-type setting to its valid range */
519 val = Clamp(val, min_val, max_val);
520 } else if (val < min_val || val > static_cast<int32_t>(max_val)) {
521 /* Reset invalid discrete setting (where different values change gameplay) to its default value */
522 val = this->GetDefaultValue();
523 }
524 }
525 break;
526 }
527 case SLE_VAR_U32: {
528 /* Override the minimum value. No value below this->min, except special value 0 */
529 uint32_t uval = static_cast<uint32_t>(val);
530 if (!this->flags.Test(SettingFlag::GuiZeroIsSpecial) || uval != 0) {
531 if (!this->flags.Test(SettingFlag::GuiDropdown)) {
532 /* Clamp value-type setting to its valid range */
533 uval = ClampU(uval, min_val, max_val);
534 } else if (uval < static_cast<uint32_t>(min_val) || uval > max_val) {
535 /* Reset invalid discrete setting to its default value */
536 uval = static_cast<uint32_t>(this->GetDefaultValue());
537 }
538 }
539 val = static_cast<int32_t>(uval);
540 return;
541 }
542 case SLE_VAR_I64:
543 case SLE_VAR_U64:
544 default: NOT_REACHED();
545 }
546}
547
553void IntSettingDesc::Write(const void *object, int32_t val) const
554{
555 void *ptr = GetVariableAddress(object, this->save);
556 WriteValue(ptr, this->save.conv, (int64_t)val);
557}
558
564int32_t IntSettingDesc::Read(const void *object) const
565{
566 void *ptr = GetVariableAddress(object, this->save);
567 return (int32_t)ReadValue(ptr, this->save.conv);
568}
569
577void StringSettingDesc::MakeValueValid(std::string &str) const
578{
579 if (this->max_length == 0 || str.size() < this->max_length) return;
580
581 /* In case a maximum length is imposed by the setting, the length
582 * includes the '\0' termination for network transfer purposes.
583 * Also ensure the string is valid after chopping of some bytes. */
584 str.erase(this->max_length - 1, std::string::npos);
585 StrMakeValidInPlace(str, {});
586}
587
593void StringSettingDesc::Write(const void *object, std::string_view str) const
594{
595 reinterpret_cast<std::string *>(GetVariableAddress(object, this->save))->assign(str);
596}
597
603const std::string &StringSettingDesc::Read(const void *object) const
604{
605 return *reinterpret_cast<std::string *>(GetVariableAddress(object, this->save));
606}
607
617static void IniLoadSettings(IniFile &ini, const SettingTable &settings_table, std::string_view grpname, void *object, bool only_startup)
618{
619 const IniGroup *group;
620 const IniGroup *group_def = ini.GetGroup(grpname);
621
622 for (auto &desc : settings_table) {
623 const SettingDesc *sd = GetSettingDesc(desc);
625 if (sd->startup != only_startup) continue;
626
627 /* For settings.xx.yy load the settings from [xx] yy = ? */
628 std::string s{ sd->GetName() };
629 auto sc = s.find('.');
630 if (sc != std::string::npos) {
631 group = ini.GetGroup(s.substr(0, sc));
632 if (group == nullptr) group = group_def;
633 s = s.substr(sc + 1);
634 } else {
635 group = group_def;
636 }
637
638 const IniItem *item = nullptr;
639 if (group != nullptr) item = group->GetItem(s);
640 if (item == nullptr && group != group_def && group_def != nullptr) {
641 /* For settings.xx.yy load the settings from [settings] yy = ? in case the previous
642 * did not exist (e.g. loading old config files with a [settings] section */
643 item = group_def->GetItem(s);
644 }
645 if (item == nullptr) {
646 /* For settings.xx.zz.yy load the settings from [zz] yy = ? in case the previous
647 * did not exist (e.g. loading old config files with a [yapf] section */
648 sc = s.find('.');
649 if (sc != std::string::npos) {
650 if (group = ini.GetGroup(s.substr(0, sc)); group != nullptr) item = group->GetItem(s.substr(sc + 1));
651 }
652 }
653
654 sd->ParseValue(item, object);
655 }
656}
657
658void IntSettingDesc::ParseValue(const IniItem *item, void *object) const
659{
660 int32_t val = (item != nullptr && item->value.has_value()) ? this->ParseValue(*item->value) : this->GetDefaultValue();
661 this->MakeValueValidAndWrite(object, val);
662}
663
664void StringSettingDesc::ParseValue(const IniItem *item, void *object) const
665{
666 std::string str{(item == nullptr) ? this->def : item->value.value_or("")};
667 this->MakeValueValid(str);
668 this->Write(object, str);
669}
670
671void ListSettingDesc::ParseValue(const IniItem *item, void *object) const
672{
673 std::optional<std::string_view> str;
674 if (item != nullptr) {
675 str = item->value;
676 } else if (!this->def.empty()) {
677 str = this->def;
678 }
679 void *ptr = GetVariableAddress(object, this->save);
680 if (!LoadIntList(str, ptr, this->save.length, GetVarMemType(this->save.conv))) {
681 _settings_error_list.emplace_back(
682 GetEncodedString(STR_CONFIG_ERROR),
683 GetEncodedString(STR_CONFIG_ERROR_ARRAY, this->GetName()));
684
685 /* Use default */
686 LoadIntList(this->def, ptr, this->save.length, GetVarMemType(this->save.conv));
687 }
688}
689
702static void IniSaveSettings(IniFile &ini, const SettingTable &settings_table, std::string_view grpname, void *object, bool)
703{
704 IniGroup *group_def = nullptr, *group;
705
706 for (auto &desc : settings_table) {
707 const SettingDesc *sd = GetSettingDesc(desc);
708 /* If the setting is not saved to the configuration
709 * file, just continue with the next setting */
711 if (sd->flags.Test(SettingFlag::NotInConfig)) continue;
712
713 /* XXX - wtf is this?? (group override?) */
714 std::string s{ sd->GetName() };
715 auto sc = s.find('.');
716 if (sc != std::string::npos) {
717 group = &ini.GetOrCreateGroup(s.substr(0, sc));
718 s = s.substr(sc + 1);
719 } else {
720 if (group_def == nullptr) group_def = &ini.GetOrCreateGroup(grpname);
721 group = group_def;
722 }
723
724 IniItem &item = group->GetOrCreateItem(s);
725
726 if (!item.value.has_value() || !sd->IsSameValue(&item, object)) {
727 /* The value is different, that means we have to write it to the ini */
728 item.value.emplace(sd->FormatValue(object));
729 }
730 }
731}
732
733std::string IntSettingDesc::FormatValue(const void *object) const
734{
735 int64_t i;
736 if (IsSignedVarMemType(this->save.conv)) {
737 i = this->Read(object);
738 } else {
739 i = (uint32_t)this->Read(object);
740 }
741 return fmt::format("{}", i);
742}
743
744std::string BoolSettingDesc::FormatValue(const void *object) const
745{
746 bool val = this->Read(object) != 0;
747 return val ? "true" : "false";
748}
749
750bool IntSettingDesc::IsSameValue(const IniItem *item, void *object) const
751{
752 int32_t item_value = static_cast<int32_t>(this->ParseValue(*item->value));
753 int32_t object_value = this->Read(object);
754 return item_value == object_value;
755}
756
757bool IntSettingDesc::IsDefaultValue(void *object) const
758{
759 int32_t object_value = this->Read(object);
760 return this->GetDefaultValue() == object_value;
761}
762
763void IntSettingDesc::ResetToDefault(void *object) const
764{
765 this->Write(object, this->GetDefaultValue());
766}
767
768std::string StringSettingDesc::FormatValue(const void *object) const
769{
770 const std::string &str = this->Read(object);
771 switch (GetVarMemType(this->save.conv)) {
772 case SLE_VAR_STR: return str;
773
774 case SLE_VAR_STRQ:
775 if (str.empty()) {
776 return str;
777 }
778 return fmt::format("\"{}\"", str);
779
780 default: NOT_REACHED();
781 }
782}
783
784bool StringSettingDesc::IsSameValue(const IniItem *item, void *object) const
785{
786 /* The ini parsing removes the quotes, which are needed to retain the spaces in STRQs,
787 * so those values are always different in the parsed ini item than they should be. */
788 if (GetVarMemType(this->save.conv) == SLE_VAR_STRQ) return false;
789
790 const std::string &str = this->Read(object);
791 return item->value->compare(str) == 0;
792}
793
794bool StringSettingDesc::IsDefaultValue(void *object) const
795{
796 const std::string &str = this->Read(object);
797 return this->def == str;
798}
799
800void StringSettingDesc::ResetToDefault(void *object) const
801{
802 this->Write(object, this->def);
803}
804
805bool ListSettingDesc::IsSameValue(const IniItem *, void *) const
806{
807 /* Checking for equality is way more expensive than just writing the value. */
808 return false;
809}
810
812{
813 /* Defaults of lists are often complicated, and hard to compare. */
814 return false;
815}
816
818{
819 /* Resetting a list to default is not supported. */
820 NOT_REACHED();
821}
822
832static void IniLoadSettingList(IniFile &ini, std::string_view grpname, StringList &list)
833{
834 const IniGroup *group = ini.GetGroup(grpname);
835
836 if (group == nullptr) return;
837
838 list.clear();
839
840 for (const IniItem &item : group->items) {
841 if (!item.name.empty()) list.push_back(item.name);
842 }
843}
844
854static void IniSaveSettingList(IniFile &ini, std::string_view grpname, StringList &list)
855{
856 IniGroup &group = ini.GetOrCreateGroup(grpname);
857 group.Clear();
858
859 for (const auto &iter : list) {
860 group.GetOrCreateItem(iter).SetValue("");
861 }
862}
863
870void IniLoadWindowSettings(IniFile &ini, std::string_view grpname, WindowDesc *desc)
871{
872 IniLoadSettings(ini, _window_settings, grpname, desc, false);
873}
874
881void IniSaveWindowSettings(IniFile &ini, std::string_view grpname, WindowDesc *desc)
882{
883 IniSaveSettings(ini, _window_settings, grpname, desc, false);
884}
885
891bool SettingDesc::IsEditable(bool do_command) const
892{
893 if (!do_command && !this->flags.Test(SettingFlag::NoNetworkSync) && _networking && !_network_server && !this->flags.Test(SettingFlag::PerCompany)) return false;
894 if (do_command && this->flags.Test(SettingFlag::NoNetworkSync)) return false;
895 if (this->flags.Test(SettingFlag::NetworkOnly) && !_networking && _game_mode != GM_MENU) return false;
896 if (this->flags.Test(SettingFlag::NoNetwork) && _networking) return false;
897 if (this->flags.Test(SettingFlag::NewgameOnly) &&
898 (_game_mode == GM_NORMAL ||
899 (_game_mode == GM_EDITOR && !this->flags.Test(SettingFlag::SceneditToo)))) return false;
900 if (this->flags.Test(SettingFlag::SceneditOnly) && _game_mode != GM_EDITOR) return false;
901 return true;
902}
903
909{
910 if (this->flags.Test(SettingFlag::PerCompany)) return ST_COMPANY;
911 return this->flags.Test(SettingFlag::NotInSave) ? ST_CLIENT : ST_GAME;
912}
913
919{
920 assert(this->IsIntSetting());
921 return static_cast<const IntSettingDesc *>(this);
922}
923
929{
930 assert(this->IsStringSetting());
931 return static_cast<const StringSettingDesc *>(this);
932}
933
935void HandleOldDiffCustom(bool savegame);
936
937
939static void ValidateSettings()
940{
941 /* Do not allow a custom sea level with the original land generator. */
942 if (_settings_newgame.game_creation.land_generator == LG_ORIGINAL &&
943 _settings_newgame.difficulty.quantity_sea_lakes == CUSTOM_SEA_LEVEL_NUMBER_DIFFICULTY) {
944 _settings_newgame.difficulty.quantity_sea_lakes = CUSTOM_SEA_LEVEL_MIN_PERCENTAGE;
945 }
946}
947
948static void AILoadConfig(const IniFile &ini, std::string_view grpname)
949{
950 const IniGroup *group = ini.GetGroup(grpname);
951
952 /* Clean any configured AI */
953 for (CompanyID c = CompanyID::Begin(); c < MAX_COMPANIES; ++c) {
955 }
956
957 /* If no group exists, return */
958 if (group == nullptr) return;
959
960 CompanyID c = CompanyID::Begin();
961 for (const IniItem &item : group->items) {
963
964 config->Change(item.name);
965 if (!config->HasScript()) {
966 if (item.name != "none") {
967 Debug(script, 0, "The AI by the name '{}' was no longer found, and removed from the list.", item.name);
968 continue;
969 }
970 }
971 if (item.value.has_value()) config->StringToSettings(*item.value);
972 ++c;
973 if (c >= MAX_COMPANIES) break;
974 }
975}
976
977static void GameLoadConfig(const IniFile &ini, std::string_view grpname)
978{
979 const IniGroup *group = ini.GetGroup(grpname);
980
981 /* Clean any configured GameScript */
983
984 /* If no group exists, return */
985 if (group == nullptr || group->items.empty()) return;
986
987 const IniItem &item = group->items.front();
988
990
991 config->Change(item.name);
992 if (!config->HasScript()) {
993 if (item.name != "none") {
994 Debug(script, 0, "The GameScript by the name '{}' was no longer found, and removed from the list.", item.name);
995 return;
996 }
997 }
998 if (item.value.has_value()) config->StringToSettings(*item.value);
999}
1000
1005{
1006 if (const IniGroup *group = ini.GetGroup("misc"); group != nullptr) {
1007 /* Load old setting first. */
1008 if (const IniItem *item = group->GetItem("graphicsset"); item != nullptr && item->value) BaseGraphics::ini_data.name = *item->value;
1009 }
1010
1011 if (const IniGroup *group = ini.GetGroup("graphicsset"); group != nullptr) {
1012 /* Load new settings. */
1013 if (const IniItem *item = group->GetItem("name"); item != nullptr && item->value) BaseGraphics::ini_data.name = *item->value;
1014
1015 if (const IniItem *item = group->GetItem("shortname"); item != nullptr && item->value && item->value->size() == 8) {
1016 auto val = ParseInteger<uint32_t>(*item->value, 16);
1017 if (val.has_value()) {
1018 BaseGraphics::ini_data.shortname = std::byteswap<uint32_t>(*val);
1019 } else {
1020 ShowErrorMessage(GetEncodedString(STR_CONFIG_ERROR),
1021 GetEncodedString(STR_CONFIG_ERROR_INVALID_VALUE, *item->value, BaseGraphics::ini_data.name),
1022 WL_CRITICAL);
1023 }
1024 }
1025
1026 if (const IniItem *item = group->GetItem("extra_version"); item != nullptr && item->value) {
1027 auto val = ParseInteger<uint32_t>(*item->value);
1028 if (val.has_value()) {
1029 BaseGraphics::ini_data.extra_version = *val;
1030 } else {
1031 ShowErrorMessage(GetEncodedString(STR_CONFIG_ERROR),
1032 GetEncodedString(STR_CONFIG_ERROR_INVALID_VALUE, *item->value, BaseGraphics::ini_data.name),
1033 WL_CRITICAL);
1034 }
1035 }
1036
1037 if (const IniItem *item = group->GetItem("extra_params"); item != nullptr && item->value) {
1038 auto params = ParseIntList(*item->value);
1039 if (params.has_value()) {
1040 BaseGraphics::ini_data.extra_params = params.value();
1041 } else {
1042 ShowErrorMessage(GetEncodedString(STR_CONFIG_ERROR),
1043 GetEncodedString(STR_CONFIG_ERROR_ARRAY, BaseGraphics::ini_data.name),
1044 WL_CRITICAL);
1045 }
1046 }
1047 }
1048}
1049
1056static GRFConfigList GRFLoadConfig(const IniFile &ini, std::string_view grpname, bool is_static)
1057{
1058 const IniGroup *group = ini.GetGroup(grpname);
1059 GRFConfigList list;
1060
1061 if (group == nullptr) return list;
1062
1063 uint num_grfs = 0;
1064 for (const IniItem &item : group->items) {
1065 std::unique_ptr<GRFConfig> c{};
1066
1067 std::array<uint8_t, 4> grfid_buf;
1068 MD5Hash md5sum;
1069 std::string_view item_name = item.name;
1070 bool has_md5sum = false;
1071
1072 /* Try reading "<grfid>|" and on success, "<md5sum>|". */
1073 auto grfid_pos = item_name.find("|");
1074 if (grfid_pos != std::string_view::npos) {
1075 std::string_view grfid_str = item_name.substr(0, grfid_pos);
1076
1077 if (ConvertHexToBytes(grfid_str, grfid_buf)) {
1078 item_name = item_name.substr(grfid_pos + 1);
1079
1080 auto md5sum_pos = item_name.find("|");
1081 if (md5sum_pos != std::string_view::npos) {
1082 std::string_view md5sum_str = item_name.substr(0, md5sum_pos);
1083
1084 has_md5sum = ConvertHexToBytes(md5sum_str, md5sum);
1085 if (has_md5sum) item_name = item_name.substr(md5sum_pos + 1);
1086 }
1087
1088 uint32_t grfid = grfid_buf[0] | (grfid_buf[1] << 8) | (grfid_buf[2] << 16) | (grfid_buf[3] << 24);
1089 if (has_md5sum) {
1090 const GRFConfig *s = FindGRFConfig(grfid, FGCM_EXACT, &md5sum);
1091 if (s != nullptr) c = std::make_unique<GRFConfig>(*s);
1092 }
1093 if (c == nullptr && !FioCheckFileExists(std::string(item_name), NEWGRF_DIR)) {
1094 const GRFConfig *s = FindGRFConfig(grfid, FGCM_NEWEST_VALID);
1095 if (s != nullptr) c = std::make_unique<GRFConfig>(*s);
1096 }
1097 }
1098 }
1099 std::string filename = std::string(item_name);
1100
1101 if (c == nullptr) c = std::make_unique<GRFConfig>(filename);
1102
1103 /* Parse parameters */
1104 if (item.value.has_value() && !item.value->empty()) {
1105 auto params = ParseIntList(*item.value);
1106 if (params.has_value()) {
1107 c->SetParams(params.value());
1108 } else {
1109 ShowErrorMessage(GetEncodedString(STR_CONFIG_ERROR),
1110 GetEncodedString(STR_CONFIG_ERROR_ARRAY, filename),
1111 WL_CRITICAL);
1112 }
1113 }
1114
1115 /* Check if item is valid */
1116 if (!FillGRFDetails(*c, is_static) || c->flags.Test(GRFConfigFlag::Invalid)) {
1117 StringID reason;
1118 if (c->status == GCS_NOT_FOUND) {
1119 reason = STR_CONFIG_ERROR_INVALID_GRF_NOT_FOUND;
1120 } else if (c->flags.Test(GRFConfigFlag::Unsafe)) {
1121 reason = STR_CONFIG_ERROR_INVALID_GRF_UNSAFE;
1122 } else if (c->flags.Test(GRFConfigFlag::System)) {
1123 reason = STR_CONFIG_ERROR_INVALID_GRF_SYSTEM;
1124 } else if (c->flags.Test(GRFConfigFlag::Invalid)) {
1125 reason = STR_CONFIG_ERROR_INVALID_GRF_INCOMPATIBLE;
1126 } else {
1127 reason = STR_CONFIG_ERROR_INVALID_GRF_UNKNOWN;
1128 }
1129
1130 ShowErrorMessage(GetEncodedString(STR_CONFIG_ERROR),
1131 GetEncodedString(STR_CONFIG_ERROR_INVALID_GRF, filename.empty() ? item.name : filename, reason),
1132 WL_CRITICAL);
1133 continue;
1134 }
1135
1136 /* Check for duplicate GRFID (will also check for duplicate filenames) */
1137 auto found = std::ranges::find_if(list, [&c](const auto &gc) { return gc->ident.grfid == c->ident.grfid; });
1138 if (found != std::end(list)) {
1139 ShowErrorMessage(GetEncodedString(STR_CONFIG_ERROR),
1140 GetEncodedString(STR_CONFIG_ERROR_DUPLICATE_GRFID, c->filename, (*found)->filename),
1141 WL_CRITICAL);
1142 continue;
1143 }
1144
1145 if (is_static) {
1146 /* Mark file as static to avoid saving in savegame. */
1147 c->flags.Set(GRFConfigFlag::Static);
1148 } else if (++num_grfs > NETWORK_MAX_GRF_COUNT) {
1149 /* Check we will not load more non-static NewGRFs than allowed. This could trigger issues for game servers. */
1150 ShowErrorMessage(GetEncodedString(STR_CONFIG_ERROR),
1151 GetEncodedString(STR_NEWGRF_ERROR_TOO_MANY_NEWGRFS_LOADED), WL_CRITICAL);
1152 break;
1153 }
1154
1155 /* Add item to list */
1156 list.push_back(std::move(c));
1157 }
1158
1159 return list;
1160}
1161
1162static IniFileVersion LoadVersionFromConfig(const IniFile &ini)
1163{
1164 const IniGroup *group = ini.GetGroup("version");
1165 if (group == nullptr) return IFV_0;
1166
1167 auto version_number = group->GetItem("ini_version");
1168 /* Older ini-file versions don't have this key yet. */
1169 if (version_number == nullptr || !version_number->value.has_value()) return IFV_0;
1170
1171 uint32_t version = 0;
1172 std::from_chars(version_number->value->data(), version_number->value->data() + version_number->value->size(), version);
1173
1174 return static_cast<IniFileVersion>(version);
1175}
1176
1177static void AISaveConfig(IniFile &ini, std::string_view grpname)
1178{
1179 IniGroup &group = ini.GetOrCreateGroup(grpname);
1180 group.Clear();
1181
1182 for (CompanyID c = CompanyID::Begin(); c < MAX_COMPANIES; ++c) {
1184 std::string name;
1185 std::string value = config->SettingsToString();
1186
1187 if (config->HasScript()) {
1188 name = config->GetName();
1189 } else {
1190 name = "none";
1191 }
1192
1193 group.CreateItem(name).SetValue(value);
1194 }
1195}
1196
1197static void GameSaveConfig(IniFile &ini, std::string_view grpname)
1198{
1199 IniGroup &group = ini.GetOrCreateGroup(grpname);
1200 group.Clear();
1201
1203 std::string name;
1204 std::string value = config->SettingsToString();
1205
1206 if (config->HasScript()) {
1207 name = config->GetName();
1208 } else {
1209 name = "none";
1210 }
1211
1212 group.CreateItem(name).SetValue(value);
1213}
1214
1220{
1221 IniGroup &group = ini.GetOrCreateGroup("version");
1222 group.GetOrCreateItem("version_string").SetValue(_openttd_revision);
1223 group.GetOrCreateItem("version_number").SetValue(fmt::format("{:08X}", _openttd_newgrf_version));
1224 group.GetOrCreateItem("ini_version").SetValue(fmt::format("{}", INIFILE_VERSION));
1225}
1226
1231{
1232 const GraphicsSet *used_set = BaseGraphics::GetUsedSet();
1233 if (used_set == nullptr) return;
1234
1235 IniGroup &group = ini.GetOrCreateGroup("graphicsset");
1236 group.Clear();
1237
1238 group.GetOrCreateItem("name").SetValue(used_set->name);
1239 group.GetOrCreateItem("shortname").SetValue(fmt::format("{:08X}", std::byteswap(used_set->shortname)));
1240
1241 const GRFConfig *extra_cfg = used_set->GetExtraConfig();
1242 if (extra_cfg != nullptr && !extra_cfg->param.empty()) {
1243 group.GetOrCreateItem("extra_version").SetValue(fmt::format("{}", extra_cfg->version));
1244 group.GetOrCreateItem("extra_params").SetValue(GRFBuildParamList(*extra_cfg));
1245 }
1246}
1247
1248/* Save a GRF configuration to the given group name */
1249static void GRFSaveConfig(IniFile &ini, std::string_view grpname, const GRFConfigList &list)
1250{
1251 IniGroup &group = ini.GetOrCreateGroup(grpname);
1252 group.Clear();
1253
1254 for (const auto &c : list) {
1255 std::string key = fmt::format("{:08X}|{}|{}", std::byteswap(c->ident.grfid),
1256 FormatArrayAsHex(c->ident.md5sum), c->filename);
1258 }
1259}
1260
1261/* Common handler for saving/loading variables to the configuration file */
1262static void HandleSettingDescs(IniFile &generic_ini, IniFile &private_ini, IniFile &secrets_ini, SettingDescProc *proc, SettingDescProcList *proc_list, bool only_startup = false)
1263{
1264 proc(generic_ini, _misc_settings, "misc", nullptr, only_startup);
1265#if defined(_WIN32) && !defined(DEDICATED)
1266 proc(generic_ini, _win32_settings, "win32", nullptr, only_startup);
1267#endif /* _WIN32 */
1268
1269 /* The name "patches" is a fallback, as every setting should sets its own group. */
1270
1271 for (auto &table : GenericSettingTables()) {
1272 proc(generic_ini, table, "patches", &_settings_newgame, only_startup);
1273 }
1274 for (auto &table : PrivateSettingTables()) {
1275 proc(private_ini, table, "patches", &_settings_newgame, only_startup);
1276 }
1277 for (auto &table : SecretSettingTables()) {
1278 proc(secrets_ini, table, "patches", &_settings_newgame, only_startup);
1279 }
1280
1281 proc(generic_ini, _currency_settings, "currency", &GetCustomCurrency(), only_startup);
1282 proc(generic_ini, _company_settings, "company", &_settings_client.company, only_startup);
1283
1284 if (!only_startup) {
1285 proc_list(private_ini, "server_bind_addresses", _network_bind_list);
1286 proc_list(private_ini, "servers", _network_host_list);
1287 proc_list(private_ini, "bans", _network_ban_list);
1288 proc_list(private_ini, "server_authorized_keys", _settings_client.network.server_authorized_keys);
1289 proc_list(private_ini, "rcon_authorized_keys", _settings_client.network.rcon_authorized_keys);
1290 proc_list(private_ini, "admin_authorized_keys", _settings_client.network.admin_authorized_keys);
1291 }
1292}
1293
1303static void RemoveEntriesFromIni(IniFile &ini, const SettingTable &table)
1304{
1305 for (auto &desc : table) {
1306 const SettingDesc *sd = GetSettingDesc(desc);
1307
1308 /* For settings.xx.yy load the settings from [xx] yy = ? */
1309 std::string s{ sd->GetName() };
1310 auto sc = s.find('.');
1311 if (sc == std::string::npos) continue;
1312
1313 IniGroup *group = ini.GetGroup(s.substr(0, sc));
1314 if (group == nullptr) continue;
1315 s = s.substr(sc + 1);
1316
1317 group->RemoveItem(s);
1318 }
1319}
1320
1344bool IsConversionNeeded(const ConfigIniFile &ini, const std::string &group, const std::string &old_var, const std::string &new_var, const IniItem **old_item)
1345{
1346 *old_item = nullptr;
1347
1348 const IniGroup *igroup = ini.GetGroup(group);
1349 /* If the group doesn't exist, there is nothing to convert. */
1350 if (igroup == nullptr) return false;
1351
1352 const IniItem *tmp_old_item = igroup->GetItem(old_var);
1353 const IniItem *new_item = igroup->GetItem(new_var);
1354
1355 /* If the old item doesn't exist, there is nothing to convert. */
1356 if (tmp_old_item == nullptr) return false;
1357
1358 /* If the new item exists, it means conversion was already done. We only
1359 * do the conversion the first time, and after that these settings are
1360 * independent. This allows users to freely change between older and
1361 * newer clients without breaking anything. */
1362 if (new_item != nullptr) return false;
1363
1364 *old_item = tmp_old_item;
1365 return true;
1366}
1367
1372void LoadFromConfig(bool startup)
1373{
1374 ConfigIniFile generic_ini(_config_file);
1375 ConfigIniFile private_ini(_private_file);
1376 ConfigIniFile secrets_ini(_secrets_file);
1377 ConfigIniFile favs_ini(_favs_file);
1378
1379 if (!startup) ResetCurrencies(false); // Initialize the array of currencies, without preserving the custom one
1380
1381 IniFileVersion generic_version = LoadVersionFromConfig(generic_ini);
1382
1383 if (startup) {
1384 GraphicsSetLoadConfig(generic_ini);
1385 }
1386
1387 /* Before the split of private/secrets, we have to look in the generic for these settings. */
1388 if (generic_version < IFV_PRIVATE_SECRETS) {
1389 HandleSettingDescs(generic_ini, generic_ini, generic_ini, IniLoadSettings, IniLoadSettingList, startup);
1390 } else {
1391 HandleSettingDescs(generic_ini, private_ini, secrets_ini, IniLoadSettings, IniLoadSettingList, startup);
1392 }
1393
1394 /* Load basic settings only during bootstrap, load other settings not during bootstrap */
1395 if (!startup) {
1396 if (generic_version < IFV_LINKGRAPH_SECONDS) {
1397 _settings_newgame.linkgraph.recalc_interval *= CalendarTime::SECONDS_PER_DAY;
1398 _settings_newgame.linkgraph.recalc_time *= CalendarTime::SECONDS_PER_DAY;
1399 }
1400
1401 /* Move use_relay_service from generic_ini to private_ini. */
1402 if (generic_version < IFV_NETWORK_PRIVATE_SETTINGS) {
1403 const IniGroup *network = generic_ini.GetGroup("network");
1404 if (network != nullptr) {
1405 const IniItem *use_relay_service = network->GetItem("use_relay_service");
1406 if (use_relay_service != nullptr) {
1407 if (use_relay_service->value == "never") {
1408 _settings_client.network.use_relay_service = UseRelayService::Never;
1409 } else if (use_relay_service->value == "ask") {
1410 _settings_client.network.use_relay_service = UseRelayService::Ask;
1411 } else if (use_relay_service->value == "allow") {
1412 _settings_client.network.use_relay_service = UseRelayService::Allow;
1413 }
1414 }
1415 }
1416 }
1417
1418 const IniItem *old_item;
1419
1420 if (generic_version < IFV_GAME_TYPE && IsConversionNeeded(generic_ini, "network", "server_advertise", "server_game_type", &old_item)) {
1421 auto old_value = BoolSettingDesc::ParseSingleValue(*old_item->value);
1422 _settings_client.network.server_game_type = old_value.value_or(false) ? SERVER_GAME_TYPE_PUBLIC : SERVER_GAME_TYPE_LOCAL;
1423 }
1424
1425 if (generic_version < IFV_AUTOSAVE_RENAME && IsConversionNeeded(generic_ini, "gui", "autosave", "autosave_interval", &old_item)) {
1426 static constexpr std::initializer_list<std::string_view> _old_autosave_interval{"off"sv, "monthly"sv, "quarterly"sv, "half year"sv, "yearly"sv};
1427 auto old_value = OneOfManySettingDesc::ParseSingleValue(*old_item->value, _old_autosave_interval).value_or(-1);
1428
1429 switch (old_value) {
1430 case 0: _settings_client.gui.autosave_interval = 0; break;
1431 case 1: _settings_client.gui.autosave_interval = 10; break;
1432 case 2: _settings_client.gui.autosave_interval = 30; break;
1433 case 3: _settings_client.gui.autosave_interval = 60; break;
1434 case 4: _settings_client.gui.autosave_interval = 120; break;
1435 default: break;
1436 }
1437 }
1438
1439 /* Persist the right click close option from older versions. */
1440 if (generic_version < IFV_RIGHT_CLICK_CLOSE && IsConversionNeeded(generic_ini, "gui", "right_mouse_wnd_close", "right_click_wnd_close", &old_item)) {
1441 auto old_value = BoolSettingDesc::ParseSingleValue(*old_item->value);
1442 _settings_client.gui.right_click_wnd_close = old_value.value_or(false) ? RightClickClose::Yes : RightClickClose::No;
1443 }
1444
1445 _grfconfig_newgame = GRFLoadConfig(generic_ini, "newgrf", false);
1446 _grfconfig_static = GRFLoadConfig(generic_ini, "newgrf-static", true);
1447 AILoadConfig(generic_ini, "ai_players");
1448 GameLoadConfig(generic_ini, "game_scripts");
1449 PickerLoadConfig(favs_ini);
1450 BadgeClassLoadConfig(favs_ini);
1451
1453 IniLoadSettings(generic_ini, _old_gameopt_settings, "gameopt", &_settings_newgame, false);
1454 HandleOldDiffCustom(false);
1455
1458
1459 /* Display scheduled errors */
1461 if (FindWindowById(WC_ERRMSG, 0) == nullptr) ShowFirstError();
1462 }
1463}
1464
1467{
1468 ConfigIniFile generic_ini(_config_file);
1469 ConfigIniFile private_ini(_private_file);
1470 ConfigIniFile secrets_ini(_secrets_file);
1471 ConfigIniFile favs_ini(_favs_file);
1472
1473 IniFileVersion generic_version = LoadVersionFromConfig(generic_ini);
1474
1475 /* If we newly create the private/secrets file, add a dummy group on top
1476 * just so we can add a comment before it (that is how IniFile works).
1477 * This to explain what the file is about. After doing it once, never touch
1478 * it again, as otherwise we might be reverting user changes. */
1479 if (IniGroup *group = private_ini.GetGroup("private"); group != nullptr) group->comment = "; This file possibly contains private information which can identify you as person.\n";
1480 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";
1481
1482 if (generic_version == IFV_0) {
1483 /* Remove some obsolete groups. These have all been loaded into other groups. */
1484 generic_ini.RemoveGroup("patches");
1485 generic_ini.RemoveGroup("yapf");
1486 generic_ini.RemoveGroup("gameopt");
1487
1488 /* Remove all settings from the generic ini that are now in the private ini. */
1489 generic_ini.RemoveGroup("server_bind_addresses");
1490 generic_ini.RemoveGroup("servers");
1491 generic_ini.RemoveGroup("bans");
1492 for (auto &table : PrivateSettingTables()) {
1493 RemoveEntriesFromIni(generic_ini, table);
1494 }
1495
1496 /* Remove all settings from the generic ini that are now in the secrets ini. */
1497 for (auto &table : SecretSettingTables()) {
1498 RemoveEntriesFromIni(generic_ini, table);
1499 }
1500 }
1501
1502 if (generic_version < IFV_REMOVE_GENERATION_SEED) {
1503 IniGroup *game_creation = generic_ini.GetGroup("game_creation");
1504 if (game_creation != nullptr) {
1505 game_creation->RemoveItem("generation_seed");
1506 }
1507 }
1508
1509 /* These variables are migrated from generic ini to private ini now. */
1510 if (generic_version < IFV_NETWORK_PRIVATE_SETTINGS) {
1511 IniGroup *network = generic_ini.GetGroup("network");
1512 if (network != nullptr) {
1513 network->RemoveItem("use_relay_service");
1514 }
1515 }
1516
1517 HandleSettingDescs(generic_ini, private_ini, secrets_ini, IniSaveSettings, IniSaveSettingList);
1518 GraphicsSetSaveConfig(generic_ini);
1519 GRFSaveConfig(generic_ini, "newgrf", _grfconfig_newgame);
1520 GRFSaveConfig(generic_ini, "newgrf-static", _grfconfig_static);
1521 AISaveConfig(generic_ini, "ai_players");
1522 GameSaveConfig(generic_ini, "game_scripts");
1523 PickerSaveConfig(favs_ini);
1524 BadgeClassSaveConfig(favs_ini);
1525
1526 SaveVersionInConfig(generic_ini);
1527 SaveVersionInConfig(private_ini);
1528 SaveVersionInConfig(secrets_ini);
1529 SaveVersionInConfig(favs_ini);
1530
1531 generic_ini.SaveToDisk(_config_file);
1532 private_ini.SaveToDisk(_private_file);
1533 secrets_ini.SaveToDisk(_secrets_file);
1534 favs_ini.SaveToDisk(_favs_file);
1535}
1536
1542{
1543 StringList list;
1544
1546 for (const IniGroup &group : ini.groups) {
1547 if (group.name.starts_with("preset-")) {
1548 list.push_back(group.name.substr(7));
1549 }
1550 }
1551
1552 return list;
1553}
1554
1561GRFConfigList LoadGRFPresetFromConfig(std::string_view config_name)
1562{
1563 std::string section("preset-");
1564 section += config_name;
1565
1567 GRFConfigList config = GRFLoadConfig(ini, section, false);
1568
1569 return config;
1570}
1571
1578void SaveGRFPresetToConfig(std::string_view config_name, GRFConfigList &config)
1579{
1580 std::string section("preset-");
1581 section += config_name;
1582
1584 GRFSaveConfig(ini, section, config);
1586}
1587
1592void DeleteGRFPresetFromConfig(std::string_view config_name)
1593{
1594 std::string section("preset-");
1595 section += config_name;
1596
1598 ini.RemoveGroup(section);
1600}
1601
1608void IntSettingDesc::ChangeValue(const void *object, int32_t newval) const
1609{
1610 int32_t oldval = this->Read(object);
1611 this->MakeValueValid(newval);
1612 if (this->pre_check != nullptr && !this->pre_check(newval)) return;
1613 if (oldval == newval) return;
1614
1615 this->Write(object, newval);
1616 if (this->post_callback != nullptr) this->post_callback(newval);
1617
1618 if (this->flags.Test(SettingFlag::NoNetwork) || this->flags.Test(SettingFlag::Sandbox)) {
1619 _gamelog.StartAction(GLAT_SETTING);
1620 _gamelog.Setting(this->GetName(), oldval, newval);
1621 _gamelog.StopAction();
1622 }
1623
1626
1627 if (_save_config) SaveToConfig();
1628}
1629
1637static const SettingDesc *GetSettingFromName(std::string_view name, const SettingTable &settings)
1638{
1639 /* First check all full names */
1640 for (auto &desc : settings) {
1641 const SettingDesc *sd = GetSettingDesc(desc);
1642 if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue;
1643 if (sd->GetName() == name) return sd;
1644 }
1645
1646 /* Then check the shortcut variant of the name. */
1647 std::string short_name_suffix = std::string{ "." }.append(name);
1648 for (auto &desc : settings) {
1649 const SettingDesc *sd = GetSettingDesc(desc);
1650 if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue;
1651 if (sd->GetName().ends_with(short_name_suffix)) return sd;
1652 }
1653
1654 return nullptr;
1655}
1656
1662void GetSaveLoadFromSettingTable(SettingTable settings, std::vector<SaveLoad> &saveloads)
1663{
1664 for (auto &desc : settings) {
1665 const SettingDesc *sd = GetSettingDesc(desc);
1666 if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue;
1667 saveloads.push_back(sd->save);
1668 }
1669}
1670
1676{
1677 static const SettingTable saveload_settings_tables[] = {
1678 _difficulty_settings,
1679 _economy_settings,
1680 _game_settings,
1681 _linkgraph_settings,
1682 _locale_settings,
1683 _pathfinding_settings,
1684 _script_settings,
1685 _world_settings,
1686 };
1687 static std::vector<SettingVariant> settings_table;
1688
1689 if (settings_table.empty()) {
1690 for (auto &saveload_settings_table : saveload_settings_tables) {
1691 for (auto &saveload_setting : saveload_settings_table) {
1692 settings_table.push_back(saveload_setting);
1693 }
1694 }
1695 }
1696
1697 return settings_table;
1698}
1699
1706static const SettingDesc *GetCompanySettingFromName(std::string_view name)
1707{
1708 static const std::string_view company_prefix = "company.";
1709 if (name.starts_with(company_prefix)) name.remove_prefix(company_prefix.size());
1710 return GetSettingFromName(name, _company_settings);
1711}
1712
1719const SettingDesc *GetSettingFromName(std::string_view name)
1720{
1721 for (auto &table : GenericSettingTables()) {
1722 auto sd = GetSettingFromName(name, table);
1723 if (sd != nullptr) return sd;
1724 }
1725 for (auto &table : PrivateSettingTables()) {
1726 auto sd = GetSettingFromName(name, table);
1727 if (sd != nullptr) return sd;
1728 }
1729 for (auto &table : SecretSettingTables()) {
1730 auto sd = GetSettingFromName(name, table);
1731 if (sd != nullptr) return sd;
1732 }
1733
1734 return GetCompanySettingFromName(name);
1735}
1736
1742std::vector<const SettingDesc *> GetFilteredSettingCollection(std::function<bool(const SettingDesc &desc)> func)
1743{
1744 std::vector<const SettingDesc *> collection;
1745
1746 for (const auto &table : GenericSettingTables()) {
1747 for (const auto &desc : table) {
1748 const auto sd = GetSettingDesc(desc);
1749 if (!func(*sd)) continue;
1750
1751 collection.push_back(sd);
1752 }
1753 }
1754
1755 return collection;
1756}
1757
1767CommandCost CmdChangeSetting(DoCommandFlags flags, const std::string &name, int32_t value)
1768{
1769 if (name.empty()) return CMD_ERROR;
1770 const SettingDesc *sd = GetSettingFromName(name);
1771
1772 if (sd == nullptr) return CMD_ERROR;
1774 if (!sd->IsIntSetting()) return CMD_ERROR;
1775
1776 if (!sd->IsEditable(true)) return CMD_ERROR;
1777
1778 if (flags.Test(DoCommandFlag::Execute)) {
1779 sd->AsIntSetting()->ChangeValue(&GetGameSettings(), value);
1780 }
1781
1782 return CommandCost();
1783}
1784
1793CommandCost CmdChangeCompanySetting(DoCommandFlags flags, const std::string &name, int32_t value)
1794{
1795 if (name.empty()) return CMD_ERROR;
1796 const SettingDesc *sd = GetCompanySettingFromName(name);
1797
1798 if (sd == nullptr) return CMD_ERROR;
1799 if (!sd->IsIntSetting()) return CMD_ERROR;
1800
1801 if (flags.Test(DoCommandFlag::Execute)) {
1803 }
1804
1805 return CommandCost();
1806}
1807
1814bool SetSettingValue(const IntSettingDesc *sd, int32_t value, bool force_newgame)
1815{
1816 const IntSettingDesc *setting = sd->AsIntSetting();
1817 if (setting->flags.Test(SettingFlag::PerCompany)) {
1818 if (Company::IsValidID(_local_company) && _game_mode != GM_MENU) {
1819 return Command<Commands::ChangeCompanySetting>::Post(setting->GetName(), value);
1820 }
1821
1822 setting->ChangeValue(&_settings_client.company, value);
1823 return true;
1824 }
1825
1826 /* If an item is company-based, we do not send it over the network
1827 * (if any) to change. Also *hack*hack* we update the _newgame version
1828 * of settings because changing a company-based setting in a game also
1829 * changes its defaults. At least that is the convention we have chosen */
1830 if (setting->flags.Test(SettingFlag::NoNetworkSync)) {
1831 if (_game_mode != GM_MENU) {
1832 setting->ChangeValue(&_settings_newgame, value);
1833 }
1834 setting->ChangeValue(&GetGameSettings(), value);
1835 return true;
1836 }
1837
1838 if (force_newgame) {
1839 setting->ChangeValue(&_settings_newgame, value);
1840 return true;
1841 }
1842
1843 /* send non-company-based settings over the network */
1845 return Command<Commands::ChangeSetting>::Post(setting->GetName(), value);
1846 }
1847 return false;
1848}
1849
1853void SetDefaultCompanySettings(CompanyID cid)
1854{
1855 Company *c = Company::Get(cid);
1857 for (auto &desc : _company_settings) {
1858 const IntSettingDesc *int_setting = GetSettingDesc(desc)->AsIntSetting();
1859 int_setting->MakeValueValidAndWrite(&c->settings, int_setting->GetDefaultValue());
1860 }
1861}
1862
1867{
1868 const void *old_object = &Company::Get(_current_company)->settings;
1869 const void *new_object = &_settings_client.company;
1870 for (auto &desc : _company_settings) {
1871 const SettingDesc *sd = GetSettingDesc(desc);
1872 uint32_t old_value = (uint32_t)sd->AsIntSetting()->Read(old_object);
1873 uint32_t new_value = (uint32_t)sd->AsIntSetting()->Read(new_object);
1874 /*
1875 * This is called from a command, and since it contains local configuration information
1876 * that the rest of the clients do not know about, we need to circumvent the normal ::Post
1877 * local command validation and immediately send the command to the server.
1878 */
1879 if (old_value != new_value) Command<Commands::ChangeCompanySetting>::SendNet(STR_NULL, _local_company, sd->GetName(), new_value);
1880 }
1881}
1882
1890bool SetSettingValue(const StringSettingDesc *sd, std::string_view value, bool force_newgame)
1891{
1893
1894 if (GetVarMemType(sd->save.conv) == SLE_VAR_STRQ && value == "(null)") {
1895 value = {};
1896 }
1897
1898 const void *object = (_game_mode == GM_MENU || force_newgame) ? &_settings_newgame : &_settings_game;
1899 sd->AsStringSetting()->ChangeValue(object, std::string{value});
1900 return true;
1901}
1902
1909void StringSettingDesc::ChangeValue(const void *object, std::string &&newval) const
1910{
1911 this->MakeValueValid(newval);
1912 if (this->pre_check != nullptr && !this->pre_check(newval)) return;
1913
1914 this->Write(object, newval);
1915 if (this->post_callback != nullptr) this->post_callback(newval);
1916
1917 if (_save_config) SaveToConfig();
1918}
1919
1920/* Those 2 functions need to be here, else we have to make some stuff non-static
1921 * and besides, it is also better to keep stuff like this at the same place */
1922void IConsoleSetSetting(std::string_view name, std::string_view value, bool force_newgame)
1923{
1924 const SettingDesc *sd = GetSettingFromName(name);
1925 /* Company settings are not in "list_settings", so don't try to modify them. */
1926 if (sd == nullptr || sd->flags.Test(SettingFlag::PerCompany)) {
1927 IConsolePrint(CC_ERROR, "'{}' is an unknown setting.", name);
1928 return;
1929 }
1930
1931 bool success = true;
1932 if (sd->IsStringSetting()) {
1933 success = SetSettingValue(sd->AsStringSetting(), value, force_newgame);
1934 } else if (sd->IsIntSetting()) {
1935 const IntSettingDesc *isd = sd->AsIntSetting();
1936 size_t val = isd->ParseValue(value);
1937 if (!_settings_error_list.empty()) {
1938 IConsolePrint(CC_ERROR, "'{}' is not a valid value for this setting.", value);
1939 _settings_error_list.clear();
1940 return;
1941 }
1942 success = SetSettingValue(isd, (int32_t)val, force_newgame);
1943 }
1944
1945 if (!success) {
1946 if (_network_server) {
1947 IConsolePrint(CC_ERROR, "This command/variable is not available during network games.");
1948 } else {
1949 IConsolePrint(CC_ERROR, "This command/variable is only available to a network server.");
1950 }
1951 }
1952}
1953
1954void IConsoleSetSetting(std::string_view name, int value)
1955{
1956 const SettingDesc *sd = GetSettingFromName(name);
1957 assert(sd != nullptr);
1958 SetSettingValue(sd->AsIntSetting(), value);
1959}
1960
1966void IConsoleGetSetting(std::string_view name, bool force_newgame)
1967{
1968 const SettingDesc *sd = GetSettingFromName(name);
1969 /* Company settings are not in "list_settings", so don't try to read them. */
1970 if (sd == nullptr || sd->flags.Test(SettingFlag::PerCompany)) {
1971 IConsolePrint(CC_ERROR, "'{}' is an unknown setting.", name);
1972 return;
1973 }
1974
1975 const void *object = (_game_mode == GM_MENU || force_newgame) ? &_settings_newgame : &_settings_game;
1976
1977 if (sd->IsStringSetting()) {
1978 IConsolePrint(CC_INFO, "Current value for '{}' is '{}'.", sd->GetName(), sd->AsStringSetting()->Read(object));
1979 } else if (sd->IsIntSetting()) {
1980 std::string value = sd->FormatValue(object);
1981 const IntSettingDesc *int_setting = sd->AsIntSetting();
1982 auto [min_val, max_val] = int_setting->GetRange();
1983 auto def_val = int_setting->GetDefaultValue();
1984 IConsolePrint(CC_INFO, "Current value for '{}' is '{}' (min: {}{}, max: {}, def: {}).",
1985 sd->GetName(), value, sd->flags.Test(SettingFlag::GuiZeroIsSpecial) ? "(0) " : "", min_val, max_val, def_val);
1986 }
1987}
1988
1989static void IConsoleListSettingsTable(const SettingTable &table, std::string_view prefilter)
1990{
1991 for (auto &desc : table) {
1992 const SettingDesc *sd = GetSettingDesc(desc);
1993 if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue;
1994 if (!prefilter.empty() && sd->GetName().find(prefilter) == std::string::npos) continue;
1995 IConsolePrint(CC_DEFAULT, "{} = {}", sd->GetName(), sd->FormatValue(&GetGameSettings()));
1996 }
1997}
1998
2004void IConsoleListSettings(std::string_view prefilter)
2005{
2006 IConsolePrint(CC_HELP, "All settings with their current value:");
2007
2008 for (auto &table : GenericSettingTables()) {
2009 IConsoleListSettingsTable(table, prefilter);
2010 }
2011 for (auto &table : PrivateSettingTables()) {
2012 IConsoleListSettingsTable(table, prefilter);
2013 }
2014 for (auto &table : SecretSettingTables()) {
2015 IConsoleListSettingsTable(table, prefilter);
2016 }
2017
2018 IConsolePrint(CC_HELP, "Use 'setting' command to change a value.");
2019}
2020
2021ScriptConfigSettings::ScriptConfigSettings()
2022{
2023 /* Instantiate here, because unique_ptr needs a complete type. */
2024}
2025
2026ScriptConfigSettings::~ScriptConfigSettings()
2027{
2028 /* Instantiate here, because unique_ptr needs a complete type. */
2029}
2030
2031ScriptConfigSettings::ScriptConfigSettings(const ScriptConfigSettings &other)
2032{
2033 *this = other;
2034}
2035
2036ScriptConfigSettings &ScriptConfigSettings::operator=(const ScriptConfigSettings &other)
2037{
2038 for (CompanyID c = CompanyID::Begin(); c < MAX_COMPANIES; ++c) {
2039 if (other.ai[c] != nullptr) {
2040 this->ai[c] = std::make_unique<AIConfig>(*other.ai[c]);
2041 }
2042 }
2043 if (other.game != nullptr) {
2044 this->game = std::make_unique<GameConfig>(*other.game);
2045 }
2046 return *this;
2047}
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.
static AIConfig * GetConfig(CompanyID company, ScriptSettingSource source=SSS_DEFAULT)
Get the config of a 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:140
static GameConfig * GetConfig(ScriptSettingSource source=SSS_DEFAULT)
Get the config of a company.
@ SSS_FORCE_NEWGAME
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:260
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:48
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:75
bool _networking
are we in networking mode?
Definition network.cpp:66
StringList _network_ban_list
The banned clients.
Definition network.cpp:76
bool _network_server
network-server is active
Definition network.cpp:67
StringList _network_bind_list
The addresses to bind on.
Definition network.cpp:74
Basic functions/variables used all over the place.
Network functions used by other parts of OpenTTD.
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, and terminate.
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:836
int64_t ReadValue(const void *ptr, VarType conv)
Return a signed-long version of the value of a setting.
Definition saveload.cpp:812
@ SLE_VAR_NULL
useful to write zeros in savegame.
Definition saveload.h:688
@ SLE_VAR_STR
string pointer
Definition saveload.h:689
@ SLE_VAR_STRQ
string pointer enclosed in quotes
Definition saveload.h:690
constexpr size_t SlVarSize(VarType type)
Return expect size in bytes of a VarType.
Definition saveload.h:818
void * GetVariableAddress(const void *object, const SaveLoad &sld)
Get the address of the variable.
Definition saveload.h:1337
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:1326
constexpr VarType GetVarMemType(VarType type)
Get the NumberType of a setting.
Definition saveload.h:787
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:870
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:939
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:832
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:617
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:282
static std::optional< std::vector< uint32_t > > ParseIntList(std::string_view str)
Parse a string into a vector of uint32s.
Definition settings.cpp:247
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:166
@ IFV_0
0 All versions prior to introduction.
Definition settings.cpp:167
@ IFV_AUTOSAVE_RENAME
5 PR#11143 Renamed values of autosave to be in minutes.
Definition settings.cpp:173
@ IFV_LINKGRAPH_SECONDS
3 PR#10610 Store linkgraph update intervals in seconds instead of days.
Definition settings.cpp:170
@ IFV_REMOVE_GENERATION_SEED
7 PR#11927 Remove "generation_seed" from configuration.
Definition settings.cpp:175
@ IFV_MAX_VERSION
Highest possible ini-file version.
Definition settings.cpp:177
@ IFV_NETWORK_PRIVATE_SETTINGS
4 PR#10762 Move use_relay_service to private settings.
Definition settings.cpp:171
@ IFV_GAME_TYPE
2 PR#9515 Convert server_advertise to server_game_type.
Definition settings.cpp:169
@ IFV_RIGHT_CLICK_CLOSE
6 PR#10204 Add alternative right click to close windows setting.
Definition settings.cpp:174
@ IFV_PRIVATE_SECRETS
1 PR#9298 Moving of settings from openttd.cfg to private.cfg / secrets.cfg.
Definition settings.cpp:168
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:854
const uint16_t INIFILE_VERSION
Current ini-file version of OpenTTD.
Definition settings.cpp:180
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:702
static auto & SecretSettingTables()
List of all the secrets setting tables.
Definition settings.cpp:114
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:103
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:221
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:81
void IniSaveWindowSettings(IniFile &ini, std::string_view grpname, WindowDesc *desc)
Save a WindowDesc to config.
Definition settings.cpp:881
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:570
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:744
static std::optional< bool > ParseSingleValue(std::string_view str)
Find whether a string was a boolean true or a boolean false.
Definition settings.cpp:206
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:408
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:86
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:499
void ResetToDefault(void *object) const override
Reset the setting to its default value.
Definition settings.cpp:763
std::string FormatValue(const void *object) const override
Format the value of the setting associated with this object.
Definition settings.cpp:733
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:473
StringID GetTitle() const
Get the title of the setting.
Definition settings.cpp:424
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:750
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:464
void Write(const void *object, int32_t value) const
Set the value of a setting.
Definition settings.cpp:553
StringID GetHelp() const
Get the help text of the setting.
Definition settings.cpp:433
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:484
std::pair< StringParameter, StringParameter > GetValueParams(int32_t value) const
Get parameters for drawing the value of the setting.
Definition settings.cpp:442
int32_t Read(const void *object) const
Read the integer from the the actual setting.
Definition settings.cpp:564
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:364
bool IsDefaultValue(void *object) const override
Check whether the value is the same as the default value.
Definition settings.cpp:757
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:671
void ResetToDefault(void *object) const override
Reset the setting to its default value.
Definition settings.cpp:817
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:805
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:307
bool IsDefaultValue(void *object) const override
Check whether the value is the same as the default value.
Definition settings.cpp:811
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:397
std::string FormatValue(const void *object) const override
Format the value of the setting associated with this object.
Definition settings.cpp:344
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:338
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:188
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:383
static Company * Get(auto index)
SaveLoadVersion version_to
Save/load the variable before this savegame version.
Definition saveload.h:759
VarType conv
Type of the variable to be saved; this field combines both FileVarType and MemVarType.
Definition saveload.h:756
SaveLoadVersion version_from
Save/load the variable starting from this savegame version.
Definition saveload.h:758
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
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:891
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:908
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:928
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:918
String settings.
const std::string & Read(const void *object) const
Read the string from the the actual setting.
Definition settings.cpp:603
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:593
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:577
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:784
bool IsDefaultValue(void *object) const override
Check whether the value is the same as the default value.
Definition settings.cpp:794
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:800
std::string FormatValue(const void *object) const override
Format the value of the setting associated with this object.
Definition settings.cpp:768
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:664
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:3218
Window * FindWindowById(WindowClass cls, WindowNumber number)
Find a window by its class and window number.
Definition window.cpp:1155
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: