Skip to content

Commit

Permalink
libcommon: Added a basic GameStateReaderFactory
Browse files Browse the repository at this point in the history
With runtime registration so that new IGameStateReaders can be added
without requiring the factory to have compile time knowledge of the
derived classes.

Todo: The implementation could probably be improved (factory should
return instances with std::auto_ptr?). Perhaps libdeng2 could provide
the abstract components necessary for building a factory?
  • Loading branch information
danij-deng committed Feb 15, 2014
1 parent 374aaee commit fb2a9bc
Show file tree
Hide file tree
Showing 26 changed files with 278 additions and 159 deletions.
8 changes: 8 additions & 0 deletions doomsday/plugins/common/include/common.h
Expand Up @@ -50,6 +50,14 @@
DENG_EXTERN_C dd_bool sc_FileScripts;
DENG_EXTERN_C char const *sc_ScriptsDir;

#ifdef __cplusplus
extern "C" {
#endif

int Common_GetInteger(int id);

#ifdef __cplusplus
} // extern "C"
#endif

#endif // LIBCOMMON_GAME_INCLUDES
77 changes: 69 additions & 8 deletions doomsday/plugins/common/include/gamestatereader.h
Expand Up @@ -44,28 +44,89 @@ class IGameStateReader
* Attempt to load (read/interpret) the saved game state.
*
* @param info SaveInfo for the saved game state to be read/interpreted.
* @param path Path to the resource file to be recognized.
* @param path Path to the saved game state to be read.
*
* @todo @a path should be provided by SaveInfo.
*/
virtual void read(SaveInfo &info, Str const *path) = 0;
};

/**
* @ingroup libcommon
* @see GameStateWriter
* Game state recognizer function ptr.
*
* The job of a recognizer function is to determine whether the resource file on @a path is interpretable
* as a potentially loadable game state.
*
* @param info SaveInfo to attempt to read game session header into.
* @param path Path to the resource file to be recognized.
*/
class GameStateReader : public IGameStateReader
typedef bool (*GameStateRecognizeFunc)(SaveInfo &info, Str const *path);

/// Game state reader instantiator function ptr.
typedef IGameStateReader *(*GameStateReaderMakeFunc)();

/**
* Factory for the construction of new IGameStateReader-derived instances.
*/
class GameStateReaderFactory
{
public:
GameStateReader();
~GameStateReader();
/**
* Register a game state reader.
*
* @param recognizer Game state recognizer function.
* @param maker Game state reader instantiator function.
*/
void declareReader(GameStateRecognizeFunc recognizer, GameStateReaderMakeFunc maker)
{
ReaderInfo info;
info.recognize = recognizer;
info.makeInstance = maker;
readers.push_back(info);
}

/**
* Determines whether the resource file on @a path is interpretable as a game state which can
* be loaded with a GameStateReader.
* Returns a new IGameStateReader instance appropriate for the specified save game @a info.
*
* @param info SaveInfo to attempt to read game session header into.
* @param path Path to the resource file to be recognized.
*
* @return New reader instance if recognized; otherwise @c 0. Ownership given to the caller.
*/
IGameStateReader *newReaderFor(SaveInfo &info, Str const *path)
{
DENG2_FOR_EACH_CONST(ReaderInfos, i, readers)
{
if(i->recognize(info, path))
{
return i->makeInstance();
}
}
return 0; // Unrecognized
}

private:
struct ReaderInfo {
GameStateRecognizeFunc recognize;
GameStateReaderMakeFunc makeInstance;
};
typedef std::list<ReaderInfo> ReaderInfos;
ReaderInfos readers;
};

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

static IGameStateReader *make();
static bool recognize(SaveInfo &info, Str const *path);

void read(SaveInfo &info, Str const *path);
Expand Down
4 changes: 3 additions & 1 deletion doomsday/plugins/common/include/gamestatewriter.h
Expand Up @@ -26,6 +26,8 @@
#include <de/Error>

/**
* Native saved game state writer.
*
* @ingroup libcommon
* @see GameStateReader
*/
Expand All @@ -38,7 +40,7 @@ class GameStateWriter
public:
GameStateWriter();

void write(SaveInfo *saveInfo, Str const *path);
void write(SaveInfo &info, Str const *path);

