File diff r25600:a0060616e61f → r25601:747c128b2f85
src/settings.cpp
Show inline comments
 
@@ -570,49 +570,49 @@ void ListSettingDesc::ParseValue(const I
 
}
 

	
 
/**
 
 * Save the values of settings to the inifile.
 
 * @param ini pointer to IniFile structure
 
 * @param sd read-only SettingDesc structure which contains the unmodified,
 
 *        loaded values of the configuration file and various information about it
 
 * @param grpname holds the name of the group (eg. [network]) where these will be saved
 
 * @param object pointer to the object been saved
 
 * The function works as follows: for each item in the SettingDesc structure we
 
 * have a look if the value has changed since we started the game (the original
 
 * values are reloaded when saving). If settings indeed have changed, we get
 
 * these and save them.
 
 */
 
static void IniSaveSettings(IniFile *ini, const SettingTable &settings_table, const char *grpname, void *object, bool)
 
{
 
	IniGroup *group_def = nullptr, *group;
 
	IniItem *item;
 
	char buf[512];
 

	
 
	for (auto &sd : settings_table) {
 
		/* 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->save.conv & SLF_NOT_IN_CONFIG) continue;
 
		if (sd->flags & SF_NOT_IN_CONFIG) continue;
 

	
 
		/* XXX - wtf is this?? (group override?) */
 
		std::string s{ sd->name };
 
		auto sc = s.find('.');
 
		if (sc != std::string::npos) {
 
			group = ini->GetGroup(s.substr(0, sc));
 
			s = s.substr(sc + 1);
 
		} else {
 
			if (group_def == nullptr) group_def = ini->GetGroup(grpname);
 
			group = group_def;
 
		}
 

	
 
		item = group->GetItem(s, true);
 

	
 
		if (!item->value.has_value() || !sd->IsSameValue(item, object)) {
 
			/* Value has changed, get the new value and put it into a buffer */
 
			sd->FormatValue(buf, lastof(buf), object);
 

	
 
			/* The value is different, that means we have to write it to the ini */
 
			item->value.emplace(buf);
 
		}
 
	}
 
}
 

	
 
