OpenTTD Source 15.0-beta2
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 "strings_func.h"
37#include "window_func.h"
38#include "company_func.h"
39#include "rev.h"
40#include "error.h"
41#include "gamelog.h"
42#include "settings_func.h"
43#include "ini_type.h"
44#include "ai/ai_config.hpp"
45#include "game/game_config.hpp"
46#include "newgrf_config.h"
47#include "picker_func.h"
48#include "base_media_base.h"
49#include "base_media_graphics.h"
50#include "fios.h"
51#include "fileio_func.h"
52#include "settings_cmd.h"
53
54#include "table/strings.h"
55
56#include "safeguards.h"
57
62std::string _config_file;
63std::string _private_file;
64std::string _secrets_file;
65std::string _favs_file;
66
68
80{
81 static const SettingTable _generic_setting_tables[] = {
82 _difficulty_settings,
83 _economy_settings,
84 _game_settings,
85 _gui_settings,
86 _linkgraph_settings,
87 _locale_settings,
88 _multimedia_settings,
89 _network_settings,
90 _news_display_settings,
91 _pathfinding_settings,
92 _script_settings,
93 _world_settings,
94 };
95 return _generic_setting_tables;
96}
97
102{
103 static const SettingTable _private_setting_tables[] = {
104 _network_private_settings,
105 };
106 return _private_setting_tables;
107}
108
113{
114 static const SettingTable _secrets_setting_tables[] = {
115 _network_secrets_settings,
116 };
117 return _secrets_setting_tables;
118}
119
120typedef void SettingDescProc(IniFile &ini, const SettingTable &desc, const char *grpname, void *object, bool only_startup);
121typedef void SettingDescProcList(IniFile &ini, const char *grpname, StringList &list);
122
123static bool IsSignedVarMemType(VarType vt)
124{
125 switch (GetVarMemType(vt)) {
126 case SLE_VAR_I8:
127 case SLE_VAR_I16:
128 case SLE_VAR_I32:
129 case SLE_VAR_I64:
130 return true;
131 }
132 return false;
133}
134
138class ConfigIniFile : public IniFile {
139private:
140 inline static const IniGroupNameList list_group_names = {
141 "bans",
142 "newgrf",
143 "servers",
144 "server_bind_addresses",
145 "server_authorized_keys",
146 "rcon_authorized_keys",
147 "admin_authorized_keys"
148 };
149
150public:
151 ConfigIniFile(const std::string &filename) : IniFile(list_group_names)
152 {
153 this->LoadFromDisk(filename, NO_DIRECTORY);
154 }
155};
156
177
179
187size_t OneOfManySettingDesc::ParseSingleValue(const char *str, size_t len, const std::vector<std::string> &many)
188{
189 /* check if it's an integer */
190 if (isdigit(*str)) return std::strtoul(str, nullptr, 0);
191
192 size_t idx = 0;
193 for (const auto &one : many) {
194 if (one.size() == len && strncmp(one.c_str(), str, len) == 0) return idx;
195 idx++;
196 }
197
198 return SIZE_MAX;
199}
200
207std::optional<bool> BoolSettingDesc::ParseSingleValue(const char *str)
208{
209 if (strcmp(str, "true") == 0 || strcmp(str, "on") == 0 || strcmp(str, "1") == 0) return true;
210 if (strcmp(str, "false") == 0 || strcmp(str, "off") == 0 || strcmp(str, "0") == 0) return false;
211
212 return std::nullopt;
213}
214
222static size_t LookupManyOfMany(const std::vector<std::string> &many, const char *str)
223{
224 const char *s;
225 size_t r;
226 size_t res = 0;
227
228 for (;;) {
229 /* skip "whitespace" */
230 while (*str == ' ' || *str == '\t' || *str == '|') str++;
231 if (*str == 0) break;
232
233 s = str;
234 while (*s != 0 && *s != ' ' && *s != '\t' && *s != '|') s++;
235
236 r = OneOfManySettingDesc::ParseSingleValue(str, s - str, many);
237 if (r == SIZE_MAX) return r;
238
239 SetBit(res, (uint8_t)r); // value found, set it
240 if (*s == 0) break;
241 str = s + 1;
242 }
243 return res;
244}
245
251static std::optional<std::vector<uint32_t>> ParseIntList(const char *p)
252{
253 bool comma = false; // do we accept comma?
254 std::vector<uint32_t> result;
255
256 while (*p != '\0') {
257 switch (*p) {
258 case ',':
259 /* Do not accept multiple commas between numbers */
260 if (!comma) return std::nullopt;
261 comma = false;
262 [[fallthrough]];
263
264 case ' ':
265 p++;
266 break;
267
268 default: {
269 char *end;
270 unsigned long v = std::strtoul(p, &end, 0);
271 if (p == end) return std::nullopt; // invalid character (not a number)
272
273 result.push_back(ClampTo<uint32_t>(v));
274 p = end; // first non-number
275 comma = true; // we accept comma now
276 break;
277 }
278 }
279 }
280
281 /* If we have read comma but no number after it, fail.
282 * We have read comma when (n != 0) and comma is not allowed */
283 if (!result.empty() && !comma) return std::nullopt;
284
285 return result;
286}
287
296static bool LoadIntList(const char *str, void *array, int nelems, VarType type)
297{
298 size_t elem_size = SlVarSize(type);
299 if (str == nullptr) {
300 memset(array, 0, nelems * elem_size);
301 return true;
302 }
303
304 auto opt_items = ParseIntList(str);
305 if (!opt_items.has_value() || opt_items->size() != (size_t)nelems) return false;
306
307 char *p = static_cast<char *>(array);
308 for (auto item : *opt_items) {
309 WriteValue(p, type, item);
310 p += elem_size;
311 }
312 return true;
313}
314
324std::string ListSettingDesc::FormatValue(const void *object) const
325{
326 const uint8_t *p = static_cast<const uint8_t *>(GetVariableAddress(object, this->save));
327
328 std::string result;
329 for (size_t i = 0; i != this->save.length; i++) {
330 int64_t v;
331 switch (GetVarMemType(this->save.conv)) {
332 case SLE_VAR_BL:
333 case SLE_VAR_I8: v = *(const int8_t *)p; p += 1; break;
334 case SLE_VAR_U8: v = *(const uint8_t *)p; p += 1; break;
335 case SLE_VAR_I16: v = *(const int16_t *)p; p += 2; break;
336 case SLE_VAR_U16: v = *(const uint16_t *)p; p += 2; break;
337 case SLE_VAR_I32: v = *(const int32_t *)p; p += 4; break;
338 case SLE_VAR_U32: v = *(const uint32_t *)p; p += 4; break;
339 default: NOT_REACHED();
340 }
341 if (i != 0) result += ',';
342 result += std::to_string(v);
343 }
344 return result;
345}
346
347std::string OneOfManySettingDesc::FormatSingleValue(uint id) const
348{
349 if (id >= this->many.size()) {
350 return std::to_string(id);
351 }
352 return this->many[id];
353}
354
355std::string OneOfManySettingDesc::FormatValue(const void *object) const
356{
357 uint id = (uint)this->Read(object);
358 return this->FormatSingleValue(id);
359}
360
361std::string ManyOfManySettingDesc::FormatValue(const void *object) const
362{
363 uint bitmask = (uint)this->Read(object);
364 if (bitmask == 0) {
365 return {};
366 }
367
368 std::string result;
369 for (uint id : SetBitIterator(bitmask)) {
370 if (!result.empty()) result += '|';
371 result += this->FormatSingleValue(id);
372 }
373 return result;
374}
375
381size_t IntSettingDesc::ParseValue(const char *str) const
382{
383 char *end;
384 size_t val = std::strtoul(str, &end, 0);
385 if (end == str) {
386 _settings_error_list.emplace_back(
387 GetEncodedString(STR_CONFIG_ERROR),
388 GetEncodedString(STR_CONFIG_ERROR_INVALID_VALUE, str, this->GetName()));
389 return this->GetDefaultValue();
390 }
391 if (*end != '\0') {
392 _settings_error_list.emplace_back(
393 GetEncodedString(STR_CONFIG_ERROR),
394 GetEncodedString(STR_CONFIG_ERROR_TRAILING_CHARACTERS, this->GetName()));
395 }
396 return val;
397}
398
399size_t OneOfManySettingDesc::ParseValue(const char *str) const
400{
401 size_t r = OneOfManySettingDesc::ParseSingleValue(str, strlen(str), this->many);
402 /* if the first attempt of conversion from string to the appropriate value fails,
403 * look if we have defined a converter from old value to new value. */
404 if (r == SIZE_MAX && this->many_cnvt != nullptr) r = this->many_cnvt(str);
405 if (r != SIZE_MAX) return r; // and here goes converted value
406
407 _settings_error_list.emplace_back(
408 GetEncodedString(STR_CONFIG_ERROR),
409 GetEncodedString(STR_CONFIG_ERROR_INVALID_VALUE, str, this->GetName()));
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
418 _settings_error_list.emplace_back(
419 GetEncodedString(STR_CONFIG_ERROR),
420 GetEncodedString(STR_CONFIG_ERROR_INVALID_VALUE, str, this->GetName()));
421 return this->GetDefaultValue();
422}
423
424size_t BoolSettingDesc::ParseValue(const char *str) const
425{
427 if (r.has_value()) return *r;
428
429 _settings_error_list.emplace_back(
430 GetEncodedString(STR_CONFIG_ERROR),
431 GetEncodedString(STR_CONFIG_ERROR_INVALID_VALUE, str, this->GetName()));
432 return this->GetDefaultValue();
433}
434
441{
442 return this->get_title_cb != nullptr ? this->get_title_cb(*this) : this->str;
443}
444
450{
451 return this->get_help_cb != nullptr ? this->get_help_cb(*this) : this->str_help;
452}
453
458std::pair<StringParameter, StringParameter> IntSettingDesc::GetValueParams(int32_t value) const
459{
460 if (this->get_value_params_cb != nullptr) {
461 return this->get_value_params_cb(*this, value);
462 }
463
464 if (this->IsBoolSetting()) {
465 return {value != 0 ? STR_CONFIG_SETTING_ON : STR_CONFIG_SETTING_OFF, {}};
466 }
467
469 auto [min_val, _] = this->GetRange();
470 return {this->str_val - min_val + value, value};
471 }
472
473 return {this->str_val + ((value == 0 && this->flags.Test(SettingFlag::GuiZeroIsSpecial)) ? 1 : 0), value};
474}
475
481{
482 return this->get_def_cb != nullptr ? this->get_def_cb(*this) : this->def;
483}
484
489std::tuple<int32_t, uint32_t> IntSettingDesc::GetRange() const
490{
491 return this->get_range_cb != nullptr ? this->get_range_cb(*this) : std::tuple(this->min, this->max);
492}
493
500void IntSettingDesc::MakeValueValidAndWrite(const void *object, int32_t val) const
501{
502 this->MakeValueValid(val);
503 this->Write(object, val);
504}
505
515void IntSettingDesc::MakeValueValid(int32_t &val) const
516{
517 auto [min_val, max_val] = this->GetRange();
518 /* We need to take special care of the uint32_t type as we receive from the function
519 * a signed integer. While here also bail out on 64-bit settings as those are not
520 * supported. Unsigned 8 and 16-bit variables are safe since they fit into a signed
521 * 32-bit variable
522 * TODO: Support 64-bit settings/variables; requires 64 bit over command protocol! */
523 switch (GetVarMemType(this->save.conv)) {
524 case SLE_VAR_NULL: return;
525 case SLE_VAR_BL:
526 case SLE_VAR_I8:
527 case SLE_VAR_U8:
528 case SLE_VAR_I16:
529 case SLE_VAR_U16:
530 case SLE_VAR_I32: {
531 /* Override the minimum value. No value below this->min, except special value 0 */
532 if (!this->flags.Test(SettingFlag::GuiZeroIsSpecial) || val != 0) {
533 if (!this->flags.Test(SettingFlag::GuiDropdown)) {
534 /* Clamp value-type setting to its valid range */
535 val = Clamp(val, min_val, max_val);
536 } else if (val < min_val || val > static_cast<int32_t>(max_val)) {
537 /* Reset invalid discrete setting (where different values change gameplay) to its default value */
538 val = this->GetDefaultValue();
539 }
540 }
541 break;
542 }
543 case SLE_VAR_U32: {
544 /* Override the minimum value. No value below this->min, except special value 0 */
545 uint32_t uval = static_cast<uint32_t>(val);
546 if (!this->flags.Test(SettingFlag::GuiZeroIsSpecial) || uval != 0) {
547 if (!this->flags.Test(SettingFlag::GuiDropdown)) {
548 /* Clamp value-type setting to its valid range */
549 uval = ClampU(uval, min_val, max_val);
550 } else if (uval < static_cast<uint32_t>(min_val) || uval > max_val) {
551 /* Reset invalid discrete setting to its default value */
552 uval = static_cast<uint32_t>(this->GetDefaultValue());
553 }
554 }
555 val = static_cast<int32_t>(uval);
556 return;
557 }
558 case SLE_VAR_I64:
559 case SLE_VAR_U64:
560 default: NOT_REACHED();
561 }
562}
563
569void IntSettingDesc::Write(const void *object, int32_t val) const
570{
571 void *ptr = GetVariableAddress(object, this->save);
572 WriteValue(ptr, this->save.conv, (int64_t)val);
573}
574
580int32_t IntSettingDesc::Read(const void *object) const
581{
582 void *ptr = GetVariableAddress(object, this->save);
583 return (int32_t)ReadValue(ptr, this->save.conv);
584}
585
593void StringSettingDesc::MakeValueValid(std::string &str) const
594{
595 if (this->max_length == 0 || str.size() < this->max_length) return;
596
597 /* In case a maximum length is imposed by the setting, the length
598 * includes the '\0' termination for network transfer purposes.
599 * Also ensure the string is valid after chopping of some bytes. */
600 str.erase(this->max_length - 1, std::string::npos);
601 StrMakeValidInPlace(str, {});
602}
603
609void StringSettingDesc::Write(const void *object, const std::string &str) const
610{
611 reinterpret_cast<std::string *>(GetVariableAddress(object, this->save))->assign(str);
612}
613
619const std::string &StringSettingDesc::Read(const void *object) const
620{
621 return *reinterpret_cast<std::string *>(GetVariableAddress(object, this->save));
622}
623
633static void IniLoadSettings(IniFile &ini, const SettingTable &settings_table, const char *grpname, void *object, bool only_startup)
634{
635 const IniGroup *group;
636 const IniGroup *group_def = ini.GetGroup(grpname);
637
638 for (auto &desc : settings_table) {
639 const SettingDesc *sd = GetSettingDesc(desc);
641 if (sd->startup != only_startup) continue;
642
643 /* For settings.xx.yy load the settings from [xx] yy = ? */
644 std::string s{ sd->GetName() };
645 auto sc = s.find('.');
646 if (sc != std::string::npos) {
647 group = ini.GetGroup(s.substr(0, sc));
648 if (group == nullptr) group = group_def;
649 s = s.substr(sc + 1);
650 } else {
651 group = group_def;
652 }
653
654 const IniItem *item = nullptr;
655 if (group != nullptr) item = group->GetItem(s);
656 if (item == nullptr && group != group_def && group_def != nullptr) {
657 /* For settings.xx.yy load the settings from [settings] yy = ? in case the previous
658 * did not exist (e.g. loading old config files with a [settings] section */
659 item = group_def->GetItem(s);
660 }
661 if (item == nullptr) {
662 /* For settings.xx.zz.yy load the settings from [zz] yy = ? in case the previous
663 * did not exist (e.g. loading old config files with a [yapf] section */
664 sc = s.find('.');
665 if (sc != std::string::npos) {
666 if (group = ini.GetGroup(s.substr(0, sc)); group != nullptr) item = group->GetItem(s.substr(sc + 1));
667 }
668 }
669
670 sd->ParseValue(item, object);
671 }
672}
673
674void IntSettingDesc::ParseValue(const IniItem *item, void *object) const
675{
676 size_t val = (item == nullptr) ? this->GetDefaultValue() : this->ParseValue(item->value.has_value() ? item->value->c_str() : "");
677 this->MakeValueValidAndWrite(object, (int32_t)val);
678}
679
680void StringSettingDesc::ParseValue(const IniItem *item, void *object) const
681{
682 std::string str = (item == nullptr) ? this->def : item->value.value_or("");
683 this->MakeValueValid(str);
684 this->Write(object, str);
685}
686
687void ListSettingDesc::ParseValue(const IniItem *item, void *object) const
688{
689 const char *str = (item == nullptr) ? this->def : item->value.has_value() ? item->value->c_str() : nullptr;
690 void *ptr = GetVariableAddress(object, this->save);
691 if (!LoadIntList(str, ptr, this->save.length, GetVarMemType(this->save.conv))) {
692 _settings_error_list.emplace_back(
693 GetEncodedString(STR_CONFIG_ERROR),
694 GetEncodedString(STR_CONFIG_ERROR_ARRAY, this->GetName()));
695
696 /* Use default */
697 LoadIntList(this->def, ptr, this->save.length, GetVarMemType(this->save.conv));
698 }
699}
700
713static void IniSaveSettings(IniFile &ini, const SettingTable &settings_table, const char *grpname, void *object, bool)
714{
715 IniGroup *group_def = nullptr, *group;
716
717 for (auto &desc : settings_table) {
718 const SettingDesc *sd = GetSettingDesc(desc);
719 /* If the setting is not saved to the configuration
720 * file, just continue with the next setting */
722 if (sd->flags.Test(SettingFlag::NotInConfig)) continue;
723
724 /* XXX - wtf is this?? (group override?) */
725 std::string s{ sd->GetName() };
726 auto sc = s.find('.');
727 if (sc != std::string::npos) {
728 group = &ini.GetOrCreateGroup(s.substr(0, sc));
729 s = s.substr(sc + 1);
730 } else {
731 if (group_def == nullptr) group_def = &ini.GetOrCreateGroup(grpname);
732 group = group_def;
733 }
734
735 IniItem &item = group->GetOrCreateItem(s);
736
737 if (!item.value.has_value() || !sd->IsSameValue(&item, object)) {
738 /* The value is different, that means we have to write it to the ini */
739 item.value.emplace(sd->FormatValue(object));
740 }
741 }
742}
743
744std::string IntSettingDesc::FormatValue(const void *object) const
745{
746 int64_t i;
747 if (IsSignedVarMemType(this->save.conv)) {
748 i = this->Read(object);
749 } else {
750 i = (uint32_t)this->Read(object);
751 }
752 return std::to_string(i);
753}
754
755std::string BoolSettingDesc::FormatValue(const void *object) const
756{
757 bool val = this->Read(object) != 0;
758 return val ? "true" : "false";
759}
760
761bool IntSettingDesc::IsSameValue(const IniItem *item, void *object) const
762{
763 int32_t item_value = (int32_t)this->ParseValue(item->value->c_str());
764 int32_t object_value = this->Read(object);
765 return item_value == object_value;
766}
767
768bool IntSettingDesc::IsDefaultValue(void *object) const
769{
770 int32_t object_value = this->Read(object);
771 return this->GetDefaultValue() == object_value;
772}
773
774void IntSettingDesc::ResetToDefault(void *object) const
775{
776 this->Write(object, this->GetDefaultValue());
777}
778
779std::string StringSettingDesc::FormatValue(const void *object) const
780{
781 const std::string &str = this->Read(object);
782 switch (GetVarMemType(this->save.conv)) {
783 case SLE_VAR_STR: return str;
784
785 case SLE_VAR_STRQ:
786 if (str.empty()) {
787 return str;
788 }
789 return fmt::format("\"{}\"", str);
790
791 default: NOT_REACHED();
792 }
793}
794
795bool StringSettingDesc::IsSameValue(const IniItem *item, void *object) const
796{
797 /* The ini parsing removes the quotes, which are needed to retain the spaces in STRQs,
798 * so those values are always different in the parsed ini item than they should be. */
799 if (GetVarMemType(this->save.conv) == SLE_VAR_STRQ) return false;
800
801 const std::string &str = this->Read(object);
802 return item->value->compare(str) == 0;
803}
804
805bool StringSettingDesc::IsDefaultValue(void *object) const
806{
807 const std::string &str = this->Read(object);
808 return this->def == str;
809}
810
811void StringSettingDesc::ResetToDefault(void *object) const
812{
813 this->Write(object, this->def);
814}
815
816bool ListSettingDesc::IsSameValue(const IniItem *, void *) const
817{
818 /* Checking for equality is way more expensive than just writing the value. */
819 return false;
820}
821
823{
824 /* Defaults of lists are often complicated, and hard to compare. */
825 return false;
826}
827
829{
830 /* Resetting a list to default is not supported. */
831 NOT_REACHED();
832}
833
843static void IniLoadSettingList(IniFile &ini, const char *grpname, StringList &list)
844{
845 const IniGroup *group = ini.GetGroup(grpname);
846
847 if (group == nullptr) return;
848
849 list.clear();
850
851 for (const IniItem &item : group->items) {
852 if (!item.name.empty()) list.push_back(item.name);
853 }
854}
855
865static void IniSaveSettingList(IniFile &ini, const char *grpname, StringList &list)
866{
867 IniGroup &group = ini.GetOrCreateGroup(grpname);
868 group.Clear();
869
870 for (const auto &iter : list) {
871 group.GetOrCreateItem(iter).SetValue("");
872 }
873}
874
881void IniLoadWindowSettings(IniFile &ini, const char *grpname, void *desc)
882{
883 IniLoadSettings(ini, _window_settings, grpname, desc, false);
884}
885
892void IniSaveWindowSettings(IniFile &ini, const char *grpname, void *desc)
893{
894 IniSaveSettings(ini, _window_settings, grpname, desc, false);
895}
896
902bool SettingDesc::IsEditable(bool do_command) const
903{
904 if (!do_command && !this->flags.Test(SettingFlag::NoNetworkSync) && _networking && !_network_server && !this->flags.Test(SettingFlag::PerCompany)) return false;
905 if (do_command && this->flags.Test(SettingFlag::NoNetworkSync)) return false;
906 if (this->flags.Test(SettingFlag::NetworkOnly) && !_networking && _game_mode != GM_MENU) return false;
907 if (this->flags.Test(SettingFlag::NoNetwork) && _networking) return false;
909 (_game_mode == GM_NORMAL ||
910 (_game_mode == GM_EDITOR && !this->flags.Test(SettingFlag::SceneditToo)))) return false;
911 if (this->flags.Test(SettingFlag::SceneditOnly) && _game_mode != GM_EDITOR) return false;
912 return true;
913}
914
924
930{
931 assert(this->IsIntSetting());
932 return static_cast<const IntSettingDesc *>(this);
933}
934
940{
941 assert(this->IsStringSetting());
942 return static_cast<const StringSettingDesc *>(this);
943}
944
946void HandleOldDiffCustom(bool savegame);
947
948
958
959static void AILoadConfig(const IniFile &ini, const char *grpname)
960{
961 const IniGroup *group = ini.GetGroup(grpname);
962
963 /* Clean any configured AI */
964 for (CompanyID c = CompanyID::Begin(); c < MAX_COMPANIES; ++c) {
966 }
967
968 /* If no group exists, return */
969 if (group == nullptr) return;
970
971 CompanyID c = CompanyID::Begin();
972 for (const IniItem &item : group->items) {
974
975 config->Change(item.name);
976 if (!config->HasScript()) {
977 if (item.name != "none") {
978 Debug(script, 0, "The AI by the name '{}' was no longer found, and removed from the list.", item.name);
979 continue;
980 }
981 }
982 if (item.value.has_value()) config->StringToSettings(*item.value);
983 ++c;
984 if (c >= MAX_COMPANIES) break;
985 }
986}
987
988static void GameLoadConfig(const IniFile &ini, const char *grpname)
989{
990 const IniGroup *group = ini.GetGroup(grpname);
991
992 /* Clean any configured GameScript */
994
995 /* If no group exists, return */
996 if (group == nullptr || group->items.empty()) return;
997
998 const IniItem &item = group->items.front();
999
1001
1002 config->Change(item.name);
1003 if (!config->HasScript()) {
1004 if (item.name != "none") {
1005 Debug(script, 0, "The GameScript by the name '{}' was no longer found, and removed from the list.", item.name);
1006 return;
1007 }
1008 }
1009 if (item.value.has_value()) config->StringToSettings(*item.value);
1010}
1011
1016{
1017 if (const IniGroup *group = ini.GetGroup("misc"); group != nullptr) {
1018 /* Load old setting first. */
1019 if (const IniItem *item = group->GetItem("graphicsset"); item != nullptr && item->value) BaseGraphics::ini_data.name = *item->value;
1020 }
1021
1022 if (const IniGroup *group = ini.GetGroup("graphicsset"); group != nullptr) {
1023 /* Load new settings. */
1024 if (const IniItem *item = group->GetItem("name"); item != nullptr && item->value) BaseGraphics::ini_data.name = *item->value;
1025
1026 if (const IniItem *item = group->GetItem("shortname"); item != nullptr && item->value && item->value->size() == 8) {
1027 BaseGraphics::ini_data.shortname = std::byteswap<uint32_t>(std::strtoul(item->value->c_str(), nullptr, 16));
1028 }
1029
1030 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);
1031
1032 if (const IniItem *item = group->GetItem("extra_params"); item != nullptr && item->value) {
1033 auto params = ParseIntList(item->value->c_str());
1034 if (params.has_value()) {
1035 BaseGraphics::ini_data.extra_params = params.value();
1036 } else {
1037 ShowErrorMessage(GetEncodedString(STR_CONFIG_ERROR),
1038 GetEncodedString(STR_CONFIG_ERROR_ARRAY, BaseGraphics::ini_data.name),
1039 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 ShowErrorMessage(GetEncodedString(STR_CONFIG_ERROR),
1105 GetEncodedString(STR_CONFIG_ERROR_ARRAY, filename),
1106 WL_CRITICAL);
1107 }
1108 }
1109
1110 /* Check if item is valid */
1111 if (!FillGRFDetails(*c, is_static) || c->flags.Test(GRFConfigFlag::Invalid)) {
1112 StringID reason;
1113 if (c->status == GCS_NOT_FOUND) {
1114 reason = STR_CONFIG_ERROR_INVALID_GRF_NOT_FOUND;
1115 } else if (c->flags.Test(GRFConfigFlag::Unsafe)) {
1116 reason = STR_CONFIG_ERROR_INVALID_GRF_UNSAFE;
1117 } else if (c->flags.Test(GRFConfigFlag::System)) {
1118 reason = STR_CONFIG_ERROR_INVALID_GRF_SYSTEM;
1119 } else if (c->flags.Test(GRFConfigFlag::Invalid)) {
1120 reason = STR_CONFIG_ERROR_INVALID_GRF_INCOMPATIBLE;
1121 } else {
1122 reason = STR_CONFIG_ERROR_INVALID_GRF_UNKNOWN;
1123 }
1124
1125 ShowErrorMessage(GetEncodedString(STR_CONFIG_ERROR),
1126 GetEncodedString(STR_CONFIG_ERROR_INVALID_GRF, filename.empty() ? item.name.c_str() : filename, reason),
1127 WL_CRITICAL);
1128 continue;
1129 }
1130
1131 /* Check for duplicate GRFID (will also check for duplicate filenames) */
1132 auto found = std::ranges::find_if(list, [&c](const auto &gc) { return gc->ident.grfid == c->ident.grfid; });
1133 if (found != std::end(list)) {
1134 ShowErrorMessage(GetEncodedString(STR_CONFIG_ERROR),
1135 GetEncodedString(STR_CONFIG_ERROR_DUPLICATE_GRFID, c->filename, (*found)->filename),
1136 WL_CRITICAL);
1137 continue;
1138 }
1139
1140 if (is_static) {
1141 /* Mark file as static to avoid saving in savegame. */
1142 c->flags.Set(GRFConfigFlag::Static);
1143 } else if (++num_grfs > NETWORK_MAX_GRF_COUNT) {
1144 /* Check we will not load more non-static NewGRFs than allowed. This could trigger issues for game servers. */
1145 ShowErrorMessage(GetEncodedString(STR_CONFIG_ERROR),
1146 GetEncodedString(STR_NEWGRF_ERROR_TOO_MANY_NEWGRFS_LOADED), WL_CRITICAL);
1147 break;
1148 }
1149
1150 /* Add item to list */
1151 list.push_back(std::move(c));
1152 }
1153
1154 return list;
1155}
1156
1157static IniFileVersion LoadVersionFromConfig(const IniFile &ini)
1158{
1159 const IniGroup *group = ini.GetGroup("version");
1160 if (group == nullptr) return IFV_0;
1161
1162 auto version_number = group->GetItem("ini_version");
1163 /* Older ini-file versions don't have this key yet. */
1164 if (version_number == nullptr || !version_number->value.has_value()) return IFV_0;
1165
1166 uint32_t version = 0;
1167 std::from_chars(version_number->value->data(), version_number->value->data() + version_number->value->size(), version);
1168
1169 return static_cast<IniFileVersion>(version);
1170}
1171
1172static void AISaveConfig(IniFile &ini, const char *grpname)
1173{
1174 IniGroup &group = ini.GetOrCreateGroup(grpname);
1175 group.Clear();
1176
1177 for (CompanyID c = CompanyID::Begin(); c < MAX_COMPANIES; ++c) {
1179 std::string name;
1180 std::string value = config->SettingsToString();
1181
1182 if (config->HasScript()) {
1183 name = config->GetName();
1184 } else {
1185 name = "none";
1186 }
1187
1188 group.CreateItem(name).SetValue(value);
1189 }
1190}
1191
1192static void GameSaveConfig(IniFile &ini, const char *grpname)
1193{
1194 IniGroup &group = ini.GetOrCreateGroup(grpname);
1195 group.Clear();
1196
1198 std::string name;
1199 std::string value = config->SettingsToString();
1200
1201 if (config->HasScript()) {
1202 name = config->GetName();
1203 } else {
1204 name = "none";
1205 }
1206
1207 group.CreateItem(name).SetValue(value);
1208}
1209
1215{
1216 IniGroup &group = ini.GetOrCreateGroup("version");
1217 group.GetOrCreateItem("version_string").SetValue(_openttd_revision);
1218 group.GetOrCreateItem("version_number").SetValue(fmt::format("{:08X}", _openttd_newgrf_version));
1219 group.GetOrCreateItem("ini_version").SetValue(std::to_string(INIFILE_VERSION));
1220}
1221
1226{
1227 const GraphicsSet *used_set = BaseGraphics::GetUsedSet();
1228 if (used_set == nullptr) return;
1229
1230 IniGroup &group = ini.GetOrCreateGroup("graphicsset");
1231 group.Clear();
1232
1233 group.GetOrCreateItem("name").SetValue(used_set->name);
1234 group.GetOrCreateItem("shortname").SetValue(fmt::format("{:08X}", std::byteswap(used_set->shortname)));
1235
1236 const GRFConfig *extra_cfg = used_set->GetExtraConfig();
1237 if (extra_cfg != nullptr && !extra_cfg->param.empty()) {
1238 group.GetOrCreateItem("extra_version").SetValue(fmt::format("{}", extra_cfg->version));
1239 group.GetOrCreateItem("extra_params").SetValue(GRFBuildParamList(*extra_cfg));
1240 }
1241}
1242
1243/* Save a GRF configuration to the given group name */
1244static void GRFSaveConfig(IniFile &ini, const char *grpname, const GRFConfigList &list)
1245{
1246 IniGroup &group = ini.GetOrCreateGroup(grpname);
1247 group.Clear();
1248
1249 for (const auto &c : list) {
1250 std::string key = fmt::format("{:08X}|{}|{}", std::byteswap(c->ident.grfid),
1251 FormatArrayAsHex(c->ident.md5sum), c->filename);
1253 }
1254}
1255
1256/* Common handler for saving/loading variables to the configuration file */
1257static void HandleSettingDescs(IniFile &generic_ini, IniFile &private_ini, IniFile &secrets_ini, SettingDescProc *proc, SettingDescProcList *proc_list, bool only_startup = false)
1258{
1259 proc(generic_ini, _misc_settings, "misc", nullptr, only_startup);
1260#if defined(_WIN32) && !defined(DEDICATED)
1261 proc(generic_ini, _win32_settings, "win32", nullptr, only_startup);
1262#endif /* _WIN32 */
1263
1264 /* The name "patches" is a fallback, as every setting should sets its own group. */
1265
1266 for (auto &table : GenericSettingTables()) {
1267 proc(generic_ini, table, "patches", &_settings_newgame, only_startup);
1268 }
1269 for (auto &table : PrivateSettingTables()) {
1270 proc(private_ini, table, "patches", &_settings_newgame, only_startup);
1271 }
1272 for (auto &table : SecretSettingTables()) {
1273 proc(secrets_ini, table, "patches", &_settings_newgame, only_startup);
1274 }
1275
1276 proc(generic_ini, _currency_settings, "currency", &GetCustomCurrency(), only_startup);
1277 proc(generic_ini, _company_settings, "company", &_settings_client.company, only_startup);
1278
1279 if (!only_startup) {
1280 proc_list(private_ini, "server_bind_addresses", _network_bind_list);
1281 proc_list(private_ini, "servers", _network_host_list);
1282 proc_list(private_ini, "bans", _network_ban_list);
1283 proc_list(private_ini, "server_authorized_keys", _settings_client.network.server_authorized_keys);
1284 proc_list(private_ini, "rcon_authorized_keys", _settings_client.network.rcon_authorized_keys);
1285 proc_list(private_ini, "admin_authorized_keys", _settings_client.network.admin_authorized_keys);
1286 }
1287}
1288
1298static void RemoveEntriesFromIni(IniFile &ini, const SettingTable &table)
1299{
1300 for (auto &desc : table) {
1301 const SettingDesc *sd = GetSettingDesc(desc);
1302
1303 /* For settings.xx.yy load the settings from [xx] yy = ? */
1304 std::string s{ sd->GetName() };
1305 auto sc = s.find('.');
1306 if (sc == std::string::npos) continue;
1307
1308 IniGroup *group = ini.GetGroup(s.substr(0, sc));
1309 if (group == nullptr) continue;
1310 s = s.substr(sc + 1);
1311
1312 group->RemoveItem(s);
1313 }
1314}
1315
1339bool IsConversionNeeded(const ConfigIniFile &ini, const std::string &group, const std::string &old_var, const std::string &new_var, const IniItem **old_item)
1340{
1341 *old_item = nullptr;
1342
1343 const IniGroup *igroup = ini.GetGroup(group);
1344 /* If the group doesn't exist, there is nothing to convert. */
1345 if (igroup == nullptr) return false;
1346
1347 const IniItem *tmp_old_item = igroup->GetItem(old_var);
1348 const IniItem *new_item = igroup->GetItem(new_var);
1349
1350 /* If the old item doesn't exist, there is nothing to convert. */
1351 if (tmp_old_item == nullptr) return false;
1352
1353 /* If the new item exists, it means conversion was already done. We only
1354 * do the conversion the first time, and after that these settings are
1355 * independent. This allows users to freely change between older and
1356 * newer clients without breaking anything. */
1357 if (new_item != nullptr) return false;
1358
1359 *old_item = tmp_old_item;
1360 return true;
1361}
1362
1367void LoadFromConfig(bool startup)
1368{
1369 ConfigIniFile generic_ini(_config_file);
1370 ConfigIniFile private_ini(_private_file);
1371 ConfigIniFile secrets_ini(_secrets_file);
1372 ConfigIniFile favs_ini(_favs_file);
1373
1374 if (!startup) ResetCurrencies(false); // Initialize the array of currencies, without preserving the custom one
1375
1376 IniFileVersion generic_version = LoadVersionFromConfig(generic_ini);
1377
1378 if (startup) {
1379 GraphicsSetLoadConfig(generic_ini);
1380 }
1381
1382 /* Before the split of private/secrets, we have to look in the generic for these settings. */
1383 if (generic_version < IFV_PRIVATE_SECRETS) {
1384 HandleSettingDescs(generic_ini, generic_ini, generic_ini, IniLoadSettings, IniLoadSettingList, startup);
1385 } else {
1386 HandleSettingDescs(generic_ini, private_ini, secrets_ini, IniLoadSettings, IniLoadSettingList, startup);
1387 }
1388
1389 /* Load basic settings only during bootstrap, load other settings not during bootstrap */
1390 if (!startup) {
1391 if (generic_version < IFV_LINKGRAPH_SECONDS) {
1394 }
1395
1396 /* Move use_relay_service from generic_ini to private_ini. */
1397 if (generic_version < IFV_NETWORK_PRIVATE_SETTINGS) {
1398 const IniGroup *network = generic_ini.GetGroup("network");
1399 if (network != nullptr) {
1400 const IniItem *use_relay_service = network->GetItem("use_relay_service");
1401 if (use_relay_service != nullptr) {
1402 if (use_relay_service->value == "never") {
1403 _settings_client.network.use_relay_service = UseRelayService::URS_NEVER;
1404 } else if (use_relay_service->value == "ask") {
1405 _settings_client.network.use_relay_service = UseRelayService::URS_ASK;
1406 } else if (use_relay_service->value == "allow") {
1407 _settings_client.network.use_relay_service = UseRelayService::URS_ALLOW;
1408 }
1409 }
1410 }
1411 }
1412
1413 const IniItem *old_item;
1414
1415 if (generic_version < IFV_GAME_TYPE && IsConversionNeeded(generic_ini, "network", "server_advertise", "server_game_type", &old_item)) {
1416 auto old_value = BoolSettingDesc::ParseSingleValue(old_item->value->c_str());
1417 _settings_client.network.server_game_type = old_value.value_or(false) ? SERVER_GAME_TYPE_PUBLIC : SERVER_GAME_TYPE_LOCAL;
1418 }
1419
1420 if (generic_version < IFV_AUTOSAVE_RENAME && IsConversionNeeded(generic_ini, "gui", "autosave", "autosave_interval", &old_item)) {
1421 static std::vector<std::string> _old_autosave_interval{"off", "monthly", "quarterly", "half year", "yearly"};
1422 auto old_value = OneOfManySettingDesc::ParseSingleValue(old_item->value->c_str(), old_item->value->size(), _old_autosave_interval);
1423
1424 switch (old_value) {
1425 case 0: _settings_client.gui.autosave_interval = 0; break;
1426 case 1: _settings_client.gui.autosave_interval = 10; break;
1427 case 2: _settings_client.gui.autosave_interval = 30; break;
1428 case 3: _settings_client.gui.autosave_interval = 60; break;
1429 case 4: _settings_client.gui.autosave_interval = 120; break;
1430 default: break;
1431 }
1432 }
1433
1434 /* Persist the right click close option from older versions. */
1435 if (generic_version < IFV_RIGHT_CLICK_CLOSE && IsConversionNeeded(generic_ini, "gui", "right_mouse_wnd_close", "right_click_wnd_close", &old_item)) {
1436 auto old_value = BoolSettingDesc::ParseSingleValue(old_item->value->c_str());
1437 _settings_client.gui.right_click_wnd_close = old_value.value_or(false) ? RCC_YES : RCC_NO;
1438 }
1439
1440 _grfconfig_newgame = GRFLoadConfig(generic_ini, "newgrf", false);
1441 _grfconfig_static = GRFLoadConfig(generic_ini, "newgrf-static", true);
1442 AILoadConfig(generic_ini, "ai_players");
1443 GameLoadConfig(generic_ini, "game_scripts");
1444 PickerLoadConfig(favs_ini);
1445
1447 IniLoadSettings(generic_ini, _old_gameopt_settings, "gameopt", &_settings_newgame, false);
1448 HandleOldDiffCustom(false);
1449
1452
1453 /* Display scheduled errors */
1455 if (FindWindowById(WC_ERRMSG, 0) == nullptr) ShowFirstError();
1456 }
1457}
1458
1461{
1462 ConfigIniFile generic_ini(_config_file);
1463 ConfigIniFile private_ini(_private_file);
1464 ConfigIniFile secrets_ini(_secrets_file);
1465 ConfigIniFile favs_ini(_favs_file);
1466
1467 IniFileVersion generic_version = LoadVersionFromConfig(generic_ini);
1468
1469 /* If we newly create the private/secrets file, add a dummy group on top
1470 * just so we can add a comment before it (that is how IniFile works).
1471 * This to explain what the file is about. After doing it once, never touch
1472 * it again, as otherwise we might be reverting user changes. */
1473 if (IniGroup *group = private_ini.GetGroup("private"); group != nullptr) group->comment = "; This file possibly contains private information which can identify you as person.\n";
1474 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";
1475
1476 if (generic_version == IFV_0) {
1477 /* Remove some obsolete groups. These have all been loaded into other groups. */
1478 generic_ini.RemoveGroup("patches");
1479 generic_ini.RemoveGroup("yapf");
1480 generic_ini.RemoveGroup("gameopt");
1481
1482 /* Remove all settings from the generic ini that are now in the private ini. */
1483 generic_ini.RemoveGroup("server_bind_addresses");
1484 generic_ini.RemoveGroup("servers");
1485 generic_ini.RemoveGroup("bans");
1486 for (auto &table : PrivateSettingTables()) {
1487 RemoveEntriesFromIni(generic_ini, table);
1488 }
1489
1490 /* Remove all settings from the generic ini that are now in the secrets ini. */
1491 for (auto &table : SecretSettingTables()) {
1492 RemoveEntriesFromIni(generic_ini, table);
1493 }
1494 }
1495
1496 if (generic_version < IFV_REMOVE_GENERATION_SEED) {
1497 IniGroup *game_creation = generic_ini.GetGroup("game_creation");
1498 if (game_creation != nullptr) {
1499 game_creation->RemoveItem("generation_seed");
1500 }
1501 }
1502
1503 /* These variables are migrated from generic ini to private ini now. */
1504 if (generic_version < IFV_NETWORK_PRIVATE_SETTINGS) {
1505 IniGroup *network = generic_ini.GetGroup("network");
1506 if (network != nullptr) {
1507 network->RemoveItem("use_relay_service");
1508 }
1509 }
1510
1511 HandleSettingDescs(generic_ini, private_ini, secrets_ini, IniSaveSettings, IniSaveSettingList);
1512 GraphicsSetSaveConfig(generic_ini);
1513 GRFSaveConfig(generic_ini, "newgrf", _grfconfig_newgame);
1514 GRFSaveConfig(generic_ini, "newgrf-static", _grfconfig_static);
1515 AISaveConfig(generic_ini, "ai_players");
1516 GameSaveConfig(generic_ini, "game_scripts");
1517 PickerSaveConfig(favs_ini);
1518
1519 SaveVersionInConfig(generic_ini);
1520 SaveVersionInConfig(private_ini);
1521 SaveVersionInConfig(secrets_ini);
1522 SaveVersionInConfig(favs_ini);
1523
1524 generic_ini.SaveToDisk(_config_file);
1525 private_ini.SaveToDisk(_private_file);
1526 secrets_ini.SaveToDisk(_secrets_file);
1527 favs_ini.SaveToDisk(_favs_file);
1528}
1529
1535{
1536 StringList list;
1537
1539 for (const IniGroup &group : ini.groups) {
1540 if (group.name.compare(0, 7, "preset-") == 0) {
1541 list.push_back(group.name.substr(7));
1542 }
1543 }
1544
1545 return list;
1546}
1547
1554GRFConfigList LoadGRFPresetFromConfig(const char *config_name)
1555{
1556 std::string section("preset-");
1557 section += config_name;
1558
1560 GRFConfigList config = GRFLoadConfig(ini, section.c_str(), false);
1561
1562 return config;
1563}
1564
1571void SaveGRFPresetToConfig(const char *config_name, GRFConfigList &config)
1572{
1573 std::string section("preset-");
1574 section += config_name;
1575
1577 GRFSaveConfig(ini, section.c_str(), config);
1579}
1580
1585void DeleteGRFPresetFromConfig(const char *config_name)
1586{
1587 std::string section("preset-");
1588 section += config_name;
1589
1591 ini.RemoveGroup(section);
1593}
1594
1601void IntSettingDesc::ChangeValue(const void *object, int32_t newval) const
1602{
1603 int32_t oldval = this->Read(object);
1604 this->MakeValueValid(newval);
1605 if (this->pre_check != nullptr && !this->pre_check(newval)) return;
1606 if (oldval == newval) return;
1607
1608 this->Write(object, newval);
1609 if (this->post_callback != nullptr) this->post_callback(newval);
1610
1611 if (this->flags.Test(SettingFlag::NoNetwork) || this->flags.Test(SettingFlag::Sandbox)) {
1613 _gamelog.Setting(this->GetName(), oldval, newval);
1615 }
1616
1619
1620 if (_save_config) SaveToConfig();
1621}
1622
1630static const SettingDesc *GetSettingFromName(const std::string_view name, const SettingTable &settings)
1631{
1632 /* First check all full names */
1633 for (auto &desc : settings) {
1634 const SettingDesc *sd = GetSettingDesc(desc);
1635 if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue;
1636 if (sd->GetName() == name) return sd;
1637 }
1638
1639 /* Then check the shortcut variant of the name. */
1640 std::string short_name_suffix = std::string{ "." }.append(name);
1641 for (auto &desc : settings) {
1642 const SettingDesc *sd = GetSettingDesc(desc);
1643 if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue;
1644 if (sd->GetName().ends_with(short_name_suffix)) return sd;
1645 }
1646
1647 return nullptr;
1648}
1649
1655void GetSaveLoadFromSettingTable(SettingTable settings, std::vector<SaveLoad> &saveloads)
1656{
1657 for (auto &desc : settings) {
1658 const SettingDesc *sd = GetSettingDesc(desc);
1659 if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue;
1660 saveloads.push_back(sd->save);
1661 }
1662}
1663
1669{
1670 static const SettingTable saveload_settings_tables[] = {
1671 _difficulty_settings,
1672 _economy_settings,
1673 _game_settings,
1674 _linkgraph_settings,
1675 _locale_settings,
1676 _pathfinding_settings,
1677 _script_settings,
1678 _world_settings,
1679 };
1680 static std::vector<SettingVariant> settings_table;
1681
1682 if (settings_table.empty()) {
1683 for (auto &saveload_settings_table : saveload_settings_tables) {
1684 for (auto &saveload_setting : saveload_settings_table) {
1685 settings_table.push_back(saveload_setting);
1686 }
1687 }
1688 }
1689
1690 return settings_table;
1691}
1692
1699static const SettingDesc *GetCompanySettingFromName(std::string_view name)
1700{
1701 static const std::string_view company_prefix = "company.";
1702 if (name.starts_with(company_prefix)) name.remove_prefix(company_prefix.size());
1703 return GetSettingFromName(name, _company_settings);
1704}
1705
1712const SettingDesc *GetSettingFromName(const std::string_view name)
1713{
1714 for (auto &table : GenericSettingTables()) {
1715 auto sd = GetSettingFromName(name, table);
1716 if (sd != nullptr) return sd;
1717 }
1718 for (auto &table : PrivateSettingTables()) {
1719 auto sd = GetSettingFromName(name, table);
1720 if (sd != nullptr) return sd;
1721 }
1722 for (auto &table : SecretSettingTables()) {
1723 auto sd = GetSettingFromName(name, table);
1724 if (sd != nullptr) return sd;
1725 }
1726
1727 return GetCompanySettingFromName(name);
1728}
1729
1735std::vector<const SettingDesc *> GetFilteredSettingCollection(std::function<bool(const SettingDesc &desc)> func)
1736{
1737 std::vector<const SettingDesc *> collection;
1738
1739 for (const auto &table : GenericSettingTables()) {
1740 for (const auto &desc : table) {
1741 const auto sd = GetSettingDesc(desc);
1742 if (!func(*sd)) continue;
1743
1744 collection.push_back(sd);
1745 }
1746 }
1747
1748 return collection;
1749}
1750
1760CommandCost CmdChangeSetting(DoCommandFlags flags, const std::string &name, int32_t value)
1761{
1762 if (name.empty()) return CMD_ERROR;
1763 const SettingDesc *sd = GetSettingFromName(name);
1764
1765 if (sd == nullptr) return CMD_ERROR;
1767 if (!sd->IsIntSetting()) return CMD_ERROR;
1768
1769 if (!sd->IsEditable(true)) return CMD_ERROR;
1770
1771 if (flags.Test(DoCommandFlag::Execute)) {
1772 sd->AsIntSetting()->ChangeValue(&GetGameSettings(), value);
1773 }
1774
1775 return CommandCost();
1776}
1777
1786CommandCost CmdChangeCompanySetting(DoCommandFlags flags, const std::string &name, int32_t value)
1787{
1788 if (name.empty()) return CMD_ERROR;
1789 const SettingDesc *sd = GetCompanySettingFromName(name);
1790
1791 if (sd == nullptr) return CMD_ERROR;
1792 if (!sd->IsIntSetting()) return CMD_ERROR;
1793
1794 if (flags.Test(DoCommandFlag::Execute)) {
1796 }
1797
1798 return CommandCost();
1799}
1800
1808bool SetSettingValue(const IntSettingDesc *sd, int32_t value, bool force_newgame)
1809{
1810 const IntSettingDesc *setting = sd->AsIntSetting();
1811 if (setting->flags.Test(SettingFlag::PerCompany)) {
1812 if (Company::IsValidID(_local_company) && _game_mode != GM_MENU) {
1813 return Command<CMD_CHANGE_COMPANY_SETTING>::Post(setting->GetName(), value);
1814 }
1815
1816 setting->ChangeValue(&_settings_client.company, value);
1817 return true;
1818 }
1819
1820 /* If an item is company-based, we do not send it over the network
1821 * (if any) to change. Also *hack*hack* we update the _newgame version
1822 * of settings because changing a company-based setting in a game also
1823 * changes its defaults. At least that is the convention we have chosen */
1824 if (setting->flags.Test(SettingFlag::NoNetworkSync)) {
1825 if (_game_mode != GM_MENU) {
1826 setting->ChangeValue(&_settings_newgame, value);
1827 }
1828 setting->ChangeValue(&GetGameSettings(), value);
1829 return true;
1830 }
1831
1832 if (force_newgame) {
1833 setting->ChangeValue(&_settings_newgame, value);
1834 return true;
1835 }
1836
1837 /* send non-company-based settings over the network */
1839 return Command<CMD_CHANGE_SETTING>::Post(setting->GetName(), value);
1840 }
1841 return false;
1842}
1843
1848{
1849 Company *c = Company::Get(cid);
1851 for (auto &desc : _company_settings) {
1852 const IntSettingDesc *int_setting = GetSettingDesc(desc)->AsIntSetting();
1853 int_setting->MakeValueValidAndWrite(&c->settings, int_setting->GetDefaultValue());
1854 }
1855}
1856
1861{
1862 const void *old_object = &Company::Get(_current_company)->settings;
1863 const void *new_object = &_settings_client.company;
1864 for (auto &desc : _company_settings) {
1865 const SettingDesc *sd = GetSettingDesc(desc);
1866 uint32_t old_value = (uint32_t)sd->AsIntSetting()->Read(old_object);
1867 uint32_t new_value = (uint32_t)sd->AsIntSetting()->Read(new_object);
1868 /*
1869 * This is called from a command, and since it contains local configuration information
1870 * that the rest of the clients do not know about, we need to circumvent the normal ::Post
1871 * local command validation and immediately send the command to the server.
1872 */
1873 if (old_value != new_value) Command<CMD_CHANGE_COMPANY_SETTING>::SendNet(STR_NULL, _local_company, sd->GetName(), new_value);
1874 }
1875}
1876
1884bool SetSettingValue(const StringSettingDesc *sd, std::string value, bool force_newgame)
1885{
1887
1888 if (GetVarMemType(sd->save.conv) == SLE_VAR_STRQ && value.compare("(null)") == 0) {
1889 value.clear();
1890 }
1891
1892 const void *object = (_game_mode == GM_MENU || force_newgame) ? &_settings_newgame : &_settings_game;
1893 sd->AsStringSetting()->ChangeValue(object, value);
1894 return true;
1895}
1896
1903void StringSettingDesc::ChangeValue(const void *object, std::string &newval) const
1904{
1905 this->MakeValueValid(newval);
1906 if (this->pre_check != nullptr && !this->pre_check(newval)) return;
1907
1908 this->Write(object, newval);
1909 if (this->post_callback != nullptr) this->post_callback(newval);
1910
1911 if (_save_config) SaveToConfig();
1912}
1913
1914/* Those 2 functions need to be here, else we have to make some stuff non-static
1915 * and besides, it is also better to keep stuff like this at the same place */
1916void IConsoleSetSetting(const char *name, const char *value, bool force_newgame)
1917{
1918 const SettingDesc *sd = GetSettingFromName(name);
1919 /* Company settings are not in "list_settings", so don't try to modify them. */
1920 if (sd == nullptr || sd->flags.Test(SettingFlag::PerCompany)) {
1921 IConsolePrint(CC_ERROR, "'{}' is an unknown setting.", name);
1922 return;
1923 }
1924
1925 bool success = true;
1926 if (sd->IsStringSetting()) {
1927 success = SetSettingValue(sd->AsStringSetting(), value, force_newgame);
1928 } else if (sd->IsIntSetting()) {
1929 const IntSettingDesc *isd = sd->AsIntSetting();
1930 size_t val = isd->ParseValue(value);
1931 if (!_settings_error_list.empty()) {
1932 IConsolePrint(CC_ERROR, "'{}' is not a valid value for this setting.", value);
1933 _settings_error_list.clear();
1934 return;
1935 }
1936 success = SetSettingValue(isd, (int32_t)val, force_newgame);
1937 }
1938
1939 if (!success) {
1940 if (_network_server) {
1941 IConsolePrint(CC_ERROR, "This command/variable is not available during network games.");
1942 } else {
1943 IConsolePrint(CC_ERROR, "This command/variable is only available to a network server.");
1944 }
1945 }
1946}
1947
1948void IConsoleSetSetting(const char *name, int value)
1949{
1950 const SettingDesc *sd = GetSettingFromName(name);
1951 assert(sd != nullptr);
1952 SetSettingValue(sd->AsIntSetting(), value);
1953}
1954
1960void IConsoleGetSetting(const char *name, bool force_newgame)
1961{
1962 const SettingDesc *sd = GetSettingFromName(name);
1963 /* Company settings are not in "list_settings", so don't try to read them. */
1964 if (sd == nullptr || sd->flags.Test(SettingFlag::PerCompany)) {
1965 IConsolePrint(CC_ERROR, "'{}' is an unknown setting.", name);
1966 return;
1967 }
1968
1969 const void *object = (_game_mode == GM_MENU || force_newgame) ? &_settings_newgame : &_settings_game;
1970
1971 if (sd->IsStringSetting()) {
1972 IConsolePrint(CC_INFO, "Current value for '{}' is '{}'.", sd->GetName(), sd->AsStringSetting()->Read(object));
1973 } else if (sd->IsIntSetting()) {
1974 std::string value = sd->FormatValue(object);
1975 const IntSettingDesc *int_setting = sd->AsIntSetting();
1976 auto [min_val, max_val] = int_setting->GetRange();
1977 IConsolePrint(CC_INFO, "Current value for '{}' is '{}' (min: {}{}, max: {}).",
1978 sd->GetName(), value, sd->flags.Test(SettingFlag::GuiZeroIsSpecial) ? "(0) " : "", min_val, max_val);
1979 }
1980}
1981
1982static void IConsoleListSettingsTable(const SettingTable &table, const char *prefilter)
1983{
1984 for (auto &desc : table) {
1985 const SettingDesc *sd = GetSettingDesc(desc);
1986 if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue;
1987 if (prefilter != nullptr && sd->GetName().find(prefilter) == std::string::npos) continue;
1988 IConsolePrint(CC_DEFAULT, "{} = {}", sd->GetName(), sd->FormatValue(&GetGameSettings()));
1989 }
1990}
1991
1997void IConsoleListSettings(const char *prefilter)
1998{
1999 IConsolePrint(CC_HELP, "All settings with their current value:");
2000
2001 for (auto &table : GenericSettingTables()) {
2002 IConsoleListSettingsTable(table, prefilter);
2003 }
2004 for (auto &table : PrivateSettingTables()) {
2005 IConsoleListSettingsTable(table, prefilter);
2006 }
2007 for (auto &table : SecretSettingTables()) {
2008 IConsoleListSettingsTable(table, prefilter);
2009 }
2010
2011 IConsolePrint(CC_HELP, "Use 'setting' command to change a value.");
2012}
2013
2014ScriptConfigSettings::ScriptConfigSettings()
2015{
2016 /* Instantiate here, because unique_ptr needs a complete type. */
2017}
2018
2019ScriptConfigSettings::~ScriptConfigSettings()
2020{
2021 /* Instantiate here, because unique_ptr needs a complete type. */
2022}
2023
2024ScriptConfigSettings::ScriptConfigSettings(const ScriptConfigSettings &other)
2025{
2026 *this = other;
2027}
2028
2029ScriptConfigSettings &ScriptConfigSettings::operator=(const ScriptConfigSettings &other)
2030{
2031 for (CompanyID c = CompanyID::Begin(); c < MAX_COMPANIES; ++c) {
2032 if (other.ai[c] != nullptr) {
2033 this->ai[c] = std::make_unique<AIConfig>(*other.ai[c]);
2034 }
2035 }
2036 if (other.game != nullptr) {
2037 this->game = std::make_unique<GameConfig>(*other.game);
2038 }
2039 return *this;
2040}
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.
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()
Return the used set.
Common return value for all commands.
IniFile to store a configuration.
Definition settings.cpp:138
Enum-as-bit-set wrapper.
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...
const std::string & GetName() const
Get the name of the Script.
void Change(std::optional< std::string > name, int version=-1, bool force_exact_match=false)
Set another Script to be loaded in this slot.
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.
@ 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: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:162
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,...)
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(const std::string &filename, Subdirectory subdir)
Check whether the given file exists.
Definition fileio.cpp:121
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: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.
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:823
int64_t ReadValue(const void *ptr, VarType conv)
Return a signed-long version of the value of a setting.
Definition saveload.cpp:799
@ SLE_VAR_NULL
useful to write zeros in savegame.
Definition saveload.h:658
@ SLE_VAR_STR
string pointer
Definition saveload.h:659
@ SLE_VAR_STRQ
string pointer enclosed in quotes
Definition saveload.h:660
constexpr size_t SlVarSize(VarType type)
Return expect size in bytes of a VarType.
Definition saveload.h:787
void * GetVariableAddress(const void *object, const SaveLoad &sld)
Get the address of the variable.
Definition saveload.h:1306
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:1295
constexpr VarType GetVarMemType(VarType type)
Get the NumberType of a setting.
Definition saveload.h:756
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:713
static void ValidateSettings()
Checks if any settings are set to incorrect values, and sets them to correct values in that case.
Definition settings.cpp:950
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:251
std::string _secrets_file
Secrets configuration file of OpenTTD.
Definition settings.cpp:64
std::string _favs_file
Picker favourites configuration file of OpenTTD.
Definition settings.cpp:65
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:633
static ErrorList _settings_error_list
Errors while loading minimal settings.
Definition settings.cpp:67
void IniLoadWindowSettings(IniFile &ini, const char *grpname, void *desc)
Load a WindowDesc from config.
Definition settings.cpp:881
static bool LoadIntList(const char *str, void *array, int nelems, VarType type)
Load parsed string-values into an integer-array (intlist)
Definition settings.cpp:296
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:61
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:843
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:892
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:865
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:59
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:222
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:164
@ IFV_0
0 All versions prior to introduction.
Definition settings.cpp:165
@ IFV_AUTOSAVE_RENAME
5 PR#11143 Renamed values of autosave to be in minutes.
Definition settings.cpp:171
@ IFV_LINKGRAPH_SECONDS
3 PR#10610 Store linkgraph update intervals in seconds instead of days.
Definition settings.cpp:168
@ IFV_REMOVE_GENERATION_SEED
7 PR#11927 Remove "generation_seed" from configuration.
Definition settings.cpp:173
@ IFV_MAX_VERSION
Highest possible ini-file version.
Definition settings.cpp:175
@ IFV_NETWORK_PRIVATE_SETTINGS
4 PR#10762 Move use_relay_service to private settings.
Definition settings.cpp:169
@ IFV_GAME_TYPE
2 PR#9515 Convert server_advertise to server_game_type.
Definition settings.cpp:167
@ IFV_RIGHT_CLICK_CLOSE
6 PR#10204 Add alternative right click to close windows setting.
Definition settings.cpp:172
@ IFV_PRIVATE_SECRETS
1 PR#9298 Moving of settings from openttd.cfg to private.cfg / secrets.cfg.
Definition settings.cpp:166
SettingTable GetSaveLoadSettingTable()
Create a single table with all settings that should be stored/loaded in the savegame.
const uint16_t INIFILE_VERSION
Current ini-file version of OpenTTD.
Definition settings.cpp:178
static auto & SecretSettingTables()
List of all the secrets setting tables.
Definition settings.cpp:112
std::string _private_file
Private configuration file of OpenTTD.
Definition settings.cpp:63
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:60
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:101
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:62
static auto & GenericSettingTables()
List of all the generic setting tables.
Definition settings.cpp:79
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.
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:58
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:659
void StrMakeValidInPlace(char *str, StringValidationSettings settings)
Scans the string for invalid characters and replaces them with a question mark '?' (if not ignored).
Definition string.cpp:194
std::string FormatArrayAsHex(std::span< const uint8_t > data)
Format a byte array into a continuous hex string.
Definition string.cpp:78
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:91
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::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:755
static std::optional< bool > ParseSingleValue(const char *str)
Find whether a string was a boolean true or a boolean false.
Definition settings.cpp:207
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:51
std::string comment
comment for group
Definition ini_type.h:38
void Clear()
Clear all items in the group.
Definition ini_load.cpp:97
void RemoveItem(std::string_view name)
Remove the item with the given name.
Definition ini_load.cpp:89
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:80
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:65
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:31
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:174
void LoadFromDisk(const std::string &filename, Subdirectory subdir)
Load the Ini file's data from the disk.
Definition ini_load.cpp:186
const IniGroup * GetGroup(std::string_view name) const
Get the group with the given name.
Definition ini_load.cpp:118
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:146
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:515
void ResetToDefault(void *object) const override
Reset the setting to its default value.
Definition settings.cpp:774
std::string FormatValue(const void *object) const override
Format the value of the setting associated with this object.
Definition settings.cpp:744
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:489
StringID GetTitle() const
Get the title of the setting.
Definition settings.cpp:440
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:761
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:480
void Write(const void *object, int32_t value) const
Set the value of a setting.
Definition settings.cpp:569
StringID GetHelp() const
Get the help text of the setting.
Definition settings.cpp:449
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:500
std::pair< StringParameter, StringParameter > GetValueParams(int32_t value) const
Get parameters for drawing the value of the setting.
Definition settings.cpp:458
virtual size_t ParseValue(const char *str) const
Convert a string representation (external) of an integer-like setting to an integer.
Definition settings.cpp:381
int32_t Read(const void *object) const
Read the integer from the the actual setting.
Definition settings.cpp:580
bool IsDefaultValue(void *object) const override
Check whether the value is the same as the default value.
Definition settings.cpp:768
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:687
void ResetToDefault(void *object) const override
Reset the setting to its default value.
Definition settings.cpp:828
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:816
std::string FormatValue(const void *object) const override
Convert an integer-array (intlist) to a string representation.
Definition settings.cpp:324
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:822
std::string FormatValue(const void *object) const override
Format the value of the setting associated with this object.
Definition settings.cpp:361
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:399
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:187
std::string FormatValue(const void *object) const override
Format the value of the setting associated with this object.
Definition settings.cpp:355
std::vector< std::string > many
possible values for this type
static Titem * Get(auto index)
Returns Titem with given index.
static bool IsValidID(auto index)
Tests whether given index can be used to get valid (non-nullptr) Titem.
uint16_t length
(Conditional) length of the variable (eg. arrays) (max array size is 65536 elements).
Definition saveload.h:726
SaveLoadVersion version_to
Save/load the variable before this savegame version.
Definition saveload.h:728
VarType conv
Type of the variable to be saved; this field combines both FileVarType and MemVarType.
Definition saveload.h:725
SaveLoadVersion version_from
Save/load the variable starting from this savegame version.
Definition saveload.h:727
Container for AI and Game script configuration.
std::unique_ptr< class GameConfig > game
settings for gamescript
ReferenceThroughBaseContainer< std::array< std::unique_ptr< class AIConfig >, MAX_COMPANIES > > 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:902
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:919
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:939
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:929
String settings.
const std::string & Read(const void *object) const
Read the string from the the actual setting.
Definition settings.cpp:619
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:593
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:795
bool IsDefaultValue(void *object) const override
Check whether the value is the same as the default value.
Definition settings.cpp:805
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:811
void Write(const void *object, const std::string &str) const
Write a string to the actual setting.
Definition settings.cpp:609
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:779
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:680
Default settings for vehicles.
void SetWindowClassesDirty(WindowClass cls)
Mark all windows of a particular class as dirty (in need of repainting)
Definition window.cpp:3132
Window * FindWindowById(WindowClass cls, WindowNumber number)
Find a window by its class and window number.
Definition window.cpp:1101
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: