From 8d8e5df0e4b4b944efe5936613f388e1144fdd88 Mon Sep 17 00:00:00 2001 From: FrancescoBorzi Date: Thu, 2 Jul 2026 16:48:35 +0200 Subject: [PATCH 1/2] fix: real-faction waiter counts and CrossFaction matcher docs/warning CountUninvitedWaiters split waiter counts by gInfo->teamId, which CFBG staging overwrites on every staging attempt and does not restore on failure, so with CrossFaction = 0 per-faction viability drifted across passes. Split by RealTeamID instead, which the core writes exactly once at queue join and never mutates. Also warn once per config load when CrossFaction = 1 runs without an active cross-faction matcher (uninvited players sitting in a faction-specific NORMAL bucket can never pop on a stock core), and document the matcher coupling in conf.dist and the README. --- README.md | 9 ++++++++- conf/mod-bg-auto-queue.conf.dist | 8 ++++++++ src/BgAutoQueue.cpp | 20 ++++++++++++++++---- src/BgAutoQueue.h | 6 +++++- 4 files changed, 37 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index ab748eb..993f4f4 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,13 @@ commands — see **[docs/how-it-works.md](docs/how-it-works.md)**. ## Interactions with other systems +- **Cross-faction matcher (mod-cfbg).** `BgAutoQueue.CrossFaction = 1` judges + viability on the total player count and assumes a cross-faction matcher such + as [mod-cfbg](https://github.com/azerothcore/mod-cfbg) fills both teams. On a + stock core the queue itself still requires the minimum in each faction, so + mode 1 can queue faction-lopsided batches that never pop; set + `CrossFaction = 0` there. The module logs a warning when it detects this + misconfiguration. - **Deserter tracking noise.** If `Battleground.TrackDeserters.Enable` is enabled, players who decline auto-queue invites may appear in the deserter tracking table. This is informational only, not a player-facing penalty. @@ -82,7 +89,7 @@ All options are documented in `conf/mod-bg-auto-queue.conf.dist`: - `BgAutoQueue.InitialDelay` — seconds before the first pass after startup/reload. - `BgAutoQueue.WarningLeadTime` — seconds before a pass to broadcast the warning. - `BgAutoQueue.BroadcastMessage` — the warning text (empty disables it). -- `BgAutoQueue.CrossFaction` — how the available count is judged against a BG's minimum players per team. +- `BgAutoQueue.CrossFaction` — how the available count is judged against a BG's minimum players per team; `1` requires a cross-faction matcher such as mod-cfbg (see "Interactions with other systems"). - `BgAutoQueue.SkipGameMasters` — skip GMs in the warning and the queueing. ## Commands diff --git a/conf/mod-bg-auto-queue.conf.dist b/conf/mod-bg-auto-queue.conf.dist index 149aade..73259b7 100644 --- a/conf/mod-bg-auto-queue.conf.dist +++ b/conf/mod-bg-auto-queue.conf.dist @@ -114,7 +114,15 @@ BgAutoQueue.BroadcastMessage = "A Battleground event is starting shortly. Type . # Description: How the available player count is judged against a # battleground's minimum players per team when several # pool candidates exist. +# Mode 1 assumes a cross-faction matcher (such as +# mod-cfbg) is installed and active. On a stock core the +# queue itself still requires the minimum in EACH +# faction, so mode 1 can queue faction-lopsided batches +# that never pop; players stay queued until enough +# minority-faction players appear. Without a +# cross-faction matcher, set this to 0. # Default: 1 - Cross-faction: total players >= 2 x MinPlayersPerTeam +# (requires a cross-faction matcher such as mod-cfbg) # 0 - Vanilla: Alliance >= min AND Horde >= min # diff --git a/src/BgAutoQueue.cpp b/src/BgAutoQueue.cpp index 65dac1d..9630e08 100644 --- a/src/BgAutoQueue.cpp +++ b/src/BgAutoQueue.cpp @@ -128,9 +128,10 @@ void BgAutoQueue::LoadConfig() } // Reset timing on (re)load. Reload re-applies InitialDelay — accepted. - _elapsedMs = 0; - _warningSent = false; - _firstPass = true; + _elapsedMs = 0; + _warningSent = false; + _firstPass = true; + _matcherWarnLogged = false; LOG_INFO("module", "mod-bg-auto-queue: enabled={}, levels=[{}-{}], pool size={}, interval={} min, initialDelay={} s, warningLead={} s, crossFaction={}, skipGM={}, skipAFK={}, skipAuras={}.", _enabled, _levelMin, _levelMax, _poolRaw.size(), intervalMin, initialDelaySec, warningLeadSec, _crossFaction, _skipGameMasters, _skipAfk, _skipAuras.size()); @@ -376,9 +377,20 @@ BgAutoQueue::QueuedWaiters BgAutoQueue::CountUninvitedWaiters(BattlegroundTypeId if (gInfo->IsInvitedToBGInstanceGUID != 0) continue; + if (_crossFaction && !_matcherWarnLogged + && (groupType == BG_QUEUE_NORMAL_ALLIANCE || groupType == BG_QUEUE_NORMAL_HORDE)) + { + LOG_WARN("module", "mod-bg-auto-queue: BgAutoQueue.CrossFaction = 1 but uninvited " + "players sit in a faction-specific queue bucket, so no cross-faction matcher " + "(e.g. mod-cfbg) appears to be active. Total-based viability can queue " + "faction-lopsided batches the core queue never pops. Set " + "BgAutoQueue.CrossFaction = 0 on a stock core."); + _matcherWarnLogged = true; + } + uint32 const count = static_cast(gInfo->Players.size()); waiters.total += count; - if (gInfo->teamId == TEAM_ALLIANCE) + if (gInfo->RealTeamID == TEAM_ALLIANCE) waiters.alliance += count; else waiters.horde += count; diff --git a/src/BgAutoQueue.h b/src/BgAutoQueue.h index 1b21105..e5120bf 100644 --- a/src/BgAutoQueue.h +++ b/src/BgAutoQueue.h @@ -134,7 +134,8 @@ class BgAutoQueue }; // Counts uninvited players already sitting in bgTypeId's core queue for this - // bracket, split by faction. Scans every solo/premade/cross-faction group + // bracket, split by the players' real faction (RealTeamID, immune to CFBG's + // staging mutations of teamId). Scans every solo/premade/cross-faction group // bucket because which bucket a manual queuer lands in depends on whether // mod-cfbg is active. Groups already invited to a forming instance are skipped. QueuedWaiters CountUninvitedWaiters(BattlegroundTypeId bgTypeId, @@ -184,6 +185,9 @@ class BgAutoQueue uint32 _elapsedMs = 0; bool _warningSent = false; bool _firstPass = true; + // Latches the CrossFaction/matcher WARN to once per config load (mutable: + // CountUninvitedWaiters is const). + mutable bool _matcherWarnLogged = false; }; #define sBgAutoQueue BgAutoQueue::instance() From d861503e43bd52c42732b2822e2794c8de60062f Mon Sep 17 00:00:00 2001 From: FrancescoBorzi Date: Thu, 2 Jul 2026 16:48:52 +0200 Subject: [PATCH 2/2] fix: warn when WarningLeadTime >= InitialDelay LoadConfig warned when WarningLeadTime swallowed the Interval half of the warning window but not the InitialDelay half: with 0 < InitialDelay <= WarningLeadTime the first pass silently queues everyone without the advertised broadcast. Log-only; default configs (InitialDelay = 0) stay silent. --- src/BgAutoQueue.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/BgAutoQueue.cpp b/src/BgAutoQueue.cpp index 9630e08..71eb3af 100644 --- a/src/BgAutoQueue.cpp +++ b/src/BgAutoQueue.cpp @@ -108,6 +108,9 @@ void BgAutoQueue::LoadConfig() if (_intervalMs > 0 && _warningLeadMs >= _intervalMs) LOG_WARN("module", "BgAutoQueue.WarningLeadTime ({} s) >= Interval ({} min); the warning will not fire.", warningLeadSec, intervalMin); + if (_initialDelayMs > 0 && _warningLeadMs >= _initialDelayMs) + LOG_WARN("module", "BgAutoQueue.WarningLeadTime ({} s) >= InitialDelay ({} s); no warning will fire before the first pass.", warningLeadSec, initialDelaySec); + _crossFaction = sConfigMgr->GetOption("BgAutoQueue.CrossFaction", true); _skipGameMasters = sConfigMgr->GetOption("BgAutoQueue.SkipGameMasters", true); _skipAfk = sConfigMgr->GetOption("BgAutoQueue.SkipAFK", true);