From ce7745bfa68124c76a13fe4d1e3d0f4f1e05de47 Mon Sep 17 00:00:00 2001 From: "techdragon.nguyen@gmail.com" Date: Thu, 27 Jan 2011 16:13:40 +0000 Subject: [PATCH] First attempt to reduce load time of player deck selection screens. This change makes use of caching the DeckStats and DeckStatsWrappers into singleton caches that get flushed when you quit the game. The initial load time will be significant as lazy loading has not been coded yet for the ai decks. TODO: lazy load the player and ai decks as they appear on the screen. Currently, each screen loads all decks. --- projects/mtg/include/DeckManager.h | 15 +- projects/mtg/include/DeckStats.h | 9 +- projects/mtg/src/ActionStack.cpp | 3 +- projects/mtg/src/DeckManager.cpp | 192 ++++++++++++++++------- projects/mtg/src/DeckStats.cpp | 61 +++++-- projects/mtg/src/GameApp.cpp | 5 +- projects/mtg/src/GameStateDeckViewer.cpp | 8 +- projects/mtg/src/GameStateDuel.cpp | 8 +- projects/mtg/src/SimplePopup.cpp | 9 +- projects/mtg/template.vcproj | 4 - 10 files changed, 213 insertions(+), 101 deletions(-) diff --git a/projects/mtg/include/DeckManager.h b/projects/mtg/include/DeckManager.h index 568289442..6587bc7dd 100644 --- a/projects/mtg/include/DeckManager.h +++ b/projects/mtg/include/DeckManager.h @@ -19,11 +19,17 @@ public: vector playerDeckOrderList; vector aiDeckOrderList; - + + map playerDeckStatsMap; + map aiDeckStatsMap; + void updateMetaDataList(vector* refList, bool isAI); vector * getPlayerDeckOrderList(); vector * getAIDeckOrderList(); + DeckMetaData * getDeckMetaDataById( int deckId, bool isAI ); + StatsWrapper * getExtendedStatsForDeckId( int deckId, MTGAllCards *collection, bool isAI ); + StatsWrapper * getExtendedDeckStats( DeckMetaData *selectedDeck, MTGAllCards *collection, bool isAI ); static DeckManager * GetInstance(); static void EndInstance(); @@ -31,10 +37,7 @@ public: //since the eventual move of all deck meta data should be managed by this class static int getDifficultyRating(Player *statsPlayer, Player *player); - - ~DeckManager() - { - instanceFlag = false; - } + + ~DeckManager(); }; diff --git a/projects/mtg/include/DeckStats.h b/projects/mtg/include/DeckStats.h index 9a14bb038..d49b716a4 100644 --- a/projects/mtg/include/DeckStats.h +++ b/projects/mtg/include/DeckStats.h @@ -15,9 +15,10 @@ class GameObserver; class DeckStat { public: + DeckStat(int _nbgames = 0, int _victories = 0); + int nbgames; int victories; - DeckStat(int _nbgames = 0, int _victories = 0); int percentVictories(); }; @@ -26,8 +27,12 @@ class DeckStats protected: static DeckStats * mInstance; public: - map stats; + //map stats; // current set of statistics + string currentDeck; + map > masterDeckStats; + static DeckStats * GetInstance(); + static void EndInstance(); void saveStats(Player * player, Player * opponent, GameObserver * game); void save(const char * filename); void save(Player * player); diff --git a/projects/mtg/src/ActionStack.cpp b/projects/mtg/src/ActionStack.cpp index 39b3dabd8..3e3fb4557 100644 --- a/projects/mtg/src/ActionStack.cpp +++ b/projects/mtg/src/ActionStack.cpp @@ -604,8 +604,7 @@ Spell * ActionStack::addSpell(MTGCardInstance * _source, TargetChooser * tc, Man } Spell * spell = NEW Spell(mCount, _source, tc, mana, payResult); addAction(spell); - if (!game->players[0]->isAI() && _source->controller() == game->players[0] && 0 - == options[Options::INTERRUPTMYSPELLS].number) + if (!game->players[0]->isAI() && _source->controller() == game->players[0] && 0 == options[Options::INTERRUPTMYSPELLS].number) interruptDecision[0] = DONT_INTERRUPT; return spell; } diff --git a/projects/mtg/src/DeckManager.cpp b/projects/mtg/src/DeckManager.cpp index e723bcba9..3188100cb 100644 --- a/projects/mtg/src/DeckManager.cpp +++ b/projects/mtg/src/DeckManager.cpp @@ -1,60 +1,132 @@ -#include "PrecompiledHeader.h" - -#include "DeckManager.h" -#include "Player.h" -#include - -void DeckManager::updateMetaDataList(vector * refList, bool isAI) -{ - if (refList) - { - vector * inputList = isAI ? &aiDeckOrderList : &playerDeckOrderList; - inputList->clear(); - inputList->assign(refList->begin(), refList -> end()); - } -} - -vector * DeckManager::getPlayerDeckOrderList() -{ - return &playerDeckOrderList; -} - -vector * DeckManager::getAIDeckOrderList() -{ - return &aiDeckOrderList; -} - -DeckManager * DeckManager::mInstance = NULL; -bool DeckManager::instanceFlag = false; - -void DeckManager::EndInstance() -{ - if (mInstance) - { - mInstance->aiDeckOrderList.clear(); - mInstance->playerDeckOrderList.clear(); - SAFE_DELETE( mInstance ); - } -} - -DeckManager* DeckManager::GetInstance() -{ - if (!instanceFlag) - { - mInstance = NEW DeckManager(); - instanceFlag = true; - } - - return mInstance; -} - -// p1 is assumed to be the player you want stats for -// p2 is the opponent -int DeckManager::getDifficultyRating(Player *statsPlayer, Player *player) -{ - DeckMetaDataList * metas = DeckMetaDataList::decksMetaData; - - DeckMetaData *meta = metas->get(player->deckFile, statsPlayer); - - return meta->getDifficulty(); -} +#include "PrecompiledHeader.h" + +#include "DeckManager.h" +#include "Player.h" +#include + +void DeckManager::updateMetaDataList(vector * refList, bool isAI) +{ + if (refList) + { + vector * inputList = isAI ? &aiDeckOrderList : &playerDeckOrderList; + inputList->clear(); + inputList->assign(refList->begin(), refList -> end()); + } +} + +vector * DeckManager::getPlayerDeckOrderList() +{ + return &playerDeckOrderList; +} + +vector * DeckManager::getAIDeckOrderList() +{ + return &aiDeckOrderList; +} + +DeckMetaData * DeckManager::getDeckMetaDataById( int deckId, bool isAI ) +{ + + DeckMetaData* currentDeck = NULL; + vector::iterator currentPos, end; + if ( isAI ) + { + currentPos = aiDeckOrderList.begin(); + end = aiDeckOrderList.end(); + } + else + { + currentPos = playerDeckOrderList.begin(); + end = playerDeckOrderList.end(); + } + + + for (; currentPos != end; ++currentPos) + { + currentDeck = *currentPos; + if (currentDeck->getDeckId() == deckId ) + return currentDeck; + } + return NULL; +} + +StatsWrapper * DeckManager::getExtendedStatsForDeckId( int deckId, MTGAllCards *collection, bool isAI ) +{ + DeckMetaData *selectedDeck = getDeckMetaDataById( deckId, isAI ); + return getExtendedDeckStats( selectedDeck, collection, isAI); +} + + +StatsWrapper * DeckManager::getExtendedDeckStats( DeckMetaData *selectedDeck, MTGAllCards *collection, bool isAI ) +{ + StatsWrapper * stats = NULL; + map *statsMap = NULL; + + string deckName = selectedDeck->getFilename(); + int deckId = selectedDeck->getDeckId(); + + if (isAI) + statsMap = &aiDeckStatsMap; + else + statsMap = &playerDeckStatsMap; + + if (statsMap->empty() || (statsMap->find(deckName) == statsMap->end())) + { + stats = NEW StatsWrapper(deckId); + stats->updateStats( deckName, collection); + statsMap->insert( make_pair( deckName, stats)); + } + stats = statsMap->find(deckName) ->second; + + return stats; +} + + +DeckManager * DeckManager::mInstance = NULL; +bool DeckManager::instanceFlag = false; + +void DeckManager::EndInstance() +{ + if (mInstance) + { + mInstance->aiDeckOrderList.clear(); + mInstance->playerDeckOrderList.clear(); + map::iterator it; + for (it = mInstance->aiDeckStatsMap.begin(); it != mInstance->aiDeckStatsMap.end(); it++){ + SAFE_DELETE(it->second); + } + for (it = mInstance->playerDeckStatsMap.begin(); it != mInstance->playerDeckStatsMap.end(); it++){ + SAFE_DELETE(it->second); + } + mInstance->aiDeckStatsMap.clear(); + mInstance->playerDeckStatsMap.clear(); + SAFE_DELETE( mInstance ); + } +} + +DeckManager* DeckManager::GetInstance() +{ + if (!instanceFlag) + { + mInstance = NEW DeckManager(); + instanceFlag = true; + } + + return mInstance; +} + +// p1 is assumed to be the player you want stats for +// p2 is the opponent +int DeckManager::getDifficultyRating(Player *statsPlayer, Player *player) +{ + DeckMetaDataList * metas = DeckMetaDataList::decksMetaData; + + DeckMetaData *meta = metas->get(player->deckFile, statsPlayer); + + return meta->getDifficulty(); +} + +DeckManager::~DeckManager() +{ + instanceFlag = false; +} \ No newline at end of file diff --git a/projects/mtg/src/DeckStats.cpp b/projects/mtg/src/DeckStats.cpp index f16271a5f..704f42b1f 100644 --- a/projects/mtg/src/DeckStats.cpp +++ b/projects/mtg/src/DeckStats.cpp @@ -23,30 +23,44 @@ DeckStats * DeckStats::GetInstance() if (!mInstance) { mInstance = NEW DeckStats(); - } return mInstance; } void DeckStats::cleanStats() { - map::iterator it; +/* map::iterator it; for (it = stats.begin(); it != stats.end(); it++) { SAFE_DELETE(it->second); } stats.clear(); + + */ } DeckStats::~DeckStats() { - cleanStats(); + map > ::iterator it; + for (it = masterDeckStats.begin(); it != masterDeckStats.end(); ++it) + { + string key = it->first; + map innerMap = masterDeckStats[key]; + map::iterator it2; + for (it2 = innerMap.begin(); it2 != innerMap.end(); it2++) + { + SAFE_DELETE(it2->second); + } + innerMap.clear(); + } + masterDeckStats.clear(); } DeckStat* DeckStats::getDeckStat(string opponentsFile) { + map stats = masterDeckStats[currentDeck]; map::iterator it = stats.find(opponentsFile); if (it == stats.end()) { @@ -61,6 +75,7 @@ DeckStat* DeckStats::getDeckStat(string opponentsFile) int DeckStats::nbGames() { int nbgames = 0; + map stats = masterDeckStats[currentDeck]; map::iterator it; for (it = stats.begin(); it != stats.end(); it++) { @@ -72,6 +87,7 @@ int DeckStats::nbGames() int DeckStats::percentVictories(string opponentsFile) { + map stats = masterDeckStats[currentDeck]; map::iterator it = stats.find(opponentsFile); if (it == stats.end()) { @@ -87,6 +103,7 @@ int DeckStats::percentVictories() { int victories = 0; int nbgames = 0; + map stats = masterDeckStats[currentDeck]; map::iterator it; for (it = stats.begin(); it != stats.end(); it++) { @@ -110,7 +127,12 @@ void DeckStats::load(Player * player) void DeckStats::load(const char * filename) { - cleanStats(); + + currentDeck = filename; + if ( masterDeckStats.find(filename) != masterDeckStats.end() ) + { + return; + } wagic::ifstream file(filename); std::string s; @@ -123,11 +145,12 @@ void DeckStats::load(const char * filename) int games = atoi(s.c_str()); std::getline(file, s); int victories = atoi(s.c_str()); - map::iterator it = stats.find(deckfile); - if (it == stats.end()) + if ( masterDeckStats[filename].find(deckfile) != masterDeckStats[filename].end()) { - stats[deckfile] = NEW DeckStat(games, victories); + SAFE_DELETE( masterDeckStats[filename][deckfile] ); } + DeckStat * newDeckStat = NEW DeckStat(games, victories); + (masterDeckStats[filename])[deckfile] = newDeckStat; } file.close(); } @@ -146,6 +169,7 @@ void DeckStats::save(const char * filename) char writer[512]; if (file) { + map stats = masterDeckStats[currentDeck]; map::iterator it; for (it = stats.begin(); it != stats.end(); it++) { @@ -173,10 +197,11 @@ void DeckStats::saveStats(Player *player, Player *opponent, GameObserver * game) victory = 0; } load(player); - map::iterator it = stats.find(opponent->deckFileSmall); - if (it == stats.end()) + map *stats = &masterDeckStats[currentDeck]; + map::iterator it = stats->find(opponent->deckFileSmall); + if (it == stats->end()) { - stats[opponent->deckFileSmall] = NEW DeckStat(1, victory); + stats->insert( make_pair( opponent->deckFileSmall, NEW DeckStat(1, victory) )); } else { @@ -186,6 +211,12 @@ void DeckStats::saveStats(Player *player, Player *opponent, GameObserver * game) save(player); } +void DeckStats::EndInstance() +{ + SAFE_DELETE( mInstance ); +} + + // StatsWrapper float noLandsProbInTurn[Constants::STATS_FOR_TURNS] = {0.0f}; @@ -256,10 +287,13 @@ void StatsWrapper::initStatistics(string deckstats) found = 0; char buffer[512]; char smallDeckName[512]; - sprintf(buffer, "%s/deck%i.txt", RESPATH"/ai/baka", nbDecks + 1); + ostringstream oss; + oss << "deck" << (nbDecks + 1); + string bakaDir = JGE_GET_RES("/ai/baka"); + string deckFilename = oss.str(); + sprintf(buffer, "%s/%s.txt", bakaDir.c_str(), deckFilename.c_str()); if (fileExists(buffer)) { - MTGDeck * mtgd = NEW MTGDeck(buffer, NULL, 1); found = 1; nbDecks++; @@ -268,11 +302,10 @@ void StatsWrapper::initStatistics(string deckstats) if ((deckStat != NULL) && (deckStat->nbgames > 0)) { - aiDeckNames.push_back(string(mtgd->meta_name)); + aiDeckNames.push_back(deckFilename); aiDeckStats.push_back(deckStat); } - delete mtgd; } } else diff --git a/projects/mtg/src/GameApp.cpp b/projects/mtg/src/GameApp.cpp index d55beec8b..2c51a03b1 100644 --- a/projects/mtg/src/GameApp.cpp +++ b/projects/mtg/src/GameApp.cpp @@ -22,6 +22,7 @@ #include "GameStateStory.h" #include "DeckStats.h" #include "DeckMetaData.h" +#include "DeckManager.h" #include "Translate.h" #include "WFilter.h" @@ -273,7 +274,9 @@ void GameApp::Destroy() collection->destroyAllCards(); SAFE_DELETE(collection); } - delete (DeckStats::GetInstance()); + + DeckManager::EndInstance(); + DeckStats::EndInstance(); SAFE_DELETE(Subtypes::subtypesList); SAFE_DELETE(DeckMetaDataList::decksMetaData); diff --git a/projects/mtg/src/GameStateDeckViewer.cpp b/projects/mtg/src/GameStateDeckViewer.cpp index fa505358a..ae3081e23 100644 --- a/projects/mtg/src/GameStateDeckViewer.cpp +++ b/projects/mtg/src/GameStateDeckViewer.cpp @@ -1453,8 +1453,12 @@ void GameStateDeckViewer::Render() int GameStateDeckViewer::loadDeck(int deckid) { - if (!stw) stw = new StatsWrapper(deckid); - + if (!stw) + { + DeckManager *deckManager = DeckManager::GetInstance(); + stw = deckManager->getExtendedStatsForDeckId( deckid, mParent->collection, false ); + } + stw->currentPage = 0; stw->pageCount = 9; stw->needUpdate = true; diff --git a/projects/mtg/src/GameStateDuel.cpp b/projects/mtg/src/GameStateDuel.cpp index c82327d6a..0ddfb82d9 100644 --- a/projects/mtg/src/GameStateDuel.cpp +++ b/projects/mtg/src/GameStateDuel.cpp @@ -83,7 +83,6 @@ GameStateDuel::GameStateDuel(GameApp* parent) : GameStateDuel::~GameStateDuel() { End(); - } void GameStateDuel::Start() @@ -156,7 +155,6 @@ void GameStateDuel::Start() { mPlayers[i] = NULL; } - } void GameStateDuel::loadPlayer(int playerId, int decknb, int isAI) @@ -231,15 +229,14 @@ void GameStateDuel::End() DebugTrace("Ending GameStateDuel"); JRenderer::GetInstance()->EnableVSync(false); - DeckManager::EndInstance(); - + if (!premadeDeck && mPlayers[0] && mPlayers[1]) // save the stats for the game mPlayers[0]->End(); else if ( !mPlayers[1] && mPlayers[0] ) // clean up player object SAFE_DELETE( mPlayers[0] ); + GameObserver::EndInstance(); // this will delete both player objects if a game has been played - GameObserver::EndInstance(); // this will delete both player objects game = NULL; premadeDeck = false; @@ -248,7 +245,6 @@ void GameStateDuel::End() mPlayers[i] = NULL; deck[i] = NULL; } - SAFE_DELETE(credits); SAFE_DELETE(rules); diff --git a/projects/mtg/src/SimplePopup.cpp b/projects/mtg/src/SimplePopup.cpp index 176c090a5..00fe4b962 100644 --- a/projects/mtg/src/SimplePopup.cpp +++ b/projects/mtg/src/SimplePopup.cpp @@ -76,9 +76,11 @@ void SimplePopup::drawBoundingBox( float x, float y, float width, float height ) void SimplePopup::Update(DeckMetaData* selectedDeck) { mDeckInformation = selectedDeck; - SAFE_DELETE(mStatsWrapper); - mStatsWrapper = NEW StatsWrapper(mDeckInformation->getDeckId()); - mStatsWrapper->updateStats(mDeckInformation->getFilename(), mCollection); + + // get the information from the cache, if it doesn't exist create an entry + DeckManager *deckManager = DeckManager::GetInstance(); + mStatsWrapper = deckManager->getExtendedDeckStats( mDeckInformation, mCollection, (mDeckInformation->getFilename().find("baka") != string::npos) ); + } @@ -184,6 +186,5 @@ SimplePopup::~SimplePopup(void) { mTextFont = NULL; mDeckInformation = NULL; - SAFE_DELETE(mStatsWrapper); } diff --git a/projects/mtg/template.vcproj b/projects/mtg/template.vcproj index c44125b49..7b2a8279d 100644 --- a/projects/mtg/template.vcproj +++ b/projects/mtg/template.vcproj @@ -1022,10 +1022,6 @@ RelativePath=".\include\DamagerDamaged.h" > - -