OpenTTD Source 20250312-master-gcdcc6b491d
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 "fios.h"
50#include "fileio_func.h"
51#include "settings_cmd.h"
52
53#include "table/strings.h"
54
55#include "safeguards.h"
56
61std::string _config_file;
62std::string _private_file;
63std::string _secrets_file;
64std::string _favs_file;
65
67
79{
80 static const SettingTable _generic_setting_tables[] = {
81 _difficulty_settings,
82 _economy_settings,
83 _game_settings,
84 _gui_settings,
85 _linkgraph_settings,
86 _locale_settings,
87 _multimedia_settings,
88 _network_settings,
89 _news_display_settings,
90 _pathfinding_settings,
91 _script_settings,
92 _world_settings,
93 };
94 return _generic_setting_tables;
95}
96
101{
102 static const SettingTable _private_setting_tables[] = {
103 _network_private_settings,
104 };
105 return _private_setting_tables;
106}
107
112{
113 static const SettingTable _secrets_setting_tables[] = {
114 _network_secrets_settings,
115 };
116 return _secrets_setting_tables;
117}
118
119typedef void SettingDescProc(IniFile &ini, const SettingTable &desc, const char *grpname, void *object, bool only_startup);
120typedef void SettingDescProcList(IniFile &ini, const char *grpname, StringList &list);
121
122static bool IsSignedVarMemType(VarType vt)
123{
124 switch (GetVarMemType(vt)) {
125 case SLE_VAR_I8:
126 case SLE_VAR_I16:
127 case SLE_VAR_I32:
128 case SLE_VAR_I64:
129 return true;
130 }
131 return false;
132}
133
137class ConfigIniFile : public IniFile {
138private:
139 inline static const IniGroupNameList list_group_names = {
140 "bans",
141 "newgrf",
142 "servers",
143 "server_bind_addresses",
144 "server_authorized_keys",
145 "rcon_authorized_keys",
146 "admin_authorized_keys"
147 };
148
149public:
150 ConfigIniFile(const std::string &filename) : IniFile(list_group_names)
151 {
152 this->LoadFromDisk(filename, NO_DIRECTORY);
153 }
154};
155
176
178
186size_t OneOfManySettingDesc::ParseSingleValue(const char *str, size_t len, const std::vector<std::string> &many)
187{
188 /* check if it's an integer */
189 if (isdigit(*str)) return std::strtoul(str, nullptr, 0);
190
191 size_t idx = 0;
192 for (const auto &one : many) {
193 if (one.size() == len && strncmp(one.c_str(), str, len) == 0) return idx;
194 idx++;
195 }
196
197 return SIZE_MAX;
198}
199
206std::optional<bool> BoolSettingDesc::ParseSingleValue(const char *str)
207{
208 if (strcmp(str, "true") == 0 || strcmp(str, "on") == 0 || strcmp(str, "1") == 0) return true;
209 if (strcmp(str, "false") == 0 || strcmp(str, "off") == 0 || strcmp(str, "0") == 0) return false;
210
211 return std::nullopt;
212}
213
221static size_t LookupManyOfMany(const std::vector<std::string> &many, const char *str)
222{
223 const char *s;
224 size_t r;
225 size_t res = 0;
226
227 for (;;) {
228 /* skip "whitespace" */
229 while (*str == ' ' || *str == '\t' || *str == '|') str++;
230 if (*str == 0) break;
231
232 s = str;
233 while (*s != 0 && *s != ' ' && *s != '\t' && *s != '|') s++;
234
235 r = OneOfManySettingDesc::ParseSingleValue(str, s - str, many);
236 if (r == SIZE_MAX) return r;
237
238 SetBit(res, (uint8_t)r); // value found, set it
239 if (*s == 0) break;
240 str = s + 1;
241 }
242 return res;
243}
244
250static std::optional<std::vector<uint32_t>> ParseIntList(const char *p)
251{
252 bool comma = false; // do we accept comma?
253 std::vector<uint32_t> result;
254
255 while (*p != '\0') {
256 switch (*p) {
257 case ',':
258 /* Do not accept multiple commas between numbers */
259 if (!comma) return std::nullopt;
260 comma = false;
261 [[fallthrough]];
262
263 case ' ':
264 p++;
265 break;
266
267 default: {
268 char *end;
269 unsigned long v = std::strtoul(p, &end, 0);
270 if (p == end) return std::nullopt; // invalid character (not a number)
271
272 result.push_back(ClampTo<uint32_t>(v));
273 p = end; // first non-number
274 comma = true; // we accept comma now
275 break;
276 }
277 }
278 }
279
280 /* If we have read comma but no number after it, fail.
281 * We have read comma when (n != 0) and comma is not allowed */
282 if (!result.empty() && !comma) return std::nullopt;
283
284 return result;
285}
286
295static bool LoadIntList(const char *str, void *array, int nelems, VarType type)
296{
297 size_t elem_size = SlVarSize(type);
298 if (str == nullptr) {
299 memset(array, 0, nelems * elem_size);
300 return true;
301 }
302
303 auto opt_items = ParseIntList(str);
304 if (!opt_items.has_value() || opt_items->size() != (size_t)nelems) return false;
305
306 char *p = static_cast<char *>(array);
307 for (auto item : *opt_items) {
308 WriteValue(p, type, item);
309 p += elem_size;
310 }
311 return true;
312}
313
323std::string ListSettingDesc::FormatValue(const void *object) const
324{
325 const uint8_t *p = static_cast<const uint8_t *>(GetVariableAddress(object, this->save));
326
327 std::string result;
328 for (size_t i = 0; i != this->save.length; i++) {
329 int64_t v;
330 switch (GetVarMemType(this->save.conv)) {
331 case SLE_VAR_BL:
332 case SLE_VAR_I8: v = *(const int8_t *)p; p += 1; break;
333 case SLE_VAR_U8: v = *(const uint8_t *)p; p += 1; break;
334 case SLE_VAR_I16: v = *(const int16_t *)p; p += 2; break;
335 case SLE_VAR_U16: v = *(const uint16_t *)p; p += 2; break;
336 case SLE_VAR_I32: v = *(const int32_t *)p; p += 4; break;
337 case SLE_VAR_U32: v = *(const uint32_t *)p; p += 4; break;
338 default: NOT_REACHED();
339 }
340 if (i != 0) result += ',';
341 result += std::to_string(v);
342 }
343 return result;
344}
345
346std::string OneOfManySettingDesc::FormatSingleValue(uint id) const
347{
348 if (id >= this->many.size()) {
349 return std::to_string(id);
350 }
351 return this->many[id];
352}
353
354std::string OneOfManySettingDesc::FormatValue(const void *object) const
355{
356 uint id = (uint)this->Read(object);
357 return this->FormatSingleValue(id);
358}
359
360std::string ManyOfManySettingDesc::FormatValue(const void *object) const
361{
362 uint bitmask = (uint)this->Read(object);
363 if (bitmask == 0) {
364 return {};
365 }
366
367 std::string result;
368 for (uint id : SetBitIterator(bitmask)) {
369 if (!result.empty()) result += '|';
370 result += this->FormatSingleValue(id);
371 }
372 return result;
373}
374
380size_t IntSettingDesc::ParseValue(const char *str) const
381{
382 char *end;
383 size_t val = std::strtoul(str, &end, 0);
384 if (end == str) {
385 _settings_error_list.emplace_back(
386 GetEncodedString(STR_CONFIG_ERROR),
387 GetEncodedString(STR_CONFIG_ERROR_INVALID_VALUE, str, this->GetName()));
388 return this->GetDefaultValue();
389 }
390 if (*end != '\0') {
391 _settings_error_list.emplace_back(
392 GetEncodedString(STR_CONFIG_ERROR),
393 GetEncodedString(STR_CONFIG_ERROR_TRAILING_CHARACTERS, this->GetName()));
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 _settings_error_list.emplace_back(
407 GetEncodedString(STR_CONFIG_ERROR),
408 GetEncodedString(STR_CONFIG_ERROR_INVALID_VALUE, str, this->GetName()));
409 return this->GetDefaultValue();
410}
411
412size_t ManyOfManySettingDesc::ParseValue(const char *str) const
413{
414 size_t r = LookupManyOfMany(this->many, str);
415 if (r != SIZE_MAX) return r;
416
417 _settings_error_list.emplace_back(
418 GetEncodedString(STR_CONFIG_ERROR),
419 GetEncodedString(STR_CONFIG_ERROR_INVALID_VALUE, str, this->GetName()));
420 return this->GetDefaultValue();
421}
422
423size_t BoolSettingDesc::ParseValue(const char *str) const
424{
426 if (r.has_value()) return *r;
427
428 _settings_error_list.emplace_back(
429 GetEncodedString(STR_CONFIG_ERROR),
430 GetEncodedString(STR_CONFIG_ERROR_INVALID_VALUE, str, this->GetName()));
431 return this->GetDefaultValue();
432}
433
440{
441 return this->get_title_cb != nullptr ? this->get_title_cb(*this) : this->str;
442}
443
449{
450 return this->get_help_cb != nullptr ? this->get_help_cb(*this) : this->str_help;
451}
452
457std::pair<StringParameter, StringParameter> IntSettingDesc::GetValueParams(int32_t value) const
458{
459 if (this->get_value_params_cb != nullptr) {
460 return this->get_value_params_cb(*this, value);
461 }
462
463 if (this->IsBoolSetting()) {
464 return {value != 0 ? STR_CONFIG_SETTING_ON : STR_CONFIG_SETTING_OFF, {}};
465 }
466
468 auto [min_val, _] = this->GetRange();
469 return {this->str_val - min_val + value, value};
470 }
471
472 return {this->str_val + ((value == 0 && this->flags.Test(SettingFlag::GuiZeroIsSpecial)) ? 1 : 0), value};
473}
474
480{
481 return this->get_def_cb != nullptr ? this->get_def_cb(*this) : this->def;
482}
483
488std::tuple<int32_t, uint32_t> IntSettingDesc::GetRange() const
489{
490 return this->get_range_cb != nullptr ? this->get_range_cb(*this) : std::tuple(this->min, this->max);
491}
492
499void IntSettingDesc::MakeValueValidAndWrite(const void *object, int32_t val) const
500{
501 this->MakeValueValid(val);
502 this->Write(object, val);
503}
504
514void IntSettingDesc::MakeValueValid(int32_t &val) const
515{
516 auto [min_val, max_val] = this->GetRange();
517 /* We need to take special care of the uint32_t type as we receive from the function
518 * a signed integer. While here also bail out on 64-bit settings as those are not
519 * supported. Unsigned 8 and 16-bit variables are safe since they fit into a signed
520 * 32-bit variable
521 * TODO: Support 64-bit settings/variables; requires 64 bit over command protocol! */
522 switch (GetVarMemType(this->save.conv)) {
523 case SLE_VAR_NULL: return;
524 case SLE_VAR_BL:
525 case SLE_VAR_I8:
526 case SLE_VAR_U8:
527 case SLE_VAR_I16:
528 case SLE_VAR_U16:
529 case SLE_VAR_I32: {
530 /* Override the minimum value. No value below this->min, except special value 0 */
531 if (!this->flags.Test(SettingFlag::GuiZeroIsSpecial) || val != 0) {
532 if (!this->flags.Test(SettingFlag::GuiDropdown)) {
533 /* Clamp value-type setting to its valid range */
534 val = Clamp(val, min_val, max_val);
535 } else if (val < min_val || val > static_cast<int32_t>(max_val)) {
536 /* Reset invalid discrete setting (where different values change gameplay) to its default value */
537 val = this->GetDefaultValue();
538 }
539 }
540 break;
541 }
542 case SLE_VAR_U32: {
543 /* Override the minimum value. No value below this->min, except special value 0 */
544 uint32_t uval = static_cast<uint32_t>(val);
545 if (!this->flags.Test(SettingFlag::GuiZeroIsSpecial) || uval != 0) {
546 if (!this->flags.Test(SettingFlag::GuiDropdown)) {
547 /* Clamp value-type setting to its valid range */
548 uval = ClampU(uval, min_val, max_val);
549 } else if (uval < static_cast<uint32_t>(min_val) || uval > max_val) {
550 /* Reset invalid discrete setting to its default value */
551 uval = static_cast<uint32_t>(this->GetDefaultValue());
552 }
553 }
554 val = static_cast<int32_t>(uval);
555 return;
556 }
557 case SLE_VAR_I64:
558 case SLE_VAR_U64:
559 default: NOT_REACHED();
560 }
561}
562
568void IntSettingDesc::Write(const void *object, int32_t val) const
569{
570 void *ptr = GetVariableAddress(object, this->save);
571 WriteValue(ptr, this->save.conv, (int64_t)val);
572}
573
579int32_t IntSettingDesc::Read(const void *object) const
580{
581 void *ptr = GetVariableAddress(object, this->save);
582 return (int32_t)ReadValue(ptr, this->save.conv);
583}
584
592void StringSettingDesc::MakeValueValid(std::string &str) const
593{
594 if (this->max_length == 0 || str.size() < this->max_length) return;
595
596 /* In case a maximum length is imposed by the setting, the length
597 * includes the '\0' termination for network transfer purposes.
598 * Also ensure the string is valid after chopping of some bytes. */
599 std::string stdstr(str, 0, this->max_length - 1);
600 str.assign(StrMakeValid(stdstr, SVS_NONE));
601}
602
608void StringSettingDesc::Write(const void *object, const std::string &str) const
609{
610 reinterpret_cast<std::string *>(GetVariableAddress(object, this->save))->assign(str);
611}
612
618const std::string &StringSettingDesc::Read(const void *object) const
619{
620 return *reinterpret_cast<std::string *>(GetVariableAddress(object, this->save));
621}
622
632static void IniLoadSettings(IniFile &ini, const SettingTable &settings_table, const char *grpname, void *object, bool only_startup)
633{
634 const IniGroup *group;
635 const IniGroup *group_def = ini.GetGroup(grpname);
636
637 for (auto &desc : settings_table) {
638 const SettingDesc *sd = GetSettingDesc(desc);
640 if (sd->startup != only_startup) continue;
641
642 /* For settings.xx.yy load the settings from [xx] yy = ? */
643 std::string s{ sd->GetName() };
644 auto sc = s.find('.');
645 if (sc != std::string::npos) {
646 group = ini.GetGroup(s.substr(0, sc));
647 if (group == nullptr) group = group_def;
648 s = s.substr(sc + 1);
649 } else {
650 group = group_def;
651 }
652
653 const IniItem *item = nullptr;
654 if (group != nullptr) item = group->GetItem(s);
655 if (item == nullptr && group != group_def && group_def != nullptr) {
656 /* For settings.xx.yy load the settings from [settings] yy = ? in case the previous
657 * did not exist (e.g. loading old config files with a [settings] section */
658 item = group_def->GetItem(s);
659 }
660 if (item == nullptr) {
661 /* For settings.xx.zz.yy load the settings from [zz] yy = ? in case the previous
662 * did not exist (e.g. loading old config files with a [yapf] section */
663 sc = s.find('.');
664 if (sc != std::string::npos) {
665 if (group = ini.GetGroup(s.substr(0, sc)); group != nullptr) item = group->GetItem(s.substr(sc + 1));
666 }
667 }
668
669 sd->ParseValue(item, object);
670 }
671}
672
673void IntSettingDesc::ParseValue(const IniItem *item, void *object) const
674{
675 size_t val = (item == nullptr) ? this->GetDefaultValue() : this->ParseValue(item->value.has_value() ? item->value->c_str() : "");
676 this->MakeValueValidAndWrite(object, (int32_t)val);
677}
678
679void StringSettingDesc::ParseValue(const IniItem *item, void *object) const
680{
681 std::string str = (item == nullptr) ? this->def : item->value.value_or("");
682 this->MakeValueValid(str);
683 this->Write(object, str);
684}
685
686void ListSettingDesc::ParseValue(const IniItem *item, void *object) const
687{
688 const char *str = (item == nullptr) ? this->def : item->value.has_value() ? item->value->c_str() : nullptr;
689 void *ptr = GetVariableAddress(object, this->save);
690 if (!LoadIntList(str, ptr, this->save.length, GetVarMemType(this->save.conv))) {
691 _settings_error_list.emplace_back(
692 GetEncodedString(STR_CONFIG_ERROR),
693 GetEncodedString(STR_CONFIG_ERROR_ARRAY, this->GetName()));
694
695 /* Use default */
696 LoadIntList(this->def, ptr, this->save.length, GetVarMemType(this->save.conv));
697 }
698}
699
712static void IniSaveSettings(IniFile &ini, const SettingTable &settings_table, const char *grpname, void *object, bool)
713{
714 IniGroup *group_def = nullptr, *group;
715
716 for (auto &desc : settings_table) {
717 const SettingDesc *sd = GetSettingDesc(desc);
718 /* If the setting is not saved to the configuration
719 * file, just continue with the next setting */
721 if (sd->flags.Test(SettingFlag::NotInConfig)) continue;
722
723 /* XXX - wtf is this?? (group override?) */
724 std::string s{ sd->GetName() };
725 auto sc = s.find('.');
726 if (sc != std::string::npos) {
727 group = &ini.GetOrCreateGroup(s.substr(0, sc));
728 s = s.substr(sc + 1);
729 } else {
730 if (group_def == nullptr) group_def = &ini.GetOrCreateGroup(grpname);
731 group = group_def;
732 }
733
734 IniItem &item = group->GetOrCreateItem(s);
735
736 if (!item.value.has_value() || !sd->IsSameValue(&item, object)) {
737 /* The value is different, that means we have to write it to the ini */
738 item.value.emplace(sd->FormatValue(object));
739 }
740 }
741}
742
743std::string IntSettingDesc::FormatValue(const void *object) const
744{
745 int64_t i;
746 if (IsSignedVarMemType(this->save.conv)) {
747 i = this->Read(object);
748 } else {
749 i = (uint32_t)this->Read(object);
750 }
751 return std::to_string(i);
752}
753
754std::string BoolSettingDesc::FormatValue(const void *object) const
755{
756 bool val = this->Read(object) != 0;
757 return val ? "true" : "false";
758}
759
760bool IntSettingDesc::IsSameValue(const IniItem *item, void *object) const
761{
762 int32_t item_value = (int32_t)this->ParseValue(item->value->c_str());
763 int32_t object_value = this->Read(object);
764 return item_value == object_value;
765}
766
767bool IntSettingDesc::IsDefaultValue(void *object) const
768{
769 int32_t object_value = this->Read(object);
770 return this->GetDefaultValue() == object_value;
771}
772
773void IntSettingDesc::ResetToDefault(void *object) const
774{
775 this->Write(object, this->GetDefaultValue());
776}
777
778std::string StringSettingDesc::FormatValue(const void *object) const
779{
780 const std::string &str = this->Read(object);
781 switch (GetVarMemType(this->save.conv)) {
782 case SLE_VAR_STR: return str;
783
784 case SLE_VAR_STRQ:
785 if (str.empty()) {
786 return str;
787 }
788 return fmt::format("\"{}\"", str);
789
790 default: NOT_REACHED();
791 }
792}
793
794bool StringSettingDesc::IsSameValue(const IniItem *item, void *object) const
795{
796 /* The ini parsing removes the quotes, which are needed to retain the spaces in STRQs,
797 * so those values are always different in the parsed ini item than they should be. */
798 if (GetVarMemType(this->save.conv) == SLE_VAR_STRQ) return false;
799
800 const std::string &str = this->Read(object);
801 return item->value->compare(str) == 0;
802}
803
804bool StringSettingDesc::IsDefaultValue(void *object) const
805{
806 const std::string &str = this->Read(object);
807 return this->def == str;
808}
809
810void StringSettingDesc::ResetToDefault(void *object) const
811{
812 this->Write(object, this->def);
813}
814
815bool ListSettingDesc::IsSameValue(const IniItem *, void *) const
816{
817 /* Checking for equality is way more expensive than just writing the value. */
818 return false;
819}
820
822{
823 /* Defaults of lists are often complicated, and hard to compare. */
824 return false;
825}
826
828{
829 /* Resetting a list to default is not supported. */
830 NOT_REACHED();
831}
832
842static void IniLoadSettingList(IniFile &ini, const char *grpname, StringList &list)
843{
844 const IniGroup *group = ini.GetGroup(grpname);
845
846 if (group == nullptr) return;
847
848 list.clear();
849
850 for (const IniItem &item : group->items) {
851 if (!item.name.empty()) list.push_back(item.name);
852 }
853}
854
864static void IniSaveSettingList(IniFile &ini, const char *grpname, StringList &list)
865{
866 IniGroup &group = ini.GetOrCreateGroup(grpname);
867 group.Clear();
868
869 for (const auto &iter : list) {
870 group.GetOrCreateItem(iter).SetValue("");
871 }
872}
873
880void IniLoadWindowSettings(IniFile &ini, const char *grpname, void *desc)
881{
882 IniLoadSettings(ini, _window_settings, grpname, desc, false);
883}
884
891void IniSaveWindowSettings(IniFile &ini, const char *grpname, void *desc)
892{
893 IniSaveSettings(ini, _window_settings, grpname, desc, false);
894}
895
901bool SettingDesc::IsEditable(bool do_command) const
902{
903 if (!do_command && !this->flags.Test(SettingFlag::NoNetworkSync) && _networking && !_network_server && !this->flags.Test(SettingFlag::PerCompany)) return false;
904 if (do_command && this->flags.Test(SettingFlag::NoNetworkSync)) return false;
905 if (this->flags.Test(SettingFlag::NetworkOnly) && !_networking && _game_mode != GM_MENU) return false;
906 if (this->flags.Test(SettingFlag::NoNetwork) && _networking) return false;
908 (_game_mode == GM_NORMAL ||
909 (_game_mode == GM_EDITOR && !this->flags.Test(SettingFlag::SceneditToo)))) return false;
910 if (this->flags.Test(SettingFlag::SceneditOnly) && _game_mode != GM_EDITOR) return false;
911 return true;
912}
913
923
929{
930 assert(this->IsIntSetting());
931 return static_cast<const IntSettingDesc *>(this);
932}
933
939{
940 assert(this->IsStringSetting());
941 return static_cast<const StringSettingDesc *>(this);
942}
943
945void HandleOldDiffCustom(bool savegame);
946
947
957
958static void AILoadConfig(const IniFile &ini, const char *grpname)
959{
960 const IniGroup *group = ini.GetGroup(grpname);
961
962 /* Clean any configured AI */
963 for (CompanyID c = CompanyID::Begin(); c < MAX_COMPANIES; ++c) {
965 }
966
967 /* If no group exists, return */
968 if (group == nullptr) return;
969
970 CompanyID c = CompanyID::Begin();
971 for (const IniItem &item : group->items) {
973
974 config->Change(item.name);
975 if (!config->HasScript()) {
976 if (item.name != "none") {
977 Debug(script, 0, "The AI by the name '{}' was no longer found, and removed from the list.", item.name);
978 continue;
979 }
980 }
981 if (item.value.has_value()) config->StringToSettings(*item.value);
982 ++c;
983 if (c >= MAX_COMPANIES) break;
984 }
985}
986
987static void GameLoadConfig(const IniFile &ini, const char *grpname)
988{
989 const IniGroup *group = ini.GetGroup(grpname);
990
991 /* Clean any configured GameScript */
993
994 /* If no group exists, return */
995 if (group == nullptr || group->items.empty()) return;
996
997 const IniItem &item = group->items.front();
998
1000
1001 config->Change(item.name);
1002 if (!config->HasScript()) {
1003 if (item.name != "none") {
1004 Debug(script, 0, "The GameScript by the name '{}' was no longer found, and removed from the list.", item.name);
1005 return;
1006 }
1007 }
1008 if (item.value.has_value()) config->StringToSettings(*item.value);
1009}
1010
1015{
1016 if (const IniGroup *group = ini.GetGroup("misc"); group != nullptr) {
1017 /* Load old setting first. */
1018 if (const IniItem *item = group->GetItem("graphicsset"); item != nullptr && item->value) BaseGraphics::ini_data.name = *item->value;
1019 }
1020
1021 if (const IniGroup *group = ini.GetGroup("graphicsset"); group != nullptr) {
1022 /* Load new settings. */
1023 if (const IniItem *item = group->GetItem("name"); item != nullptr && item->value) BaseGraphics::ini_data.name = *item->value;
1024
1025 if (const IniItem *item = group->GetItem("shortname"); item != nullptr && item->value && item->value->size() == 8) {
1026 BaseGraphics::ini_data.shortname = std::byteswap<uint32_t>(std::strtoul(item->value->c_str(), nullptr, 16));
1027 }
1028
1029 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);
1030
1031 if (const IniItem *item = group->GetItem("extra_params"); item != nullptr && item->value) {
1032 auto params = ParseIntList(item->value->c_str());
1033 if (params.has_value()) {
1034 BaseGraphics::ini_data.extra_params = params.value();
1035 } else {
1036 ShowErrorMessage(GetEncodedString(STR_CONFIG_ERROR),
1037 GetEncodedString(STR_CONFIG_ERROR_ARRAY, BaseGraphics::ini_data.name),
1038 WL_CRITICAL);
1039 }
1040 }
1041 }
1042}
1043
1050static GRFConfigList GRFLoadConfig(const IniFile &ini, const char *grpname, bool is_static)
1051{
1052 const IniGroup *group = ini.GetGroup(grpname);
1053 GRFConfigList list;
1054
1055 if (group == nullptr) return list;
1056
1057 uint num_grfs = 0;
1058 for (const IniItem &item : group->items) {
1059 std::unique_ptr<GRFConfig> c{};
1060
1061 std::array<uint8_t, 4> grfid_buf;
1062 MD5Hash md5sum;
1063 std::string_view item_name = item.name;
1064 bool has_md5sum = false;
1065
1066 /* Try reading "<grfid>|" and on success, "<md5sum>|". */
1067 auto grfid_pos = item_name.find("|");
1068 if (grfid_pos != std::string_view::npos) {
1069 std::string_view grfid_str = item_name.substr(0, grfid_pos);
1070
1071 if (ConvertHexToBytes(grfid_str, grfid_buf)) {
1072 item_name = item_name.substr(grfid_pos + 1);
1073
1074 auto md5sum_pos = item_name.find("|");
1075 if (md5sum_pos != std::string_view::npos) {
1076 std::string_view md5sum_str = item_name.substr(0, md5sum_pos);
1077
1078 has_md5sum = ConvertHexToBytes(md5sum_str, md5sum);
1079 if (has_md5sum) item_name = item_name.substr(md5sum_pos + 1);
1080 }
1081
1082 uint32_t grfid = grfid_buf[0] | (grfid_buf[1] << 8) | (grfid_buf[2] << 16) | (grfid_buf[3] << 24);
1083 if (has_md5sum) {
1084 const GRFConfig *s = FindGRFConfig(grfid, FGCM_EXACT, &md5sum);
1085 if (s != nullptr) c = std::make_unique<GRFConfig>(*s);
1086 }
1087 if (c == nullptr && !FioCheckFileExists(std::string(item_name), NEWGRF_DIR)) {
1088 const GRFConfig *s = FindGRFConfig(grfid, FGCM_NEWEST_VALID);
1089 if (s != nullptr) c = std::make_unique<GRFConfig>(*s);
1090 }
1091 }
1092 }
1093 std::string filename = std::string(item_name);
1094
1095 if (c == nullptr) c = std::make_unique<GRFConfig>(filename);
1096
1097 /* Parse parameters */
1098 if (item.value.has_value() && !item.value->empty()) {
1099 auto params = ParseIntList(item.value->c_str());
1100 if (params.has_value()) {
1101 c->SetParams(params.value());
1102 } else {
1103 ShowErrorMessage(GetEncodedString(STR_CONFIG_ERROR),
1104 GetEncodedString(STR_CONFIG_ERROR_ARRAY, filename),
1105 WL_CRITICAL);
1106 }
1107 }
1108
1109 /* Check if item is valid */
1110 if (!FillGRFDetails(*c, is_static) || c->flags.Test(GRFConfigFlag::Invalid)) {
1111 StringID reason;
1112 if (c->status == GCS_NOT_FOUND) {
1113 reason = STR_CONFIG_ERROR_INVALID_GRF_NOT_FOUND;
1114 } else if (c->flags.Test(GRFConfigFlag::Unsafe)) {
1115 reason = STR_CONFIG_ERROR_INVALID_GRF_UNSAFE;
1116 } else if (c->flags.Test(GRFConfigFlag::System)) {
1117 reason = STR_CONFIG_ERROR_INVALID_GRF_SYSTEM;
1118 } else if (c->flags.Test(GRFConfigFlag::Invalid)) {
1119 reason = STR_CONFIG_ERROR_INVALID_GRF_INCOMPATIBLE;
1120 } else {
1121 reason = STR_CONFIG_ERROR_INVALID_GRF_UNKNOWN;
1122 }
1123
1124 ShowErrorMessage(GetEncodedString(STR_CONFIG_ERROR),
1125 GetEncodedString(STR_CONFIG_ERROR_INVALID_GRF, filename.empty() ? item.name.c_str() : filename, reason),
1126 WL_CRITICAL);
1127 continue;
1128 }
1129
1130 /* Check for duplicate GRFID (will also check for duplicate filenames) */
1131 auto found = std::ranges::find_if(list, [&c](const auto &gc) { return gc->ident.grfid == c->ident.grfid; });
1132 if (found != std::end(list)) {
1133 ShowErrorMessage(GetEncodedString(STR_CONFIG_ERROR),
1134 GetEncodedString(STR_CONFIG_ERROR_DUPLICATE_GRFID, c->filename, (*found)->filename),
1135 WL_CRITICAL);
1136 continue;
1137 }
1138
1139 if (is_static) {
1140 /* Mark file as static to avoid saving in savegame. */
1141 c->flags.Set(GRFConfigFlag::Static);
1142 } else if (++num_grfs > NETWORK_MAX_GRF_COUNT) {
1143 /* Check we will not load more non-static NewGRFs than allowed. This could trigger issues for game servers. */
1144 ShowErrorMessage(GetEncodedString(STR_CONFIG_ERROR),
1145 GetEncodedString(STR_NEWGRF_ERROR_TOO_MANY_NEWGRFS_LOADED), WL_CRITICAL);
1146 break;
1147 }
1148
1149 /* Add item to list */
1150 list.push_back(std::move(c));
1151 }
1152
1153 return list;
1154}
1155
1156static IniFileVersion LoadVersionFromConfig(const IniFile &ini)
1157{
1158 const IniGroup *group = ini.GetGroup("version");
1159 if (group == nullptr) return IFV_0;
1160
1161 auto version_number = group->GetItem("ini_version");
1162 /* Older ini-file versions don't have this key yet. */
1163 if (version_number == nullptr || !version_number->value.has_value()) return IFV_0;
1164
1165 uint32_t version = 0;
1166 std::from_chars(version_number->value->data(), version_number->value->data() + version_number->value->size(), version);
1167
1168 return static_cast<IniFileVersion>(version);
1169}
1170
1171static void AISaveConfig(IniFile &ini, const char *grpname)
1172{
1173 IniGroup &group = ini.GetOrCreateGroup(grpname);
1174 group.Clear();
1175
1176 for (CompanyID c = CompanyID::Begin(); c < MAX_COMPANIES; ++c) {
1178 std::string name;
1179 std::string value = config->SettingsToString();
1180
1181 if (config->HasScript()) {
1182 name = config->GetName();
1183 } else {
1184 name = "none";
1185 }
1186
1187 group.CreateItem(name).SetValue(value);
1188 }
1189}
1190
1191static void GameSaveConfig(IniFile &ini, const char *grpname)
1192{
1193 IniGroup &group = ini.GetOrCreateGroup(grpname);
1194 group.Clear();
1195
1197 std::string name;
1198 std::string value = config->SettingsToString();
1199
1200 if (config->HasScript()) {
1201 name = config->GetName();
1202 } else {
1203 name = "none";
1204 }
1205
1206 group.CreateItem(name).SetValue(value);
1207}
1208
1214{
1215 IniGroup &group = ini.GetOrCreateGroup("version");
1216 group.GetOrCreateItem("version_string").SetValue(_openttd_revision);
1217 group.GetOrCreateItem("version_number").SetValue(fmt::format("{:08X}", _openttd_newgrf_version));
1218 group.GetOrCreateItem("ini_version").SetValue(std::to_string(INIFILE_VERSION));
1219}
1220
1225{
1226 const GraphicsSet *used_set = BaseGraphics::GetUsedSet();
1227 if (used_set == nullptr) return;
1228
1229 IniGroup &group = ini.GetOrCreateGroup("graphicsset");
1230 group.Clear();
1231
1232 group.GetOrCreateItem("name").SetValue(used_set->name);
1233 group.GetOrCreateItem("shortname").SetValue(fmt::format("{:08X}", std::byteswap(used_set->shortname)));
1234
1235 const GRFConfig *extra_cfg = used_set->GetExtraConfig();
1236 if (extra_cfg != nullptr && !extra_cfg->param.empty()) {
1237 group.GetOrCreateItem("extra_version").SetValue(fmt::format("{}", extra_cfg->version));
1238 group.GetOrCreateItem("extra_params").SetValue(GRFBuildParamList(*extra_cfg));
1239 }
1240}
1241
1242/* Save a GRF configuration to the given group name */
1243static void GRFSaveConfig(IniFile &ini, const char *grpname, const GRFConfigList &list)
1244{
1245 IniGroup &group = ini.GetOrCreateGroup(grpname);
1246 group.Clear();
1247
1248 for (const auto &c : list) {
1249 std::string key = fmt::format("{:08X}|{}|{}", std::byteswap(c->ident.grfid),
1250 FormatArrayAsHex(c->ident.md5sum), c->filename);
1252 }
1253}
1254
1255/* Common handler for saving/loading variables to the configuration file */
1256static void HandleSettingDescs(IniFile &generic_ini, IniFile &private_ini, IniFile &secrets_ini, SettingDescProc *proc, SettingDescProcList *proc_list, bool only_startup = false)
1257{
1258 proc(generic_ini, _misc_settings, "misc", nullptr, only_startup);
1259#if defined(_WIN32) && !defined(DEDICATED)
1260 proc(generic_ini, _win32_settings, "win32", nullptr, only_startup);
1261#endif /* _WIN32 */
1262
1263 /* The name "patches" is a fallback, as every setting should sets its own group. */
1264
1265 for (auto &table : GenericSettingTables()) {
1266 proc(generic_ini, table, "patches", &_settings_newgame, only_startup);
1267 }
1268 for (auto &table : PrivateSettingTables()) {
1269 proc(private_ini, table, "patches", &_settings_newgame, only_startup);
1270 }
1271 for (auto &table : SecretSettingTables()) {
1272 proc(secrets_ini, table, "patches", &_settings_newgame, only_startup);
1273 }
1274
1275 proc(generic_ini, _currency_settings, "currency", &GetCustomCurrency(), only_startup);
1276 proc(generic_ini, _company_settings, "company", &_settings_client.company, only_startup);
1277
1278 if (!only_startup) {
1279 proc_list(private_ini, "server_bind_addresses", _network_bind_list);
1280 proc_list(private_ini, "servers", _network_host_list);
1281 proc_list(private_ini, "bans", _network_ban_list);
1282 proc_list(private_ini, "server_authorized_keys", _settings_client.network.server_authorized_keys);
1283 proc_list(private_ini, "rcon_authorized_keys", _settings_client.network.rcon_authorized_keys);
1284 proc_list(private_ini, "admin_authorized_keys", _settings_client.network.admin_authorized_keys);
1285 }
1286}
1287
1297static void RemoveEntriesFromIni(IniFile &ini, const SettingTable &table)
1298{
1299 for (auto &desc : table) {
1300 const SettingDesc *sd = GetSettingDesc(desc);
1301
1302 /* For settings.xx.yy load the settings from [xx] yy = ? */
1303 std::string s{ sd->GetName() };
1304 auto sc = s.find('.');
1305 if (sc == std::string::npos) continue;
1306
1307 IniGroup *group = ini.GetGroup(s.substr(0, sc));
1308 if (group == nullptr) continue;
1309 s = s.substr(sc + 1);
1310
1311 group->RemoveItem(s);
1312 }
1313}
1314
1338bool IsConversionNeeded(const ConfigIniFile &ini, const std::string &group, const std::string &old_var, const std::string &new_var, const IniItem **old_item)
1339{
1340 *old_item = nullptr;
1341
1342 const IniGroup *igroup = ini.GetGroup(group);
1343 /* If the group doesn't exist, there is nothing to convert. */
1344 if (igroup == nullptr) return false;
1345
1346 const IniItem *tmp_old_item = igroup->GetItem(old_var);
1347 const IniItem *new_item = igroup->GetItem(new_var);
1348
1349 /* If the old item doesn't exist, there is nothing to convert. */
1350 if (tmp_old_item == nullptr) return false;
1351
1352 /* If the new item exists, it means conversion was already done. We only
1353 * do the conversion the first time, and after that these settings are
1354 * independent. This allows users to freely change between older and
1355 * newer clients without breaking anything. */
1356 if (new_item != nullptr) return false;
1357
1358 *old_item = tmp_old_item;
1359 return true;
1360}
1361
1366void LoadFromConfig(bool startup)
1367{
1368 ConfigIniFile generic_ini(_config_file);
1369 ConfigIniFile private_ini(_private_file);
1370 ConfigIniFile secrets_ini(_secrets_file);
1371 ConfigIniFile favs_ini(_favs_file);
1372
1373 if (!startup) ResetCurrencies(false); // Initialize the array of currencies, without preserving the custom one
1374
1375 IniFileVersion generic_version = LoadVersionFromConfig(generic_ini);
1376
1377 if (startup) {
1378 GraphicsSetLoadConfig(generic_ini);
1379 }
1380
1381 /* Before the split of private/secrets, we have to look in the generic for these settings. */
1382 if (generic_version < IFV_PRIVATE_SECRETS) {
1383 HandleSettingDescs(generic_ini, generic_ini, generic_ini, IniLoadSettings, IniLoadSettingList, startup);
1384 } else {
1385 HandleSettingDescs(generic_ini, private_ini, secrets_ini, IniLoadSettings, IniLoadSettingList, startup);
1386 }
1387
1388 /* Load basic settings only during bootstrap, load other settings not during bootstrap */
1389 if (!startup) {
1390 if (generic_version < IFV_LINKGRAPH_SECONDS) {
1393 }
1394
1395 /* Move use_relay_service from generic_ini to private_ini. */
1396 if (generic_version < IFV_NETWORK_PRIVATE_SETTINGS) {
1397 const IniGroup *network = generic_ini.GetGroup("network");
1398 if (network != nullptr) {
1399 const IniItem *use_relay_service = network->GetItem("use_relay_service");
1400 if (use_relay_service != nullptr) {
1401 if (use_relay_service->value == "never") {
1402 _settings_client.network.use_relay_service = UseRelayService::URS_NEVER;
1403 } else if (use_relay_service->value == "ask") {
1404 _settings_client.network.use_relay_service = UseRelayService::URS_ASK;
1405 } else if (use_relay_service->value == "allow") {
1406 _settings_client.network.use_relay_service = UseRelayService::URS_ALLOW;
1407 }
1408 }
1409 }
1410 }
1411
1412 const IniItem *old_item;
1413
1414 if (generic_version < IFV_GAME_TYPE && IsConversionNeeded(generic_ini, "network", "server_advertise", "server_game_type", &old_item)) {
1415 auto old_value = BoolSettingDesc::ParseSingleValue(old_item->value->c_str());
1416 _settings_client.network.server_game_type = old_value.value_or(false) ? SERVER_GAME_TYPE_PUBLIC : SERVER_GAME_TYPE_LOCAL;
1417 }
1418
1419 if (generic_version < IFV_AUTOSAVE_RENAME && IsConversionNeeded(generic_ini, "gui", "autosave", "autosave_interval", &old_item)) {
1420 static std::vector<std::string> _old_autosave_interval{"off", "monthly", "quarterly", "half year", "yearly"};
1421 auto old_value = OneOfManySettingDesc::ParseSingleValue(old_item->value->c_str(), old_item->value->size(), _old_autosave_interval);
1422
1423 switch (old_value) {
1424 case 0: _settings_client.gui.autosave_interval = 0; break;
1425 case 1: _settings_client.gui.autosave_interval = 10; break;
1426 case 2: _settings_client.gui.autosave_interval = 30; break;
1427 case 3: _settings_client.gui.autosave_interval = 60; break;
1428 case 4: _settings_client.gui.autosave_interval = 120; break;
1429 default: break;
1430 }
1431 }
1432
1433 /* Persist the right click close option from older versions. */
1434 if (generic_version < IFV_RIGHT_CLICK_CLOSE && IsConversionNeeded(generic_ini, "gui", "right_mouse_wnd_close", "right_click_wnd_close", &old_item)) {
1435 auto old_value = BoolSettingDesc::ParseSingleValue(old_item->value->c_str());
1436 _settings_client.gui.right_click_wnd_close = old_value.value_or(false) ? RCC_YES : RCC_NO;
1437 }
1438
1439 _grfconfig_newgame = GRFLoadConfig(generic_ini, "newgrf", false);
1440 _grfconfig_static = GRFLoadConfig(generic_ini, "newgrf-static", true);
1441 AILoadConfig(generic_ini, "ai_players");
1442 GameLoadConfig(generic_ini, "game_scripts");
1443 PickerLoadConfig(favs_ini);
1444
1446 IniLoadSettings(generic_ini, _old_gameopt_settings, "gameopt", &_settings_newgame, false);
1447 HandleOldDiffCustom(false);
1448
1451
1452 /* Display scheduled errors */
1454 if (FindWindowById(WC_ERRMSG, 0) == nullptr) ShowFirstError();
1455 }
1456}
1457
1460{
1461 ConfigIniFile generic_ini(_config_file);
1462 ConfigIniFile private_ini(_private_file);
1463 ConfigIniFile secrets_ini(_secrets_file);
1464 ConfigIniFile favs_ini(_favs_file);
1465
1466 IniFileVersion generic_version = LoadVersionFromConfig(generic_ini);
1467
1468 /* If we newly create the private/secrets file, add a dummy group on top
1469 * just so we can add a comment before it (that is how IniFile works).
1470 * This to explain what the file is about. After doing it once, never touch
1471 * it again, as otherwise we might be reverting user changes. */
1472 if (IniGroup *group = private_ini.GetGroup("private"); group != nullptr) group->comment = "; This file possibly contains private information which can identify you as person.\n";
1473 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";
1474
1475 if (generic_version == IFV_0) {
1476 /* Remove some obsolete groups. These have all been loaded into other groups. */
1477 generic_ini.RemoveGroup("patches");
1478 generic_ini.RemoveGroup("yapf");
1479 generic_ini.RemoveGroup("gameopt");
1480
1481 /* Remove all settings from the generic ini that are now in the private ini. */
1482 generic_ini.RemoveGroup("server_bind_addresses");
1483 generic_ini.RemoveGroup("servers");
1484 generic_ini.RemoveGroup("bans");
1485 for (auto &table : PrivateSettingTables()) {
1486 RemoveEntriesFromIni(generic_ini, table);
1487 }
1488
1489 /* Remove all settings from the generic ini that are now in the secrets ini. */
1490 for (auto &table : SecretSettingTables()) {
1491 RemoveEntriesFromIni(generic_ini, table);
1492 }
1493 }
1494
1495 if (generic_version < IFV_REMOVE_GENERATION_SEED) {
1496 IniGroup *game_creation = generic_ini.GetGroup("game_creation");
1497 if (game_creation != nullptr) {
1498 game_creation->RemoveItem("generation_seed");
1499 }
1500 }
1501
1502 /* These variables are migrated from generic ini to private ini now. */
1503 if (generic_version < IFV_NETWORK_PRIVATE_SETTINGS) {
1504 IniGroup *network = generic_ini.GetGroup("network");
1505 if (network != nullptr) {
1506 network->RemoveItem("use_relay_service");
1507 }
1508 }
1509
1510 HandleSettingDescs(generic_ini, private_ini, secrets_ini, IniSaveSettings, IniSaveSettingList);
1511 GraphicsSetSaveConfig(generic_ini);
1512 GRFSaveConfig(generic_ini, "newgrf", _grfconfig_newgame);
1513 GRFSaveConfig(generic_ini, "newgrf-static", _grfconfig_static);
1514 AISaveConfig(generic_ini, "ai_players");
1515 GameSaveConfig(generic_ini, "game_scripts");
1516 PickerSaveConfig(favs_ini);
1517
1518 SaveVersionInConfig(generic_ini);
1519 SaveVersionInConfig(private_ini);
1520 SaveVersionInConfig(secrets_ini);
1521 SaveVersionInConfig(favs_ini);
1522
1523 generic_ini.SaveToDisk(_config_file);
1524 private_ini.SaveToDisk(_private_file);
1525 secrets_ini.SaveToDisk(_secrets_file);
1526 favs_ini.SaveToDisk(_favs_file);
1527}
1528
1534{
1535 StringList list;
1536
1538 for (const IniGroup &group : ini.groups) {
1539 if (group.name.compare(0, 7, "preset-") == 0) {
1540 list.push_back(group.name.substr(7));
1541 }
1542 }
1543
1544 return list;
1545}
1546
1553GRFConfigList LoadGRFPresetFromConfig(const char *config_name)
1554{
1555 std::string section("preset-");
1556 section += config_name;
1557
1559 GRFConfigList config = GRFLoadConfig(ini, section.c_str(), false);
1560
1561 return config;
1562}
1563
1570void SaveGRFPresetToConfig(const char *config_name, GRFConfigList &config)
1571{
1572 std::string section("preset-");
1573 section += config_name;
1574
1576 GRFSaveConfig(ini, section.c_str(), config);
1578}
1579
1584void DeleteGRFPresetFromConfig(const char *config_name)
1585{
1586 std::string section("preset-");
1587 section += config_name;
1588
1590 ini.RemoveGroup(section);
1592}
1593
1600void IntSettingDesc::ChangeValue(const void *object, int32_t newval) const
1601{
1602 int32_t oldval = this->Read(object);
1603 this->MakeValueValid(newval);
1604 if (this->pre_check != nullptr && !this->pre_check(newval)) return;
1605 if (oldval == newval) return;
1606
1607 this->Write(object, newval);
1608 if (this->post_callback != nullptr) this->post_callback(newval);
1609
1610 if (this->flags.Test(SettingFlag::NoNetwork) || this->flags.Test(SettingFlag::Sandbox)) {
1612 _gamelog.Setting(this->GetName(), oldval, newval);
1614 }
1615
1618
1619 if (_save_config) SaveToConfig();
1620}
1621
1629static const SettingDesc *GetSettingFromName(const std::string_view name, const SettingTable &settings)
1630{
1631 /* First check all full names */
1632 for (auto &desc : settings) {
1633 const SettingDesc *sd = GetSettingDesc(desc);
1634 if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue;
1635 if (sd->GetName() == name) return sd;
1636 }
1637
1638 /* Then check the shortcut variant of the name. */
1639 std::string short_name_suffix = std::string{ "." }.append(name);
1640 for (auto &desc : settings) {
1641 const SettingDesc *sd = GetSettingDesc(desc);
1642 if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue;
1643 if (sd->GetName().ends_with(short_name_suffix)) return sd;
1644 }
1645
1646 return nullptr;
1647}
1648
1654void GetSaveLoadFromSettingTable(SettingTable settings, std::vector<SaveLoad> &saveloads)
1655{
1656 for (auto &desc : settings) {
1657 const SettingDesc *sd = GetSettingDesc(desc);
1658 if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue;
1659 saveloads.push_back(sd->save);
1660 }
1661}
1662
1669static const SettingDesc *GetCompanySettingFromName(std::string_view name)
1670{
1671 static const std::string_view company_prefix = "company.";
1672 if (name.starts_with(company_prefix)) name.remove_prefix(company_prefix.size());
1673 return GetSettingFromName(name, _company_settings);
1674}
1675
1682const SettingDesc *GetSettingFromName(const std::string_view name)
1683{
1684 for (auto &table : GenericSettingTables()) {
1685 auto sd = GetSettingFromName(name, table);
1686 if (sd != nullptr) return sd;
1687 }
1688 for (auto &table : PrivateSettingTables()) {
1689 auto sd = GetSettingFromName(name, table);
1690 if (sd != nullptr) return sd;
1691 }
1692 for (auto &table : SecretSettingTables()) {
1693 auto sd = GetSettingFromName(name, table);
1694 if (sd != nullptr) return sd;
1695 }
1696
1697 return GetCompanySettingFromName(name);
1698}
1699
1705std::vector<const SettingDesc *> GetFilteredSettingCollection(std::function<bool(const SettingDesc &desc)> func)
1706{
1707 std::vector<const SettingDesc *> collection;
1708
1709 for (const auto &table : GenericSettingTables()) {
1710 for (const auto &desc : table) {
1711 const auto sd = GetSettingDesc(desc);
1712 if (!func(*sd)) continue;
1713
1714 collection.push_back(sd);
1715 }
1716 }
1717
1718 return collection;
1719}
1720
1730CommandCost CmdChangeSetting(DoCommandFlags flags, const std::string &name, int32_t value)
1731{
1732 if (name.empty()) return CMD_ERROR;
1733 const SettingDesc *sd = GetSettingFromName(name);
1734
1735 if (sd == nullptr) return CMD_ERROR;
1737 if (!sd->IsIntSetting()) return CMD_ERROR;
1738
1739 if (!sd->IsEditable(true)) return CMD_ERROR;
1740
1741 if (flags.Test(DoCommandFlag::Execute)) {
1742 sd->AsIntSetting()->ChangeValue(&GetGameSettings(), value);
1743 }
1744
1745 return CommandCost();
1746}
1747
1756CommandCost CmdChangeCompanySetting(DoCommandFlags flags, const std::string &name, int32_t value)
1757{
1758 if (name.empty()) return CMD_ERROR;
1759 const SettingDesc *sd = GetCompanySettingFromName(name);
1760
1761 if (sd == nullptr) return CMD_ERROR;
1762 if (!sd->IsIntSetting()) return CMD_ERROR;
1763
1764 if (flags.Test(DoCommandFlag::Execute)) {
1766 }
1767
1768 return CommandCost();
1769}
1770
1778bool SetSettingValue(const IntSettingDesc *sd, int32_t value, bool force_newgame)
1779{
1780 const IntSettingDesc *setting = sd->AsIntSetting();
1781 if (setting->flags.Test(SettingFlag::PerCompany)) {
1782 if (Company::IsValidID(_local_company) && _game_mode != GM_MENU) {
1783 return Command<CMD_CHANGE_COMPANY_SETTING>::Post(setting->GetName(), value);
1784 }
1785
1786 setting->ChangeValue(&_settings_client.company, value);
1787 return true;
1788 }
1789
1790 /* If an item is company-based, we do not send it over the network
1791 * (if any) to change. Also *hack*hack* we update the _newgame version
1792 * of settings because changing a company-based setting in a game also
1793 * changes its defaults. At least that is the convention we have chosen */
1794 if (setting->flags.Test(SettingFlag::NoNetworkSync)) {
1795 if (_game_mode != GM_MENU) {
1796 setting->ChangeValue(&_settings_newgame, value);
1797 }
1798 setting->ChangeValue(&GetGameSettings(), value);
1799 return true;
1800 }
1801
1802 if (force_newgame) {
1803 setting->ChangeValue(&_settings_newgame, value);
1804 return true;
1805 }
1806
1807 /* send non-company-based settings over the network */
1809 return Command<CMD_CHANGE_SETTING>::Post(setting->GetName(), value);
1810 }
1811 return false;
1812}
1813
1818{
1819 Company *c = Company::Get(cid);
1821 for (auto &desc : _company_settings) {
1822 const IntSettingDesc *int_setting = GetSettingDesc(desc)->AsIntSetting();
1823 int_setting->MakeValueValidAndWrite(&c->settings, int_setting->GetDefaultValue());
1824 }
1825}
1826
1831{
1832 const void *old_object = &Company::Get(_current_company)->settings;
1833 const void *new_object = &_settings_client.company;
1834 for (auto &desc : _company_settings) {
1835 const SettingDesc *sd = GetSettingDesc(desc);
1836 uint32_t old_value = (uint32_t)sd->AsIntSetting()->Read(old_object);
1837 uint32_t new_value = (uint32_t)sd->AsIntSetting()->Read(new_object);
1838 /*
1839 * This is called from a command, and since it contains local configuration information
1840 * that the rest of the clients do not know about, we need to circumvent the normal ::Post
1841 * local command validation and immediately send the command to the server.
1842 */
1843 if (old_value != new_value) Command<CMD_CHANGE_COMPANY_SETTING>::SendNet(STR_NULL, _local_company, sd->GetName(), new_value);
1844 }
1845}
1846
1854bool SetSettingValue(const StringSettingDesc *sd, std::string value, bool force_newgame)
1855{
1857
1858 if (GetVarMemType(sd->save.conv) == SLE_VAR_STRQ && value.compare("(null)") == 0) {
1859 value.clear();
1860 }
1861
1862 const void *object = (_game_mode == GM_MENU || force_newgame) ? &_settings_newgame : &_settings_game;
1863 sd->AsStringSetting()->ChangeValue(object, value);
1864 return true;
1865}
1866
1873void StringSettingDesc::ChangeValue(const void *object, std::string &newval) const
1874{
1875 this->MakeValueValid(newval);
1876 if (this->pre_check != nullptr && !this->pre_check(newval)) return;
1877
1878 this->Write(object, newval);
1879 if (this->post_callback != nullptr) this->post_callback(newval);
1880
1881 if (_save_config) SaveToConfig();
1882}
1883
1884/* Those 2 functions need to be here, else we have to make some stuff non-static
1885 * and besides, it is also better to keep stuff like this at the same place */
1886void IConsoleSetSetting(const char *name, const char *value, bool force_newgame)
1887{
1888 const SettingDesc *sd = GetSettingFromName(name);
1889 /* Company settings are not in "list_settings", so don't try to modify them. */
1890 if (sd == nullptr || sd->flags.Test(SettingFlag::PerCompany)) {
1891 IConsolePrint(CC_ERROR, "'{}' is an unknown setting.", name);
1892 return;
1893 }
1894
1895 bool success = true;
1896 if (sd->IsStringSetting()) {
1897 success = SetSettingValue(sd->AsStringSetting(), value, force_newgame);
1898 } else if (sd->IsIntSetting()) {
1899 const IntSettingDesc *isd = sd->AsIntSetting();
1900 size_t val = isd->ParseValue(value);
1901 if (!_settings_error_list.empty()) {
1902 IConsolePrint(CC_ERROR, "'{}' is not a valid value for this setting.", value);
1903 _settings_error_list.clear();
1904 return;
1905 }
1906 success = SetSettingValue(isd, (int32_t)val, force_newgame);
1907 }
1908
1909 if (!success) {
1910 if (_network_server) {
1911 IConsolePrint(CC_ERROR, "This command/variable is not available during network games.");
1912 } else {
1913 IConsolePrint(CC_ERROR, "This command/variable is only available to a network server.");
1914 }
1915 }
1916}
1917
1918void IConsoleSetSetting(const char *name, int value)
1919{
1920 const SettingDesc *sd = GetSettingFromName(name);
1921 assert(sd != nullptr);
1922 SetSettingValue(sd->AsIntSetting(), value);
1923}
1924
1930void IConsoleGetSetting(const char *name, bool force_newgame)
1931{
1932 const SettingDesc *sd = GetSettingFromName(name);
1933 /* Company settings are not in "list_settings", so don't try to read them. */
1934 if (sd == nullptr || sd->flags.Test(SettingFlag::PerCompany)) {
1935 IConsolePrint(CC_ERROR, "'{}' is an unknown setting.", name);
1936 return;
1937 }
1938
1939 const void *object = (_game_mode == GM_MENU || force_newgame) ? &_settings_newgame : &_settings_game;
1940
1941 if (sd->IsStringSetting()) {
1942 IConsolePrint(CC_INFO, "Current value for '{}' is '{}'.", sd->GetName(), sd->AsStringSetting()->Read(object));
1943 } else if (sd->IsIntSetting()) {
1944 std::string value = sd->FormatValue(object);
1945 const IntSettingDesc *int_setting = sd->AsIntSetting();
1946 auto [min_val, max_val] = int_setting->GetRange();
1947 IConsolePrint(CC_INFO, "Current value for '{}' is '{}' (min: {}{}, max: {}).",
1948 sd->GetName(), value, sd->flags.Test(SettingFlag::GuiZeroIsSpecial) ? "(0) " : "", min_val, max_val);
1949 }
1950}
1951
1952static void IConsoleListSettingsTable(const SettingTable &table, const char *prefilter)
1953{
1954 for (auto &desc : table) {
1955 const SettingDesc *sd = GetSettingDesc(desc);
1956 if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue;
1957 if (prefilter != nullptr && sd->GetName().find(prefilter) == std::string::npos) continue;
1958 IConsolePrint(CC_DEFAULT, "{} = {}", sd->GetName(), sd->FormatValue(&GetGameSettings()));
1959 }
1960}
1961
1967void IConsoleListSettings(const char *prefilter)
1968{
1969 IConsolePrint(CC_HELP, "All settings with their current value:");
1970
1971 for (auto &table : GenericSettingTables()) {
1972 IConsoleListSettingsTable(table, prefilter);
1973 }
1974 for (auto &table : PrivateSettingTables()) {
1975 IConsoleListSettingsTable(table, prefilter);
1976 }
1977 for (auto &table : SecretSettingTables()) {
1978 IConsoleListSettingsTable(table, prefilter);
1979 }
1980
1981 IConsolePrint(CC_HELP, "Use 'setting' command to change a value.");
1982}
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
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:137
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 ShowFirstError()
Show the first error of the queue.
void ShowErrorMessage(EncodedString &&summary_msg, int x, int y, const CommandCost &cc)
Display an error message in a window.
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:822
int64_t ReadValue(const void *ptr, VarType conv)
Return a signed-long version of the value of a setting.
Definition saveload.cpp:798
@ 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:712
static void ValidateSettings()
Checks if any settings are set to incorrect values, and sets them to correct values in that case.
Definition settings.cpp:949
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:250
std::string _secrets_file
Secrets configuration file of OpenTTD.
Definition settings.cpp:63
std::string _favs_file
Picker favourites configuration file of OpenTTD.
Definition settings.cpp:64
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:632
static ErrorList _settings_error_list
Errors while loading minimal settings.
Definition settings.cpp:66
void IniLoadWindowSettings(IniFile &ini, const char *grpname, void *desc)
Load a WindowDesc from config.
Definition settings.cpp:880
static bool LoadIntList(const char *str, void *array, int nelems, VarType type)
Load parsed string-values into an integer-array (intlist)
Definition settings.cpp:295
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:60
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:842
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:891
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:864
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:58
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:221
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:163
@ IFV_0
0 All versions prior to introduction.
Definition settings.cpp:164
@ IFV_AUTOSAVE_RENAME
5 PR#11143 Renamed values of autosave to be in minutes.
Definition settings.cpp:170
@ IFV_LINKGRAPH_SECONDS
3 PR#10610 Store linkgraph update intervals in seconds instead of days.
Definition settings.cpp:167
@ IFV_REMOVE_GENERATION_SEED
7 PR#11927 Remove "generation_seed" from configuration.
Definition settings.cpp:172
@ IFV_MAX_VERSION
Highest possible ini-file version.
Definition settings.cpp:174
@ IFV_NETWORK_PRIVATE_SETTINGS
4 PR#10762 Move use_relay_service to private settings.
Definition settings.cpp:168
@ IFV_GAME_TYPE
2 PR#9515 Convert server_advertise to server_game_type.
Definition settings.cpp:166
@ IFV_RIGHT_CLICK_CLOSE
6 PR#10204 Add alternative right click to close windows setting.
Definition settings.cpp:171
@ IFV_PRIVATE_SECRETS
1 PR#9298 Moving of settings from openttd.cfg to private.cfg / secrets.cfg.
Definition settings.cpp:165
const uint16_t INIFILE_VERSION
Current ini-file version of OpenTTD.
Definition settings.cpp:177
static auto & SecretSettingTables()
List of all the secrets setting tables.
Definition settings.cpp:111
std::string _private_file
Private configuration file of OpenTTD.
Definition settings.cpp:62
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:59
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:100
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:61
static auto & GenericSettingTables()
List of all the generic setting tables.
Definition settings.cpp:78
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:57
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:125
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:752
std::string FormatArrayAsHex(std::span< const uint8_t > data)
Format a byte array into a continuous hex string.
Definition string.cpp:80
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
EncodedString GetEncodedString(StringID str)
Encode a string with no parameters into an encoded string.
Definition strings.cpp:90
Functions related to OTTD's strings.
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
Class to backup a specific variable and restore it upon destruction of this object to prevent stack v...
std::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:754
static std::optional< bool > ParseSingleValue(const char *str)
Find whether a string was a boolean true or a boolean false.
Definition settings.cpp:206
size_t ParseValue(const char *str) const override
Convert a string representation (external) of an integer-like setting to an integer.
Definition settings.cpp:423
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:514
void ResetToDefault(void *object) const override
Reset the setting to its default value.
Definition settings.cpp:773
std::string FormatValue(const void *object) const override
Format the value of the setting associated with this object.
Definition settings.cpp:743
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:488
StringID GetTitle() const
Get the title of the setting.
Definition settings.cpp:439
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:760
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:479
void Write(const void *object, int32_t value) const
Set the value of a setting.
Definition settings.cpp:568
StringID GetHelp() const
Get the help text of the setting.
Definition settings.cpp:448
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:499
std::pair< StringParameter, StringParameter > GetValueParams(int32_t value) const
Get parameters for drawing the value of the setting.
Definition settings.cpp:457
virtual size_t ParseValue(const char *str) const
Convert a string representation (external) of an integer-like setting to an integer.
Definition settings.cpp:380
int32_t Read(const void *object) const
Read the integer from the the actual setting.
Definition settings.cpp:579
bool IsDefaultValue(void *object) const override
Check whether the value is the same as the default value.
Definition settings.cpp:767
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:686
void ResetToDefault(void *object) const override
Reset the setting to its default value.
Definition settings.cpp:827
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:815
std::string FormatValue(const void *object) const override
Convert an integer-array (intlist) to a string representation.
Definition settings.cpp:323
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:821
std::string FormatValue(const void *object) const override
Format the value of the setting associated with this object.
Definition settings.cpp:360
size_t ParseValue(const char *str) const override
Convert a string representation (external) of an integer-like setting to an integer.
Definition settings.cpp:412
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:186
std::string FormatValue(const void *object) const override
Format the value of the setting associated with this object.
Definition settings.cpp:354
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
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:901
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:918
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:938
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:928
String settings.
const std::string & Read(const void *object) const
Read the string from the the actual setting.
Definition settings.cpp:618
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:592
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:794
bool IsDefaultValue(void *object) const override
Check whether the value is the same as the default value.
Definition settings.cpp:804
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:810
void Write(const void *object, const std::string &str) const
Write a string to the actual setting.
Definition settings.cpp:608
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:778
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:679
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: