From fe82e9faf8736642f0844f2bc65f6003dfa73975 Mon Sep 17 00:00:00 2001 From: blinkysc <37940565+blinkysc@users.noreply.github.com> Date: Sun, 5 Jul 2026 09:52:41 -0500 Subject: [PATCH] refactor(Core/LFG): Reduce memory allocations in LFG hot paths (#25064) Co-authored-by: blinkysc Co-authored-by: sudlud --- src/server/game/DungeonFinding/LFGMgr.cpp | 99 +++++++++------------ src/server/game/DungeonFinding/LFGMgr.h | 11 ++- src/server/game/DungeonFinding/LFGQueue.cpp | 2 +- 3 files changed, 52 insertions(+), 60 deletions(-) diff --git a/src/server/game/DungeonFinding/LFGMgr.cpp b/src/server/game/DungeonFinding/LFGMgr.cpp index 6472843221..d3505b7739 100644 --- a/src/server/game/DungeonFinding/LFGMgr.cpp +++ b/src/server/game/DungeonFinding/LFGMgr.cpp @@ -826,7 +826,6 @@ namespace lfg return; } - std::string debugNames = ""; if (grp) // Begin rolecheck { // Create new rolecheck @@ -857,9 +856,6 @@ namespace lfg if (!isContinue) SetSelectedDungeons(pguid, dungeons); roleCheck.roles[pguid] = 0; - if (!debugNames.empty()) - debugNames.append(", "); - debugNames.append(plrg->GetName()); } } // Update leader role @@ -886,16 +882,7 @@ namespace lfg player->GetSession()->SendLfgUpdatePlayer(LfgUpdateData(LFG_UPDATETYPE_JOIN_QUEUE, dungeons, comment)); SetState(guid, LFG_STATE_QUEUED); SetRoles(guid, roles); - debugNames.append(player->GetName()); } - - /*if (sLog->ShouldLog(LOG_FILTER_LFG, LOG_LEVEL_DEBUG)) - { - std::ostringstream o; - o << "LFGMgr::Join: [" << guid << "] joined (" << (grp ? "group" : "player") << ") Members: " << debugNames.c_str() - << ". Dungeons (" << uint32(dungeons.size()) << "): " << ConcatenateDungeons(dungeons); - LOG_DEBUG("lfg", "{}", o.str()); - }*/ } void LFGMgr::ToggleTesting() @@ -1099,10 +1086,7 @@ namespace lfg int32 spellDamage, spellHeal; uint32 dungeonId, encounterMask, maxPower; uint32 deletedCounter, groupCounter, playerCounter; - ByteBuffer buffer_deleted, buffer_groups, buffer_players; std::string emptyComment; - GuidSet deletedGroups, deletedGroupsToErase; - RBInternalInfoMap copy; for (uint8 team = 0; team < 2; ++team) { @@ -1207,18 +1191,18 @@ namespace lfg } } - copy.clear(); - copy = currInternalInfoMap; // will be saved as prev at the end + _rbCopy.clear(); + _rbCopy = currInternalInfoMap; // will be saved as prev at the end // compare prev with curr to build difference packet deletedCounter = 0; groupCounter = 0; playerCounter = 0; - buffer_deleted.clear(); - buffer_groups.clear(); - buffer_players.clear(); - deletedGroups.clear(); - deletedGroupsToErase.clear(); + _rbBufferDeleted.clear(); + _rbBufferGroups.clear(); + _rbBufferPlayers.clear(); + _rbDeletedGroups.clear(); + _rbDeletedGroupsToErase.clear(); RBInternalInfoMap& prevInternalInfoMap = RBInternalInfoStorePrev[team][dungeonId]; RBInternalInfoMap::iterator iter, iterTmp; @@ -1228,50 +1212,51 @@ namespace lfg if (iter == currInternalInfoMap.end()) // was -> isn't { if (sitr->second.isGroupLeader) - deletedGroups.insert(sitr->second.groupGuid); + _rbDeletedGroups.insert(sitr->second.groupGuid); + ++deletedCounter; - buffer_deleted << sitr->second.guid; + _rbBufferDeleted << sitr->second.guid; } else // was -> is { if (sitr->second.isGroupLeader) // was a leader { if (!iter->second.isGroupLeader) // leader -> no longer a leader - deletedGroups.insert(sitr->second.groupGuid); + _rbDeletedGroups.insert(sitr->second.groupGuid); else if (sitr->second.groupGuid != iter->second.groupGuid) // leader -> leader of another group { - deletedGroups.insert(sitr->second.groupGuid); - deletedGroupsToErase.insert(iter->second.groupGuid); + _rbDeletedGroups.insert(sitr->second.groupGuid); + _rbDeletedGroupsToErase.insert(iter->second.groupGuid); ++groupCounter; - RBPacketAppendGroup(iter->second, buffer_groups); + RBPacketAppendGroup(iter->second, _rbBufferGroups); } else if (sitr->second.comment != iter->second.comment || sitr->second.encounterMask != iter->second.encounterMask || sitr->second.instanceGuid != iter->second.instanceGuid) // leader -> nothing changed { ++groupCounter; - RBPacketAppendGroup(iter->second, buffer_groups); + RBPacketAppendGroup(iter->second, _rbBufferGroups); } } else if (iter->second.isGroupLeader) // wasn't a leader -> is a leader { - deletedGroupsToErase.insert(iter->second.groupGuid); + _rbDeletedGroupsToErase.insert(iter->second.groupGuid); ++groupCounter; - RBPacketAppendGroup(iter->second, buffer_groups); + RBPacketAppendGroup(iter->second, _rbBufferGroups); } if (!iter->second._online) // if offline, copy previous stats (itemLevel, talents, area, etc.) { - iterTmp = copy.find(sitr->first); // copied container is for building a full packet, so modify it there (currInternalInfoMap is erased) + iterTmp = _rbCopy.find(sitr->first); // copied container is for building a full packet, so modify it there (currInternalInfoMap is erased) iterTmp->second.CopyStats(sitr->second); if (!sitr->second.PlayerSameAs(iterTmp->second)) // player info changed { ++playerCounter; - RBPacketAppendPlayer(iterTmp->second, buffer_players); + RBPacketAppendPlayer(iterTmp->second, _rbBufferPlayers); } } else if (!sitr->second.PlayerSameAs(iter->second)) // player info changed { ++playerCounter; - RBPacketAppendPlayer(iter->second, buffer_players); + RBPacketAppendPlayer(iter->second, _rbBufferPlayers); } currInternalInfoMap.erase(iter); } @@ -1281,38 +1266,38 @@ namespace lfg { if (sitr->second.isGroupLeader) { - deletedGroupsToErase.insert(sitr->second.groupGuid); + _rbDeletedGroupsToErase.insert(sitr->second.groupGuid); ++groupCounter; - RBPacketAppendGroup(sitr->second, buffer_groups); + RBPacketAppendGroup(sitr->second, _rbBufferGroups); } ++playerCounter; - RBPacketAppendPlayer(sitr->second, buffer_players); + RBPacketAppendPlayer(sitr->second, _rbBufferPlayers); } - if (!deletedGroupsToErase.empty()) + if (!_rbDeletedGroupsToErase.empty()) { - for (ObjectGuid const& toErase : deletedGroupsToErase) + for (ObjectGuid const& toErase : _rbDeletedGroupsToErase) { - deletedGroups.erase(toErase); + _rbDeletedGroups.erase(toErase); } } - if (!deletedGroups.empty()) + if (!_rbDeletedGroups.empty()) { - for (ObjectGuid const& deletedGroup : deletedGroups) + for (ObjectGuid const& deletedGroup : _rbDeletedGroups) { ++deletedCounter; - buffer_deleted << deletedGroup; + _rbBufferDeleted << deletedGroup; } } WorldPacket differencePacket(SMSG_UPDATE_LFG_LIST, 1000); - RBPacketBuildDifference(differencePacket, dungeonId, deletedCounter, buffer_deleted, groupCounter, buffer_groups, playerCounter, buffer_players); + RBPacketBuildDifference(differencePacket, dungeonId, deletedCounter, _rbBufferDeleted, groupCounter, _rbBufferGroups, playerCounter, _rbBufferPlayers); WorldPacket fullPacket(SMSG_UPDATE_LFG_LIST, 1000); - RBPacketBuildFull(fullPacket, dungeonId, copy); + RBPacketBuildFull(fullPacket, dungeonId, _rbCopy); RBCacheStore[team][dungeonId] = fullPacket; - prevInternalInfoMap = copy; + prevInternalInfoMap = _rbCopy; currInternalInfoMap.clear(); if (entryInfoMap.empty()) @@ -1403,44 +1388,44 @@ namespace lfg buffer << (uint32)info.encounterMask; } - void LFGMgr::RBPacketBuildDifference(WorldPacket& differencePacket, uint32 dungeonId, uint32 deletedCounter, ByteBuffer& buffer_deleted, uint32 groupCounter, ByteBuffer& buffer_groups, uint32 playerCounter, ByteBuffer& buffer_players) + void LFGMgr::RBPacketBuildDifference(WorldPacket& differencePacket, uint32 dungeonId, uint32 deletedCounter, ByteBuffer const& bufferDeleted, uint32 groupCounter, ByteBuffer const& bufferGroups, uint32 playerCounter, ByteBuffer const& bufferPlayers) { differencePacket << (uint32)LFG_TYPE_RAID; differencePacket << (uint32)dungeonId; differencePacket << (uint8)1; differencePacket << (uint32)deletedCounter; - differencePacket.append(buffer_deleted); + differencePacket.append(bufferDeleted); differencePacket << (uint32)groupCounter; differencePacket << (uint32)0; - differencePacket.append(buffer_groups); + differencePacket.append(bufferGroups); differencePacket << (uint32)playerCounter; differencePacket << (uint32)0; - differencePacket.append(buffer_players); + differencePacket.append(bufferPlayers); } - void LFGMgr::RBPacketBuildFull(WorldPacket& fullPacket, uint32 dungeonId, RBInternalInfoMap& infoMap) + void LFGMgr::RBPacketBuildFull(WorldPacket& fullPacket, uint32 dungeonId, RBInternalInfoMap const& infoMap) { fullPacket << (uint32)LFG_TYPE_RAID; fullPacket << (uint32)dungeonId; fullPacket << (uint8)0; uint32 groupCounter = 0, playerCounter = 0; - ByteBuffer buffer_groups, buffer_players; + ByteBuffer bufferGroups, bufferPlayers; for (RBInternalInfoMap::const_iterator itr = infoMap.begin(); itr != infoMap.end(); ++itr) { if (itr->second.isGroupLeader) { ++groupCounter; - RBPacketAppendGroup(itr->second, buffer_groups); + RBPacketAppendGroup(itr->second, bufferGroups); } ++playerCounter; - RBPacketAppendPlayer(itr->second, buffer_players); + RBPacketAppendPlayer(itr->second, bufferPlayers); } fullPacket << (uint32)groupCounter; fullPacket << (uint32)0; - fullPacket.append(buffer_groups); + fullPacket.append(bufferGroups); fullPacket << (uint32)playerCounter; fullPacket << (uint32)0; - fullPacket.append(buffer_players); + fullPacket.append(bufferPlayers); } // pussywizard: diff --git a/src/server/game/DungeonFinding/LFGMgr.h b/src/server/game/DungeonFinding/LFGMgr.h index 2164de0595..358c5802a5 100644 --- a/src/server/game/DungeonFinding/LFGMgr.h +++ b/src/server/game/DungeonFinding/LFGMgr.h @@ -20,6 +20,7 @@ #include +#include "ByteBuffer.h" #include "DBCStructure.h" #include "Field.h" #include "LFG.h" @@ -562,8 +563,8 @@ namespace lfg void SendRaidBrowserJoinedPacket(Player* p, LfgDungeonSet& dungeons, std::string comment); void RBPacketAppendGroup(const RBInternalInfo& info, ByteBuffer& buffer); void RBPacketAppendPlayer(const RBInternalInfo& info, ByteBuffer& buffer); - void RBPacketBuildDifference(WorldPacket& differencePacket, uint32 dungeonId, uint32 deletedCounter, ByteBuffer& buffer_deleted, uint32 groupCounter, ByteBuffer& buffer_groups, uint32 playerCounter, ByteBuffer& buffer_players); - void RBPacketBuildFull(WorldPacket& fullPacket, uint32 dungeonId, RBInternalInfoMap& infoMap); + void RBPacketBuildDifference(WorldPacket& differencePacket, uint32 dungeonId, uint32 deletedCounter, ByteBuffer const& bufferDeleted, uint32 groupCounter, ByteBuffer const& bufferGroups, uint32 playerCounter, ByteBuffer const& bufferPlayers); + void RBPacketBuildFull(WorldPacket& fullPacket, uint32 dungeonId, RBInternalInfoMap const& infoMap); // LfgQueue /// Get last lfg state (NONE, DUNGEON or FINISHED_DUNGEON) @@ -627,6 +628,12 @@ namespace lfg uint32 lastProposalId; ///< pussywizard, store it here because of splitting LFGMgr update into tasks uint32 m_raidBrowserUpdateTimer[2]; ///< pussywizard uint32 m_raidBrowserLastUpdatedDungeonId[2]; ///< pussywizard: for 2 factions + ByteBuffer _rbBufferDeleted; + ByteBuffer _rbBufferGroups; + ByteBuffer _rbBufferPlayers; + GuidSet _rbDeletedGroups; + GuidSet _rbDeletedGroupsToErase; + RBInternalInfoMap _rbCopy; LfgQueueContainer QueuesStore; ///< Queues LfgCachedDungeonContainer CachedDungeonMapStore; ///< Stores all dungeons by groupType diff --git a/src/server/game/DungeonFinding/LFGQueue.cpp b/src/server/game/DungeonFinding/LFGQueue.cpp index a7890fc9f6..b45d7a0c5e 100644 --- a/src/server/game/DungeonFinding/LFGQueue.cpp +++ b/src/server/game/DungeonFinding/LFGQueue.cpp @@ -374,7 +374,7 @@ namespace lfg LfgDungeonSet temporal; LfgDungeonSet& dungeons = QueueDataStore[check.guids[i]].dungeons; std::set_intersection(proposalDungeons.begin(), proposalDungeons.end(), dungeons.begin(), dungeons.end(), std::inserter(temporal, temporal.begin())); - proposalDungeons = temporal; + std::swap(proposalDungeons, temporal); } if (proposalDungeons.empty())