diff --git a/JGE/include/JNetwork.h b/JGE/include/JNetwork.h index 547678678..71ed10334 100644 --- a/JGE/include/JNetwork.h +++ b/JGE/include/JNetwork.h @@ -13,31 +13,42 @@ class JSocket; #include #include "Threading.h" -typedef void(*processCmd)(istream&, ostream&); +typedef void(*processCmd)(void*, stringstream&, stringstream&); class JNetwork { private: + struct CommandStruc{ + void* object; + string command; + processCmd processCommand; + }; + + string serverIP; int connected_to_ap; JSocket* socket; boost::mutex sendMutex; boost::mutex receiveMutex; stringstream received; stringstream toSend; - static map sCommandMap; + static map sCommandMap; + static JNetwork* mInstance; public: JNetwork(); ~JNetwork(); - string serverIP; + static JNetwork* GetInstance(); + static void Destroy(); + void Update(); int connect(string serverIP = ""); bool isConnected(); + bool isServer() { return serverIP == ""; }; static void ThreadProc(void* param); #if !defined (WIN32) && !defined (LINUX) static int connect_to_apctl(int config); #endif - bool sendCommand(string command); - static void registerCommand(string command, processCmd processCommand, processCmd processResponse); + bool sendCommand(const string& command, const string& payload = "", const string& suffix = "Request"); + static void registerCommand(string command, void* object, processCmd processRequest, processCmd processResponse); private: boost::thread *mpWorkerThread; diff --git a/JGE/src/JNetwork.cpp b/JGE/src/JNetwork.cpp index 31c9cdfe5..9d10fe8e9 100644 --- a/JGE/src/JNetwork.cpp +++ b/JGE/src/JNetwork.cpp @@ -33,15 +33,16 @@ #include #include "../include/JSocket.h" -map JNetwork::sCommandMap; +map JNetwork::sCommandMap; +JNetwork* JNetwork::mInstance = NULL; bool JNetwork::isConnected(){ - if (connected_to_ap !=1) return false; + if (connected_to_ap !=1 || !socket) return false; return socket->isConnected(); } JNetwork::JNetwork() - : mpWorkerThread(NULL) + : mpWorkerThread(NULL), socket(0) { #if (defined WIN32) || (defined LINUX) connected_to_ap = 1; @@ -62,30 +63,83 @@ JNetwork::~JNetwork() delete socket; } -bool JNetwork::sendCommand(string xString) +JNetwork* JNetwork::GetInstance() { - string aString = xString; + if (mInstance == NULL) mInstance = new JNetwork(); + return mInstance; +} + +void JNetwork::Destroy() +{ + if (mInstance) + { + delete mInstance; + mInstance = NULL; + } +} + +bool JNetwork::sendCommand(const string& xString, const string& payload, const string& suffix) +{ + string aString; boost::mutex::scoped_lock l(sendMutex); if(!socket) { - DebugTrace("sendCommand failed: no sockeet"); + DebugTrace("sendCommand failed: no socket"); return false; } - aString = aString + "Command"; + aString = xString + suffix; if(sCommandMap.find(aString) == sCommandMap.end()) { DebugTrace("sendCommand failed: command not registered"); return false; } - aString = aString + "\n"; + aString = "<" + aString + ">" + "\n" + payload + "\n" + "<" + aString + "/>"; toSend << aString; return true; } -void JNetwork::registerCommand(string command, processCmd processCommand, processCmd processResponse) +void JNetwork::registerCommand(string command, void* object, processCmd processCommand, processCmd processResponse) { - sCommandMap[command + "Command"] = processCommand; - sCommandMap[command + "Response"] = processResponse; + CommandStruc struc; + struc.object = object; + struc.command = command; + struc.processCommand = processCommand; + + sCommandMap[command + "Request"] = struc; + struc.processCommand = processResponse; + sCommandMap[command + "Response"] = struc; +} + +void JNetwork::Update() +{ + boost::mutex::scoped_lock r(receiveMutex); + // Checking for some command to execute + size_t begin_start_tag = received.str().find("<"); + size_t end_start_tag = received.str().find(">"); + string command = received.str().substr(begin_start_tag+1, end_start_tag-(begin_start_tag+1)); + size_t begin_end_tag = received.str().find(command + "/>"); + size_t end_end_tag = received.str().find("/>"); + if(begin_start_tag != string::npos && begin_end_tag != string::npos ) + { + map::iterator ite = sCommandMap.find(command); + if(ite != sCommandMap.end()) + { + DebugTrace("begin of command received : " + received.str() ); + DebugTrace("begin of command toSend : " + toSend.str() ); + + processCmd theMethod = (ite)->second.processCommand; + stringstream input(received.str().substr(end_start_tag+1, (begin_end_tag-1)-(end_start_tag+1))); + stringstream output; + theMethod((ite)->second.object, input, output); + string aString = received.str().substr(end_end_tag+2, string::npos); + received.str(aString); + if(output.str().size()) + sendCommand((ite)->second.command, output.str(), "Response"); + + DebugTrace("end of command received : "<< received.str() ); + DebugTrace("end of command toSend : "<< toSend.str() ); + } + } } void JNetwork::ThreadProc(void* param) @@ -105,64 +159,25 @@ void JNetwork::ThreadProc(void* param) } while(pSocket && pSocket->isConnected()) { - char buff[1024]; + char buff[4096]; { boost::mutex::scoped_lock l(pThis->receiveMutex); int len = pSocket->Read(buff, sizeof(buff)); - if(len) { + if(len > 0) { DebugTrace("receiving " << len << " bytes : " << buff); - pThis->received << buff; - } - // Checking for some command to execute - size_t found = pThis->received.str().find("Command"); - if(found != string::npos) - { - map::iterator ite = sCommandMap.find((pThis->received.str()).substr(0, found) + "Command"); - if(ite != sCommandMap.end()) - { - DebugTrace("begin of command received : "<< pThis->received.str() ); - DebugTrace("begin of command toSend : "<< pThis->toSend.str() ); - - boost::mutex::scoped_lock l(pThis->sendMutex); - pThis->toSend << pThis->received.str().substr(0, found) + "Response "; - pThis->received.str(""); - processCmd theMethod = (ite)->second; - theMethod(pThis->received, pThis->toSend); - - DebugTrace("end of command received : "<< pThis->received.str() ); - DebugTrace("end of command toSend : "<< pThis->toSend.str() ); - } - } - // Checking for some response to execute - found = pThis->received.str().find("Response"); - if(found != string::npos) - { - map::iterator ite = sCommandMap.find((pThis->received.str()).substr(0, found) + "Response"); - if(ite != sCommandMap.end()) - { - DebugTrace("begin of response received : "<< pThis->received.str() ); - DebugTrace("begin of response toSend : "<< pThis->toSend.str() ); - - boost::mutex::scoped_lock l(pThis->sendMutex); - string aString; - pThis->received >> aString; - processCmd theMethod = (ite)->second; - theMethod(pThis->received, pThis->toSend); - pThis->received.str(""); - - DebugTrace("end of response received : "<< pThis->received.str() ); - DebugTrace("end of response toSend : "<< pThis->toSend.str() ); - } + pThis->received.str(pThis->received.str() + buff); + DebugTrace("received " << pThis->received.str().size() << " bytes : " << pThis->received.str()); } } - - boost::mutex::scoped_lock l(pThis->sendMutex); - if(!pThis->toSend.str().empty()) - { - DebugTrace("sending " << pThis->toSend.str().size() << " bytes : " << pThis->toSend.str()); - pSocket->Write((char*)pThis->toSend.str().c_str(), pThis->toSend.str().size()+1); - pThis->toSend.str(""); - } + { + boost::mutex::scoped_lock l(pThis->sendMutex); + if(!pThis->toSend.str().empty()) + { + DebugTrace("sending " << pThis->toSend.str().size() << " bytes : " << pThis->toSend.str()); + pSocket->Write((char*)pThis->toSend.str().c_str(), pThis->toSend.str().size()+1); + pThis->toSend.str(""); + } + } } DebugTrace("Quitting Thread"); diff --git a/JGE/src/pc/JSocket.cpp b/JGE/src/pc/JSocket.cpp index 27d708ac0..adcaffaf4 100644 --- a/JGE/src/pc/JSocket.cpp +++ b/JGE/src/pc/JSocket.cpp @@ -264,9 +264,17 @@ int JSocket::Read(char* buff, int size) #endif //WINDOWS if(readbytes < 0) { - DebugTrace("Error reading from socket\n"); +#ifdef WIN32 + DebugTrace("Error reading from socket: " << WSAGetLastError()); +#endif //WINDOWS + Disconnect(); return -1; } + else if(readbytes == 0) + { + Disconnect(); + return 0; + } else return readbytes; } @@ -303,6 +311,7 @@ int JSocket::Write(char* buff, int size) } else if (result < 0) { + Disconnect(); return -1; } } diff --git a/projects/mtg/include/GameObserver.h b/projects/mtg/include/GameObserver.h index cee0072f0..7a91bfb50 100644 --- a/projects/mtg/include/GameObserver.h +++ b/projects/mtg/include/GameObserver.h @@ -12,7 +12,9 @@ #include "GuiStatic.h" #include #include - +#ifdef NETWORK_SUPPORT +#include "JNetwork.h" +#endif //NETWORK_SUPPORT class MTGGamePhase; class MTGAbility; @@ -42,13 +44,15 @@ class GameObserver{ JGE* mJGE; DeckManager* mDeckManager; Player * gameOver; + GamePhase mCurrentGamePhase; int untap(MTGCardInstance * card); bool WaitForExtraPayment(MTGCardInstance* card); void cleanup(); string startupGameSerialized; bool parseLine(const string& s); - void logAction(const string& s); + virtual void logAction(const string& s); + bool processAction(const string& s, bool swapPlayer = false); bool processActions(bool undo #ifdef TESTSUITE , TestSuiteGame* testgame @@ -58,7 +62,7 @@ class GameObserver{ bool mLoading; void nextGamePhase(); void shuffleLibrary(Player* p); - void createPlayer(const string& playerMode + Player* createPlayer(const string& playerMode #ifdef TESTSUITE , TestSuiteGame* testgame #endif //TESTSUITE @@ -73,7 +77,6 @@ class GameObserver{ PhaseRing * phaseRing; vector >gameTurn; int cancelCurrentAction(); - GamePhase currentGamePhase; ExtraCosts * mExtraPayment; int oldGamePhase; TargetChooser * targetChooser; @@ -85,10 +88,7 @@ class GameObserver{ MTGCardInstance* ExtraRules; Trash* mTrash; - GameType gameType() const - { - return mGameType; - }; + GameType gameType() const { return mGameType; }; TargetChooser * getCurrentTargetChooser(); void stackObjectClicked(Interruptible * action); @@ -97,6 +97,7 @@ class GameObserver{ int cardClick(MTGCardInstance * card, int abilityType); int cardClick(MTGCardInstance * card,Targetable * _object = NULL, bool log = true); GamePhase getCurrentGamePhase(); + void setCurrentGamePhase(GamePhase phase) { mCurrentGamePhase = phase; }; const char * getCurrentGamePhaseName(); const char * getNextGamePhaseName(); void nextCombatStep(); @@ -107,7 +108,7 @@ class GameObserver{ #ifdef TESTSUITE void loadTestSuitePlayer(int playerId, TestSuiteGame* testSuite); #endif //TESTSUITE - void loadPlayer(int playerId, PlayerType playerType = PLAYER_TYPE_HUMAN, int decknb=0, bool premadeDeck=false); + virtual void loadPlayer(int playerId, PlayerType playerType = PLAYER_TYPE_HUMAN, int decknb=0, bool premadeDeck=false); void loadPlayer(int playerId, Player* player); Player * currentPlayer; @@ -117,7 +118,7 @@ class GameObserver{ Player * nextTurnsPlayer(); Player * currentlyActing(); GameObserver(WResourceManager* output = 0, JGE* input = 0); - ~GameObserver(); + virtual ~GameObserver(); void gameStateBasedEffects(); void enchantmentStatus(); void Affinity(); @@ -129,7 +130,7 @@ class GameObserver{ int isInPlay(MTGCardInstance * card); int isInGrave(MTGCardInstance * card); int isInExile(MTGCardInstance * card); - void Update(float dt); + virtual void Update(float dt); void Render(); void ButtonPressed(PlayGuiObject*); int getPlayersNumber() {return players.size();}; @@ -181,4 +182,27 @@ class GameObserver{ }; }; +#ifdef NETWORK_SUPPORT +class NetworkGameObserver : public GameObserver +{ +protected: + JNetwork* mpNetworkSession; + bool mSynchronized; + bool mForwardAction; + virtual void logAction(const string& s); +public: + // no serverIp means a server is being instantiated, otherwise a client + NetworkGameObserver(JNetwork* pNetwork, WResourceManager* output = 0, JGE* input = 0); + virtual ~NetworkGameObserver(); + virtual void loadPlayer(int playerId, PlayerType playerType = PLAYER_TYPE_HUMAN, int decknb=0, bool premadeDeck=false); + virtual void Update(float dt); + void synchronize(); + static void loadPlayer(void*pThis, stringstream& in, stringstream& out); + static void sendAction(void*pThis, stringstream& in, stringstream& out); + static void synchronize(void*pThis, stringstream& in, stringstream& out); + static void ignoreResponse(void*pThis, stringstream& in, stringstream& out){}; +}; +#endif + + #endif diff --git a/projects/mtg/include/NetworkPlayer.h b/projects/mtg/include/NetworkPlayer.h index dc62678d4..a07679b5e 100644 --- a/projects/mtg/include/NetworkPlayer.h +++ b/projects/mtg/include/NetworkPlayer.h @@ -15,7 +15,7 @@ protected: static ProxyPlayer* mInstance; public: ProxyPlayer(Player* pxPlayer, JNetwork* pxNetwork); - static void Serialize(istream& in, ostream& out); + static void Serialize(void*, stringstream& in, stringstream& out); }; @@ -25,8 +25,8 @@ protected: JNetwork* mpNetwork; static RemotePlayer* mInstance; public: - RemotePlayer(JNetwork*); - static void Deserialize(istream& in, ostream& out); + RemotePlayer(GameObserver* observer, JNetwork*); + static void Deserialize(void*, stringstream& in, stringstream& out); bool isLoaded() {return game!=NULL;}; }; diff --git a/projects/mtg/include/Player.h b/projects/mtg/include/Player.h index 4bc516c6a..b60045725 100644 --- a/projects/mtg/include/Player.h +++ b/projects/mtg/include/Player.h @@ -102,6 +102,7 @@ public: std::string GetCurrentDeckStatsFile(); virtual bool parseLine(const string& s); friend ostream& operator<<(ostream&, const Player&); + friend istream& operator>>(istream&, Player&); bool operator<(Player& aPlayer); bool isDead(); }; diff --git a/projects/mtg/src/GameApp.cpp b/projects/mtg/src/GameApp.cpp index 0c97ebddf..674b36898 100644 --- a/projects/mtg/src/GameApp.cpp +++ b/projects/mtg/src/GameApp.cpp @@ -75,7 +75,7 @@ GameApp::GameApp() : mCurrentState = NULL; mNextState = NULL; - + rules = 0; music = NULL; } diff --git a/projects/mtg/src/GameObserver.cpp b/projects/mtg/src/GameObserver.cpp index 23748b8f1..0118a592a 100644 --- a/projects/mtg/src/GameObserver.cpp +++ b/projects/mtg/src/GameObserver.cpp @@ -15,9 +15,14 @@ #include "Trash.h" #include "DeckManager.h" #include "GuiCombat.h" +#include #ifdef TESTSUITE #include "TestSuiteAI.h" #endif +#ifdef NETWORK_SUPPORT +#include "NetworkPlayer.h" +#endif + void GameObserver::cleanup() { @@ -35,7 +40,7 @@ void GameObserver::cleanup() currentActionPlayer = NULL; isInterrupting = NULL; currentPlayerId = 0; - currentGamePhase = MTG_PHASE_INVALID; + mCurrentGamePhase = MTG_PHASE_INVALID; targetChooser = NULL; cardWaitingForTargets = NULL; mExtraPayment = NULL; @@ -51,6 +56,7 @@ void GameObserver::cleanup() GameObserver::~GameObserver() { LOG("==Destroying GameObserver=="); + for (size_t i = 0; i < players.size(); ++i) { players[i]->End(); @@ -83,7 +89,7 @@ GameObserver::GameObserver(WResourceManager *output, JGE* input) currentActionPlayer = NULL; isInterrupting = NULL; currentPlayerId = 0; - currentGamePhase = MTG_PHASE_INVALID; + mCurrentGamePhase = MTG_PHASE_INVALID; targetChooser = NULL; cardWaitingForTargets = NULL; mExtraPayment = NULL; @@ -101,17 +107,17 @@ GameObserver::GameObserver(WResourceManager *output, JGE* input) GamePhase GameObserver::getCurrentGamePhase() { - return currentGamePhase; + return mCurrentGamePhase; } const char* GameObserver::getCurrentGamePhaseName() { - return phaseRing->phaseName(currentGamePhase); + return phaseRing->phaseName(mCurrentGamePhase); } const char* GameObserver::getNextGamePhaseName() { - return phaseRing->phaseName((currentGamePhase + 1) % MTG_PHASE_CLEANUP); + return phaseRing->phaseName((mCurrentGamePhase + 1) % MTG_PHASE_CLEANUP); } Player * GameObserver::opponent() @@ -182,18 +188,18 @@ void GameObserver::nextGamePhase() } Phase * cPhase = phaseRing->getCurrentPhase(); - currentGamePhase = cPhase->id; + mCurrentGamePhase = cPhase->id; - if (MTG_PHASE_COMBATDAMAGE == currentGamePhase) + if (MTG_PHASE_COMBATDAMAGE == mCurrentGamePhase) nextCombatStep(); - if (MTG_PHASE_COMBATEND == currentGamePhase) + if (MTG_PHASE_COMBATEND == mCurrentGamePhase) combatStep = BLOCKERS; //if (currentPlayer != cPhase->player) // nextPlayer();//depreciated; we call this at EOT step now. unsure what the purpose of this was originally.fix for a bug? //init begin of turn - if (currentGamePhase == MTG_PHASE_BEFORE_BEGIN) + if (mCurrentGamePhase == MTG_PHASE_BEFORE_BEGIN) { cleanupPhase(); currentPlayer->damageCount = 0; @@ -211,7 +217,7 @@ void GameObserver::nextGamePhase() return nextGamePhase(); } - if (currentGamePhase == MTG_PHASE_AFTER_EOT) + if (mCurrentGamePhase == MTG_PHASE_AFTER_EOT) { //Auto Hand cleaning, in case the player didn't do it himself while (currentPlayer->game->hand->nb_cards > currentPlayer->handsize && currentPlayer->nomaxhandsize == false) @@ -228,7 +234,7 @@ void GameObserver::nextGamePhase() } //Phase Specific actions - switch (currentGamePhase) + switch (mCurrentGamePhase) { case MTG_PHASE_UNTAP: DebugTrace("Untap Phase ------------- Turn " << turn ); @@ -281,7 +287,7 @@ void GameObserver::userRequestNextGamePhase(bool allowInterrupt, bool log) { if(log) { stringstream stream; - stream << "next " << allowInterrupt << " " <id == MTG_PHASE_COMBATBLOCKERS && combatStep == TRIGGERS) || (cPhaseOld->id == MTG_PHASE_COMBATDAMAGE) || opponent()->isAI() - || options[Options::optionInterrupt(currentGamePhase)].number - || currentPlayer->offerInterruptOnPhase - 1 == currentGamePhase + || options[Options::optionInterrupt(mCurrentGamePhase)].number + || currentPlayer->offerInterruptOnPhase - 1 == mCurrentGamePhase )) { mLayers->stackLayer()->AddNextGamePhase(); @@ -480,7 +486,7 @@ bool GameObserver::operator==(const GameObserver& aGame) { int error = 0; - if (aGame.currentGamePhase != currentGamePhase) + if (aGame.mCurrentGamePhase != mCurrentGamePhase) { error++; } @@ -544,7 +550,7 @@ void GameObserver::dumpAssert(bool val) void GameObserver::Update(float dt) { Player * player = currentPlayer; - if (MTG_PHASE_COMBATBLOCKERS == currentGamePhase && BLOCKERS == combatStep) + if (MTG_PHASE_COMBATBLOCKERS == mCurrentGamePhase && BLOCKERS == combatStep) { player = player->opponent(); } @@ -567,7 +573,7 @@ void GameObserver::Update(float dt) } gameStateBasedEffects(); } - oldGamePhase = currentGamePhase; + oldGamePhase = mCurrentGamePhase; } //applies damage to creatures after updates @@ -649,7 +655,7 @@ void GameObserver::gameStateBasedEffects() ////////////////////////// //handles phasing events// ////////////////////////// - if(card->has(Constants::PHASING)&& currentGamePhase == MTG_PHASE_UNTAP && currentPlayer == card->controller() && card->phasedTurn != turn && !card->isPhased) + if(card->has(Constants::PHASING)&& mCurrentGamePhase == MTG_PHASE_UNTAP && currentPlayer == card->controller() && card->phasedTurn != turn && !card->isPhased) { card->isPhased = true; card->phasedTurn = turn; @@ -657,7 +663,7 @@ void GameObserver::gameStateBasedEffects() card->view->alpha = 50; card->initAttackersDefensers(); } - else if((card->has(Constants::PHASING) || card->isPhased)&& currentGamePhase == MTG_PHASE_UNTAP && currentPlayer == card->controller() && card->phasedTurn != turn) + else if((card->has(Constants::PHASING) || card->isPhased)&& mCurrentGamePhase == MTG_PHASE_UNTAP && currentPlayer == card->controller() && card->phasedTurn != turn) { card->isPhased = false; card->phasedTurn = turn; @@ -761,7 +767,7 @@ void GameObserver::gameStateBasedEffects() ///////////////////////////////////////////////// //handle end of turn effects while we're at it.// ///////////////////////////////////////////////// - if (currentGamePhase == MTG_PHASE_ENDOFTURN+1) + if (mCurrentGamePhase == MTG_PHASE_ENDOFTURN+1) { for (int j = 0; j < nbcards; ++j) { @@ -860,17 +866,17 @@ void GameObserver::gameStateBasedEffects() if (skipLevel == Constants::ASKIP_SAFE || skipLevel == Constants::ASKIP_FULL) { - if ((opponent()->isAI() && !(isInterrupting)) && ((currentGamePhase == MTG_PHASE_UNTAP) - || (currentGamePhase == MTG_PHASE_DRAW) || (currentGamePhase == MTG_PHASE_COMBATBEGIN) - || ((currentGamePhase == MTG_PHASE_COMBATATTACKERS) && (nrCreatures == 0)) - || currentGamePhase == MTG_PHASE_COMBATEND || currentGamePhase == MTG_PHASE_ENDOFTURN - || ((currentGamePhase == MTG_PHASE_CLEANUP) && (currentPlayer->game->hand->nb_cards < 8)))) + if ((opponent()->isAI() && !(isInterrupting)) && ((mCurrentGamePhase == MTG_PHASE_UNTAP) + || (mCurrentGamePhase == MTG_PHASE_DRAW) || (mCurrentGamePhase == MTG_PHASE_COMBATBEGIN) + || ((mCurrentGamePhase == MTG_PHASE_COMBATATTACKERS) && (nrCreatures == 0)) + || mCurrentGamePhase == MTG_PHASE_COMBATEND || mCurrentGamePhase == MTG_PHASE_ENDOFTURN + || ((mCurrentGamePhase == MTG_PHASE_CLEANUP) && (currentPlayer->game->hand->nb_cards < 8)))) userRequestNextGamePhase(); } if (skipLevel == Constants::ASKIP_FULL) { - if ((opponent()->isAI() && !(isInterrupting)) && (currentGamePhase == MTG_PHASE_UPKEEP - || currentGamePhase == MTG_PHASE_COMBATDAMAGE)) + if ((opponent()->isAI() && !(isInterrupting)) && (mCurrentGamePhase == MTG_PHASE_UPKEEP + || mCurrentGamePhase == MTG_PHASE_COMBATDAMAGE)) userRequestNextGamePhase(); } } @@ -1316,7 +1322,7 @@ int GameObserver::cardClick(MTGCardInstance * card, Targetable * object, bool lo } //Current player's hand - if (currentPlayer->game->hand->hasCard(card) && currentGamePhase == MTG_PHASE_CLEANUP + if (currentPlayer->game->hand->hasCard(card) && mCurrentGamePhase == MTG_PHASE_CLEANUP && currentPlayer->game->hand->nb_cards > currentPlayer->handsize && currentPlayer->nomaxhandsize == false) { WEvent * e = NEW WEventCardDiscard(currentPlayer->game->hand->cards[0]); @@ -1475,8 +1481,8 @@ ostream& operator<<(ostream& out, const GameObserver& g) { out << "[init]" << endl; out << "player=" << g.currentPlayerId + 1 << endl; - if(g.currentGamePhase != -1) - out << "phase=" << g.phaseRing->phaseName(g.currentGamePhase) << endl; + if(g.mCurrentGamePhase != MTG_PHASE_INVALID) + out << "phase=" << g.phaseRing->phaseName(g.mCurrentGamePhase) << endl; out << "[player1]" << endl; out << *(g.players[0]) << endl; out << "[player2]" << endl; @@ -1518,7 +1524,7 @@ bool GameObserver::parseLine(const string& s) } else if (areaS.compare("phase") == 0) { - currentGamePhase = PhaseRing::phaseStrToInt(s.substr(limiter + 1).c_str()); + mCurrentGamePhase = PhaseRing::phaseStrToInt(s.substr(limiter + 1).c_str()); return true; } } @@ -1630,7 +1636,7 @@ bool GameObserver::load(const string& ss, bool undo mRules->initGame(this); phaseRing->goToPhase(0, currentPlayer, false); - phaseRing->goToPhase(currentGamePhase, currentPlayer); + phaseRing->goToPhase(mCurrentGamePhase, currentPlayer); #ifdef TESTSUITE if(testgame) @@ -1654,6 +1660,63 @@ bool GameObserver::load(const string& ss, bool undo return true; } +bool GameObserver::processAction(const string& s, bool swapPlayer) +{ + Player* p = (swapPlayer)?players[0]:players[1]; + if (s.find("p1") != string::npos) + p = (swapPlayer)?players[1]:players[0]; + + MTGGameZone* zone = NULL; + if(s.find(string(p->game->hand->getName())+"[") != string::npos) + zone = p->game->hand; + else if(s.find(string(p->game->battlefield->getName())+"[") != string::npos) + zone = p->game->battlefield; + else if(s.find(string(p->game->graveyard->getName())+"[") != string::npos) + zone = p->game->graveyard; + else if(s.find(string(p->game->library->getName())+"[") != string::npos) + zone = p->game->library; + + if(zone) { + size_t begin = s.find("[")+1; + size_t size = s.find("]")-begin; + size_t index = atoi(s.substr(begin, size).c_str()); + dumpAssert(index < zone->cards.size()); + cardClick(zone->cards[index], zone->cards[index]); + } else if (s.find("stack") != string::npos) { + size_t begin = s.find("[")+1; + size_t size = s.find("]")-begin; + size_t index = atoi(s.substr(begin, size).c_str()); + stackObjectClicked((Interruptible*)mLayers->stackLayer()->getByIndex(index)); + } else if (s.find("yes") != string::npos) { + mLayers->stackLayer()->setIsInterrupting(p); + } else if (s.find("no") != string::npos) { + mLayers->stackLayer()->cancelInterruptOffer(); + } else if (s.find("endinterruption") != string::npos) { + mLayers->stackLayer()->endOfInterruption(); + } else if (s.find("next") != string::npos) { + userRequestNextGamePhase(); + } else if (s.find("combatok") != string::npos) { + mLayers->combatLayer()->clickOK(); + } else if (s == "p1" || s == "p2") { + cardClick(NULL, p); + } else if (s.find("choice") != string::npos) { + int choice = atoi(s.substr(s.find("choice ") + 7).c_str()); + mLayers->actionLayer()->doReactTo(choice); + } else if (s == "p1" || s == "p2") { + cardClick(NULL, p); + } else if(s.find("mulligan") != string::npos) { + Mulligan(p); + } else if(s.find("shufflelib") != string::npos) { + // This should probably be differently and be automatically part of the ability triggered + // that would allow the AI to use it as well. + shuffleLibrary(p); + } else { + DebugTrace("no clue about: " + s); + } + + return true; +} + bool GameObserver::processActions(bool undo #ifdef TESTSUITE , TestSuiteGame* testgame @@ -1680,7 +1743,7 @@ bool GameObserver::processActions(bool undo // We fake here cause the initialization before caused mana pool reset events to be triggered // So, we need them flushed to be able to set the manapool to whatever we need - Update(counter); + GameObserver::Update(counter); counter += 1.000f; #ifdef TESTSUITE @@ -1692,65 +1755,14 @@ bool GameObserver::processActions(bool undo for(loadingite = loadingList.begin(); loadingite != loadingList.end(); loadingite++, cmdIndex++) { - string s = *loadingite; - Player* p = players[1]; - if (s.find("p1") != string::npos) - p = players[0]; - - MTGGameZone* zone = NULL; - if(s.find(string(p->game->hand->getName())+"[") != string::npos) - zone = p->game->hand; - else if(s.find(string(p->game->battlefield->getName())+"[") != string::npos) - zone = p->game->battlefield; - else if(s.find(string(p->game->graveyard->getName())+"[") != string::npos) - zone = p->game->graveyard; - else if(s.find(string(p->game->library->getName())+"[") != string::npos) - zone = p->game->library; - - if(zone) { - size_t begin = s.find("[")+1; - size_t size = s.find("]")-begin; - size_t index = atoi(s.substr(begin, size).c_str()); - dumpAssert(index < zone->cards.size()); - cardClick(zone->cards[index], zone->cards[index]); - } else if (s.find("stack") != string::npos) { - size_t begin = s.find("[")+1; - size_t size = s.find("]")-begin; - size_t index = atoi(s.substr(begin, size).c_str()); - stackObjectClicked((Interruptible*)mLayers->stackLayer()->getByIndex(index)); - } else if (s.find("yes") != string::npos) { - mLayers->stackLayer()->setIsInterrupting(p); - } else if (s.find("no") != string::npos) { - mLayers->stackLayer()->cancelInterruptOffer(); - } else if (s.find("endinterruption") != string::npos) { - mLayers->stackLayer()->endOfInterruption(); - } else if (s.find("next") != string::npos) { - userRequestNextGamePhase(); - } else if (s.find("combatok") != string::npos) { - mLayers->combatLayer()->clickOK(); - } else if (s == "p1" || s == "p2") { - cardClick(NULL, p); - } else if (s.find("choice") != string::npos) { - int choice = atoi(s.substr(s.find("choice ") + 7).c_str()); - mLayers->actionLayer()->doReactTo(choice); - } else if (s == "p1" || s == "p2") { - cardClick(NULL, p); - } else if(s.find("mulligan") != string::npos) { - Mulligan(p); - } else if(s.find("shufflelib") != string::npos) { - // This should probably be differently and be automatically part of the ability triggered - // that would allow the AI to use it as well. - shuffleLibrary(p); - } else { - dumpAssert(0); - } + processAction(*loadingite); size_t nb = actionsList.size(); for (int i = 0; i<6; i++) { // let's fake an update - Update(counter); + GameObserver::Update(counter); counter += 1.000f; } dumpAssert(actionsList.back() == *loadingite); @@ -1809,34 +1821,43 @@ void GameObserver::Mulligan(Player* player) player->takeMulligan(); } -void GameObserver::createPlayer(const string& playerMode +Player* GameObserver::createPlayer(const string& playerMode #ifdef TESTSUITE , TestSuiteGame* testgame #endif //TESTSUITE ) { Player::Mode aMode = (Player::Mode)atoi(playerMode.c_str()); + Player* pPlayer = 0; + switch(aMode) { case Player::MODE_AI: AIPlayerFactory playerCreator; if(players.size()) - players.push_back(playerCreator.createAIPlayer(this, MTGCollection(), players[0])); + pPlayer = playerCreator.createAIPlayer(this, MTGCollection(), players[0]); else - players.push_back(playerCreator.createAIPlayer(this, MTGCollection(), 0)); + pPlayer = playerCreator.createAIPlayer(this, MTGCollection(), 0); break; case Player::MODE_HUMAN: - players.push_back(new HumanPlayer(this, "", "")); + pPlayer = new HumanPlayer(this, "", ""); break; case Player::MODE_TEST_SUITE: #ifdef TESTSUITE if(players.size()) - players.push_back(new TestSuiteAI(testgame, 1)); + pPlayer = new TestSuiteAI(testgame, 1); else - players.push_back(new TestSuiteAI(testgame, 0)); + pPlayer = new TestSuiteAI(testgame, 0); #endif //TESTSUITE break; } + + if(pPlayer) + { + players.push_back(pPlayer); + } + + return pPlayer; } #ifdef TESTSUITE @@ -1881,20 +1902,19 @@ void GameObserver::loadPlayer(int playerId, PlayerType playerType, int decknb, b sprintf(deckFileSmall, "player_deck%i", decknb); loadPlayer(playerId, NEW HumanPlayer(this, deckFile, deckFileSmall, premadeDeck)); + } + } #ifdef NETWORK_SUPPORT - // FIXME, this is broken - if(isNetwork) - { - ProxyPlayer* mProxy; - mProxy = NEW ProxyPlayer(mPlayers[playerId], mParent->mpNetwork); - } - } - else - { //Remote player - loadPlayer(playerId, NEW RemotePlayer(mParent->mpNetwork)); -#endif //NETWORK_SUPPORT - } + else if(playerType == PLAYER_TYPE_REMOTE) + { + //Player 0 is the human player + ProxyPlayer* mProxy; + mProxy = NEW ProxyPlayer(players[0], JNetwork::GetInstance()); + + //Player 1 is the remote player + loadPlayer(playerId, NEW RemotePlayer(this, JNetwork::GetInstance())); } +#endif //NETWORK_SUPPORT else { //AI Player, chooses deck AIPlayerFactory playerCreator; @@ -1928,3 +1948,91 @@ void GameObserver::loadPlayer(int playerId, PlayerType playerType, int decknb, b } } +#ifdef NETWORK_SUPPORT +NetworkGameObserver::NetworkGameObserver(JNetwork* pNetwork, WResourceManager* output, JGE* input) + : GameObserver(output, input), mpNetworkSession(pNetwork), mSynchronized(false) +{ + mpNetworkSession->registerCommand("loadPlayer", this, loadPlayer, ignoreResponse); + mpNetworkSession->registerCommand("synchronize", this, synchronize, ignoreResponse); + mpNetworkSession->registerCommand("sendAction", this, sendAction, ignoreResponse); +} + +NetworkGameObserver::~NetworkGameObserver() +{ +} + +void NetworkGameObserver::Update(float dt) +{ + mpNetworkSession->Update(); + ::GameObserver::Update(dt); +} + +void NetworkGameObserver::loadPlayer(int playerId, PlayerType playerType, int decknb, bool premadeDeck) +{ + GameObserver::loadPlayer(playerId, playerType, decknb, premadeDeck); + Player* player = getPlayer(playerId); + stringstream out; + out << *player; + mpNetworkSession->sendCommand("loadPlayer", out.str()); +} + +void NetworkGameObserver::loadPlayer(void*pxThis, stringstream& in, stringstream& out) +{ + NetworkGameObserver* pThis = (NetworkGameObserver*)pxThis; + Player* pPlayer = 0; + string s; + + while(std::getline(in, s)) + { + if (s.find("mode=") == 0) + { + pPlayer = pThis->createPlayer(s.substr(5) + #ifdef TESTSUITE + , 0 + #endif //TESTSUITE + ); + } + + if(pPlayer && (!pPlayer->parseLine(s))) + { + break; + } + } +} + +void NetworkGameObserver::synchronize() +{ + if(!mSynchronized && mpNetworkSession->isServer()) + { + stringstream out; + out << *this; + mpNetworkSession->sendCommand("synchronize", out.str()); + mSynchronized = true; + } +} + +void NetworkGameObserver::synchronize(void*pxThis, stringstream& in, stringstream& out) +{ + NetworkGameObserver* pThis = (NetworkGameObserver*)pxThis; + pThis->load(in.str()); + // now, we need to swap players as player1 for host is player 2 for guest + std::swap(pThis->players[0], pThis->players[1]); +} + +void NetworkGameObserver::sendAction(void*pxThis, stringstream& in, stringstream& out) +{ + NetworkGameObserver* pThis = (NetworkGameObserver*)pxThis; + + pThis->mForwardAction = false; + pThis->processAction(in.str(), true); + pThis->mForwardAction = true; +} + +void NetworkGameObserver::logAction(const string& s) +{ + GameObserver::logAction(s); + if(mForwardAction) + mpNetworkSession->sendCommand("sendAction", s); +} + +#endif \ No newline at end of file diff --git a/projects/mtg/src/GameStateDuel.cpp b/projects/mtg/src/GameStateDuel.cpp index a222663a6..34563e8ce 100644 --- a/projects/mtg/src/GameStateDuel.cpp +++ b/projects/mtg/src/GameStateDuel.cpp @@ -120,7 +120,17 @@ void GameStateDuel::Start() renderer->EnableVSync(true); OpponentsDeckid = 0; - game = NEW GameObserver(WResourceManager::Instance(), JGE::GetInstance()); + +#ifdef NETWORK_SUPPORT + if(!mParent->mpNetwork) { +#endif //NETWORK_SUPPORT + game = NEW GameObserver(WResourceManager::Instance(), JGE::GetInstance()); +#ifdef NETWORK_SUPPORT + } else { + game = NEW NetworkGameObserver(mParent->mpNetwork, WResourceManager::Instance(), JGE::GetInstance()); + } +#endif //NETWORK_SUPPORT + #ifdef TESTSUITE SAFE_DELETE(testSuite); @@ -298,7 +308,7 @@ void GameStateDuel::ThreadProc(void* inParam) observer.startGame(instance->mParent->gameType, instance->mParent->rules); while(!observer.didWin()) { - if(observer.turn == oldTurn && observer.currentGamePhase == oldPhase) + if(observer.turn == oldTurn && observer.getCurrentGamePhase() == oldPhase) { stagnationCounter++; } @@ -453,6 +463,10 @@ void GameStateDuel::Update(float dt) // That's mostly because of a legacy bug, where we use the update sequence for some things when we should use events (such as phase changes) mParent->rules->postUpdateInit(game); +#ifdef NETWORK_SUPPORT + if(mParent->mpNetwork) ((NetworkGameObserver*)game)->synchronize(); +#endif + if (game->didWin()) { if (game->players[1]->playMode != Player::MODE_TEST_SUITE) credits->compute(game, mParent); @@ -487,7 +501,10 @@ void GameStateDuel::Update(float dt) #ifdef QT_CONFIG thread_count = QThread::idealThreadCount(); - #endif + + #else + thread_count = 4; + #endif for(size_t i = 0; i < (thread_count); i++) mWorkerThread.push_back(boost::thread(ThreadProc, this)); } @@ -508,7 +525,7 @@ void GameStateDuel::Update(float dt) int cardsinhand = game->currentPlayer->game->hand->nb_cards; //almosthumane - mulligan - if ((game->turn < 1) && (cardsinhand != 0) && game->currentGamePhase == MTG_PHASE_FIRSTMAIN + if ((game->turn < 1) && (cardsinhand != 0) && game->getCurrentGamePhase() == MTG_PHASE_FIRSTMAIN && game->currentPlayer->game->inPlay->nb_cards == 0 && game->currentPlayer->game->graveyard->nb_cards == 0 && game->currentPlayer->game->exile->nb_cards == 0 && game->currentlyActing() == (Player*)game->currentPlayer) //1st Play Check //IF there was no play at the moment automatically mulligan @@ -517,7 +534,7 @@ void GameStateDuel::Update(float dt) } //END almosthumane - mulligan menu->Add(MENUITEM_MAIN_MENU, "Back to main menu"); -#ifdef DEBUG +#ifdef TESTSUITE menu->Add(MENUITEM_UNDO, "Undo"); #endif #ifdef TESTSUITE @@ -531,23 +548,23 @@ void GameStateDuel::Update(float dt) #ifdef NETWORK_SUPPORT case DUEL_STATE_OPPONENT_WAIT: { - if(mPlayers[1] && mPlayers[1]->game) - { // Player loaded - menu->Close(); - SAFE_DELETE(menu); - setGamePhase(DUEL_STATE_PLAY); - } else if(menu == NULL) - { - loadPlayer(1, 42/* 0 not good*/, false, true); - menu = NEW SimpleMenu(DUEL_STATE_OPPONENT_WAIT, this, Fonts::MENU_FONT, 150, 60); - if (menu) - { - menu->Add(MENUITEM_MAIN_MENU, "Back to main menu"); - } - } else - { - menu->Update(dt); - } + if(game->players.size() > 1) + { // Player loaded + menu->Close(); + SAFE_DELETE(menu); + setGamePhase(DUEL_STATE_PLAY); + } else if(menu == NULL) + { + menu = NEW SimpleMenu(JGE::GetInstance(), DUEL_STATE_OPPONENT_WAIT, this, Fonts::MENU_FONT, 150, 60); + if (menu) + { + menu->Add(MENUITEM_MAIN_MENU, "Back to main menu"); + } + } else + { + menu->Update(dt); + game->Update(dt); + } } break; #endif //NETWORK_SUPPORT @@ -732,10 +749,13 @@ void GameStateDuel::Render() // display the player deck names in their respective corners string playerDeckName = game->players[0]->deckName; - string opponentDeckName = game->players[1]->deckName; float playerDeckNamePixelLength = mFont->GetStringWidth(playerDeckName.c_str()); - mFont->DrawString( opponentDeckName, 0, 50); mFont->DrawString( playerDeckName, SCREEN_WIDTH_F - playerDeckNamePixelLength, SCREEN_HEIGHT_F - 50); + if(game->players.size()>1) + { + string opponentDeckName = game->players[1]->deckName; + mFont->DrawString( opponentDeckName, 0, 50); + } } } } diff --git a/projects/mtg/src/GameStateMenu.cpp b/projects/mtg/src/GameStateMenu.cpp index 0937650d5..31b41cf7e 100644 --- a/projects/mtg/src/GameStateMenu.cpp +++ b/projects/mtg/src/GameStateMenu.cpp @@ -558,15 +558,18 @@ void GameStateMenu::Update(float dt) } #ifdef NETWORK_SUPPORT case MENU_STATE_NETWORK_DEFINE: - currentState = MENU_STATE_MAJOR_SUBMENU; - subMenuController = NEW SimpleMenu(MENU_FIRST_DUEL_SUBMENU, this, Fonts::MENU_FONT, 150, 60); - if (subMenuController) + if(MENU_STATE_MINOR_NONE == (currentState & MENU_STATE_MINOR)) { - subMenuController->Add(SUBMENUITEM_HOST_GAME, "Host a game"); - subMenuController->Add(SUBMENUITEM_JOIN_GAME, "Join a game"); - subMenuController->Add(SUBMENUITEM_CANCEL, "Cancel"); - } - break; + currentState = MENU_STATE_MAJOR_SUBMENU; + subMenuController = NEW SimpleMenu(JGE::GetInstance(), MENU_FIRST_DUEL_SUBMENU, this, Fonts::MENU_FONT, 150, 60); + if (subMenuController) + { + subMenuController->Add(SUBMENUITEM_HOST_GAME, "Host a game"); + subMenuController->Add(SUBMENUITEM_JOIN_GAME, "Join a game"); + subMenuController->Add(SUBMENUITEM_CANCEL, "Cancel"); + } + } + break; case MENU_STATE_NETWORK_WAIT: if(MENU_STATE_MINOR_NONE == (currentState & MENU_STATE_MINOR)) { @@ -578,7 +581,7 @@ void GameStateMenu::Update(float dt) else if(!subMenuController) { // currentState = MENU_STATE_MAJOR_SUBMENU; - subMenuController = NEW SimpleMenu(MENU_FIRST_DUEL_SUBMENU, this, Fonts::MENU_FONT, 150, 60); + subMenuController = NEW SimpleMenu(JGE::GetInstance(), MENU_FIRST_DUEL_SUBMENU, this, Fonts::MENU_FONT, 150, 60); if (subMenuController) { subMenuController->Add(SUBMENUITEM_CANCEL, "Cancel connection"); @@ -840,7 +843,7 @@ void GameStateMenu::ButtonPressed(int controllerId, int controlId) { if(!mParent->mpNetwork) { - mParent->mpNetwork = new JNetwork(); + mParent->mpNetwork = JNetwork::GetInstance(); } mParent->mpNetwork->connect(); subMenuController->Close(); @@ -851,16 +854,17 @@ void GameStateMenu::ButtonPressed(int controllerId, int controlId) { if(!mParent->mpNetwork) { - mParent->mpNetwork = new JNetwork(); + mParent->mpNetwork = JNetwork::GetInstance(); } // FIXME needs to be able to specify the server ip mParent->mpNetwork->connect("127.0.0.1"); // we let the server choose the game mode mParent->gameType = GAME_TYPE_SLAVE; + // just to select one, the HOST is in control here. + mParent->rules = Rules::getRulesByFilename("classic.txt"); hasChosenGameType = true; subMenuController->Close(); -// currentState = MENU_STATE_MAJOR_DUEL | MENU_STATE_MINOR_SUBMENU_CLOSING; - currentState = MENU_STATE_NETWORK_WAIT; + currentState = MENU_STATE_NETWORK_WAIT | MENU_STATE_MINOR_SUBMENU_CLOSING; break; } #endif //NETWORK_SUPPORT @@ -878,10 +882,8 @@ void GameStateMenu::ButtonPressed(int controllerId, int controlId) subMenuController->Close(); } #ifdef NETWORK_SUPPORT - if(mParent->mpNetwork) - { - SAFE_DELETE(mParent->mpNetwork); - } + JNetwork::Destroy(); + mParent->mpNetwork=0; #endif //NETWORK_SUPPORT currentState = MENU_STATE_MAJOR_MAINMENU | MENU_STATE_MINOR_SUBMENU_CLOSING; break; diff --git a/projects/mtg/src/MTGCardInstance.cpp b/projects/mtg/src/MTGCardInstance.cpp index 1e559236d..b7d795483 100644 --- a/projects/mtg/src/MTGCardInstance.cpp +++ b/projects/mtg/src/MTGCardInstance.cpp @@ -824,7 +824,7 @@ int MTGCardInstance::removeBlocker(MTGCardInstance * blocker) // Blockers can be removed "manually" (by the blocking player) at the Blockers step, // Or "automatically" in the damage phase, when they die and regenerate (see http://code.google.com/p/wagic/issues/detail?id=563 ) // In the second case, we still want the card to be marked as "blocked" this turn - if (!blockers.size() && observer->currentGamePhase == MTG_PHASE_COMBATBLOCKERS) + if (!blockers.size() && observer->getCurrentGamePhase() == MTG_PHASE_COMBATBLOCKERS) { blocked = false; } diff --git a/projects/mtg/src/MTGRules.cpp b/projects/mtg/src/MTGRules.cpp index 9d4a75d6f..c9f35f83b 100644 --- a/projects/mtg/src/MTGRules.cpp +++ b/projects/mtg/src/MTGRules.cpp @@ -288,7 +288,7 @@ int MTGPutInPlayRule::isReactingToClick(MTGCardInstance * card, ManaCost * mana) if (!player->game->hand->hasCard(card)) return 0; if ((game->turn < 1) && (cardsinhand != 0) && (card->basicAbilities[(int)Constants::LEYLINE]) - && game->currentGamePhase == MTG_PHASE_FIRSTMAIN + && game->getCurrentGamePhase() == MTG_PHASE_FIRSTMAIN && game->players[0]->game->graveyard->nb_cards == 0 && game->players[0]->game->exile->nb_cards == 0 ) @@ -311,7 +311,7 @@ int MTGPutInPlayRule::isReactingToClick(MTGCardInstance * card, ManaCost * mana) if (game->currentActionPlayer->game->playRestrictions->canPutIntoZone(card, game->currentActionPlayer->game->inPlay) == PlayRestriction::CANT_PLAY) return 0; if (player == currentPlayer - && (game->currentGamePhase == MTG_PHASE_FIRSTMAIN || game->currentGamePhase == MTG_PHASE_SECONDMAIN) + && (game->getCurrentGamePhase() == MTG_PHASE_FIRSTMAIN || game->getCurrentGamePhase() == MTG_PHASE_SECONDMAIN) ) { return 1; @@ -319,8 +319,8 @@ int MTGPutInPlayRule::isReactingToClick(MTGCardInstance * card, ManaCost * mana) } else if ((card->hasType(Subtypes::TYPE_INSTANT)) || card->has(Constants::FLASH) || (player == currentPlayer && !game->isInterrupting - && (game->currentGamePhase == MTG_PHASE_FIRSTMAIN - || game->currentGamePhase == MTG_PHASE_SECONDMAIN)) + && (game->getCurrentGamePhase() == MTG_PHASE_FIRSTMAIN + || game->getCurrentGamePhase() == MTG_PHASE_SECONDMAIN)) ) { @@ -644,15 +644,15 @@ int MTGAlternativeCostRule::isReactingToClick(MTGCardInstance * card, ManaCost * if (game->currentActionPlayer->game->playRestrictions->canPutIntoZone(card, game->currentActionPlayer->game->inPlay) == PlayRestriction::CANT_PLAY) return 0; if (player == currentPlayer - && (game->currentGamePhase == MTG_PHASE_FIRSTMAIN - || game->currentGamePhase == MTG_PHASE_SECONDMAIN) + && (game->getCurrentGamePhase() == MTG_PHASE_FIRSTMAIN + || game->getCurrentGamePhase() == MTG_PHASE_SECONDMAIN) ) return 1; } else if ((card->hasType(Subtypes::TYPE_INSTANT)) || card->has(Constants::FLASH) || (player == currentPlayer && !game->isInterrupting - && (game->currentGamePhase == MTG_PHASE_FIRSTMAIN - || game->currentGamePhase == MTG_PHASE_SECONDMAIN)) + && (game->getCurrentGamePhase() == MTG_PHASE_FIRSTMAIN + || game->getCurrentGamePhase() == MTG_PHASE_SECONDMAIN)) ) { if (game->currentActionPlayer->game->playRestrictions->canPutIntoZone(card, game->currentActionPlayer->game->stack) == PlayRestriction::CANT_PLAY) @@ -1039,8 +1039,8 @@ int MTGMorphCostRule::isReactingToClick(MTGCardInstance * card, ManaCost * mana) //note lands can morph too, this is different from other cost types. if ((card->hasType(Subtypes::TYPE_INSTANT)) || card->has(Constants::FLASH) || (player == currentPlayer && !game->isInterrupting - && (game->currentGamePhase == MTG_PHASE_FIRSTMAIN - || game->currentGamePhase == MTG_PHASE_SECONDMAIN)) + && (game->getCurrentGamePhase() == MTG_PHASE_FIRSTMAIN + || game->getCurrentGamePhase() == MTG_PHASE_SECONDMAIN)) ) { if (game->currentActionPlayer->game->playRestrictions->canPutIntoZone(card, game->currentActionPlayer->game->stack) == PlayRestriction::CANT_PLAY) @@ -1640,8 +1640,8 @@ int MTGMomirRule::isReactingToClick(MTGCardInstance * card, ManaCost * mana) if (!player->game->hand->hasCard(card)) return 0; if (player == currentPlayer && !game->isInterrupting - && (game->currentGamePhase == MTG_PHASE_FIRSTMAIN - || game->currentGamePhase == MTG_PHASE_SECONDMAIN) + && (game->getCurrentGamePhase() == MTG_PHASE_FIRSTMAIN + || game->getCurrentGamePhase() == MTG_PHASE_SECONDMAIN) ) { return 1; diff --git a/projects/mtg/src/NetworkPlayer.cpp b/projects/mtg/src/NetworkPlayer.cpp index ade7a7e7d..146d1efa7 100644 --- a/projects/mtg/src/NetworkPlayer.cpp +++ b/projects/mtg/src/NetworkPlayer.cpp @@ -1,3 +1,4 @@ +#include "PrecompiledHeader.h" #include "NetworkPlayer.h" #include @@ -10,14 +11,14 @@ void RegisterNetworkPlayers() } -RemotePlayer::RemotePlayer(JNetwork* pxNetwork) - : Player("remote", "", NULL), mpNetwork(pxNetwork) +RemotePlayer::RemotePlayer(GameObserver* observer, JNetwork* pxNetwork) + : Player(observer, "remote", "", NULL), mpNetwork(pxNetwork) { mInstance = this; mpNetwork->sendCommand("GetPlayer"); } -void RemotePlayer::Deserialize(istream& in, ostream& out) +void RemotePlayer::Deserialize(void*, stringstream& in, stringstream& out) { // istringstream ss(mInstance->mpNetwork->receiveString()); in >> *mInstance; @@ -28,14 +29,14 @@ ProxyPlayer::ProxyPlayer(Player* pxPlayer, JNetwork* pxNetwork) : mpPlayer(pxPlayer), mpNetwork(pxNetwork) { mInstance = this; - JNetwork::registerCommand("GetPlayer", ProxyPlayer::Serialize, RemotePlayer::Deserialize); + JNetwork::registerCommand("GetPlayer", this, ProxyPlayer::Serialize, RemotePlayer::Deserialize); // ostringstream ss; // ss << "Player : " << *mpPlayer; // mpNetwork->send(ss.str()); } -void ProxyPlayer::Serialize(istream& in, ostream& out) +void ProxyPlayer::Serialize(void*, stringstream& in, stringstream& out) { out << *(mInstance->mpPlayer); } diff --git a/projects/mtg/src/Player.cpp b/projects/mtg/src/Player.cpp index 6d510bf06..b6504664e 100644 --- a/projects/mtg/src/Player.cpp +++ b/projects/mtg/src/Player.cpp @@ -243,6 +243,11 @@ bool Player::parseLine(const string& s) ManaCost::parseManaCost(s.substr(limiter + 1), manaPool); return true; } + else if (areaS.compare("mode") == 0) + { + this->playMode = (Player::Mode)atoi(s.substr(limiter + 1).c_str()); + return true; + } else if (areaS.compare("avatar") == 0) { mAvatarName = s.substr(limiter + 1); @@ -326,9 +331,12 @@ ostream& operator<<(ostream& out, const Player& p) { out << "mode=" << p.playMode << endl; out << *(Damageable*)&p; - string manapoolstring = p.manaPool->toString(); - if(manapoolstring != "") - out << "manapool=" << manapoolstring << endl; + if(p.manaPool) + { + string manapoolstring = p.manaPool->toString(); + if(manapoolstring != "") + out << "manapool=" << manapoolstring << endl; + } if(p.mAvatarName != "") out << "avatar=" << p.mAvatarName << endl; if(p.phaseRing != "") @@ -348,6 +356,22 @@ ostream& operator<<(ostream& out, const Player& p) return out; } +istream& operator>>(istream& in, Player& p) +{ + string s; + + while(std::getline(in, s)) + { + if(!p.parseLine(s)) + { + break; + } + } + + return in; +} + + // Method comparing "this" to "aPlayer", each in their own gameObserver bool Player::operator<(Player& aPlayer) { diff --git a/projects/mtg/src/Rules.cpp b/projects/mtg/src/Rules.cpp index 1a7488d70..b22317060 100644 --- a/projects/mtg/src/Rules.cpp +++ b/projects/mtg/src/Rules.cpp @@ -159,9 +159,9 @@ void Rules::addExtraRules(GameObserver* g) if (p->playMode != Player::MODE_TEST_SUITE && g->mRules->gamemode != GAME_TYPE_MOMIR && g->mRules->gamemode != GAME_TYPE_RANDOM1 && g->mRules->gamemode != GAME_TYPE_RANDOM2 && g->mRules->gamemode != GAME_TYPE_STORY && - g->mRules->gamemode != GAME_TYPE_DEMO && (!g->players[0] == PLAYER_TYPE_CPU && !g->players[1] == PLAYER_TYPE_CPU) + g->mRules->gamemode != GAME_TYPE_DEMO && (!g->players[0]->playMode == PLAYER_TYPE_CPU && !g->players[1]->playMode == PLAYER_TYPE_CPU) #ifdef NETWORK_SUPPORT - && !g->players[1] == PLAYER_TYPE_REMOTE + && !(g->players[1]->playMode == PLAYER_TYPE_REMOTE) && !(g->players[1]->playMode == PLAYER_TYPE_HUMAN) #endif //NETWORK_SUPPORT )//keep this out of momir and other game modes. { @@ -377,7 +377,7 @@ void Rules::initGame(GameObserver *g) g->currentPlayerId = initState.player; g->phaseRing->goToPhase(0, g->currentPlayer, false); g->phaseRing->goToPhase(initState.phase, g->currentPlayer); - g->currentGamePhase = initState.phase; + g->setCurrentGamePhase(initState.phase); for (int i = 0; i < 2; i++) { diff --git a/projects/mtg/src/TestSuiteAI.cpp b/projects/mtg/src/TestSuiteAI.cpp index eaf5eceb1..cd89949de 100644 --- a/projects/mtg/src/TestSuiteAI.cpp +++ b/projects/mtg/src/TestSuiteAI.cpp @@ -160,7 +160,7 @@ int TestSuiteAI::Act(float dt) phaseToGo = i; } } - if(observer->currentGamePhase != phaseToGo) + if(observer->getCurrentGamePhase() != phaseToGo) suite->currentAction--; else { @@ -340,11 +340,11 @@ void TestSuiteGame::assertGame() int error = 0; bool wasAI = false; - if (observer->currentGamePhase != endState.phase) + if (observer->getCurrentGamePhase() != endState.phase) { sprintf(result, "==phase problem. Expected [ %s ](%i), got [ %s ](%i)==
", Constants::MTGPhaseNames[endState.phase],endState.phase, - Constants::MTGPhaseNames[observer->currentGamePhase], observer->currentGamePhase); + Constants::MTGPhaseNames[observer->getCurrentGamePhase()], observer->getCurrentGamePhase()); Log(result); error++; } @@ -560,6 +560,8 @@ int TestSuite::loadNext() thread_count = QThread::idealThreadCount(); #elif defined(IOS) thread_count = 6; +#else + thread_count = 4; #endif for(size_t i = 0; i < (thread_count-1); i++) mWorkerThread.push_back(new boost::thread(ThreadProc, this)); @@ -819,7 +821,7 @@ void TestSuiteGame::initGame() { DebugTrace("TESTSUITE Init Game"); observer->phaseRing->goToPhase(initState.phase, observer->players[0], false); - observer->currentGamePhase = initState.phase; + observer->setCurrentGamePhase(initState.phase); observer->resetStartupGame(); diff --git a/projects/mtg/template.vcxproj b/projects/mtg/template.vcxproj index b06862787..7109ebd09 100644 --- a/projects/mtg/template.vcxproj +++ b/projects/mtg/template.vcxproj @@ -158,7 +158,6 @@ Disabled ./include;$(MTGEXTRAS);../../JGE/include;../../JGE/Dependencies/include;../../Boost;../../JGE/Dependencies/SDL/include;../../JGE/src/zipFS;%(AdditionalIncludeDirectories) SDL_CONFIG;WIN32;_DEBUG;_WINDOWS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) - true EnableFastChecks MultiThreadedDebugDLL .\Debug/template.pch @@ -171,7 +170,7 @@ false Use PrecompiledHeader.h - false + true true @@ -375,7 +374,7 @@ - + @@ -390,6 +389,7 @@ + @@ -499,7 +499,7 @@ - + @@ -514,6 +514,7 @@ + @@ -571,4 +572,4 @@ - + \ No newline at end of file diff --git a/projects/mtg/template.vcxproj.filters b/projects/mtg/template.vcxproj.filters index d4e1ebe09..32cd0ca8b 100644 --- a/projects/mtg/template.vcxproj.filters +++ b/projects/mtg/template.vcxproj.filters @@ -322,12 +322,15 @@ src - - src - - - src - + + src + + + src + + + src + @@ -681,6 +684,9 @@ inc + + inc + @@ -704,4 +710,4 @@ res - + \ No newline at end of file