From c8b3ca53fe083c1b869625bbae1b5f9b13b75f02 Mon Sep 17 00:00:00 2001 From: Chris Miles Date: Thu, 14 Jul 2022 02:39:01 -0500 Subject: [PATCH] [World] World Bootup Consolidation (#2294) --- common/eq_limits.cpp | 32 +- world/CMakeLists.txt | 2 + world/main.cpp | 524 +++++---------------------------- world/world_boot.cpp | 641 +++++++++++++++++++++++++++++++++++++++++ world/world_boot.h | 21 ++ world/world_config.cpp | 228 --------------- world/world_config.h | 2 - 7 files changed, 756 insertions(+), 694 deletions(-) create mode 100644 world/world_boot.cpp create mode 100644 world/world_boot.h diff --git a/common/eq_limits.cpp b/common/eq_limits.cpp index 188c8f888..051857681 100644 --- a/common/eq_limits.cpp +++ b/common/eq_limits.cpp @@ -1,5 +1,5 @@ /* EQEMu: Everquest Server Emulator - + Copyright (C) 2001-2016 EQEMu Development Team (http://eqemulator.net) This program is free software; you can redistribute it and/or modify @@ -11,7 +11,7 @@ are required to give you total support for your newly bought product; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA @@ -26,7 +26,7 @@ static bool global_dictionary_init = false; void EQ::InitializeDynamicLookups() { - if (global_dictionary_init == true) + if (global_dictionary_init) return; constants::InitializeDynamicLookups(); @@ -167,7 +167,7 @@ static const EQ::inventory::LookupEntry inventory_static_lookup_entries[EQ::vers ClientUnknown::INULL, ClientUnknown::INULL, ClientUnknown::INULL, ClientUnknown::INULL ), - + ClientUnknown::INULL, ClientUnknown::INULL, ClientUnknown::INULL, @@ -175,7 +175,7 @@ static const EQ::inventory::LookupEntry inventory_static_lookup_entries[EQ::vers ClientUnknown::INULL, ClientUnknown::INULL, ClientUnknown::INULL, - + false, false, false, @@ -194,7 +194,7 @@ static const EQ::inventory::LookupEntry inventory_static_lookup_entries[EQ::vers Client62::INULL, Client62::INULL, Client62::INULL, Client62::INULL ), - + Client62::INULL, Client62::INULL, Client62::INULL, @@ -202,7 +202,7 @@ static const EQ::inventory::LookupEntry inventory_static_lookup_entries[EQ::vers Client62::INULL, Client62::INULL, Client62::INULL, - + false, false, false, @@ -221,7 +221,7 @@ static const EQ::inventory::LookupEntry inventory_static_lookup_entries[EQ::vers Titanium::INULL, Titanium::INULL, Titanium::INULL, Titanium::invtype::OTHER_SIZE ), - + Titanium::invslot::EQUIPMENT_BITMASK, Titanium::invslot::GENERAL_BITMASK, Titanium::invslot::CURSOR_BITMASK, @@ -229,7 +229,7 @@ static const EQ::inventory::LookupEntry inventory_static_lookup_entries[EQ::vers Titanium::invslot::CORPSE_BITMASK, Titanium::invbag::SLOT_COUNT, Titanium::invaug::SOCKET_COUNT, - + Titanium::inventory::AllowEmptyBagInBag, Titanium::inventory::AllowClickCastFromBag, Titanium::inventory::ConcatenateInvTypeLimbo, @@ -248,7 +248,7 @@ static const EQ::inventory::LookupEntry inventory_static_lookup_entries[EQ::vers SoF::INULL, SoF::INULL, SoF::INULL, SoF::invtype::OTHER_SIZE ), - + SoF::invslot::EQUIPMENT_BITMASK, SoF::invslot::GENERAL_BITMASK, SoF::invslot::CURSOR_BITMASK, @@ -256,7 +256,7 @@ static const EQ::inventory::LookupEntry inventory_static_lookup_entries[EQ::vers SoF::invslot::CORPSE_BITMASK, SoF::invbag::SLOT_COUNT, SoF::invaug::SOCKET_COUNT, - + SoF::inventory::AllowEmptyBagInBag, SoF::inventory::AllowClickCastFromBag, SoF::inventory::ConcatenateInvTypeLimbo, @@ -763,7 +763,7 @@ void EQ::inventory::InitializeDynamicLookups() { // Notes: // - Currently, there are only 3 known expansions that affect inventory-related settings in the clients.. // -- Expansion::PoR "Prophecy of Ro" - toggles between 24 (set) and 16 (clear) bank slots - // -- Expansion::TBS "The Buried Sea" - toggles slotPowerSource activated (set) and deactivated (clear) + // -- Expansion::TBS "The Buried Sea" - toggles slotPowerSource activated (set) and deactivated (clear) // -- Expansion::HoT "House of Thule" - toggles slotGeneral9/slotGeneral10 activated (set) and deactivated (clear) // - Corspe size does not appear to reflect loss of active possessions slots // - Inspect size does not appear to reflect loss of active equipment slots @@ -772,7 +772,7 @@ void EQ::inventory::InitializeDynamicLookups() { // - General9 and General10 slots are activated by GM flag when expansion bit is (clear) // - Obviously, the client must support the expansion to allow any (set) or override condition - const uint32 dynamic_check_mask = + const uint32 dynamic_check_mask = ( EQ::expansions::bitPoR | EQ::expansions::bitTBS | @@ -1210,10 +1210,10 @@ void EQ::spells::InitializeDynamicLookups() { if (spells_dictionary_init == true) return; spells_dictionary_init = true; - + if (RuleB(World, UseClientBasedExpansionSettings)) return; - + // use static references for now } @@ -1239,7 +1239,7 @@ const EQ::spells::LookupEntry* EQ::spells::DynamicGMLookup(versions::ClientVersi client_version = versions::ValidateClientVersion(client_version); if (spells_dynamic_gm_lookup_entries[static_cast(client_version)]) return spells_dynamic_gm_lookup_entries[static_cast(client_version)].get(); - + return &spells_static_lookup_entries[static_cast(client_version)]; } diff --git a/world/CMakeLists.txt b/world/CMakeLists.txt index 650d8f189..fbd040e60 100644 --- a/world/CMakeLists.txt +++ b/world/CMakeLists.txt @@ -31,6 +31,7 @@ SET(world_sources world_console_connection.cpp world_server_command_handler.cpp worlddb.cpp + world_boot.cpp world_store.cpp zonelist.cpp zoneserver.cpp @@ -68,6 +69,7 @@ SET(world_headers world_tcp_connection.h world_server_command_handler.h worlddb.h + world_boot.h world_event_scheduler.h world_store.h zonelist.h diff --git a/world/main.cpp b/world/main.cpp index 6173c0c65..0771ef559 100644 --- a/world/main.cpp +++ b/world/main.cpp @@ -56,12 +56,8 @@ #include #else -#include #include "../common/unix.h" -#include -#include #include -#include #if not defined (FREEBSD) && not defined (DARWIN) union semun { @@ -76,16 +72,13 @@ union semun { #endif #include "../common/patches/patches.h" -#include "../common/random.h" #include "zoneserver.h" #include "login_server.h" #include "login_server_list.h" #include "world_config.h" -#include "zoneserver.h" #include "zonelist.h" #include "clientlist.h" #include "launcher_list.h" -#include "wguild_mgr.h" #include "lfplist.h" #include "adventure_manager.h" #include "ucs.h" @@ -95,18 +88,13 @@ union semun { #include "dynamic_zone_manager.h" #include "expedition_database.h" -#include "../common/net/servertalk_server.h" -#include "../zone/data_bucket.h" #include "world_server_command_handler.h" #include "../common/content/world_content_service.h" #include "../common/repositories/character_task_timers_repository.h" -#include "../common/repositories/merchantlist_temp_repository.h" #include "world_store.h" #include "world_event_scheduler.h" #include "shared_task_manager.h" -#include "../common/ip_util.h" -#include "../common/http/httplib.h" -#include "../common/http/uri.h" +#include "world_boot.h" WorldStore world_store; ClientList client_list; @@ -129,7 +117,6 @@ WorldContentService content_service; WebInterfaceList web_interface; void CatchSignal(int sig_num); -void CheckForServerScript(bool force_download = false); inline void UpdateWindowTitle(std::string new_title) { @@ -138,148 +125,6 @@ inline void UpdateWindowTitle(std::string new_title) #endif } -void LoadDatabaseConnections() -{ - LogInfo( - "Connecting to MySQL [{}]@[{}]:[{}]", - Config->DatabaseUsername.c_str(), - Config->DatabaseHost.c_str(), - Config->DatabasePort - ); - - if (!database.Connect( - Config->DatabaseHost.c_str(), - Config->DatabaseUsername.c_str(), - Config->DatabasePassword.c_str(), - Config->DatabaseDB.c_str(), - Config->DatabasePort - )) { - LogError("Cannot continue without a database connection"); - - std::exit(1); - } - - /** - * Multi-tenancy: Content database - */ - if (!Config->ContentDbHost.empty()) { - if (!content_db.Connect( - Config->ContentDbHost.c_str(), - Config->ContentDbUsername.c_str(), - Config->ContentDbPassword.c_str(), - Config->ContentDbName.c_str(), - Config->ContentDbPort, - "content" - )) { - LogError("Cannot continue without a content database connection"); - std::exit(1); - } - } - else { - content_db.SetMysql(database.getMySQL()); - } - -} - -void CheckForXMLConfigUpgrade() -{ - if (!std::ifstream("eqemu_config.json") && std::ifstream("eqemu_config.xml")) { - CheckForServerScript(true); - if (system("perl eqemu_server.pl convert_xml")) {} - } - else { - CheckForServerScript(); - } -} - -void LoadServerConfig() -{ - LogInfo("Loading server configuration"); - if (!WorldConfig::LoadConfig()) { - LogError("Loading server configuration failed"); - std::exit(1); - } -} - -void RegisterLoginservers() -{ - if (Config->LoginCount == 0) { - if (Config->LoginHost.length()) { - loginserverlist.Add( - Config->LoginHost.c_str(), - Config->LoginPort, - Config->LoginAccount.c_str(), - Config->LoginPassword.c_str(), - Config->LoginLegacy - ); - LogInfo("Added loginserver [{}]:[{}]", Config->LoginHost.c_str(), Config->LoginPort); - } - } - else { - LinkedList loginlist = Config->loginlist; - LinkedListIterator iterator(loginlist); - iterator.Reset(); - while (iterator.MoreElements()) { - if (iterator.GetData()->LoginHost.length()) { - loginserverlist.Add( - iterator.GetData()->LoginHost.c_str(), - iterator.GetData()->LoginPort, - iterator.GetData()->LoginAccount.c_str(), - iterator.GetData()->LoginPassword.c_str(), - iterator.GetData()->LoginLegacy - ); - - LogInfo( - "Added loginserver [{}]:[{}]", - iterator.GetData()->LoginHost.c_str(), - iterator.GetData()->LoginPort - ); - } - iterator.Advance(); - } - } -} - -static void GMSayHookCallBackProcessWorld(uint16 log_category, std::string message) -{ - // Cut messages down to 4000 max to prevent client crash - if (!message.empty()) { - message = message.substr(0, 4000); - } - - // Replace Occurrences of % or MessageStatus will crash - Strings::FindReplace(message, std::string("%"), std::string(".")); - - if (message.find('\n') != std::string::npos) { - auto message_split = Strings::Split(message, '\n'); - - for (size_t iter = 0; iter < message_split.size(); ++iter) { - zoneserver_list.SendEmoteMessage( - 0, - 0, - AccountStatus::QuestTroupe, - LogSys.GetGMSayColorFromCategory(log_category), - fmt::format( - " {}{}", - (iter == 0 ? " ---" : ""), - message_split[iter] - ).c_str() - ); - } - - return; - } - - zoneserver_list.SendEmoteMessage( - 0, - 0, - AccountStatus::QuestTroupe, - LogSys.GetGMSayColorFromCategory(log_category), - "%s", - message.c_str() - ); -} - /** * World process entrypoint * @@ -293,35 +138,15 @@ int main(int argc, char **argv) LogSys.LoadLogSettingsDefaults(); set_exception_handler(); - /** - * Database version - */ - uint32 database_version = CURRENT_BINARY_DATABASE_VERSION; - uint32 bots_database_version = CURRENT_BINARY_BOTS_DATABASE_VERSION; - if (argc >= 2) { - if (strcasecmp(argv[1], "db_version") == 0) { - std::cout << "Binary Database Version: " << database_version << " : " << bots_database_version << std::endl; - return 0; - } + if (!WorldBoot::LoadServerConfig()) { + return 0; } - /** - * Command handler - */ - if (argc > 1) { - LogSys.SilenceConsoleLogging(); - - WorldConfig::LoadConfig(); - Config = WorldConfig::get(); - - LoadDatabaseConnections(); - LogSys.EnableConsoleLogging(); - - WorldserverCommandHandler::CommandHandler(argc, argv); + if (WorldBoot::HandleCommandInput(argc, argv)) { + return 0; } - CheckForXMLConfigUpgrade(); - LoadServerConfig(); + WorldBoot::CheckForXMLConfigUpgrade(); Config = WorldConfig::get(); @@ -344,190 +169,30 @@ int main(int argc, char **argv) } #endif - RegisterLoginservers(); - LoadDatabaseConnections(); - - guild_mgr.SetDatabase(&database); - - // logging system init - auto logging = LogSys.SetDatabase(&database) - ->LoadLogDatabaseSettings(); - - if (RuleB(Logging, WorldGMSayLogging)) { - logging->SetGMSayHandler(&GMSayHookCallBackProcessWorld); + WorldBoot::RegisterLoginservers(); + WorldBoot::LoadDatabaseConnections(); + if (!WorldBoot::DatabaseLoadRoutines(argc, argv)) { + return 1; } - logging->StartFileLogs(); - - /** - * Parse simple CLI passes - */ - bool ignore_db = false; - if (argc >= 2) { - if (strcasecmp(argv[1], "ignore_db") == 0) { - ignore_db = true; - } - else { - std::cerr << "Error, unknown command line option" << std::endl; - return 1; - } - } - - if (!ignore_db) { - LogInfo("Checking Database Conversions"); - database.CheckDatabaseConversions(); - } - LogInfo("Loading variables"); - database.LoadVariables(); - - std::string hotfix_name; - if (database.GetVariable("hotfix_name", hotfix_name)) { - if (!hotfix_name.empty()) { - LogInfo("Current hotfix in use: [{}]", hotfix_name.c_str()); - } - } - - LogInfo("Purging expired data buckets"); - database.PurgeAllDeletedDataBuckets(); - - LogInfo("Loading zones"); - - world_store.LoadZones(); - - LogInfo("Clearing groups"); - database.ClearGroup(); - LogInfo("Clearing raids"); - database.ClearRaid(); - database.ClearRaidDetails(); - database.ClearRaidLeader(); - LogInfo("Clearing inventory snapshots"); - database.ClearInvSnapshots(); - LogInfo("Loading items"); - - if (!content_db.LoadItems(hotfix_name)) { - LogError("Error: Could not load item data. But ignoring"); - } - - LogInfo("Loading skill caps"); - if (!content_db.LoadSkillCaps(std::string(hotfix_name))) { - LogError("Error: Could not load skill cap data. But ignoring"); - } - - LogInfo("Loading guilds"); - guild_mgr.LoadGuilds(); - - //rules: - { - if (!RuleManager::Instance()->UpdateOrphanedRules(&database)) { - LogInfo("Failed to process 'Orphaned Rules' update operation."); - } - - if (!RuleManager::Instance()->UpdateInjectedRules(&database, "default")) { - LogInfo("Failed to process 'Injected Rules' for ruleset 'default' update operation."); - } - - std::string tmp; - if (database.GetVariable("RuleSet", tmp)) { - LogInfo("Loading rule set [{}]", tmp.c_str()); - - if (!RuleManager::Instance()->LoadRules(&database, tmp.c_str(), false)) { - LogInfo("Failed to load ruleset [{}], falling back to defaults", tmp.c_str()); - } - } - else { - - if (!RuleManager::Instance()->LoadRules(&database, "default", false)) { - LogInfo("No rule set configured, using default rules"); - } - else { - LogInfo("Loaded default rule set [default]", tmp.c_str()); - } - } - - if (!RuleManager::Instance()->RestoreRuleNotes(&database)) { - LogInfo("Failed to process 'Restore Rule Notes' update operation."); - } - } - - EQ::InitializeDynamicLookups(); - LogInfo("Initialized dynamic dictionary entries"); - - if (RuleB(World, ClearTempMerchantlist)) { - LogInfo("Clearing temporary merchant lists"); - database.ClearMerchantTemp(); - } - - LogInfo("Loading EQ time of day"); - TimeOfDay_Struct eqTime; - time_t realtime; - eqTime = database.LoadTime(realtime); - zoneserver_list.worldclock.SetCurrentEQTimeOfDay(eqTime, realtime); + // timers + Timer PurgeInstanceTimer(450000); + PurgeInstanceTimer.Start(450000); Timer EQTimeTimer(600000); EQTimeTimer.Start(600000); + // global loads LogInfo("Loading launcher list"); launcher_list.LoadList(); - - LogInfo("Deleted [{}] stale player corpses from database", database.DeleteStalePlayerCorpses()); - - LogInfo("Loading adventures"); - if (!adventure_manager.LoadAdventureTemplates()) { - LogInfo("Unable to load adventure templates"); - } - - if (!adventure_manager.LoadAdventureEntries()) { - LogInfo("Unable to load adventure templates"); - } - - adventure_manager.LoadLeaderboardInfo(); - - LogInfo("Purging expired dynamic zones and members"); - dynamic_zone_manager.PurgeExpiredDynamicZones(); - - LogInfo("Purging expired expeditions"); - ExpeditionDatabase::PurgeExpiredExpeditions(); - ExpeditionDatabase::PurgeExpiredCharacterLockouts(); - - LogInfo("Purging expired character task timers"); - CharacterTaskTimersRepository::DeleteWhere(database, "expire_time <= NOW()"); - - LogInfo("Purging expired instances"); - database.PurgeExpiredInstances(); - - Timer PurgeInstanceTimer(450000); - PurgeInstanceTimer.Start(450000); - - LogInfo("Loading dynamic zones"); - dynamic_zone_manager.CacheAllFromDatabase(); - - LogInfo("Loading char create info"); - content_db.LoadCharacterCreateAllocations(); - content_db.LoadCharacterCreateCombos(); - - LogInfo("Initializing [EventScheduler]"); - event_scheduler.SetDatabase(&database)->LoadScheduledEvents(); - - LogInfo("Initializing [WorldContentService]"); - content_service.SetDatabase(&database) - ->SetExpansionContext() - ->ReloadContentFlags(); - - LogInfo("Initializing [SharedTaskManager]"); - shared_task_manager.SetDatabase(&database) - ->SetContentDatabase(&content_db) - ->LoadTaskData() - ->LoadSharedTaskState(); - - shared_task_manager.PurgeExpiredSharedTasks(); + zoneserver_list.Init(); std::unique_ptr console; if (Config->TelnetEnabled) { - LogInfo("Console (TCP) listener started"); + LogInfo("Console (TCP) listener started on [{}:{}]", Config->TelnetIP, Config->TelnetTCPPort); console = std::make_unique(Config->TelnetIP, Config->TelnetTCPPort); RegisterConsoleFunctions(console); } - zoneserver_list.Init(); std::unique_ptr server_connection; server_connection = std::make_unique(); @@ -536,32 +201,44 @@ int main(int argc, char **argv) server_opts.ipv6 = false; server_opts.credentials = Config->SharedKey; server_connection->Listen(server_opts); - LogInfo("Server (TCP) listener started"); + LogInfo("Server (TCP) listener started on port [{}]", Config->WorldTCPPort); server_connection->OnConnectionIdentified( "Zone", [&console](std::shared_ptr connection) { - LogInfo("New Zone Server connection from [{2}] at [{0}:{1}]", - connection->Handle()->RemoteIP(), connection->Handle()->RemotePort(), connection->GetUUID()); - numzones++; zoneserver_list.Add(new ZoneServer(connection, console.get())); + + LogInfo( + "New Zone Server connection from [{}] at [{}:{}] zone_count ({})", + connection->Handle()->RemoteIP(), + connection->Handle()->RemotePort(), + connection->GetUUID(), + numzones + ); } ); server_connection->OnConnectionRemoved( "Zone", [](std::shared_ptr connection) { - LogInfo("Removed Zone Server connection from [{0}]", - connection->GetUUID()); - numzones--; zoneserver_list.Remove(connection->GetUUID()); + + LogInfo( + "Removed Zone Server connection from [{}] total zone_count [{}]", + connection->GetUUID(), + numzones + ); } ); server_connection->OnConnectionIdentified( "Launcher", [](std::shared_ptr connection) { - LogInfo("New Launcher connection from [{2}] at [{0}:{1}]", - connection->Handle()->RemoteIP(), connection->Handle()->RemotePort(), connection->GetUUID()); + LogInfo( + "New Launcher connection from [{}] at [{}:{}]", + connection->Handle()->RemoteIP(), + connection->Handle()->RemotePort(), + connection->GetUUID() + ); launcher_list.Add(connection); } @@ -569,8 +246,10 @@ int main(int argc, char **argv) server_connection->OnConnectionRemoved( "Launcher", [](std::shared_ptr connection) { - LogInfo("Removed Launcher connection from [{0}]", - connection->GetUUID()); + LogInfo( + "Removed Launcher connection from [{0}]", + connection->GetUUID() + ); launcher_list.Remove(connection); } @@ -578,8 +257,11 @@ int main(int argc, char **argv) server_connection->OnConnectionIdentified( "QueryServ", [](std::shared_ptr connection) { - LogInfo("New Query Server connection from [{2}] at [{0}:{1}]", - connection->Handle()->RemoteIP(), connection->Handle()->RemotePort(), connection->GetUUID()); + LogInfo( + "New Query Server connection from [{}] at [{}:{}]", + connection->Handle()->RemoteIP(), + connection->Handle()->RemotePort(), + connection->GetUUID()); QSLink.AddConnection(connection); } @@ -587,8 +269,10 @@ int main(int argc, char **argv) server_connection->OnConnectionRemoved( "QueryServ", [](std::shared_ptr connection) { - LogInfo("Removed Query Server connection from [{0}]", - connection->GetUUID()); + LogInfo( + "Removed Query Server connection from [{}]", + connection->GetUUID() + ); QSLink.RemoveConnection(connection); } @@ -596,8 +280,12 @@ int main(int argc, char **argv) server_connection->OnConnectionIdentified( "UCS", [](std::shared_ptr connection) { - LogInfo("New UCS Server connection from [{2}] at [{0}:{1}]", - connection->Handle()->RemoteIP(), connection->Handle()->RemotePort(), connection->GetUUID()); + LogInfo( + "New UCS Server connection from [{}] at [{}:{}]", + connection->Handle()->RemoteIP(), + connection->Handle()->RemotePort(), + connection->GetUUID() + ); UCSLink.SetConnection(connection); @@ -607,7 +295,7 @@ int main(int argc, char **argv) server_connection->OnConnectionRemoved( "UCS", [](std::shared_ptr connection) { - LogInfo("Connection lost from UCS Server [{0}]", connection->GetUUID()); + LogInfo("Connection lost from UCS Server [{}]", connection->GetUUID()); auto ucs_connection = UCSLink.GetConnection(); @@ -621,8 +309,12 @@ int main(int argc, char **argv) server_connection->OnConnectionIdentified( "WebInterface", [](std::shared_ptr connection) { - LogInfo("New WebInterface Server connection from [{2}] at [{0}:{1}]", - connection->Handle()->RemoteIP(), connection->Handle()->RemotePort(), connection->GetUUID()); + LogInfo( + "New WebInterface Server connection from [{}] at [{}:{}]", + connection->Handle()->RemoteIP(), + connection->Handle()->RemotePort(), + connection->GetUUID() + ); web_interface.AddConnection(connection); } @@ -630,14 +322,16 @@ int main(int argc, char **argv) server_connection->OnConnectionRemoved( "WebInterface", [](std::shared_ptr connection) { - LogInfo("Removed WebInterface Server connection from [{0}]", - connection->GetUUID()); + LogInfo( + "Removed WebInterface Server connection from [{}]", + connection->GetUUID() + ); web_interface.RemoveConnection(connection); } ); - WorldConfig::CheckForPossibleConfigurationIssues(); + WorldBoot::CheckForPossibleConfigurationIssues(); EQStreamManagerInterfaceOptions opts(9000, false, false); opts.daybreak_options.resend_delay_ms = RuleI(Network, ResendDelayBaseMS); @@ -664,7 +358,11 @@ int main(int argc, char **argv) eqsm.OnNewConnection( [&stream_identifier](std::shared_ptr stream) { stream_identifier.AddStream(stream); - LogInfo("New connection from IP {}:{}", long2ip(stream->GetRemoteIP()), ntohs(stream->GetRemotePort())); + LogInfo( + "New [EverQuest Client] connection from IP [{}:{}]", + long2ip(stream->GetRemoteIP()), + ntohs(stream->GetRemotePort()) + ); } ); @@ -736,9 +434,9 @@ int main(int argc, char **argv) database.ping(); content_db.ping(); - std::string window_title = StringFormat( - "World: %s Clients: %i", - Config->LongName.c_str(), + std::string window_title = fmt::format( + "World [{}] Clients [{}]", + Config->LongName, client_list.GetClientCount() ); UpdateWindowTitle(window_title); @@ -762,73 +460,3 @@ void CatchSignal(int sig_num) LogInfo("Caught signal [{}]", sig_num); RunLoops = false; } - -void UpdateWindowTitle(char *iNewTitle) -{ -#ifdef _WINDOWS - char tmp[500]; - if (iNewTitle) { - snprintf(tmp, sizeof(tmp), "World: %s", iNewTitle); - } - else { - snprintf(tmp, sizeof(tmp), "World"); - } - SetConsoleTitle(tmp); -#endif -} - -int get_file_size(const std::string& filename) // path to file -{ - FILE *p_file = NULL; - p_file = fopen(filename.c_str(),"rb"); - fseek(p_file,0,SEEK_END); - int size = ftell(p_file); - fclose(p_file); - return size; -} - -void CheckForServerScript(bool force_download) -{ - const std::string file = "eqemu_server.pl"; - std::ifstream f(file); - - /* Fetch EQEmu Server script */ - if (!f || get_file_size(file) < 100 || force_download) { - - if (force_download) { - std::remove("eqemu_server.pl"); - } /* Delete local before fetch */ - - std::cout << "Pulling down EQEmu Server Maintenance Script (eqemu_server.pl)..." << std::endl; - - // http get request - uri u("https://raw.githubusercontent.com/EQEmu/Server/master/utils/scripts/eqemu_server.pl"); - - httplib::Client r( - fmt::format( - "{}://{}", - u.get_scheme(), - u.get_host() - ).c_str() - ); - - r.set_connection_timeout(1, 0); - r.set_read_timeout(1, 0); - r.set_write_timeout(1, 0); - - if (auto res = r.Get(u.get_path().c_str())) { - if (res->status == 200) { - // write file - std::ofstream out("eqemu_server.pl"); - out << res->body; - out.close(); -#ifdef _WIN32 -#else - system("chmod 755 eqemu_server.pl"); - system("chmod +x eqemu_server.pl"); -#endif - } - } - } -} - diff --git a/world/world_boot.cpp b/world/world_boot.cpp new file mode 100644 index 000000000..2e4b8d4ea --- /dev/null +++ b/world/world_boot.cpp @@ -0,0 +1,641 @@ +#include "../common/content/world_content_service.h" +#include "../common/emu_constants.h" +#include "../common/eqemu_logsys.h" +#include "../common/http/httplib.h" +#include "../common/http/uri.h" +#include "../common/net/console_server.h" +#include "../common/net/servertalk_server.h" +#include "../common/repositories/character_task_timers_repository.h" +#include "../common/rulesys.h" +#include "../common/strings.h" +#include "adventure_manager.h" +#include "dynamic_zone_manager.h" +#include "expedition_database.h" +#include "login_server_list.h" +#include "shared_task_manager.h" +#include "ucs.h" +#include "wguild_mgr.h" +#include "world_boot.h" +#include "world_config.h" +#include "world_event_scheduler.h" +#include "world_server_command_handler.h" +#include "world_store.h" +#include "worlddb.h" +#include "zonelist.h" +#include "zoneserver.h" +#include "../common/ip_util.h" + +extern ZSList zoneserver_list; +extern WorldConfig Config; + +void WorldBoot::GMSayHookCallBackProcessWorld(uint16 log_category, std::string message) +{ + // Cut messages down to 4000 max to prevent client crash + if (!message.empty()) { + message = message.substr(0, 4000); + } + + // Replace Occurrences of % or MessageStatus will crash + Strings::FindReplace(message, std::string("%"), std::string(".")); + + if (message.find('\n') != std::string::npos) { + auto message_split = Strings::Split(message, '\n'); + + for (size_t iter = 0; iter < message_split.size(); ++iter) { + zoneserver_list.SendEmoteMessage( + 0, + 0, + AccountStatus::QuestTroupe, + LogSys.GetGMSayColorFromCategory(log_category), + fmt::format( + " {}{}", + (iter == 0 ? " ---" : ""), + message_split[iter] + ).c_str() + ); + } + + return; + } + + zoneserver_list.SendEmoteMessage( + 0, + 0, + AccountStatus::QuestTroupe, + LogSys.GetGMSayColorFromCategory(log_category), + "%s", + message.c_str() + ); +} + +bool WorldBoot::HandleCommandInput(int argc, char **argv) +{ + // database version + uint32 database_version = CURRENT_BINARY_DATABASE_VERSION; + uint32 bots_database_version = CURRENT_BINARY_BOTS_DATABASE_VERSION; + if (argc >= 2) { + if (strcasecmp(argv[1], "db_version") == 0) { + std::cout << "Binary Database Version: " << database_version << " : " << bots_database_version << std::endl; + return true; + } + } + + // command handler + if (argc > 1) { + LogSys.SilenceConsoleLogging(); + WorldConfig::LoadConfig(); + LoadDatabaseConnections(); + LogSys.EnableConsoleLogging(); + WorldserverCommandHandler::CommandHandler(argc, argv); + } + + return false; +} + +bool WorldBoot::LoadServerConfig() +{ + LogInfo("[WorldBoot::LoadServerConfig] Loading server configuration"); + if (!WorldConfig::LoadConfig()) { + LogError("[WorldBoot::LoadServerConfig] Loading server configuration failed"); + return false; + } + + return true; +} + + +bool WorldBoot::LoadDatabaseConnections() +{ + const auto c = EQEmuConfig::get(); + + LogInfo( + "Connecting to MySQL [{}]@[{}]:[{}]", + c->DatabaseUsername.c_str(), + c->DatabaseHost.c_str(), + c->DatabasePort + ); + + if (!database.Connect( + c->DatabaseHost.c_str(), + c->DatabaseUsername.c_str(), + c->DatabasePassword.c_str(), + c->DatabaseDB.c_str(), + c->DatabasePort + )) { + LogError("Cannot continue without a database connection"); + + return false; + } + + /** + * Multi-tenancy: Content database + */ + if (!c->ContentDbHost.empty()) { + if (!content_db.Connect( + c->ContentDbHost.c_str(), + c->ContentDbUsername.c_str(), + c->ContentDbPassword.c_str(), + c->ContentDbName.c_str(), + c->ContentDbPort, + "content" + )) { + LogError("Cannot continue without a content database connection"); + return false; + } + } + else { + content_db.SetMysql(database.getMySQL()); + } + + return true; +} + +int get_file_size(const std::string &filename) // path to file +{ + FILE *p_file = NULL; + p_file = fopen(filename.c_str(), "rb"); + fseek(p_file, 0, SEEK_END); + int size = ftell(p_file); + fclose(p_file); + return size; +} + + +void WorldBoot::CheckForServerScript(bool force_download) +{ + const std::string file = "eqemu_server.pl"; + std::ifstream f(file); + + /* Fetch EQEmu Server script */ + if (!f || get_file_size(file) < 100 || force_download) { + + if (force_download) { + std::remove("eqemu_server.pl"); + } /* Delete local before fetch */ + + std::cout << "Pulling down EQEmu Server Maintenance Script (eqemu_server.pl)..." << std::endl; + + // http get request + uri u("https://raw.githubusercontent.com/EQEmu/Server/master/utils/scripts/eqemu_server.pl"); + + httplib::Client r( + fmt::format( + "{}://{}", + u.get_scheme(), + u.get_host() + ).c_str() + ); + + r.set_connection_timeout(1, 0); + r.set_read_timeout(1, 0); + r.set_write_timeout(1, 0); + + if (auto res = r.Get(u.get_path().c_str())) { + if (res->status == 200) { + // write file + std::ofstream out("eqemu_server.pl"); + out << res->body; + out.close(); +#ifdef _WIN32 +#else + system("chmod 755 eqemu_server.pl"); + system("chmod +x eqemu_server.pl"); +#endif + } + } + } +} + +void WorldBoot::CheckForXMLConfigUpgrade() +{ + if (!std::ifstream("eqemu_config.json") && std::ifstream("eqemu_config.xml")) { + CheckForServerScript(true); + if (system("perl eqemu_server.pl convert_xml")) {} + } + else { + CheckForServerScript(); + } +} + +extern LoginServerList loginserverlist; + +void WorldBoot::RegisterLoginservers() +{ + const auto c = EQEmuConfig::get(); + + if (c->LoginCount == 0) { + if (c->LoginHost.length()) { + loginserverlist.Add( + c->LoginHost.c_str(), + c->LoginPort, + c->LoginAccount.c_str(), + c->LoginPassword.c_str(), + c->LoginLegacy + ); + LogInfo("Added loginserver [{}]:[{}]", c->LoginHost.c_str(), c->LoginPort); + } + } + else { + LinkedList loginlist = c->loginlist; + LinkedListIterator iterator(loginlist); + iterator.Reset(); + while (iterator.MoreElements()) { + if (iterator.GetData()->LoginHost.length()) { + loginserverlist.Add( + iterator.GetData()->LoginHost.c_str(), + iterator.GetData()->LoginPort, + iterator.GetData()->LoginAccount.c_str(), + iterator.GetData()->LoginPassword.c_str(), + iterator.GetData()->LoginLegacy + ); + + LogInfo( + "Added loginserver [{}]:[{}]", + iterator.GetData()->LoginHost.c_str(), + iterator.GetData()->LoginPort + ); + } + iterator.Advance(); + } + } +} + +extern SharedTaskManager shared_task_manager; +extern AdventureManager adventure_manager; +extern WorldEventScheduler event_scheduler; + +bool WorldBoot::DatabaseLoadRoutines(int argc, char **argv) +{ + // ignore + bool ignore_db = false; + if (argc >= 2) { + if (strcasecmp(argv[1], "ignore_db") == 0) { + ignore_db = true; + } + else { + std::cerr << "Error, unknown command line option" << std::endl; + return false; + } + } + + if (!ignore_db) { + LogInfo("Checking Database Conversions"); + database.CheckDatabaseConversions(); + } + + // logging system init + auto logging = LogSys.SetDatabase(&database) + ->LoadLogDatabaseSettings(); + + if (RuleB(Logging, WorldGMSayLogging)) { + logging->SetGMSayHandler(&WorldBoot::GMSayHookCallBackProcessWorld); + } + + logging->StartFileLogs(); + + LogInfo("Loading variables"); + database.LoadVariables(); + + std::string hotfix_name; + if (database.GetVariable("hotfix_name", hotfix_name)) { + if (!hotfix_name.empty()) { + LogInfo("Current hotfix in use: [{}]", hotfix_name.c_str()); + } + } + + guild_mgr.SetDatabase(&database); + + LogInfo("Purging expired data buckets"); + database.PurgeAllDeletedDataBuckets(); + + LogInfo("Loading zones"); + + world_store.LoadZones(); + + LogInfo("Clearing groups"); + database.ClearGroup(); + LogInfo("Clearing raids"); + database.ClearRaid(); + database.ClearRaidDetails(); + database.ClearRaidLeader(); + LogInfo("Clearing inventory snapshots"); + database.ClearInvSnapshots(); + LogInfo("Loading items"); + + if (!content_db.LoadItems(hotfix_name)) { + LogError("Error: Could not load item data. But ignoring"); + } + + LogInfo("Loading skill caps"); + if (!content_db.LoadSkillCaps(std::string(hotfix_name))) { + LogError("Error: Could not load skill cap data. But ignoring"); + } + + LogInfo("Loading guilds"); + guild_mgr.LoadGuilds(); + + //rules: + { + if (!RuleManager::Instance()->UpdateOrphanedRules(&database)) { + LogInfo("Failed to process 'Orphaned Rules' update operation."); + } + + if (!RuleManager::Instance()->UpdateInjectedRules(&database, "default")) { + LogInfo("Failed to process 'Injected Rules' for ruleset 'default' update operation."); + } + + std::string tmp; + if (database.GetVariable("RuleSet", tmp)) { + LogInfo("Loading rule set [{}]", tmp.c_str()); + + if (!RuleManager::Instance()->LoadRules(&database, tmp.c_str(), false)) { + LogInfo("Failed to load ruleset [{}], falling back to defaults", tmp.c_str()); + } + } + else { + + if (!RuleManager::Instance()->LoadRules(&database, "default", false)) { + LogInfo("No rule set configured, using default rules"); + } + else { + LogInfo("Loaded default rule set [default]", tmp.c_str()); + } + } + + if (!RuleManager::Instance()->RestoreRuleNotes(&database)) { + LogInfo("Failed to process 'Restore Rule Notes' update operation."); + } + } + + EQ::InitializeDynamicLookups(); + LogInfo("Initialized dynamic dictionary entries"); + + if (RuleB(World, ClearTempMerchantlist)) { + LogInfo("Clearing temporary merchant lists"); + database.ClearMerchantTemp(); + } + + LogInfo("Loading EQ time of day"); + TimeOfDay_Struct eqTime{}; + time_t realtime; + eqTime = database.LoadTime(realtime); + zoneserver_list.worldclock.SetCurrentEQTimeOfDay(eqTime, realtime); + + LogInfo("Deleted [{}] stale player corpses from database", database.DeleteStalePlayerCorpses()); + + LogInfo("Loading adventures"); + if (!adventure_manager.LoadAdventureTemplates()) { + LogInfo("Unable to load adventure templates"); + } + + if (!adventure_manager.LoadAdventureEntries()) { + LogInfo("Unable to load adventure templates"); + } + + adventure_manager.LoadLeaderboardInfo(); + + LogInfo("Purging expired dynamic zones and members"); + dynamic_zone_manager.PurgeExpiredDynamicZones(); + + LogInfo("Purging expired expeditions"); + ExpeditionDatabase::PurgeExpiredExpeditions(); + ExpeditionDatabase::PurgeExpiredCharacterLockouts(); + + LogInfo("Purging expired character task timers"); + CharacterTaskTimersRepository::DeleteWhere(database, "expire_time <= NOW()"); + + LogInfo("Purging expired instances"); + database.PurgeExpiredInstances(); + + LogInfo("Loading dynamic zones"); + dynamic_zone_manager.CacheAllFromDatabase(); + + LogInfo("Loading char create info"); + content_db.LoadCharacterCreateAllocations(); + content_db.LoadCharacterCreateCombos(); + + LogInfo("Initializing [EventScheduler]"); + event_scheduler.SetDatabase(&database)->LoadScheduledEvents(); + + LogInfo("Initializing [WorldContentService]"); + content_service.SetDatabase(&database) + ->SetExpansionContext() + ->ReloadContentFlags(); + + LogInfo("Initializing [SharedTaskManager]"); + shared_task_manager.SetDatabase(&database) + ->SetContentDatabase(&content_db) + ->LoadTaskData() + ->LoadSharedTaskState(); + + shared_task_manager.PurgeExpiredSharedTasks(); + + return true; +} + +void WorldBoot::CheckForPossibleConfigurationIssues() +{ + const auto c = EQEmuConfig::get(); + + if (c->DisableConfigChecks) { + LogInfo("Configuration checking [disabled]"); + return; + } + + const std::string local_address = IpUtil::GetLocalIPAddress(); + const std::string public_address = IpUtil::GetPublicIPAddress(); + const std::string config_file = "eqemu_config.json"; + const std::ifstream is_in_docker("/.dockerenv"); + + if (local_address.empty() && public_address.empty()) { + LogInfo("Configuration check, probes failed for local and public address, returning"); + return; + } + + LogInfo("Checking for possible configuration issues"); + LogInfo("To disable configuration checks, set [server.disable_config_checks] to [true] in [{}]", config_file); + + std::string config_address = c->WorldAddress; + if (!IpUtil::IsIPAddress(config_address)) { + config_address = IpUtil::DNSLookupSync(c->WorldAddress, 9000); + LogInfo( + "World config address using DNS [{}] resolves to [{}]", + c->WorldAddress, + config_address + ); + } + + std::cout << std::endl; + + // lan detection + if (local_address != public_address + && IpUtil::IsIpInPrivateRfc1918(local_address) + && local_address != c->LocalAddress + && !is_in_docker + ) { + LogWarning("# LAN detection (Configuration)"); + LogWarning(""); + LogWarning("You appear to be on a LAN and your localaddress may not be properly set!"); + LogWarning("This can prevent local clients from properly connecting to your server"); + LogWarning(""); + LogWarning("Docs [https://docs.eqemu.io/server/installation/configure-your-eqemu_config/#world]"); + LogWarning(""); + LogWarning("Config file [{}] path [server.world] variable [localaddress]", config_file); + LogWarning(""); + LogWarning("Local address (eqemu_config) value [{}] detected value [{}]", c->LocalAddress, local_address); + std::cout << std::endl; + } + + // docker configuration + if ( + ( + (c->LocalAddress.empty() && config_address.empty()) || + (config_address != public_address) + ) + && is_in_docker + ) { + LogWarning("# Docker Configuration (Configuration)"); + LogWarning(""); + LogWarning("You appear to running EQEmu in a docker container"); + LogWarning("In order for networking to work properly you will need to properly configure your server"); + LogWarning(""); + LogWarning( + "If your Docker host is on a [LAN] or behind a NAT / Firewall, your [localaddress] variable under [server.world] will need to"); + LogWarning( + "be set to your LAN address on the host, not the container address. [address] will need to be your public address"); + LogWarning(""); + LogWarning( + "If your Docker host is directly on the [public internet], your [localaddress] variable under [server.world] can be set to [127.0.0.1]." + ); + LogWarning(""); + LogWarning("[address] will need to be your public address"); + LogWarning(""); + LogWarning("Docs [https://docs.eqemu.io/server/installation/configure-your-eqemu_config/#world]"); + LogWarning(""); + LogWarning("Config file [{}] path [server.world] variable(s) [localaddress] [address]", config_file); + LogWarning(""); + LogWarning("Local address (eqemu_config) value [{}] detected value [{}]", c->LocalAddress, local_address); + LogWarning( + "Public address (eqemu_config) value [{}] detected value [{}]", + config_address, + public_address + ); + std::cout << std::endl; + } + + // docker LAN not set + if (c->LocalAddress.empty() && is_in_docker) { + LogWarning("# Docker LAN (Configuration)"); + LogWarning(""); + LogWarning("You appear to running EQEmu in a docker container"); + LogWarning( + "Your local address does not appear to be set, this may not be an issue if your deployment is not on a LAN" + ); + LogWarning(""); + LogWarning( + "If your Docker host is on a [LAN] or behind a NAT / Firewall, your [localaddress] variable under [server.world] will need to"); + LogWarning( + "be set to your LAN address on the host, not the container address. [address] will need to be your public address"); + LogWarning(""); + LogWarning( + "If your Docker host is directly on the [public internet], your [localaddress] variable under [server.world] can be set to [127.0.0.1]." + ); + LogWarning(""); + LogWarning("[address] will need to be your public address"); + LogWarning(""); + LogWarning("Docs [https://docs.eqemu.io/server/installation/configure-your-eqemu_config/#world]"); + LogWarning(""); + LogWarning("Config file [{}] path [server.world] variable(s) [localaddress] [address]", config_file); + LogWarning(""); + LogWarning("Local address (eqemu_config) value [{}] detected value [{}]", c->LocalAddress, local_address); + LogWarning( + "Public address (eqemu_config) value [{}] detected value [{}]", + config_address, + public_address + ); + std::cout << std::endl; + } + + // public address different from configuration + if (!config_address.empty() && public_address != config_address) { + LogWarning("# Public address (Configuration)"); + LogWarning(""); + LogWarning("Your configured public address appears to be different from what's detected!"); + LogWarning(""); + LogWarning("Docs [https://docs.eqemu.io/server/installation/configure-your-eqemu_config/#world]"); + LogWarning(""); + LogWarning("Config file [{}] path [server.world] variable [address]", config_file); + LogWarning(""); + LogWarning( + "Public address (eqemu_config) value [{}] detected value [{}]", + config_address, + public_address + ); + std::cout << std::endl; + } + + // public address set to meta-address + if (config_address == "0.0.0.0") { + LogWarning("# Public meta-address (Configuration)"); + LogWarning(""); + LogWarning("Your configured public address is set to a meta-address (0.0.0.0) (all-interfaces)"); + LogWarning( + "The meta-address may not work properly and it is recommended you configure your public address explicitly"); + LogWarning(""); + LogWarning("Docs [https://docs.eqemu.io/server/installation/configure-your-eqemu_config/#world]"); + LogWarning(""); + LogWarning("Config file [{}] path [server.world] variable [address]", config_file); + LogWarning(""); + LogWarning( + "Public address (eqemu_config) value [{}] detected value [{}]", + config_address, + public_address + ); + std::cout << std::endl; + } + + // local address set to meta-address + if (c->LocalAddress == "0.0.0.0") { + LogWarning("# Local meta-address (Configuration)"); + LogWarning(""); + LogWarning("Your configured local address is set to a meta-address (0.0.0.0) (all-interfaces)"); + LogWarning( + "The meta-address may not work properly and it is recommended you configure your local address explicitly" + ); + LogWarning(""); + LogWarning("Docs [https://docs.eqemu.io/server/installation/configure-your-eqemu_config/#world]"); + LogWarning(""); + LogWarning("Config file [{}] path [server.world] variable [localaddress]", config_file); + LogWarning(""); + LogWarning("Local address (eqemu_config) value [{}] detected value [{}]", c->LocalAddress, local_address); + std::cout << std::endl; + } + + // ucs (public) + if ( + (!config_address.empty() && c->MailHost != config_address) || + (!config_address.empty() && c->ChatHost != config_address) + ) { + LogWarning("# UCS Address Mailhost (Configuration)"); + LogWarning(""); + LogWarning( + "UCS (Universal Chat Service) mail or chat appears to use a different address from your main world address" + ); + LogWarning("This can result in a chat service that doesn't network properly"); + LogWarning(""); + LogWarning("Docs [https://docs.eqemu.io/server/installation/configure-your-eqemu_config/#mailserver]"); + LogWarning(""); + LogWarning( + "[server.world.address] value [{}] [server.chatserver.host] [{}]", + config_address, + c->ChatHost + ); + LogWarning( + "[server.world.address] value [{}] [server.mailserver.host] [{}]", + config_address, + c->MailHost + ); + std::cout << std::endl; + } +} + diff --git a/world/world_boot.h b/world/world_boot.h new file mode 100644 index 000000000..80afb6370 --- /dev/null +++ b/world/world_boot.h @@ -0,0 +1,21 @@ +#ifndef EQEMU_WORLD_BOOT_H +#define EQEMU_WORLD_BOOT_H + +#include +#include "../common/types.h" + +class WorldBoot { +public: + static void GMSayHookCallBackProcessWorld(uint16 log_category, std::string message); + static bool HandleCommandInput(int argc, char **argv); + static bool LoadServerConfig(); + static bool LoadDatabaseConnections(); + static void CheckForServerScript(bool force_download = false); + static void CheckForXMLConfigUpgrade(); + static void RegisterLoginservers(); + static bool DatabaseLoadRoutines(int argc, char **argv); + static void CheckForPossibleConfigurationIssues(); +}; + + +#endif //EQEMU_WORLD_BOOT_H diff --git a/world/world_config.cpp b/world/world_config.cpp index b66d4b9d7..d49884740 100644 --- a/world/world_config.cpp +++ b/world/world_config.cpp @@ -18,7 +18,6 @@ #include "../common/global_define.h" #include "../common/eqemu_logsys.h" #include "world_config.h" -#include "../common/ip_util.h" WorldConfig *WorldConfig::_world_config = nullptr; @@ -32,231 +31,4 @@ std::string WorldConfig::GetByName(const std::string &var_name) const } return (EQEmuConfig::GetByName(var_name)); } - -void WorldConfig::CheckForPossibleConfigurationIssues() -{ - if (_config->DisableConfigChecks) { - LogInfo("Configuration checking [disabled]"); - return; - } - - const std::string local_address = IpUtil::GetLocalIPAddress(); - const std::string public_address = IpUtil::GetPublicIPAddress(); - const std::string config_file = "eqemu_config.json"; - const std::ifstream is_in_docker("/.dockerenv"); - - if (local_address.empty() && public_address.empty()) { - LogInfo("Configuration check, probes failed for local and public address, returning"); - return; - } - - LogInfo("Checking for possible configuration issues"); - LogInfo("To disable configuration checks, set [server.disable_config_checks] to [true] in [{}]", config_file); - - std::string config_address = _config->WorldAddress; - if (!IpUtil::IsIPAddress(config_address)) { - config_address = IpUtil::DNSLookupSync(_config->WorldAddress, 9000); - LogInfo( - "World config address using DNS [{}] resolves to [{}]", - _config->WorldAddress, - config_address - ); - } - - std::cout << std::endl; - - // lan detection - if (local_address != public_address - && IpUtil::IsIpInPrivateRfc1918(local_address) - && local_address != _config->LocalAddress - && !is_in_docker - ) { - LogWarning("# LAN detection (Configuration)"); - LogWarning(""); - LogWarning("You appear to be on a LAN and your localaddress may not be properly set!"); - LogWarning("This can prevent local clients from properly connecting to your server"); - LogWarning(""); - LogWarning("Docs [https://docs.eqemu.io/server/installation/configure-your-eqemu_config/#world]"); - LogWarning(""); - LogWarning("Config file [{}] path [server.world] variable [localaddress]", config_file); - LogWarning(""); - LogWarning("Local address (eqemu_config) value [{}] detected value [{}]", _config->LocalAddress, local_address); - std::cout << std::endl; - } - - // docker configuration - if ( - ( - (_config->LocalAddress.empty() && config_address.empty()) || - (config_address != public_address) - ) - && is_in_docker - ) { - LogWarning("# Docker Configuration (Configuration)"); - LogWarning(""); - LogWarning("You appear to running EQEmu in a docker container"); - LogWarning("In order for networking to work properly you will need to properly configure your server"); - LogWarning(""); - LogWarning( - "If your Docker host is on a [LAN] or behind a NAT / Firewall, your [localaddress] variable under [server.world] will need to"); - LogWarning( - "be set to your LAN address on the host, not the container address. [address] will need to be your public address"); - LogWarning(""); - LogWarning( - "If your Docker host is directly on the [public internet], your [localaddress] variable under [server.world] can be set to [127.0.0.1]." - ); - LogWarning(""); - LogWarning("[address] will need to be your public address"); - LogWarning(""); - LogWarning("Docs [https://docs.eqemu.io/server/installation/configure-your-eqemu_config/#world]"); - LogWarning(""); - LogWarning("Config file [{}] path [server.world] variable(s) [localaddress] [address]", config_file); - LogWarning(""); - LogWarning("Local address (eqemu_config) value [{}] detected value [{}]", _config->LocalAddress, local_address); - LogWarning( - "Public address (eqemu_config) value [{}] detected value [{}]", - config_address, - public_address - ); - std::cout << std::endl; - } - - // docker LAN not set - if (_config->LocalAddress.empty() && is_in_docker) { - LogWarning("# Docker LAN (Configuration)"); - LogWarning(""); - LogWarning("You appear to running EQEmu in a docker container"); - LogWarning( - "Your local address does not appear to be set, this may not be an issue if your deployment is not on a LAN" - ); - LogWarning(""); - LogWarning( - "If your Docker host is on a [LAN] or behind a NAT / Firewall, your [localaddress] variable under [server.world] will need to"); - LogWarning( - "be set to your LAN address on the host, not the container address. [address] will need to be your public address"); - LogWarning(""); - LogWarning( - "If your Docker host is directly on the [public internet], your [localaddress] variable under [server.world] can be set to [127.0.0.1]." - ); - LogWarning(""); - LogWarning("[address] will need to be your public address"); - LogWarning(""); - LogWarning("Docs [https://docs.eqemu.io/server/installation/configure-your-eqemu_config/#world]"); - LogWarning(""); - LogWarning("Config file [{}] path [server.world] variable(s) [localaddress] [address]", config_file); - LogWarning(""); - LogWarning("Local address (eqemu_config) value [{}] detected value [{}]", _config->LocalAddress, local_address); - LogWarning( - "Public address (eqemu_config) value [{}] detected value [{}]", - config_address, - public_address - ); - std::cout << std::endl; - } - - // public address different from configuration - if (!config_address.empty() && public_address != config_address) { - LogWarning("# Public address (Configuration)"); - LogWarning(""); - LogWarning("Your configured public address appears to be different from what's detected!"); - LogWarning(""); - LogWarning("Docs [https://docs.eqemu.io/server/installation/configure-your-eqemu_config/#world]"); - LogWarning(""); - LogWarning("Config file [{}] path [server.world] variable [address]", config_file); - LogWarning(""); - LogWarning( - "Public address (eqemu_config) value [{}] detected value [{}]", - config_address, - public_address - ); - std::cout << std::endl; - } - - // public address set to meta-address - if (config_address == "0.0.0.0") { - LogWarning("# Public meta-address (Configuration)"); - LogWarning(""); - LogWarning("Your configured public address is set to a meta-address (0.0.0.0) (all-interfaces)"); - LogWarning( - "The meta-address may not work properly and it is recommended you configure your public address explicitly"); - LogWarning(""); - LogWarning("Docs [https://docs.eqemu.io/server/installation/configure-your-eqemu_config/#world]"); - LogWarning(""); - LogWarning("Config file [{}] path [server.world] variable [address]", config_file); - LogWarning(""); - LogWarning( - "Public address (eqemu_config) value [{}] detected value [{}]", - config_address, - public_address - ); - std::cout << std::endl; - } - - // local address set to meta-address - if (_config->LocalAddress == "0.0.0.0") { - LogWarning("# Local meta-address (Configuration)"); - LogWarning(""); - LogWarning("Your configured local address is set to a meta-address (0.0.0.0) (all-interfaces)"); - LogWarning( - "The meta-address may not work properly and it is recommended you configure your local address explicitly" - ); - LogWarning(""); - LogWarning("Docs [https://docs.eqemu.io/server/installation/configure-your-eqemu_config/#world]"); - LogWarning(""); - LogWarning("Config file [{}] path [server.world] variable [localaddress]", config_file); - LogWarning(""); - LogWarning("Local address (eqemu_config) value [{}] detected value [{}]", _config->LocalAddress, local_address); - std::cout << std::endl; - } - - // ucs (public) - if ( - (!config_address.empty() && _config->MailHost != config_address) || - (!config_address.empty() && _config->ChatHost != config_address) - ) { - LogWarning("# UCS Address Mailhost (Configuration)"); - LogWarning(""); - LogWarning( - "UCS (Universal Chat Service) mail or chat appears to use a different address from your main world address" - ); - LogWarning("This can result in a chat service that doesn't network properly"); - LogWarning(""); - LogWarning("Docs [https://docs.eqemu.io/server/installation/configure-your-eqemu_config/#mailserver]"); - LogWarning(""); - LogWarning( - "[server.world.address] value [{}] [server.chatserver.host] [{}]", - config_address, - _config->ChatHost - ); - LogWarning( - "[server.world.address] value [{}] [server.mailserver.host] [{}]", - config_address, - _config->MailHost - ); - std::cout << std::endl; - } -} - - - - - - - - - - - - - - - - - - - - - - - diff --git a/world/world_config.h b/world/world_config.h index 5af2ee976..2a274ed29 100644 --- a/world/world_config.h +++ b/world/world_config.h @@ -68,8 +68,6 @@ public: static void SetWorldAddress(std::string addr) { if (_world_config) _world_config->WorldAddress=addr; } static void SetLocalAddress(std::string addr) { if (_world_config) _world_config->LocalAddress=addr; } - static void CheckForPossibleConfigurationIssues(); - void Dump() const; };