Skip to content

Commit

Permalink
libcommon|SaveSlots: Mechanism for binding save game file names to lo…
Browse files Browse the repository at this point in the history
…gical save slots
  • Loading branch information
danij-deng committed Feb 21, 2014
1 parent 2f75519 commit ec54087
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 52 deletions.
20 changes: 11 additions & 9 deletions doomsday/plugins/common/include/saveslots.h
Expand Up @@ -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;

Expand Down Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion doomsday/plugins/common/src/gamestatereader.cpp
Expand Up @@ -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() + "\"");
Expand Down
2 changes: 1 addition & 1 deletion doomsday/plugins/common/src/gamestatewriter.cpp
Expand Up @@ -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);
Expand Down
10 changes: 5 additions & 5 deletions doomsday/plugins/common/src/p_saveg.cpp
Expand Up @@ -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);
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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",
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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");
Expand Down
14 changes: 7 additions & 7 deletions doomsday/plugins/common/src/p_saveio.cpp
Expand Up @@ -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
Expand All @@ -44,7 +44,7 @@ static void *saveEndPtr;

void SV_InitIO()
{
savePath.clear();
saveName.clear();
#if !__JHEXEN__
clientSavePath.clear();
#endif
Expand All @@ -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()))
{
Expand All @@ -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__
Expand Down
61 changes: 32 additions & 29 deletions doomsday/plugins/common/src/saveslots.cpp
Expand Up @@ -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();
}
Expand All @@ -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
Expand All @@ -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.
Expand All @@ -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.
Expand All @@ -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)
Expand All @@ -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)));
}
}

Expand Down Expand Up @@ -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;
}
}
}
Expand Down Expand Up @@ -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);
Expand All @@ -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()));
Expand Down

0 comments on commit ec54087

Please sign in to comment.