Changeset - r25602:6ef361b0a726
[Not reviewed]
master
0 3 0
Patric Stout - 3 years ago 2021-06-07 21:03:12
truebrain@openttd.org
Codechange: make [Save|Load]Settings() behave more like other Save/Load code (#9335)

Prepare the full description and send it to SlObject. This does
require some code to be able to read to a SLE_VAR_NULL, like strings
etc, as there is no way to know their length beforehand.
3 files changed with 48 insertions and 30 deletions:
0 comments (0 inline, 0 general)
src/saveload/saveload.cpp
Show inline comments
 
@@ -581,13 +581,13 @@ static inline uint SlGetArrayLength(size
 
/**
 
 * Return the size in bytes of a certain type of normal/atomic variable
 
 * as it appears in memory. See VarTypes
 
 * @param conv VarType type of variable that is used for calculating the size
 
 * @return Return the size of this type in bytes
 
 */
 
uint SlCalcConvMemLen(VarType conv)
 
static inline uint SlCalcConvMemLen(VarType conv)
 
{
 
	static const byte conv_mem_size[] = {1, 1, 1, 2, 2, 4, 4, 8, 8, 0};
 
	byte length = GB(conv, 4, 4);
 

	
 
	switch (length << 4) {
 
		case SLE_VAR_STRB:
 
@@ -940,12 +940,15 @@ static void SlString(void *ptr, size_t l
 
		case SLA_LOAD_CHECK:
 
		case SLA_LOAD: {
 
			size_t len = SlReadArrayLength();
 

	
 
			switch (GetVarMemType(conv)) {
 
				default: NOT_REACHED();
 
				case SLE_VAR_NULL:
 
					SlSkipBytes(len);
 
					return;
 
				case SLE_VAR_STRB:
 
					if (len >= length) {
 
						DEBUG(sl, 1, "String length in savegame is bigger than buffer, truncating");
 
						SlCopyBytes(ptr, length);
 
						SlSkipBytes(len - length);
 
						len = length - 1;
 
@@ -1004,14 +1007,18 @@ static void SlStdString(void *ptr, VarTy
 
			break;
 
		}
 

	
 
		case SLA_LOAD_CHECK:
 
		case SLA_LOAD: {
 
			size_t len = SlReadArrayLength();
 
			if (GetVarMemType(conv) == SLE_VAR_NULL) {
 
				SlSkipBytes(len);
 
				return;
 
			}
 

	
 
			char *buf = AllocaM(char, len + 1);
 

	
 
			SlCopyBytes(buf, len);
 
			buf[len] = '\0'; // properly terminate the string
 

	
 
			StringValidationSettings settings = SVS_REPLACE_WITH_QUESTION_MARK;
 
			if ((conv & SLF_ALLOW_CONTROL) != 0) {
 
				settings = settings | SVS_ALLOW_CONTROL_CODE;
 
@@ -1466,12 +1473,14 @@ size_t SlCalcObjMemberLength(const void 
 
 * Check whether the variable size of the variable in the saveload configuration
 
 * matches with the actual variable size.
 
 * @param sld The saveload configuration to test.
 
 */
 
[[maybe_unused]] static bool IsVariableSizeRight(const SaveLoad &sld)
 
{
 
	if (GetVarMemType(sld.conv) == SLE_VAR_NULL) return true;
 

	
 
	switch (sld.cmd) {
 
		case SL_VAR:
 
			switch (GetVarMemType(sld.conv)) {
 
				case SLE_VAR_BL:
 
					return sld.size == sizeof(bool);
 
				case SLE_VAR_I8:
src/saveload/saveload.h
Show inline comments
 
@@ -890,13 +890,12 @@ static inline void *GetVariableAddress(c
 
int64 ReadValue(const void *ptr, VarType conv);
 
void WriteValue(void *ptr, VarType conv, int64 val);
 

	
 
void SlSetArrayIndex(uint index);
 
int SlIterateArray();
 

	
 
uint SlCalcConvMemLen(VarType conv);
 
void SlAutolength(AutolengthProc *proc, void *arg);
 
size_t SlGetFieldLength();
 
void SlSetLength(size_t length);
 
size_t SlCalcObjMemberLength(const void *object, const SaveLoad &sld);
 
size_t SlCalcObjLength(const void *object, const SaveLoadTable &slt);
 

	
src/settings.cpp
Show inline comments
 
@@ -2012,33 +2012,56 @@ void IConsoleListSettings(const char *pr
 
	}
 

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

	
 
/**
 
 * Get the SaveLoad description for the SettingTable.
 
 * @param settings SettingDesc struct containing all information.
 
 * @param is_loading True iff the SaveLoad table is for loading.
 
 * @return Vector with SaveLoad entries for the SettingTable.
 
 */
 
static std::vector<SaveLoad> GetSettingsDesc(const SettingTable &settings, bool is_loading)
 
{
 
	std::vector<SaveLoad> saveloads;
 
	for (auto &sd : settings) {
 
		if (sd->flags & SF_NOT_IN_SAVE) continue;
 

	
 
		if (is_loading && (sd->flags & SF_NO_NETWORK_SYNC) && _networking && !_network_server) {
 
			/* We don't want to read this setting, so we do need to skip over it. */
 
			saveloads.push_back({sd->save.cmd, GetVarFileType(sd->save.conv) | SLE_VAR_NULL, sd->save.length, sd->save.version_from, sd->save.version_to, 0, nullptr, 0});
 
			continue;
 
		}
 

	
 
		saveloads.push_back(sd->save);
 
	}
 

	
 
	return saveloads;
 
}
 

	
 

	
 
/**
 
 * 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->flags & SF_NOT_IN_SAVE) continue;
 
	const std::vector<SaveLoad> slt = GetSettingsDesc(settings, true);
 

	
 
	SlObject(object, slt);
 

	
 
		SaveLoad sl = osd->save;
 
		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));
 
		}
 
	/* Ensure all IntSettings are valid (min/max could have changed between versions etc). */
 
	for (auto &sd : settings) {
 
		if (sd->flags & SF_NOT_IN_SAVE) continue;
 
		if ((sd->flags & SF_NO_NETWORK_SYNC) && _networking && !_network_server) continue;
 
		if (!SlIsObjectCurrentlyValid(sd->save.version_from, sd->save.version_to)) continue;
 

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

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

	
 
/**
 
@@ -2046,28 +2069,15 @@ static void LoadSettings(const SettingTa
 
 * @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->flags & SF_NOT_IN_SAVE) continue;
 
	const std::vector<SaveLoad> slt = GetSettingsDesc(settings, false);
 

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

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

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

	
 
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
0 comments (0 inline, 0 general)