@@ -720,66 +720,66 @@ static void IniSaveSettingList(IniFile *
 
 */
 
void IniLoadWindowSettings(IniFile *ini, const char *grpname, void *desc)
 
{
 
	IniLoadSettings(ini, _window_settings, grpname, desc, false);
 
}
 

	
 
/**
 
 * Save a WindowDesc to config.
 
 * @param ini IniFile handle to the ini file where the destination data is saved
 
 * @param grpname character string identifying the section-header of the ini file
 
 * @param desc Source WindowDesc
 
 */
 
void IniSaveWindowSettings(IniFile *ini, const char *grpname, void *desc)
 
{
 
	IniSaveSettings(ini, _window_settings, grpname, desc, false);
 
}
 

	
 
/**
 
 * Check whether the setting is editable in the current gamemode.
 
 * @param do_command true if this is about checking a command from the server.
 
 * @return true if editable.
 
 */
 
bool SettingDesc::IsEditable(bool do_command) const
 
{
 
	if (!do_command && !(this->save.conv & SLF_NO_NETWORK_SYNC) && _networking && !_network_server && !(this->flags & SF_PER_COMPANY)) return false;
 
	if (!do_command && !(this->flags & SF_NO_NETWORK_SYNC) && _networking && !_network_server && !(this->flags & SF_PER_COMPANY)) 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) &&
 
			(_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;
 
	return true;
 
}
 

	
 
/**
 
 * Return the type of the setting.
 
 * @return type of setting
 
 */
 
SettingType SettingDesc::GetType() const
 
{
 
	if (this->flags & SF_PER_COMPANY) return ST_COMPANY;
 
	return (this->save.conv & SLF_NOT_IN_SAVE) ? ST_CLIENT : ST_GAME;
 
	return (this->flags & SF_NOT_IN_SAVE) ? ST_CLIENT : ST_GAME;
 
}
 

	
 
/**
 
 * Get the setting description of this setting as an integer setting.
 
 * @return The integer setting description.
 
 */
 
const IntSettingDesc *SettingDesc::AsIntSetting() const
 
{
 
	assert(this->IsIntSetting());
 
	return static_cast<const IntSettingDesc *>(this);
 
}
 

	
 
/**
 
 * Get the setting description of this setting as a string setting.
 
 * @return The string setting description.
 
 */
 
const StringSettingDesc *SettingDesc::AsStringSetting() const
 
{
 
	assert(this->IsStringSetting());
 
	return static_cast<const StringSettingDesc *>(this);
 
}
 

	
 
/* Begin - Callback Functions for the various settings. */
 

	
 
@@ -1823,49 +1823,49 @@ CommandCost CmdChangeCompanySetting(Tile
 

	
 
/**
 
 * Top function to save the new value of an element of the Settings struct
 
 * @param index offset in the SettingDesc array of the Settings struct which
 
 * identifies the setting member we want to change
 
 * @param value new value of the setting
 
 * @param force_newgame force the newgame settings
 
 */
 
bool SetSettingValue(const IntSettingDesc *sd, int32 value, bool force_newgame)
 
{
 
	const IntSettingDesc *setting = sd->AsIntSetting();
 
	if ((setting->flags & SF_PER_COMPANY) != 0) {
 
		if (Company::IsValidID(_local_company) && _game_mode != GM_MENU) {
 
			return DoCommandP(0, 0, value, CMD_CHANGE_COMPANY_SETTING, nullptr, setting->name);
 
		}
 

	
 
		setting->ChangeValue(&_settings_client.company, value);
 
		return true;
 
	}
 

	
 
	/* If an item is company-based, we do not send it over the network
 
	 * (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->save.conv & SLF_NO_NETWORK_SYNC) {
 
	if (setting->flags & SF_NO_NETWORK_SYNC) {
 
		if (_game_mode != GM_MENU) {
 
			setting->ChangeValue(&_settings_newgame, value);
 
		}
 
		setting->ChangeValue(&GetGameSettings(), value);
 
		return true;
 
	}
 

	
 
	if (force_newgame) {
 
		setting->ChangeValue(&_settings_newgame, value);
 
		return true;
 
	}
 

	
 
	/* send non-company-based settings over the network */
 
	if (!_networking || (_networking && _network_server)) {
 
		return DoCommandP(0, 0, value, CMD_CHANGE_SETTING, nullptr, setting->name);
 
	}
 
	return false;
 
}
 

	
 
/**
 
 * Set the company settings for a new company to their default values.
 
 */
 
void SetDefaultCompanySettings(CompanyID cid)
 
{
 
@@ -1878,49 +1878,49 @@ void SetDefaultCompanySettings(CompanyID
 

	
 
/**
 
 * Sync all company settings in a multiplayer game.
 
 */
 
void SyncCompanySettings()
 
{
 
	const void *old_object = &Company::Get(_current_company)->settings;
 
	const void *new_object = &_settings_client.company;
 
	for (auto &sd : _company_settings) {
 
		uint32 old_value = (uint32)sd->AsIntSetting()->Read(new_object);
 
		uint32 new_value = (uint32)sd->AsIntSetting()->Read(old_object);
 
		if (old_value != new_value) NetworkSendCommand(0, 0, new_value, CMD_CHANGE_COMPANY_SETTING, nullptr, sd->name, _local_company);
 
	}
 
}
 

	
 
/**
 
 * Set a setting value with a string.
 
 * @param sd the setting to change.
 
 * @param value the value to write
 
 * @param force_newgame force the newgame settings
 
 * @note Strings WILL NOT be synced over the network
 
 */
 
bool SetSettingValue(const StringSettingDesc *sd, std::string value, bool force_newgame)
 
{
 
	assert(sd->save.conv & SLF_NO_NETWORK_SYNC);
 
	assert(sd->flags & SF_NO_NETWORK_SYNC);
 

	
 
	if (GetVarMemType(sd->save.conv) == SLE_VAR_STRQ && value.compare("(null)") == 0) {
 
		value.clear();
 
	}
 

	
 
	const void *object = (_game_mode == GM_MENU || force_newgame) ? &_settings_newgame : &_settings_game;
 
	sd->AsStringSetting()->ChangeValue(object, value);
 
	return true;
 
}
 

	
 
/**
 
 * Handle changing a string value. This performs validation of the input value
 
 * and calls the appropriate callbacks, and saves it when the value is changed.
 
 * @param object The object the setting is in.
 
 * @param newval The new value for the setting.
 
 */
 
void StringSettingDesc::ChangeValue(const void *object, std::string &newval) const
 
{
 
	this->MakeValueValid(newval);
 
	if (this->pre_check != nullptr && !this->pre_check(newval)) return;
 

	
 
	this->Write(object, newval);
 
	if (this->post_callback != nullptr) this->post_callback(newval);
 

	
 
@@ -2002,86 +2002,86 @@ void IConsoleGetSetting(const char *name
 
void IConsoleListSettings(const char *prefilter)
 
{
 
	IConsolePrintF(CC_WARNING, "All settings with their current value:");
 

	
 
	for (auto &sd : _settings) {
 
		if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue;
 
		if (prefilter != nullptr && strstr(sd->name, prefilter) == nullptr) continue;
 
		char value[80];
 
		sd->FormatValue(value, lastof(value), &GetGameSettings());
 
		IConsolePrintF(CC_DEFAULT, "%s = %s", sd->name, value);
 
	}
 

	
 
	IConsolePrintF(CC_WARNING, "Use 'setting' command to change a value");
 
}
 

	
 
/**
 
 * Save and load handler for settings
 
 * @param settings SettingDesc struct containing all information
 
 * @param object can be either nullptr in which case we load global variables or
 
 * a pointer to a struct which is getting saved
 
 */
 
static void LoadSettings(const SettingTable &settings, void *object)
 
{
 
	for (auto &osd : settings) {
 
		if (osd->save.conv & SLF_NOT_IN_SAVE) continue;
 
		if (osd->flags & SF_NOT_IN_SAVE) continue;
 

	
 
		SaveLoad sl = osd->save;
 
		if ((osd->save.conv & SLF_NO_NETWORK_SYNC) && _networking && !_network_server) {
 
		if ((osd->flags & SF_NO_NETWORK_SYNC) && _networking && !_network_server) {
 
			/* We don't want to read this setting, so we do need to skip over it. */
 
			sl = SLE_NULL(static_cast<uint16>(SlCalcConvMemLen(osd->save.conv) * osd->save.length));
 
		}
 

	
 
		void *ptr = GetVariableAddress(object, sl);
 
		if (!SlObjectMember(ptr, sl)) continue;
 

	
 
		if (osd->IsIntSetting()) {
 
			const IntSettingDesc *int_setting = osd->AsIntSetting();
 
			int_setting->MakeValueValidAndWrite(object, int_setting->Read(object));
 
		}
 
	}
 
}
 

	
 
/**
 
 * Save and load handler for settings
 
 * @param settings SettingDesc struct containing all information
 
 * @param object can be either nullptr in which case we load global variables or
 
 * a pointer to a struct which is getting saved
 
 */
 
static void SaveSettings(const SettingTable &settings, void *object)
 
{
 
	/* We need to write the CH_RIFF header, but unfortunately can't call
 
	 * SlCalcLength() because we have a different format. So do this manually */
 
	size_t length = 0;
 
	for (auto &sd : settings) {
 
		if (sd->save.conv & SLF_NOT_IN_SAVE) continue;
 
		if (sd->flags & SF_NOT_IN_SAVE) continue;
 

	
 
		length += SlCalcObjMemberLength(object, sd->save);
 
	}
 
	SlSetLength(length);
 

	
 
	for (auto &sd : settings) {
 
		if (sd->save.conv & SLF_NOT_IN_SAVE) continue;
 
		if (sd->flags & SF_NOT_IN_SAVE) continue;
 

	
 
		void *ptr = GetVariableAddress(object, sd->save);
 
		SlObjectMember(ptr, sd->save);
 
	}
 
}
 

	
 
static void Load_OPTS()
 
{
 
	/* Copy over default setting since some might not get loaded in
 
	 * a networking environment. This ensures for example that the local
 
	 * autosave-frequency stays when joining a network-server */
 
	PrepareOldDiffCustom();
 
	LoadSettings(_gameopt_settings, &_settings_game);
 
	HandleOldDiffCustom(true);
 
}
 

	
 
static void Load_PATS()
 
{
 
	/* Copy over default setting since some might not get loaded in
 
	 * a networking environment. This ensures for example that the local
 
	 * currency setting stays when joining a network-server */
 
	LoadSettings(_settings, &_settings_game);
 
}