fix(Core/Battlegrounds): aggregate BG queue announcer on burst (#26086)

This commit is contained in:
Francesco Borzì
2026-06-07 16:20:29 +02:00
committed by GitHub
parent 4a940e4983
commit 4d26913310
5 changed files with 90 additions and 37 deletions
+1
View File
@@ -2,6 +2,7 @@
# AzerothCore # AzerothCore
# #
.cache
/conf/* /conf/*
!/conf/dist !/conf/dist
/modules/* /modules/*
@@ -1039,42 +1039,43 @@ void BattlegroundQueue::BattlegroundQueueAnnouncerUpdate(uint32 diff, Battlegrou
return; return;
} }
if (sWorld->getBoolConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_TIMED)) // Armed per-bracket timer drives both Timed mode and the deferred immediate
{ // announcement; the spam-window/Limit throttle gates only immediate mode.
uint32 qPlayers = 0; bool const isTimed = sWorld->getBoolConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_TIMED);
if (_queueAnnouncementCrossfactioned) uint32 qPlayers = 0;
if (_queueAnnouncementCrossfactioned)
qPlayers = GetPlayersCountInGroupsQueue(bracket_id, BG_QUEUE_CFBG);
else
qPlayers = GetPlayersCountInGroupsQueue(bracket_id, BG_QUEUE_NORMAL_HORDE) + GetPlayersCountInGroupsQueue(bracket_id, BG_QUEUE_NORMAL_ALLIANCE);
if (!qPlayers)
{
_queueAnnouncementTimer[bracket_id] = -1;
return;
}
if (_queueAnnouncementTimer[bracket_id] >= 0)
{
if (_queueAnnouncementTimer[bracket_id] <= static_cast<int32>(diff))
{ {
qPlayers = GetPlayersCountInGroupsQueue(bracket_id, BG_QUEUE_CFBG); _queueAnnouncementTimer[bracket_id] = -1;
uint32 q_min_level = std::min(bracketEntry->minLevel, (uint32) 80);
if (!isTimed && !sBGSpam->CanAnnounce(bg_template, bracket_id, q_min_level, qPlayers))
return;
auto bgName = bg_template->GetName();
uint32 MaxPlayers = GetMinPlayersPerTeam(bg_template, bracketEntry) * 2;
uint32 q_max_level = std::min(bracketEntry->maxLevel, (uint32) 80);
ChatHandler(nullptr).SendWorldTextOptional(LANG_BG_QUEUE_ANNOUNCE_WORLD, ANNOUNCER_FLAG_DISABLE_BG_QUEUE, bgName.c_str(), q_min_level, q_max_level, qPlayers, MaxPlayers);
} }
else else
{ {
qPlayers = GetPlayersCountInGroupsQueue(bracket_id, BG_QUEUE_NORMAL_HORDE) + GetPlayersCountInGroupsQueue(bracket_id, BG_QUEUE_NORMAL_ALLIANCE); _queueAnnouncementTimer[bracket_id] -= static_cast<int32>(diff);
}
if (!qPlayers)
{
_queueAnnouncementTimer[bracket_id] = -1;
return;
}
if (_queueAnnouncementTimer[bracket_id] >= 0)
{
if (_queueAnnouncementTimer[bracket_id] <= static_cast<int32>(diff))
{
_queueAnnouncementTimer[bracket_id] = -1;
auto bgName = bg_template->GetName();
uint32 MaxPlayers = GetMinPlayersPerTeam(bg_template, bracketEntry) * 2;
uint32 q_min_level = std::min(bracketEntry->minLevel, (uint32) 80);
uint32 q_max_level = std::min(bracketEntry->maxLevel, (uint32) 80);
ChatHandler(nullptr).SendWorldTextOptional(LANG_BG_QUEUE_ANNOUNCE_WORLD, ANNOUNCER_FLAG_DISABLE_BG_QUEUE, bgName.c_str(), q_min_level, q_max_level, qPlayers, MaxPlayers);
}
else
{
_queueAnnouncementTimer[bracket_id] -= static_cast<int32>(diff);
}
} }
} }
} }
@@ -1145,12 +1146,10 @@ void BattlegroundQueue::SendMessageBGQueue(Player* leader, Battleground* bg, PvP
} }
else else
{ {
if (!sBGSpam->CanAnnounce(leader, bg, q_min_level, qTotal)) // Arm the per-bracket debounce; first join arms, rest are no-ops.
{ // BattlegroundQueueAnnouncerUpdate emits the aggregated line later.
return; if (_queueAnnouncementTimer[bracketId] < 0)
} SetQueueAnnouncementTimer(bracketId, BG_QUEUE_ANNOUNCER_IMMEDIATE_DEBOUNCE, false);
ChatHandler(nullptr).SendWorldTextOptional(LANG_BG_QUEUE_ANNOUNCE_WORLD, ANNOUNCER_FLAG_DISABLE_BG_QUEUE, bgName.c_str(), q_min_level, q_max_level, qAlliance + qHorde, MaxPlayers);
} }
} }
} }
@@ -27,6 +27,10 @@
constexpr auto COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME = 10; constexpr auto COUNT_OF_PLAYERS_TO_AVERAGE_WAIT_TIME = 10;
// Immediate-mode announcer debounce (ms): fires on the next periodic pass, by
// which point a same-tick queue burst has collapsed into one aggregated line.
constexpr int32 BG_QUEUE_ANNOUNCER_IMMEDIATE_DEBOUNCE = 1;
struct GroupQueueInfo // stores information about the group in queue (also used when joined as solo!) struct GroupQueueInfo // stores information about the group in queue (also used when joined as solo!)
{ {
GuidSet Players; // player guid set GuidSet Players; // player guid set
@@ -25,6 +25,7 @@
namespace namespace
{ {
std::unordered_map<ObjectGuid /*player guid*/, uint32 /*time*/> _players; std::unordered_map<ObjectGuid /*player guid*/, uint32 /*time*/> _players;
std::unordered_map<uint32 /*bracket+bg key*/, uint32 /*time*/> _brackets;
void AddTime(ObjectGuid guid) void AddTime(ObjectGuid guid)
{ {
@@ -47,6 +48,26 @@ namespace
// Skip if spam time < 30 secs (default) // Skip if spam time < 30 secs (default)
return GameTime::GetGameTime().count() - GetTime(guid) >= sWorld->getIntConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_SPAM_DELAY); return GameTime::GetGameTime().count() - GetTime(guid) >= sWorld->getIntConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_SPAM_DELAY);
} }
void AddTime(uint32 key)
{
_brackets.insert_or_assign(key, GameTime::GetGameTime().count());
}
uint32 GetTime(uint32 key)
{
auto const& itr = _brackets.find(key);
if (itr != _brackets.end())
return itr->second;
return 0;
}
bool IsCorrectDelay(uint32 key)
{
// Skip if spam time < 30 secs (default)
return GameTime::GetGameTime().count() - GetTime(key) >= sWorld->getIntConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_SPAM_DELAY);
}
} }
BGSpamProtect* BGSpamProtect::instance() BGSpamProtect* BGSpamProtect::instance()
@@ -84,3 +105,29 @@ bool BGSpamProtect::CanAnnounce(Player* player, Battleground* bg, uint32 minLeve
AddTime(guid); AddTime(guid);
return true; return true;
} }
bool BGSpamProtect::CanAnnounce(Battleground* bg, BattlegroundBracketId bracketId, uint32 minLevel, uint32 queueTotal)
{
if (!bg)
return false;
uint32 key = uint32(bg->GetBgTypeID()) * MAX_BATTLEGROUND_BRACKETS + uint32(bracketId);
// Check prev time
if (!IsCorrectDelay(key))
return false;
// When limited, it announces only if there are at least CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_LIMIT_MIN_PLAYERS in queue
auto limitQueueMinLevel = sWorld->getIntConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_LIMIT_MIN_LEVEL);
if (limitQueueMinLevel && minLevel >= limitQueueMinLevel)
{
// limit only RBG for 80, WSG for lower levels
auto bgTypeToLimit = minLevel == 80 ? BATTLEGROUND_RB : BATTLEGROUND_WS;
if (bg->GetBgTypeID() == bgTypeToLimit && queueTotal < sWorld->getIntConfig(CONFIG_BATTLEGROUND_QUEUE_ANNOUNCER_LIMIT_MIN_PLAYERS))
return false;
}
AddTime(key);
return true;
}
@@ -19,6 +19,7 @@
#define _BATTLEGROUND_SPAM_PROTECT_H_ #define _BATTLEGROUND_SPAM_PROTECT_H_
#include "Define.h" #include "Define.h"
#include "DBCEnums.h"
class Player; class Player;
class Battleground; class Battleground;
@@ -29,6 +30,7 @@ public:
static BGSpamProtect* instance(); static BGSpamProtect* instance();
bool CanAnnounce(Player* player, Battleground* bg, uint32 minLevel, uint32 queueTotal); bool CanAnnounce(Player* player, Battleground* bg, uint32 minLevel, uint32 queueTotal);
bool CanAnnounce(Battleground* bg, BattlegroundBracketId bracketId, uint32 minLevel, uint32 queueTotal);
}; };
#define sBGSpam BGSpamProtect::instance() #define sBGSpam BGSpamProtect::instance()