From 7ab3d3b1347d60a4629f6324919944bf0867ab17 Mon Sep 17 00:00:00 2001 From: Foereaper Date: Mon, 24 Nov 2025 14:53:07 +0100 Subject: [PATCH 01/13] Implement deferred timed event actions Should hopefully fix some edge case crashes during recursive event queue manipulation during update loop --- ElunaEventMgr.cpp | 94 ++++++++++++++++++++++++++--- ElunaEventMgr.h | 24 +++++++- methods/TrinityCore/GlobalMethods.h | 2 +- 3 files changed, 109 insertions(+), 11 deletions(-) diff --git a/ElunaEventMgr.cpp b/ElunaEventMgr.cpp index 6b006f4931..010cae976b 100644 --- a/ElunaEventMgr.cpp +++ b/ElunaEventMgr.cpp @@ -36,8 +36,12 @@ ElunaEventProcessor::~ElunaEventProcessor() void ElunaEventProcessor::Update(uint32 diff) { + isUpdating = true; + m_time += diff; - for (EventList::iterator it = eventList.begin(); it != eventList.end() && it->first <= m_time; it = eventList.begin()) + for (EventList::iterator it = eventList.begin(); + it != eventList.end() && it->first <= m_time; + it = eventList.begin()) { LuaEvent* luaEvent = it->second; eventList.erase(it); @@ -50,50 +54,81 @@ void ElunaEventProcessor::Update(uint32 diff) uint32 delay = luaEvent->delay; bool remove = luaEvent->repeats == 1; if (!remove) - AddEvent(luaEvent); // Reschedule before calling incase RemoveEvents used + AddEvent(luaEvent); // may be deferred if we recurse into Update - // Call the timed event - if(!obj || (obj && obj->IsInWorld())) - E->OnTimedEvent(luaEvent->funcRef, delay, luaEvent->repeats ? luaEvent->repeats-- : luaEvent->repeats, obj); + if (!obj || (obj && obj->IsInWorld())) + E->OnTimedEvent(luaEvent->funcRef, delay, + luaEvent->repeats ? luaEvent->repeats-- : luaEvent->repeats, + obj); if (!remove) continue; } - // Event should be deleted (executed last time or set to be aborted) RemoveEvent(luaEvent); } + + isUpdating = false; + ProcessDeferredOps(); } void ElunaEventProcessor::SetStates(LuaEventState state) { + if (isUpdating) + { + QueueDeferredOp(DeferredOpType::SetStates, nullptr, 0, state); + return; + } + for (EventList::iterator it = eventList.begin(); it != eventList.end(); ++it) it->second->SetState(state); + if (state == LUAEVENT_STATE_ERASE) eventMap.clear(); } void ElunaEventProcessor::RemoveEvents_internal() { + if (isUpdating) + { + QueueDeferredOp(DeferredOpType::ClearAll); + return; + } + for (EventList::iterator it = eventList.begin(); it != eventList.end(); ++it) RemoveEvent(it->second); + deferredOps.clear(); eventList.clear(); eventMap.clear(); } void ElunaEventProcessor::SetState(int eventId, LuaEventState state) { - if (eventMap.find(eventId) != eventMap.end()) - eventMap[eventId]->SetState(state); + if (isUpdating) + { + QueueDeferredOp(DeferredOpType::SetState, nullptr, eventId, state); + return; + } + + auto itr = eventMap.find(eventId); + if (itr != eventMap.end()) + itr->second->SetState(state); + if (state == LUAEVENT_STATE_ERASE) eventMap.erase(eventId); } void ElunaEventProcessor::AddEvent(LuaEvent* luaEvent) { + if (isUpdating) + { + QueueDeferredOp(DeferredOpType::AddEvent, luaEvent); + return; + } + luaEvent->GenerateDelay(); - eventList.insert(std::pair(m_time + luaEvent->delay, luaEvent)); + eventList.insert(std::make_pair(m_time + luaEvent->delay, luaEvent)); eventMap[luaEvent->funcRef] = luaEvent; } @@ -113,6 +148,47 @@ void ElunaEventProcessor::RemoveEvent(LuaEvent* luaEvent) delete luaEvent; } +void ElunaEventProcessor::QueueDeferredOp(DeferredOpType type, LuaEvent* event, int eventId, LuaEventState state) +{ + DeferredOp op; + op.type = type; + op.event = event; + op.eventId = eventId; + op.state = state; + deferredOps.push_back(op); +} + +void ElunaEventProcessor::ProcessDeferredOps() +{ + if (deferredOps.empty()) + return; + + std::vector ops; + ops.swap(deferredOps); + + for (DeferredOp& op : ops) + { + switch (op.type) + { + case DeferredOpType::AddEvent: + AddEvent(op.event); + break; + + case DeferredOpType::SetState: + SetState(op.eventId, op.state); + break; + + case DeferredOpType::SetStates: + SetStates(op.state); + break; + + case DeferredOpType::ClearAll: + RemoveEvents_internal(); + break; + } + } +} + EventMgr::EventMgr(Eluna* _E) : E(_E) { globalProcessor = std::make_unique(E, nullptr); diff --git a/ElunaEventMgr.h b/ElunaEventMgr.h index cdad3f6146..93e0f9146b 100644 --- a/ElunaEventMgr.h +++ b/ElunaEventMgr.h @@ -79,13 +79,35 @@ class ElunaEventProcessor // set the event to be removed when executing void SetState(int eventId, LuaEventState state); void AddEvent(int funcRef, uint32 min, uint32 max, uint32 repeats); - EventMap eventMap; private: + enum class DeferredOpType + { + AddEvent, + SetState, + SetStates, + ClearAll + }; + + struct DeferredOp + { + DeferredOpType type; + LuaEvent* event = nullptr; + int eventId = 0; + LuaEventState state = LUAEVENT_STATE_RUN; + }; + void RemoveEvents_internal(); void AddEvent(LuaEvent* luaEvent); void RemoveEvent(LuaEvent* luaEvent); + + void QueueDeferredOp(DeferredOpType type, LuaEvent* event = nullptr, int eventId = 0, LuaEventState state = LUAEVENT_STATE_RUN); + void ProcessDeferredOps(); + bool isUpdating = false; + std::vector deferredOps; + EventList eventList; + EventMap eventMap; uint64 m_time; WorldObject* obj; Eluna* E; diff --git a/methods/TrinityCore/GlobalMethods.h b/methods/TrinityCore/GlobalMethods.h index ff3fd02567..96ab2903e5 100644 --- a/methods/TrinityCore/GlobalMethods.h +++ b/methods/TrinityCore/GlobalMethods.h @@ -1609,7 +1609,7 @@ namespace LuaGlobalFunctions int RemoveEventById(Eluna* E) { int eventId = E->CHECKVAL(1); - bool all_Events = E->CHECKVAL(1, false); + bool all_Events = E->CHECKVAL(2, false); // not thread safe if (all_Events) From 964185275d0468fb894b51ee6523c3e19d13b333 Mon Sep 17 00:00:00 2001 From: Foereaper Date: Mon, 24 Nov 2025 15:00:39 +0100 Subject: [PATCH 02/13] Wrapping cleanup --- ElunaEventMgr.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/ElunaEventMgr.cpp b/ElunaEventMgr.cpp index 010cae976b..4cede81bf6 100644 --- a/ElunaEventMgr.cpp +++ b/ElunaEventMgr.cpp @@ -39,9 +39,7 @@ void ElunaEventProcessor::Update(uint32 diff) isUpdating = true; m_time += diff; - for (EventList::iterator it = eventList.begin(); - it != eventList.end() && it->first <= m_time; - it = eventList.begin()) + for (EventList::iterator it = eventList.begin(); it != eventList.end() && it->first <= m_time; it = eventList.begin()) { LuaEvent* luaEvent = it->second; eventList.erase(it); @@ -57,9 +55,7 @@ void ElunaEventProcessor::Update(uint32 diff) AddEvent(luaEvent); // may be deferred if we recurse into Update if (!obj || (obj && obj->IsInWorld())) - E->OnTimedEvent(luaEvent->funcRef, delay, - luaEvent->repeats ? luaEvent->repeats-- : luaEvent->repeats, - obj); + E->OnTimedEvent(luaEvent->funcRef, delay, luaEvent->repeats ? luaEvent->repeats-- : luaEvent->repeats, obj); if (!remove) continue; From 121958f6b43c3e4e2be2fd8fc22e8a5ceee4ad07 Mon Sep 17 00:00:00 2001 From: Foereaper Date: Mon, 24 Nov 2025 15:49:00 +0100 Subject: [PATCH 03/13] Copy processors before update --- ElunaEventMgr.cpp | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/ElunaEventMgr.cpp b/ElunaEventMgr.cpp index 4cede81bf6..11452cb84d 100644 --- a/ElunaEventMgr.cpp +++ b/ElunaEventMgr.cpp @@ -192,32 +192,38 @@ EventMgr::EventMgr(Eluna* _E) : E(_E) EventMgr::~EventMgr() { - if (!processors.empty()) - for (ProcessorSet::const_iterator it = processors.begin(); it != processors.end(); ++it) // loop processors - (*it)->RemoveEvents_internal(); + for (auto* processor : processors) + processor->RemoveEvents_internal(); + globalProcessor->RemoveEvents_internal(); } void EventMgr::UpdateProcessors(uint32 diff) { if (!processors.empty()) - for (ProcessorSet::const_iterator it = processors.begin(); it != processors.end(); ++it) // loop processors - (*it)->Update(diff); + { + // iterate a copy because processors may be destroyed during update (creature removed by a script, etc) + ProcessorSet copy = processors; + + for (auto* processor : copy) + processor->Update(diff); + } + globalProcessor->Update(diff); } void EventMgr::SetStates(LuaEventState state) { - if (!processors.empty()) - for (ProcessorSet::const_iterator it = processors.begin(); it != processors.end(); ++it) // loop processors - (*it)->SetStates(state); + for (auto* processor : processors) + processor->SetStates(state); + globalProcessor->SetStates(state); } void EventMgr::SetState(int eventId, LuaEventState state) { - if (!processors.empty()) - for (ProcessorSet::const_iterator it = processors.begin(); it != processors.end(); ++it) // loop processors - (*it)->SetState(eventId, state); + for (auto* processor : processors) + processor->SetState(eventId, state); + globalProcessor->SetState(eventId, state); } From 49937a58a5d8d4cb07ff28af7c1ac0ec6b2c38f5 Mon Sep 17 00:00:00 2001 From: Foereaper Date: Mon, 24 Nov 2025 16:44:08 +0100 Subject: [PATCH 04/13] Move state-owned timed events to generic processor list --- ElunaEventMgr.cpp | 34 ++++++++++++++--------------- ElunaEventMgr.h | 28 ++++++++++++++---------- methods/TrinityCore/GlobalMethods.h | 6 ++--- 3 files changed, 37 insertions(+), 31 deletions(-) diff --git a/ElunaEventMgr.cpp b/ElunaEventMgr.cpp index 11452cb84d..df5c9afa1c 100644 --- a/ElunaEventMgr.cpp +++ b/ElunaEventMgr.cpp @@ -20,17 +20,15 @@ extern "C" ElunaEventProcessor::ElunaEventProcessor(Eluna* _E, WorldObject* _obj) : m_time(0), obj(_obj), E(_E) { - if (obj) + if (E->eventMgr) E->eventMgr->processors.insert(this); } ElunaEventProcessor::~ElunaEventProcessor() { - { - RemoveEvents_internal(); - } + RemoveEvents_internal(); - if (obj) + if (E->eventMgr) E->eventMgr->processors.erase(this); } @@ -187,7 +185,9 @@ void ElunaEventProcessor::ProcessDeferredOps() EventMgr::EventMgr(Eluna* _E) : E(_E) { - globalProcessor = std::make_unique(E, nullptr); + auto gp = std::make_unique(E, nullptr); + processors.insert(gp.get()); + globalProcessors.emplace(GLOBAL_EVENTS, std::move(gp)); } EventMgr::~EventMgr() @@ -195,35 +195,35 @@ EventMgr::~EventMgr() for (auto* processor : processors) processor->RemoveEvents_internal(); - globalProcessor->RemoveEvents_internal(); + globalProcessors.clear(); } void EventMgr::UpdateProcessors(uint32 diff) { - if (!processors.empty()) - { - // iterate a copy because processors may be destroyed during update (creature removed by a script, etc) - ProcessorSet copy = processors; + // iterate a copy because processors may be destroyed during update (creature removed by a script, etc) + ProcessorSet copy = processors; - for (auto* processor : copy) + for (auto* processor : copy) + { + if (processors.find(processor) != processors.end()) processor->Update(diff); } - - globalProcessor->Update(diff); } void EventMgr::SetStates(LuaEventState state) { for (auto* processor : processors) processor->SetStates(state); - - globalProcessor->SetStates(state); } void EventMgr::SetState(int eventId, LuaEventState state) { for (auto* processor : processors) processor->SetState(eventId, state); +} - globalProcessor->SetState(eventId, state); +ElunaEventProcessor* EventMgr::GetGlobalProcessor(GlobalEventSpace space) +{ + auto it = globalProcessors.find(space); + return (it != globalProcessors.end()) ? it->second.get() : nullptr; } diff --git a/ElunaEventMgr.h b/ElunaEventMgr.h index 93e0f9146b..565579b56b 100644 --- a/ElunaEventMgr.h +++ b/ElunaEventMgr.h @@ -36,6 +36,11 @@ enum LuaEventState LUAEVENT_STATE_ERASE, // On next call just erases the data }; +enum GlobalEventSpace +{ + GLOBAL_EVENTS +}; + struct LuaEvent { LuaEvent(int _funcRef, uint32 _min, uint32 _max, uint32 _repeats) : @@ -116,23 +121,24 @@ class ElunaEventProcessor class EventMgr { public: - typedef std::unordered_set ProcessorSet; - ProcessorSet processors; - std::unique_ptr globalProcessor; - Eluna* E; - EventMgr(Eluna* _E); ~EventMgr(); - // Set the state of all timed events - // Execute only in safe env + void UpdateProcessors(uint32 diff); void SetStates(LuaEventState state); - - // Sets the eventId's state in all processors - // Execute only in safe env void SetState(int eventId, LuaEventState state); - void UpdateProcessors(uint32 diff); + ElunaEventProcessor* GetGlobalProcessor(GlobalEventSpace space); + +private: + typedef std::unordered_set ProcessorSet; + + ProcessorSet processors; // tracks ALL processors (object + global) + std::unordered_map> globalProcessors; + + Eluna* E; + + friend class ElunaEventProcessor; }; #endif diff --git a/methods/TrinityCore/GlobalMethods.h b/methods/TrinityCore/GlobalMethods.h index 96ab2903e5..28058ada04 100644 --- a/methods/TrinityCore/GlobalMethods.h +++ b/methods/TrinityCore/GlobalMethods.h @@ -1594,7 +1594,7 @@ namespace LuaGlobalFunctions int functionRef = luaL_ref(E->L, LUA_REGISTRYINDEX); if (functionRef != LUA_REFNIL && functionRef != LUA_NOREF) { - E->eventMgr->globalProcessor->AddEvent(functionRef, min, max, repeats); + E->eventMgr->GetGlobalProcessor(GLOBAL_EVENTS)->AddEvent(functionRef, min, max, repeats); E->Push(functionRef); } return 1; @@ -1615,7 +1615,7 @@ namespace LuaGlobalFunctions if (all_Events) E->eventMgr->SetState(eventId, LUAEVENT_STATE_ABORT); else - E->eventMgr->globalProcessor->SetState(eventId, LUAEVENT_STATE_ABORT); + E->eventMgr->GetGlobalProcessor(GLOBAL_EVENTS)->SetState(eventId, LUAEVENT_STATE_ABORT); return 0; } @@ -1632,7 +1632,7 @@ namespace LuaGlobalFunctions if (all_Events) E->eventMgr->SetStates(LUAEVENT_STATE_ABORT); else - E->eventMgr->globalProcessor->SetStates(LUAEVENT_STATE_ABORT); + E->eventMgr->GetGlobalProcessor(GLOBAL_EVENTS)->SetStates(LUAEVENT_STATE_ABORT); return 0; } From 4de365ce6f257e8f7c5bcb9abc52eaa71d1bd912 Mon Sep 17 00:00:00 2001 From: Foereaper Date: Mon, 24 Nov 2025 17:01:53 +0100 Subject: [PATCH 05/13] Update global processor call for other cores --- methods/CMangos/GlobalMethods.h | 6 +++--- methods/Mangos/GlobalMethods.h | 6 +++--- methods/VMangos/GlobalMethods.h | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/methods/CMangos/GlobalMethods.h b/methods/CMangos/GlobalMethods.h index 13e08024c4..af0d2fed42 100644 --- a/methods/CMangos/GlobalMethods.h +++ b/methods/CMangos/GlobalMethods.h @@ -1600,7 +1600,7 @@ namespace LuaGlobalFunctions int functionRef = luaL_ref(E->L, LUA_REGISTRYINDEX); if (functionRef != LUA_REFNIL && functionRef != LUA_NOREF) { - E->eventMgr->globalProcessor->AddEvent(functionRef, min, max, repeats); + E->eventMgr->GetGlobalProcessor(GLOBAL_EVENTS)->AddEvent(functionRef, min, max, repeats); E->Push(functionRef); } return 1; @@ -1621,7 +1621,7 @@ namespace LuaGlobalFunctions if (all_Events) E->eventMgr->SetState(eventId, LUAEVENT_STATE_ABORT); else - E->eventMgr->globalProcessor->SetState(eventId, LUAEVENT_STATE_ABORT); + E->eventMgr->GetGlobalProcessor(GLOBAL_EVENTS)->SetState(eventId, LUAEVENT_STATE_ABORT); return 0; } @@ -1638,7 +1638,7 @@ namespace LuaGlobalFunctions if (all_Events) E->eventMgr->SetStates(LUAEVENT_STATE_ABORT); else - E->eventMgr->globalProcessor->SetStates(LUAEVENT_STATE_ABORT); + E->eventMgr->GetGlobalProcessor(GLOBAL_EVENTS)->SetStates(LUAEVENT_STATE_ABORT); return 0; } diff --git a/methods/Mangos/GlobalMethods.h b/methods/Mangos/GlobalMethods.h index 1aeabfa98d..8aed24cdd5 100644 --- a/methods/Mangos/GlobalMethods.h +++ b/methods/Mangos/GlobalMethods.h @@ -1394,7 +1394,7 @@ namespace LuaGlobalFunctions int functionRef = luaL_ref(E->L, LUA_REGISTRYINDEX); if (functionRef != LUA_REFNIL && functionRef != LUA_NOREF) { - E->eventMgr->globalProcessor->AddEvent(functionRef, min, max, repeats); + E->eventMgr->GetGlobalProcessor(GLOBAL_EVENTS)->AddEvent(functionRef, min, max, repeats); E->Push(functionRef); } return 1; @@ -1415,7 +1415,7 @@ namespace LuaGlobalFunctions if (all_Events) E->eventMgr->SetState(eventId, LUAEVENT_STATE_ABORT); else - E->eventMgr->globalProcessor->SetState(eventId, LUAEVENT_STATE_ABORT); + E->eventMgr->GetGlobalProcessor(GLOBAL_EVENTS)->SetState(eventId, LUAEVENT_STATE_ABORT); return 0; } @@ -1432,7 +1432,7 @@ namespace LuaGlobalFunctions if (all_Events) E->eventMgr->SetStates(LUAEVENT_STATE_ABORT); else - E->eventMgr->globalProcessor->SetStates(LUAEVENT_STATE_ABORT); + E->eventMgr->GetGlobalProcessor(GLOBAL_EVENTS)->SetStates(LUAEVENT_STATE_ABORT); return 0; } diff --git a/methods/VMangos/GlobalMethods.h b/methods/VMangos/GlobalMethods.h index b77ec26255..2eb712ca13 100644 --- a/methods/VMangos/GlobalMethods.h +++ b/methods/VMangos/GlobalMethods.h @@ -1390,7 +1390,7 @@ namespace LuaGlobalFunctions int functionRef = luaL_ref(E->L, LUA_REGISTRYINDEX); if (functionRef != LUA_REFNIL && functionRef != LUA_NOREF) { - E->eventMgr->globalProcessor->AddEvent(functionRef, min, max, repeats); + E->eventMgr->GetGlobalProcessor(GLOBAL_EVENTS)->AddEvent(functionRef, min, max, repeats); E->Push(functionRef); } return 1; @@ -1411,7 +1411,7 @@ namespace LuaGlobalFunctions if (all_Events) E->eventMgr->SetState(eventId, LUAEVENT_STATE_ABORT); else - E->eventMgr->globalProcessor->SetState(eventId, LUAEVENT_STATE_ABORT); + E->eventMgr->GetGlobalProcessor(GLOBAL_EVENTS)->SetState(eventId, LUAEVENT_STATE_ABORT); return 0; } @@ -1428,7 +1428,7 @@ namespace LuaGlobalFunctions if (all_Events) E->eventMgr->SetStates(LUAEVENT_STATE_ABORT); else - E->eventMgr->globalProcessor->SetStates(LUAEVENT_STATE_ABORT); + E->eventMgr->GetGlobalProcessor(GLOBAL_EVENTS)->SetStates(LUAEVENT_STATE_ABORT); return 0; } From 2103ce73da428cfbd2f3b416f9545ea363c857ad Mon Sep 17 00:00:00 2001 From: Foereaper Date: Mon, 24 Nov 2025 17:33:20 +0100 Subject: [PATCH 06/13] Clean up naming convention and EventMgr destructor --- ElunaEventMgr.cpp | 12 +++++------- ElunaEventMgr.h | 4 ++-- LuaEngine.cpp | 2 +- methods/CMangos/GlobalMethods.h | 4 ++-- methods/Mangos/GlobalMethods.h | 4 ++-- methods/TrinityCore/GlobalMethods.h | 4 ++-- methods/VMangos/GlobalMethods.h | 4 ++-- 7 files changed, 16 insertions(+), 18 deletions(-) diff --git a/ElunaEventMgr.cpp b/ElunaEventMgr.cpp index df5c9afa1c..06d5abe1b6 100644 --- a/ElunaEventMgr.cpp +++ b/ElunaEventMgr.cpp @@ -20,7 +20,7 @@ extern "C" ElunaEventProcessor::ElunaEventProcessor(Eluna* _E, WorldObject* _obj) : m_time(0), obj(_obj), E(_E) { - if (E->eventMgr) + if (E && E->eventMgr) E->eventMgr->processors.insert(this); } @@ -28,7 +28,7 @@ ElunaEventProcessor::~ElunaEventProcessor() { RemoveEvents_internal(); - if (E->eventMgr) + if (E && E->eventMgr) E->eventMgr->processors.erase(this); } @@ -192,10 +192,8 @@ EventMgr::EventMgr(Eluna* _E) : E(_E) EventMgr::~EventMgr() { - for (auto* processor : processors) - processor->RemoveEvents_internal(); - globalProcessors.clear(); + processors.clear(); } void EventMgr::UpdateProcessors(uint32 diff) @@ -210,13 +208,13 @@ void EventMgr::UpdateProcessors(uint32 diff) } } -void EventMgr::SetStates(LuaEventState state) +void EventMgr::SetAllEventStates(LuaEventState state) { for (auto* processor : processors) processor->SetStates(state); } -void EventMgr::SetState(int eventId, LuaEventState state) +void EventMgr::SetEventState(int eventId, LuaEventState state) { for (auto* processor : processors) processor->SetState(eventId, state); diff --git a/ElunaEventMgr.h b/ElunaEventMgr.h index 565579b56b..a6a8a7ac24 100644 --- a/ElunaEventMgr.h +++ b/ElunaEventMgr.h @@ -125,8 +125,8 @@ class EventMgr ~EventMgr(); void UpdateProcessors(uint32 diff); - void SetStates(LuaEventState state); - void SetState(int eventId, LuaEventState state); + void SetAllEventStates(LuaEventState state); + void SetEventState(int eventId, LuaEventState state); ElunaEventProcessor* GetGlobalProcessor(GlobalEventSpace space); diff --git a/LuaEngine.cpp b/LuaEngine.cpp index a0fb2ac6b3..1be89b9769 100644 --- a/LuaEngine.cpp +++ b/LuaEngine.cpp @@ -33,7 +33,7 @@ extern void RegisterMethods(Eluna* E); void Eluna::_ReloadEluna() { // Remove all timed events - eventMgr->SetStates(LUAEVENT_STATE_ERASE); + eventMgr->SetAllEventStates(LUAEVENT_STATE_ERASE); #if defined ELUNA_TRINITY // Cancel all pending async queries diff --git a/methods/CMangos/GlobalMethods.h b/methods/CMangos/GlobalMethods.h index af0d2fed42..fc821dc42e 100644 --- a/methods/CMangos/GlobalMethods.h +++ b/methods/CMangos/GlobalMethods.h @@ -1619,7 +1619,7 @@ namespace LuaGlobalFunctions // not thread safe if (all_Events) - E->eventMgr->SetState(eventId, LUAEVENT_STATE_ABORT); + E->eventMgr->SetEventState(eventId, LUAEVENT_STATE_ABORT); else E->eventMgr->GetGlobalProcessor(GLOBAL_EVENTS)->SetState(eventId, LUAEVENT_STATE_ABORT); return 0; @@ -1636,7 +1636,7 @@ namespace LuaGlobalFunctions // not thread safe if (all_Events) - E->eventMgr->SetStates(LUAEVENT_STATE_ABORT); + E->eventMgr->SetAllEventStates(LUAEVENT_STATE_ABORT); else E->eventMgr->GetGlobalProcessor(GLOBAL_EVENTS)->SetStates(LUAEVENT_STATE_ABORT); return 0; diff --git a/methods/Mangos/GlobalMethods.h b/methods/Mangos/GlobalMethods.h index 8aed24cdd5..7ec43330e7 100644 --- a/methods/Mangos/GlobalMethods.h +++ b/methods/Mangos/GlobalMethods.h @@ -1413,7 +1413,7 @@ namespace LuaGlobalFunctions // not thread safe if (all_Events) - E->eventMgr->SetState(eventId, LUAEVENT_STATE_ABORT); + E->eventMgr->SetEventState(eventId, LUAEVENT_STATE_ABORT); else E->eventMgr->GetGlobalProcessor(GLOBAL_EVENTS)->SetState(eventId, LUAEVENT_STATE_ABORT); return 0; @@ -1430,7 +1430,7 @@ namespace LuaGlobalFunctions // not thread safe if (all_Events) - E->eventMgr->SetStates(LUAEVENT_STATE_ABORT); + E->eventMgr->SetAllEventStates(LUAEVENT_STATE_ABORT); else E->eventMgr->GetGlobalProcessor(GLOBAL_EVENTS)->SetStates(LUAEVENT_STATE_ABORT); return 0; diff --git a/methods/TrinityCore/GlobalMethods.h b/methods/TrinityCore/GlobalMethods.h index 28058ada04..31680ca980 100644 --- a/methods/TrinityCore/GlobalMethods.h +++ b/methods/TrinityCore/GlobalMethods.h @@ -1613,7 +1613,7 @@ namespace LuaGlobalFunctions // not thread safe if (all_Events) - E->eventMgr->SetState(eventId, LUAEVENT_STATE_ABORT); + E->eventMgr->SetEventState(eventId, LUAEVENT_STATE_ABORT); else E->eventMgr->GetGlobalProcessor(GLOBAL_EVENTS)->SetState(eventId, LUAEVENT_STATE_ABORT); return 0; @@ -1630,7 +1630,7 @@ namespace LuaGlobalFunctions // not thread safe if (all_Events) - E->eventMgr->SetStates(LUAEVENT_STATE_ABORT); + E->eventMgr->SetAllEventStates(LUAEVENT_STATE_ABORT); else E->eventMgr->GetGlobalProcessor(GLOBAL_EVENTS)->SetStates(LUAEVENT_STATE_ABORT); return 0; diff --git a/methods/VMangos/GlobalMethods.h b/methods/VMangos/GlobalMethods.h index 2eb712ca13..38c6500fa8 100644 --- a/methods/VMangos/GlobalMethods.h +++ b/methods/VMangos/GlobalMethods.h @@ -1409,7 +1409,7 @@ namespace LuaGlobalFunctions // not thread safe if (all_Events) - E->eventMgr->SetState(eventId, LUAEVENT_STATE_ABORT); + E->eventMgr->SetEventState(eventId, LUAEVENT_STATE_ABORT); else E->eventMgr->GetGlobalProcessor(GLOBAL_EVENTS)->SetState(eventId, LUAEVENT_STATE_ABORT); return 0; @@ -1426,7 +1426,7 @@ namespace LuaGlobalFunctions // not thread safe if (all_Events) - E->eventMgr->SetStates(LUAEVENT_STATE_ABORT); + E->eventMgr->SetAllEventStates(LUAEVENT_STATE_ABORT); else E->eventMgr->GetGlobalProcessor(GLOBAL_EVENTS)->SetStates(LUAEVENT_STATE_ABORT); return 0; From 09ab37c915e1dc5a7dd3837c9f175b214a857698 Mon Sep 17 00:00:00 2001 From: Foereaper Date: Tue, 25 Nov 2025 18:07:30 +0100 Subject: [PATCH 07/13] Move object processor ownership to the EventMgr Objects retain a process info object with a key to fetch the correct processor We only create processors lazily whenever they are required instead of always initializing them --- ElunaEventMgr.cpp | 75 ++++++++++++++++++++---- ElunaEventMgr.h | 53 +++++++++++++---- methods/TrinityCore/WorldObjectMethods.h | 23 +++++++- 3 files changed, 123 insertions(+), 28 deletions(-) diff --git a/ElunaEventMgr.cpp b/ElunaEventMgr.cpp index 06d5abe1b6..2ab72350bc 100644 --- a/ElunaEventMgr.cpp +++ b/ElunaEventMgr.cpp @@ -1,9 +1,3 @@ -/* -* Copyright (C) 2010 - 2024 Eluna Lua Engine -* This program is free software licensed under GPL version 3 -* Please see the included DOCS/LICENSE.md for more information -*/ - #include "ElunaEventMgr.h" #include "LuaEngine.h" #if !defined ELUNA_CMANGOS @@ -20,16 +14,11 @@ extern "C" ElunaEventProcessor::ElunaEventProcessor(Eluna* _E, WorldObject* _obj) : m_time(0), obj(_obj), E(_E) { - if (E && E->eventMgr) - E->eventMgr->processors.insert(this); } ElunaEventProcessor::~ElunaEventProcessor() { RemoveEvents_internal(); - - if (E && E->eventMgr) - E->eventMgr->processors.erase(this); } void ElunaEventProcessor::Update(uint32 diff) @@ -183,6 +172,12 @@ void ElunaEventProcessor::ProcessDeferredOps() } } +ElunaProcessorInfo::~ElunaProcessorInfo() +{ + if (mgr) + mgr->FlagObjectProcessorForDeletion(processorId); +} + EventMgr::EventMgr(Eluna* _E) : E(_E) { auto gp = std::make_unique(E, nullptr); @@ -193,7 +188,9 @@ EventMgr::EventMgr(Eluna* _E) : E(_E) EventMgr::~EventMgr() { globalProcessors.clear(); + objectProcessors.clear(); processors.clear(); + objectProcessorsPendingDelete.clear(); } void EventMgr::UpdateProcessors(uint32 diff) @@ -204,8 +201,11 @@ void EventMgr::UpdateProcessors(uint32 diff) for (auto* processor : copy) { if (processors.find(processor) != processors.end()) - processor->Update(diff); + if (!processor->pendingDeletion) + processor->Update(diff); } + + CleanupObjectProcessors(); } void EventMgr::SetAllEventStates(LuaEventState state) @@ -225,3 +225,54 @@ ElunaEventProcessor* EventMgr::GetGlobalProcessor(GlobalEventSpace space) auto it = globalProcessors.find(space); return (it != globalProcessors.end()) ? it->second.get() : nullptr; } + +uint64 EventMgr::CreateObjectProcessor(WorldObject* obj) +{ + uint64 id = nextProcessorId++; + auto proc = std::make_unique(E, obj); + ElunaEventProcessor* raw = proc.get(); + + processors.insert(raw); + objectProcessors.emplace(id, std::move(proc)); + + return id; +} + +ElunaEventProcessor* EventMgr::GetObjectProcessor(uint64 processorId) +{ + auto it = objectProcessors.find(processorId); + return it == objectProcessors.end() ? nullptr : it->second.get(); +} + +void EventMgr::FlagObjectProcessorForDeletion(uint64 processorId) +{ + auto it = objectProcessors.find(processorId); + if (it == objectProcessors.end()) + return; + + ElunaEventProcessor* p = it->second.get(); + if (!p->pendingDeletion) + { + p->pendingDeletion = true; + p->obj = nullptr; + objectProcessorsPendingDelete.insert(processorId); + } +} + +void EventMgr::CleanupObjectProcessors() +{ + for (uint64 processorId : objectProcessorsPendingDelete) + { + auto it = objectProcessors.find(processorId); + if (it == objectProcessors.end()) + continue; + + ElunaEventProcessor* p = it->second.get(); + p->SetStates(LUAEVENT_STATE_ERASE); + + processors.erase(p); + objectProcessors.erase(it); + } + + objectProcessorsPendingDelete.clear(); +} diff --git a/ElunaEventMgr.h b/ElunaEventMgr.h index a6a8a7ac24..243b79efce 100644 --- a/ElunaEventMgr.h +++ b/ElunaEventMgr.h @@ -1,9 +1,3 @@ -/* -* Copyright (C) 2010 - 2024 Eluna Lua Engine -* This program is free software licensed under GPL version 3 -* Please see the included DOCS/LICENSE.md for more information -*/ - #ifndef _ELUNA_EVENT_MGR_H #define _ELUNA_EVENT_MGR_H @@ -59,12 +53,12 @@ struct LuaEvent delay = urand(min, max); } - uint32 min; // Minimum delay between event calls - uint32 max; // Maximum delay between event calls - uint32 delay; // The currently used waiting time - uint32 repeats; // Amount of repeats to make, 0 for infinite - int funcRef; // Lua function reference ID, also used as event ID - LuaEventState state; // State for next call + uint32 min; // Minimum delay between event calls + uint32 max; // Maximum delay between event calls + uint32 delay; // The currently used waiting time + uint32 repeats; // Amount of repeats to make, 0 for infinite + int funcRef; // Lua function reference ID, also used as event ID + LuaEventState state; // State for next call }; class ElunaEventProcessor @@ -114,10 +108,29 @@ class ElunaEventProcessor EventList eventList; EventMap eventMap; uint64 m_time; + + bool pendingDeletion = false; + WorldObject* obj; Eluna* E; }; +class ElunaProcessorInfo +{ +public: + ElunaProcessorInfo(EventMgr* mgr, uint64 processorId) + : mgr(mgr), processorId(processorId) { + } + + ~ElunaProcessorInfo(); + + uint64 GetProcessorId() const { return processorId; } + +private: + EventMgr* mgr; + uint64 processorId; +}; + class EventMgr { public: @@ -130,15 +143,29 @@ class EventMgr ElunaEventProcessor* GetGlobalProcessor(GlobalEventSpace space); + // Per-object processors (keyed by internal processorId) + uint64 CreateObjectProcessor(WorldObject* obj); + ElunaEventProcessor* GetObjectProcessor(uint64 processorId); + void FlagObjectProcessorForDeletion(uint64 processorId); + private: typedef std::unordered_set ProcessorSet; + typedef std::unordered_map> ObjectProcessorMap; + typedef std::unordered_map> GlobalProcessorsMap; ProcessorSet processors; // tracks ALL processors (object + global) - std::unordered_map> globalProcessors; + GlobalProcessorsMap globalProcessors; + ObjectProcessorMap objectProcessors; + std::unordered_set objectProcessorsPendingDelete; Eluna* E; + uint64 nextProcessorId = 1; // internal ID generator + + void CleanupObjectProcessors(); + friend class ElunaEventProcessor; + friend class ElunaProcessorInfo; }; #endif diff --git a/methods/TrinityCore/WorldObjectMethods.h b/methods/TrinityCore/WorldObjectMethods.h index 32118558ae..0dc9591c0a 100644 --- a/methods/TrinityCore/WorldObjectMethods.h +++ b/methods/TrinityCore/WorldObjectMethods.h @@ -765,7 +765,15 @@ namespace LuaWorldObject int functionRef = luaL_ref(E->L, LUA_REGISTRYINDEX); if (functionRef != LUA_REFNIL && functionRef != LUA_NOREF) { - obj->GetElunaEvents(E->GetBoundMapId())->AddEvent(functionRef, min, max, repeats); + ElunaEventProcessor* proc = obj->GetElunaEvents(E->GetBoundMapId()); + if (!proc) + { + luaL_unref(E->L, LUA_REGISTRYINDEX, functionRef); + E->Push(); + return 1; + } + + proc->AddEvent(functionRef, min, max, repeats); E->Push(functionRef); } return 1; @@ -779,7 +787,12 @@ namespace LuaWorldObject int RemoveEventById(Eluna* E, WorldObject* obj) { int eventId = E->CHECKVAL(2); - obj->GetElunaEvents(E->GetBoundMapId())->SetState(eventId, LUAEVENT_STATE_ABORT); + + ElunaEventProcessor* proc = obj->GetElunaEvents(E->GetBoundMapId()); + if (!proc) + return 0; + + proc->SetState(eventId, LUAEVENT_STATE_ABORT); return 0; } @@ -788,7 +801,11 @@ namespace LuaWorldObject */ int RemoveEvents(Eluna* E, WorldObject* obj) { - obj->GetElunaEvents(E->GetBoundMapId())->SetStates(LUAEVENT_STATE_ABORT); + ElunaEventProcessor* proc = obj->GetElunaEvents(E->GetBoundMapId()); + if (!proc) + return 0; + + proc->SetStates(LUAEVENT_STATE_ABORT); return 0; } From 1fef70b748bfe13f618b8e58546f14d1bd5a1793 Mon Sep 17 00:00:00 2001 From: Foereaper Date: Tue, 25 Nov 2025 18:10:27 +0100 Subject: [PATCH 08/13] Remove accidentally removed headers --- ElunaEventMgr.cpp | 6 ++++++ ElunaEventMgr.h | 18 ++++++++++++------ 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/ElunaEventMgr.cpp b/ElunaEventMgr.cpp index 2ab72350bc..91764ef711 100644 --- a/ElunaEventMgr.cpp +++ b/ElunaEventMgr.cpp @@ -1,3 +1,9 @@ +/* +* Copyright (C) 2010 - 2024 Eluna Lua Engine +* This program is free software licensed under GPL version 3 +* Please see the included DOCS/LICENSE.md for more information +*/ + #include "ElunaEventMgr.h" #include "LuaEngine.h" #if !defined ELUNA_CMANGOS diff --git a/ElunaEventMgr.h b/ElunaEventMgr.h index 243b79efce..1151c21b86 100644 --- a/ElunaEventMgr.h +++ b/ElunaEventMgr.h @@ -1,3 +1,9 @@ +/* +* Copyright (C) 2010 - 2024 Eluna Lua Engine +* This program is free software licensed under GPL version 3 +* Please see the included DOCS/LICENSE.md for more information +*/ + #ifndef _ELUNA_EVENT_MGR_H #define _ELUNA_EVENT_MGR_H @@ -53,12 +59,12 @@ struct LuaEvent delay = urand(min, max); } - uint32 min; // Minimum delay between event calls - uint32 max; // Maximum delay between event calls - uint32 delay; // The currently used waiting time - uint32 repeats; // Amount of repeats to make, 0 for infinite - int funcRef; // Lua function reference ID, also used as event ID - LuaEventState state; // State for next call + uint32 min; // Minimum delay between event calls + uint32 max; // Maximum delay between event calls + uint32 delay; // The currently used waiting time + uint32 repeats; // Amount of repeats to make, 0 for infinite + int funcRef; // Lua function reference ID, also used as event ID + LuaEventState state; // State for next call }; class ElunaEventProcessor From 6dcd7e7603651a430bea0c616dbf3acfac08a7e1 Mon Sep 17 00:00:00 2001 From: Foereaper Date: Fri, 28 Nov 2025 23:04:09 +0100 Subject: [PATCH 09/13] Switch to using GUID as hashmap key --- ElunaEventMgr.cpp | 4 ++-- ElunaEventMgr.h | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/ElunaEventMgr.cpp b/ElunaEventMgr.cpp index 91764ef711..c005b84640 100644 --- a/ElunaEventMgr.cpp +++ b/ElunaEventMgr.cpp @@ -234,7 +234,7 @@ ElunaEventProcessor* EventMgr::GetGlobalProcessor(GlobalEventSpace space) uint64 EventMgr::CreateObjectProcessor(WorldObject* obj) { - uint64 id = nextProcessorId++; + uint64 id = obj->GetGUID().GetRawValue(); auto proc = std::make_unique(E, obj); ElunaEventProcessor* raw = proc.get(); @@ -247,7 +247,7 @@ uint64 EventMgr::CreateObjectProcessor(WorldObject* obj) ElunaEventProcessor* EventMgr::GetObjectProcessor(uint64 processorId) { auto it = objectProcessors.find(processorId); - return it == objectProcessors.end() ? nullptr : it->second.get(); + return (it != objectProcessors.end()) ? it->second.get() : nullptr; } void EventMgr::FlagObjectProcessorForDeletion(uint64 processorId) diff --git a/ElunaEventMgr.h b/ElunaEventMgr.h index 1151c21b86..a61da6ebaa 100644 --- a/ElunaEventMgr.h +++ b/ElunaEventMgr.h @@ -125,7 +125,8 @@ class ElunaProcessorInfo { public: ElunaProcessorInfo(EventMgr* mgr, uint64 processorId) - : mgr(mgr), processorId(processorId) { + : mgr(mgr), processorId(processorId) + { } ~ElunaProcessorInfo(); @@ -166,8 +167,6 @@ class EventMgr Eluna* E; - uint64 nextProcessorId = 1; // internal ID generator - void CleanupObjectProcessors(); friend class ElunaEventProcessor; From 71e0aa7cce255b063e8892e86f0aa98a3b58e765 Mon Sep 17 00:00:00 2001 From: Foereaper Date: Sat, 29 Nov 2025 13:43:33 +0100 Subject: [PATCH 10/13] PR cleanup --- ElunaEventMgr.cpp | 27 +++++++++++++-------------- ElunaEventMgr.h | 20 +++++++------------- 2 files changed, 20 insertions(+), 27 deletions(-) diff --git a/ElunaEventMgr.cpp b/ElunaEventMgr.cpp index c005b84640..91f809b24d 100644 --- a/ElunaEventMgr.cpp +++ b/ElunaEventMgr.cpp @@ -18,13 +18,9 @@ extern "C" #include "lauxlib.h" }; -ElunaEventProcessor::ElunaEventProcessor(Eluna* _E, WorldObject* _obj) : m_time(0), obj(_obj), E(_E) -{ -} - ElunaEventProcessor::~ElunaEventProcessor() { - RemoveEvents_internal(); + ClearAllEvents(); } void ElunaEventProcessor::Update(uint32 diff) @@ -32,8 +28,9 @@ void ElunaEventProcessor::Update(uint32 diff) isUpdating = true; m_time += diff; - for (EventList::iterator it = eventList.begin(); it != eventList.end() && it->first <= m_time; it = eventList.begin()) + while (!eventList.empty() && eventList.begin()->first <= m_time) { + auto it = eventList.begin(); LuaEvent* luaEvent = it->second; eventList.erase(it); @@ -47,13 +44,15 @@ void ElunaEventProcessor::Update(uint32 diff) if (!remove) AddEvent(luaEvent); // may be deferred if we recurse into Update + // Call the timed event if (!obj || (obj && obj->IsInWorld())) - E->OnTimedEvent(luaEvent->funcRef, delay, luaEvent->repeats ? luaEvent->repeats-- : luaEvent->repeats, obj); + mgr->E->OnTimedEvent(luaEvent->funcRef, delay, luaEvent->repeats ? luaEvent->repeats-- : luaEvent->repeats, obj); if (!remove) continue; } + // Event should be deleted (executed last time or set to be aborted) RemoveEvent(luaEvent); } @@ -76,7 +75,7 @@ void ElunaEventProcessor::SetStates(LuaEventState state) eventMap.clear(); } -void ElunaEventProcessor::RemoveEvents_internal() +void ElunaEventProcessor::ClearAllEvents() { if (isUpdating) { @@ -117,7 +116,7 @@ void ElunaEventProcessor::AddEvent(LuaEvent* luaEvent) } luaEvent->GenerateDelay(); - eventList.insert(std::make_pair(m_time + luaEvent->delay, luaEvent)); + eventList.emplace(m_time + luaEvent->delay, luaEvent); eventMap[luaEvent->funcRef] = luaEvent; } @@ -129,10 +128,10 @@ void ElunaEventProcessor::AddEvent(int funcRef, uint32 min, uint32 max, uint32 r void ElunaEventProcessor::RemoveEvent(LuaEvent* luaEvent) { // Unreference if should and if Eluna was not yet uninitialized and if the lua state still exists - if (luaEvent->state != LUAEVENT_STATE_ERASE && E->HasLuaState()) + if (luaEvent->state != LUAEVENT_STATE_ERASE && mgr->E->HasLuaState()) { // Free lua function ref - luaL_unref(E->L, LUA_REGISTRYINDEX, luaEvent->funcRef); + luaL_unref(mgr->E->L, LUA_REGISTRYINDEX, luaEvent->funcRef); } delete luaEvent; } @@ -172,7 +171,7 @@ void ElunaEventProcessor::ProcessDeferredOps() break; case DeferredOpType::ClearAll: - RemoveEvents_internal(); + ClearAllEvents(); break; } } @@ -186,7 +185,7 @@ ElunaProcessorInfo::~ElunaProcessorInfo() EventMgr::EventMgr(Eluna* _E) : E(_E) { - auto gp = std::make_unique(E, nullptr); + auto gp = std::make_unique(this, nullptr); processors.insert(gp.get()); globalProcessors.emplace(GLOBAL_EVENTS, std::move(gp)); } @@ -235,7 +234,7 @@ ElunaEventProcessor* EventMgr::GetGlobalProcessor(GlobalEventSpace space) uint64 EventMgr::CreateObjectProcessor(WorldObject* obj) { uint64 id = obj->GetGUID().GetRawValue(); - auto proc = std::make_unique(E, obj); + auto proc = std::make_unique(this, obj); ElunaEventProcessor* raw = proc.get(); processors.insert(raw); diff --git a/ElunaEventMgr.h b/ElunaEventMgr.h index a61da6ebaa..8d8b642a8b 100644 --- a/ElunaEventMgr.h +++ b/ElunaEventMgr.h @@ -43,10 +43,7 @@ enum GlobalEventSpace struct LuaEvent { - LuaEvent(int _funcRef, uint32 _min, uint32 _max, uint32 _repeats) : - min(_min), max(_max), delay(0), repeats(_repeats), funcRef(_funcRef), state(LUAEVENT_STATE_RUN) - { - } + LuaEvent(int _funcRef, uint32 _min, uint32 _max, uint32 _repeats) : min(_min), max(_max), delay(0), repeats(_repeats), funcRef(_funcRef), state(LUAEVENT_STATE_RUN) { } void SetState(LuaEventState _state) { @@ -75,7 +72,7 @@ class ElunaEventProcessor typedef std::multimap EventList; typedef std::unordered_map EventMap; - ElunaEventProcessor(Eluna* _E, WorldObject* _obj); + ElunaEventProcessor(EventMgr* mgr, WorldObject* obj) : m_time(0), obj(obj), mgr(mgr) { } ~ElunaEventProcessor(); void Update(uint32 diff); @@ -102,7 +99,7 @@ class ElunaEventProcessor LuaEventState state = LUAEVENT_STATE_RUN; }; - void RemoveEvents_internal(); + void ClearAllEvents(); void AddEvent(LuaEvent* luaEvent); void RemoveEvent(LuaEvent* luaEvent); @@ -118,17 +115,13 @@ class ElunaEventProcessor bool pendingDeletion = false; WorldObject* obj; - Eluna* E; + EventMgr* mgr; }; class ElunaProcessorInfo { public: - ElunaProcessorInfo(EventMgr* mgr, uint64 processorId) - : mgr(mgr), processorId(processorId) - { - } - + ElunaProcessorInfo(EventMgr* mgr, uint64 processorId) : mgr(mgr), processorId(processorId) { } ~ElunaProcessorInfo(); uint64 GetProcessorId() const { return processorId; } @@ -148,9 +141,10 @@ class EventMgr void SetAllEventStates(LuaEventState state); void SetEventState(int eventId, LuaEventState state); + // Global (per state) processors ElunaEventProcessor* GetGlobalProcessor(GlobalEventSpace space); - // Per-object processors (keyed by internal processorId) + // Per-object processors uint64 CreateObjectProcessor(WorldObject* obj); ElunaEventProcessor* GetObjectProcessor(uint64 processorId); void FlagObjectProcessorForDeletion(uint64 processorId); From 9cc6067e9f87d87e9d7a4db821f69f1f9d9bd082 Mon Sep 17 00:00:00 2001 From: Foereaper Date: Sun, 30 Nov 2025 14:11:49 +0100 Subject: [PATCH 11/13] Add method changes for other cores --- ElunaEventMgr.cpp | 8 ++++---- methods/CMangos/WorldObjectMethods.h | 23 ++++++++++++++++++++--- methods/Mangos/WorldObjectMethods.h | 25 +++++++++++++++++++++---- methods/VMangos/WorldObjectMethods.h | 23 ++++++++++++++++++++--- 4 files changed, 65 insertions(+), 14 deletions(-) diff --git a/ElunaEventMgr.cpp b/ElunaEventMgr.cpp index 91f809b24d..4d2fa68303 100644 --- a/ElunaEventMgr.cpp +++ b/ElunaEventMgr.cpp @@ -68,8 +68,8 @@ void ElunaEventProcessor::SetStates(LuaEventState state) return; } - for (EventList::iterator it = eventList.begin(); it != eventList.end(); ++it) - it->second->SetState(state); + for (auto& [time, event] : eventList) + event->SetState(state); if (state == LUAEVENT_STATE_ERASE) eventMap.clear(); @@ -83,8 +83,8 @@ void ElunaEventProcessor::ClearAllEvents() return; } - for (EventList::iterator it = eventList.begin(); it != eventList.end(); ++it) - RemoveEvent(it->second); + for (auto& [time, event] : eventList) + RemoveEvent(event); deferredOps.clear(); eventList.clear(); diff --git a/methods/CMangos/WorldObjectMethods.h b/methods/CMangos/WorldObjectMethods.h index 5788197fa6..a41e40f9a2 100644 --- a/methods/CMangos/WorldObjectMethods.h +++ b/methods/CMangos/WorldObjectMethods.h @@ -766,7 +766,15 @@ namespace LuaWorldObject int functionRef = luaL_ref(E->L, LUA_REGISTRYINDEX); if (functionRef != LUA_REFNIL && functionRef != LUA_NOREF) { - obj->GetElunaEvents(E->GetBoundMapId())->AddEvent(functionRef, min, max, repeats); + ElunaEventProcessor* proc = obj->GetElunaEvents(E->GetBoundMapId()); + if (!proc) + { + luaL_unref(E->L, LUA_REGISTRYINDEX, functionRef); + E->Push(); + return 1; + } + + proc->AddEvent(functionRef, min, max, repeats); E->Push(functionRef); } return 1; @@ -780,7 +788,12 @@ namespace LuaWorldObject int RemoveEventById(Eluna* E, WorldObject* obj) { int eventId = E->CHECKVAL(2); - obj->GetElunaEvents(E->GetBoundMapId())->SetState(eventId, LUAEVENT_STATE_ABORT); + + ElunaEventProcessor* proc = obj->GetElunaEvents(E->GetBoundMapId()); + if (!proc) + return 0; + + proc->SetState(eventId, LUAEVENT_STATE_ABORT); return 0; } @@ -790,7 +803,11 @@ namespace LuaWorldObject */ int RemoveEvents(Eluna* E, WorldObject* obj) { - obj->GetElunaEvents(E->GetBoundMapId())->SetStates(LUAEVENT_STATE_ABORT); + ElunaEventProcessor* proc = obj->GetElunaEvents(E->GetBoundMapId()); + if (!proc) + return 0; + + proc->SetStates(LUAEVENT_STATE_ABORT); return 0; } diff --git a/methods/Mangos/WorldObjectMethods.h b/methods/Mangos/WorldObjectMethods.h index b3a4987318..675812bc21 100644 --- a/methods/Mangos/WorldObjectMethods.h +++ b/methods/Mangos/WorldObjectMethods.h @@ -768,7 +768,15 @@ namespace LuaWorldObject int functionRef = luaL_ref(E->L, LUA_REGISTRYINDEX); if (functionRef != LUA_REFNIL && functionRef != LUA_NOREF) { - obj->elunaEvents->AddEvent(functionRef, min, max, repeats); + ElunaEventProcessor* proc = obj->GetElunaEvents(E->GetBoundMapId()); + if (!proc) + { + luaL_unref(E->L, LUA_REGISTRYINDEX, functionRef); + E->Push(); + return 1; + } + + proc->AddEvent(functionRef, min, max, repeats); E->Push(functionRef); } return 1; @@ -782,7 +790,12 @@ namespace LuaWorldObject int RemoveEventById(Eluna* E, WorldObject* obj) { int eventId = E->CHECKVAL(2); - obj->elunaEvents->SetState(eventId, LUAEVENT_STATE_ABORT); + + ElunaEventProcessor* proc = obj->GetElunaEvents(E->GetBoundMapId()); + if (!proc) + return 0; + + proc->SetState(eventId, LUAEVENT_STATE_ABORT); return 0; } @@ -790,9 +803,13 @@ namespace LuaWorldObject * Removes all timed events from a [WorldObject] * */ - int RemoveEvents(Eluna* /*E*/, WorldObject* obj) + int RemoveEvents(Eluna* E, WorldObject* obj) { - obj->elunaEvents->SetStates(LUAEVENT_STATE_ABORT); + ElunaEventProcessor* proc = obj->GetElunaEvents(E->GetBoundMapId()); + if (!proc) + return 0; + + proc->SetStates(LUAEVENT_STATE_ABORT); return 0; } diff --git a/methods/VMangos/WorldObjectMethods.h b/methods/VMangos/WorldObjectMethods.h index ba30bd7a3e..367cc2d8f9 100644 --- a/methods/VMangos/WorldObjectMethods.h +++ b/methods/VMangos/WorldObjectMethods.h @@ -735,7 +735,15 @@ namespace LuaWorldObject int functionRef = luaL_ref(E->L, LUA_REGISTRYINDEX); if (functionRef != LUA_REFNIL && functionRef != LUA_NOREF) { - obj->GetElunaEvents(E->GetBoundMapId())->AddEvent(functionRef, min, max, repeats); + ElunaEventProcessor* proc = obj->GetElunaEvents(E->GetBoundMapId()); + if (!proc) + { + luaL_unref(E->L, LUA_REGISTRYINDEX, functionRef); + E->Push(); + return 1; + } + + proc->AddEvent(functionRef, min, max, repeats); E->Push(functionRef); } return 1; @@ -749,7 +757,12 @@ namespace LuaWorldObject int RemoveEventById(Eluna* E, WorldObject* obj) { int eventId = E->CHECKVAL(2); - obj->GetElunaEvents(E->GetBoundMapId())->SetState(eventId, LUAEVENT_STATE_ABORT); + + ElunaEventProcessor* proc = obj->GetElunaEvents(E->GetBoundMapId()); + if (!proc) + return 0; + + proc->SetState(eventId, LUAEVENT_STATE_ABORT); return 0; } @@ -759,7 +772,11 @@ namespace LuaWorldObject */ int RemoveEvents(Eluna* E, WorldObject* obj) { - obj->GetElunaEvents(E->GetBoundMapId())->SetStates(LUAEVENT_STATE_ABORT); + ElunaEventProcessor* proc = obj->GetElunaEvents(E->GetBoundMapId()); + if (!proc) + return 0; + + proc->SetStates(LUAEVENT_STATE_ABORT); return 0; } From 717d45330ad0279eaa32d8303579b6ea49d25f80 Mon Sep 17 00:00:00 2001 From: Foereaper Date: Sun, 30 Nov 2025 20:30:44 +0100 Subject: [PATCH 12/13] PR cleanup 2 --- ElunaEventMgr.cpp | 31 ++++++++++--------------------- ElunaEventMgr.h | 24 ++++++++++++------------ 2 files changed, 22 insertions(+), 33 deletions(-) diff --git a/ElunaEventMgr.cpp b/ElunaEventMgr.cpp index 4d2fa68303..1dda6a1887 100644 --- a/ElunaEventMgr.cpp +++ b/ElunaEventMgr.cpp @@ -151,29 +151,18 @@ void ElunaEventProcessor::ProcessDeferredOps() if (deferredOps.empty()) return; - std::vector ops; - ops.swap(deferredOps); - - for (DeferredOp& op : ops) + using Handler = void(*)(ElunaEventProcessor*, DeferredOp&); + static constexpr Handler handlers[] = { - switch (op.type) - { - case DeferredOpType::AddEvent: - AddEvent(op.event); - break; - - case DeferredOpType::SetState: - SetState(op.eventId, op.state); - break; + [](ElunaEventProcessor* self, DeferredOp& op) { self->AddEvent(op.event); }, + [](ElunaEventProcessor* self, DeferredOp& op) { self->SetState(op.eventId, op.state); }, + [](ElunaEventProcessor* self, DeferredOp& op) { self->SetStates(op.state); }, + [](ElunaEventProcessor* self, DeferredOp& /*op*/) { self->ClearAllEvents(); } + }; - case DeferredOpType::SetStates: - SetStates(op.state); - break; - - case DeferredOpType::ClearAll: - ClearAllEvents(); - break; - } + for (DeferredOp& op : deferredOps) + { + handlers[op.type](this, op); } } diff --git a/ElunaEventMgr.h b/ElunaEventMgr.h index 8d8b642a8b..7ed736a2ca 100644 --- a/ElunaEventMgr.h +++ b/ElunaEventMgr.h @@ -29,14 +29,22 @@ class EventMgr; class ElunaEventProcessor; class WorldObject; -enum LuaEventState +enum LuaEventState : uint8 { LUAEVENT_STATE_RUN, // On next call run the function normally LUAEVENT_STATE_ABORT, // On next call unregisters reffed function and erases the data LUAEVENT_STATE_ERASE, // On next call just erases the data }; -enum GlobalEventSpace +enum DeferredOpType : uint8 +{ + AddEvent, + SetState, + SetStates, + ClearAll +}; + +enum GlobalEventSpace : uint8 { GLOBAL_EVENTS }; @@ -83,20 +91,12 @@ class ElunaEventProcessor void AddEvent(int funcRef, uint32 min, uint32 max, uint32 repeats); private: - enum class DeferredOpType - { - AddEvent, - SetState, - SetStates, - ClearAll - }; - struct DeferredOp { - DeferredOpType type; - LuaEvent* event = nullptr; int eventId = 0; + DeferredOpType type; LuaEventState state = LUAEVENT_STATE_RUN; + LuaEvent* event = nullptr; }; void ClearAllEvents(); From 9e9a438dfbbf5616dd6acfa94ce59038675ca7a8 Mon Sep 17 00:00:00 2001 From: Foereaper Date: Sun, 30 Nov 2025 20:42:40 +0100 Subject: [PATCH 13/13] Re-add processor list copy --- ElunaEventMgr.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ElunaEventMgr.cpp b/ElunaEventMgr.cpp index 1dda6a1887..bda1fb855f 100644 --- a/ElunaEventMgr.cpp +++ b/ElunaEventMgr.cpp @@ -151,6 +151,9 @@ void ElunaEventProcessor::ProcessDeferredOps() if (deferredOps.empty()) return; + std::vector ops; + ops.swap(deferredOps); + using Handler = void(*)(ElunaEventProcessor*, DeferredOp&); static constexpr Handler handlers[] = { @@ -160,7 +163,7 @@ void ElunaEventProcessor::ProcessDeferredOps() [](ElunaEventProcessor* self, DeferredOp& /*op*/) { self->ClearAllEvents(); } }; - for (DeferredOp& op : deferredOps) + for (DeferredOp& op : ops) { handlers[op.type](this, op); }