Skip to content

Commit e609c5c

Browse files
fix: queue system
1 parent 71110c2 commit e609c5c

2 files changed

Lines changed: 135 additions & 20 deletions

File tree

src/BgAutoQueue.cpp

Lines changed: 108 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -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

345404
BattlegroundTypeId 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

src/BgAutoQueue.h

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -118,15 +118,37 @@ class BgAutoQueue
118118
// True when the player can be queued into bgTypeId at their level.
119119
bool CanEnter(Player* player, BattlegroundTypeId bgTypeId) const;
120120

121-
// True when every player in the bucket passes CanEnter for bgTypeId.
122-
bool IsBracketEligible(BattlegroundTypeId bgTypeId, BracketBucket const& bucket) const;
121+
// True when at least one bucket player can be queued into bgTypeId at their
122+
// level (subset-friendly; QueueBucket skips the rest at queue time).
123+
bool BucketHasAnyFit(BattlegroundTypeId bgTypeId, BracketBucket const& bucket) const;
124+
125+
// True when at least one bucket player resolves, on this live game's own map,
126+
// to this game's own bracket and has BG access for its type.
127+
bool BucketFitsLiveBg(Battleground* bg, BracketBucket const& bucket) const;
128+
129+
struct QueuedWaiters
130+
{
131+
uint32 total = 0;
132+
uint32 alliance = 0;
133+
uint32 horde = 0;
134+
};
135+
136+
// Counts uninvited players already sitting in bgTypeId's core queue for this
137+
// bracket, split by faction. Scans every solo/premade/cross-faction group
138+
// bucket because which bucket a manual queuer lands in depends on whether
139+
// mod-cfbg is active. Groups already invited to a forming instance are skipped.
140+
QueuedWaiters CountUninvitedWaiters(BattlegroundTypeId bgTypeId,
141+
BattlegroundBracketId bracketId) const;
123142

124143
// Viability per CrossFaction: cross-faction => total >= 2*min; otherwise
125-
// each faction tally >= min.
126-
bool IsViable(Battleground* bgTemplate, BracketBucket const& bucket) const;
144+
// each faction tally >= min. Includes uninvited players already queued for
145+
// the candidate BG in this bracket, not just the freshly-gathered batch.
146+
bool IsViable(Battleground* bgTemplate, BracketBucket const& bucket,
147+
BattlegroundBracketId bracketId) const;
127148

128149
// Selects the BG for a populated bracket: live-BG reinforcement first,
129-
// then a random pick from the configured pool with documented fallbacks.
150+
// then a not-yet-running BG that already has uninvited queuers, then a
151+
// random pick from the configured pool with documented fallbacks.
130152
BattlegroundTypeId SelectBattlegroundForBracket(BattlegroundBracketId bracketId,
131153
BracketBucket const& bucket) const;
132154

0 commit comments

Comments
 (0)