diff --git a/source/glest_game/game/commander.cpp b/source/glest_game/game/commander.cpp index 2f433362..d9c77a55 100644 --- a/source/glest_game/game/commander.cpp +++ b/source/glest_game/game/commander.cpp @@ -483,13 +483,17 @@ void Commander::tryDisconnectNetworkPlayer(const Faction* faction, int playerInd pushNetworkCommand(&command); } -void Commander::tryPauseGame(bool clearCaches) const { - NetworkCommand command(this->world,nctPauseResume, 1, (clearCaches == true ? 1 : 0)); +void Commander::tryPauseGame(bool joinNetworkGame, bool clearCaches) const { + NetworkCommand command(this->world,nctPauseResume,1); + command.commandTypeId = (clearCaches == true ? 1 : 0); + command.unitTypeId = (joinNetworkGame == true ? 1 : 0); pushNetworkCommand(&command); } -void Commander::tryResumeGame(bool clearCaches) const { - NetworkCommand command(this->world,nctPauseResume, 0, (clearCaches == true ? 1 : 0)); +void Commander::tryResumeGame(bool joinNetworkGame, bool clearCaches) const { + NetworkCommand command(this->world,nctPauseResume,0); + command.commandTypeId = (clearCaches == true ? 1 : 0); + command.unitTypeId = (joinNetworkGame == true ? 1 : 0); pushNetworkCommand(&command); } @@ -873,12 +877,13 @@ void Commander::giveNetworkCommand(NetworkCommand* networkCommand) const { commandWasHandled = true; - bool pauseGame = networkCommand->getUnitId() != 0; - bool clearCaches = networkCommand->getCommandTypeId(); + bool pauseGame = networkCommand->getUnitId() != 0; + bool clearCaches = networkCommand->getCommandTypeId(); + bool joinNetworkGame = networkCommand->getUnitTypeId(); Game *game = this->world->getGame(); //printf("nctPauseResume pauseGame = %d\n",pauseGame); - game->setPaused(pauseGame,true,clearCaches); + game->setPaused(pauseGame,true,clearCaches,joinNetworkGame); if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] found nctPauseResume\n",__FILE__,__FUNCTION__,__LINE__); } diff --git a/source/glest_game/game/commander.h b/source/glest_game/game/commander.h index 73dbc061..aa46d9e2 100644 --- a/source/glest_game/game/commander.h +++ b/source/glest_game/game/commander.h @@ -114,8 +114,10 @@ public: void trySwitchTeam(const Faction* faction, int teamIndex) const; void trySwitchTeamVote(const Faction* faction, SwitchTeamVote *vote) const; void tryDisconnectNetworkPlayer(const Faction* faction, int playerIndex) const; - void tryPauseGame(bool clearCaches) const; - void tryResumeGame(bool clearCaches) const; + + void tryPauseGame(bool joinNetworkGame, bool clearCaches) const; + void tryResumeGame(bool joinNetworkGame, bool clearCaches) const; + void tryNetworkPlayerDisconnected(int factionIndex) const; Command* buildCommand(const NetworkCommand* networkCommand) const; diff --git a/source/glest_game/game/game.cpp b/source/glest_game/game/game.cpp index 20c11a20..cbd739c9 100644 --- a/source/glest_game/game/game.cpp +++ b/source/glest_game/game/game.cpp @@ -79,6 +79,7 @@ Game::Game() : ProgramState(NULL) { avgRenderFps=0; currentAvgRenderFpsTotal=0; paused=false; + pausedForJoinGame=false; pauseRequestSent=false; resumeRequestSent=false; pauseStateChanged=false; @@ -238,6 +239,7 @@ void Game::resetMembers() { currentAvgRenderFpsTotal=0; tickCount=0; paused= false; + pausedForJoinGame=false; resumeRequestSent=false; pauseRequestSent=false; pauseStateChanged=false; @@ -1519,6 +1521,9 @@ void Game::init(bool initForPreviewOnly) { if(role == nrClient) { ClientInterface *clientInterface = dynamic_cast(networkManager.getClientInterface()); if(clientInterface != NULL && clientInterface->getResumeInGameJoin() == true) { + + //printf("Client sending resume message to server...\n"); + clientInterface->sendResumeGameMessage(); //this->initialResumeSpeedLoops = true; } @@ -2085,7 +2090,7 @@ void Game::update() { } } - if(paused == false || clientNeedsGameSetup == true) { + if(pausedForJoinGame == false || clientNeedsGameSetup == true) { //printf("================= Switching player pausing game\n"); for(int i = 0; i < world.getFactionCount(); ++i) { @@ -2164,15 +2169,17 @@ void Game::update() { } } - if(pauseAndSaveGameForNewClient == true && paused == false && + if(pauseAndSaveGameForNewClient == true && pausedForJoinGame == false && pauseRequestSent == false) { - commander.tryPauseGame(true); + //printf("Pausing game for join in progress game...\n"); + + commander.tryPauseGame(true,true); pauseRequestSent = true; - //return; + return; } } //else if(server->getPauseForInGameConnection() == true && paused == true && - if(paused == true) { + if(pausedForJoinGame == true) { if(pauseStateChanged == true) { pauseStateChanged = false; } @@ -2188,7 +2195,9 @@ void Game::update() { slot->setUnPauseForInGameConnection(false); } } - commander.tryResumeGame(false); + //printf("Resuming game for join in progress game resumeRequestSent: %d...\n",resumeRequestSent); + + commander.tryResumeGame(true,false); resumeRequestSent = true; // server->setAllowInGameConnections(false); @@ -2266,7 +2275,7 @@ void Game::update() { //} // Make the server wait a bit for clients to start. - if(paused == false && resumeRequestSent == true) { + if(pausedForJoinGame == false && resumeRequestSent == true) { resumeRequestSent = false; //sleep(500); } @@ -2562,6 +2571,7 @@ bool Game::switchSetupForSlots(ServerInterface *& serverInterface, if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] caught exception error = [%s]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,e.what()); } } + //printf("AFTER switchSlot returned\n"); } else { try { @@ -3136,14 +3146,14 @@ void Game::tryPauseToggle(bool pauseValue) { if(allowAdminMenuItems) { if(pauseValue == true) { - commander.tryPauseGame(false); + commander.tryPauseGame(false,false); } else { if(isNetworkGame == false) { - setPaused(pauseValue, true); + setPaused(pauseValue, true,false,false); } else { - commander.tryResumeGame(false); + commander.tryResumeGame(false,false); } } } @@ -3437,10 +3447,10 @@ void Game::mouseDownLeft(int x, int y) { if(allowAdminMenuItems) { if(getPaused() == false) { - commander.tryPauseGame(false); + commander.tryPauseGame(false,false); } else { - commander.tryResumeGame(false); + commander.tryResumeGame(false,false); } } } @@ -4347,10 +4357,10 @@ void Game::keyDown(SDL_KeyboardEvent key) { if(allowAdminMenuItems) { if(getPaused() == false) { - commander.tryPauseGame(false); + commander.tryPauseGame(false,false); } else { - commander.tryResumeGame(false); + commander.tryResumeGame(false,false); } } } @@ -5433,17 +5443,51 @@ void Game::decSpeed() { } } -void Game::setPaused(bool value,bool forceAllowPauseStateChange,bool clearCaches) { +void Game::setPaused(bool value,bool forceAllowPauseStateChange,bool clearCaches, bool joinNetworkGame) { bool speedChangesAllowed= !NetworkManager::getInstance().isNetworkGame(); //printf("Toggle pause value = %d, speedChangesAllowed = %d, forceAllowPauseStateChange = %d\n",value,speedChangesAllowed,forceAllowPauseStateChange); if(forceAllowPauseStateChange == true || speedChangesAllowed == true) { //printf("setPaused paused = %d, value = %d\n",paused,value); + // Cannot change pause state while client is joining in progress game + if(pausedForJoinGame == true && joinNetworkGame == false) { + + ServerInterface *server = NetworkManager::getInstance().getServerInterface(); + Lang &lang= Lang::getInstance(); + const vector languageList = this->gameSettings.getUniqueNetworkPlayerLanguages(); + + bool haveClientConnectedButNoReady = false; + for(int i = 0; i < world.getFactionCount(); ++i) { + Faction *faction = world.getFaction(i); + ConnectionSlot *slot = server->getSlot(faction->getStartLocationIndex()); + if(slot != NULL && slot->isConnected() == true && slot->isReady() == false) { + for(unsigned int i = 0; i < languageList.size(); ++i) { + char szMsg[8096]=""; + if(lang.hasString("JoinPlayerToCurrentGameLaunch",languageList[i]) == true) { + snprintf(szMsg,8096,lang.get("JoinPlayerToCurrentGameLaunch",languageList[i]).c_str(), slot->getName().c_str()); + } + else { + snprintf(szMsg,8096,"Player: %s is about to join the game, please wait...",slot->getName().c_str()); + } + bool localEcho = lang.isLanguageLocal(languageList[i]); + server->sendTextMessage(szMsg,-1, localEcho,languageList[i]); + + haveClientConnectedButNoReady = true; + } + } + } + + if(haveClientConnectedButNoReady == true) { + return; + } + } + Lang &lang= Lang::getInstance(); if(value == false) { console.addLine(lang.get("GameResumed")); paused= false; + pausedForJoinGame = false; pauseStateChanged = true; if(clearCaches == true) { @@ -5467,6 +5511,7 @@ void Game::setPaused(bool value,bool forceAllowPauseStateChange,bool clearCaches else { console.addLine(lang.get("GamePaused")); paused= true; + pausedForJoinGame = joinNetworkGame; pauseStateChanged = true; //!!! diff --git a/source/glest_game/game/game.h b/source/glest_game/game/game.h index 312fcd71..faa7daac 100644 --- a/source/glest_game/game/game.h +++ b/source/glest_game/game/game.h @@ -93,6 +93,8 @@ private: bool pauseRequestSent; bool resumeRequestSent; bool pauseStateChanged; + bool pausedForJoinGame; + bool gameOver; bool renderNetworkStatus; bool showFullConsole; @@ -243,7 +245,7 @@ public: Uint64 getTickCount() {return tickCount;} bool getPaused(); - void setPaused(bool value, bool forceAllowPauseStateChange=false,bool clearCaches=false); + void setPaused(bool value, bool forceAllowPauseStateChange,bool clearCaches,bool joinNetworkGame); void tryPauseToggle(bool pause); void setupRenderForVideo(); void saveGame(); diff --git a/source/glest_game/main/main.cpp b/source/glest_game/main/main.cpp index d3c1ea37..efe9b9c8 100644 --- a/source/glest_game/main/main.cpp +++ b/source/glest_game/main/main.cpp @@ -5231,7 +5231,7 @@ static bool MinidumpCallback(const google_breakpad::MinidumpDescriptor& descript if(GlobalStaticFlags::getIsNonGraphicalModeEnabled() == false) { char szBuf[8096]; - snprintf(szBuf,8096,"An unhandled error was detected.\n\nA crash dump file has been created in the folder:\n%s\nCrash dump filename is: %s.dmp",descriptor.directory().c_str(),descriptor.path()); + snprintf(szBuf,8096,"An unhandled error was detected.\n\nA crash dump file has been created in the folder:\n%s\nCrash dump filename is: %s",descriptor.directory().c_str(),descriptor.path()); //MessageBox(NULL, szBuf, "Unhandled error", MB_OK|MB_SYSTEMMODAL); message(szBuf); } diff --git a/source/glest_game/menu/menu_state_connected_game.cpp b/source/glest_game/menu/menu_state_connected_game.cpp index 368f20b8..88118ac6 100644 --- a/source/glest_game/menu/menu_state_connected_game.cpp +++ b/source/glest_game/menu/menu_state_connected_game.cpp @@ -2709,7 +2709,8 @@ void MenuStateConnectedGame::update() { clientInterface->updateLobby(); - if(clientInterface->isConnected() && clientInterface->getPausedForInGameJoin() == false && + //if(clientInterface->isConnected() && clientInterface->getPausedForInGameJoin() == false && + if(clientInterface->isConnected() && clientInterface->getJoinGameInProgress() == false && pingCount >= 3 && clientInterface->getLastPingLag() >= (GameConstants::networkPingInterval * 3)) { MutexSafeWrapper safeMutexFTPProgress((ftpClientThread != NULL ? ftpClientThread->getProgressMutex() : NULL),string(__FILE__) + "_" + intToStr(__LINE__)); if(fileFTPProgressList.empty() == true) { diff --git a/source/glest_game/network/client_interface.cpp b/source/glest_game/network/client_interface.cpp index b4924bce..0c5d4587 100644 --- a/source/glest_game/network/client_interface.cpp +++ b/source/glest_game/network/client_interface.cpp @@ -53,7 +53,6 @@ ClientInterface::ClientInterface() : GameNetworkInterface() { cachedPendingCommandsIndex = 0; cachedLastPendingFrameCount = 0; - this->pausedForInGameJoin = false; this->readyForInGameJoin = false; clientSocket= NULL; sessionKey = 0; @@ -83,11 +82,13 @@ void ClientInterface::shutdownNetworkCommandListThread() { if(networkCommandListThread != NULL) { time_t elapsed = time(NULL); + this->quit = true; networkCommandListThread->signalQuit(); for(;networkCommandListThread->canShutdown(false) == false && difftime((long int)time(NULL),elapsed) <= 15;) { //sleep(150); } + sleep(0); if(networkCommandListThread->canShutdown(true)) { delete networkCommandListThread; networkCommandListThread = NULL; @@ -656,13 +657,14 @@ void ClientInterface::updateLobby() { if(receiveMessage(&networkMessageReady)) { this->readyForInGameJoin = true; } + + //printf("ClientInterface got nmtReady this->readyForInGameJoin: %d\n",this->readyForInGameJoin); } break; case nmtCommandList: { - int waitCount = 0; //make sure we read the message time_t receiveTimeElapsed = time(NULL); NetworkMessageCommandList networkMessageCommandList; @@ -670,7 +672,6 @@ void ClientInterface::updateLobby() { if(gotCmd == false) { throw megaglest_runtime_error("error retrieving nmtCommandList returned false!"); } - this->pausedForInGameJoin = true; } break; @@ -1088,7 +1089,6 @@ void ClientInterface::waitUntilReady(Checksum* checksum) { if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__); bool signalServerWhenReadyToStartJoinedGame = this->readyForInGameJoin; - this->pausedForInGameJoin = false; this->readyForInGameJoin = false; Logger &logger= Logger::getInstance(); @@ -1594,7 +1594,6 @@ void ClientInterface::close() this->joinGameInProgress = false; this->joinGameInProgressLaunch = false; - this->pausedForInGameJoin = false; this->readyForInGameJoin = false; if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] END\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__); @@ -1795,13 +1794,19 @@ void ClientInterface::broadcastGameSetup(const GameSettings *gameSettings) { void ClientInterface::broadcastGameStart(const GameSettings *gameSettings) { if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__); - //MutexSafeWrapper safeMutex(&serverSynchAccessor,string(extractFileFromDirectoryPath(__FILE__).c_str()) + "_" + intToStr(__LINE__)); + + if(this->joinGameInProgress == true) { + this->joinGameInProgressLaunch = true; + } + + //printf("Sending game launch joinGameInProgress: %d\n",joinGameInProgress); + NetworkMessageLaunch networkMessageLaunch(gameSettings, nmtLaunch); - //broadcastMessage(&networkMessageLaunch); sendMessage(&networkMessageLaunch); + if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__); - this->joinGameInProgressLaunch = true; } + void ClientInterface::setGameSettingsReceived(bool value) { //printf("In [%s:%s] Line: %d gameSettingsReceived = %d value = %d, gameSettingsReceivedCount = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,gameSettingsReceived,value,gameSettingsReceivedCount); gameSettingsReceived = value; diff --git a/source/glest_game/network/client_interface.h b/source/glest_game/network/client_interface.h index aef8d924..8cdc1164 100644 --- a/source/glest_game/network/client_interface.h +++ b/source/glest_game/network/client_interface.h @@ -70,7 +70,6 @@ private: bool joinGameInProgress; bool joinGameInProgressLaunch; - bool pausedForInGameJoin; bool readyForInGameJoin; bool resumeInGameJoin; @@ -85,7 +84,6 @@ public: bool getJoinGameInProgress() const { return joinGameInProgress; } bool getJoinGameInProgressLaunch() const { return joinGameInProgressLaunch; } - bool getPausedForInGameJoin() const { return pausedForInGameJoin; } bool getReadyForInGameJoin() const { return readyForInGameJoin; } bool getResumeInGameJoin() const { return resumeInGameJoin; } diff --git a/source/glest_game/network/connection_slot.cpp b/source/glest_game/network/connection_slot.cpp index adc2b4d0..846a161d 100644 --- a/source/glest_game/network/connection_slot.cpp +++ b/source/glest_game/network/connection_slot.cpp @@ -380,6 +380,14 @@ ConnectionSlot::~ConnectionSlot() { if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] END\n",__FILE__,__FUNCTION__); } +void ConnectionSlot::setPlayerIndex(int value) { + playerIndex = value; + + if(this->slotThreadWorker != NULL) { + this->slotThreadWorker->setSlotIndex(playerIndex); + } +} + void ConnectionSlot::setReady() { this->ready= true; this->skipLagCheck = false; @@ -960,7 +968,7 @@ void ConnectionSlot::update(bool checkForNewClients,int lockedSlotIndex) { if(networkMessageLaunch.getMessageType() == nmtLaunch) { if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Lined: %d] got nmtLaunch\n",__FILE__,__FUNCTION__,__LINE__); - //printf("Got launch request from client joinGameInProgress = %d!\n",joinGameInProgress); + //printf("Got launch request from client joinGameInProgress = %d joinGameInProgress = %d!\n",joinGameInProgress,joinGameInProgress); } else if(networkMessageLaunch.getMessageType() == nmtBroadCastSetup) { if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Lined: %d] got nmtBroadCastSetup\n",__FILE__,__FUNCTION__,__LINE__); @@ -974,8 +982,8 @@ void ConnectionSlot::update(bool checkForNewClients,int lockedSlotIndex) { } int minHeadLessPlayersRequired = Config::getInstance().getInt("MinHeadlessPlayersRequired","2"); - if(joinGameInProgress == false && networkMessageLaunch.getMessageType() == nmtLaunch && - ready == false && + if(this->joinGameInProgress == false && networkMessageLaunch.getMessageType() == nmtLaunch && + this->ready == false && this->serverInterface->getConnectedSlotCount(true) < minHeadLessPlayersRequired) { Lang &lang= Lang::getInstance(); const vector languageList = this->serverInterface->getGameSettings()->getUniqueNetworkPlayerLanguages(); @@ -1000,7 +1008,7 @@ void ConnectionSlot::update(bool checkForNewClients,int lockedSlotIndex) { } } else { - if(joinGameInProgress == false) { + if(this->joinGameInProgress == false) { GameSettings gameSettingsBuffer; networkMessageLaunch.buildGameSettings(&gameSettingsBuffer); @@ -1011,10 +1019,10 @@ void ConnectionSlot::update(bool checkForNewClients,int lockedSlotIndex) { this->serverInterface->broadcastGameSetup(&gameSettingsBuffer, true); } - if(joinGameInProgress == false && networkMessageLaunch.getMessageType() == nmtLaunch) { + if(this->joinGameInProgress == false && networkMessageLaunch.getMessageType() == nmtLaunch) { this->serverInterface->setMasterserverAdminRequestLaunch(true); } - else if(joinGameInProgress == true && networkMessageLaunch.getMessageType() == nmtLaunch) { + else if(this->joinGameInProgress == true && networkMessageLaunch.getMessageType() == nmtLaunch) { //printf("!!! setStartInGameConnectionLaunch for client joinGameInProgress = %d!\n",joinGameInProgress); //GameSettings gameSettingsBuffer; diff --git a/source/glest_game/network/connection_slot.h b/source/glest_game/network/connection_slot.h index cf8d5a97..89fad4a2 100644 --- a/source/glest_game/network/connection_slot.h +++ b/source/glest_game/network/connection_slot.h @@ -102,7 +102,9 @@ public: virtual void execute(); void signalUpdate(ConnectionSlotEvent *event); bool isSignalCompleted(ConnectionSlotEvent *event); + int getSlotIndex() const {return slotIndex; } + void setSlotIndex(int index) { this->slotIndex = index; } void purgeCompletedEvents(); void purgeAllEvents(); @@ -172,7 +174,7 @@ public: ConnectionSlotThread *getWorkerThread() { return slotThreadWorker; } void update(bool checkForNewClients,int lockedSlotIndex); - void setPlayerIndex(int value) { playerIndex = value; } + void setPlayerIndex(int value); int getPlayerIndex() const {return playerIndex;} uint32 getConnectedRemoteIPAddress() const { return connectedRemoteIPAddress; } diff --git a/source/glest_game/network/server_interface.cpp b/source/glest_game/network/server_interface.cpp index 2b4bfe5e..546786cd 100644 --- a/source/glest_game/network/server_interface.cpp +++ b/source/glest_game/network/server_interface.cpp @@ -495,6 +495,9 @@ void ServerInterface::removeSlot(int playerIndex, int lockedSlotIndex) { bool ServerInterface::switchSlot(int fromPlayerIndex, int toPlayerIndex) { if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__); bool result = false; + + //printf("#1 Server is switching slots\n"); + //assert(fromPlayerIndex >= 0 && fromPlayerIndex < GameConstants::maxPlayers); if(fromPlayerIndex < 0 || fromPlayerIndex >= GameConstants::maxPlayers) { char szBuf[8096]=""; @@ -517,9 +520,10 @@ bool ServerInterface::switchSlot(int fromPlayerIndex, int toPlayerIndex) { MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[fromPlayerIndex],CODE_AT_LINE_X(fromPlayerIndex)); MutexSafeWrapper safeMutexSlot2(slotAccessorMutexes[toPlayerIndex],CODE_AT_LINE_X(toPlayerIndex)); - //printf("#1 Server is switching slots\n"); + //printf("#1a Server is switching slots\n"); + if(slots[toPlayerIndex] != NULL && - slots[toPlayerIndex]->isConnected() == false) { + slots[toPlayerIndex]->hasValidSocketId() == false) { //printf("#2 Server is switching slots\n"); @@ -548,6 +552,8 @@ bool ServerInterface::switchSlot(int fromPlayerIndex, int toPlayerIndex) { safeMutexSlot2.ReleaseLock(); safeMutex.ReleaseLock(); } + //printf("#4 Server is switching slots\n"); + if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__); return result; } @@ -1014,11 +1020,17 @@ void ServerInterface::checkForLaggingClients(std::map &mapSlotSignalle threadsDone = true; // Examine all threads for completion of delegation for(int i= 0; exitServer == false && i < GameConstants::maxPlayers; ++i) { + //printf("#1 Check lag for i: %d\n",i); + MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[i],CODE_AT_LINE_X(i)); ConnectionSlot* connectionSlot = slots[i]; - if(connectionSlot != NULL && connectionSlot->hasValidSocketId() == true && + if(connectionSlot != NULL && connectionSlot->isConnected() == true && + connectionSlot->getSkipLagCheck() == false && mapSlotSignalledList[i] == true && slotsCompleted.find(i) == slotsCompleted.end()) { + + //printf("#2 Check lag for i: %d playerindex: %d name [%s] socket: %d\n",i,connectionSlot->getPlayerIndex(),connectionSlot->getName().c_str(),connectionSlot->getSocketId()); + try { std::vector errorList = connectionSlot->getThreadErrorList(); // Show any collected errors from threads @@ -1035,6 +1047,7 @@ void ServerInterface::checkForLaggingClients(std::map &mapSlotSignalle // Not done waiting for data yet bool updateFinished = (connectionSlot != NULL ? connectionSlot->updateCompleted(&eventList[i]) : true); if(updateFinished == false) { + //printf("#2a Check lag for i: %d\n",i); threadsDone = false; break; } @@ -1070,6 +1083,8 @@ void ServerInterface::checkForLaggingClients(std::map &mapSlotSignalle } ConnectionSlotEvent &event = eventList[i]; mapSlotSignalledList[i] = signalClientReceiveCommands(connectionSlot,i,socketTriggered,event); + + //printf("#2b Check lag for i: %d\n",i); threadsDone = false; } if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d, clientLagExceededOrWarned.first = %d, clientLagExceededOrWarned.second = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,clientLagExceededOrWarned.first,clientLagExceededOrWarned.second); @@ -1087,7 +1102,12 @@ void ServerInterface::checkForLaggingClients(std::map &mapSlotSignalle } } - if(connectionSlot != NULL && connectionSlot->isConnected() == true) { + //printf("#3 Check lag for i: %d\n",i); + + if(connectionSlot != NULL && connectionSlot->isConnected() == true && + connectionSlot->getSkipLagCheck() == false) { + //printf("#4 Check lag for i: %d\n",i); + try { if(gameHasBeenInitiated == true && difftime((long int)time(NULL),lastGlobalLagCheckTime) >= LAG_CHECK_GRACE_PERIOD) { @@ -1117,6 +1137,8 @@ void ServerInterface::checkForLaggingClients(std::map &mapSlotSignalle errorMsgList.push_back(ex.what()); } } + + //printf("#5 Check lag for i: %d\n",i); } } } @@ -2144,18 +2166,28 @@ bool ServerInterface::launchGame(const GameSettings *gameSettings) { if(connectionSlot != NULL && connectionSlot->isConnected()) { connectionSlot->getSocket()->setBlock(true); } - else if(this->getAllowInGameConnections() == true) { - // Open slots for joining in progress game - if(gameSettings->getFactionControl(factionIndex) != ctClosed && - gameSettings->getFactionControl(factionIndex) != ctHuman) { + } + } - //printf("Opening slot for in game connections for slot: %d, faction: %d\n",i,factionIndex); - if(connectionSlot == NULL) { - addSlot(i); - connectionSlot = slots[i]; - } - connectionSlot->setCanAcceptConnections(true); + bool requiresUPNPTrigger = false; + if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__); + for(int i= 0; i < GameConstants::maxPlayers; ++i) { + int factionIndex = gameSettings->getFactionIndexForStartLocation(i); + MutexSafeWrapper safeMutexSlot(slotAccessorMutexes[i],CODE_AT_LINE_X(i)); + ConnectionSlot *connectionSlot= slots[i]; + if((connectionSlot == NULL || connectionSlot->isConnected() == false) && + this->getAllowInGameConnections() == true) { + // Open slots for joining in progress game + if(gameSettings->getFactionControl(factionIndex) != ctClosed && + gameSettings->getFactionControl(factionIndex) != ctHuman) { + + //printf("Opening slot for in game connections for slot: %d, faction: %d\n",i,factionIndex); + if(connectionSlot == NULL) { + addSlot(i); + connectionSlot = slots[i]; + requiresUPNPTrigger = true; } + connectionSlot->setCanAcceptConnections(true); } } } @@ -2203,6 +2235,10 @@ bool ServerInterface::launchGame(const GameSettings *gameSettings) { shutdownFTPServer(); } + if(requiresUPNPTrigger == true) { + this->getServerSocket()->NETdiscoverUPnPDevices(); + } + gameLaunched = true; } if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__); diff --git a/source/glest_game/world/world.cpp b/source/glest_game/world/world.cpp index f424c7ea..609140c3 100644 --- a/source/glest_game/world/world.cpp +++ b/source/glest_game/world/world.cpp @@ -1536,7 +1536,7 @@ void World::clearCaches() { } void World::togglePauseGame(bool pauseStatus,bool forceAllowPauseStateChange) { - game->setPaused(pauseStatus, forceAllowPauseStateChange); + game->setPaused(pauseStatus, forceAllowPauseStateChange, false, false); } void World::addConsoleText(const string &text) { diff --git a/source/shared_lib/sources/platform/posix/socket.cpp b/source/shared_lib/sources/platform/posix/socket.cpp index f45b6fe8..fe7cfcca 100644 --- a/source/shared_lib/sources/platform/posix/socket.cpp +++ b/source/shared_lib/sources/platform/posix/socket.cpp @@ -980,8 +980,7 @@ bool Socket::hasDataToRead(std::map &socketTriggeredList) { bool bResult = false; - if(socketTriggeredList.empty() == false) - { + if(socketTriggeredList.empty() == false) { /* Watch stdin (fd 0) to see when it has input. */ fd_set rfds; FD_ZERO(&rfds); @@ -989,11 +988,9 @@ bool Socket::hasDataToRead(std::map &socketTriggeredList) string socketDebugList = ""; PLATFORM_SOCKET imaxsocket = 0; for(std::map::iterator itermap = socketTriggeredList.begin(); - itermap != socketTriggeredList.end(); ++itermap) - { + itermap != socketTriggeredList.end(); ++itermap) { PLATFORM_SOCKET socket = itermap->first; - if(Socket::isSocketValid(&socket) == true) - { + if(Socket::isSocketValid(&socket) == true) { FD_SET(socket, &rfds); imaxsocket = max(socket,imaxsocket); @@ -1004,8 +1001,7 @@ bool Socket::hasDataToRead(std::map &socketTriggeredList) } } - if(imaxsocket > 0) - { + if(imaxsocket > 0) { /* Wait up to 0 seconds. */ struct timeval tv; tv.tv_sec = 0; @@ -1017,24 +1013,19 @@ bool Socket::hasDataToRead(std::map &socketTriggeredList) //MutexSafeWrapper safeMutex(&dataSynchAccessor); retval = select((int)imaxsocket + 1, &rfds, NULL, NULL, &tv); } - if(retval < 0) - { + if(retval < 0) { if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d, ERROR SELECTING SOCKET DATA retval = %d error = %s, socketDebugList [%s]\n",__FILE__,__FUNCTION__,__LINE__,retval,getLastSocketErrorFormattedText().c_str(),socketDebugList.c_str()); } - else if(retval) - { + else if(retval) { bResult = true; for(std::map::iterator itermap = socketTriggeredList.begin(); - itermap != socketTriggeredList.end(); ++itermap) - { + itermap != socketTriggeredList.end(); ++itermap) { PLATFORM_SOCKET socket = itermap->first; - if (FD_ISSET(socket, &rfds)) - { + if (FD_ISSET(socket, &rfds)) { itermap->second = true; } - else - { + else { itermap->second = false; } } diff --git a/source/shared_lib/sources/platform/sdl/thread.cpp b/source/shared_lib/sources/platform/sdl/thread.cpp index 70d2b313..14c9c361 100644 --- a/source/shared_lib/sources/platform/sdl/thread.cpp +++ b/source/shared_lib/sources/platform/sdl/thread.cpp @@ -16,6 +16,7 @@ #include #include "platform_util.h" #include "platform_common.h" +#include using namespace std; @@ -136,6 +137,9 @@ public: } }; +const bool debugMutexLock = false; +const int debugMutexLockMillisecondThreshold = 2000; + Mutex::Mutex(string ownerId) { mutexAccessor = SDL_CreateMutex(); SDLMutexSafeWrapper safeMutex(&mutexAccessor); @@ -151,7 +155,10 @@ Mutex::Mutex(string ownerId) { } deleteownerId = ""; - //chronoPerf = new Chrono(); + chronoPerf = NULL; + if(debugMutexLock == true) { + chronoPerf = new Chrono(); + } } Mutex::~Mutex() { @@ -168,8 +175,10 @@ Mutex::~Mutex() { throw megaglest_runtime_error(szBuf); } - //delete chronoPerf; - //chronoPerf = NULL; + if(debugMutexLock == true) { + delete chronoPerf; + chronoPerf = NULL; + } if(mutex != NULL) { deleteownerId = ownerId; @@ -184,16 +193,21 @@ void Mutex::p() { snprintf(szBuf,1023,"In [%s::%s Line: %d] mutex == NULL refCount = %d owner [%s] deleteownerId [%s]",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,refCount,ownerId.c_str(),deleteownerId.c_str()); throw megaglest_runtime_error(szBuf); } - //Chrono chrono; - //chrono.start(); + std::auto_ptr chronoLockPerf; + if(debugMutexLock == true) { + chronoLockPerf.reset(new Chrono()); + chronoLockPerf->start(); + } + SDL_mutexP(mutex); refCount++; - //if(chrono.getMillis() > 2000) { - // printf("Last ownerid: [%s]\n",lastownerId.c_str()); - //} - - //chronoPerf->start(); + if(debugMutexLock == true) { + if(chronoLockPerf->getMillis() >= debugMutexLockMillisecondThreshold) { + printf("\n**WARNING possible mutex lock detected ms [%lld] Last ownerid: [%s]\n",(long long int)chronoLockPerf->getMillis(),lastownerId.c_str()); + } + chronoPerf->start(); + } } void Mutex::v() { @@ -205,9 +219,15 @@ void Mutex::v() { refCount--; lastownerId = ownerId; - //if(chronoPerf->getMillis() > 2000) { - // lastownerId = PlatformExceptionHandler::getStackTrace(); - //} + if(debugMutexLock == true) { + if(chronoPerf->getMillis() >= debugMutexLockMillisecondThreshold) { + printf("About to get stacktrace for stuck mutex ...\n"); + string oldLastownerId = lastownerId; + lastownerId = PlatformExceptionHandler::getStackTrace(); + + printf("\n**WARNING possible mutex lock (on unlock) detected ms [%lld] Last ownerid: [%s]\noldLastownerId: [%s]\n",(long long int)chronoPerf->getMillis(),lastownerId.c_str(),oldLastownerId.c_str()); + } + } SDL_mutexV(mutex); }