fix(Core/Battlegrounds): fix invited-count accounting on BG entry (#26556)

This commit is contained in:
Francesco Borzì
2026-07-11 22:32:41 +02:00
committed by GitHub
parent 8e48af8091
commit 82f87a8b82
5 changed files with 54 additions and 12 deletions

View File

@@ -647,7 +647,7 @@ void BattlegroundMgr::BuildBattlegroundListPacket(WorldPacket* data, ObjectGuid
}
}
void BattlegroundMgr::SendToBattleground(Player* player, uint32 instanceId, BattlegroundTypeId bgTypeId)
bool BattlegroundMgr::SendToBattleground(Player* player, uint32 instanceId, BattlegroundTypeId bgTypeId)
{
if (Battleground* bg = GetBattleground(instanceId, bgTypeId))
{
@@ -655,12 +655,11 @@ void BattlegroundMgr::SendToBattleground(Player* player, uint32 instanceId, Batt
Position const* pos = bg->GetTeamStartPosition(player->GetBgTeamId());
LOG_DEBUG("bg.battleground", "BattlegroundMgr::SendToBattleground: Sending {} to map {}, {} (bgType {})", player->GetName(), mapid, pos->ToString(), bgTypeId);
player->TeleportTo(mapid, pos->GetPositionX(), pos->GetPositionY(), pos->GetPositionZ(), pos->GetOrientation());
}
else
{
LOG_ERROR("bg.battleground", "BattlegroundMgr::SendToBattleground: Instance {} (bgType {}) not found while trying to teleport player {}", instanceId, bgTypeId, player->GetName());
return player->TeleportTo(mapid, pos->GetPositionX(), pos->GetPositionY(), pos->GetPositionZ(), pos->GetOrientation());
}
LOG_ERROR("bg.battleground", "BattlegroundMgr::SendToBattleground: Instance {} (bgType {}) not found while trying to teleport player {}", instanceId, bgTypeId, player->GetName());
return false;
}
void BattlegroundMgr::SendAreaSpiritHealerQueryOpcode(Player* player, Battleground* bg, ObjectGuid guid)

View File

@@ -93,7 +93,10 @@ public:
void LoadBattlegroundTemplates();
void DeleteAllBattlegrounds();
void SendToBattleground(Player* player, uint32 InstanceID, BattlegroundTypeId bgTypeId);
// Returns false when the teleport could not start (instance gone, or a
// synchronous TeleportTo failure) so the accept path can release the
// otherwise-orphaned invited reservation.
bool SendToBattleground(Player* player, uint32 InstanceID, BattlegroundTypeId bgTypeId);
/* Battleground queues */
BattlegroundQueue& GetBattlegroundQueue(BattlegroundQueueTypeId bgQueueTypeId) { return m_BattlegroundQueues[bgQueueTypeId]; }

View File

@@ -1302,13 +1302,16 @@ int32 BattlegroundQueue::GetQueueAnnouncementTimer(uint32 bracketId) const
void BattlegroundQueue::InviteGroupToBG(GroupQueueInfo* ginfo, Battleground* bg, TeamId teamId)
{
// An already-invited group keeps the side it was invited under: writing
// teamId here would split a future re-invite's IncreaseInvitedCount from the
// original side's DecreaseInvitedCount at leave, desyncing the ledger.
if (ginfo->IsInvitedToBGInstanceGUID)
return;
// set side if needed
if (teamId != TEAM_NEUTRAL)
ginfo->teamId = teamId;
if (ginfo->IsInvitedToBGInstanceGUID)
return;
// set invitation
ginfo->IsInvitedToBGInstanceGUID = bg->GetInstanceID();

View File

@@ -544,7 +544,31 @@ void WorldSession::HandleBattleFieldPortOpcode(WorldPacket& recvData)
sLFGMgr->LeaveAllLfgQueues(_player->GetGUID(), false);
_player->SetBattlegroundId(bg->GetInstanceID(), bg->GetBgTypeID(), queueSlot, true, bgTypeId == BATTLEGROUND_RB, teamId);
sBattlegroundMgr->SendToBattleground(_player, ginfo.IsInvitedToBGInstanceGUID, bgTypeId);
if (!sBattlegroundMgr->SendToBattleground(_player, ginfo.IsInvitedToBGInstanceGUID, bgTypeId))
{
// The teleport never started (instance gone, or a synchronous
// TeleportTo veto such as a DK still locked to Ebon Hold). The accept
// already pulled the player out of the queue and he can't decline
// now, so undo the accept here -- otherwise the invited reservation
// leaks forever, permanently skewing team selection and blocking the
// empty instance's cleanup.
bg->DecreaseInvitedCount(teamId);
_player->RemoveBattlegroundQueueId(bgQueueTypeId);
_player->SetBattlegroundId(0, BATTLEGROUND_TYPE_NONE, PLAYER_MAX_BATTLEGROUND_QUEUES, false, false, TEAM_NEUTRAL);
sBattlegroundMgr->BuildBattlegroundStatusPacket(&data, bg, queueSlot, STATUS_NONE, 0, 0, 0, TEAM_NEUTRAL);
SendPacket(&data);
// Free slot -> let the queue refill it. BG only, like the sibling
// leave-queue path: an arena update needs its own type/rating.
if (!ginfo.ArenaType)
sBattlegroundMgr->ScheduleQueueUpdate(0, 0, bgQueueTypeId, bgTypeId, bracketEntry->GetBracketId());
LOG_ERROR("bg.battleground", "Battleground: player {} {} failed to teleport into bg {}, bgtype {}; released the invited reservation.",
_player->GetName(), _player->GetGUID().ToString(), bg->GetInstanceID(), bg->GetBgTypeID());
return;
}
LOG_DEBUG("bg.battleground", "Battleground: player {} {} joined battle for bg {}, bgtype {}, queue type {}.", _player->GetName(), _player->GetGUID().ToString(), bg->GetInstanceID(), bg->GetBgTypeID(), bgQueueTypeId);
}

View File

@@ -499,8 +499,21 @@ public:
// Remove from LFG queues
sLFGMgr->LeaveAllLfgQueues(player->GetGUID(), false);
// Book the reservation like the queue path does, so it is symmetric
// with RemovePlayerAtLeave's decrement and the 0-players/0-invited
// state can't let Battleground::Update delete the arena while players
// are still on the loading screen.
bg->IncreaseInvitedCount(teamId);
player->SetBattlegroundId(bg->GetInstanceID(), bgTypeId, queueSlot, true, false, teamId);
sBattlegroundMgr->SendToBattleground(player, bg->GetInstanceID(), bgTypeId);
// A synchronous teleport failure would strand that reservation (the
// player never enters and never reaches RemovePlayerAtLeave), leaving
// the arena undeletable; release it and reset his bg data.
if (!sBattlegroundMgr->SendToBattleground(player, bg->GetInstanceID(), bgTypeId))
{
bg->DecreaseInvitedCount(teamId);
player->SetBattlegroundId(0, BATTLEGROUND_TYPE_NONE, PLAYER_MAX_BATTLEGROUND_QUEUES, false, false, TEAM_NEUTRAL);
}
}
handler->PSendSysMessage("Success! Players are now being teleported to the arena.");