Engine²
Open-source game engine written in C++.
Loading...
Searching...
No Matches
EventManager.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <any>
4#include <functional>
5#include <memory>
6#include <mutex>
7#include <queue>
8#include <typeindex>
9#include <unordered_map>
10#include <utility>
11
12#include "core/Core.hpp"
13#include "scheduler/Update.hpp"
15
16namespace Event::Resource {
24 private:
26
27 public:
31 using EventTypeID = size_t;
32
36 using EventCallbackID = size_t;
37
41 EventManager() = default;
42
44 {
45 std::scoped_lock lock(_queueMutex, _callbacksMutex);
46 _eventCallbacks.clear();
47 _eventQueue.clear();
48 }
49
50 EventManager(const EventManager &) = delete;
52
58 {
59 std::scoped_lock lock(other._queueMutex, other._callbacksMutex);
60 _eventCallbacks = std::move(other._eventCallbacks);
61 _eventQueue = std::move(other._eventQueue);
62 }
63
70 {
71 if (this != &other)
72 {
73 std::scoped_lock lock(other._queueMutex, _queueMutex, other._callbacksMutex, _callbacksMutex);
74 _eventCallbacks = std::move(other._eventCallbacks);
75 _eventQueue = std::move(other._eventQueue);
76 }
77
78 return *this;
79 }
80
89 template <typename TEvent, typename TScheduler = DirectCallbackSchedulerTag, typename TCallBack>
90 EventCallbackID RegisterCallback(TCallBack &&callback)
91 {
92 return _RegisterCallbackImpl<TEvent, TCallBack, TScheduler>(std::forward<TCallBack>(callback));
93 }
94
104 template <typename TEvent> void PushEvent(const TEvent &event)
105 {
106 EventTypeID typeID = _GetId<TEvent>();
107 std::shared_ptr<Utils::EventContainer<TEvent>> directContainer;
108
109 {
110 std::scoped_lock lock(_queueMutex, _callbacksMutex);
111
112 for (const auto &[schedulerID, callbacks] : _eventCallbacks)
113 {
114 if (callbacks.contains(typeID))
115 {
116 _eventQueue[schedulerID].push({typeID, event});
117 }
118 }
119
120 auto schedulerID = std::type_index(typeid(DirectCallbackSchedulerTag));
121 if (_eventCallbacks.contains(schedulerID) && _eventCallbacks[schedulerID].contains(typeID))
122 {
123 directContainer =
124 std::static_pointer_cast<Utils::EventContainer<TEvent>>(_eventCallbacks[schedulerID][typeID]);
125 }
126 }
127
128 if (directContainer)
129 {
130 for (auto &callback : directContainer->GetFunctions())
131 {
132 callback->Call(event);
133 }
134 }
135 }
136
146 template <typename TScheduler> void ProcessEvents(void)
147 {
148 auto schedulerID = std::type_index(typeid(TScheduler));
149
150 std::queue<std::pair<EventTypeID, std::any>> queueCopy;
151 {
152 std::scoped_lock lock(_queueMutex);
153 if (_eventQueue.contains(schedulerID))
154 {
155 std::swap(queueCopy, _eventQueue[schedulerID]);
156 }
157 }
158
159 while (!queueCopy.empty())
160 {
161 auto [typeID, event] = std::move(queueCopy.front());
162 queueCopy.pop();
163
164 std::shared_ptr<Utils::IEventContainer> callback;
165 {
166 std::scoped_lock lock(_callbacksMutex);
167 if (_eventCallbacks.contains(schedulerID) && _eventCallbacks[schedulerID].contains(typeID))
168 {
169 callback = _eventCallbacks[schedulerID][typeID];
170 }
171 }
172
173 if (callback)
174 {
175 callback->Trigger(event);
176 }
177 }
178 }
179
190 template <typename TEvent, typename TScheduler = DirectCallbackSchedulerTag>
192 {
193 EventTypeID typeID = _GetId<TEvent>();
194 std::scoped_lock lock(_callbacksMutex);
195 auto schedulerID = std::type_index(typeid(TScheduler));
196 if (!_eventCallbacks.contains(schedulerID) || !_eventCallbacks[schedulerID].contains(typeID))
197 {
198 Log::Warning("EventManager::UnregisterCallback: No callbacks registered for this event type.");
199 return;
200 }
201 auto container = std::static_pointer_cast<Utils::EventContainer<TEvent>>(_eventCallbacks[schedulerID][typeID]);
202 if (!container->Contains(callbackID))
203 {
204 Log::Warning("EventManager::UnregisterCallback: Callback ID not found.");
205 return;
206 }
207 container->DeleteFunction(callbackID);
208 }
209
210 private:
211 template <typename TEvent, typename TCallBack, typename TScheduler>
213 {
214 EventTypeID typeID = _GetId<TEvent>();
215 std::scoped_lock lock(_callbacksMutex);
216 auto schedulerID = std::type_index(typeid(TScheduler));
217
218 if (!_eventCallbacks.contains(schedulerID))
219 {
220 _eventCallbacks[schedulerID] = {};
221 }
222
223 if (!_eventCallbacks[schedulerID].contains(typeID))
224 {
225 _eventCallbacks[schedulerID].try_emplace(typeID, std::make_shared<Utils::EventContainer<TEvent>>());
226 }
227 auto container = std::static_pointer_cast<Utils::EventContainer<TEvent>>(_eventCallbacks[schedulerID][typeID]);
228 return container->AddFunction(std::forward<TCallBack>(callback));
229 }
230
232 {
233 static EventCallbackID currentID = 0;
234 return currentID++;
235 }
236
237 template <typename TEvent> static EventTypeID _GetId(void) { return typeid(TEvent).hash_code(); }
238
239 std::unordered_map<std::type_index, std::unordered_map<EventTypeID, std::shared_ptr<Utils::IEventContainer>>>
241 std::unordered_map<std::type_index, std::queue<std::pair<EventTypeID, std::any>>> _eventQueue;
242 std::mutex _queueMutex;
243 std::mutex _callbacksMutex;
244};
245} // namespace Event::Resource
static EventCallbackID _GenerateRandomID()
Definition EventManager.hpp:231
EventCallbackID _RegisterCallbackImpl(TCallBack &&callback)
Definition EventManager.hpp:212
std::unordered_map< std::type_index, std::queue< std::pair< EventTypeID, std::any > > > _eventQueue
Definition EventManager.hpp:241
size_t EventTypeID
Type identifier for event types.
Definition EventManager.hpp:31
void UnregisterCallback(EventCallbackID callbackID)
Unregister a previously registered callback.
Definition EventManager.hpp:191
EventManager & operator=(EventManager &&other) noexcept
Move assignment operator.
Definition EventManager.hpp:69
void PushEvent(const TEvent &event)
Queue an event for processing.
Definition EventManager.hpp:104
EventManager & operator=(const EventManager &)=delete
~EventManager()
Definition EventManager.hpp:43
std::mutex _callbacksMutex
Definition EventManager.hpp:243
static EventTypeID _GetId(void)
Definition EventManager.hpp:237
EventManager(const EventManager &)=delete
EventManager()=default
Default constructor.
std::unordered_map< std::type_index, std::unordered_map< EventTypeID, std::shared_ptr< Utils::IEventContainer > > > _eventCallbacks
Definition EventManager.hpp:240
EventManager(EventManager &&other) noexcept
Move constructor.
Definition EventManager.hpp:57
size_t EventCallbackID
Unique identifier for registered event callbacks.
Definition EventManager.hpp:36
EventCallbackID RegisterCallback(TCallBack &&callback)
Definition EventManager.hpp:90
void ProcessEvents(void)
Process all queued events for a specific scheduler.
Definition EventManager.hpp:146
std::mutex _queueMutex
Definition EventManager.hpp:242
Definition EventContainer.hpp:17
Definition EventManager.hpp:16
void Warning(const T &msg) noexcept
Definition Logger.hpp:49