Skip to content

Commit

Permalink
Refactor: Moved the current game and game change audience to App level
Browse files Browse the repository at this point in the history
Moving these from the Games collection up to app level is important
as this change as this significantly alters game change semantics.

However, presently de::App can not implement these as it would mean
relocating the Games collection to libdeng2 (which is not feasible
yet as Game depends on the FS1 file system). So for now these are
implemented as globals.
  • Loading branch information
danij-deng committed Jun 17, 2013
1 parent d1039de commit 73c8fe4
Show file tree
Hide file tree
Showing 13 changed files with 83 additions and 79 deletions.
27 changes: 22 additions & 5 deletions doomsday/client/include/dd_main.h
Expand Up @@ -179,19 +179,36 @@ de::ResourceClass& DD_ResourceClassByName(de::String name);
/// @return Symbolic name of the material scheme associated with @a textureSchemeName.
de::String DD_MaterialSchemeNameForTextureScheme(de::String textureSchemeName);

/// @todo The GameChange audience belongs in the App class.
DENG2_DECLARE_AUDIENCE(GameChange, void currentGameChanged(de::Game &newGame))
DENG2_EXTERN_AUDIENCE(GameChange)

/// @return @c true iff there is presently a game loaded.
boolean App_GameLoaded();

/// @return The application's global Game collection.
de::Games &App_Games();

/// @return The current Game in the application's global collection.
/// @return The current game from the application's global collection.
de::Game &App_CurrentGame();

/**
* Switch to/activate the specified game.
*/
bool App_ChangeGame(de::Game &game, bool allowReload = false);

/**
* Temporarily change the current game. (Which is presently necessary when locating
* resource files for said game and during app init.)
*
* @param newGame New game to temporarily change to.
*/
void App_SetCurrentGame(de::Game const &newGame);

/// @return The application's global Games (collection).
de::Games &App_Games();

/// @return The application's global World.
de::World &App_World();

/// @return The application's global Material collection.
/// @return The application's global Materials (collection).
de::Materials &App_Materials();

/**
Expand Down
15 changes: 0 additions & 15 deletions doomsday/client/include/games.h
Expand Up @@ -62,11 +62,6 @@ class Games
/// Game instances.
typedef QList<Game *> All;

/**
* Notified when the current game is changed.
*/
DENG2_DEFINE_AUDIENCE(GameChange, void currentGameChanged(Game &newGame))

/**
* Notified when a new game is added.
*/
Expand All @@ -81,12 +76,6 @@ class Games
/// @return The special "null" Game instance.
Game &nullGame() const;

/// @return The currently active Game instance.
Game &current() const;

/// Change the currently active game.
void setCurrent(Game const &game);

/// @return Total number of registered games.
inline int count() const { return all().count(); }

Expand Down Expand Up @@ -159,10 +148,6 @@ class Games
*/
void locateStartupResources(Game &game);

/// @todo This should be an internal private method; the App needs to be
/// responsible for changing the current game.
void notifyGameChange();

private:
DENG2_PRIVATE(d)
};
Expand Down
9 changes: 6 additions & 3 deletions doomsday/client/include/world/maputil.h
Expand Up @@ -24,9 +24,12 @@

#include <de/Vector>

#include "Line"
#include "Sector"
#include "Vertex"
#include "Line" // Line::Side

class Sector;
#ifdef __CLIENT__
class LineOwner;
#endif

void R_SetRelativeHeights(Sector const *front, Sector const *back, int planeIndex,
coord_t *fz = 0, coord_t *bz = 0, coord_t *bhz = 0);
Expand Down
1 change: 1 addition & 0 deletions doomsday/client/include/world/vertex.h
Expand Up @@ -129,6 +129,7 @@ class Vertex : public de::MapElement
*/
inline void setY(coord_t newPosition) { setOriginComponent(1, newPosition); }

public:
/**
* Returns the total number of Line owners for the vertex.
*
Expand Down
2 changes: 1 addition & 1 deletion doomsday/client/include/world/world.h
Expand Up @@ -100,7 +100,7 @@ class World
* To be called to reset the world back to the initial state. Any currently
* loaded map will be unloaded and player states are re-initialized.
*
* @todo World should observe Games::GameChange.
* @todo World should observe GameChange.
*/
void reset();

Expand Down
3 changes: 3 additions & 0 deletions doomsday/client/src/clientapp.cpp
Expand Up @@ -131,6 +131,9 @@ ClientApp::ClientApp(int &argc, char **argv)
QCoreApplication::setApplicationVersion (DOOMSDAY_VERSION_BASE);

setTerminateFunc(handleLegacyCoreTerminate);