private:
DENG2_PRIVATE(d)
Expand Down
10 changes: 10 additions & 0 deletions doomsday/plugins/common/include/p_saveg.h
Expand Up @@ -132,6 +132,16 @@ void SV_SaveInfo_Read(SaveInfo *info, Reader *reader);
#endif

#ifdef __cplusplus
#include "gamestatereader.h"

/**
* Declare a new saved game state reader/interpreter.
*
* @param recognizer Format recognizer function.
* @param maker Reader instantiator function.
*/
void SV_DeclareGameStateReader(GameStateRecognizeFunc recognizer, GameStateReaderMakeFunc maker);

class MapStateReader;
class MapStateWriter;

Expand Down
5 changes: 5 additions & 0 deletions doomsday/plugins/common/src/gamestatereader.cpp
Expand Up @@ -323,6 +323,11 @@ bool GameStateReader::recognize(SaveInfo &info, Str const *path) // static
return true;
}

IGameStateReader *GameStateReader::make() // static
{
return new GameStateReader;
}

void GameStateReader::read(SaveInfo &info, Str const *path)
{
DENG_ASSERT(path != 0);
Expand Down
6 changes: 3 additions & 3 deletions doomsday/plugins/common/src/gamestatewriter.cpp
Expand Up @@ -123,10 +123,10 @@ DENG2_PIMPL(GameStateWriter)
GameStateWriter::GameStateWriter() : d(new Instance(this))
{}

void GameStateWriter::write(SaveInfo *saveInfo, Str const *path)
void GameStateWriter::write(SaveInfo &info, Str const *path)
{
DENG_ASSERT(saveInfo != 0 && path != 0);
d->saveInfo = saveInfo;
DENG_ASSERT(path != 0);
d->saveInfo = &info;

// In networked games the server tells the clients to save their games.
#if !__JHEXEN__
Expand Down
56 changes: 27 additions & 29 deletions doomsday/plugins/common/src/p_saveg.cpp
Expand Up @@ -30,19 +30,14 @@
#include "gamestatereader.h"
#include "mapstatereader.h"
#include "mapstatewriter.h"
#if __JDOOM__
# include "doomv9gamestatereader.h"
#endif
#if __JHERETIC__
# include "hereticv13gamestatereader.h"
#endif
#include <de/String>
#include <de/memory.h>
#include <cstdio>
#include <cstring>

static bool inited = false;

static GameStateReaderFactory gameStateReaderFactory;
static SaveSlots sslots(NUMSAVESLOTS);
SaveSlots *saveSlots = &sslots;

Expand Down Expand Up @@ -880,6 +875,12 @@ void SV_Initialize()
// (Re)Initialize the saved game paths, possibly creating them if they do not exist.
SV_ConfigureSavePaths();

if(!inited)
{
// Declare the native game state reader.
gameStateReaderFactory.declareReader(&GameStateReader::recognize, &GameStateReader::make);
}

inited = true;
}

Expand All @@ -893,6 +894,23 @@ void SV_Shutdown()
inited = false;
}

void SV_DeclareGameStateReader(GameStateRecognizeFunc recognizer, GameStateReaderMakeFunc maker)
{
DENG_ASSERT(inited);
gameStateReaderFactory.declareReader(recognizer, maker);
}

static std::auto_ptr<IGameStateReader> gameStateReaderFor(SaveInfo &info, Str const *path)
{
std::auto_ptr<IGameStateReader> p(gameStateReaderFactory.newReaderFor(info, path));
if(!p.get())
{
/// @throw Error The saved game state format was not recognized.
throw de::Error("gameStateReaderFor", "Unrecognized savegame format");
}
return p;
}

