46extern int m_ServiceStatus;
51#include <sys/resource.h>
52#define PROCESS_HIGH_PRIORITY -15
60 sConfigMgr->GetBoolDefault(
"CharacterDatabase.AutoSetup",
false),
61 sConfigMgr->GetBoolDefault(
"CharacterDatabase.AutoCreate",
false),
62 sConfigMgr->GetBoolDefault(
"CharacterDatabase.AutoBaseline",
false),
63 sConfigMgr->GetStringDefault(
"CharacterDatabase.SqlPath",
""));
66 sConfigMgr->GetBoolDefault(
"CharacterDatabase.AllowUpdateHashMismatch",
true);
68 sConfigMgr->GetBoolDefault(
"CharacterDatabase.ImportPendingUpdates",
false);
76 sConfigMgr->GetBoolDefault(
"WorldDatabase.AutoSetup",
false),
77 sConfigMgr->GetBoolDefault(
"WorldDatabase.AutoCreate",
false),
78 sConfigMgr->GetBoolDefault(
"WorldDatabase.AutoBaseline",
false),
79 sConfigMgr->GetStringDefault(
"WorldDatabase.SqlPath",
""),
80 sConfigMgr->GetStringDefault(
"WorldDatabase.BaseSqlFile",
""));
83 sConfigMgr->GetBoolDefault(
"WorldDatabase.AllowUpdateHashMismatch",
true);
85 sConfigMgr->GetBoolDefault(
"WorldDatabase.ImportPendingUpdates",
false);
99 "Failed while executing character setup SQL"
107 "server.worldserver",
112 "Failed while executing world setup SQL"
116 bool RunCharacterDatabaseSetup(MySQLConnectionInfo
const& connectionInfo,
123 SF_LOG_ERROR(
"server.worldserver",
"CharacterDatabase.AutoSetup requires CharacterDatabase.SqlPath.");
128 "CharacterDatabase.SqlPath is not configured; character database update check skipped.");
132 if (connectionInfo._database.empty())
135 "CharacterDatabase setup and update checks require a character database name.");
143 MYSQL* setupConnectionRaw = NULL;
145 setupConnectionRaw, context))
148 std::unique_ptr<MYSQL,
decltype(&mysql_close)> setupConnection(setupConnectionRaw, mysql_close);
151 bool baseSqlExists = std::filesystem::exists(baseSqlPath);
170 SF_LOG_INFO(
"server.worldserver",
"Installing character database base SQL from %s.",
171 baseSqlPath.string().c_str());
186 "Character database setup/update complete. Base installed: %s, updates applied: %u, updates baselined: %u.",
192 bool RunWorldDatabaseSetup(MySQLConnectionInfo
const& connectionInfo,
199 SF_LOG_ERROR(
"server.worldserver",
"WorldDatabase.AutoSetup requires WorldDatabase.SqlPath.");
204 "WorldDatabase.SqlPath is not configured; world database update check skipped.");
208 if (connectionInfo._database.empty())
210 SF_LOG_ERROR(
"server.worldserver",
"WorldDatabase setup and update checks require a world database name.");
218 MYSQL* setupConnectionRaw = NULL;
220 setupConnectionRaw, context))
223 std::unique_ptr<MYSQL,
decltype(&mysql_close)> setupConnection(setupConnectionRaw, mysql_close);
226 externalBaseSqlPath.make_preferred();
227 bool externalBaseSqlExists = !options.
ExternalBaseFile.empty() && std::filesystem::exists(externalBaseSqlPath);
229 bool requiredBaseSqlExists =
true;
230 std::vector<std::filesystem::path> requiredBaseSqlPaths;
234 requiredBaseSqlPaths.push_back(requiredBaseSqlPath);
235 requiredBaseSqlExists = requiredBaseSqlExists && std::filesystem::exists(requiredBaseSqlPath);
245 externalBaseSqlExists, requiredBaseSqlExists, updates);
257 SF_LOG_INFO(
"server.worldserver",
"Installing world database base SQL from %s.",
258 externalBaseSqlPath.string().c_str());
263 if (applyRequiredSql)
265 for (std::filesystem::path
const& requiredBaseSqlPath : requiredBaseSqlPaths)
267 std::string requiredBaseSql;
268 SF_LOG_INFO(
"server.worldserver",
"Applying world database required SQL from %s.",
269 requiredBaseSqlPath.string().c_str());
286 "World database setup/update complete. Base installed: %s, updates applied: %u, updates baselined: %u.",
303 if (m_ServiceStatus != 1)
326 SF_LOG_INFO(
"server.worldserver",
"Starting up anti-freeze thread (%u seconds max stuck time)...",
_delaytime / 1000);
335 if (
_loops != worldLoopCounter)
338 _loops = worldLoopCounter;
343 SF_LOG_ERROR(
"server.worldserver",
"World Thread hangs, kicking out server!");
347 SF_LOG_INFO(
"server.worldserver",
"Anti-freeze thread exiting without problems.");
356 SF_LOG_INFO(
"server.worldserver",
"worldserver-daemon. revision: % s", SKYFIRE_VER_PRODUCTVERSION_STR);
357 SF_LOG_INFO(
"server.worldserver",
"<Ctrl-C> to stop.\n");
359 SF_LOG_INFO(
"server.worldserver",
" ______ __ __ __ __ ______ __ ______ ______ ");
360 SF_LOG_INFO(
"server.worldserver",
" /\\ ___\\/\\ \\/ / /\\ \\_\\ \\/\\ ___/\\ \\/\\ == \\/\\ ___\\ ");
361 SF_LOG_INFO(
"server.worldserver",
" \\ \\___ \\ \\ _'-\\ \\____ \\ \\ __\\ \\ \\ \\ __<\\ \\ __\\ ");
362 SF_LOG_INFO(
"server.worldserver",
" \\/\\_____\\ \\_\\ \\_\\/\\_____\\ \\_\\ \\ \\_\\ \\_\\ \\_\\ \\_____\\ ");
363 SF_LOG_INFO(
"server.worldserver",
" \\/_____/\\/_/\\/_/\\/_____/\\/_/ \\/_/\\/_/ /_/\\/_____/ ");
364 SF_LOG_INFO(
"server.worldserver",
" %s Open-sourced Game Emulation", SKYFIRE_VER_LEGALCOPYRIGHT_STR);
365 SF_LOG_INFO(
"server.worldserver",
" <http://www.projectskyfire.org/> \n");
371 SF_LOG_INFO(
"server.worldserver",
"*****************************************************************************");
372 SF_LOG_INFO(
"server.worldserver",
" WARNING: Your worldserver.conf version indicates your conf file is out of date!");
373 SF_LOG_INFO(
"server.worldserver",
" Please check for updates, as your current default values may cause");
374 SF_LOG_INFO(
"server.worldserver",
" strange behavior.");
375 SF_LOG_INFO(
"server.worldserver",
"*****************************************************************************");
379 std::string pidFile =
sConfigMgr->GetStringDefault(
"PidFile",
"");
380 if (!pidFile.empty())
383 SF_LOG_INFO(
"server.worldserver",
"Daemon PID: %u\n", pid);
386 SF_LOG_ERROR(
"server.worldserver",
"Cannot create PID file %s.\n", pidFile.c_str());
402 sWorld->SetInitialWorldSettings();
413 if (worldRunner.
Start([] { WorldRunnable().Run(); }) == -1)
415 SF_LOG_ERROR(
"server.worldserver",
"Failed to start world task");
421 if (raRunner.
Start([] { RARunnable().Run(); }) == -1)
423 SF_LOG_ERROR(
"server.worldserver",
"Failed to start RA task");
430 std::unique_ptr<Skyfire::Asio::IoContextTaskRunner> cliRunner;
433 if (
sConfigMgr->GetBoolDefault(
"Console.Enable",
true) && (m_ServiceStatus == -1))
435 if (
sConfigMgr->GetBoolDefault(
"Console.Enable",
true))
440 if (cliRunner->Start([] { CliRunnable().Run(); }) == -1)
442 SF_LOG_ERROR(
"server.worldserver",
"Failed to start CLI task");
447#if defined(_WIN32) || defined(__linux__)
450 bool highPriority =
sConfigMgr->GetBoolDefault(
"ProcessPriority",
false);
454 HANDLE hProcess = GetCurrentProcess();
461 if (GetProcessAffinityMask(hProcess, &appAff, &sysAff))
463 ULONG_PTR currentAffinity = affinity & appAff;
465 if (!currentAffinity)
466 SF_LOG_ERROR(
"server.worldserver",
"Processors marked in UseProcessors bitmask (hex) %x are not accessible for the worldserver. Accessible processors bitmask (hex): %x", affinity, appAff);
467 else if (SetProcessAffinityMask(hProcess, currentAffinity))
468 SF_LOG_INFO(
"server.worldserver",
"Using processors (bitmask, hex): %x", currentAffinity);
470 SF_LOG_ERROR(
"server.worldserver",
"Can't set used processors (hex): %x", currentAffinity);
476 if (SetPriorityClass(hProcess, HIGH_PRIORITY_CLASS))
477 SF_LOG_INFO(
"server.worldserver",
"worldserver process priority class set to HIGH");
479 SF_LOG_ERROR(
"server.worldserver",
"Can't set worldserver process priority class.");
488 for (
unsigned int i = 0; i <
sizeof(affinity) * 8; ++i)
489 if (affinity & (1 << i))
492 if (sched_setaffinity(0,
sizeof(mask), &mask))
493 SF_LOG_ERROR(
"server.worldserver",
"Can't set used processors (hex): %x, error: %s", affinity, strerror(errno));
497 sched_getaffinity(0,
sizeof(mask), &mask);
498 SF_LOG_INFO(
"server.worldserver",
"Using processors (bitmask, hex): %lx", *(__cpu_mask*)(&mask));
504 if (setpriority(PRIO_PROCESS, 0, PROCESS_HIGH_PRIORITY))
505 SF_LOG_ERROR(
"server.worldserver",
"Can't set worldserver process priority class, error: %s", strerror(errno));
507 SF_LOG_INFO(
"server.worldserver",
"worldserver process priority class set to %i", getpriority(PRIO_PROCESS, 0));
516 if (
sConfigMgr->GetBoolDefault(
"SOAP.Enabled",
false))
527 if (freezeDetectorRunner.
Start([fdr]()
mutable { fdr.Run(); }) == -1)
528 SF_LOG_ERROR(
"server.worldserver",
"Failed to start anti-freeze task");
533 std::string bindIp =
sConfigMgr->GetStringDefault(
"BindIP",
"0.0.0.0");
537 SF_LOG_ERROR(
"server.worldserver",
"Failed to start network");
548 SF_LOG_INFO(
"server.worldserver",
" % s (worldserver-daemon) ready...", SKYFIRE_VER_PRODUCTVERSION_STR);
556 freezeDetectorRunner.
Join();
571 SF_LOG_INFO(
"server.worldserver",
"Halting process...");
581 HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE);
582 b[0].EventType = KEY_EVENT;
583 b[0].Event.KeyEvent.bKeyDown = TRUE;
584 b[0].Event.KeyEvent.uChar.AsciiChar =
'X';
585 b[0].Event.KeyEvent.wVirtualKeyCode =
'X';
586 b[0].Event.KeyEvent.wRepeatCount = 1;
588 b[1].EventType = KEY_EVENT;
589 b[1].Event.KeyEvent.bKeyDown = FALSE;
590 b[1].Event.KeyEvent.uChar.AsciiChar =
'X';
591 b[1].Event.KeyEvent.wVirtualKeyCode =
'X';
592 b[1].Event.KeyEvent.wRepeatCount = 1;
594 b[2].EventType = KEY_EVENT;
595 b[2].Event.KeyEvent.bKeyDown = TRUE;
596 b[2].Event.KeyEvent.dwControlKeyState = 0;
597 b[2].Event.KeyEvent.uChar.AsciiChar =
'\r';
598 b[2].Event.KeyEvent.wVirtualKeyCode = VK_RETURN;
599 b[2].Event.KeyEvent.wRepeatCount = 1;
600 b[2].Event.KeyEvent.wVirtualScanCode = 0x1c;
602 b[3].EventType = KEY_EVENT;
603 b[3].Event.KeyEvent.bKeyDown = FALSE;
604 b[3].Event.KeyEvent.dwControlKeyState = 0;
605 b[3].Event.KeyEvent.uChar.AsciiChar =
'\r';
606 b[3].Event.KeyEvent.wVirtualKeyCode = VK_RETURN;
607 b[3].Event.KeyEvent.wVirtualScanCode = 0x1c;
608 b[3].Event.KeyEvent.wRepeatCount = 1;
610 WriteConsoleInput(hStdIn, b, 4, &numb);
634 std::string dbString;
635 uint8 asyncThreads, synchThreads;
639 dbString =
sConfigMgr->GetStringDefault(
"WorldDatabaseInfo",
"");
640 if (dbString.empty())
642 SF_LOG_ERROR(
"server.worldserver",
"World database not specified in configuration file");
647 asyncThreads =
uint8(
sConfigMgr->GetIntDefault(
"WorldDatabase.WorkerThreads", 1));
648 if (asyncThreads < 1 || asyncThreads > 32)
650 SF_LOG_ERROR(
"server.worldserver",
"World database: invalid number of worker threads specified. "
651 "Please pick a value between 1 and 32.");
655 synchThreads =
uint8(
sConfigMgr->GetIntDefault(
"WorldDatabase.SynchThreads", 1));
659 ? MySQLConnectionInfo(dbString)
662 if (!RunWorldDatabaseSetup(worldSetupConnectionInfo, worldSetupOptions))
669 if (!
WorldDatabase.Open(dbString, asyncThreads, synchThreads))
671 SF_LOG_ERROR(
"server.worldserver",
"Cannot connect to world database %s", dbString.c_str());
679 SF_LOG_ERROR(
"server.worldserver",
"Cannot connect to world database %s, %s, %s, %s, %s",
_dbHost,
_dbPort,
_dbUser,
_dbPassword,
_worldDB);
687 dbString =
sConfigMgr->GetStringDefault(
"CharacterDatabaseInfo",
"");
688 if (dbString.empty())
690 SF_LOG_ERROR(
"server.worldserver",
"Character database not specified in configuration file");
695 asyncThreads =
uint8(
sConfigMgr->GetIntDefault(
"CharacterDatabase.WorkerThreads", 1));
696 if (asyncThreads < 1 || asyncThreads > 32)
698 SF_LOG_ERROR(
"server.worldserver",
"Character database: invalid number of worker threads specified. "
699 "Please pick a value between 1 and 32.");
703 synchThreads =
uint8(
sConfigMgr->GetIntDefault(
"CharacterDatabase.SynchThreads", 2));
707 ? MySQLConnectionInfo(dbString)
710 if (!RunCharacterDatabaseSetup(characterSetupConnectionInfo, characterSetupOptions))
718 SF_LOG_ERROR(
"server.worldserver",
"Cannot connect to Character database%s, %s", dbString.c_str());
727 SF_LOG_ERROR(
"server.worldserver",
"Cannot connect to Character database%s, %s, %s, %s, %s",
_dbHost,
_dbPort,
_dbUser,
_dbPassword,
_charactersDB);
735 dbString =
sConfigMgr->GetStringDefault(
"LoginDatabaseInfo",
"");
736 if (dbString.empty())
738 SF_LOG_ERROR(
"server.worldserver",
"Login database not specified in configuration file");
743 asyncThreads =
uint8(
sConfigMgr->GetIntDefault(
"LoginDatabase.WorkerThreads", 1));
744 if (asyncThreads < 1 || asyncThreads > 32)
746 SF_LOG_ERROR(
"server.worldserver",
"Login database: invalid number of worker threads specified. "
747 "Please pick a value between 1 and 32.");
751 synchThreads =
uint8(
sConfigMgr->GetIntDefault(
"LoginDatabase.SynchThreads", 1));
756 if (!
LoginDatabase.Open(dbString, asyncThreads, synchThreads))
758 SF_LOG_ERROR(
"server.worldserver",
"Cannot connect to login database %s", dbString.c_str());
779 Field* fields = result->Fetch();
781 }
while (result->NextRow());
785 SF_LOG_INFO(
"server.worldserver",
"World running as realm ID %d", itr->first);
792 WorldDatabase.PExecute(
"UPDATE version SET core_version = '%s', core_revision = '%s'", SKYFIRE_VER_PRODUCTVERSION_STR, _HASH);
815 LoginDatabase.DirectPExecute(
"UPDATE account SET online = 0 WHERE online > 0 AND id IN (SELECT acctid FROM realmcharacters WHERE realmid = %d)", itr->first);
819 CharacterDatabase.DirectExecute(
"UPDATE characters SET online = 0 WHERE online <> 0");
822 CharacterDatabase.DirectExecute(
"UPDATE character_battleground_data SET instanceId = 0");
#define SF_LOG_ERROR(filterType__,...)
#define SF_LOG_INFO(filterType__,...)
void WorldServerSignalHandler(int sigNum)
Skyfire::AutoPtr< PreparedResultSet, Skyfire::Mutex > PreparedQueryResult
#define SKYFIREWORLD_CONFIG_VERSION
uint32 getMSTimeDiff(uint32 oldMSTime, uint32 newMSTime)
uint32 CreatePIDFile(const std::string &filename)
create PID file
void SetRand(int32 numbits)
std::string GetString() const
void SetDelayTime(uint32 t)
bool _StartDB()
Initialize connection to the databases.
void ClearOnlineAccounts()
Clear 'online' status for all accounts with characters in this realm.
bool _noUseConfigDatabaseInfo
const char * _charactersDB
static void Library_Init()
static void Library_End()
void setInt32(const uint8 index, const int32 value)
bool Start(const std::string &host, uint16 port)
static uint8 GetExitCode()
static void StopNow(uint8 exitcode)
static std::atomic< uint32 > m_worldLoopCounter
CharacterDatabaseWorkerPool CharacterDatabase
Accessor to the character database.
WorldDatabaseWorkerPool WorldDatabase
Accessor to the world database.
RealmNameMap realmNameStore
std::vector< SqlUpdateFile > DiscoverSqlUpdates(SetupOptions const &options)
SetupPlan BuildWorldDatabaseSetupPlan(SetupOptions const &options, SetupState const &state, bool externalBaseSqlExists, bool requiredBaseSqlExists, std::vector< SqlUpdateFile > const &updates)
bool EnsureDatabaseExists(MySQLConnectionInfo const &connectionInfo, SetupOptions const &options, SetupRuntimeContext const &context)
bool LoadDatabaseSetupState(MYSQL *setupConnection, SetupOptions const &options, SetupState &state, SetupRuntimeContext const &context)
bool ConnectToMySQLServer(MySQLConnectionInfo const &connectionInfo, char const *databaseName, MYSQL *&handle, SetupRuntimeContext const &context)
bool ExecuteSqlFile(MYSQL *setupConnection, std::filesystem::path const &path, std::string &contents, SetupRuntimeContext const &context)
SetupOptions MakeWorldDatabaseSetupOptions(bool autoSetup, bool autoCreate, std::string sqlPath, std::string externalBaseFile)
SetupOptions MakeCharacterDatabaseSetupOptions(bool autoSetup, bool autoCreate, std::string sqlPath)
SetupPlan BuildCharacterDatabaseSetupPlan(SetupOptions const &options, SetupState const &state, bool baseSqlExists, std::vector< SqlUpdateFile > const &updates)
bool BaselineSetupUpdates(MYSQL *setupConnection, SetupOptions const &options, SetupPlan const &plan, SetupRuntimeContext const &context)
std::filesystem::path GetDatabaseBaseSqlPath(SetupOptions const &options)
void LogSetupPlan(SetupPlan const &plan, std::size_t discoveredUpdateCount, bool appliesRequiredSql, SetupRuntimeContext const &context)
bool EnsureSetupTrackingTables(MYSQL *setupConnection, SetupRuntimeContext const &context)
bool ApplyPendingSetupUpdates(MYSQL *setupConnection, SetupOptions const &options, SetupPlan const &plan, SetupRuntimeContext const &context)
void SleepForSeconds(uint32 seconds)
LoginDatabaseWorkerPool LoginDatabase
std::vector< std::string > RequiredBaseFileNames
std::string ExternalBaseFile
bool AllowUpdateHashMismatch
bool ImportPendingUpdates
std::vector< SqlUpdateFile > PendingUpdates
std::vector< SqlUpdateFile > BaselineUpdates