Skip to content

Commit 4790ef8

Browse files
authored
Timed event rewrite (#528)
* Implement deferred timed event actions, should fix some edge case crashes * 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, big performance improvement
1 parent 58ca9b6 commit 4790ef8

File tree

11 files changed

+347
-101
lines changed

11 files changed

+347
-101
lines changed

ElunaEventMgr.cpp

Lines changed: 169 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -18,27 +18,19 @@ extern "C"
1818
#include "lauxlib.h"
1919
};
2020

21-
ElunaEventProcessor::ElunaEventProcessor(Eluna* _E, WorldObject* _obj) : m_time(0), obj(_obj), E(_E)
22-
{
23-
if (obj)
24-
E->eventMgr->processors.insert(this);
25-
}
26-
2721
ElunaEventProcessor::~ElunaEventProcessor()
2822
{
29-
{
30-
RemoveEvents_internal();
31-
}
32-
33-
if (obj)
34-
E->eventMgr->processors.erase(this);
23+
ClearAllEvents();
3524
}
3625

3726
void ElunaEventProcessor::Update(uint32 diff)
3827
{
28+
isUpdating = true;
29+
3930
m_time += diff;
40-
for (EventList::iterator it = eventList.begin(); it != eventList.end() && it->first <= m_time; it = eventList.begin())
31+
while (!eventList.empty() && eventList.begin()->first <= m_time)
4132
{
33+
auto it = eventList.begin();
4234
LuaEvent* luaEvent = it->second;
4335
eventList.erase(it);
4436

@@ -50,11 +42,11 @@ void ElunaEventProcessor::Update(uint32 diff)
5042
uint32 delay = luaEvent->delay;
5143
bool remove = luaEvent->repeats == 1;
5244
if (!remove)
53-
AddEvent(luaEvent); // Reschedule before calling incase RemoveEvents used
45+
AddEvent(luaEvent); // may be deferred if we recurse into Update
5446

5547
// Call the timed event
56-
if(!obj || (obj && obj->IsInWorld()))
57-
E->OnTimedEvent(luaEvent->funcRef, delay, luaEvent->repeats ? luaEvent->repeats-- : luaEvent->repeats, obj);
48+
if (!obj || (obj && obj->IsInWorld()))
49+
mgr->E->OnTimedEvent(luaEvent->funcRef, delay, luaEvent->repeats ? luaEvent->repeats-- : luaEvent->repeats, obj);
5850

5951
if (!remove)
6052
continue;
@@ -63,37 +55,68 @@ void ElunaEventProcessor::Update(uint32 diff)
6355
// Event should be deleted (executed last time or set to be aborted)
6456
RemoveEvent(luaEvent);
6557
}
58+
59+
isUpdating = false;
60+
ProcessDeferredOps();
6661
}
6762

6863
void ElunaEventProcessor::SetStates(LuaEventState state)
6964
{
70-
for (EventList::iterator it = eventList.begin(); it != eventList.end(); ++it)
71-
it->second->SetState(state);
65+
if (isUpdating)
66+
{
67+
QueueDeferredOp(DeferredOpType::SetStates, nullptr, 0, state);
68+
return;
69+
}
70+
71+
for (auto& [time, event] : eventList)
72+
event->SetState(state);
73+
7274
if (state == LUAEVENT_STATE_ERASE)
7375
eventMap.clear();
7476
}
7577

76-
void ElunaEventProcessor::RemoveEvents_internal()
78+
void ElunaEventProcessor::ClearAllEvents()
7779
{
78-
for (EventList::iterator it = eventList.begin(); it != eventList.end(); ++it)
79-
RemoveEvent(it->second);
80+
if (isUpdating)
81+
{
82+
QueueDeferredOp(DeferredOpType::ClearAll);
83+
return;
84+
}
85+
86+
for (auto& [time, event] : eventList)
87+
RemoveEvent(event);
8088

89+
deferredOps.clear();
8190
eventList.clear();
8291
eventMap.clear();
8392
}
8493