dd_bool SV_LoadGame(int slot)
{
DENG_ASSERT(inited);
Expand Down Expand Up @@ -931,28 +949,8 @@ dd_bool SV_LoadGame(int slot)
{
SaveInfo &info = saveSlots->saveInfo(logicalSlot);

if(GameStateReader::recognize(info, path))
{
GameStateReader().read(info, path);
}
// Perhaps an original game state?
#if __JDOOM__
else if(DoomV9GameStateReader::recognize(info, path))
{
DoomV9GameStateReader().read(info, path);
}
#endif
#if __JHERETIC__
else if(HereticV13GameStateReader::recognize(info, path))
{
HereticV13GameStateReader().read(info, path);
}
#endif
else
{
/// @throw Error The savegame was not recognized.
throw de::Error("loadGameState", "Unrecognized savegame format");
}
// Attempt to recognize and load the saved game state.
gameStateReaderFor(info, path)->read(info, path);

// Make note of the last used save slot.
Con_SetInteger2("game-save-last-slot", slot, SVF_WRITE_OVERRIDE);
Expand Down Expand Up @@ -1000,7 +998,7 @@ dd_bool SV_SaveGame(int slot, char const *description)
SaveInfo *info = SaveInfo::newWithCurrentSessionMetadata(AutoStr_FromTextStd(description));
try
{
GameStateWriter().write(info, path);
GameStateWriter().write(*info, path);

// Swap the save info.
saveSlots->replaceSaveInfo(logicalSlot, info);
Expand Down
2 changes: 1 addition & 1 deletion doomsday/plugins/doom/doom.pro
Expand Up @@ -75,7 +75,7 @@ SOURCES += \
src/d_api.c \
src/d_console.c \
src/d_items.c \
src/d_main.c \
src/d_main.cpp \
src/d_refresh.c \
src/doomv9gamestatereader.cpp \
src/m_cheat.c \
Expand Down
2 changes: 1 addition & 1 deletion doomsday/plugins/doom/include/acfnlink.h
Expand Up @@ -37,7 +37,7 @@ typedef struct {
void (C_DECL *func)(); // Pointer to the function.
} actionlink_t;

extern actionlink_t actionlinks[];
DENG_EXTERN_C actionlink_t actionlinks[];

void C_DECL A_BabyMetal();
void C_DECL A_BFGsound();
Expand Down
73 changes: 33 additions & 40 deletions doomsday/plugins/doom/include/d_main.h
@@ -1,25 +1,21 @@
/**\file d_main.h
*\section License
* License: GPL
* Online License Link: http://www.gnu.org/licenses/gpl.html
/** @file d_main.h Doom-specific game initialization
*
*\author Copyright © 2003-2013 Jaakko Keränen <jaakko.keranen@iki.fi>
*\author Copyright © 2005-2013 Daniel Swanson <danij@dengine.net>
* @authors Copyright © 2003-2013 Jaakko Keränen <jaakko.keranen@iki.fi>
* @authors Copyright © 2005-2013 Daniel Swanson <danij@dengine.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* @par License
* GPL: http://www.gnu.org/licenses/gpl.html
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301 USA
* <small>This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. This program is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details. You should have received a copy of the GNU
* General Public License along with this program; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA</small>
*/

#ifndef LIBJDOOM_MAIN_H
Expand All @@ -31,40 +27,37 @@

#include "doomdef.h"

#ifdef __cplusplus
extern "C" {
#endif

extern int verbose;
DENG_EXTERN_C int verbose;

//extern dd_bool noMonstersParm; // checkparm of -nomonsters
//extern dd_bool respawnParm; // checkparm of -respawn
//extern dd_bool turboParm; // checkparm of -turbo
//extern dd_bool randomClassParm; // checkparm of -randclass
//extern dd_bool devParm; // checkparm of -devparm
//extern dd_bool fastParm; // checkparm of -fast
DENG_EXTERN_C float turboMul; // Multiplier for turbo.

extern float turboMul; // Multiplier for turbo.
DENG_EXTERN_C gamemode_t gameMode;
DENG_EXTERN_C int gameModeBits;

extern gamemode_t gameMode;
extern int gameModeBits;
DENG_EXTERN_C char *borderGraphics[];

extern char* borderGraphics[];
DENG_EXTERN_C float defFontRGB[];
DENG_EXTERN_C float defFontRGB2[];
DENG_EXTERN_C float defFontRGB3[];

extern float defFontRGB[];
extern float defFontRGB2[];
extern float defFontRGB3[];
DENG_EXTERN_C dd_bool monsterInfight;

extern dd_bool monsterInfight;
#ifdef __cplusplus
extern "C" {
#endif

void D_PreInit(void);

void D_PostInit(void);

void D_Shutdown(void);

int D_GetInteger(int id);
void* D_GetVariable(int id);

void *D_GetVariable(int id);

#ifdef __cplusplus
} // extern "C"
#endif

#endif /* LIBJDOOM_MAIN_H */
#endif // LIBJDOOM_MAIN_H

0 comments on commit fb2a9bc

Please sign in to comment.