Skip to content

Commit

Permalink
Refactor|libdeng: Renamed IGameStateReader as IMapStateReader
Browse files Browse the repository at this point in the history
The saved session game state (i.e., session metadata) will soon be
read on engine side. The serialized map state is now stored within
separate files, the format of which can be recognized without the
need to defer the decision to a game plugin.
  • Loading branch information
danij-deng committed Mar 9, 2014
1 parent aec5c7e commit ed622fd
Show file tree
Hide file tree
Showing 20 changed files with 132 additions and 115 deletions.
4 changes: 2 additions & 2 deletions doomsday/libdeng2/game.pri
@@ -1,11 +1,11 @@
publicHeaders(game, \
include/de/game/Game \
include/de/game/IGameStateReader \
include/de/game/IMapStateReader \
include/de/game/SavedSession \
include/de/game/SavedSessionRepository \
\
include/de/game/game.h \
include/de/game/igamestatereader.h \
include/de/game/imapstatereader.h \
include/de/game/savedsession.h \
include/de/game/savedsessionrepository.h \
)
Expand Down
1 change: 0 additions & 1 deletion doomsday/libdeng2/include/de/game/IGameStateReader

This file was deleted.

1 change: 1 addition & 0 deletions doomsday/libdeng2/include/de/game/IMapStateReader
@@ -0,0 +1 @@
#include "imapstatereader.h"
@@ -1,4 +1,4 @@
/** @file igamestatereader.h Interface for a serialized game state reader.
/** @file imapstatereader.h Interface for a serialized game map state reader.
*
* @authors Copyright © 2014 Daniel Swanson <danij@dengine.net>
*
Expand All @@ -16,8 +16,8 @@
* http://www.gnu.org/licenses</small>
*/

#ifndef LIBDENG2_IGAMESTATEREADER_H
#define LIBDENG2_IGAMESTATEREADER_H
#ifndef LIBDENG2_IMAPSTATEREADER_H
#define LIBDENG2_IMAPSTATEREADER_H

#include <de/Error>
#include <de/Path>
Expand All @@ -28,11 +28,11 @@ namespace de {
namespace game {

/**
* Interface for serialized game state (savegame) readers.
* Interface for serialized game map state (savegame) readers.
*
* @ingroup game
*/
class DENG2_PUBLIC IGameStateReader
class DENG2_PUBLIC IMapStateReader
{
public:
/// An error occurred attempting to open the input file. @ingroup errors
Expand All @@ -42,22 +42,19 @@ class DENG2_PUBLIC IGameStateReader
DENG2_ERROR(ReadError);

public:
virtual ~IGameStateReader() {}
virtual ~IMapStateReader() {}

/**
* Attempt to load (read/interpret) the serialized game state.
* Attempt to load (read/interpret) the serialized game map state.
*
* @paran stateFilePath Path to the game state file to be read/interpreted.
* @param mapStateFilePath Path to the map state file to be read/interpreted.
* @param filePath Path to the map state file to be read/interpreted.
*
* @param metadata Deserialized save session metadata for the game state. At this point
* the metadata has already been read once, so this is provided FYI.
* @param metadata Deserialized save session metadata for the game state (FYI).
*/
virtual void read(Path const &stateFilePath, Path const &mapStateFilePath,
SavedSession::Metadata const &metadata) = 0;
virtual void read(Path const &mapStateFilePath, SavedSession::Metadata const &metadata) = 0;
};

} // namespace game
} // namespace de

#endif // LIBDENG2_IGAMESTATEREADER_H
#endif // LIBDENG2_IMAPSTATEREADER_H
15 changes: 11 additions & 4 deletions doomsday/libdeng2/include/de/game/savedsession.h
Expand Up @@ -27,7 +27,7 @@
namespace de {
namespace game {

class IGameStateReader;
class IMapStateReader;
class SavedSessionRepository;

/**
Expand All @@ -47,8 +47,8 @@ class DENG2_PUBLIC SavedSession
/// Required/referenced repository is missing. @ingroup errors
DENG2_ERROR(MissingRepositoryError);

/// The associated game state file was missing/unrecognized. @ingroup errors
DENG2_ERROR(UnrecognizedGameStateError);
/// The associated game map state file was missing/unrecognized. @ingroup errors
DENG2_ERROR(UnrecognizedMapStateError);

/// Logical session status:
enum Status {
Expand All @@ -63,6 +63,13 @@ class DENG2_PUBLIC SavedSession
class DENG2_PUBLIC Metadata : public Record
{
public:
/**
* Parses metadata in Info syntax from a text string.
*
* @param source Source string to be parsed.
*/
void parse(String const &source);

/**
* Generates a textual representation of the session metadata with Info syntax.
*
Expand Down Expand Up @@ -148,7 +155,7 @@ class DENG2_PUBLIC SavedSession
Metadata const &metadata() const;
void replaceMetadata(Metadata *newMetadata);

std::auto_ptr<IGameStateReader> gameStateReader();
std::auto_ptr<IMapStateReader> mapStateReader();

private:
DENG2_PRIVATE(d)
Expand Down
12 changes: 6 additions & 6 deletions doomsday/libdeng2/include/de/game/savedsessionrepository.h
Expand Up @@ -21,7 +21,7 @@

#include "../Error"
#include "../Folder"
#include "../game/IGameStateReader"
#include "../game/IMapStateReader"
#include "../game/SavedSession"
#include "../Path"
#include "../String"
Expand All @@ -37,7 +37,7 @@
typedef bool (*GameStateRecognizeFunc)(de::Path const &stateFilePath, de::game::SessionMetadata &metadata);

/// Game state reader instantiator function ptr.
typedef de::game::IGameStateReader *(*GameStateReaderMakeFunc)();
typedef de::game::IMapStateReader *(*GameStateReaderMakeFunc)();

namespace de {
namespace game {
Expand Down Expand Up @@ -99,10 +99,10 @@ class DENG2_PUBLIC SavedSessionRepository
* @param recognizer Game state recognizer function.
* @param maker Game state reader instantiator function.
*/
void declareReader(GameStateRecognizeFunc recognizer, GameStateReaderMakeFunc maker);
void declareReader(/*GameStateRecognizeFunc recognizer,*/ GameStateReaderMakeFunc maker);

/**
* Determines whether a IGameStateReader appropriate for the specified saved @a session
* Determines whether a IMapStateReader appropriate for the specified saved @a session
* is available and if so, reads the session metadata.
*
* @param record The session metadata will be written here if recognized.
Expand All @@ -114,7 +114,7 @@ class DENG2_PUBLIC SavedSessionRepository
bool recognize(SavedSession &session) const;

/**
* Determines whether a IGameStateReader appropriate for the specified saved @a session
* Determines whether a IMapStateReader appropriate for the specified saved @a session
* is available and if so, reads the session metadata and returns a new reader instance
* for deserializing the game state.
*
Expand All @@ -124,7 +124,7 @@ class DENG2_PUBLIC SavedSessionRepository
*
* @see recognize()
*/
IGameStateReader *recognizeAndMakeReader(SavedSession &session) const;
IMapStateReader *recognizeAndMakeReader(SavedSession &session) const;

private:
DENG2_PRIVATE(d)
Expand Down
13 changes: 9 additions & 4 deletions doomsday/libdeng2/src/game/savedsession.cpp
Expand Up @@ -29,6 +29,11 @@
namespace de {
namespace game {

void SavedSession::Metadata::parse(String const & /*source*/)
{
DENG2_ASSERT(!"SavedSession::Metadata::parse - Not yet implemented");
}

String SavedSession::Metadata::asTextWithInfoSyntax() const
{
String text;
Expand Down Expand Up @@ -299,13 +304,13 @@ void SavedSession::replaceMetadata(Metadata *newMetadata)
d->needUpdateStatus = true;
}

std::auto_ptr<IGameStateReader> SavedSession::gameStateReader()
std::auto_ptr<IMapStateReader> SavedSession::mapStateReader()
{
std::auto_ptr<IGameStateReader> p(repository().recognizeAndMakeReader(*this));
std::auto_ptr<IMapStateReader> p(repository().recognizeAndMakeReader(*this));
if(!p.get())
{
/// @throw UnrecognizedGameStateError The game state format was not recognized.
throw UnrecognizedGameStateError("SavedSession::gameStateReader", "Unrecognized game state format");
/// @throw UnrecognizedMapStateError The game state format was not recognized.
throw UnrecognizedMapStateError("SavedSession::mapStateReader", "Unrecognized map state format");
}
return p;
}
Expand Down
52 changes: 37 additions & 15 deletions doomsday/libdeng2/src/game/savedsessionrepository.cpp
Expand Up @@ -20,7 +20,7 @@

#include "de/App"
#include "de/game/Game"
#include "de/game/IGameStateReader"
#include "de/game/IMapStateReader"
#include "de/Log"
#include "de/NativePath"

Expand All @@ -40,13 +40,13 @@ DENG2_PIMPL(SavedSessionRepository)
Sessions sessions;

struct ReaderInfo {
GameStateRecognizeFunc recognize;
//GameStateRecognizeFunc recognize;
GameStateReaderMakeFunc newReader;

ReaderInfo(GameStateRecognizeFunc recognize, GameStateReaderMakeFunc newReader)
: recognize(recognize), newReader(newReader)
ReaderInfo(/*GameStateRecognizeFunc recognize,*/ GameStateReaderMakeFunc newReader)
: /*recognize(recognize),*/ newReader(newReader)
{
DENG2_ASSERT(recognize != 0 && newReader != 0);
DENG2_ASSERT(/*recognize != 0 &&*/ newReader != 0);
}
};
typedef QList<ReaderInfo> ReaderInfos;
Expand Down Expand Up @@ -75,20 +75,42 @@ DENG2_PIMPL(SavedSessionRepository)
sessions.clear();
}

bool recognize(File &file, SessionMetadata &metadata) const
{
Block raw;
file >> raw;

metadata.parse(String::fromUtf8(raw));

int const saveVersion = metadata["version"].value().asNumber();
if(saveVersion > 14) // Future version?
{
return false;
}
return true;
}

ReaderInfo const *readSessionMetadata(SavedSession &session) const
{
foreach(ReaderInfo const &rdrInfo, readers)
try
{
Path stateFilePath = self.folder().path() / session.fileName();
Path filePath = self.folder().path() / session.fileName();
File &file = App::fileSystem().find<File>(filePath);

// Attempt to recognize the game state and deserialize the metadata.
QScopedPointer<SessionMetadata> metadata(new SessionMetadata);
if(rdrInfo.recognize(stateFilePath, *metadata))
foreach(ReaderInfo const &rdrInfo, readers)
{
session.replaceMetadata(metadata.take());
return &rdrInfo;
// Attempt to recognize the game state and deserialize the metadata.
QScopedPointer<SessionMetadata> metadata(new SessionMetadata);
if(recognize(file, *metadata))
{
session.replaceMetadata(metadata.take());
return &rdrInfo;
}
}
}
catch(FileSystem::NotFoundError const &)
{} // Ignore this error.

return 0; // Unrecognized
}

Expand Down Expand Up @@ -179,17 +201,17 @@ SavedSession &SavedSessionRepository::session(String fileName) const
throw MissingSessionError("SavedSessionRepository::session", "Unknown session '" + fileName + "'");
}

void SavedSessionRepository::declareReader(GameStateRecognizeFunc recognizer, GameStateReaderMakeFunc maker)
void SavedSessionRepository::declareReader(/*GameStateRecognizeFunc recognizer,*/ GameStateReaderMakeFunc maker)
{
d->readers.append(Instance::ReaderInfo(recognizer, maker));
d->readers.append(Instance::ReaderInfo(/*recognizer,*/ maker));
}

bool SavedSessionRepository::recognize(SavedSession &session) const
{
return d->readSessionMetadata(session) != 0;
}

IGameStateReader *SavedSessionRepository::recognizeAndMakeReader(SavedSession &session) const
IMapStateReader *SavedSessionRepository::recognizeAndMakeReader(SavedSession &session) const
{
if(Instance::ReaderInfo const *rdrInfo = d->readSessionMetadata(session))
{
Expand Down
2 changes: 1 addition & 1 deletion doomsday/plugins/common/include/g_common.h
Expand Up @@ -178,7 +178,7 @@ D_CMD( CCmdExitLevel );
#endif

#if __cplusplus
#include <de/game/IGameStateReader>
#include <de/game/IMapStateReader>
#include <de/String>
#include "gamerules.h"

Expand Down
15 changes: 7 additions & 8 deletions doomsday/plugins/common/include/gamestatereader.h
@@ -1,4 +1,4 @@
/** @file gamestatereader.h Saved game state reader.
/** @file gamestatereader.h Saved game map state reader.
*
* @authors Copyright © 2014 Daniel Swanson <danij@dengine.net>
*
Expand All @@ -20,25 +20,24 @@
#ifndef LIBCOMMON_GAMESTATEREADER_H
#define LIBCOMMON_GAMESTATEREADER_H

#include <de/game/IGameStateReader>
#include <de/game/IMapStateReader>

/**
* Native saved game state reader.
* Native saved game map state reader.
*
* @ingroup libcommon
* @see GameStateWriter
*/
class GameStateReader : public de::game::IGameStateReader
class GameStateReader : public de::game::IMapStateReader
{
public:
GameStateReader();
~GameStateReader();

static de::game::IGameStateReader *make();
static bool recognize(de::Path const &stateFilePath, de::game::SessionMetadata &metadata);
static de::game::IMapStateReader *make();
//static bool recognize(de::Path const &stateFilePath, de::game::SessionMetadata &metadata);

void read(de::Path const &stateFilePath, de::Path const &mapStateFilePath,
de::game::SessionMetadata const &metadata);
void read(de::Path const &filePath, de::game::SessionMetadata const &metadata);

private:
DENG2_PRIVATE(d)
Expand Down
2 changes: 1 addition & 1 deletion doomsday/plugins/common/include/gamestatewriter.h
Expand Up @@ -22,7 +22,7 @@
#define LIBCOMMON_GAMESTATEWRITER_H

#include <de/Error>
#include <de/game/IGameStateReader>
#include <de/game/IMapStateReader>
#include <de/Path>

/**
Expand Down
13 changes: 5 additions & 8 deletions doomsday/plugins/common/src/g_game.cpp
Expand Up @@ -61,7 +61,7 @@
#include "x_hair.h"

#include <de/ArrayValue>
#include <de/game/IGameStateReader>
#include <de/game/IMapStateReader>
#include <de/game/SavedSessionRepository>
#include <de/NativePath>
#include <de/NumberValue>
Expand Down Expand Up @@ -484,7 +484,7 @@ static void initSaveSlots()

// Declare the native game state reader.
de::game::SavedSessionRepository &saveRepo = G_SavedSessionRepository();
saveRepo.declareReader(&GameStateReader::recognize, &GameStateReader::make);
saveRepo.declareReader(/*&GameStateReader::recognize,*/ &GameStateReader::make);

// Setup the logical save slot bindings.
int const gameMenuSaveSlotWidgetIds[NUMSAVESLOTS] = {
Expand Down Expand Up @@ -3260,16 +3260,13 @@ void G_DoLoadSession(de::String slotId)
#endif

SaveSlot &sslot = G_SaveSlots()[logicalSlot];
de::Path const filePath = sslot.filePath();
de::Path const mapStateFilePath(Str_Text(Uri_Resolved(gameMapUri)));

// Attempt to recognize and load the saved game state.
App_Log(DE2_LOG_VERBOSE, "Attempting load save game from \"%s\"",
de::NativePath(filePath).pretty().toLatin1().constData());
de::NativePath(sslot.filePath()).pretty().toLatin1().constData());

sslot.savedSession()
.gameStateReader()->read(filePath, mapStateFilePath,
sslot.saveMetadata());
sslot.savedSession().mapStateReader()
->read(de::Path(Str_Text(Uri_Resolved(gameMapUri))), sslot.saveMetadata());

// Make note of the last used save slot.
Con_SetInteger2("game-save-last-slot", slotId.toInt(), SVF_WRITE_OVERRIDE);
Expand Down

0 comments on commit ed622fd

Please sign in to comment.