Merge remote-tracking branch 'upstream/master'
This commit is contained in:
372
src/settings.cpp
372
src/settings.cpp
@@ -33,6 +33,7 @@
|
||||
#include "console_func.h"
|
||||
#include "genworld.h"
|
||||
#include "string_func.h"
|
||||
#include "strings_func.h"
|
||||
#include "window_func.h"
|
||||
#include "company_func.h"
|
||||
#include "rev.h"
|
||||
@@ -45,6 +46,7 @@
|
||||
#include "newgrf_config.h"
|
||||
#include "picker_func.h"
|
||||
#include "base_media_base.h"
|
||||
#include "base_media_graphics.h"
|
||||
#include "fios.h"
|
||||
#include "fileio_func.h"
|
||||
#include "settings_cmd.h"
|
||||
@@ -190,7 +192,7 @@ size_t OneOfManySettingDesc::ParseSingleValue(const char *str, size_t len, const
|
||||
if (isdigit(*str)) return std::strtoul(str, nullptr, 0);
|
||||
|
||||
size_t idx = 0;
|
||||
for (auto one : many) {
|
||||
for (const auto &one : many) {
|
||||
if (one.size() == len && strncmp(one.c_str(), str, len) == 0) return idx;
|
||||
idx++;
|
||||
}
|
||||
@@ -383,16 +385,15 @@ size_t IntSettingDesc::ParseValue(const char *str) const
|
||||
char *end;
|
||||
size_t val = std::strtoul(str, &end, 0);
|
||||
if (end == str) {
|
||||
ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_VALUE);
|
||||
msg.SetDParamStr(0, str);
|
||||
msg.SetDParamStr(1, this->GetName());
|
||||
_settings_error_list.push_back(msg);
|
||||
return this->def;
|
||||
_settings_error_list.emplace_back(
|
||||
GetEncodedString(STR_CONFIG_ERROR),
|
||||
GetEncodedString(STR_CONFIG_ERROR_INVALID_VALUE, str, this->GetName()));
|
||||
return this->GetDefaultValue();
|
||||
}
|
||||
if (*end != '\0') {
|
||||
ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_TRAILING_CHARACTERS);
|
||||
msg.SetDParamStr(0, this->GetName());
|
||||
_settings_error_list.push_back(msg);
|
||||
_settings_error_list.emplace_back(
|
||||
GetEncodedString(STR_CONFIG_ERROR),
|
||||
GetEncodedString(STR_CONFIG_ERROR_TRAILING_CHARACTERS, this->GetName()));
|
||||
}
|
||||
return val;
|
||||
}
|
||||
@@ -405,22 +406,21 @@ size_t OneOfManySettingDesc::ParseValue(const char *str) const
|
||||
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);
|
||||
msg.SetDParamStr(1, this->GetName());
|
||||
_settings_error_list.push_back(msg);
|
||||
return this->def;
|
||||
_settings_error_list.emplace_back(
|
||||
GetEncodedString(STR_CONFIG_ERROR),
|
||||
GetEncodedString(STR_CONFIG_ERROR_INVALID_VALUE, str, this->GetName()));
|
||||
return this->GetDefaultValue();
|
||||
}
|
||||
|
||||
size_t ManyOfManySettingDesc::ParseValue(const char *str) const
|
||||
{
|
||||
size_t r = LookupManyOfMany(this->many, str);
|
||||
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());
|
||||
_settings_error_list.push_back(msg);
|
||||
return this->def;
|
||||
|
||||
_settings_error_list.emplace_back(
|
||||
GetEncodedString(STR_CONFIG_ERROR),
|
||||
GetEncodedString(STR_CONFIG_ERROR_INVALID_VALUE, str, this->GetName()));
|
||||
return this->GetDefaultValue();
|
||||
}
|
||||
|
||||
size_t BoolSettingDesc::ParseValue(const char *str) const
|
||||
@@ -428,11 +428,10 @@ size_t BoolSettingDesc::ParseValue(const char *str) const
|
||||
auto r = BoolSettingDesc::ParseSingleValue(str);
|
||||
if (r.has_value()) return *r;
|
||||
|
||||
ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_VALUE);
|
||||
msg.SetDParamStr(0, str);
|
||||
msg.SetDParamStr(1, this->GetName());
|
||||
_settings_error_list.push_back(msg);
|
||||
return this->def;
|
||||
_settings_error_list.emplace_back(
|
||||
GetEncodedString(STR_CONFIG_ERROR),
|
||||
GetEncodedString(STR_CONFIG_ERROR_INVALID_VALUE, str, this->GetName()));
|
||||
return this->GetDefaultValue();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -455,24 +454,43 @@ StringID IntSettingDesc::GetHelp() const
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the DParams for drawing the value of the setting.
|
||||
* @param first_param First DParam to use
|
||||
* Get parameters for drawing the value of the setting.
|
||||
* @param value Setting value to set params for.
|
||||
*/
|
||||
void IntSettingDesc::SetValueDParams(uint first_param, int32_t value) const
|
||||
std::pair<StringParameter, StringParameter> IntSettingDesc::GetValueParams(int32_t value) const
|
||||
{
|
||||
if (this->set_value_dparams_cb != nullptr) {
|
||||
this->set_value_dparams_cb(*this, first_param, value);
|
||||
} else if (this->IsBoolSetting()) {
|
||||
SetDParam(first_param++, value != 0 ? STR_CONFIG_SETTING_ON : STR_CONFIG_SETTING_OFF);
|
||||
} else {
|
||||
if ((this->flags & SF_GUI_DROPDOWN) != 0) {
|
||||
SetDParam(first_param++, this->str_val - this->min + value);
|
||||
} else {
|
||||
SetDParam(first_param++, this->str_val + ((value == 0 && (this->flags & SF_GUI_0_IS_SPECIAL) != 0) ? 1 : 0));
|
||||
}
|
||||
SetDParam(first_param++, value);
|
||||
if (this->get_value_params_cb != nullptr) {
|
||||
return this->get_value_params_cb(*this, value);
|
||||
}
|
||||
|
||||
if (this->IsBoolSetting()) {
|
||||
return {value != 0 ? STR_CONFIG_SETTING_ON : STR_CONFIG_SETTING_OFF, {}};
|
||||
}
|
||||
|
||||
if (this->flags.Test(SettingFlag::GuiDropdown)) {
|
||||
auto [min_val, _] = this->GetRange();
|
||||
return {this->str_val - min_val + value, value};
|
||||
}
|
||||
|
||||
return {this->str_val + ((value == 0 && this->flags.Test(SettingFlag::GuiZeroIsSpecial)) ? 1 : 0), value};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default value of the setting.
|
||||
* @return The default value.
|
||||
*/
|
||||
int32_t IntSettingDesc::GetDefaultValue() const
|
||||
{
|
||||
return this->get_def_cb != nullptr ? this->get_def_cb(*this) : this->def;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the min/max range for the setting.
|
||||
* @return The min/max range.
|
||||
*/
|
||||
std::tuple<int32_t, uint32_t> IntSettingDesc::GetRange() const
|
||||
{
|
||||
return this->get_range_cb != nullptr ? this->get_range_cb(*this) : std::tuple(this->min, this->max);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -491,13 +509,14 @@ void IntSettingDesc::MakeValueValidAndWrite(const void *object, int32_t val) con
|
||||
* Make the value valid given the limitations of this setting.
|
||||
*
|
||||
* In the case of int settings this is ensuring the value is between the minimum and
|
||||
* maximum value, with a special case for 0 if SF_GUI_0_IS_SPECIAL is set.
|
||||
* maximum value, with a special case for 0 if SettingFlag::GuiZeroIsSpecial is set.
|
||||
* This is generally done by clamping the value so it is within the allowed value range.
|
||||
* However, for SF_GUI_DROPDOWN the default is used when the value is not valid.
|
||||
* However, for SettingFlag::GuiDropdown the default is used when the value is not valid.
|
||||
* @param val The value to make valid.
|
||||
*/
|
||||
void IntSettingDesc::MakeValueValid(int32_t &val) const
|
||||
{
|
||||
auto [min_val, max_val] = this->GetRange();
|
||||
/* We need to take special care of the uint32_t type as we receive from the function
|
||||
* a signed integer. While here also bail out on 64-bit settings as those are not
|
||||
* supported. Unsigned 8 and 16-bit variables are safe since they fit into a signed
|
||||
@@ -512,30 +531,30 @@ void IntSettingDesc::MakeValueValid(int32_t &val) const
|
||||
case SLE_VAR_U16:
|
||||
case SLE_VAR_I32: {
|
||||
/* Override the minimum value. No value below this->min, except special value 0 */
|
||||
if (!(this->flags & SF_GUI_0_IS_SPECIAL) || val != 0) {
|
||||
if (!(this->flags & SF_GUI_DROPDOWN)) {
|
||||
if (!this->flags.Test(SettingFlag::GuiZeroIsSpecial) || val != 0) {
|
||||
if (!this->flags.Test(SettingFlag::GuiDropdown)) {
|
||||
/* Clamp value-type setting to its valid range */
|
||||
val = Clamp(val, this->min, this->max);
|
||||
} else if (val < this->min || val > (int32_t)this->max) {
|
||||
val = Clamp(val, min_val, max_val);
|
||||
} else if (val < min_val || val > static_cast<int32_t>(max_val)) {
|
||||
/* Reset invalid discrete setting (where different values change gameplay) to its default value */
|
||||
val = this->def;
|
||||
val = this->GetDefaultValue();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SLE_VAR_U32: {
|
||||
/* Override the minimum value. No value below this->min, except special value 0 */
|
||||
uint32_t uval = (uint32_t)val;
|
||||
if (!(this->flags & SF_GUI_0_IS_SPECIAL) || uval != 0) {
|
||||
if (!(this->flags & SF_GUI_DROPDOWN)) {
|
||||
uint32_t uval = static_cast<uint32_t>(val);
|
||||
if (!this->flags.Test(SettingFlag::GuiZeroIsSpecial) || uval != 0) {
|
||||
if (!this->flags.Test(SettingFlag::GuiDropdown)) {
|
||||
/* Clamp value-type setting to its valid range */
|
||||
uval = ClampU(uval, this->min, this->max);
|
||||
} else if (uval < (uint)this->min || uval > this->max) {
|
||||
uval = ClampU(uval, min_val, max_val);
|
||||
} else if (uval < static_cast<uint32_t>(min_val) || uval > max_val) {
|
||||
/* Reset invalid discrete setting to its default value */
|
||||
uval = (uint32_t)this->def;
|
||||
uval = static_cast<uint32_t>(this->GetDefaultValue());
|
||||
}
|
||||
}
|
||||
val = (int32_t)uval;
|
||||
val = static_cast<int32_t>(uval);
|
||||
return;
|
||||
}
|
||||
case SLE_VAR_I64:
|
||||
@@ -580,8 +599,8 @@ 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, 0, this->max_length - 1);
|
||||
str.assign(StrMakeValid(stdstr, SVS_NONE));
|
||||
str.erase(this->max_length - 1, std::string::npos);
|
||||
StrMakeValidInPlace(str, {});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -656,7 +675,7 @@ static void IniLoadSettings(IniFile &ini, const SettingTable &settings_table, co
|
||||
|
||||
void IntSettingDesc::ParseValue(const IniItem *item, void *object) const
|
||||
{
|
||||
size_t val = (item == nullptr) ? this->def : this->ParseValue(item->value.has_value() ? item->value->c_str() : "");
|
||||
size_t val = (item == nullptr) ? this->GetDefaultValue() : this->ParseValue(item->value.has_value() ? item->value->c_str() : "");
|
||||
this->MakeValueValidAndWrite(object, (int32_t)val);
|
||||
}
|
||||
|
||||
@@ -672,9 +691,9 @@ void ListSettingDesc::ParseValue(const IniItem *item, void *object) const
|
||||
const char *str = (item == nullptr) ? this->def : item->value.has_value() ? item->value->c_str() : nullptr;
|
||||
void *ptr = GetVariableAddress(object, this->save);
|
||||
if (!LoadIntList(str, ptr, this->save.length, GetVarMemType(this->save.conv))) {
|
||||
ErrorMessageData msg(STR_CONFIG_ERROR, STR_CONFIG_ERROR_ARRAY);
|
||||
msg.SetDParamStr(0, this->GetName());
|
||||
_settings_error_list.push_back(msg);
|
||||
_settings_error_list.emplace_back(
|
||||
GetEncodedString(STR_CONFIG_ERROR),
|
||||
GetEncodedString(STR_CONFIG_ERROR_ARRAY, this->GetName()));
|
||||
|
||||
/* Use default */
|
||||
LoadIntList(this->def, ptr, this->save.length, GetVarMemType(this->save.conv));
|
||||
@@ -702,7 +721,7 @@ static void IniSaveSettings(IniFile &ini, const SettingTable &settings_table, co
|
||||
/* If the setting is not saved to the configuration
|
||||
* file, just continue with the next setting */
|
||||
if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue;
|
||||
if (sd->flags & SF_NOT_IN_CONFIG) continue;
|
||||
if (sd->flags.Test(SettingFlag::NotInConfig)) continue;
|
||||
|
||||
/* XXX - wtf is this?? (group override?) */
|
||||
std::string s{ sd->GetName() };
|
||||
@@ -751,12 +770,12 @@ bool IntSettingDesc::IsSameValue(const IniItem *item, void *object) const
|
||||
bool IntSettingDesc::IsDefaultValue(void *object) const
|
||||
{
|
||||
int32_t object_value = this->Read(object);
|
||||
return this->def == object_value;
|
||||
return this->GetDefaultValue() == object_value;
|
||||
}
|
||||
|
||||
void IntSettingDesc::ResetToDefault(void *object) const
|
||||
{
|
||||
this->Write(object, this->def);
|
||||
this->Write(object, this->GetDefaultValue());
|
||||
}
|
||||
|
||||
std::string StringSettingDesc::FormatValue(const void *object) const
|
||||
@@ -884,14 +903,14 @@ void IniSaveWindowSettings(IniFile &ini, const char *grpname, void *desc)
|
||||
*/
|
||||
bool SettingDesc::IsEditable(bool do_command) const
|
||||
{
|
||||
if (!do_command && !(this->flags & SF_NO_NETWORK_SYNC) && _networking && !_network_server && !(this->flags & SF_PER_COMPANY)) return false;
|
||||
if (do_command && (this->flags & SF_NO_NETWORK_SYNC)) return false;
|
||||
if ((this->flags & SF_NETWORK_ONLY) && !_networking && _game_mode != GM_MENU) return false;
|
||||
if ((this->flags & SF_NO_NETWORK) && _networking) return false;
|
||||
if ((this->flags & SF_NEWGAME_ONLY) &&
|
||||
if (!do_command && !this->flags.Test(SettingFlag::NoNetworkSync) && _networking && !_network_server && !this->flags.Test(SettingFlag::PerCompany)) return false;
|
||||
if (do_command && this->flags.Test(SettingFlag::NoNetworkSync)) return false;
|
||||
if (this->flags.Test(SettingFlag::NetworkOnly) && !_networking && _game_mode != GM_MENU) return false;
|
||||
if (this->flags.Test(SettingFlag::NoNetwork) && _networking) return false;
|
||||
if (this->flags.Test(SettingFlag::NewgameOnly) &&
|
||||
(_game_mode == GM_NORMAL ||
|
||||
(_game_mode == GM_EDITOR && !(this->flags & SF_SCENEDIT_TOO)))) return false;
|
||||
if ((this->flags & SF_SCENEDIT_ONLY) && _game_mode != GM_EDITOR) return false;
|
||||
(_game_mode == GM_EDITOR && !this->flags.Test(SettingFlag::SceneditToo)))) return false;
|
||||
if (this->flags.Test(SettingFlag::SceneditOnly) && _game_mode != GM_EDITOR) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -901,8 +920,8 @@ bool SettingDesc::IsEditable(bool do_command) const
|
||||
*/
|
||||
SettingType SettingDesc::GetType() const
|
||||
{
|
||||
if (this->flags & SF_PER_COMPANY) return ST_COMPANY;
|
||||
return (this->flags & SF_NOT_IN_SAVE) ? ST_CLIENT : ST_GAME;
|
||||
if (this->flags.Test(SettingFlag::PerCompany)) return ST_COMPANY;
|
||||
return this->flags.Test(SettingFlag::NotInSave) ? ST_CLIENT : ST_GAME;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -944,14 +963,14 @@ static void AILoadConfig(const IniFile &ini, const char *grpname)
|
||||
const IniGroup *group = ini.GetGroup(grpname);
|
||||
|
||||
/* Clean any configured AI */
|
||||
for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) {
|
||||
for (CompanyID c = CompanyID::Begin(); c < MAX_COMPANIES; ++c) {
|
||||
AIConfig::GetConfig(c, AIConfig::SSS_FORCE_NEWGAME)->Change(std::nullopt);
|
||||
}
|
||||
|
||||
/* If no group exists, return */
|
||||
if (group == nullptr) return;
|
||||
|
||||
CompanyID c = COMPANY_FIRST;
|
||||
CompanyID c = CompanyID::Begin();
|
||||
for (const IniItem &item : group->items) {
|
||||
AIConfig *config = AIConfig::GetConfig(c, AIConfig::SSS_FORCE_NEWGAME);
|
||||
|
||||
@@ -963,7 +982,7 @@ static void AILoadConfig(const IniFile &ini, const char *grpname)
|
||||
}
|
||||
}
|
||||
if (item.value.has_value()) config->StringToSettings(*item.value);
|
||||
c++;
|
||||
++c;
|
||||
if (c >= MAX_COMPANIES) break;
|
||||
}
|
||||
}
|
||||
@@ -1007,7 +1026,7 @@ static void GraphicsSetLoadConfig(IniFile &ini)
|
||||
if (const IniItem *item = group->GetItem("name"); item != nullptr && item->value) BaseGraphics::ini_data.name = *item->value;
|
||||
|
||||
if (const IniItem *item = group->GetItem("shortname"); item != nullptr && item->value && item->value->size() == 8) {
|
||||
BaseGraphics::ini_data.shortname = BSWAP32(std::strtoul(item->value->c_str(), nullptr, 16));
|
||||
BaseGraphics::ini_data.shortname = std::byteswap<uint32_t>(std::strtoul(item->value->c_str(), nullptr, 16));
|
||||
}
|
||||
|
||||
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);
|
||||
@@ -1017,8 +1036,9 @@ static void GraphicsSetLoadConfig(IniFile &ini)
|
||||
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);
|
||||
ShowErrorMessage(GetEncodedString(STR_CONFIG_ERROR),
|
||||
GetEncodedString(STR_CONFIG_ERROR_ARRAY, BaseGraphics::ini_data.name),
|
||||
WL_CRITICAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1030,17 +1050,16 @@ static void GraphicsSetLoadConfig(IniFile &ini)
|
||||
* @param grpname Group name containing the configuration of the GRF.
|
||||
* @param is_static GRF is static.
|
||||
*/
|
||||
static GRFConfig *GRFLoadConfig(const IniFile &ini, const char *grpname, bool is_static)
|
||||
static GRFConfigList GRFLoadConfig(const IniFile &ini, const char *grpname, bool is_static)
|
||||
{
|
||||
const IniGroup *group = ini.GetGroup(grpname);
|
||||
GRFConfig *first = nullptr;
|
||||
GRFConfig **curr = &first;
|
||||
GRFConfigList list;
|
||||
|
||||
if (group == nullptr) return nullptr;
|
||||
if (group == nullptr) return list;
|
||||
|
||||
uint num_grfs = 0;
|
||||
for (const IniItem &item : group->items) {
|
||||
GRFConfig *c = nullptr;
|
||||
std::unique_ptr<GRFConfig> c{};
|
||||
|
||||
std::array<uint8_t, 4> grfid_buf;
|
||||
MD5Hash md5sum;
|
||||
@@ -1066,17 +1085,17 @@ static GRFConfig *GRFLoadConfig(const IniFile &ini, const char *grpname, bool is
|
||||
uint32_t grfid = grfid_buf[0] | (grfid_buf[1] << 8) | (grfid_buf[2] << 16) | (grfid_buf[3] << 24);
|
||||
if (has_md5sum) {
|
||||
const GRFConfig *s = FindGRFConfig(grfid, FGCM_EXACT, &md5sum);
|
||||
if (s != nullptr) c = new GRFConfig(*s);
|
||||
if (s != nullptr) c = std::make_unique<GRFConfig>(*s);
|
||||
}
|
||||
if (c == nullptr && !FioCheckFileExists(std::string(item_name), NEWGRF_DIR)) {
|
||||
const GRFConfig *s = FindGRFConfig(grfid, FGCM_NEWEST_VALID);
|
||||
if (s != nullptr) c = new GRFConfig(*s);
|
||||
if (s != nullptr) c = std::make_unique<GRFConfig>(*s);
|
||||
}
|
||||
}
|
||||
}
|
||||
std::string filename = std::string(item_name);
|
||||
|
||||
if (c == nullptr) c = new GRFConfig(filename);
|
||||
if (c == nullptr) c = std::make_unique<GRFConfig>(filename);
|
||||
|
||||
/* Parse parameters */
|
||||
if (item.value.has_value() && !item.value->empty()) {
|
||||
@@ -1084,62 +1103,57 @@ static GRFConfig *GRFLoadConfig(const IniFile &ini, const char *grpname, bool is
|
||||
if (params.has_value()) {
|
||||
c->SetParams(params.value());
|
||||
} else {
|
||||
SetDParamStr(0, filename);
|
||||
ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_ARRAY, WL_CRITICAL);
|
||||
ShowErrorMessage(GetEncodedString(STR_CONFIG_ERROR),
|
||||
GetEncodedString(STR_CONFIG_ERROR_ARRAY, filename),
|
||||
WL_CRITICAL);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if item is valid */
|
||||
if (!FillGRFDetails(c, is_static) || HasBit(c->flags, GCF_INVALID)) {
|
||||
if (!FillGRFDetails(*c, is_static) || c->flags.Test(GRFConfigFlag::Invalid)) {
|
||||
StringID reason;
|
||||
if (c->status == GCS_NOT_FOUND) {
|
||||
SetDParam(1, STR_CONFIG_ERROR_INVALID_GRF_NOT_FOUND);
|
||||
} else if (HasBit(c->flags, GCF_UNSAFE)) {
|
||||
SetDParam(1, STR_CONFIG_ERROR_INVALID_GRF_UNSAFE);
|
||||
} else if (HasBit(c->flags, GCF_SYSTEM)) {
|
||||
SetDParam(1, STR_CONFIG_ERROR_INVALID_GRF_SYSTEM);
|
||||
} else if (HasBit(c->flags, GCF_INVALID)) {
|
||||
SetDParam(1, STR_CONFIG_ERROR_INVALID_GRF_INCOMPATIBLE);
|
||||
reason = STR_CONFIG_ERROR_INVALID_GRF_NOT_FOUND;
|
||||
} else if (c->flags.Test(GRFConfigFlag::Unsafe)) {
|
||||
reason = STR_CONFIG_ERROR_INVALID_GRF_UNSAFE;
|
||||
} else if (c->flags.Test(GRFConfigFlag::System)) {
|
||||
reason = STR_CONFIG_ERROR_INVALID_GRF_SYSTEM;
|
||||
} else if (c->flags.Test(GRFConfigFlag::Invalid)) {
|
||||
reason = STR_CONFIG_ERROR_INVALID_GRF_INCOMPATIBLE;
|
||||
} else {
|
||||
SetDParam(1, STR_CONFIG_ERROR_INVALID_GRF_UNKNOWN);
|
||||
reason = STR_CONFIG_ERROR_INVALID_GRF_UNKNOWN;
|
||||
}
|
||||
|
||||
SetDParamStr(0, filename.empty() ? item.name.c_str() : filename);
|
||||
ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_INVALID_GRF, WL_CRITICAL);
|
||||
delete c;
|
||||
ShowErrorMessage(GetEncodedString(STR_CONFIG_ERROR),
|
||||
GetEncodedString(STR_CONFIG_ERROR_INVALID_GRF, filename.empty() ? item.name.c_str() : filename, reason),
|
||||
WL_CRITICAL);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Check for duplicate GRFID (will also check for duplicate filenames) */
|
||||
bool duplicate = false;
|
||||
for (const GRFConfig *gc = first; gc != nullptr; gc = gc->next) {
|
||||
if (gc->ident.grfid == c->ident.grfid) {
|
||||
SetDParamStr(0, c->filename);
|
||||
SetDParamStr(1, gc->filename);
|
||||
ShowErrorMessage(STR_CONFIG_ERROR, STR_CONFIG_ERROR_DUPLICATE_GRFID, WL_CRITICAL);
|
||||
duplicate = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (duplicate) {
|
||||
delete c;
|
||||
auto found = std::ranges::find_if(list, [&c](const auto &gc) { return gc->ident.grfid == c->ident.grfid; });
|
||||
if (found != std::end(list)) {
|
||||
ShowErrorMessage(GetEncodedString(STR_CONFIG_ERROR),
|
||||
GetEncodedString(STR_CONFIG_ERROR_DUPLICATE_GRFID, c->filename, (*found)->filename),
|
||||
WL_CRITICAL);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_static) {
|
||||
/* Mark file as static to avoid saving in savegame. */
|
||||
SetBit(c->flags, GCF_STATIC);
|
||||
c->flags.Set(GRFConfigFlag::Static);
|
||||
} else if (++num_grfs > NETWORK_MAX_GRF_COUNT) {
|
||||
/* Check we will not load more non-static NewGRFs than allowed. This could trigger issues for game servers. */
|
||||
ShowErrorMessage(STR_CONFIG_ERROR, STR_NEWGRF_ERROR_TOO_MANY_NEWGRFS_LOADED, WL_CRITICAL);
|
||||
ShowErrorMessage(GetEncodedString(STR_CONFIG_ERROR),
|
||||
GetEncodedString(STR_NEWGRF_ERROR_TOO_MANY_NEWGRFS_LOADED), WL_CRITICAL);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Add item to list */
|
||||
*curr = c;
|
||||
curr = &c->next;
|
||||
list.push_back(std::move(c));
|
||||
}
|
||||
|
||||
return first;
|
||||
return list;
|
||||
}
|
||||
|
||||
static IniFileVersion LoadVersionFromConfig(const IniFile &ini)
|
||||
@@ -1162,7 +1176,7 @@ static void AISaveConfig(IniFile &ini, const char *grpname)
|
||||
IniGroup &group = ini.GetOrCreateGroup(grpname);
|
||||
group.Clear();
|
||||
|
||||
for (CompanyID c = COMPANY_FIRST; c < MAX_COMPANIES; c++) {
|
||||
for (CompanyID c = CompanyID::Begin(); c < MAX_COMPANIES; ++c) {
|
||||
AIConfig *config = AIConfig::GetConfig(c, AIConfig::SSS_FORCE_NEWGAME);
|
||||
std::string name;
|
||||
std::string value = config->SettingsToString();
|
||||
@@ -1219,26 +1233,25 @@ static void GraphicsSetSaveConfig(IniFile &ini)
|
||||
group.Clear();
|
||||
|
||||
group.GetOrCreateItem("name").SetValue(used_set->name);
|
||||
group.GetOrCreateItem("shortname").SetValue(fmt::format("{:08X}", BSWAP32(used_set->shortname)));
|
||||
group.GetOrCreateItem("shortname").SetValue(fmt::format("{:08X}", std::byteswap(used_set->shortname)));
|
||||
|
||||
const GRFConfig *extra_cfg = used_set->GetExtraConfig();
|
||||
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));
|
||||
group.GetOrCreateItem("extra_params").SetValue(GRFBuildParamList(*extra_cfg));
|
||||
}
|
||||
}
|
||||
|
||||
/* Save a GRF configuration to the given group name */
|
||||
static void GRFSaveConfig(IniFile &ini, const char *grpname, const GRFConfig *list)
|
||||
static void GRFSaveConfig(IniFile &ini, const char *grpname, const GRFConfigList &list)
|
||||
{
|
||||
IniGroup &group = ini.GetOrCreateGroup(grpname);
|
||||
group.Clear();
|
||||
const GRFConfig *c;
|
||||
|
||||
for (c = list; c != nullptr; c = c->next) {
|
||||
std::string key = fmt::format("{:08X}|{}|{}", BSWAP32(c->ident.grfid),
|
||||
for (const auto &c : list) {
|
||||
std::string key = fmt::format("{:08X}|{}|{}", std::byteswap(c->ident.grfid),
|
||||
FormatArrayAsHex(c->ident.md5sum), c->filename);
|
||||
group.GetOrCreateItem(key).SetValue(GRFBuildParamList(c));
|
||||
group.GetOrCreateItem(key).SetValue(GRFBuildParamList(*c));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1540,13 +1553,13 @@ StringList GetGRFPresetList()
|
||||
* @return NewGRF configuration.
|
||||
* @see GetGRFPresetList
|
||||
*/
|
||||
GRFConfig *LoadGRFPresetFromConfig(const char *config_name)
|
||||
GRFConfigList LoadGRFPresetFromConfig(const char *config_name)
|
||||
{
|
||||
std::string section("preset-");
|
||||
section += config_name;
|
||||
|
||||
ConfigIniFile ini(_config_file);
|
||||
GRFConfig *config = GRFLoadConfig(ini, section.c_str(), false);
|
||||
GRFConfigList config = GRFLoadConfig(ini, section.c_str(), false);
|
||||
|
||||
return config;
|
||||
}
|
||||
@@ -1557,7 +1570,7 @@ GRFConfig *LoadGRFPresetFromConfig(const char *config_name)
|
||||
* @param config NewGRF configuration to save.
|
||||
* @see GetGRFPresetList
|
||||
*/
|
||||
void SaveGRFPresetToConfig(const char *config_name, GRFConfig *config)
|
||||
void SaveGRFPresetToConfig(const char *config_name, GRFConfigList &config)
|
||||
{
|
||||
std::string section("preset-");
|
||||
section += config_name;
|
||||
@@ -1597,13 +1610,14 @@ void IntSettingDesc::ChangeValue(const void *object, int32_t newval) const
|
||||
this->Write(object, newval);
|
||||
if (this->post_callback != nullptr) this->post_callback(newval);
|
||||
|
||||
if (this->flags & SF_NO_NETWORK) {
|
||||
if (this->flags.Test(SettingFlag::NoNetwork) || this->flags.Test(SettingFlag::Sandbox)) {
|
||||
_gamelog.StartAction(GLAT_SETTING);
|
||||
_gamelog.Setting(this->GetName(), oldval, newval);
|
||||
_gamelog.StopAction();
|
||||
}
|
||||
|
||||
SetWindowClassesDirty(WC_GAME_OPTIONS);
|
||||
if (this->flags.Test(SettingFlag::Sandbox)) SetWindowClassesDirty(WC_CHEATS);
|
||||
|
||||
if (_save_config) SaveToConfig();
|
||||
}
|
||||
@@ -1649,6 +1663,35 @@ void GetSaveLoadFromSettingTable(SettingTable settings, std::vector<SaveLoad> &s
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a single table with all settings that should be stored/loaded
|
||||
* in the savegame.
|
||||
*/
|
||||
SettingTable GetSaveLoadSettingTable()
|
||||
{
|
||||
static const SettingTable saveload_settings_tables[] = {
|
||||
_difficulty_settings,
|
||||
_economy_settings,
|
||||
_game_settings,
|
||||
_linkgraph_settings,
|
||||
_locale_settings,
|
||||
_pathfinding_settings,
|
||||
_script_settings,
|
||||
_world_settings,
|
||||
};
|
||||
static std::vector<SettingVariant> settings_table;
|
||||
|
||||
if (settings_table.empty()) {
|
||||
for (auto &saveload_settings_table : saveload_settings_tables) {
|
||||
for (auto &saveload_setting : saveload_settings_table) {
|
||||
settings_table.push_back(saveload_setting);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return settings_table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a name of setting, return a company setting description of it.
|
||||
* @param name Name of the company setting to return a setting description of.
|
||||
@@ -1686,6 +1729,27 @@ const SettingDesc *GetSettingFromName(const std::string_view name)
|
||||
return GetCompanySettingFromName(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a collection of settings matching a custom filter.
|
||||
* @param func Function to filter each setting.
|
||||
* @returns Vector containing the list of collections.
|
||||
*/
|
||||
std::vector<const SettingDesc *> GetFilteredSettingCollection(std::function<bool(const SettingDesc &desc)> func)
|
||||
{
|
||||
std::vector<const SettingDesc *> collection;
|
||||
|
||||
for (const auto &table : GenericSettingTables()) {
|
||||
for (const auto &desc : table) {
|
||||
const auto sd = GetSettingDesc(desc);
|
||||
if (!func(*sd)) continue;
|
||||
|
||||
collection.push_back(sd);
|
||||
}
|
||||
}
|
||||
|
||||
return collection;
|
||||
}
|
||||
|
||||
/**
|
||||
* Network-safe changing of settings (server-only).
|
||||
* @param flags operation to perform
|
||||
@@ -1695,7 +1759,7 @@ const SettingDesc *GetSettingFromName(const std::string_view name)
|
||||
* @return the cost of this operation or an error
|
||||
* @see _settings
|
||||
*/
|
||||
CommandCost CmdChangeSetting(DoCommandFlag flags, const std::string &name, int32_t value)
|
||||
CommandCost CmdChangeSetting(DoCommandFlags flags, const std::string &name, int32_t value)
|
||||
{
|
||||
if (name.empty()) return CMD_ERROR;
|
||||
const SettingDesc *sd = GetSettingFromName(name);
|
||||
@@ -1706,7 +1770,7 @@ CommandCost CmdChangeSetting(DoCommandFlag flags, const std::string &name, int32
|
||||
|
||||
if (!sd->IsEditable(true)) return CMD_ERROR;
|
||||
|
||||
if (flags & DC_EXEC) {
|
||||
if (flags.Test(DoCommandFlag::Execute)) {
|
||||
sd->AsIntSetting()->ChangeValue(&GetGameSettings(), value);
|
||||
}
|
||||
|
||||
@@ -1721,7 +1785,7 @@ CommandCost CmdChangeSetting(DoCommandFlag flags, const std::string &name, int32
|
||||
* The new value is properly clamped to its minimum/maximum when setting
|
||||
* @return the cost of this operation or an error
|
||||
*/
|
||||
CommandCost CmdChangeCompanySetting(DoCommandFlag flags, const std::string &name, int32_t value)
|
||||
CommandCost CmdChangeCompanySetting(DoCommandFlags flags, const std::string &name, int32_t value)
|
||||
{
|
||||
if (name.empty()) return CMD_ERROR;
|
||||
const SettingDesc *sd = GetCompanySettingFromName(name);
|
||||
@@ -1729,7 +1793,7 @@ CommandCost CmdChangeCompanySetting(DoCommandFlag flags, const std::string &name
|
||||
if (sd == nullptr) return CMD_ERROR;
|
||||
if (!sd->IsIntSetting()) return CMD_ERROR;
|
||||
|
||||
if (flags & DC_EXEC) {
|
||||
if (flags.Test(DoCommandFlag::Execute)) {
|
||||
sd->AsIntSetting()->ChangeValue(&Company::Get(_current_company)->settings, value);
|
||||
}
|
||||
|
||||
@@ -1746,7 +1810,7 @@ CommandCost CmdChangeCompanySetting(DoCommandFlag flags, const std::string &name
|
||||
bool SetSettingValue(const IntSettingDesc *sd, int32_t value, bool force_newgame)
|
||||
{
|
||||
const IntSettingDesc *setting = sd->AsIntSetting();
|
||||
if ((setting->flags & SF_PER_COMPANY) != 0) {
|
||||
if (setting->flags.Test(SettingFlag::PerCompany)) {
|
||||
if (Company::IsValidID(_local_company) && _game_mode != GM_MENU) {
|
||||
return Command<CMD_CHANGE_COMPANY_SETTING>::Post(setting->GetName(), value);
|
||||
}
|
||||
@@ -1759,7 +1823,7 @@ bool SetSettingValue(const IntSettingDesc *sd, int32_t value, bool force_newgame
|
||||
* (if any) to change. Also *hack*hack* we update the _newgame version
|
||||
* of settings because changing a company-based setting in a game also
|
||||
* changes its defaults. At least that is the convention we have chosen */
|
||||
if (setting->flags & SF_NO_NETWORK_SYNC) {
|
||||
if (setting->flags.Test(SettingFlag::NoNetworkSync)) {
|
||||
if (_game_mode != GM_MENU) {
|
||||
setting->ChangeValue(&_settings_newgame, value);
|
||||
}
|
||||
@@ -1785,9 +1849,10 @@ bool SetSettingValue(const IntSettingDesc *sd, int32_t value, bool force_newgame
|
||||
void SetDefaultCompanySettings(CompanyID cid)
|
||||
{
|
||||
Company *c = Company::Get(cid);
|
||||
AutoRestoreBackup backup(_current_company, cid);
|
||||
for (auto &desc : _company_settings) {
|
||||
const IntSettingDesc *int_setting = GetSettingDesc(desc)->AsIntSetting();
|
||||
int_setting->MakeValueValidAndWrite(&c->settings, int_setting->def);
|
||||
int_setting->MakeValueValidAndWrite(&c->settings, int_setting->GetDefaultValue());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1820,7 +1885,7 @@ void SyncCompanySettings()
|
||||
*/
|
||||
bool SetSettingValue(const StringSettingDesc *sd, std::string value, bool force_newgame)
|
||||
{
|
||||
assert(sd->flags & SF_NO_NETWORK_SYNC);
|
||||
assert(sd->flags.Test(SettingFlag::NoNetworkSync));
|
||||
|
||||
if (GetVarMemType(sd->save.conv) == SLE_VAR_STRQ && value.compare("(null)") == 0) {
|
||||
value.clear();
|
||||
@@ -1853,7 +1918,8 @@ void StringSettingDesc::ChangeValue(const void *object, std::string &newval) con
|
||||
void IConsoleSetSetting(const char *name, const char *value, bool force_newgame)
|
||||
{
|
||||
const SettingDesc *sd = GetSettingFromName(name);
|
||||
if (sd == nullptr) {
|
||||
/* Company settings are not in "list_settings", so don't try to modify them. */
|
||||
if (sd == nullptr || sd->flags.Test(SettingFlag::PerCompany)) {
|
||||
IConsolePrint(CC_ERROR, "'{}' is an unknown setting.", name);
|
||||
return;
|
||||
}
|
||||
@@ -1896,7 +1962,8 @@ void IConsoleSetSetting(const char *name, int value)
|
||||
void IConsoleGetSetting(const char *name, bool force_newgame)
|
||||
{
|
||||
const SettingDesc *sd = GetSettingFromName(name);
|
||||
if (sd == nullptr) {
|
||||
/* Company settings are not in "list_settings", so don't try to read them. */
|
||||
if (sd == nullptr || sd->flags.Test(SettingFlag::PerCompany)) {
|
||||
IConsolePrint(CC_ERROR, "'{}' is an unknown setting.", name);
|
||||
return;
|
||||
}
|
||||
@@ -1908,8 +1975,9 @@ void IConsoleGetSetting(const char *name, bool force_newgame)
|
||||
} else if (sd->IsIntSetting()) {
|
||||
std::string value = sd->FormatValue(object);
|
||||
const IntSettingDesc *int_setting = sd->AsIntSetting();
|
||||
auto [min_val, max_val] = int_setting->GetRange();
|
||||
IConsolePrint(CC_INFO, "Current value for '{}' is '{}' (min: {}{}, max: {}).",
|
||||
sd->GetName(), value, (sd->flags & SF_GUI_0_IS_SPECIAL) ? "(0) " : "", int_setting->min, int_setting->max);
|
||||
sd->GetName(), value, sd->flags.Test(SettingFlag::GuiZeroIsSpecial) ? "(0) " : "", min_val, max_val);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1944,3 +2012,31 @@ void IConsoleListSettings(const char *prefilter)
|
||||
|
||||
IConsolePrint(CC_HELP, "Use 'setting' command to change a value.");
|
||||
}
|
||||
|
||||
ScriptConfigSettings::ScriptConfigSettings()
|
||||
{
|
||||
/* Instantiate here, because unique_ptr needs a complete type. */
|
||||
}
|
||||
|
||||
ScriptConfigSettings::~ScriptConfigSettings()
|
||||
{
|
||||
/* Instantiate here, because unique_ptr needs a complete type. */
|
||||
}
|
||||
|
||||
ScriptConfigSettings::ScriptConfigSettings(const ScriptConfigSettings &other)
|
||||
{
|
||||
*this = other;
|
||||
}
|
||||
|
||||
ScriptConfigSettings &ScriptConfigSettings::operator=(const ScriptConfigSettings &other)
|
||||
{
|
||||
for (CompanyID c = CompanyID::Begin(); c < MAX_COMPANIES; ++c) {
|
||||
if (other.ai[c] != nullptr) {
|
||||
this->ai[c] = std::make_unique<AIConfig>(*other.ai[c]);
|
||||
}
|
||||
}
|
||||
if (other.game != nullptr) {
|
||||
this->game = std::make_unique<GameConfig>(*other.game);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user