OpenTTD Source 20241222-master-gc72542431a
settings.cpp
Go to the documentation of this file.
1/*
2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
6 */
7
24#include "stdafx.h"
25#include <charconv>
26#include "settings_table.h"
27#include "debug.h"
28#include "currency.h"
29#include "network/network.h"
31#include "network/core/config.h"
32#include "command_func.h"
33#include "console_func.h"
34#include "genworld.h"
35#include "string_func.h"
36#include "window_func.h"
37#include "company_func.h"
38#include "rev.h"
39#include "error.h"
40#include "gamelog.h"
41#include "settings_func.h"
42#include "ini_type.h"
43#include "ai/ai_config.hpp"
44#include "game/game_config.hpp"
45#include "newgrf_config.h"
46#include "picker_func.h"
47#include "base_media_base.h"
48#include "fios.h"
49#include "fileio_func.h"
50#include "settings_cmd.h"
51
52#include "table/strings.h"
53
54#include "safeguards.h"
55
60std::string _config_file;
61std::string _private_file;
62std::string _secrets_file;
63std::string _favs_file;
64
66
78{
79 static const SettingTable _generic_setting_tables[] = {
80 _difficulty_settings,
81 _economy_settings,
82 _game_settings,
83 _gui_settings,
84 _linkgraph_settings,
85 _locale_settings,
86 _multimedia_settings,
87 _network_settings,
88 _news_display_settings,
89 _pathfinding_settings,
90 _script_settings,
91 _world_settings,
92 };
93 return _generic_setting_tables;
94}
95
100{
101 static const SettingTable _private_setting_tables[] = {
102 _network_private_settings,
103 };
104 return _private_setting_tables;
105}
106
111{
112 static const SettingTable _secrets_setting_tables[] = {
113 _network_secrets_settings,
114 };
115 return _secrets_setting_tables;
116}
117
118typedef void SettingDescProc(IniFile &ini, const SettingTable &desc, const char *grpname, void *object, bool only_startup);
119typedef void SettingDescProcList(IniFile &ini, const char *grpname, StringList &list);
120
121static bool IsSignedVarMemType(VarType vt)
122{
123 switch (GetVarMemType(vt)) {
124 case SLE_VAR_I8:
125 case SLE_VAR_I16:
126 case SLE_VAR_I32:
127 case SLE_VAR_I64:
128 return true;
129 }
130 return false;
131}
132
136class ConfigIniFile : public IniFile {
137private:
138 inline static const IniGroupNameList list_group_names = {
139 "bans",
140 "newgrf",
141 "servers",
142 "server_bind_addresses",
143 "server_authorized_keys",
144 "rcon_authorized_keys",
145 "admin_authorized_keys"
146 };
147
148public:
149 ConfigIniFile(const std::string &filename) : IniFile(list_group_names)
150 {
151 this->LoadFromDisk(filename, NO_DIRECTORY);
152 }
153};
154
175
177
185size_t OneOfManySettingDesc::ParseSingleValue(const char *str, size_t len, const std::vector<std::string> &many)
186{
187 /* check if it's an integer */
188 if (isdigit(*str)) return std::strtoul(str, nullptr, 0);
189
190 size_t idx = 0;
191 for (auto one : many) {
192 if (one.size() == len && strncmp(one.c_str(), str, len) == 0) return idx;
193 idx++;
194 }
195
196 return SIZE_MAX;
197}
198
205std::optional<bool> BoolSettingDesc::ParseSingleValue(const char *str)
206{
207 if (strcmp(str, "true") == 0 || strcmp(str, "on") == 0 || strcmp(str, "1") == 0) return true;
208 if (strcmp(str, "false") == 0 || strcmp(str, "off") == 0 || strcmp(str, "0") == 0) return false;
209
210 return std::nullopt;
211}
212
220static size_t LookupManyOfMany(const std::vector<std::string> &many, const char *str)
221{
222 const char *s;
223 size_t r;
224 size_t res = 0;
225
226 for (;;) {
227 /* skip "whitespace" */
228 while (*str == ' ' || *str == '\t' || *str == '|') str++;
229 if (*str == 0) break;
230
231 s = str;
232 while (*s != 0 && *s != ' ' && *s != '\t' && *s != '|') s++;
233
234 r = OneOfManySettingDesc::ParseSingleValue(str, s - str, many);
235 if (r == SIZE_MAX) return r;
236
237 SetBit(res, (uint8_t)r); // value found, set it
238 if (*s == 0) break;
239 str = s + 1;
240 }
241 return res;
242}
243
249static std::optional<std::vector<uint32_t>> ParseIntList(const char *p)
250{
251 bool comma = false; // do we accept comma?
252 std::vector<uint32_t> result;
253
254 while (*p != '\0') {
255 switch (*p) {
256 case ',':
257 /* Do not accept multiple commas between numbers */
258 if (!comma) return std::nullopt;
259 comma = false;
260 [[fallthrough]];
261
262 case ' ':
263 p++;
264 break;
265
266 default: {
267 char *end;
268 unsigned long v = std::strtoul(p, &end, 0);
269 if (p == end) return std::nullopt; // invalid character (not a number)
270
271 result.push_back(ClampTo<uint32_t>(v));
272 p = end; // first non-number
273 comma = true; // we accept comma now
274 break;
275 }
276 }
277 }
278
279 /* If we have read comma but no number after it, fail.
280 * We have read comma when (n != 0) and comma is not allowed */
281 if (!result.empty() && !comma) return std::nullopt;
282
283 return result;
284}
285
294static bool LoadIntList(const char *str, void *array, int nelems, VarType type)
295{
296 size_t elem_size = SlVarSize(type);
297 if (str == nullptr) {
298 memset(array, 0, nelems * elem_size);
299 return true;
300 }
301
302 auto opt_items = ParseIntList(str);
303 if (!opt_items.has_value() || opt_items->size() != (size_t)nelems) return false;
304
305 char *p = static_cast<char *>(array);
306 for (auto item : *opt_items) {
307 WriteValue(p, type, item);
308 p += elem_size;
309 }
310 return true;
311}
312
322std::string ListSettingDesc::FormatValue(const void *object) const
323{
324 const uint8_t *p = static_cast<const uint8_t *>(GetVariableAddress(object, this->save));
325
326 std::string result;
327 for (size_t i = 0; i != this->save.length; i++) {
328 int64_t v;
329 switch (GetVarMemType(this->save.conv)) {
330 case SLE_VAR_BL:
331 case SLE_VAR_I8: v = *(const int8_t *)p; p += 1; break;
332 case SLE_VAR_U8: v = *(const uint8_t *)p; p += 1; break;
333 case SLE_VAR_I16: v = *(const int16_t *)p; p += 2; break;
334 case SLE_VAR_U16: v = *(const uint16_t *)p; p += 2; break;
335 case SLE_VAR_I32: v = *(const int32_t *)p; p += 4; break;
336 case SLE_VAR_U32: v = *(const uint32_t *)p; p += 4; break;
337 default: NOT_REACHED();
338 }
339 if (i != 0) result += ',';
340 result += std::to_string(v);
341 }
342 return result;
343}
344
345std::string OneOfManySettingDesc::FormatSingleValue(uint id) const
346{
347 if (id >= this->many.size()) {
348 return std::to_string(id);
349 }
350 return this->many[id];
351}
352
353std::string OneOfManySettingDesc::FormatValue(const void *object) const
354{
355 uint id = (uint)this->Read(object);
356 return this->FormatSingleValue(id);
357}
358
359std::string ManyOfManySettingDesc::FormatValue(const void *object) const
360{
361 uint bitmask = (uint)this->Read(object);
362 if (bitmask == 0) {
363 return {};
364 }
365
366 std::string result;
367 for (uint id : SetBitIterator(bitmask)) {
368 if (!result.empty()) result += '|';
369 result += this->FormatSingleValue(id);
370 }
371 return result;
372}
373
379size_t IntSettingDesc::ParseValue(const char *str) const
380{
381 char *end;
382 size_t val = std::strtoul(str, &end, 0);
383 if (end == str) {
384 ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_VALUE);
385 msg.SetDParamStr(0, str);
386 msg.SetDParamStr(1, this->GetName());
387 _settings_error_list.push_back(msg);
388 return this->def;
389 }
390 if (*end != '\0') {
391 ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_TRAILING_CHARACTERS);
392 msg.SetDParamStr(0, this->GetName());
393 _settings_error_list.push_back(msg);
394 }
395 return val;
396}
397
398size_t OneOfManySettingDesc::ParseValue(const char *str) const
399{
400 size_t r = OneOfManySettingDesc::ParseSingleValue(str, strlen(str), this->many);
401 /* if the first attempt of conversion from string to the appropriate value fails,
402 * look if we have defined a converter from old value to new value. */
403 if (r == SIZE_MAX && this->many_cnvt != nullptr) r = this->many_cnvt(str);
404 if (r != SIZE_MAX) return r; // and here goes converted value
405
406 ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_VALUE);
407 msg.SetDParamStr(0, str);
408 msg.SetDParamStr(1, this->GetName());
409 _settings_error_list.push_back(msg);
410 return this->def;
411}
412
413size_t ManyOfManySettingDesc::ParseValue(const char *str) const
414{
415 size_t r = LookupManyOfMany(this->many, str);
416 if (r != SIZE_MAX) return r;
417 ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_VALUE);
418 msg.SetDParamStr(0, str);
419 msg.SetDParamStr(1, this->GetName());
420 _settings_error_list.push_back(msg);
421 return this->def;
422}
423
424size_t BoolSettingDesc::ParseValue(const char *str) const
425{
427 if (r.has_value()) return *r;
428
429 ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_VALUE);
430 msg.SetDParamStr(0, str);
431 msg.SetDParamStr(1, this->GetName());
432 _settings_error_list.push_back(msg);
433 return this->def;
434}
435
442{
443 return this->get_title_cb != nullptr ? this->get_title_cb(*this) : this->str;
444}
445
451{
452 return this->get_help_cb != nullptr ? this->get_help_cb(*this) : this->str_help;
453}
454
460void IntSettingDesc::SetValueDParams(uint first_param, int32_t value) const
461{
462 if (this->set_value_dparams_cb != nullptr) {
463 this->set_value_dparams_cb(*this, first_param, value);
464 } else if (this->IsBoolSetting()) {
465 SetDParam(first_param++, value != 0 ? STR_CONFIG_SETTING_ON : STR_CONFIG_SETTING_OFF);
466 } else {
467 if ((this->flags & SF_GUI_DROPDOWN) != 0) {
468 SetDParam(first_param++, this->str_val - this->min + value);
469 } else {
470 SetDParam(first_param++, this->str_val + ((value == 0 && (this->flags & SF_GUI_0_IS_SPECIAL) != 0) ? 1 : 0));
471 }
472 SetDParam(first_param++, value);
473 }
474}
475
482void IntSettingDesc::MakeValueValidAndWrite(const void *object, int32_t val) const
483{
484 this->MakeValueValid(val);
485 this->Write(object, val);
486}
487
497void IntSettingDesc::MakeValueValid(int32_t &val) const
498{
499 /* We need to take special care of the uint32_t type as we receive from the function
500 * a signed integer. While here also bail out on 64-bit settings as those are not
501 * supported. Unsigned 8 and 16-bit variables are safe since they fit into a signed
502 * 32-bit variable
503 * TODO: Support 64-bit settings/variables; requires 64 bit over command protocol! */
504 switch (GetVarMemType(this->save.conv)) {
505 case SLE_VAR_NULL: return;
506 case SLE_VAR_BL:
507 case SLE_VAR_I8:
508 case SLE_VAR_U8:
509 case SLE_VAR_I16:
510 case SLE_VAR_U16:
511 case SLE_VAR_I32: {
512 /* Override the minimum value. No value below this->min, except special value 0 */
513 if (!(this->flags & SF_GUI_0_IS_SPECIAL) || val != 0) {
514 if (!(this->flags & SF_GUI_DROPDOWN)) {
515 /* Clamp value-type setting to its valid range */
516 val = Clamp(val, this->min, this->max);
517 } else if (val < this->min || val > (int32_t)this->max) {
518 /* Reset invalid discrete setting (where different values change gameplay) to its default value */
519 val = this->def;
520 }
521 }
522 break;
523 }
524 case SLE_VAR_U32: {
525 /* Override the minimum value. No value below this->min, except special value 0 */
526 uint32_t uval = (uint32_t)val;
527 if (!(this->flags & SF_GUI_0_IS_SPECIAL) || uval != 0) {
528 if (!(this->flags & SF_GUI_DROPDOWN)) {
529 /* Clamp value-type setting to its valid range */
530 uval = ClampU(uval, this->min, this->max);
531 } else if (uval < (uint)this->min || uval > this->max) {
532 /* Reset invalid discrete setting to its default value */
533 uval = (uint32_t)this->def;
534 }
535 }
536 val = (int32_t)uval;
537 return;
538 }
539 case SLE_VAR_I64:
540 case SLE_VAR_U64:
541 default: NOT_REACHED();
542 }
543}
544
550void IntSettingDesc::Write(const void *object, int32_t val) const
551{
552 void *ptr = GetVariableAddress(object, this->save);
553 WriteValue(ptr, this->save.conv, (int64_t)val);
554}
555
561int32_t IntSettingDesc::Read(const void *object) const
562{
563 void *ptr = GetVariableAddress(object, this->save);
564 return (int32_t)ReadValue(ptr, this->save.conv);
565}
566
574void StringSettingDesc::MakeValueValid(std::string &str) const
575{
576 if (this->max_length == 0 || str.size() < this->max_length) return;
577
578 /* In case a maximum length is imposed by the setting, the length
579 * includes the '\0' termination for network transfer purposes.
580 * Also ensure the string is valid after chopping of some bytes. */
581 std::string stdstr(str, 0, this->max_length - 1);
582 str.assign(StrMakeValid(stdstr, SVS_NONE));
583}
584
590void StringSettingDesc::Write(const void *object, const std::string &str) const
591{
592 reinterpret_cast<std::string *>(GetVariableAddress(object, this->save))->assign(str);
593}
594
600const std::string &StringSettingDesc::Read(const void *object) const
601{
602 return *reinterpret_cast<std::string *>(GetVariableAddress(object, this->save));
603}
604
614static void IniLoadSettings(IniFile &ini, const SettingTable &settings_table, const char *grpname, void *object, bool only_startup)
615{
616 const IniGroup *group;
617 const IniGroup *group_def = ini.GetGroup(grpname);
618
619 for (auto &desc : settings_table) {
620 const SettingDesc *sd = GetSettingDesc(desc);
622 if (sd->startup != only_startup) continue;
623
624 /* For settings.xx.yy load the settings from [xx] yy = ? */
625 std::string s{ sd->GetName() };
626 auto sc = s.find('.');
627 if (sc != std::string::npos) {
628 group = ini.GetGroup(s.substr(0, sc));
629 if (group == nullptr) group = group_def;
630 s = s.substr(sc + 1);
631 } else {
632 group = group_def;
633 }
634
635 const IniItem *item = nullptr;
636 if (group != nullptr) item = group->GetItem(s);
637 if (item == nullptr && group != group_def && group_def != nullptr) {
638 /* For settings.xx.yy load the settings from [settings] yy = ? in case the previous
639 * did not exist (e.g. loading old config files with a [settings] section */
640 item = group_def->GetItem(s);
641 }
642 if (item == nullptr) {
643 /* For settings.xx.zz.yy load the settings from [zz] yy = ? in case the previous
644 * did not exist (e.g. loading old config files with a [yapf] section */
645 sc = s.find('.');
646 if (sc != std::string::npos) {
647 if (group = ini.GetGroup(s.substr(0, sc)); group != nullptr) item = group->GetItem(s.substr(sc + 1));
648 }
649 }
650
651 sd->ParseValue(item, object);
652 }
653}
654
655void IntSettingDesc::ParseValue(const IniItem *item, void *object) const
656{
657 size_t val = (item == nullptr) ? this->def : this->ParseValue(item->value.has_value() ? item->value->c_str() : "");
658 this->MakeValueValidAndWrite(object, (int32_t)val);
659}
660
661void StringSettingDesc::ParseValue(const IniItem *item, void *object) const
662{
663 std::string str = (item == nullptr) ? this->def : item->value.value_or("");
664 this->MakeValueValid(str);
665 this->Write(object, str);
666}
667
668void ListSettingDesc::ParseValue(const IniItem *item, void *object) const
669{
670 const char *str = (item == nullptr) ? this->def : item->value.has_value() ? item->value->c_str() : nullptr;
671 void *ptr = GetVariableAddress(object, this->save);
672 if (!LoadIntList(str, ptr, this->save.length, GetVarMemType(this->save.conv))) {
673 ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_ARRAY);
674 msg.SetDParamStr(0, this->GetName());
675 _settings_error_list.push_back(msg);
676
677 /* Use default */
678 LoadIntList(this->def, ptr, this->save.length, GetVarMemType(this->save.conv));
679 }
680}
681
694static void IniSaveSettings(IniFile &ini, const SettingTable &settings_table, const char *grpname, void *object, bool)
695{
696 IniGroup *group_def = nullptr, *group;
697
698 for (auto &desc : settings_table) {
699 const SettingDesc *sd = GetSettingDesc(desc);
700 /* If the setting is not saved to the configuration
701 * file, just continue with the next setting */
703 if (sd->flags & SF_NOT_IN_CONFIG) continue;
704
705 /* XXX - wtf is this?? (group override?) */
706 std::string s{ sd->GetName() };
707 auto sc = s.find('.');
708 if (sc != std::string::npos) {
709 group = &ini.GetOrCreateGroup(s.substr(0, sc));
710 s = s.substr(sc + 1);
711 } else {
712 if (group_def == nullptr) group_def = &ini.GetOrCreateGroup(grpname);
713 group = group_def;
714 }
715
716 IniItem &item = group->GetOrCreateItem(s);
717
718 if (!item.value.has_value() || !sd->IsSameValue(&item, object)) {
719 /* The value is different, that means we have to write it to the ini */
720 item.value.emplace(sd->FormatValue(object));
721 }
722 }
723}
724
725std::string IntSettingDesc::FormatValue(const void *object) const
726{
727 int64_t i;
728 if (IsSignedVarMemType(this->save.conv)) {
729 i = this->Read(object);
730 } else {
731 i = (uint32_t)this->Read(object);
732 }
733 return std::to_string(i);
734}
735
736std::string BoolSettingDesc::FormatValue(const void *object) const
737{
738 bool val = this->Read(object) != 0;
739 return val ? "true" : "false";
740}
741
742bool IntSettingDesc::IsSameValue(const IniItem *item, void *object) const
743{
744 int32_t item_value = (int32_t)this->ParseValue(item->value->c_str());
745 int32_t object_value = this->Read(object);
746 return item_value == object_value;
747}
748
749bool IntSettingDesc::IsDefaultValue(void *object) const
750{
751 int32_t object_value = this->Read(object);
752 return this->def == object_value;
753}
754
755void IntSettingDesc::ResetToDefault(void *object) const
756{
757 this->Write(object, this->def);
758}
759
760std::string StringSettingDesc::FormatValue(const void *object) const
761{
762 const std::string &str = this->Read(object);
763 switch (GetVarMemType(this->save.conv)) {
764 case SLE_VAR_STR: return str;
765
766 case SLE_VAR_STRQ:
767 if (str.empty()) {
768 return str;
769 }
770 return fmt::format("\"{}\"", str);
771
772 default: NOT_REACHED();
773 }
774}
775
776bool StringSettingDesc::IsSameValue(const IniItem *item, void *object) const
777{
778 /* The ini parsing removes the quotes, which are needed to retain the spaces in STRQs,
779 * so those values are always different in the parsed ini item than they should be. */
780 if (GetVarMemType(this->save.conv) == SLE_VAR_STRQ) return false;
781
782 const std::string &str = this->Read(object);
783 return item->value->compare(str) == 0;
784}
785
786bool StringSettingDesc::IsDefaultValue(void *object) const
787{
788 const std::string &str = this->Read(object);
789 return this->def == str;
790}
791
792void StringSettingDesc::ResetToDefault(void *object) const
793{
794 this->Write(object, this->def);
795}
796
797bool ListSettingDesc::IsSameValue(const IniItem *, void *) const
798{
799 /* Checking for equality is way more expensive than just writing the value. */
800 return false;
801}
802
804{
805 /* Defaults of lists are often complicated, and hard to compare. */
806 return false;
807}
808
810{
811 /* Resetting a list to default is not supported. */
812 NOT_REACHED();
813}
814
824static void IniLoadSettingList(IniFile &ini, const char *grpname, StringList &list)
825{
826 const IniGroup *group = ini.GetGroup(grpname);
827
828 if (group == nullptr) return;
829
830 list.clear();
831
832 for (const IniItem &item : group->items) {
833 if (!item.name.empty()) list.push_back(item.name);
834 }
835}
836
846static void IniSaveSettingList(IniFile &ini, const char *grpname, StringList &list)
847{
848 IniGroup &group = ini.GetOrCreateGroup(grpname);
849 group.Clear();
850
851 for (const auto &iter : list) {
852 group.GetOrCreateItem(iter).SetValue("");
853 }
854}
855
862void IniLoadWindowSettings(IniFile &ini, const char *grpname, void *desc)
863{
864 IniLoadSettings(ini, _window_settings, grpname, desc, false);
865}
866
873void IniSaveWindowSettings(IniFile &ini, const char *grpname, void *desc)
874{
875 IniSaveSettings(ini, _window_settings, grpname, desc, false);
876}
877
883bool SettingDesc::IsEditable(bool do_command) const
884{
885 if (!do_command && !(this->flags & SF_NO_NETWORK_SYNC) && _networking && !_network_server && !(this->flags & SF_PER_COMPANY)) return false;
886 if (do_command && (this->flags & SF_NO_NETWORK_SYNC)) return false;
887 if ((this->flags & SF_NETWORK_ONLY) && !_networking && _game_mode != GM_MENU) return false;
888 if ((this->flags & SF_NO_NETWORK) && _networking) return false;
889 if ((this->flags & SF_NEWGAME_ONLY) &&
890 (_game_mode == GM_NORMAL ||
891 (_game_mode == GM_EDITOR && !(this->flags & SF_SCENEDIT_TOO)))) return false;
892 if ((this->flags & SF_SCENEDIT_ONLY) && _game_mode != GM_EDITOR) return false;
893 return true;
894}
895
901{
902 if (this->flags & SF_PER_COMPANY) return ST_COMPANY;
903 return (this->flags & SF_NOT_IN_SAVE) ? ST_CLIENT : ST_GAME;
904}
905
911{
912 assert(this->IsIntSetting());
913 return static_cast<const IntSettingDesc *>(this);
914}
915
921{
922 assert(this->IsStringSetting());
923 return static_cast<const StringSettingDesc *>(this);
924}
925
927void HandleOldDiffCustom(bool savegame);
928
929
939
940static void AILoadConfig(const IniFile &ini, const char *grpname)
941{
942 const IniGroup *group = ini.GetGroup(grpname);
943
944 /* Clean any configured AI */
945 for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) {
947 }
948
949 /* If no group exists, return */
950 if (group == nullptr) return;
951
953 for (const IniItem &item : group->items) {
955
956 config->Change(item.name);
957 if (!config->HasScript()) {
958 if (item.name != "none") {
959 Debug(script, 0, "The AI by the name '{}' was no longer found, and removed from the list.", item.name);
960 continue;
961 }
962 }
963 if (item.value.has_value()) config->StringToSettings(*item.value);
964 c++;
965 if (c >= MAX_COMPANIES) break;
966 }
967}
968
969static void GameLoadConfig(const IniFile &ini, const char *grpname)
970{
971 const IniGroup *group = ini.GetGroup(grpname);
972
973 /* Clean any configured GameScript */
975
976 /* If no group exists, return */
977 if (group == nullptr || group->items.empty()) return;
978
979 const IniItem &item = group->items.front();
980
982
983 config->Change(item.name);
984 if (!config->HasScript()) {
985 if (item.name != "none") {
986 Debug(script, 0, "The GameScript by the name '{}' was no longer found, and removed from the list.", item.name);
987 return;
988 }
989 }
990 if (item.value.has_value()) config->StringToSettings(*item.value);
991}
992
997{
998 if (const IniGroup *group = ini.GetGroup("misc"); group != nullptr) {
999 /* Load old setting first. */
1000 if (const IniItem *item = group->GetItem("graphicsset"); item != nullptr && item->value) BaseGraphics::ini_data.name = *item->value;
1001 }
1002
1003 if (const IniGroup *group = ini.GetGroup("graphicsset"); group != nullptr) {
1004 /* Load new settings. */
1005 if (const IniItem *item = group->GetItem("name"); item != nullptr && item->value) BaseGraphics::ini_data.name = *item->value;
1006
1007 if (const IniItem *item = group->GetItem("shortname"); item != nullptr && item->value && item->value->size() == 8) {
1008 BaseGraphics::ini_data.shortname = BSWAP32(std::strtoul(item->value->c_str(), nullptr, 16));
1009 }
1010
1011 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);
1012
1013 if (const IniItem *item = group->GetItem("extra_params"); item != nullptr && item->value) {
1014 auto params = ParseIntList(item->value->c_str());
1015 if (params.has_value()) {
1016 BaseGraphics::ini_data.extra_params = params.value();
1017 } else {
1018 SetDParamStr(0, BaseGraphics::ini_data.name);
1019 ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_ARRAY, WL_CRITICAL);
1020 }
1021 }
1022 }
1023}
1024
1031static GRFConfig *GRFLoadConfig(const IniFile &ini, const char *grpname, bool is_static)
1032{
1033 const IniGroup *group = ini.GetGroup(grpname);
1034 GRFConfig *first = nullptr;
1035 GRFConfig **curr = &first;
1036
1037 if (group == nullptr) return nullptr;
1038
1039 uint num_grfs = 0;
1040 for (const IniItem &item : group->items) {
1041 GRFConfig *c = nullptr;
1042
1043 std::array<uint8_t, 4> grfid_buf;
1044 MD5Hash md5sum;
1045 std::string_view item_name = item.name;
1046 bool has_md5sum = false;
1047
1048 /* Try reading "<grfid>|" and on success, "<md5sum>|". */
1049 auto grfid_pos = item_name.find("|");
1050 if (grfid_pos != std::string_view::npos) {
1051 std::string_view grfid_str = item_name.substr(0, grfid_pos);
1052
1053 if (ConvertHexToBytes(grfid_str, grfid_buf)) {
1054 item_name = item_name.substr(grfid_pos + 1);
1055
1056 auto md5sum_pos = item_name.find("|");
1057 if (md5sum_pos != std::string_view::npos) {
1058 std::string_view md5sum_str = item_name.substr(0, md5sum_pos);
1059
1060 has_md5sum = ConvertHexToBytes(md5sum_str, md5sum);
1061 if (has_md5sum) item_name = item_name.substr(md5sum_pos + 1);
1062 }
1063
1064 uint32_t grfid = grfid_buf[0] | (grfid_buf[1] << 8) | (grfid_buf[2] << 16) | (grfid_buf[3] << 24);
1065 if (has_md5sum) {
1066 const GRFConfig *s = FindGRFConfig(grfid, FGCM_EXACT, &md5sum);
1067 if (s != nullptr) c = new GRFConfig(*s);
1068 }
1069 if (c == nullptr && !FioCheckFileExists(std::string(item_name), NEWGRF_DIR)) {
1070 const GRFConfig *s = FindGRFConfig(grfid, FGCM_NEWEST_VALID);
1071 if (s != nullptr) c = new GRFConfig(*s);
1072 }
1073 }
1074 }
1075 std::string filename = std::string(item_name);
1076
1077 if (c == nullptr) c = new GRFConfig(filename);
1078
1079 /* Parse parameters */
1080 if (item.value.has_value() && !item.value->empty()) {
1081 auto params = ParseIntList(item.value->c_str());
1082 if (params.has_value()) {
1083 c->SetParams(params.value());
1084 } else {
1085 SetDParamStr(0, filename);
1086 ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_ARRAY, WL_CRITICAL);
1087 }
1088 }
1089
1090 /* Check if item is valid */
1091 if (!FillGRFDetails(c, is_static) || HasBit(c->flags, GCF_INVALID)) {
1092 if (c->status == GCS_NOT_FOUND) {
1093 SetDParam(1, STR_CONFIG_ERROR_INVALID_GRF_NOT_FOUND);
1094 } else if (HasBit(c->flags, GCF_UNSAFE)) {
1095 SetDParam(1, STR_CONFIG_ERROR_INVALID_GRF_UNSAFE);
1096 } else if (HasBit(c->flags, GCF_SYSTEM)) {
1097 SetDParam(1, STR_CONFIG_ERROR_INVALID_GRF_SYSTEM);
1098 } else if (HasBit(c->flags, GCF_INVALID)) {
1099 SetDParam(1, STR_CONFIG_ERROR_INVALID_GRF_INCOMPATIBLE);
1100 } else {
1101 SetDParam(1, STR_CONFIG_ERROR_INVALID_GRF_UNKNOWN);
1102 }
1103
1104 SetDParamStr(0, filename.empty() ? item.name.c_str() : filename);
1105 ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_GRF, WL_CRITICAL);
1106 delete c;
1107 continue;
1108 }
1109
1110 /* Check for duplicate GRFID (will also check for duplicate filenames) */
1111 bool duplicate = false;
1112 for (const GRFConfig *gc = first; gc != nullptr; gc = gc->next) {
1113 if (gc->ident.grfid == c->ident.grfid) {
1114 SetDParamStr(0, c->filename);
1115 SetDParamStr(1, gc->filename);
1116 ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_DUPLICATE_GRFID, WL_CRITICAL);
1117 duplicate = true;
1118 break;
1119 }
1120 }
1121 if (duplicate) {
1122 delete c;
1123 continue;
1124 }
1125
1126 if (is_static) {
1127 /* Mark file as static to avoid saving in savegame. */
1128 SetBit(c->flags, GCF_STATIC);
1129 } else if (++num_grfs > NETWORK_MAX_GRF_COUNT) {
1130 /* Check we will not load more non-static NewGRFs than allowed. This could trigger issues for game servers. */
1131 ShowErrorMessage(STR_CONFIG_ERROR, STR_NEWGRF_ERROR_TOO_MANY_NEWGRFS_LOADED, WL_CRITICAL);
1132 break;
1133 }
1134
1135 /* Add item to list */
1136 *curr = c;
1137 curr = &c->next;
1138 }
1139
1140 return first;
1141}
1142
1143static IniFileVersion LoadVersionFromConfig(const IniFile &ini)
1144{
1145 const IniGroup *group = ini.GetGroup("version");
1146 if (group == nullptr) return IFV_0;
1147
1148 auto version_number = group->GetItem("ini_version");
1149 /* Older ini-file versions don't have this key yet. */
1150 if (version_number == nullptr || !version_number->value.has_value()) return IFV_0;
1151
1152 uint32_t version = 0;
1153 std::from_chars(version_number->value->data(), version_number->value->data() + version_number->value->size(), version);
1154
1155 return static_cast<IniFileVersion>(version);
1156}
1157
1158static void AISaveConfig(IniFile &ini, const char *grpname)
1159{
1160 IniGroup &group = ini.GetOrCreateGroup(grpname);
1161 group.Clear();
1162
1163 for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) {
1165 std::string name;
1166 std::string value = config->SettingsToString();
1167
1168 if (config->HasScript()) {
1169 name = config->GetName();
1170 } else {
1171 name = "none";
1172 }
1173
1174 group.CreateItem(name).SetValue(value);
1175 }
1176}
1177
1178static void GameSaveConfig(IniFile &ini, const char *grpname)
1179{
1180 IniGroup &group = ini.GetOrCreateGroup(grpname);
1181 group.Clear();
1182
1184 std::string name;
1185 std::string value = config->SettingsToString();
1186
1187 if (config->HasScript()) {
1188 name = config->GetName();
1189 } else {
1190 name = "none";
1191 }
1192
1193 group.CreateItem(name).SetValue(value);
1194}
1195
1201{
1202 IniGroup &group = ini.GetOrCreateGroup("version");
1203 group.GetOrCreateItem("version_string").SetValue(_openttd_revision);
1204 group.GetOrCreateItem("version_number").SetValue(fmt::format("{:08X}", _openttd_newgrf_version));
1205 group.GetOrCreateItem("ini_version").SetValue(std::to_string(INIFILE_VERSION));
1206}
1207
1212{
1213 const GraphicsSet *used_set = BaseGraphics::GetUsedSet();
1214 if (used_set == nullptr) return;
1215
1216 IniGroup &group = ini.GetOrCreateGroup("graphicsset");
1217 group.Clear();
1218
1219 group.GetOrCreateItem("name").SetValue(used_set->name);
1220 group.GetOrCreateItem("shortname").SetValue(fmt::format("{:08X}", BSWAP32(used_set->shortname)));
1221
1222 const GRFConfig *extra_cfg = used_set->GetExtraConfig();
1223 if (extra_cfg != nullptr && !extra_cfg->param.empty()) {
1224 group.GetOrCreateItem("extra_version").SetValue(fmt::format("{}", extra_cfg->version));
1225 group.GetOrCreateItem("extra_params").SetValue(GRFBuildParamList(extra_cfg));
1226 }
1227}
1228
1229/* Save a GRF configuration to the given group name */
1230static void GRFSaveConfig(IniFile &ini, const char *grpname, const GRFConfig *list)
1231{
1232 IniGroup &group = ini.GetOrCreateGroup(grpname);
1233 group.Clear();
1234 const GRFConfig *c;
1235
1236 for (c = list; c != nullptr; c = c->next) {
1237 std::string key = fmt::format("{:08X}|{}|{}", BSWAP32(c->ident.grfid),
1240 }
1241}
1242
1243/* Common handler for saving/loading variables to the configuration file */
1244static void HandleSettingDescs(IniFile &generic_ini, IniFile &private_ini, IniFile &secrets_ini, SettingDescProc *proc, SettingDescProcList *proc_list, bool only_startup = false)
1245{
1246 proc(generic_ini, _misc_settings, "misc", nullptr, only_startup);
1247#if defined(_WIN32) && !defined(DEDICATED)
1248 proc(generic_ini, _win32_settings, "win32", nullptr, only_startup);
1249#endif /* _WIN32 */
1250
1251 /* The name "patches" is a fallback, as every setting should sets its own group. */
1252
1253 for (auto &table : GenericSettingTables()) {
1254 proc(generic_ini, table, "patches", &_settings_newgame, only_startup);
1255 }
1256 for (auto &table : PrivateSettingTables()) {
1257 proc(private_ini, table, "patches", &_settings_newgame, only_startup);
1258 }
1259 for (auto &table : SecretSettingTables()) {
1260 proc(secrets_ini, table, "patches", &_settings_newgame, only_startup);
1261 }
1262
1263 proc(generic_ini, _currency_settings, "currency", &GetCustomCurrency(), only_startup);
1264 proc(generic_ini, _company_settings, "company", &_settings_client.company, only_startup);
1265
1266 if (!only_startup) {
1267 proc_list(private_ini, "server_bind_addresses", _network_bind_list);
1268 proc_list(private_ini, "servers", _network_host_list);
1269 proc_list(private_ini, "bans", _network_ban_list);
1270 proc_list(private_ini, "server_authorized_keys", _settings_client.network.server_authorized_keys);
1271 proc_list(private_ini, "rcon_authorized_keys", _settings_client.network.rcon_authorized_keys);
1272 proc_list(private_ini, "admin_authorized_keys", _settings_client.network.admin_authorized_keys);
1273 }
1274}
1275
1285static void RemoveEntriesFromIni(IniFile &ini, const SettingTable &table)
1286{
1287 for (auto &desc : table) {
1288 const SettingDesc *sd = GetSettingDesc(desc);
1289
1290 /* For settings.xx.yy load the settings from [xx] yy = ? */
1291 std::string s{ sd->GetName() };
1292 auto sc = s.find('.');
1293 if (sc == std::string::npos) continue;
1294
1295 IniGroup *group = ini.GetGroup(s.substr(0, sc));
1296 if (group == nullptr) continue;
1297 s = s.substr(sc + 1);
1298
1299 group->RemoveItem(s);
1300 }
1301}
1302
1326bool IsConversionNeeded(const ConfigIniFile &ini, const std::string &group, const std::string &old_var, const std::string &new_var, const IniItem **old_item)
1327{
1328 *old_item = nullptr;
1329
1330 const IniGroup *igroup = ini.GetGroup(group);
1331 /* If the group doesn't exist, there is nothing to convert. */
1332 if (igroup == nullptr) return false;
1333
1334 const IniItem *tmp_old_item = igroup->GetItem(old_var);
1335 const IniItem *new_item = igroup->GetItem(new_var);
1336
1337 /* If the old item doesn't exist, there is nothing to convert. */
1338 if (tmp_old_item == nullptr) return false;
1339
1340 /* If the new item exists, it means conversion was already done. We only
1341 * do the conversion the first time, and after that these settings are
1342 * independent. This allows users to freely change between older and
1343 * newer clients without breaking anything. */
1344 if (new_item != nullptr) return false;
1345
1346 *old_item = tmp_old_item;
1347 return true;
1348}
1349
1354void LoadFromConfig(bool startup)
1355{
1356 ConfigIniFile generic_ini(_config_file);
1357 ConfigIniFile private_ini(_private_file);
1358 ConfigIniFile secrets_ini(_secrets_file);
1359 ConfigIniFile favs_ini(_favs_file);
1360
1361 if (!startup) ResetCurrencies(false); // Initialize the array of currencies, without preserving the custom one
1362
1363 IniFileVersion generic_version = LoadVersionFromConfig(generic_ini);
1364
1365 if (startup) {
1366 GraphicsSetLoadConfig(generic_ini);
1367 }
1368
1369 /* Before the split of private/secrets, we have to look in the generic for these settings. */
1370 if (generic_version < IFV_PRIVATE_SECRETS) {
1371 HandleSettingDescs(generic_ini, generic_ini, generic_ini, IniLoadSettings, IniLoadSettingList, startup);
1372 } else {
1373 HandleSettingDescs(generic_ini, private_ini, secrets_ini, IniLoadSettings, IniLoadSettingList, startup);
1374 }
1375
1376 /* Load basic settings only during bootstrap, load other settings not during bootstrap */
1377 if (!startup) {
1378 if (generic_version < IFV_LINKGRAPH_SECONDS) {
1381 }
1382
1383 /* Move use_relay_service from generic_ini to private_ini. */
1384 if (generic_version < IFV_NETWORK_PRIVATE_SETTINGS) {
1385 const IniGroup *network = generic_ini.GetGroup("network");
1386 if (network != nullptr) {
1387 const IniItem *use_relay_service = network->GetItem("use_relay_service");
1388 if (use_relay_service != nullptr) {
1389 if (use_relay_service->value == "never") {
1390 _settings_client.network.use_relay_service = UseRelayService::URS_NEVER;
1391 } else if (use_relay_service->value == "ask") {
1392 _settings_client.network.use_relay_service = UseRelayService::URS_ASK;
1393 } else if (use_relay_service->value == "allow") {
1394 _settings_client.network.use_relay_service = UseRelayService::URS_ALLOW;
1395 }
1396 }
1397 }
1398 }
1399
1400 const IniItem *old_item;
1401
1402 if (generic_version < IFV_GAME_TYPE && IsConversionNeeded(generic_ini, "network", "server_advertise", "server_game_type", &old_item)) {
1403 auto old_value = BoolSettingDesc::ParseSingleValue(old_item->value->c_str());
1404 _settings_client.network.server_game_type = old_value.value_or(false) ? SERVER_GAME_TYPE_PUBLIC : SERVER_GAME_TYPE_LOCAL;
1405 }
1406
1407 if (generic_version < IFV_AUTOSAVE_RENAME && IsConversionNeeded(generic_ini, "gui", "autosave", "autosave_interval", &old_item)) {
1408 static std::vector<std::string> _old_autosave_interval{"off", "monthly", "quarterly", "half year", "yearly"};
1409 auto old_value = OneOfManySettingDesc::ParseSingleValue(old_item->value->c_str(), old_item->value->size(), _old_autosave_interval);
1410
1411 switch (old_value) {
1412 case 0: _settings_client.gui.autosave_interval = 0; break;
1413 case 1: _settings_client.gui.autosave_interval = 10; break;
1414 case 2: _settings_client.gui.autosave_interval = 30; break;
1415 case 3: _settings_client.gui.autosave_interval = 60; break;
1416 case 4: _settings_client.gui.autosave_interval = 120; break;
1417 default: break;
1418 }
1419 }
1420
1421 /* Persist the right click close option from older versions. */
1422 if (generic_version < IFV_RIGHT_CLICK_CLOSE && IsConversionNeeded(generic_ini, "gui", "right_mouse_wnd_close", "right_click_wnd_close", &old_item)) {
1423 auto old_value = BoolSettingDesc::ParseSingleValue(old_item->value->c_str());
1424 _settings_client.gui.right_click_wnd_close = old_value.value_or(false) ? RCC_YES : RCC_NO;
1425 }
1426
1427 _grfconfig_newgame = GRFLoadConfig(generic_ini, "newgrf", false);
1428 _grfconfig_static = GRFLoadConfig(generic_ini, "newgrf-static", true);
1429 AILoadConfig(generic_ini, "ai_players");
1430 GameLoadConfig(generic_ini, "game_scripts");
1431 PickerLoadConfig(favs_ini);
1432
1434 IniLoadSettings(generic_ini, _old_gameopt_settings, "gameopt", &_settings_newgame, false);
1435 HandleOldDiffCustom(false);
1436
1439
1440 /* Display scheduled errors */
1442 if (FindWindowById(WC_ERRMSG, 0) == nullptr) ShowFirstError();
1443 }
1444}
1445
1448{
1449 ConfigIniFile generic_ini(_config_file);
1450 ConfigIniFile private_ini(_private_file);
1451 ConfigIniFile secrets_ini(_secrets_file);
1452 ConfigIniFile favs_ini(_favs_file);
1453
1454 IniFileVersion generic_version = LoadVersionFromConfig(generic_ini);
1455
1456 /* If we newly create the private/secrets file, add a dummy group on top
1457 * just so we can add a comment before it (that is how IniFile works).
1458 * This to explain what the file is about. After doing it once, never touch
1459 * it again, as otherwise we might be reverting user changes. */
1460 if (IniGroup *group = private_ini.GetGroup("private"); group != nullptr) group->comment = "; This file possibly contains private information which can identify you as person.\n";
1461 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";
1462
1463 if (generic_version == IFV_0) {
1464 /* Remove some obsolete groups. These have all been loaded into other groups. */
1465 generic_ini.RemoveGroup("patches");
1466 generic_ini.RemoveGroup("yapf");
1467 generic_ini.RemoveGroup("gameopt");
1468
1469 /* Remove all settings from the generic ini that are now in the private ini. */
1470 generic_ini.RemoveGroup("server_bind_addresses");
1471 generic_ini.RemoveGroup("servers");
1472 generic_ini.RemoveGroup("bans");
1473 for (auto &table : PrivateSettingTables()) {
1474 RemoveEntriesFromIni(generic_ini, table);
1475 }
1476
1477 /* Remove all settings from the generic ini that are now in the secrets ini. */
1478 for (auto &table : SecretSettingTables()) {
1479 RemoveEntriesFromIni(generic_ini, table);
1480 }
1481 }
1482
1483 if (generic_version < IFV_REMOVE_GENERATION_SEED) {
1484 IniGroup *game_creation = generic_ini.GetGroup("game_creation");
1485 if (game_creation != nullptr) {
1486 game_creation->RemoveItem("generation_seed");
1487 }
1488 }
1489
1490 /* These variables are migrated from generic ini to private ini now. */
1491 if (generic_version < IFV_NETWORK_PRIVATE_SETTINGS) {
1492 IniGroup *network = generic_ini.GetGroup("network");
1493 if (network != nullptr) {
1494 network->RemoveItem("use_relay_service");
1495 }
1496 }
1497
1498 HandleSettingDescs(generic_ini, private_ini, secrets_ini, IniSaveSettings, IniSaveSettingList);
1499 GraphicsSetSaveConfig(generic_ini);
1500 GRFSaveConfig(generic_ini, "newgrf", _grfconfig_newgame);
1501 GRFSaveConfig(generic_ini, "newgrf-static", _grfconfig_static);
1502 AISaveConfig(generic_ini, "ai_players");
1503 GameSaveConfig(generic_ini, "game_scripts");
1504 PickerSaveConfig(favs_ini);
1505
1506 SaveVersionInConfig(generic_ini);
1507 SaveVersionInConfig(private_ini);
1508 SaveVersionInConfig(secrets_ini);
1509 SaveVersionInConfig(favs_ini);
1510
1511 generic_ini.SaveToDisk(_config_file);
1512 private_ini.SaveToDisk(_private_file);
1513 secrets_ini.SaveToDisk(_secrets_file);
1514 favs_ini.SaveToDisk(_favs_file);
1515}
1516
1522{
1523 StringList list;
1524
1526 for (const IniGroup &group : ini.groups) {
1527 if (group.name.compare(0, 7, "preset-") == 0) {
1528 list.push_back(group.name.substr(7));
1529 }
1530 }
1531
1532 return list;
1533}
1534
1541GRFConfig *LoadGRFPresetFromConfig(const char *config_name)
1542{
1543 std::string section("preset-");
1544 section += config_name;
1545
1547 GRFConfig *config = GRFLoadConfig(ini, section.c_str(), false);
1548
1549 return config;
1550}
1551
1558void SaveGRFPresetToConfig(const char *config_name, GRFConfig *config)
1559{
1560 std::string section("preset-");
1561 section += config_name;
1562
1564 GRFSaveConfig(ini, section.c_str(), config);
1566}
1567
1572void DeleteGRFPresetFromConfig(const char *config_name)
1573{
1574 std::string section("preset-");
1575 section += config_name;
1576
1578 ini.RemoveGroup(section);
1580}
1581
1588void IntSettingDesc::ChangeValue(const void *object, int32_t newval) const
1589{
1590 int32_t oldval = this->Read(object);
1591 this->MakeValueValid(newval);
1592 if (this->pre_check != nullptr && !this->pre_check(newval)) return;
1593 if (oldval == newval) return;
1594
1595 this->Write(object, newval);
1596 if (this->post_callback != nullptr) this->post_callback(newval);
1597
1598 if (this->flags & SF_NO_NETWORK) {
1600 _gamelog.Setting(this->GetName(), oldval, newval);
1602 }
1603
1605
1606 if (_save_config) SaveToConfig();
1607}
1608
1616static const SettingDesc *GetSettingFromName(const std::string_view name, const SettingTable &settings)
1617{
1618 /* First check all full names */
1619 for (auto &desc : settings) {
1620 const SettingDesc *sd = GetSettingDesc(desc);
1621 if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue;
1622 if (sd->GetName() == name) return sd;
1623 }
1624
1625 /* Then check the shortcut variant of the name. */
1626 std::string short_name_suffix = std::string{ "." }.append(name);
1627 for (auto &desc : settings) {
1628 const SettingDesc *sd = GetSettingDesc(desc);
1629 if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue;
1630 if (sd->GetName().ends_with(short_name_suffix)) return sd;
1631 }
1632
1633 return nullptr;
1634}
1635
1641void GetSaveLoadFromSettingTable(SettingTable settings, std::vector<SaveLoad> &saveloads)
1642{
1643 for (auto &desc : settings) {
1644 const SettingDesc *sd = GetSettingDesc(desc);
1645 if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue;
1646 saveloads.push_back(sd->save);
1647 }
1648}
1649
1656static const SettingDesc *GetCompanySettingFromName(std::string_view name)
1657{
1658 static const std::string_view company_prefix = "company.";
1659 if (name.starts_with(company_prefix)) name.remove_prefix(company_prefix.size());
1660 return GetSettingFromName(name, _company_settings);
1661}
1662
1669const SettingDesc *GetSettingFromName(const std::string_view name)
1670{
1671 for (auto &table : GenericSettingTables()) {
1672 auto sd = GetSettingFromName(name, table);
1673 if (sd != nullptr) return sd;
1674 }
1675 for (auto &table : PrivateSettingTables()) {
1676 auto sd = GetSettingFromName(name, table);
1677 if (sd != nullptr) return sd;
1678 }
1679 for (auto &table : SecretSettingTables()) {
1680 auto sd = GetSettingFromName(name, table);
1681 if (sd != nullptr) return sd;
1682 }
1683
1684 return GetCompanySettingFromName(name);
1685}
1686
1696CommandCost CmdChangeSetting(DoCommandFlag flags, const std::string &name, int32_t value)
1697{
1698 if (name.empty()) return CMD_ERROR;
1699 const SettingDesc *sd = GetSettingFromName(name);
1700
1701 if (sd == nullptr) return CMD_ERROR;
1703 if (!sd->IsIntSetting()) return CMD_ERROR;
1704
1705 if (!sd->IsEditable(true)) return CMD_ERROR;
1706
1707 if (flags & DC_EXEC) {
1708 sd->AsIntSetting()->ChangeValue(&GetGameSettings(), value);
1709 }
1710
1711 return CommandCost();
1712}
1713
1722CommandCost CmdChangeCompanySetting(DoCommandFlag flags, const std::string &name, int32_t value)
1723{
1724 if (name.empty()) return CMD_ERROR;
1725 const SettingDesc *sd = GetCompanySettingFromName(name);
1726
1727 if (sd == nullptr) return CMD_ERROR;
1728 if (!sd->IsIntSetting()) return CMD_ERROR;
1729
1730 if (flags & DC_EXEC) {
1732 }
1733
1734 return CommandCost();
1735}
1736
1744bool SetSettingValue(const IntSettingDesc *sd, int32_t value, bool force_newgame)
1745{
1746 const IntSettingDesc *setting = sd->AsIntSetting();
1747 if ((setting->flags & SF_PER_COMPANY) != 0) {
1748 if (Company::IsValidID(_local_company) && _game_mode != GM_MENU) {
1749 return Command<CMD_CHANGE_COMPANY_SETTING>::Post(setting->GetName(), value);
1750 }
1751
1752 setting->ChangeValue(&_settings_client.company, value);
1753 return true;
1754 }
1755
1756 /* If an item is company-based, we do not send it over the network
1757 * (if any) to change. Also *hack*hack* we update the _newgame version
1758 * of settings because changing a company-based setting in a game also
1759 * changes its defaults. At least that is the convention we have chosen */
1760 if (setting->flags & SF_NO_NETWORK_SYNC) {
1761 if (_game_mode != GM_MENU) {
1762 setting->ChangeValue(&_settings_newgame, value);
1763 }
1764 setting->ChangeValue(&GetGameSettings(), value);
1765 return true;
1766 }
1767
1768 if (force_newgame) {
1769 setting->ChangeValue(&_settings_newgame, value);
1770 return true;
1771 }
1772
1773 /* send non-company-based settings over the network */
1775 return Command<CMD_CHANGE_SETTING>::Post(setting->GetName(), value);
1776 }
1777 return false;
1778}
1779
1784{
1785 Company *c = Company::Get(cid);
1786 for (auto &desc : _company_settings) {
1787 const IntSettingDesc *int_setting = GetSettingDesc(desc)->AsIntSetting();
1788 int_setting->MakeValueValidAndWrite(&c->settings, int_setting->def);
1789 }
1790}
1791
1796{
1797 const void *old_object = &Company::Get(_current_company)->settings;
1798 const void *new_object = &_settings_client.company;
1799 for (auto &desc : _company_settings) {
1800 const SettingDesc *sd = GetSettingDesc(desc);
1801 uint32_t old_value = (uint32_t)sd->AsIntSetting()->Read(old_object);
1802 uint32_t new_value = (uint32_t)sd->AsIntSetting()->Read(new_object);
1803 /*
1804 * This is called from a command, and since it contains local configuration information
1805 * that the rest of the clients do not know about, we need to circumvent the normal ::Post
1806 * local command validation and immediately send the command to the server.
1807 */
1808 if (old_value != new_value) Command<CMD_CHANGE_COMPANY_SETTING>::SendNet(STR_NULL, _local_company, sd->GetName(), new_value);
1809 }
1810}
1811
1819bool SetSettingValue(const StringSettingDesc *sd, std::string value, bool force_newgame)
1820{
1821 assert(sd->flags & SF_NO_NETWORK_SYNC);
1822
1823 if (GetVarMemType(sd->save.conv) == SLE_VAR_STRQ && value.compare("(null)") == 0) {
1824 value.clear();
1825 }
1826
1827 const void *object = (_game_mode == GM_MENU || force_newgame) ? &_settings_newgame : &_settings_game;
1828 sd->AsStringSetting()->ChangeValue(object, value);
1829 return true;
1830}
1831
1838void StringSettingDesc::ChangeValue(const void *object, std::string &newval) const
1839{
1840 this->MakeValueValid(newval);
1841 if (this->pre_check != nullptr && !this->pre_check(newval)) return;
1842
1843 this->Write(object, newval);
1844 if (this->post_callback != nullptr) this->post_callback(newval);
1845
1846 if (_save_config) SaveToConfig();
1847}
1848
1849/* Those 2 functions need to be here, else we have to make some stuff non-static
1850 * and besides, it is also better to keep stuff like this at the same place */
1851void IConsoleSetSetting(const char *name, const char *value, bool force_newgame)
1852{
1853 const SettingDesc *sd = GetSettingFromName(name);
1854 if (sd == nullptr) {
1855 IConsolePrint(CC_ERROR, "'{}' is an unknown setting.", name);
1856 return;
1857 }
1858
1859 bool success = true;
1860 if (sd->IsStringSetting()) {
1861 success = SetSettingValue(sd->AsStringSetting(), value, force_newgame);
1862 } else if (sd->IsIntSetting()) {
1863 const IntSettingDesc *isd = sd->AsIntSetting();
1864 size_t val = isd->ParseValue(value);
1865 if (!_settings_error_list.empty()) {
1866 IConsolePrint(CC_ERROR, "'{}' is not a valid value for this setting.", value);
1867 _settings_error_list.clear();
1868 return;
1869 }
1870 success = SetSettingValue(isd, (int32_t)val, force_newgame);
1871 }
1872
1873 if (!success) {
1874 if (_network_server) {
1875 IConsolePrint(CC_ERROR, "This command/variable is not available during network games.");
1876 } else {
1877 IConsolePrint(CC_ERROR, "This command/variable is only available to a network server.");
1878 }
1879 }
1880}
1881
1882void IConsoleSetSetting(const char *name, int value)
1883{
1884 const SettingDesc *sd = GetSettingFromName(name);
1885 assert(sd != nullptr);
1886 SetSettingValue(sd->AsIntSetting(), value);
1887}
1888
1894void IConsoleGetSetting(const char *name, bool force_newgame)
1895{
1896 const SettingDesc *sd = GetSettingFromName(name);
1897 if (sd == nullptr) {
1898 IConsolePrint(CC_ERROR, "'{}' is an unknown setting.", name);
1899 return;
1900 }
1901
1902 const void *object = (_game_mode == GM_MENU || force_newgame) ? &_settings_newgame : &_settings_game;
1903
1904 if (sd->IsStringSetting()) {
1905 IConsolePrint(CC_INFO, "Current value for '{}' is '{}'.", sd->GetName(), sd->AsStringSetting()->Read(object));
1906 } else if (sd->IsIntSetting()) {
1907 std::string value = sd->FormatValue(object);
1908 const IntSettingDesc *int_setting = sd->AsIntSetting();
1909 IConsolePrint(CC_INFO, "Current value for '{}' is '{}' (min: {}{}, max: {}).",
1910 sd->GetName(), value, (sd->flags & SF_GUI_0_IS_SPECIAL) ? "(0) " : "", int_setting->min, int_setting->max);
1911 }
1912}
1913
1914static void IConsoleListSettingsTable(const SettingTable &table, const char *prefilter)
1915{
1916 for (auto &desc : table) {
1917 const SettingDesc *sd = GetSettingDesc(desc);
1918 if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue;
1919 if (prefilter != nullptr && sd->GetName().find(prefilter) == std::string::npos) continue;
1920 IConsolePrint(CC_DEFAULT, "{} = {}", sd->GetName(), sd->FormatValue(&GetGameSettings()));
1921 }
1922}
1923
1929void IConsoleListSettings(const char *prefilter)
1930{
1931 IConsolePrint(CC_HELP, "All settings with their current value:");
1932
1933 for (auto &table : GenericSettingTables()) {
1934 IConsoleListSettingsTable(table, prefilter);
1935 }
1936 for (auto &table : PrivateSettingTables()) {
1937 IConsoleListSettingsTable(table, prefilter);
1938 }
1939 for (auto &table : SecretSettingTables()) {
1940 IConsoleListSettingsTable(table, prefilter);
1941 }
1942
1943 IConsolePrint(CC_HELP, "Use 'setting' command to change a value.");
1944}
AIConfig stores the configuration settings of every AI.
Generic functions for replacing base data (graphics, sounds).
debug_inline constexpr bool HasBit(const T x, const uint8_t y)
Checks if a bit in a value is set.
constexpr T SetBit(T &x, const uint8_t y)
Set a bit in a variable.
static uint32_t BSWAP32(uint32_t x)
Perform a 32 bits endianness bitswap on x.
static AIConfig * GetConfig(CompanyID company, ScriptSettingSource source=SSS_DEFAULT)
Get the config of a company.
Definition ai_config.cpp:20
static const GraphicsSet * GetUsedSet()
Return the used set.
Common return value for all commands.
IniFile to store a configuration.
Definition settings.cpp:136
The data of the error message.
Definition error.h:31
void SetDParamStr(uint n, const char *str)
Set a rawstring parameter.
static GameConfig * GetConfig(ScriptSettingSource source=SSS_DEFAULT)
Get the config of a company.
void StartAction(GamelogActionType at)
Stores information about new action, but doesn't allocate it Action is allocated only when there is a...
Definition gamelog.cpp:65
void StopAction()
Stops logging of any changes.
Definition gamelog.cpp:74
void Setting(const std::string &name, int32_t oldval, int32_t newval)
Logs change in game settings.
Definition gamelog.cpp:413
@ SSS_FORCE_NEWGAME
Get the newgame Script config.
bool HasScript() const
Is this config attached to an Script? In other words, is there a Script that is assigned to this slot...
void Change(std::optional< const std::string > name, int version=-1, bool force_exact_match=false)
Set another Script to be loaded in this slot.
const std::string & GetName() const
Get the name of the Script.
void StringToSettings(const std::string &value)
Convert a string which is stored in the config file or savegames to custom settings of this Script.
std::string SettingsToString() const
Convert the custom settings to a string that can be stored in the config file or savegames.
static constexpr int SECONDS_PER_DAY
approximate seconds per day, not for precise calculations
Functions related to commands.
static const CommandCost CMD_ERROR
Define a default return value for a failed command.
DoCommandFlag
List of flags for a command.
@ DC_EXEC
execute the given command
CompanyID _local_company
Company controlled by the human player at this client. Can also be COMPANY_SPECTATOR.
CompanyID _current_company
Company currently doing an action.
Functions related to companies.
Owner
Enum for all companies/owners.
@ COMPANY_FIRST
First company, same as owner.
@ MAX_COMPANIES
Maximum number of companies.
Configuration options of the network stuff.
static const uint NETWORK_MAX_GRF_COUNT
Maximum number of GRFs that can be sent.
Definition config.h:90
void IConsolePrint(TextColour colour_code, const std::string &string)
Handle the printing of text entered into the console or redirected there by any other means.
Definition console.cpp:89
Console functions used outside of the console code.
static const TextColour CC_HELP
Colour for help lines.
static const TextColour CC_INFO
Colour for information lines.
static const TextColour CC_DEFAULT
Default colour of the console.
static const TextColour CC_ERROR
Colour for error lines.
void ResetCurrencies(bool preserve_custom)
Will fill _currency_specs array with default values from origin_currency_specs Called only from newgr...
Definition currency.cpp:160
Functions to handle different currencies.
CurrencySpec & GetCustomCurrency()
Get the custom currency.
Definition currency.h:108
void DebugReconsiderSendRemoteMessages()
Reconsider whether we need to send debug messages to either NetworkAdminConsole or IConsolePrint.
Definition debug.cpp:264
Functions related to debugging.
#define Debug(category, level, format_string,...)
Ouptut a line of debugging information.
Definition debug.h:37
Functions related to errors.
std::list< ErrorMessageData > ErrorList
Define a queue with errors.
Definition error.h:62
void ScheduleErrorMessage(ErrorList &datas)
Schedule a list of errors.
void ShowErrorMessage(StringID summary_msg, int x, int y, CommandCost cc)
Display an error message in a window.
void ShowFirstError()
Show the first error of the queue.
@ WL_CRITICAL
Critical errors, the MessageBox is shown in all cases.
Definition error.h:27
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.
static const uint CUSTOM_SEA_LEVEL_NUMBER_DIFFICULTY
Value for custom sea level in difficulty settings.
Definition genworld.h:47
static const uint CUSTOM_SEA_LEVEL_MIN_PERCENTAGE
Minimum percentage a user can specify for custom sea level.
Definition genworld.h:48
@ LG_ORIGINAL
The original landscape generator.
Definition genworld.h:20
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.
std::string GRFBuildParamList(const GRFConfig *c)
Build a string containing space separated parameter values, and terminate.
bool FillGRFDetails(GRFConfig *config, bool is_static, Subdirectory subdir)
Find the GRFID of a given grf, and calculate its md5sum.
const GRFConfig * FindGRFConfig(uint32_t grfid, FindGRFConfigMode mode, const MD5Hash *md5sum, uint32_t desired_version)
Find a NewGRF in the scanned list.
GRFConfig * _grfconfig_static
First item in list of static GRF set up.
GRFConfig * _grfconfig_newgame
First item in list of default GRF set up.
Functions to find and configure NewGRFs.
@ GCF_INVALID
GRF is unusable with this version of OpenTTD.
@ GCF_STATIC
GRF file is used statically (can be used in any MP game)
@ GCF_UNSAFE
GRF file is unsafe for static usage.
@ GCF_SYSTEM
GRF file is an openttd-internal system grf.
@ GCS_NOT_FOUND
GRF file was not found in the local cache.
@ FGCM_NEWEST_VALID
Find newest Grf, ignoring Grfs with GCF_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:818
int64_t ReadValue(const void *ptr, VarType conv)
Return a signed-long version of the value of a setting.
Definition saveload.cpp:794
@ SLE_VAR_NULL
useful to write zeros in savegame.
Definition saveload.h:653
@ SLE_VAR_STR
string pointer
Definition saveload.h:654
@ SLE_VAR_STRQ
string pointer enclosed in quotes
Definition saveload.h:655
constexpr size_t SlVarSize(VarType type)
Return expect size in bytes of a VarType.
Definition saveload.h:782
void * GetVariableAddress(const void *object, const SaveLoad &sld)
Get the address of the variable.
Definition saveload.h:1301
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:1290
constexpr VarType GetVarMemType(VarType type)
Get the NumberType of a setting.
Definition saveload.h:751
static void GraphicsSetLoadConfig(IniFile &ini)
Load BaseGraphics set selection and configuration.
Definition settings.cpp:996
void HandleOldDiffCustom(bool savegame)
Reading of the old diff_custom array and transforming it to the new format.
GRFConfig * LoadGRFPresetFromConfig(const char *config_name)
Load a NewGRF configuration by preset-name.
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:694
static void ValidateSettings()
Checks if any settings are set to incorrect values, and sets them to correct values in that case.
Definition settings.cpp:931
bool IsConversionNeeded(const ConfigIniFile &ini, const std::string &group, const std::string &old_var, const std::string &new_var, const IniItem **old_item)
Check whether a conversion should be done, and based on what old setting information.
static std::optional< std::vector< uint32_t > > ParseIntList(const char *p)
Parse a string into a vector of uint32s.
Definition settings.cpp:249
std::string _secrets_file
Secrets configuration file of OpenTTD.
Definition settings.cpp:62
std::string _favs_file
Picker favourites configuration file of OpenTTD.
Definition settings.cpp:63
static void IniLoadSettings(IniFile &ini, const SettingTable &settings_table, const char *grpname, void *object, bool only_startup)
Load values from a group of an IniFile structure into the internal representation.
Definition settings.cpp:614
static ErrorList _settings_error_list
Errors while loading minimal settings.
Definition settings.cpp:65
void IniLoadWindowSettings(IniFile &ini, const char *grpname, void *desc)
Load a WindowDesc from config.
Definition settings.cpp:862
static bool LoadIntList(const char *str, void *array, int nelems, VarType type)
Load parsed string-values into an integer-array (intlist)
Definition settings.cpp:294
void SetDefaultCompanySettings(CompanyID cid)
Set the company settings for a new company to their default values.
void SaveGRFPresetToConfig(const char *config_name, GRFConfig *config)
Save a NewGRF configuration with a preset name.
void LoadFromConfig(bool startup)
Load the values from the configuration files.
bool SetSettingValue(const IntSettingDesc *sd, int32_t value, bool force_newgame)
Top function to save the new value of an element of the Settings struct.
void SaveToConfig()
Save the values to the configuration file.
VehicleDefaultSettings _old_vds
Used for loading default vehicles settings from old savegames.
Definition settings.cpp:59
void PrepareOldDiffCustom()
Prepare for reading and old diff_custom by zero-ing the memory.
static void IniLoadSettingList(IniFile &ini, const char *grpname, StringList &list)
Loads all items from a 'grpname' section into a list The list parameter can be a nullptr pointer,...
Definition settings.cpp:824
CommandCost CmdChangeCompanySetting(DoCommandFlag flags, const std::string &name, int32_t value)
Change one of the per-company settings.
void GetSaveLoadFromSettingTable(SettingTable settings, std::vector< SaveLoad > &saveloads)
Get the SaveLoad for all settings in the settings table.
void IniSaveWindowSettings(IniFile &ini, const char *grpname, void *desc)
Save a WindowDesc to config.
Definition settings.cpp:873
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:846
static void GraphicsSetSaveConfig(IniFile &ini)
Save BaseGraphics set selection and configuration.
GameSettings _settings_game
Game settings of a running game or the scenario editor.
Definition settings.cpp:57
static size_t LookupManyOfMany(const std::vector< std::string > &many, const char *str)
Find the set-integer value MANYofMANY type in a string.
Definition settings.cpp:220
IniFileVersion
Ini-file versions.
Definition settings.cpp:162
@ IFV_0
0 All versions prior to introduction.
Definition settings.cpp:163
@ IFV_AUTOSAVE_RENAME
5 PR#11143 Renamed values of autosave to be in minutes.
Definition settings.cpp:169
@ IFV_LINKGRAPH_SECONDS
3 PR#10610 Store linkgraph update intervals in seconds instead of days.
Definition settings.cpp:166
@ IFV_REMOVE_GENERATION_SEED
7 PR#11927 Remove "generation_seed" from configuration.
Definition settings.cpp:171
@ IFV_MAX_VERSION
Highest possible ini-file version.
Definition settings.cpp:173
@ IFV_NETWORK_PRIVATE_SETTINGS
4 PR#10762 Move use_relay_service to private settings.
Definition settings.cpp:167
@ IFV_GAME_TYPE
2 PR#9515 Convert server_advertise to server_game_type.
Definition settings.cpp:165
@ IFV_RIGHT_CLICK_CLOSE
6 PR#10204 Add alternative right click to close windows setting.
Definition settings.cpp:170
@ IFV_PRIVATE_SECRETS
1 PR#9298 Moving of settings from openttd.cfg to private.cfg / secrets.cfg.
Definition settings.cpp:164
CommandCost CmdChangeSetting(DoCommandFlag flags, const std::string &name, int32_t value)
Network-safe changing of settings (server-only).
const uint16_t INIFILE_VERSION
Current ini-file version of OpenTTD.
Definition settings.cpp:176
static auto & SecretSettingTables()
List of all the secrets setting tables.
Definition settings.cpp:110
std::string _private_file
Private configuration file of OpenTTD.
Definition settings.cpp:61
void DeleteGRFPresetFromConfig(const char *config_name)
Delete a NewGRF configuration by preset name.
static const SettingDesc * GetSettingFromName(const std::string_view name, const SettingTable &settings)
Given a name of setting, return a setting description from the table.
GameSettings _settings_newgame
Game settings for new games (updated from the intro screen).
Definition settings.cpp:58
static GRFConfig * GRFLoadConfig(const IniFile &ini, const char *grpname, bool is_static)
Load a GRF configuration.
void IConsoleGetSetting(const char *name, bool force_newgame)
Output value of a specific setting to the console.
void IConsoleListSettings(const char *prefilter)
List all settings and their value to the console.
static auto & PrivateSettingTables()
List of all the private setting tables.
Definition settings.cpp:99
static void SaveVersionInConfig(IniFile &ini)
Save the version of OpenTTD to the ini file.
std::string _config_file
Configuration file of OpenTTD.
Definition settings.cpp:60
static auto & GenericSettingTables()
List of all the generic setting tables.
Definition settings.cpp:77
static const SettingDesc * GetCompanySettingFromName(std::string_view name)
Given a name of setting, return a company setting description of it.
ClientSettings _settings_client
The current settings for this game.
Definition settings.cpp:56
Command definitions related to settings.
Functions related to setting/changing the settings.
SettingType
Type of settings for filtering.
@ ST_CLIENT
Client setting.
@ ST_GAME
Game setting.
@ ST_COMPANY
Company setting.
@ SF_NOT_IN_CONFIG
Do not save to config file.
@ SF_GUI_DROPDOWN
The value represents a limited number of string-options (internally integer) presented as dropdown.
@ SF_PER_COMPANY
This setting can be different for each company (saved in company struct).
@ SF_NETWORK_ONLY
This setting only applies to network games.
@ SF_NOT_IN_SAVE
Do not save with savegame, basically client-based.
@ SF_NEWGAME_ONLY
This setting cannot be changed in a game.
@ SF_SCENEDIT_ONLY
This setting can only be changed in the scenario editor.
@ SF_NO_NETWORK_SYNC
Do not synchronize over network (but it is saved if SF_NOT_IN_SAVE is not set).
@ SF_NO_NETWORK
This setting does not apply to network games; it may not be changed during the game.
@ SF_SCENEDIT_TOO
This setting can be changed in the scenario editor (only makes sense when SF_NEWGAME_ONLY is set).
@ SF_GUI_0_IS_SPECIAL
A value of zero is possible and has a custom string (the one after "strval").
static constexpr const SettingDesc * GetSettingDesc(const SettingVariant &desc)
Helper to convert the type of the iterated settings description to a pointer to it.
Definition of the configuration tables of the settings.
GameSettings & GetGameSettings()
Get the settings-object applicable for the current situation: the newgame settings when we're in the ...
Definition of base types and functions in a cross-platform compatible way.
static void StrMakeValid(T &dst, const char *str, const char *last, StringValidationSettings settings)
Copies the valid (UTF-8) characters from str up to last to the dst.
Definition string.cpp:107
bool ConvertHexToBytes(std::string_view hex, std::span< uint8_t > bytes)
Convert a hex-string to a byte-array, while validating it was actually hex.
Definition string.cpp:734
std::string FormatArrayAsHex(std::span< const uint8_t > data)
Format a byte array into a continuous hex string.
Definition string.cpp:81
Functions related to low-level strings.
@ SVS_NONE
Allow nothing and replace nothing.
Definition string_type.h:45
std::vector< std::string > StringList
Type for a list of strings.
Definition string_type.h:60
void SetDParam(size_t n, uint64_t v)
Set a string parameter v at index n in the global string parameter array.
Definition strings.cpp:104
void SetDParamStr(size_t n, const char *str)
This function is used to "bind" a C string to a OpenTTD dparam slot.
Definition strings.cpp:371
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
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:736
static std::optional< bool > ParseSingleValue(const char *str)
Find whether a string was a boolean true or a boolean false.
Definition settings.cpp:205
size_t ParseValue(const char *str) const override
Convert a string representation (external) of an integer-like setting to an integer.
Definition settings.cpp:424
All settings that are only important for the local client.
CompanySettings company
default values for per-company settings
NetworkSettings network
settings related to the network
GUISettings gui
settings related to the GUI
CompanySettings settings
settings specific for each company
uint8_t quantity_sea_lakes
the amount of seas/lakes
Information about GRF, used in the game and (part of it) in savegames.
uint8_t flags
NOSAVE: GCF_Flags, bitset.
uint32_t version
NOSAVE: Version a NewGRF can set so only the newest NewGRF is shown.
std::vector< uint32_t > param
GRF parameters.
struct GRFConfig * next
NOSAVE: Next item in the linked list.
GRFStatus status
NOSAVE: GRFStatus, enum.
std::string filename
Filename - either with or without full path.
GRFIdentifier ident
grfid and md5sum to uniquely identify newgrfs
uint32_t grfid
GRF ID (defined by Action 0x08)
MD5Hash md5sum
MD5 checksum of file to distinguish files with the same GRF ID (eg. newer version of GRF)
uint32_t autosave_interval
how often should we do autosaves?
RightClickClose right_click_wnd_close
close window with right click
uint8_t land_generator
the landscape generator
All settings together for the game.
DifficultySettings difficulty
settings related to the difficulty
GameCreationSettings game_creation
settings used during the creation of a game (map)
LinkGraphSettings linkgraph
settings for link graph calculations
All data of a graphics set.
Ini file that supports both loading and saving.
Definition ini_type.h:88
bool SaveToDisk(const std::string &filename)
Save the Ini file's data to the disk.
Definition ini.cpp:42
A group within an ini file.
Definition ini_type.h:34
const IniItem * GetItem(std::string_view name) const
Get the item with the given name.
Definition ini_load.cpp:52
std::string comment
comment for group
Definition ini_type.h:38
void Clear()
Clear all items in the group.
Definition ini_load.cpp:98
void RemoveItem(std::string_view name)
Remove the item with the given name.
Definition ini_load.cpp:90
std::string name
name of group
Definition ini_type.h:37
IniItem & CreateItem(std::string_view name)
Create an item with the given name.
Definition ini_load.cpp:81
IniItem & GetOrCreateItem(std::string_view name)
Get the item with the given name, and if it doesn't exist create a new item.
Definition ini_load.cpp:66
std::list< IniItem > items
all items in the group
Definition ini_type.h:35
A single "line" in an ini file.
Definition ini_type.h:23
std::optional< std::string > value
The value of this item.
Definition ini_type.h:25
std::string name
The name of this item.
Definition ini_type.h:24
void SetValue(std::string_view value)
Replace the current value with another value.
Definition ini_load.cpp:32
std::list< IniGroup > groups
all groups in the ini
Definition ini_type.h:53
void RemoveGroup(std::string_view name)
Remove the group with the given name.
Definition ini_load.cpp:175
void LoadFromDisk(const std::string &filename, Subdirectory subdir)
Load the Ini file's data from the disk.
Definition ini_load.cpp:187
const IniGroup * GetGroup(std::string_view name) const
Get the group with the given name.
Definition ini_load.cpp:119
IniGroup & GetOrCreateGroup(std::string_view name)
Get the group with the given name, and if it doesn't exist create a new group.
Definition ini_load.cpp:147
Base integer type, including boolean, settings.
void SetValueDParams(uint first_param, int32_t value) const
Set the DParams for drawing the value of the setting.
Definition settings.cpp:460
StringID str_help
(Translated) string with help text; gui only.
StringID str_val
(Translated) first string describing the value.
void MakeValueValid(int32_t &value) const
Make the value valid given the limitations of this setting.
Definition settings.cpp:497
void ResetToDefault(void *object) const override
Reset the setting to its default value.
Definition settings.cpp:755
std::string FormatValue(const void *object) const override
Format the value of the setting associated with this object.
Definition settings.cpp:725
int32_t def
default value given when none is present
StringID GetTitle() const
Get the title of the setting.
Definition settings.cpp:441
void ChangeValue(const void *object, int32_t newvalue) const
Handle changing a value.
uint32_t max
maximum values
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:742
int32_t min
minimum values
PreChangeCheck * pre_check
Callback to check for the validity of the setting.
void Write(const void *object, int32_t value) const
Set the value of a setting.
Definition settings.cpp:550
StringID GetHelp() const
Get the help text of the setting.
Definition settings.cpp:450
virtual bool IsBoolSetting() const
Check whether this setting is a boolean type setting.
PostChangeCallback * post_callback
Callback when the setting has been changed.
StringID str
(translated) string with descriptive text; gui and console
void MakeValueValidAndWrite(const void *object, int32_t value) const
Make the value valid and then write it to the setting.
Definition settings.cpp:482
virtual size_t ParseValue(const char *str) const
Convert a string representation (external) of an integer-like setting to an integer.
Definition settings.cpp:379
int32_t Read(const void *object) const
Read the integer from the the actual setting.
Definition settings.cpp:561
bool IsDefaultValue(void *object) const override
Check whether the value is the same as the default value.
Definition settings.cpp:749
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:668
void ResetToDefault(void *object) const override
Reset the setting to its default value.
Definition settings.cpp:809
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:797
std::string FormatValue(const void *object) const override
Convert an integer-array (intlist) to a string representation.
Definition settings.cpp:322
const char * def
default value given when none is present
bool IsDefaultValue(void *object) const override
Check whether the value is the same as the default value.
Definition settings.cpp:803
std::string FormatValue(const void *object) const override
Format the value of the setting associated with this object.
Definition settings.cpp:359
size_t ParseValue(const char *str) const override
Convert a string representation (external) of an integer-like setting to an integer.
Definition settings.cpp:413
NetworkAuthorizedKeys admin_authorized_keys
Public keys of clients that are authorized to use the admin network.
ServerGameType server_game_type
Server type: local / public / invite-only.
NetworkAuthorizedKeys rcon_authorized_keys
Public keys of clients that are authorized to use the rconsole (server side).
UseRelayService use_relay_service
Use relay service?
NetworkAuthorizedKeys server_authorized_keys
Public keys of clients that are authorized to connect to the game.
OnConvert * many_cnvt
callback procedure when loading value mechanism fails
size_t ParseValue(const char *str) const override
Convert a string representation (external) of an integer-like setting to an integer.
Definition settings.cpp:398
static size_t ParseSingleValue(const char *str, size_t len, const std::vector< std::string > &many)
Find the index value of a ONEofMANY type in a string separated by |.
Definition settings.cpp:185
std::string FormatValue(const void *object) const override
Format the value of the setting associated with this object.
Definition settings.cpp:353
std::vector< std::string > many
possible values for this type
static bool IsValidID(size_t index)
Tests whether given index can be used to get valid (non-nullptr) Titem.
static Titem * Get(size_t index)
Returns Titem with given index.
uint16_t length
(Conditional) length of the variable (eg. arrays) (max array size is 65536 elements).
Definition saveload.h:721
SaveLoadVersion version_to
Save/load the variable before this savegame version.
Definition saveload.h:723
VarType conv
Type of the variable to be saved; this field combines both FileVarType and MemVarType.
Definition saveload.h:720
SaveLoadVersion version_from
Save/load the variable starting from this savegame version.
Definition saveload.h:722
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:883
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:900
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:920
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:910
SettingFlag flags
Handles how a setting would show up in the GUI (text/currency, etc.).
String settings.
const std::string & Read(const void *object) const
Read the string from the the actual setting.
Definition settings.cpp:600
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:574
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:776
bool IsDefaultValue(void *object) const override
Check whether the value is the same as the default value.
Definition settings.cpp:786
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:792
void Write(const void *object, const std::string &str) const
Write a string to the actual setting.
Definition settings.cpp:590
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:760
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:661
Default settings for vehicles.
void SetWindowClassesDirty(WindowClass cls)
Mark all windows of a particular class as dirty (in need of repainting)
Definition window.cpp:3127
Window * FindWindowById(WindowClass cls, WindowNumber number)
Find a window by its class and window number.
Definition window.cpp:1098
Window functions not directly related to making/drawing windows.
@ WC_ERRMSG
Error message; Window numbers:
@ WC_GAME_OPTIONS
Game options window; Window numbers: