From b4d04b1af1b9e4ead50b874aa28ae7197f3a3f9f Mon Sep 17 00:00:00 2001 From: Exitare Date: Sun, 22 Dec 2024 00:44:50 -0800 Subject: [PATCH] refactor(Core/Event): Load event vendors seperatly (#20906) --- .../rev_1734055142233360300.sql | 3 + .../Database/Implementation/WorldDatabase.cpp | 1 + .../Database/Implementation/WorldDatabase.h | 1 + src/server/game/Events/GameEventMgr.cpp | 150 ++++++++++-------- src/server/game/Events/GameEventMgr.h | 2 + src/server/scripts/Commands/cs_reload.cpp | 9 ++ 6 files changed, 103 insertions(+), 63 deletions(-) create mode 100644 data/sql/updates/pending_db_world/rev_1734055142233360300.sql diff --git a/data/sql/updates/pending_db_world/rev_1734055142233360300.sql b/data/sql/updates/pending_db_world/rev_1734055142233360300.sql new file mode 100644 index 000000000..b9bb38aab --- /dev/null +++ b/data/sql/updates/pending_db_world/rev_1734055142233360300.sql @@ -0,0 +1,3 @@ +-- +DELETE FROM `command` where `name` = 'reload game_event_npc_vendor'; +INSERT INTO `command` (`name`, `security`, `help`) VALUES ('reload game_event_npc_vendor', 3, 'Syntax: .reload game_event_npc_vendor\r Reload game_event_npc_vendor table.'); diff --git a/src/server/database/Database/Implementation/WorldDatabase.cpp b/src/server/database/Database/Implementation/WorldDatabase.cpp index 323f4ccbd..d6081c983 100644 --- a/src/server/database/Database/Implementation/WorldDatabase.cpp +++ b/src/server/database/Database/Implementation/WorldDatabase.cpp @@ -86,6 +86,7 @@ void WorldDatabaseConnection::DoPrepareStatements() PrepareStatement(WORLD_INS_CREATURE, "INSERT INTO creature (guid, id1, id2, id3, map, spawnMask, phaseMask, equipment_id, position_x, position_y, position_z, orientation, spawntimesecs, wander_distance, currentwaypoint, curhealth, curmana, MovementType, npcflag, unit_flags, dynamicflags) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(WORLD_DEL_GAME_EVENT_CREATURE, "DELETE FROM game_event_creature WHERE guid = ?", CONNECTION_ASYNC); PrepareStatement(WORLD_DEL_GAME_EVENT_MODEL_EQUIP, "DELETE FROM game_event_model_equip WHERE guid = ?", CONNECTION_ASYNC); + PrepareStatement(WORLD_SEL_GAME_EVENT_NPC_VENDOR, "SELECT eventEntry, guid, item, maxcount, incrtime, ExtendedCost FROM game_event_npc_vendor ORDER BY guid, slot ASC", CONNECTION_SYNCH); PrepareStatement(WORLD_INS_GAMEOBJECT, "INSERT INTO gameobject (guid, id, map, spawnMask, phaseMask, position_x, position_y, position_z, orientation, rotation0, rotation1, rotation2, rotation3, spawntimesecs, animprogress, state) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(WORLD_INS_DISABLES, "INSERT INTO disables (entry, sourceType, flags, comment) VALUES (?, ?, ?, ?)", CONNECTION_ASYNC); PrepareStatement(WORLD_SEL_DISABLES, "SELECT entry FROM disables WHERE entry = ? AND sourceType = ?", CONNECTION_SYNCH); diff --git a/src/server/database/Database/Implementation/WorldDatabase.h b/src/server/database/Database/Implementation/WorldDatabase.h index ebfdcfe07..049766725 100644 --- a/src/server/database/Database/Implementation/WorldDatabase.h +++ b/src/server/database/Database/Implementation/WorldDatabase.h @@ -92,6 +92,7 @@ enum WorldDatabaseStatements : uint32 WORLD_INS_CREATURE, WORLD_DEL_GAME_EVENT_CREATURE, WORLD_DEL_GAME_EVENT_MODEL_EQUIP, + WORLD_SEL_GAME_EVENT_NPC_VENDOR, WORLD_INS_GAMEOBJECT, WORLD_SEL_DISABLES, WORLD_INS_DISABLES, diff --git a/src/server/game/Events/GameEventMgr.cpp b/src/server/game/Events/GameEventMgr.cpp index a914182c8..0909ae7db 100644 --- a/src/server/game/Events/GameEventMgr.cpp +++ b/src/server/game/Events/GameEventMgr.cpp @@ -236,6 +236,92 @@ void GameEventMgr::StopEvent(uint16 event_id, bool overwrite) sScriptMgr->OnGameEventStop(event_id); } +void GameEventMgr::LoadEventVendors() +{ + uint32 oldMSTime = getMSTime(); + WorldDatabasePreparedStatement* stmt = WorldDatabase.GetPreparedStatement(WORLD_SEL_GAME_EVENT_NPC_VENDOR); + PreparedQueryResult result = WorldDatabase.Query(stmt); + + if (!result) + { + LOG_WARN("server.loading", ">> Loaded 0 Vendor Additions In Game Events. DB Table `game_event_npc_vendor` Is Empty."); + LOG_INFO("server.loading", " "); + return; + } + + uint32 count = 0; + std::unordered_set processedEvents; + + do + { + Field* fields = result->Fetch(); + uint8 eventId = fields[0].Get(); + ObjectGuid::LowType guid = fields[1].Get(); + + if (eventId >= mGameEventVendors.size()) + { + LOG_ERROR("sql.sql", "Table `game_event_npc_vendor` has invalid eventEntry ({}) for GUID ({}), skipped.", eventId, guid); + continue; + } + + // Clear existing vendors for this event only once + if (processedEvents.find(eventId) == processedEvents.end()) + { + // Remove vendor items from in-memory data + for (auto& entry : mGameEventVendors[eventId]) + { + sObjectMgr->RemoveVendorItem(entry.entry, entry.item, false); + } + mGameEventVendors[eventId].clear(); + processedEvents.insert(eventId); + } + + NPCVendorList& vendors = mGameEventVendors[eventId]; + NPCVendorEntry newEntry; + newEntry.item = fields[2].Get(); + newEntry.maxcount = fields[3].Get(); + newEntry.incrtime = fields[4].Get(); + newEntry.ExtendedCost = fields[5].Get(); + + // Get the event NPC flag for validity check + uint32 event_npc_flag = 0; + NPCFlagList& flist = mGameEventNPCFlags[eventId]; + for (NPCFlagList::const_iterator itr = flist.begin(); itr != flist.end(); ++itr) + { + if (itr->first == guid) + { + event_npc_flag = itr->second; + break; + } + } + + // Get creature entry + newEntry.entry = 0; + if (CreatureData const* data = sObjectMgr->GetCreatureData(guid)) + newEntry.entry = data->id1; + + // Validate vendor item + if (!sObjectMgr->IsVendorItemValid(newEntry.entry, newEntry.item, newEntry.maxcount, newEntry.incrtime, newEntry.ExtendedCost, nullptr, nullptr, event_npc_flag)) + { + LOG_ERROR("sql.sql", "Table `game_event_npc_vendor` has invalid item ({}) for guid ({}) for event ({}), skipped.", + newEntry.item, newEntry.entry, eventId); + continue; + } + + // Add the item to the vendor if event is active + if (IsEventActive(eventId)) + sObjectMgr->AddVendorItem(newEntry.entry, newEntry.item, newEntry.maxcount, newEntry.incrtime, newEntry.ExtendedCost, false); + + vendors.push_back(newEntry); + + ++count; + } while (result->NextRow()); + + LOG_INFO("server.loading", ">> Loaded {} Vendor Additions In Game Events in {} ms", count, GetMSTimeDiffToNow(oldMSTime)); + LOG_INFO("server.loading", " "); + +} + void GameEventMgr::LoadFromDB() { { @@ -852,69 +938,7 @@ void GameEventMgr::LoadFromDB() } LOG_INFO("server.loading", "Loading Game Event Vendor Additions Data..."); - { - uint32 oldMSTime = getMSTime(); - - // 0 1 2 3 4 5 - QueryResult result = WorldDatabase.Query("SELECT eventEntry, guid, item, maxcount, incrtime, ExtendedCost FROM game_event_npc_vendor ORDER BY guid, slot ASC"); - - if (!result) - { - LOG_WARN("server.loading", ">> Loaded 0 Vendor Additions In Game Events. DB Table `game_event_npc_vendor` Is Empty."); - LOG_INFO("server.loading", " "); - } - else - { - uint32 count = 0; - do - { - Field* fields = result->Fetch(); - - uint8 event_id = fields[0].Get(); - - if (event_id >= mGameEventVendors.size()) - { - LOG_ERROR("sql.sql", "`game_event_npc_vendor` game event id ({}) is out of range compared to max event id in `game_event`", event_id); - continue; - } - - NPCVendorList& vendors = mGameEventVendors[event_id]; - NPCVendorEntry newEntry; - ObjectGuid::LowType guid = fields[1].Get(); - newEntry.item = fields[2].Get(); - newEntry.maxcount = fields[3].Get(); - newEntry.incrtime = fields[4].Get(); - newEntry.ExtendedCost = fields[5].Get(); - // get the event npc flag for checking if the npc will be vendor during the event or not - uint32 event_npc_flag = 0; - NPCFlagList& flist = mGameEventNPCFlags[event_id]; - for (NPCFlagList::const_iterator itr = flist.begin(); itr != flist.end(); ++itr) - { - if (itr->first == guid) - { - event_npc_flag = itr->second; - break; - } - } - // get creature entry - newEntry.entry = 0; - - if (CreatureData const* data = sObjectMgr->GetCreatureData(guid)) - newEntry.entry = data->id1; - - // check validity with event's npcflag - if (!sObjectMgr->IsVendorItemValid(newEntry.entry, newEntry.item, newEntry.maxcount, newEntry.incrtime, newEntry.ExtendedCost, nullptr, nullptr, event_npc_flag)) - continue; - - vendors.push_back(newEntry); - - ++count; - } while (result->NextRow()); - - LOG_INFO("server.loading", ">> Loaded {} Vendor Additions In Game Events in {} ms", count, GetMSTimeDiffToNow(oldMSTime)); - LOG_INFO("server.loading", " "); - } - } + LoadEventVendors(); LOG_INFO("server.loading", "Loading Game Event Battleground Data..."); { diff --git a/src/server/game/Events/GameEventMgr.h b/src/server/game/Events/GameEventMgr.h index c251cf803..b997efe06 100644 --- a/src/server/game/Events/GameEventMgr.h +++ b/src/server/game/Events/GameEventMgr.h @@ -121,6 +121,8 @@ public: void StopEvent(uint16 event_id, bool overwrite = false); void HandleQuestComplete(uint32 quest_id); // called on world event type quest completions uint32 GetNPCFlag(Creature* cr); + // Load the game event npc vendor table from the DB + void LoadEventVendors(); [[nodiscard]] uint32 GetHolidayEventId(uint32 holidayId) const; private: void SendWorldStateUpdate(Player* player, uint16 event_id); diff --git a/src/server/scripts/Commands/cs_reload.cpp b/src/server/scripts/Commands/cs_reload.cpp index a8544c218..b11eb2c1e 100644 --- a/src/server/scripts/Commands/cs_reload.cpp +++ b/src/server/scripts/Commands/cs_reload.cpp @@ -135,6 +135,7 @@ public: { "npc_spellclick_spells", HandleReloadSpellClickSpellsCommand, SEC_ADMINISTRATOR, Console::Yes }, { "npc_trainer", HandleReloadNpcTrainerCommand, SEC_ADMINISTRATOR, Console::Yes }, { "npc_vendor", HandleReloadNpcVendorCommand, SEC_ADMINISTRATOR, Console::Yes }, + { "game_event_npc_vendor", HandleReloadGameEventNPCVendorCommand, SEC_ADMINISTRATOR, Console::Yes }, { "page_text", HandleReloadPageTextsCommand, SEC_ADMINISTRATOR, Console::Yes }, { "pickpocketing_loot_template", HandleReloadLootTemplatesPickpocketingCommand, SEC_ADMINISTRATOR, Console::Yes }, { "points_of_interest", HandleReloadPointsOfInterestCommand, SEC_ADMINISTRATOR, Console::Yes }, @@ -765,6 +766,14 @@ public: return true; } + static bool HandleReloadGameEventNPCVendorCommand(ChatHandler* handler) + { + LOG_INFO("server.loading", "Reloading `game_event_npc_vendor` Table!"); + sGameEventMgr->LoadEventVendors(); + handler->SendGlobalGMSysMessage("DB table `game_event_npc_vendor` reloaded."); + return true; + } + static bool HandleReloadPointsOfInterestCommand(ChatHandler* handler) { LOG_INFO("server.loading", "Reloading `points_of_interest` Table!");