From ec54087bbb5ce8464d7548ad510efe710b75e7de Mon Sep 17 00:00:00 2001 From: danij Date: Fri, 21 Feb 2014 12:15:14 +0000 Subject: [PATCH] libcommon|SaveSlots: Mechanism for binding save game file names to logical save slots --- doomsday/plugins/common/include/saveslots.h | 20 +++--- .../plugins/common/src/gamestatereader.cpp | 2 +- .../plugins/common/src/gamestatewriter.cpp | 2 +- doomsday/plugins/common/src/p_saveg.cpp | 10 +-- doomsday/plugins/common/src/p_saveio.cpp | 14 ++--- doomsday/plugins/common/src/saveslots.cpp | 61 ++++++++++--------- 6 files changed, 57 insertions(+), 52 deletions(-) diff --git a/doomsday/plugins/common/include/saveslots.h b/doomsday/plugins/common/include/saveslots.h index ed57ee56e8..e6c141cb75 100644 --- a/doomsday/plugins/common/include/saveslots.h +++ b/doomsday/plugins/common/include/saveslots.h @@ -52,17 +52,19 @@ class SaveSlots DENG2_ERROR(MissingInfoError); public: - Slot(int index); + Slot(de::String const &saveName = ""); /** - * Returns @c true iff a saved game state exists for the logical save slot. + * Change the save game name bound to the logical save slot. + * + * @param newSaveName New save game name to apply. */ - bool isUsed() const; + void bindSaveName(de::String newSaveName); /** - * Returns the unique index of the logical save slot. + * Returns @c true iff a saved game state exists for the logical save slot. */ - int index() const; + bool isUsed() const; bool hasSaveInfo() const; @@ -90,15 +92,15 @@ class SaveSlots void addMissingSaveInfo(); /** - * Compose the (possibly relative) file path to the map state associated with the save slot. + * Returns the save name (with file extension) of the game state associated with the save slot. * * @param map Logical map index. * - * @return The composed path if reachable (else a zero-length string). + * @return The composed name if reachable (else a zero-length string). */ - de::Path mapSavePath(uint map) const; + de::String mapSaveName(uint map) const; - de::Path savePath() const; + de::String saveName() const; private: DENG2_PRIVATE(d) diff --git a/doomsday/plugins/common/src/gamestatereader.cpp b/doomsday/plugins/common/src/gamestatereader.cpp index 5e70c81820..7184048597 100644 --- a/doomsday/plugins/common/src/gamestatereader.cpp +++ b/doomsday/plugins/common/src/gamestatereader.cpp @@ -114,7 +114,7 @@ DENG2_PIMPL(GameStateReader) SV_HxReleaseSaveBuffer(); // Open the map state file. - de::Path path = SV_SaveSlots()[BASE_SLOT].mapSavePath(gameMap); + de::Path path = SV_SavePath() / SV_SaveSlots()[BASE_SLOT].mapSaveName(gameMap); if(!SV_OpenMapSaveFile(path)) { throw FileAccessError("GameStateReader", "Failed opening \"" + de::NativePath(path).pretty() + "\""); diff --git a/doomsday/plugins/common/src/gamestatewriter.cpp b/doomsday/plugins/common/src/gamestatewriter.cpp index c3c92a8051..655b5d3946 100644 --- a/doomsday/plugins/common/src/gamestatewriter.cpp +++ b/doomsday/plugins/common/src/gamestatewriter.cpp @@ -89,7 +89,7 @@ DENG2_PIMPL(GameStateWriter) SV_CloseFile(); // Open the map state file. - SV_OpenFile(SV_SaveSlots()[BASE_SLOT].mapSavePath(gameMap), "wp"); + SV_OpenFile(SV_SavePath() / SV_SaveSlots()[BASE_SLOT].mapSaveName(gameMap), "wp"); #endif MapStateWriter(*thingArchive).write(writer); diff --git a/doomsday/plugins/common/src/p_saveg.cpp b/doomsday/plugins/common/src/p_saveg.cpp index aa8ddc4008..bbf951240b 100644 --- a/doomsday/plugins/common/src/p_saveg.cpp +++ b/doomsday/plugins/common/src/p_saveg.cpp @@ -76,7 +76,7 @@ static de::Path savePathForClientSessionId(uint sessionId) dd_bool SV_HxHaveMapStateForSlot(int slotNumber, uint map) { DENG2_ASSERT(inited); - de::Path path = SV_SaveSlots()[slotNumber].mapSavePath(map); + de::Path path = SV_SavePath() / SV_SaveSlots()[slotNumber].mapSaveName(map); if(!path.isEmpty()) { return SV_ExistingFile(path); @@ -868,7 +868,7 @@ dd_bool SV_LoadGame(int slotNumber) App_Log(DE2_RES_VERBOSE, "Attempting load of save slot #%i...", slotNumber); - de::Path path = SV_SaveSlots()[slotNumber].savePath(); + de::Path path = SV_SavePath() / SV_SaveSlots()[slotNumber].saveName(); if(path.isEmpty()) { App_Log(DE2_RES_ERROR, "Game not loaded: path \"%s\" is unreachable", @@ -928,7 +928,7 @@ dd_bool SV_SaveGame(int slotNumber, char const *description) return false; } - de::Path path = SV_SaveSlots()[logicalSlot].savePath(); + de::Path path = SV_SavePath() / SV_SaveSlots()[logicalSlot].saveName(); if(path.isEmpty()) { App_Log(DE2_RES_WARNING, "Cannot save game: path \"%s\" is unreachable", @@ -1105,7 +1105,7 @@ void SV_LoadGameClient(uint sessionId) #if __JHEXEN__ void SV_HxSaveHubMap() { - SV_OpenFile(SV_SaveSlots()[BASE_SLOT].mapSavePath(gameMap), "wp"); + SV_OpenFile(SV_SavePath() / SV_SaveSlots()[BASE_SLOT].mapSaveName(gameMap), "wp"); // Set the mobj archive numbers ThingArchive thingArchive; @@ -1133,7 +1133,7 @@ void SV_HxLoadHubMap() try { SaveSlot &sslot = SV_SaveSlots()[BASE_SLOT]; - de::Path path = sslot.mapSavePath(gameMap); + de::Path path = SV_SavePath() / sslot.mapSaveName(gameMap); if(!SV_OpenMapSaveFile(path)) { throw de::Error("SV_HxLoadHubMap", "Failed opening \"" + de::NativePath(path).pretty() + "\" for read"); diff --git a/doomsday/plugins/common/src/p_saveio.cpp b/doomsday/plugins/common/src/p_saveio.cpp index 0b00064bbc..82c9aa02db 100644 --- a/doomsday/plugins/common/src/p_saveio.cpp +++ b/doomsday/plugins/common/src/p_saveio.cpp @@ -31,7 +31,7 @@ static bool inited; static LZFILE *savefile; -static de::Path savePath; // e.g., "savegame" +static de::Path saveName; // e.g., "savegame" #if !__JHEXEN__ static de::Path clientSavePath; // e.g., "savegame/client" #endif @@ -44,7 +44,7 @@ static void *saveEndPtr; void SV_InitIO() { - savePath.clear(); + saveName.clear(); #if !__JHEXEN__ clientSavePath.clear(); #endif @@ -67,13 +67,13 @@ void SV_SetupSaveDirectory(de::Path newRootSaveDir) if(!newRootSaveDir.isEmpty()) { - savePath = newRootSaveDir; + saveName = newRootSaveDir; #if !__JHEXEN__ clientSavePath = newRootSaveDir / "client"; #endif // Ensure that these paths exist. - bool savePathExists = F_MakePath(de::NativePath(savePath).expand().toUtf8().constData()); + bool savePathExists = F_MakePath(de::NativePath(saveName).expand().toUtf8().constData()); #if !__JHEXEN__ if(!F_MakePath(de::NativePath(clientSavePath).expand().toUtf8().constData())) { @@ -87,19 +87,19 @@ void SV_SetupSaveDirectory(de::Path newRootSaveDir) } } - savePath.clear(); + saveName.clear(); #if !__JHEXEN__ clientSavePath.clear(); #endif App_Log(DE2_RES_ERROR, "SV_SetupSaveDirectory: \"%s\" could not be accessed. Perhaps it could " "not be created (insufficient permissions?). Saving will not be possible.", - de::NativePath(savePath).pretty().toLatin1().constData()); + de::NativePath(saveName).pretty().toLatin1().constData()); } de::Path SV_SavePath() { - return savePath; + return saveName; } #if !__JHEXEN__ diff --git a/doomsday/plugins/common/src/saveslots.cpp b/doomsday/plugins/common/src/saveslots.cpp index 92f43032cd..8531641549 100644 --- a/doomsday/plugins/common/src/saveslots.cpp +++ b/doomsday/plugins/common/src/saveslots.cpp @@ -33,24 +33,30 @@ static int cvarQuickSlot = -1; ///< @c -1= Not yet chosen/determined. DENG2_PIMPL_NOREF(SaveSlots::Slot) { - int index; + de::String saveName; SaveInfo *info; - Instance(int index) : index(index), info(0) {} + Instance() : info(0) {} ~Instance() { delete info; } }; -SaveSlots::Slot::Slot(int index) : d(new Instance(index)) -{} +SaveSlots::Slot::Slot(de::String const &saveName) : d(new Instance) +{ + d->saveName = saveName; +} -int SaveSlots::Slot::index() const +void SaveSlots::Slot::bindSaveName(de::String newSaveName) { - return d->index; + if(d->saveName.compareWithoutCase(newSaveName)) + { + clearSaveInfo(); + } + d->saveName = newSaveName; } bool SaveSlots::Slot::isUsed() const { - if(SV_ExistingFile(savePath())) + if(SV_ExistingFile(SV_SavePath() / saveName())) { return saveInfo().isLoadable(); } @@ -77,7 +83,7 @@ void SaveSlots::Slot::addMissingSaveInfo() { if(d->info) return; d->info = new SaveInfo; - d->info->updateFromFile(savePath()); + d->info->updateFromFile(SV_SavePath() / saveName()); } SaveInfo &SaveSlots::Slot::saveInfo(bool canCreate) const @@ -94,7 +100,7 @@ SaveInfo &SaveSlots::Slot::saveInfo(bool canCreate) const throw MissingInfoError("SaveSlots::Slot::saveInfo", "No SaveInfo exists"); } -de::Path SaveSlots::Slot::mapSavePath(uint map) const +de::String SaveSlots::Slot::mapSaveName(uint map) const { // Do we have a valid path? /// @todo Do not do alter the file system until necessary. @@ -103,14 +109,12 @@ de::Path SaveSlots::Slot::mapSavePath(uint map) const return ""; } - // Compose the full game-save path and filename. - return SV_SavePath() - / de::String(SAVEGAMENAME "%1%2." SAVEGAMEEXTENSION) - .arg(d->index) - .arg(int(map + 1), 2, 10, QChar('0')); + // Compose the full game-save filename. + return d->saveName + de::String("%1." SAVEGAMEEXTENSION) + .arg(int(map + 1), 2, 10, QChar('0')); } -de::Path SaveSlots::Slot::savePath() const +de::String SaveSlots::Slot::saveName() const { // Do we have a valid path? /// @todo Do not do alter the file system until necessary. @@ -119,10 +123,8 @@ de::Path SaveSlots::Slot::savePath() const return ""; } - // Compose the full game-save path and filename. - return SV_SavePath() - / de::String(SAVEGAMENAME "%1." SAVEGAMEEXTENSION) - .arg(d->index); + // Compose the full game-save filename. + return d->saveName + de::String("." SAVEGAMEEXTENSION); } DENG2_PIMPL(SaveSlots) @@ -138,14 +140,14 @@ DENG2_PIMPL(SaveSlots) Instance(Public *i, int slotCount) : Base(i) , slotCount(de::max(1, slotCount)) - , autoSlot(AUTO_SLOT) + , autoSlot(de::String(SAVEGAMENAME "%1").arg(AUTO_SLOT)) #if __JHEXEN__ - , baseSlot(BASE_SLOT) + , baseSlot(de::String(SAVEGAMENAME "%1").arg(BASE_SLOT)) #endif { for(int i = 0; i < slotCount; ++i) { - sslots.push_back(new Slot(i)); + sslots.push_back(new Slot(de::String(SAVEGAMENAME "%1").arg(i))); } } @@ -251,13 +253,13 @@ int SaveSlots::findSlotWithUserSaveDescription(de::String description) const { if(!description.isEmpty()) { - DENG2_FOR_EACH_CONST(Instance::Slots, i, d->sslots) + for(int i = 0; i < (signed)d->sslots.size(); ++i) { - SaveSlot &sslot = **i; + SaveSlot &sslot = *d->sslots[i]; if(sslot.hasSaveInfo() && !sslot.saveInfo().userDescription().compareWithoutCase(description)) { - return sslot.index(); + return i; } } } @@ -318,10 +320,10 @@ void SaveSlots::clearSlot(int slotNumber) for(int i = 0; i < MAX_HUB_MAPS; ++i) { - SV_RemoveFile(sslot.mapSavePath(i)); + SV_RemoveFile(SV_SavePath() / sslot.mapSaveName(i)); } - SV_RemoveFile(sslot.savePath()); + SV_RemoveFile(SV_SavePath() / sslot.saveName()); sslot.saveInfo().setUserDescription(""); sslot.saveInfo().setSessionId(0); @@ -339,10 +341,11 @@ void SaveSlots::copySlot(int sourceSlotNumber, int destSlotNumber) for(int i = 0; i < MAX_HUB_MAPS; ++i) { - SV_CopyFile(sourceSlot.mapSavePath(i), destSlot.mapSavePath(i)); + SV_CopyFile(SV_SavePath() / sourceSlot.mapSaveName(i), + SV_SavePath() / destSlot.mapSaveName(i)); } - SV_CopyFile(sourceSlot.savePath(), destSlot.savePath()); + SV_CopyFile(SV_SavePath() / sourceSlot.saveName(), SV_SavePath() / destSlot.saveName()); // Copy save info too. destSlot.replaceSaveInfo(new SaveInfo(sourceSlot.saveInfo()));