diff --git a/README.md b/README.md index 87319c10..bd9dd6b7 100644 --- a/README.md +++ b/README.md @@ -422,11 +422,6 @@ Here is a summary of the commands available in-game. All commands are prefixed b # Credits -## Active Contributors -* [EmosewaMC](https://github.com/EmosewaMC) -* [Jettford](https://github.com/Jettford) -* [Aaron K.](https://github.com/aronwk-aaron) - ## DLU Team * [DarwinAnim8or](https://github.com/DarwinAnim8or) * [Wincent01](https://github.com/Wincent01) @@ -434,25 +429,30 @@ Here is a summary of the commands available in-game. All commands are prefixed b * [averysumner](https://github.com/codeshaunted) * [Jon002](https://github.com/jaller200) * [Jonny](https://github.com/cuzitsjonny) +* [Aaron K.](https://github.com/aronwk-aaron) -### Research and tools +### Research and Tools * [lcdr](https://github.com/lcdr) * [Xiphoseer](https://github.com/Xiphoseer) -### Community management +### Community Management * [Neal](https://github.com/NealSpellman) -### Former contributors +### Logo +* Cole Peterson (BlasterBuilder) + +## Active Contributors +* [EmosewaMC](https://github.com/EmosewaMC) +* [Jettford](https://github.com/Jettford) + +## Former Contributors * TheMachine * Matthew * [Raine](https://github.com/Rainebannister) * Bricknave -### Logo -* Cole Peterson (BlasterBuilder) - -## Special thanks +## Special Thanks * humanoid24 * pwjones1969 * [Simon](https://github.com/SimonNitzsche) -* ALL OF THE NETDEVIL AND LEGO TEAMS! +* [ALL OF THE NETDEVIL AND LEGO TEAMS!](https://www.mobygames.com/game/macintosh/lego-universe/credits) diff --git a/dAuthServer/AuthServer.cpp b/dAuthServer/AuthServer.cpp index 3fd4b0bf..f5090495 100644 --- a/dAuthServer/AuthServer.cpp +++ b/dAuthServer/AuthServer.cpp @@ -32,6 +32,8 @@ dLogger* SetupLogger(); void HandlePacket(Packet* packet); int main(int argc, char** argv) { + constexpr uint32_t authFramerate = mediumFramerate; + constexpr uint32_t authFrameDelta = mediumFrameDelta; Diagnostics::SetProcessName("Auth"); Diagnostics::SetProcessFileName(argv[0]); Diagnostics::Initialize(); @@ -67,7 +69,7 @@ int main(int argc, char** argv) { //Find out the master's IP: std::string masterIP; - int masterPort = 1500; + uint32_t masterPort = 1500; sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT ip, port FROM servers WHERE name='master';"); auto res = stmt->executeQuery(); while (res->next()) { @@ -79,8 +81,8 @@ int main(int argc, char** argv) { delete stmt; //It's safe to pass 'localhost' here, as the IP is only used as the external IP. - int maxClients = 50; - int ourPort = 1001; //LU client is hardcoded to use this for auth port, so I'm making it the default. + uint32_t maxClients = 50; + uint32_t ourPort = 1001; //LU client is hardcoded to use this for auth port, so I'm making it the default. if (Game::config->GetValue("max_clients") != "") maxClients = std::stoi(Game::config->GetValue("max_clients")); if (Game::config->GetValue("port") != "") ourPort = std::atoi(Game::config->GetValue("port").c_str()); @@ -89,16 +91,18 @@ int main(int argc, char** argv) { //Run it until server gets a kill message from Master: auto t = std::chrono::high_resolution_clock::now(); Packet* packet = nullptr; - int framesSinceLastFlush = 0; - int framesSinceMasterDisconnect = 0; - int framesSinceLastSQLPing = 0; + constexpr uint32_t logFlushTime = 30 * authFramerate; // 30 seconds in frames + constexpr uint32_t sqlPingTime = 10 * 60 * authFramerate; // 10 minutes in frames + uint32_t framesSinceLastFlush = 0; + uint32_t framesSinceMasterDisconnect = 0; + uint32_t framesSinceLastSQLPing = 0; while (!Game::shouldShutdown) { //Check if we're still connected to master: if (!Game::server->GetIsConnectedToMaster()) { framesSinceMasterDisconnect++; - if (framesSinceMasterDisconnect >= 30) + if (framesSinceMasterDisconnect >= authFramerate) break; //Exit our loop, shut down. } else framesSinceMasterDisconnect = 0; @@ -114,16 +118,16 @@ int main(int argc, char** argv) { } //Push our log every 30s: - 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; + uint32_t masterPort; sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT ip, port FROM servers WHERE name='master';"); auto res = stmt->executeQuery(); while (res->next()) { @@ -138,7 +142,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(authFrameDelta); //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..a75c4d51 100644 --- a/dChatServer/ChatServer.cpp +++ b/dChatServer/ChatServer.cpp @@ -19,6 +19,9 @@ #include "ChatPacketHandler.h" #include "Game.h" + +//RakNet includes: +#include "RakNetDefines.h" namespace Game { dLogger* logger = nullptr; dServer* server = nullptr; @@ -28,8 +31,6 @@ namespace Game { bool shouldShutdown = false; } -//RakNet includes: -#include "RakNetDefines.h" dLogger* SetupLogger(); void HandlePacket(Packet* packet); @@ -37,6 +38,8 @@ void HandlePacket(Packet* packet); PlayerContainer playerContainer; int main(int argc, char** argv) { + constexpr uint32_t chatFramerate = mediumFramerate; + constexpr uint32_t chatFrameDelta = mediumFrameDelta; Diagnostics::SetProcessName("Chat"); Diagnostics::SetProcessFileName(argv[0]); Diagnostics::Initialize(); @@ -65,7 +68,7 @@ int main(int argc, char** argv) { Game::assetManager = new AssetManager(clientPath); } catch (std::runtime_error& ex) { Game::logger->Log("ChatServer", "Got an error while setting up assets: %s", ex.what()); - + return EXIT_FAILURE; } @@ -87,7 +90,7 @@ int main(int argc, char** argv) { //Find out the master's IP: std::string masterIP; - int masterPort = 1000; + uint32_t masterPort = 1000; sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT ip, port FROM servers WHERE name='master';"); auto res = stmt->executeQuery(); while (res->next()) { @@ -99,8 +102,8 @@ int main(int argc, char** argv) { delete stmt; //It's safe to pass 'localhost' here, as the IP is only used as the external IP. - int maxClients = 50; - int ourPort = 1501; + uint32_t maxClients = 50; + uint32_t ourPort = 1501; if (Game::config->GetValue("max_clients") != "") maxClients = std::stoi(Game::config->GetValue("max_clients")); if (Game::config->GetValue("port") != "") ourPort = std::atoi(Game::config->GetValue("port").c_str()); @@ -111,16 +114,18 @@ int main(int argc, char** argv) { //Run it until server gets a kill message from Master: auto t = std::chrono::high_resolution_clock::now(); Packet* packet = nullptr; - int framesSinceLastFlush = 0; - int framesSinceMasterDisconnect = 0; - int framesSinceLastSQLPing = 0; + constexpr uint32_t logFlushTime = 30 * chatFramerate; // 30 seconds in frames + constexpr uint32_t sqlPingTime = 10 * 60 * chatFramerate; // 10 minutes in frames + uint32_t framesSinceLastFlush = 0; + uint32_t framesSinceMasterDisconnect = 0; + uint32_t framesSinceLastSQLPing = 0; while (!Game::shouldShutdown) { //Check if we're still connected to master: if (!Game::server->GetIsConnectedToMaster()) { framesSinceMasterDisconnect++; - if (framesSinceMasterDisconnect >= 30) + if (framesSinceMasterDisconnect >= chatFramerate) break; //Exit our loop, shut down. } else framesSinceMasterDisconnect = 0; @@ -136,16 +141,16 @@ int main(int argc, char** argv) { } //Push our log every 30s: - 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; + uint32_t masterPort; sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT ip, port FROM servers WHERE name='master';"); auto res = stmt->executeQuery(); while (res->next()) { @@ -160,7 +165,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(chatFrameDelta); //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 d13e8b94..1fd5d071 100644 --- a/dCommon/dEnums/dCommonVars.h +++ b/dCommon/dEnums/dCommonVars.h @@ -6,15 +6,25 @@ #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 +// These are the same define, but they mean two different things in different contexts +// so a different define to distinguish what calculation is happening will help clarity. +#define FRAMES_TO_MS(x) 1000 / x +#define MS_TO_FRAMES(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/dGame/dComponents/ScriptedActivityComponent.cpp b/dGame/dComponents/ScriptedActivityComponent.cpp index da546910..ee7ca22e 100644 --- a/dGame/dComponents/ScriptedActivityComponent.cpp +++ b/dGame/dComponents/ScriptedActivityComponent.cpp @@ -208,7 +208,7 @@ void ScriptedActivityComponent::PlayerLeave(LWOOBJID playerID) { } void ScriptedActivityComponent::Update(float deltaTime) { - + std::vector lobbiesToRemove{}; // Ticks all the lobbies, not applicable for non-instance activities for (Lobby* lobby : m_Queue) { for (LobbyPlayer* player : lobby->players) { @@ -219,6 +219,11 @@ void ScriptedActivityComponent::Update(float deltaTime) { } } + if (lobby->players.empty()) { + lobbiesToRemove.push_back(lobby); + continue; + } + // Update the match time for all players if (m_ActivityInfo.maxTeamSize != 1 && lobby->players.size() >= m_ActivityInfo.minTeamSize || m_ActivityInfo.maxTeamSize == 1 && lobby->players.size() >= m_ActivityInfo.minTeams) { @@ -262,13 +267,17 @@ void ScriptedActivityComponent::Update(float deltaTime) { // The timer has elapsed, start the instance if (lobby->timer <= 0.0f) { Game::logger->Log("ScriptedActivityComponent", "Setting up instance."); - ActivityInstance* instance = NewInstance(); LoadPlayersIntoInstance(instance, lobby->players); - RemoveLobby(lobby); instance->StartZone(); + lobbiesToRemove.push_back(lobby); } } + + while (!lobbiesToRemove.empty()) { + RemoveLobby(lobbiesToRemove.front()); + lobbiesToRemove.erase(lobbiesToRemove.begin()); + } } void ScriptedActivityComponent::RemoveLobby(Lobby* lobby) { 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 08d9bc58..ba36247c 100644 --- a/dMasterServer/MasterServer.cpp +++ b/dMasterServer/MasterServer.cpp @@ -52,8 +52,8 @@ namespace Game { } //namespace Game bool shutdownSequenceStarted = false; -void ShutdownSequence(int signal = -1); -int FinalizeShutdown(int signal = -1); +void ShutdownSequence(int32_t signal = -1); +int32_t FinalizeShutdown(int32_t signal = -1); dLogger* SetupLogger(); void StartAuthServer(); void StartChatServer(); @@ -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(); @@ -73,8 +75,8 @@ int main(int argc, char** argv) { //Triggers the shutdown sequence at application exit std::atexit([]() { ShutdownSequence(); }); - signal(SIGINT, [](int signal) { ShutdownSequence(EXIT_FAILURE); }); - signal(SIGTERM, [](int signal) { ShutdownSequence(EXIT_FAILURE); }); + signal(SIGINT, [](int32_t signal) { ShutdownSequence(EXIT_FAILURE); }); + signal(SIGTERM, [](int32_t signal) { ShutdownSequence(EXIT_FAILURE); }); //Create all the objects we need to run our service: Game::logger = SetupLogger(); @@ -237,8 +239,8 @@ int main(int argc, char** argv) { return EXIT_SUCCESS; } - int maxClients = 999; - int ourPort = 1000; + uint32_t maxClients = 999; + uint32_t ourPort = 1000; if (Game::config->GetValue("max_clients") != "") maxClients = std::stoi(Game::config->GetValue("max_clients")); if (Game::config->GetValue("port") != "") ourPort = std::stoi(Game::config->GetValue("port")); @@ -287,9 +289,13 @@ int main(int argc, char** argv) { auto t = std::chrono::high_resolution_clock::now(); Packet* packet = nullptr; - int framesSinceLastFlush = 0; - int framesSinceLastSQLPing = 0; - int framesSinceKillUniverseCommand = 0; + 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; + uint32_t framesSinceLastFlush = 0; + uint32_t framesSinceLastSQLPing = 0; + uint32_t framesSinceKillUniverseCommand = 0; while (true) { //In world we'd update our other systems here. @@ -303,17 +309,17 @@ 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; + uint32_t masterPort; sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT ip, port FROM servers WHERE name='master';"); auto res = stmt->executeQuery(); while (res->next()) { @@ -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); @@ -644,7 +652,7 @@ void HandlePacket(Packet* packet) { uint32_t len; inStream.Read(len); - for (int i = 0; len > i; i++) { + for (uint32_t i = 0; len > i; i++) { char character; inStream.Read(character); password += character; @@ -670,7 +678,7 @@ void HandlePacket(Packet* packet) { uint32_t len; inStream.Read(len); - for (int i = 0; i < len; i++) { + for (uint32_t i = 0; i < len; i++) { char character; inStream.Read(character); password += character; } @@ -718,11 +726,15 @@ void HandlePacket(Packet* packet) { RakNet::BitStream inStream(packet->data, packet->length, false); uint64_t header = inStream.Read(header); - int zoneID; + int32_t 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,15 +818,20 @@ void StartAuthServer() { auto result = system(("sudo " + (BinaryPathFinder::GetBinaryDir() / "AuthServer").string() + "&").c_str()); } else { auto result = system(((BinaryPathFinder::GetBinaryDir() / "AuthServer").string() + "&").c_str()); - } +} #endif } -void ShutdownSequence(int signal) { +void ShutdownSequence(int32_t signal) { if (shutdownSequenceStarted) { 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; } @@ -890,7 +905,7 @@ void ShutdownSequence(int signal) { FinalizeShutdown(signal); } -int FinalizeShutdown(int signal) { +int32_t FinalizeShutdown(int32_t signal) { //Delete our objects here: Database::Destroy("MasterServer"); if (Game::config) delete Game::config; diff --git a/dWorldServer/PerformanceManager.cpp b/dWorldServer/PerformanceManager.cpp index 85546f28..19f38d00 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); @@ -91,10 +79,10 @@ void PerformanceManager::SelectProfile(LWOMAPID mapID) { m_CurrentProfile = pair->second; } -uint32_t PerformanceManager::GetServerFramerate() { +uint32_t PerformanceManager::GetServerFrameDelta() { if (UserManager::Instance()->GetUserCount() == 0) { - return m_InactiveProfile.serverFramerate; + return m_InactiveProfile.serverFrameDelta; } - return m_CurrentProfile.serverFramerate; + return m_CurrentProfile.serverFrameDelta; } diff --git a/dWorldServer/PerformanceManager.h b/dWorldServer/PerformanceManager.h index b8a090e0..c584d4ac 100644 --- a/dWorldServer/PerformanceManager.h +++ b/dWorldServer/PerformanceManager.h @@ -5,21 +5,16 @@ #include "dCommonVars.h" struct PerformanceProfile { - uint32_t serverFramerate; + uint32_t serverFrameDelta; }; - class PerformanceManager { public: - ~PerformanceManager(); - static void SelectProfile(LWOMAPID mapID); - static uint32_t GetServerFramerate(); + static uint32_t GetServerFrameDelta(); 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 d204d5c9..adb87ba0 100644 --- a/dWorldServer/WorldServer.cpp +++ b/dWorldServer/WorldServer.cpp @@ -82,7 +82,7 @@ void WorldShutdownProcess(uint32_t zoneId); void FinalizeShutdown(); void SendShutdownMessageToMaster(); -dLogger* SetupLogger(int zoneID, int instanceID); +dLogger* SetupLogger(uint32_t zoneID, uint32_t instanceID); void HandlePacketChat(Packet* packet); void HandlePacket(Packet* packet); @@ -92,8 +92,8 @@ struct tempSessionInfo { }; std::map m_PendingUsers; -int instanceID = 0; -int g_CloneID = 0; +uint32_t instanceID = 0; +uint32_t g_CloneID = 0; std::string databaseChecksum = ""; int main(int argc, char** argv) { @@ -107,13 +107,13 @@ int main(int argc, char** argv) { signal(SIGINT, [](int) { WorldShutdownSequence(); }); signal(SIGTERM, [](int) { WorldShutdownSequence(); }); - int zoneID = 1000; - int cloneID = 0; - int maxClients = 8; - int ourPort = 2007; + uint32_t zoneID = 1000; + uint32_t cloneID = 0; + uint32_t maxClients = 8; + uint32_t ourPort = 2007; //Check our arguments: - for (int i = 0; i < argc; ++i) { + for (int32_t i = 0; i < argc; ++i) { std::string argument(argv[i]); if (argument == "-zone") zoneID = atoi(argv[i + 1]); @@ -185,7 +185,7 @@ int main(int argc, char** argv) { //Find out the master's IP: std::string masterIP = "localhost"; - int masterPort = 1000; + uint32_t masterPort = 1000; sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT ip, port FROM servers WHERE name='master';"); auto res = stmt->executeQuery(); while (res->next()) { @@ -204,7 +204,7 @@ int main(int argc, char** argv) { Game::server = new dServer(masterIP, ourPort, instanceID, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::World, Game::config, &Game::shouldShutdown, zoneID); //Connect to the chat server: - int chatPort = 1501; + uint32_t chatPort = 1501; if (Game::config->GetValue("chat_server_port") != "") chatPort = std::atoi(Game::config->GetValue("chat_server_port").c_str()); auto chatSock = SocketDescriptor(uint16_t(ourPort + 2), 0); @@ -220,22 +220,22 @@ int main(int argc, char** argv) { auto t = std::chrono::high_resolution_clock::now(); Packet* packet = nullptr; - int framesSinceLastFlush = 0; - int framesSinceMasterDisconnect = 0; - int framesSinceChatDisconnect = 0; - int framesSinceLastUsersSave = 0; - int framesSinceLastSQLPing = 0; - int framesSinceLastUser = 0; + uint32_t framesSinceLastFlush = 0; + uint32_t framesSinceMasterDisconnect = 0; + uint32_t framesSinceChatDisconnect = 0; + uint32_t framesSinceLastUsersSave = 0; + uint32_t framesSinceLastSQLPing = 0; + uint32_t framesSinceLastUser = 0; const float maxPacketProcessingTime = 1.5f; //0.015f; - const int maxPacketsToProcess = 1024; + const uint32_t maxPacketsToProcess = 1024; bool ready = false; - int framesSinceMasterStatus = 0; - int framesSinceShutdownSequence = 0; - int currentFramerate = highFrameRate; + uint32_t framesSinceMasterStatus = 0; + uint32_t framesSinceShutdownSequence = 0; + uint32_t currentFramerate = highFramerate; - int ghostingStepCount = 0; + uint32_t ghostingStepCount = 0; auto ghostingLastTime = std::chrono::high_resolution_clock::now(); PerformanceManager::SelectProfile(zoneID); @@ -264,7 +264,7 @@ int main(int argc, char** argv) { } } - const int bufferSize = 1024; + const int32_t bufferSize = 1024; MD5* md5 = new MD5(); char fileStreamBuffer[1024] = {}; @@ -288,6 +288,14 @@ int main(int argc, char** argv) { } } + uint32_t currentFrameDelta = highFrameDelta; + // These values are adjust them selves to the current framerate should it update. + uint32_t logFlushTime = 15 * currentFramerate; // 15 seconds in frames + uint32_t shutdownTimeout = 10 * 60 * currentFramerate; // 10 minutes in frames + uint32_t noMasterConnectionTimeout = 5 * currentFramerate; // 5 seconds in frames + uint32_t chatReconnectionTime = 30 * currentFramerate; // 30 seconds in frames + uint32_t saveTime = 10 * 60 * currentFramerate; // 10 minutes in frames + uint32_t sqlPingTime = 10 * 60 * currentFramerate; // 10 minutes in frames while (true) { Metrics::StartMeasurement(MetricVariable::Frame); Metrics::StartMeasurement(MetricVariable::GameLoop); @@ -300,24 +308,44 @@ int main(int argc, char** argv) { const auto occupied = UserManager::Instance()->GetUserCount() != 0; + uint32_t newFrameDelta = currentFrameDelta; if (!ready) { - currentFramerate = highFrameRate; + newFrameDelta = highFrameDelta; } else { - currentFramerate = PerformanceManager::GetServerFramerate(); + newFrameDelta = PerformanceManager::GetServerFrameDelta(); + } + + // Update to the new framerate and scale all timings to said new framerate + if (newFrameDelta != currentFrameDelta) { + float_t ratioBeforeToAfter = (float)currentFrameDelta / (float)newFrameDelta; + currentFrameDelta = newFrameDelta; + currentFramerate = MS_TO_FRAMES(newFrameDelta); + Game::logger->LogDebug("WorldServer", "Framerate for zone/instance/clone %i/%i/%i is now %i", zoneID, instanceID, cloneID, currentFramerate); + logFlushTime = 15 * currentFramerate; // 15 seconds in frames + framesSinceLastFlush *= ratioBeforeToAfter; + shutdownTimeout = 10 * 60 * currentFramerate; // 10 minutes in frames + framesSinceLastUser *= ratioBeforeToAfter; + noMasterConnectionTimeout = 5 * currentFramerate; // 5 seconds in frames + framesSinceMasterDisconnect *= ratioBeforeToAfter; + chatReconnectionTime = 30 * currentFramerate; // 30 seconds in frames + framesSinceChatDisconnect *= ratioBeforeToAfter; + saveTime = 10 * 60 * currentFramerate; // 10 minutes in frames + framesSinceLastUsersSave *= ratioBeforeToAfter; + sqlPingTime = 10 * 60 * currentFramerate; // 10 minutes in frames + framesSinceLastSQLPing *= ratioBeforeToAfter; } //Warning if we ran slow - if (deltaTime > currentFramerate) { - Game::logger->Log("WorldServer", "We're running behind, dT: %f > %f (framerate)", deltaTime, currentFramerate); + if (deltaTime > currentFrameDelta) { + Game::logger->Log("WorldServer", "We're running behind, dT: %f > %f (framerate %i)", deltaTime, currentFrameDelta, currentFramerate); } //Check if we're still connected to master: if (!Game::server->GetIsConnectedToMaster()) { framesSinceMasterDisconnect++; - int framesToWaitForMaster = ready ? 10 : 200; - if (framesSinceMasterDisconnect >= framesToWaitForMaster && !Game::shouldShutdown) { - Game::logger->Log("WorldServer", "Game loop running but no connection to master for %d frames, shutting down", framesToWaitForMaster); + if (framesSinceMasterDisconnect >= noMasterConnectionTimeout && !Game::shouldShutdown) { + Game::logger->Log("WorldServer", "Game loop running but no connection to master for %d frames, shutting down", noMasterConnectionTimeout); Game::shouldShutdown = true; } } else framesSinceMasterDisconnect = 0; @@ -326,8 +354,7 @@ int main(int argc, char** argv) { if (!chatConnected) { framesSinceChatDisconnect++; - // Attempt to reconnect every 30 seconds. - if (framesSinceChatDisconnect >= 2000) { + if (framesSinceChatDisconnect >= chatReconnectionTime) { framesSinceChatDisconnect = 0; Game::chatServer->Connect(masterIP.c_str(), chatPort, "3.25 ND1", 8); @@ -379,7 +406,7 @@ int main(int argc, char** argv) { UserManager::Instance()->DeletePendingRemovals(); auto t1 = std::chrono::high_resolution_clock::now(); - for (int curPacket = 0; curPacket < maxPacketsToProcess && timeSpent < maxPacketProcessingTime; curPacket++) { + for (uint32_t curPacket = 0; curPacket < maxPacketsToProcess && timeSpent < maxPacketProcessingTime; curPacket++) { packet = Game::server->Receive(); if (packet) { auto t1 = std::chrono::high_resolution_clock::now(); @@ -404,7 +431,7 @@ int main(int argc, char** argv) { Metrics::EndMeasurement(MetricVariable::UpdateReplica); //Push our log every 15s: - if (framesSinceLastFlush >= 1000) { + if (framesSinceLastFlush >= logFlushTime) { Game::logger->Flush(); framesSinceLastFlush = 0; } else framesSinceLastFlush++; @@ -421,7 +448,7 @@ int main(int argc, char** argv) { } //Save all connected users every 10 minutes: - if (framesSinceLastUsersSave >= 40000 && zoneID != 0) { + if (framesSinceLastUsersSave >= saveTime && zoneID != 0) { UserManager::Instance()->SaveAllActiveCharacters(); framesSinceLastUsersSave = 0; @@ -431,10 +458,10 @@ int main(int argc, char** argv) { } else framesSinceLastUsersSave++; //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; + uint32_t masterPort; sql::PreparedStatement* stmt = Database::CreatePreppedStmt("SELECT ip, port FROM servers WHERE name='master';"); auto res = stmt->executeQuery(); while (res->next()) { @@ -452,7 +479,7 @@ int main(int argc, char** argv) { Metrics::StartMeasurement(MetricVariable::Sleep); - t += std::chrono::milliseconds(currentFramerate); + t += std::chrono::milliseconds(currentFrameDelta); std::this_thread::sleep_until(t); Metrics::EndMeasurement(MetricVariable::Sleep); @@ -483,7 +510,7 @@ int main(int argc, char** argv) { return EXIT_SUCCESS; } -dLogger* SetupLogger(int zoneID, int instanceID) { +dLogger* SetupLogger(uint32_t zoneID, uint32_t instanceID) { std::string logPath = (BinaryPathFinder::GetBinaryDir() / ("logs/WorldServer_" + std::to_string(zoneID) + "_" + std::to_string(instanceID) + "_" + std::to_string(time(nullptr)) + ".log")).string(); bool logToConsole = false; bool logDebugStatements = false; @@ -525,7 +552,7 @@ void HandlePacketChat(Packet* packet) { //Write our stream outwards: CBITSTREAM; - for (int i = 0; i < inStream.GetNumberOfBytesUsed(); i++) { + for (BitSize_t i = 0; i < inStream.GetNumberOfBytesUsed(); i++) { bitStream.Write(packet->data[i + 16]); //16 bytes == header + playerID to skip } @@ -544,7 +571,7 @@ void HandlePacketChat(Packet* packet) { uint32_t len; inStream.Read(len); - for (int i = 0; len > i; i++) { + for (uint32_t i = 0; len > i; i++) { char character; inStream.Read(character); title += character; @@ -552,7 +579,7 @@ void HandlePacketChat(Packet* packet) { len = 0; inStream.Read(len); - for (int i = 0; len > i; i++) { + for (uint32_t i = 0; len > i; i++) { char character; inStream.Read(character); msg += character; @@ -805,7 +832,7 @@ void HandlePacket(Packet* packet) { uint32_t len; inStream.Read(len); - for (int i = 0; i < len; i++) { + for (uint32_t i = 0; i < len; i++) { char character; inStream.Read(character); username += character; } @@ -1048,7 +1075,7 @@ void HandlePacket(Packet* packet) { //Check for BBB models: auto stmt = Database::CreatePreppedStmt("SELECT ugc_id FROM properties_contents WHERE lot=14 AND property_id=?"); - int templateId = result.getIntField(0); + int32_t templateId = result.getIntField(0); result.finalize(); diff --git a/vanity/CREDITS.md b/vanity/CREDITS.md index e130cfb3..6780cff7 100644 --- a/vanity/CREDITS.md +++ b/vanity/CREDITS.md @@ -1,18 +1,17 @@ # CREDITS -## Developers +## DLU Team DarwinAnim8or (Max) Wincent01 Mick averysumner (codeshaunted) Jon002 Jonny -EmosewaMC -Jettford - -## Research & Tooling Xiphoseer lcdr - -## Community Management +Aaron K. Neal + +## Active Contributors +EmosewaMC +Jettford \ No newline at end of file