From 1bd281c8f2ad230b26a4184d47279ca545914e8f Mon Sep 17 00:00:00 2001 From: Chris Miles Date: Tue, 18 Feb 2025 00:54:37 -0600 Subject: [PATCH] [Performance] Server Reload Overhaul (#4689) * [Performance] Server Reload Overhaul * Client::SendReloadCommandMessages * Remove global buffs --- common/CMakeLists.txt | 1 + common/server_reload_types.h | 143 +++++++ common/servertalk.h | 32 +- common/strings.cpp | 24 ++ common/strings.h | 2 + queryserv/worldserver.cpp | 11 +- ucs/worldserver.cpp | 11 +- world/console.cpp | 6 +- world/eqemu_api_world_data_service.cpp | 116 +----- world/world_boot.h | 1 + world/world_event_scheduler.cpp | 7 +- world/zonelist.cpp | 82 ++++ world/zonelist.h | 2 + world/zoneserver.cpp | 64 +-- zone/client.cpp | 460 +--------------------- zone/gm_commands/logs.cpp | 4 +- zone/gm_commands/reload.cpp | 292 ++------------ zone/gm_commands/set/checksum.cpp | 8 +- zone/titles.cpp | 8 +- zone/trap.cpp | 4 - zone/worldserver.cpp | 515 ++++++++++++------------- zone/worldserver.h | 12 +- zone/zone.cpp | 55 +-- zone/zone.h | 5 +- 24 files changed, 607 insertions(+), 1258 deletions(-) create mode 100644 common/server_reload_types.h diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 9b16c604c..8111c6fa3 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -645,6 +645,7 @@ SET(common_headers server_event_scheduler.h serverinfo.h servertalk.h + server_reload_types.h shared_tasks.h shareddb.h skills.h diff --git a/common/server_reload_types.h b/common/server_reload_types.h new file mode 100644 index 000000000..a31f59f1d --- /dev/null +++ b/common/server_reload_types.h @@ -0,0 +1,143 @@ +#ifndef EQEMU_SERVER_RELOAD_TYPES_H +#define EQEMU_SERVER_RELOAD_TYPES_H + +#include +#include +#include + +namespace ServerReload { + enum Type { + ReloadTypeNone = 0, + AAData, + AlternateCurrencies, + BaseData, + BlockedSpells, + Commands, + ContentFlags, + DataBucketsCache, + Doors, + DzTemplates, + Factions, + GroundSpawns, + LevelEXPMods, + Logs, + Loot, + Merchants, + NPCEmotes, + NPCSpells, + Objects, + Opcodes, + PerlExportSettings, + Quests, + QuestsTimerReset, + Rules, + SkillCaps, + StaticZoneData, + Tasks, + Titles, + Traps, + Variables, + VeteranRewards, + WorldRepop, + WorldWithRespawn, + ZoneData, + ZonePoints, + Max + }; + + static const char *Name[ServerReload::Max] = { + "None", + "AA Data", + "Alternate Currencies", + "Base Data", + "Blocked Spells", + "Commands", + "Content Flags", + "Data Buckets Cache", + "Doors", + "DZ Templates", + "Factions", + "Ground Spawns", + "Level EXP Mods", + "Logs", + "Loot", + "Merchants", + "NPC Emotes", + "NPC Spells", + "Objects", + "Opcodes", + "Perl Event Export Settings", + "Quests", + "Quests With Timer (Resets timer events)", + "Rules", + "Skill Caps", + "Static Zone Data", + "Tasks", + "Titles", + "Traps", + "Variables", + "Veteran Rewards", + "World Repop", + "World Repop Timers (Clear Respawn Timers)", + "Zone Data", + "Zone Points" + }; + + inline std::string GetName(int reload_type) + { + if (reload_type < 0 || reload_type >= ServerReload::Type::Max) { + return "Unknown"; + } + + return ServerReload::Name[reload_type]; + } + + // Get a clean name without spaces or special characters + inline std::string GetNameClean(int reload_type) + { + if (reload_type < 0 || reload_type >= ServerReload::Type::Max) { + return "Unknown"; + } + + // get the name before parentheses + std::string name = ServerReload::Name[reload_type]; + size_t pos = name.find('('); + if (pos != std::string::npos) { + name = name.substr(0, pos); + } + + // Trim leading spaces + size_t start = name.find_first_not_of(' '); + if (start == std::string::npos) { + return ""; // If all spaces, return empty string + } + + // Trim trailing spaces + size_t end = name.find_last_not_of(' '); + + // Extract trimmed substring + return name.substr(start, end - start + 1); + + return name; + } + + inline std::vector GetTypes() + { + std::vector types; + types.reserve(ServerReload::Type::Max); + for (int i = 1; i < ServerReload::Type::Max; i++) { + types.push_back(static_cast(i)); + } + return types; + } + + struct Request { + int type = 0; + bool requires_zone_booted = false; + int64 reload_at_unix = 0; + int32 opt_param = 0; + uint32_t zone_server_id = 0; + }; +} + +#endif //EQEMU_SERVER_RELOAD_TYPES_H diff --git a/common/servertalk.h b/common/servertalk.h index d20309c21..d830fda33 100644 --- a/common/servertalk.h +++ b/common/servertalk.h @@ -248,37 +248,7 @@ #define ServerOP_UpdateSchedulerEvents 0x4007 #define ServerOP_DiscordWebhookMessage 0x4008 -#define ServerOP_ReloadAAData 0x4100 -#define ServerOP_ReloadAlternateCurrencies 0x4101 -#define ServerOP_ReloadBlockedSpells 0x4102 -#define ServerOP_ReloadCommands 0x4103 -#define ServerOP_ReloadContentFlags 0x4104 -#define ServerOP_ReloadDoors 0x4105 -#define ServerOP_ReloadGroundSpawns 0x4106 -#define ServerOP_ReloadLevelEXPMods 0x4107 -#define ServerOP_ReloadLogs 0x4108 -#define ServerOP_ReloadMerchants 0x4109 -#define ServerOP_ReloadNPCEmotes 0x4110 -#define ServerOP_ReloadObjects 0x4111 -#define ServerOP_ReloadOpcodes 0x4112 -#define ServerOP_ReloadPerlExportSettings 0x4113 -#define ServerOP_ReloadRules 0x4114 -#define ServerOP_ReloadStaticZoneData 0x4115 -#define ServerOP_ReloadTasks 0x4116 -#define ServerOP_ReloadTitles 0x4117 -#define ServerOP_ReloadTraps 0x4118 -#define ServerOP_ReloadVariables 0x4119 -#define ServerOP_ReloadVeteranRewards 0x4120 -#define ServerOP_ReloadWorld 0x4121 -#define ServerOP_ReloadZonePoints 0x4122 -#define ServerOP_ReloadDzTemplates 0x4123 -#define ServerOP_ReloadZoneData 0x4124 -#define ServerOP_ReloadDataBucketsCache 0x4125 -#define ServerOP_ReloadFactions 0x4126 -#define ServerOP_ReloadLoot 0x4127 -#define ServerOP_ReloadBaseData 0x4128 -#define ServerOP_ReloadSkillCaps 0x4129 -#define ServerOP_ReloadNPCSpells 0x4130 +#define ServerOP_ServerReloadRequest 0x4100 #define ServerOP_CZDialogueWindow 0x4500 #define ServerOP_CZLDoNUpdate 0x4501 diff --git a/common/strings.cpp b/common/strings.cpp index 1f35e30eb..04d973af1 100644 --- a/common/strings.cpp +++ b/common/strings.cpp @@ -912,3 +912,27 @@ std::string Strings::ZoneTime(const uint8 hours, const uint8 minutes) hours >= 13 ? "PM" : "AM" ); } + +std::string Strings::Slugify(const std::string& input, const std::string& separator) { + std::string slug; + bool last_was_hyphen = false; + + for (char c : input) { + if (std::isalnum(c)) { + slug += std::tolower(c); + last_was_hyphen = false; + } else if (c == ' ' || c == '_' || c == '-') { + if (!last_was_hyphen && !slug.empty()) { + slug += separator; + last_was_hyphen = true; + } + } + } + + // Remove trailing hyphen if present + if (!slug.empty() && slug.back() == '-') { + slug.pop_back(); + } + + return slug; +} diff --git a/common/strings.h b/common/strings.h index 7c6f6462a..6024aad35 100644 --- a/common/strings.h +++ b/common/strings.h @@ -186,6 +186,8 @@ public: value = strtod(tmp_str.data(), nullptr); return res; } + + static std::string Slugify(const std::string &input, const std::string &separator = "-"); }; const std::string StringFormat(const char *format, ...); diff --git a/queryserv/worldserver.cpp b/queryserv/worldserver.cpp index 0ff8698d5..948ab931e 100644 --- a/queryserv/worldserver.cpp +++ b/queryserv/worldserver.cpp @@ -12,6 +12,7 @@ #include "worldserver.h" #include "../common/events/player_events.h" #include "../common/events/player_event_logs.h" +#include "../common/server_reload_types.h" #include #include #include @@ -72,9 +73,13 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) case 0: { break; } - case ServerOP_ReloadLogs: { - LogSys.LoadLogDatabaseSettings(); - player_event_logs.ReloadSettings(); + case ServerOP_ServerReloadRequest: { + auto o = (ServerReload::Request*) p.Data(); + if (o->type == ServerReload::Type::Logs) { + LogSys.LoadLogDatabaseSettings(); + player_event_logs.ReloadSettings(); + } + break; } case ServerOP_QueryServGeneric: { diff --git a/ucs/worldserver.cpp b/ucs/worldserver.cpp index 91439dbf5..253f61fc3 100644 --- a/ucs/worldserver.cpp +++ b/ucs/worldserver.cpp @@ -28,6 +28,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "database.h" #include "../common/discord/discord_manager.h" #include "../common/events/player_event_logs.h" +#include "../common/server_reload_types.h" #include #include @@ -75,9 +76,13 @@ void WorldServer::ProcessMessage(uint16 opcode, EQ::Net::Packet &p) { break; } - case ServerOP_ReloadLogs: { - LogSys.LoadLogDatabaseSettings(); - player_event_logs.ReloadSettings(); + case ServerOP_ServerReloadRequest: { + auto o = (ServerReload::Request*) pack->pBuffer; + if (o->type == ServerReload::Type::Logs) { + LogSys.LoadLogDatabaseSettings(); + player_event_logs.ReloadSettings(); + } + break; } case ServerOP_PlayerEvent: { diff --git a/world/console.cpp b/world/console.cpp index 25a7cd793..b24ae4797 100644 --- a/world/console.cpp +++ b/world/console.cpp @@ -911,11 +911,7 @@ void ConsoleReloadWorld( ) { connection->SendLine("Reloading World..."); - auto pack = new ServerPacket(ServerOP_ReloadWorld, sizeof(ReloadWorld_Struct)); - ReloadWorld_Struct *RW = (ReloadWorld_Struct *) pack->pBuffer; - RW->global_repop = ReloadWorld::Repop; - zoneserver_list.SendPacket(pack); - safe_delete(pack); + zoneserver_list.SendServerReload(ServerReload::Type::WorldRepop, nullptr); } auto debounce_reload = std::chrono::system_clock::now(); diff --git a/world/eqemu_api_world_data_service.cpp b/world/eqemu_api_world_data_service.cpp index 12f7193d5..f760b9ec1 100644 --- a/world/eqemu_api_world_data_service.cpp +++ b/world/eqemu_api_world_data_service.cpp @@ -5,6 +5,7 @@ #include "zoneserver.h" #include "zonelist.h" #include "../common/database_schema.h" +#include "../common/server_reload_types.h" #include "../common/zone_store.h" #include "worlddb.h" #include "wguild_mgr.h" @@ -113,136 +114,47 @@ void callGetClientList(Json::Value &response) client_list.GetClientList(response); } - -struct Reload { - std::string command{}; - uint16 opcode; - std::string desc{}; -}; - -std::vector reload_types = { - Reload{.command = "aa", .opcode = ServerOP_ReloadAAData, .desc = "Alternate Advancement"}, - Reload{.command = "alternate_currencies", .opcode = ServerOP_ReloadAlternateCurrencies, .desc = "Alternate Currencies"}, - Reload{.command = "base_data", .opcode = ServerOP_ReloadBaseData, .desc = "Base Data"}, - Reload{.command = "blocked_spells", .opcode = ServerOP_ReloadBlockedSpells, .desc = "Blocked Spells"}, - Reload{.command = "commands", .opcode = ServerOP_ReloadCommands, .desc = "Commands"}, - Reload{.command = "content_flags", .opcode = ServerOP_ReloadContentFlags, .desc = "Content Flags"}, - Reload{.command = "data_buckets_cache", .opcode = ServerOP_ReloadDataBucketsCache, .desc = "Data Buckets Cache"}, - Reload{.command = "doors", .opcode = ServerOP_ReloadDoors, .desc = "Doors"}, - Reload{.command = "dztemplates", .opcode = ServerOP_ReloadDzTemplates, .desc = "Dynamic Zone Templates"}, - Reload{.command = "ground_spawns", .opcode = ServerOP_ReloadGroundSpawns, .desc = "Ground Spawns"}, - Reload{.command = "level_mods", .opcode = ServerOP_ReloadLevelEXPMods, .desc = "Level Mods"}, - Reload{.command = "logs", .opcode = ServerOP_ReloadLogs, .desc = "Log Settings"}, - Reload{.command = "loot", .opcode = ServerOP_ReloadLoot, .desc = "Loot"}, - Reload{.command = "merchants", .opcode = ServerOP_ReloadMerchants, .desc = "Merchants"}, - Reload{.command = "npc_emotes", .opcode = ServerOP_ReloadNPCEmotes, .desc = "NPC Emotes"}, - Reload{.command = "npc_spells", .opcode = ServerOP_ReloadNPCSpells, .desc = "NPC Spells"}, - Reload{.command = "objects", .opcode = ServerOP_ReloadObjects, .desc = "Objects"}, - Reload{.command = "opcodes", .opcode = ServerOP_ReloadOpcodes, .desc = "Opcodes"}, - Reload{.command = "perl_export", .opcode = ServerOP_ReloadPerlExportSettings, .desc = "Perl Event Export Settings"}, - Reload{.command = "rules", .opcode = ServerOP_ReloadRules, .desc = "Rules"}, - Reload{.command = "skill_caps", .opcode = ServerOP_ReloadSkillCaps, .desc = "Skill Caps"}, - Reload{.command = "static", .opcode = ServerOP_ReloadStaticZoneData, .desc = "Static Zone Data"}, - Reload{.command = "tasks", .opcode = ServerOP_ReloadTasks, .desc = "Tasks"}, - Reload{.command = "titles", .opcode = ServerOP_ReloadTitles, .desc = "Titles"}, - Reload{.command = "traps", .opcode = ServerOP_ReloadTraps, .desc = "Traps"}, - Reload{.command = "variables", .opcode = ServerOP_ReloadVariables, .desc = "Variables"}, - Reload{.command = "veteran_rewards", .opcode = ServerOP_ReloadVeteranRewards, .desc = "Veteran Rewards"}, - Reload{.command = "world", .opcode = ServerOP_ReloadWorld, .desc = "World"}, - Reload{.command = "zone_points", .opcode = ServerOP_ReloadZonePoints, .desc = "Zone Points"}, -}; - void getReloadTypes(Json::Value &response) { - for (auto &c: reload_types) { + for (auto &t: ServerReload::GetTypes()) { Json::Value v; - v["command"] = c.command; - v["opcode"] = c.opcode; - v["description"] = c.desc; + v["command"] = std::to_string(t); + v["description"] = ServerReload::GetName(t); response.append(v); } } - void EQEmuApiWorldDataService::reload(Json::Value &r, const std::vector &args) { std::vector commands{}; - commands.reserve(reload_types.size()); - for (auto &c: reload_types) { - commands.emplace_back(c.command); + commands.reserve(ServerReload::GetTypes().size()); + for (auto &c: ServerReload::GetTypes()) { + commands.emplace_back(std::to_string(c)); } std::string command = !args[1].empty() ? args[1] : ""; if (command.empty()) { - message(r, fmt::format("Need to provide a type to reload. Example(s) [{}]", Strings::Implode("|", commands))); + message(r, fmt::format("Need to provide a type ID to reload. Example(s) [{}]", Strings::Implode("|", commands))); return; } ServerPacket *pack = nullptr; - bool found_command = false; - for (auto &c: reload_types) { - if (command == c.command) { - if (c.command == "world") { - uint8 global_repop = ReloadWorld::NoRepop; + bool found_command = false; - if (Strings::IsNumber(args[2])) { - global_repop = static_cast(Strings::ToUnsignedInt(args[2])); - - if (global_repop > ReloadWorld::ForceRepop) { - global_repop = ReloadWorld::ForceRepop; - } - } - - message( - r, - fmt::format( - "Attempting to reload Quests {}worldwide.", - ( - global_repop ? - ( - global_repop == ReloadWorld::Repop ? - "and repop NPCs " : - "and forcefully repop NPCs " - ) : - "" - ) - ) - ); - - pack = new ServerPacket(ServerOP_ReloadWorld, sizeof(ReloadWorld_Struct)); - auto RW = (ReloadWorld_Struct *) pack->pBuffer; - RW->global_repop = global_repop; - } - else { - pack = new ServerPacket(c.opcode, 0); - message(r, fmt::format("Reloading [{}] globally", c.desc)); - - if (c.opcode == ServerOP_ReloadLogs) { - LogSys.LoadLogDatabaseSettings(); - QSLink.SendPacket(pack); - UCSLink.SendPacket(pack); - } - else if (c.opcode == ServerOP_ReloadRules) { - RuleManager::Instance()->LoadRules(&database, RuleManager::Instance()->GetActiveRuleset(), true); - } - } - - found_command = true; + for (auto &t: ServerReload::GetTypes()) { + if (std::to_string(t) == command || Strings::ToLower(ServerReload::GetName(t)) == command) { + message(r, fmt::format("Reloading [{}] globally", ServerReload::GetName(t))); + zoneserver_list.SendServerReload(t, nullptr); } + found_command = true; } if (!found_command) { message(r, fmt::format("Need to provide a type to reload. Example(s) [{}]", Strings::Implode("|", commands))); return; } - - if (pack) { - zoneserver_list.SendPacket(pack); - } - - safe_delete(pack); } void EQEmuApiWorldDataService::message(Json::Value &r, const std::string &message) diff --git a/world/world_boot.h b/world/world_boot.h index 5ac9552d6..2149a6ea5 100644 --- a/world/world_boot.h +++ b/world/world_boot.h @@ -4,6 +4,7 @@ #include #include "../common/types.h" #include "../common/discord/discord.h" +#include "ucs.h" extern UCSConnection UCSLink; diff --git a/world/world_event_scheduler.cpp b/world/world_event_scheduler.cpp index 86342b882..c1ab226ab 100644 --- a/world/world_event_scheduler.cpp +++ b/world/world_event_scheduler.cpp @@ -2,6 +2,7 @@ #include "../common/servertalk.h" #include #include "../common/rulesys.h" +#include "../common/server_reload_types.h" void WorldEventScheduler::Process(ZSList *zs_list) { @@ -55,11 +56,7 @@ void WorldEventScheduler::Process(ZSList *zs_list) if (e.event_type == ServerEvents::EVENT_TYPE_RELOAD_WORLD) { LogScheduler("Sending reload world event [{}]", e.event_data.c_str()); - auto pack = new ServerPacket(ServerOP_ReloadWorld, sizeof(ReloadWorld_Struct)); - auto *reload_world = (ReloadWorld_Struct *) pack->pBuffer; - reload_world->global_repop = ReloadWorld::Repop; - zs_list->SendPacket(pack); - safe_delete(pack); + zs_list->SendServerReload(ServerReload::Type::WorldRepop, nullptr); } } } diff --git a/world/zonelist.cpp b/world/zonelist.cpp index c2e572a68..f8d54113c 100644 --- a/world/zonelist.cpp +++ b/world/zonelist.cpp @@ -28,10 +28,19 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "../common/event_sub.h" #include "web_interface.h" #include "../common/zone_store.h" +#include "../common/events/player_event_logs.h" +#include "../common/patches/patches.h" +#include "../common/skill_caps.h" +#include "../common/content/world_content_service.h" +#include "world_boot.h" +#include "shared_task_manager.h" +#include "dynamic_zone_manager.h" +#include "ucs.h" extern uint32 numzones; extern EQ::Random emu_random; extern WebInterfaceList web_interface; +extern SharedTaskManager shared_task_manager; volatile bool UCSServerAvailable_ = false; void CatchSignal(int sig_num); @@ -861,3 +870,76 @@ bool ZSList::SendPacketToBootedZones(ServerPacket* pack) return true; } + +void ZSList::SendServerReload(ServerReload::Type type, uchar *packet) +{ + static auto pack = ServerPacket(ServerOP_ServerReloadRequest, sizeof(ServerReload::Request)); + auto r = (ServerReload::Request *) pack.pBuffer; + + // Copy the packet data if it exists + if (packet) { + memcpy(pack.pBuffer, packet, sizeof(ServerReload::Request)); + } + + r->type = type; + r->requires_zone_booted = true; + + LogInfo("Sending reload to all zones for type [{}]", ServerReload::GetName(type)); + + static const std::unordered_set no_zone_boot_required = { + ServerReload::Type::Opcodes, + ServerReload::Type::Rules, + ServerReload::Type::ContentFlags, + ServerReload::Type::Logs, + ServerReload::Type::Commands, + ServerReload::Type::PerlExportSettings, + ServerReload::Type::DataBucketsCache, + ServerReload::Type::WorldRepop + }; + + // Set requires_zone_booted flag before executing reload logic + if (no_zone_boot_required.contains(type)) { + r->requires_zone_booted = false; + } + + // reload at the world level + if (type == ServerReload::Type::Opcodes) { + ReloadAllPatches(); + } else if (type == ServerReload::Type::Rules) { + RuleManager::Instance()->LoadRules(&database, RuleManager::Instance()->GetActiveRuleset(), true); + } else if (type == ServerReload::Type::SkillCaps) { + skill_caps.ReloadSkillCaps(); + } else if (type == ServerReload::Type::ContentFlags) { + content_service.SetExpansionContext()->ReloadContentFlags(); + } else if (type == ServerReload::Type::Logs) { + LogSys.LoadLogDatabaseSettings(); + player_event_logs.ReloadSettings(); + UCSLink.SendPacket(&pack); + } else if (type == ServerReload::Type::Tasks) { + shared_task_manager.LoadTaskData(); + } else if (type == ServerReload::Type::DzTemplates) { + dynamic_zone_manager.LoadTemplates(); + } + + // Send the packet to all zones with staggered delays + // to prevent all zones from reloading at the same time + // and causing a massive spike in CPU usage + // This is especially important for large servers + // with many zones + // we reload 10 zones every second + int counter = 0; + + for (auto &z: zone_server_list) { + bool is_local = r->zone_server_id != 0; + + // if the zone reload is local to a specific zone + if (r->zone_server_id != 0 && r->zone_server_id != z->GetID()) { + continue; + } + + // if the reload is local, we don't need to stagger the reloads + r->reload_at_unix = is_local ? 0 : (std::time(nullptr) + 1) + (counter / 10); + z->SendPacket(&pack); + ++counter; + } +} diff --git a/world/zonelist.h b/world/zonelist.h index e096f0363..aa59b1fd6 100644 --- a/world/zonelist.h +++ b/world/zonelist.h @@ -5,6 +5,7 @@ #include "../common/eqtime.h" #include "../common/timer.h" #include "../common/event/timer.h" +#include "../common/server_reload_types.h" #include #include #include @@ -69,6 +70,7 @@ public: ZoneServer* FindByZoneID(uint32 ZoneID); const std::list> &getZoneServerList() const; + void SendServerReload(ServerReload::Type type, uchar *packet = nullptr); private: void OnTick(EQ::Timer *t); diff --git a/world/zoneserver.cpp b/world/zoneserver.cpp index b5497da9b..94c605436 100644 --- a/world/zoneserver.cpp +++ b/world/zoneserver.cpp @@ -49,6 +49,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "../zone/data_bucket.h" #include "../common/repositories/guild_tributes_repository.h" #include "../common/skill_caps.h" +#include "../common/server_reload_types.h" extern ClientList client_list; extern GroupLFPList LFPGroupList; @@ -1356,11 +1357,6 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) { QSLink.SendPacket(pack); break; } - case ServerOP_ReloadOpcodes: { - ReloadAllPatches(); - zoneserver_list.SendPacket(pack); - break; - } case ServerOP_CZDialogueWindow: case ServerOP_CZLDoNUpdate: case ServerOP_CZMarquee: @@ -1384,30 +1380,6 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) { case ServerOP_RaidGroupSay: case ServerOP_RaidSay: case ServerOP_RefreshCensorship: - case ServerOP_ReloadAAData: - case ServerOP_ReloadAlternateCurrencies: - case ServerOP_ReloadBaseData: - case ServerOP_ReloadBlockedSpells: - case ServerOP_ReloadCommands: - case ServerOP_ReloadDoors: - case ServerOP_ReloadDataBucketsCache: - case ServerOP_ReloadFactions: - case ServerOP_ReloadGroundSpawns: - case ServerOP_ReloadLevelEXPMods: - case ServerOP_ReloadMerchants: - case ServerOP_ReloadNPCEmotes: - case ServerOP_ReloadNPCSpells: - case ServerOP_ReloadObjects: - case ServerOP_ReloadPerlExportSettings: - case ServerOP_ReloadStaticZoneData: - case ServerOP_ReloadTitles: - case ServerOP_ReloadTraps: - case ServerOP_ReloadVariables: - case ServerOP_ReloadVeteranRewards: - case ServerOP_ReloadWorld: - case ServerOP_ReloadZonePoints: - case ServerOP_ReloadZoneData: - case ServerOP_ReloadLoot: case ServerOP_RezzPlayerAccept: case ServerOP_SpawnStatusChange: case ServerOP_TraderMessaging: @@ -1425,14 +1397,9 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) { zoneserver_list.SendPacket(pack); break; } - case ServerOP_ReloadSkillCaps: { - zoneserver_list.SendPacket(pack); - skill_caps.ReloadSkillCaps(); - break; - } - case ServerOP_ReloadRules: { - zoneserver_list.SendPacket(pack); - RuleManager::Instance()->LoadRules(&database, "default", true); + case ServerOP_ServerReloadRequest: { + auto o = (ServerReload::Request*) pack->pBuffer; + zoneserver_list.SendServerReload((ServerReload::Type) o->type, pack->pBuffer); break; } case ServerOP_IsOwnerOnline: { @@ -1460,29 +1427,6 @@ void ZoneServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) { } break; } - case ServerOP_ReloadContentFlags: { - zoneserver_list.SendPacket(pack); - content_service.SetExpansionContext()->ReloadContentFlags(); - break; - } - case ServerOP_ReloadLogs: { - zoneserver_list.SendPacket(pack); - QSLink.SendPacket(pack); - UCSLink.SendPacket(pack); - LogSys.LoadLogDatabaseSettings(); - player_event_logs.ReloadSettings(); - break; - } - case ServerOP_ReloadTasks: { - shared_task_manager.LoadTaskData(); - zoneserver_list.SendPacket(pack); - break; - } - case ServerOP_ReloadDzTemplates: { - dynamic_zone_manager.LoadTemplates(); - zoneserver_list.SendPacket(pack); - break; - } case ServerOP_ChangeSharedMem: { auto hotfix_name = std::string((char*) pack->pBuffer); diff --git a/zone/client.cpp b/zone/client.cpp index cfd6ddb1c..a315d122f 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -9728,14 +9728,6 @@ void Client::ShowDevToolsMenu() std::string menu_search; std::string menu_show; std::string menu_reload_one; - std::string menu_reload_two; - std::string menu_reload_three; - std::string menu_reload_four; - std::string menu_reload_five; - std::string menu_reload_six; - std::string menu_reload_seven; - std::string menu_reload_eight; - std::string menu_reload_nine; std::string menu_toggle; std::string window_toggle; @@ -9760,45 +9752,7 @@ void Client::ShowDevToolsMenu() /** * Reload */ - menu_reload_one += Saylink::Silent("#reload aa", "AAs"); - menu_reload_one += " | " + Saylink::Silent("#reload alternate_currencies", "Alternate Currencies"); - menu_reload_one += " | " + Saylink::Silent("#reload base_data", "Base Data"); - menu_reload_one += " | " + Saylink::Silent("#reload blocked_spells", "Blocked Spells"); - - menu_reload_two += Saylink::Silent("#reload commands", "Commands"); - menu_reload_two += " | " + Saylink::Silent("#reload content_flags", "Content Flags"); - - menu_reload_three += Saylink::Silent("#reload data_buckets_cache", "Databuckets"); - menu_reload_three += " | " + Saylink::Silent("#reload doors", "Doors"); - menu_reload_three += " | " + Saylink::Silent("#reload factions", "Factions"); - menu_reload_three += " | " + Saylink::Silent("#reload ground_spawns", "Ground Spawns"); - - menu_reload_four += Saylink::Silent("#reload logs", "Level Based Experience Modifiers"); - menu_reload_four += " | " + Saylink::Silent("#reload logs", "Log Settings"); - menu_reload_four += " | " + Saylink::Silent("#reload Loot", "Loot"); - - menu_reload_five += Saylink::Silent("#reload merchants", "Merchants"); - menu_reload_five += " | " + Saylink::Silent("#reload npc_emotes", "NPC Emotes"); - menu_reload_five += " | " + Saylink::Silent("#reload npc_spells", "NPC Spells"); - menu_reload_five += " | " + Saylink::Silent("#reload objects", "Objects"); - menu_reload_five += " | " + Saylink::Silent("#reload opcodes", "Opcodes"); - - menu_reload_six += Saylink::Silent("#reload perl_export", "Perl Event Export Settings"); - menu_reload_six += " | " + Saylink::Silent("#reload quest", "Quests"); - - menu_reload_seven += Saylink::Silent("#reload rules", "Rules"); - menu_reload_seven += " | " + Saylink::Silent("#reload skill_caps", "Skill Caps"); - menu_reload_seven += " | " + Saylink::Silent("#reload static", "Static Zone Data"); - menu_reload_seven += " | " + Saylink::Silent("#reload tasks", "Tasks"); - - menu_reload_eight += Saylink::Silent("#reload titles", "Titles"); - menu_reload_eight += " | " + Saylink::Silent("#reload traps 1", "Traps"); - menu_reload_eight += " | " + Saylink::Silent("#reload variables", "Variables"); - menu_reload_eight += " | " + Saylink::Silent("#reload veteran_rewards", "Veteran Rewards"); - - menu_reload_nine += Saylink::Silent("#reload world", "World"); - menu_reload_nine += " | " + Saylink::Silent("#reload zone", "Zone"); - menu_reload_nine += " | " + Saylink::Silent("#reload zone_points", "Zone Points"); + menu_reload_one += Saylink::Silent("#reload", "Reload Menu (#reload)"); /** * Show window status @@ -9868,70 +9822,6 @@ void Client::ShowDevToolsMenu() ).c_str() ); - Message( - Chat::White, - fmt::format( - "Reload | {}", - menu_reload_two - ).c_str() - ); - - Message( - Chat::White, - fmt::format( - "Reload | {}", - menu_reload_three - ).c_str() - ); - - Message( - Chat::White, - fmt::format( - "Reload | {}", - menu_reload_four - ).c_str() - ); - - Message( - Chat::White, - fmt::format( - "Reload | {}", - menu_reload_five - ).c_str() - ); - - Message( - Chat::White, - fmt::format( - "Reload | {}", - menu_reload_six - ).c_str() - ); - - Message( - Chat::White, - fmt::format( - "Reload | {}", - menu_reload_seven - ).c_str() - ); - - Message( - Chat::White, - fmt::format( - "Reload | {}", - menu_reload_eight - ).c_str() - ); - - Message( - Chat::White, - fmt::format( - "Reload | {}", - menu_reload_nine - ).c_str() - ); - auto help_link = Saylink::Silent("#help"); Message( @@ -11681,338 +11571,22 @@ void Client::ReconnectUCS() void Client::SendReloadCommandMessages() { SendChatLineBreak(); - auto aa_link = Saylink::Silent("#reload aa"); + for (auto &t: ServerReload::GetTypes()) { + std::string reload_slug = Strings::Slugify(ServerReload::GetNameClean(t), "_");; + auto reload_link = Saylink::Silent(fmt::format("#reload {}", reload_slug), "Local"); + auto reload_link_global = Saylink::Silent(fmt::format("#reload {} global", reload_slug), "Global"); - Message( - Chat::White, - fmt::format( - "Usage: {} - Reloads Alternate Advancement Data globally", - aa_link - ).c_str() - ); - - auto alternate_currencies_link = Saylink::Silent("#reload alternate_currencies"); - - Message( - Chat::White, - fmt::format( - "Usage: {} - Reloads Alternate Currencies globally", - alternate_currencies_link - ).c_str() - ); - - auto base_data_link = Saylink::Silent("#reload base_data"); - - Message( - Chat::White, - fmt::format( - "Usage: {} - Reloads Base Data globally", - base_data_link - ).c_str() - ); - - auto blocked_spells_link = Saylink::Silent("#reload blocked_spells"); - - Message( - Chat::White, - fmt::format( - "Usage: {} - Reloads Blocked Spells globally", - blocked_spells_link - ).c_str() - ); - - auto commands_link = Saylink::Silent("#reload commands"); - - Message( - Chat::White, - fmt::format( - "Usage: {} - Reloads Commands globally", - commands_link - ).c_str() - ); - - auto content_flags_link = Saylink::Silent("#reload content_flags"); - - Message( - Chat::White, - fmt::format( - "Usage: {} - Reloads Content Flags globally", - content_flags_link - ).c_str() - ); - - auto doors_link = Saylink::Silent("#reload doors"); - - Message( - Chat::White, - fmt::format( - "Usage: {} - Reloads Doors globally", - doors_link - ).c_str() - ); - - auto data_buckets_link = Saylink::Silent("#reload data_buckets_cache"); - - Message( - Chat::White, - fmt::format( - "Usage: {} - Reloads data buckets cache globally", - data_buckets_link - ).c_str() - ); - - auto dztemplates_link = Saylink::Silent("#reload dztemplates"); - - Message( - Chat::White, - fmt::format( - "Usage: {} - Reloads Dynamic Zone Templates globally", - dztemplates_link - ).c_str() - ); - - auto factions_link = Saylink::Silent("#reload factions"); - - Message( - Chat::White, - fmt::format( - "Usage: {} - Reloads Factions globally", - factions_link - ).c_str() - ); - - auto ground_spawns_link = Saylink::Silent("#reload ground_spawns"); - - Message( - Chat::White, - fmt::format( - "Usage: {} - Reloads Ground Spawns globally", - ground_spawns_link - ).c_str() - ); - - auto level_mods_link = Saylink::Silent("#reload level_mods"); - - Message( - Chat::White, - fmt::format( - "Usage: {} - Reloads Level Based Experience Modifiers globally", - level_mods_link - ).c_str() - ); - - auto logs_link = Saylink::Silent("#reload logs"); - - Message( - Chat::White, - fmt::format( - "Usage: {} - Reloads Log Settings globally", - logs_link - ).c_str() - ); - - auto loot_link = Saylink::Silent("#reload loot"); - - Message( - Chat::White, - fmt::format( - "Usage: {} - Reloads Loot globally", - loot_link - ).c_str() - ); - - auto merchants_link = Saylink::Silent("#reload merchants"); - - Message( - Chat::White, - fmt::format( - "Usage: {} - Reloads Merchants globally", - merchants_link - ).c_str() - ); - - auto npc_emotes_link = Saylink::Silent("#reload npc_emotes"); - - Message( - Chat::White, - fmt::format( - "Usage: {} - Reloads NPC Emotes globally", - npc_emotes_link - ).c_str() - ); - - auto npc_spells_link = Saylink::Silent("#reload npc_spells"); - Message( - Chat::White, - fmt::format( - "Usage: {} - Reloads NPC Spells globally", - npc_spells_link - ).c_str() - ); - - auto objects_link = Saylink::Silent("#reload objects"); - - Message( - Chat::White, - fmt::format( - "Usage: {} - Reloads Objects globally", - objects_link - ).c_str() - ); - - auto opcodes_link = Saylink::Silent("#reload opcodes"); - - Message( - Chat::White, - fmt::format( - "Usage: {} - Reloads Opcodes globally", - opcodes_link - ).c_str() - ); - - auto perl_export_link = Saylink::Silent("#reload perl_export"); - - Message( - Chat::White, - fmt::format( - "Usage: {} - Reloads Perl Event Export Settings globally", - perl_export_link - ).c_str() - ); - - auto quest_link_one = Saylink::Silent("#reload quest"); - auto quest_link_two = Saylink::Silent("#reload quest", "0"); - auto quest_link_three = Saylink::Silent("#reload quest 1", "1"); - - Message( - Chat::White, - fmt::format( - "Usage: {} [{}|{}] - Reloads Quests and Timers in your current zone if specified (0 = Do Not Reload Timers, 1 = Reload Timers)", - quest_link_one, - quest_link_two, - quest_link_three - ).c_str() - ); - - auto rules_link = Saylink::Silent("#reload rules"); - - Message( - Chat::White, - fmt::format( - "Usage: {} - Reloads Rules globally", - rules_link - ).c_str() - ); - - auto skill_caps_link = Saylink::Silent("#reload skill_caps"); - - Message( - Chat::White, - fmt::format( - "Usage: {} - Reloads Skill Caps globally", - skill_caps_link - ).c_str() - ); - - auto static_link = Saylink::Silent("#reload static"); - - Message( - Chat::White, - fmt::format( - "Usage: {} - Reloads Static Zone Data globally", - static_link - ).c_str() - ); - - auto tasks_link = Saylink::Silent("#reload tasks"); - - Message( - Chat::White, - fmt::format( - "Usage: {} [Task ID] - Reloads Tasks globally or by ID if specified", - tasks_link - ).c_str() - ); - - auto titles_link = Saylink::Silent("#reload titles"); - - Message( - Chat::White, - fmt::format( - "Usage: {} - Reloads Titles globally", - titles_link - ).c_str() - ); - - auto traps_link_one = Saylink::Silent("#reload traps"); - auto traps_link_two = Saylink::Silent("#reload traps", "0"); - auto traps_link_three = Saylink::Silent("#reload traps 1", "1"); - - Message( - Chat::White, - fmt::format( - "Usage: {} [{}|{}] - Reloads Traps in your current zone or globally if specified", - traps_link_one, - traps_link_two, - traps_link_three - ).c_str() - ); - - auto variables_link = Saylink::Silent("#reload variables"); - - Message( - Chat::White, - fmt::format( - "Usage: {} - Reloads Variables globally", - variables_link - ).c_str() - ); - - auto veteran_rewards_link = Saylink::Silent("#reload veteran_rewards"); - - Message( - Chat::White, - fmt::format( - "Usage: {} - Reloads Veteran Rewards globally", - veteran_rewards_link - ).c_str() - ); - - auto world_link_one = Saylink::Silent("#reload world"); - auto world_link_two = Saylink::Silent("#reload world", "0"); - auto world_link_three = Saylink::Silent("#reload world 1", "1"); - auto world_link_four = Saylink::Silent("#reload world 2", "2"); - - Message( - Chat::White, - fmt::format( - "Usage: {} [{}|{}|{}] - Reloads Quests and repops globally if specified (0 = No Repop, 1 = Repop, 2 = Force Repop)", - world_link_one, - world_link_two, - world_link_three, - world_link_four - ).c_str() - ); - - auto zone_link = Saylink::Silent("#reload zone"); - - Message( - Chat::White, - fmt::format( - "Usage: {} [Zone ID] [Version] - Reloads Zone configuration for your current zone, can load another Zone's configuration if specified", - zone_link - ).c_str() - ); - - auto zone_points_link = Saylink::Silent("#reload zone_points"); - - Message( - Chat::White, - fmt::format( - "Usage: {} - Reloads Zone Points globally", - zone_points_link - ).c_str() - ); + Message( + Chat::White, + fmt::format( + "Usage: [{}] [{}] #reload {} - Reloads {}", + reload_link, + reload_link_global, + reload_slug, + ServerReload::GetName(t) + ).c_str() + ); + } SendChatLineBreak(); } @@ -13479,4 +13053,4 @@ void Client::CheckItemDiscoverability(uint32 item_id) } DiscoverItem(item_id); -} \ No newline at end of file +} diff --git a/zone/gm_commands/logs.cpp b/zone/gm_commands/logs.cpp index 3cd590e6d..031d04dd1 100755 --- a/zone/gm_commands/logs.cpp +++ b/zone/gm_commands/logs.cpp @@ -182,9 +182,7 @@ void command_logs(Client *c, const Seperator *sep) } else if (is_reload) { c->Message(Chat::White, "Attempting to reload Log Settings globally."); - auto pack = new ServerPacket(ServerOP_ReloadLogs, 0); - worldserver.SendPacket(pack); - safe_delete(pack); + worldserver.SendReload(ServerReload::Type::Logs); } else if (is_set && sep->IsNumber(3)) { auto logs_set = false; diff --git a/zone/gm_commands/reload.cpp b/zone/gm_commands/reload.cpp index 361b02a95..b4a494660 100644 --- a/zone/gm_commands/reload.cpp +++ b/zone/gm_commands/reload.cpp @@ -1,6 +1,3 @@ -#include "../client.h" -#include "../../common/patches/patches.h" - void command_reload(Client *c, const Seperator *sep) { std::string command = sep->arg[0] ? sep->arg[0] : ""; @@ -10,261 +7,48 @@ void command_reload(Client *c, const Seperator *sep) return; } + std::string full_command = command; + for (int i = 1; i <= sep->argnum; ++i) { + full_command += " " + std::string(sep->arg[i]); + } + bool is_logs_reload_alias = sep->arg[0] && Strings::Contains(command, "#rl"); bool is_opcodes_reload_alias = sep->arg[0] && Strings::Contains(command, "#opcode"); bool is_rq_alias = sep->arg[0] && Strings::Contains(command, "#rq"); - bool is_aa = !strcasecmp(sep->arg[1], "aa"); - bool is_alternate_currencies = !strcasecmp(sep->arg[1], "alternate_currencies"); - bool is_base_data = !strcasecmp(sep->arg[1], "base_data"); - bool is_blocked_spells = !strcasecmp(sep->arg[1], "blocked_spells"); - bool is_commands = !strcasecmp(sep->arg[1], "commands"); - bool is_content_flags = !strcasecmp(sep->arg[1], "content_flags"); - bool is_data_buckets = !strcasecmp(sep->arg[1], "data_buckets_cache"); - bool is_doors = !strcasecmp(sep->arg[1], "doors"); - bool is_dztemplates = !strcasecmp(sep->arg[1], "dztemplates"); - bool is_factions = !strcasecmp(sep->arg[1], "factions"); - bool is_ground_spawns = !strcasecmp(sep->arg[1], "ground_spawns"); - bool is_level_mods = !strcasecmp(sep->arg[1], "level_mods"); - bool is_logs = !strcasecmp(sep->arg[1], "logs") || is_logs_reload_alias; - bool is_loot = !strcasecmp(sep->arg[1], "loot"); - bool is_merchants = !strcasecmp(sep->arg[1], "merchants"); - bool is_npc_emotes = !strcasecmp(sep->arg[1], "npc_emotes"); - bool is_npc_spells = !strcasecmp(sep->arg[1], "npc_spells"); - bool is_objects = !strcasecmp(sep->arg[1], "objects"); - bool is_opcodes = !strcasecmp(sep->arg[1], "opcodes") || is_opcodes_reload_alias; - bool is_perl_export = !strcasecmp(sep->arg[1], "perl_export"); - bool is_quest = !strcasecmp(sep->arg[1], "quest") || (is_rq_alias); - bool is_rules = !strcasecmp(sep->arg[1], "rules"); - bool is_skill_caps = !strcasecmp(sep->arg[1], "skill_caps"); - bool is_static = !strcasecmp(sep->arg[1], "static"); - bool is_tasks = !strcasecmp(sep->arg[1], "tasks"); - bool is_titles = !strcasecmp(sep->arg[1], "titles"); - bool is_traps = !strcasecmp(sep->arg[1], "traps"); - bool is_variables = !strcasecmp(sep->arg[1], "variables"); - bool is_veteran_rewards = !strcasecmp(sep->arg[1], "veteran_rewards"); - bool is_world = !strcasecmp(sep->arg[1], "world"); - bool is_zone = !strcasecmp(sep->arg[1], "zone"); - bool is_zone_points = !strcasecmp(sep->arg[1], "zone_points"); + if (is_logs_reload_alias) { + full_command = "#reload logs"; + } + else if (is_opcodes_reload_alias) { + full_command = "#reload opcodes"; + } + else if (is_rq_alias) { + full_command = "#reload quest"; + } - if ( - !is_aa && - !is_alternate_currencies && - !is_base_data && - !is_blocked_spells && - !is_commands && - !is_content_flags && - !is_data_buckets && - !is_doors && - !is_dztemplates && - !is_factions && - !is_ground_spawns && - !is_level_mods && - !is_logs && - !is_loot && - !is_merchants && - !is_npc_emotes && - !is_npc_spells && - !is_objects && - !is_opcodes && - !is_perl_export && - !is_quest && - !is_rules && - !is_skill_caps && - !is_static && - !is_tasks && - !is_titles && - !is_traps && - !is_variables && - !is_veteran_rewards && - !is_world && - !is_zone && - !is_zone_points - ) { + auto args = Strings::Split(full_command, ' '); + + bool found_command = false; + + for (auto &t: ServerReload::GetTypes()) { + std::string reload_slug = Strings::Slugify(ServerReload::GetNameClean(t), "_"); + std::string command_arg = args.size() > 1 ? args[1] : ""; + bool is_global = args.size() > 2 && args[2] == "global"; + if (sep->arg[0] && Strings::EqualFold(command_arg, reload_slug)) { + c->Message( + Chat::White, + fmt::format( + "Attempting to reload [{}] {} from command [{}]", + ServerReload::GetName(t), + is_global ? "globally" : "locally", + full_command + ).c_str() + ); + worldserver.SendReload(t, is_global); + found_command = true; + } + } + + if (!found_command) { c->SendReloadCommandMessages(); - return; } - - ServerPacket *pack = nullptr; - - if (is_aa) { - c->Message(Chat::White, "Attempting to reload Alternate Advancement Data globally."); - pack = new ServerPacket(ServerOP_ReloadAAData, 0); - } else if (is_alternate_currencies) { - c->Message(Chat::White, "Attempting to reload Alternate Currencies globally."); - pack = new ServerPacket(ServerOP_ReloadAlternateCurrencies, 0); - } else if (is_base_data) { - c->Message(Chat::White, "Attempting to reload Base Data globally."); - pack = new ServerPacket(ServerOP_ReloadBaseData, 0); - } else if (is_blocked_spells) { - c->Message(Chat::White, "Attempting to reload Blocked Spells globally."); - pack = new ServerPacket(ServerOP_ReloadBlockedSpells, 0); - } else if (is_commands) { - c->Message(Chat::White, "Attempting to reload Commands globally."); - pack = new ServerPacket(ServerOP_ReloadCommands, 0); - } else if (is_content_flags) { - c->Message(Chat::White, "Attempting to reload Content Flags globally."); - pack = new ServerPacket(ServerOP_ReloadContentFlags, 0); - } else if (is_doors) { - c->Message(Chat::White, "Attempting to reload Doors globally."); - pack = new ServerPacket(ServerOP_ReloadDoors, 0); - } else if (is_data_buckets) { - c->Message(Chat::White, "Attempting to flush data buckets cache globally."); - pack = new ServerPacket(ServerOP_ReloadDataBucketsCache, 0); - } else if (is_dztemplates) { - c->Message(Chat::White, "Attempting to reload Dynamic Zone Templates globally."); - pack = new ServerPacket(ServerOP_ReloadDzTemplates, 0); - } else if (is_factions) { - c->Message(Chat::White, "Attempting to reload Factions globally."); - pack = new ServerPacket(ServerOP_ReloadFactions, 0); - } else if (is_ground_spawns) { - c->Message(Chat::White, "Attempting to reload Ground Spawns globally."); - pack = new ServerPacket(ServerOP_ReloadGroundSpawns, 0); - } else if (is_level_mods) { - if (!RuleB(Zone, LevelBasedEXPMods)) { - c->Message(Chat::White, "Level Based Experience Modifiers are disabled."); - return; - } - - c->Message(Chat::White, "Attempting to reload Level Based Experience Modifiers globally."); - pack = new ServerPacket(ServerOP_ReloadLevelEXPMods, 0); - } else if (is_logs) { - c->Message(Chat::White, "Attempting to reload Log Settings globally."); - pack = new ServerPacket(ServerOP_ReloadLogs, 0); - } else if (is_loot) { - c->Message(Chat::White, "Attempting to reload Loot globally."); - pack = new ServerPacket(ServerOP_ReloadLoot, 0); - } else if (is_merchants) { - c->Message(Chat::White, "Attempting to reload Merchants globally."); - pack = new ServerPacket(ServerOP_ReloadMerchants, 0); - } else if (is_npc_emotes) { - c->Message(Chat::White, "Attempting to reload NPC Emotes globally."); - pack = new ServerPacket(ServerOP_ReloadNPCEmotes, 0); - } else if (is_npc_spells) { - c->Message(Chat::White, "Attempting to reload NPC Spells globally."); - pack = new ServerPacket(ServerOP_ReloadNPCSpells, 0); - } else if (is_objects) { - c->Message(Chat::White, "Attempting to reload Objects globally."); - pack = new ServerPacket(ServerOP_ReloadObjects, 0); - } else if (is_opcodes) { - c->Message(Chat::White, "Attempting to reload Opcodes globally."); - pack = new ServerPacket(ServerOP_ReloadOpcodes, 0); - } else if (is_perl_export) { - c->Message(Chat::White, "Attempting to reload Perl Event Export Settings globally."); - pack = new ServerPacket(ServerOP_ReloadPerlExportSettings, 0); - } else if (is_quest) { - const auto stop_timers = sep->IsNumber(2) ? Strings::ToBool(sep->arg[2]) : false; - - c->Message( - Chat::Yellow, - fmt::format( - "Quests reloaded{} for {}.", - stop_timers ? " and timers stopped" : "", - zone->GetZoneDescription() - ).c_str() - ); - - entity_list.ClearAreas(); - parse->ReloadQuests(stop_timers); - } else if (is_rules) { - c->Message(Chat::White, "Attempting to reload Rules globally."); - pack = new ServerPacket(ServerOP_ReloadRules, 0); - } else if (is_skill_caps) { - c->Message(Chat::White, "Attempting to reload Skill Caps globally."); - pack = new ServerPacket(ServerOP_ReloadSkillCaps, 0); - } else if (is_static) { - c->Message(Chat::White, "Attempting to reload Static Zone Data globally."); - pack = new ServerPacket(ServerOP_ReloadStaticZoneData, 0); - } else if (is_tasks) { - uint32 task_id = 0; - if (!sep->IsNumber(2)) { - c->Message(Chat::White, "Attempting to reload Tasks globally."); - pack = new ServerPacket(ServerOP_ReloadTasks, sizeof(ReloadTasks_Struct)); - } else { - task_id = Strings::ToUnsignedInt(sep->arg[2]); - } - - auto rts = (ReloadTasks_Struct *) pack->pBuffer; - rts->reload_type = RELOADTASKS; - rts->task_id = task_id; - } else if (is_titles) { - c->Message(Chat::White, "Attempting to reload Titles globally."); - pack = new ServerPacket(ServerOP_ReloadTitles, 0); - } else if (is_traps) { - if (arguments < 2 || !sep->IsNumber(2)) { - entity_list.UpdateAllTraps(true, true); - c->Message( - Chat::Yellow, - fmt::format( - "Traps reloaded for {}.", - zone->GetZoneDescription() - ).c_str() - ); - return; - } - - const auto global = Strings::ToBool(sep->arg[2]); - - if (!global) { - entity_list.UpdateAllTraps(true, true); - c->Message( - Chat::Yellow, - fmt::format( - "Traps reloaded for {}.", - zone->GetZoneDescription() - ).c_str() - ); - return; - } - - c->Message(Chat::White, "Attempting to reload Traps globally."); - pack = new ServerPacket(ServerOP_ReloadTraps, 0); - } else if (is_variables) { - c->Message(Chat::White, "Attempting to reload Variables globally."); - pack = new ServerPacket(ServerOP_ReloadVariables, 0); - } else if (is_veteran_rewards) { - c->Message(Chat::White, "Attempting to reload Veteran Rewards globally."); - pack = new ServerPacket(ServerOP_ReloadVeteranRewards, 0); - } else if (is_world) { - uint8 global_repop = ReloadWorld::NoRepop; - - if (sep->IsNumber(2)) { - global_repop = static_cast(Strings::ToUnsignedInt(sep->arg[2])); - - if (global_repop > ReloadWorld::ForceRepop) { - global_repop = ReloadWorld::ForceRepop; - } - } - - c->Message( - Chat::White, - fmt::format( - "Attempting to reload Quests {}worldwide.", - ( - global_repop ? - ( - global_repop == ReloadWorld::Repop ? - "and repop NPCs " : - "and forcefully repop NPCs " - ) : - "" - ) - ).c_str() - ); - - pack = new ServerPacket(ServerOP_ReloadWorld, sizeof(ReloadWorld_Struct)); - auto RW = (ReloadWorld_Struct *) pack->pBuffer; - RW->global_repop = global_repop; - } else if (is_zone) { - c->Message(Chat::White, "Attempting to reloading Zone data globally."); - pack = new ServerPacket(ServerOP_ReloadZoneData, sizeof(NewZone_Struct)); - } else if (is_zone_points) { - c->Message(Chat::White, "Attempting to reloading Zone Points globally."); - pack = new ServerPacket(ServerOP_ReloadZonePoints, 0); - } - - if (pack) { - worldserver.SendPacket(pack); - } - - safe_delete(pack); } diff --git a/zone/gm_commands/set/checksum.cpp b/zone/gm_commands/set/checksum.cpp index 76df72d29..02032fe01 100755 --- a/zone/gm_commands/set/checksum.cpp +++ b/zone/gm_commands/set/checksum.cpp @@ -17,12 +17,8 @@ void SetChecksum(Client *c, const Seperator *sep) database.SetVariable("crc_basedata", account.crc_basedata); c->Message(Chat::White, "Attempting to reload Rules globally."); - auto pack = new ServerPacket(ServerOP_ReloadRules, 0); - worldserver.SendPacket(pack); - safe_delete(pack); + worldserver.SendReload(ServerReload::Type::Rules); c->Message(Chat::White, "Attempting to reload Variables globally."); - pack = new ServerPacket(ServerOP_ReloadVariables, 0); - worldserver.SendPacket(pack); - safe_delete(pack); + worldserver.SendReload(ServerReload::Type::Variables); } diff --git a/zone/titles.cpp b/zone/titles.cpp index ae078600a..5eb61c8a0 100644 --- a/zone/titles.cpp +++ b/zone/titles.cpp @@ -243,9 +243,7 @@ void TitleManager::CreateNewPlayerTitle(Client* c, std::string title) return; } - auto pack = new ServerPacket(ServerOP_ReloadTitles, 0); - worldserver.SendPacket(pack); - safe_delete(pack); + worldserver.SendReload(ServerReload::Type::Titles); } void TitleManager::CreateNewPlayerSuffix(Client* c, std::string suffix) @@ -278,9 +276,7 @@ void TitleManager::CreateNewPlayerSuffix(Client* c, std::string suffix) return; } - auto pack = new ServerPacket(ServerOP_ReloadTitles, 0); - worldserver.SendPacket(pack); - safe_delete(pack); + worldserver.SendReload(ServerReload::Type::Titles); } void Client::SetAATitle(std::string title) diff --git a/zone/trap.cpp b/zone/trap.cpp index ba0dfb4ea..7377d5897 100644 --- a/zone/trap.cpp +++ b/zone/trap.cpp @@ -462,10 +462,6 @@ bool ZoneDatabase::LoadTraps(const std::string& zone_short_name, int16 instance_ ) ); - if (l.empty()) { - return false; - } - for (const auto& e : l) { if (e.group_) { if (entity_list.IsTrapGroupSpawned(e.id, e.group_)) { diff --git a/zone/worldserver.cpp b/zone/worldserver.cpp index 50d0e9e19..d181d8db4 100644 --- a/zone/worldserver.cpp +++ b/zone/worldserver.cpp @@ -60,6 +60,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA #include "../common/repositories/guild_tributes_repository.h" #include "../common/patches/patches.h" #include "../common/skill_caps.h" +#include "../common/server_reload_types.h" #include "queryserv.h" extern EntityList entity_list; @@ -80,11 +81,28 @@ WorldServer::WorldServer() cur_groupid = 0; last_groupid = 0; oocmuted = false; + m_process_timer = std::make_unique(1000, true, std::bind(&WorldServer::Process, this)); } WorldServer::~WorldServer() { } +void WorldServer::Process() +{ + if (!m_reload_queue.empty()) { + m_reload_mutex.lock(); + for (auto it = m_reload_queue.begin(); it != m_reload_queue.end(); ) { + if (it->second.reload_at_unix < std::time(nullptr)) { + ProcessReload(it->second); + it = m_reload_queue.erase(it); + } else { + ++it; + } + } + m_reload_mutex.unlock(); + } +} + void WorldServer::Connect() { m_connection = std::make_unique(Config->WorldIP, Config->WorldTCPPort, false, "Zone", Config->SharedKey); @@ -605,6 +623,10 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) } Zone::Bootup(s->zone_id, s->instance_id, s->is_static); + if (zone) { + zone->SetZoneServerId(s->zone_server_id); + } + break; } case ServerOP_ZoneIncClient: { @@ -1973,232 +1995,10 @@ void WorldServer::HandleMessage(uint16 opcode, const EQ::Net::Packet &p) } break; } - case ServerOP_ReloadAAData: + case ServerOP_ServerReloadRequest: { - if (zone && zone->IsLoaded()) { - zone->SendReloadMessage("Alternate Advancement Data"); - zone->LoadAlternateAdvancement(); - entity_list.SendAlternateAdvancementStats(); - } - break; - } - case ServerOP_ReloadOpcodes: - { - zone->SendReloadMessage("Opcodes"); - ReloadAllPatches(); - break; - } - case ServerOP_ReloadAlternateCurrencies: - { - if (zone && zone->IsLoaded()) { - zone->SendReloadMessage("Alternate Currencies"); - zone->LoadAlternateCurrencies(); - } - break; - } - case ServerOP_ReloadBaseData: - { - if (zone && zone->IsLoaded()) { - zone->SendReloadMessage("Base Data"); - zone->ReloadBaseData(); - } - - break; - } - case ServerOP_ReloadBlockedSpells: - { - if (zone && zone->IsLoaded()) { - zone->SendReloadMessage("Blocked Spells"); - zone->LoadZoneBlockedSpells(); - } - break; - } - case ServerOP_ReloadCommands: - { - zone->SendReloadMessage("Commands"); - command_init(); - if (RuleB(Bots, Enabled) && database.DoesTableExist("bot_command_settings")) { - bot_command_init(); - } - break; - } - case ServerOP_ReloadContentFlags: - { - zone->SendReloadMessage("Content Flags"); - content_service.SetExpansionContext()->ReloadContentFlags(); - break; - } - case ServerOP_ReloadDzTemplates: - { - if (zone) - { - zone->SendReloadMessage("Dynamic Zone Templates"); - zone->LoadDynamicZoneTemplates(); - } - break; - } - case ServerOP_ReloadFactions: - { - if (zone && zone->IsLoaded()) { - zone->SendReloadMessage("Factions"); - content_db.LoadFactionData(); - zone->ReloadNPCFactions(); - zone->ReloadFactionAssociations(); - } - - break; - } - case ServerOP_ReloadLevelEXPMods: - { - if (zone && zone->IsLoaded()) { - zone->SendReloadMessage("Level Based Experience Modifiers"); - zone->LoadLevelEXPMods(); - } - break; - } - case ServerOP_ReloadLogs: - { - zone->SendReloadMessage("Log Settings"); - LogSys.LoadLogDatabaseSettings(); - player_event_logs.ReloadSettings(); - break; - } - case ServerOP_ReloadLoot: - { - if (zone && zone->IsLoaded()) { - zone->SendReloadMessage("Loot"); - zone->ReloadLootTables(); - } - break; - } - case ServerOP_ReloadMerchants: { - if (zone && zone->IsLoaded()) { - zone->SendReloadMessage("Merchants"); - entity_list.ReloadMerchants(); - } - break; - } - case ServerOP_ReloadNPCEmotes: - { - if (zone && zone->IsLoaded()) { - zone->SendReloadMessage("NPC Emotes"); - zone->LoadNPCEmotes(&zone->npc_emote_list); - } - break; - } - case ServerOP_ReloadNPCSpells: - { - if (zone && zone->IsLoaded()) { - zone->SendReloadMessage("NPC Spells"); - content_db.ClearNPCSpells(); - for (auto& e : entity_list.GetNPCList()) { - e.second->ReloadSpells(); - } - } - break; - } - case ServerOP_ReloadPerlExportSettings: - { - zone->SendReloadMessage("Perl Event Export Settings"); - parse->LoadPerlEventExportSettings(parse->perl_event_export_settings); - break; - } - case ServerOP_ReloadRules: - { - zone->SendReloadMessage("Rules"); - RuleManager::Instance()->LoadRules(&database, RuleManager::Instance()->GetActiveRuleset(), true); - break; - } - case ServerOP_ReloadSkillCaps: - { - if (zone && zone->IsLoaded()) { - zone->SendReloadMessage("Skill Caps"); - skill_caps.ReloadSkillCaps(); - } - - break; - } - case ServerOP_ReloadDataBucketsCache: - { - zone->SendReloadMessage("Data buckets cache"); - DataBucket::ClearCache(); - break; - } - case ServerOP_ReloadDoors: - case ServerOP_ReloadGroundSpawns: - case ServerOP_ReloadObjects: - case ServerOP_ReloadStaticZoneData: { - if (zone && zone->IsLoaded()) { - zone->SendReloadMessage("Static Zone Data"); - zone->ReloadStaticData(); - } - break; - } - case ServerOP_ReloadTasks: - { - if (RuleB(Tasks, EnableTaskSystem) && zone && zone->IsLoaded()) { - zone->SendReloadMessage("Tasks"); - HandleReloadTasks(pack); - } - - break; - } - case ServerOP_ReloadTitles: - { - if (zone && zone->IsLoaded()) { - zone->SendReloadMessage("Titles"); - title_manager.LoadTitles(); - } - break; - } - case ServerOP_ReloadTraps: - { - if (zone && zone->IsLoaded()) { - zone->SendReloadMessage("Traps"); - entity_list.UpdateAllTraps(true, true); - } - - break; - } - case ServerOP_ReloadVariables: - { - if (zone && zone->IsLoaded()) { - zone->SendReloadMessage("Variables"); - database.LoadVariables(); - } - break; - } - case ServerOP_ReloadVeteranRewards: - { - if (zone && zone->IsLoaded()) { - zone->SendReloadMessage("Veteran Rewards"); - zone->LoadVeteranRewards(); - } - break; - } - case ServerOP_ReloadWorld: - { - auto* reload_world = (ReloadWorld_Struct*)pack->pBuffer; - if (zone) { - zone->ReloadWorld(reload_world->global_repop); - } - break; - } - case ServerOP_ReloadZonePoints: - { - if (zone && zone->IsLoaded()) { - zone->SendReloadMessage("Zone Points"); - content_db.LoadStaticZonePoints(&zone->zone_point_list, zone->GetShortName(), zone->GetInstanceVersion()); - } - break; - } - case ServerOP_ReloadZoneData: - { - zone_store.LoadZones(content_db); - if (zone && zone->IsLoaded()) { - zone->LoadZoneCFG(zone->GetShortName(), zone->GetInstanceVersion()); - zone->SendReloadMessage("Zone Data"); - } + auto o = (ServerReload::Request*) pack->pBuffer; + QueueReload(*o); break; } case ServerOP_CameraShake: @@ -4499,59 +4299,9 @@ bool WorldServer::RezzPlayer(EQApplicationPacket* rpack, uint32 rezzexp, uint32 } void WorldServer::SendReloadTasks(uint8 reload_type, uint32 task_id) { - auto pack = new ServerPacket(ServerOP_ReloadTasks, sizeof(ReloadTasks_Struct)); - auto rts = (ReloadTasks_Struct*) pack->pBuffer; - - rts->reload_type = reload_type; - rts->task_id = task_id; - - SendPacket(pack); - safe_delete(pack); + SendReload(ServerReload::Type::Tasks); } -void WorldServer::HandleReloadTasks(ServerPacket *pack) -{ - auto rts = (ReloadTasks_Struct*) pack->pBuffer; - - LogTasks("Global reload of tasks received with Reload Type [{}] Task ID [{}]", rts->reload_type, rts->task_id); - - switch (rts->reload_type) { - case RELOADTASKS: - { - entity_list.SaveAllClientsTaskState(); - - // TODO: Reload at the world level for shared tasks - - if (!rts->task_id) { - LogTasks("Global reload of all Tasks"); - safe_delete(task_manager); - task_manager = new TaskManager; - task_manager->LoadTasks(); - - entity_list.ReloadAllClientsTaskState(); - } else { - LogTasks("Global reload of Task ID [{}]", rts->task_id); - task_manager->LoadTasks(rts->task_id); - entity_list.ReloadAllClientsTaskState(rts->task_id); - } - - break; - } - case RELOADTASKSETS: - { - LogTasks("Global reload of all Task Sets"); - task_manager->LoadTaskSets(); - break; - } - default: - { - LogTasks("Unhandled global reload of Tasks Reload Type [{}] Task ID [{}]", rts->reload_type, rts->task_id); - break; - } - } -} - - uint32 WorldServer::NextGroupID() { //this system wastes a lot of potential group IDs (~5%), but //if you are creating 2 billion groups in 1 run of the emu, @@ -4732,3 +4482,216 @@ void WorldServer::SetScheduler(ZoneEventScheduler *scheduler) WorldServer::m_zone_scheduler = scheduler; } +void WorldServer::SendReload(ServerReload::Type type, bool is_global) +{ + static auto pack = ServerPacket(ServerOP_ServerReloadRequest, sizeof(ServerReload::Request)); + auto reload = (ServerReload::Request*) pack.pBuffer; + reload->type = type; + reload->zone_server_id = 0; + if (!is_global && zone && zone->IsLoaded()) { + reload->zone_server_id = zone->GetZoneServerId(); + } + + SendPacket(&pack); +} + +void WorldServer::QueueReload(ServerReload::Request r) +{ + m_reload_mutex.lock(); + int64_t reload_at = r.reload_at_unix - std::time(nullptr); + + // If the reload is set to happen now, process it immediately versus queuing it + if (reload_at <= 0) { + ProcessReload(r); + m_reload_mutex.unlock(); + return; + } + + LogInfo( + "Queuing reload for [{}] ({}) to reload in [{}]", + ServerReload::GetName(r.type), + r.type, + reload_at > 0 ? Strings::SecondsToTime(reload_at) : "Now" + ); + + m_reload_queue[r.type] = r; + m_reload_mutex.unlock(); +} + +void WorldServer::ProcessReload(const ServerReload::Request& request) +{ + LogInfo( + "Reloading [{}] ({}) zone booted required [{}]", + ServerReload::GetName(request.type), + request.type, + request.requires_zone_booted + ); + + if (request.requires_zone_booted) { + if (!zone || (zone && !zone->IsLoaded())) { + LogInfo("Zone not booted, skipping reload for [{}] ({})", ServerReload::GetName(request.type), request.type); + return; + } + } + + zone->SendReloadMessage(ServerReload::GetName(request.type)); + + switch (request.type) { + case ServerReload::Type::AAData: + zone->LoadAlternateAdvancement(); + entity_list.SendAlternateAdvancementStats(); + break; + + case ServerReload::Type::Opcodes: + ReloadAllPatches(); + break; + + case ServerReload::Type::AlternateCurrencies: + zone->LoadAlternateCurrencies(); + break; + + case ServerReload::Type::BaseData: + zone->ReloadBaseData(); + break; + + case ServerReload::Type::BlockedSpells: + zone->LoadZoneBlockedSpells(); + break; + + case ServerReload::Type::Commands: + command_init(); + if (RuleB(Bots, Enabled) && database.DoesTableExist("bot_command_settings")) { + bot_command_init(); + } + break; + + case ServerReload::Type::ContentFlags: + content_service.SetExpansionContext()->ReloadContentFlags(); + break; + + case ServerReload::Type::DzTemplates: + zone->LoadDynamicZoneTemplates(); + break; + + case ServerReload::Type::Factions: + content_db.LoadFactionData(); + zone->ReloadNPCFactions(); + zone->ReloadFactionAssociations(); + break; + + case ServerReload::Type::LevelEXPMods: + zone->LoadLevelEXPMods(); + break; + + case ServerReload::Type::Logs: + LogSys.LoadLogDatabaseSettings(); + player_event_logs.ReloadSettings(); + break; + + case ServerReload::Type::Loot: + zone->ReloadLootTables(); + break; + + case ServerReload::Type::Merchants: + entity_list.ReloadMerchants(); + break; + + case ServerReload::Type::NPCEmotes: + zone->LoadNPCEmotes(&zone->npc_emote_list); + break; + + case ServerReload::Type::NPCSpells: + content_db.ClearNPCSpells(); + for (auto &e: entity_list.GetNPCList()) { + e.second->ReloadSpells(); + } + break; + + case ServerReload::Type::PerlExportSettings: + parse->LoadPerlEventExportSettings(parse->perl_event_export_settings); + break; + + case ServerReload::Type::Rules: + RuleManager::Instance()->LoadRules(&database, RuleManager::Instance()->GetActiveRuleset(), true); + break; + + case ServerReload::Type::SkillCaps: + skill_caps.ReloadSkillCaps(); + break; + + case ServerReload::Type::DataBucketsCache: + DataBucket::ClearCache(); + break; + + case ServerReload::Type::StaticZoneData: + case ServerReload::Type::Doors: + case ServerReload::Type::GroundSpawns: + case ServerReload::Type::Objects: + zone->ReloadStaticData(); + break; + + case ServerReload::Type::Tasks: + if (RuleB(Tasks, EnableTaskSystem)) { + entity_list.SaveAllClientsTaskState(); + safe_delete(task_manager); + task_manager = new TaskManager; + task_manager->LoadTasks(); + entity_list.ReloadAllClientsTaskState(); + task_manager->LoadTaskSets(); + } + break; + + case ServerReload::Type::Quests: + entity_list.ClearAreas(); + parse->ReloadQuests(false); + break; + + case ServerReload::Type::QuestsTimerReset: + entity_list.ClearAreas(); + parse->ReloadQuests(true); + break; + + case ServerReload::Type::Titles: + title_manager.LoadTitles(); + break; + + case ServerReload::Type::Traps: + entity_list.UpdateAllTraps(true, true); + break; + + case ServerReload::Type::Variables: + database.LoadVariables(); + break; + + case ServerReload::Type::VeteranRewards: + zone->LoadVeteranRewards(); + break; + + case ServerReload::Type::WorldRepop: + entity_list.ClearAreas(); + parse->ReloadQuests(); + zone->Repop(); + break; + + case ServerReload::Type::WorldWithRespawn: + entity_list.ClearAreas(); + parse->ReloadQuests(); + zone->Repop(); + zone->ClearSpawnTimers(); + break; + + case ServerReload::Type::ZonePoints: + content_db.LoadStaticZonePoints(&zone->zone_point_list, zone->GetShortName(), zone->GetInstanceVersion()); + break; + + case ServerReload::Type::ZoneData: + zone_store.LoadZones(content_db); + zone->LoadZoneCFG(zone->GetShortName(), zone->GetInstanceVersion()); + break; + + default: + break; + } + + LogInfo("Reloaded [{}] ({})", ServerReload::GetName(request.type), request.type); +} diff --git a/zone/worldserver.h b/zone/worldserver.h index de3ac5e97..d54731758 100644 --- a/zone/worldserver.h +++ b/zone/worldserver.h @@ -21,6 +21,7 @@ #include "../common/eq_packet_structs.h" #include "../common/net/servertalk_client_connection.h" #include "zone_event_scheduler.h" +#include "../common/server_reload_types.h" class ServerPacket; class EQApplicationPacket; @@ -31,6 +32,7 @@ public: WorldServer(); ~WorldServer(); + void Process(); void Connect(); bool SendPacket(ServerPacket* pack); std::string GetIP() const; @@ -52,7 +54,6 @@ public: void SetLaunchedName(const char *n) { m_launchedName = n; } void SetLauncherName(const char *n) { m_launcherName = n; } void SendReloadTasks(uint8 reload_type, uint32 task_id = 0); - void HandleReloadTasks(ServerPacket *pack); void UpdateLFP(uint32 LeaderID, uint8 Action, uint8 MatchFilter, uint32 FromLevel, uint32 ToLevel, uint32 Classes, const char *Comments, GroupLFPMemberEntry *LFPMembers); void UpdateLFP(uint32 LeaderID, GroupLFPMemberEntry *LFPMembers); @@ -61,7 +62,8 @@ public: void HandleLFPMatches(ServerPacket *pack); void RequestTellQueue(const char *who); - + void QueueReload(ServerReload::Request r); + void ProcessReload(const ServerReload::Request &request); private: virtual void OnConnected(); @@ -77,9 +79,15 @@ private: std::unique_ptr m_keepalive; ZoneEventScheduler *m_zone_scheduler; + + // server reload queue + std::unique_ptr m_process_timer; + std::mutex m_reload_mutex = {}; + std::map m_reload_queue = {}; public: ZoneEventScheduler *GetScheduler() const; void SetScheduler(ZoneEventScheduler *scheduler); + void SendReload(ServerReload::Type type, bool is_global = true); }; #endif diff --git a/zone/zone.cpp b/zone/zone.cpp index 8b1639ba4..48eedf76b 100644 --- a/zone/zone.cpp +++ b/zone/zone.cpp @@ -2605,52 +2605,6 @@ void Zone::LoadNPCEmotes(std::vector* v) } -void Zone::ReloadWorld(uint8 global_repop) -{ - entity_list.ClearAreas(); - parse->ReloadQuests(); - - if (global_repop) { - if (global_repop == ReloadWorld::ForceRepop) { - zone->ClearSpawnTimers(); - } - - zone->Repop(); - } - - worldserver.SendEmoteMessage( - 0, - 0, - AccountStatus::GMAdmin, - Chat::Yellow, - fmt::format( - "Quests reloaded {}for {}{}.", - ( - global_repop ? - ( - global_repop == ReloadWorld::Repop ? - "and repopped NPCs " : - "and forcefully repopped NPCs " - ) : - "" - ), - fmt::format( - "{} ({})", - GetLongName(), - GetZoneID() - ), - ( - GetInstanceID() ? - fmt::format( - " (Instance ID {})", - GetInstanceID() - ) : - "" - ) - ).c_str() - ); -} - void Zone::ClearSpawnTimers() { LinkedListIterator iterator(spawn2_list); @@ -2859,8 +2813,6 @@ std::string Zone::GetZoneDescription() void Zone::SendReloadMessage(std::string reload_type) { - LogInfo("Reloaded [{}]", reload_type); - worldserver.SendEmoteMessage( 0, 0, @@ -3014,12 +2966,7 @@ bool Zone::CompareDataBucket(uint8 comparison_type, const std::string& bucket, c void Zone::ReloadContentFlags() { - auto pack = new ServerPacket(ServerOP_ReloadContentFlags, 0); - if (pack) { - worldserver.SendPacket(pack); - } - - safe_delete(pack); + worldserver.SendReload(ServerReload::Type::ContentFlags); } void Zone::ClearEXPModifier(Client* c) diff --git a/zone/zone.h b/zone/zone.h index 4d78a5b2b..def760907 100755 --- a/zone/zone.h +++ b/zone/zone.h @@ -310,7 +310,6 @@ public: void LoadVeteranRewards(); void LoadZoneDoors(); void ReloadStaticData(); - void ReloadWorld(uint8 global_repop); void RemoveAuth(const char *iCharName, const char *iLSKey); void RemoveAuth(uint32 lsid); void Repop(bool is_forced = false); @@ -457,6 +456,8 @@ public: void DeleteBucket(const std::string& bucket_name); std::string GetBucketExpires(const std::string& bucket_name); std::string GetBucketRemaining(const std::string& bucket_name); + inline void SetZoneServerId(uint32 id) { m_zone_server_id = id; } + inline uint32 GetZoneServerId() const { return m_zone_server_id; } private: bool allow_mercs; @@ -521,6 +522,8 @@ private: // Base Data std::vector m_base_data = { }; + + uint32_t m_zone_server_id = 0; }; #endif