From 87aeaf10fdcc74caf1b5986bc988ee21a966ac41 Mon Sep 17 00:00:00 2001 From: Dan Costinas <19265585+Dantsz@users.noreply.github.com> Date: Tue, 22 Oct 2024 18:31:45 +0300 Subject: [PATCH] fix(Core/SmartAI) : use explicit stack DS for ProcessAction instead of recursion (#16739) * Use dequeue instead of recursion * Remove to do comments * Fix formatting * Fix more formatting :( * Use references instead of copies in the stack to correctly update event state * formatting * Revert FindLinkedEvent parameter name change and check for event type * Fix event processing in SmartScript::UpdateTimer * Use struct for defining SmartScriptFrame instead of tuple * Fix emplace_back not working on default constructor on clang 15 * Fix const placement --- .../game/AI/SmartScripts/SmartScript.cpp | 26 +++++++++++++++---- src/server/game/AI/SmartScripts/SmartScript.h | 22 +++++++++++++--- 2 files changed, 39 insertions(+), 9 deletions(-) diff --git a/src/server/game/AI/SmartScripts/SmartScript.cpp b/src/server/game/AI/SmartScripts/SmartScript.cpp index 91eda147d0f950..f68477ca09d662 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.cpp +++ b/src/server/game/AI/SmartScripts/SmartScript.cpp @@ -145,7 +145,16 @@ void SmartScript::ProcessEventsFor(SMART_EVENT e, Unit* unit, uint32 var0, uint3 ConditionSourceInfo info = ConditionSourceInfo(unit, GetBaseObject(), me ? me->GetVictim() : nullptr); if (sConditionMgr->IsObjectMeetToConditions(info, conds)) - ProcessEvent(*i, unit, var0, var1, bvar, spell, gob); + { + ASSERT(executionStack.empty()); + executionStack.emplace_back(SmartScriptFrame{ *i, unit, var0, var1, bvar, spell, gob }); + while (!executionStack.empty()) + { + auto [stack_holder , stack_unit, stack_var0, stack_var1, stack_bvar, stack_spell, stack_gob] = executionStack.back(); + executionStack.pop_back(); + ProcessEvent(stack_holder, stack_unit, stack_var0, stack_var1, stack_bvar, stack_spell, stack_gob); + } + } } } } @@ -3255,9 +3264,9 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u if (e.link && e.link != e.event_id) { - SmartScriptHolder linked = FindLinkedEvent(e.link); - if (linked.GetActionType() && linked.GetEventType() == SMART_EVENT_LINK) - ProcessEvent(linked, unit, var0, var1, bvar, spell, gob); + auto linked = FindLinkedEvent(e.link); + if (linked.has_value() && linked.value().get().GetEventType() == SMART_EVENT_LINK) + executionStack.emplace_back(SmartScriptFrame{ linked.value(), unit, var0, var1, bvar, spell, gob }); else LOG_ERROR("sql.sql", "SmartScript::ProcessAction: Entry {} SourceType {}, Event {}, Link Event {} not found or invalid, skipped.", e.entryOrGuid, e.GetScriptType(), e.event_id, e.link); } @@ -4852,7 +4861,14 @@ void SmartScript::UpdateTimer(SmartScriptHolder& e, uint32 const diff) case SMART_EVENT_DISTANCE_CREATURE: case SMART_EVENT_DISTANCE_GAMEOBJECT: { - ProcessEvent(e); + ASSERT(executionStack.empty()); + executionStack.emplace_back(SmartScriptFrame{ e, nullptr, 0, 0, false, nullptr, nullptr }); + while (!executionStack.empty()) + { + auto [stack_holder, stack_unit, stack_var0, stack_var1, stack_bvar, stack_spell, stack_gob] = executionStack.back(); + executionStack.pop_back(); + ProcessEvent(stack_holder, stack_unit, stack_var0, stack_var1, stack_bvar, stack_spell, stack_gob); + } if (e.GetScriptType() == SMART_SCRIPT_TYPE_TIMED_ACTIONLIST) { e.enableTimed = false;//disable event if it is in an ActionList and was processed once diff --git a/src/server/game/AI/SmartScripts/SmartScript.h b/src/server/game/AI/SmartScripts/SmartScript.h index 0f84cc2fd95fa3..361384a1cf12d3 100644 --- a/src/server/game/AI/SmartScripts/SmartScript.h +++ b/src/server/game/AI/SmartScripts/SmartScript.h @@ -25,9 +25,21 @@ #include "SmartScriptMgr.h" #include "Spell.h" #include "Unit.h" +#include class SmartScript { + struct SmartScriptFrame + { + SmartScriptHolder& holder; + Unit* unit; + uint32 var0; + uint32 var1; + bool bvar; + SpellInfo const* spell; + GameObject* gob; + }; + public: SmartScript(); ~SmartScript(); @@ -253,7 +265,8 @@ class SmartScript } } } - SmartScriptHolder FindLinkedEvent (uint32 link) + std::optional> FindLinkedEvent(uint32 link) { if (!mEvents.empty()) { @@ -261,15 +274,16 @@ class SmartScript { if (i->event_id == link) { - return (*i); + return std::ref(*i); } } } - SmartScriptHolder s; - return s; + return std::nullopt; } GuidUnorderedSet _summonList; + + std::deque executionStack; }; #endif