From 594db1a57b2dc4cac53529a1f606e2f4fdc49ded Mon Sep 17 00:00:00 2001 From: danij Date: Mon, 10 Feb 2014 22:14:38 +0000 Subject: [PATCH] libcommon|SaveSlots: Added a C wrapper API for SaveSlots and made use of it --- doomsday/plugins/common/include/p_saveg.h | 20 +-- doomsday/plugins/common/include/saveslots.h | 70 +++++++-- doomsday/plugins/common/src/g_game.c | 84 +++++----- doomsday/plugins/common/src/hu_menu.c | 16 +- doomsday/plugins/common/src/p_saveg.cpp | 98 ++---------- doomsday/plugins/common/src/saveslots.cpp | 161 +++++++++++++++++--- doomsday/plugins/doom/src/d_main.c | 4 +- doomsday/plugins/doom/src/p_oldsvg.cpp | 1 + doomsday/plugins/doom64/src/d_main.c | 4 +- doomsday/plugins/heretic/src/h_main.c | 4 +- doomsday/plugins/heretic/src/p_oldsvg.cpp | 1 + doomsday/plugins/hexen/src/h2_main.c | 4 +- 12 files changed, 275 insertions(+), 192 deletions(-) diff --git a/doomsday/plugins/common/include/p_saveg.h b/doomsday/plugins/common/include/p_saveg.h index 864dd045aa..e94ebfa7bd 100644 --- a/doomsday/plugins/common/include/p_saveg.h +++ b/doomsday/plugins/common/include/p_saveg.h @@ -22,13 +22,13 @@ #define LIBCOMMON_SAVESTATE_H #include "common.h" -#ifdef __cplusplus -# include "dmu_archiveindex.h" -#endif -#include "p_saveio.h" +#include "saveinfo.h" +#include "saveslots.h" +//#include "p_saveio.h" DENG_EXTERN_C int thingArchiveVersion; DENG_EXTERN_C uint thingArchiveSize; +DENG_EXTERN_C SaveSlots saveSlots; #ifdef __cplusplus extern "C" { @@ -45,13 +45,6 @@ void SV_Shutdown(void); dd_bool SV_RecogniseGameState(Str const *path, SaveInfo *info); -void SV_UpdateAllSaveInfo(void); -int SV_SlotForSaveName(char const *name); -int SV_ParseSlotIdentifier(char const *str); -dd_bool SV_IsValidSlot(int slot); -dd_bool SV_IsUserWritableSlot(int slot); -dd_bool SV_IsSlotUsed(int slot); - #if __JHEXEN__ /** * Returns @c true iff a game-save is present and serialized @a map state is @@ -60,11 +53,6 @@ dd_bool SV_IsSlotUsed(int slot); dd_bool SV_HxHaveMapStateForSlot(int slot, uint map); #endif -SaveInfo *SV_SaveInfoForSlot(int slot); -AutoStr *SV_ComposeSlotIdentifier(int slot); -void SV_ClearSlot(int slot); -void SV_CopySlot(int sourceSlot, int destSlot); - /** * Save the current game state to the specified @a slot number. * diff --git a/doomsday/plugins/common/include/saveslots.h b/doomsday/plugins/common/include/saveslots.h index 8096cd880c..80416a5f47 100644 --- a/doomsday/plugins/common/include/saveslots.h +++ b/doomsday/plugins/common/include/saveslots.h @@ -25,6 +25,8 @@ #include "saveinfo.h" #include "p_savedef.h" /// @todo remove me +#ifdef __cplusplus + /** * Maps saved games into a finite set of "save slots". * @@ -53,6 +55,11 @@ class SaveSlots */ void updateAllSaveInfo(); + /** + * Returns @c true iff @a slot is a valid logical slot number (in range). + */ + bool isValidSlot(int slot); + /** * Composes the textual identifier/name for save @a slot. */ @@ -76,44 +83,39 @@ class SaveSlots int parseSlotIdentifier(char const *str); /** - * Lookup a save slot by searching for a match on game-save name. Search is in ascending - * logical slot order 0...N (where N is the number of available save slots). + * Lookup a save slot by searching for a match on game-save description. The search is in + * ascending logical slot order 0...N (where N is the number of available save slots). * - * @param name Name of the game-save to look for. Case insensitive. + * @param description Description of the game-save to look for. Case insensitive. * * @return Logical slot number of the found game-save else @c -1 */ - int slotForSaveName(char const *description); + int findSlotWithSaveDescription(char const *description); /** * Returns @c true iff a game-save is present for logical save @a slot. */ bool slotInUse(int slot); - /** - * Returns @c true iff @a slot is a valid logical save slot. - */ - bool isValidSlot(int slot); - /** * Returns @c true iff @a slot is user-writable save slot (i.e., its not one of the special * slots such as @em auto). */ - bool isUserWritableSlot(int slot); + bool slotIsUserWritable(int slot); /** * Returns the save info for save @a slot. Always returns SaveInfo even if supplied with an * invalid or unused slot identifer (a null object). */ - SaveInfo *findSaveInfoForSlot(int slot); - - void replaceSaveInfo(int slot, SaveInfo *newInfo); + SaveInfo *saveInfo(int slot); /** * Deletes all save game files associated with a slot number. */ void clearSlot(int slot); + void replaceSaveInfo(int slot, SaveInfo *newInfo); + /** * Copies all the save game files from one slot to another. */ @@ -127,10 +129,46 @@ class SaveSlots * * @return The composed path if reachable (else a zero-length string). */ - AutoStr *composeGameSavePathForSlot(int slot, int map = -1); + AutoStr *composeSavePathForSlot(int slot, int map = -1); + + /// Register the console commands and variables of this module. + static void consoleRegister(); private: DENG2_PRIVATE(d) }; - -#endif // LIBCOMMON_MAPSTATEREADER_H +#endif // __cplusplus + +// C wrapper API --------------------------------------------------------------- + +#ifdef __cplusplus +extern "C" { +#else +typedef void *SaveSlots; +#endif + +SaveSlots *SaveSlots_New(void); +void SaveSlots_Delete(SaveSlots *sslots); + +void SaveSlots_ClearSaveInfo(SaveSlots *sslots); +void SaveSlots_BuildSaveInfo(SaveSlots *sslots); +void SaveSlots_UpdateAllSaveInfo(SaveSlots *sslots); +dd_bool SaveSlots_IsValidSlot(SaveSlots *sslots, int slot); +AutoStr *SaveSlots_ComposeSlotIdentifier(SaveSlots *sslots, int slot); +int SaveSlots_ParseSlotIdentifier(SaveSlots *sslots, char const *str); +int SaveSlots_SlotForSaveName(SaveSlots *sslots, char const *description); +dd_bool SaveSlots_SlotInUse(SaveSlots *sslots, int slot); +dd_bool SaveSlots_SlotIsUserWritable(SaveSlots *sslots, int slot); +SaveInfo *SaveSlots_FindSaveInfoForSlot(SaveSlots *sslots, int slot); +void SaveSlots_ReplaceSaveInfo(SaveSlots *sslots, int slot, SaveInfo *newInfo); +void SaveSlots_ClearSlot(SaveSlots *sslots, int slot); +void SaveSlots_CopySlot(SaveSlots *sslots, int sourceSlot, int destSlot); +AutoStr *SaveSlots_ComposeSavePathForSlot(SaveSlots *sslots, int slot, int map); + +void SaveSlots_ConsoleRegister(); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // LIBCOMMON_SAVESLOTS_H diff --git a/doomsday/plugins/common/src/g_game.c b/doomsday/plugins/common/src/g_game.c index 3487e58ea4..5c7225880a 100644 --- a/doomsday/plugins/common/src/g_game.c +++ b/doomsday/plugins/common/src/g_game.c @@ -2063,7 +2063,7 @@ int rebornLoadConfirmResponse(msgresponse_t response, int userValue, void* userP { #if __JHEXEN__ // Load the last autosave? (Not optional in Hexen). - if(SV_IsSlotUsed(AUTO_SLOT)) + if(SaveSlots_SlotInUse(saveSlots, AUTO_SLOT)) { gaLoadGameSlot = AUTO_SLOT; G_SetGameAction(GA_LOADGAME); @@ -2100,13 +2100,13 @@ void G_DoReborn(int plrNum) int lastSlot = -1; // First ensure we have up-to-date info. - SV_UpdateAllSaveInfo(); + SaveSlots_UpdateAllSaveInfo(saveSlots); // Use the latest save? if(cfg.loadLastSaveOnReborn) { lastSlot = Con_GetInteger("game-save-last-slot"); - if(!SV_IsSlotUsed(lastSlot)) lastSlot = -1; + if(!SaveSlots_SlotInUse(saveSlots, lastSlot)) lastSlot = -1; } // Use the latest autosave? (Not optional in Hexen). @@ -2114,7 +2114,7 @@ void G_DoReborn(int plrNum) if(cfg.loadAutoSaveOnReborn) { autoSlot = AUTO_SLOT; - if(!SV_IsSlotUsed(autoSlot)) autoSlot = -1; + if(!SaveSlots_SlotInUse(saveSlots, autoSlot)) autoSlot = -1; } #endif @@ -2139,8 +2139,8 @@ void G_DoReborn(int plrNum) else { // Compose the confirmation message. - SaveInfo* info = SV_SaveInfoForSlot(chosenSlot); - AutoStr* msg = Str_Appendf(AutoStr_NewStd(), REBORNLOAD_CONFIRM, Str_Text(SaveInfo_Description(info))); + SaveInfo *info = SaveSlots_FindSaveInfoForSlot(saveSlots, chosenSlot); + AutoStr *msg = Str_Appendf(AutoStr_NewStd(), REBORNLOAD_CONFIRM, Str_Text(SaveInfo_Description(info))); S_LocalSound(SFX_REBORNLOAD_CONFIRM, NULL); Hu_MsgStart(MSG_YESNO, Str_Text(msg), rebornLoadConfirmResponse, chosenSlot, 0); } @@ -2149,7 +2149,7 @@ void G_DoReborn(int plrNum) // Autosave loading cannot be disabled in Hexen. #if __JHEXEN__ - if(SV_IsSlotUsed(AUTO_SLOT)) + if(SaveSlots_SlotInUse(saveSlots, AUTO_SLOT)) { gaLoadGameSlot = AUTO_SLOT; G_SetGameAction(GA_LOADGAME); @@ -2171,7 +2171,7 @@ static void G_InitNewGame(void) /// @todo Do not clear this save slot. Instead we should set a game state /// flag to signal when a new game should be started instead of loading /// the autosave slot. - SV_ClearSlot(AUTO_SLOT); + SaveSlots_ClearSlot(saveSlots, AUTO_SLOT); #if __JHEXEN__ Game_InitACScriptsForNewGame(); @@ -2614,7 +2614,7 @@ void G_DoLeaveMap(void) { if(!gameRules.deathmatch) { - SV_ClearSlot(BASE_SLOT); + SaveSlots_ClearSlot(saveSlots, BASE_SLOT); } } @@ -2777,9 +2777,9 @@ dd_bool G_LoadGame(int slot) // no guarantee that the game-save will be accessible come load time. // First ensure we have up-to-date info. - SV_UpdateAllSaveInfo(); + SaveSlots_UpdateAllSaveInfo(saveSlots); - if(!SV_IsSlotUsed(slot)) + if(!SaveSlots_SlotInUse(saveSlots, slot)) { App_Log(DE2_RES_ERROR, "Cannot load from save slot #%i: not in use", slot); return false; @@ -2808,7 +2808,7 @@ void G_DoLoadGame(void) if(IS_NETGAME) return; // Copy the base slot to the autosave slot. - SV_CopySlot(BASE_SLOT, AUTO_SLOT); + SaveSlots_CopySlot(saveSlots, BASE_SLOT, AUTO_SLOT); #endif } @@ -2896,7 +2896,7 @@ AutoStr *G_GenerateSaveGameName(void) void G_DoSaveGame(void) { savestateworker_params_t p; - const char* name; + char const *name; dd_bool didSave; if(gaSaveGameName && !Str_IsEmpty(gaSaveGameName)) @@ -2906,7 +2906,7 @@ void G_DoSaveGame(void) else { // No name specified. - SaveInfo* info = SV_SaveInfoForSlot(gaSaveGameSlot); + SaveInfo *info = SaveSlots_FindSaveInfoForSlot(saveSlots, gaSaveGameSlot); if(!gaSaveGameGenerateName && !Str_IsEmpty(SaveInfo_Description(info))) { // Slot already in use; reuse the existing name. @@ -3668,7 +3668,7 @@ int loadGameConfirmResponse(msgresponse_t response, int userValue, void* userPoi D_CMD(LoadGame) { - const dd_bool confirm = (argc == 3 && !stricmp(argv[2], "confirm")); + dd_bool const confirm = (argc == 3 && !stricmp(argv[2], "confirm")); int slot; if(G_QuitInProgress()) return false; @@ -3682,14 +3682,14 @@ D_CMD(LoadGame) } // Ensure we have up-to-date info. - SV_UpdateAllSaveInfo(); + SaveSlots_UpdateAllSaveInfo(saveSlots); - slot = SV_ParseSlotIdentifier(argv[1]); - if(SV_IsSlotUsed(slot)) + slot = SaveSlots_ParseSlotIdentifier(saveSlots, argv[1]); + if(SaveSlots_SlotInUse(saveSlots, slot)) { // A known used slot identifier. - SaveInfo* info; - AutoStr* msg; + SaveInfo *info; + AutoStr *msg; if(confirm || !cfg.confirmQuickGameSave) { @@ -3698,7 +3698,7 @@ D_CMD(LoadGame) return G_LoadGame(slot); } - info = SV_SaveInfoForSlot(slot); + info = SaveSlots_FindSaveInfoForSlot(saveSlots, slot); // Compose the confirmation message. msg = Str_Appendf(AutoStr_NewStd(), QLPROMPT, Str_Text(SaveInfo_Description(info))); @@ -3779,16 +3779,16 @@ D_CMD(SaveGame) } // Ensure we have up-to-date info. - SV_UpdateAllSaveInfo(); + SaveSlots_UpdateAllSaveInfo(saveSlots); - slot = SV_ParseSlotIdentifier(argv[1]); - if(SV_IsUserWritableSlot(slot)) + slot = SaveSlots_ParseSlotIdentifier(saveSlots, argv[1]); + if(SaveSlots_SlotIsUserWritable(saveSlots, slot)) { // A known slot identifier. - const dd_bool slotIsUsed = SV_IsSlotUsed(slot); - SaveInfo* info = SV_SaveInfoForSlot(slot); + dd_bool const slotIsUsed = SaveSlots_SlotInUse(saveSlots, slot); + SaveInfo *info = SaveSlots_FindSaveInfoForSlot(saveSlots, slot); ddstring_t localName, *name; - AutoStr* msg; + AutoStr *msg; Str_InitStatic(&localName, (argc >= 3 && stricmp(argv[2], "confirm"))? argv[2] : ""); if(!slotIsUsed || confirm || !cfg.confirmQuickGameSave) @@ -3819,7 +3819,7 @@ D_CMD(SaveGame) } // Clearly the caller needs some assistance... - if(!SV_IsValidSlot(slot)) + if(!SaveSlots_IsValidSlot(saveSlots, slot)) App_Log(DE2_SCR_WARNING, "Failed to determine save slot from \"%s\"", argv[1]); else App_Log(DE2_LOG_ERROR, "Save slot #%i is non-user-writable", slot); @@ -3836,14 +3836,15 @@ D_CMD(QuickSaveGame) dd_bool G_DeleteSaveGame(int slot) { - SaveInfo* info; + SaveInfo *info; - if(!SV_IsUserWritableSlot(slot) || !SV_IsSlotUsed(slot)) return false; + if(!SaveSlots_SlotIsUserWritable(saveSlots, slot)) return false; + if(!SaveSlots_SlotInUse(saveSlots, slot)) return false; // A known slot identifier. - info = SV_SaveInfoForSlot(slot); - DENG_ASSERT(info); - SV_ClearSlot(slot); + info = SaveSlots_FindSaveInfoForSlot(saveSlots, slot); + DENG_ASSERT(info != 0); + SaveSlots_ClearSlot(saveSlots, slot); if(Hu_MenuIsActive()) { @@ -3872,17 +3873,18 @@ int deleteSaveGameConfirmResponse(msgresponse_t response, int userValue, void* u D_CMD(DeleteGameSave) { - const dd_bool confirm = (argc >= 3 && !stricmp(argv[argc-1], "confirm")); - player_t* player = &players[CONSOLEPLAYER]; + dd_bool const confirm = (argc >= 3 && !stricmp(argv[argc-1], "confirm")); + player_t *player = &players[CONSOLEPLAYER]; int slot; if(G_QuitInProgress()) return false; // Ensure we have up-to-date info. - SV_UpdateAllSaveInfo(); + SaveSlots_UpdateAllSaveInfo(saveSlots); - slot = SV_ParseSlotIdentifier(argv[1]); - if(SV_IsUserWritableSlot(slot) && SV_IsSlotUsed(slot)) + slot = SaveSlots_ParseSlotIdentifier(saveSlots, argv[1]); + if(SaveSlots_SlotIsUserWritable(saveSlots, slot) && + SaveSlots_SlotInUse(saveSlots, slot)) { // A known slot identifier. if(confirm) @@ -3892,8 +3894,8 @@ D_CMD(DeleteGameSave) else { // Compose the confirmation message. - SaveInfo* info = SV_SaveInfoForSlot(slot); - AutoStr* msg = Str_Appendf(AutoStr_NewStd(), DELETESAVEGAME_CONFIRM, Str_Text(SaveInfo_Description(info))); + SaveInfo *info = SaveSlots_FindSaveInfoForSlot(saveSlots, slot); + AutoStr *msg = Str_Appendf(AutoStr_NewStd(), DELETESAVEGAME_CONFIRM, Str_Text(SaveInfo_Description(info))); S_LocalSound(SFX_DELETESAVEGAME_CONFIRM, NULL); Hu_MsgStart(MSG_YESNO, Str_Text(msg), deleteSaveGameConfirmResponse, slot, 0); } @@ -3901,7 +3903,7 @@ D_CMD(DeleteGameSave) } // Clearly the caller needs some assistance... - if(!SV_IsValidSlot(slot)) + if(!SaveSlots_IsValidSlot(saveSlots, slot)) App_Log(DE2_SCR_WARNING, "Failed to determine save slot from \"%s\"", argv[1]); else App_Log(DE2_LOG_ERROR, "Save slot #%i is non-user-writable", slot); diff --git a/doomsday/plugins/common/src/hu_menu.c b/doomsday/plugins/common/src/hu_menu.c index cb0a9a45e2..5f4f16636b 100644 --- a/doomsday/plugins/common/src/hu_menu.c +++ b/doomsday/plugins/common/src/hu_menu.c @@ -5634,13 +5634,13 @@ void Hu_MenuDrawSkillPage(mn_page_t* page, const Point2Raw* origin) void Hu_MenuUpdateGameSaveWidgets(void) { - const int saveSlotObjectIds[NUMSAVESLOTS] = { + int const saveSlotObjectIds[NUMSAVESLOTS] = { MNF_ID0, MNF_ID1, MNF_ID2, MNF_ID3, MNF_ID4, MNF_ID5, #if !__JHEXEN__ MNF_ID6, MNF_ID7 #endif }; - mn_page_t* page; + mn_page_t *page; int i; if(!menuActive) return; @@ -5648,20 +5648,20 @@ void Hu_MenuUpdateGameSaveWidgets(void) // Prompt a refresh of the game-save info. We don't yet actively monitor // the contents of the game-save paths, so instead we settle for manual // updates whenever the save/load menu is opened. - SV_UpdateAllSaveInfo(); + SaveSlots_UpdateAllSaveInfo(saveSlots); // Update widgets. page = Hu_MenuFindPageByName("LoadGame"); for(i = 0; i < NUMSAVESLOTS; ++i) { - mn_object_t* obj = MN_MustFindObjectOnPage(page, 0, saveSlotObjectIds[i]); - mndata_edit_t* edit = (mndata_edit_t*) obj->_typedata; - const char* text = ""; + mn_object_t *obj = MN_MustFindObjectOnPage(page, 0, saveSlotObjectIds[i]); + mndata_edit_t *edit = (mndata_edit_t *) obj->_typedata; + char const *text = ""; MNObject_SetFlags(obj, FO_SET, MNF_DISABLED); - if(SV_IsSlotUsed(edit->data2)) + if(SaveSlots_SlotInUse(saveSlots, edit->data2)) { - SaveInfo* info = SV_SaveInfoForSlot(edit->data2); + SaveInfo *info = SaveSlots_FindSaveInfoForSlot(saveSlots, edit->data2); text = Str_Text(SaveInfo_Description(info)); MNObject_SetFlags(obj, FO_CLEAR, MNF_DISABLED); } diff --git a/doomsday/plugins/common/src/p_saveg.cpp b/doomsday/plugins/common/src/p_saveg.cpp index 724324a45c..319e955342 100644 --- a/doomsday/plugins/common/src/p_saveg.cpp +++ b/doomsday/plugins/common/src/p_saveg.cpp @@ -34,6 +34,7 @@ #include "p_tick.h" #include "r_common.h" #include "p_savedef.h" +#include "p_saveio.h" #include "polyobjs.h" #include "mapstatereader.h" #include "mapstatewriter.h" @@ -63,11 +64,9 @@ struct playerheader_t static bool inited = false; -static int cvarLastSlot; ///< @c -1= Not yet loaded/saved in this game session. -static int cvarQuickSlot; ///< @c -1= Not yet chosen/determined. +SaveSlots saveSlots; -static SaveSlots saveSlots; -SaveInfo const *curInfo; +static SaveInfo const *curInfo; static playerheader_t playerHeader; static dd_bool playerHeaderOK; @@ -207,64 +206,11 @@ dd_bool SV_RecogniseGameState(Str const *path, SaveInfo *info) return false; } -AutoStr *SV_ComposeSlotIdentifier(int slot) -{ - return saveSlots.composeSlotIdentifier(slot); -} - -void SV_ClearSlot(int slot) -{ - DENG_ASSERT(inited); - saveSlots.clearSlot(slot); -} - -dd_bool SV_IsValidSlot(int slot) -{ - DENG_ASSERT(inited); - return saveSlots.isValidSlot(slot); -} - -dd_bool SV_IsUserWritableSlot(int slot) -{ - DENG_ASSERT(inited); - return saveSlots.isUserWritableSlot(slot); -} - -SaveInfo *SV_SaveInfoForSlot(int slot) -{ - DENG_ASSERT(inited); - return saveSlots.findSaveInfoForSlot(slot); -} - -void SV_UpdateAllSaveInfo() -{ - DENG_ASSERT(inited); - saveSlots.buildSaveInfo(); -} - -int SV_ParseSlotIdentifier(char const *str) -{ - DENG_ASSERT(inited); - return saveSlots.parseSlotIdentifier(str); -} - -int SV_SlotForSaveName(char const *name) -{ - DENG_ASSERT(inited); - return saveSlots.slotForSaveName(name); -} - -dd_bool SV_IsSlotUsed(int slot) -{ - DENG_ASSERT(inited); - return saveSlots.slotInUse(slot); -} - #if __JHEXEN__ dd_bool SV_HxHaveMapStateForSlot(int slot, uint map) { DENG_ASSERT(inited); - AutoStr *path = saveSlots.composeGameSavePathForSlot(slot, (int)map+1); + AutoStr *path = saveSlots.composeSavePathForSlot(slot, (int)map+1); if(!path || Str_IsEmpty(path)) return false; return SV_ExistingFile(path); } @@ -2364,9 +2310,6 @@ void SV_Initialize() targetPlayerAddrs = 0; saveBuffer = 0; #endif - // -1 = Not yet chosen/determined. - cvarLastSlot = -1; - cvarQuickSlot = -1; } // (Re)Initialize the saved game paths, possibly creating them if they do not exist. @@ -2380,9 +2323,6 @@ void SV_Shutdown() SV_ShutdownIO(); saveSlots.clearSaveInfo(); - cvarLastSlot = -1; - cvarQuickSlot = -1; - inited = false; } @@ -2498,7 +2438,7 @@ static int SV_LoadState(Str const *path, SaveInfo *info) // Load the current map state. #if __JHEXEN__ - readMapState(reader, info->version(), saveSlots.composeGameSavePathForSlot(BASE_SLOT, gameMap+1)); + readMapState(reader, info->version(), saveSlots.composeSavePathForSlot(BASE_SLOT, gameMap+1)); #else readMapState(reader, info->version()); #endif @@ -2642,10 +2582,10 @@ dd_bool SV_LoadGame(int slot) int const logicalSlot = slot; #endif - if(!SV_IsValidSlot(slot)) + if(!saveSlots.isValidSlot(slot)) return false; - AutoStr *path = saveSlots.composeGameSavePathForSlot(slot); + AutoStr *path = saveSlots.composeSavePathForSlot(slot); if(Str_IsEmpty(path)) { App_Log(DE2_RES_ERROR, "Game not loaded: path \"%s\" is unreachable", SV_SavePath()); @@ -2664,7 +2604,7 @@ dd_bool SV_LoadGame(int slot) } #endif - SaveInfo *saveInfo = SV_SaveInfoForSlot(logicalSlot); + SaveInfo *saveInfo = saveSlots.saveInfo(logicalSlot); DENG_ASSERT(saveInfo != 0); int loadError = loadStateWorker(path, *saveInfo); @@ -2850,7 +2790,7 @@ static int saveStateWorker(Str const *path, SaveInfo *saveInfo) */ #if __JHEXEN__ // ...map state is actually written to a separate file. - SV_OpenFile(saveSlots.composeGameSavePathForSlot(BASE_SLOT, gameMap+1), "wp"); + SV_OpenFile(saveSlots.composeSavePathForSlot(BASE_SLOT, gameMap+1), "wp"); #endif MapStateWriter(thingArchiveExcludePlayers).write(writer); @@ -2891,7 +2831,7 @@ dd_bool SV_SaveGame(int slot, char const *name) int const logicalSlot = slot; #endif - if(!SV_IsValidSlot(slot)) + if(!saveSlots.isValidSlot(slot)) { DENG_ASSERT(!"Invalid slot '%i' specified"); return false; @@ -2902,7 +2842,7 @@ dd_bool SV_SaveGame(int slot, char const *name) return false; } - AutoStr *path = saveSlots.composeGameSavePathForSlot(logicalSlot); + AutoStr *path = saveSlots.composeSavePathForSlot(logicalSlot); if(Str_IsEmpty(path)) { App_Log(DE2_RES_WARNING, "Cannot save game: path \"%s\" is unreachable", SV_SavePath()); @@ -2944,7 +2884,7 @@ void SV_HxSaveHubMap() { playerHeaderOK = false; // Uninitialized. - SV_OpenFile(saveSlots.composeGameSavePathForSlot(BASE_SLOT, gameMap+1), "wp"); + SV_OpenFile(saveSlots.composeSavePathForSlot(BASE_SLOT, gameMap+1), "wp"); // Set the mobj archive numbers initThingArchiveForSave(true /*exclude players*/); @@ -2974,7 +2914,7 @@ void SV_HxLoadHubMap() Reader *reader = SV_NewReader(); // Been here before, load the previous map state. - readMapState(reader, info->version(), saveSlots.composeGameSavePathForSlot(BASE_SLOT, gameMap+1)); + readMapState(reader, info->version(), saveSlots.composeSavePathForSlot(BASE_SLOT, gameMap+1)); Reader_Delete(reader); } @@ -3148,15 +3088,5 @@ void SV_HxRestorePlayersInHub(playerbackup_t playerBackup[MAXPLAYERS], void SV_Register() { -#if !__JHEXEN__ - C_VAR_BYTE("game-save-auto-loadonreborn", &cfg.loadAutoSaveOnReborn, 0, 0, 1); -#endif - C_VAR_BYTE("game-save-confirm", &cfg.confirmQuickGameSave, 0, 0, 1); - C_VAR_BYTE("game-save-confirm-loadonreborn", &cfg.confirmRebornLoad, 0, 0, 1); - C_VAR_BYTE("game-save-last-loadonreborn", &cfg.loadLastSaveOnReborn, 0, 0, 1); - C_VAR_INT ("game-save-last-slot", &cvarLastSlot, CVF_NO_MIN|CVF_NO_MAX|CVF_NO_ARCHIVE|CVF_READ_ONLY, 0, 0); - C_VAR_INT ("game-save-quick-slot", &cvarQuickSlot, CVF_NO_MAX|CVF_NO_ARCHIVE, -1, 0); - - // Aliases for obsolete cvars: - C_VAR_BYTE("menu-quick-ask", &cfg.confirmQuickGameSave, 0, 0, 1); + SaveSlots::consoleRegister(); } diff --git a/doomsday/plugins/common/src/saveslots.cpp b/doomsday/plugins/common/src/saveslots.cpp index 72eb315241..2ace8c10dd 100644 --- a/doomsday/plugins/common/src/saveslots.cpp +++ b/doomsday/plugins/common/src/saveslots.cpp @@ -21,11 +21,15 @@ #include "common.h" #include "saveslots.h" +#include "p_saveio.h" #include "p_saveg.h" /// @todo remove me #include #define MAX_HUB_MAPS 99 +static int cvarLastSlot = -1; ///< @c -1= Not yet loaded/saved in this game session. +static int cvarQuickSlot = -1; ///< @c -1= Not yet chosen/determined. + DENG2_PIMPL(SaveSlots) { SaveInfo **saveInfo; @@ -118,6 +122,9 @@ void SaveSlots::clearSaveInfo() { delete d->nullSaveInfo; d->nullSaveInfo = 0; } + + cvarLastSlot = -1; + cvarQuickSlot = -1; } void SaveSlots::buildSaveInfo() @@ -145,11 +152,11 @@ void SaveSlots::buildSaveInfo() for(int i = 0; i < NUMSAVESLOTS; ++i) { SaveInfo *info = d->saveInfo[i]; - d->updateSaveInfo(composeGameSavePathForSlot(i), info); + d->updateSaveInfo(composeSavePathForSlot(i), info); } - d->updateSaveInfo(composeGameSavePathForSlot(AUTO_SLOT), d->autoSaveInfo); + d->updateSaveInfo(composeSavePathForSlot(AUTO_SLOT), d->autoSaveInfo); #if __JHEXEN__ - d->updateSaveInfo(composeGameSavePathForSlot(BASE_SLOT), d->baseSaveInfo); + d->updateSaveInfo(composeSavePathForSlot(BASE_SLOT), d->baseSaveInfo); #endif } @@ -172,7 +179,7 @@ AutoStr *SaveSlots::composeSlotIdentifier(int slot) int SaveSlots::parseSlotIdentifier(char const *str) { // Try game-save name match. - int slot = SV_SlotForSaveName(str); + int slot = findSlotWithSaveDescription(str); if(slot >= 0) return slot; // Try keyword identifiers. @@ -199,7 +206,7 @@ int SaveSlots::parseSlotIdentifier(char const *str) return -1; } -int SaveSlots::slotForSaveName(char const *description) +int SaveSlots::findSlotWithSaveDescription(char const *description) { DENG_ASSERT(description != 0); @@ -229,9 +236,9 @@ int SaveSlots::slotForSaveName(char const *description) bool SaveSlots::slotInUse(int slot) { - if(SV_ExistingFile(composeGameSavePathForSlot(slot))) + if(SV_ExistingFile(composeSavePathForSlot(slot))) { - return findSaveInfoForSlot(slot)->isLoadable(); + return saveInfo(slot)->isLoadable(); } return false; } @@ -245,7 +252,7 @@ bool SaveSlots::isValidSlot(int slot) return (slot >= 0 && slot < NUMSAVESLOTS); } -bool SaveSlots::isUserWritableSlot(int slot) +bool SaveSlots::slotIsUserWritable(int slot) { if(slot == AUTO_SLOT) return false; #if __JHEXEN__ @@ -254,7 +261,7 @@ bool SaveSlots::isUserWritableSlot(int slot) return isValidSlot(slot); } -SaveInfo *SaveSlots::findSaveInfoForSlot(int slot) +SaveInfo *SaveSlots::saveInfo(int slot) { if(!isValidSlot(slot)) return d->nullSaveInfo; @@ -302,20 +309,20 @@ void SaveSlots::clearSlot(int slot) if(d->announceOnClearingSlot(slot)) { - AutoStr *ident = SV_ComposeSlotIdentifier(slot); + AutoStr *ident = composeSlotIdentifier(slot); App_Log(DE2_RES_MSG, "Clearing save slot %s", Str_Text(ident)); } for(int i = 0; i < MAX_HUB_MAPS; ++i) { - AutoStr *path = composeGameSavePathForSlot(slot, i); + AutoStr *path = composeSavePathForSlot(slot, i); SV_RemoveFile(path); } - AutoStr *path = composeGameSavePathForSlot(slot); + AutoStr *path = composeSavePathForSlot(slot); SV_RemoveFile(path); - d->updateSaveInfo(path, findSaveInfoForSlot(slot)); + d->updateSaveInfo(path, saveInfo(slot)); } void SaveSlots::copySlot(int sourceSlot, int destSlot) @@ -338,22 +345,22 @@ void SaveSlots::copySlot(int sourceSlot, int destSlot) AutoStr *src, *dst; for(int i = 0; i < MAX_HUB_MAPS; ++i) { - src = composeGameSavePathForSlot(sourceSlot, i); - dst = composeGameSavePathForSlot(destSlot, i); + src = composeSavePathForSlot(sourceSlot, i); + dst = composeSavePathForSlot(destSlot, i); SV_CopyFile(src, dst); } - src = composeGameSavePathForSlot(sourceSlot); - dst = composeGameSavePathForSlot(destSlot); + src = composeSavePathForSlot(sourceSlot); + dst = composeSavePathForSlot(destSlot); SV_CopyFile(src, dst); // Copy saveinfo too. - SaveInfo *info = findSaveInfoForSlot(sourceSlot); + SaveInfo *info = saveInfo(sourceSlot); DENG_ASSERT(info != 0); replaceSaveInfo(destSlot, new SaveInfo(*info)); } -AutoStr *SaveSlots::composeGameSavePathForSlot(int slot, int map) +AutoStr *SaveSlots::composeSavePathForSlot(int slot, int map) { AutoStr *path = AutoStr_NewStd(); @@ -376,3 +383,119 @@ AutoStr *SaveSlots::composeGameSavePathForSlot(int slot, int map) F_TranslatePath(path, path); return path; } + +void SaveSlots::consoleRegister() // static +{ +#if !__JHEXEN__ + C_VAR_BYTE("game-save-auto-loadonreborn", &cfg.loadAutoSaveOnReborn, 0, 0, 1); +#endif + C_VAR_BYTE("game-save-confirm", &cfg.confirmQuickGameSave, 0, 0, 1); + C_VAR_BYTE("game-save-confirm-loadonreborn", &cfg.confirmRebornLoad, 0, 0, 1); + C_VAR_BYTE("game-save-last-loadonreborn", &cfg.loadLastSaveOnReborn, 0, 0, 1); + C_VAR_INT ("game-save-last-slot", &cvarLastSlot, CVF_NO_MIN|CVF_NO_MAX|CVF_NO_ARCHIVE|CVF_READ_ONLY, 0, 0); + C_VAR_INT ("game-save-quick-slot", &cvarQuickSlot, CVF_NO_MAX|CVF_NO_ARCHIVE, -1, 0); + + // Aliases for obsolete cvars: + C_VAR_BYTE("menu-quick-ask", &cfg.confirmQuickGameSave, 0, 0, 1); +} + +// C wrapper API --------------------------------------------------------------- + +SaveSlots *SaveSlots_New() +{ + return new SaveSlots; +} + +void SaveSlots_Delete(SaveSlots *sslots) +{ + delete sslots; +} + +void SaveSlots_ClearSaveInfo(SaveSlots *sslots) +{ + DENG_ASSERT(sslots != 0); + sslots->clearSaveInfo(); +} + +void SaveSlots_BuildSaveInfo(SaveSlots *sslots) +{ + DENG_ASSERT(sslots != 0); + sslots->buildSaveInfo(); +} + +void SaveSlots_UpdateAllSaveInfo(SaveSlots *sslots) +{ + DENG_ASSERT(sslots != 0); + sslots->updateAllSaveInfo(); +} + +dd_bool SaveSlots_IsValidSlot(SaveSlots *sslots, int slot) +{ + DENG_ASSERT(sslots != 0); + return sslots->isValidSlot(slot); +} + +AutoStr *SaveSlots_ComposeSlotIdentifier(SaveSlots *sslots, int slot) +{ + DENG_ASSERT(sslots != 0); + return sslots->composeSlotIdentifier(slot); +} + +int SaveSlots_ParseSlotIdentifier(SaveSlots *sslots, char const *str) +{ + DENG_ASSERT(sslots != 0); + return sslots->parseSlotIdentifier(str); +} + +int SaveSlots_SlotForSaveName(SaveSlots *sslots, char const *description) +{ + DENG_ASSERT(sslots != 0); + return sslots->findSlotWithSaveDescription(description); +} + +dd_bool SaveSlots_SlotInUse(SaveSlots *sslots, int slot) +{ + DENG_ASSERT(sslots != 0); + return sslots->slotInUse(slot); +} + +dd_bool SaveSlots_SlotIsUserWritable(SaveSlots *sslots, int slot) +{ + DENG_ASSERT(sslots != 0); + return sslots->slotIsUserWritable(slot); +} + +SaveInfo *SaveSlots_FindSaveInfoForSlot(SaveSlots *sslots, int slot) +{ + DENG_ASSERT(sslots != 0); + return sslots->saveInfo(slot); +} + +void SaveSlots_ReplaceSaveInfo(SaveSlots *sslots, int slot, SaveInfo *newInfo) +{ + DENG_ASSERT(sslots != 0); + sslots->replaceSaveInfo(slot, newInfo); +} + +void SaveSlots_ClearSlot(SaveSlots *sslots, int slot) +{ + DENG_ASSERT(sslots != 0); + sslots->clearSlot(slot); +} + +void SaveSlots_CopySlot(SaveSlots *sslots, int sourceSlot, int destSlot) +{ + DENG_ASSERT(sslots != 0); + sslots->copySlot(sourceSlot, destSlot); +} + +AutoStr *SaveSlots_ComposeSavePathForSlot(SaveSlots *sslots, int slot, int map) +{ + DENG_ASSERT(sslots != 0); + return sslots->composeSavePathForSlot(slot, map); +} + +void SaveSlots_ConsoleRegister() +{ + SaveSlots::consoleRegister(); +} diff --git a/doomsday/plugins/doom/src/d_main.c b/doomsday/plugins/doom/src/d_main.c index cc0292b384..e9ab63288b 100644 --- a/doomsday/plugins/doom/src/d_main.c +++ b/doomsday/plugins/doom/src/d_main.c @@ -470,8 +470,8 @@ void D_PostInit(void) p = CommandLine_Check("-loadgame"); if(p && p < myargc - 1) { - int const saveSlot = SV_ParseSlotIdentifier(CommandLine_At(p + 1)); - if(SV_IsUserWritableSlot(saveSlot) && G_LoadGame(saveSlot)) + int const slotNumber = SaveSlots_ParseSlotIdentifier(saveSlots, CommandLine_At(p + 1)); + if(SaveSlots_SlotIsUserWritable(saveSlots, slotNumber) && G_LoadGame(slotNumber)) { // No further initialization is to be done. return; diff --git a/doomsday/plugins/doom/src/p_oldsvg.cpp b/doomsday/plugins/doom/src/p_oldsvg.cpp index 8f0fd21290..5fea620900 100644 --- a/doomsday/plugins/doom/src/p_oldsvg.cpp +++ b/doomsday/plugins/doom/src/p_oldsvg.cpp @@ -23,6 +23,7 @@ #include "p_oldsvg.h" #include "dmu_lib.h" +#include "p_saveio.h" #include "p_saveg.h" #include "p_map.h" #include "p_mapsetup.h" diff --git a/doomsday/plugins/doom64/src/d_main.c b/doomsday/plugins/doom64/src/d_main.c index 5c953df16d..9fd3fb4b4c 100644 --- a/doomsday/plugins/doom64/src/d_main.c +++ b/doomsday/plugins/doom64/src/d_main.c @@ -375,8 +375,8 @@ void D_PostInit(void) p = CommandLine_Check("-loadgame"); if(p && p < myargc - 1) { - int const saveSlot = SV_ParseSlotIdentifier(CommandLine_At(p + 1)); - if(SV_IsUserWritableSlot(saveSlot) && G_LoadGame(saveSlot)) + int const slotNumber = SaveSlots_ParseSlotIdentifier(saveSlots, CommandLine_At(p + 1)); + if(SaveSlots_SlotIsUserWritable(saveSlots, slotNumber) && G_LoadGame(slotNumber)) { // No further initialization is to be done. return; diff --git a/doomsday/plugins/heretic/src/h_main.c b/doomsday/plugins/heretic/src/h_main.c index a4aca3abe4..1840157b13 100644 --- a/doomsday/plugins/heretic/src/h_main.c +++ b/doomsday/plugins/heretic/src/h_main.c @@ -398,8 +398,8 @@ void H_PostInit(void) p = CommandLine_Check("-loadgame"); if(p && p < myargc - 1) { - const int saveSlot = SV_ParseSlotIdentifier(CommandLine_At(p + 1)); - if(SV_IsUserWritableSlot(saveSlot) && G_LoadGame(saveSlot)) + int const slotNumber = SaveSlots_ParseSlotIdentifier(saveSlots, CommandLine_At(p + 1)); + if(SaveSlots_SlotIsUserWritable(saveSlots, slotNumber) && G_LoadGame(slotNumber)) { // No further initialization is to be done. return; diff --git a/doomsday/plugins/heretic/src/p_oldsvg.cpp b/doomsday/plugins/heretic/src/p_oldsvg.cpp index 3b83c4ee37..de4df173b6 100644 --- a/doomsday/plugins/heretic/src/p_oldsvg.cpp +++ b/doomsday/plugins/heretic/src/p_oldsvg.cpp @@ -23,6 +23,7 @@ #include "p_oldsvg.h" #include "dmu_lib.h" +#include "p_saveio.h" #include "p_saveg.h" #include "p_map.h" #include "p_mapsetup.h" diff --git a/doomsday/plugins/hexen/src/h2_main.c b/doomsday/plugins/hexen/src/h2_main.c index 5390ab3dfa..9a572eabdf 100644 --- a/doomsday/plugins/hexen/src/h2_main.c +++ b/doomsday/plugins/hexen/src/h2_main.c @@ -371,8 +371,8 @@ void X_PostInit(void) p = CommandLine_CheckWith("-loadgame", 1); if(p != 0) { - int const saveSlot = SV_ParseSlotIdentifier(CommandLine_At(p + 1)); - if(SV_IsUserWritableSlot(saveSlot) && G_LoadGame(saveSlot)) + int const slotNumber = SaveSlots_ParseSlotIdentifier(saveSlots, CommandLine_At(p + 1)); + if(SaveSlots_SlotIsUserWritable(saveSlots, slotNumber) && G_LoadGame(slotNumber)) { // No further initialization is to be done. return;