[Performance] Server Reload Overhaul (#4689)

* [Performance] Server Reload Overhaul

* Client::SendReloadCommandMessages

* Remove global buffs
This commit is contained in:
Chris Miles 2025-02-18 00:54:37 -06:00 committed by GitHub
parent 49cf97ae9c
commit 1bd281c8f2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
24 changed files with 607 additions and 1258 deletions

View File

@ -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

View File

@ -0,0 +1,143 @@
#ifndef EQEMU_SERVER_RELOAD_TYPES_H
#define EQEMU_SERVER_RELOAD_TYPES_H
#include <string>
#include <vector>
#include <cstdint>
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<ServerReload::Type> GetTypes()
{
std::vector<ServerReload::Type> types;
types.reserve(ServerReload::Type::Max);
for (int i = 1; i < ServerReload::Type::Max; i++) {
types.push_back(static_cast<ServerReload::Type>(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

View File

@ -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

View File

@ -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;
}

View File

@ -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, ...);

View File

@ -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 <iomanip>
#include <iostream>
#include <stdarg.h>
@ -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: {

View File

@ -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 <iostream>
#include <string.h>
@ -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: {

View File

@ -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();

View File

@ -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> 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<std::string> &args)
{
std::vector<std::string> 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<uint8>(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)

View File

@ -4,6 +4,7 @@
#include <string>
#include "../common/types.h"
#include "../common/discord/discord.h"
#include "ucs.h"
extern UCSConnection UCSLink;

View File

@ -2,6 +2,7 @@
#include "../common/servertalk.h"
#include <ctime>
#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);
}
}
}

View File

@ -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<ServerReload::Type> 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;
}
}

View File

@ -5,6 +5,7 @@
#include "../common/eqtime.h"
#include "../common/timer.h"
#include "../common/event/timer.h"
#include "../common/server_reload_types.h"
#include <vector>
#include <memory>
#include <deque>
@ -69,6 +70,7 @@ public:
ZoneServer* FindByZoneID(uint32 ZoneID);
const std::list<std::unique_ptr<ZoneServer>> &getZoneServerList() const;
void SendServerReload(ServerReload::Type type, uchar *packet = nullptr);
private:
void OnTick(EQ::Timer *t);

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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<uint8>(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);
}

View File

@ -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);
}

View File

@ -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)

View File

@ -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_)) {

View File

@ -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<EQ::Timer>(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<EQ::Net::ServertalkClient>(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);
}

View File

@ -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<EQ::Timer> m_keepalive;
ZoneEventScheduler *m_zone_scheduler;
// server reload queue
std::unique_ptr<EQ::Timer> m_process_timer;
std::mutex m_reload_mutex = {};
std::map<int, ServerReload::Request> m_reload_queue = {};
public:
ZoneEventScheduler *GetScheduler() const;
void SetScheduler(ZoneEventScheduler *scheduler);
void SendReload(ServerReload::Type type, bool is_global = true);
};
#endif

View File

@ -2605,52 +2605,6 @@ void Zone::LoadNPCEmotes(std::vector<NPC_Emote_Struct*>* 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<Spawn2 *> 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)

View File

@ -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<BaseDataRepository::BaseData> m_base_data = { };
uint32_t m_zone_server_id = 0;
};
#endif