From d5d61361ba90f464ab997592cd3feee76e9c5ef0 Mon Sep 17 00:00:00 2001 From: agatho Date: Wed, 4 Feb 2026 15:15:17 +0100 Subject: [PATCH] fix(lifecycle): Fix incomplete type error and deprecated APIs in clean build - Add BotAI.h include to 9 files that use unique_ptr via BotSession.h Files fixed: BotCharacterCreator, BotResourcePool, BotSpawnOrchestrator, BotSpawner, GracefulExitHandler, DynamicQuestSystem, ObjectiveTracker, LootDistribution - Fix CorpseCrashMitigation.cpp deprecated TrinityCore APIs: * Replace SetDeathState() with setDeathState() (correct casing) * Replace SetFlag/RemoveFlag/GetByteValue with internal tracking set * Replace deprecated PLAYER_FIELD_BYTES2 with _pendingPrevention set * Fix dynamic_cast by using BotSession->GetAI() pattern * Fix OrderedSharedMutex usage (direct lock/unlock instead of std::lock) - Add _pendingPrevention unordered_set to CorpseCrashMitigation.h Co-Authored-By: Claude Opus 4.5 Signed-off-by: luis --- .../Lifecycle/BotCharacterCreator.cpp | 1 + .../Playerbot/Lifecycle/BotResourcePool.cpp | 1 + .../Lifecycle/BotSpawnOrchestrator.cpp | 1 + .../Playerbot/Lifecycle/BotSpawner.cpp | 1 + .../Lifecycle/CorpseCrashMitigation.cpp | 116 +++++++++++++----- .../Lifecycle/CorpseCrashMitigation.h | 4 + .../Retirement/GracefulExitHandler.cpp | 1 + .../Playerbot/Quest/DynamicQuestSystem.cpp | 1 + .../Playerbot/Quest/ObjectiveTracker.cpp | 1 + .../Playerbot/Social/LootDistribution.cpp | 1 + 10 files changed, 98 insertions(+), 30 deletions(-) diff --git a/src/modules/Playerbot/Lifecycle/BotCharacterCreator.cpp b/src/modules/Playerbot/Lifecycle/BotCharacterCreator.cpp index f744403ea..2ba06d957 100644 --- a/src/modules/Playerbot/Lifecycle/BotCharacterCreator.cpp +++ b/src/modules/Playerbot/Lifecycle/BotCharacterCreator.cpp @@ -23,6 +23,7 @@ #include "World.h" #include "WorldSession.h" #include "../Session/BotSession.h" +#include "../AI/BotAI.h" // P1 FIX: Required for unique_ptr in BotSession.h #include "Data/WoW120CharacterCreation.h" #include "CharacterPackets.h" #include diff --git a/src/modules/Playerbot/Lifecycle/BotResourcePool.cpp b/src/modules/Playerbot/Lifecycle/BotResourcePool.cpp index 1dcfa9eb2..08c0d0e15 100644 --- a/src/modules/Playerbot/Lifecycle/BotResourcePool.cpp +++ b/src/modules/Playerbot/Lifecycle/BotResourcePool.cpp @@ -4,6 +4,7 @@ #include "BotResourcePool.h" #include "BotSession.h" +#include "../AI/BotAI.h" // P1 FIX: Required for unique_ptr in BotSession.h #include "Config/PlayerbotConfig.h" #include "Logging/Log.h" #include "Player.h" diff --git a/src/modules/Playerbot/Lifecycle/BotSpawnOrchestrator.cpp b/src/modules/Playerbot/Lifecycle/BotSpawnOrchestrator.cpp index 6de681d26..de8d859b3 100644 --- a/src/modules/Playerbot/Lifecycle/BotSpawnOrchestrator.cpp +++ b/src/modules/Playerbot/Lifecycle/BotSpawnOrchestrator.cpp @@ -16,6 +16,7 @@ #include "BotSpawnEventBus.h" #include "BotSpawner.h" #include "Session/BotSession.h" +#include "../AI/BotAI.h" // P1 FIX: Required for unique_ptr in BotSession.h #include "Logging/Log.h" #include "Player.h" diff --git a/src/modules/Playerbot/Lifecycle/BotSpawner.cpp b/src/modules/Playerbot/Lifecycle/BotSpawner.cpp index bbf145d78..3ca27d068 100644 --- a/src/modules/Playerbot/Lifecycle/BotSpawner.cpp +++ b/src/modules/Playerbot/Lifecycle/BotSpawner.cpp @@ -42,6 +42,7 @@ #include "CharacterDatabase.h" #include "BotWorldSessionMgr.h" #include "Session/BotSession.h" +#include "../AI/BotAI.h" // P1 FIX: Required for unique_ptr in BotSession.h #include "BotResourcePool.h" #include "BotAccountMgr.h" #include "Config/PlayerbotConfig.h" diff --git a/src/modules/Playerbot/Lifecycle/CorpseCrashMitigation.cpp b/src/modules/Playerbot/Lifecycle/CorpseCrashMitigation.cpp index 9b16f607e..44e3a9ccf 100644 --- a/src/modules/Playerbot/Lifecycle/CorpseCrashMitigation.cpp +++ b/src/modules/Playerbot/Lifecycle/CorpseCrashMitigation.cpp @@ -14,6 +14,7 @@ #include "WorldSession.h" #include "Log.h" #include "../AI/BotAI.h" +#include "../Session/BotSession.h" #include "DeathRecoveryManager.h" namespace Playerbot @@ -47,9 +48,12 @@ void CorpseCrashMitigation::OnBotDeath(Player* bot) // Cache death location BEFORE death for corpse-less resurrection CacheDeathLocation(bot); - // Mark bot for corpse prevention using custom player flag - // Safe because it's in the unused flag range (high byte) - bot->SetFlag(PLAYER_FIELD_BYTES2, 0x80000000); + // Mark bot for corpse prevention in our internal tracking + { + _mutex.lock(); + _pendingPrevention.insert(bot->GetGUID()); + _mutex.unlock(); + } } } @@ -61,8 +65,13 @@ void CorpseCrashMitigation::OnCorpseCreated(Player* bot, Corpse* corpse) if (!bot->GetSession()->IsBot()) return; - // Check if this bot has corpse prevention flag - bool preventionAttempted = (bot->GetByteValue(PLAYER_FIELD_BYTES2, 3) & 0x80); + // Check if this bot has corpse prevention flag in our internal tracking + bool preventionAttempted = false; + { + _mutex.lock_shared(); + preventionAttempted = (_pendingPrevention.count(bot->GetGUID()) > 0); + _mutex.unlock_shared(); + } if (preventionAttempted) { @@ -91,8 +100,12 @@ void CorpseCrashMitigation::OnCorpseCreated(Player* bot, Corpse* corpse) TrackCorpseSafely(bot, corpse); } - // Clear prevention flag - bot->RemoveFlag(PLAYER_FIELD_BYTES2, 0x80000000); + // Clear prevention flag from our internal tracking + { + _mutex.lock(); + _pendingPrevention.erase(bot->GetGUID()); + _mutex.unlock(); + } // Decrement active prevention counter --_activePrevention; @@ -115,7 +128,7 @@ void CorpseCrashMitigation::OnBotResurrection(Player* bot) ObjectGuid botGuid = bot->GetGUID(); - ::std::unique_lock<::std::shared_mutex> lock(_mutex); + _mutex.lock(); // Clean up death location cache _deathLocations.erase(botGuid); @@ -131,6 +144,8 @@ void CorpseCrashMitigation::OnBotResurrection(Player* bot) TC_LOG_DEBUG("playerbot.corpse", "Bot {} resurrected - cleaned up corpse tracking", bot->GetName()); } + + _mutex.unlock(); } // ============================================================================ @@ -146,7 +161,7 @@ bool CorpseCrashMitigation::TryPreventCorpse(Player* bot) // CRITICAL: Set death state to ALIVE immediately to prevent corpse creation // This MUST happen before TrinityCore's death handling creates the corpse - bot->SetDeathState(ALIVE); + bot->setDeathState(ALIVE); // Set bot as ghost for visual effect (but alive mechanically) bot->SetPlayerFlag(PLAYER_FLAGS_GHOST); @@ -158,12 +173,18 @@ bool CorpseCrashMitigation::TryPreventCorpse(Player* bot) bot->SetHealth(1); // Get BotAI to handle the fake death recovery - if (BotAI* ai = dynamic_cast(bot->GetAI())) + if (WorldSession* session = bot->GetSession()) { - if (DeathRecoveryManager* drm = ai->GetDeathRecoveryManager()) + if (BotSession* botSession = dynamic_cast(session)) { - // Initialize death recovery with cached location (no corpse needed) - drm->OnDeath(); + if (BotAI* ai = botSession->GetAI()) + { + if (DeathRecoveryManager* drm = ai->GetDeathRecoveryManager()) + { + // Initialize death recovery with cached location (no corpse needed) + drm->OnDeath(); + } + } } } @@ -207,28 +228,36 @@ void CorpseCrashMitigation::CacheDeathLocation(Player* bot) location.z = bot->GetPositionZ(); location.deathTime = ::std::chrono::steady_clock::now(); - ::std::unique_lock<::std::shared_mutex> lock(_mutex); + _mutex.lock(); _deathLocations[botGuid] = location; + _mutex.unlock(); TC_LOG_DEBUG("playerbot.corpse", "Cached death location for bot {} at ({:.2f}, {:.2f}, {:.2f}) map {}", bot->GetName(), location.x, location.y, location.z, location.mapId); // Also notify DeathRecoveryManager if available - if (BotAI* ai = dynamic_cast(bot->GetAI())) + if (WorldSession* session = bot->GetSession()) { - if (DeathRecoveryManager* drm = ai->GetDeathRecoveryManager()) + if (BotSession* botSession = dynamic_cast(session)) { - // DeathRecoveryManager will cache location in OnDeath() - // This is a pre-cache to ensure it happens BEFORE corpse creation - TC_LOG_TRACE("playerbot.corpse", "Pre-cached death location in unified mitigation system"); + if (BotAI* ai = botSession->GetAI()) + { + if (DeathRecoveryManager* drm = ai->GetDeathRecoveryManager()) + { + // DeathRecoveryManager will cache location in OnDeath() + // This is a pre-cache to ensure it happens BEFORE corpse creation + TC_LOG_TRACE("playerbot.corpse", "Pre-cached death location in unified mitigation system"); + } + } } } } void CorpseCrashMitigation::UncacheDeathLocation(ObjectGuid botGuid) { - ::std::unique_lock<::std::shared_mutex> lock(_mutex); + _mutex.lock(); _deathLocations.erase(botGuid); + _mutex.unlock(); } // ============================================================================ @@ -255,17 +284,18 @@ void CorpseCrashMitigation::TrackCorpseSafely(Player* bot, Corpse* corpse) tracker->safeToDelete = false; // NOT safe until Map update completes tracker->referenceCount = 1; - ::std::unique_lock<::std::shared_mutex> lock(_mutex); + _mutex.lock(); _trackedCorpses[corpseGuid] = ::std::move(tracker); _ownerToCorpse[ownerGuid] = corpseGuid; + _mutex.unlock(); TC_LOG_DEBUG("playerbot.corpse", "Tracking corpse {} for bot {} at ({:.2f}, {:.2f}, {:.2f}) (strategy 2 fallback)", - corpseGuid.ToString(), bot->GetName(), tracker->x, tracker->y, tracker->z); + corpseGuid.ToString(), bot->GetName(), corpse->GetPositionX(), corpse->GetPositionY(), corpse->GetPositionZ()); } void CorpseCrashMitigation::UntrackCorpse(ObjectGuid corpseGuid) { - ::std::unique_lock<::std::shared_mutex> lock(_mutex); + _mutex.lock(); auto it = _trackedCorpses.find(corpseGuid); if (it != _trackedCorpses.end()) @@ -276,11 +306,13 @@ void CorpseCrashMitigation::UntrackCorpse(ObjectGuid corpseGuid) TC_LOG_DEBUG("playerbot.corpse", "Untracked corpse {}", corpseGuid.ToString()); } + + _mutex.unlock(); } bool CorpseCrashMitigation::IsCorpseSafeToDelete(ObjectGuid corpseGuid) const { - ::std::shared_lock<::std::shared_mutex> lock(_mutex); + _mutex.lock_shared(); auto it = _trackedCorpses.find(corpseGuid); if (it != _trackedCorpses.end()) @@ -291,6 +323,8 @@ bool CorpseCrashMitigation::IsCorpseSafeToDelete(ObjectGuid corpseGuid) const bool safe = it->second->safeToDelete.load() && (it->second->referenceCount.load() == 0); + _mutex.unlock_shared(); + if (!safe) { const_cast(this)->_safetyDelayedDeletions++; @@ -303,13 +337,15 @@ bool CorpseCrashMitigation::IsCorpseSafeToDelete(ObjectGuid corpseGuid) const return safe; } + _mutex.unlock_shared(); + // Unknown corpse = not a bot corpse = safe to delete normally return true; } void CorpseCrashMitigation::MarkCorpseSafeForDeletion(ObjectGuid corpseGuid) { - ::std::shared_lock<::std::shared_mutex> lock(_mutex); + _mutex.lock_shared(); auto it = _trackedCorpses.find(corpseGuid); if (it != _trackedCorpses.end()) @@ -317,11 +353,13 @@ void CorpseCrashMitigation::MarkCorpseSafeForDeletion(ObjectGuid corpseGuid) it->second->safeToDelete = true; TC_LOG_DEBUG("playerbot.corpse", "Corpse {} marked safe for deletion", corpseGuid.ToString()); } + + _mutex.unlock_shared(); } void CorpseCrashMitigation::AddCorpseReference(ObjectGuid corpseGuid) { - ::std::shared_lock<::std::shared_mutex> lock(_mutex); + _mutex.lock_shared(); auto it = _trackedCorpses.find(corpseGuid); if (it != _trackedCorpses.end()) @@ -330,11 +368,13 @@ void CorpseCrashMitigation::AddCorpseReference(ObjectGuid corpseGuid) TC_LOG_TRACE("playerbot.corpse", "Corpse {} reference++ (count={})", corpseGuid.ToString(), it->second->referenceCount.load()); } + + _mutex.unlock_shared(); } void CorpseCrashMitigation::RemoveCorpseReference(ObjectGuid corpseGuid) { - ::std::shared_lock<::std::shared_mutex> lock(_mutex); + _mutex.lock_shared(); auto it = _trackedCorpses.find(corpseGuid); if (it != _trackedCorpses.end()) @@ -350,6 +390,8 @@ void CorpseCrashMitigation::RemoveCorpseReference(ObjectGuid corpseGuid) corpseGuid.ToString()); } } + + _mutex.unlock_shared(); } // ============================================================================ @@ -358,32 +400,44 @@ void CorpseCrashMitigation::RemoveCorpseReference(ObjectGuid corpseGuid) CorpseLocation const* CorpseCrashMitigation::GetDeathLocation(ObjectGuid botGuid) const { - ::std::shared_lock<::std::shared_mutex> lock(_mutex); + _mutex.lock_shared(); auto it = _deathLocations.find(botGuid); if (it != _deathLocations.end()) + { + _mutex.unlock_shared(); return &it->second; + } + _mutex.unlock_shared(); return nullptr; } bool CorpseCrashMitigation::GetCorpseLocation(ObjectGuid ownerGuid, float& x, float& y, float& z, uint32& mapId) const { - ::std::shared_lock<::std::shared_mutex> lock(_mutex); + _mutex.lock_shared(); auto ownerIt = _ownerToCorpse.find(ownerGuid); if (ownerIt == _ownerToCorpse.end()) + { + _mutex.unlock_shared(); return false; + } auto corpseIt = _trackedCorpses.find(ownerIt->second); if (corpseIt == _trackedCorpses.end()) + { + _mutex.unlock_shared(); return false; + } x = corpseIt->second->x; y = corpseIt->second->y; z = corpseIt->second->z; mapId = corpseIt->second->mapId; + _mutex.unlock_shared(); + TC_LOG_TRACE("playerbot.corpse", "Retrieved corpse location for owner {} at ({:.2f}, {:.2f}, {:.2f})", ownerGuid.ToString(), x, y, z); @@ -396,7 +450,7 @@ bool CorpseCrashMitigation::GetCorpseLocation(ObjectGuid ownerGuid, float& x, fl void CorpseCrashMitigation::CleanupExpiredCorpses() { - ::std::unique_lock<::std::shared_mutex> lock(_mutex); + _mutex.lock(); auto now = ::std::chrono::steady_clock::now(); @@ -438,6 +492,8 @@ void CorpseCrashMitigation::CleanupExpiredCorpses() ++it; } } + + _mutex.unlock(); } } // namespace Playerbot diff --git a/src/modules/Playerbot/Lifecycle/CorpseCrashMitigation.h b/src/modules/Playerbot/Lifecycle/CorpseCrashMitigation.h index ffd42bbd9..262bfc386 100644 --- a/src/modules/Playerbot/Lifecycle/CorpseCrashMitigation.h +++ b/src/modules/Playerbot/Lifecycle/CorpseCrashMitigation.h @@ -25,6 +25,7 @@ #include "ObjectGuid.h" #include #include +#include #include #include #include @@ -289,6 +290,9 @@ private: // Strategy 1: Death location cache (for corpse-less resurrection) ::std::unordered_map _deathLocations; + // Strategy 1: Pending prevention tracking (internal flag replacement) + ::std::unordered_set _pendingPrevention; + // Strategy 2: Corpse tracking (fallback if prevention fails) ::std::unordered_map> _trackedCorpses; ::std::unordered_map _ownerToCorpse; // owner -> corpse mapping diff --git a/src/modules/Playerbot/Lifecycle/Retirement/GracefulExitHandler.cpp b/src/modules/Playerbot/Lifecycle/Retirement/GracefulExitHandler.cpp index b75c5051d..e5d98054a 100644 --- a/src/modules/Playerbot/Lifecycle/Retirement/GracefulExitHandler.cpp +++ b/src/modules/Playerbot/Lifecycle/Retirement/GracefulExitHandler.cpp @@ -21,6 +21,7 @@ #include "WorldSession.h" #include "Session/BotSession.h" #include "Session/BotWorldSessionMgr.h" +#include "../../AI/BotAI.h" // P1 FIX: Required for unique_ptr in BotSession.h #include namespace Playerbot diff --git a/src/modules/Playerbot/Quest/DynamicQuestSystem.cpp b/src/modules/Playerbot/Quest/DynamicQuestSystem.cpp index a7b1ad90a..7c6b1be3c 100644 --- a/src/modules/Playerbot/Quest/DynamicQuestSystem.cpp +++ b/src/modules/Playerbot/Quest/DynamicQuestSystem.cpp @@ -23,6 +23,7 @@ #include "MapManager.h" #include "ObjectAccessor.h" #include "Session/BotSession.h" +#include "../AI/BotAI.h" // P1 FIX: Required for unique_ptr in BotSession.h #include "Spatial/SpatialGridQueryHelpers.h" // PHASE 2G: For snapshot-based player validation #include #include diff --git a/src/modules/Playerbot/Quest/ObjectiveTracker.cpp b/src/modules/Playerbot/Quest/ObjectiveTracker.cpp index a109f9822..81cf38380 100644 --- a/src/modules/Playerbot/Quest/ObjectiveTracker.cpp +++ b/src/modules/Playerbot/Quest/ObjectiveTracker.cpp @@ -23,6 +23,7 @@ #include "Map.h" #include "Group.h" #include "Session/BotSession.h" +#include "../AI/BotAI.h" // P1 FIX: Required for unique_ptr in BotSession.h #include "Core/Services/BotNpcLocationService.h" #include "Core/Threading/SafeGridOperations.h" // SEH-protected grid operations #include diff --git a/src/modules/Playerbot/Social/LootDistribution.cpp b/src/modules/Playerbot/Social/LootDistribution.cpp index c11336207..6b908d67c 100644 --- a/src/modules/Playerbot/Social/LootDistribution.cpp +++ b/src/modules/Playerbot/Social/LootDistribution.cpp @@ -21,6 +21,7 @@ #include "WorldSession.h" #include "ObjectAccessor.h" #include "Session/BotSession.h" +#include "../AI/BotAI.h" // P1 FIX: Required for unique_ptr in BotSession.h #include "Spatial/SpatialGridQueryHelpers.h" #include "../Group/GroupMemberResolver.h" #include "../Core/Diagnostics/GroupMemberDiagnostics.h"