OpenTTD Source 20250529-master-g10c159a79f
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>
27#include "settings_table.h"
28#include "debug.h"
29#include "currency.h"
30#include "network/network.h"
32#include "network/core/config.h"
33#include "command_func.h"
34#include "console_func.h"
35#include "genworld.h"
36#include "string_func.h"
37#include "strings_func.h"
38#include "window_func.h"
39#include "company_func.h"
40#include "rev.h"
41#include "error.h"
42#include "gamelog.h"
43#include "settings_func.h"
44#include "ini_type.h"
45#include "ai/ai_config.hpp"
46#include "game/game_config.hpp"
47#include "newgrf_config.h"
48#include "picker_func.h"
49#include "newgrf_badge_config.h"
50#include "base_media_base.h"
51#include "base_media_graphics.h"
52#include "fios.h"
53#include "fileio_func.h"
54#include "settings_cmd.h"
55
56#include "table/strings.h"
57
58#include "safeguards.h"
59
64std::string _config_file;
65std::string _private_file;
66std::string _secrets_file;
67std::string _favs_file;
68
70
82{
83 static const SettingTable _generic_setting_tables[] = {
84 _difficulty_settings,
85 _economy_settings,
86 _game_settings,
87 _gui_settings,
88 _linkgraph_settings,
89 _locale_settings,
90 _multimedia_settings,
91 _network_settings,
92 _news_display_settings,
93 _pathfinding_settings,
94 _script_settings,
95 _world_settings,
96 };
97 return _generic_setting_tables;
98}
99
104{
105 static const SettingTable _private_setting_tables[] = {
106 _network_private_settings,
107 };
108 return _private_setting_tables;
109}
110
115{
116 static const SettingTable _secrets_setting_tables[] = {
117 _network_secrets_settings,
118 };
119 return _secrets_setting_tables;
120}
121
122using SettingDescProc = void(IniFile &ini, const SettingTable &desc, std::string_view grpname, void *object, bool only_startup);
123using SettingDescProcList = void(IniFile &ini, std::string_view grpname, StringList &list);
124
125static bool IsSignedVarMemType(VarType vt)
126{
127 switch (GetVarMemType(vt)) {
128 case SLE_VAR_I8:
129 case SLE_VAR_I16:
130 case SLE_VAR_I32:
131 case SLE_VAR_I64:
132 return true;
133 }
134 return false;
135}
136
140class ConfigIniFile : public IniFile {
141private:
142 static inline const IniGroupNameList list_group_names = {
143 "bans",
144 "newgrf",
145 "servers",
146 "server_bind_addresses",
147 "server_authorized_keys",
148 "rcon_authorized_keys",
149 "admin_authorized_keys"
150 };
151
152public:
153 ConfigIniFile(const std::string &filename) : IniFile(list_group_names)
154 {
155 this->LoadFromDisk(filename, NO_DIRECTORY);
156 }
157};
158
179
181
188std::optional<uint32_t> OneOfManySettingDesc::ParseSingleValue(std::string_view str, std::span<const std::string_view> many)
189{
190 StringConsumer consumer{str};
191 auto digit = consumer.TryReadIntegerBase<uint32_t>(10);
192 /* check if it's an integer */
193 if (digit.has_value()) return digit;
194
195 auto it = std::ranges::find(many, str);
196 if (it == many.end()) return std::nullopt;
197 return static_cast<uint32_t>(it - many.begin());
198}
199
206std::optional<bool> BoolSettingDesc::ParseSingleValue(std::string_view str)
207{
208 if (str == "true" || str == "on" || str == "1") return true;
209 if (str == "false" || str == "off" || str == "0") return false;
210
211 return std::nullopt;
212}
213
221static std::optional<uint32_t> LookupManyOfMany(std::span<const std::string_view> many, std::string_view str)
222{
223 static const std::string_view separators{" \t|"};
224
225 uint32_t res = 0;
226 StringConsumer consumer{str};
227 while (consumer.AnyBytesLeft()) {
228 /* skip "whitespace" */
229 consumer.SkipUntilCharNotIn(separators);
230
231 std::string_view value = consumer.ReadUntilCharIn(separators);
232 if (value.empty()) break;
233
234 auto r = OneOfManySettingDesc::ParseSingleValue(value, many);
235 if (!r.has_value()) return r;
236
237 SetBit(res, *r); // value found, set it
238 }
239 return res;
240}
241
247static std::optional<std::vector<uint32_t>> ParseIntList(std::string_view str)
248{
249 bool comma = false; // do we accept comma?
250 std::vector<uint32_t> result;
251
252 StringConsumer consumer{str};
253 for (;;) {
255 if (!consumer.AnyBytesLeft()) break;
256 if (comma && consumer.ReadIf(",")) {
257 /* commas are optional, but we only accept one between values */
258 comma = false;
259 continue;
260 }
261 auto v = consumer.TryReadIntegerBase<uint32_t>(10);
262 if (!v.has_value()) return std::nullopt;
263 result.push_back(*v);
264 comma = true;
265 }
266
267 /* If we have read comma but no number after it, fail.
268 * We have read comma when (n != 0) and comma is not allowed */
269 if (!result.empty() && !comma) return std::nullopt;
270
271 return result;
272}
273
282static bool LoadIntList(std::optional<std::string_view> str, void *array, int nelems, VarType type)
283{
284 size_t elem_size = SlVarSize(type);
285 std::byte *p = static_cast<std::byte *>(array);
286 if (!str.has_value()) {
287 std::fill_n(p, nelems * elem_size, static_cast<std::byte>(0));
288 return true;
289 }
290
291 auto opt_items = ParseIntList(*str);
292 if (!opt_items.has_value() || opt_items->size() != (size_t)nelems) return false;
293
294 for (auto item : *opt_items) {
295 WriteValue(p, type, item);
296 p += elem_size;
297 }
298 return true;
299}
300
310std::string ListSettingDesc::FormatValue(const void *object) const
311{
312 const uint8_t *p = static_cast<const uint8_t *>(GetVariableAddress(object, this->save));
313
314 std::string result;
315 for (size_t i = 0; i != this->save.length; i++) {
316 int64_t v;
317 switch (GetVarMemType(this->save.conv)) {
318 case SLE_VAR_BL:
319 case SLE_VAR_I8: v = *(const int8_t *)p; p += 1; break;
320 case SLE_VAR_U8: v = *(const uint8_t *)p; p += 1; break;
321 case SLE_VAR_I16: v = *(const int16_t *)p; p += 2; break;
322 case SLE_VAR_U16: v = *(const uint16_t *)p; p += 2; break;
323 case SLE_VAR_I32: v = *(const int32_t *)p; p += 4; break;
324 case SLE_VAR_U32: v = *(const uint32_t *)p; p += 4; break;
325 default: NOT_REACHED();
326 }
327 if (i != 0) result += ',';
328 format_append(result, "{}", v);
329 }
330 return result;
331}
332
333std::string OneOfManySettingDesc::FormatSingleValue(uint id) const
334{
335 if (id >= this->many.size()) {
336 return fmt::format("{}", id);
337 }
338 return std::string{this->many[id]};
339}
340
341std::string OneOfManySettingDesc::FormatValue(const void *object) const
342{
343 uint id = (uint)this->Read(object);
344 return this->FormatSingleValue(id);
345}
346
347std::string ManyOfManySettingDesc::FormatValue(const void *object) const
348{
349 uint bitmask = (uint)this->Read(object);
350 if (bitmask == 0) {
351 return {};
352 }
353
354 std::string result;
355 for (uint id : SetBitIterator(bitmask)) {
356 if (!result.empty()) result += '|';
357 result += this->FormatSingleValue(id);
358 }
359 return result;
360}
361
367int32_t IntSettingDesc::ParseValue(std::string_view str) const
368{
369 StringConsumer consumer{str};
370 /* The actual settings value might be int32 or uint32. Read as int64 and just cast away the high bits. */
371 auto value = consumer.TryReadIntegerBase<int64_t>(10);
372 if (!value.has_value()) {
373 _settings_error_list.emplace_back(
374 GetEncodedString(STR_CONFIG_ERROR),
375 GetEncodedString(STR_CONFIG_ERROR_INVALID_VALUE, str, this->GetName()));
376 return this->GetDefaultValue();
377 }
378 if (consumer.AnyBytesLeft()) {
379 _settings_error_list.emplace_back(
380 GetEncodedString(STR_CONFIG_ERROR),
381 GetEncodedString(STR_CONFIG_ERROR_TRAILING_CHARACTERS, this->GetName()));
382 }
383 return static_cast<int32_t>(*value);
384}
385
386int32_t OneOfManySettingDesc::ParseValue(std::string_view str) const
387{
389 /* if the first attempt of conversion from string to the appropriate value fails,
390 * look if we have defined a converter from old value to new value. */
391 if (!r.has_value() && this->many_cnvt != nullptr) r = this->many_cnvt(str);
392 if (r.has_value()) return *r; // and here goes converted value
393
394 _settings_error_list.emplace_back(
395 GetEncodedString(STR_CONFIG_ERROR),
396 GetEncodedString(STR_CONFIG_ERROR_INVALID_VALUE, str, this->GetName()));
397 return this->GetDefaultValue();
398}
399
400int32_t ManyOfManySettingDesc::ParseValue(std::string_view str) const
401{
402 auto r = LookupManyOfMany(this->many, str);
403 if (r.has_value()) return *r;
404
405 _settings_error_list.emplace_back(
406 GetEncodedString(STR_CONFIG_ERROR),
407 GetEncodedString(STR_CONFIG_ERROR_INVALID_VALUE, str, this->GetName()));
408 return this->GetDefaultValue();
409}
410
411int32_t BoolSettingDesc::ParseValue(std::string_view str) const
412{
414 if (r.has_value()) return *r;
415
416 _settings_error_list.emplace_back(
417 GetEncodedString(STR_CONFIG_ERROR),
418 GetEncodedString(STR_CONFIG_ERROR_INVALID_VALUE, str, this->GetName()));
419 return this->GetDefaultValue();
420}
421
428{
429 return this->get_title_cb != nullptr ? this->get_title_cb(*this) : this->str;
430}
431
437{
438 return this->get_help_cb != nullptr ? this->get_help_cb(*this) : this->str_help;
439}
440
445std::pair<StringParameter, StringParameter> IntSettingDesc::GetValueParams(int32_t value) const
446{
447 if (this->get_value_params_cb != nullptr) {
448 return this->get_value_params_cb(*this, value);
449 }
450
451 if (this->IsBoolSetting()) {
452 return {value != 0 ? STR_CONFIG_SETTING_ON : STR_CONFIG_SETTING_OFF, {}};
453 }
454
456 auto [min_val, _] = this->GetRange();
457 return {this->str_val - min_val + value, value};
458 }
459
460 return {this->str_val + ((value == 0 && this->flags.Test(SettingFlag::GuiZeroIsSpecial)) ? 1 : 0), value};
461}
462
468{
469 return this->get_def_cb != nullptr ? this->get_def_cb(*this) : this->def;
470}
471
476std::tuple<int32_t, uint32_t> IntSettingDesc::GetRange() const
477{
478 return this->get_range_cb != nullptr ? this->get_range_cb(*this) : std::tuple(this->min, this->max);
479}
480
487void IntSettingDesc::MakeValueValidAndWrite(const void *object, int32_t val) const
488{
489 this->MakeValueValid(val);
490 this->Write(object, val);
491}
492
502void IntSettingDesc::MakeValueValid(int32_t &val) const
503{
504 auto [min_val, max_val] = this->GetRange();
505 /* We need to take special care of the uint32_t type as we receive from the function
506 * a signed integer. While here also bail out on 64-bit settings as those are not
507 * supported. Unsigned 8 and 16-bit variables are safe since they fit into a signed
508 * 32-bit variable
509 * TODO: Support 64-bit settings/variables; requires 64 bit over command protocol! */
510 switch (GetVarMemType(this->save.conv)) {
511 case SLE_VAR_NULL: return;
512 case SLE_VAR_BL:
513 case SLE_VAR_I8:
514 case SLE_VAR_U8:
515 case SLE_VAR_I16:
516 case SLE_VAR_U16:
517 case SLE_VAR_I32: {
518 /* Override the minimum value. No value below this->min, except special value 0 */
519 if (!this->flags.Test(SettingFlag::GuiZeroIsSpecial) || val != 0) {
520 if (!this->flags.Test(SettingFlag::GuiDropdown)) {
521 /* Clamp value-type setting to its valid range */
522 val = Clamp(val, min_val, max_val);
523 } else if (val < min_val || val > static_cast<int32_t>(max_val)) {
524 /* Reset invalid discrete setting (where different values change gameplay) to its default value */
525 val = this->GetDefaultValue();
526 }
527 }
528 break;
529 }
530 case SLE_VAR_U32: {
531 /* Override the minimum value. No value below this->min, except special value 0 */
532 uint32_t uval = static_cast<uint32_t>(val);
533 if (!this->flags.Test(SettingFlag::GuiZeroIsSpecial) || uval != 0) {
534 if (!this->flags.Test(SettingFlag::GuiDropdown)) {
535 /* Clamp value-type setting to its valid range */
536 uval = ClampU(uval, min_val, max_val);
537 } else if (uval < static_cast<uint32_t>(min_val) || uval > max_val) {
538 /* Reset invalid discrete setting to its default value */
539 uval = static_cast<uint32_t>(this->GetDefaultValue());
540 }
541 }
542 val = static_cast<int32_t>(uval);
543 return;
544 }
545 case SLE_VAR_I64:
546 case SLE_VAR_U64:
547 default: NOT_REACHED();
548 }
549}
550
556void IntSettingDesc::Write(const void *object, int32_t val) const
557{
558 void *ptr = GetVariableAddress(object, this->save);
559 WriteValue(ptr, this->save.conv, (int64_t)val);
560}
561
567int32_t IntSettingDesc::Read(const void *object) const
568{
569 void *ptr = GetVariableAddress(object, this->save);
570 return (int32_t)ReadValue(ptr, this->save.conv);
571}
572
580void StringSettingDesc::MakeValueValid(std::string &str) const
581{
582 if (this->max_length == 0 || str.size() < this->max_length) return;
583
584 /* In case a maximum length is imposed by the setting, the length
585 * includes the '\0' termination for network transfer purposes.
586 * Also ensure the string is valid after chopping of some bytes. */
587 str.erase(this->max_length - 1, std::string::npos);
588 StrMakeValidInPlace(str, {});
589}
590
596void StringSettingDesc::Write(const void *object, std::string_view str) const
597{
598 reinterpret_cast<std::string *>(GetVariableAddress(object, this->save))->assign(str);
599}
600
606const std::string &StringSettingDesc::Read(const void *object) const
607{
608 return *reinterpret_cast<std::string *>(GetVariableAddress(object, this->save));
609}
610
620static void IniLoadSettings(IniFile &ini, const SettingTable &settings_table, std::string_view grpname, void *object, bool only_startup)
621{
622 const IniGroup *group;
623 const IniGroup *group_def = ini.GetGroup(grpname);
624
625 for (auto &desc : settings_table) {
626 const SettingDesc *sd = GetSettingDesc(desc);
628 if (sd->startup != only_startup) continue;
629
630 /* For settings.xx.yy load the settings from [xx] yy = ? */
631 std::string s{ sd->GetName() };
632 auto sc = s.find('.');
633 if (sc != std::string::npos) {
634 group = ini.GetGroup(s.substr(0, sc));
635 if (group == nullptr) group = group_def;
636 s = s.substr(sc + 1);
637 } else {
638 group = group_def;
639 }
640
641 const IniItem *item = nullptr;
642 if (group != nullptr) item = group->GetItem(s);
643 if (item == nullptr && group != group_def && group_def != nullptr) {
644 /* For settings.xx.yy load the settings from [settings] yy = ? in case the previous
645 * did not exist (e.g. loading old config files with a [settings] section */
646 item = group_def->GetItem(s);
647 }
648 if (item == nullptr) {
649 /* For settings.xx.zz.yy load the settings from [zz] yy = ? in case the previous
650 * did not exist (e.g. loading old config files with a [yapf] section */
651 sc = s.find('.');
652 if (sc != std::string::npos) {
653 if (group = ini.GetGroup(s.substr(0, sc)); group != nullptr) item = group->GetItem(s.substr(sc + 1));
654 }
655 }
656
657 sd->ParseValue(item, object);
658 }
659}
660
661void IntSettingDesc::ParseValue(const IniItem *item, void *object) const
662{
663 int32_t val = (item != nullptr && item->value.has_value()) ? this->ParseValue(*item->value) : this->GetDefaultValue();
664 this->MakeValueValidAndWrite(object, val);
665}
666
667void StringSettingDesc::ParseValue(const IniItem *item, void *object) const
668{
669 std::string str{(item == nullptr) ? this->def : item->value.value_or("")};
670 this->MakeValueValid(str);
671 this->Write(object, str);
672}
673
674void ListSettingDesc::ParseValue(const IniItem *item, void *object) const
675{
676 std::optional<std::string_view> str;
677 if (item != nullptr) {
678 str = item->value;
679 } else if (!this->def.empty()) {
680 str = this->def;
681 }
682 void *ptr = GetVariableAddress(object, this->save);
683 if (!LoadIntList(str, ptr, this->save.length, GetVarMemType(this->save.conv))) {
684 _settings_error_list.emplace_back(
685 GetEncodedString(STR_CONFIG_ERROR),
686 GetEncodedString(STR_CONFIG_ERROR_ARRAY, this->GetName()));
687
688 /* Use default */
689 LoadIntList(this->def, ptr, this->save.length, GetVarMemType(this->save.conv));
690 }
691}
692
705static void IniSaveSettings(IniFile &ini, const SettingTable &settings_table, std::string_view grpname, void *object, bool)
706{
707 IniGroup *group_def = nullptr, *group;
708
709 for (auto &desc : settings_table) {
710 const SettingDesc *sd = GetSettingDesc(desc);
711 /* If the setting is not saved to the configuration
712 * file, just continue with the next setting */
714 if (sd->flags.Test(SettingFlag::NotInConfig)) continue;
715
716 /* XXX - wtf is this?? (group override?) */
717 std::string s{ sd->GetName() };
718 auto sc = s.find('.');
719 if (sc != std::string::npos) {
720 group = &ini.GetOrCreateGroup(s.substr(0, sc));
721 s = s.substr(sc + 1);
722 } else {
723 if (group_def == nullptr) group_def = &ini.GetOrCreateGroup(grpname);
724 group = group_def;
725 }
726
727 IniItem &item = group->GetOrCreateItem(s);
728
729 if (!item.value.has_value() || !sd->IsSameValue(&item, object)) {
730 /* The value is different, that means we have to write it to the ini */
731 item.value.emplace(sd->FormatValue(object));
732 }
733 }
734}
735
736std::string IntSettingDesc::FormatValue(const void *object) const
737{
738 int64_t i;
739 if (IsSignedVarMemType(this->save.conv)) {
740 i = this->Read(object);
741 } else {
742 i = (uint32_t)this->Read(object);
743 }
744 return fmt::format("{}", i);
745}
746
747std::string BoolSettingDesc::FormatValue(const void *object) const
748{
749 bool val = this->Read(object) != 0;
750 return val ? "true" : "false";
751}
752
753bool IntSettingDesc::IsSameValue(const IniItem *item, void *object) const
754{
755 int32_t item_value = static_cast<int32_t>(this->ParseValue(*item->value));
756 int32_t object_value = this->Read(object);
757 return item_value == object_value;
758}
759
760bool IntSettingDesc::IsDefaultValue(void *object) const
761{
762 int32_t object_value = this->Read(object);
763 return this->GetDefaultValue() == object_value;
764}
765
766void IntSettingDesc::ResetToDefault(void *object) const
767{
768 this->Write(object, this->GetDefaultValue());
769}
770
771std::string StringSettingDesc::FormatValue(const void *object) const
772{
773 const std::string &str = this->Read(object);
774 switch (GetVarMemType(this->save.conv)) {
775 case SLE_VAR_STR: return str;
776
777 case SLE_VAR_STRQ:
778 if (str.empty()) {
779 return str;
780 }
781 return fmt::format("\"{}\"", str);
782
783 default: NOT_REACHED();
784 }
785}
786
787bool StringSettingDesc::IsSameValue(const IniItem *item, void *object) const
788{
789 /* The ini parsing removes the quotes, which are needed to retain the spaces in STRQs,
790 * so those values are always different in the parsed ini item than they should be. */
791 if (GetVarMemType(this->save.conv) == SLE_VAR_STRQ) return false;
792
793 const std::string &str = this->Read(object);
794 return item->value->compare(str) == 0;
795}
796
797bool StringSettingDesc::IsDefaultValue(void *object) const
798{
799 const std::string &str = this->Read(object);
800 return this->def == str;
801}
802
803void StringSettingDesc::ResetToDefault(void *object) const
804{
805 this->Write(object, this->def);
806}
807
808bool ListSettingDesc::IsSameValue(const IniItem *, void *) const
809{
810 /* Checking for equality is way more expensive than just writing the value. */
811 return false;
812}
813
815{
816 /* Defaults of lists are often complicated, and hard to compare. */
817 return false;
818}
819
821{
822 /* Resetting a list to default is not supported. */
823 NOT_REACHED();
824}
825
835static void IniLoadSettingList(IniFile &ini, std::string_view grpname, StringList &list)
836{
837 const IniGroup *group = ini.GetGroup(grpname);
838
839 if (group == nullptr) return;
840
841 list.clear();
842
843 for (const IniItem &item : group->items) {
844 if (!item.name.empty()) list.push_back(item.name);
845 }
846}
847
857static void IniSaveSettingList(IniFile &ini, std::string_view grpname, StringList &list)
858{
859 IniGroup &group = ini.GetOrCreateGroup(grpname);
860 group.Clear();
861
862 for (const auto &iter : list) {
863 group.GetOrCreateItem(iter).SetValue("");
864 }
865}
866
873void IniLoadWindowSettings(IniFile &ini, std::string_view grpname, WindowDesc *desc)
874{
875 IniLoadSettings(ini, _window_settings, grpname, desc, false);
876}
877
884void IniSaveWindowSettings(IniFile &ini, std::string_view grpname, WindowDesc *desc)
885{
886 IniSaveSettings(ini, _window_settings, grpname, desc, false);
887}
888
894bool SettingDesc::IsEditable(bool do_command) const
895{
896 if (!do_command && !this->flags.Test(SettingFlag::NoNetworkSync) && _networking && !_network_server && !this->flags.Test(SettingFlag::PerCompany)) return false;
897 if (do_command && this->flags.Test(SettingFlag::NoNetworkSync)) return false;
898 if (this->flags.Test(SettingFlag::NetworkOnly) && !_networking && _game_mode != GM_MENU) return false;
899 if (this->flags.Test(SettingFlag::NoNetwork) && _networking) return false;
901 (_game_mode == GM_NORMAL ||
902 (_game_mode == GM_EDITOR && !this->flags.Test(SettingFlag::SceneditToo)))) return false;
903 if (this->flags.Test(SettingFlag::SceneditOnly) && _game_mode != GM_EDITOR) return false;
904 return true;
905}
906
916
922{
923 assert(this->IsIntSetting());
924 return static_cast<const IntSettingDesc *>(this);
925}
926
932{
933 assert(this->IsStringSetting());
934 return static_cast<const StringSettingDesc *>(this);
935}
936
938void HandleOldDiffCustom(bool savegame);
939
940
950
951static void AILoadConfig(const IniFile &ini, std::string_view grpname)
952{
953 const IniGroup *group = ini.GetGroup(grpname);
954
955 /* Clean any configured AI */
956 for (CompanyID c = CompanyID::Begin(); c < MAX_COMPANIES; ++c) {
958 }
959
960 /* If no group exists, return */
961 if (group == nullptr) return;
962
963 CompanyID c = CompanyID::Begin();
964 for (const IniItem &item : group->items) {
966
967 config->Change(item.name);
968 if (!config->HasScript()) {
969 if (item.name != "none") {
970 Debug(script, 0, "The AI by the name '{}' was no longer found, and removed from the list.", item.name);
971 continue;
972 }
973 }
974 if (item.value.has_value()) config->StringToSettings(*item.value);
975 ++c;
976 if (c >= MAX_COMPANIES) break;
977 }
978}
979
980static void GameLoadConfig(const IniFile &ini, std::string_view grpname)
981{
982 const IniGroup *group = ini.GetGroup(grpname);
983
984 /* Clean any configured GameScript */
986
987 /* If no group exists, return */
988 if (group == nullptr || group->items.empty()) return;
989
990 const IniItem &item = group->items.front();
991
993
994 config->Change(item.name);
995 if (!config->HasScript()) {
996 if (item.name != "none") {
997 Debug(script, 0, "The GameScript by the name '{}' was no longer found, and removed from the list.", item.name);
998 return;
999 }
1000 }
1001 if (item.value.has_value()) config->StringToSettings(*item.value);
1002}
1003
1008{
1009 if (const IniGroup *group = ini.GetGroup("misc"); group != nullptr) {
1010 /* Load old setting first. */
1011 if (const IniItem *item = group->GetItem("graphicsset"); item != nullptr && item->value) BaseGraphics::ini_data.name = *item->value;
1012 }
1013
1014 if (const IniGroup *group = ini.GetGroup("graphicsset"); group != nullptr) {
1015 /* Load new settings. */
1016 if (const IniItem *item = group->GetItem("name"); item != nullptr && item->value) BaseGraphics::ini_data.name = *item->value;
1017
1018 if (const IniItem *item = group->GetItem("shortname"); item != nullptr && item->value && item->value->size() == 8) {
1019 auto val = ParseInteger<uint32_t>(*item->value, 16);
1020 if (val.has_value()) {
1021 BaseGraphics::ini_data.shortname = std::byteswap<uint32_t>(*val);
1022 } else {
1023 ShowErrorMessage(GetEncodedString(STR_CONFIG_ERROR),
1024 GetEncodedString(STR_CONFIG_ERROR_INVALID_VALUE, *item->value, BaseGraphics::ini_data.name),
1025 WL_CRITICAL);
1026 }
1027 }
1028
1029 if (const IniItem *item = group->GetItem("extra_version"); item != nullptr && item->value) {
1030 auto val = ParseInteger<uint32_t>(*item->value);
1031 if (val.has_value()) {
1032 BaseGraphics::ini_data.extra_version = *val;
1033 } else {
1034 ShowErrorMessage(GetEncodedString(STR_CONFIG_ERROR),
1035 GetEncodedString(STR_CONFIG_ERROR_INVALID_VALUE, *item->value, BaseGraphics::ini_data.name),
1036 WL_CRITICAL);
1037 }
1038 }
1039
1040 if (const IniItem *item = group->GetItem("extra_params"); item != nullptr && item->value) {
1041 auto params = ParseIntList(*item->value);
1042 if (params.has_value()) {
1043 BaseGraphics::ini_data.extra_params = params.value();
1044 } else {
1045 ShowErrorMessage(GetEncodedString(STR_CONFIG_ERROR),
1046 GetEncodedString(STR_CONFIG_ERROR_ARRAY, BaseGraphics::ini_data.name),
1047 WL_CRITICAL);
1048 }
1049 }
1050 }
1051}
1052
1059static GRFConfigList GRFLoadConfig(const IniFile &ini, std::string_view grpname, bool is_static)
1060{
1061 const IniGroup *group = ini.GetGroup(grpname);
1062 GRFConfigList list;
1063
1064 if (group == nullptr) return list;
1065
1066 uint num_grfs = 0;
1067 for (const IniItem &item : group->items) {
1068 std::unique_ptr<GRFConfig> c{};
1069
1070 std::array<uint8_t, 4> grfid_buf;
1071 MD5Hash md5sum;
1072 std::string_view item_name = item.name;
1073 bool has_md5sum = false;
1074
1075 /* Try reading "<grfid>|" and on success, "<md5sum>|". */
1076 auto grfid_pos = item_name.find("|");
1077 if (grfid_pos != std::string_view::npos) {
1078 std::string_view grfid_str = item_name.substr(0, grfid_pos);
1079
1080 if (ConvertHexToBytes(grfid_str, grfid_buf)) {
1081 item_name = item_name.substr(grfid_pos + 1);
1082
1083 auto md5sum_pos = item_name.find("|");
1084 if (md5sum_pos != std::string_view::npos) {
1085 std::string_view md5sum_str = item_name.substr(0, md5sum_pos);
1086
1087 has_md5sum = ConvertHexToBytes(md5sum_str, md5sum);
1088 if (has_md5sum) item_name = item_name.substr(md5sum_pos + 1);
1089 }
1090
1091 uint32_t grfid = grfid_buf[0] | (grfid_buf[1] << 8) | (grfid_buf[2] << 16) | (grfid_buf[3] << 24);
1092 if (has_md5sum) {
1093 const GRFConfig *s = FindGRFConfig(grfid, FGCM_EXACT, &md5sum);
1094 if (s != nullptr) c = std::make_unique<GRFConfig>(*s);
1095 }
1096 if (c == nullptr && !FioCheckFileExists(std::string(item_name), NEWGRF_DIR)) {
1097 const GRFConfig *s = FindGRFConfig(grfid, FGCM_NEWEST_VALID);
1098 if (s != nullptr) c = std::make_unique<GRFConfig>(*s);
1099 }
1100 }
1101 }
1102 std::string filename = std::string(item_name);
1103
1104 if (c == nullptr) c = std::make_unique<GRFConfig>(filename);
1105
1106 /* Parse parameters */
1107 if (item.value.has_value() && !item.value->empty()) {
1108 auto params = ParseIntList(*item.value);
1109 if (params.has_value()) {
1110 c->SetParams(params.value());
1111 } else {
1112 ShowErrorMessage(GetEncodedString(STR_CONFIG_ERROR),
1113 GetEncodedString(STR_CONFIG_ERROR_ARRAY, filename),
1114 WL_CRITICAL);
1115 }
1116 }
1117
1118 /* Check if item is valid */
1119 if (!FillGRFDetails(*c, is_static) || c->flags.Test(GRFConfigFlag::Invalid)) {
1120 StringID reason;
1121 if (c->status == GCS_NOT_FOUND) {
1122 reason = STR_CONFIG_ERROR_INVALID_GRF_NOT_FOUND;
1123 } else if (c->flags.Test(GRFConfigFlag::Unsafe)) {
1124 reason = STR_CONFIG_ERROR_INVALID_GRF_UNSAFE;
1125 } else if (c->flags.Test(GRFConfigFlag::System)) {
1126 reason = STR_CONFIG_ERROR_INVALID_GRF_SYSTEM;
1127 } else if (c->flags.Test(GRFConfigFlag::Invalid)) {
1128 reason = STR_CONFIG_ERROR_INVALID_GRF_INCOMPATIBLE;
1129 } else {
1130 reason = STR_CONFIG_ERROR_INVALID_GRF_UNKNOWN;
1131 }
1132
1133 ShowErrorMessage(GetEncodedString(STR_CONFIG_ERROR),
1134 GetEncodedString(STR_CONFIG_ERROR_INVALID_GRF, filename.empty() ? item.name : filename, reason),
1135 WL_CRITICAL);
1136 continue;
1137 }
1138
1139 /* Check for duplicate GRFID (will also check for duplicate filenames) */
1140 auto found = std::ranges::find_if(list, [&c](const auto &gc) { return gc->ident.grfid == c->ident.grfid; });
1141 if (found != std::end(list)) {
1142 ShowErrorMessage(GetEncodedString(STR_CONFIG_ERROR),
1143 GetEncodedString(STR_CONFIG_ERROR_DUPLICATE_GRFID, c->filename, (*found)->filename),
1144 WL_CRITICAL);
1145 continue;
1146 }
1147
1148 if (is_static) {
1149 /* Mark file as static to avoid saving in savegame. */
1150 c->flags.Set(GRFConfigFlag::Static);
1151 } else if (++num_grfs > NETWORK_MAX_GRF_COUNT) {
1152 /* Check we will not load more non-static NewGRFs than allowed. This could trigger issues for game servers. */
1153 ShowErrorMessage(GetEncodedString(STR_CONFIG_ERROR),
1154 GetEncodedString(STR_NEWGRF_ERROR_TOO_MANY_NEWGRFS_LOADED), WL_CRITICAL);
1155 break;
1156 }
1157
1158 /* Add item to list */
1159 list.push_back(std::move(c));
1160 }
1161
1162 return list;
1163}
1164
1165static IniFileVersion LoadVersionFromConfig(const IniFile &ini)
1166{
1167 const IniGroup *group = ini.GetGroup("version");
1168 if (group == nullptr) return IFV_0;
1169
1170 auto version_number = group->GetItem("ini_version");
1171 /* Older ini-file versions don't have this key yet. */
1172 if (version_number == nullptr || !version_number->value.has_value()) return IFV_0;
1173
1174 uint32_t version = 0;
1175 std::from_chars(version_number->value->data(), version_number->value->data() + version_number->value->size(), version);
1176
1177 return static_cast<IniFileVersion>(version);
1178}
1179
1180static void AISaveConfig(IniFile &ini, std::string_view grpname)
1181{
1182 IniGroup &group = ini.GetOrCreateGroup(grpname);
1183 group.Clear();
1184
1185 for (CompanyID c = CompanyID::Begin(); c < MAX_COMPANIES; ++c) {
1187 std::string name;
1188 std::string value = config->SettingsToString();
1189
1190 if (config->HasScript()) {
1191 name = config->GetName();
1192 } else {
1193 name = "none";
1194 }
1195
1196 group.CreateItem(name).SetValue(value);
1197 }
1198}
1199
1200static void GameSaveConfig(IniFile &ini, std::string_view grpname)
1201{
1202 IniGroup &group = ini.GetOrCreateGroup(grpname);
1203 group.Clear();
1204
1206 std::string name;
1207 std::string value = config->SettingsToString();
1208
1209 if (config->HasScript()) {
1210 name = config->GetName();
1211 } else {
1212 name = "none";
1213 }
1214
1215 group.CreateItem(name).SetValue(value);
1216}
1217
1223{
1224 IniGroup &group = ini.GetOrCreateGroup("version");
1225 group.GetOrCreateItem("version_string").SetValue(_openttd_revision);
1226 group.GetOrCreateItem("version_number").SetValue(fmt::format("{:08X}", _openttd_newgrf_version));
1227 group.GetOrCreateItem("ini_version").SetValue(fmt::format("{}", INIFILE_VERSION));
1228}
1229
1234{
1235 const GraphicsSet *used_set = BaseGraphics::GetUsedSet();
1236 if (used_set == nullptr) return;
1237
1238 IniGroup &group = ini.GetOrCreateGroup("graphicsset");
1239 group.Clear();
1240
1241 group.GetOrCreateItem("name").SetValue(used_set->name);
1242 group.GetOrCreateItem("shortname").SetValue(fmt::format("{:08X}", std::byteswap(used_set->shortname)));
1243
1244 const GRFConfig *extra_cfg = used_set->GetExtraConfig();
1245 if (extra_cfg != nullptr && !extra_cfg->param.empty()) {
1246 group.GetOrCreateItem("extra_version").SetValue(fmt::format("{}", extra_cfg->version));
1247 group.GetOrCreateItem("extra_params").SetValue(GRFBuildParamList(*extra_cfg));
1248 }
1249}
1250
1251/* Save a GRF configuration to the given group name */
1252static void GRFSaveConfig(IniFile &ini, std::string_view grpname, const GRFConfigList &list)
1253{
1254 IniGroup &group = ini.GetOrCreateGroup(grpname);
1255 group.Clear();
1256
1257 for (const auto &c : list) {
1258 std::string key = fmt::format("{:08X}|{}|{}", std::byteswap(c->ident.grfid),
1259 FormatArrayAsHex(c->ident.md5sum), c->filename);
1261 }
1262}
1263
1264/* Common handler for saving/loading variables to the configuration file */
1265static void HandleSettingDescs(IniFile &generic_ini, IniFile &private_ini, IniFile &secrets_ini, SettingDescProc *proc, SettingDescProcList *proc_list, bool only_startup = false)
1266{
1267 proc(generic_ini, _misc_settings, "misc", nullptr, only_startup);
1268#if defined(_WIN32) && !defined(DEDICATED)
1269 proc(generic_ini, _win32_settings, "win32", nullptr, only_startup);
1270#endif /* _WIN32 */
1271
1272 /* The name "patches" is a fallback, as every setting should sets its own group. */
1273
1274 for (auto &table : GenericSettingTables()) {
1275 proc(generic_ini, table, "patches", &_settings_newgame, only_startup);
1276 }
1277 for (auto &table : PrivateSettingTables()) {
1278 proc(private_ini, table, "patches", &_settings_newgame, only_startup);
1279 }
1280 for (auto &table : SecretSettingTables()) {
1281 proc(secrets_ini, table, "patches", &_settings_newgame, only_startup);
1282 }
1283
1284 proc(generic_ini, _currency_settings, "currency", &GetCustomCurrency(), only_startup);
1285 proc(generic_ini, _company_settings, "company", &_settings_client.company, only_startup);
1286
1287 if (!only_startup) {
1288 proc_list(private_ini, "server_bind_addresses", _network_bind_list);
1289 proc_list(private_ini, "servers", _network_host_list);
1290 proc_list(private_ini, "bans", _network_ban_list);
1291 proc_list(private_ini, "server_authorized_keys", _settings_client.network.server_authorized_keys);
1292 proc_list(private_ini, "rcon_authorized_keys", _settings_client.network.rcon_authorized_keys);
1293 proc_list(private_ini, "admin_authorized_keys", _settings_client.network.admin_authorized_keys);
1294 }
1295}
1296
1306static void RemoveEntriesFromIni(IniFile &ini, const SettingTable &table)
1307{
1308 for (auto &desc : table) {
1309 const SettingDesc *sd = GetSettingDesc(desc);
1310
1311 /* For settings.xx.yy load the settings from [xx] yy = ? */
1312 std::string s{ sd->GetName() };
1313 auto sc = s.find('.');
1314 if (sc == std::string::npos) continue;
1315
1316 IniGroup *group = ini.GetGroup(s.substr(0, sc));
1317 if (group == nullptr) continue;
1318 s = s.substr(sc + 1);
1319
1320 group->RemoveItem(s);
1321 }
1322}
1323
1347bool IsConversionNeeded(const ConfigIniFile &ini, const std::string &group, const std::string &old_var, const std::string &new_var, const IniItem **old_item)
1348{
1349 *old_item = nullptr;
1350
1351 const IniGroup *igroup = ini.GetGroup(group);
1352 /* If the group doesn't exist, there is nothing to convert. */
1353 if (igroup == nullptr) return false;
1354
1355 const IniItem *tmp_old_item = igroup->GetItem(old_var);
1356 const IniItem *new_item = igroup->GetItem(new_var);
1357
1358 /* If the old item doesn't exist, there is nothing to convert. */
1359 if (tmp_old_item == nullptr) return false;
1360
1361 /* If the new item exists, it means conversion was already done. We only
1362 * do the conversion the first time, and after that these settings are
1363 * independent. This allows users to freely change between older and
1364 * newer clients without breaking anything. */
1365 if (new_item != nullptr) return false;
1366
1367 *old_item = tmp_old_item;
1368 return true;
1369}
1370
1375void LoadFromConfig(bool startup)
1376{
1377 ConfigIniFile generic_ini(_config_file);
1378 ConfigIniFile private_ini(_private_file);
1379 ConfigIniFile secrets_ini(_secrets_file);
1380 ConfigIniFile favs_ini(_favs_file);
1381
1382 if (!startup) ResetCurrencies(false); // Initialize the array of currencies, without preserving the custom one
1383
1384 IniFileVersion generic_version = LoadVersionFromConfig(generic_ini);
1385
1386 if (startup) {
1387 GraphicsSetLoadConfig(generic_ini);
1388 }
1389
1390 /* Before the split of private/secrets, we have to look in the generic for these settings. */
1391 if (generic_version < IFV_PRIVATE_SECRETS) {
1392 HandleSettingDescs(generic_ini, generic_ini, generic_ini, IniLoadSettings, IniLoadSettingList, startup);
1393 } else {
1394 HandleSettingDescs(generic_ini, private_ini, secrets_ini, IniLoadSettings, IniLoadSettingList, startup);
1395 }
1396
1397 /* Load basic settings only during bootstrap, load other settings not during bootstrap */
1398 if (!startup) {
1399 if (generic_version < IFV_LINKGRAPH_SECONDS) {
1402 }
1403
1404 /* Move use_relay_service from generic_ini to private_ini. */
1405 if (generic_version < IFV_NETWORK_PRIVATE_SETTINGS) {
1406 const IniGroup *network = generic_ini.GetGroup("network");
1407 if (network != nullptr) {
1408 const IniItem *use_relay_service = network->GetItem("use_relay_service");
1409 if (use_relay_service != nullptr) {
1410 if (use_relay_service->value == "never") {
1411 _settings_client.network.use_relay_service = UseRelayService::URS_NEVER;
1412 } else if (use_relay_service->value == "ask") {
1413 _settings_client.network.use_relay_service = UseRelayService::URS_ASK;
1414 } else if (use_relay_service->value == "allow") {
1415 _settings_client.network.use_relay_service = UseRelayService::URS_ALLOW;
1416 }
1417 }
1418 }
1419 }
1420
1421 const IniItem *old_item;
1422
1423 if (generic_version < IFV_GAME_TYPE && IsConversionNeeded(generic_ini, "network", "server_advertise", "server_game_type", &old_item)) {
1424 auto old_value = BoolSettingDesc::ParseSingleValue(*old_item->value);
1425 _settings_client.network.server_game_type = old_value.value_or(false) ? SERVER_GAME_TYPE_PUBLIC : SERVER_GAME_TYPE_LOCAL;
1426 }
1427
1428 if (generic_version < IFV_AUTOSAVE_RENAME && IsConversionNeeded(generic_ini, "gui", "autosave", "autosave_interval", &old_item)) {
1429 static constexpr std::initializer_list<std::string_view> _old_autosave_interval{"off"sv, "monthly"sv, "quarterly"sv, "half year"sv, "yearly"sv};
1430 auto old_value = OneOfManySettingDesc::ParseSingleValue(*old_item->value, _old_autosave_interval).value_or(-1);
1431
1432 switch (old_value) {
1433 case 0: _settings_client.gui.autosave_interval = 0; break;
1434 case 1: _settings_client.gui.autosave_interval = 10; break;
1435 case 2: _settings_client.gui.autosave_interval = 30; break;
1436 case 3: _settings_client.gui.autosave_interval = 60; break;
1437 case 4: _settings_client.gui.autosave_interval = 120; break;
1438 default: break;
1439 }
1440 }
1441
1442 /* Persist the right click close option from older versions. */
1443 if (generic_version < IFV_RIGHT_CLICK_CLOSE && IsConversionNeeded(generic_ini, "gui", "right_mouse_wnd_close", "right_click_wnd_close", &old_item)) {
1444 auto old_value = BoolSettingDesc::ParseSingleValue(*old_item->value);
1445 _settings_client.gui.right_click_wnd_close = old_value.value_or(false) ? RCC_YES : RCC_NO;
1446 }
1447
1448 _grfconfig_newgame = GRFLoadConfig(generic_ini, "newgrf", false);
1449 _grfconfig_static = GRFLoadConfig(generic_ini, "newgrf-static", true);
1450 AILoadConfig(generic_ini, "ai_players");
1451 GameLoadConfig(generic_ini, "game_scripts");
1452 PickerLoadConfig(favs_ini);
1453 BadgeClassLoadConfig(favs_ini);
1454
1456 IniLoadSettings(generic_ini, _old_gameopt_settings, "gameopt", &_settings_newgame, false);
1457 HandleOldDiffCustom(false);
1458
1461
1462 /* Display scheduled errors */
1464 if (FindWindowById(WC_ERRMSG, 0) == nullptr) ShowFirstError();
1465 }
1466}
1467
1470{
1471 ConfigIniFile generic_ini(_config_file);
1472 ConfigIniFile private_ini(_private_file);
1473 ConfigIniFile secrets_ini(_secrets_file);
1474 ConfigIniFile favs_ini(_favs_file);
1475
1476 IniFileVersion generic_version = LoadVersionFromConfig(generic_ini);
1477
1478 /* If we newly create the private/secrets file, add a dummy group on top
1479 * just so we can add a comment before it (that is how IniFile works).
1480 * This to explain what the file is about. After doing it once, never touch
1481 * it again, as otherwise we might be reverting user changes. */
1482 if (IniGroup *group = private_ini.GetGroup("private"); group != nullptr) group->comment = "; This file possibly contains private information which can identify you as person.\n";
1483 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";
1484
1485 if (generic_version == IFV_0) {
1486 /* Remove some obsolete groups. These have all been loaded into other groups. */
1487 generic_ini.RemoveGroup("patches");
1488 generic_ini.RemoveGroup("yapf");
1489 generic_ini.RemoveGroup("gameopt");
1490
1491 /* Remove all settings from the generic ini that are now in the private ini. */
1492 generic_ini.RemoveGroup("server_bind_addresses");
1493 generic_ini.RemoveGroup("servers");
1494 generic_ini.RemoveGroup("bans");
1495 for (auto &table : PrivateSettingTables()) {
1496 RemoveEntriesFromIni(generic_ini, table);
1497 }
1498
1499 /* Remove all settings from the generic ini that are now in the secrets ini. */
1500 for (auto &table : SecretSettingTables()) {
1501 RemoveEntriesFromIni(generic_ini, table);
1502 }
1503 }
1504
1505 if (generic_version < IFV_REMOVE_GENERATION_SEED) {
1506 IniGroup *game_creation = generic_ini.GetGroup("game_creation");
1507 if (game_creation != nullptr) {
1508 game_creation->RemoveItem("generation_seed");
1509 }
1510 }
1511
1512 /* These variables are migrated from generic ini to private ini now. */
1513 if (generic_version < IFV_NETWORK_PRIVATE_SETTINGS) {
1514 IniGroup *network = generic_ini.GetGroup("network");
1515 if (network != nullptr) {
1516 network->RemoveItem("use_relay_service");
1517 }
1518 }
1519
1520 HandleSettingDescs(generic_ini, private_ini, secrets_ini, IniSaveSettings, IniSaveSettingList);
1521 GraphicsSetSaveConfig(generic_ini);
1522 GRFSaveConfig(generic_ini, "newgrf", _grfconfig_newgame);
1523 GRFSaveConfig(generic_ini, "newgrf-static", _grfconfig_static);
1524 AISaveConfig(generic_ini, "ai_players");
1525 GameSaveConfig(generic_ini, "game_scripts");
1526 PickerSaveConfig(favs_ini);
1527 BadgeClassSaveConfig(favs_ini);
1528
1529 SaveVersionInConfig(generic_ini);
1530 SaveVersionInConfig(private_ini);
1531 SaveVersionInConfig(secrets_ini);
1532 SaveVersionInConfig(favs_ini);
1533
1534 generic_ini.SaveToDisk(_config_file);
1535 private_ini.SaveToDisk(_private_file);
1536 secrets_ini.SaveToDisk(_secrets_file);
1537 favs_ini.SaveToDisk(_favs_file);
1538}
1539
1545{
1546 StringList list;
1547
1549 for (const IniGroup &group : ini.groups) {
1550 if (group.name.compare(0, 7, "preset-") == 0) {
1551 list.push_back(group.name.substr(7));
1552 }
1553 }
1554
1555 return list;
1556}
1557
1564GRFConfigList LoadGRFPresetFromConfig(std::string_view config_name)
1565{
1566 std::string section("preset-");
1567 section += config_name;
1568
1570 GRFConfigList config = GRFLoadConfig(ini, section, false);
1571
1572 return config;
1573}
1574
1581void SaveGRFPresetToConfig(std::string_view config_name, GRFConfigList &config)
1582{
1583 std::string section("preset-");
1584 section += config_name;
1585
1587 GRFSaveConfig(ini, section, config);
1589}
1590
1595void DeleteGRFPresetFromConfig(std::string_view config_name)
1596{
1597 std::string section("preset-");
1598 section += config_name;
1599
1601 ini.RemoveGroup(section);
1603}
1604
1611void IntSettingDesc::ChangeValue(const void *object, int32_t newval) const
1612{
1613 int32_t oldval = this->Read(object);
1614 this->MakeValueValid(newval);
1615 if (this->pre_check != nullptr && !this->pre_check(newval)) return;
1616 if (oldval == newval) return;
1617
1618 this->Write(object, newval);
1619 if (this->post_callback != nullptr) this->post_callback(newval);
1620
1621 if (this->flags.Test(SettingFlag::NoNetwork) || this->flags.Test(SettingFlag::Sandbox)) {
1623 _gamelog.Setting(this->GetName(), oldval, newval);
1625 }
1626
1629
1630 if (_save_config) SaveToConfig();
1631}
1632
1640static const SettingDesc *GetSettingFromName(std::string_view name, const SettingTable &settings)
1641{
1642 /* First check all full names */
1643 for (auto &desc : settings) {
1644 const SettingDesc *sd = GetSettingDesc(desc);
1645 if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue;
1646 if (sd->GetName() == name) return sd;
1647 }
1648
1649 /* Then check the shortcut variant of the name. */
1650 std::string short_name_suffix = std::string{ "." }.append(name);
1651 for (auto &desc : settings) {
1652 const SettingDesc *sd = GetSettingDesc(desc);
1653 if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue;
1654 if (sd->GetName().ends_with(short_name_suffix)) return sd;
1655 }
1656
1657 return nullptr;
1658}
1659
1665void GetSaveLoadFromSettingTable(SettingTable settings, std::vector<SaveLoad> &saveloads)
1666{
1667 for (auto &desc : settings) {
1668 const SettingDesc *sd = GetSettingDesc(desc);
1669 if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue;
1670 saveloads.push_back(sd->save);
1671 }
1672}
1673
1679{
1680 static const SettingTable saveload_settings_tables[] = {
1681 _difficulty_settings,
1682 _economy_settings,
1683 _game_settings,
1684 _linkgraph_settings,
1685 _locale_settings,
1686 _pathfinding_settings,
1687 _script_settings,
1688 _world_settings,
1689 };
1690 static std::vector<SettingVariant> settings_table;
1691
1692 if (settings_table.empty()) {
1693 for (auto &saveload_settings_table : saveload_settings_tables) {
1694 for (auto &saveload_setting : saveload_settings_table) {
1695 settings_table.push_back(saveload_setting);
1696 }
1697 }
1698 }
1699
1700 return settings_table;
1701}
1702
1709static const SettingDesc *GetCompanySettingFromName(std::string_view name)
1710{
1711 static const std::string_view company_prefix = "company.";
1712 if (name.starts_with(company_prefix)) name.remove_prefix(company_prefix.size());
1713 return GetSettingFromName(name, _company_settings);
1714}
1715
1722const SettingDesc *GetSettingFromName(std::string_view name)
1723{
1724 for (auto &table : GenericSettingTables()) {
1725 auto sd = GetSettingFromName(name, table);
1726 if (sd != nullptr) return sd;
1727 }
1728 for (auto &table : PrivateSettingTables()) {
1729 auto sd = GetSettingFromName(name, table);
1730 if (sd != nullptr) return sd;
1731 }
1732 for (auto &table : SecretSettingTables()) {
1733 auto sd = GetSettingFromName(name, table);
1734 if (sd != nullptr) return sd;
1735 }
1736
1737 return GetCompanySettingFromName(name);
1738}
1739
1745std::vector<const SettingDesc *> GetFilteredSettingCollection(std::function<bool(const SettingDesc &desc)> func)
1746{
1747 std::vector<const SettingDesc *> collection;
1748
1749 for (const auto &table : GenericSettingTables()) {
1750 for (const auto &desc : table) {
1751 const auto sd = GetSettingDesc(desc);
1752 if (!func(*sd)) continue;
1753
1754 collection.push_back(sd);
1755 }
1756 }
1757
1758 return collection;
1759}
1760
1770CommandCost CmdChangeSetting(DoCommandFlags flags, const std::string &name, int32_t value)
1771{
1772 if (name.empty()) return CMD_ERROR;
1773 const SettingDesc *sd = GetSettingFromName(name);
1774
1775 if (sd == nullptr) return CMD_ERROR;
1777 if (!sd->IsIntSetting()) return CMD_ERROR;
1778
1779 if (!sd->IsEditable(true)) return CMD_ERROR;
1780
1781 if (flags.Test(DoCommandFlag::Execute)) {
1782 sd->AsIntSetting()->ChangeValue(&GetGameSettings(), value);
1783 }
1784
1785 return CommandCost();
1786}
1787
1796CommandCost CmdChangeCompanySetting(DoCommandFlags flags, const std::string &name, int32_t value)
1797{
1798 if (name.empty()) return CMD_ERROR;
1799 const SettingDesc *sd = GetCompanySettingFromName(name);
1800
1801 if (sd == nullptr) return CMD_ERROR;
1802 if (!sd->IsIntSetting()) return CMD_ERROR;
1803
1804 if (flags.Test(DoCommandFlag::Execute)) {
1806 }
1807
1808 return CommandCost();
1809}
1810
1818bool SetSettingValue(const IntSettingDesc *sd, int32_t value, bool force_newgame)
1819{
1820 const IntSettingDesc *setting = sd->AsIntSetting();
1821 if (setting->flags.Test(SettingFlag::PerCompany)) {
1822 if (Company::IsValidID(_local_company) && _game_mode != GM_MENU) {
1823 return Command<CMD_CHANGE_COMPANY_SETTING>::Post(setting->GetName(), value);
1824 }
1825
1826 setting->ChangeValue(&_settings_client.company, value);
1827 return true;
1828 }
1829
1830 /* If an item is company-based, we do not send it over the network
1831 * (if any) to change. Also *hack*hack* we update the _newgame version
1832 * of settings because changing a company-based setting in a game also
1833 * changes its defaults. At least that is the convention we have chosen */
1834 if (setting->flags.Test(SettingFlag::NoNetworkSync)) {
1835 if (_game_mode != GM_MENU) {
1836 setting->ChangeValue(&_settings_newgame, value);
1837 }
1838 setting->ChangeValue(&GetGameSettings(), value);
1839 return true;
1840 }
1841
1842 if (force_newgame) {
1843 setting->ChangeValue(&_settings_newgame, value);
1844 return true;
1845 }
1846
1847 /* send non-company-based settings over the network */
1849 return Command<CMD_CHANGE_SETTING>::Post(setting->GetName(), value);
1850 }
1851 return false;
1852}
1853
1858{
1859 Company *c = Company::Get(cid);
1861 for (auto &desc : _company_settings) {
1862 const IntSettingDesc *int_setting = GetSettingDesc(desc)->AsIntSetting();
1863 int_setting->MakeValueValidAndWrite(&c->settings, int_setting->GetDefaultValue());
1864 }
1865}
1866
1871{
1872 const void *old_object = &Company::Get(_current_company)->settings;
1873 const void *new_object = &_settings_client.company;
1874 for (auto &desc : _company_settings) {
1875 const SettingDesc *sd = GetSettingDesc(desc);
1876 uint32_t old_value = (uint32_t)sd->AsIntSetting()->Read(old_object);
1877 uint32_t new_value = (uint32_t)sd->AsIntSetting()->Read(new_object);
1878 /*
1879 * This is called from a command, and since it contains local configuration information
1880 * that the rest of the clients do not know about, we need to circumvent the normal ::Post
1881 * local command validation and immediately send the command to the server.
1882 */
1883 if (old_value != new_value) Command<CMD_CHANGE_COMPANY_SETTING>::SendNet(STR_NULL, _local_company, sd->GetName(), new_value);
1884 }
1885}
1886
1894bool SetSettingValue(const StringSettingDesc *sd, std::string_view value, bool force_newgame)
1895{
1897
1898 if (GetVarMemType(sd->save.conv) == SLE_VAR_STRQ && value == "(null)") {
1899 value = {};
1900 }
1901
1902 const void *object = (_game_mode == GM_MENU || force_newgame) ? &_settings_newgame : &_settings_game;
1903 sd->AsStringSetting()->ChangeValue(object, std::string{value});
1904 return true;
1905}
1906
1913void StringSettingDesc::ChangeValue(const void *object, std::string &&newval) const
1914{
1915 this->MakeValueValid(newval);
1916 if (this->pre_check != nullptr && !this->pre_check(newval)) return;
1917
1918 this->Write(object, newval);
1919 if (this->post_callback != nullptr) this->post_callback(newval);
1920
1921 if (_save_config) SaveToConfig();
1922}
1923
1924/* Those 2 functions need to be here, else we have to make some stuff non-static
1925 * and besides, it is also better to keep stuff like this at the same place */
1926void IConsoleSetSetting(std::string_view name, std::string_view value, bool force_newgame)
1927{
1928 const SettingDesc *sd = GetSettingFromName(name);
1929 /* Company settings are not in "list_settings", so don't try to modify them. */
1930 if (sd == nullptr || sd->flags.Test(SettingFlag::PerCompany)) {
1931 IConsolePrint(CC_ERROR, "'{}' is an unknown setting.", name);
1932 return;
1933 }
1934
1935 bool success = true;
1936 if (sd->IsStringSetting()) {
1937 success = SetSettingValue(sd->AsStringSetting(), value, force_newgame);
1938 } else if (sd->IsIntSetting()) {
1939 const IntSettingDesc *isd = sd->AsIntSetting();
1940 size_t val = isd->ParseValue(value);
1941 if (!_settings_error_list.empty()) {
1942 IConsolePrint(CC_ERROR, "'{}' is not a valid value for this setting.", value);
1943 _settings_error_list.clear();
1944 return;
1945 }
1946 success = SetSettingValue(isd, (int32_t)val, force_newgame);
1947 }
1948
1949 if (!success) {
1950 if (_network_server) {
1951 IConsolePrint(CC_ERROR, "This command/variable is not available during network games.");
1952 } else {
1953 IConsolePrint(CC_ERROR, "This command/variable is only available to a network server.");
1954 }
1955 }
1956}
1957
1958void IConsoleSetSetting(std::string_view name, int value)
1959{
1960 const SettingDesc *sd = GetSettingFromName(name);
1961 assert(sd != nullptr);
1962 SetSettingValue(sd->AsIntSetting(), value);
1963}
1964
1970void IConsoleGetSetting(std::string_view name, bool force_newgame)
1971{
1972 const SettingDesc *sd = GetSettingFromName(name);
1973 /* Company settings are not in "list_settings", so don't try to read them. */
1974 if (sd == nullptr || sd->flags.Test(SettingFlag::PerCompany)) {
1975 IConsolePrint(CC_ERROR, "'{}' is an unknown setting.", name);
1976 return;
1977 }
1978
1979 const void *object = (_game_mode == GM_MENU || force_newgame) ? &_settings_newgame : &_settings_game;
1980
1981 if (sd->IsStringSetting()) {
1982 IConsolePrint(CC_INFO, "Current value for '{}' is '{}'.", sd->GetName(), sd->AsStringSetting()->Read(object));
1983 } else if (sd->IsIntSetting()) {
1984 std::string value = sd->FormatValue(object);
1985 const IntSettingDesc *int_setting = sd->AsIntSetting();
1986 auto [min_val, max_val] = int_setting->GetRange();
1987 auto def_val = int_setting->GetDefaultValue();
1988 IConsolePrint(CC_INFO, "Current value for '{}' is '{}' (min: {}{}, max: {}, def: {}).",
1989 sd->GetName(), value, sd->flags.Test(SettingFlag::GuiZeroIsSpecial) ? "(0) " : "", min_val, max_val, def_val);
1990 }
1991}
1992
1993static void IConsoleListSettingsTable(const SettingTable &table, std::string_view prefilter)
1994{
1995 for (auto &desc : table) {
1996 const SettingDesc *sd = GetSettingDesc(desc);
1997 if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue;
1998 if (!prefilter.empty() && sd->GetName().find(prefilter) == std::string::npos) continue;
1999 IConsolePrint(CC_DEFAULT, "{} = {}", sd->GetName(), sd->FormatValue(&GetGameSettings()));
2000 }
2001}
2002
2008void IConsoleListSettings(std::string_view prefilter)
2009{
2010 IConsolePrint(CC_HELP, "All settings with their current value:");
2011
2012 for (auto &table : GenericSettingTables()) {
2013 IConsoleListSettingsTable(table, prefilter);
2014 }
2015 for (auto &table : PrivateSettingTables()) {
2016 IConsoleListSettingsTable(table, prefilter);
2017 }
2018 for (auto &table : SecretSettingTables()) {
2019 IConsoleListSettingsTable(table, prefilter);
2020 }
2021
2022 IConsolePrint(CC_HELP, "Use 'setting' command to change a value.");
2023}
2024
2025ScriptConfigSettings::ScriptConfigSettings()
2026{
2027 /* Instantiate here, because unique_ptr needs a complete type. */
2028}
2029
2030ScriptConfigSettings::~ScriptConfigSettings()
2031{
2032 /* Instantiate here, because unique_ptr needs a complete type. */
2033}
2034
2035ScriptConfigSettings::ScriptConfigSettings(const ScriptConfigSettings &other)
2036{
2037 *this = other;
2038}
2039
2040ScriptConfigSettings &ScriptConfigSettings::operator=(const ScriptConfigSettings &other)
2041{
2042 for (CompanyID c = CompanyID::Begin(); c < MAX_COMPANIES; ++c) {
2043 if (other.ai[c] != nullptr) {
2044 this->ai[c] = std::make_unique<AIConfig>(*other.ai[c]);
2045 }
2046 }
2047 if (other.game != nullptr) {
2048 this->game = std::make_unique<GameConfig>(*other.game);
2049 }
2050 return *this;
2051}
AIConfig stores the configuration settings of every AI.
Generic functions for replacing base data (graphics, sounds).
Generic functions for replacing base graphics data.
constexpr T SetBit(T &x, const uint8_t y)
Set a bit in a variable.
static AIConfig * GetConfig(CompanyID company, ScriptSettingSource source=SSS_DEFAULT)
Get the config of a company.
Definition ai_config.cpp:20
constexpr bool Test(Tvalue_type value) const
Test if the value-th bit is set.
static const GraphicsSet * GetUsedSet()
Return the used set.
Common return value for all commands.
IniFile to store a configuration.
Definition settings.cpp:140
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...
void Change(std::optional< std::string_view > name, int version=-1, bool force_exact_match=false)
Set another Script to be loaded in this slot.
void StringToSettings(std::string_view value)
Convert a string which is stored in the config file or savegames to custom settings of this Script.
const std::string & GetName() const
Get the name of the Script.
std::string SettingsToString() const
Convert the custom settings to a string that can be stored in the config file or savegames.
Parse data from a string / buffer.
std::optional< T > TryReadIntegerBase(int base, bool clamp=false)
Try to read and parse an integer in number 'base', and then advance the reader.
static const std::string_view WHITESPACE_NO_NEWLINE
ASCII whitespace characters, excluding new-line.
void SkipUntilCharNotIn(std::string_view chars)
Skip 8-bit chars, while they are in 'chars', until they are not.
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:90
Console functions used outside of the console code.
static const TextColour CC_HELP
Colour for help lines.
static const TextColour CC_INFO
Colour for information lines.
static const TextColour CC_DEFAULT
Default colour of the console.
static const TextColour CC_ERROR
Colour for error lines.
void ResetCurrencies(bool preserve_custom)
Will fill _currency_specs array with default values from origin_currency_specs Called only from newgr...
Definition currency.cpp: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:259
Functions related to debugging.
#define Debug(category, level, format_string,...)
Output a line of debugging information.
Definition debug.h:37
Functions related to errors.
std::list< ErrorMessageData > ErrorList
Define a queue with errors.
Definition error.h:48
void ScheduleErrorMessage(ErrorList &datas)
Schedule a list of errors.
@ WL_CRITICAL
Critical errors, the MessageBox is shown in all cases.
Definition error.h:27
void ShowErrorMessage(EncodedString &&summary_msg, int x, int y, CommandCost &cc)
Display an error message in a window.
void ShowFirstError()
Show the first error of the queue.
bool FioCheckFileExists(std::string_view filename, Subdirectory subdir)
Check whether the given file exists.
Definition fileio.cpp:121
Functions for Standard In/Out file operations.
@ NO_DIRECTORY
A path without any base directory.
@ NEWGRF_DIR
Subdirectory for all NewGRFs.
Definition fileio_type.h:96
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:76
bool _networking
are we in networking mode?
Definition network.cpp:67
StringList _network_ban_list
The banned clients.
Definition network.cpp:77
bool _network_server
network-server is active
Definition network.cpp:68
StringList _network_bind_list
The addresses to bind on.
Definition network.cpp:75
Basic functions/variables used all over the place.
Network functions used by other parts of OpenTTD.
void BadgeClassSaveConfig(IniFile &ini)
Save badge column preferences.
void BadgeClassLoadConfig(const IniFile &ini)
Load badge column preferences.
Functions related to NewGRF badge configuration.
GRFConfigList _grfconfig_static
First item in list of static GRF set up.
std::string GRFBuildParamList(const GRFConfig &c)
Build a string containing space separated parameter values, and terminate.
const GRFConfig * FindGRFConfig(uint32_t grfid, FindGRFConfigMode mode, const MD5Hash *md5sum, uint32_t desired_version)
Find a NewGRF in the scanned list.
GRFConfigList _grfconfig_newgame
First item in list of default GRF set up.
bool FillGRFDetails(GRFConfig &config, bool is_static, Subdirectory subdir)
Find the GRFID of a given grf, and calculate its md5sum.
Functions to find and configure NewGRFs.
@ GCS_NOT_FOUND
GRF file was not found in the local cache.
@ 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:824
int64_t ReadValue(const void *ptr, VarType conv)
Return a signed-long version of the value of a setting.
Definition saveload.cpp:800
@ SLE_VAR_NULL
useful to write zeros in savegame.
Definition saveload.h:657
@ SLE_VAR_STR
string pointer
Definition saveload.h:658
@ SLE_VAR_STRQ
string pointer enclosed in quotes
Definition saveload.h:659
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.
void IniLoadWindowSettings(IniFile &ini, std::string_view grpname, WindowDesc *desc)
Load a WindowDesc from config.
Definition settings.cpp:873
static void RemoveEntriesFromIni(IniFile &ini, const SettingTable &table)
Remove all entries from a settings table from an ini-file.
void SaveGRFPresetToConfig(std::string_view config_name, GRFConfigList &config)
Save a NewGRF configuration with a preset name.
StringList GetGRFPresetList()
Get the list of known NewGrf presets.
static void ValidateSettings()
Checks if any settings are set to incorrect values, and sets them to correct values in that case.
Definition settings.cpp:942
bool IsConversionNeeded(const ConfigIniFile &ini, const std::string &group, const std::string &old_var, const std::string &new_var, const IniItem **old_item)
Check whether a conversion should be done, and based on what old setting information.
void IConsoleGetSetting(std::string_view name, bool force_newgame)
Output value of a specific setting to the console.
std::string _secrets_file
Secrets configuration file of OpenTTD.
Definition settings.cpp:66
static GRFConfigList GRFLoadConfig(const IniFile &ini, std::string_view grpname, bool is_static)
Load a GRF configuration.
std::string _favs_file
Picker favourites configuration file of OpenTTD.
Definition settings.cpp:67
static ErrorList _settings_error_list
Errors while loading minimal settings.
Definition settings.cpp:69
void DeleteGRFPresetFromConfig(std::string_view config_name)
Delete a NewGRF configuration by preset name.
void SetDefaultCompanySettings(CompanyID cid)
Set the company settings for a new company to their default values.
static void IniLoadSettingList(IniFile &ini, std::string_view grpname, StringList &list)
Loads all items from a 'grpname' section into a list The list parameter can be a nullptr pointer,...
Definition settings.cpp:835
std::vector< const SettingDesc * > GetFilteredSettingCollection(std::function< bool(const SettingDesc &desc)> func)
Get a collection of settings matching a custom filter.
void LoadFromConfig(bool startup)
Load the values from the configuration files.
GRFConfigList LoadGRFPresetFromConfig(std::string_view config_name)
Load a NewGRF configuration by preset-name.
bool SetSettingValue(const IntSettingDesc *sd, int32_t value, bool force_newgame)
Top function to save the new value of an element of the Settings struct.
void SaveToConfig()
Save the values to the configuration file.
VehicleDefaultSettings _old_vds
Used for loading default vehicles settings from old savegames.
Definition settings.cpp:63
void PrepareOldDiffCustom()
Prepare for reading and old diff_custom by zero-ing the memory.
static void IniLoadSettings(IniFile &ini, const SettingTable &settings_table, std::string_view grpname, void *object, bool only_startup)
Load values from a group of an IniFile structure into the internal representation.
Definition settings.cpp:620
void GetSaveLoadFromSettingTable(SettingTable settings, std::vector< SaveLoad > &saveloads)
Get the SaveLoad for all settings in the settings table.
static void GraphicsSetSaveConfig(IniFile &ini)
Save BaseGraphics set selection and configuration.
static bool LoadIntList(std::optional< std::string_view > str, void *array, int nelems, VarType type)
Load parsed string-values into an integer-array (intlist)
Definition settings.cpp:282
static std::optional< std::vector< uint32_t > > ParseIntList(std::string_view str)
Parse a string into a vector of uint32s.
Definition settings.cpp:247
GameSettings _settings_game
Game settings of a running game or the scenario editor.
Definition settings.cpp:61
CommandCost CmdChangeCompanySetting(DoCommandFlags flags, const std::string &name, int32_t value)
Change one of the per-company settings.
IniFileVersion
Ini-file versions.
Definition settings.cpp:166
@ IFV_0
0 All versions prior to introduction.
Definition settings.cpp:167
@ IFV_AUTOSAVE_RENAME
5 PR#11143 Renamed values of autosave to be in minutes.
Definition settings.cpp:173
@ IFV_LINKGRAPH_SECONDS
3 PR#10610 Store linkgraph update intervals in seconds instead of days.
Definition settings.cpp:170
@ IFV_REMOVE_GENERATION_SEED
7 PR#11927 Remove "generation_seed" from configuration.
Definition settings.cpp:175
@ IFV_MAX_VERSION
Highest possible ini-file version.
Definition settings.cpp:177
@ IFV_NETWORK_PRIVATE_SETTINGS
4 PR#10762 Move use_relay_service to private settings.
Definition settings.cpp:171
@ IFV_GAME_TYPE
2 PR#9515 Convert server_advertise to server_game_type.
Definition settings.cpp:169
@ IFV_RIGHT_CLICK_CLOSE
6 PR#10204 Add alternative right click to close windows setting.
Definition settings.cpp:174
@ IFV_PRIVATE_SECRETS
1 PR#9298 Moving of settings from openttd.cfg to private.cfg / secrets.cfg.
Definition settings.cpp:168
SettingTable GetSaveLoadSettingTable()
Create a single table with all settings that should be stored/loaded in the savegame.
void IConsoleListSettings(std::string_view prefilter)
List all settings and their value to the console.
static void IniSaveSettingList(IniFile &ini, std::string_view grpname, StringList &list)
Saves all items from a list into the 'grpname' section The list parameter can be a nullptr pointer,...
Definition settings.cpp:857
const uint16_t INIFILE_VERSION
Current ini-file version of OpenTTD.
Definition settings.cpp:180
static void IniSaveSettings(IniFile &ini, const SettingTable &settings_table, std::string_view grpname, void *object, bool)
Save the values of settings to the inifile.
Definition settings.cpp:705
static auto & SecretSettingTables()
List of all the secrets setting tables.
Definition settings.cpp:114
std::string _private_file
Private configuration file of OpenTTD.
Definition settings.cpp:65
GameSettings _settings_newgame
Game settings for new games (updated from the intro screen).
Definition settings.cpp:62
static auto & PrivateSettingTables()
List of all the private setting tables.
Definition settings.cpp:103
static void SaveVersionInConfig(IniFile &ini)
Save the version of OpenTTD to the ini file.
std::string _config_file
Configuration file of OpenTTD.
Definition settings.cpp:64
static std::optional< uint32_t > LookupManyOfMany(std::span< const std::string_view > many, std::string_view str)
Find the set-integer value MANYofMANY type in a string.
Definition settings.cpp:221
static const SettingDesc * GetSettingFromName(std::string_view name, const SettingTable &settings)
Given a name of setting, return a setting description from the table.
static auto & GenericSettingTables()
List of all the generic setting tables.
Definition settings.cpp:81
void IniSaveWindowSettings(IniFile &ini, std::string_view grpname, WindowDesc *desc)
Save a WindowDesc to config.
Definition settings.cpp:884
static const SettingDesc * GetCompanySettingFromName(std::string_view name)
Given a name of setting, return a company setting description of it.
CommandCost CmdChangeSetting(DoCommandFlags flags, const std::string &name, int32_t value)
Network-safe changing of settings (server-only).
ClientSettings _settings_client
The current settings for this game.
Definition settings.cpp:60
Command definitions related to settings.
Functions related to setting/changing the settings.
@ NotInSave
Do not save with savegame, basically client-based.
@ Sandbox
This setting is a sandbox setting.
@ SceneditOnly
This setting can only be changed in the scenario editor.
@ PerCompany
This setting can be different for each company (saved in company struct).
@ NewgameOnly
This setting cannot be changed in a game.
@ GuiZeroIsSpecial
A value of zero is possible and has a custom string (the one after "strval").
@ NoNetwork
This setting does not apply to network games; it may not be changed during the game.
@ NotInConfig
Do not save to config file.
@ GuiDropdown
The value represents a limited number of string-options (internally integer) presented as dropdown.
@ SceneditToo
This setting can be changed in the scenario editor (only makes sense when SettingFlag::NewgameOnly is...
@ NoNetworkSync
Do not synchronize over network (but it is saved if SettingFlag::NotInSave is not set).
@ NetworkOnly
This setting only applies to network games.
SettingType
Type of settings for filtering.
@ ST_CLIENT
Client setting.
@ ST_GAME
Game setting.
@ ST_COMPANY
Company setting.
static constexpr const SettingDesc * GetSettingDesc(const SettingVariant &desc)
Helper to convert the type of the iterated settings description to a pointer to it.
Definition of the configuration tables of the settings.
GameSettings & GetGameSettings()
Get the settings-object applicable for the current situation: the newgame settings when we're in the ...
Definition of base types and functions in a cross-platform compatible way.
bool ConvertHexToBytes(std::string_view hex, std::span< uint8_t > bytes)
Convert a hex-string to a byte-array, while validating it was actually hex.
Definition string.cpp:570
void StrMakeValidInPlace(char *str, StringValidationSettings settings)
Scans the string for invalid characters and replaces them with a question mark '?' (if not ignored).
Definition string.cpp:155
std::string FormatArrayAsHex(std::span< const uint8_t > data)
Format a byte array into a continuous hex string.
Definition string.cpp:75
Parse strings.
Functions related to low-level strings.
std::vector< std::string > StringList
Type for a list of strings.
Definition string_type.h:60
EncodedString GetEncodedString(StringID str)
Encode a string with no parameters into an encoded string.
Definition strings.cpp:91
Functions related to OTTD's strings.
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
Class to backup a specific variable and restore it upon destruction of this object to prevent stack v...
uint32_t extra_version
version of the extra GRF
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:747
static std::optional< bool > ParseSingleValue(std::string_view str)
Find whether a string was a boolean true or a boolean false.
Definition settings.cpp:206
int32_t ParseValue(std::string_view str) const override
Convert a string representation (external) of an integer-like setting to an integer.
Definition settings.cpp:411
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:86
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
const IniGroup * GetGroup(std::string_view name) const
Get the group with the given name.
Definition ini_load.cpp:118
void LoadFromDisk(std::string_view filename, Subdirectory subdir)
Load the Ini file's data from the disk.
Definition ini_load.cpp:186
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:502
void ResetToDefault(void *object) const override
Reset the setting to its default value.
Definition settings.cpp:766
std::string FormatValue(const void *object) const override
Format the value of the setting associated with this object.
Definition settings.cpp:736
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:476
StringID GetTitle() const
Get the title of the setting.
Definition settings.cpp:427
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:753
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:467
void Write(const void *object, int32_t value) const
Set the value of a setting.
Definition settings.cpp:556
StringID GetHelp() const
Get the help text of the setting.
Definition settings.cpp:436
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:487
std::pair< StringParameter, StringParameter > GetValueParams(int32_t value) const
Get parameters for drawing the value of the setting.
Definition settings.cpp:445
int32_t Read(const void *object) const
Read the integer from the the actual setting.
Definition settings.cpp:567
virtual int32_t ParseValue(std::string_view str) const
Convert a string representation (external) of an integer-like setting to an integer.
Definition settings.cpp:367
bool IsDefaultValue(void *object) const override
Check whether the value is the same as the default value.
Definition settings.cpp:760
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:674
void ResetToDefault(void *object) const override
Reset the setting to its default value.
Definition settings.cpp:820
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:808
std::string_view def
default value given when none is present
std::string FormatValue(const void *object) const override
Convert an integer-array (intlist) to a string representation.
Definition settings.cpp:310
bool IsDefaultValue(void *object) const override
Check whether the value is the same as the default value.
Definition settings.cpp:814
int32_t ParseValue(std::string_view str) const override
Convert a string representation (external) of an integer-like setting to an integer.
Definition settings.cpp:400
std::string FormatValue(const void *object) const override
Format the value of the setting associated with this object.
Definition settings.cpp:347
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
std::string FormatValue(const void *object) const override
Format the value of the setting associated with this object.
Definition settings.cpp:341
static std::optional< uint32_t > ParseSingleValue(std::string_view str, std::span< const std::string_view > many)
Find the index value of a ONEofMANY type in a string.
Definition settings.cpp:188
std::vector< std::string_view > many
possible values for this type
int32_t ParseValue(std::string_view str) const override
Convert a string representation (external) of an integer-like setting to an integer.
Definition settings.cpp:386
static Titem * Get(auto index)
Returns Titem with given index.
static bool IsValidID(auto index)
Tests whether given index can be used to get valid (non-nullptr) Titem.
uint16_t length
(Conditional) length of the variable (eg. arrays) (max array size is 65536 elements).
Definition saveload.h:726
SaveLoadVersion version_to
Save/load the variable before this savegame version.
Definition saveload.h:728
VarType conv
Type of the variable to be saved; this field combines both FileVarType and MemVarType.
Definition saveload.h:725
SaveLoadVersion version_from
Save/load the variable starting from this savegame version.
Definition saveload.h:727
Container for AI and Game script configuration.
std::unique_ptr< class GameConfig > game
settings for gamescript
ReferenceThroughBaseContainer< std::array< std::unique_ptr< class AIConfig >, MAX_COMPANIES > > ai
settings per company
Iterable ensemble of each set bit in a value.
Properties of config file settings.
virtual void ParseValue(const IniItem *item, void *object) const =0
Parse/read the value from the Ini item into the setting associated with this object.
bool IsEditable(bool do_command=false) const
Check whether the setting is editable in the current gamemode.
Definition settings.cpp:894
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:911
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:931
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:921
String settings.
const std::string & Read(const void *object) const
Read the string from the the actual setting.
Definition settings.cpp:606
std::string_view def
Default value given when none is present.
void Write(const void *object, std::string_view str) const
Write a string to the actual setting.
Definition settings.cpp:596
uint32_t max_length
Maximum length of the string, 0 means no maximum length.
PreChangeCheck * pre_check
Callback to check for the validity of the setting.
void ChangeValue(const void *object, std::string &&newval) const
Handle changing a string value.
void MakeValueValid(std::string &str) const
Make the value valid given the limitations of this setting.
Definition settings.cpp:580
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:787
bool IsDefaultValue(void *object) const override
Check whether the value is the same as the default value.
Definition settings.cpp:797
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:803
std::string FormatValue(const void *object) const override
Format the value of the setting associated with this object.
Definition settings.cpp:771
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:667
Default settings for vehicles.
High level window description.
Definition window_gui.h:167
void SetWindowClassesDirty(WindowClass cls)
Mark all windows of a particular class as dirty (in need of repainting)
Definition window.cpp:3173
Window * FindWindowById(WindowClass cls, WindowNumber number)
Find a window by its class and window number.
Definition window.cpp:1140
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: