Skip to content

Commit 419af57

Browse files
NyeriahZakamuritexfurryclaude
authored
feat(Core/Battlefield): grace period for mid-war logout/relog (azerothcore#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>
1 parent 74da7dd commit 419af57

2 files changed

Lines changed: 56 additions & 1 deletion

File tree

src/server/game/Battlefield/Battlefield.cpp

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@ void Battlefield::HandlePlayerEnterZone(Player* player, uint32 /*zone*/)
9393
// any team-based battlefield containers (such as player lists or queues) are updated.
9494
sScriptMgr->OnBattlefieldPlayerEnterZone(this, player);
9595

96+
TryRejoinAfterLogout(player); // relog: auto-rejoin, skip invite below
97+
9698
// Xinef: do not invite players on taxi
9799
if (!player->IsInFlight())
98100
{
@@ -124,12 +126,20 @@ void Battlefield::HandlePlayerEnterZone(Player* player, uint32 /*zone*/)
124126

125127
void Battlefield::HandlePlayerLeaveZone(Player* player, uint32 /*zone*/)
126128
{
129+
// Logout still runs full leave-war cleanup, but marks the player for grace-window auto-rejoin.
130+
bool const isLogout = player->GetSession() && player->GetSession()->PlayerLogout();
131+
127132
if (IsWarTime())
128133
{
129134
// If the player is participating to the battle
130135
if (PlayersInWar[player->GetTeamId()].erase(player->GetGUID()))
131136
{
132-
player->GetSession()->SendBfLeaveMessage(BattleId);
137+
if (isLogout)
138+
LogoutGracePlayers[player->GetTeamId()][player->GetGUID()] =
139+
GameTime::GetGameTime().count() + LOGOUT_GRACE_SECONDS;
140+
else
141+
player->GetSession()->SendBfLeaveMessage(BattleId);
142+
133143
if (Group* group = player->GetGroup()) // Remove the player from the raid group
134144
if (group->isBFGroup())
135145
group->RemoveMember(player->GetGUID());
@@ -321,6 +331,7 @@ void Battlefield::StartBattle()
321331
{
322332
PlayersInWar[team].clear();
323333
Groups[team].clear();
334+
LogoutGracePlayers[team].clear();
324335
}
325336

326337
Timer = BattleTime;
@@ -588,6 +599,41 @@ bool Battlefield::AddOrSetPlayerToCorrectBfGroup(Player* player)
588599
return true;
589600
}
590601

602+
void Battlefield::TryRejoinAfterLogout(Player* player)
603+
{
604+
ObjectGuid const guid = player->GetGUID();
605+
time_t const now = GameTime::GetGameTime().count();
606+
607+
// Consume the marker and honor its grace window (check both teams; team may have changed).
608+
bool pending = false;
609+
for (uint8 team = 0; team < PVP_TEAMS_COUNT; ++team)
610+
if (auto itr = LogoutGracePlayers[team].find(guid); itr != LogoutGracePlayers[team].end())
611+
{
612+
pending = itr->second > now;
613+
LogoutGracePlayers[team].erase(itr);
614+
}
615+
616+
// Vacancy gate mirrors HandlePlayerEnterZone (full team -> queue path). Pre-hook:
617+
// we can't abort after JoinWar, which may already have mutated module state.
618+
if (!pending || !IsWarTime() || !HasWarVacancy(player->GetTeamId()))
619+
return;
620+
621+
if (Group* current = player->GetGroup())
622+
if (current->isBGGroup() || current->isBFGroup())
623+
return;
624+
625+
// Rejoin via the normal join path: firing JoinWar lets modules rebuild
626+
// per-session (Player*-keyed) state and pick the team before the raid bind.
627+
sScriptMgr->OnBattlefieldPlayerJoinWar(this, player);
628+
629+
if (AddOrSetPlayerToCorrectBfGroup(player))
630+
{
631+
player->GetSession()->SendBfEntered(BattleId);
632+
PlayersInWar[player->GetTeamId()].insert(guid);
633+
OnPlayerJoinWar(player);
634+
}
635+
}
636+
591637
BfGraveyard* Battlefield::GetGraveyardById(uint32 id) const
592638
{
593639
if (id < GraveyardList.size())

src/server/game/Battlefield/Battlefield.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,11 @@ class Battlefield : public ZoneScript
278278
/// Force player to join a battlefield group
279279
bool AddOrSetPlayerToCorrectBfGroup(Player* player);
280280

281+
/// Auto-rejoin a player who relogged within the grace window after a mid-war
282+
/// logout, via the normal join hooks. No-op without a pending logout marker.
283+
/// Called from HandlePlayerEnterZone (which fires on the post-login zone set).
284+
void TryRejoinAfterLogout(Player* player);
285+
281286
// Graveyard methods
282287
// Find which graveyard the player must be teleported to to be resurrected by spiritguide
283288
GraveyardStruct const* GetClosestGraveyard(Player* player);
@@ -381,6 +386,10 @@ class Battlefield : public ZoneScript
381386
GuidUnorderedSet PlayersInWar[PVP_TEAMS_COUNT]; // Players in WG combat
382387
PlayerTimerMap InvitedPlayers[PVP_TEAMS_COUNT];
383388
PlayerTimerMap PlayersWillBeKick[PVP_TEAMS_COUNT];
389+
// Mid-war logouts: GUID -> timestamp until which a relog auto-rejoins the war.
390+
PlayerTimerMap LogoutGracePlayers[PVP_TEAMS_COUNT];
391+
392+
static constexpr uint32 LOGOUT_GRACE_SECONDS = 120; // relog auto-rejoin window
384393

385394
// Variables that must exist for each battlefield
386395
uint32 TypeId; // See enum BattlefieldTypes

0 commit comments

Comments
 (0)