@@ -320,26 +320,85 @@ bool BgAutoQueue::CanEnter(Player* player, BattlegroundTypeId bgTypeId) const
320320 return GetBattlegroundBracketByLevel (bgTemplate->GetMapId (), player->GetLevel ()) != nullptr ;
321321}
322322
323- bool BgAutoQueue::IsBracketEligible (BattlegroundTypeId bgTypeId, BracketBucket const & bucket) const
323+ bool BgAutoQueue::BucketHasAnyFit (BattlegroundTypeId bgTypeId, BracketBucket const & bucket) const
324324{
325325 for (ObjectGuid guid : bucket.players )
326326 {
327327 Player* player = ObjectAccessor::FindPlayer (guid);
328- if (! player || ! CanEnter (player, bgTypeId))
329- return false ;
328+ if (player && CanEnter (player, bgTypeId))
329+ return true ;
330330 }
331331
332- return true ;
332+ return false ;
333+ }
334+
335+ bool BgAutoQueue::BucketFitsLiveBg (Battleground* bg, BracketBucket const & bucket) const
336+ {
337+ BattlegroundTypeId const bgTypeId = bg->GetBgTypeID ();
338+ for (ObjectGuid guid : bucket.players )
339+ {
340+ Player* player = ObjectAccessor::FindPlayer (guid);
341+ if (!player || !player->GetBGAccessByLevel (bgTypeId))
342+ continue ;
343+
344+ PvPDifficultyEntry const * entry = GetBattlegroundBracketByLevel (bg->GetMapId (), player->GetLevel ());
345+ if (entry && entry->GetBracketId () == bg->GetBracketId ())
346+ return true ;
347+ }
348+
349+ return false ;
333350}
334351
335- bool BgAutoQueue::IsViable (Battleground* bgTemplate, BracketBucket const & bucket) const
352+ BgAutoQueue::QueuedWaiters BgAutoQueue::CountUninvitedWaiters (BattlegroundTypeId bgTypeId,
353+ BattlegroundBracketId bracketId) const
354+ {
355+ QueuedWaiters waiters;
356+
357+ BattlegroundQueueTypeId bgQueueTypeId = BattlegroundMgr::BGQueueTypeId (bgTypeId, 0 );
358+ if (bgQueueTypeId == BATTLEGROUND_QUEUE_NONE )
359+ return waiters;
360+
361+ BattlegroundQueue& bgQueue = sBattlegroundMgr ->GetBattlegroundQueue (bgQueueTypeId);
362+
363+ static constexpr BattlegroundQueueGroupTypes WAITER_GROUP_TYPES [] =
364+ {
365+ BG_QUEUE_PREMADE_ALLIANCE ,
366+ BG_QUEUE_PREMADE_HORDE ,
367+ BG_QUEUE_NORMAL_ALLIANCE ,
368+ BG_QUEUE_NORMAL_HORDE ,
369+ BG_QUEUE_CFBG
370+ };
371+
372+ for (BattlegroundQueueGroupTypes groupType : WAITER_GROUP_TYPES )
373+ {
374+ for (GroupQueueInfo const * gInfo : bgQueue.m_QueuedGroups [bracketId][groupType])
375+ {
376+ if (gInfo ->IsInvitedToBGInstanceGUID != 0 )
377+ continue ;
378+
379+ uint32 const count = static_cast <uint32>(gInfo ->Players .size ());
380+ waiters.total += count;
381+ if (gInfo ->teamId == TEAM_ALLIANCE )
382+ waiters.alliance += count;
383+ else
384+ waiters.horde += count;
385+ }
386+ }
387+
388+ return waiters;
389+ }
390+
391+ bool BgAutoQueue::IsViable (Battleground* bgTemplate, BracketBucket const & bucket,
392+ BattlegroundBracketId bracketId) const
336393{
337394 uint32 const minPerTeam = bgTemplate->GetMinPlayersPerTeam ();
395+ QueuedWaiters const waiters = CountUninvitedWaiters (bgTemplate->GetBgTypeID (), bracketId);
338396
339397 if (_crossFaction)
340- return (bucket.alliance + bucket.horde ) >= (2u * minPerTeam);
398+ return (bucket.alliance + bucket.horde + waiters. total ) >= (2u * minPerTeam);
341399
342- return bucket.alliance >= minPerTeam && bucket.horde >= minPerTeam;
400+ return (bucket.alliance + waiters.alliance ) >= minPerTeam
401+ && (bucket.horde + waiters.horde ) >= minPerTeam;
343402}
344403
345404BattlegroundTypeId BgAutoQueue::SelectBattlegroundForBracket (BattlegroundBracketId bracketId, BracketBucket const & bucket) const
@@ -351,20 +410,20 @@ BattlegroundTypeId BgAutoQueue::SelectBattlegroundForBracket(BattlegroundBracket
351410 if (sDisableMgr ->IsDisabledFor (DISABLE_TYPE_BATTLEGROUND , bgTypeId, nullptr ))
352411 continue ;
353412
354- if (!IsBracketEligible (bgTypeId, bucket))
355- continue ;
356-
357413 for (Battleground* bg : sBattlegroundMgr ->GetBGFreeSlotQueueStore (bgTypeId))
358414 {
359- if (bg->GetBracketId () != bracketId)
360- continue ;
361-
362415 if (!(bg->GetStatus () > STATUS_WAIT_QUEUE && bg->GetStatus () < STATUS_WAIT_LEAVE ))
363416 continue ;
364417
365418 if (!bg->HasFreeSlots ())
366419 continue ;
367420
421+ // Match each live game by its own map-relative bracket, reinforced by
422+ // whichever subset of bucket players fits it (off-boundary players are
423+ // skipped at queue time, not blocking the whole game).
424+ if (!BucketFitsLiveBg (bg, bucket))
425+ continue ;
426+
368427 liveTypes.push_back (bgTypeId);
369428 break ;
370429 }
@@ -373,14 +432,48 @@ BattlegroundTypeId BgAutoQueue::SelectBattlegroundForBracket(BattlegroundBracket
373432 if (!liveTypes.empty ())
374433 return Acore::Containers::SelectRandomContainerElement (liveTypes);
375434
435+ // (a2) Prefer a not-yet-running BG that already has uninvited queuers, so a
436+ // manual queuer's chosen BG is reinforced instead of bypassed. Among viable
437+ // candidates pick the one closest to popping (most waiters); ties at random.
438+ std::vector<BattlegroundTypeId> waiterLeaders;
439+ uint32 bestWaiters = 0 ;
440+ for (BattlegroundTypeId bgTypeId : BG_NORMAL_TYPES )
441+ {
442+ if (sDisableMgr ->IsDisabledFor (DISABLE_TYPE_BATTLEGROUND , bgTypeId, nullptr ))
443+ continue ;
444+
445+ if (!BucketHasAnyFit (bgTypeId, bucket))
446+ continue ;
447+
448+ QueuedWaiters const waiters = CountUninvitedWaiters (bgTypeId, bracketId);
449+ if (waiters.total == 0 )
450+ continue ;
451+
452+ Battleground* bgTemplate = sBattlegroundMgr ->GetBattlegroundTemplate (bgTypeId);
453+ if (!bgTemplate || !IsViable (bgTemplate, bucket, bracketId))
454+ continue ;
455+
456+ if (waiters.total > bestWaiters)
457+ {
458+ bestWaiters = waiters.total ;
459+ waiterLeaders.clear ();
460+ waiterLeaders.push_back (bgTypeId);
461+ }
462+ else if (waiters.total == bestWaiters)
463+ waiterLeaders.push_back (bgTypeId);
464+ }
465+
466+ if (!waiterLeaders.empty ())
467+ return Acore::Containers::SelectRandomContainerElement (waiterLeaders);
468+
376469 // (b) Random pick from the configured pool.
377470 std::vector<BattlegroundTypeId> candidates;
378471 for (BattlegroundTypeId bgTypeId : _pool)
379472 {
380473 if (sDisableMgr ->IsDisabledFor (DISABLE_TYPE_BATTLEGROUND , bgTypeId, nullptr ))
381474 continue ;
382475
383- if (IsBracketEligible (bgTypeId, bucket))
476+ if (BucketHasAnyFit (bgTypeId, bucket))
384477 candidates.push_back (bgTypeId);
385478 }
386479
@@ -394,7 +487,7 @@ BattlegroundTypeId BgAutoQueue::SelectBattlegroundForBracket(BattlegroundBracket
394487 for (BattlegroundTypeId bgTypeId : candidates)
395488 {
396489 Battleground* bgTemplate = sBattlegroundMgr ->GetBattlegroundTemplate (bgTypeId);
397- if (bgTemplate && IsViable (bgTemplate, bucket))
490+ if (bgTemplate && IsViable (bgTemplate, bucket, bracketId ))
398491 viable.push_back (bgTypeId);
399492 }
400493
0 commit comments