diff options
-rw-r--r-- | misc.c | 60 | ||||
-rw-r--r-- | saveload.c | 148 | ||||
-rw-r--r-- | saveload.h | 146 |
3 files changed, 197 insertions, 157 deletions
@@ -661,7 +661,7 @@ static void Load_NAME(void) static const SaveLoad _game_opt_desc[] = { // added a new difficulty option (town attitude) in version 4 SLE_CONDARR(GameOptions,diff, SLE_FILE_I16 | SLE_VAR_I32, 17, 0, 3), - SLE_CONDARR(GameOptions,diff, SLE_FILE_I16 | SLE_VAR_I32, 18, 4, 255), + SLE_CONDARR(GameOptions,diff, SLE_FILE_I16 | SLE_VAR_I32, 18, 4, SL_MAX_VERSION), SLE_VAR(GameOptions,diff_level, SLE_UINT8), SLE_VAR(GameOptions,currency, SLE_UINT8), SLE_VAR(GameOptions,kilometers, SLE_UINT8), @@ -681,26 +681,26 @@ static void SaveLoad_OPTS(void) static const SaveLoadGlobVarList _date_desc[] = { - {&_date, SLE_UINT16, 0, 255}, - {&_date_fract, SLE_UINT16, 0, 255}, - {&_tick_counter, SLE_UINT16, 0, 255}, - {&_vehicle_id_ctr_day, SLE_UINT16, 0, 255}, - {&_age_cargo_skip_counter, SLE_UINT8, 0, 255}, - {&_avail_aircraft, SLE_UINT8, 0, 255}, - {&_cur_tileloop_tile, SLE_FILE_U16 | SLE_VAR_U32, 0, 5}, - {&_cur_tileloop_tile, SLE_UINT32, 6, 255}, - {&_disaster_delay, SLE_UINT16, 0, 255}, - {&_station_tick_ctr, SLE_UINT16, 0, 255}, - {&_random_seeds[0][0], SLE_UINT32, 0, 255}, - {&_random_seeds[0][1], SLE_UINT32, 0, 255}, - {&_cur_town_ctr, SLE_FILE_U8 | SLE_VAR_U32, 0, 9}, - {&_cur_town_ctr, SLE_UINT32, 10, 255}, - {&_cur_player_tick_index, SLE_FILE_U8 | SLE_VAR_UINT, 0, 255}, - {&_next_competitor_start, SLE_FILE_U16 | SLE_VAR_UINT, 0, 255}, - {&_trees_tick_ctr, SLE_UINT8, 0, 255}, - {&_pause, SLE_UINT8, 4, 255}, - {&_cur_town_iter, SLE_UINT32, 11, 255}, - {NULL, 0, 0, 0} + SLEG_VAR(_date, SLE_UINT16), + SLEG_VAR(_date_fract, SLE_UINT16), + SLEG_VAR(_tick_counter, SLE_UINT16), + SLEG_VAR(_vehicle_id_ctr_day, SLE_UINT16), + SLEG_VAR(_age_cargo_skip_counter,SLE_UINT8), + SLEG_VAR(_avail_aircraft, SLE_UINT8), + SLEG_CONDVAR(_cur_tileloop_tile, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), + SLEG_CONDVAR(_cur_tileloop_tile, SLE_UINT32, 6, SL_MAX_VERSION), + SLEG_VAR(_disaster_delay, SLE_UINT16), + SLEG_VAR(_station_tick_ctr, SLE_UINT16), + SLEG_VAR(_random_seeds[0][0], SLE_UINT32), + SLEG_VAR(_random_seeds[0][1], SLE_UINT32), + SLEG_CONDVAR(_cur_town_ctr, SLE_FILE_U8 | SLE_VAR_U32, 0, 9), + SLEG_CONDVAR(_cur_town_ctr, SLE_UINT32, 10, SL_MAX_VERSION), + SLEG_VAR(_cur_player_tick_index, SLE_FILE_U8 | SLE_VAR_U32), + SLEG_VAR(_next_competitor_start, SLE_FILE_U16 | SLE_VAR_U32), + SLEG_VAR(_trees_tick_ctr, SLE_UINT8), + SLEG_CONDVAR(_pause, SLE_UINT8, 4, SL_MAX_VERSION), + SLEG_CONDVAR(_cur_town_iter, SLE_UINT32, 11, SL_MAX_VERSION), + SLEG_END() }; // Save load date related variables as well as persistent tick counters @@ -712,12 +712,12 @@ static void SaveLoad_DATE(void) static const SaveLoadGlobVarList _view_desc[] = { - {&_saved_scrollpos_x, SLE_FILE_I16 | SLE_VAR_INT, 0, 5}, - {&_saved_scrollpos_x, SLE_INT32, 6, 255}, - {&_saved_scrollpos_y, SLE_FILE_I16 | SLE_VAR_INT, 0, 5}, - {&_saved_scrollpos_y, SLE_INT32, 6, 255}, - {&_saved_scrollpos_zoom, SLE_UINT8, 0, 255}, - {NULL, 0, 0, 0} + SLEG_CONDVAR(_saved_scrollpos_x, SLE_FILE_I16 | SLE_VAR_I32, 0, 5), + SLEG_CONDVAR(_saved_scrollpos_x, SLE_INT32, 6, SL_MAX_VERSION), + SLEG_CONDVAR(_saved_scrollpos_y, SLE_FILE_I16 | SLE_VAR_I32, 0, 5), + SLEG_CONDVAR(_saved_scrollpos_y, SLE_INT32, 6, SL_MAX_VERSION), + SLEG_VAR(_saved_scrollpos_zoom,SLE_UINT8), + SLEG_END() }; static void SaveLoad_VIEW(void) @@ -729,9 +729,9 @@ static uint32 _map_dim_x; static uint32 _map_dim_y; static const SaveLoadGlobVarList _map_dimensions[] = { - {&_map_dim_x, SLE_UINT32, 6, 255}, - {&_map_dim_y, SLE_UINT32, 6, 255}, - {NULL, 0, 0, 0} + SLEG_CONDVAR(_map_dim_x, SLE_UINT32, 6, SL_MAX_VERSION), + SLEG_CONDVAR(_map_dim_y, SLE_UINT32, 6, SL_MAX_VERSION), + SLEG_END() }; static void Save_MAPS(void) diff --git a/saveload.c b/saveload.c index dff7fb681..5401e0ace 100644 --- a/saveload.c +++ b/saveload.c @@ -536,24 +536,82 @@ static size_t SlCalcObjLength(const SaveLoad *sld) // Need to determine the length and write a length tag. for (; sld->cmd != SL_END; sld++) { - if (sld->cmd < SL_WRITEBYTE) { + length += SlCalcObjMemberLength(sld); + } + return length; +} + +size_t SlCalcObjMemberLength(const SaveLoad *sld) +{ + assert(_sl.save); + + switch (sld->cmd) { + case SL_VAR: + case SL_REF: + case SL_ARR: /* CONDITIONAL saveload types depend on the savegame version */ - if (!SlIsObjectValidInSavegame(sld)) continue; + if (!SlIsObjectValidInSavegame(sld)) break; switch (sld->cmd) { - case SL_VAR: length += SlCalcConvFileLen(sld->type); break; - case SL_REF: length += SlCalcRefLen(); break; - case SL_ARR: length += SlCalcArrayLen(sld->length, sld->type); break; + case SL_VAR: return SlCalcConvFileLen(sld->conv); + case SL_REF: return SlCalcRefLen(); + case SL_ARR: return SlCalcArrayLen(sld->length, sld->conv); default: NOT_REACHED(); } - } else if (sld->cmd == SL_WRITEBYTE) { - length++; // a byte is logically of size 1 - } else if (sld->cmd == SL_INCLUDE) { - length += SlCalcObjLength(_sl.includes[sld->version_from]); - } else - assert(sld->cmd == SL_END); + break; + case SL_WRITEBYTE: return 1; // a byte is logically of size 1 + case SL_INCLUDE: return SlCalcObjLength(_sl.includes[sld->version_from]); + default: NOT_REACHED(); } - return length; + return 0; +} + +bool SlObjectMember(void *ptr, const SaveLoad *sld) +{ + VarType conv = GB(sld->conv, 0, 8); + switch (sld->cmd) { + case SL_VAR: + case SL_REF: + case SL_ARR: + /* CONDITIONAL saveload types depend on the savegame version */ + if (!SlIsObjectValidInSavegame(sld)) return false; + + switch (sld->cmd) { + case SL_VAR: SlSaveLoadConv(ptr, conv); break; + case SL_REF: /* Reference variable, translate */ + /// @todo XXX - another artificial limitof 65K elements of pointers? + if (_sl.save) { // XXX - read/write pointer as uint16? What is with higher indeces? + SlWriteUint16(_sl.ref_to_int_proc(*(void**)ptr, conv)); + } else + *(void**)ptr = _sl.int_to_ref_proc(SlReadUint16(), conv); + break; + case SL_ARR: SlArray(ptr, sld->length, conv); break; + default: NOT_REACHED(); + } + break; + + /* SL_WRITEBYTE translates a value of a variable to another one upon + * saving or loading. + * XXX - variable renaming abuse + * game_value: the value of the variable ingame is abused by sld->version_from + * file_value: the value of the variable in the savegame is abused by sld->version_to */ + case SL_WRITEBYTE: + if (_sl.save) { + SlWriteByte(sld->version_to); + } else { + *(byte*)ptr = sld->version_from; + } + break; + + /* SL_INCLUDE loads common code for a type + * XXX - variable renaming abuse + * include_index: common code to include from _desc_includes[], abused by sld->version_from */ + case SL_INCLUDE: + SlObject(ptr, _sl.includes[sld->version_from]); + break; + default: NOT_REACHED(); + } + return true; } /** @@ -570,76 +628,24 @@ void SlObject(void *object, const SaveLoad *sld) } for (; sld->cmd != SL_END; sld++) { - void *ptr = (byte*)object + sld->offset; - - if (sld->cmd < SL_WRITEBYTE) { - /* CONDITIONAL saveload types depend on the savegame version */ - if (!SlIsObjectValidInSavegame(sld)) continue; - - switch (sld->cmd) { - case SL_VAR: SlSaveLoadConv(ptr, sld->type); break; - case SL_REF: /* Reference variable, translate */ - /// @todo XXX - another artificial limitof 65K elements of pointers? - if (_sl.save) { // XXX - read/write pointer as uint16? What is with higher indeces? - SlWriteUint16(_sl.ref_to_int_proc(*(void**)ptr, sld->type)); - } else - *(void**)ptr = _sl.int_to_ref_proc(SlReadUint16(), sld->type); - break; - case SL_ARR: SlArray(ptr, sld->length, sld->type); break; - default: NOT_REACHED(); - } - - /* SL_WRITEBYTE translates a value of a variable to another one upon - * saving or loading. - * XXX - variable renaming abuse - * g_value: the value of the variable ingame is abused by sld->version_from - * f_value: the value of the variable in the savegame is abused by sld->version_to */ - } else if (sld->cmd == SL_WRITEBYTE) { - if (_sl.save) { - SlWriteByte(sld->version_to); - } else - *(byte*)ptr = sld->version_from; - /* SL_INCLUDE loads common code for a type - * XXX - variable renaming abuse - * include_index: common code to include from _desc_includes[], abused by sld->version_from */ - } else if (sld->cmd == SL_INCLUDE) { - SlObject(ptr, _sl.includes[sld->version_from]); - } else - assert(sld->cmd == SL_END); + void *ptr = (byte*)object + sld->s.offset; + SlObjectMember(ptr, sld); } } -/** Calculate the length of global variables - * @param desc The global variable that we want to know the size of - * @return Returns the length of the sought global object - */ -static size_t SlCalcGlobListLength(const SaveLoadGlobVarList *desc) -{ - size_t length = 0; - - for (; desc->address != NULL; desc++) { - // Of course the global variable must exist in the sought savegame version - if (_sl_version >= desc->from_version && _sl_version <= desc->to_version) - length += SlCalcConvFileLen(desc->conv); - } - return length; -} - /** * Save or Load (a list of) global variables * @param desc The global variable that is being loaded or saved */ -void SlGlobList(const SaveLoadGlobVarList *desc) +void SlGlobList(const SaveLoadGlobVarList *sldg) { if (_sl.need_length != NL_NONE) { - SlSetLength(SlCalcGlobListLength(desc)); - if (_sl.need_length == NL_CALCLENGTH) - return; + SlSetLength(SlCalcObjLength((const SaveLoad*)sldg)); + if (_sl.need_length == NL_CALCLENGTH) return; } - for (; desc->address != NULL; desc++) { - if (_sl_version >= desc->from_version && _sl_version <= desc->to_version) - SlSaveLoadConv(desc->address, desc->conv); + for (; sldg->cmd != SL_END; sldg++) { + SlObjectMember(sldg->s.address, (const SaveLoad*)sldg); } } diff --git a/saveload.h b/saveload.h index bcd6c6ad7..f2f04248d 100644 --- a/saveload.h +++ b/saveload.h @@ -23,13 +23,6 @@ void WaitTillSaved(void); typedef void ChunkSaveLoadProc(void); typedef void AutolengthProc(void *arg); -typedef struct SaveLoadGlobVarList { - void *address; - byte conv; - uint16 from_version; - uint16 to_version; -} SaveLoadGlobVarList; - typedef struct { uint32 id; ChunkSaveLoadProc *save_proc; @@ -73,45 +66,53 @@ enum { CH_NUM_PRI_LEVELS = 4, }; -typedef enum VarTypes { - SLE_FILE_I8 = 0, - SLE_FILE_U8 = 1, - SLE_FILE_I16 = 2, - SLE_FILE_U16 = 3, - SLE_FILE_I32 = 4, - SLE_FILE_U32 = 5, - SLE_FILE_I64 = 6, - SLE_FILE_U64 = 7, - - SLE_FILE_STRINGID = 8, -// SLE_FILE_IVAR = 8, -// SLE_FILE_UVAR = 9, - - SLE_VAR_I8 = 0 << 4, - SLE_VAR_U8 = 1 << 4, - SLE_VAR_I16 = 2 << 4, - SLE_VAR_U16 = 3 << 4, - SLE_VAR_I32 = 4 << 4, - SLE_VAR_U32 = 5 << 4, - SLE_VAR_I64 = 6 << 4, - SLE_VAR_U64 = 7 << 4, - - SLE_VAR_NULL = 8 << 4, // useful to write zeros in savegame. - - SLE_VAR_INT = SLE_VAR_I32, - SLE_VAR_UINT = SLE_VAR_U32, - - SLE_INT8 = SLE_FILE_I8 | SLE_VAR_I8, - SLE_UINT8 = SLE_FILE_U8 | SLE_VAR_U8, - SLE_INT16 = SLE_FILE_I16 | SLE_VAR_I16, - SLE_UINT16 = SLE_FILE_U16 | SLE_VAR_U16, - SLE_INT32 = SLE_FILE_I32 | SLE_VAR_I32, - SLE_UINT32 = SLE_FILE_U32 | SLE_VAR_U32, - SLE_INT64 = SLE_FILE_I64 | SLE_VAR_I64, - SLE_UINT64 = SLE_FILE_U64 | SLE_VAR_U64, - - SLE_STRINGID = SLE_FILE_STRINGID | SLE_VAR_U16, -} VarType; +enum VarTypes { + /* 4 bytes allocated a maximum of 16 types for NumberType */ + SLE_FILE_I8 = 0, + SLE_FILE_U8 = 1, + SLE_FILE_I16 = 2, + SLE_FILE_U16 = 3, + SLE_FILE_I32 = 4, + SLE_FILE_U32 = 5, + SLE_FILE_I64 = 6, + SLE_FILE_U64 = 7, + SLE_FILE_STRINGID = 8, /// StringID offset into strings-array + /* 7 more possible primitives */ + + /* 4 bytes allocated a maximum of 16 types for NumberType */ + SLE_VAR_I8 = 0 << 4, + SLE_VAR_U8 = 1 << 4, + SLE_VAR_I16 = 2 << 4, + SLE_VAR_U16 = 3 << 4, + SLE_VAR_I32 = 4 << 4, + SLE_VAR_U32 = 5 << 4, + SLE_VAR_I64 = 6 << 4, + SLE_VAR_U64 = 7 << 4, + SLE_VAR_NULL = 8 << 4, /// useful to write zeros in savegame. + /* 7 more possible primitives */ + + /* Shortcut values */ + SLE_VAR_CHAR = SLE_VAR_I8, + + /* Default combinations of variables. As savegames change, so can variables + * and thus it is possible that the saved value and internal size do not + * match and you need to specify custom combo. The defaults are listed here */ + SLE_INT8 = SLE_FILE_I8 | SLE_VAR_I8, + SLE_UINT8 = SLE_FILE_U8 | SLE_VAR_U8, + SLE_INT16 = SLE_FILE_I16 | SLE_VAR_I16, + SLE_UINT16 = SLE_FILE_U16 | SLE_VAR_U16, + SLE_INT32 = SLE_FILE_I32 | SLE_VAR_I32, + SLE_UINT32 = SLE_FILE_U32 | SLE_VAR_U32, + SLE_INT64 = SLE_FILE_I64 | SLE_VAR_I64, + SLE_UINT64 = SLE_FILE_U64 | SLE_VAR_U64, + SLE_STRINGID = SLE_FILE_STRINGID | SLE_VAR_U16, + + /* Shortcut values */ + SLE_UINT = SLE_UINT32, + SLE_INT = SLE_INT32, +}; + +typedef uint32 VarType; enum SaveLoadTypes { SL_VAR = 0, @@ -123,18 +124,31 @@ enum SaveLoadTypes { SL_END = 15 }; +typedef byte SaveLoadType; +typedef uint16 OffSetType; + /** SaveLoad type struct. Do NOT use this directly but use the SLE_ macros defined just below! */ typedef struct SaveLoad { - byte cmd; /// the action to take with the saved/loaded type, All types need different action - VarType type; /// type of the variable to be saved, int - uint16 offset; /// offset of this variable in the struct (max offset is 65536) + SaveLoadType cmd; /// the action to take with the saved/loaded type, All types need different action + VarType conv; /// type of the variable to be saved, int uint16 length; /// (conditional) length of the variable (eg. arrays) (max array size is 65536 elements) uint16 version_from; /// save/load the variable starting from this savegame version uint16 version_to; /// save/load the variable until this savegame version + /* NOTE: This element either denotes the address of the variable for a global + * variable, or the offset within a struct which is then bound to a variable + * during runtime. Decision on which one to use is controlled by the function + * that is called to save it. address: SlGlobList, offset: SlObject */ + union { + void *address; /// address of variable + OffSetType offset; /// offset of variable in the struct (max offset is 65536) + } s; } SaveLoad; +/* Same as SaveLoad but global variables are used (for better readability); */ +typedef SaveLoad SaveLoadGlobVarList; + /* Simple variables, references (pointers) and arrays */ -#define SLE_GENERAL(cmd, base, variable, type, length, from, to) {cmd, type, offsetof(base, variable), length, from, to} +#define SLE_GENERAL(cmd, base, variable, type, length, from, to) {cmd, type, length, from, to, (void*)offsetof(base, variable)} #define SLE_CONDVAR(base, variable, type, from, to) SLE_GENERAL(SL_VAR, base, variable, type, 0, from, to) #define SLE_CONDREF(base, variable, type, from, to) SLE_GENERAL(SL_REF, base, variable, type, 0, from, to) #define SLE_CONDARR(base, variable, type, length, from, to) SLE_GENERAL(SL_ARR, base, variable, type, length, from, to) @@ -151,7 +165,7 @@ typedef struct SaveLoad { #define SLE_INCLUDE(base, variable, include_index) SLE_GENERAL(SL_INCLUDE, base, variable, 0, 0, include_index, 0) /* The same as the ones at the top, only the offset is given directly; used for unions */ -#define SLE_GENERALX(cmd, offset, type, param1, param2) {cmd, type, (offset), 0, param1, param2} +#define SLE_GENERALX(cmd, offset, type, param1, param2) {cmd, type, 0, param1, param2, (void*)(offset)} #define SLE_CONDVARX(offset, type, from, to) SLE_GENERALX(SL_VAR, offset, type, from, to) #define SLE_CONDREFX(offset, type, from, to) SLE_GENERALX(SL_REF, offset, type, from, to) @@ -162,7 +176,22 @@ typedef struct SaveLoad { #define SLE_INCLUDEX(offset, type) SLE_GENERALX(SL_INCLUDE, offset, type, 0, SL_MAX_VERSION) /* End marker */ -#define SLE_END() {SL_END, 0, 0, 0, 0, 0} +#define SLE_END() {SL_END, 0, 0, 0, 0, (void*)0} + +/* Simple variables, references (pointers) and arrays, but for global variables */ +#define SLEG_GENERAL(cmd, variable, type, length, from, to) {cmd, type, length, from, to, &variable} + +#define SLEG_CONDVAR(variable, type, from, to) SLEG_GENERAL(SL_VAR, variable, type, 0, from, to) +#define SLEG_CONDREF(variable, type, from, to) SLEG_GENERAL(SL_REF, variable, type, 0, from, to) +#define SLEG_CONDARR(variable, type, length, from, to) SLEG_GENERAL(SL_ARR, variable, type, length, from, to) +#define SLEG_CONDSTR(variable, type, length, from, to) SLEG_GENERAL(SL_STR, variable, type, length, from, to) + +#define SLEG_VAR(variable, type) SLEG_CONDVAR(variable, type, 0, SL_MAX_VERSION) +#define SLEG_REF(variable, type) SLEG_CONDREF(variable, type, 0, SL_MAX_VERSION) +#define SLEG_ARR(variable, type) SLEG_CONDARR(variable, type, lengthof(variable), SL_MAX_VERSION) +#define SLEG_STR(variable, type) SLEG_CONDSTR(variable, type, lengthof(variable), SL_MAX_VERSION) + +#define SLEG_END() {SL_END, 0, 0, 0, 0, NULL} /** Checks if the savegame is below major.minor. */ @@ -183,14 +212,19 @@ static inline bool CheckSavegameVersion(uint16 version) void SlSetArrayIndex(uint index); int SlIterateArray(void); -void SlArray(void *array, uint length, VarType conv); -void SlObject(void *object, const SaveLoad *desc); + void SlAutolength(AutolengthProc *proc, void *arg); uint SlGetFieldLength(void); -byte SlReadByte(void); void SlSetLength(size_t length); +size_t SlCalcObjMemberLength(const SaveLoad *sld); + +byte SlReadByte(void); void SlWriteByte(byte b); -void SlGlobList(const SaveLoadGlobVarList *desc); + +void SlGlobList(const SaveLoadGlobVarList *sldg); +void SlArray(void *array, uint length, VarType conv); +void SlObject(void *object, const SaveLoad *sld); +bool SlObjectMember(void *object, const SaveLoad *sld); void SaveFileStart(void); void SaveFileDone(void); |