From 3d467ce3bb4f846d512324a729f2237db8a8236a Mon Sep 17 00:00:00 2001 From: bashermens <31279994+hermensbas@users.noreply.github.com> Date: Sat, 24 Jan 2026 20:41:12 +0100 Subject: [PATCH] Added some additional defense checks around isHostile and unit/target (#2056) Needs second pair of eyes, they appear in crash logs here and there. Its merely a patch on a open wound. ---- As in aslong there multithreads in mapupdate, which we need for decent performance and core calls are not done correctly due various reasons. These type of issues remain. Although i am planning to experiment a little with threadsafe execution of our strategies vs performance. The most effective thing we could do is check every single action and check its stateless and where it does effect the state or read the state of a core object its done in the safest way. flags, worldthread where possible and/ot simply taking into account the state might be invalid. --- src/Ai/Base/Actions/TravelAction.cpp | 2 +- src/Ai/Base/Actions/UseItemAction.cpp | 6 ++-- src/Ai/Base/Value/AttackersValue.cpp | 3 ++ src/Ai/Base/Value/GrindTargetValue.cpp | 10 ++---- src/Ai/Base/Value/NearestNpcsValue.cpp | 11 ++++++- src/Ai/Base/Value/PossibleRpgTargetsValue.cpp | 9 ++++- .../Raid/Icecrown/Trigger/RaidIccTriggers.cpp | 10 ++++-- .../Ulduar/Trigger/RaidUlduarTriggers.cpp | 33 ++++++++++++++----- 8 files changed, 62 insertions(+), 22 deletions(-) diff --git a/src/Ai/Base/Actions/TravelAction.cpp b/src/Ai/Base/Actions/TravelAction.cpp index f99f8b29..a2906057 100644 --- a/src/Ai/Base/Actions/TravelAction.cpp +++ b/src/Ai/Base/Actions/TravelAction.cpp @@ -28,7 +28,7 @@ bool TravelAction::Execute(Event event) for (Unit* unit : targets) { newTarget = unit; - if (!newTarget) + if (!newTarget || !newTarget->IsInWorld() || newTarget->IsDuringRemoveFromWorld()) continue; if (newTarget->GetMapId() != bot->GetMapId()) diff --git a/src/Ai/Base/Actions/UseItemAction.cpp b/src/Ai/Base/Actions/UseItemAction.cpp index 690d2d4b..bfb86ef0 100644 --- a/src/Ai/Base/Actions/UseItemAction.cpp +++ b/src/Ai/Base/Actions/UseItemAction.cpp @@ -245,8 +245,10 @@ bool UseItemAction::UseItem(Item* item, ObjectGuid goGuid, Item* itemTarget, Uni { packet << unitTarget->GetGUID(); targetSelected = true; - // If the target is bot or is an enemy, say "on self" - if (unitTarget == bot || (unitTarget->IsHostileTo(bot))) + + if (unitTarget == bot || !unitTarget->IsInWorld() || unitTarget->IsDuringRemoveFromWorld()) + out << " on self"; + else if (unitTarget->IsHostileTo(bot)) out << " on self"; else out << " on " << unitTarget->GetName(); diff --git a/src/Ai/Base/Value/AttackersValue.cpp b/src/Ai/Base/Value/AttackersValue.cpp index 3c968589..f6da0aa7 100644 --- a/src/Ai/Base/Value/AttackersValue.cpp +++ b/src/Ai/Base/Value/AttackersValue.cpp @@ -258,6 +258,9 @@ bool PossibleAddsValue::Calculate() if (Unit* add = botAI->GetUnit(guid)) { + if (!add->IsInWorld() || add->IsDuringRemoveFromWorld()) + continue; + if (!add->GetTarget() && !add->GetThreatMgr().getCurrentVictim() && add->IsHostileTo(bot)) { for (ObjectGuid const attackerGUID : attackers) diff --git a/src/Ai/Base/Value/GrindTargetValue.cpp b/src/Ai/Base/Value/GrindTargetValue.cpp index d1d7f912..7e6168c7 100644 --- a/src/Ai/Base/Value/GrindTargetValue.cpp +++ b/src/Ai/Base/Value/GrindTargetValue.cpp @@ -59,26 +59,22 @@ Unit* GrindTargetValue::FindTargetForGrinding(uint32 assistCount) for (ObjectGuid const guid : targets) { Unit* unit = botAI->GetUnit(guid); - if (!unit) continue; + if (!unit->IsInWorld() || unit->IsDuringRemoveFromWorld()) + continue; + auto& rep = bot->ToPlayer()->GetReputationMgr(); if (unit->ToCreature() && !unit->ToCreature()->GetCreatureTemplate()->lootid && bot->GetReactionTo(unit) >= REP_NEUTRAL) - { continue; - } if (!bot->IsHostileTo(unit) && unit->GetNpcFlags() != UNIT_NPC_FLAG_NONE) - { continue; - } if (!bot->isHonorOrXPTarget(unit)) - { continue; - } if (abs(bot->GetPositionZ() - unit->GetPositionZ()) > INTERACTION_DISTANCE) continue; diff --git a/src/Ai/Base/Value/NearestNpcsValue.cpp b/src/Ai/Base/Value/NearestNpcsValue.cpp index 1c188d29..a32c007f 100644 --- a/src/Ai/Base/Value/NearestNpcsValue.cpp +++ b/src/Ai/Base/Value/NearestNpcsValue.cpp @@ -27,7 +27,16 @@ void NearestHostileNpcsValue::FindUnits(std::list& targets) Cell::VisitObjects(bot, searcher, range); } -bool NearestHostileNpcsValue::AcceptUnit(Unit* unit) { return unit->IsHostileTo(bot) && !unit->IsPlayer(); } +bool NearestHostileNpcsValue::AcceptUnit(Unit* unit) +{ + if (!unit || !unit->IsInWorld() || unit->IsDuringRemoveFromWorld()) + return false; + + if (unit->IsPlayer()) + return false; + + return unit->IsHostileTo(bot); +} void NearestVehiclesValue::FindUnits(std::list& targets) { diff --git a/src/Ai/Base/Value/PossibleRpgTargetsValue.cpp b/src/Ai/Base/Value/PossibleRpgTargetsValue.cpp index 6e78f37f..e9b79deb 100644 --- a/src/Ai/Base/Value/PossibleRpgTargetsValue.cpp +++ b/src/Ai/Base/Value/PossibleRpgTargetsValue.cpp @@ -54,6 +54,9 @@ void PossibleRpgTargetsValue::FindUnits(std::list& targets) bool PossibleRpgTargetsValue::AcceptUnit(Unit* unit) { + if (!unit || !unit->IsInWorld() || unit->IsDuringRemoveFromWorld()) + return false; + if (unit->IsHostileTo(bot) || unit->IsPlayer()) return false; @@ -70,7 +73,8 @@ bool PossibleRpgTargetsValue::AcceptUnit(Unit* unit) } TravelTarget* travelTarget = context->GetValue("travel target")->Get(); - if (travelTarget->getDestination() && travelTarget->getDestination()->getEntry() == unit->GetEntry()) + if (travelTarget && travelTarget->getDestination() && + travelTarget->getDestination()->getEntry() == unit->GetEntry()) return true; if (urand(1, 100) < 25 && unit->IsFriendlyTo(bot)) @@ -145,6 +149,9 @@ void PossibleNewRpgTargetsValue::FindUnits(std::list& targets) bool PossibleNewRpgTargetsValue::AcceptUnit(Unit* unit) { + if (!unit || !unit->IsInWorld() || unit->IsDuringRemoveFromWorld()) + return false; + if (unit->IsHostileTo(bot) || unit->IsPlayer()) return false; diff --git a/src/Ai/Raid/Icecrown/Trigger/RaidIccTriggers.cpp b/src/Ai/Raid/Icecrown/Trigger/RaidIccTriggers.cpp index 55cfe9fc..b9ebb8ca 100644 --- a/src/Ai/Raid/Icecrown/Trigger/RaidIccTriggers.cpp +++ b/src/Ai/Raid/Icecrown/Trigger/RaidIccTriggers.cpp @@ -99,7 +99,10 @@ bool IccGunshipCannonNearTrigger::IsActive() bool IccGunshipTeleportAllyTrigger::IsActive() { Unit* boss = bot->FindNearestCreature(NPC_HIGH_OVERLORD_SAURFANG, 100.0f); - if (!boss) + if (!boss || !boss->IsInWorld() || boss->IsDuringRemoveFromWorld()) + return false; + + if (!boss->IsAlive()) return false; if (!boss->IsHostileTo(bot)) @@ -111,7 +114,10 @@ bool IccGunshipTeleportAllyTrigger::IsActive() bool IccGunshipTeleportHordeTrigger::IsActive() { Unit* boss = bot->FindNearestCreature(NPC_MURADIN_BRONZEBEARD, 100.0f); - if (!boss) + if (!boss || !boss->IsInWorld() || boss->IsDuringRemoveFromWorld()) + return false; + + if (!boss->IsAlive()) return false; if (!boss->IsHostileTo(bot)) diff --git a/src/Ai/Raid/Ulduar/Trigger/RaidUlduarTriggers.cpp b/src/Ai/Raid/Ulduar/Trigger/RaidUlduarTriggers.cpp index 89ad7ac5..f883917e 100644 --- a/src/Ai/Raid/Ulduar/Trigger/RaidUlduarTriggers.cpp +++ b/src/Ai/Raid/Ulduar/Trigger/RaidUlduarTriggers.cpp @@ -765,9 +765,13 @@ bool FreyaMoveToHealingSporeTrigger::IsActive() bool ThorimUnbalancingStrikeTrigger::IsActive() { Unit* boss = AI_VALUE2(Unit*, "find target", "thorim"); + if (!boss || !boss->IsInWorld() || boss->IsDuringRemoveFromWorld()) + return false; - // Check boss and it is alive - if (!boss || !boss->IsAlive() || !boss->IsHostileTo(bot)) + if (!boss->IsAlive()) + return false; + + if (!boss->IsHostileTo(bot)) return false; return bot->HasAura(SPELL_UNBALANCING_STRIKE); @@ -804,8 +808,13 @@ bool ThorimMarkDpsTargetTrigger::IsActive() Unit* boss = AI_VALUE2(Unit*, "find target", "thorim"); - // Check boss and it is alive - if (!boss || !boss->IsAlive() || !boss->IsHostileTo(bot)) + if (!boss || !boss->IsInWorld() || boss->IsDuringRemoveFromWorld()) + return false; + + if (!boss->IsAlive()) + return false; + + if (!boss->IsHostileTo(bot)) return false; if (boss->GetPositionZ() < ULDUAR_THORIM_AXIS_Z_FLOOR_THRESHOLD && (!currentSkullUnit || !currentSkullUnit->IsAlive())) @@ -982,9 +991,13 @@ bool ThorimGauntletPositioningTrigger::IsActive() bool ThorimArenaPositioningTrigger::IsActive() { Unit* boss = AI_VALUE2(Unit*, "find target", "thorim"); + if (!boss || !boss->IsInWorld() || boss->IsDuringRemoveFromWorld()) + return false; - // Check boss and it is alive - if (!boss || !boss->IsAlive() || !boss->IsHostileTo(bot)) + if (!boss->IsAlive()) + return false; + + if (!boss->IsHostileTo(bot)) return false; if (boss->GetPositionZ() < ULDUAR_THORIM_AXIS_Z_FLOOR_THRESHOLD) @@ -1080,9 +1093,13 @@ bool ThorimPhase2PositioningTrigger::IsActive() return false; Unit* boss = AI_VALUE2(Unit*, "find target", "thorim"); + if (!boss || !boss->IsInWorld() || boss->IsDuringRemoveFromWorld()) + return false; - // Check boss and it is alive - if (!boss || !boss->IsAlive() || !boss->IsHostileTo(bot)) + if (!boss->IsAlive()) + return false; + + if (!boss->IsHostileTo(bot)) return false; if (boss->GetPositionZ() > ULDUAR_THORIM_AXIS_Z_FLOOR_THRESHOLD)