feat(Core/Battlefield): grace period for mid-war logout/relog (#26013)

Co-authored-by: Yaki Khadafi <ElSolDolLo@gmail.com>
Co-authored-by: Xfurry <xfurry.cmangos@outlook.com>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Andrew
2026-05-28 21:18:24 -03:00
committed by GitHub
parent 74da7dda12
commit 419af5796e
2 changed files with 56 additions and 1 deletions
+47 -1
View File
@@ -93,6 +93,8 @@ void Battlefield::HandlePlayerEnterZone(Player* player, uint32 /*zone*/)
// any team-based battlefield containers (such as player lists or queues) are updated.
sScriptMgr->OnBattlefieldPlayerEnterZone(this, player);
TryRejoinAfterLogout(player); // relog: auto-rejoin, skip invite below
// Xinef: do not invite players on taxi
if (!player->IsInFlight())
{
@@ -124,12 +126,20 @@ void Battlefield::HandlePlayerEnterZone(Player* player, uint32 /*zone*/)
void Battlefield::HandlePlayerLeaveZone(Player* player, uint32 /*zone*/)
{
// Logout still runs full leave-war cleanup, but marks the player for grace-window auto-rejoin.
bool const isLogout = player->GetSession() && player->GetSession()->PlayerLogout();
if (IsWarTime())
{
// If the player is participating to the battle
if (PlayersInWar[player->GetTeamId()].erase(player->GetGUID()))
{
player->GetSession()->SendBfLeaveMessage(BattleId);
if (isLogout)
LogoutGracePlayers[player->GetTeamId()][player->GetGUID()] =
GameTime::GetGameTime().count() + LOGOUT_GRACE_SECONDS;
else
player->GetSession()->SendBfLeaveMessage(BattleId);
if (Group* group = player->GetGroup()) // Remove the player from the raid group
if (group->isBFGroup())
group->RemoveMember(player->GetGUID());
@@ -321,6 +331,7 @@ void Battlefield::StartBattle()
{
PlayersInWar[team].clear();
Groups[team].clear();
LogoutGracePlayers[team].clear();
}
Timer = BattleTime;
@@ -588,6 +599,41 @@ bool Battlefield::AddOrSetPlayerToCorrectBfGroup(Player* player)
return true;
}
void Battlefield::TryRejoinAfterLogout(Player* player)
{
ObjectGuid const guid = player->GetGUID();
time_t const now = GameTime::GetGameTime().count();
// Consume the marker and honor its grace window (check both teams; team may have changed).
bool pending = false;
for (uint8 team = 0; team < PVP_TEAMS_COUNT; ++team)
if (auto itr = LogoutGracePlayers[team].find(guid); itr != LogoutGracePlayers[team].end())
{
pending = itr->second > now;
LogoutGracePlayers[team].erase(itr);
}
// Vacancy gate mirrors HandlePlayerEnterZone (full team -> queue path). Pre-hook:
// we can't abort after JoinWar, which may already have mutated module state.
if (!pending || !IsWarTime() || !HasWarVacancy(player->GetTeamId()))
return;
if (Group* current = player->GetGroup())
if (current->isBGGroup() || current->isBFGroup())
return;
// Rejoin via the normal join path: firing JoinWar lets modules rebuild
// per-session (Player*-keyed) state and pick the team before the raid bind.
sScriptMgr->OnBattlefieldPlayerJoinWar(this, player);
if (AddOrSetPlayerToCorrectBfGroup(player))
{
player->GetSession()->SendBfEntered(BattleId);
PlayersInWar[player->GetTeamId()].insert(guid);
OnPlayerJoinWar(player);
}
}
BfGraveyard* Battlefield::GetGraveyardById(uint32 id) const
{
if (id < GraveyardList.size())
@@ -278,6 +278,11 @@ public:
/// Force player to join a battlefield group
bool AddOrSetPlayerToCorrectBfGroup(Player* player);
/// Auto-rejoin a player who relogged within the grace window after a mid-war
/// logout, via the normal join hooks. No-op without a pending logout marker.
/// Called from HandlePlayerEnterZone (which fires on the post-login zone set).
void TryRejoinAfterLogout(Player* player);
// Graveyard methods
// Find which graveyard the player must be teleported to to be resurrected by spiritguide
GraveyardStruct const* GetClosestGraveyard(Player* player);
@@ -381,6 +386,10 @@ protected:
GuidUnorderedSet PlayersInWar[PVP_TEAMS_COUNT]; // Players in WG combat
PlayerTimerMap InvitedPlayers[PVP_TEAMS_COUNT];
PlayerTimerMap PlayersWillBeKick[PVP_TEAMS_COUNT];
// Mid-war logouts: GUID -> timestamp until which a relog auto-rejoins the war.
PlayerTimerMap LogoutGracePlayers[PVP_TEAMS_COUNT];
static constexpr uint32 LOGOUT_GRACE_SECONDS = 120; // relog auto-rejoin window
// Variables that must exist for each battlefield
uint32 TypeId; // See enum BattlefieldTypes