mirror of
https://github.com/DarkflameUniverse/DarkflameServer.git
synced 2026-10-02 02:43:44 +00:00
Frames and phase scopes in the world, auth, chat and UGC loops (packets per type, entities, physics, ghosting, replica, spawners, log flush, saves, web requests by route). Scopes at LoadPlayer, CreateEntity, each component's construction, InventoryComponent::LoadXml, script timers and a world's zone load; game database queries in the query helpers; CDClient statements timed through sqlite3_trace_v2 as CDClient <table> (CppSQLite3DB gets a handle accessor). Task 96. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
203 lines
6.0 KiB
C++
203 lines
6.0 KiB
C++
#include <iostream>
|
|
#include <string>
|
|
#include <ctime>
|
|
#include <csignal>
|
|
#include <chrono>
|
|
#include <thread>
|
|
|
|
//DLU Includes:
|
|
#include "Profiler.h"
|
|
#include "dCommonVars.h"
|
|
#include "ConfigSync.h"
|
|
#include "dServer.h"
|
|
#include "Logger.h"
|
|
#include "Database.h"
|
|
#include "dConfig.h"
|
|
#include "Diagnostics.h"
|
|
#include "BinaryPathFinder.h"
|
|
|
|
//RakNet includes:
|
|
#include "RakNetDefines.h"
|
|
#include "MessageIdentifiers.h"
|
|
|
|
//Auth includes:
|
|
#include "AuthPackets.h"
|
|
#include "BitStreamUtils.h"
|
|
#include "CommonPackets.h"
|
|
#include "ServiceType.h"
|
|
#include "MessageType/Server.h"
|
|
#include "MessageType/Auth.h"
|
|
|
|
#include "Game.h"
|
|
#include "Server.h"
|
|
#include "BuildInfo.h"
|
|
|
|
namespace Game {
|
|
Logger* logger = nullptr;
|
|
dServer* server = nullptr;
|
|
dConfig* config = nullptr;
|
|
Game::signal_t lastSignal = 0;
|
|
std::mt19937 randomEngine;
|
|
}
|
|
|
|
void HandlePacket(Packet* packet);
|
|
|
|
int main(int argc, char** argv) {
|
|
constexpr uint32_t authFramerate = mediumFramerate;
|
|
constexpr uint32_t authFrameDelta = mediumFrameDelta;
|
|
const auto curTimeStr = std::to_string(time(nullptr));
|
|
const auto serviceName = "AuthServer_" + curTimeStr;
|
|
Diagnostics::SetProcessName(serviceName);
|
|
Diagnostics::SetProcessFileName(argv[0]);
|
|
Diagnostics::Initialize();
|
|
|
|
std::signal(SIGINT, Game::OnSignal);
|
|
std::signal(SIGTERM, Game::OnSignal);
|
|
|
|
Game::config = new dConfig("authconfig.ini");
|
|
|
|
//Create all the objects we need to run our service:
|
|
Server::SetupLogger(serviceName, "AuthServer");
|
|
if (!Game::logger) return EXIT_FAILURE;
|
|
Game::config->LogSettings();
|
|
|
|
LOG("Starting Auth server...");
|
|
LOG("Version: %s", std::string(BuildInfo::buildString).c_str());
|
|
LOG("Compiled on: %s", __TIMESTAMP__);
|
|
|
|
try {
|
|
Database::Connect();
|
|
} catch (std::exception& ex) {
|
|
LOG("Got an error while connecting to the database: %s", ex.what());
|
|
Database::Destroy(serviceName);
|
|
delete Game::server;
|
|
delete Game::logger;
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
// Settings edited on the dashboard (server_config table) are layered over the files from here on
|
|
Game::config->SetDatabaseSync(ConfigSync::Sync);
|
|
|
|
//Find out the master's IP:
|
|
std::string masterIP;
|
|
uint32_t masterPort = 1500;
|
|
std::string masterPassword;
|
|
|
|
auto masterInfo = Database::Get()->GetMasterInfo();
|
|
if (masterInfo) {
|
|
masterIP = masterInfo->ip;
|
|
masterPort = masterInfo->port;
|
|
masterPassword = masterInfo->password;
|
|
}
|
|
|
|
LOG("Master is at %s:%d", masterIP.c_str(), masterPort);
|
|
|
|
Game::randomEngine = std::mt19937(time(0));
|
|
|
|
//It's safe to pass 'localhost' here, as the IP is only used as the external IP.
|
|
std::string ourIP = "localhost";
|
|
const uint32_t maxClients = GeneralUtils::TryParse<uint32_t>(Game::config->GetValue("max_clients")).value_or(999);
|
|
|
|
//LU client is hardcoded to use this for auth port, so I'm making it the default.
|
|
const uint32_t ourPort = GeneralUtils::TryParse<uint32_t>(Game::config->GetValue("auth_server_port")).value_or(1001);
|
|
const auto externalIPString = Game::config->GetValue("external_ip");
|
|
if (!externalIPString.empty()) ourIP = externalIPString;
|
|
|
|
Game::server = new dServer(ourIP, ourPort, 0, maxClients, false, true, Game::logger, masterIP, masterPort, ServiceType::AUTH, Game::config, &Game::lastSignal, masterPassword);
|
|
|
|
//Run it until server gets a kill message from Master:
|
|
auto t = std::chrono::high_resolution_clock::now();
|
|
Packet* packet = nullptr;
|
|
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;
|
|
|
|
AuthPackets::LoadClaimCodes();
|
|
|
|
Game::logger->Flush(); // once immediately before main loop
|
|
while (!Game::ShouldShutdown()) {
|
|
Profiler::BeginFrame();
|
|
//Check if we're still connected to master:
|
|
if (!Game::server->GetIsConnectedToMaster()) {
|
|
framesSinceMasterDisconnect++;
|
|
|
|
if (framesSinceMasterDisconnect >= authFramerate) {
|
|
LOG("No connection to master!");
|
|
break; //Exit our loop, shut down.
|
|
}
|
|
} else framesSinceMasterDisconnect = 0;
|
|
|
|
//In world we'd update our other systems here.
|
|
|
|
//Check for packets here:
|
|
{
|
|
Profiler::Scope scope("Master packets", Profiler::Phase::PACKETS);
|
|
Game::server->ReceiveFromMaster(); //ReceiveFromMaster also handles the master packets if needed.
|
|
}
|
|
packet = Game::server->Receive();
|
|
if (packet) {
|
|
Profiler::PacketScope scope(packet->data, packet->length);
|
|
HandlePacket(packet);
|
|
Game::server->DeallocatePacket(packet);
|
|
packet = nullptr;
|
|
}
|
|
|
|
//Push our log every 30s:
|
|
if (framesSinceLastFlush >= logFlushTime) {
|
|
Profiler::Scope scope("Log flush", Profiler::Phase::LOG_FLUSH);
|
|
Game::logger->Flush();
|
|
framesSinceLastFlush = 0;
|
|
} else framesSinceLastFlush++;
|
|
|
|
//Every 10 min we ping our sql server to keep it alive hopefully:
|
|
if (framesSinceLastSQLPing >= sqlPingTime) {
|
|
//Find out the master's IP for absolutely no reason:
|
|
std::string masterIP;
|
|
uint32_t masterPort;
|
|
auto masterInfo = Database::Get()->GetMasterInfo();
|
|
if (masterInfo) {
|
|
masterIP = masterInfo->ip;
|
|
masterPort = masterInfo->port;
|
|
}
|
|
|
|
framesSinceLastSQLPing = 0;
|
|
} else framesSinceLastSQLPing++;
|
|
|
|
Profiler::EndFrame();
|
|
//Sleep our thread since auth can afford to.
|
|
t += std::chrono::milliseconds(authFrameDelta); //Auth can run at a lower "fps"
|
|
std::this_thread::sleep_until(t);
|
|
}
|
|
|
|
LOG("Exited Main Loop! (signal %d)", Game::lastSignal);
|
|
//Delete our objects here:
|
|
Database::Destroy(serviceName);
|
|
delete Game::server;
|
|
delete Game::logger;
|
|
delete Game::config;
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
void HandlePacket(Packet* packet) {
|
|
if (packet->length < 4) return;
|
|
if (packet->data[0] != ID_USER_PACKET_ENUM) return;
|
|
|
|
RakNet::BitStream inStream(packet->data, packet->length, false);
|
|
LUBitStream header;
|
|
if (!header.ReadHeader(inStream)) return;
|
|
|
|
switch (header.connectionType) {
|
|
case ServiceType::COMMON:
|
|
CommonPackets::Handle(inStream, packet->systemAddress, header.internalPacketID);
|
|
break;
|
|
case ServiceType::AUTH:
|
|
AuthPackets::Handle(inStream, packet->systemAddress, header.internalPacketID);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|