fix: don't set releasedSpirit_ optimistically in releaseSpirit()

Setting releasedSpirit_=true immediately on CMSG_REPOP_REQUEST raced
with PLAYER_FLAGS field updates that arrive from the server before it
processes the repop: the PLAYER_FLAGS handler saw wasGhost=true /
nowGhost=false and fired the 'ghost cleared' path, wiping corpseMapId_
and corpseGuid_ — so the minimap skull marker and the Resurrect from
Corpse dialog never appeared.

Ghost state is now driven entirely by the server-confirmed PLAYER_FLAGS
GHOST bit (and the login-as-ghost path), eliminating the race.
This commit is contained in:
Kelsi 2026-03-18 05:35:23 -07:00
parent d0f544395e
commit 90843ea989

View file

@ -14050,7 +14050,11 @@ void GameHandler::releaseSpirit() {
}
auto packet = RepopRequestPacket::build();
socket->send(packet);
releasedSpirit_ = true;
// Do NOT set releasedSpirit_ = true here. Setting it optimistically races
// with PLAYER_FLAGS field updates that arrive before the server processes
// CMSG_REPOP_REQUEST: the PLAYER_FLAGS handler sees wasGhost=true/nowGhost=false
// and fires the "ghost cleared" path, wiping corpseMapId_/corpseGuid_.
// Let the server drive ghost state via PLAYER_FLAGS_GHOST (field update path).
selfResAvailable_ = false; // self-res window closes when spirit is released
repopPending_ = true;
lastRepopRequestMs_ = static_cast<uint64_t>(now);