8594
void ElunaEventProcessor::SetState(int eventId, LuaEventState state)
8695
{
87-
if (eventMap.find(eventId) != eventMap.end())
88-
eventMap[eventId]->SetState(state);
96+
if (isUpdating)
97+
{
98+
QueueDeferredOp(DeferredOpType::SetState, nullptr, eventId, state);
99+
return;
100+
}
101+
102+
auto itr = eventMap.find(eventId);
103+
if (itr != eventMap.end())
104+
itr->second->SetState(state);
105+
89106
if (state == LUAEVENT_STATE_ERASE)
90107
eventMap.erase(eventId);
91108
}
92109

93110
void ElunaEventProcessor::AddEvent(LuaEvent* luaEvent)
94111
{
112+
if (isUpdating)
113+
{
114+
QueueDeferredOp(DeferredOpType::AddEvent, luaEvent);
115+
return;
116+
}
117+
95118
luaEvent->GenerateDelay();
96-
eventList.insert(std::pair<uint64, LuaEvent*>(m_time + luaEvent->delay, luaEvent));
119+
eventList.emplace(m_time + luaEvent->delay, luaEvent);
97120
eventMap[luaEvent->funcRef] = luaEvent;
98121
}
99122

@@ -105,47 +128,148 @@ void ElunaEventProcessor::AddEvent(int funcRef, uint32 min, uint32 max, uint32 r
105128
void ElunaEventProcessor::RemoveEvent(LuaEvent* luaEvent)
106129
{
107130
// Unreference if should and if Eluna was not yet uninitialized and if the lua state still exists
108-
if (luaEvent->state != LUAEVENT_STATE_ERASE && E->HasLuaState())
131+
if (luaEvent->state != LUAEVENT_STATE_ERASE && mgr->E->HasLuaState())
109132
{
110133
// Free lua function ref
111-
luaL_unref(E->L, LUA_REGISTRYINDEX, luaEvent->funcRef);
134+
luaL_unref(mgr->E->L, LUA_REGISTRYINDEX, luaEvent->funcRef);
112135
}
113136
delete luaEvent;
114137
}
115138

139+
void ElunaEventProcessor::QueueDeferredOp(DeferredOpType type, LuaEvent* event, int eventId, LuaEventState state)
140+
{
141+
DeferredOp op;
142+
op.type = type;
143+
op.event = event;
144+
op.eventId = eventId;
145+
op.state = state;
146+
deferredOps.push_back(op);
147+
}
148+
149+
void ElunaEventProcessor::ProcessDeferredOps()
150+
{
151+
if (deferredOps.empty())
152+
return;
153+
154+
std::vector<DeferredOp> ops;
155+
ops.swap(deferredOps);
156+
157+
using Handler = void(*)(ElunaEventProcessor*, DeferredOp&);
158+
static constexpr Handler handlers[] =
159+
{
160+
[](ElunaEventProcessor* self, DeferredOp& op) { self->AddEvent(op.event); },
161+
[](ElunaEventProcessor* self, DeferredOp& op) { self->SetState(op.eventId, op.state); },
162+
[](ElunaEventProcessor* self, DeferredOp& op) { self->SetStates(op.state); },
163+
[](ElunaEventProcessor* self, DeferredOp& /*op*/) { self->ClearAllEvents(); }
164+
};
165+
166+
for (DeferredOp& op : ops)
167+
{
168+
handlers[op.type](this, op);
169+
}
170+
}
171+
172+
ElunaProcessorInfo::~ElunaProcessorInfo()
173+
{
174+
if (mgr)
175+
mgr->FlagObjectProcessorForDeletion(processorId);
176+
}
177+
116178
EventMgr::EventMgr(Eluna* _E) : E(_E)
117179
{
118-
globalProcessor = std::make_unique<ElunaEventProcessor>(E, nullptr);
180+
auto gp = std::make_unique<ElunaEventProcessor>(this, nullptr);
181+
processors.insert(gp.get());
182+
globalProcessors.emplace(GLOBAL_EVENTS, std::move(gp));
119183
}
120184

121185
EventMgr::~EventMgr()
122186
{
123-
if (!processors.empty())
124-
for (ProcessorSet::const_iterator it = processors.begin(); it != processors.end(); ++it) // loop processors
125-
(*it)->RemoveEvents_internal();
126-
globalProcessor->RemoveEvents_internal();
187+
globalProcessors.clear();
188+
objectProcessors.clear();
189+
processors.clear();
190+
objectProcessorsPendingDelete.clear();
127191
}
128192

129193
void EventMgr::UpdateProcessors(uint32 diff)
130194
{
131-
if (!processors.empty())
132-
for (ProcessorSet::const_iterator it = processors.begin(); it != processors.end(); ++it) // loop processors
133-
(*it)->Update(diff);
134-
globalProcessor->Update(diff);
195+
// iterate a copy because processors may be destroyed during update (creature removed by a script, etc)
196+
ProcessorSet copy = processors;
197+
198+
for (auto* processor : copy)
199+
{
200+
if (processors.find(processor) != processors.end())
201+
if (!processor->pendingDeletion)
202+
processor->Update(diff);
203+
}
204+
205+
CleanupObjectProcessors();
135206
}
136207

137-
void EventMgr::SetStates(LuaEventState state)
208+
void EventMgr::SetAllEventStates(LuaEventState state)
138209
{
139-
if (!processors.empty())
140-
for (ProcessorSet::const_iterator it = processors.begin(); it != processors.end(); ++it) // loop processors
141-
(*it)->SetStates(state);
142-
globalProcessor->SetStates(state);
210+
for (auto* processor : processors)
211+
processor->SetStates(state);
143212
}
144213

145-
void EventMgr::SetState(int eventId, LuaEventState state)
214+
void EventMgr::SetEventState(int eventId, LuaEventState state)
146215
{
147-
if (!processors.empty())
148-
for (ProcessorSet::const_iterator it = processors.begin(); it != processors.end(); ++it) // loop processors
149-
(*it)->SetState(eventId, state);
150-
globalProcessor->SetState(eventId, state);
216+
for (auto* processor : processors)
217+
processor->SetState(eventId, state);
218+
}
219+
220+
ElunaEventProcessor* EventMgr::GetGlobalProcessor(GlobalEventSpace space)
221+
{
222+
auto it = globalProcessors.find(space);
223+
return (it != globalProcessors.end()) ? it->second.get() : nullptr;
224+
}
225+
226+
uint64 EventMgr::CreateObjectProcessor(WorldObject* obj)
227+
{
228+
uint64 id = obj->GetGUID().GetRawValue();
229+
auto proc = std::make_unique<ElunaEventProcessor>(this, obj);
230+
ElunaEventProcessor* raw = proc.get();
231+
232+
processors.insert(raw);
233+
objectProcessors.emplace(id, std::move(proc));
234+
235+
return id;
236+
}
237+
238+
ElunaEventProcessor* EventMgr::GetObjectProcessor(uint64 processorId)
239+
{
240+
auto it = objectProcessors.find(processorId);
241+
return (it != objectProcessors.end()) ? it->second.get() : nullptr;
242+
}
243+
244+
void EventMgr::FlagObjectProcessorForDeletion(uint64 processorId)
245+
{
246+
auto it = objectProcessors.find(processorId);
247+
if (it == objectProcessors.end())
248+
return;
249+
250+
ElunaEventProcessor* p = it->second.get();
251+
if (!p->pendingDeletion)
252+
{
253+
p->pendingDeletion = true;
254+
p->obj = nullptr;
255+
objectProcessorsPendingDelete.insert(processorId);
256+
}
257+
}
258+
259+
void EventMgr::CleanupObjectProcessors()
260+
{
261+
for (uint64 processorId : objectProcessorsPendingDelete)
262+
{
263+
auto it = objectProcessors.find(processorId);
264+
if (it == objectProcessors.end())
265+
continue;
266+
267+
ElunaEventProcessor* p = it->second.get();
268+
p->SetStates(LUAEVENT_STATE_ERASE);
269+
270+
processors.erase(p);
271+
objectProcessors.erase(it);
272+
}
273+
274+
objectProcessorsPendingDelete.clear();
151275
}

0 commit comments

Comments
 (0)