Merge remote-tracking branch 'upstream/master'
This commit is contained in:
124
src/settings.cpp
124
src/settings.cpp
@@ -32,6 +32,7 @@
|
||||
#include "command_func.h"
|
||||
#include "console_func.h"
|
||||
#include "genworld.h"
|
||||
#include "string_func.h"
|
||||
#include "window_func.h"
|
||||
#include "company_func.h"
|
||||
#include "rev.h"
|
||||
@@ -42,6 +43,7 @@
|
||||
#include "ai/ai_config.hpp"
|
||||
#include "game/game_config.hpp"
|
||||
#include "newgrf_config.h"
|
||||
#include "picker_func.h"
|
||||
#include "base_media_base.h"
|
||||
#include "fios.h"
|
||||
#include "fileio_func.h"
|
||||
@@ -58,6 +60,7 @@ VehicleDefaultSettings _old_vds; ///< Used for loading default vehicles settings
|
||||
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.
|
||||
std::string _favs_file; ///< Picker favourites configuration file of OpenTTD.
|
||||
|
||||
static ErrorList _settings_error_list; ///< Errors while loading minimal settings.
|
||||
|
||||
@@ -139,6 +142,9 @@ private:
|
||||
"newgrf",
|
||||
"servers",
|
||||
"server_bind_addresses",
|
||||
"server_authorized_keys",
|
||||
"rcon_authorized_keys",
|
||||
"admin_authorized_keys"
|
||||
};
|
||||
|
||||
public:
|
||||
@@ -176,7 +182,7 @@ const uint16_t INIFILE_VERSION = (IniFileVersion)(IFV_MAX_VERSION - 1); ///< Cur
|
||||
* @param str the current value of the setting for which a value needs found
|
||||
* @param len length of the string
|
||||
* @param many full domain of values the ONEofMANY setting can have
|
||||
* @return the integer index of the full-list, or -1 if not found
|
||||
* @return the integer index of the full-list, or SIZE_MAX if not found
|
||||
*/
|
||||
size_t OneOfManySettingDesc::ParseSingleValue(const char *str, size_t len, const std::vector<std::string> &many)
|
||||
{
|
||||
@@ -189,7 +195,7 @@ size_t OneOfManySettingDesc::ParseSingleValue(const char *str, size_t len, const
|
||||
idx++;
|
||||
}
|
||||
|
||||
return (size_t)-1;
|
||||
return SIZE_MAX;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -211,7 +217,7 @@ std::optional<bool> BoolSettingDesc::ParseSingleValue(const char *str)
|
||||
* @param many full domain of values the MANYofMANY setting can have
|
||||
* @param str the current string value of the setting, each individual
|
||||
* of separated by a whitespace,tab or | character
|
||||
* @return the 'fully' set integer, or -1 if a set is not found
|
||||
* @return the 'fully' set integer, or SIZE_MAX if a set is not found
|
||||
*/
|
||||
static size_t LookupManyOfMany(const std::vector<std::string> &many, const char *str)
|
||||
{
|
||||
@@ -228,7 +234,7 @@ static size_t LookupManyOfMany(const std::vector<std::string> &many, const char
|
||||
while (*s != 0 && *s != ' ' && *s != '\t' && *s != '|') s++;
|
||||
|
||||
r = OneOfManySettingDesc::ParseSingleValue(str, s - str, many);
|
||||
if (r == (size_t)-1) return r;
|
||||
if (r == SIZE_MAX) return r;
|
||||
|
||||
SetBit(res, (uint8_t)r); // value found, set it
|
||||
if (*s == 0) break;
|
||||
@@ -238,24 +244,20 @@ static size_t LookupManyOfMany(const std::vector<std::string> &many, const char
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse an integerlist string and set each found value
|
||||
* @param p the string to be parsed. Each element in the list is separated by a
|
||||
* comma or a space character
|
||||
* @param items pointer to the integerlist-array that will be filled with values
|
||||
* @param maxitems the maximum number of elements the integerlist-array has
|
||||
* @return returns the number of items found, or -1 on an error
|
||||
* Parse a string into a vector of uint32s.
|
||||
* @param p the string to be parsed. Each element in the list is separated by a comma or a space character
|
||||
* @return std::optional with a vector of parsed integers. The optional is empty upon an error.
|
||||
*/
|
||||
template<typename T>
|
||||
static int ParseIntList(const char *p, T *items, size_t maxitems)
|
||||
static std::optional<std::vector<uint32_t>> ParseIntList(const char *p)
|
||||
{
|
||||
size_t n = 0; // number of items read so far
|
||||
bool comma = false; // do we accept comma?
|
||||
std::vector<uint32_t> result;
|
||||
|
||||
while (*p != '\0') {
|
||||
switch (*p) {
|
||||
case ',':
|
||||
/* Do not accept multiple commas between numbers */
|
||||
if (!comma) return -1;
|
||||
if (!comma) return std::nullopt;
|
||||
comma = false;
|
||||
[[fallthrough]];
|
||||
|
||||
@@ -264,12 +266,11 @@ static int ParseIntList(const char *p, T *items, size_t maxitems)
|
||||
break;
|
||||
|
||||
default: {
|
||||
if (n == maxitems) return -1; // we don't accept that many numbers
|
||||
char *end;
|
||||
unsigned long v = std::strtoul(p, &end, 0);
|
||||
if (p == end) return -1; // invalid character (not a number)
|
||||
if (sizeof(T) < sizeof(v)) v = Clamp<unsigned long>(v, std::numeric_limits<T>::min(), std::numeric_limits<T>::max());
|
||||
items[n++] = v;
|
||||
if (p == end) return std::nullopt; // invalid character (not a number)
|
||||
|
||||
result.push_back(ClampTo<uint32_t>(v));
|
||||
p = end; // first non-number
|
||||
comma = true; // we accept comma now
|
||||
break;
|
||||
@@ -279,52 +280,35 @@ static int ParseIntList(const char *p, T *items, size_t maxitems)
|
||||
|
||||
/* If we have read comma but no number after it, fail.
|
||||
* We have read comma when (n != 0) and comma is not allowed */
|
||||
if (n != 0 && !comma) return -1;
|
||||
if (!result.empty() && !comma) return std::nullopt;
|
||||
|
||||
return ClampTo<int>(n);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load parsed string-values into an integer-array (intlist)
|
||||
* @param str the string that contains the values (and will be parsed)
|
||||
* @param array pointer to the integer-arrays that will be filled
|
||||
* @param nelems the number of elements the array holds. Maximum is 64 elements
|
||||
* @param nelems the number of elements the array holds.
|
||||
* @param type the type of elements the array holds (eg INT8, UINT16, etc.)
|
||||
* @return return true on success and false on error
|
||||
*/
|
||||
static bool LoadIntList(const char *str, void *array, int nelems, VarType type)
|
||||
{
|
||||
unsigned long items[64];
|
||||
int i, nitems;
|
||||
|
||||
size_t elem_size = SlVarSize(type);
|
||||
if (str == nullptr) {
|
||||
memset(items, 0, sizeof(items));
|
||||
nitems = nelems;
|
||||
} else {
|
||||
nitems = ParseIntList(str, items, lengthof(items));
|
||||
if (nitems != nelems) return false;
|
||||
memset(array, 0, nelems * elem_size);
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case SLE_VAR_BL:
|
||||
case SLE_VAR_I8:
|
||||
case SLE_VAR_U8:
|
||||
for (i = 0; i != nitems; i++) ((byte*)array)[i] = items[i];
|
||||
break;
|
||||
auto opt_items = ParseIntList(str);
|
||||
if (!opt_items.has_value() || opt_items->size() != (size_t)nelems) return false;
|
||||
|
||||
case SLE_VAR_I16:
|
||||
case SLE_VAR_U16:
|
||||
for (i = 0; i != nitems; i++) ((uint16_t*)array)[i] = items[i];
|
||||
break;
|
||||
|
||||
case SLE_VAR_I32:
|
||||
case SLE_VAR_U32:
|
||||
for (i = 0; i != nitems; i++) ((uint32_t*)array)[i] = items[i];
|
||||
break;
|
||||
|
||||
default: NOT_REACHED();
|
||||
char *p = static_cast<char *>(array);
|
||||
for (auto item : *opt_items) {
|
||||
WriteValue(p, type, item);
|
||||
p += elem_size;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -339,7 +323,7 @@ static bool LoadIntList(const char *str, void *array, int nelems, VarType type)
|
||||
*/
|
||||
std::string ListSettingDesc::FormatValue(const void *object) const
|
||||
{
|
||||
const byte *p = static_cast<const byte *>(GetVariableAddress(object, this->save));
|
||||
const uint8_t *p = static_cast<const uint8_t *>(GetVariableAddress(object, this->save));
|
||||
|
||||
std::string result;
|
||||
for (size_t i = 0; i != this->save.length; i++) {
|
||||
@@ -418,8 +402,8 @@ size_t OneOfManySettingDesc::ParseValue(const char *str) const
|
||||
size_t r = OneOfManySettingDesc::ParseSingleValue(str, strlen(str), this->many);
|
||||
/* if the first attempt of conversion from string to the appropriate value fails,
|
||||
* look if we have defined a converter from old value to new value. */
|
||||
if (r == (size_t)-1 && this->many_cnvt != nullptr) r = this->many_cnvt(str);
|
||||
if (r != (size_t)-1) return r; // and here goes converted value
|
||||
if (r == SIZE_MAX && this->many_cnvt != nullptr) r = this->many_cnvt(str);
|
||||
if (r != SIZE_MAX) return r; // and here goes converted value
|
||||
|
||||
ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_VALUE);
|
||||
msg.SetDParamStr(0, str);
|
||||
@@ -431,7 +415,7 @@ size_t OneOfManySettingDesc::ParseValue(const char *str) const
|
||||
size_t ManyOfManySettingDesc::ParseValue(const char *str) const
|
||||
{
|
||||
size_t r = LookupManyOfMany(this->many, str);
|
||||
if (r != (size_t)-1) return r;
|
||||
if (r != SIZE_MAX) return r;
|
||||
ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_VALUE);
|
||||
msg.SetDParamStr(0, str);
|
||||
msg.SetDParamStr(1, this->GetName());
|
||||
@@ -596,7 +580,7 @@ void StringSettingDesc::MakeValueValid(std::string &str) const
|
||||
/* In case a maximum length is imposed by the setting, the length
|
||||
* includes the '\0' termination for network transfer purposes.
|
||||
* Also ensure the string is valid after chopping of some bytes. */
|
||||
std::string stdstr(str, this->max_length - 1);
|
||||
std::string stdstr(str, 0, this->max_length - 1);
|
||||
str.assign(StrMakeValid(stdstr, SVS_NONE));
|
||||
}
|
||||
|
||||
@@ -1029,15 +1013,13 @@ static void GraphicsSetLoadConfig(IniFile &ini)
|
||||
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);
|
||||
|
||||
if (const IniItem *item = group->GetItem("extra_params"); item != nullptr && item->value) {
|
||||
auto &extra_params = BaseGraphics::ini_data.extra_params;
|
||||
extra_params.resize(0x80); // TODO: make ParseIntList work nicely with C++ containers
|
||||
int count = ParseIntList(item->value->c_str(), &extra_params.front(), extra_params.size());
|
||||
if (count < 0) {
|
||||
auto params = ParseIntList(item->value->c_str());
|
||||
if (params.has_value()) {
|
||||
BaseGraphics::ini_data.extra_params = params.value();
|
||||
} else {
|
||||
SetDParamStr(0, BaseGraphics::ini_data.name);
|
||||
ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_ARRAY, WL_CRITICAL);
|
||||
count = 0;
|
||||
}
|
||||
extra_params.resize(count);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1098,13 +1080,13 @@ static GRFConfig *GRFLoadConfig(const IniFile &ini, const char *grpname, bool is
|
||||
|
||||
/* Parse parameters */
|
||||
if (item.value.has_value() && !item.value->empty()) {
|
||||
int count = ParseIntList(item.value->c_str(), c->param.data(), c->param.size());
|
||||
if (count < 0) {
|
||||
auto params = ParseIntList(item.value->c_str());
|
||||
if (params.has_value()) {
|
||||
c->SetParams(params.value());
|
||||
} else {
|
||||
SetDParamStr(0, filename);
|
||||
ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_ARRAY, WL_CRITICAL);
|
||||
count = 0;
|
||||
}
|
||||
c->num_params = count;
|
||||
}
|
||||
|
||||
/* Check if item is valid */
|
||||
@@ -1240,7 +1222,7 @@ static void GraphicsSetSaveConfig(IniFile &ini)
|
||||
group.GetOrCreateItem("shortname").SetValue(fmt::format("{:08X}", BSWAP32(used_set->shortname)));
|
||||
|
||||
const GRFConfig *extra_cfg = used_set->GetExtraConfig();
|
||||
if (extra_cfg != nullptr && extra_cfg->num_params > 0) {
|
||||
if (extra_cfg != nullptr && !extra_cfg->param.empty()) {
|
||||
group.GetOrCreateItem("extra_version").SetValue(fmt::format("{}", extra_cfg->version));
|
||||
group.GetOrCreateItem("extra_params").SetValue(GRFBuildParamList(extra_cfg));
|
||||
}
|
||||
@@ -1280,13 +1262,16 @@ static void HandleSettingDescs(IniFile &generic_ini, IniFile &private_ini, IniFi
|
||||
proc(secrets_ini, table, "patches", &_settings_newgame, only_startup);
|
||||
}
|
||||
|
||||
proc(generic_ini, _currency_settings, "currency", &_custom_currency, only_startup);
|
||||
proc(generic_ini, _currency_settings, "currency", &GetCustomCurrency(), only_startup);
|
||||
proc(generic_ini, _company_settings, "company", &_settings_client.company, only_startup);
|
||||
|
||||
if (!only_startup) {
|
||||
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);
|
||||
proc_list(private_ini, "server_authorized_keys", _settings_client.network.server_authorized_keys);
|
||||
proc_list(private_ini, "rcon_authorized_keys", _settings_client.network.rcon_authorized_keys);
|
||||
proc_list(private_ini, "admin_authorized_keys", _settings_client.network.admin_authorized_keys);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1373,6 +1358,7 @@ void LoadFromConfig(bool startup)
|
||||
ConfigIniFile generic_ini(_config_file);
|
||||
ConfigIniFile private_ini(_private_file);
|
||||
ConfigIniFile secrets_ini(_secrets_file);
|
||||
ConfigIniFile favs_ini(_favs_file);
|
||||
|
||||
if (!startup) ResetCurrencies(false); // Initialize the array of currencies, without preserving the custom one
|
||||
|
||||
@@ -1444,6 +1430,7 @@ void LoadFromConfig(bool startup)
|
||||
_grfconfig_static = GRFLoadConfig(generic_ini, "newgrf-static", true);
|
||||
AILoadConfig(generic_ini, "ai_players");
|
||||
GameLoadConfig(generic_ini, "game_scripts");
|
||||
PickerLoadConfig(favs_ini);
|
||||
|
||||
PrepareOldDiffCustom();
|
||||
IniLoadSettings(generic_ini, _old_gameopt_settings, "gameopt", &_settings_newgame, false);
|
||||
@@ -1464,6 +1451,7 @@ void SaveToConfig()
|
||||
ConfigIniFile generic_ini(_config_file);
|
||||
ConfigIniFile private_ini(_private_file);
|
||||
ConfigIniFile secrets_ini(_secrets_file);
|
||||
ConfigIniFile favs_ini(_favs_file);
|
||||
|
||||
IniFileVersion generic_version = LoadVersionFromConfig(generic_ini);
|
||||
|
||||
@@ -1515,14 +1503,17 @@ void SaveToConfig()
|
||||
GRFSaveConfig(generic_ini, "newgrf-static", _grfconfig_static);
|
||||
AISaveConfig(generic_ini, "ai_players");
|
||||
GameSaveConfig(generic_ini, "game_scripts");
|
||||
PickerSaveConfig(favs_ini);
|
||||
|
||||
SaveVersionInConfig(generic_ini);
|
||||
SaveVersionInConfig(private_ini);
|
||||
SaveVersionInConfig(secrets_ini);
|
||||
SaveVersionInConfig(favs_ini);
|
||||
|
||||
generic_ini.SaveToDisk(_config_file);
|
||||
private_ini.SaveToDisk(_private_file);
|
||||
secrets_ini.SaveToDisk(_secrets_file);
|
||||
favs_ini.SaveToDisk(_favs_file);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1811,6 +1802,11 @@ void SyncCompanySettings()
|
||||
const SettingDesc *sd = GetSettingDesc(desc);
|
||||
uint32_t old_value = (uint32_t)sd->AsIntSetting()->Read(old_object);
|
||||
uint32_t new_value = (uint32_t)sd->AsIntSetting()->Read(new_object);
|
||||
/*
|
||||
* This is called from a command, and since it contains local configuration information
|
||||
* that the rest of the clients do not know about, we need to circumvent the normal ::Post
|
||||
* local command validation and immediately send the command to the server.
|
||||
*/
|
||||
if (old_value != new_value) Command<CMD_CHANGE_COMPANY_SETTING>::SendNet(STR_NULL, _local_company, sd->GetName(), new_value);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user