From f23f340033253a3f3d1544abad31d536b88f6f33 Mon Sep 17 00:00:00 2001 From: FrancescoBorzi Date: Thu, 2 Jul 2026 13:24:27 +0200 Subject: [PATCH 1/3] fix: drop the fake-store record on WG wartime logout instead of leaking it --- src/CFBG.cpp | 7 +++++++ src/CFBG.h | 1 + src/CFBG_SC.cpp | 22 +++++++++++++++------- 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/CFBG.cpp b/src/CFBG.cpp index b2d9b97..13e5ff3 100644 --- a/src/CFBG.cpp +++ b/src/CFBG.cpp @@ -548,6 +548,13 @@ void CFBG::ClearFakePlayer(Player* player) _fakePlayerStore.erase(player); } +// Erase-only: no race/morph/faction/m_team restore. Used at wartime WG logout, +// where Player::RemoveFromWorld still erases PlayersInWar keyed on the fake team. +void CFBG::DropFakePlayerRecord(Player* player) +{ + _fakePlayerStore.erase(player); +} + void CFBG::ReapplyFakePlayer(Player* player) { FakePlayer const* info = GetFakePlayer(player); diff --git a/src/CFBG.h b/src/CFBG.h index 0cfb317..46d14a0 100644 --- a/src/CFBG.h +++ b/src/CFBG.h @@ -169,6 +169,7 @@ class CFBG void SetFakeRaceAndMorphForBF(Player* player, TeamId assignedTeam); void SetFactionForRace(Player* player, uint8 Race, TeamId teamId); void ClearFakePlayer(Player* player); + void DropFakePlayerRecord(Player* player); void ReapplyFakePlayer(Player* player); void DoForgetPlayersInList(Player* player); void FitPlayerInTeam(Player* player, bool action, Battleground* bg); diff --git a/src/CFBG_SC.cpp b/src/CFBG_SC.cpp index 3447810..92845d5 100644 --- a/src/CFBG_SC.cpp +++ b/src/CFBG_SC.cpp @@ -126,14 +126,22 @@ class CFBG_Player : public PlayerScript if (!sCFBG->IsEnableSystem() || !sCFBG->IsPlayerFake(player)) return; - // Only clear the WG fake state when the battlefield is not actively at - // war. During a running war the player may safely relog and rejoin - // their assigned faction, so we leave the fake state intact for that - // case. BG fakes are always cleaned up by OnBattlegroundRemovePlayerAtLeave - // and do not need to be handled here. + // Only WG fakes are handled here; BG fakes are owned by + // OnBattlegroundRemovePlayerAtLeave. Outside a war, fully restore. + // During a running war, only drop the Player*-keyed record: relog + // constructs a new Player*, so the entry can never serve the rejoin + // (Battlefield::TryRejoinAfterLogout re-fakes via the GUID-keyed + // _wgWarAssignmentStore) and would dangle. Restoring race/faction here + // would flip m_team before Player::RemoveFromWorld and mis-key core's + // PlayersInWar erase. Battlefield* bf = sBattlefieldMgr->GetBattlefieldToZoneId(player->GetZoneId()); - if (bf && bf->GetTypeId() == BATTLEFIELD_WG && !bf->IsWarTime()) - sCFBG->ClearFakePlayer(player); + if (bf && bf->GetTypeId() == BATTLEFIELD_WG) + { + if (!bf->IsWarTime()) + sCFBG->ClearFakePlayer(player); + else + sCFBG->DropFakePlayerRecord(player); + } } // Fires after Player::UpdateZone has finished all Battlefield/OutdoorPvP/WorldState From 003447b2568c1c22986e1fb3dfd4c69023e8345e Mon Sep 17 00:00:00 2001 From: FrancescoBorzi Date: Thu, 2 Jul 2026 13:24:54 +0200 Subject: [PATCH 2/3] fix: remove charms before unfaking so charm end cannot restore the fake faction --- src/CFBG.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/CFBG.cpp b/src/CFBG.cpp index 13e5ff3..84001e7 100644 --- a/src/CFBG.cpp +++ b/src/CFBG.cpp @@ -536,6 +536,13 @@ void CFBG::ClearFakePlayer(Player* player) if (!IsPlayerFake(player)) return; + // Unwind any charm ON the player while the fake record still exists: + // Unit::RemoveCharmedBy blindly restores the faction snapshotted at charm + // time (the fake one), which the restore below then overwrites. A charm + // ending after the unfake would re-plant the fake template (#166). + if (player->IsCharmed()) + player->RemoveCharmAuras(); + player->setRace(_fakePlayerStore[player].RealRace); player->SetDisplayId(_fakePlayerStore[player].RealMorph); player->SetNativeDisplayId(_fakePlayerStore[player].RealNativeMorph); From 7fe3759559dacdf02da6fa22e6bdb83b4bb4c326 Mon Sep 17 00:00:00 2001 From: FrancescoBorzi Date: Thu, 2 Jul 2026 13:25:30 +0200 Subject: [PATCH 3/3] fix: verify the faction template for native players in EnforceBGTeamConsistency --- src/CFBG.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/CFBG.cpp b/src/CFBG.cpp index 84001e7..2d4581c 100644 --- a/src/CFBG.cpp +++ b/src/CFBG.cpp @@ -327,6 +327,18 @@ void CFBG::EnforceBGTeamConsistency(Player* player) { if (IsPlayerFake(player)) ClearFakePlayer(player); + + // A foreign template can outlive its writer on a non-faked native + // (e.g. a charm undone after an unfake). Repair it unless a legitimate + // writer owns it: GM-on holds FACTION_FRIENDLY; an active MOD_FACTION + // aura restores natives correctly on removal. + if (!player->IsGameMaster() && !player->HasAuraType(SPELL_AURA_MOD_FACTION)) + { + ChrRacesEntry const* raceEntry = sChrRacesStore.LookupEntry(player->getRace(true)); + if (raceEntry && player->GetFaction() != raceEntry->FactionID) + SetFactionForRace(player, player->getRace(true), player->GetTeamId(true)); + } + return; }