Skip to content

Commit

Permalink
Resource System: Trying out automatic conversion of legacy savegames
Browse files Browse the repository at this point in the history
Any existing savegames for a newly added game are now automatically
converted at this time. However, the converted .save package is not
currently written to proper output path (presently they end up in
Savegame Tool's /home folder).

A more intelligent mechanism that considers things such as custom
and game-specific save folders is needed.
  • Loading branch information
danij-deng committed Mar 20, 2014
1 parent e735ce0 commit ec0738d
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 25 deletions.
105 changes: 81 additions & 24 deletions doomsday/client/src/resource/resourcesystem.cpp
Expand Up @@ -66,6 +66,7 @@
#include <de/DirectoryFeed>
#include <de/game/SavedSession>
#include <de/Log>
#include <de/NativeFile>
#include <de/Reader>
#include <de/Time>
#ifdef __CLIENT__
Expand Down Expand Up @@ -323,20 +324,22 @@ DENG2_PIMPL(ResourceSystem)
typedef QMap<spritenum_t, SpriteGroup> SpriteGroups;
SpriteGroups spriteGroups;

NativePath nativeSavePath;
game::SavedSessionRepository saveRepo;

Instance(Public *i)
: Base(i)
, defaultColorPalette(0)
, materialManifestCount(0)
, defaultColorPalette (0)
, materialManifestCount (0)
, materialManifestIdMapSize(0)
, materialManifestIdMap(0)
, materialManifestIdMap (0)
#ifdef __CLIENT__
, fontManifestCount(0)
, fontManifestIdMapSize(0)
, fontManifestIdMap(0)
, modelRepository(0)
, fontManifestCount (0)
, fontManifestIdMapSize (0)
, fontManifestIdMap (0)
, modelRepository (0)
#endif
, nativeSavePath (App::app().nativeHomePath() / "savegame") // default
{
LOG_AS("ResourceSystem");
resClasses.append(new ResourceClass("RC_PACKAGE", "Packages"));
Expand Down Expand Up @@ -376,18 +379,13 @@ DENG2_PIMPL(ResourceSystem)
App_Games().audienceForAddition += this;

// Determine the root directory of the saved session repository.
NativePath nativeSavePath;
if(int arg = App::commandLine().check("-savedir", 1))
{
// Using a custom root save directory.
App::commandLine().makeAbsolutePath(arg + 1);
nativeSavePath = App::commandLine().at(arg + 1);
}
else
{
// Use the default.
nativeSavePath = App::app().nativeHomePath() / "savegame";
}
// Else use the default.

// Create the user's saved game folder if it doesn't yet exist.
App::fileSystem().makeFolder("/savegame", FS::DontInheritFeeds)
Expand Down Expand Up @@ -1918,11 +1916,44 @@ DENG2_PIMPL(ResourceSystem)

#endif // __CLIENT__

/// @todo Move to Game?
String legacySavegameExtension(Game const &game)
{
String const gameId = game.identityKey();
if(gameId.beginsWith("doom")) return ".dsg";
if(gameId.beginsWith("heretic")) return ".hsg";
if(gameId.beginsWith("hexen")) return ".hxs";
return "";
}

/// @todo Move to Game?
String legacySavegameSubfolder(Game const &game)
{
String const gameId = game.identityKey();
if(gameId.beginsWith("doom")) return "savegame";
if(gameId.beginsWith("heretic")) return "savegame";
if(gameId.beginsWith("hexen")) return "hexndata";
return "";
}

/**
* Determine the absolute path to the legacy savegame folder for the specified @a game.
* If there is no possibility of a legacy savegame existing (e.g., because the game is
* newer than the introduction of the modern, packaged based save format) then a zero
* length string is returned.
*
* @param game Game to return the legacy savegame folder path for.
*/
String legacySavePath(Game const &/*game*/)
{
return nativeSavePath;// / legacySavegameSubfolder(game);
}

void gameAdded(Game &game)
{
// Called from a non-UI thread.
LOG_AS("ResourceSystem");
String gameId = game.identityKey();
String const gameId = game.identityKey();

// Attempt to create a new subfolder in the saved session repository for the game.
// Once created, any existing saved sessions in this folder will be added automatically.
Expand All @@ -1931,28 +1962,54 @@ DENG2_PIMPL(ResourceSystem)
Folder &saveFolder = App::fileSystem().makeFolder(String("/savegame") / gameId);

// Find any .save files in this folder and generate sessions for the db.
/// @todo This extra step is unnecessary. SavedSession should inherit from PackageFolder.
DENG2_FOR_EACH_CONST(Folder::Contents, i, saveFolder.contents())
{
if(i->first.fileNameExtension() == ".save")
{
String const &relPath = saveFolder.name() / i->first.fileNameWithoutExtension();
game::SavedSession *newSession = new game::SavedSession(relPath);
saveRepo.add(relPath, newSession);
String const &repoPath = gameId / i->first.fileNameWithoutExtension();
game::SavedSession *newSession = new game::SavedSession(repoPath);
saveRepo.add(repoPath, newSession);

newSession->updateFromFile();
}
}

/// @todo Attempt to automatically convert any legacy saved game sessions.
/*for(;;)
// Perhaps there are legacy saved game sessions which need to be converted?
NativePath oldSavePath = legacySavePath(game);
if(oldSavePath.isEmpty()) return;

oldSavePath = oldSavePath / gameId;

// Attempt to automatically convert the legacy save games. Try in both the root of
// this folder and in the game-specific subfolder.
if(oldSavePath.exists() && oldSavePath.isReadable())
{
String const &relPath = saveFolder.name() / outFileName;
QScopedPointer<game::SavedSession> newSession(new game::SavedSession(relPath));
if(convertSavegame(inputPath, *newSavedSession, gameId))
Folder &oldSaveFolder = App::fileSystem().makeFolder("/oldsavegames");
oldSaveFolder.setMode(Folder::ReadOnly);
oldSaveFolder.attach(new DirectoryFeed(oldSavePath));
oldSaveFolder.populate(Folder::PopulateOnlyThisFolder);

String const oldSaveExt = legacySavegameExtension(game);
DENG2_FOR_EACH_CONST(Folder::Contents, i, oldSaveFolder.contents())
{
saveRepo.add(relPath, newSession.take());
if(i->first.fileNameExtension() == oldSaveExt)
{
String const oldFileName = i->first.fileNameWithoutExtension();
String const oldFilePath = i->second->as<NativeFile>().nativePath().withSeparators('/');

String const &repoPath = gameId / oldFileName;
QScopedPointer<game::SavedSession> newSession(new game::SavedSession(repoPath));
if(convertSavegame(oldFilePath, *newSession, gameId))
{
saveRepo.add(repoPath, newSession.take());
}
}
}
}*/

// We're done with this folder.
delete &oldSaveFolder;
}
}
};

