|
@@ -23,6 +23,7 @@
|
|
|
|
|
|
#include "stdafx.h"
|
|
|
#include <array>
|
|
|
#include <charconv>
|
|
|
#include <limits>
|
|
|
#include "currency.h"
|
|
|
#include "screenshot.h"
|
|
@@ -81,8 +82,10 @@
|
|
|
ClientSettings _settings_client;
|
|
|
GameSettings _settings_game; ///< Game settings of a running game or the scenario editor.
|
|
|
GameSettings _settings_newgame; ///< Game settings for new games (updated from the intro screen).
|
|
|
VehicleDefaultSettings _old_vds; ///< Used for loading default vehicles settings from old savegames
|
|
|
std::string _config_file; ///< Configuration file of OpenTTD
|
|
|
VehicleDefaultSettings _old_vds; ///< Used for loading default vehicles settings from old savegames.
|
|
|
std::string _config_file; ///< Configuration file of OpenTTD.
|
|
|
std::string _private_file; ///< Private configuration file of OpenTTD.
|
|
|
std::string _secrets_file; ///< Secrets configuration file of OpenTTD.
|
|
|
|
|
|
typedef std::list<ErrorMessageData> ErrorList;
|
|
|
static ErrorList _settings_error_list; ///< Errors while loading minimal settings.
|
|
@@ -90,7 +93,7 @@ static ErrorList _settings_error_list; /
|
|
|
typedef span<const SettingVariant> SettingTable;
|
|
|
|
|
|
/**
|
|
|
* List of all the setting tables.
|
|
|
* List of all the generic setting tables.
|
|
|
*
|
|
|
* There are a few tables that are special and not processed like the rest:
|
|
|
* - _currency_settings
|
|
@@ -99,11 +102,25 @@ typedef span<const SettingVariant> Setti
|
|
|
* - _win32_settings
|
|
|
* As such, they are not part of this list.
|
|
|
*/
|
|
|
static const SettingTable _setting_tables[] = {
|
|
|
static const SettingTable _generic_setting_tables[] = {
|
|
|
_settings,
|
|
|
_network_settings,
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* List of all the private setting tables.
|
|
|
*/
|
|
|
static const SettingTable _private_setting_tables[] = {
|
|
|
_network_private_settings,
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* List of all the secrets setting tables.
|
|
|
*/
|
|
|
static const SettingTable _secrets_setting_tables[] = {
|
|
|
_network_secrets_settings,
|
|
|
};
|
|
|
|
|
|
typedef void SettingDescProc(IniFile &ini, const SettingTable &desc, const char *grpname, void *object, bool only_startup);
|
|
|
typedef void SettingDescProcList(IniFile &ini, const char *grpname, StringList &list);
|
|
|
|
|
@@ -130,6 +147,22 @@ public:
|
|
|
};
|
|
|
|
|
|
/**
|
|
|
* Ini-file versions.
|
|
|
*
|
|
|
* Sometimes we move settings between different ini-files, as we need to know
|
|
|
* when we have to load/remove it from the old versus reading it from the new
|
|
|
* location. These versions assist with situations like that.
|
|
|
*/
|
|
|
enum IniFileVersion : uint32 {
|
|
|
IFV_0, ///< 0 All versions prior to introduction.
|
|
|
IFV_PRIVATE_SECRETS, ///< 1 PR#9298 Moving of settings from openttd.cfg to private.cfg / secrets.cfg.
|
|
|
|
|
|
IFV_MAX_VERSION, ///< Highest possible ini-file version.
|
|
|
};
|
|
|
|
|
|
const uint16 INIFILE_VERSION = (IniFileVersion)(IFV_MAX_VERSION - 1); ///< Current ini-file version of OpenTTD.
|
|
|
|
|
|
/**
|
|
|
* Helper to convert the type of the iterated settings description to a pointer to it.
|
|
|
* @param desc The type of the iterator of the value in SettingTable.
|
|
|
* @return The actual pointer to SettingDesc.
|
|
@@ -1473,6 +1506,20 @@ static GRFConfig *GRFLoadConfig(IniFile
|
|
|
return first;
|
|
|
}
|
|
|
|
|
|
static IniFileVersion LoadVersionFromConfig(IniFile &ini)
|
|
|
{
|
|
|
IniGroup *group = ini.GetGroup("version");
|
|
|
|
|
|
auto version_number = group->GetItem("ini_version", false);
|
|
|
/* Older ini-file versions don't have this key yet. */
|
|
|
if (version_number == nullptr || !version_number->value.has_value()) return IFV_0;
|
|
|
|
|
|
uint32 version = 0;
|
|
|
std::from_chars(version_number->value->data(), version_number->value->data() + version_number->value->size(), version);
|
|
|
|
|
|
return static_cast<IniFileVersion>(version);
|
|
|
}
|
|
|
|
|
|
static void AISaveConfig(IniFile &ini, const char *grpname)
|
|
|
{
|
|
|
IniGroup *group = ini.GetGroup(grpname);
|
|
@@ -1526,6 +1573,7 @@ static void SaveVersionInConfig(IniFile
|
|
|
IniGroup *group = ini.GetGroup("version");
|
|
|
group->GetItem("version_string", true)->SetValue(_openttd_revision);
|
|
|
group->GetItem("version_number", true)->SetValue(fmt::format("{:08X}", _openttd_newgrf_version));
|
|
|
group->GetItem("ini_version", true)->SetValue(std::to_string(INIFILE_VERSION));
|
|
|
}
|
|
|
|
|
|
/* Save a GRF configuration to the given group name */
|
|
@@ -1549,25 +1597,58 @@ static void GRFSaveConfig(IniFile &ini,
|
|
|
}
|
|
|
|
|
|
/* Common handler for saving/loading variables to the configuration file */
|
|
|
static void HandleSettingDescs(IniFile &ini, SettingDescProc *proc, SettingDescProcList *proc_list, bool only_startup = false)
|
|
|
static void HandleSettingDescs(IniFile &generic_ini, IniFile &private_ini, IniFile &secrets_ini, SettingDescProc *proc, SettingDescProcList *proc_list, bool only_startup = false)
|
|
|
{
|
|
|
proc(ini, _misc_settings, "misc", nullptr, only_startup);
|
|
|
proc(generic_ini, _misc_settings, "misc", nullptr, only_startup);
|
|
|
#if defined(_WIN32) && !defined(DEDICATED)
|
|
|
proc(ini, _win32_settings, "win32", nullptr, only_startup);
|
|
|
proc(generic_ini, _win32_settings, "win32", nullptr, only_startup);
|
|
|
#endif /* _WIN32 */
|
|
|
|
|
|
for (auto &table : _setting_tables) {
|
|
|
/* The name "patches" is a fallback, as every setting should sets its own group. */
|
|
|
proc(ini, table, "patches", &_settings_newgame, only_startup);
|
|
|
/* The name "patches" is a fallback, as every setting should sets its own group. */
|
|
|
|
|
|
for (auto &table : _generic_setting_tables) {
|
|
|
proc(generic_ini, table, "patches", &_settings_newgame, only_startup);
|
|
|
}
|
|
|
for (auto &table : _private_setting_tables) {
|
|
|
proc(private_ini, table, "patches", &_settings_newgame, only_startup);
|
|
|
}
|
|
|
for (auto &table : _secrets_setting_tables) {
|
|
|
proc(secrets_ini, table, "patches", &_settings_newgame, only_startup);
|
|
|
}
|
|
|
|
|
|
proc(ini, _currency_settings,"currency", &_custom_currency, only_startup);
|
|
|
proc(ini, _company_settings, "company", &_settings_client.company, only_startup);
|
|
|
proc(generic_ini, _currency_settings, "currency", &_custom_currency, only_startup);
|
|
|
proc(generic_ini, _company_settings, "company", &_settings_client.company, only_startup);
|
|
|
|
|
|
if (!only_startup) {
|
|
|
proc_list(ini, "server_bind_addresses", _network_bind_list);
|
|
|
proc_list(ini, "servers", _network_host_list);
|
|
|
proc_list(ini, "bans", _network_ban_list);
|
|
|
proc_list(private_ini, "server_bind_addresses", _network_bind_list);
|
|
|
proc_list(private_ini, "servers", _network_host_list);
|
|
|
proc_list(private_ini, "bans", _network_ban_list);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Remove all entries from a settings table from an ini-file.
|
|
|
*
|
|
|
* This is only useful if those entries are moved to another file, and you
|
|
|
* want to clean up what is left behind.
|
|
|
*
|
|
|
* @param ini The ini file to remove the entries from.
|
|
|
* @param table The table to look for entries to remove.
|
|
|
*/
|
|
|
static void RemoveEntriesFromIni(IniFile &ini, const SettingTable &table)
|
|
|
{
|
|
|
for (auto &desc : table) {
|
|
|
const SettingDesc *sd = GetSettingDesc(desc);
|
|
|
|
|
|
/* For settings.xx.yy load the settings from [xx] yy = ? */
|
|
|
std::string s{ sd->name };
|
|
|
auto sc = s.find('.');
|
|
|
if (sc == std::string::npos) continue;
|
|
|
|
|
|
IniGroup *group = ini.GetGroup(s.substr(0, sc));
|
|
|
s = s.substr(sc + 1);
|
|
|
|
|
|
group->RemoveItem(s);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -1577,20 +1658,30 @@ static void HandleSettingDescs(IniFile &
|
|
|
*/
|
|
|
void LoadFromConfig(bool startup)
|
|
|
{
|
|
|
ConfigIniFile ini(_config_file);
|
|
|
ConfigIniFile generic_ini(_config_file);
|
|
|
ConfigIniFile private_ini(_private_file);
|
|
|
ConfigIniFile secrets_ini(_secrets_file);
|
|
|
|
|
|
if (!startup) ResetCurrencies(false); // Initialize the array of currencies, without preserving the custom one
|
|
|
|
|
|
IniFileVersion generic_version = LoadVersionFromConfig(generic_ini);
|
|
|
|
|
|
/* Before the split of private/secrets, we have to look in the generic for these settings. */
|
|
|
if (generic_version < IFV_PRIVATE_SECRETS) {
|
|
|
HandleSettingDescs(generic_ini, generic_ini, generic_ini, IniLoadSettings, IniLoadSettingList, startup);
|
|
|
} else {
|
|
|
HandleSettingDescs(generic_ini, private_ini, secrets_ini, IniLoadSettings, IniLoadSettingList, startup);
|
|
|
}
|
|
|
|
|
|
/* Load basic settings only during bootstrap, load other settings not during bootstrap */
|
|
|
HandleSettingDescs(ini, IniLoadSettings, IniLoadSettingList, startup);
|
|
|
|
|
|
if (!startup) {
|
|
|
_grfconfig_newgame = GRFLoadConfig(ini, "newgrf", false);
|
|
|
_grfconfig_static = GRFLoadConfig(ini, "newgrf-static", true);
|
|
|
AILoadConfig(ini, "ai_players");
|
|
|
GameLoadConfig(ini, "game_scripts");
|
|
|
_grfconfig_newgame = GRFLoadConfig(generic_ini, "newgrf", false);
|
|
|
_grfconfig_static = GRFLoadConfig(generic_ini, "newgrf-static", true);
|
|
|
AILoadConfig(generic_ini, "ai_players");
|
|
|
GameLoadConfig(generic_ini, "game_scripts");
|
|
|
|
|
|
PrepareOldDiffCustom();
|
|
|
IniLoadSettings(ini, _gameopt_settings, "gameopt", &_settings_newgame, false);
|
|
|
IniLoadSettings(generic_ini, _gameopt_settings, "gameopt", &_settings_newgame, false);
|
|
|
HandleOldDiffCustom(false);
|
|
|
|
|
|
ValidateSettings();
|
|
@@ -1605,20 +1696,52 @@ void LoadFromConfig(bool startup)
|
|
|
/** Save the values to the configuration file */
|
|
|
void SaveToConfig()
|
|
|
{
|
|
|
ConfigIniFile ini(_config_file);
|
|
|
ConfigIniFile generic_ini(_config_file);
|
|
|
ConfigIniFile private_ini(_private_file);
|
|
|
ConfigIniFile secrets_ini(_secrets_file);
|
|
|
|
|
|
IniFileVersion generic_version = LoadVersionFromConfig(generic_ini);
|
|
|
|
|
|
/* Remove some obsolete groups. These have all been loaded into other groups. */
|
|
|
ini.RemoveGroup("patches");
|
|
|
ini.RemoveGroup("yapf");
|
|
|
ini.RemoveGroup("gameopt");
|
|
|
/* If we newly create the private/secrets file, add a dummy group on top
|
|
|
* just so we can add a comment before it (that is how IniFile works).
|
|
|
* This to explain what the file is about. After doing it once, never touch
|
|
|
* it again, as otherwise we might be reverting user changes. */
|
|
|
if (!private_ini.GetGroup("private", false)) private_ini.GetGroup("private")->comment = "; This file possibly contains private information which can identify you as person.\n";
|
|
|
if (!secrets_ini.GetGroup("secrets", false)) secrets_ini.GetGroup("secrets")->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";
|
|
|
|
|
|
if (generic_version == IFV_0) {
|
|
|
/* Remove some obsolete groups. These have all been loaded into other groups. */
|
|
|
generic_ini.RemoveGroup("patches");
|
|
|
generic_ini.RemoveGroup("yapf");
|
|
|
generic_ini.RemoveGroup("gameopt");
|
|
|
|
|
|
HandleSettingDescs(ini, IniSaveSettings, IniSaveSettingList);
|
|
|
GRFSaveConfig(ini, "newgrf", _grfconfig_newgame);
|
|
|
GRFSaveConfig(ini, "newgrf-static", _grfconfig_static);
|
|
|
AISaveConfig(ini, "ai_players");
|
|
|
GameSaveConfig(ini, "game_scripts");
|
|
|
SaveVersionInConfig(ini);
|
|
|
ini.SaveToDisk(_config_file);
|
|
|
/* Remove all settings from the generic ini that are now in the private ini. */
|
|
|
generic_ini.RemoveGroup("server_bind_addresses");
|
|
|
generic_ini.RemoveGroup("servers");
|
|
|
generic_ini.RemoveGroup("bans");
|
|
|
for (auto &table : _private_setting_tables) {
|
|
|
RemoveEntriesFromIni(generic_ini, table);
|
|
|
}
|
|
|
|
|
|
/* Remove all settings from the generic ini that are now in the secrets ini. */
|
|
|
for (auto &table : _secrets_setting_tables) {
|
|
|
RemoveEntriesFromIni(generic_ini, table);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
HandleSettingDescs(generic_ini, private_ini, secrets_ini, IniSaveSettings, IniSaveSettingList);
|
|
|
GRFSaveConfig(generic_ini, "newgrf", _grfconfig_newgame);
|
|
|
GRFSaveConfig(generic_ini, "newgrf-static", _grfconfig_static);
|
|
|
AISaveConfig(generic_ini, "ai_players");
|
|
|
GameSaveConfig(generic_ini, "game_scripts");
|
|
|
|
|
|
SaveVersionInConfig(generic_ini);
|
|
|
SaveVersionInConfig(private_ini);
|
|
|
SaveVersionInConfig(secrets_ini);
|
|
|
|
|
|
generic_ini.SaveToDisk(_config_file);
|
|
|
private_ini.SaveToDisk(_private_file);
|
|
|
secrets_ini.SaveToDisk(_secrets_file);
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -1778,7 +1901,15 @@ static const SettingDesc *GetCompanySett
|
|
|
*/
|
|
|
const SettingDesc *GetSettingFromName(const std::string_view name)
|
|
|
{
|
|
|
for (auto &table : _setting_tables) {
|
|
|
for (auto &table : _generic_setting_tables) {
|
|
|
auto sd = GetSettingFromName(name, table);
|
|
|
if (sd != nullptr) return sd;
|
|
|
}
|
|
|
for (auto &table : _private_setting_tables) {
|
|
|
auto sd = GetSettingFromName(name, table);
|
|
|
if (sd != nullptr) return sd;
|
|
|
}
|
|
|
for (auto &table : _secrets_setting_tables) {
|
|
|
auto sd = GetSettingFromName(name, table);
|
|
|
if (sd != nullptr) return sd;
|
|
|
}
|
|
@@ -2014,6 +2145,18 @@ void IConsoleGetSetting(const char *name
|
|
|
}
|
|
|
}
|
|
|
|
|
|
static void IConsoleListSettingsTable(const SettingTable &table, const char *prefilter)
|
|
|
{
|
|
|
for (auto &desc : table) {
|
|
|
const SettingDesc *sd = GetSettingDesc(desc);
|
|
|
if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue;
|
|
|
if (prefilter != nullptr && sd->name.find(prefilter) == std::string::npos) continue;
|
|
|
char value[80];
|
|
|
sd->FormatValue(value, lastof(value), &GetGameSettings());
|
|
|
IConsolePrint(CC_DEFAULT, "{} = {}", sd->name, value);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* List all settings and their value to the console
|
|
|
*
|
|
@@ -2023,15 +2166,14 @@ void IConsoleListSettings(const char *pr
|
|
|
{
|
|
|
IConsolePrint(CC_HELP, "All settings with their current value:");
|
|
|
|
|
|
for (auto &table : _setting_tables) {
|
|
|
for (auto &desc : table) {
|
|
|
const SettingDesc *sd = GetSettingDesc(desc);
|
|
|
if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue;
|
|
|
if (prefilter != nullptr && sd->name.find(prefilter) == std::string::npos) continue;
|
|
|
char value[80];
|
|
|
sd->FormatValue(value, lastof(value), &GetGameSettings());
|
|
|
IConsolePrint(CC_DEFAULT, "{} = {}", sd->name, value);
|
|
|
}
|
|
|
for (auto &table : _generic_setting_tables) {
|
|
|
IConsoleListSettingsTable(table, prefilter);
|
|
|
}
|
|
|
for (auto &table : _private_setting_tables) {
|
|
|
IConsoleListSettingsTable(table, prefilter);
|
|
|
}
|
|
|
for (auto &table : _secrets_setting_tables) {
|
|
|
IConsoleListSettingsTable(table, prefilter);
|
|
|
}
|
|
|
|
|
|
IConsolePrint(CC_HELP, "Use 'setting' command to change a value.");
|