From ac992b431dc6037d7090fbdeddc33536f95f5163 Mon Sep 17 00:00:00 2001 From: Mark Vejvoda Date: Sat, 9 Mar 2013 20:57:06 +0000 Subject: [PATCH] - attempt to fix threaded client stability and fixed some server side network bugs to also improve its stability --- .../glest_game/network/client_interface.cpp | 148 ++++++++++++++++-- source/glest_game/network/client_interface.h | 35 ++++- source/glest_game/network/connection_slot.cpp | 2 + .../glest_game/network/network_interface.cpp | 60 +++++++ source/glest_game/network/network_interface.h | 11 +- source/glest_game/type_instances/unit.cpp | 14 +- source/glest_game/world/world.cpp | 22 +++ 7 files changed, 261 insertions(+), 31 deletions(-) diff --git a/source/glest_game/network/client_interface.cpp b/source/glest_game/network/client_interface.cpp index a62b5d15..3558017d 100644 --- a/source/glest_game/network/client_interface.cpp +++ b/source/glest_game/network/client_interface.cpp @@ -37,6 +37,115 @@ using namespace Shared::Util; namespace Glest{ namespace Game{ +// ===================================================== +// class ClientInterfaceThread +// ===================================================== + +ClientInterfaceThread::ClientInterfaceThread(ClientInterface *client) : BaseThread() { + //this->triggerIdMutex = new Mutex(); + this->clientInterface = client; + //this->masterController = NULL; +} + +ClientInterfaceThread::~ClientInterfaceThread() { + this->clientInterface = NULL; + //this->masterController = NULL; + //delete this->triggerIdMutex; + //this->triggerIdMutex = NULL; +} + +void ClientInterfaceThread::setQuitStatus(bool value) { + if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s] Line: %d value = %d\n",__FILE__,__FUNCTION__,__LINE__,value); + + BaseThread::setQuitStatus(value); +// if(value == true) { +// semTaskSignalled.signal(); +// } + + if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__); +} + +bool ClientInterfaceThread::canShutdown(bool deleteSelfIfShutdownDelayed) { + bool ret = (getExecutingTask() == false); + if(ret == false && deleteSelfIfShutdownDelayed == true) { + setDeleteSelfOnExecutionDone(deleteSelfIfShutdownDelayed); + signalQuit(); + } + + return ret; +} + +void ClientInterfaceThread::execute() { + RunningStatusSafeWrapper runningStatus(this); + try { + //setRunningStatus(true); + if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d] ****************** STARTING worker thread this = %p\n",__FILE__,__FUNCTION__,__LINE__,this); + + bool minorDebugPerformance = false; + Chrono chrono; + + //unsigned int idx = 0; + for(;this->clientInterface != NULL;) { + if(getQuitStatus() == true) { + if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + break; + } + + //semTaskSignalled.waitTillSignalled(); + + //printf("In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + //static string masterSlaveOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__); + //MasterSlaveThreadControllerSafeWrapper safeMasterController(masterController,20000,masterSlaveOwnerId); + //printf("In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + + if(getQuitStatus() == true) { + if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + break; + } + + ExecutingTaskSafeWrapper safeExecutingTaskMutex(this); + + //Chrono chrono; + //if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled) chrono.start(); + + //printf("START === Client thread ended\n"); + + while(this->getQuitStatus() == false && clientInterface != NULL) { + clientInterface->updateNetworkFrame(); + } + + //printf("END === Client thread ended\n"); + + //if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took %lld msecs\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,chrono.getMillis()); + + if(getQuitStatus() == true) { + if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + break; + } + } + + if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + if(SystemFlags::VERBOSE_MODE_ENABLED) printf("In [%s::%s Line: %d] ****************** ENDING worker thread this = %p\n",__FILE__,__FUNCTION__,__LINE__,this); + } + catch(const exception &ex) { + //setRunningStatus(false); + + SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",__FILE__,__FUNCTION__,__LINE__,ex.what()); + if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + + throw megaglest_runtime_error(ex.what()); + } + catch(...) { + char szBuf[8096]=""; + snprintf(szBuf,8096,"In [%s::%s %d] UNKNOWN error\n",__FILE__,__FUNCTION__,__LINE__); + SystemFlags::OutputDebug(SystemFlags::debugError,szBuf); + throw megaglest_runtime_error(szBuf); + } + + if(SystemFlags::getSystemSettingType(SystemFlags::debugSystem).enabled) SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__); +} + // ===================================================== // class ClientInterface // ===================================================== @@ -113,7 +222,6 @@ ClientInterface::~ClientInterface() { MutexSafeWrapper safeMutex(networkCommandListThreadAccessor,CODE_AT_LINE); shutdownNetworkCommandListThread(); - //printf("A === Client destructor\n"); if(clientSocket != NULL && clientSocket->isConnected() == true) { @@ -735,6 +843,10 @@ void ClientInterface::updateLobby() { } } +void ClientInterface::updateNetworkFrame() { + this->updateFrame(NULL); +} + void ClientInterface::updateFrame(int *checkFrame) { //printf("#1 ClientInterface::updateFrame\n"); @@ -1019,20 +1131,20 @@ uint64 ClientInterface::getCachedLastPendingFrameCount() { return result; } -void ClientInterface::simpleTask(BaseThread *callingThread) { - Chrono chrono; - if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled) chrono.start(); - - //printf("START === Client thread ended\n"); - - while(callingThread->getQuitStatus() == false && this->quitThread == false) { - updateFrame(NULL); - } - - //printf("END === Client thread ended\n"); - - if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took %lld msecs\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,chrono.getMillis()); -} +//void ClientInterface::simpleTask(BaseThread *callingThread) { +// Chrono chrono; +// if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled) chrono.start(); +// +// //printf("START === Client thread ended\n"); +// +// while(callingThread->getQuitStatus() == false && this->quitThread == false) { +// updateFrame(NULL); +// } +// +// //printf("END === Client thread ended\n"); +// +// if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s Line: %d] took %lld msecs\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,chrono.getMillis()); +//} bool ClientInterface::getNetworkCommand(int frameCount, int currentCachedPendingCommandsIndex) { bool result = false; @@ -1108,9 +1220,13 @@ void ClientInterface::updateKeyframe(int frameCount) { else { if(networkCommandListThread == NULL) { static string mutexOwnerId = string(extractFileFromDirectoryPath(__FILE__).c_str()) + string("_") + intToStr(__LINE__); - networkCommandListThread = new SimpleTaskThread(this,0,0); +// networkCommandListThread = new SimpleTaskThread(this,0,0); +// networkCommandListThread->setUniqueID(mutexOwnerId); +// networkCommandListThread->start(); + networkCommandListThread = new ClientInterfaceThread(this); networkCommandListThread->setUniqueID(mutexOwnerId); networkCommandListThread->start(); + sleep(0); } diff --git a/source/glest_game/network/client_interface.h b/source/glest_game/network/client_interface.h index 91590eda..5c8fcbde 100644 --- a/source/glest_game/network/client_interface.h +++ b/source/glest_game/network/client_interface.h @@ -28,12 +28,36 @@ using std::vector; namespace Glest{ namespace Game{ +class ClientInterface; + +class ClientInterfaceThread : public BaseThread, public SlaveThreadControllerInterface { +protected: + + ClientInterface *clientInterface; + //Semaphore semTaskSignalled; + //Mutex *triggerIdMutex; + //MasterSlaveThreadController *masterController; + + virtual void setQuitStatus(bool value); + +public: + ClientInterfaceThread(ClientInterface *client); + virtual ~ClientInterfaceThread(); + virtual void execute(); + + //virtual void setMasterController(MasterSlaveThreadController *master) { masterController = master; } + virtual void setMasterController(MasterSlaveThreadController *master) { } + virtual void signalSlave(void *userdata) { } + + virtual bool canShutdown(bool deleteSelfIfShutdownDelayed=false); +}; + // ===================================================== // class ClientInterface // ===================================================== -class ClientInterface: public GameNetworkInterface, - public SimpleTaskCallbackInterface { +class ClientInterface: public GameNetworkInterface { + //public SimpleTaskCallbackInterface { private: static const int messageWaitTimeout; static const int waitSleepTime; @@ -62,7 +86,9 @@ private: int sessionKey; int serverFTPPort; - SimpleTaskThread *networkCommandListThread; + //SimpleTaskThread *networkCommandListThread; + ClientInterfaceThread *networkCommandListThread; + Mutex *networkCommandListThreadAccessor; std::map cachedPendingCommands; //commands ready to be given uint64 cachedPendingCommandsIndex; @@ -152,7 +178,8 @@ public: void broadcastGameSetup(const GameSettings *gameSettings); void broadcastGameStart(const GameSettings *gameSettings); - virtual void simpleTask(BaseThread *callingThread); + //virtual void simpleTask(BaseThread *callingThread); + void updateNetworkFrame(); virtual void saveGame(XmlNode *rootNode) {}; diff --git a/source/glest_game/network/connection_slot.cpp b/source/glest_game/network/connection_slot.cpp index 846a161d..742cca48 100644 --- a/source/glest_game/network/connection_slot.cpp +++ b/source/glest_game/network/connection_slot.cpp @@ -325,6 +325,7 @@ ConnectionSlot::ConnectionSlot(ServerInterface* serverInterface, int playerIndex this->canAcceptConnections = true; this->startInGameConnectionLaunch = false; this->sentSavedGameInfo = false; + this->unPauseForInGameConnection = false; this->skipLagCheck = false; this->joinGameInProgress = false; @@ -1459,6 +1460,7 @@ void ConnectionSlot::close() { this->skipLagCheck = false; this->joinGameInProgress = false; this->sentSavedGameInfo = false; + this->unPauseForInGameConnection = false; this->ready= false; this->connectedTime = 0; diff --git a/source/glest_game/network/network_interface.cpp b/source/glest_game/network/network_interface.cpp index 2151cb39..7d6add3d 100644 --- a/source/glest_game/network/network_interface.cpp +++ b/source/glest_game/network/network_interface.cpp @@ -40,6 +40,35 @@ DisplayMessageFunction NetworkInterface::pCB_DisplayMessage = NULL; Vec3f MarkedCell::static_system_marker_color(MAGENTA.x,MAGENTA.y,MAGENTA.z); +NetworkInterface::NetworkInterface() { + networkAccessMutex = new Mutex(); +} + +NetworkInterface::~NetworkInterface() { + delete networkAccessMutex; + networkAccessMutex = NULL; +} + +void NetworkInterface::addChatInfo(const ChatMsgInfo &msg) { + static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__); + MutexSafeWrapper safeMutex(networkAccessMutex,mutexOwnerId); + + chatTextList.push_back(msg); +} + +void NetworkInterface::addMarkedCell(const MarkedCell &msg) { + static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__); + MutexSafeWrapper safeMutex(networkAccessMutex,mutexOwnerId); + + markedCellList.push_back(msg); +} +void NetworkInterface::addUnMarkedCell(const UnMarkedCell &msg) { + static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__); + MutexSafeWrapper safeMutex(networkAccessMutex,mutexOwnerId); + + unmarkedCellList.push_back(msg); +} + void NetworkInterface::sendMessage(NetworkMessage* networkMessage){ Socket* socket= getSocket(false); @@ -112,6 +141,10 @@ void NetworkInterface::DisplayErrorMessage(string sErr, bool closeSocket) { std::vector NetworkInterface::getChatTextList(bool clearList) { std::vector result; + + static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__); + MutexSafeWrapper safeMutex(networkAccessMutex,mutexOwnerId); + if(chatTextList.empty() == false) { result = chatTextList; @@ -123,6 +156,9 @@ std::vector NetworkInterface::getChatTextList(bool clearList) { } void NetworkInterface::clearChatInfo() { + static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__); + MutexSafeWrapper safeMutex(networkAccessMutex,mutexOwnerId); + if(chatTextList.empty() == false) { if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] chatTextList.size() = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,chatTextList.size()); chatTextList.clear(); @@ -131,6 +167,10 @@ void NetworkInterface::clearChatInfo() { std::vector NetworkInterface::getMarkedCellList(bool clearList) { std::vector result; + + static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__); + MutexSafeWrapper safeMutex(networkAccessMutex,mutexOwnerId); + if(markedCellList.empty() == false) { result = markedCellList; @@ -142,6 +182,9 @@ std::vector NetworkInterface::getMarkedCellList(bool clearList) { } void NetworkInterface::clearMarkedCellList() { + static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__); + MutexSafeWrapper safeMutex(networkAccessMutex,mutexOwnerId); + if(markedCellList.empty() == false) { if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] markedCellList.size() = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,markedCellList.size()); markedCellList.clear(); @@ -150,6 +193,10 @@ void NetworkInterface::clearMarkedCellList() { std::vector NetworkInterface::getUnMarkedCellList(bool clearList) { std::vector result; + + static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__); + MutexSafeWrapper safeMutex(networkAccessMutex,mutexOwnerId); + if(unmarkedCellList.empty() == false) { result = unmarkedCellList; @@ -161,6 +208,9 @@ std::vector NetworkInterface::getUnMarkedCellList(bool clearList) } void NetworkInterface::clearUnMarkedCellList() { + static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__); + MutexSafeWrapper safeMutex(networkAccessMutex,mutexOwnerId); + if(unmarkedCellList.empty() == false) { if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] unmarkedCellList.size() = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,unmarkedCellList.size()); unmarkedCellList.clear(); @@ -169,6 +219,10 @@ void NetworkInterface::clearUnMarkedCellList() { std::vector NetworkInterface::getHighlightedCellList(bool clearList) { std::vector result; + + static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__); + MutexSafeWrapper safeMutex(networkAccessMutex,mutexOwnerId); + if(highlightedCellList.empty() == false) { result = highlightedCellList; @@ -180,6 +234,9 @@ std::vector NetworkInterface::getHighlightedCellList(bool clearList) } void NetworkInterface::clearHighlightedCellList() { + static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__); + MutexSafeWrapper safeMutex(networkAccessMutex,mutexOwnerId); + if(highlightedCellList.empty() == false) { if(SystemFlags::getSystemSettingType(SystemFlags::debugNetwork).enabled) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] markedCellList.size() = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,markedCellList.size()); highlightedCellList.clear(); @@ -187,6 +244,9 @@ void NetworkInterface::clearHighlightedCellList() { } void NetworkInterface::setHighlightedCell(const MarkedCell &msg){ + static string mutexOwnerId = string(__FILE__) + string("_") + intToStr(__LINE__); + MutexSafeWrapper safeMutex(networkAccessMutex,mutexOwnerId); + for(int idx = 0; idx < highlightedCellList.size(); idx++) { MarkedCell mc = highlightedCellList[idx]; if(mc.getFactionIndex()==msg.getFactionIndex()){ diff --git a/source/glest_game/network/network_interface.h b/source/glest_game/network/network_interface.h index 9a7b1c95..9414baba 100644 --- a/source/glest_game/network/network_interface.h +++ b/source/glest_game/network/network_interface.h @@ -185,12 +185,15 @@ protected: std::vector highlightedCellList; + Mutex *networkAccessMutex; + public: static const int readyWaitTimeout; GameSettings gameSettings; public: - virtual ~NetworkInterface(){} + NetworkInterface(); + virtual ~NetworkInterface(); virtual Socket* getSocket(bool mutexLock=true)= 0; virtual void close()= 0; @@ -228,15 +231,15 @@ public: std::vector getChatTextList(bool clearList); void clearChatInfo(); - void addChatInfo(const ChatMsgInfo &msg) { chatTextList.push_back(msg); } + void addChatInfo(const ChatMsgInfo &msg); std::vector getMarkedCellList(bool clearList); void clearMarkedCellList(); - void addMarkedCell(const MarkedCell &msg) { markedCellList.push_back(msg); } + void addMarkedCell(const MarkedCell &msg); std::vector getUnMarkedCellList(bool clearList); void clearUnMarkedCellList(); - void addUnMarkedCell(const UnMarkedCell &msg) { unmarkedCellList.push_back(msg); } + void addUnMarkedCell(const UnMarkedCell &msg); std::vector getHighlightedCellList(bool clearList); void clearHighlightedCellList(); diff --git a/source/glest_game/type_instances/unit.cpp b/source/glest_game/type_instances/unit.cpp index 5349a32e..8b3c36ba 100644 --- a/source/glest_game/type_instances/unit.cpp +++ b/source/glest_game/type_instances/unit.cpp @@ -1816,17 +1816,17 @@ const CommandType *Unit::computeCommandType(const Vec2i &pos, const Unit *target targetUnit->getType() != NULL && targetUnit->getType()->getStore(this->getLoadType()) > 0) { - const HarvestCommandType *previousHarvestCmd = this->getType()->getFirstHarvestCommand(this->getLoadType(),this->getFaction()); - if(previousHarvestCmd != NULL) { + //const HarvestCommandType *previousHarvestCmd = this->getType()->getFirstHarvestCommand(this->getLoadType(),this->getFaction()); + //if(previousHarvestCmd != NULL) { //printf("\n#1 return harvested resources\n\n"); //this->setCurrSkill(previousHarvestCmd->getStopLoadedSkillType()); // make sure we use the right harvest animation - commandType = type->getFirstHarvestEmergencyReturnCommand(); - } - else { + commandType = type->getFirstHarvestEmergencyReturnCommand(); + //} + //else { //printf("\n#2 return harvested resources\n\n"); //this->setCurrSkill(hct->getStopLoadedSkillType()); - commandType = type->getFirstHarvestEmergencyReturnCommand(); - } + // commandType = type->getFirstHarvestEmergencyReturnCommand(); + //} } } } diff --git a/source/glest_game/world/world.cpp b/source/glest_game/world/world.cpp index 0b49641e..e1235cb1 100644 --- a/source/glest_game/world/world.cpp +++ b/source/glest_game/world/world.cpp @@ -348,6 +348,28 @@ void World::init(Game *game, bool createUnits, bool initFactions){ if(loadWorldNode != NULL) { map.loadGame(loadWorldNode,this); + + if(fogOfWar == false) { + for(int i=0; i< map.getSurfaceW(); ++i) { + for(int j=0; j< map.getSurfaceH(); ++j) { + + SurfaceCell *sc= map.getSurfaceCell(i, j); + if(sc == NULL) { + throw megaglest_runtime_error("sc == NULL"); + } + + for (int k = 0; k < GameConstants::maxPlayers; k++) { + //sc->setExplored(k, (game->getGameSettings()->getFlagTypes1() & ft1_show_map_resources) == ft1_show_map_resources); + sc->setVisible(k, !fogOfWar); + } + for (int k = GameConstants::maxPlayers; k < GameConstants::maxPlayers + GameConstants::specialFactions; k++) { + sc->setExplored(k, true); + sc->setVisible(k, true); + } + } + } + } + minimap.loadGame(loadWorldNode); }