From 8c25abca72772e2962bac7f460a567a943388a05 Mon Sep 17 00:00:00 2001 From: Giacomo Pozzoni Date: Mon, 27 Dec 2021 13:33:37 +0100 Subject: Core/AI: Fix crashes caused by charmed Creatures having null AI for 1 map update tick (#27434) Implement using ScheduledChangeAI instead of nullptr to signal a required AI change (cherry picked from commit 19e99db821ba5975e88ec160df3f4ff78ed562b0) --- src/server/game/AI/CoreAI/ScheduledChangeAI.cpp | 22 ++++++++++++++ src/server/game/AI/CoreAI/ScheduledChangeAI.h | 40 +++++++++++++++++++++++++ src/server/game/AI/CreatureAIRegistry.cpp | 2 ++ src/server/game/Entities/Unit/Unit.cpp | 25 +++++++++++++--- src/server/game/Entities/Unit/Unit.h | 2 ++ 5 files changed, 87 insertions(+), 4 deletions(-) create mode 100644 src/server/game/AI/CoreAI/ScheduledChangeAI.cpp create mode 100644 src/server/game/AI/CoreAI/ScheduledChangeAI.h (limited to 'src') diff --git a/src/server/game/AI/CoreAI/ScheduledChangeAI.cpp b/src/server/game/AI/CoreAI/ScheduledChangeAI.cpp new file mode 100644 index 00000000000..3bb985e80cc --- /dev/null +++ b/src/server/game/AI/CoreAI/ScheduledChangeAI.cpp @@ -0,0 +1,22 @@ +/* + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#include "ScheduledChangeAI.h" + +ScheduledChangeAI::ScheduledChangeAI(Creature* creature, uint32 scriptId /*= {}*/): CreatureAI(creature, scriptId) +{ +} diff --git a/src/server/game/AI/CoreAI/ScheduledChangeAI.h b/src/server/game/AI/CoreAI/ScheduledChangeAI.h new file mode 100644 index 00000000000..0d5970ec00d --- /dev/null +++ b/src/server/game/AI/CoreAI/ScheduledChangeAI.h @@ -0,0 +1,40 @@ +/* + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see . + */ + +#ifndef TRINITY_SCHEDULEDCHANGEAI_H +#define TRINITY_SCHEDULEDCHANGEAI_H + +#include "CreatureAI.h" + +class TC_GAME_API ScheduledChangeAI final : public CreatureAI +{ + public: + explicit ScheduledChangeAI(Creature* creature, uint32 scriptId = {}); + + void MoveInLineOfSight(Unit*) override { } + void AttackStart(Unit*) override { } + void JustStartedThreateningMe(Unit*) override { } + void JustEnteredCombat(Unit*) override { } + void UpdateAI(uint32) override { } + void JustAppeared() override { } + void EnterEvadeMode(EvadeReason /*why*/) override { } + void OnCharmed(bool /*isNew*/) override { } + + static int Permissible(Creature const* /*creature*/) { return PERMIT_BASE_NO; } +}; + +#endif diff --git a/src/server/game/AI/CreatureAIRegistry.cpp b/src/server/game/AI/CreatureAIRegistry.cpp index a1a2d3dbdb5..462dc5ae9b0 100644 --- a/src/server/game/AI/CreatureAIRegistry.cpp +++ b/src/server/game/AI/CreatureAIRegistry.cpp @@ -23,6 +23,7 @@ #include "PassiveAI.h" #include "PetAI.h" #include "ReactorAI.h" +#include "ScheduledChangeAI.h" #include "SmartAI.h" #include "TotemAI.h" #include "ObjectMgr.h" @@ -48,6 +49,7 @@ namespace AIRegistry (new CreatureAIFactory("TurretAI"))->RegisterSelf(); (new CreatureAIFactory("VehicleAI"))->RegisterSelf(); (new CreatureAIFactory("SmartAI"))->RegisterSelf(); + (new CreatureAIFactory("ScheduledChangeAI"))->RegisterSelf(); (new GameObjectAIFactory("NullGameObjectAI"))->RegisterSelf(); (new GameObjectAIFactory("GameObjectAI"))->RegisterSelf(); diff --git a/src/server/game/Entities/Unit/Unit.cpp b/src/server/game/Entities/Unit/Unit.cpp index d7a6627b609..f3cbbcf7a42 100644 --- a/src/server/game/Entities/Unit/Unit.cpp +++ b/src/server/game/Entities/Unit/Unit.cpp @@ -66,6 +66,7 @@ #include "PlayerAI.h" #include "QuestDef.h" #include "Spell.h" +#include "ScheduledChangeAI.h" #include "SpellAuraEffects.h" #include "SpellAuras.h" #include "SpellHistory.h" @@ -502,7 +503,7 @@ void Unit::Update(uint32 p_time) // All position info based actions have been executed, reset info _positionUpdateInfo.Reset(); - if (!GetAI() && (GetTypeId() != TYPEID_PLAYER || (IsCharmed() && GetCharmerGUID().IsCreature()))) + if (HasScheduledAIChange() && (GetTypeId() != TYPEID_PLAYER || (IsCharmed() && GetCharmerGUID().IsCreature()))) UpdateCharmAI(); RefreshAI(); } @@ -9218,11 +9219,11 @@ void Unit::ScheduleAIChange() bool const charmed = IsCharmed(); if (charmed) - PushAI(nullptr); + PushAI(GetScheduledChangeAI()); else { RestoreDisabledAI(); - PushAI(nullptr); //This could actually be PopAI() to get the previous AI but it's required atm to trigger UpdateCharmAI() + PushAI(GetScheduledChangeAI()); //This could actually be PopAI() to get the previous AI but it's required atm to trigger UpdateCharmAI() } } @@ -9230,10 +9231,26 @@ void Unit::RestoreDisabledAI() { // Keep popping the stack until we either reach the bottom or find a valid AI while (PopAI()) - if (GetTopAI()) + if (GetTopAI() && dynamic_cast(GetTopAI()) == nullptr) return; } +UnitAI* Unit::GetScheduledChangeAI() +{ + if (Creature* creature = ToCreature()) + return sCreatureAIRegistry->GetRegistryItem("ScheduledChangeAI")->Create(creature); + else + return nullptr; +} + +bool Unit::HasScheduledAIChange() const +{ + if (UnitAI* ai = GetAI()) + return dynamic_cast(ai) != nullptr; + else + return true; +} + void Unit::AddToWorld() { WorldObject::AddToWorld(); diff --git a/src/server/game/Entities/Unit/Unit.h b/src/server/game/Entities/Unit/Unit.h index fb4a8f17a99..ba5a12a0152 100644 --- a/src/server/game/Entities/Unit/Unit.h +++ b/src/server/game/Entities/Unit/Unit.h @@ -783,6 +783,8 @@ class TC_GAME_API Unit : public WorldObject void SetAI(UnitAI* newAI); UnitAI* GetTopAI() const { return i_AIs.empty() ? nullptr : i_AIs.top().get(); } void RefreshAI(); + UnitAI* GetScheduledChangeAI(); + bool HasScheduledAIChange() const; public: void AddToWorld() override; -- cgit v1.2.3