From af8f95ebcf88dd28f7ce96a2772cb5da86f6d49c Mon Sep 17 00:00:00 2001 From: Guangcong Luo Date: Tue, 6 Apr 2010 13:54:56 +0000 Subject: [PATCH] Apply patch #1746 - new savegame format; load savegames using the mod they were saved with. (refs #1746) git-svn-id: https://warzone2100.svn.sourceforge.net/svnroot/warzone2100/trunk@10497 4a71c877-e1ca-e34f-864e-861f7616d084 --- src/game.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++--- src/game.h | 5 +++-- src/init.c | 47 +++++++++++++++++++++++++++++------------- src/init.h | 2 +- src/levels.c | 5 ++++- src/main.c | 34 ++++++++++++++++++++++++++++++ src/main.h | 4 ++++ src/modding.h | 3 +++ 8 files changed, 136 insertions(+), 21 deletions(-) diff --git a/src/game.c b/src/game.c index 6171eaea8..1b06cc48e 100644 --- a/src/game.c +++ b/src/game.c @@ -40,6 +40,7 @@ #include "lib/script/script.h" #include "lib/sound/audio.h" #include "lib/sound/audio_id.h" +#include "modding.h" #include "game.h" @@ -1467,20 +1468,52 @@ static bool deserializeSaveGameV35Data(PHYSFS_file* fileHandle, SAVE_GAME_V35* s return deserializeSaveGameV34Data(fileHandle, (SAVE_GAME_V34*) serializeGame); } +// Store loaded mods in savegame +#define GAME_SAVE_V38 \ + GAME_SAVE_V35; \ + char modList[modlist_string_size] + +typedef struct save_game_v38 +{ + GAME_SAVE_V38; +} SAVE_GAME_V38; + +static bool serializeSaveGameV38Data(PHYSFS_file* fileHandle, const SAVE_GAME_V38* serializeGame) +{ + if (!serializeSaveGameV35Data(fileHandle, (const SAVE_GAME_V35*) serializeGame)) + return false; + + if (PHYSFS_write(fileHandle, serializeGame->modList, modlist_string_size, 1) != 1) + return false; + + return true; +} + +static bool deserializeSaveGameV38Data(PHYSFS_file* fileHandle, SAVE_GAME_V38* serializeGame) +{ + if (!deserializeSaveGameV35Data(fileHandle, (SAVE_GAME_V35*) serializeGame)) + return false; + + if (PHYSFS_read(fileHandle, serializeGame->modList, modlist_string_size, 1) != 1) + return false; + + return true; +} + // Current save game version typedef struct save_game { - GAME_SAVE_V35; + GAME_SAVE_V38; } SAVE_GAME; static bool serializeSaveGameData(PHYSFS_file* fileHandle, const SAVE_GAME* serializeGame) { - return serializeSaveGameV35Data(fileHandle, (const SAVE_GAME_V35*) serializeGame); + return serializeSaveGameV38Data(fileHandle, (const SAVE_GAME_V38*) serializeGame); } static bool deserializeSaveGameData(PHYSFS_file* fileHandle, SAVE_GAME* serializeGame) { - return deserializeSaveGameV35Data(fileHandle, (SAVE_GAME_V35*) serializeGame); + return deserializeSaveGameV38Data(fileHandle, (SAVE_GAME_V38*) serializeGame); } #define TEMP_DROID_MAXPROGS 3 @@ -4424,6 +4457,16 @@ bool gameLoadV(PHYSFS_file* fileHandle, unsigned int version) return false; } } + else if (version <= VERSION_37) // versions 35-37 use the same save game format + { + //if (PHYSFS_read(fileHandle, &saveGameData, sizeof(SAVE_GAME_V35), 1) != 1) + if (!deserializeSaveGameV35Data(fileHandle, (SAVE_GAME_V35*) &saveGameData)) + { + debug(LOG_ERROR, "gameLoadV: error while reading file (with version number %u): %s", version, PHYSFS_getLastError()); + + return false; + } + } else if (version <= CURRENT_VERSION_NUM) { if (!deserializeSaveGameData(fileHandle, &saveGameData)) @@ -4448,6 +4491,11 @@ bool gameLoadV(PHYSFS_file* fileHandle, unsigned int version) debug(LOG_ERROR, "Skirmish savegames of version %u are not supported in this release.", version); return false; } + /* Test mod list */ + if (version >= VERSION_38) + { + setOverrideMods(saveGameData.modList); + } // All savegames from version 34 or before are little endian so swap them. All // from version 35, and onward, are already swapped to the native byte-order @@ -4966,6 +5014,9 @@ static bool writeGameFile(const char* fileName, SDWORD saveType) strcpy(saveGame.sPlayerName[i], getPlayerName(i)); } + //version 38 + sstrcpy(saveGame.modList, getModList()); + status = serializeSaveGameData(fileHandle, &saveGame); // Close the file diff --git a/src/game.h b/src/game.h index 9f1ac5a83..5ff8edce9 100644 --- a/src/game.h +++ b/src/game.h @@ -78,10 +78,11 @@ extern "C" #define VERSION_34 34 //saves AI names for multiplayer (.gam file) #define VERSION_35 35 //uses the (de)serialization API for saving/loading games and is big-endian instead of little-endian #define VERSION_36 36 //saves beacon properly -#define VERSION_37 37 //dpid changes; this had better be the last version +#define VERSION_37 37 //dpid changes; this had better be the last version +#define VERSION_38 38 //mod list! -#define CURRENT_VERSION_NUM VERSION_37 +#define CURRENT_VERSION_NUM VERSION_38 //used in the loadGame #define KEEPOBJECTS true diff --git a/src/init.c b/src/init.c index 720a8ef40..bbe8a6c01 100644 --- a/src/init.c +++ b/src/init.c @@ -234,11 +234,15 @@ BOOL rebuildSearchPath( searchPathMode mode, BOOL force ) wzSearchPath * curSearchPath = searchPathRegistry; char tmpstr[PATH_MAX] = "\0"; - if ( mode != current_mode || force ) + if (mode != current_mode || force || + (use_override_mods && strcmp(override_mod_list, getModList()))) { - current_mode = mode; + if (mode != mod_clean) + { + rebuildSearchPath( mod_clean, false ); + } - rebuildSearchPath( mod_clean, false ); + current_mode = mode; // Start at the lowest priority while( curSearchPath->lowerPriority ) @@ -258,9 +262,10 @@ BOOL rebuildSearchPath( searchPathMode mode, BOOL force ) // Remove maps and mods removeSubdirs( curSearchPath->path, "maps", NULL ); removeSubdirs( curSearchPath->path, "mods/music", NULL ); - removeSubdirs( curSearchPath->path, "mods/global", global_mods ); - removeSubdirs( curSearchPath->path, "mods/campaign", campaign_mods ); - removeSubdirs( curSearchPath->path, "mods/multiplay", multiplay_mods ); + removeSubdirs( curSearchPath->path, "mods/global", NULL ); + removeSubdirs( curSearchPath->path, "mods/campaign", NULL ); + removeSubdirs( curSearchPath->path, "mods/multiplay", NULL ); + removeSubdirs( curSearchPath->path, "mods/autoload", NULL ); // Remove multiplay patches sstrcpy(tmpstr, curSearchPath->path); @@ -301,10 +306,10 @@ BOOL rebuildSearchPath( searchPathMode mode, BOOL force ) PHYSFS_addToSearchPath( curSearchPath->path, PHYSFS_APPEND ); addSubdirs( curSearchPath->path, "mods/music", PHYSFS_APPEND, NULL, false ); - addSubdirs( curSearchPath->path, "mods/global", PHYSFS_APPEND, global_mods, true ); - addSubdirs( curSearchPath->path, "mods", PHYSFS_APPEND, global_mods, true ); - addSubdirs( curSearchPath->path, "mods/autoload", PHYSFS_APPEND, NULL, true ); - addSubdirs( curSearchPath->path, "mods/campaign", PHYSFS_APPEND, campaign_mods, true ); + addSubdirs( curSearchPath->path, "mods/global", PHYSFS_APPEND, use_override_mods?override_mods:global_mods, true ); + addSubdirs( curSearchPath->path, "mods", PHYSFS_APPEND, use_override_mods?override_mods:global_mods, true ); + addSubdirs( curSearchPath->path, "mods/autoload", PHYSFS_APPEND, use_override_mods?override_mods:NULL, true ); + addSubdirs( curSearchPath->path, "mods/campaign", PHYSFS_APPEND, use_override_mods?override_mods:campaign_mods, true ); if (!PHYSFS_removeFromSearchPath( curSearchPath->path )) { info("* Failed to remove path %s again", curSearchPath->path); @@ -342,10 +347,10 @@ BOOL rebuildSearchPath( searchPathMode mode, BOOL force ) PHYSFS_addToSearchPath( curSearchPath->path, PHYSFS_APPEND ); addSubdirs( curSearchPath->path, "maps", PHYSFS_APPEND, NULL, false ); addSubdirs( curSearchPath->path, "mods/music", PHYSFS_APPEND, NULL, false ); - addSubdirs( curSearchPath->path, "mods/global", PHYSFS_APPEND, global_mods, true ); - addSubdirs( curSearchPath->path, "mods", PHYSFS_APPEND, global_mods, true ); - addSubdirs( curSearchPath->path, "mods/autoload", PHYSFS_APPEND, NULL, true ); - addSubdirs( curSearchPath->path, "mods/multiplay", PHYSFS_APPEND, multiplay_mods, true ); + addSubdirs( curSearchPath->path, "mods/global", PHYSFS_APPEND, use_override_mods?override_mods:global_mods, true ); + addSubdirs( curSearchPath->path, "mods", PHYSFS_APPEND, use_override_mods?override_mods:global_mods, true ); + addSubdirs( curSearchPath->path, "mods/autoload", PHYSFS_APPEND, use_override_mods?override_mods:NULL, true ); + addSubdirs( curSearchPath->path, "mods/multiplay", PHYSFS_APPEND, use_override_mods?override_mods:multiplay_mods, true ); PHYSFS_removeFromSearchPath( curSearchPath->path ); // Add multiplay patches @@ -379,6 +384,15 @@ BOOL rebuildSearchPath( searchPathMode mode, BOOL force ) debug(LOG_ERROR, "Can't switch to unknown mods %i", mode); return false; } + if (use_override_mods && mode != mod_clean) + { + if (strcmp(getModList(),override_mod_list)) + { + debug(LOG_POPUP, _("The required mod could not be loaded: %s\n\nWarzone will try to load the game without it."), override_mod_list); + } + clearOverrideMods(); + current_mode = mod_override; + } // User's home dir must be first so we allways see what we write PHYSFS_removeFromSearchPath(PHYSFS_getWriteDir()); @@ -388,6 +402,11 @@ BOOL rebuildSearchPath( searchPathMode mode, BOOL force ) printSearchPath(); #endif // DEBUG } + else if (use_override_mods) + { + // override mods are already the same as current mods, so no need to do anything + clearOverrideMods(); + } return true; } diff --git a/src/init.h b/src/init.h index 5cd5a33cf..3f964122d 100644 --- a/src/init.h +++ b/src/init.h @@ -59,7 +59,7 @@ typedef struct _wzSearchPath struct _wzSearchPath * higherPriority, * lowerPriority; } wzSearchPath; -typedef enum { mod_clean=0, mod_campaign=1, mod_multiplay=2 } searchPathMode; +typedef enum { mod_clean=0, mod_campaign=1, mod_multiplay=2, mod_override=3 } searchPathMode; void cleanSearchPath( void ); void registerSearchPath( const char path[], unsigned int priority ); diff --git a/src/levels.c b/src/levels.c index 96656c68f..30096c959 100644 --- a/src/levels.c +++ b/src/levels.c @@ -677,7 +677,10 @@ BOOL levLoadData(const char* name, char *pSaveName, GAME_TYPE saveType) } } - rebuildSearchPath(psNewLevel->dataDir, false); + if (!rebuildSearchPath(psNewLevel->dataDir, false)) + { + return false; + } // reset the old mission data if necessary if (psCurrLevel != NULL) diff --git a/src/main.c b/src/main.c index 796864747..8975f4e80 100644 --- a/src/main.c +++ b/src/main.c @@ -108,6 +108,10 @@ char * global_mods[MAX_MODS] = { NULL }; char * campaign_mods[MAX_MODS] = { NULL }; char * multiplay_mods[MAX_MODS] = { NULL }; +char * override_mods[MAX_MODS] = { NULL }; +char * override_mod_list = NULL; +bool use_override_mods = false; + char * loaded_mods[MAX_MODS] = { NULL }; char * mod_list = NULL; int num_loaded_mods = 0; @@ -225,6 +229,36 @@ void printSearchPath( void ) PHYSFS_freeList( searchPath ); } +void setOverrideMods(char * modlist) +{ + char * curmod = modlist; + char * nextmod; + int i=0; + while ((nextmod = strstr(curmod, ", ")) && i