Improve shutdown

This commit is contained in:
EmosewaMC 2022-12-15 04:02:38 -08:00
parent 9659000569
commit 435761f64b
9 changed files with 160 additions and 147 deletions

View File

@ -22,9 +22,10 @@
#include "Game.h" #include "Game.h"
namespace Game { namespace Game {
dLogger* logger = nullptr; dLogger* logger;
dServer* server = nullptr; dServer* server;
dConfig* config = nullptr; dConfig* config;
bool shouldShutdown = false;
} }
dLogger* SetupLogger(); dLogger* SetupLogger();
@ -37,22 +38,22 @@ int main(int argc, char** argv) {
//Create all the objects we need to run our service: //Create all the objects we need to run our service:
Game::logger = SetupLogger(); Game::logger = SetupLogger();
if (!Game::logger) return EXIT_FAILURE; if (!Game::logger) return 0;
//Read our config:
Game::config = new dConfig((BinaryPathFinder::GetBinaryDir() / "authconfig.ini").string());
Game::logger->SetLogToConsole(Game::config->GetValue("log_to_console") != "0");
Game::logger->SetLogDebugStatements(Game::config->GetValue("log_debug_statements") == "1");
Game::logger->Log("AuthServer", "Starting Auth server..."); Game::logger->Log("AuthServer", "Starting Auth server...");
Game::logger->Log("AuthServer", "Version: %i.%i", PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR); Game::logger->Log("AuthServer", "Version: %i.%i", PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR);
Game::logger->Log("AuthServer", "Compiled on: %s", __TIMESTAMP__); Game::logger->Log("AuthServer", "Compiled on: %s", __TIMESTAMP__);
//Read our config:
dConfig config("authconfig.ini");
Game::config = &config;
Game::logger->SetLogToConsole(bool(std::stoi(config.GetValue("log_to_console"))));
Game::logger->SetLogDebugStatements(config.GetValue("log_debug_statements") == "1");
//Connect to the MySQL Database //Connect to the MySQL Database
std::string mysql_host = Game::config->GetValue("mysql_host"); std::string mysql_host = config.GetValue("mysql_host");
std::string mysql_database = Game::config->GetValue("mysql_database"); std::string mysql_database = config.GetValue("mysql_database");
std::string mysql_username = Game::config->GetValue("mysql_username"); std::string mysql_username = config.GetValue("mysql_username");
std::string mysql_password = Game::config->GetValue("mysql_password"); std::string mysql_password = config.GetValue("mysql_password");
try { try {
Database::Connect(mysql_host, mysql_database, mysql_username, mysql_password); Database::Connect(mysql_host, mysql_database, mysql_username, mysql_password);
@ -61,7 +62,7 @@ int main(int argc, char** argv) {
Database::Destroy("AuthServer"); Database::Destroy("AuthServer");
delete Game::server; delete Game::server;
delete Game::logger; delete Game::logger;
return EXIT_FAILURE; return 0;
} }
//Find out the master's IP: //Find out the master's IP:
@ -80,10 +81,10 @@ int main(int argc, char** argv) {
//It's safe to pass 'localhost' here, as the IP is only used as the external IP. //It's safe to pass 'localhost' here, as the IP is only used as the external IP.
int maxClients = 50; int maxClients = 50;
int ourPort = 1001; //LU client is hardcoded to use this for auth port, so I'm making it the default. int 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 (config.GetValue("max_clients") != "") maxClients = std::stoi(config.GetValue("max_clients"));
if (Game::config->GetValue("port") != "") ourPort = std::atoi(Game::config->GetValue("port").c_str()); if (config.GetValue("port") != "") ourPort = std::atoi(config.GetValue("port").c_str());
Game::server = new dServer(Game::config->GetValue("external_ip"), ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Auth, Game::config); Game::server = new dServer(Game::config->GetValue("external_ip"), ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Auth, Game::config, Game::shouldShutdown);
//Run it until server gets a kill message from Master: //Run it until server gets a kill message from Master:
auto t = std::chrono::high_resolution_clock::now(); auto t = std::chrono::high_resolution_clock::now();
@ -92,7 +93,7 @@ int main(int argc, char** argv) {
int framesSinceMasterDisconnect = 0; int framesSinceMasterDisconnect = 0;
int framesSinceLastSQLPing = 0; int framesSinceLastSQLPing = 0;
while (true) { while (!Game::shouldShutdown) {
//Check if we're still connected to master: //Check if we're still connected to master:
if (!Game::server->GetIsConnectedToMaster()) { if (!Game::server->GetIsConnectedToMaster()) {
framesSinceMasterDisconnect++; framesSinceMasterDisconnect++;
@ -145,8 +146,8 @@ int main(int argc, char** argv) {
Database::Destroy("AuthServer"); Database::Destroy("AuthServer");
delete Game::server; delete Game::server;
delete Game::logger; delete Game::logger;
delete Game::config;
exit(EXIT_SUCCESS);
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }

View File

@ -20,11 +20,12 @@
#include "Game.h" #include "Game.h"
namespace Game { namespace Game {
dLogger* logger = nullptr; dLogger* logger;
dServer* server = nullptr; dServer* server;
dConfig* config = nullptr; dConfig* config;
dChatFilter* chatFilter = nullptr; dChatFilter* chatFilter;
AssetManager* assetManager = nullptr; AssetManager* assetManager;
bool shouldShutdown = false;
} }
//RakNet includes: //RakNet includes:
@ -42,19 +43,19 @@ int main(int argc, char** argv) {
//Create all the objects we need to run our service: //Create all the objects we need to run our service:
Game::logger = SetupLogger(); Game::logger = SetupLogger();
if (!Game::logger) return EXIT_FAILURE; if (!Game::logger) return 0;
//Read our config:
Game::config = new dConfig((BinaryPathFinder::GetBinaryDir() / "chatconfig.ini").string());
Game::logger->SetLogToConsole(Game::config->GetValue("log_to_console") != "0");
Game::logger->SetLogDebugStatements(Game::config->GetValue("log_debug_statements") == "1");
Game::logger->Log("ChatServer", "Starting Chat server..."); Game::logger->Log("ChatServer", "Starting Chat server...");
Game::logger->Log("ChatServer", "Version: %i.%i", PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR); Game::logger->Log("ChatServer", "Version: %i.%i", PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR);
Game::logger->Log("ChatServer", "Compiled on: %s", __TIMESTAMP__); Game::logger->Log("ChatServer", "Compiled on: %s", __TIMESTAMP__);
//Read our config:
dConfig config("chatconfig.ini");
Game::config = &config;
Game::logger->SetLogToConsole(bool(std::stoi(config.GetValue("log_to_console"))));
Game::logger->SetLogDebugStatements(config.GetValue("log_debug_statements") == "1");
try { try {
std::string clientPathStr = Game::config->GetValue("client_location"); std::string clientPathStr = config.GetValue("client_location");
if (clientPathStr.empty()) clientPathStr = "./res"; if (clientPathStr.empty()) clientPathStr = "./res";
std::filesystem::path clientPath = std::filesystem::path(clientPathStr); std::filesystem::path clientPath = std::filesystem::path(clientPathStr);
if (clientPath.is_relative()) { if (clientPath.is_relative()) {
@ -69,10 +70,10 @@ int main(int argc, char** argv) {
} }
//Connect to the MySQL Database //Connect to the MySQL Database
std::string mysql_host = Game::config->GetValue("mysql_host"); std::string mysql_host = config.GetValue("mysql_host");
std::string mysql_database = Game::config->GetValue("mysql_database"); std::string mysql_database = config.GetValue("mysql_database");
std::string mysql_username = Game::config->GetValue("mysql_username"); std::string mysql_username = config.GetValue("mysql_username");
std::string mysql_password = Game::config->GetValue("mysql_password"); std::string mysql_password = config.GetValue("mysql_password");
try { try {
Database::Connect(mysql_host, mysql_database, mysql_username, mysql_password); Database::Connect(mysql_host, mysql_database, mysql_username, mysql_password);
@ -81,7 +82,7 @@ int main(int argc, char** argv) {
Database::Destroy("ChatServer"); Database::Destroy("ChatServer");
delete Game::server; delete Game::server;
delete Game::logger; delete Game::logger;
return EXIT_FAILURE; return 0;
} }
//Find out the master's IP: //Find out the master's IP:
@ -100,12 +101,12 @@ int main(int argc, char** argv) {
//It's safe to pass 'localhost' here, as the IP is only used as the external IP. //It's safe to pass 'localhost' here, as the IP is only used as the external IP.
int maxClients = 50; int maxClients = 50;
int ourPort = 1501; int ourPort = 1501;
if (Game::config->GetValue("max_clients") != "") maxClients = std::stoi(Game::config->GetValue("max_clients")); if (config.GetValue("max_clients") != "") maxClients = std::stoi(config.GetValue("max_clients"));
if (Game::config->GetValue("port") != "") ourPort = std::atoi(Game::config->GetValue("port").c_str()); if (config.GetValue("port") != "") ourPort = std::atoi(config.GetValue("port").c_str());
Game::server = new dServer(Game::config->GetValue("external_ip"), ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Chat, Game::config); Game::server = new dServer(config.GetValue("external_ip"), ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::Chat, Game::config, Game::shouldShutdown);
Game::chatFilter = new dChatFilter(Game::assetManager->GetResPath().string() + "/chatplus_en_us", bool(std::stoi(Game::config->GetValue("dont_generate_dcf")))); Game::chatFilter = new dChatFilter(Game::assetManager->GetResPath().string() + "/chatplus_en_us", bool(std::stoi(config.GetValue("dont_generate_dcf"))));
//Run it until server gets a kill message from Master: //Run it until server gets a kill message from Master:
auto t = std::chrono::high_resolution_clock::now(); auto t = std::chrono::high_resolution_clock::now();
@ -114,7 +115,7 @@ int main(int argc, char** argv) {
int framesSinceMasterDisconnect = 0; int framesSinceMasterDisconnect = 0;
int framesSinceLastSQLPing = 0; int framesSinceLastSQLPing = 0;
while (true) { while (!Game::shouldShutdown) {
//Check if we're still connected to master: //Check if we're still connected to master:
if (!Game::server->GetIsConnectedToMaster()) { if (!Game::server->GetIsConnectedToMaster()) {
framesSinceMasterDisconnect++; framesSinceMasterDisconnect++;
@ -167,8 +168,8 @@ int main(int argc, char** argv) {
Database::Destroy("ChatServer"); Database::Destroy("ChatServer");
delete Game::server; delete Game::server;
delete Game::logger; delete Game::logger;
delete Game::config;
exit(EXIT_SUCCESS);
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }

View File

@ -5,6 +5,7 @@
class dServer; class dServer;
class dLogger; class dLogger;
class InstanceManager; class InstanceManager;
class dpWorld;
class dChatFilter; class dChatFilter;
class dConfig; class dConfig;
class RakPeerInterface; class RakPeerInterface;
@ -15,10 +16,12 @@ namespace Game {
extern dLogger* logger; extern dLogger* logger;
extern dServer* server; extern dServer* server;
extern InstanceManager* im; extern InstanceManager* im;
extern dpWorld* physicsWorld;
extern dChatFilter* chatFilter; extern dChatFilter* chatFilter;
extern dConfig* config; extern dConfig* config;
extern std::mt19937 randomEngine; extern std::mt19937 randomEngine;
extern RakPeerInterface* chatServer; extern RakPeerInterface* chatServer;
extern AssetManager* assetManager; extern AssetManager* assetManager;
extern SystemAddress chatSysAddr; extern SystemAddress chatSysAddr;
extern bool shouldShutdown;
} }

View File

@ -74,7 +74,7 @@ Instance* InstanceManager::GetInstance(LWOMAPID mapID, bool isFriendTransfer, LW
cmd.append("&"); //Sends our next process to the background on Linux cmd.append("&"); //Sends our next process to the background on Linux
#endif #endif
auto ret = system(cmd.c_str()); system(cmd.c_str());
m_Instances.push_back(instance); m_Instances.push_back(instance);
@ -322,7 +322,7 @@ Instance* InstanceManager::CreatePrivateInstance(LWOMAPID mapID, LWOCLONEID clon
cmd.append("&"); //Sends our next process to the background on Linux cmd.append("&"); //Sends our next process to the background on Linux
#endif #endif
auto ret = system(cmd.c_str()); system(cmd.c_str());
m_Instances.push_back(instance); m_Instances.push_back(instance);
@ -391,5 +391,5 @@ void Instance::Shutdown() {
Game::server->Send(&bitStream, this->m_SysAddr, false); Game::server->Send(&bitStream, this->m_SysAddr, false);
Game::logger->Log("Instance", "Triggered world shutdown"); Game::logger->Log("Instance", "Triggered world shutdown for zone/clone/instance %i/%i/%i", GetMapID(), GetCloneID(), GetInstanceID());
} }

View File

@ -43,11 +43,12 @@
#include "FdbToSqlite.h" #include "FdbToSqlite.h"
namespace Game { namespace Game {
dLogger* logger = nullptr; dLogger* logger;
dServer* server = nullptr; dServer* server;
InstanceManager* im = nullptr; InstanceManager* im;
dConfig* config = nullptr; dConfig* config;
AssetManager* assetManager = nullptr; AssetManager* assetManager;
bool shouldShutdown = false;
} //namespace Game } //namespace Game
bool shutdownSequenceStarted = false; bool shutdownSequenceStarted = false;
@ -58,7 +59,6 @@ void StartAuthServer();
void StartChatServer(); void StartChatServer();
void HandlePacket(Packet* packet); void HandlePacket(Packet* packet);
std::map<uint32_t, std::string> activeSessions; std::map<uint32_t, std::string> activeSessions;
bool shouldShutdown = false;
SystemAddress chatServerMasterPeerSysAddr; SystemAddress chatServerMasterPeerSysAddr;
int main(int argc, char** argv) { int main(int argc, char** argv) {
@ -79,39 +79,14 @@ int main(int argc, char** argv) {
Game::logger = SetupLogger(); Game::logger = SetupLogger();
if (!Game::logger) return EXIT_FAILURE; if (!Game::logger) return EXIT_FAILURE;
if (!std::filesystem::exists(BinaryPathFinder::GetBinaryDir() / "authconfig.ini")) {
Game::logger->Log("MasterServer", "Couldnt find authconfig.ini");
return EXIT_FAILURE;
}
if (!std::filesystem::exists(BinaryPathFinder::GetBinaryDir() / "chatconfig.ini")) {
Game::logger->Log("MasterServer", "Couldnt find chatconfig.ini");
return EXIT_FAILURE;
}
if (!std::filesystem::exists(BinaryPathFinder::GetBinaryDir() / "masterconfig.ini")) {
Game::logger->Log("MasterServer", "Couldnt find masterconfig.ini");
return EXIT_FAILURE;
}
if (!std::filesystem::exists(BinaryPathFinder::GetBinaryDir() / "sharedconfig.ini")) {
Game::logger->Log("MasterServer", "Couldnt find sharedconfig.ini");
return EXIT_FAILURE;
}
if (!std::filesystem::exists(BinaryPathFinder::GetBinaryDir() / "worldconfig.ini")) {
Game::logger->Log("MasterServer", "Couldnt find worldconfig.ini");
return EXIT_FAILURE;
}
Game::config = new dConfig((BinaryPathFinder::GetBinaryDir() / "masterconfig.ini").string());
Game::logger->SetLogToConsole(Game::config->GetValue("log_to_console") != "0");
Game::logger->SetLogDebugStatements(Game::config->GetValue("log_debug_statements") == "1");
Game::logger->Log("MasterServer", "Starting Master server..."); Game::logger->Log("MasterServer", "Starting Master server...");
Game::logger->Log("MasterServer", "Version: %i.%i", PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR); Game::logger->Log("MasterServer", "Version: %i.%i", PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR);
Game::logger->Log("MasterServer", "Compiled on: %s", __TIMESTAMP__); Game::logger->Log("MasterServer", "Compiled on: %s", __TIMESTAMP__);
Game::config = new dConfig("masterconfig.ini");
Game::logger->SetLogToConsole(bool(std::stoi(Game::config->GetValue("log_to_console"))));
Game::logger->SetLogDebugStatements(Game::config->GetValue("log_debug_statements") == "1");
//Connect to the MySQL Database //Connect to the MySQL Database
std::string mysql_host = Game::config->GetValue("mysql_host"); std::string mysql_host = Game::config->GetValue("mysql_host");
std::string mysql_database = Game::config->GetValue("mysql_database"); std::string mysql_database = Game::config->GetValue("mysql_database");
@ -241,7 +216,7 @@ int main(int argc, char** argv) {
if (Game::config->GetValue("max_clients") != "") maxClients = std::stoi(Game::config->GetValue("max_clients")); 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")); if (Game::config->GetValue("port") != "") ourPort = std::stoi(Game::config->GetValue("port"));
Game::server = new dServer(Game::config->GetValue("external_ip"), ourPort, 0, maxClients, true, false, Game::logger, "", 0, ServerType::Master, Game::config); Game::server = new dServer(config.GetValue("external_ip"), ourPort, 0, maxClients, true, false, Game::logger, "", 0, ServerType::Master, Game::config, Game::shouldShutdown);
//Query for the database for a server labeled "master" //Query for the database for a server labeled "master"
auto* masterLookupStatement = Database::CreatePreppedStmt("SELECT id FROM `servers` WHERE `name` = 'master'"); auto* masterLookupStatement = Database::CreatePreppedStmt("SELECT id FROM `servers` WHERE `name` = 'master'");
@ -328,7 +303,7 @@ int main(int argc, char** argv) {
framesSinceLastSQLPing++; framesSinceLastSQLPing++;
//10m shutdown for universe kill command //10m shutdown for universe kill command
if (shouldShutdown) { if (Game::shouldShutdown) {
if (framesSinceKillUniverseCommand >= 40000) { if (framesSinceKillUniverseCommand >= 40000) {
//Break main loop and exit //Break main loop and exit
break; break;
@ -406,7 +381,7 @@ void HandlePacket(Packet* packet) {
Game::im->RemoveInstance(instance); //Delete the old Game::im->RemoveInstance(instance); //Delete the old
} }
if (packet->systemAddress == chatServerMasterPeerSysAddr && !shouldShutdown) { if (packet->systemAddress == chatServerMasterPeerSysAddr && !Game::shouldShutdown) {
StartChatServer(); StartChatServer();
} }
} }
@ -422,7 +397,7 @@ void HandlePacket(Packet* packet) {
//Game::im->GetInstance(zoneID.GetMapID(), false, 0); //Create the new //Game::im->GetInstance(zoneID.GetMapID(), false, 0); //Create the new
} }
if (packet->systemAddress == chatServerMasterPeerSysAddr && !shouldShutdown) { if (packet->systemAddress == chatServerMasterPeerSysAddr && !Game::shouldShutdown) {
StartChatServer(); StartChatServer();
} }
} }
@ -744,7 +719,7 @@ void HandlePacket(Packet* packet) {
case MSG_MASTER_SHUTDOWN_UNIVERSE: { case MSG_MASTER_SHUTDOWN_UNIVERSE: {
Game::logger->Log("MasterServer", "Received shutdown universe command, shutting down in 10 minutes."); Game::logger->Log("MasterServer", "Received shutdown universe command, shutting down in 10 minutes.");
shouldShutdown = true; Game::shouldShutdown = true;
break; break;
} }
@ -757,28 +732,28 @@ void HandlePacket(Packet* packet) {
void StartChatServer() { void StartChatServer() {
#ifdef __APPLE__ #ifdef __APPLE__
//macOS doesn't need sudo to run on ports < 1024 //macOS doesn't need sudo to run on ports < 1024
auto result = system(((BinaryPathFinder::GetBinaryDir() / "ChatServer").string() + "&").c_str()); system(((BinaryPathFinder::GetBinaryDir() / "ChatServer").string() + "&").c_str());
#elif _WIN32 #elif _WIN32
auto result = system(("start " + (BinaryPathFinder::GetBinaryDir() / "ChatServer.exe").string()).c_str()); system(("start " + (BinaryPathFinder::GetBinaryDir() / "ChatServer.exe").string()).c_str());
#else #else
if (std::atoi(Game::config->GetValue("use_sudo_chat").c_str())) { if (std::atoi(Game::config->GetValue("use_sudo_chat").c_str())) {
auto result = system(("sudo " + (BinaryPathFinder::GetBinaryDir() / "ChatServer").string() + "&").c_str()); system(("sudo " + (BinaryPathFinder::GetBinaryDir() / "ChatServer").string() + "&").c_str());
} else { } else {
auto result = system(((BinaryPathFinder::GetBinaryDir() / "ChatServer").string() + "&").c_str()); system(((BinaryPathFinder::GetBinaryDir() / "ChatServer").string() + "&").c_str());
} }
#endif #endif
} }
void StartAuthServer() { void StartAuthServer() {
#ifdef __APPLE__ #ifdef __APPLE__
auto result = system(((BinaryPathFinder::GetBinaryDir() / "AuthServer").string() + "&").c_str()); system(((BinaryPathFinder::GetBinaryDir() / "AuthServer").string() + "&").c_str());
#elif _WIN32 #elif _WIN32
auto result = system(("start " + (BinaryPathFinder::GetBinaryDir() / "AuthServer.exe").string()).c_str()); system(("start " + (BinaryPathFinder::GetBinaryDir() / "AuthServer.exe").string()).c_str());
#else #else
if (std::atoi(Game::config->GetValue("use_sudo_auth").c_str())) { if (std::atoi(Game::config->GetValue("use_sudo_auth").c_str())) {
auto result = system(("sudo " + (BinaryPathFinder::GetBinaryDir() / "AuthServer").string() + "&").c_str()); system(("sudo " + (BinaryPathFinder::GetBinaryDir() / "AuthServer").string() + "&").c_str());
} else { } else {
auto result = system(((BinaryPathFinder::GetBinaryDir() / "AuthServer").string() + "&").c_str()); system(((BinaryPathFinder::GetBinaryDir() / "AuthServer").string() + "&").c_str());
} }
#endif #endif
} }
@ -790,14 +765,11 @@ void ShutdownSequence() {
shutdownSequenceStarted = true; shutdownSequenceStarted = true;
if (Game::im) { {
for (auto* instance : Game::im->GetInstances()) { CBITSTREAM;
if (instance == nullptr) { PacketUtils::WriteHeader(bitStream, MASTER, MSG_MASTER_SHUTDOWN);
continue; Game::server->Send(&bitStream, UNASSIGNED_SYSTEM_ADDRESS, true);
} Game::logger->Log("MasterServer", "Triggered master shutdown");
instance->Shutdown();
}
} }
auto* objIdManager = ObjectIDManager::TryInstance(); auto* objIdManager = ObjectIDManager::TryInstance();
@ -813,6 +785,10 @@ void ShutdownSequence() {
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} }
for (auto instance : Game::im->GetInstances()) {
instance->SetIsShuttingDown(true);
}
Game::logger->Log("MasterServer", "Attempting to shutdown instances, max 60 seconds..."); Game::logger->Log("MasterServer", "Attempting to shutdown instances, max 60 seconds...");
while (true) { while (true) {

View File

@ -36,7 +36,7 @@ public:
} }
} ReceiveDownloadCompleteCB; } ReceiveDownloadCompleteCB;
dServer::dServer(const std::string& ip, int port, int instanceID, int maxConnections, bool isInternal, bool useEncryption, dLogger* logger, const std::string masterIP, int masterPort, ServerType serverType, dConfig* config, unsigned int zoneID) { dServer::dServer(const std::string& ip, int port, int instanceID, int maxConnections, bool isInternal, bool useEncryption, dLogger* logger, const std::string masterIP, int masterPort, ServerType serverType, dConfig* config, bool& shouldShutdown, unsigned int zoneID) {
mIP = ip; mIP = ip;
mPort = port; mPort = port;
mZoneID = zoneID; mZoneID = zoneID;
@ -52,6 +52,7 @@ dServer::dServer(const std::string& ip, int port, int instanceID, int maxConnect
mReplicaManager = nullptr; mReplicaManager = nullptr;
mServerType = serverType; mServerType = serverType;
mConfig = config; mConfig = config;
mShouldShutdown = &shouldShutdown;
//Attempt to start our server here: //Attempt to start our server here:
mIsOkay = Startup(); mIsOkay = Startup();
@ -124,8 +125,11 @@ Packet* dServer::ReceiveFromMaster() {
ZoneInstanceManager::Instance()->HandleRequestZoneTransferResponse(requestID, packet); ZoneInstanceManager::Instance()->HandleRequestZoneTransferResponse(requestID, packet);
break; break;
} }
case MSG_MASTER_SHUTDOWN:
*mShouldShutdown = true;
break;
//When we handle these packets in World instead dServer, we just return the packet's pointer. //When we handle these packets in World instead dServer, we just return the packet's pointer.
default: default:
return packet; return packet;

View File

@ -18,7 +18,20 @@ class dServer {
public: public:
// Default constructor should only used for testing! // Default constructor should only used for testing!
dServer() {}; dServer() {};
dServer(const std::string& ip, int port, int instanceID, int maxConnections, bool isInternal, bool useEncryption, dLogger* logger, const std::string masterIP, int masterPort, ServerType serverType, dConfig* config, unsigned int zoneID = 0); dServer(
const std::string& ip,
int port,
int instanceID,
int maxConnections,
bool isInternal,
bool useEncryption,
dLogger* logger,
const std::string masterIP,
int masterPort,
ServerType serverType,
dConfig* config,
bool& shouldShutdown,
unsigned int zoneID = 0);
~dServer(); ~dServer();
Packet* ReceiveFromMaster(); Packet* ReceiveFromMaster();
@ -64,6 +77,11 @@ private:
RakPeerInterface* mPeer = nullptr; RakPeerInterface* mPeer = nullptr;
ReplicaManager* mReplicaManager = nullptr; ReplicaManager* mReplicaManager = nullptr;
NetworkIDManager* mNetIDManager = nullptr; NetworkIDManager* mNetIDManager = nullptr;
/**
* Whether or not to shut down the server. Pointer to Game::shouldShutdown.
*/
bool* mShouldShutdown = nullptr;
SocketDescriptor mSocketDescriptor; SocketDescriptor mSocketDescriptor;
std::string mIP; std::string mIP;
int mPort; int mPort;

View File

@ -61,20 +61,23 @@
#include "ZCompression.h" #include "ZCompression.h"
namespace Game { namespace Game {
dLogger* logger = nullptr; dLogger* logger;
dServer* server = nullptr; dServer* server;
dpWorld* physicsWorld = nullptr; dZoneManager* zoneManager;
dChatFilter* chatFilter = nullptr; dpWorld* physicsWorld;
dConfig* config = nullptr; dChatFilter* chatFilter;
AssetManager* assetManager = nullptr; dConfig* config;
RakPeerInterface* chatServer = nullptr;
std::mt19937 randomEngine; std::mt19937 randomEngine;
AssetManager* assetManager;
RakPeerInterface* chatServer;
SystemAddress chatSysAddr; SystemAddress chatSysAddr;
} bool shouldShutdown = false;
} // namespace Game
bool chatDisabled = false; bool chatDisabled = false;
bool chatConnected = false; bool chatConnected = false;
bool worldShutdownSequenceStarted = false;
bool worldShutdownSequenceComplete = false; bool worldShutdownSequenceComplete = false;
void WorldShutdownSequence(); void WorldShutdownSequence();
void WorldShutdownProcess(uint32_t zoneId); void WorldShutdownProcess(uint32_t zoneId);
@ -124,21 +127,26 @@ int main(int argc, char** argv) {
//Create all the objects we need to run our service: //Create all the objects we need to run our service:
Game::logger = SetupLogger(zoneID, instanceID); Game::logger = SetupLogger(zoneID, instanceID);
if (!Game::logger) return EXIT_FAILURE; if (!Game::logger) return 0;
//Read our config:
Game::config = new dConfig((BinaryPathFinder::GetBinaryDir() / "worldconfig.ini").string());
Game::logger->SetLogToConsole(Game::config->GetValue("log_to_console") != "0");
Game::logger->SetLogDebugStatements(Game::config->GetValue("log_debug_statements") == "1");
Game::logger->SetLogToConsole(true); //We want this info to always be logged.
Game::logger->Log("WorldServer", "Starting World server..."); Game::logger->Log("WorldServer", "Starting World server...");
Game::logger->Log("WorldServer", "Version: %i.%i", PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR); Game::logger->Log("WorldServer", "Version: %i.%i", PROJECT_VERSION_MAJOR, PROJECT_VERSION_MINOR);
Game::logger->Log("WorldServer", "Compiled on: %s", __TIMESTAMP__); Game::logger->Log("WorldServer", "Compiled on: %s", __TIMESTAMP__);
if (Game::config->GetValue("disable_chat") == "1") chatDisabled = true; #ifndef _DEBUG
Game::logger->SetLogToConsole(false); //By default, turn it back off if not in debug.
#endif
//Read our config:
dConfig config("worldconfig.ini");
Game::config = &config;
Game::logger->SetLogToConsole(bool(std::stoi(config.GetValue("log_to_console"))));
Game::logger->SetLogDebugStatements(config.GetValue("log_debug_statements") == "1");
if (config.GetValue("disable_chat") == "1") chatDisabled = true;
try { try {
std::string clientPathStr = Game::config->GetValue("client_location"); std::string clientPathStr = config.GetValue("client_location");
if (clientPathStr.empty()) clientPathStr = "./res"; if (clientPathStr.empty()) clientPathStr = "./res";
std::filesystem::path clientPath = std::filesystem::path(clientPathStr); std::filesystem::path clientPath = std::filesystem::path(clientPathStr);
if (clientPath.is_relative()) { if (clientPath.is_relative()) {
@ -158,28 +166,28 @@ int main(int argc, char** argv) {
Game::logger->Log("WorldServer", "Unable to connect to CDServer SQLite Database"); Game::logger->Log("WorldServer", "Unable to connect to CDServer SQLite Database");
Game::logger->Log("WorldServer", "Error: %s", e.errorMessage()); Game::logger->Log("WorldServer", "Error: %s", e.errorMessage());
Game::logger->Log("WorldServer", "Error Code: %i", e.errorCode()); Game::logger->Log("WorldServer", "Error Code: %i", e.errorCode());
return EXIT_FAILURE; return -1;
} }
CDClientManager::Instance()->Initialize(); CDClientManager::Instance()->Initialize();
//Connect to the MySQL Database //Connect to the MySQL Database
std::string mysql_host = Game::config->GetValue("mysql_host"); std::string mysql_host = config.GetValue("mysql_host");
std::string mysql_database = Game::config->GetValue("mysql_database"); std::string mysql_database = config.GetValue("mysql_database");
std::string mysql_username = Game::config->GetValue("mysql_username"); std::string mysql_username = config.GetValue("mysql_username");
std::string mysql_password = Game::config->GetValue("mysql_password"); std::string mysql_password = config.GetValue("mysql_password");
Diagnostics::SetProduceMemoryDump(Game::config->GetValue("generate_dump") == "1"); Diagnostics::SetProduceMemoryDump(config.GetValue("generate_dump") == "1");
if (!Game::config->GetValue("dump_folder").empty()) { if (!config.GetValue("dump_folder").empty()) {
Diagnostics::SetOutDirectory(Game::config->GetValue("dump_folder")); Diagnostics::SetOutDirectory(config.GetValue("dump_folder"));
} }
try { try {
Database::Connect(mysql_host, mysql_database, mysql_username, mysql_password); Database::Connect(mysql_host, mysql_database, mysql_username, mysql_password);
} catch (sql::SQLException& ex) { } catch (sql::SQLException& ex) {
Game::logger->Log("WorldServer", "Got an error while connecting to the database: %s", ex.what()); Game::logger->Log("WorldServer", "Got an error while connecting to the database: %s", ex.what());
return EXIT_FAILURE; return 0;
} }
//Find out the master's IP: //Find out the master's IP:
@ -198,13 +206,13 @@ int main(int argc, char** argv) {
ObjectIDManager::Instance()->Initialize(); ObjectIDManager::Instance()->Initialize();
UserManager::Instance()->Initialize(); UserManager::Instance()->Initialize();
LootGenerator::Instance(); LootGenerator::Instance();
Game::chatFilter = new dChatFilter(Game::assetManager->GetResPath().string() + "/chatplus_en_us", bool(std::stoi(Game::config->GetValue("dont_generate_dcf")))); Game::chatFilter = new dChatFilter(Game::assetManager->GetResPath().string() + "/chatplus_en_us", bool(std::stoi(config.GetValue("dont_generate_dcf"))));
Game::server = new dServer(masterIP, ourPort, instanceID, maxClients, false, true, Game::logger, masterIP, masterPort, ServerType::World, Game::config, zoneID); 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: //Connect to the chat server:
int chatPort = 1501; int chatPort = 1501;
if (Game::config->GetValue("chat_server_port") != "") chatPort = std::atoi(Game::config->GetValue("chat_server_port").c_str()); if (config.GetValue("chat_server_port") != "") chatPort = std::atoi(config.GetValue("chat_server_port").c_str());
auto chatSock = SocketDescriptor(uint16_t(ourPort + 2), 0); auto chatSock = SocketDescriptor(uint16_t(ourPort + 2), 0);
Game::chatServer = RakNetworkFactory::GetRakPeerInterface(); Game::chatServer = RakNetworkFactory::GetRakPeerInterface();
@ -315,9 +323,9 @@ int main(int argc, char** argv) {
framesSinceMasterDisconnect++; framesSinceMasterDisconnect++;
int framesToWaitForMaster = ready ? 10 : 200; int framesToWaitForMaster = ready ? 10 : 200;
if (framesSinceMasterDisconnect >= framesToWaitForMaster && !worldShutdownSequenceStarted) { if (framesSinceMasterDisconnect >= framesToWaitForMaster && !Game::shouldShutdown) {
Game::logger->Log("WorldServer", "Game loop running but no connection to master for %d frames, shutting down", framesToWaitForMaster); Game::logger->Log("WorldServer", "Game loop running but no connection to master for %d frames, shutting down", framesToWaitForMaster);
worldShutdownSequenceStarted = true; Game::shouldShutdown = true;
} }
} else framesSinceMasterDisconnect = 0; } else framesSinceMasterDisconnect = 0;
@ -413,7 +421,7 @@ int main(int argc, char** argv) {
//If we haven't had any players for a while, time out and shut down: //If we haven't had any players for a while, time out and shut down:
if (framesSinceLastUser == (cloneID != 0 ? 4000 : 40000)) { if (framesSinceLastUser == (cloneID != 0 ? 4000 : 40000)) {
worldShutdownSequenceStarted = true; Game::shouldShutdown = true;
} }
} else { } else {
framesSinceLastUser = 0; framesSinceLastUser = 0;
@ -470,7 +478,7 @@ int main(int argc, char** argv) {
} }
} }
if (worldShutdownSequenceStarted && !worldShutdownSequenceComplete) { if (Game::shouldShutdown && !worldShutdownSequenceComplete) {
WorldShutdownProcess(zoneID); WorldShutdownProcess(zoneID);
break; break;
} }
@ -789,7 +797,7 @@ void HandlePacket(Packet* packet) {
} }
case MSG_MASTER_SHUTDOWN: { case MSG_MASTER_SHUTDOWN: {
worldShutdownSequenceStarted = true; Game::shouldShutdown = true;
Game::logger->Log("WorldServer", "Got shutdown request from master, zone (%i), instance (%i)", Game::server->GetZoneID(), Game::server->GetInstanceID()); Game::logger->Log("WorldServer", "Got shutdown request from master, zone (%i), instance (%i)", Game::server->GetZoneID(), Game::server->GetInstanceID());
break; break;
} }
@ -1259,11 +1267,11 @@ void WorldShutdownProcess(uint32_t zoneId) {
} }
void WorldShutdownSequence() { void WorldShutdownSequence() {
if (worldShutdownSequenceStarted || worldShutdownSequenceComplete) { if (Game::shouldShutdown || worldShutdownSequenceComplete) {
return; return;
} }
worldShutdownSequenceStarted = true; Game::shouldShutdown = true;
Game::logger->Log("WorldServer", "Zone (%i) instance (%i) shutting down outside of main loop!", Game::server->GetZoneID(), instanceID); Game::logger->Log("WorldServer", "Zone (%i) instance (%i) shutting down outside of main loop!", Game::server->GetZoneID(), instanceID);
WorldShutdownProcess(Game::server->GetZoneID()); WorldShutdownProcess(Game::server->GetZoneID());
@ -1271,15 +1279,16 @@ void WorldShutdownSequence() {
} }
void FinalizeShutdown() { void FinalizeShutdown() {
//Delete our objects here:
if (Game::zoneManager) delete Game::zoneManager;
Game::logger->Log("WorldServer", "Shutdown complete, zone (%i), instance (%i)", Game::server->GetZoneID(), instanceID); Game::logger->Log("WorldServer", "Shutdown complete, zone (%i), instance (%i)", Game::server->GetZoneID(), instanceID);
//Delete our objects here:
Metrics::Clear(); Metrics::Clear();
Database::Destroy("WorldServer"); Database::Destroy("WorldServer");
if (Game::chatFilter) delete Game::chatFilter; delete Game::chatFilter;
if (Game::server) delete Game::server; delete Game::server;
if (Game::logger) delete Game::logger; delete Game::logger;
if (Game::config) delete Game::config;
worldShutdownSequenceComplete = true; worldShutdownSequenceComplete = true;

View File

@ -4,6 +4,7 @@ namespace Game {
dLogger* logger; dLogger* logger;
dServer* server; dServer* server;
dZoneManager* zoneManager; dZoneManager* zoneManager;
dpWorld* physicsWorld;
dChatFilter* chatFilter; dChatFilter* chatFilter;
dConfig* config; dConfig* config;
std::mt19937 randomEngine; std::mt19937 randomEngine;