// We must presently set the current game manually (the collection is global).
App_SetCurrentGame(d->games.nullGame());
}

void ClientApp::initialize()
Expand Down
44 changes: 28 additions & 16 deletions doomsday/client/src/dd_main.cpp
Expand Up @@ -180,7 +180,13 @@ extern GETGAMEAPI GetGameAPI;
static Materials *materials;

// The app's global Texture collection.
static Textures* textures;
static Textures *textures;

/// Notified when the current game changes. @todo Should be owned by App.
GameChangeAudience audienceForGameChange;

/// Current game. @todo Should be owned by App.
Game *currentGame;

#ifdef __CLIENT__

Expand Down Expand Up @@ -869,7 +875,7 @@ static void loadResource(ResourceManifest &manifest)
}

typedef struct {
/// @c true iff caller (i.e., DD_ChangeGame) initiated busy mode.
/// @c true iff caller (i.e., App_ChangeGame) initiated busy mode.
boolean initiatedBusyMode;
} ddgamechange_paramaters_t;

Expand Down Expand Up @@ -1292,7 +1298,15 @@ de::Games &App_Games()

Game &App_CurrentGame()
{
return App_Games().current();
DENG_ASSERT(currentGame != 0);
return *currentGame;
}

void App_SetCurrentGame(Game const &game)
{
// Ensure the specified game is actually in this collection (NullGame is implicitly).
DENG_ASSERT(isNullGame(game) || App_Games().id(game) > 0);
currentGame = const_cast<Game *>(&game);
}

boolean App_GameLoaded()
Expand All @@ -1310,6 +1324,7 @@ void DD_DestroyGames()
{
destroyPathList(&sessionResourceFileList, &numSessionResourceFileList);
App_Games().clear();
currentGame = &App_Games().nullGame();
}

static void populateGameInfo(GameInfo& info, de::Game& game)
Expand Down Expand Up @@ -1420,12 +1435,9 @@ gameid_t DD_GameIdForKey(char const *identityKey)
return 0; // Invalid id.
}

/**
* Switch to/activate the specified game.
*/
bool DD_ChangeGame(Game &game, bool allowReload = false)
bool App_ChangeGame(Game &game, bool allowReload)
{
//LOG_AS("DD_ChangeGame");
//LOG_AS("App_ChangeGame");

bool isReload = false;

Expand Down Expand Up @@ -1522,7 +1534,7 @@ bool DD_ChangeGame(Game &game, bool allowReload = false)
}

// The current game is now the special "null-game".
App_Games().setCurrent(App_Games().nullGame());
currentGame = &App_Games().nullGame();

Con_InitDatabases();
DD_Register();
Expand Down Expand Up @@ -1592,7 +1604,7 @@ bool DD_ChangeGame(Game &game, bool allowReload = false)
}

// This is now the current game.
App_Games().setCurrent(game);
currentGame = &game;

#ifdef __CLIENT__
DD_ComposeMainWindowTitle(buf);
Expand Down Expand Up @@ -1686,7 +1698,7 @@ bool DD_ChangeGame(Game &game, bool allowReload = false)
}
#endif

App_Games().notifyGameChange();
DENG2_FOR_AUDIENCE(GameChange, i) i->currentGameChanged(App_CurrentGame());

return true;
}
Expand Down Expand Up @@ -1939,7 +1951,7 @@ boolean DD_Init(void)
}

// Begin the game session.
DD_ChangeGame(*game);
App_ChangeGame(*game);

// We do not want to load these resources again on next game change.
destroyPathList(&sessionResourceFileList, &numSessionResourceFileList);
Expand Down Expand Up @@ -2769,7 +2781,7 @@ D_CMD(Load)
Con_Message("%s (%s) cannot be loaded.", Str_Text(game.title()), Str_Text(game.identityKey()));
return true;
}
if(!DD_ChangeGame(game)) return false;
if(!App_ChangeGame(game)) return false;

didLoadGame = true;
++arg;
Expand Down Expand Up @@ -2868,7 +2880,7 @@ D_CMD(Unload)
Con_Message("There is no game currently loaded.");
return true;
}
return DD_ChangeGame(App_Games().nullGame());
return App_ChangeGame(App_Games().nullGame());
}

AutoStr *searchPath = AutoStr_NewStd();
Expand All @@ -2893,7 +2905,7 @@ D_CMD(Unload)
Game &game = App_Games().byIdentityKey(Str_Text(searchPath));
if(App_GameLoaded())
{
return DD_ChangeGame(App_Games().nullGame());
return App_ChangeGame(App_Games().nullGame());
}

