[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
24 changed files with 607 additions and 1258 deletions
+239 -276
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);
}