diff --git a/source/WorldServer/Commands/Commands.cpp b/source/WorldServer/Commands/Commands.cpp index 10e3ab6..10b6b61 100644 --- a/source/WorldServer/Commands/Commands.cpp +++ b/source/WorldServer/Commands/Commands.cpp @@ -5818,6 +5818,7 @@ void Commands::Process(int32 index, EQ2_16BitString* command_parms, Client* clie case COMMAND_LEAVERAID: { Command_LeaveRaid(client, sep); break; } case COMMAND_SPLIT: { Command_Split(client, sep); break; } case COMMAND_RAIDSAY: { Command_RaidSay(client, sep); break; } + case COMMAND_RELOAD_ZONEINFO: { Command_ReloadZoneInfo(client, sep); break; } default: { LogWrite(COMMAND__WARNING, 0, "Command", "Unhandled command: %s", command->command.data.c_str()); @@ -12850,4 +12851,13 @@ void Commands::Command_RaidSay(Client* client, Seperator* sep) { peer_manager.SendPeersChannelMessage(gmi->group_id, std::string(client->GetPlayer()->GetName()), std::string(sep->argplus[0]), CHANNEL_RAID_SAY, client->GetPlayer()->GetCurrentLanguage()); } } +} + +/* + Function: Command_ReloadZoneInfo() + Purpose : Clears ZoneInfoMemory used for database.LoadZoneInfo + Example : /reload zoneinfo +*/ +void Commands::Command_ReloadZoneInfo(Client* client, Seperator* sep) { + world.ClearZoneInfoCache(); } \ No newline at end of file diff --git a/source/WorldServer/Commands/Commands.h b/source/WorldServer/Commands/Commands.h index 547595e..6a3981e 100644 --- a/source/WorldServer/Commands/Commands.h +++ b/source/WorldServer/Commands/Commands.h @@ -464,6 +464,8 @@ public: void Command_LeaveRaid(Client* client, Seperator* sep); void Command_Split(Client* client, Seperator* sep); void Command_RaidSay(Client* client, Seperator* sep); + + void Command_ReloadZoneInfo(Client* client, Seperator* sep); // AA Commands void Get_AA_Xml(Client* client, Seperator* sep); @@ -993,4 +995,6 @@ private: #define COMMAND_MODIFY_SPELL 1008 #define COMMAND_MODIFY_ZONE 1009 +#define COMMAND_RELOAD_ZONEINFO 1010 + #endif diff --git a/source/WorldServer/World.cpp b/source/WorldServer/World.cpp index 59f7e3c..82fc022 100644 --- a/source/WorldServer/World.cpp +++ b/source/WorldServer/World.cpp @@ -3650,4 +3650,66 @@ void World::ClientAuthApproval(int32 success, std::string charName, int32 accoun else { // can't find client } +} + +void World::ClearZoneInfoCache() { + std::unique_lock lock(cacheMutex); + zoneInfoByID.clear(); + zoneInfoByName.clear(); +} + +std::shared_ptr World::GetZoneInfoById(int32 zoneID) { + std::shared_lock lock(cacheMutex); + auto it = zoneInfoByID.find(zoneID); + if (it != zoneInfoByID.end()) { + return it->second; + } + return nullptr; +} + +std::shared_ptr World::GetZoneInfoByName(const std::string& zoneName) { + std::shared_lock lock(cacheMutex); + auto it = zoneInfoByName.find(zoneName); + if (it != zoneInfoByName.end()) { + return it->second; + } + return nullptr; +} + +void World::AddZoneInfo(int32 zoneID, std::shared_ptr zoneInfo) { + std::unique_lock lock(cacheMutex); + zoneInfoByID[zoneInfo->zoneID] = zoneInfo; + zoneInfoByName[zoneInfo->zoneName] = zoneInfo; +} + +void ZoneInfoMemory::LoadFromDatabaseRow(MYSQL_ROW row) { + zoneID = atoul(row[0]); + zoneFile = (row[1] != nullptr) ? row[1] : ""; + zoneDescription = (row[2] != nullptr) ? row[2] : ""; + underworld = atof(row[3]); + safeX = atof(row[4]); + safeY = atof(row[5]); + safeZ = atof(row[6]); + minimumLevel = atoi(row[8]); + maximumLevel = atoi(row[9]); + int8 type = (atoi(row[10]) == 0) ? 0 : atoi(row[10]) - 1; + shutdownTime = atoul(row[11]); + instanceType = (Instance_Type)type; + zoneMotd = (row[12] != nullptr) ? row[12] : ""; + defReenterTime = atoi(row[13]); + defResetTime = atoi(row[14]); + defLockoutTime = atoi(row[15]); + groupZoneOption = atoi(row[16]); + safeHeading = atof(row[17]); + xpModifier = atof(row[18]); + rulesetID = atoul(row[19]); + if (rulesetID > 0 && !rule_manager.SetZoneRuleSet(zoneID, rulesetID)) + LogWrite(ZONE__ERROR, 0, "Zones", "Error setting rule set for zone '%s' (%u). A rule set with ID %u does not exist.", zoneFile.c_str(), zoneID, rulesetID); + minimumVersion = database.GetMinimumClientVersion(atoul(row[20])); + weatherAllowed = atoul(row[21]); + zoneSkyFile = (row[22] != nullptr) ? row[22] : ""; + canBind = atoul(row[23]); + canGate = atoul(row[24]); + cityZone = atoul(row[25]); + canEvac = atoul(row[26]); } \ No newline at end of file diff --git a/source/WorldServer/World.h b/source/WorldServer/World.h index e31d6a9..039c83d 100644 --- a/source/WorldServer/World.h +++ b/source/WorldServer/World.h @@ -27,6 +27,7 @@ #include #include #include +#include #include "SpawnLists.h" #include "zoneserver.h" #include "NPC.h" @@ -412,6 +413,37 @@ struct WhoAllPeerPlayer { level = inLevel; } }; + +class ZoneInfoMemory { +public: + int32 zoneID; + std::string zoneName; + std::string zoneFile; + std::string zoneDescription; + std::string zoneMotd; + std::string zoneSkyFile; + float underworld; + float safeX, safeY, safeZ, safeHeading; + int16 minimumLevel, maximumLevel, minimumVersion; + int32 defReenterTime, defResetTime, defLockoutTime; + int8 groupZoneOption; + float xpModifier; + bool cityZone, canBind, canGate, canEvac, weatherAllowed; + int32 rulesetID; + Instance_Type instanceType; + int32 shutdownTime; + // Add other fields as necessary + + // Constructor + ZoneInfoMemory() : zoneID(0), underworld(0.0f), safeX(0.0f), safeY(0.0f), safeZ(0.0f), + safeHeading(0.0f), minimumLevel(0), maximumLevel(0), minimumVersion(0), + defReenterTime(0), defResetTime(0), defLockoutTime(0), groupZoneOption(0), + xpModifier(1.0f), cityZone(false), canBind(false), canGate(false), + canEvac(false), weatherAllowed(true), rulesetID(0) {} + + void LoadFromDatabaseRow(MYSQL_ROW row); +}; + class ZoneList { public: ZoneList(); @@ -713,9 +745,16 @@ public: static void Web_worldhandle_peerstatus(const http::request& req, http::response& res); static void Web_populate_status(boost::property_tree::ptree& pt); + + void ClearZoneInfoCache(); + std::shared_ptr GetZoneInfoById(int32 zoneID); + std::shared_ptr GetZoneInfoByName(const std::string& zoneName); + void AddZoneInfo(int32 zoneID, std::shared_ptr zoneInfo); + Mutex MVoiceOvers; static sint64 newValue; + private: multimap*> voiceover_map[3]; int32 suppressed_warning = 0; @@ -786,5 +825,9 @@ private: map > npc_spell_list; WebServer* world_webserver; + + std::unordered_map> zoneInfoByID; + std::unordered_map> zoneInfoByName; + mutable std::shared_mutex cacheMutex; }; #endif diff --git a/source/WorldServer/WorldDatabase.cpp b/source/WorldServer/WorldDatabase.cpp index 5491cf7..a5bfae0 100644 --- a/source/WorldServer/WorldDatabase.cpp +++ b/source/WorldServer/WorldDatabase.cpp @@ -2961,44 +2961,55 @@ void WorldDatabase::LoadZoneInfo(ZoneServer* zone, int32 minLevel, int32 maxLeve zone->setGroupRaidLevels(minLevel, maxLevel, avgLevel, firstLevel); char* escaped = getEscapeString(zone->GetZoneName()); - MYSQL_RES* result = query.RunQuery2(Q_SELECT, "SELECT id, file, description, underworld, safe_x, safe_y, safe_z, min_status, min_level, max_level, instance_type+0, shutdown_timer, zone_motd, default_reenter_time, default_reset_time, default_lockout_time, force_group_to_zone, safe_heading, xp_modifier, ruleset_id, expansion_id, weather_allowed, sky_file, can_bind, can_gate, city_zone, can_evac FROM zones where name='%s'",escaped); - if(result && mysql_num_rows(result) > 0) { - MYSQL_ROW row; - row = mysql_fetch_row(result); + std::shared_ptr zoneInfo = world.GetZoneInfoByName(escaped); + + MYSQL_RES* result = nullptr; + + if(zoneInfo == nullptr) + result = query.RunQuery2(Q_SELECT, "SELECT id, file, description, underworld, safe_x, safe_y, safe_z, min_status, min_level, max_level, instance_type+0, shutdown_timer, zone_motd, default_reenter_time, default_reset_time, default_lockout_time, force_group_to_zone, safe_heading, xp_modifier, ruleset_id, expansion_id, weather_allowed, sky_file, can_bind, can_gate, city_zone, can_evac FROM zones where name='%s'",escaped); + if((zoneInfo || (result && mysql_num_rows(result) > 0))) { + if(result && zoneInfo == nullptr) + { + MYSQL_ROW row; + row = mysql_fetch_row(result); + + zoneInfo = std::make_shared(); + zoneInfo->LoadFromDatabaseRow(row); + world.AddZoneInfo(zoneInfo->zoneID, zoneInfo); + } + + if(!result && !zoneInfo) { + LogWrite(ZONE__ERROR, 0, "Zones", "Failed to get zone info for %s.", escaped); + safe_delete_array(escaped); + return; + } zone->SetZoneName(escaped); - zone->SetZoneID(strtoul(row[0], NULL, 0)); - zone->SetZoneFile(row[1]); - zone->SetZoneDescription(row[2]); - zone->SetUnderWorld(atof(row[3])); - zone->SetSafeX(atof(row[4])); - zone->SetSafeY(atof(row[5])); - zone->SetSafeZ(atof(row[6])); - zone->SetMinimumStatus(atoi(row[7])); - zone->SetMinimumLevel(atoi(row[8])); - zone->SetMaximumLevel(atoi(row[9])); - int8 type = (atoi(row[10]) == 0) ? 0 : atoi(row[10]) - 1; - zone->SetInstanceType(type); - zone->SetShutdownTimer(atoul(row[11])); + zone->SetZoneID(zoneInfo->zoneID); + zone->SetZoneFile((char*)zoneInfo->zoneFile.c_str()); + zone->SetZoneDescription((char*)zoneInfo->zoneDescription.c_str()); + zone->SetUnderWorld(zoneInfo->underworld); + zone->SetSafeX(zoneInfo->safeX); + zone->SetSafeY(zoneInfo->safeY); + zone->SetSafeZ(zoneInfo->safeZ); + zone->SetMinimumStatus(zoneInfo->minimumVersion); + zone->SetMinimumLevel(zoneInfo->minimumLevel); + zone->SetMaximumLevel(zoneInfo->maximumLevel); + zone->SetInstanceType(zoneInfo->instanceType); + zone->SetShutdownTimer(zoneInfo->shutdownTime); + zone->SetZoneMOTD(zoneInfo->zoneMotd); - char* zone_motd = row[12]; - if (zone_motd && strlen(zone_motd) > 0) - zone->SetZoneMOTD(string(zone_motd)); - - zone->SetDefaultReenterTime(atoi(row[13])); - zone->SetDefaultResetTime(atoi(row[14])); - zone->SetDefaultLockoutTime(atoi(row[15])); - zone->SetForceGroupZoneOption(atoi(row[16])); - zone->SetSafeHeading(atof(row[17])); - zone->SetXPModifier(atof(row[18])); - - if ((ruleset_id = atoul(row[19])) > 0 && !rule_manager.SetZoneRuleSet(zone->GetZoneID(), ruleset_id)) - LogWrite(ZONE__ERROR, 0, "Zones", "Error setting rule set for zone '%s' (%u). A rule set with ID %u does not exist.", zone->GetZoneName(), zone->GetZoneID(), ruleset_id); + zone->SetDefaultReenterTime(zoneInfo->defReenterTime); + zone->SetDefaultResetTime(zoneInfo->defResetTime); + zone->SetDefaultLockoutTime(zoneInfo->defLockoutTime); + zone->SetForceGroupZoneOption(zoneInfo->groupZoneOption); + zone->SetSafeHeading(zoneInfo->safeHeading); + zone->SetXPModifier(zoneInfo->xpModifier); // check data_version to see if client has proper expansion to enter a zone - zone->SetMinimumVersion(GetMinimumClientVersion(atoi(row[20]))); - zone->SetWeatherAllowed(atoi(row[21]) == 0 ? false : true); + zone->SetMinimumVersion(zoneInfo->minimumVersion); + zone->SetWeatherAllowed(zoneInfo->weatherAllowed); - zone->SetZoneSkyFile(row[22]); + zone->SetZoneSkyFile((char*)zoneInfo->zoneSkyFile.c_str()); if (zone->IsInstanceZone()) { @@ -3011,10 +3022,10 @@ void WorldDatabase::LoadZoneInfo(ZoneServer* zone, int32 minLevel, int32 maxLeve LoadZonePlayerLevels(zone); } } - zone->SetCanBind(atoul(row[23])); - zone->SetCanGate(atoul(row[24])); - zone->SetCityZone(atoi(row[25])); - zone->SetCanEvac(atoul(row[26])); + zone->SetCanBind(zoneInfo->canBind); + zone->SetCanGate(zoneInfo->canGate); + zone->SetCityZone(zoneInfo->cityZone); + zone->SetCanEvac(zoneInfo->canEvac); } safe_delete_array(escaped); } diff --git a/source/WorldServer/zoneserver.cpp b/source/WorldServer/zoneserver.cpp index 48433b4..3ea502b 100644 --- a/source/WorldServer/zoneserver.cpp +++ b/source/WorldServer/zoneserver.cpp @@ -8770,7 +8770,7 @@ void ZoneServer::SendFlightPathsPackets(Client* client) { } } } - packet->PrintPacket(); + //packet->PrintPacket(); client->QueuePacket(packet->serialize()); safe_delete(packet); }