OpenTTD Source 20250205-master-gfd85ab1e2c
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 <http://www.gnu.org/licenses/>.
6 */
7
24#include "stdafx.h"
25#include <charconv>
26#include "settings_table.h"
27#include "debug.h"
28#include "currency.h"
29#include "network/network.h"
31#include "network/core/config.h"
32#include "command_func.h"
33#include "console_func.h"
34#include "genworld.h"
35#include "string_func.h"
36#include "window_func.h"
37#include "company_func.h"
38#include "rev.h"
39#include "error.h"
40#include "gamelog.h"
41#include "settings_func.h"
42#include "ini_type.h"
43#include "ai/ai_config.hpp"
44#include "game/game_config.hpp"
45#include "newgrf_config.h"
46#include "picker_func.h"
47#include "base_media_base.h"
48#include "fios.h"
49#include "fileio_func.h"
50#include "settings_cmd.h"
51
52#include "table/strings.h"
53
54#include "safeguards.h"
55
60std::string _config_file;
61std::string _private_file;
62std::string _secrets_file;
63std::string _favs_file;
64
66
78{
79 static const SettingTable _generic_setting_tables[] = {
80 _difficulty_settings,
81 _economy_settings,
82 _game_settings,
83 _gui_settings,
84 _linkgraph_settings,
85 _locale_settings,
86 _multimedia_settings,
87 _network_settings,
88 _news_display_settings,
89 _pathfinding_settings,
90 _script_settings,
91 _world_settings,
92 };
93 return _generic_setting_tables;
94}
95
100{
101 static const SettingTable _private_setting_tables[] = {
102 _network_private_settings,
103 };
104 return _private_setting_tables;
105}
106
111{
112 static const SettingTable _secrets_setting_tables[] = {
113 _network_secrets_settings,
114 };
115 return _secrets_setting_tables;
116}
117
118typedef void SettingDescProc(IniFile &ini, const SettingTable &desc, const char *grpname, void *object, bool only_startup);
119typedef void SettingDescProcList(IniFile &ini, const char *grpname, StringList &list);
120
121static bool IsSignedVarMemType(VarType vt)
122{
123 switch (GetVarMemType(vt)) {
124 case SLE_VAR_I8:
125 case SLE_VAR_I16:
126 case SLE_VAR_I32:
127 case SLE_VAR_I64:
128 return true;
129 }
130 return false;
131}
132
136class ConfigIniFile : public IniFile {
137private:
138 inline static const IniGroupNameList list_group_names = {
139 "bans",
140 "newgrf",
141 "servers",
142 "server_bind_addresses",
143 "server_authorized_keys",
144 "rcon_authorized_keys",
145 "admin_authorized_keys"
146 };
147
148public:
149 ConfigIniFile(const std::string &filename) : IniFile(list_group_names)
150 {
151 this->LoadFromDisk(filename, NO_DIRECTORY);
152 }
153};
154
175
177
185size_t OneOfManySettingDesc::ParseSingleValue(const char *str, size_t len, const std::vector<std::string> &many)
186{
187 /* check if it's an integer */
188 if (isdigit(*str)) return std::strtoul(str, nullptr, 0);
189
190 size_t idx = 0;
191 for (auto one : many) {
192 if (one.size() == len && strncmp(one.c_str(), str, len) == 0) return idx;
193 idx++;
194 }
195
196 return SIZE_MAX;
197}
198
205std::optional<bool> BoolSettingDesc::ParseSingleValue(const char *str)
206{
207 if (strcmp(str, "true") == 0 || strcmp(str, "on") == 0 || strcmp(str, "1") == 0) return true;
208 if (strcmp(str, "false") == 0 || strcmp(str, "off") == 0 || strcmp(str, "0") == 0) return false;
209
210 return std::nullopt;
211}
212
220static size_t LookupManyOfMany(const std::vector<std::string> &many, const char *str)
221{
222 const char *s;
223 size_t r;
224 size_t res = 0;
225
226 for (;;) {
227 /* skip "whitespace" */
228 while (*str == ' ' || *str == '\t' || *str == '|') str++;
229 if (*str == 0) break;
230
231 s = str;
232 while (*s != 0 && *s != ' ' && *s != '\t' && *s != '|') s++;
233
234 r = OneOfManySettingDesc::ParseSingleValue(str, s - str, many);
235 if (r == SIZE_MAX) return r;
236
237 SetBit(res, (uint8_t)r); // value found, set it
238 if (*s == 0) break;
239 str = s + 1;
240 }
241 return res;
242}
243
249static std::optional<std::vector<uint32_t>> ParseIntList(const char *p)
250{
251 bool comma = false; // do we accept comma?
252 std::vector<uint32_t> result;
253
254 while (*p != '\0') {
255 switch (*p) {
256 case ',':
257 /* Do not accept multiple commas between numbers */
258 if (!comma) return std::nullopt;
259 comma = false;
260 [[fallthrough]];
261
262 case ' ':
263 p++;
264 break;
265
266 default: {
267 char *end;
268 unsigned long v = std::strtoul(p, &end, 0);
269 if (p == end) return std::nullopt; // invalid character (not a number)
270
271 result.push_back(ClampTo<uint32_t>(v));
272 p = end; // first non-number
273 comma = true; // we accept comma now
274 break;
275 }
276 }
277 }
278
279 /* If we have read comma but no number after it, fail.
280 * We have read comma when (n != 0) and comma is not allowed */
281 if (!result.empty() && !comma) return std::nullopt;
282
283 return result;
284}
285
294static bool LoadIntList(const char *str, void *array, int nelems, VarType type)
295{
296 size_t elem_size = SlVarSize(type);
297 if (str == nullptr) {
298 memset(array, 0, nelems * elem_size);
299 return true;
300 }
301
302 auto opt_items = ParseIntList(str);
303 if (!opt_items.has_value() || opt_items->size() != (size_t)nelems) return false;
304
305 char *p = static_cast<char *>(array);
306 for (auto item : *opt_items) {
307 WriteValue(p, type, item);
308 p += elem_size;
309 }
310 return true;
311}
312
322std::string ListSettingDesc::FormatValue(const void *object) const
323{
324 const uint8_t *p = static_cast<const uint8_t *>(GetVariableAddress(object, this->save));
325
326 std::string result;
327 for (size_t i = 0; i != this->save.length; i++) {
328 int64_t v;
329 switch (GetVarMemType(this->save.conv)) {
330 case SLE_VAR_BL:
331 case SLE_VAR_I8: v = *(const int8_t *)p; p += 1; break;
332 case SLE_VAR_U8: v = *(const uint8_t *)p; p += 1; break;
333 case SLE_VAR_I16: v = *(const int16_t *)p; p += 2; break;
334 case SLE_VAR_U16: v = *(const uint16_t *)p; p += 2; break;
335 case SLE_VAR_I32: v = *(const int32_t *)p; p += 4; break;
336 case SLE_VAR_U32: v = *(const uint32_t *)p; p += 4; break;
337 default: NOT_REACHED();
338 }
339 if (i != 0) result += ',';
340 result += std::to_string(v);
341 }
342 return result;
343}
344
345std::string OneOfManySettingDesc::FormatSingleValue(uint id) const
346{
347 if (id >= this->many.size()) {
348 return std::to_string(id);
349 }
350 return this->many[id];
351}
352
353std::string OneOfManySettingDesc::FormatValue(const void *object) const
354{
355 uint id = (uint)this->Read(object);
356 return this->FormatSingleValue(id);
357}
358
359std::string ManyOfManySettingDesc::FormatValue(const void *object) const
360{
361 uint bitmask = (uint)this->Read(object);
362 if (bitmask == 0) {
363 return {};
364 }
365
366 std::string result;
367 for (uint id : SetBitIterator(bitmask)) {
368 if (!result.empty()) result += '|';
369 result += this->FormatSingleValue(id);
370 }
371 return result;
372}
373
379size_t IntSettingDesc::ParseValue(const char *str) const
380{
381 char *end;
382 size_t val = std::strtoul(str, &end, 0);
383 if (end == str) {
384 ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_VALUE);
385 msg.SetDParamStr(0, str);
386 msg.SetDParamStr(1, this->GetName());
387 _settings_error_list.push_back(msg);
388 return this->GetDefaultValue();
389 }
390 if (*end != '\0') {
391 ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_TRAILING_CHARACTERS);
392 msg.SetDParamStr(0, this->GetName());
393 _settings_error_list.push_back(msg);
394 }
395 return val;
396}
397
398size_t OneOfManySettingDesc::ParseValue(const char *str) const
399{
400 size_t r = OneOfManySettingDesc::ParseSingleValue(str, strlen(str), this->many);
401 /* if the first attempt of conversion from string to the appropriate value fails,
402 * look if we have defined a converter from old value to new value. */
403 if (r == SIZE_MAX && this->many_cnvt != nullptr) r = this->many_cnvt(str);
404 if (r != SIZE_MAX) return r; // and here goes converted value
405
406 ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_VALUE);
407 msg.SetDParamStr(0, str);
408 msg.SetDParamStr(1, this->GetName());
409 _settings_error_list.push_back(msg);
410 return this->GetDefaultValue();
411}
412
413size_t ManyOfManySettingDesc::ParseValue(const char *str) const
414{
415 size_t r = LookupManyOfMany(this->many, str);
416 if (r != SIZE_MAX) return r;
417 ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_VALUE);
418 msg.SetDParamStr(0, str);
419 msg.SetDParamStr(1, this->GetName());
420 _settings_error_list.push_back(msg);
421 return this->GetDefaultValue();
422}
423
424size_t BoolSettingDesc::ParseValue(const char *str) const
425{
427 if (r.has_value()) return *r;
428
429 ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_VALUE);
430 msg.SetDParamStr(0, str);
431 msg.SetDParamStr(1, this->GetName());
432 _settings_error_list.push_back(msg);
433 return this->GetDefaultValue();
434}
435
442{
443 return this->get_title_cb != nullptr ? this->get_title_cb(*this) : this->str;
444}
445
451{
452 return this->get_help_cb != nullptr ? this->get_help_cb(*this) : this->str_help;
453}
454
460void IntSettingDesc::SetValueDParams(uint first_param, int32_t value) const
461{
462 auto [min_val, _] = this->GetRange();
463 if (this->set_value_dparams_cb != nullptr) {
464 this->set_value_dparams_cb(*this, first_param, value);
465 } else if (this->IsBoolSetting()) {
466 SetDParam(first_param++, value != 0 ? STR_CONFIG_SETTING_ON : STR_CONFIG_SETTING_OFF);
467 } else {
469 SetDParam(first_param++, this->str_val - min_val + value);
470 } else {
471 SetDParam(first_param++, this->str_val + ((value == 0 && this->flags.Test(SettingFlag::GuiZeroIsSpecial)) ? 1 : 0));
472 }
473 SetDParam(first_param++, value);
474 }
475}
476
482{
483 return this->get_def_cb != nullptr ? this->get_def_cb(*this) : this->def;
484}
485
490std::tuple<int32_t, uint32_t> IntSettingDesc::GetRange() const
491{
492 return this->get_range_cb != nullptr ? this->get_range_cb(*this) : std::tuple(this->min, this->max);
493}
494
501void IntSettingDesc::MakeValueValidAndWrite(const void *object, int32_t val) const
502{
503 this->MakeValueValid(val);
504 this->Write(object, val);
505}
506
516void IntSettingDesc::MakeValueValid(int32_t &val) const
517{
518 auto [min_val, max_val] = this->GetRange();
519 /* We need to take special care of the uint32_t type as we receive from the function
520 * a signed integer. While here also bail out on 64-bit settings as those are not
521 * supported. Unsigned 8 and 16-bit variables are safe since they fit into a signed
522 * 32-bit variable
523 * TODO: Support 64-bit settings/variables; requires 64 bit over command protocol! */
524 switch (GetVarMemType(this->save.conv)) {
525 case SLE_VAR_NULL: return;
526 case SLE_VAR_BL:
527 case SLE_VAR_I8:
528 case SLE_VAR_U8:
529 case SLE_VAR_I16:
530 case SLE_VAR_U16:
531 case SLE_VAR_I32: {
532 /* Override the minimum value. No value below this->min, except special value 0 */
533 if (!this->flags.Test(SettingFlag::GuiZeroIsSpecial) || val != 0) {
534 if (!this->flags.Test(SettingFlag::GuiDropdown)) {
535 /* Clamp value-type setting to its valid range */
536 val = Clamp(val, min_val, max_val);
537 } else if (val < min_val || val > static_cast<int32_t>(max_val)) {
538 /* Reset invalid discrete setting (where different values change gameplay) to its default value */
539 val = this->GetDefaultValue();
540 }
541 }
542 break;
543 }
544 case SLE_VAR_U32: {
545 /* Override the minimum value. No value below this->min, except special value 0 */
546 uint32_t uval = static_cast<uint32_t>(val);
547 if (!this->flags.Test(SettingFlag::GuiZeroIsSpecial) || uval != 0) {
548 if (!this->flags.Test(SettingFlag::GuiDropdown)) {
549 /* Clamp value-type setting to its valid range */
550 uval = ClampU(uval, min_val, max_val);
551 } else if (uval < static_cast<uint32_t>(min_val) || uval > max_val) {
552 /* Reset invalid discrete setting to its default value */
553 uval = static_cast<uint32_t>(this->GetDefaultValue());
554 }
555 }
556 val = static_cast<int32_t>(uval);
557 return;
558 }
559 case SLE_VAR_I64:
560 case SLE_VAR_U64:
561 default: NOT_REACHED();
562 }
563}
564
570void IntSettingDesc::Write(const void *object, int32_t val) const
571{
572 void *ptr = GetVariableAddress(object, this->save);
573 WriteValue(ptr, this->save.conv, (int64_t)val);
574}
575
581int32_t IntSettingDesc::Read(const void *object) const
582{
583 void *ptr = GetVariableAddress(object, this->save);
584 return (int32_t)ReadValue(ptr, this->save.conv);
585}
586
594void StringSettingDesc::MakeValueValid(std::string &str) const
595{
596 if (this->max_length == 0 || str.size() < this->max_length) return;
597
598 /* In case a maximum length is imposed by the setting, the length
599 * includes the '\0' termination for network transfer purposes.
600 * Also ensure the string is valid after chopping of some bytes. */
601 std::string stdstr(str, 0, this->max_length - 1);
602 str.assign(StrMakeValid(stdstr, SVS_NONE));
603}
604
610void StringSettingDesc::Write(const void *object, const std::string &str) const
611{
612 reinterpret_cast<std::string *>(GetVariableAddress(object, this->save))->assign(str);
613}
614
620const std::string &StringSettingDesc::Read(const void *object) const
621{
622 return *reinterpret_cast<std::string *>(GetVariableAddress(object, this->save));
623}
624
634static void IniLoadSettings(IniFile &ini, const SettingTable &settings_table, const char *grpname, void *object, bool only_startup)
635{
636 const IniGroup *group;
637 const IniGroup *group_def = ini.GetGroup(grpname);
638
639 for (auto &desc : settings_table) {
640 const SettingDesc *sd = GetSettingDesc(desc);
642 if (sd->startup != only_startup) continue;
643
644 /* For settings.xx.yy load the settings from [xx] yy = ? */
645 std::string s{ sd->GetName() };
646 auto sc = s.find('.');
647 if (sc != std::string::npos) {
648 group = ini.GetGroup(s.substr(0, sc));
649 if (group == nullptr) group = group_def;
650 s = s.substr(sc + 1);
651 } else {
652 group = group_def;
653 }
654
655 const IniItem *item = nullptr;
656 if (group != nullptr) item = group->GetItem(s);
657 if (item == nullptr && group != group_def && group_def != nullptr) {
658 /* For settings.xx.yy load the settings from [settings] yy = ? in case the previous
659 * did not exist (e.g. loading old config files with a [settings] section */
660 item = group_def->GetItem(s);
661 }
662 if (item == nullptr) {
663 /* For settings.xx.zz.yy load the settings from [zz] yy = ? in case the previous
664 * did not exist (e.g. loading old config files with a [yapf] section */
665 sc = s.find('.');
666 if (sc != std::string::npos) {
667 if (group = ini.GetGroup(s.substr(0, sc)); group != nullptr) item = group->GetItem(s.substr(sc + 1));
668 }
669 }
670
671 sd->ParseValue(item, object);
672 }
673}
674
675void IntSettingDesc::ParseValue(const IniItem *item, void *object) const
676{
677 size_t val = (item == nullptr) ? this->GetDefaultValue() : this->ParseValue(item->value.has_value() ? item->value->c_str() : "");
678 this->MakeValueValidAndWrite(object, (int32_t)val);
679}
680
681void StringSettingDesc::ParseValue(const IniItem *item, void *object) const
682{
683 std::string str = (item == nullptr) ? this->def : item->value.value_or("");
684 this->MakeValueValid(str);
685 this->Write(object, str);
686}
687
688void ListSettingDesc::ParseValue(const IniItem *item, void *object) const
689{
690 const char *str = (item == nullptr) ? this->def : item->value.has_value() ? item->value->c_str() : nullptr;
691 void *ptr = GetVariableAddress(object, this->save);
692 if (!LoadIntList(str, ptr, this->save.length, GetVarMemType(this->save.conv))) {
693 ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_ARRAY);
694 msg.SetDParamStr(0, this->GetName());
695 _settings_error_list.push_back(msg);
696
697 /* Use default */
698 LoadIntList(this->def, ptr, this->save.length, GetVarMemType(this->save.conv));
699 }
700}
701
714static void IniSaveSettings(IniFile &ini, const SettingTable &settings_table, const char *grpname, void *object, bool)
715{
716 IniGroup *group_def = nullptr, *group;
717
718 for (auto &desc : settings_table) {
719 const SettingDesc *sd = GetSettingDesc(desc);
720 /* If the setting is not saved to the configuration
721 * file, just continue with the next setting */
723 if (sd->flags.Test(SettingFlag::NotInConfig)) continue;
724
725 /* XXX - wtf is this?? (group override?) */
726 std::string s{ sd->GetName() };
727 auto sc = s.find('.');
728 if (sc != std::string::npos) {
729 group = &ini.GetOrCreateGroup(s.substr(0, sc));
730 s = s.substr(sc + 1);
731 } else {
732 if (group_def == nullptr) group_def = &ini.GetOrCreateGroup(grpname);
733 group = group_def;
734 }
735
736 IniItem &item = group->GetOrCreateItem(s);
737
738 if (!item.value.has_value() || !sd->IsSameValue(&item, object)) {
739 /* The value is different, that means we have to write it to the ini */
740 item.value.emplace(sd->FormatValue(object));
741 }
742 }
743}
744
745std::string IntSettingDesc::FormatValue(const void *object) const
746{
747 int64_t i;
748 if (IsSignedVarMemType(this->save.conv)) {
749 i = this->Read(object);
750 } else {
751 i = (uint32_t)this->Read(object);
752 }
753 return std::to_string(i);
754}
755
756std::string BoolSettingDesc::FormatValue(const void *object) const
757{
758 bool val = this->Read(object) != 0;
759 return val ? "true" : "false";
760}
761
762bool IntSettingDesc::IsSameValue(const IniItem *item, void *object) const
763{
764 int32_t item_value = (int32_t)this->ParseValue(item->value->c_str());
765 int32_t object_value = this->Read(object);
766 return item_value == object_value;
767}
768
769bool IntSettingDesc::IsDefaultValue(void *object) const
770{
771 int32_t object_value = this->Read(object);
772 return this->GetDefaultValue() == object_value;
773}
774
775void IntSettingDesc::ResetToDefault(void *object) const
776{
777 this->Write(object, this->GetDefaultValue());
778}
779
780std::string StringSettingDesc::FormatValue(const void *object) const
781{
782 const std::string &str = this->Read(object);
783 switch (GetVarMemType(this->save.conv)) {
784 case SLE_VAR_STR: return str;
785
786 case SLE_VAR_STRQ:
787 if (str.empty()) {
788 return str;
789 }
790 return fmt::format("\"{}\"", str);
791
792 default: NOT_REACHED();
793 }
794}
795
796bool StringSettingDesc::IsSameValue(const IniItem *item, void *object) const
797{
798 /* The ini parsing removes the quotes, which are needed to retain the spaces in STRQs,
799 * so those values are always different in the parsed ini item than they should be. */
800 if (GetVarMemType(this->save.conv) == SLE_VAR_STRQ) return false;
801
802 const std::string &str = this->Read(object);
803 return item->value->compare(str) == 0;
804}
805
806bool StringSettingDesc::IsDefaultValue(void *object) const
807{
808 const std::string &str = this->Read(object);
809 return this->def == str;
810}
811
812void StringSettingDesc::ResetToDefault(void *object) const
813{
814 this->Write(object, this->def);
815}
816
817bool ListSettingDesc::IsSameValue(const IniItem *, void *) const
818{
819 /* Checking for equality is way more expensive than just writing the value. */
820 return false;
821}
822
824{
825 /* Defaults of lists are often complicated, and hard to compare. */
826 return false;
827}
828
830{
831 /* Resetting a list to default is not supported. */
832 NOT_REACHED();
833}
834
844static void IniLoadSettingList(IniFile &ini, const char *grpname, StringList &list)
845{
846 const IniGroup *group = ini.GetGroup(grpname);
847
848 if (group == nullptr) return;
849
850 list.clear();
851
852 for (const IniItem &item : group->items) {
853 if (!item.name.empty()) list.push_back(item.name);
854 }
855}
856
866static void IniSaveSettingList(IniFile &ini, const char *grpname, StringList &list)
867{
868 IniGroup &group = ini.GetOrCreateGroup(grpname);
869 group.Clear();
870
871 for (const auto &iter : list) {
872 group.GetOrCreateItem(iter).SetValue("");
873 }
874}
875
882void IniLoadWindowSettings(IniFile &ini, const char *grpname, void *desc)
883{
884 IniLoadSettings(ini, _window_settings, grpname, desc, false);
885}
886
893void IniSaveWindowSettings(IniFile &ini, const char *grpname, void *desc)
894{
895 IniSaveSettings(ini, _window_settings, grpname, desc, false);
896}
897
903bool SettingDesc::IsEditable(bool do_command) const
904{
905 if (!do_command && !this->flags.Test(SettingFlag::NoNetworkSync) && _networking && !_network_server && !this->flags.Test(SettingFlag::PerCompany)) return false;
906 if (do_command && this->flags.Test(SettingFlag::NoNetworkSync)) return false;
907 if (this->flags.Test(SettingFlag::NetworkOnly) && !_networking && _game_mode != GM_MENU) return false;
908 if (this->flags.Test(SettingFlag::NoNetwork) && _networking) return false;
910 (_game_mode == GM_NORMAL ||
911 (_game_mode == GM_EDITOR && !this->flags.Test(SettingFlag::SceneditToo)))) return false;
912 if (this->flags.Test(SettingFlag::SceneditOnly) && _game_mode != GM_EDITOR) return false;
913 return true;
914}
915
925
931{
932 assert(this->IsIntSetting());
933 return static_cast<const IntSettingDesc *>(this);
934}
935
941{
942 assert(this->IsStringSetting());
943 return static_cast<const StringSettingDesc *>(this);
944}
945
947void HandleOldDiffCustom(bool savegame);
948
949
959
960static void AILoadConfig(const IniFile &ini, const char *grpname)
961{
962 const IniGroup *group = ini.GetGroup(grpname);
963
964 /* Clean any configured AI */
965 for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) {
967 }
968
969 /* If no group exists, return */
970 if (group == nullptr) return;
971
973 for (const IniItem &item : group->items) {
975
976 config->Change(item.name);
977 if (!config->HasScript()) {
978 if (item.name != "none") {
979 Debug(script, 0, "The AI by the name '{}' was no longer found, and removed from the list.", item.name);
980 continue;
981 }
982 }
983 if (item.value.has_value()) config->StringToSettings(*item.value);
984 c++;
985 if (c >= MAX_COMPANIES) break;
986 }
987}
988
989static void GameLoadConfig(const IniFile &ini, const char *grpname)
990{
991 const IniGroup *group = ini.GetGroup(grpname);
992
993 /* Clean any configured GameScript */
995
996 /* If no group exists, return */
997 if (group == nullptr || group->items.empty()) return;
998
999 const IniItem &item = group->items.front();
1000
1002
1003 config->Change(item.name);
1004 if (!config->HasScript()) {
1005 if (item.name != "none") {
1006 Debug(script, 0, "The GameScript by the name '{}' was no longer found, and removed from the list.", item.name);
1007 return;
1008 }
1009 }
1010 if (item.value.has_value()) config->StringToSettings(*item.value);
1011}
1012
1017{
1018 if (const IniGroup *group = ini.GetGroup("misc"); group != nullptr) {
1019 /* Load old setting first. */
1020 if (const IniItem *item = group->GetItem("graphicsset"); item != nullptr && item->value) BaseGraphics::ini_data.name = *item->value;
1021 }
1022
1023 if (const IniGroup *group = ini.GetGroup("graphicsset"); group != nullptr) {
1024 /* Load new settings. */
1025 if (const IniItem *item = group->GetItem("name"); item != nullptr && item->value) BaseGraphics::ini_data.name = *item->value;
1026
1027 if (const IniItem *item = group->GetItem("shortname"); item != nullptr && item->value && item->value->size() == 8) {
1028 BaseGraphics::ini_data.shortname = std::byteswap<uint32_t>(std::strtoul(item->value->c_str(), nullptr, 16));
1029 }
1030
1031 if (const IniItem *item = group->GetItem("extra_version"); item != nullptr && item->value) BaseGraphics::ini_data.extra_version = std::strtoul(item->value->c_str(), nullptr, 10);
1032
1033 if (const IniItem *item = group->GetItem("extra_params"); item != nullptr && item->value) {
1034 auto params = ParseIntList(item->value->c_str());
1035 if (params.has_value()) {
1036 BaseGraphics::ini_data.extra_params = params.value();
1037 } else {
1038 SetDParamStr(0, BaseGraphics::ini_data.name);
1039 ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_ARRAY, WL_CRITICAL);
1040 }
1041 }
1042 }
1043}
1044
1051static GRFConfigList GRFLoadConfig(const IniFile &ini, const char *grpname, bool is_static)
1052{
1053 const IniGroup *group = ini.GetGroup(grpname);
1054 GRFConfigList list;
1055
1056 if (group == nullptr) return list;
1057
1058 uint num_grfs = 0;
1059 for (const IniItem &item : group->items) {
1060 std::unique_ptr<GRFConfig> c{};
1061
1062 std::array<uint8_t, 4> grfid_buf;
1063 MD5Hash md5sum;
1064 std::string_view item_name = item.name;
1065 bool has_md5sum = false;
1066
1067 /* Try reading "<grfid>|" and on success, "<md5sum>|". */
1068 auto grfid_pos = item_name.find("|");
1069 if (grfid_pos != std::string_view::npos) {
1070 std::string_view grfid_str = item_name.substr(0, grfid_pos);
1071
1072 if (ConvertHexToBytes(grfid_str, grfid_buf)) {
1073 item_name = item_name.substr(grfid_pos + 1);
1074
1075 auto md5sum_pos = item_name.find("|");
1076 if (md5sum_pos != std::string_view::npos) {
1077 std::string_view md5sum_str = item_name.substr(0, md5sum_pos);
1078
1079 has_md5sum = ConvertHexToBytes(md5sum_str, md5sum);
1080 if (has_md5sum) item_name = item_name.substr(md5sum_pos + 1);
1081 }
1082
1083 uint32_t grfid = grfid_buf[0] | (grfid_buf[1] << 8) | (grfid_buf[2] << 16) | (grfid_buf[3] << 24);
1084 if (has_md5sum) {
1085 const GRFConfig *s = FindGRFConfig(grfid, FGCM_EXACT, &md5sum);
1086 if (s != nullptr) c = std::make_unique<GRFConfig>(*s);
1087 }
1088 if (c == nullptr && !FioCheckFileExists(std::string(item_name), NEWGRF_DIR)) {
1089 const GRFConfig *s = FindGRFConfig(grfid, FGCM_NEWEST_VALID);
1090 if (s != nullptr) c = std::make_unique<GRFConfig>(*s);
1091 }
1092 }
1093 }
1094 std::string filename = std::string(item_name);
1095
1096 if (c == nullptr) c = std::make_unique<GRFConfig>(filename);
1097
1098 /* Parse parameters */
1099 if (item.value.has_value() && !item.value->empty()) {
1100 auto params = ParseIntList(item.value->c_str());
1101 if (params.has_value()) {
1102 c->SetParams(params.value());
1103 } else {
1104 SetDParamStr(0, filename);
1105 ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_ARRAY, WL_CRITICAL);
1106 }
1107 }
1108
1109 /* Check if item is valid */
1110 if (!FillGRFDetails(*c, is_static) || c->flags.Test(GRFConfigFlag::Invalid)) {
1111 if (c->status == GCS_NOT_FOUND) {
1112 SetDParam(1, STR_CONFIG_ERROR_INVALID_GRF_NOT_FOUND);
1113 } else if (c->flags.Test(GRFConfigFlag::Unsafe)) {
1114 SetDParam(1, STR_CONFIG_ERROR_INVALID_GRF_UNSAFE);
1115 } else if (c->flags.Test(GRFConfigFlag::System)) {
1116 SetDParam(1, STR_CONFIG_ERROR_INVALID_GRF_SYSTEM);
1117 } else if (c->flags.Test(GRFConfigFlag::Invalid)) {
1118 SetDParam(1, STR_CONFIG_ERROR_INVALID_GRF_INCOMPATIBLE);
1119 } else {
1120 SetDParam(1, STR_CONFIG_ERROR_INVALID_GRF_UNKNOWN);
1121 }
1122
1123 SetDParamStr(0, filename.empty() ? item.name.c_str() : filename);
1124 ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_GRF, WL_CRITICAL);
1125 continue;
1126 }
1127
1128 /* Check for duplicate GRFID (will also check for duplicate filenames) */
1129 auto found = std::ranges::find_if(list, [&c](const auto &gc) { return gc->ident.grfid == c->ident.grfid; });
1130 if (found != std::end(list)) {
1131 SetDParamStr(0, c->filename);
1132 SetDParamStr(1, (*found)->filename);
1133 ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_DUPLICATE_GRFID, WL_CRITICAL);
1134 continue;
1135 }
1136
1137 if (is_static) {
1138 /* Mark file as static to avoid saving in savegame. */
1139 c->flags.Set(GRFConfigFlag::Static);
1140 } else if (++num_grfs > NETWORK_MAX_GRF_COUNT) {
1141 /* Check we will not load more non-static NewGRFs than allowed. This could trigger issues for game servers. */
1142 ShowErrorMessage(STR_CONFIG_ERROR, STR_NEWGRF_ERROR_TOO_MANY_NEWGRFS_LOADED, WL_CRITICAL);
1143 break;
1144 }
1145
1146 /* Add item to list */
1147 list.push_back(std::move(c));
1148 }
1149
1150 return list;
1151}
1152
1153static IniFileVersion LoadVersionFromConfig(const IniFile &ini)
1154{
1155 const IniGroup *group = ini.GetGroup("version");
1156 if (group == nullptr) return IFV_0;
1157
1158 auto version_number = group->GetItem("ini_version");
1159 /* Older ini-file versions don't have this key yet. */
1160 if (version_number == nullptr || !version_number->value.has_value()) return IFV_0;
1161
1162 uint32_t version = 0;
1163 std::from_chars(version_number->value->data(), version_number->value->data() + version_number->value->size(), version);
1164
1165 return static_cast<IniFileVersion>(version);
1166}
1167
1168static void AISaveConfig(IniFile &ini, const char *grpname)
1169{
1170 IniGroup &group = ini.GetOrCreateGroup(grpname);
1171 group.Clear();
1172
1173 for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) {
1175 std::string name;
1176 std::string value = config->SettingsToString();
1177
1178 if (config->HasScript()) {
1179 name = config->GetName();
1180 } else {
1181 name = "none";
1182 }
1183
1184 group.CreateItem(name).SetValue(value);
1185 }
1186}
1187
1188static void GameSaveConfig(IniFile &ini, const char *grpname)
1189{
1190 IniGroup &group = ini.GetOrCreateGroup(grpname);
1191 group.Clear();
1192
1194 std::string name;
1195 std::string value = config->SettingsToString();
1196
1197 if (config->HasScript()) {
1198 name = config->GetName();
1199 } else {
1200 name = "none";
1201 }
1202
1203 group.CreateItem(name).SetValue(value);
1204}
1205
1211{
1212 IniGroup &group = ini.GetOrCreateGroup("version");
1213 group.GetOrCreateItem("version_string").SetValue(_openttd_revision);
1214 group.GetOrCreateItem("version_number").SetValue(fmt::format("{:08X}", _openttd_newgrf_version));
1215 group.GetOrCreateItem("ini_version").SetValue(std::to_string(INIFILE_VERSION));
1216}
1217
1222{
1223 const GraphicsSet *used_set = BaseGraphics::GetUsedSet();
1224 if (used_set == nullptr) return;
1225
1226 IniGroup &group = ini.GetOrCreateGroup("graphicsset");
1227 group.Clear();
1228
1229 group.GetOrCreateItem("name").SetValue(used_set->name);
1230 group.GetOrCreateItem("shortname").SetValue(fmt::format("{:08X}", std::byteswap(used_set->shortname)));
1231
1232 const GRFConfig *extra_cfg = used_set->GetExtraConfig();
1233 if (extra_cfg != nullptr && !extra_cfg->param.empty()) {
1234 group.GetOrCreateItem("extra_version").SetValue(fmt::format("{}", extra_cfg->version));
1235 group.GetOrCreateItem("extra_params").SetValue(GRFBuildParamList(*extra_cfg));
1236 }
1237}
1238
1239/* Save a GRF configuration to the given group name */
1240static void GRFSaveConfig(IniFile &ini, const char *grpname, const GRFConfigList &list)
1241{
1242 IniGroup &group = ini.GetOrCreateGroup(grpname);
1243 group.Clear();
1244
1245 for (const auto &c : list) {
1246 std::string key = fmt::format("{:08X}|{}|{}", std::byteswap(c->ident.grfid),
1247 FormatArrayAsHex(c->ident.md5sum), c->filename);
1249 }
1250}
1251
1252/* Common handler for saving/loading variables to the configuration file */
1253static void HandleSettingDescs(IniFile &generic_ini, IniFile &private_ini, IniFile &secrets_ini, SettingDescProc *proc, SettingDescProcList *proc_list, bool only_startup = false)
1254{
1255 proc(generic_ini, _misc_settings, "misc", nullptr, only_startup);
1256#if defined(_WIN32) && !defined(DEDICATED)
1257 proc(generic_ini, _win32_settings, "win32", nullptr, only_startup);
1258#endif /* _WIN32 */
1259
1260 /* The name "patches" is a fallback, as every setting should sets its own group. */
1261
1262 for (auto &table : GenericSettingTables()) {
1263 proc(generic_ini, table, "patches", &_settings_newgame, only_startup);
1264 }
1265 for (auto &table : PrivateSettingTables()) {
1266 proc(private_ini, table, "patches", &_settings_newgame, only_startup);
1267 }
1268 for (auto &table : SecretSettingTables()) {
1269 proc(secrets_ini, table, "patches", &_settings_newgame, only_startup);
1270 }
1271
1272 proc(generic_ini, _currency_settings, "currency", &GetCustomCurrency(), only_startup);
1273 proc(generic_ini, _company_settings, "company", &_settings_client.company, only_startup);
1274
1275 if (!only_startup) {
1276 proc_list(private_ini, "server_bind_addresses", _network_bind_list);
1277 proc_list(private_ini, "servers", _network_host_list);
1278 proc_list(private_ini, "bans", _network_ban_list);
1279 proc_list(private_ini, "server_authorized_keys", _settings_client.network.server_authorized_keys);
1280 proc_list(private_ini, "rcon_authorized_keys", _settings_client.network.rcon_authorized_keys);
1281 proc_list(private_ini, "admin_authorized_keys", _settings_client.network.admin_authorized_keys);
1282 }
1283}
1284
1294static void RemoveEntriesFromIni(IniFile &ini, const SettingTable &table)
1295{
1296 for (auto &desc : table) {
1297 const SettingDesc *sd = GetSettingDesc(desc);
1298
1299 /* For settings.xx.yy load the settings from [xx] yy = ? */
1300 std::string s{ sd->GetName() };
1301 auto sc = s.find('.');
1302 if (sc == std::string::npos) continue;
1303
1304 IniGroup *group = ini.GetGroup(s.substr(0, sc));
1305 if (group == nullptr) continue;
1306 s = s.substr(sc + 1);
1307
1308 group->RemoveItem(s);
1309 }
1310}
1311
1335bool IsConversionNeeded(const ConfigIniFile &ini, const std::string &group, const std::string &old_var, const std::string &new_var, const IniItem **old_item)
1336{
1337 *old_item = nullptr;
1338
1339 const IniGroup *igroup = ini.GetGroup(group);
1340 /* If the group doesn't exist, there is nothing to convert. */
1341 if (igroup == nullptr) return false;
1342
1343 const IniItem *tmp_old_item = igroup->GetItem(old_var);
1344 const IniItem *new_item = igroup->GetItem(new_var);
1345
1346 /* If the old item doesn't exist, there is nothing to convert. */
1347 if (tmp_old_item == nullptr) return false;
1348
1349 /* If the new item exists, it means conversion was already done. We only
1350 * do the conversion the first time, and after that these settings are
1351 * independent. This allows users to freely change between older and
1352 * newer clients without breaking anything. */
1353 if (new_item != nullptr) return false;
1354
1355 *old_item = tmp_old_item;
1356 return true;
1357}
1358
1363void LoadFromConfig(bool startup)
1364{
1365 ConfigIniFile generic_ini(_config_file);
1366 ConfigIniFile private_ini(_private_file);
1367 ConfigIniFile secrets_ini(_secrets_file);
1368 ConfigIniFile favs_ini(_favs_file);
1369
1370 if (!startup) ResetCurrencies(false); // Initialize the array of currencies, without preserving the custom one
1371
1372 IniFileVersion generic_version = LoadVersionFromConfig(generic_ini);
1373
1374 if (startup) {
1375 GraphicsSetLoadConfig(generic_ini);
1376 }
1377
1378 /* Before the split of private/secrets, we have to look in the generic for these settings. */
1379 if (generic_version < IFV_PRIVATE_SECRETS) {
1380 HandleSettingDescs(generic_ini, generic_ini, generic_ini, IniLoadSettings, IniLoadSettingList, startup);
1381 } else {
1382 HandleSettingDescs(generic_ini, private_ini, secrets_ini, IniLoadSettings, IniLoadSettingList, startup);
1383 }
1384
1385 /* Load basic settings only during bootstrap, load other settings not during bootstrap */
1386 if (!startup) {
1387 if (generic_version < IFV_LINKGRAPH_SECONDS) {
1390 }
1391
1392 /* Move use_relay_service from generic_ini to private_ini. */
1393 if (generic_version < IFV_NETWORK_PRIVATE_SETTINGS) {
1394 const IniGroup *network = generic_ini.GetGroup("network");
1395 if (network != nullptr) {
1396 const IniItem *use_relay_service = network->GetItem("use_relay_service");
1397 if (use_relay_service != nullptr) {
1398 if (use_relay_service->value == "never") {
1399 _settings_client.network.use_relay_service = UseRelayService::URS_NEVER;
1400 } else if (use_relay_service->value == "ask") {
1401 _settings_client.network.use_relay_service = UseRelayService::URS_ASK;
1402 } else if (use_relay_service->value == "allow") {
1403 _settings_client.network.use_relay_service = UseRelayService::URS_ALLOW;
1404 }
1405 }
1406 }
1407 }
1408
1409 const IniItem *old_item;
1410
1411 if (generic_version < IFV_GAME_TYPE && IsConversionNeeded(generic_ini, "network", "server_advertise", "server_game_type", &old_item)) {
1412 auto old_value = BoolSettingDesc::ParseSingleValue(old_item->value->c_str());
1413 _settings_client.network.server_game_type = old_value.value_or(false) ? SERVER_GAME_TYPE_PUBLIC : SERVER_GAME_TYPE_LOCAL;
1414 }
1415
1416 if (generic_version < IFV_AUTOSAVE_RENAME && IsConversionNeeded(generic_ini, "gui", "autosave", "autosave_interval", &old_item)) {
1417 static std::vector<std::string> _old_autosave_interval{"off", "monthly", "quarterly", "half year", "yearly"};
1418 auto old_value = OneOfManySettingDesc::ParseSingleValue(old_item->value->c_str(), old_item->value->size(), _old_autosave_interval);
1419
1420 switch (old_value) {
1421 case 0: _settings_client.gui.autosave_interval = 0; break;
1422 case 1: _settings_client.gui.autosave_interval = 10; break;
1423 case 2: _settings_client.gui.autosave_interval = 30; break;
1424 case 3: _settings_client.gui.autosave_interval = 60; break;
1425 case 4: _settings_client.gui.autosave_interval = 120; break;
1426 default: break;
1427 }
1428 }
1429
1430 /* Persist the right click close option from older versions. */
1431 if (generic_version < IFV_RIGHT_CLICK_CLOSE && IsConversionNeeded(generic_ini, "gui", "right_mouse_wnd_close", "right_click_wnd_close", &old_item)) {
1432 auto old_value = BoolSettingDesc::ParseSingleValue(old_item->value->c_str());
1433 _settings_client.gui.right_click_wnd_close = old_value.value_or(false) ? RCC_YES : RCC_NO;
1434 }
1435
1436 _grfconfig_newgame = GRFLoadConfig(generic_ini, "newgrf", false);
1437 _grfconfig_static = GRFLoadConfig(generic_ini, "newgrf-static", true);
1438 AILoadConfig(generic_ini, "ai_players");
1439 GameLoadConfig(generic_ini, "game_scripts");
1440 PickerLoadConfig(favs_ini);
1441
1443 IniLoadSettings(generic_ini, _old_gameopt_settings, "gameopt", &_settings_newgame, false);
1444 HandleOldDiffCustom(false);
1445
1448
1449 /* Display scheduled errors */
1451 if (FindWindowById(WC_ERRMSG, 0) == nullptr) ShowFirstError();
1452 }
1453}
1454
1457{
1458 ConfigIniFile generic_ini(_config_file);
1459 ConfigIniFile private_ini(_private_file);
1460 ConfigIniFile secrets_ini(_secrets_file);
1461 ConfigIniFile favs_ini(_favs_file);
1462
1463 IniFileVersion generic_version = LoadVersionFromConfig(generic_ini);
1464
1465 /* If we newly create the private/secrets file, add a dummy group on top
1466 * just so we can add a comment before it (that is how IniFile works).
1467 * This to explain what the file is about. After doing it once, never touch
1468 * it again, as otherwise we might be reverting user changes. */
1469 if (IniGroup *group = private_ini.GetGroup("private"); group != nullptr) group->comment = "; This file possibly contains private information which can identify you as person.\n";
1470 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";
1471
1472 if (generic_version == IFV_0) {
1473 /* Remove some obsolete groups. These have all been loaded into other groups. */
1474 generic_ini.RemoveGroup("patches");
1475 generic_ini.RemoveGroup("yapf");
1476 generic_ini.RemoveGroup("gameopt");
1477
1478 /* Remove all settings from the generic ini that are now in the private ini. */
1479 generic_ini.RemoveGroup("server_bind_addresses");
1480 generic_ini.RemoveGroup("servers");
1481 generic_ini.RemoveGroup("bans");
1482 for (auto &table : PrivateSettingTables()) {
1483 RemoveEntriesFromIni(generic_ini, table);
1484 }
1485
1486 /* Remove all settings from the generic ini that are now in the secrets ini. */
1487 for (auto &table : SecretSettingTables()) {
1488 RemoveEntriesFromIni(generic_ini, table);
1489 }
1490 }
1491
1492 if (generic_version < IFV_REMOVE_GENERATION_SEED) {
1493 IniGroup *game_creation = generic_ini.GetGroup("game_creation");
1494 if (game_creation != nullptr) {
1495 game_creation->RemoveItem("generation_seed");
1496 }
1497 }
1498
1499 /* These variables are migrated from generic ini to private ini now. */
1500 if (generic_version < IFV_NETWORK_PRIVATE_SETTINGS) {
1501 IniGroup *network = generic_ini.GetGroup("network");
1502 if (network != nullptr) {
1503 network->RemoveItem("use_relay_service");
1504 }
1505 }
1506
1507 HandleSettingDescs(generic_ini, private_ini, secrets_ini, IniSaveSettings, IniSaveSettingList);
1508 GraphicsSetSaveConfig(generic_ini);
1509 GRFSaveConfig(generic_ini, "newgrf", _grfconfig_newgame);
1510 GRFSaveConfig(generic_ini, "newgrf-static", _grfconfig_static);
1511 AISaveConfig(generic_ini, "ai_players");
1512 GameSaveConfig(generic_ini, "game_scripts");
1513 PickerSaveConfig(favs_ini);
1514
1515 SaveVersionInConfig(generic_ini);
1516 SaveVersionInConfig(private_ini);
1517 SaveVersionInConfig(secrets_ini);
1518 SaveVersionInConfig(favs_ini);
1519
1520 generic_ini.SaveToDisk(_config_file);
1521 private_ini.SaveToDisk(_private_file);
1522 secrets_ini.SaveToDisk(_secrets_file);
1523 favs_ini.SaveToDisk(_favs_file);
1524}
1525
1531{
1532 StringList list;
1533
1535 for (const IniGroup &group : ini.groups) {
1536 if (group.name.compare(0, 7, "preset-") == 0) {
1537 list.push_back(group.name.substr(7));
1538 }
1539 }
1540
1541 return list;
1542}
1543
1550GRFConfigList LoadGRFPresetFromConfig(const char *config_name)
1551{
1552 std::string section("preset-");
1553 section += config_name;
1554
1556 GRFConfigList config = GRFLoadConfig(ini, section.c_str(), false);
1557
1558 return config;
1559}
1560
1567void SaveGRFPresetToConfig(const char *config_name, GRFConfigList &config)
1568{
1569 std::string section("preset-");
1570 section += config_name;
1571
1573 GRFSaveConfig(ini, section.c_str(), config);
1575}
1576
1581void DeleteGRFPresetFromConfig(const char *config_name)
1582{
1583 std::string section("preset-");
1584 section += config_name;
1585
1587 ini.RemoveGroup(section);
1589}
1590
1597void IntSettingDesc::ChangeValue(const void *object, int32_t newval) const
1598{
1599 int32_t oldval = this->Read(object);
1600 this->MakeValueValid(newval);
1601 if (this->pre_check != nullptr && !this->pre_check(newval)) return;
1602 if (oldval == newval) return;
1603
1604 this->Write(object, newval);
1605 if (this->post_callback != nullptr) this->post_callback(newval);
1606
1607 if (this->flags.Test(SettingFlag::NoNetwork) || this->flags.Test(SettingFlag::Sandbox)) {
1609 _gamelog.Setting(this->GetName(), oldval, newval);
1611 }
1612
1615
1616 if (_save_config) SaveToConfig();
1617}
1618
1626static const SettingDesc *GetSettingFromName(const std::string_view name, const SettingTable &settings)
1627{
1628 /* First check all full names */
1629 for (auto &desc : settings) {
1630 const SettingDesc *sd = GetSettingDesc(desc);
1631 if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue;
1632 if (sd->GetName() == name) return sd;
1633 }
1634
1635 /* Then check the shortcut variant of the name. */
1636 std::string short_name_suffix = std::string{ "." }.append(name);
1637 for (auto &desc : settings) {
1638 const SettingDesc *sd = GetSettingDesc(desc);
1639 if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue;
1640 if (sd->GetName().ends_with(short_name_suffix)) return sd;
1641 }
1642
1643 return nullptr;
1644}
1645
1651void GetSaveLoadFromSettingTable(SettingTable settings, std::vector<SaveLoad> &saveloads)
1652{
1653 for (auto &desc : settings) {
1654 const SettingDesc *sd = GetSettingDesc(desc);
1655 if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue;
1656 saveloads.push_back(sd->save);
1657 }
1658}
1659
1666static const SettingDesc *GetCompanySettingFromName(std::string_view name)
1667{
1668 static const std::string_view company_prefix = "company.";
1669 if (name.starts_with(company_prefix)) name.remove_prefix(company_prefix.size());
1670 return GetSettingFromName(name, _company_settings);
1671}
1672
1679const SettingDesc *GetSettingFromName(const std::string_view name)
1680{
1681 for (auto &table : GenericSettingTables()) {
1682 auto sd = GetSettingFromName(name, table);
1683 if (sd != nullptr) return sd;
1684 }
1685 for (auto &table : PrivateSettingTables()) {
1686 auto sd = GetSettingFromName(name, table);
1687 if (sd != nullptr) return sd;
1688 }
1689 for (auto &table : SecretSettingTables()) {
1690 auto sd = GetSettingFromName(name, table);
1691 if (sd != nullptr) return sd;
1692 }
1693
1694 return GetCompanySettingFromName(name);
1695}
1696
1702std::vector<const SettingDesc *> GetFilteredSettingCollection(std::function<bool(const SettingDesc &desc)> func)
1703{
1704 std::vector<const SettingDesc *> collection;
1705
1706 for (const auto &table : GenericSettingTables()) {
1707 for (const auto &desc : table) {
1708 const auto sd = GetSettingDesc(desc);
1709 if (!func(*sd)) continue;
1710
1711 collection.push_back(sd);
1712 }
1713 }
1714
1715 return collection;
1716}
1717
1727CommandCost CmdChangeSetting(DoCommandFlag flags, const std::string &name, int32_t value)
1728{
1729 if (name.empty()) return CMD_ERROR;
1730 const SettingDesc *sd = GetSettingFromName(name);
1731
1732 if (sd == nullptr) return CMD_ERROR;
1734 if (!sd->IsIntSetting()) return CMD_ERROR;
1735
1736 if (!sd->IsEditable(true)) return CMD_ERROR;
1737
1738 if (flags & DC_EXEC) {
1739 sd->AsIntSetting()->ChangeValue(&GetGameSettings(), value);
1740 }
1741
1742 return CommandCost();
1743}
1744
1753CommandCost CmdChangeCompanySetting(DoCommandFlag flags, const std::string &name, int32_t value)
1754{
1755 if (name.empty()) return CMD_ERROR;
1756 const SettingDesc *sd = GetCompanySettingFromName(name);
1757
1758 if (sd == nullptr) return CMD_ERROR;
1759 if (!sd->IsIntSetting()) return CMD_ERROR;
1760
1761 if (flags & DC_EXEC) {
1763 }
1764
1765 return CommandCost();
1766}
1767
1775bool SetSettingValue(const IntSettingDesc *sd, int32_t value, bool force_newgame)
1776{
1777 const IntSettingDesc *setting = sd->AsIntSetting();
1778 if (setting->flags.Test(SettingFlag::PerCompany)) {
1779 if (Company::IsValidID(_local_company) && _game_mode != GM_MENU) {
1780 return Command<CMD_CHANGE_COMPANY_SETTING>::Post(setting->GetName(), value);
1781 }
1782
1783 setting->ChangeValue(&_settings_client.company, value);
1784 return true;
1785 }
1786
1787 /* If an item is company-based, we do not send it over the network
1788 * (if any) to change. Also *hack*hack* we update the _newgame version
1789 * of settings because changing a company-based setting in a game also
1790 * changes its defaults. At least that is the convention we have chosen */
1791 if (setting->flags.Test(SettingFlag::NoNetworkSync)) {
1792 if (_game_mode != GM_MENU) {
1793 setting->ChangeValue(&_settings_newgame, value);
1794 }
1795 setting->ChangeValue(&GetGameSettings(), value);
1796 return true;
1797 }
1798
1799 if (force_newgame) {
1800 setting->ChangeValue(&_settings_newgame, value);
1801 return true;
1802 }
1803
1804 /* send non-company-based settings over the network */
1806 return Command<CMD_CHANGE_SETTING>::Post(setting->GetName(), value);
1807 }
1808 return false;
1809}
1810
1815{
1816 Company *c = Company::Get(cid);
1818 for (auto &desc : _company_settings) {
1819 const IntSettingDesc *int_setting = GetSettingDesc(desc)->AsIntSetting();
1820 int_setting->MakeValueValidAndWrite(&c->settings, int_setting->GetDefaultValue());
1821 }
1822}
1823
1828{
1829 const void *old_object = &Company::Get(_current_company)->settings;
1830 const void *new_object = &_settings_client.company;
1831 for (auto &desc : _company_settings) {
1832 const SettingDesc *sd = GetSettingDesc(desc);
1833 uint32_t old_value = (uint32_t)sd->AsIntSetting()->Read(old_object);
1834 uint32_t new_value = (uint32_t)sd->AsIntSetting()->Read(new_object);
1835 /*
1836 * This is called from a command, and since it contains local configuration information
1837 * that the rest of the clients do not know about, we need to circumvent the normal ::Post
1838 * local command validation and immediately send the command to the server.
1839 */
1840 if (old_value != new_value) Command<CMD_CHANGE_COMPANY_SETTING>::SendNet(STR_NULL, _local_company, sd->GetName(), new_value);
1841 }
1842}
1843
1851bool SetSettingValue(const StringSettingDesc *sd, std::string value, bool force_newgame)
1852{
1854
1855 if (GetVarMemType(sd->save.conv) == SLE_VAR_STRQ && value.compare("(null)") == 0) {
1856 value.clear();
1857 }
1858
1859 const void *object = (_game_mode == GM_MENU || force_newgame) ? &_settings_newgame : &_settings_game;
1860 sd->AsStringSetting()->ChangeValue(object, value);
1861 return true;
1862}
1863
1870void StringSettingDesc::ChangeValue(const void *object, std::string &newval) const
1871{
1872 this->MakeValueValid(newval);
1873 if (this->pre_check != nullptr && !this->pre_check(newval)) return;
1874
1875 this->Write(object, newval);
1876 if (this->post_callback != nullptr) this->post_callback(newval);
1877
1878 if (_save_config) SaveToConfig();
1879}
1880
1881/* Those 2 functions need to be here, else we have to make some stuff non-static
1882 * and besides, it is also better to keep stuff like this at the same place */
1883void IConsoleSetSetting(const char *name, const char *value, bool force_newgame)
1884{
1885 const SettingDesc *sd = GetSettingFromName(name);
1886 /* Company settings are not in "list_settings", so don't try to modify them. */
1887 if (sd == nullptr || sd->flags.Test(SettingFlag::PerCompany)) {
1888 IConsolePrint(CC_ERROR, "'{}' is an unknown setting.", name);
1889 return;
1890 }
1891
1892 bool success = true;
1893 if (sd->IsStringSetting()) {
1894 success = SetSettingValue(sd->AsStringSetting(), value, force_newgame);
1895 } else if (sd->IsIntSetting()) {
1896 const IntSettingDesc *isd = sd->AsIntSetting();
1897 size_t val = isd->ParseValue(value);
1898 if (!_settings_error_list.empty()) {
1899 IConsolePrint(CC_ERROR, "'{}' is not a valid value for this setting.", value);
1900 _settings_error_list.clear();
1901 return;
1902 }
1903 success = SetSettingValue(isd, (int32_t)val, force_newgame);
1904 }
1905
1906 if (!success) {
1907 if (_network_server) {
1908 IConsolePrint(CC_ERROR, "This command/variable is not available during network games.");
1909 } else {
1910 IConsolePrint(CC_ERROR, "This command/variable is only available to a network server.");
1911 }
1912 }
1913}
1914
1915void IConsoleSetSetting(const char *name, int value)
1916{
1917 const SettingDesc *sd = GetSettingFromName(name);
1918 assert(sd != nullptr);
1919 SetSettingValue(sd->AsIntSetting(), value);
1920}
1921
1927void IConsoleGetSetting(const char *name, bool force_newgame)
1928{
1929 const SettingDesc *sd = GetSettingFromName(name);
1930 /* Company settings are not in "list_settings", so don't try to read them. */
1931 if (sd == nullptr || sd->flags.Test(SettingFlag::PerCompany)) {
1932 IConsolePrint(CC_ERROR, "'{}' is an unknown setting.", name);
1933 return;
1934 }
1935
1936 const void *object = (_game_mode == GM_MENU || force_newgame) ? &_settings_newgame : &_settings_game;
1937
1938 if (sd->IsStringSetting()) {
1939 IConsolePrint(CC_INFO, "Current value for '{}' is '{}'.", sd->GetName(), sd->AsStringSetting()->Read(object));
1940 } else if (sd->IsIntSetting()) {
1941 std::string value = sd->FormatValue(object);
1942 const IntSettingDesc *int_setting = sd->AsIntSetting();
1943 auto [min_val, max_val] = int_setting->GetRange();
1944 IConsolePrint(CC_INFO, "Current value for '{}' is '{}' (min: {}{}, max: {}).",
1945 sd->GetName(), value, sd->flags.Test(SettingFlag::GuiZeroIsSpecial) ? "(0) " : "", min_val, max_val);
1946 }
1947}
1948
1949static void IConsoleListSettingsTable(const SettingTable &table, const char *prefilter)
1950{
1951 for (auto &desc : table) {
1952 const SettingDesc *sd = GetSettingDesc(desc);
1953 if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue;
1954 if (prefilter != nullptr && sd->GetName().find(prefilter) == std::string::npos) continue;
1955 IConsolePrint(CC_DEFAULT, "{} = {}", sd->GetName(), sd->FormatValue(&GetGameSettings()));
1956 }
1957}
1958
1964void IConsoleListSettings(const char *prefilter)
1965{
1966 IConsolePrint(CC_HELP, "All settings with their current value:");
1967
1968 for (auto &table : GenericSettingTables()) {
1969 IConsoleListSettingsTable(table, prefilter);
1970 }
1971 for (auto &table : PrivateSettingTables()) {
1972 IConsoleListSettingsTable(table, prefilter);
1973 }
1974 for (auto &table : SecretSettingTables()) {
1975 IConsoleListSettingsTable(table, prefilter);
1976 }
1977
1978 IConsolePrint(CC_HELP, "Use 'setting' command to change a value.");
1979}
AIConfig stores the configuration settings of every AI.
Generic functions for replacing base data (graphics, sounds).
constexpr T SetBit(T &x, const uint8_t y)
Set a bit in a variable.
static AIConfig * GetConfig(CompanyID company, ScriptSettingSource source=SSS_DEFAULT)
Get the config of a company.
Definition ai_config.cpp:20
static const GraphicsSet * GetUsedSet()
Return the used set.
Common return value for all commands.
IniFile to store a configuration.
Definition settings.cpp:136
constexpr bool Test(Tenum value) const
Test if the enum value is set.
The data of the error message.
Definition error.h:31
void SetDParamStr(uint n, const char *str)
Set a rawstring parameter.
static GameConfig * GetConfig(ScriptSettingSource source=SSS_DEFAULT)
Get the config of a company.
void StartAction(GamelogActionType at)
Stores information about new action, but doesn't allocate it Action is allocated only when there is a...
Definition gamelog.cpp:65
void StopAction()
Stops logging of any changes.
Definition gamelog.cpp:74
void Setting(const std::string &name, int32_t oldval, int32_t newval)
Logs change in game settings.
Definition gamelog.cpp:413
@ SSS_FORCE_NEWGAME
Get the newgame Script config.
bool HasScript() const
Is this config attached to an Script? In other words, is there a Script that is assigned to this slot...
void Change(std::optional< const std::string > name, int version=-1, bool force_exact_match=false)
Set another Script to be loaded in this slot.
const std::string & GetName() const
Get the name of the Script.
void StringToSettings(const std::string &value)
Convert a string which is stored in the config file or savegames to custom settings of this Script.
std::string SettingsToString() const
Convert the custom settings to a string that can be stored in the config file or savegames.
static constexpr int SECONDS_PER_DAY
approximate seconds per day, not for precise calculations
Functions related to commands.
static const CommandCost CMD_ERROR
Define a default return value for a failed command.
DoCommandFlag
List of flags for a command.
@ DC_EXEC
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.
Owner
Enum for all companies/owners.
@ COMPANY_FIRST
First company, same as owner.
@ MAX_COMPANIES
Maximum number of 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:90
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:89
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:161
Functions to handle different currencies.
CurrencySpec & GetCustomCurrency()
Get the custom currency.
Definition currency.h:109
void DebugReconsiderSendRemoteMessages()
Reconsider whether we need to send debug messages to either NetworkAdminConsole or IConsolePrint.
Definition debug.cpp:264
Functions related to debugging.
#define Debug(category, level, format_string,...)
Ouptut 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:62
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(StringID 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(const std::string &filename, Subdirectory subdir)
Check whether the given file exists.
Definition fileio.cpp:122
Functions for Standard In/Out file operations.
@ NO_DIRECTORY
A path without any base directory.
@ NEWGRF_DIR
Subdirectory for all NewGRFs.
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:48
static const uint CUSTOM_SEA_LEVEL_MIN_PERCENTAGE
Minimum percentage a user can specify for custom sea level.
Definition genworld.h:49
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:74
bool _networking
are we in networking mode?
Definition network.cpp:65
StringList _network_ban_list
The banned clients.
Definition network.cpp:75
bool _network_server
network-server is active
Definition network.cpp:66
StringList _network_bind_list
The addresses to bind on.
Definition network.cpp:73
Basic functions/variables used all over the place.
Network functions used by other parts of OpenTTD.
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.
@ System
GRF file is an openttd-internal system grf.
@ Static
GRF file is used statically (can be used in any MP game)
@ Unsafe
GRF file is unsafe for static usage.
@ Invalid
GRF is unusable with this version of OpenTTD.
@ 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:821
int64_t ReadValue(const void *ptr, VarType conv)
Return a signed-long version of the value of a setting.
Definition saveload.cpp:797
@ SLE_VAR_NULL
useful to write zeros in savegame.
Definition saveload.h:654
@ SLE_VAR_STR
string pointer
Definition saveload.h:655
@ SLE_VAR_STRQ
string pointer enclosed in quotes
Definition saveload.h:656
constexpr size_t SlVarSize(VarType type)
Return expect size in bytes of a VarType.
Definition saveload.h:783
void * GetVariableAddress(const void *object, const SaveLoad &sld)
Get the address of the variable.
Definition saveload.h:1302
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:1291
constexpr VarType GetVarMemType(VarType type)
Get the NumberType of a setting.
Definition saveload.h:752
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.
static void RemoveEntriesFromIni(IniFile &ini, const SettingTable &table)
Remove all entries from a settings table from an ini-file.
StringList GetGRFPresetList()
Get the list of known NewGrf presets.
static void IniSaveSettings(IniFile &ini, const SettingTable &settings_table, const char *grpname, void *object, bool)
Save the values of settings to the inifile.
Definition settings.cpp:714
static void ValidateSettings()
Checks if any settings are set to incorrect values, and sets them to correct values in that case.
Definition settings.cpp:951
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.
static std::optional< std::vector< uint32_t > > ParseIntList(const char *p)
Parse a string into a vector of uint32s.
Definition settings.cpp:249
std::string _secrets_file
Secrets configuration file of OpenTTD.
Definition settings.cpp:62
std::string _favs_file
Picker favourites configuration file of OpenTTD.
Definition settings.cpp:63
static void IniLoadSettings(IniFile &ini, const SettingTable &settings_table, const char *grpname, void *object, bool only_startup)
Load values from a group of an IniFile structure into the internal representation.
Definition settings.cpp:634
static ErrorList _settings_error_list
Errors while loading minimal settings.
Definition settings.cpp:65
void IniLoadWindowSettings(IniFile &ini, const char *grpname, void *desc)
Load a WindowDesc from config.
Definition settings.cpp:882
static bool LoadIntList(const char *str, void *array, int nelems, VarType type)
Load parsed string-values into an integer-array (intlist)
Definition settings.cpp:294
void SetDefaultCompanySettings(CompanyID cid)
Set the company settings for a new company to their default values.
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.
void SaveGRFPresetToConfig(const char *config_name, GRFConfigList &config)
Save a NewGRF configuration with a 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:59
void PrepareOldDiffCustom()
Prepare for reading and old diff_custom by zero-ing the memory.
static void IniLoadSettingList(IniFile &ini, const char *grpname, StringList &list)
Loads all items from a 'grpname' section into a list The list parameter can be a nullptr pointer,...
Definition settings.cpp:844
CommandCost CmdChangeCompanySetting(DoCommandFlag flags, const std::string &name, int32_t value)
Change one of the per-company settings.
void GetSaveLoadFromSettingTable(SettingTable settings, std::vector< SaveLoad > &saveloads)
Get the SaveLoad for all settings in the settings table.
void IniSaveWindowSettings(IniFile &ini, const char *grpname, void *desc)
Save a WindowDesc to config.
Definition settings.cpp:893
static void IniSaveSettingList(IniFile &ini, const char *grpname, StringList &list)
Saves all items from a list into the 'grpname' section The list parameter can be a nullptr pointer,...
Definition settings.cpp:866
static void GraphicsSetSaveConfig(IniFile &ini)
Save BaseGraphics set selection and configuration.
GameSettings _settings_game
Game settings of a running game or the scenario editor.
Definition settings.cpp:57
static size_t LookupManyOfMany(const std::vector< std::string > &many, const char *str)
Find the set-integer value MANYofMANY type in a string.
Definition settings.cpp:220
IniFileVersion
Ini-file versions.
Definition settings.cpp:162
@ IFV_0
0 All versions prior to introduction.
Definition settings.cpp:163
@ IFV_AUTOSAVE_RENAME
5 PR#11143 Renamed values of autosave to be in minutes.
Definition settings.cpp:169
@ IFV_LINKGRAPH_SECONDS
3 PR#10610 Store linkgraph update intervals in seconds instead of days.
Definition settings.cpp:166
@ IFV_REMOVE_GENERATION_SEED
7 PR#11927 Remove "generation_seed" from configuration.
Definition settings.cpp:171
@ IFV_MAX_VERSION
Highest possible ini-file version.
Definition settings.cpp:173
@ IFV_NETWORK_PRIVATE_SETTINGS
4 PR#10762 Move use_relay_service to private settings.
Definition settings.cpp:167
@ IFV_GAME_TYPE
2 PR#9515 Convert server_advertise to server_game_type.
Definition settings.cpp:165
@ IFV_RIGHT_CLICK_CLOSE
6 PR#10204 Add alternative right click to close windows setting.
Definition settings.cpp:170
@ IFV_PRIVATE_SECRETS
1 PR#9298 Moving of settings from openttd.cfg to private.cfg / secrets.cfg.
Definition settings.cpp:164
CommandCost CmdChangeSetting(DoCommandFlag flags, const std::string &name, int32_t value)
Network-safe changing of settings (server-only).
const uint16_t INIFILE_VERSION
Current ini-file version of OpenTTD.
Definition settings.cpp:176
static auto & SecretSettingTables()
List of all the secrets setting tables.
Definition settings.cpp:110
std::string _private_file
Private configuration file of OpenTTD.
Definition settings.cpp:61
void DeleteGRFPresetFromConfig(const char *config_name)
Delete a NewGRF configuration by preset name.
static const SettingDesc * GetSettingFromName(const std::string_view name, const SettingTable &settings)
Given a name of setting, return a setting description from the table.
GameSettings _settings_newgame
Game settings for new games (updated from the intro screen).
Definition settings.cpp:58
static GRFConfigList GRFLoadConfig(const IniFile &ini, const char *grpname, bool is_static)
Load a GRF configuration.
void IConsoleGetSetting(const char *name, bool force_newgame)
Output value of a specific setting to the console.
void IConsoleListSettings(const char *prefilter)
List all settings and their value to the console.
static auto & PrivateSettingTables()
List of all the private setting tables.
Definition settings.cpp:99
static void SaveVersionInConfig(IniFile &ini)
Save the version of OpenTTD to the ini file.
std::string _config_file
Configuration file of OpenTTD.
Definition settings.cpp:60
static auto & GenericSettingTables()
List of all the generic setting tables.
Definition settings.cpp:77
GRFConfigList LoadGRFPresetFromConfig(const char *config_name)
Load a NewGRF configuration by preset-name.
static const SettingDesc * GetCompanySettingFromName(std::string_view name)
Given a name of setting, return a company setting description of it.
ClientSettings _settings_client
The current settings for this game.
Definition settings.cpp:56
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.
static void StrMakeValid(T &dst, const char *str, const char *last, StringValidationSettings settings)
Copies the valid (UTF-8) characters from str up to last to the dst.
Definition string.cpp:107
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:734
std::string FormatArrayAsHex(std::span< const uint8_t > data)
Format a byte array into a continuous hex string.
Definition string.cpp:81
Functions related to low-level strings.
@ SVS_NONE
Allow nothing and replace nothing.
Definition string_type.h:45
std::vector< std::string > StringList
Type for a list of strings.
Definition string_type.h:60
void SetDParam(size_t n, uint64_t v)
Set a string parameter v at index n in the global string parameter array.
Definition strings.cpp:104
void SetDParamStr(size_t n, const char *str)
This function is used to "bind" a C string to a OpenTTD dparam slot.
Definition strings.cpp:370
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::vector< uint32_t > extra_params
parameters for the extra GRF
uint32_t shortname
unique key for base set
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:756
static std::optional< bool > ParseSingleValue(const char *str)
Find whether a string was a boolean true or a boolean false.
Definition settings.cpp:205
size_t ParseValue(const char *str) const override
Convert a string representation (external) of an integer-like setting to an integer.
Definition settings.cpp:424
All settings that are only important for the local client.
CompanySettings company
default values for per-company settings
NetworkSettings network
settings related to the network
GUISettings gui
settings related to the GUI
CompanySettings settings
settings specific for each company
uint8_t quantity_sea_lakes
the amount of seas/lakes
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.
uint32_t autosave_interval
how often should we do autosaves?
RightClickClose right_click_wnd_close
close window with right click
uint8_t land_generator
the landscape generator
All settings together for the game.
DifficultySettings difficulty
settings related to the difficulty
GameCreationSettings game_creation
settings used during the creation of a game (map)
LinkGraphSettings linkgraph
settings for link graph calculations
All data of a graphics set.
Ini file that supports both loading and saving.
Definition ini_type.h:88
bool SaveToDisk(const std::string &filename)
Save the Ini file's data to the disk.
Definition ini.cpp:42
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:52
std::string comment
comment for group
Definition ini_type.h:38
void Clear()
Clear all items in the group.
Definition ini_load.cpp:98
void RemoveItem(std::string_view name)
Remove the item with the given name.
Definition ini_load.cpp:90
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:81
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:66
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:32
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:175
void LoadFromDisk(const std::string &filename, Subdirectory subdir)
Load the Ini file's data from the disk.
Definition ini_load.cpp:187
const IniGroup * GetGroup(std::string_view name) const
Get the group with the given name.
Definition ini_load.cpp:119
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:147
Base integer type, including boolean, settings.
void SetValueDParams(uint first_param, int32_t value) const
Set the DParams for drawing the value of the setting.
Definition settings.cpp:460
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:516
void ResetToDefault(void *object) const override
Reset the setting to its default value.
Definition settings.cpp:775
std::string FormatValue(const void *object) const override
Format the value of the setting associated with this object.
Definition settings.cpp:745
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:490
StringID GetTitle() const
Get the title of the setting.
Definition settings.cpp:441
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:762
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:481
void Write(const void *object, int32_t value) const
Set the value of a setting.
Definition settings.cpp:570
StringID GetHelp() const
Get the help text of the setting.
Definition settings.cpp:450
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:501
virtual size_t ParseValue(const char *str) const
Convert a string representation (external) of an integer-like setting to an integer.
Definition settings.cpp:379
int32_t Read(const void *object) const
Read the integer from the the actual setting.
Definition settings.cpp:581
bool IsDefaultValue(void *object) const override
Check whether the value is the same as the default value.
Definition settings.cpp:769
uint16_t recalc_time
time (in days) for recalculating each link graph component.
uint16_t recalc_interval
time (in days) between subsequent checks for link graphs to be calculated.
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:688
void ResetToDefault(void *object) const override
Reset the setting to its default value.
Definition settings.cpp:829
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:817
std::string FormatValue(const void *object) const override
Convert an integer-array (intlist) to a string representation.
Definition settings.cpp:322
const char * def
default value given when none is present
bool IsDefaultValue(void *object) const override
Check whether the value is the same as the default value.
Definition settings.cpp:823
std::string FormatValue(const void *object) const override
Format the value of the setting associated with this object.
Definition settings.cpp:359
size_t ParseValue(const char *str) const override
Convert a string representation (external) of an integer-like setting to an integer.
Definition settings.cpp:413
NetworkAuthorizedKeys admin_authorized_keys
Public keys of clients that are authorized to use the admin network.
ServerGameType server_game_type
Server type: local / public / invite-only.
NetworkAuthorizedKeys rcon_authorized_keys
Public keys of clients that are authorized to use the rconsole (server side).
UseRelayService use_relay_service
Use relay service?
NetworkAuthorizedKeys server_authorized_keys
Public keys of clients that are authorized to connect to the game.
OnConvert * many_cnvt
callback procedure when loading value mechanism fails
size_t ParseValue(const char *str) const override
Convert a string representation (external) of an integer-like setting to an integer.
Definition settings.cpp:398
static size_t ParseSingleValue(const char *str, size_t len, const std::vector< std::string > &many)
Find the index value of a ONEofMANY type in a string separated by |.
Definition settings.cpp:185
std::string FormatValue(const void *object) const override
Format the value of the setting associated with this object.
Definition settings.cpp:353
std::vector< std::string > many
possible values for this type
static bool IsValidID(size_t index)
Tests whether given index can be used to get valid (non-nullptr) Titem.
static Titem * Get(size_t index)
Returns Titem with given index.
uint16_t length
(Conditional) length of the variable (eg. arrays) (max array size is 65536 elements).
Definition saveload.h:722
SaveLoadVersion version_to
Save/load the variable before this savegame version.
Definition saveload.h:724
VarType conv
Type of the variable to be saved; this field combines both FileVarType and MemVarType.
Definition saveload.h:721
SaveLoadVersion version_from
Save/load the variable starting from this savegame version.
Definition saveload.h:723
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:903
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:920
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:940
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:930
String settings.
const std::string & Read(const void *object) const
Read the string from the the actual setting.
Definition settings.cpp:620
std::string def
Default value given when none is present.
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 MakeValueValid(std::string &str) const
Make the value valid given the limitations of this setting.
Definition settings.cpp:594
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:796
bool IsDefaultValue(void *object) const override
Check whether the value is the same as the default value.
Definition settings.cpp:806
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:812
void Write(const void *object, const std::string &str) const
Write a string to the actual setting.
Definition settings.cpp:610
void ChangeValue(const void *object, std::string &newval) const
Handle changing a string value.
std::string FormatValue(const void *object) const override
Format the value of the setting associated with this object.
Definition settings.cpp:780
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:681
Default settings for vehicles.
void SetWindowClassesDirty(WindowClass cls)
Mark all windows of a particular class as dirty (in need of repainting)
Definition window.cpp:3125
Window * FindWindowById(WindowClass cls, WindowNumber number)
Find a window by its class and window number.
Definition window.cpp:1095
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: