Changeset - r28772:5bdd1bea8cf0
[Not reviewed]
master
0 2 0
Rubidium - 10 months ago 2024-02-16 06:28:32
rubidium@openttd.org
Codechange: Add support for NULL strings in SaveLoadCompat
2 files changed with 27 insertions and 11 deletions:
0 comments (0 inline, 0 general)
src/saveload/saveload.cpp
Show inline comments
 
@@ -614,27 +614,34 @@ static inline uint SlCalcConvMemLen(VarT
 
}
 

	
 
/**
 
 * Return the size in bytes of a certain type of normal/atomic variable
 
 * as it appears in a saved game. See VarTypes
 
 * @param conv VarType type of variable that is used for calculating the size
 
 * @return Return the size of this type in bytes
 
 */
 
static inline byte SlCalcConvFileLen(VarType conv)
 
{
 
	static const byte conv_file_size[] = {0, 1, 1, 2, 2, 4, 4, 8, 8, 2};
 

	
 
	uint8_t type = GetVarFileType(conv);
 
	assert(type < lengthof(conv_file_size));
 
	return conv_file_size[type];
 
	switch (GetVarFileType(conv)) {
 
		case SLE_FILE_STRING:
 
			return SlReadArrayLength();
 

	
 
		default:
 
			uint8_t type = GetVarFileType(conv);
 
			if (type >= lengthof(conv_file_size)) fmt::println("{}", type);
 
			assert(type < lengthof(conv_file_size));
 
			return conv_file_size[type];
 
	}
 
}
 

	
 
/** Return the size in bytes of a reference (pointer) */
 
static inline size_t SlCalcRefLen()
 
{
 
	return IsSavegameVersionBefore(SLV_69) ? 2 : 4;
 
}
 

	
 
void SlSetArrayIndex(uint index)
 
{
 
	_sl.need_length = NL_WANTLENGTH;
 
	_sl.array_index = index;
 
@@ -1855,25 +1862,25 @@ std::vector<SaveLoad> SlCompatTableHeade
 
	for (auto &sld : slt) {
 
		/* All entries should have a name; otherwise the entry should just be removed. */
 
		assert(!sld.name.empty());
 

	
 
		key_lookup[sld.name].push_back(&sld);
 
	}
 

	
 
	for (auto &slc : slct) {
 
		if (slc.name.empty()) {
 
			/* In old savegames there can be data we no longer care for. We
 
			 * skip this by simply reading the amount of bytes indicated and
 
			 * send those to /dev/null. */
 
			saveloads.push_back({"", SL_NULL, SLE_FILE_U8 | SLE_VAR_NULL, slc.length, slc.version_from, slc.version_to, 0, nullptr, 0, nullptr});
 
			saveloads.push_back({"", SL_NULL, GetVarFileType(slc.null_type) | SLE_VAR_NULL, slc.null_length, slc.version_from, slc.version_to, 0, nullptr, 0, nullptr});
 
		} else {
 
			auto sld_it = key_lookup.find(slc.name);
 
			/* If this branch triggers, it means that an entry in the
 
			 * SaveLoadCompat list is not mentioned in the SaveLoad list. Did
 
			 * you rename a field in one and not in the other? */
 
			if (sld_it == key_lookup.end()) {
 
				/* This isn't an assert, as that leaves no information what
 
				 * field was to blame. This way at least we have breadcrumbs. */
 
				Debug(sl, 0, "internal error: saveload compatibility field '{}' not found", slc.name);
 
				SlErrorCorrupt("Internal error with savegame compatibility");
 
			}
 
			for (auto &sld : sld_it->second) {
src/saveload/saveload.h
Show inline comments
 
@@ -706,28 +706,29 @@ struct SaveLoad {
 
	std::shared_ptr<SaveLoadHandler> handler; ///< Custom handler for Save/Load procs.
 
};
 

	
 
/**
 
 * SaveLoad information for backwards compatibility.
 
 *
 
 * At SLV_SETTINGS_NAME a new method of keeping track of fields in a savegame
 
 * was added, where the order of fields is no longer important. For older
 
 * savegames we still need to know the correct order. This struct is the glue
 
 * to make that happen.
 
 */
 
struct SaveLoadCompat {
 
	std::string name;             ///< Name of the field.
 
	uint16_t length;                ///< Length of the NULL field.
 
	std::string name; ///< Name of the field.
 
	VarTypes null_type; ///< The type associated with the NULL field; defaults to SLE_FILE_U8 to just count bytes.
 
	uint16_t null_length; ///< Length of the NULL field.
 
	SaveLoadVersion version_from; ///< Save/load the variable starting from this savegame version.
 
	SaveLoadVersion version_to;   ///< Save/load the variable before this savegame version.
 
	SaveLoadVersion version_to; ///< Save/load the variable before this savegame version.
 
};
 

	
 
/**
 
 * Get the NumberType of a setting. This describes the integer type
 
 * as it is represented in memory
 
 * @param type VarType holding information about the variable-type
 
 * @return the SLE_VAR_* part of a variable-type description
 
 */
 
inline constexpr VarType GetVarMemType(VarType type)
 
{
 
	return GB(type, 4, 4) << 4;
 
}
 
@@ -1174,36 +1175,44 @@ inline constexpr bool SlCheckVarSize(Sav
 

	
 
/**
 
 * Storage of a list of structs in every savegame version.
 
 * @param name    The name of the field.
 
 * @param handler SaveLoadHandler for the list of structs.
 
 */
 
#define SLEG_STRUCTLIST(name, handler) SLEG_CONDSTRUCTLIST(name, handler, SL_MIN_VERSION, SL_MAX_VERSION)
 

	
 
/**
 
 * Field name where the real SaveLoad can be located.
 
 * @param name The name of the field.
 
 */
 
#define SLC_VAR(name) {name, 0, SL_MIN_VERSION, SL_MAX_VERSION}
 
#define SLC_VAR(name) {name, SLE_FILE_U8, 0, SL_MIN_VERSION, SL_MAX_VERSION}
 

	
 
/**
 
 * Empty space in every savegame version.
 
 * @param length Length of the empty space.
 
 * @param length Length of the empty space in bytes.
 
 * @param from   First savegame version that has the empty space.
 
 * @param to     Last savegame version that has the empty space.
 
 */
 
#define SLC_NULL(length, from, to) {{}, length, from, to}
 
#define SLC_NULL(length, from, to) {{}, SLE_FILE_U8, length, from, to}
 

	
 
/**
 
 * Empty space in every savegame version that was filled with a string.
 
 * @param length Number of strings in the empty space.
 
 * @param from   First savegame version that has the empty space.
 
 * @param to     Last savegame version that has the empty space.
 
 */
 
#define SLC_NULL_STR(length, from, to) {{}, SLE_FILE_STRING, length, from, to}
 

	
 
/** End marker of compat variables save or load. */
 
#define SLC_END() {{}, 0, SL_MIN_VERSION, SL_MIN_VERSION}
 
#define SLC_END() {{}, 0, 0, SL_MIN_VERSION, SL_MIN_VERSION}
 

	
 
/**
 
 * Checks whether the savegame is below \a major.\a minor.
 
 * @param major Major number of the version to check against.
 
 * @param minor Minor number of the version to check against. If \a minor is 0 or not specified, only the major number is checked.
 
 * @return Savegame version is earlier than the specified version.
 
 */
 
inline bool IsSavegameVersionBefore(SaveLoadVersion major, byte minor = 0)
 
{
 
	extern SaveLoadVersion _sl_version;
 
	extern byte            _sl_minor_version;
 
	return _sl_version < major || (minor > 0 && _sl_version == major && _sl_minor_version < minor);
0 comments (0 inline, 0 general)