AireEngine
A 3D Open-World Game Engine
Loading...
Searching...
No Matches
event.h
1#pragma once
2#include<string>
3#include<unordered_map>
4#include<vector>
5
6#include"../utils/hashSet.h"
7
8namespace Aire {
11 struct Event {
12 public:
13 Event(const std::string& eventType): type(eventType) {}
14 std::string type;
15 };
16
22 struct GameObject {
27 virtual void onEvent(const Event& e) = 0;
28
30 virtual ~GameObject();
31 };
32
34 struct StagedEvent {
35 Event* event;
36 float timer;
37 bool destroy;
38 ~StagedEvent() {
39 if (destroy) delete event;
40 }
41 };
42
47 struct EventManager {
53 static void registerForEvent(GameObject* obj, std::string eventType) {
54 if (!obj) return;
55
56 // If this is the first object registered for the event, create a new object list.
57 auto itEvent = eventMap.find(eventType);
58 if (itEvent == eventMap.end()) {
59 itEvent = eventMap.emplace(eventType, HashSet<GameObject*>()).first;
60 }
61
62 // Regiser the object for the event type
63 auto& objSet = itEvent->second;
64 objSet.insert(obj);
65
66 // If this is the first event this object is registered for, create a new event list.
67 auto itObj = objMap.find(obj);
68 if (itObj == objMap.end()) {
69 itObj = objMap.emplace(obj, HashSet<std::string>()).first;
70 }
71
72 // Add the event to the object's list of registered events
73 auto& eventSet = itObj->second;
74 eventSet.insert(eventType);
75 }
76
81 static void unregisterFromEvent(GameObject* obj, std::string eventType) {
82 if (!obj) return;
83
84 // Remove the object from the event's list of objects registered to it
85 auto itEvent = eventMap.find(eventType);
86 if (itEvent != eventMap.end()) {
87 auto& objSet = itEvent->second;
88 objSet.erase(obj);
89 // If this was the last object, remove the event entirely
90 if (objSet.empty()) {
91 eventMap.erase(itEvent);
92 }
93 }
94
95 // Remove the event from the object's list of events it is registered for
96 auto itObj = objMap.find(obj);
97 if (itObj != objMap.end()) {
98 auto& eventSet = itObj->second;
99 eventSet.erase(eventType);
100 // If this was the last event, remove the object from the list entirely
101 if (eventSet.empty()) {
102 objMap.erase(itObj);
103 }
104 }
105 }
106
111 if (!obj) return;
112
113 auto itObj = objMap.find(obj);
114 if (itObj != objMap.end()) {
115 // Traverse the set of event this object is registered for and
116 // unregister it from every event in the set.
117 auto& eventSet = itObj->second;
118 for (auto it = eventSet.begin(); it!=eventSet.end(); ++it) {
119 // Remove the object from the event's list of objects registered to it
120 auto itEvent = eventMap.find(*it);
121 if (itEvent != eventMap.end()) {
122 auto& objSet = itEvent->second;
123 objSet.erase(obj);
124 // If this was the last object, remove the event entirely
125 if (objSet.empty()) {
126 eventMap.erase(itEvent);
127 }
128 }
129 }
130
131 // Remove the object from the object list
132 eventSet.clear();
133 objMap.erase(itObj);
134 }
135 }
136
139 static void dispatchEvent(const Event& eventInstance) {
140 auto it = eventMap.find(eventInstance.type);
141 if (it != eventMap.end()) {
142 // Walk through all objects registered for this event and trigger their event handler
143 auto& objSet = it->second;
144 for (auto objIt = objSet.begin(); objIt!=objSet.end(); ++objIt) {
145 (*objIt)->onEvent(eventInstance);
146 }
147 }
148 }
149
155 static StagedEvent* stageEvent(Event* eventToStage, float timer, bool destroyWhenDone) {
156 if (!eventToStage) {
157 return nullptr;
158 }
159 if (timer>0.0001f) {
160 // Dynamically grow the array to avoid re-allocation on every insertion.
161 // The capacity of the array is doubled.
162 if (stagedEvents.size()==stagedEvents.capacity()) {
163 size_t newSize = std::max(stagedEvents.size(), size_t(1)) * 2;
164 stagedEvents.reserve(newSize);
165 }
166 stagedEvents.push_back(new StagedEvent{ eventToStage, timer, destroyWhenDone });
167 return stagedEvents.back();
168 }
169 }
170
174 static void updateEventTimer(float dt) {
175 for (size_t i=0; i<stagedEvents.size(); ) {
176 StagedEvent* e = stagedEvents[i];
177 if (!e) continue;
178 e->timer-=dt;
179 if (e->timer<=0.f) {
180 // Activate the event and remove it from the list
181 if (e->event) {
182 dispatchEvent(*(e->event));
183 delete e;
184 }
185
186 // Swap the element with the last element in the array and then pop.
187 std::swap(stagedEvents[i], stagedEvents.back());
188 stagedEvents.pop_back();
189 } else {
190 // Move to next position only if there was no swap performed.
191 i++;
192 }
193 }
194 }
195
199 static const HashSet<GameObject*>& getAllRegisteredObjects(const std::string& eventType) {
200 auto it = eventMap.find(eventType);
201 if (it != eventMap.end()) {
202 return it->second;
203 } else {
204 return emptyObjSet;
205 }
206 }
207
212 auto it = objMap.find(obj);
213 if (it != objMap.end()) {
214 return it->second;
215 } else {
216 return emptyEventSet;
217 }
218 }
219
221 static void freeMem() {
222 std::unordered_map<std::string, HashSet<GameObject*>> emptyEventMap;
223 std::unordered_map<GameObject*, HashSet<std::string>> emptyObjMap;
224 std::swap(eventMap, emptyEventMap);
225 std::swap(objMap, emptyObjMap);
226 emptyObjSet.freeMem();
227 emptyEventSet.freeMem();
228 for (auto it = stagedEvents.begin(); it!=stagedEvents.end(); it++) {
229 if (*it) {
230 delete *it;
231 }
232 }
233 std::vector<StagedEvent*> emptyStagedEvents;
234 std::swap(stagedEvents, emptyStagedEvents);
235 }
236
237 private:
238 // Although it is sufficient to store only an event map (eventType->registered objects),
239 // we maintain an object map as well (obj->events it is registered for). This allows
240 // unregistering the object from all events it is registered for when it is destroyed.
241
243 static std::unordered_map<std::string, HashSet<GameObject*>> eventMap;
244
246 static std::unordered_map<GameObject*, HashSet<std::string>> objMap;
247
249 static HashSet<GameObject*> emptyObjSet;
250
252 static HashSet<std::string> emptyEventSet;
253
255 static std::vector<StagedEvent*> stagedEvents;
256 };
257
258 // Game object destructor ensures that on deletion, the object if unregistered from all events.
262
263 // Static member definitions
264 std::unordered_map<std::string, HashSet<GameObject*>> EventManager::eventMap;
265 std::unordered_map<GameObject*, HashSet<std::string>> EventManager::objMap;
266 std::vector<StagedEvent*> EventManager::stagedEvents;
267}
Definition hashSet.h:18
void freeMem()
Definition hashSet.h:168
Definition event.h:11
std::string type
Type of the event. Serves as event identifier. Case sensitive.
Definition event.h:14
Definition event.h:47
static const HashSet< std::string > & getAllRegiteredEvents(GameObject *obj)
Definition event.h:211
static StagedEvent * stageEvent(Event *eventToStage, float timer, bool destroyWhenDone)
Definition event.h:155
static void unregisterFromEvent(GameObject *obj, std::string eventType)
Definition event.h:81
static void updateEventTimer(float dt)
Definition event.h:174
static void freeMem()
Use this to free all memory used by internal static members.
Definition event.h:221
static void registerForEvent(GameObject *obj, std::string eventType)
Definition event.h:53
static void dispatchEvent(const Event &eventInstance)
Definition event.h:139
static const HashSet< GameObject * > & getAllRegisteredObjects(const std::string &eventType)
Definition event.h:199
static void unregisterFromAllEvents(GameObject *obj)
Definition event.h:110
Definition event.h:22
virtual void onEvent(const Event &e)=0
virtual ~GameObject()
Destructor ensures that on deletion, the object if unregistered from all events.
Definition event.h:259
Event staged for a later execution.
Definition event.h:34