Con_Message("%s is not currently loaded.", Str_Text(game.identityKey()));
Expand Down Expand Up @@ -2948,7 +2960,7 @@ D_CMD(ReloadGame)
Con_Message("No game is presently loaded.");
return true;
}
DD_ChangeGame(App_CurrentGame(), true/* allow reload */);
App_ChangeGame(App_CurrentGame(), true/* allow reload */);
return true;
}

Expand Down
39 changes: 9 additions & 30 deletions doomsday/client/src/games.cpp
Expand Up @@ -34,19 +34,16 @@ DENG2_PIMPL(Games)
/// The actual collection.
Games::All games;

/// Currently active game (in this collection).
Game *currentGame;

/// Special "null-game" object for this collection.
NullGame *nullGame;

Instance(Public *i) : Base(i), games(), currentGame(0), nullGame(0)
Instance(Public *i) : Base(i), games(), nullGame(0)
{
/*
* One-time creation and initialization of the special "null-game"
* object (activated once created).
*/
currentGame = nullGame = new NullGame;
nullGame = new NullGame;
}

~Instance()
Expand All @@ -61,35 +58,17 @@ DENG2_PIMPL(Games)

qDeleteAll(games);
games.clear();
currentGame = nullGame;
}
};

Games::Games() : d(new Instance(this))
{}

Game &Games::current() const
{
return *d->currentGame;
}

Game &Games::nullGame() const
{
return *d->nullGame;
}

void Games::setCurrent(Game const &game)
{
// Ensure the specified game is actually in this collection (NullGame is implicitly).
DENG_ASSERT(isNullGame(game) || id(game) > 0);
d->currentGame = const_cast<Game *>(&game);
}

void Games::notifyGameChange()
{
DENG2_FOR_AUDIENCE(GameChange, i) i->currentGameChanged(current());
}

int Games::numPlayable() const
{
int count = 0;
Expand Down Expand Up @@ -192,11 +171,11 @@ void Games::add(Game &game)

void Games::locateStartupResources(Game &game)
{
Game *oldCurrrentGame = d->currentGame;
if(d->currentGame != &game)
Game *oldCurrentGame = &App_CurrentGame();
if(oldCurrentGame != &game)
{
/// @attention Kludge: Temporarily switch Game.
d->currentGame = &game;
App_SetCurrentGame(game);
DD_ExchangeGamePluginEntryPoints(game.pluginId());

// Re-init the filesystem subspace schemes using the search paths of this Game.
Expand All @@ -211,11 +190,11 @@ void Games::locateStartupResources(Game &game)
manifest->locateFile();
}

if(d->currentGame != oldCurrrentGame)
if(oldCurrentGame != &game)
{
// Kludge end - Restore the old Game.
d->currentGame = oldCurrrentGame;
DD_ExchangeGamePluginEntryPoints(oldCurrrentGame->pluginId());
App_SetCurrentGame(*oldCurrentGame);
DD_ExchangeGamePluginEntryPoints(oldCurrentGame->pluginId());

// Re-init the filesystem subspace schemes using the search paths of this Game.
App_FileSystem().resetAllSchemes();
Expand Down Expand Up @@ -279,7 +258,7 @@ D_CMD(ListGames)
DENG2_FOR_EACH_CONST(de::Games::GameList, i, found)
{
de::Game *game = i->game;
bool isCurrent = (&games.current() == game);
bool isCurrent = (&App_CurrentGame() == game);

if(!list.isEmpty()) list += "\n";

Expand Down
6 changes: 3 additions & 3 deletions doomsday/client/src/ui/clientwindow.cpp
Expand Up @@ -54,7 +54,7 @@ DENG2_OBSERVES(KeyEventSource, KeyEvent),
DENG2_OBSERVES(MouseEventSource, MouseStateChange),
DENG2_OBSERVES(MouseEventSource, MouseEvent),
DENG2_OBSERVES(Canvas, FocusChange),
DENG2_OBSERVES(Games, GameChange)
public IGameChangeObserver
{
bool needMainInit;
bool needRecreateCanvas;
Expand Down Expand Up @@ -85,7 +85,7 @@ DENG2_OBSERVES(Games, GameChange)
/// @todo The decision whether to receive input notifications from the
/// canvas is really a concern for the input drivers.

App_Games().audienceForGameChange += this;
audienceForGameChange += this;

// Listen to input.
self.canvas().audienceForKeyEvent += this;
Expand All @@ -95,7 +95,7 @@ DENG2_OBSERVES(Games, GameChange)

~Instance()
{
App_Games().audienceForGameChange -= this;
audienceForGameChange -= this;

self.canvas().audienceForFocusChange -= this;
self.canvas().audienceForMouseStateChange -= this;
Expand Down

0 comments on commit 73c8fe4

Please sign in to comment.