OpenTTD Source  20241108-master-g80f628063a
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"
30 #include "network/network_func.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 
60 std::string _config_file;
61 std::string _private_file;
62 std::string _secrets_file;
63 std::string _favs_file;
64 
66 
77 static auto &GenericSettingTables()
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 
99 static auto &PrivateSettingTables()
100 {
101  static const SettingTable _private_setting_tables[] = {
102  _network_private_settings,
103  };
104  return _private_setting_tables;
105 }
106 
110 static auto &SecretSettingTables()
111 {
112  static const SettingTable _secrets_setting_tables[] = {
113  _network_secrets_settings,
114  };
115  return _secrets_setting_tables;
116 }
117 
118 typedef void SettingDescProc(IniFile &ini, const SettingTable &desc, const char *grpname, void *object, bool only_startup);
119 typedef void SettingDescProcList(IniFile &ini, const char *grpname, StringList &list);
120 
121 static 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 
136 class ConfigIniFile : public IniFile {
137 private:
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 
148 public:
149  ConfigIniFile(const std::string &filename) : IniFile(list_group_names)
150  {
151  this->LoadFromDisk(filename, NO_DIRECTORY);
152  }
153 };
154 
162 enum IniFileVersion : uint32_t {
168 
172 
174 };
175 
177 
185 size_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 
205 std::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 
220 static 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 
249 static 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 
294 static 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 
322 std::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 
345 std::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 
353 std::string OneOfManySettingDesc::FormatValue(const void *object) const
354 {
355  uint id = (uint)this->Read(object);
356  return this->FormatSingleValue(id);
357 }
358 
359 std::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 
379 size_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 
398 size_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 
413 size_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 
424 size_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 
460 void 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 
482 void IntSettingDesc::MakeValueValidAndWrite(const void *object, int32_t val) const
483 {
484  this->MakeValueValid(val);
485  this->Write(object, val);
486 }
487 
497 void 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 
550 void 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 
561 int32_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 
574 void 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 
590 void StringSettingDesc::Write(const void *object, const std::string &str) const
591 {
592  reinterpret_cast<std::string *>(GetVariableAddress(object, this->save))->assign(str);
593 }
594 
600 const std::string &StringSettingDesc::Read(const void *object) const
601 {
602  return *reinterpret_cast<std::string *>(GetVariableAddress(object, this->save));
603 }
604 
614 static 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);
621  if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue;
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 
655 void 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 
661 void 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 
668 void 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 
694 static 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 */
702  if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue;
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 
725 std::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 
736 std::string BoolSettingDesc::FormatValue(const void *object) const
737 {
738  bool val = this->Read(object) != 0;
739  return val ? "true" : "false";
740 }
741 
742 bool 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 
749 bool IntSettingDesc::IsDefaultValue(void *object) const
750 {
751  int32_t object_value = this->Read(object);
752  return this->def == object_value;
753 }
754 
755 void IntSettingDesc::ResetToDefault(void *object) const
756 {
757  this->Write(object, this->def);
758 }
759 
760 std::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 
776 bool 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 
786 bool StringSettingDesc::IsDefaultValue(void *object) const
787 {
788  const std::string &str = this->Read(object);
789  return this->def == str;
790 }
791 
792 void StringSettingDesc::ResetToDefault(void *object) const
793 {
794  this->Write(object, this->def);
795 }
796 
797 bool 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 
824 static 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 
846 static 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 
862 void IniLoadWindowSettings(IniFile &ini, const char *grpname, void *desc)
863 {
864  IniLoadSettings(ini, _window_settings, grpname, desc, false);
865 }
866 
873 void IniSaveWindowSettings(IniFile &ini, const char *grpname, void *desc)
874 {
875  IniSaveSettings(ini, _window_settings, grpname, desc, false);
876 }
877 
883 bool 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 
926 void PrepareOldDiffCustom();
927 void HandleOldDiffCustom(bool savegame);
928 
929 
931 static void ValidateSettings()
932 {
933  /* Do not allow a custom sea level with the original land generator. */
937  }
938 }
939 
940 static 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 
969 static 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 
1031 static 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 
1143 static 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 
1158 static 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 
1178 static 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 
1200 static void SaveVersionInConfig(IniFile &ini)
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->num_params > 0) {
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 */
1230 static 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 */
1244 static 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 
1285 static 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 
1326 bool 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 
1354 void 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 
1437  ValidateSettings();
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 
1541 GRFConfig *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 
1558 void 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);
1565  ini.SaveToDisk(_config_file);
1566 }
1567 
1572 void DeleteGRFPresetFromConfig(const char *config_name)
1573 {
1574  std::string section("preset-");
1575  section += config_name;
1576 
1578  ini.RemoveGroup(section);
1579  ini.SaveToDisk(_config_file);
1580 }
1581 
1588 void 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);
1601  _gamelog.StopAction();
1602  }
1603 
1605 
1606  if (_save_config) SaveToConfig();
1607 }
1608 
1616 static 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 
1641 void 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 
1656 static 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 
1669 const 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 
1696 CommandCost 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 
1722 CommandCost 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 
1744 bool 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 */
1774  if (!_networking || (_networking && _network_server)) {
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 
1819 bool 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 
1838 void 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 */
1851 void 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 
1882 void IConsoleSetSetting(const char *name, int value)
1883 {
1884  const SettingDesc *sd = GetSettingFromName(name);
1885  assert(sd != nullptr);
1886  SetSettingValue(sd->AsIntSetting(), value);
1887 }
1888 
1894 void 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 
1914 static 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 
1929 void 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).
constexpr debug_inline 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.
Definition: command_type.h:23
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.
Definition: error_gui.cpp:146
static GameConfig * GetConfig(ScriptSettingSource source=SSS_DEFAULT)
Get the config of a company.
Definition: game_config.cpp:18
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.
Definition: command_func.h:28
DoCommandFlag
List of flags for a command.
Definition: command_type.h:374
@ DC_EXEC
execute the given command
Definition: command_type.h:376
CompanyID _local_company
Company controlled by the human player at this client. Can also be COMPANY_SPECTATOR.
Definition: company_cmd.cpp:52
CompanyID _current_company
Company currently doing an action.
Definition: company_cmd.cpp:53
Functions related to companies.
Owner
Enum for all companies/owners.
Definition: company_type.h:18
@ COMPANY_FIRST
First company, same as owner.
Definition: company_type.h:22
@ MAX_COMPANIES
Maximum number of companies.
Definition: company_type.h:23
Configuration options of the network stuff.
static const uint NETWORK_MAX_GRF_COUNT
Maximum number of GRFs that can be sent.
Definition: config.h:91
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.
Definition: console_type.h:26
static const TextColour CC_INFO
Colour for information lines.
Definition: console_type.h:27
static const TextColour CC_DEFAULT
Default colour of the console.
Definition: console_type.h:23
static const TextColour CC_ERROR
Colour for error lines.
Definition: console_type.h:24
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.
Definition: error_gui.cpp:452
void ShowErrorMessage(StringID summary_msg, int x, int y, CommandCost cc)
Display an error message in a window.
Definition: error_gui.cpp:367
void ShowFirstError()
Show the first error of the queue.
Definition: error_gui.cpp:335
@ 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.
Definition: fileio_type.h:133
@ NEWGRF_DIR
Subdirectory for all NewGRFs.
Definition: fileio_type.h:124
Declarations for savegames operations.
fluid_settings_t * settings
FluidSynth settings handle.
Definition: fluidsynth.cpp:21
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.
Definition: math_func.hpp:150
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.
GRFConfig * _grfconfig_static
First item in list of static GRF set up.
const GRFConfig * FindGRFConfig(uint32_t grfid, FindGRFConfigMode mode, const MD5Hash *md5sum, uint32_t desired_version)
Find a NewGRF in the scanned list.
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.
Definition: newgrf_config.h:29
@ GCF_STATIC
GRF file is used statically (can be used in any MP game)
Definition: newgrf_config.h:24
@ GCF_UNSAFE
GRF file is unsafe for static usage.
Definition: newgrf_config.h:23
@ GCF_SYSTEM
GRF file is an openttd-internal system grf.
Definition: newgrf_config.h:22
@ GCS_NOT_FOUND
GRF file was not found in the local cache.
Definition: newgrf_config.h:36
@ 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.
Definition: picker_gui.cpp:118
void PickerLoadConfig(const IniFile &ini)
Load favourites of all registered Pickers from config.
Definition: picker_gui.cpp:109
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:817
int64_t ReadValue(const void *ptr, VarType conv)
Return a signed-long version of the value of a setting.
Definition: saveload.cpp:793
@ SLE_VAR_NULL
useful to write zeros in savegame.
Definition: saveload.h:649
@ SLE_VAR_STR
string pointer
Definition: saveload.h:650
@ SLE_VAR_STRQ
string pointer enclosed in quotes
Definition: saveload.h:651
void * GetVariableAddress(const void *object, const SaveLoad &sld)
Get the address of the variable.
Definition: saveload.h:1265
constexpr size_t SlVarSize(VarType type)
Return expect size in bytes of a VarType.
Definition: saveload.h:776
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:1254
constexpr VarType GetVarMemType(VarType type)
Get the NumberType of a setting.
Definition: saveload.h:745
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.
Definition: settings_sl.cpp:36
void SyncCompanySettings()
Sync all company settings in a multiplayer game.
Definition: settings.cpp:1795
static void RemoveEntriesFromIni(IniFile &ini, const SettingTable &table)
Remove all entries from a settings table from an ini-file.
Definition: settings.cpp:1285
StringList GetGRFPresetList()
Get the list of known NewGrf presets.
Definition: settings.cpp:1521
static const SettingDesc * GetSettingFromName(const std::string_view name, const SettingTable &settings)
Given a name of setting, return a setting description from the table.
Definition: settings.cpp:1616
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.
Definition: settings.cpp:1326
GRFConfig * LoadGRFPresetFromConfig(const char *config_name)
Load a NewGRF configuration by preset-name.
Definition: settings.cpp:1541
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.
Definition: settings.cpp:1783
void SaveGRFPresetToConfig(const char *config_name, GRFConfig *config)
Save a NewGRF configuration with a preset name.
Definition: settings.cpp:1558
static auto & SecretSettingTables()
List of all the secrets setting tables.
Definition: settings.cpp:110
void LoadFromConfig(bool startup)
Load the values from the configuration files.
Definition: settings.cpp:1354
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.
Definition: settings.cpp:1744
void SaveToConfig()
Save the values to the configuration file.
Definition: settings.cpp:1447
VehicleDefaultSettings _old_vds
Used for loading default vehicles settings from old savegames.
Definition: settings.cpp:59
static auto & PrivateSettingTables()
List of all the private setting tables.
Definition: settings.cpp:99
void PrepareOldDiffCustom()
Prepare for reading and old diff_custom by zero-ing the memory.
Definition: settings_sl.cpp:25
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.
Definition: settings.cpp:1722
void GetSaveLoadFromSettingTable(SettingTable settings, std::vector< SaveLoad > &saveloads)
Get the SaveLoad for all settings in the settings table.
Definition: settings.cpp:1641
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.
Definition: settings.cpp:1211
static const SettingDesc * GetCompanySettingFromName(std::string_view name)
Given a name of setting, return a company setting description of it.
Definition: settings.cpp:1656
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).
Definition: settings.cpp:1696
const uint16_t INIFILE_VERSION
Current ini-file version of OpenTTD.
Definition: settings.cpp:176
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 _private_file
Private configuration file of OpenTTD.
Definition: settings.cpp:61
void DeleteGRFPresetFromConfig(const char *config_name)
Delete a NewGRF configuration by preset name.
Definition: settings.cpp:1572
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.
Definition: settings.cpp:1031
void IConsoleGetSetting(const char *name, bool force_newgame)
Output value of a specific setting to the console.
Definition: settings.cpp:1894
void IConsoleListSettings(const char *prefilter)
List all settings and their value to the console.
Definition: settings.cpp:1929
static void SaveVersionInConfig(IniFile &ini)
Save the version of OpenTTD to the ini file.
Definition: settings.cpp:1200
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
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.
static constexpr const SettingDesc * GetSettingDesc(const SettingVariant &desc)
Helper to convert the type of the iterated settings description to a pointer to it.
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").
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:357
uint32_t StringID
Numeric value that represents a string, independent of the selected language.
Definition: strings_type.h:16
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: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
Definition: company_base.h:122
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.
uint8_t num_params
Number of used 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)
Definition: newgrf_config.h:83
MD5Hash md5sum
MD5 checksum of file to distinguish files with the same GRF ID (eg. newer version of GRF)
Definition: newgrf_config.h:84
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
IniFile(const IniGroupNameList &list_group_names={})
Create a new ini file with given group names.
Definition: ini.cpp:33
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.
Definition: settings.cpp:1588
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 Titem * Get(size_t index)
Returns Titem with given index.
Definition: pool_type.hpp:339
static bool IsValidID(size_t index)
Tests whether given index can be used to get valid (non-nullptr) Titem.
Definition: pool_type.hpp:328
uint16_t length
(Conditional) length of the variable (eg. arrays) (max array size is 65536 elements).
Definition: saveload.h:715
SaveLoadVersion version_to
Save/load the variable before this savegame version.
Definition: saveload.h:717
VarType conv
Type of the variable to be saved; this field combines both FileVarType and MemVarType.
Definition: saveload.h:714
SaveLoadVersion version_from
Save/load the variable starting from this savegame version.
Definition: saveload.h:716
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.
constexpr const std::string & GetName() const
Get the name of this setting.
SettingType GetType() const
Return the type of the setting.
Definition: settings.cpp:900
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.
Definition: settings.cpp:1838
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.
Window * FindWindowById(WindowClass cls, WindowNumber number)
Find a window by its class and window number.
Definition: window.cpp:1098
void SetWindowClassesDirty(WindowClass cls)
Mark all windows of a particular class as dirty (in need of repainting)
Definition: window.cpp:3119
Window functions not directly related to making/drawing windows.
@ WC_ERRMSG
Error message; Window numbers:
Definition: window_type.h:110
@ WC_GAME_OPTIONS
Game options window; Window numbers:
Definition: window_type.h:624