From 1e533698696b746de9b128f356b19436d0363fd0 Mon Sep 17 00:00:00 2001 From: Kelsi Date: Tue, 10 Mar 2026 06:40:07 -0700 Subject: [PATCH] game: fix player phantom model on SMSG_DESTROY_OBJECT handleDestroyObject invoked creatureDespawnCallback_ and gameObjectDespawnCallback_ but not playerDespawnCallback_ for PLAYER entities. This caused the CharacterRenderer instance for nearby players to remain alive after they received a DESTROY_OBJECT packet (e.g. when they teleported or went out of range via server-forced despawn), leaving phantom models in the world. Mirror the same despawn logic used for out-of-range removal: call playerDespawnCallback_ and clean up the per-player bookkeeping maps so the renderer cleans up the character instance correctly. --- src/game/game_handler.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/game/game_handler.cpp b/src/game/game_handler.cpp index d530de95..78089bd7 100644 --- a/src/game/game_handler.cpp +++ b/src/game/game_handler.cpp @@ -8399,6 +8399,14 @@ void GameHandler::handleDestroyObject(network::Packet& packet) { if (entity) { if (entity->getType() == ObjectType::UNIT && creatureDespawnCallback_) { creatureDespawnCallback_(data.guid); + } else if (entity->getType() == ObjectType::PLAYER && playerDespawnCallback_) { + // Player entities also need renderer cleanup on DESTROY_OBJECT, not just out-of-range. + playerDespawnCallback_(data.guid); + otherPlayerVisibleItemEntries_.erase(data.guid); + otherPlayerVisibleDirty_.erase(data.guid); + otherPlayerMoveTimeMs_.erase(data.guid); + inspectedPlayerItemEntries_.erase(data.guid); + pendingAutoInspect_.erase(data.guid); } else if (entity->getType() == ObjectType::GAMEOBJECT && gameObjectDespawnCallback_) { gameObjectDespawnCallback_(data.guid); }