Merge remote-tracking branch 'upstream/master'

This commit is contained in:
dP
2025-06-14 17:01:17 +05:00
1132 changed files with 59430 additions and 52889 deletions

View File

@@ -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;
}