From 591f0e0d305a3367adfef8e9ab37f367bb1586dc Mon Sep 17 00:00:00 2001 From: "wagic.the.homebrew" Date: Wed, 28 Dec 2011 16:14:08 +0000 Subject: [PATCH] - fix for issue 772 - fixed some issues in zstream that prevented to use "getline" in zipped streams - added a "pooled buffers" system to keep a cache of file descriptors. This is potentially dangerous though, but shaves several seconds of loading time on the PSP. If problems arise on other platforms I'll make it a compilation parameter - gracefully fail when calling manacost information on a not properly initialized mana cost --- JGE/include/JFileSystem.h | 2 + JGE/src/JFileSystem.cpp | 13 +++- JGE/src/JGE.cpp | 2 + JGE/src/zipFS/zfsystem.cpp | 119 ++++++++++++++++++++++++++--- JGE/src/zipFS/zfsystem.h | 34 ++++++++- JGE/src/zipFS/zstream.cpp | 54 +++++++++---- JGE/src/zipFS/zstream.h | 29 ++++--- projects/mtg/src/GameApp.cpp | 13 ++-- projects/mtg/src/GameObserver.cpp | 32 ++++++-- projects/mtg/src/GameStateMenu.cpp | 6 +- projects/mtg/src/MTGDeck.cpp | 14 ++-- projects/mtg/src/ManaCost.cpp | 19 ++++- 12 files changed, 276 insertions(+), 61 deletions(-) diff --git a/JGE/include/JFileSystem.h b/JGE/include/JFileSystem.h index 9efa7cd39..6c658a8b3 100644 --- a/JGE/include/JFileSystem.h +++ b/JGE/include/JFileSystem.h @@ -77,6 +77,8 @@ public: static void Destroy(); + // closes temporary files when the machine goes to sleep + void Pause(); ////////////////////////////////////////////////////////////////////////// /// Open file for reading. /// diff --git a/JGE/src/JFileSystem.cpp b/JGE/src/JFileSystem.cpp index 9e88baeda..16586f2c1 100644 --- a/JGE/src/JFileSystem.cpp +++ b/JGE/src/JFileSystem.cpp @@ -41,6 +41,11 @@ JZipCache::~JZipCache() dir.clear(); } +void JFileSystem::Pause() +{ + filesystem::closeTempFiles(); +} + void JFileSystem::preloadZip(const string& filename) { map::iterator it = mZipCache.find(filename); @@ -202,6 +207,7 @@ bool JFileSystem::MakeDir(const string & dir) JFileSystem::~JFileSystem() { clearZipCache(); + filesystem::closeTempFiles(); SAFE_DELETE(mUserFS); SAFE_DELETE(mSystemFS); } @@ -286,7 +292,12 @@ bool JFileSystem::readIntoString(const string & FilePath, string & target) int fileSize = GetFileSize(file); - target.resize((std::string::size_type) fileSize); + try { + target.resize((std::string::size_type) fileSize); + } catch (bad_alloc&) { + return false; + } + if (fileSize) file.read(&target[0], fileSize); diff --git a/JGE/src/JGE.cpp b/JGE/src/JGE.cpp index c4618c5db..a5f647a57 100644 --- a/JGE/src/JGE.cpp +++ b/JGE/src/JGE.cpp @@ -556,6 +556,8 @@ void JGE::Pause() mPaused = true; if (mApp != NULL) mApp->Pause(); + + JFileSystem::GetInstance()->Pause(); } void JGE::Resume() diff --git a/JGE/src/zipFS/zfsystem.cpp b/JGE/src/zipFS/zfsystem.cpp index 7fe932dbe..bd313d956 100644 --- a/JGE/src/zipFS/zfsystem.cpp +++ b/JGE/src/zipFS/zfsystem.cpp @@ -3,7 +3,7 @@ // zfsystem.cpp: implementation of the zip file system classes. // -// Copyright (C) 2004 Tanguy Fautré. +// Copyright (C) 2004 Tanguy Fautré. // For conditions of distribution and use, // see copyright notice in zfsystem.h // @@ -39,6 +39,7 @@ filesystem * izfstream::pDefaultFS = NULL; string filesystem::CurrentZipName = ""; ifstream filesystem::CurrentZipFile; filesystem * filesystem::pCurrentFS = NULL; +std::vector filesystem::m_Buffers; static const int STORED = 0; static const int DEFLATED = 8; @@ -86,6 +87,90 @@ filesystem::filesystem(const char * BasePath, const char * FileExt, bool Default // File System Member Functions ////////////////////////////////////////////////////////////////////// +zbuffer * filesystem::getValidBuffer(const std::string & filename, const std::string & externalFilename, std::streamoff Offset, std::streamoff Size ) +{ + //if exists filename in pool and is not in use, return that + for (size_t i = 0; i < m_Buffers.size(); ++i) + { + if (m_Buffers[i]->filename != filename) + continue; + zbuffer * buffer = m_Buffers[i]->buffer; + if (buffer && !buffer->is_used()) + { + buffer->use(Offset, Size); + return buffer; + } + } + + // if more than 3 objects in the pool, delete and close the first one that is unused + if (m_Buffers.size() > 3) + { + for (size_t i = 0; i < m_Buffers.size(); ++i) + { + zbuffer * buffer = m_Buffers[i]->buffer; + if (buffer && !buffer->is_used()) + { + delete m_Buffers[i]; + m_Buffers.erase(m_Buffers.begin() + i); + break; + } + } + } + + //No possiblility to open more files for now + if (m_Buffers.size() > 3) + return NULL; + + //create a new buffer object, add it to the pool, and return that + pooledBuffer * pb = new pooledBuffer(filename, externalFilename); + + zbuffer * buffer = new zbuffer_stored(); + buffer->open(filename.c_str(), Offset, Size); + pb->buffer = buffer; + + m_Buffers.push_back(pb); + return pb->buffer; + + +} + + +void filesystem::closeBufferPool() +{ + for (size_t i = 0; i < m_Buffers.size(); ++i) + { + if (m_Buffers[i]) + { + if (m_Buffers[i]->buffer && m_Buffers[i]->buffer->is_used()) + { + LOG("FATAL: File Buffer still in use but need to close"); + } + + delete m_Buffers[i]; + } + } + m_Buffers.clear(); +} + +void filesystem::unuse(izfstream & File) +{ + + File.setstate(std::ios::badbit); + + if (!File.Zipped()) + { + std::streambuf * buffer = File.rdbuf(NULL); + if (buffer) + delete(buffer); + } + else + { + zbuffer * buffer = static_cast(File.rdbuf()); + if (buffer) + buffer->unuse(); + } +} + void filesystem::Open(izfstream & File, const char * Filename) { // Close the file if it was opened; @@ -99,11 +184,11 @@ void filesystem::Open(izfstream & File, const char * Filename) if (FileNotZipped(FullPath.c_str())) { // Link the izfile object with an opened filebuf - filebuf * FileBuf = new filebuf; + filebuf * FileBuf = new filebuf; FileBuf->open(FullPath.c_str(), ios::binary | ios::in); if (FileBuf->is_open()) { - delete File.rdbuf(FileBuf); + File.rdbuf(FileBuf); File.clear(ios::goodbit); File.m_FilePath = Filename; File.m_FullFilePath = FullPath; @@ -148,14 +233,12 @@ void filesystem::Open(izfstream & File, const char * Filename) if (DataPos != streamoff(-1)) { string zipName = m_BasePath + CurrentZipName; // Open the file at the right position - ((izstream &) File).open( - zipName.c_str(), - streamoff(DataPos), - streamoff(FileInfo.m_CompSize), - FileInfo.m_CompMethod - ); + zbuffer * buffer = getValidBuffer(zipName, Filename, streamoff(DataPos), streamoff(FileInfo.m_CompSize)); + + if (buffer) { + File.rdbuf(buffer); + File.SetCompMethod(FileInfo.m_CompMethod); - if (File) { File.m_FilePath = Filename; File.m_FullFilePath = FullPath; File.m_Zipped = true; @@ -163,6 +246,10 @@ void filesystem::Open(izfstream & File, const char * Filename) File.m_CompSize = FileInfo.m_CompSize; File.m_Offset = FileInfo.m_Offset; } + else + { + File.setstate(ios::badbit); + } } } @@ -326,7 +413,11 @@ void filesystem::InsertZip(const char * Filename, const size_t PackID) return; // Find the start of the central directory - if (! File.seekg(CentralDir(File))) return; + if (! File.seekg(CentralDir(File))) + { + File.close(); + return; + } LOG("open zip ok"); @@ -381,7 +472,10 @@ bool filesystem::PreloadZip(const char * Filename, map& scanfolder(const std::string& folderName, std::vector& results); friend std::ostream & operator << (std::ostream & Out, const filesystem & FS); - + static void closeTempFiles(); + protected: + + // Zip file info class class zipfile_info { @@ -181,6 +198,9 @@ protected: const std::string & FindZip(size_t PackID) const; void InsertZip(const char * Filename, const size_t PackID); + static zbuffer * getValidBuffer(const std::string & filename, const std::string & externalFilename, std::streamoff Offset = 0, std::streamoff Size = 0); + static void closeBufferPool(); + // New type definitions typedef std::map zipmap; typedef std::map::iterator zipmap_iterator; @@ -194,6 +214,7 @@ protected: std::string m_FileExt; zipmap m_Zips; filemap m_Files; + static std::vector m_Buffers; static std::ifstream CurrentZipFile; static std::string CurrentZipName; static filesystem * pCurrentFS; @@ -242,7 +263,8 @@ inline void izfstream::open(const char * FilePath, filesystem * pFS) { } inline void izfstream::close() { - izstream::close(); + if (m_pFS) + m_pFS->unuse( * this); m_FilePath = m_FullFilePath = ""; m_UncompSize = 0; } @@ -255,6 +277,10 @@ inline bool izfstream::Zipped() const { return m_Zipped; } +inline bool izfstream::isBeingUsed() const { + return m_Used; +} + inline const std::string & izfstream::FilePath() const { return m_FilePath; } @@ -273,14 +299,16 @@ inline filesystem::~filesystem() { // Security mesure with izfile::pDefaultFS if (izfstream::pDefaultFS == this) izfstream::pDefaultFS = NULL; +} +inline void filesystem::closeTempFiles() { if (CurrentZipName.size()) { CurrentZipFile.close(); CurrentZipName = ""; } + closeBufferPool(); } - inline void filesystem::MakeDefault() { izfstream::pDefaultFS = this; } diff --git a/JGE/src/zipFS/zstream.cpp b/JGE/src/zipFS/zstream.cpp index e9ee966ff..1d15ff541 100644 --- a/JGE/src/zipFS/zstream.cpp +++ b/JGE/src/zipFS/zstream.cpp @@ -22,6 +22,7 @@ using namespace std; // zstream Member Functions ////////////////////////////////////////////////////////////////////// +/* void izstream::open(const char * Filename, streamoff Offset, streamoff Size, int CompMethod) { // Change the buffer if need @@ -67,8 +68,33 @@ zbuffer * izstream::GetRightBuffer(int CompMethod) const default: return NULL; } -} +}*/ +bool zbuffer::use(std::streamoff Offset, std::streamoff Size) +{ + if (! m_ZipFile) + return false; + + //Don't use a buffer already used; + if (m_Used) + return false; + + // adjust file position + if (! m_ZipFile.seekg(Offset, ios::beg)) + return false; + + setg( m_Buffer, // beginning of putback area + m_Buffer, // read position + m_Buffer); // end of buffer + + m_Buffer[0] = 0; + + m_Pos = -1; + m_Size = Size; + m_Used = true; + + return true; +} ////////////////////////////////////////////////////////////////////// @@ -83,13 +109,11 @@ zbuffer_stored * zbuffer_stored::open(const char * Filename, streamoff Offset, s return NULL; // adjust file position - if (! m_ZipFile.seekg(Offset, ios::beg)) + if (! use(Offset, Size)) return NULL; m_Opened = true; - m_Pos = -1; - m_Size = Size; - + m_Filename = Filename; return this; } @@ -101,6 +125,7 @@ zbuffer_stored * zbuffer_stored::close() return NULL; else { m_Opened = false; + m_Used = false; m_ZipFile.close(); } @@ -127,15 +152,15 @@ int zbuffer_stored::underflow() return static_cast(* gptr()); // Refill de buffer. - streamoff ToRead = ((m_Size - m_Pos) < BUFFERSIZE) ? (m_Size - m_Pos) : BUFFERSIZE; - if ((ToRead == 0) || (! m_ZipFile.read(m_Buffer, BUFFERSIZE))) - return EOF; - // Set the real position of the beginning of the buffer. if (m_Pos == streamoff(-1)) m_Pos = 0; - else - m_Pos += ToRead; + + streamoff ToRead = ((m_Size - m_Pos) < BUFFERSIZE) ? (m_Size - m_Pos) : BUFFERSIZE; + if ((ToRead == 0) || (! m_ZipFile.read(m_Buffer, ToRead))) + return EOF; + + m_Pos += ToRead; // Reset buffer pointers. setg( m_Buffer, // beginning of putback area @@ -188,7 +213,7 @@ streampos zbuffer_stored::seekoff(streamoff off, ios::seekdir dir, ios::openmod if (ToRead == 0) return WantedPos; - if (! m_ZipFile.read(m_Buffer, BUFFERSIZE)) + if (! m_ZipFile.read(m_Buffer, ToRead)) return streambuf::seekoff(off, dir, nMode); // Set the buffer at the right position @@ -225,7 +250,7 @@ zbuffer_deflated * zbuffer_deflated::open(const char * Filename, streamoff Offse return NULL; // adjust file position - if (! m_ZipFile.seekg(Offset, ios::beg)) + if (! use(Offset, Size)) return NULL; // z_stream (NULL) Initialization @@ -247,7 +272,7 @@ zbuffer_deflated * zbuffer_deflated::open(const char * Filename, streamoff Offse m_StreamEnd = false; m_Pos = 0; m_CompPos = 0; - m_Size = Size; + m_Filename = Filename; return this; } @@ -260,6 +285,7 @@ zbuffer_deflated * zbuffer_deflated::close() return NULL; else { m_Opened = false; + m_Used = false; m_ZipFile.close(); // z_stream unitialization. diff --git a/JGE/src/zipFS/zstream.h b/JGE/src/zipFS/zstream.h index 12768c223..1d3ef3aec 100644 --- a/JGE/src/zipFS/zstream.h +++ b/JGE/src/zipFS/zstream.h @@ -69,17 +69,25 @@ public: virtual zbuffer * close() = 0; bool is_open() const { return m_Opened; } + bool is_used() const {return m_Used;} + void unuse() { m_Used = false;} + bool use(std::streamoff Offset, std::streamoff Size); + std::string getFilename() { return m_Filename; } protected: - zbuffer() : m_Size(0), m_Opened(false) { } + zbuffer() : m_Size(0), m_Opened(false), m_Used(false) { } static const int BUFFERSIZE = 4092; + std::string m_Filename; + + std::ifstream m_ZipFile; std::streamoff m_Pos; std::streamoff m_Size; char m_Buffer[BUFFERSIZE]; bool m_Opened; + bool m_Used; }; @@ -88,7 +96,7 @@ protected: class zbuffer_stored : public zbuffer { public: - virtual ~zbuffer_stored() { } + virtual ~zbuffer_stored() { close(); } virtual zbuffer_stored * open(const char * Filename, std::streamoff Offset, std::streamoff Size); virtual zbuffer_stored * close(); @@ -112,8 +120,7 @@ class zbuffer_deflated : public zbuffer public: virtual ~zbuffer_deflated() { - if (m_Opened) - inflateEnd(&m_ZStream); + close(); } virtual zbuffer_deflated * open(const char * Filename, std::streamoff Offset, std::streamoff Size); @@ -144,23 +151,25 @@ class izstream : public std::istream public: izstream() : std::istream(NULL), m_CompMethod(-1) { setstate(std::ios::badbit); } - virtual ~izstream() { delete rdbuf(); } + virtual ~izstream() { rdbuf(NULL); } //This doesn't delete the buffer, deletion is handled by zfsystem; - void open(const char * Filename, std::streamoff Offset, std::streamoff Size, int CompMethod); - void close() { SetCompMethod(-1); } + //void open(const char * Filename, std::streamoff Offset, std::streamoff Size, int CompMethod); + //void close() { SetCompMethod(-1); } + + void SetCompMethod(int CompMethod) { m_CompMethod = CompMethod; }; protected: static const int STORED = 0; static const int DEFLATED = 8; - zbuffer * GetRightBuffer(int CompMethod) const; + //zbuffer * GetRightBuffer(int CompMethod) const; - void SetCompMethod(int CompMethod) { + /*void SetCompMethod(int CompMethod) { delete rdbuf(GetRightBuffer(m_CompMethod = CompMethod)); if (rdbuf() == NULL) setstate(std::ios::badbit); - } + }*/ int m_CompMethod; }; diff --git a/projects/mtg/src/GameApp.cpp b/projects/mtg/src/GameApp.cpp index dd2cd8c9d..232341d96 100644 --- a/projects/mtg/src/GameApp.cpp +++ b/projects/mtg/src/GameApp.cpp @@ -126,6 +126,7 @@ void GameApp::Create() LOG("init Res Folder at " + foldersRoot); JFileSystem::init(foldersRoot + "User/", foldersRoot + systemFolder); + // Create User Folders (for write access) if they don't exist { const char* folders[] = { "ai", "ai/baka", "ai/baka/stats", "campaigns", "graphics", "lang", "packs", "player", "player/stats", "profiles", "rules", "sets", "settings", "sound", "sound/sfx", "themes", "test"}; @@ -160,6 +161,13 @@ void GameApp::Create() //Test for Music files presence JFileSystem * jfs = JFileSystem::GetInstance(); HasMusic = jfs->FileExists(WResourceManager::Instance()->musicFile("Track0.mp3")) && jfs->FileExists(WResourceManager::Instance()->musicFile("Track1.mp3")); + + LOG("Init Collection"); + MTGAllCards::loadInstance(); + + LOG("Loading rules"); + Rules::loadAllRules(); + LOG("Loading Textures"); LOG("--Loading menuicons.png"); @@ -235,8 +243,6 @@ void GameApp::Create() jq = WResourceManager::Instance()->RetrieveQuad("phasebar.png", 0, 0, 0, 0, "phasebar", RETRIEVE_MANAGE); - LOG("Init Collection"); - MTGAllCards::loadInstance(); LOG("Creating Game States"); mGameStates[GAME_STATE_DECK_VIEWER] = NEW GameStateDeckViewer(this); @@ -265,9 +271,6 @@ void GameApp::Create() mCurrentState = NULL; mNextState = mGameStates[GAME_STATE_MENU]; - LOG("--Load Game rules"); - Rules::loadAllRules(); - //Set Audio volume JSoundSystem::GetInstance()->SetSfxVolume(options[Options::SFXVOLUME].number); JSoundSystem::GetInstance()->SetMusicVolume(options[Options::MUSICVOLUME].number); diff --git a/projects/mtg/src/GameObserver.cpp b/projects/mtg/src/GameObserver.cpp index 017bb5c23..f6acc711a 100644 --- a/projects/mtg/src/GameObserver.cpp +++ b/projects/mtg/src/GameObserver.cpp @@ -1750,17 +1750,33 @@ void GameObserver::createPlayer(const string& playerMode #ifdef TESTSUITE void GameObserver::loadTestSuitePlayer(int playerId, TestSuiteGame* testSuite) { - players.push_back(new TestSuiteAI(testSuite, playerId)); + loadPlayer(playerId, new TestSuiteAI(testSuite, playerId)); } #endif //TESTSUITE void GameObserver::loadPlayer(int playerId, Player* player) { - players.push_back(player); + //Because we're using a vector instead of an array (why?), + // we have to prepare the vector in order to be the right size to accomodate the playerId variable + // see http://code.google.com/p/wagic/issues/detail?id=772 + if (players.size() > (size_t) playerId) { + SAFE_DELETE(players[playerId]); + players[playerId] = NULL; + } else { + while (players.size() <= (size_t) playerId) + { + players.push_back(NULL); + } + } + + players[playerId] = player; } void GameObserver::loadPlayer(int playerId, PlayerType playerType, int decknb, bool premadeDeck) { + + + if (decknb) { if (playerType == PLAYER_TYPE_HUMAN) @@ -1774,7 +1790,8 @@ void GameObserver::loadPlayer(int playerId, PlayerType playerType, int decknb, b sprintf(deckFile, "%s/deck%i.txt", options.profileFile().c_str(), decknb); char deckFileSmall[255]; sprintf(deckFileSmall, "player_deck%i", decknb); - players.push_back(NEW HumanPlayer(this, deckFile, deckFileSmall, premadeDeck)); + + loadPlayer(playerId, NEW HumanPlayer(this, deckFile, deckFileSmall, premadeDeck)); #ifdef NETWORK_SUPPORT // FIXME, this is broken if(isNetwork) @@ -1785,7 +1802,7 @@ void GameObserver::loadPlayer(int playerId, PlayerType playerType, int decknb, b } else { //Remote player - mPlayers.push_back(NEW RemotePlayer(mParent->mpNetwork)); + loadPlayer(playerId, NEW RemotePlayer(mParent->mpNetwork)); #endif //NETWORK_SUPPORT } } @@ -1794,7 +1811,8 @@ void GameObserver::loadPlayer(int playerId, PlayerType playerType, int decknb, b AIPlayerFactory playerCreator; Player * opponent = NULL; if (playerId == 1) opponent = players[0]; - players.push_back(playerCreator.createAIPlayer(this, MTGCollection(), opponent, decknb)); + + loadPlayer(playerId, playerCreator.createAIPlayer(this, MTGCollection(), opponent, decknb)); } } else @@ -1809,11 +1827,11 @@ void GameObserver::loadPlayer(int playerId, PlayerType playerType, int decknb, b if (playerId == 1) opponent = players[0]; #ifdef AI_CHANGE_TESTING if (playerType == PLAYER_TYPE_CPU_TEST) - players.push_back(playerCreator.createAIPlayerTest(this, MTGCollection(), opponent, playerId == 0 ? "ai/bakaA/" : "ai/bakaB/")); + loadPlayer(playerId, playerCreator.createAIPlayerTest(this, MTGCollection(), opponent, playerId == 0 ? "ai/bakaA/" : "ai/bakaB/")); else #endif { - players.push_back(playerCreator.createAIPlayer(this, MTGCollection(), opponent)); + loadPlayer(playerId, playerCreator.createAIPlayer(this, MTGCollection(), opponent)); } if (playerType == PLAYER_TYPE_CPU_TEST) diff --git a/projects/mtg/src/GameStateMenu.cpp b/projects/mtg/src/GameStateMenu.cpp index 017200447..b59e39bff 100644 --- a/projects/mtg/src/GameStateMenu.cpp +++ b/projects/mtg/src/GameStateMenu.cpp @@ -394,11 +394,9 @@ void GameStateMenu::listPrimitives() { string filename = "sets/primitives/"; filename.append(primitiveFiles[i]); - izfstream file; - if (! JFileSystem::GetInstance()->openForRead(file, filename)) - continue; - file.close(); + if (! JFileSystem::GetInstance()->FileExists(filename)) + continue; primitives.push_back(filename); } primitivesLoadCounter = 0; diff --git a/projects/mtg/src/MTGDeck.cpp b/projects/mtg/src/MTGDeck.cpp index 6756f195d..1e3268429 100644 --- a/projects/mtg/src/MTGDeck.cpp +++ b/projects/mtg/src/MTGDeck.cpp @@ -330,18 +330,20 @@ int MTGAllCards::load(const char * config_file, const char * set_name, int autol int lineNumber = 0; std::string contents; - if (!JFileSystem::GetInstance()->readIntoString(config_file, contents)) + izfstream file; + if (!JFileSystem::GetInstance()->openForRead(file, config_file)) return total_cards; - std::stringstream stream(contents); + string s; - while (true) + while (getline(file,s)) { - if (!std::getline(stream, s)) return total_cards; lineNumber++; if (!s.size()) continue; - if (s[s.size() - 1] == '\r') s.erase(s.size() - 1); // Handle DOS files + if (s[s.size() - 1] == '\r') + s.erase(s.size() - 1); //Handle DOS files if (!s.size()) continue; + if (s.find("#AUTO_DEFINE ") == 0) { string toAdd = s.substr(13); @@ -374,6 +376,7 @@ int MTGAllCards::load(const char * config_file, const char * set_name, int autol if (!maxGrade) maxGrade = Constants::GRADE_BORDERLINE; //Default setting for grade is borderline? if (fileGrade > maxGrade) { + file.close(); return total_cards; } } @@ -405,6 +408,7 @@ int MTGAllCards::load(const char * config_file, const char * set_name, int autol continue; } } + file.close(); return total_cards; } diff --git a/projects/mtg/src/ManaCost.cpp b/projects/mtg/src/ManaCost.cpp index a616dd4e6..088947f28 100644 --- a/projects/mtg/src/ManaCost.cpp +++ b/projects/mtg/src/ManaCost.cpp @@ -351,11 +351,23 @@ ManaCost::~ManaCost() void ManaCost::x() { + if (cost.size() <= (size_t)Constants::NB_Colors) + { + DebugTrace("Seems ManaCost was not properly initialized"); + return; + } + cost[Constants::NB_Colors] = 1; } int ManaCost::hasX() { + if (cost.size() <= (size_t)Constants::NB_Colors) + { + DebugTrace("Seems ManaCost was not properly initialized"); + return 0; + } + return cost[Constants::NB_Colors]; } @@ -465,6 +477,11 @@ void ManaCost::copy(ManaCost * _manaCost) int ManaCost::getCost(int color) { + if (cost.size() <= (size_t)color) + { + DebugTrace("Seems ManaCost was not properly initialized"); + return 0; + } return cost[color]; } @@ -477,7 +494,7 @@ ManaCostHybrid * ManaCost::getHybridCost(unsigned int i) int ManaCost::hasColor(int color) { - if (cost[color]) + if (getCost(color)) return 1; for (size_t i = 0; i < hybrids.size(); i++) {