diff --git a/network_client.c b/network_client.c index f8d88e8fc2..83a20de5b7 100644 --- a/network_client.c +++ b/network_client.c @@ -826,7 +826,7 @@ static NetworkClientPacket* const _network_client_packet[] = { // If this fails, check the array above with network_data.h assert_compile(lengthof(_network_client_packet) == PACKET_END); -extern const SettingDesc patch_settings[]; +extern const SettingDesc _patch_settings[]; // This is a TEMPORARY solution to get the patch-settings // to the client. When the patch-settings are saved in the savegame @@ -835,25 +835,25 @@ static void NetworkRecvPatchSettings(NetworkClientState* cs, Packet* p) { const SettingDesc *item; - item = patch_settings; + item = _patch_settings; - while (item->name != NULL) { - switch (item->flags) { - case SDT_BOOL: - case SDT_INT8: - case SDT_UINT8: - *(uint8 *)(item->ptr) = NetworkRecv_uint8(cs, p); + for (; item->save.cmd != SL_END; item++) { + void *var = ini_get_variable(&item->save, &_patches); + switch (GetVarMemType(item->save.conv)) { + case SLE_VAR_BL: + case SLE_VAR_I8: + case SLE_VAR_U8: + *(uint8 *)(var) = NetworkRecv_uint8(cs, p); break; - case SDT_INT16: - case SDT_UINT16: - *(uint16 *)(item->ptr) = NetworkRecv_uint16(cs, p); + case SLE_VAR_I16: + case SLE_VAR_U16: + *(uint16 *)(var) = NetworkRecv_uint16(cs, p); break; - case SDT_INT32: - case SDT_UINT32: - *(uint32 *)(item->ptr) = NetworkRecv_uint32(cs, p); + case SLE_VAR_I32: + case SLE_VAR_U32: + *(uint32 *)(var) = NetworkRecv_uint32(cs, p); break; } - item++; } } diff --git a/network_server.c b/network_server.c index 095922c10a..2c863587db 100644 --- a/network_server.c +++ b/network_server.c @@ -1188,7 +1188,7 @@ static NetworkServerPacket* const _network_server_packet[] = { assert_compile(lengthof(_network_server_packet) == PACKET_END); -extern const SettingDesc patch_settings[]; +extern const SettingDesc _patch_settings[]; // This is a TEMPORARY solution to get the patch-settings // to the client. When the patch-settings are saved in the savegame @@ -1200,25 +1200,25 @@ static void NetworkSendPatchSettings(NetworkClientState* cs) NetworkSend_uint8(p, MAP_PACKET_PATCH); // Now send all the patch-settings in a pretty order.. - item = patch_settings; + item = _patch_settings; - while (item->name != NULL) { - switch (item->flags) { - case SDT_BOOL: - case SDT_INT8: - case SDT_UINT8: - NetworkSend_uint8(p, *(uint8 *)item->ptr); + for (; item->save.cmd != SL_END; item++) { + const void *var = ini_get_variable(&item->save, &_patches); + switch (GetVarMemType(item->save.conv)) { + case SLE_VAR_BL: + case SLE_VAR_I8: + case SLE_VAR_U8: + NetworkSend_uint8(p, *(uint8 *)var); break; - case SDT_INT16: - case SDT_UINT16: - NetworkSend_uint16(p, *(uint16 *)item->ptr); + case SLE_VAR_I16: + case SLE_VAR_U16: + NetworkSend_uint16(p, *(uint16 *)var); break; - case SDT_INT32: - case SDT_UINT32: - NetworkSend_uint32(p, *(uint32 *)item->ptr); + case SLE_VAR_I32: + case SLE_VAR_U32: + NetworkSend_uint32(p, *(uint32 *)var); break; } - item++; } NetworkSend_Packet(p, cs); diff --git a/saveload.c b/saveload.c index 20c27b6c55..206b6f9c12 100644 --- a/saveload.c +++ b/saveload.c @@ -25,14 +25,11 @@ #include "town.h" #include "player.h" #include "saveload.h" +#include "network.h" #include "variables.h" #include -enum { - SAVEGAME_VERSION = 21, - -}; - +const uint16 SAVEGAME_VERSION = 21; uint16 _sl_version; /// the major savegame version identifier byte _sl_minor_version; /// the minor savegame version, DO NOT USE! @@ -381,19 +378,14 @@ static void SlCopyBytes(void *ptr, size_t length) } } -#if 0 -/** - * Read in bytes from the file/data structure but don't do - * anything with them - * NOTICE: currently unused +/** Read in bytes from the file/data structure but don't do + * anything with them, discarding them in effect * @param length The amount of bytes that is being treated this way */ static inline void SlSkipBytes(size_t length) { - for (; length != 0; length--) - SlReadByte(); + for (; length != 0; length--) SlReadByte(); } -#endif /* Get the length of the current object */ uint SlGetFieldLength(void) {return _sl.obj_len;} @@ -570,10 +562,24 @@ void SlArray(void *array, uint length, VarType conv) static inline bool SlIsObjectValidInSavegame(const SaveLoad *sld) { if (_sl_version < sld->version_from || _sl_version > sld->version_to) return false; + if (sld->conv & SLF_SAVE_NO) return false; return true; } +/** Are we going to load this variable when loading a savegame or not? + * @note If the variable is skipped it is skipped in the savegame + * bytestream itself as well, so there is no need to skip it somewhere else */ +static inline bool SlSkipVariableOnLoad(const SaveLoad *sld) +{ + if ((sld->conv & SLF_NETWORK_NO) && !_sl.save && _networking && !_network_server) { + SlSkipBytes(SlCalcConvMemLen(sld->conv) * sld->length); + return true; + } + + return false; +} + /** * Calculate the size of an object. * @param sld The @SaveLoad description of the object so we know how to manipulate it @@ -626,6 +632,7 @@ bool SlObjectMember(void *ptr, const SaveLoad *sld) case SL_STR: /* CONDITIONAL saveload types depend on the savegame version */ if (!SlIsObjectValidInSavegame(sld)) return false; + if (SlSkipVariableOnLoad(sld)) return false; switch (sld->cmd) { case SL_VAR: SlSaveLoadConv(ptr, conv); break; diff --git a/saveload.h b/saveload.h index e56d25876b..077f3c84c3 100644 --- a/saveload.h +++ b/saveload.h @@ -230,6 +230,16 @@ static inline bool CheckSavegameVersion(uint16 version) return _sl_version < version; } +/** Checks if some version from/to combination falls within the range of the + * active savegame version */ +static inline bool SlIsObjectCurrentlyValid(uint16 version_from, uint16 version_to) +{ + extern const uint16 SAVEGAME_VERSION; + if (SAVEGAME_VERSION < version_from || SAVEGAME_VERSION > version_to) return false; + + return true; +} + /* 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 diff --git a/settings.c b/settings.c index 351d50e7b4..862155dc6c 100644 --- a/settings.c +++ b/settings.c @@ -609,6 +609,8 @@ static void ini_load_settings(IniFile *ini, const SettingDesc *sd, const char *g const SettingDescBase *sdb = &sd->desc; const SaveLoad *sld = &sd->save; + if (!SlIsObjectCurrentlyValid(sld->version_from, sld->version_to)) continue; + // XXX - wtf is this?? (group override?) s = strchr(sdb->name, '.'); if (s != NULL) { @@ -673,6 +675,7 @@ static void ini_save_settings(IniFile *ini, const SettingDesc *sd, const char *g /* If the setting is not saved to the configuration * file, just continue with the next setting */ + if (!SlIsObjectCurrentlyValid(sld->version_from, sld->version_to)) continue; if (sld->conv & SLF_CONFIG_NO) continue; // XXX - wtf is this?? (group override?) @@ -1252,6 +1255,71 @@ void SaveToConfig(void) ini_free(ini); } +/** Save and load handler for patches/settings + * @param osd SettingDesc struct containing all information + * @param object can be either NULL in which case we load global variables or + * a pointer to a struct which is getting saved */ +static void LoadSettings(const SettingDesc *osd, void *object) +{ + for (; osd->save.cmd != SL_END; osd++) { + const SaveLoad *sld = &osd->save; + void *ptr = ini_get_variable(sld, object); + + if (!SlObjectMember(ptr, sld)) continue; + } +} + +/** Loadhandler for a list of global variables + * @note this is actually a stub for LoadSettings with the + * object pointer set to NULL */ +static inline void LoadSettingsGlobList(const SettingDescGlobVarList *sdg) +{ + LoadSettings((const SettingDesc*)sdg, NULL); +} + +/** Save and load handler for patches/settings + * @param osd SettingDesc struct containing all information + * @param object can be either NULL in which case we load global variables or + * a pointer to a struct which is getting saved */ +static void SaveSettings(const SettingDesc *sd, 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 */ + const SettingDesc *i; + size_t length = 0; + for (i = sd; i->save.cmd != SL_END; i++) { + length += SlCalcObjMemberLength(&i->save); + } + SlSetLength(length); + + for (i = sd; i->save.cmd != SL_END; i++) { + void *ptr = ini_get_variable(&i->save, object); + SlObjectMember(ptr, &i->save); + } +} + +/** Savehandler for a list of global variables + * @note this is actually a stub for SaveSettings with the + * object pointer set to NULL */ +static inline void SaveSettingsGlobList(const SettingDescGlobVarList *sdg) +{ + SaveSettings((const SettingDesc*)sdg, NULL); +} + +static void Load_OPTS(void) +{ + /* 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 */ + _opt = _opt_newgame; + LoadSettings(_gameopt_settings, &_opt); +} + +static void Save_OPTS(void) +{ + SaveSettings(_gameopt_settings, &_opt); +} + void CheckConfig(void) { // fix up news_display_opt from old to new @@ -1273,5 +1341,5 @@ void CheckConfig(void) } const ChunkHandler _setting_chunk_handlers[] = { - { 'OPTS', SaveLoad_OPTS, SaveLoad_OPTS, CH_RIFF | CH_LAST} + { 'OPTS', Save_OPTS, Load_OPTS, CH_RIFF | CH_LAST} };