diff --git a/dAuthServer/AuthServer.cpp b/dAuthServer/AuthServer.cpp index 3fd4b0bf..e4d8a052 100644 --- a/dAuthServer/AuthServer.cpp +++ b/dAuthServer/AuthServer.cpp @@ -138,7 +138,7 @@ int main(int argc, char** argv) { } else framesSinceLastSQLPing++; //Sleep our thread since auth can afford to. - t += std::chrono::milliseconds(mediumFramerate); //Auth can run at a lower "fps" + t += std::chrono::milliseconds(mediumFrameDelta); //Auth can run at a lower "fps" std::this_thread::sleep_until(t); } diff --git a/dChatServer/ChatServer.cpp b/dChatServer/ChatServer.cpp index f3b2c123..8ae1a9bd 100644 --- a/dChatServer/ChatServer.cpp +++ b/dChatServer/ChatServer.cpp @@ -160,7 +160,7 @@ int main(int argc, char** argv) { } else framesSinceLastSQLPing++; //Sleep our thread since auth can afford to. - t += std::chrono::milliseconds(mediumFramerate); //Chat can run at a lower "fps" + t += std::chrono::milliseconds(mediumFrameDelta); //Chat can run at a lower "fps" std::this_thread::sleep_until(t); } diff --git a/dCommon/dEnums/dCommonVars.h b/dCommon/dEnums/dCommonVars.h index f64d496f..f3d02bf7 100644 --- a/dCommon/dEnums/dCommonVars.h +++ b/dCommon/dEnums/dCommonVars.h @@ -6,15 +6,22 @@ #include #include #include -#include "../thirdparty/raknet/Source/BitStream.h" +#include "BitStream.h" #pragma warning (disable:4251) //Disables SQL warnings typedef int RESTICKET; -const int highFrameRate = 16; //60fps -const int mediumFramerate = 33; //30fps -const int lowFramerate = 66; //15fps +#define FRAMES_TO_MS(x) 1000 / x + +//=========== FRAME TIMINGS =========== +constexpr uint32_t highFramerate = 60; +constexpr uint32_t mediumFramerate = 30; +constexpr uint32_t lowFramerate = 15; + +constexpr uint32_t highFrameDelta = FRAMES_TO_MS(highFramerate); +constexpr uint32_t mediumFrameDelta = FRAMES_TO_MS(mediumFramerate); +constexpr uint32_t lowFrameDelta = FRAMES_TO_MS(lowFramerate); //========== MACROS =========== diff --git a/dMasterServer/InstanceManager.cpp b/dMasterServer/InstanceManager.cpp index 868bf6ee..b277adbf 100644 --- a/dMasterServer/InstanceManager.cpp +++ b/dMasterServer/InstanceManager.cpp @@ -31,6 +31,15 @@ Instance* InstanceManager::GetInstance(LWOMAPID mapID, bool isFriendTransfer, LW Instance* instance = FindInstance(mapID, isFriendTransfer, cloneID); if (instance) return instance; + // If we are shutting down, return a nullptr so a new instance is not created. + if (m_IsShuttingDown) { + Game::logger->Log("InstanceManager", + "Tried to create a new instance map/instance/clone %i/%i/%i, but Master is shutting down.", + mapID, + m_LastInstanceID + 1, + cloneID); + return nullptr; + } //TODO: Update this so that the IP is read from a configuration file instead int softCap = 8; @@ -238,7 +247,7 @@ void InstanceManager::RedirectPendingRequests(Instance* instance) { for (const auto& request : instance->GetPendingAffirmations()) { auto* in = Game::im->GetInstance(zoneId.GetMapID(), false, zoneId.GetCloneID()); - if (!in->GetIsReady()) // Instance not ready, make a pending request + if (in && !in->GetIsReady()) // Instance not ready, make a pending request { in->GetPendingRequests().push_back(request); @@ -295,6 +304,15 @@ Instance* InstanceManager::CreatePrivateInstance(LWOMAPID mapID, LWOCLONEID clon return instance; } + if (m_IsShuttingDown) { + Game::logger->Log("InstanceManager", + "Tried to create a new private instance map/instance/clone %i/%i/%i, but Master is shutting down.", + mapID, + m_LastInstanceID + 1, + cloneID); + return nullptr; + } + int maxPlayers = 999; uint32_t port = GetFreePort(); diff --git a/dMasterServer/InstanceManager.h b/dMasterServer/InstanceManager.h index 2c5083d4..5f48f93b 100644 --- a/dMasterServer/InstanceManager.h +++ b/dMasterServer/InstanceManager.h @@ -128,6 +128,7 @@ public: Instance* CreatePrivateInstance(LWOMAPID mapID, LWOCLONEID cloneID, const std::string& password); Instance* FindPrivateInstance(const std::string& password); + void SetIsShuttingDown(bool value) { this->m_IsShuttingDown = value; }; private: dLogger* mLogger; @@ -136,6 +137,11 @@ private: unsigned short m_LastPort; LWOINSTANCEID m_LastInstanceID; + /** + * Whether or not the master server is currently shutting down. + */ + bool m_IsShuttingDown = false; + //Private functions: bool IsInstanceFull(Instance* instance, bool isFriendTransfer); int GetSoftCap(LWOMAPID mapID); diff --git a/dMasterServer/MasterServer.cpp b/dMasterServer/MasterServer.cpp index bfe9f323..ed94ff83 100644 --- a/dMasterServer/MasterServer.cpp +++ b/dMasterServer/MasterServer.cpp @@ -63,6 +63,8 @@ SystemAddress authServerMasterPeerSysAddr; SystemAddress chatServerMasterPeerSysAddr; int main(int argc, char** argv) { + constexpr uint32_t masterFramerate = mediumFramerate; + constexpr uint32_t masterFrameDelta = mediumFrameDelta; Diagnostics::SetProcessName("Master"); Diagnostics::SetProcessFileName(argv[0]); Diagnostics::Initialize(); @@ -287,6 +289,10 @@ int main(int argc, char** argv) { auto t = std::chrono::high_resolution_clock::now(); Packet* packet = nullptr; + constexpr uint32_t logFlushTime = 15 * masterFramerate; + constexpr uint32_t sqlPingTime = 10 * 60 * masterFramerate; + constexpr uint32_t shutdownUniverseTime = 10 * 60 * masterFramerate; + constexpr uint32_t instanceReadyTimeout = 30 * masterFramerate; int framesSinceLastFlush = 0; int framesSinceLastSQLPing = 0; int framesSinceKillUniverseCommand = 0; @@ -303,14 +309,14 @@ int main(int argc, char** argv) { } //Push our log every 15s: - if (framesSinceLastFlush >= 900) { + if (framesSinceLastFlush >= logFlushTime) { Game::logger->Flush(); framesSinceLastFlush = 0; } else framesSinceLastFlush++; //Every 10 min we ping our sql server to keep it alive hopefully: - if (framesSinceLastSQLPing >= 40000) { + if (framesSinceLastSQLPing >= sqlPingTime) { //Find out the master's IP for absolutely no reason: std::string masterIP; int masterPort; @@ -330,7 +336,7 @@ int main(int argc, char** argv) { //10m shutdown for universe kill command if (Game::shouldShutdown) { - if (framesSinceKillUniverseCommand >= 40000) { + if (framesSinceKillUniverseCommand >= shutdownUniverseTime) { //Break main loop and exit break; } else @@ -354,7 +360,7 @@ int main(int argc, char** argv) { instance->SetAffirmationTimeout(affirmTimeout); - if (affirmTimeout == 1000) { + if (affirmTimeout == instanceReadyTimeout) { instance->Shutdown(); instance->SetIsShuttingDown(true); @@ -373,7 +379,7 @@ int main(int argc, char** argv) { } } - t += std::chrono::milliseconds(highFrameRate); + t += std::chrono::milliseconds(masterFrameDelta); std::this_thread::sleep_until(t); } return FinalizeShutdown(EXIT_SUCCESS); @@ -424,7 +430,6 @@ void HandlePacket(Packet* packet) { if (instance) { LWOZONEID zoneID = instance->GetZoneID(); //Get the zoneID so we can recreate a server Game::im->RemoveInstance(instance); //Delete the old - //Game::im->GetInstance(zoneID.GetMapID(), false, 0); //Create the new } if (packet->systemAddress == chatServerMasterPeerSysAddr) { @@ -465,14 +470,17 @@ void HandlePacket(Packet* packet) { inStream.Read(mythranShift); inStream.Read(zoneID); inStream.Read(zoneClone); - + if (shutdownSequenceStarted) { + Game::logger->Log("MasterServer", "Shutdown sequence has been started. Not creating a new zone."); + break; + } Instance* in = Game::im->GetInstance(zoneID, false, zoneClone); for (auto* instance : Game::im->GetInstances()) { Game::logger->Log("MasterServer", "Instance: %i/%i/%i -> %i", instance->GetMapID(), instance->GetCloneID(), instance->GetInstanceID(), instance == in); } - if (!in->GetIsReady()) //Instance not ready, make a pending request + if (in && !in->GetIsReady()) //Instance not ready, make a pending request { in->GetPendingRequests().push_back({ requestID, static_cast(mythranShift), packet->systemAddress }); Game::logger->Log("MasterServer", "Server not ready, adding pending request %llu %i %i", requestID, zoneID, zoneClone); @@ -720,9 +728,13 @@ void HandlePacket(Packet* packet) { int zoneID; inStream.Read(zoneID); - - Game::logger->Log("MasterServer", "Prepping zone %i", zoneID); - Game::im->GetInstance(zoneID, false, 0); + if (shutdownSequenceStarted) { + Game::logger->Log("MasterServer", "Shutdown sequence has been started. Not prepping a new zone."); + break; + } else { + Game::logger->Log("MasterServer", "Prepping zone %i", zoneID); + Game::im->GetInstance(zoneID, false, 0); + } break; } @@ -770,8 +782,8 @@ void HandlePacket(Packet* packet) { default: Game::logger->Log("MasterServer", "Unknown master packet ID from server: %i", packet->data[3]); } - } } +} void StartChatServer() { if (Game::shouldShutdown) { @@ -788,9 +800,9 @@ void StartChatServer() { auto result = system(("sudo " + (BinaryPathFinder::GetBinaryDir() / "ChatServer").string() + "&").c_str()); } else { auto result = system(((BinaryPathFinder::GetBinaryDir() / "ChatServer").string() + "&").c_str()); - } +} #endif - } +} void StartAuthServer() { if (Game::shouldShutdown) { @@ -806,7 +818,7 @@ void StartAuthServer() { auto result = system(("sudo " + (BinaryPathFinder::GetBinaryDir() / "AuthServer").string() + "&").c_str()); } else { auto result = system(((BinaryPathFinder::GetBinaryDir() / "AuthServer").string() + "&").c_str()); - } +} #endif } @@ -815,6 +827,11 @@ void ShutdownSequence(int signal) { return; } + if (!Game::im) { + FinalizeShutdown(EXIT_FAILURE); + } + + Game::im->SetIsShuttingDown(true); shutdownSequenceStarted = true; Game::shouldShutdown = true; @@ -826,40 +843,38 @@ void ShutdownSequence(int signal) { } auto* objIdManager = ObjectIDManager::TryInstance(); - if (objIdManager != nullptr) { + if (objIdManager) { objIdManager->SaveToDatabase(); Game::logger->Log("MasterServer", "Saved ObjectIDTracker to DB"); } - auto t = std::chrono::high_resolution_clock::now(); - auto ticks = 0; - - if (!Game::im) { - FinalizeShutdown(EXIT_FAILURE); - } - // A server might not be finished spinning up yet, remove all of those here. - for (auto instance : Game::im->GetInstances()) { + for (auto* instance : Game::im->GetInstances()) { if (!instance->GetIsReady()) { Game::im->RemoveInstance(instance); } } - for (auto instance : Game::im->GetInstances()) { + for (auto* instance : Game::im->GetInstances()) { instance->SetIsShuttingDown(true); } Game::logger->Log("MasterServer", "Attempting to shutdown instances, max 60 seconds..."); + auto t = std::chrono::high_resolution_clock::now(); + uint32_t framesSinceShutdownStart = 0; + constexpr uint32_t maxShutdownTime = 60 * mediumFramerate; + bool allInstancesShutdown = false; + Packet* packet = nullptr; while (true) { - auto packet = Game::server->Receive(); + packet = Game::server->Receive(); if (packet) { HandlePacket(packet); Game::server->DeallocatePacket(packet); packet = nullptr; } - auto done = true; + allInstancesShutdown = true; for (auto* instance : Game::im->GetInstances()) { if (instance == nullptr) { @@ -867,21 +882,21 @@ void ShutdownSequence(int signal) { } if (!instance->GetShutdownComplete()) { - done = false; + allInstancesShutdown = false; } } - - if (done && authServerMasterPeerSysAddr == UNASSIGNED_SYSTEM_ADDRESS && chatServerMasterPeerSysAddr == UNASSIGNED_SYSTEM_ADDRESS) { + + if (allInstancesShutdown && authServerMasterPeerSysAddr == UNASSIGNED_SYSTEM_ADDRESS && chatServerMasterPeerSysAddr == UNASSIGNED_SYSTEM_ADDRESS) { Game::logger->Log("MasterServer", "Finished shutting down MasterServer!"); break; } - t += std::chrono::milliseconds(highFrameRate); + t += std::chrono::milliseconds(mediumFrameDelta); std::this_thread::sleep_until(t); - ticks++; + framesSinceShutdownStart++; - if (ticks == 600 * 6) { + if (framesSinceShutdownStart == maxShutdownTime) { Game::logger->Log("MasterServer", "Finished shutting down by timeout!"); break; } diff --git a/dWorldServer/PerformanceManager.cpp b/dWorldServer/PerformanceManager.cpp index 85546f28..66dcb615 100644 --- a/dWorldServer/PerformanceManager.cpp +++ b/dWorldServer/PerformanceManager.cpp @@ -2,23 +2,18 @@ #include "UserManager.h" -//Times are 1 / fps, in ms -#define HIGH 16 //60 fps -#define MEDIUM 33 //30 fps -#define LOW 66 //15 fps - -#define SOCIAL { LOW } -#define SOCIAL_HUB { MEDIUM } //Added to compensate for the large playercounts in NS and NT -#define BATTLE { HIGH } -#define BATTLE_INSTANCE { MEDIUM } -#define RACE { HIGH } -#define PROPERTY { LOW } +#define SOCIAL { lowFrameDelta } +#define SOCIAL_HUB { mediumFrameDelta } //Added to compensate for the large playercounts in NS and NT +#define BATTLE { highFrameDelta } +#define BATTLE_INSTANCE { mediumFrameDelta } +#define RACE { highFrameDelta } +#define PROPERTY { lowFrameDelta } PerformanceProfile PerformanceManager::m_CurrentProfile = SOCIAL; PerformanceProfile PerformanceManager::m_DefaultProfile = SOCIAL; -PerformanceProfile PerformanceManager::m_InactiveProfile = { LOW }; +PerformanceProfile PerformanceManager::m_InactiveProfile = { lowFrameDelta }; std::map PerformanceManager::m_Profiles = { // VE @@ -72,13 +67,6 @@ std::map PerformanceManager::m_Profiles = { { 2001, BATTLE_INSTANCE }, }; - -PerformanceManager::PerformanceManager() { -} - -PerformanceManager::~PerformanceManager() { -} - void PerformanceManager::SelectProfile(LWOMAPID mapID) { const auto pair = m_Profiles.find(mapID); diff --git a/dWorldServer/PerformanceManager.h b/dWorldServer/PerformanceManager.h index b8a090e0..3d8517eb 100644 --- a/dWorldServer/PerformanceManager.h +++ b/dWorldServer/PerformanceManager.h @@ -8,18 +8,13 @@ struct PerformanceProfile { uint32_t serverFramerate; }; - class PerformanceManager { public: - ~PerformanceManager(); - static void SelectProfile(LWOMAPID mapID); static uint32_t GetServerFramerate(); private: - PerformanceManager(); - static PerformanceProfile m_CurrentProfile; static PerformanceProfile m_DefaultProfile; static PerformanceProfile m_InactiveProfile; diff --git a/dWorldServer/WorldServer.cpp b/dWorldServer/WorldServer.cpp index 594d3dc7..c531595f 100644 --- a/dWorldServer/WorldServer.cpp +++ b/dWorldServer/WorldServer.cpp @@ -232,7 +232,7 @@ int main(int argc, char** argv) { bool ready = false; int framesSinceMasterStatus = 0; int framesSinceShutdownSequence = 0; - int currentFramerate = highFrameRate; + int currentFramerate = highFrameDelta; int ghostingStepCount = 0; auto ghostingLastTime = std::chrono::high_resolution_clock::now(); @@ -300,7 +300,7 @@ int main(int argc, char** argv) { const auto occupied = UserManager::Instance()->GetUserCount() != 0; if (!ready) { - currentFramerate = highFrameRate; + currentFramerate = highFrameDelta; } else { currentFramerate = PerformanceManager::GetServerFramerate(); }