Expand Down
2 changes: 1 addition & 1 deletion doomsday/client/src/resource/savegameconverter.cpp
Expand Up @@ -40,7 +40,7 @@ static void tryConversion(Path const &inputFilePath, Path const &outputFilePath,
Str_Set(Str_InitStd(&parm.fallbackGameIdentityKey), fallbackGameIdentityKey.toUtf8().constData());

// Try to convert the savegame via each plugin in turn.
dd_bool success = DD_CallHooks(HOOK_MAP_CONVERT, 0, &parm);
dd_bool success = DD_CallHooks(HOOK_SAVEGAME_CONVERT, 0, &parm);

Str_Free(&parm.inputFilePath);
Str_Free(&parm.outputFilePath);
Expand Down
2 changes: 2 additions & 0 deletions doomsday/server/server.pro
Expand Up @@ -207,6 +207,7 @@ DENG_HEADERS += \
$$SRC/include/resource/patchname.h \
$$SRC/include/resource/rawtexture.h \
$$SRC/include/resource/resourcesystem.h \
$$SRC/include/resource/savegameconverter.h \
$$SRC/include/resource/sprite.h \
$$SRC/include/resource/texture.h \
$$SRC/include/resource/texturemanifest.h \
Expand Down Expand Up @@ -374,6 +375,7 @@ SOURCES += \
$$SRC/src/resource/patchname.cpp \
$$SRC/src/resource/pcx.cpp \
$$SRC/src/resource/resourcesystem.cpp \
$$SRC/src/resource/savegameconverter.cpp \
$$SRC/src/resource/sprite.cpp \
$$SRC/src/resource/texture.cpp \
$$SRC/src/resource/texturemanifest.cpp \
Expand Down

0 comments on commit ec0738d

Please sign in to comment.