diff --git a/source/glest_game/network/client_interface.cpp b/source/glest_game/network/client_interface.cpp index 93e22550f..4888db329 100755 --- a/source/glest_game/network/client_interface.cpp +++ b/source/glest_game/network/client_interface.cpp @@ -48,6 +48,7 @@ ClientInterface::ClientInterface(){ gotIntro = false; lastNetworkCommandListSendTime = 0; currentFrameCount = 0; + clientSimulationLagStartTime = 0; networkGameDataSynchCheckOkMap = false; networkGameDataSynchCheckOkTile = false; @@ -508,6 +509,17 @@ void ClientInterface::updateKeyframe(int frameCount) //wait for the next message waitForMessage(); + // START: Test simulating lag for the client + if(Config::getInstance().getInt("SimulateClientLag","0") > 0) { + if(clientSimulationLagStartTime == 0) { + clientSimulationLagStartTime = time(NULL); + } + if(difftime(time(NULL),clientSimulationLagStartTime) <= Config::getInstance().getInt("SimulateClientLagDurationSeconds","0")) { + sleep(Config::getInstance().getInt("SimulateClientLag","0")); + } + } + // END: Test simulating lag for the client + //check we have an expected message NetworkMessageType networkMessageType= getNextMessageType(true); @@ -533,7 +545,10 @@ void ClientInterface::updateKeyframe(int frameCount) chrono.start(); //check that we are in the right frame if(networkMessageCommandList.getFrameCount() != frameCount) { - string sErr = "Network synchronization error, frame counts do not match, server frameCount = " + intToStr(networkMessageCommandList.getFrameCount()) + ", local frameCount = " + intToStr(frameCount); + string sErr = "Player: " + Config::getInstance().getString("NetPlayerName",Socket::getHostName().c_str()) + + " got a Network synchronization error, frame counts do not match, server frameCount = " + + intToStr(networkMessageCommandList.getFrameCount()) + ", local frameCount = " + + intToStr(frameCount); //throw runtime_error("Network synchronization error, frame counts do not match"); sendTextMessage(sErr,-1, true); DisplayErrorMessage(sErr); diff --git a/source/glest_game/network/client_interface.h b/source/glest_game/network/client_interface.h index d5f811269..9a8ecd724 100644 --- a/source/glest_game/network/client_interface.h +++ b/source/glest_game/network/client_interface.h @@ -52,6 +52,7 @@ private: int currentFrameCount; time_t lastNetworkCommandListSendTime; + time_t clientSimulationLagStartTime; string versionString; public: diff --git a/source/glest_game/network/connection_slot.cpp b/source/glest_game/network/connection_slot.cpp index eea325d75..eabec37d4 100644 --- a/source/glest_game/network/connection_slot.cpp +++ b/source/glest_game/network/connection_slot.cpp @@ -249,11 +249,15 @@ void ConnectionSlot::update(bool checkForNewClients) { if(socket->isConnected()) { this->clearChatInfo(); - if(socket->hasDataToRead() == true) { - NetworkMessageType networkMessageType= getNextMessageType(); + bool gotTextMsg = true; + for(;socket->hasDataToRead() == true && gotTextMsg == true;) { + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] polling for networkMessageType...\n",__FILE__,__FUNCTION__,__LINE__); + + NetworkMessageType networkMessageType= getNextMessageType(true); SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] networkMessageType = %d\n",__FILE__,__FUNCTION__,__LINE__,networkMessageType); + gotTextMsg = false; //process incoming commands switch(networkMessageType) { @@ -281,6 +285,7 @@ void ConnectionSlot::update(bool checkForNewClients) { if(receiveMessage(&networkMessageText)) { ChatMsgInfo msg(networkMessageText.getText().c_str(),networkMessageText.getSender().c_str(),networkMessageText.getTeamIndex()); this->addChatInfo(msg); + gotTextMsg = true; //SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] chatText [%s] chatSender [%s] chatTeamIndex = %d\n",__FILE__,__FUNCTION__,__LINE__,chatText.c_str(),chatSender.c_str(),chatTeamIndex); } diff --git a/source/glest_game/network/network_message.cpp b/source/glest_game/network/network_message.cpp index ed2118a46..07a3abc18 100644 --- a/source/glest_game/network/network_message.cpp +++ b/source/glest_game/network/network_message.cpp @@ -97,8 +97,9 @@ bool NetworkMessage::receive(Socket* socket, void* data, int dataSize) return false; } -void NetworkMessage::send(Socket* socket, const void* data, int dataSize) const -{ +void NetworkMessage::send(Socket* socket, const void* data, int dataSize) const { + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] socket = %p, data = %p, dataSize = %d\n",__FILE__,__FUNCTION__,__LINE__,socket,data,dataSize); + if(socket != NULL) { int sendResult = socket->send(data, dataSize); if(sendResult != dataSize) { @@ -137,6 +138,7 @@ bool NetworkMessageIntro::receive(Socket* socket){ } void NetworkMessageIntro::send(Socket* socket) const{ + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] nmtIntro\n",__FILE__,__FUNCTION__,__LINE__); assert(data.messageType==nmtIntro); NetworkMessage::send(socket, &data, sizeof(data)); } @@ -163,6 +165,7 @@ bool NetworkMessagePing::receive(Socket* socket){ } void NetworkMessagePing::send(Socket* socket) const{ + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] nmtPing\n",__FILE__,__FUNCTION__,__LINE__); assert(data.messageType==nmtPing); NetworkMessage::send(socket, &data, sizeof(data)); } @@ -185,6 +188,7 @@ bool NetworkMessageReady::receive(Socket* socket){ } void NetworkMessageReady::send(Socket* socket) const{ + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] nmtReady\n",__FILE__,__FUNCTION__,__LINE__); assert(data.messageType==nmtReady); NetworkMessage::send(socket, &data, sizeof(data)); } @@ -258,6 +262,7 @@ bool NetworkMessageLaunch::receive(Socket* socket){ } void NetworkMessageLaunch::send(Socket* socket) const{ + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] nmtLaunch\n",__FILE__,__FUNCTION__,__LINE__); NetworkMessage::send(socket, &data, sizeof(data)); } @@ -335,6 +340,8 @@ bool NetworkMessageCommandList::receive(Socket* socket) { } void NetworkMessageCommandList::send(Socket* socket) const{ + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] nmtCommandList, frameCount = %d\n",__FILE__,__FUNCTION__,__LINE__,data.header.frameCount); + assert(data.header.messageType==nmtCommandList); int totalMsgSize = commandListHeaderSize + (sizeof(NetworkCommand) * data.header.commandCount); NetworkMessage::send(socket, &data, totalMsgSize); @@ -359,6 +366,16 @@ void NetworkMessageCommandList::send(Socket* socket) const{ // ===================================================== NetworkMessageText::NetworkMessageText(const string &text, const string &sender, int teamIndex){ + + if(text.length() >= maxTextStringSize) { + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] WARNING / ERROR - text [%s] length = %d, max = %d\n",__FILE__,__FUNCTION__,__LINE__,text.c_str(),text.length(),maxTextStringSize); + //throw runtime_error("NetworkMessageText - text.length() >= maxStringSize"); + } + if(sender.length() >= maxSenderStringSize) { + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] WARNING / ERROR - sender [%s] length = %d, max = %d\n",__FILE__,__FUNCTION__,__LINE__,sender.c_str(),sender.length(),maxSenderStringSize); + //throw runtime_error("NetworkMessageText - sender.length() >= maxSenderStringSize"); + } + data.messageType= nmtText; data.text= text; data.sender= sender; @@ -370,6 +387,8 @@ bool NetworkMessageText::receive(Socket* socket){ } void NetworkMessageText::send(Socket* socket) const{ + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] nmtText\n",__FILE__,__FUNCTION__,__LINE__); + assert(data.messageType==nmtText); NetworkMessage::send(socket, &data, sizeof(data)); } @@ -387,6 +406,8 @@ bool NetworkMessageQuit::receive(Socket* socket){ } void NetworkMessageQuit::send(Socket* socket) const{ + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] nmtQuit\n",__FILE__,__FUNCTION__,__LINE__); + assert(data.messageType==nmtQuit); NetworkMessage::send(socket, &data, sizeof(data)); } @@ -442,8 +463,9 @@ bool NetworkMessageSynchNetworkGameData::receive(Socket* socket) return NetworkMessage::receive(socket, &data, sizeof(data)); } -void NetworkMessageSynchNetworkGameData::send(Socket* socket) const -{ +void NetworkMessageSynchNetworkGameData::send(Socket* socket) const { + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] nmtSynchNetworkGameData\n",__FILE__,__FUNCTION__,__LINE__); + assert(data.messageType==nmtSynchNetworkGameData); NetworkMessage::send(socket, &data, sizeof(data)); } @@ -467,8 +489,9 @@ bool NetworkMessageSynchNetworkGameDataStatus::receive(Socket* socket) return NetworkMessage::receive(socket, &data, sizeof(data)); } -void NetworkMessageSynchNetworkGameDataStatus::send(Socket* socket) const -{ +void NetworkMessageSynchNetworkGameDataStatus::send(Socket* socket) const { + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] nmtSynchNetworkGameDataStatus\n",__FILE__,__FUNCTION__,__LINE__); + assert(data.messageType==nmtSynchNetworkGameDataStatus); NetworkMessage::send(socket, &data, sizeof(data)); } @@ -492,8 +515,9 @@ bool NetworkMessageSynchNetworkGameDataFileCRCCheck::receive(Socket* socket) return NetworkMessage::receive(socket, &data, sizeof(data)); } -void NetworkMessageSynchNetworkGameDataFileCRCCheck::send(Socket* socket) const -{ +void NetworkMessageSynchNetworkGameDataFileCRCCheck::send(Socket* socket) const { + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] nmtSynchNetworkGameDataFileCRCCheck\n",__FILE__,__FUNCTION__,__LINE__); + assert(data.messageType==nmtSynchNetworkGameDataFileCRCCheck); NetworkMessage::send(socket, &data, sizeof(data)); } @@ -514,8 +538,9 @@ bool NetworkMessageSynchNetworkGameDataFileGet::receive(Socket* socket) return NetworkMessage::receive(socket, &data, sizeof(data)); } -void NetworkMessageSynchNetworkGameDataFileGet::send(Socket* socket) const -{ +void NetworkMessageSynchNetworkGameDataFileGet::send(Socket* socket) const { + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] nmtSynchNetworkGameDataFileGet\n",__FILE__,__FUNCTION__,__LINE__); + assert(data.messageType==nmtSynchNetworkGameDataFileGet); NetworkMessage::send(socket, &data, sizeof(data)); } diff --git a/source/glest_game/network/network_message.h b/source/glest_game/network/network_message.h index b58ea5222..48f30c9db 100644 --- a/source/glest_game/network/network_message.h +++ b/source/glest_game/network/network_message.h @@ -270,13 +270,14 @@ public: class NetworkMessageText: public NetworkMessage{ private: - static const int maxStringSize= 256; + static const int maxTextStringSize= 340; + static const int maxSenderStringSize= 60; private: struct Data{ int8 messageType; - NetworkString text; - NetworkString sender; + NetworkString text; + NetworkString sender; int8 teamIndex; }; diff --git a/source/glest_game/network/network_types.h b/source/glest_game/network/network_types.h index a63a96a74..0d1897316 100644 --- a/source/glest_game/network/network_types.h +++ b/source/glest_game/network/network_types.h @@ -39,9 +39,13 @@ private: char buffer[S]; public: - NetworkString() {memset(buffer, 0, S);} - void operator=(const string& str) {strncpy(buffer, str.c_str(), S-1);} - string getString() const {return buffer;} + NetworkString() {memset(buffer, 0, S);} + void operator=(const string& str) { + // ensure we don't have a buffer overflow + int maxBufferSize = sizeof(buffer) / sizeof(buffer[0]); + strncpy(buffer, str.c_str(), std::min(S-1,maxBufferSize)); + } + string getString() const {return buffer;} }; // ===================================================== diff --git a/source/glest_game/network/server_interface.cpp b/source/glest_game/network/server_interface.cpp index 2f0eb720a..cf0070d65 100644 --- a/source/glest_game/network/server_interface.cpp +++ b/source/glest_game/network/server_interface.cpp @@ -51,6 +51,10 @@ double warnFrameCountLagPercent = 0.65; // Seconds grace period before we start checking LAG double LAG_CHECK_GRACE_PERIOD = 15; +// The max amount of time to 'freeze' gameplay per packet when a client is lagging +// badly and we want to give time for them to catch up +double MAX_CLIENT_WAIT_SECONDS_FOR_PAUSE = 2; + ServerInterface::ServerInterface(){ gameHasBeenInitiated = false; gameSettingsUpdateCount = 0; @@ -264,7 +268,7 @@ void ServerInterface::updateSlot(ConnectionSlotEvent *event) { } // Only call when client has just sent us data -std::pair ServerInterface::clientLagCheck(ConnectionSlot* connectionSlot) { +std::pair ServerInterface::clientLagCheck(ConnectionSlot* connectionSlot, bool skipNetworkBroadCast) { std::pair clientLagExceededOrWarned = std::make_pair(false,false); static bool alreadyInLagCheck = false; @@ -320,8 +324,10 @@ std::pair ServerInterface::clientLagCheck(ConnectionSlot* connectionS #endif SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] %s\n",__FILE__,__FUNCTION__,__LINE__,szBuf); - string sMsg = szBuf; - sendTextMessage(sMsg,-1, true); + if(skipNetworkBroadCast == false) { + string sMsg = szBuf; + sendTextMessage(sMsg,-1, true); + } if(gameSettings.getNetworkPauseGameForLaggedClients() == false) { connectionSlot->close(); @@ -347,8 +353,10 @@ std::pair ServerInterface::clientLagCheck(ConnectionSlot* connectionS #endif SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] %s\n",__FILE__,__FUNCTION__,__LINE__,szBuf); - string sMsg = szBuf; - sendTextMessage(sMsg,-1, true); + if(skipNetworkBroadCast == false) { + string sMsg = szBuf; + sendTextMessage(sMsg,-1, true); + } } } else if(connectionSlot->getLagCountWarning() == true) { @@ -437,11 +445,58 @@ void ServerInterface::update() { mapSlotSignalledList[i] = signalClientReceiveCommands(connectionSlot,i,socketTriggered,event); } - SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__); + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] ============ Step #2\n",__FILE__,__FUNCTION__,__LINE__); // Step #2 check all connection slot worker threads for completed status std::map slotsCompleted; - std::map slotsWarnedAndRetried; + 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 && mapSlotSignalledList[i] == true && + slotsCompleted.find(i) == slotsCompleted.end()) { + try { + std::vector errorList = connectionSlot->getThreadErrorList(); + // Collect any collected errors from threads + if(errorList.size() > 0) { + for(int iErrIdx = 0; iErrIdx < errorList.size(); ++iErrIdx) { + string &sErr = errorList[iErrIdx]; + if(sErr != "") { + errorMsgList.push_back(sErr); + } + } + connectionSlot->clearThreadErrorList(); + } + + connectionSlot = slots[i]; + + // Not done waiting for data yet + bool updateFinished = (connectionSlot != NULL ? connectionSlot->updateCompleted() : true); + if(updateFinished == false) { + threadsDone = false; + sleep(0); + break; + } + else { + slotsCompleted[i] = true; + } + } + catch(const exception &ex) { + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] error detected [%s]\n",__FILE__,__FUNCTION__,__LINE__,ex.what()); + errorMsgList.push_back(ex.what()); + } + } + } + } + + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] ============ Step #3\n",__FILE__,__FUNCTION__,__LINE__); + + // Step #3 check clients for any lagging scenarios and try to deal with them + time_t waitForClientsElapsed = time(NULL); + slotsCompleted.clear(); + //std::map slotsWarnedAndRetried; + std::map slotsWarnedList; for(bool threadsDone = false; threadsDone == false;) { threadsDone = true; // Examine all threads for completion of delegation @@ -456,7 +511,6 @@ void ServerInterface::update() { for(int iErrIdx = 0; iErrIdx < errorList.size(); ++iErrIdx) { string &sErr = errorList[iErrIdx]; if(sErr != "") { - //DisplayErrorMessage(sErr); errorMsgList.push_back(sErr); } } @@ -479,20 +533,38 @@ void ServerInterface::update() { std::pair clientLagExceededOrWarned = std::make_pair(false,false); if( gameHasBeenInitiated == true && connectionSlot != NULL && connectionSlot->isConnected() == true) { - clientLagExceededOrWarned = clientLagCheck(connectionSlot); + clientLagExceededOrWarned = clientLagCheck(connectionSlot,slotsWarnedList[i]); + + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] clientLagExceededOrWarned.first = %d, clientLagExceededOrWarned.second = %d, gameSettings.getNetworkPauseGameForLaggedClients() = %d\n",__FILE__,__FUNCTION__,__LINE__,clientLagExceededOrWarned.first,clientLagExceededOrWarned.second,gameSettings.getNetworkPauseGameForLaggedClients()); + + if(clientLagExceededOrWarned.first == true) { + slotsWarnedList[i] = true; + } } // If the client has exceeded lag and the server wants // to pause while they catch up, re-trigger the // client reader thread - if((clientLagExceededOrWarned.first == true && gameSettings.getNetworkPauseGameForLaggedClients() == true) || - (clientLagExceededOrWarned.second == true && slotsWarnedAndRetried[i] == false)) { - bool socketTriggered = (connectionSlot != NULL && connectionSlot->getSocket() != NULL ? socketTriggeredList[connectionSlot->getSocket()->getSocketId()] : false); - ConnectionSlotEvent &event = eventList[i]; - signalClientReceiveCommands(connectionSlot,i,socketTriggered,event); - sleep(0); + if((clientLagExceededOrWarned.first == true && gameSettings.getNetworkPauseGameForLaggedClients() == true)) { // || + //(clientLagExceededOrWarned.second == true && slotsWarnedAndRetried[i] == false)) { - if(gameSettings.getNetworkPauseGameForLaggedClients() == false) { - slotsWarnedAndRetried[i] = true; + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d, clientLagExceededOrWarned.first = %d, clientLagExceededOrWarned.second = %d, difftime(time(NULL),waitForClientsElapsed) = %.2f, MAX_CLIENT_WAIT_SECONDS_FOR_PAUSE = %.2f\n",__FILE__,__FUNCTION__,__LINE__,clientLagExceededOrWarned.first,clientLagExceededOrWarned.second,difftime(time(NULL),waitForClientsElapsed),MAX_CLIENT_WAIT_SECONDS_FOR_PAUSE); + + if(difftime(time(NULL),waitForClientsElapsed) < MAX_CLIENT_WAIT_SECONDS_FOR_PAUSE) { + connectionSlot = slots[i]; + if(connectionSlot != NULL) { + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d, clientLagExceededOrWarned.first = %d, clientLagExceededOrWarned.second = %d\n",__FILE__,__FUNCTION__,__LINE__,clientLagExceededOrWarned.first,clientLagExceededOrWarned.second); + + bool socketTriggered = (connectionSlot != NULL && connectionSlot->getSocket() != NULL ? socketTriggeredList[connectionSlot->getSocket()->getSocketId()] : false); + ConnectionSlotEvent &event = eventList[i]; + mapSlotSignalledList[i] = signalClientReceiveCommands(connectionSlot,i,socketTriggered,event); + sleep(0); + threadsDone = false; + } + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d, clientLagExceededOrWarned.first = %d, clientLagExceededOrWarned.second = %d\n",__FILE__,__FUNCTION__,__LINE__,clientLagExceededOrWarned.first,clientLagExceededOrWarned.second); + + //if(gameSettings.getNetworkPauseGameForLaggedClients() == false) { + // slotsWarnedAndRetried[i] = true; + //} } } else { @@ -508,20 +580,20 @@ void ServerInterface::update() { } } - SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__); + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] ============ Step #4\n",__FILE__,__FUNCTION__,__LINE__); - // Step #3 dispatch network commands to the pending list so that they are done in proper order + // Step #4 dispatch network commands to the pending list so that they are done in proper order if(gameHasBeenInitiated == true) { for(int i= 0; i< GameConstants::maxPlayers; ++i) { ConnectionSlot* connectionSlot= slots[i]; if(connectionSlot != NULL && connectionSlot->isConnected() == true) { if(connectionSlot->getPendingNetworkCommandList().size() > 0) { // New lag check - std::pair clientLagExceededOrWarned = clientLagCheck(connectionSlot); - if(clientLagExceededOrWarned.first == true) { - SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] slotIndex = %d, clientLagExceeded = %d, warned = %d\n",__FILE__,__FUNCTION__,__LINE__,i,clientLagExceededOrWarned.first,clientLagExceededOrWarned.second); - } - else { + //std::pair clientLagExceededOrWarned = clientLagCheck(connectionSlot); + //if(clientLagExceededOrWarned.first == true) { + // SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] slotIndex = %d, clientLagExceeded = %d, warned = %d\n",__FILE__,__FUNCTION__,__LINE__,i,clientLagExceededOrWarned.first,clientLagExceededOrWarned.second); + //} + //else { vector vctPendingNetworkCommandList = connectionSlot->getPendingNetworkCommandList(); for(int idx = 0; idx < vctPendingNetworkCommandList.size(); ++idx) { @@ -529,33 +601,36 @@ void ServerInterface::update() { this->requestCommand(&cmd); } connectionSlot->clearPendingNetworkCommandList(); - } + //} } } } } - SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__); + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] ============ Step #5\n",__FILE__,__FUNCTION__,__LINE__); - // Step #4 dispatch pending chat messages + // Step #5 dispatch pending chat messages for(int i= 0; i< GameConstants::maxPlayers; ++i) { ConnectionSlot* connectionSlot= slots[i]; if(connectionSlot != NULL && connectionSlot->getChatTextList().empty() == false) { try { - for(int chatIdx = 0; chatIdx < connectionSlot->getChatTextList().size(); chatIdx++) { - ChatMsgInfo msg(connectionSlot->getChatTextList()[chatIdx]); - this->addChatInfo(msg); + for(int chatIdx = 0; slots[i] != NULL && chatIdx < connectionSlot->getChatTextList().size(); chatIdx++) { + connectionSlot= slots[i]; + if(connectionSlot != NULL) { + ChatMsgInfo msg(connectionSlot->getChatTextList()[chatIdx]); + this->addChatInfo(msg); - string newChatText = msg.chatText.c_str(); - string newChatSender = msg.chatSender.c_str(); - int newChatTeamIndex = msg.chatTeamIndex; + string newChatText = msg.chatText.c_str(); + string newChatSender = msg.chatSender.c_str(); + int newChatTeamIndex = msg.chatTeamIndex; - SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] #1 about to broadcast nmtText chatText [%s] chatSender [%s] chatTeamIndex = %d\n",__FILE__,__FUNCTION__,__LINE__,newChatText.c_str(),newChatSender.c_str(),newChatTeamIndex); + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] #1 about to broadcast nmtText chatText [%s] chatSender [%s] chatTeamIndex = %d\n",__FILE__,__FUNCTION__,__LINE__,newChatText.c_str(),newChatSender.c_str(),newChatTeamIndex); - NetworkMessageText networkMessageText(newChatText.c_str(),newChatSender.c_str(),newChatTeamIndex); - broadcastMessage(&networkMessageText, connectionSlot->getPlayerIndex()); + NetworkMessageText networkMessageText(newChatText.c_str(),newChatSender.c_str(),newChatTeamIndex); + broadcastMessage(&networkMessageText, connectionSlot->getPlayerIndex()); - SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] after broadcast nmtText chatText [%s] chatSender [%s] chatTeamIndex = %d\n",__FILE__,__FUNCTION__,__LINE__,newChatText.c_str(),newChatSender.c_str(),newChatTeamIndex); + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] after broadcast nmtText chatText [%s] chatSender [%s] chatTeamIndex = %d\n",__FILE__,__FUNCTION__,__LINE__,newChatText.c_str(),newChatSender.c_str(),newChatTeamIndex); + } } SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] i = %d\n",__FILE__,__FUNCTION__,__LINE__,i); @@ -573,50 +648,6 @@ void ServerInterface::update() { } SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__); - - //process text messages -/* - if(this->getChatTextList().empty() == true) { - SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); - - for(int i= 0; i< GameConstants::maxPlayers; ++i) { - ConnectionSlot* connectionSlot= slots[i]; - - if(connectionSlot!= NULL && - (gameHasBeenInitiated == false || (connectionSlot->getSocket() != NULL && socketTriggeredList[connectionSlot->getSocket()->getSocketId()] == true))) { - if( connectionSlot->isConnected() && - socketTriggeredList[connectionSlot->getSocket()->getSocketId()] == true) { - if(connectionSlot->getSocket() != NULL) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] calling connectionSlot->getNextMessageType() for slots[i]->getSocket()->getSocketId() = %d\n",__FILE__,__FUNCTION__,connectionSlot->getSocket()->getSocketId()); - - try { - if(connectionSlot->getNextMessageType() == nmtText) { - NetworkMessageText networkMessageText; - if(connectionSlot->receiveMessage(&networkMessageText)) { - SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] #2 about to broadcast nmtText msg for SlotIndex# %d\n",__FILE__,__FUNCTION__,i); - - broadcastMessage(&networkMessageText, i); - - //chatText= networkMessageText.getText(); - //chatSender= networkMessageText.getSender(); - //chatTeamIndex= networkMessageText.getTeamIndex(); - //break; - - ChatMsgInfo msg(networkMessageText.getText().c_str(),networkMessageText.getSender().c_str(),networkMessageText.getTeamIndex()); - this->addChatInfo(msg); - } - } - } - catch(const exception &ex) { - SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] error detected [%s]\n",__FILE__,__FUNCTION__,__LINE__,ex.what()); - errorMsgList.push_back(ex.what()); - } - } - } - } - } - - SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__); -*/ } } } @@ -990,12 +1021,12 @@ void ServerInterface::broadcastMessage(const NetworkMessage* networkMessage, int ConnectionSlot* connectionSlot = slots[i]; // New lag check - std::pair clientLagExceededOrWarned = std::make_pair(false,false); - if( gameHasBeenInitiated == true && connectionSlot != NULL && - connectionSlot->isConnected() == true) { - clientLagExceededOrWarned = clientLagCheck(connectionSlot); - } - if(clientLagExceededOrWarned.first == false) { + //std::pair clientLagExceededOrWarned = std::make_pair(false,false); + //if( gameHasBeenInitiated == true && connectionSlot != NULL && + // connectionSlot->isConnected() == true) { + // clientLagExceededOrWarned = clientLagCheck(connectionSlot); + //} + //if(clientLagExceededOrWarned.first == false) { SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] networkMessage = %p\n",__FILE__,__FUNCTION__,__LINE__,networkMessage); ConnectionSlotEvent &event = eventList[i]; @@ -1024,7 +1055,7 @@ void ServerInterface::broadcastMessage(const NetworkMessage* networkMessage, int 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__); @@ -1064,12 +1095,12 @@ void ServerInterface::broadcastMessage(const NetworkMessage* networkMessage, int if(i != excludeSlot && connectionSlot != NULL) { // New lag check - std::pair clientLagExceededOrWarned = std::make_pair(false,false); - if( gameHasBeenInitiated == true && connectionSlot != NULL && - connectionSlot->isConnected() == true) { - clientLagExceededOrWarned = clientLagCheck(connectionSlot); - } - if(clientLagExceededOrWarned.first == false) { + //std::pair clientLagExceededOrWarned = std::make_pair(false,false); + //if( gameHasBeenInitiated == true && connectionSlot != NULL && + // connectionSlot->isConnected() == true) { + // clientLagExceededOrWarned = clientLagCheck(connectionSlot); + //} + //if(clientLagExceededOrWarned.first == false) { if(connectionSlot->isConnected()) { SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] before sendMessage\n",__FILE__,__FUNCTION__,__LINE__); connectionSlot->sendMessage(networkMessage); @@ -1079,7 +1110,7 @@ void ServerInterface::broadcastMessage(const NetworkMessage* networkMessage, int SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] #1 before removeSlot for slot# %d\n",__FILE__,__FUNCTION__,__LINE__,i); removeSlot(i); } - } + //} } else if(i == excludeSlot && gameHasBeenInitiated == true && connectionSlot != NULL && connectionSlot->isConnected() == false) { diff --git a/source/glest_game/network/server_interface.h b/source/glest_game/network/server_interface.h index 9f92254f7..abbaab189 100644 --- a/source/glest_game/network/server_interface.h +++ b/source/glest_game/network/server_interface.h @@ -80,7 +80,7 @@ public: virtual void slotUpdateTask(ConnectionSlotEvent *event); bool hasClientConnection(); int getCurrentFrameCount() const { return currentFrameCount; } - std::pair clientLagCheck(ConnectionSlot* connectionSlot); + std::pair clientLagCheck(ConnectionSlot* connectionSlot,bool skipNetworkBroadCast=false); bool signalClientReceiveCommands(ConnectionSlot* connectionSlot, int slotIndex, diff --git a/source/glest_game/type_instances/command.cpp b/source/glest_game/type_instances/command.cpp index 30dce586b..fa2e534c8 100644 --- a/source/glest_game/type_instances/command.cpp +++ b/source/glest_game/type_instances/command.cpp @@ -91,7 +91,8 @@ std::string Command::toString() const { //SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__, __LINE__); if(unitType != NULL) { - result += ", unitTypeId = " + intToStr(unitType->getId()) + ", unitTypeDesc = " + unitType->getReqDesc(); + result += ", unitTypeId = " + intToStr(unitType->getId()); + result += ", unitTypeDesc = " + unitType->getReqDesc(); } //SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__, __LINE__); diff --git a/source/glest_game/types/element_type.cpp b/source/glest_game/types/element_type.cpp new file mode 100644 index 000000000..a8a4abe5a --- /dev/null +++ b/source/glest_game/types/element_type.cpp @@ -0,0 +1,117 @@ +// ============================================================== +// This file is part of Glest (www.glest.org) +// +// Copyright (C) 2001-2008 Martio Figueroa +// +// You can redistribute this code and/or modify it under +// the terms of the GNU General Public License as published +// by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version +// ============================================================== + +#include "element_type.h" + +#include + +#include "resource_type.h" +#include "upgrade_type.h" +#include "unit_type.h" +#include "resource.h" +#include "tech_tree.h" +#include "logger.h" +#include "lang.h" +#include "renderer.h" +#include "leak_dumper.h" + +using namespace Shared::Util; + +namespace Glest{ namespace Game{ + +// ===================================================== +// class DisplayableType +// ===================================================== + +DisplayableType::DisplayableType(){ + image= NULL; +} + +// ===================================================== +// class RequirableType +// ===================================================== + +string RequirableType::getReqDesc() const{ + bool anyReqs= false; + + string reqString=""; + for(int i=0; igetName(); + reqString+= "\n"; + anyReqs= true; + } + + for(int i=0; igetName(); + reqString+= "\n"; + anyReqs= true; + } + + string str= getName(); + if(anyReqs){ + return str + " " + Lang::getInstance().get("Reqs") + ":\n" + reqString; + } + else{ + return str; + } +} + +// ===================================================== +// class ProducibleType +// ===================================================== + +ProducibleType::ProducibleType(){ + cancelImage= NULL; +} + +ProducibleType::~ProducibleType(){ +} + +const Resource *ProducibleType::getCost(const ResourceType *rt) const{ + for(int i=0; igetAmount()!=0){ + str+= getCost(i)->getType()->getName(); + str+= ": "+ intToStr(getCost(i)->getAmount()); + str+= "\n"; + } + } + + for(int i=0; igetName(); + str+= "\n"; + } + + for(int i=0; igetName(); + str+= "\n"; + } + + return str; +} + +}}//end namespace diff --git a/source/glest_game/world/world.cpp b/source/glest_game/world/world.cpp index 9aba9aa72..58700b02c 100644 --- a/source/glest_game/world/world.cpp +++ b/source/glest_game/world/world.cpp @@ -155,9 +155,11 @@ void World::init(Game *game, bool createUnits){ initMap(); initSplattedTextures(); - // must be done after initMap() - routePlanner = new RoutePlanner(this); - cartographer = new Cartographer(this); + // must be done after initMap() + if(gs->getPathFinderType() != pfBasic) { + routePlanner = new RoutePlanner(this); + cartographer = new Cartographer(this); + } unitUpdater.init(game); @@ -338,7 +340,9 @@ void World::tick(){ } } } - cartographer->tick(); + if(cartographer != NULL) { + cartographer->tick(); + } } Unit* World::findUnitById(int id){ @@ -784,8 +788,10 @@ void World::initUnits(){ throw runtime_error("Unit cant be placed, this error is caused because there is no enough place to put the units near its start location, make a better map: "+unit->getType()->getName() + " Faction: "+intToStr(i)); } if (unit->getType()->hasSkillClass(scBeBuilt)) { - map.flatternTerrain(unit); - cartographer->updateMapMetrics(unit->getPos(), unit->getType()->getSize()); + map.flatternTerrain(unit); + if(cartographer != NULL) { + cartographer->updateMapMetrics(unit->getPos(), unit->getType()->getSize()); + } } SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d] unit created for unit [%s]\n",__FILE__,__FUNCTION__,__LINE__,unit->toString().c_str()); } diff --git a/source/shared_lib/include/platform/posix/socket.h b/source/shared_lib/include/platform/posix/socket.h index dc6afd72d..4d126530c 100644 --- a/source/shared_lib/include/platform/posix/socket.h +++ b/source/shared_lib/include/platform/posix/socket.h @@ -98,6 +98,8 @@ protected: time_t lastThreadedPing; Mutex pingThreadAccessor; + Mutex dataSynchAccessor; + public: Socket(PLATFORM_SOCKET sock); Socket(); diff --git a/source/shared_lib/sources/platform/common/platform_common.cpp b/source/shared_lib/sources/platform/common/platform_common.cpp index d7a25557f..6b91937db 100644 --- a/source/shared_lib/sources/platform/common/platform_common.cpp +++ b/source/shared_lib/sources/platform/common/platform_common.cpp @@ -788,8 +788,14 @@ void showCursor(bool b) { if(b) { //SDL_GetMouseState( &x, &y ); } + int state = SDL_ShowCursor(SDL_QUERY); + if( (state == SDL_DISABLE && b == false) || + (state == SDL_ENABLE && b == true)) { + return; + } + SDL_ShowCursor(b ? SDL_ENABLE : SDL_DISABLE); - SDL_WM_GrabInput(SDL_GRAB_OFF); + //SDL_WM_GrabInput(SDL_GRAB_OFF); if(b) { //SDL_WM_GrabInput(SDL_GRAB_OFF); //SDL_WarpMouse(x,y); diff --git a/source/shared_lib/sources/platform/posix/socket.cpp b/source/shared_lib/sources/platform/posix/socket.cpp index 798c8d803..8f05249ba 100644 --- a/source/shared_lib/sources/platform/posix/socket.cpp +++ b/source/shared_lib/sources/platform/posix/socket.cpp @@ -827,7 +827,12 @@ bool Socket::hasDataToRead(std::map &socketTriggeredList) tv.tv_sec = 0; tv.tv_usec = 0; - int retval = select(imaxsocket + 1, &rfds, NULL, NULL, &tv); + + int retval = 0; + { + //MutexSafeWrapper safeMutex(&dataSynchAccessor); + retval = select(imaxsocket + 1, &rfds, NULL, NULL, &tv); + } if(retval < 0) { SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] ERROR SELECTING SOCKET DATA retval = %d error = %s\n",__FILE__,__FUNCTION__,retval,getLastSocketErrorFormattedText().c_str()); @@ -884,7 +889,11 @@ bool Socket::hasDataToRead(PLATFORM_SOCKET socket) tv.tv_sec = 0; tv.tv_usec = 0; - int retval = select(socket + 1, &rfds, NULL, NULL, &tv); + int retval = 0; + { + //MutexSafeWrapper safeMutex(&dataSynchAccessor); + retval = select(socket + 1, &rfds, NULL, NULL, &tv); + } if(retval) { if (FD_ISSET(socket, &rfds)) @@ -933,6 +942,10 @@ int Socket::getDataToRead(bool wantImmediateReply) { } else if(err == 0) { + if(isConnected() == false) { + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] ERROR PEEKING SOCKET DATA, err = %d %s\n",__FILE__,__FUNCTION__,err,getLastSocketErrorFormattedText().c_str()); + break; + } //if(Socket::enableNetworkDebugInfo) printf("In [%s] ioctl returned = %d, size = %ld\n",__FUNCTION__,err,size); } @@ -962,6 +975,8 @@ int Socket::send(const void *data, int dataSize) { ssize_t bytesSent= 0; if(isSocketValid() == true) { errno = 0; + + MutexSafeWrapper safeMutex(&dataSynchAccessor); bytesSent = ::send(sock, reinterpret_cast(data), dataSize, 0); } @@ -985,6 +1000,7 @@ int Socket::send(const void *data, int dataSize) { if(Socket::isWritable(true) == true) { SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] attemptCount = %d, sock = %d, dataSize = %d, data = %p\n",__FILE__,__FUNCTION__,__LINE__,attemptCount,sock,dataSize,data); + MutexSafeWrapper safeMutex(&dataSynchAccessor); bytesSent = ::send(sock, reinterpret_cast(data), dataSize, 0); SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] #2 EAGAIN during send, trying again returned: %d\n",__FILE__,__FUNCTION__,bytesSent); @@ -1012,6 +1028,7 @@ int Socket::receive(void *data, int dataSize) ssize_t bytesReceived = 0; if(isSocketValid() == true) { + MutexSafeWrapper safeMutex(&dataSynchAccessor); bytesReceived = recv(sock, reinterpret_cast(data), dataSize, 0); } if(bytesReceived < 0 && getLastSocketError() != PLATFORM_SOCKET_TRY_AGAIN) { @@ -1024,6 +1041,7 @@ int Socket::receive(void *data, int dataSize) time_t tStartTimer = time(NULL); while((bytesReceived < 0 && getLastSocketError() == PLATFORM_SOCKET_TRY_AGAIN) && (difftime(time(NULL),tStartTimer) <= 5)) { if(Socket::isReadable() == true) { + MutexSafeWrapper safeMutex(&dataSynchAccessor); bytesReceived = recv(sock, reinterpret_cast(data), dataSize, 0); SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] #2 EAGAIN during receive, trying again returned: %d\n",__FILE__,__FUNCTION__,bytesReceived); @@ -1044,6 +1062,7 @@ int Socket::receive(void *data, int dataSize) int Socket::peek(void *data, int dataSize){ ssize_t err = 0; if(isSocketValid() == true) { + MutexSafeWrapper safeMutex(&dataSynchAccessor); err = recv(sock, reinterpret_cast(data), dataSize, MSG_PEEK); } if(err < 0 && getLastSocketError() != PLATFORM_SOCKET_TRY_AGAIN) { @@ -1058,6 +1077,7 @@ int Socket::peek(void *data, int dataSize){ time_t tStartTimer = time(NULL); while((err < 0 && getLastSocketError() == PLATFORM_SOCKET_TRY_AGAIN) && (difftime(time(NULL),tStartTimer) <= 5)) { if(Socket::isReadable() == true) { + MutexSafeWrapper safeMutex(&dataSynchAccessor); err = recv(sock, reinterpret_cast(data), dataSize, MSG_PEEK); SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] #2 EAGAIN during peek, trying again returned: %d\n",__FILE__,__FUNCTION__,err); @@ -1106,7 +1126,11 @@ bool Socket::isReadable() { FD_ZERO(&set); FD_SET(sock, &set); - int i= select(sock+1, &set, NULL, NULL, &tv); + int i = 0; + { + MutexSafeWrapper safeMutex(&dataSynchAccessor); + i= select(sock+1, &set, NULL, NULL, &tv); + } if(i < 0) { if(difftime(time(NULL),lastDebugEvent) >= 1) { lastDebugEvent = time(NULL); @@ -1137,7 +1161,11 @@ bool Socket::isWritable(bool waitOnDelayedResponse) { bool result = false; do { - int i = select(sock+1, NULL, &set, NULL, &tv); + int i = 0; + { + MutexSafeWrapper safeMutex(&dataSynchAccessor); + i = select(sock+1, NULL, &set, NULL, &tv); + } if(i < 0 ) { if(difftime(time(NULL),lastDebugEvent) >= 1) { lastDebugEvent = time(NULL); @@ -1302,7 +1330,10 @@ void ClientSocket::connect(const Ip &ip, int port) FD_ZERO(&myset); FD_SET(sock, &myset); - err = select(sock+1, NULL, &myset, NULL, &tv); + { + MutexSafeWrapper safeMutex(&dataSynchAccessor); + err = select(sock+1, NULL, &myset, NULL, &tv); + } if (err < 0 && getLastSocketError() != PLATFORM_SOCKET_INTERRUPTED) {