diff --git a/source/glest_game/game/game.cpp b/source/glest_game/game/game.cpp index a17faa34b..04da39910 100644 --- a/source/glest_game/game/game.cpp +++ b/source/glest_game/game/game.cpp @@ -118,6 +118,8 @@ void Game::load(){ originalDisplayMsgCallback = NetworkInterface::getDisplayMessageFunction(); NetworkInterface::setDisplayMessageFunction(ErrorDisplayMessage); + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] gameSettings = [%s]\n",__FILE__,__FUNCTION__,__LINE__,this->gameSettings.toString().c_str()); + Logger &logger= Logger::getInstance(); string mapName= gameSettings.getMap(); string tilesetName= gameSettings.getTileset(); diff --git a/source/glest_game/game/game_settings.h b/source/glest_game/game/game_settings.h index 084cabec5..35f03368a 100644 --- a/source/glest_game/game/game_settings.h +++ b/source/glest_game/game/game_settings.h @@ -13,6 +13,9 @@ #define _GLEST_GAME_GAMESETTINGS_H_ #include "game_constants.h" +#include "conversion.h" + +using namespace Shared::Util; namespace Glest{ namespace Game{ @@ -115,6 +118,38 @@ public: void setFogOfWar(bool fogOfWar) {this->fogOfWar = fogOfWar;} void setEnableObserverModeAtEndGame(bool value) {this->enableObserverModeAtEndGame = value;} void setEnableServerControlledAI(bool value) {this->enableServerControlledAI = value;} + + string toString() const { + string result = ""; + + result += "description = " + description + "\n"; + result += "map = " + map + "\n"; + result += "tileset = " + tileset + "\n"; + result += "tech = " + tech + "\n"; + result += "scenario = " + scenario + "\n"; + result += "scenarioDir = " + scenarioDir + "\n"; + + for(int idx =0; idx < GameConstants::maxPlayers; idx++) { + result += "player index = " + intToStr(idx) + "\n"; + result += "factionTypeName = " + factionTypeNames[idx] + "\n"; + result += "networkPlayerName = " + networkPlayerNames[idx] + "\n"; + + result += "factionControl = " + intToStr(factionControls[idx]) + "\n"; + result += "team = " + intToStr(teams[idx]) + "\n"; + result += "startLocationIndex = " + intToStr(startLocationIndex[idx]) + "\n"; + } + + result += "thisFactionIndex = " + intToStr(thisFactionIndex) + "\n"; + result += "factionCount = " + intToStr(factionCount) + "\n"; + result += "defaultUnits = " + intToStr(defaultUnits) + "\n"; + result += "defaultResources = " + intToStr(defaultResources) + "\n"; + result += "defaultVictoryConditions = " + intToStr(defaultVictoryConditions) + "\n"; + result += "fogOfWar = " + intToStr(fogOfWar) + "\n"; + result += "enableObserverModeAtEndGame = " + intToStr(enableObserverModeAtEndGame) + "\n"; + result += "enableServerControlledAI = " + intToStr(enableServerControlledAI) + "\n"; + + return result; + } }; }}//end namespace diff --git a/source/glest_game/menu/menu_state_connected_game.cpp b/source/glest_game/menu/menu_state_connected_game.cpp index 44b1befa6..ae813a758 100644 --- a/source/glest_game/menu/menu_state_connected_game.cpp +++ b/source/glest_game/menu/menu_state_connected_game.cpp @@ -617,7 +617,7 @@ bool MenuStateConnectedGame::loadFactions(const GameSettings *gameSettings, bool for(int idx = 0; idx < techPaths.size(); idx++) { string &techPath = techPaths[idx]; - findAll(techPath + "/" + gameSettings->getTech() + "xx/factions/*.", results, false, false); + findAll(techPath + "/" + gameSettings->getTech() + "/factions/*.", results, false, false); if(results.size() > 0) { break; } diff --git a/source/glest_game/network/connection_slot.cpp b/source/glest_game/network/connection_slot.cpp index c8f990800..ed0b59d66 100644 --- a/source/glest_game/network/connection_slot.cpp +++ b/source/glest_game/network/connection_slot.cpp @@ -553,4 +553,10 @@ bool ConnectionSlot::updateCompleted() { return (waitingForThread == false); } +void ConnectionSlot::sendMessage(const NetworkMessage* networkMessage) { + MutexSafeWrapper safeMutex(&socketSynchAccessor); + NetworkInterface::sendMessage(networkMessage); + safeMutex.ReleaseLock(); +} + }}//end namespace diff --git a/source/glest_game/network/connection_slot.h b/source/glest_game/network/connection_slot.h index 73d72fbca..df9869e6b 100644 --- a/source/glest_game/network/connection_slot.h +++ b/source/glest_game/network/connection_slot.h @@ -34,8 +34,17 @@ class ConnectionSlot; class ConnectionSlotEvent { public: + ConnectionSlotEvent() { + triggerId = -1; + connectionSlot = NULL; + networkMessage = NULL; + socketTriggered = false; + eventCompleted = false; + } + int64 triggerId; ConnectionSlot* connectionSlot; + const NetworkMessage* networkMessage; bool socketTriggered; bool eventCompleted; }; @@ -120,10 +129,13 @@ public: void signalUpdate(ConnectionSlotEvent *event); bool updateCompleted(); + virtual void sendMessage(const NetworkMessage* networkMessage); + protected: Mutex * getServerSynchAccessor(); std::vector threadErrorList; + Mutex socketSynchAccessor; }; }}//end namespace diff --git a/source/glest_game/network/network_interface.h b/source/glest_game/network/network_interface.h index a9625b01b..c78ac3d7b 100644 --- a/source/glest_game/network/network_interface.h +++ b/source/glest_game/network/network_interface.h @@ -74,7 +74,7 @@ public: string getIp() const {return getSocket()->getIp();} string getHostName() const {return getSocket()->getHostName();} - void sendMessage(const NetworkMessage* networkMessage); + virtual void sendMessage(const NetworkMessage* networkMessage); NetworkMessageType getNextMessageType(bool checkHasDataFirst = false); bool receiveMessage(NetworkMessage* networkMessage); diff --git a/source/glest_game/network/network_message.cpp b/source/glest_game/network/network_message.cpp index 86d0b4164..b557afd59 100644 --- a/source/glest_game/network/network_message.cpp +++ b/source/glest_game/network/network_message.cpp @@ -184,6 +184,8 @@ NetworkMessageLaunch::NetworkMessageLaunch(const GameSettings *gameSettings,int8 data.defaultUnits= gameSettings->getDefaultUnits(); data.defaultVictoryConditions= gameSettings->getDefaultVictoryConditions(); data.fogOfWar = gameSettings->getFogOfWar(); + data.enableObserverModeAtEndGame = gameSettings->getEnableObserverModeAtEndGame(); + data.enableServerControlledAI = gameSettings->getEnableServerControlledAI(); for(int i= 0; igetFactionTypeName(i); @@ -206,6 +208,10 @@ void NetworkMessageLaunch::buildGameSettings(GameSettings *gameSettings) const{ gameSettings->setDefaultVictoryConditions(data.defaultVictoryConditions); gameSettings->setFogOfWar(data.fogOfWar); + gameSettings->setFogOfWar(data.fogOfWar); + gameSettings->setEnableObserverModeAtEndGame(data.enableObserverModeAtEndGame); + gameSettings->setEnableServerControlledAI(data.enableServerControlledAI); + for(int i= 0; isetFactionTypeName(i, data.factionTypeNames[i].getString()); gameSettings->setNetworkPlayerName(i,data.networkPlayerNames[i].getString()); diff --git a/source/glest_game/network/network_message.h b/source/glest_game/network/network_message.h index 0bcd387c7..0ff19f3f9 100644 --- a/source/glest_game/network/network_message.h +++ b/source/glest_game/network/network_message.h @@ -165,6 +165,8 @@ private: int8 defaultUnits; int8 defaultVictoryConditions; int8 fogOfWar; + int8 enableObserverModeAtEndGame; + int8 enableServerControlledAI; }; private: diff --git a/source/glest_game/network/server_interface.cpp b/source/glest_game/network/server_interface.cpp index 605e39722..65dc03b03 100644 --- a/source/glest_game/network/server_interface.cpp +++ b/source/glest_game/network/server_interface.cpp @@ -34,6 +34,9 @@ namespace Glest{ namespace Game{ // class ServerInterface // ===================================================== +// Experimental threading of broadcasts to clients +bool enabledThreadedClientCommandBroadcast = true; + ServerInterface::ServerInterface(){ gameHasBeenInitiated = false; gameSettingsUpdateCount = 0; @@ -144,7 +147,15 @@ void ServerInterface::slotUpdateTask(ConnectionSlotEvent *event) { if(event != NULL) { SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); - updateSlot(event); + + if(event->networkMessage != NULL) { + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] before sendMessage\n",__FILE__,__FUNCTION__); + event->connectionSlot->sendMessage(event->networkMessage); + } + else { + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + updateSlot(event); + } } SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); } @@ -223,6 +234,7 @@ void ServerInterface::update() { bool socketTriggered = (connectionSlot != NULL && connectionSlot->getSocket() != NULL ? socketTriggeredList[connectionSlot->getSocket()->getSocketId()] : false); ConnectionSlotEvent &event = eventList[i]; + event.networkMessage = NULL; event.connectionSlot = connectionSlot; event.socketTriggered = socketTriggered; event.triggerId = i; @@ -682,32 +694,100 @@ void ServerInterface::broadcastGameSetup(const GameSettings* gameSettings) { SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__); } - void ServerInterface::broadcastMessage(const NetworkMessage* networkMessage, int excludeSlot){ //SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__); try { - for(int i= 0; iisConnected()) { + if(enabledThreadedClientCommandBroadcast == true) { + // Step #1 signal worker threads to send this broadcast to each client + std::map eventList; + for(int i= 0; isendMessage(networkMessage); + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__); + + ConnectionSlotEvent &event = eventList[i]; + event.networkMessage = networkMessage; + event.connectionSlot = connectionSlot; + event.socketTriggered = true; + event.triggerId = i; + + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__); + + // Step #1 tell all connection slot worker threads to receive socket data + if(i != excludeSlot && connectionSlot != NULL) { + if(connectionSlot->isConnected()) { + connectionSlot->signalUpdate(&event); + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__); + } + else if(gameHasBeenInitiated == true) { + + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] #1 before removeSlot for slot# %d\n",__FILE__,__FUNCTION__,i); + removeSlot(i); + } } - else if(gameHasBeenInitiated == true) { - - SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] #1 before removeSlot for slot# %d\n",__FILE__,__FUNCTION__,i); + else if(i == excludeSlot && gameHasBeenInitiated == true && + connectionSlot != NULL && connectionSlot->isConnected() == false) { + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] #2 before removeSlot for slot# %d\n",__FILE__,__FUNCTION__,i); removeSlot(i); } } - else if(i == excludeSlot && gameHasBeenInitiated == true && - connectionSlot != NULL && connectionSlot->isConnected() == false) { - SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] #2 before removeSlot for slot# %d\n",__FILE__,__FUNCTION__,i); - removeSlot(i); + + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + + // Step #2 check all connection slot worker threads for completed status + std::map slotsCompleted; + for(bool threadsDone = false; threadsDone == false;) { + threadsDone = true; + // Examine all threads for completion of delegation + for(int i= 0; i< GameConstants::maxPlayers; ++i) { + ConnectionSlot* connectionSlot = slots[i]; + if(connectionSlot != NULL && slotsCompleted.find(i) == slotsCompleted.end()) { + std::vector errorList = connectionSlot->getThreadErrorList(); + if(errorList.size() > 0) { + for(int iErrIdx = 0; iErrIdx < errorList.size(); ++iErrIdx) { + string &sErr = errorList[iErrIdx]; + DisplayErrorMessage(sErr); + } + connectionSlot->clearThreadErrorList(); + } + + if(connectionSlot->updateCompleted() == false) { + threadsDone = false; + break; + } + else { + slotsCompleted[i] = true; + } + } + } + sleep(0); } - } + } + else { + for(int i= 0; iisConnected()) { + + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] before sendMessage\n",__FILE__,__FUNCTION__); + connectionSlot->sendMessage(networkMessage); + } + else if(gameHasBeenInitiated == true) { + + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] #1 before removeSlot for slot# %d\n",__FILE__,__FUNCTION__,i); + removeSlot(i); + } + } + else if(i == excludeSlot && gameHasBeenInitiated == true && + connectionSlot != NULL && connectionSlot->isConnected() == false) { + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] #2 before removeSlot for slot# %d\n",__FILE__,__FUNCTION__,i); + removeSlot(i); + } + } + } } catch(const exception &ex) { SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] ERROR [%s]\n",__FILE__,__FUNCTION__,__LINE__,ex.what());