From fa337ae64a554ae77fed3dfb1147acc7890e77ca Mon Sep 17 00:00:00 2001 From: Darkvater Date: Mon, 20 Feb 2006 19:42:39 +0000 Subject: (svn r3626) - Merge the SlGlobVarList (global variables) and SaveLoad (offset in struct, variable determined runtime) structs. The only difference between these two is the last element that either holds the address or the offset in the struct. Which one to take is determined by which function is called; SlObject or SlGlobList. --- misc.c | 60 ++++++++++++------------- saveload.c | 148 ++++++++++++++++++++++++++++++++----------------------------- saveload.h | 146 +++++++++++++++++++++++++++++++++++++----------------------- 3 files changed, 197 insertions(+), 157 deletions(-) diff --git a/misc.c b/misc.c index cd8f85f87..25a6f5193 100644 --- a/misc.c +++ b/misc.c @@ -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); -- cgit v1.2.3-70-g09d2