diff --git a/source/glest_game/game/commander.cpp b/source/glest_game/game/commander.cpp index 31070517..f4e679e4 100644 --- a/source/glest_game/game/commander.cpp +++ b/source/glest_game/game/commander.cpp @@ -37,6 +37,135 @@ namespace Glest{ namespace Game{ // ===================== PUBLIC ======================== +CommanderNetworkThread::CommanderNetworkThread() : BaseThread() { + this->idStatus = make_pair(-1,false); + this->commanderInterface = NULL; +} + +CommanderNetworkThread::CommanderNetworkThread(CommanderNetworkCallbackInterface *commanderInterface) : BaseThread() { + this->idStatus = make_pair(-1,false); + this->commanderInterface = commanderInterface; +} + +void CommanderNetworkThread::setQuitStatus(bool value) { + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d value = %d\n",__FILE__,__FUNCTION__,__LINE__,value); + + BaseThread::setQuitStatus(value); + if(value == true) { + signalUpdate(-1); + } + + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__); +} + +void CommanderNetworkThread::signalUpdate(int id) { + //SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] event = %p\n",__FILE__,__FUNCTION__,__LINE__,event); + + MutexSafeWrapper safeMutex(&idMutex); + this->idStatus.first = id; + this->idStatus.second = false; + safeMutex.ReleaseLock(); + + //SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__); + semTaskSignalled.signal(); +} + +void CommanderNetworkThread::setTaskCompleted(int id) { + //SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__); + + MutexSafeWrapper safeMutex(&idMutex); + this->idStatus.second = true; + safeMutex.ReleaseLock(); + + //SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__); +} + +bool CommanderNetworkThread::isSignalCompleted(int id) { + //SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] slotIndex = %d\n",__FILE__,__FUNCTION__,__LINE__,slotIndex); + MutexSafeWrapper safeMutex(&idMutex); + bool result = this->idStatus.second; + safeMutex.ReleaseLock(); + //if(result == false) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] slotIndex = %d, result = %d\n",__FILE__,__FUNCTION__,__LINE__,slotIndex,result); + return result; +} + +void CommanderNetworkThread::execute() { + RunningStatusSafeWrapper runningStatus(this); + try { + //setRunningStatus(true); + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + + unsigned int idx = 0; + for(;this->commanderInterface != NULL;) { + if(getQuitStatus() == true) { + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + break; + } + + //SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + semTaskSignalled.waitTillSignalled(); + //SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__); + + if(getQuitStatus() == true) { + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + break; + } + + //SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + + MutexSafeWrapper safeMutex(&idMutex); + if(idStatus.first > 0) { + int updateId = this->idStatus.first; + safeMutex.ReleaseLock(); + + this->commanderInterface->commanderNetworkUpdateTask(updateId); + setTaskCompleted(updateId); + } + else { + safeMutex.ReleaseLock(); + } + //SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__); + + if(getQuitStatus() == true) { + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + break; + } + //SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__); + } + + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + } + catch(const exception &ex) { + //setRunningStatus(false); + + SystemFlags::OutputDebug(SystemFlags::debugError,"In [%s::%s Line: %d] Error [%s]\n",__FILE__,__FUNCTION__,__LINE__,ex.what()); + SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + + throw runtime_error(ex.what()); + } + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__); + //setRunningStatus(false); +} + +// ===================================================== +// class +// ===================================================== + +Commander::Commander() { + this->networkThread = new CommanderNetworkThread(this); + this->networkThread->setUniqueID(__FILE__); + this->networkThread->start(); +} + +Commander::~Commander() { + if(BaseThread::shutdownAndWait(networkThread) == true) { + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + delete networkThread; + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + } + networkThread = NULL; +} + void Commander::init(World *world){ this->world= world; } @@ -325,11 +454,29 @@ CommandResult Commander::pushNetworkCommand(const NetworkCommand* networkCommand return cr; } -void Commander::updateNetwork() { +void Commander::signalNetworkUpdate(Game *game) { + if(this->networkThread != NULL) { + this->game = game; + this->networkThread->signalUpdate(1); + + time_t elapsedWait = time(NULL); + for(;difftime(time(NULL),elapsedWait) <= 4 && + this->networkThread->isSignalCompleted(1) == false;) { + game->render(); + } + } +} + +void Commander::commanderNetworkUpdateTask(int id) { + updateNetwork(game); +} + +void Commander::updateNetwork(Game *game) { NetworkManager &networkManager= NetworkManager::getInstance(); //check that this is a keyframe - GameSettings *gameSettings = this->world->getGame()->getGameSettings(); + //GameSettings *gameSettings = this->world->getGame()->getGameSettings(); + GameSettings *gameSettings = game->getGameSettings(); if( networkManager.isNetworkGame() == false || (world->getFrameCount() % gameSettings->getNetworkFramePeriod()) == 0) { diff --git a/source/glest_game/game/commander.h b/source/glest_game/game/commander.h index 471a7bdc..87737a9b 100644 --- a/source/glest_game/game/commander.h +++ b/source/glest_game/game/commander.h @@ -18,6 +18,7 @@ #include "selection.h" #include "command_type.h" #include "platform_util.h" +#include "base_thread.h" #include "leak_dumper.h" using std::vector; @@ -32,6 +33,7 @@ class Unit; class Command; class CommandType; class NetworkCommand; +class Game; // ===================================================== // class Commander @@ -39,7 +41,35 @@ class NetworkCommand; /// Gives commands to the units // ===================================================== -class Commander{ +// +// This interface describes the methods a callback object must implement +// +class CommanderNetworkCallbackInterface { +public: + virtual void commanderNetworkUpdateTask(int id) = 0; +}; + +class CommanderNetworkThread : public BaseThread +{ +protected: + + CommanderNetworkCallbackInterface *commanderInterface; + Semaphore semTaskSignalled; + + virtual void setQuitStatus(bool value); + virtual void setTaskCompleted(int id); + Mutex idMutex; + std::pair idStatus; + +public: + CommanderNetworkThread(); + CommanderNetworkThread(CommanderNetworkCallbackInterface *commanderInterface); + virtual void execute(); + void signalUpdate(int id); + bool isSignalCompleted(int id); +}; + +class Commander : public CommanderNetworkCallbackInterface { private: typedef vector CommandResultContainer; @@ -47,9 +77,16 @@ private: World *world; Chrono perfTimer; + CommanderNetworkThread *networkThread; + Game *game; + public: + Commander(); + ~Commander(); + + void signalNetworkUpdate(Game *game); void init(World *world); - void updateNetwork(); + void updateNetwork(Game *game); CommandResult tryGiveCommand(const Selection *selection, const CommandType *commandType, const Vec2i &pos, const UnitType* unitType, @@ -68,6 +105,8 @@ private: CommandResult computeResult(const CommandResultContainer &results) const; void giveNetworkCommand(NetworkCommand* networkCommand) const; Command* buildCommand(const NetworkCommand* networkCommand) const; + + virtual void commanderNetworkUpdateTask(int id); }; }} //end namespace diff --git a/source/glest_game/game/game.cpp b/source/glest_game/game/game.cpp index 1bd5723b..c67a542e 100644 --- a/source/glest_game/game/game.cpp +++ b/source/glest_game/game/game.cpp @@ -735,7 +735,9 @@ void Game::update() { //SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); // Commander - commander.updateNetwork(); + //commander.updateNetwork(); + commander.signalNetworkUpdate(this); + if(chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s] Line: %d took msecs: %lld [commander updateNetwork i = %d]\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis(),i); if(chrono.getMillis() > 0) chrono.start(); diff --git a/source/glest_game/network/connection_slot.cpp b/source/glest_game/network/connection_slot.cpp index a573329f..2e5df4f9 100644 --- a/source/glest_game/network/connection_slot.cpp +++ b/source/glest_game/network/connection_slot.cpp @@ -62,30 +62,60 @@ void ConnectionSlotThread::signalUpdate(ConnectionSlotEvent *event) { if(event != NULL) { MutexSafeWrapper safeMutex(&triggerIdMutex); - eventList.push_back(event); + eventList.push_back(*event); safeMutex.ReleaseLock(); } //SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__); semTaskSignalled.signal(); } -void ConnectionSlotThread::setTaskCompleted(ConnectionSlotEvent *event) { +void ConnectionSlotThread::setTaskCompleted(int eventId) { //SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__); - if(event != NULL) { + if(eventId > 0) { MutexSafeWrapper safeMutex(&triggerIdMutex); - event->eventCompleted = true; - eventList.erase(eventList.begin()); + //event->eventCompleted = true; + for(int i = 0; i < eventList.size(); ++i) { + ConnectionSlotEvent &slotEvent = eventList[i]; + if(slotEvent.eventId == eventId) { + //eventList.erase(eventList.begin() + i); + slotEvent.eventCompleted = true; + break; + } + } safeMutex.ReleaseLock(); } //SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__); } +void ConnectionSlotThread::purgeCompletedEvents() { + MutexSafeWrapper safeMutex(&triggerIdMutex); + //event->eventCompleted = true; + for(int i = eventList.size() - 1; i >= 0; i--) { + ConnectionSlotEvent &slotEvent = eventList[i]; + if(slotEvent.eventCompleted == true) { + eventList.erase(eventList.begin() + i); + } + } + safeMutex.ReleaseLock(); +} + bool ConnectionSlotThread::isSignalCompleted(ConnectionSlotEvent *event) { //SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] slotIndex = %d\n",__FILE__,__FUNCTION__,__LINE__,slotIndex); MutexSafeWrapper safeMutex(&triggerIdMutex); - bool result = (event != NULL ? event->eventCompleted : true); + //bool result = (event != NULL ? event->eventCompleted : true); + bool result = false; + if(event != NULL) { + for(int i = 0; i < eventList.size(); ++i) { + ConnectionSlotEvent &slotEvent = eventList[i]; + if(slotEvent.eventId == event->eventId) { + //eventList.erase(eventList.begin() + i); + result = slotEvent.eventCompleted; + break; + } + } + } safeMutex.ReleaseLock(); //if(result == false) SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] slotIndex = %d, result = %d\n",__FILE__,__FUNCTION__,__LINE__,slotIndex,result); return result; @@ -118,11 +148,22 @@ void ConnectionSlotThread::execute() { MutexSafeWrapper safeMutex(&triggerIdMutex); int eventCount = eventList.size(); if(eventCount > 0) { - ConnectionSlotEvent *event = eventList[0]; + ConnectionSlotEvent *event = NULL; + + for(int i = 0; i < eventList.size(); ++i) { + ConnectionSlotEvent &slotEvent = eventList[i]; + if(slotEvent.eventCompleted == false) { + event = &slotEvent; + break; + } + } + safeMutex.ReleaseLock(); - this->slotInterface->slotUpdateTask(event); - setTaskCompleted(event); + if(event != NULL) { + this->slotInterface->slotUpdateTask(event); + setTaskCompleted(event->eventId); + } } else { safeMutex.ReleaseLock(); @@ -201,6 +242,9 @@ ConnectionSlot::~ConnectionSlot() { } void ConnectionSlot::update() { + if(slotThreadWorker != NULL) { + slotThreadWorker->purgeCompletedEvents(); + } update(true); } diff --git a/source/glest_game/network/connection_slot.h b/source/glest_game/network/connection_slot.h index 33fb206b..bafe8109 100644 --- a/source/glest_game/network/connection_slot.h +++ b/source/glest_game/network/connection_slot.h @@ -49,6 +49,7 @@ public: networkMessage = NULL; socketTriggered = false; eventCompleted = false; + eventId = -1; } int64 triggerId; @@ -57,6 +58,7 @@ public: const NetworkMessage *networkMessage; bool socketTriggered; bool eventCompleted; + int64 eventId; }; // @@ -74,11 +76,11 @@ protected: ConnectionSlotCallbackInterface *slotInterface; Semaphore semTaskSignalled; Mutex triggerIdMutex; - vector eventList; + vector eventList; int slotIndex; virtual void setQuitStatus(bool value); - virtual void setTaskCompleted(ConnectionSlotEvent *event); + virtual void setTaskCompleted(int eventId); public: ConnectionSlotThread(int slotIndex); @@ -87,6 +89,8 @@ public: void signalUpdate(ConnectionSlotEvent *event); bool isSignalCompleted(ConnectionSlotEvent *event); int getSlotIndex() const {return slotIndex; } + + void purgeCompletedEvents(); }; // ===================================================== diff --git a/source/glest_game/network/server_interface.cpp b/source/glest_game/network/server_interface.cpp index fb872379..43ac864a 100644 --- a/source/glest_game/network/server_interface.cpp +++ b/source/glest_game/network/server_interface.cpp @@ -58,10 +58,11 @@ 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 = 1; +double MAX_CLIENT_WAIT_SECONDS_FOR_PAUSE = 2; ServerInterface::ServerInterface() : GameNetworkInterface() { SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + nextEventId = 1; gameHasBeenInitiated = false; exitServer = false; gameSettingsUpdateCount = 0; @@ -349,11 +350,21 @@ int ServerInterface::getConnectedSlotCount() { return connectedSlotCount; } +int64 ServerInterface::getNextEventId() { + nextEventId++; + + // Rollover when # gets large + if(nextEventId > INT_MAX) { + nextEventId = 1; + } + return nextEventId; +} + void ServerInterface::slotUpdateTask(ConnectionSlotEvent *event) { SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); if(event != NULL) { - SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] event->eventType = %d\n",__FILE__,__FUNCTION__,__LINE__,event->eventType); if(event->eventType == eSendSocketData) { SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] before sendMessage, event->networkMessage = %p\n",__FILE__,__FUNCTION__,event->networkMessage); @@ -364,6 +375,9 @@ void ServerInterface::slotUpdateTask(ConnectionSlotEvent *event) { SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); updateSlot(event); } + else { + SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + } } SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); } @@ -536,6 +550,7 @@ bool ServerInterface::signalClientReceiveCommands(ConnectionSlot* connectionSlot event.connectionSlot = connectionSlot; event.socketTriggered = socketTriggered; event.triggerId = slotIndex; + event.eventId = getNextEventId(); //SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d] slotIndex = %d\n",__FILE__,__FUNCTION__,__LINE__,slotIndex); @@ -580,6 +595,7 @@ void ServerInterface::validateConnectedClients() { void ServerInterface::update() { //SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s] Line: %d\n",__FILE__,__FUNCTION__,__LINE__); + const int MAX_SLOT_THREAD_WAIT_TIME = 3; std::vector errorMsgList; try { // The first thing we will do is check all clients to ensure they have @@ -619,7 +635,6 @@ void ServerInterface::update() { // Step #2 check all connection slot worker threads for completed status time_t waitForThreadElapsed = time(NULL); - const int MAX_SLOT_THREAD_WAIT_TIME = 6; std::map slotsCompleted; for(bool threadsDone = false; exitServer == false && threadsDone == false && @@ -725,7 +740,10 @@ void ServerInterface::update() { 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); + bool socketTriggered = false; + if(connectionSlot->getSocket() != NULL && connectionSlot->getSocket()->getSocketId() > 0) { + socketTriggered = socketTriggeredList[connectionSlot->getSocket()->getSocketId()]; + } ConnectionSlotEvent &event = eventList[i]; mapSlotSignalledList[i] = signalClientReceiveCommands(connectionSlot,i,socketTriggered,event); threadsDone = false; @@ -1249,6 +1267,7 @@ void ServerInterface::broadcastMessage(const NetworkMessage* networkMessage, int event.connectionSlot = connectionSlot; event.socketTriggered = true; event.triggerId = i; + event.eventId = getNextEventId(); SystemFlags::OutputDebug(SystemFlags::debugNetwork,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); @@ -1574,7 +1593,8 @@ void ServerInterface::simpleTask(BaseThread *callingThread) { //SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line %d]\n",__FILE__,__FUNCTION__,__LINE__); MutexSafeWrapper safeMutex(&masterServerThreadAccessor,intToStr(__LINE__)); - if(difftime(time(NULL),lastMasterserverHeartbeatTime) >= 30) { + const int MASTERSERVER_HEARTBEAT_GAME_STATUS_SECONDS = 30; + if(difftime(time(NULL),lastMasterserverHeartbeatTime) >= MASTERSERVER_HEARTBEAT_GAME_STATUS_SECONDS) { SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line %d]\n",__FILE__,__FUNCTION__,__LINE__); lastMasterserverHeartbeatTime = time(NULL); diff --git a/source/glest_game/network/server_interface.h b/source/glest_game/network/server_interface.h index 69709098..7214a2c8 100644 --- a/source/glest_game/network/server_interface.h +++ b/source/glest_game/network/server_interface.h @@ -55,6 +55,7 @@ private: Shared::PlatformCommon::FTPServerThread *ftpServer; bool exitServer; + int64 nextEventId; public: ServerInterface(); @@ -135,6 +136,8 @@ private: void validateConnectedClients(); std::map publishToMasterserver(); + + int64 getNextEventId(); }; }}//end namespace diff --git a/source/shared_lib/include/sound/openal/sound_player_openal.h b/source/shared_lib/include/sound/openal/sound_player_openal.h index cf2d5962..d5376039 100644 --- a/source/shared_lib/include/sound/openal/sound_player_openal.h +++ b/source/shared_lib/include/sound/openal/sound_player_openal.h @@ -69,7 +69,7 @@ public: protected: friend class SoundPlayerOpenAL; static const size_t STREAMBUFFERSIZE = 1024 * 500; - static const size_t STREAMFRAGMENTS = 10; + static const size_t STREAMFRAGMENTS = 5; static const size_t STREAMFRAGMENTSIZE = STREAMBUFFERSIZE / STREAMFRAGMENTS;