|
@@ -4,6 +4,7 @@
|
|
|
#include <algorithm>
|
|
#include <algorithm>
|
|
|
#include <functional>
|
|
#include <functional>
|
|
|
#include <memory>
|
|
#include <memory>
|
|
|
|
|
+#include <mutex>
|
|
|
#include <typeindex>
|
|
#include <typeindex>
|
|
|
#include <unordered_map>
|
|
#include <unordered_map>
|
|
|
#include <vector>
|
|
#include <vector>
|
|
@@ -13,12 +14,18 @@ namespace Engine::Core {
|
|
|
class Event {
|
|
class Event {
|
|
|
public:
|
|
public:
|
|
|
virtual ~Event() = default;
|
|
virtual ~Event() = default;
|
|
|
|
|
+ virtual const char *getTypeName() const { return "Event"; }
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
template <typename T> using EventHandler = std::function<void(const T &)>;
|
|
template <typename T> using EventHandler = std::function<void(const T &)>;
|
|
|
|
|
|
|
|
using SubscriptionHandle = std::size_t;
|
|
using SubscriptionHandle = std::size_t;
|
|
|
|
|
|
|
|
|
|
+struct EventStats {
|
|
|
|
|
+ size_t publishCount = 0;
|
|
|
|
|
+ size_t subscriberCount = 0;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
class EventManager {
|
|
class EventManager {
|
|
|
public:
|
|
public:
|
|
|
static EventManager &instance() {
|
|
static EventManager &instance() {
|
|
@@ -28,36 +35,80 @@ public:
|
|
|
|
|
|
|
|
template <typename T> SubscriptionHandle subscribe(EventHandler<T> handler) {
|
|
template <typename T> SubscriptionHandle subscribe(EventHandler<T> handler) {
|
|
|
static_assert(std::is_base_of_v<Event, T>, "T must inherit from Event");
|
|
static_assert(std::is_base_of_v<Event, T>, "T must inherit from Event");
|
|
|
|
|
+ std::lock_guard<std::mutex> lock(m_mutex);
|
|
|
|
|
+
|
|
|
SubscriptionHandle handle = m_nextHandle++;
|
|
SubscriptionHandle handle = m_nextHandle++;
|
|
|
auto wrapper = [handler, handle](const void *event) {
|
|
auto wrapper = [handler, handle](const void *event) {
|
|
|
handler(*static_cast<const T *>(event));
|
|
handler(*static_cast<const T *>(event));
|
|
|
};
|
|
};
|
|
|
HandlerEntry entry{handle, wrapper};
|
|
HandlerEntry entry{handle, wrapper};
|
|
|
m_handlers[std::type_index(typeid(T))].push_back(entry);
|
|
m_handlers[std::type_index(typeid(T))].push_back(entry);
|
|
|
|
|
+
|
|
|
|
|
+ m_stats[std::type_index(typeid(T))].subscriberCount++;
|
|
|
|
|
+
|
|
|
return handle;
|
|
return handle;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
template <typename T> void unsubscribe(SubscriptionHandle handle) {
|
|
template <typename T> void unsubscribe(SubscriptionHandle handle) {
|
|
|
static_assert(std::is_base_of_v<Event, T>, "T must inherit from Event");
|
|
static_assert(std::is_base_of_v<Event, T>, "T must inherit from Event");
|
|
|
|
|
+ std::lock_guard<std::mutex> lock(m_mutex);
|
|
|
|
|
+
|
|
|
auto it = m_handlers.find(std::type_index(typeid(T)));
|
|
auto it = m_handlers.find(std::type_index(typeid(T)));
|
|
|
if (it != m_handlers.end()) {
|
|
if (it != m_handlers.end()) {
|
|
|
auto &handlers = it->second;
|
|
auto &handlers = it->second;
|
|
|
|
|
+ auto sizeBefore = handlers.size();
|
|
|
handlers.erase(std::remove_if(handlers.begin(), handlers.end(),
|
|
handlers.erase(std::remove_if(handlers.begin(), handlers.end(),
|
|
|
[handle](const HandlerEntry &e) {
|
|
[handle](const HandlerEntry &e) {
|
|
|
return e.handle == handle;
|
|
return e.handle == handle;
|
|
|
}),
|
|
}),
|
|
|
handlers.end());
|
|
handlers.end());
|
|
|
|
|
+
|
|
|
|
|
+ if (handlers.size() < sizeBefore) {
|
|
|
|
|
+ m_stats[std::type_index(typeid(T))].subscriberCount--;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
template <typename T> void publish(const T &event) {
|
|
template <typename T> void publish(const T &event) {
|
|
|
static_assert(std::is_base_of_v<Event, T>, "T must inherit from Event");
|
|
static_assert(std::is_base_of_v<Event, T>, "T must inherit from Event");
|
|
|
- auto it = m_handlers.find(std::type_index(typeid(T)));
|
|
|
|
|
- if (it != m_handlers.end()) {
|
|
|
|
|
- for (const auto &entry : it->second) {
|
|
|
|
|
- entry.handler(&event);
|
|
|
|
|
|
|
+ std::vector<HandlerEntry> handlersCopy;
|
|
|
|
|
+
|
|
|
|
|
+ {
|
|
|
|
|
+ std::lock_guard<std::mutex> lock(m_mutex);
|
|
|
|
|
+ auto it = m_handlers.find(std::type_index(typeid(T)));
|
|
|
|
|
+ if (it != m_handlers.end()) {
|
|
|
|
|
+ handlersCopy = it->second;
|
|
|
|
|
+ m_stats[std::type_index(typeid(T))].publishCount++;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ for (const auto &entry : handlersCopy) {
|
|
|
|
|
+ entry.handler(&event);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ EventStats getStats(const std::type_index &eventType) const {
|
|
|
|
|
+ std::lock_guard<std::mutex> lock(m_mutex);
|
|
|
|
|
+ auto it = m_stats.find(eventType);
|
|
|
|
|
+ if (it != m_stats.end()) {
|
|
|
|
|
+ return it->second;
|
|
|
|
|
+ }
|
|
|
|
|
+ return EventStats{};
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ size_t getSubscriberCount(const std::type_index &eventType) const {
|
|
|
|
|
+ std::lock_guard<std::mutex> lock(m_mutex);
|
|
|
|
|
+ auto it = m_handlers.find(eventType);
|
|
|
|
|
+ if (it != m_handlers.end()) {
|
|
|
|
|
+ return it->second.size();
|
|
|
|
|
+ }
|
|
|
|
|
+ return 0;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ void clearAllSubscriptions() {
|
|
|
|
|
+ std::lock_guard<std::mutex> lock(m_mutex);
|
|
|
|
|
+ m_handlers.clear();
|
|
|
|
|
+ m_stats.clear();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
private:
|
|
@@ -66,7 +117,9 @@ private:
|
|
|
std::function<void(const void *)> handler;
|
|
std::function<void(const void *)> handler;
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
|
|
+ mutable std::mutex m_mutex;
|
|
|
std::unordered_map<std::type_index, std::vector<HandlerEntry>> m_handlers;
|
|
std::unordered_map<std::type_index, std::vector<HandlerEntry>> m_handlers;
|
|
|
|
|
+ std::unordered_map<std::type_index, EventStats> m_stats;
|
|
|
SubscriptionHandle m_nextHandle = 1;
|
|
SubscriptionHandle m_nextHandle = 1;
|
|
|
};
|
|
};
|
|
|
|
|
|
|
@@ -111,6 +164,7 @@ class UnitSelectedEvent : public Event {
|
|
|
public:
|
|
public:
|
|
|
UnitSelectedEvent(EntityID unitId) : unitId(unitId) {}
|
|
UnitSelectedEvent(EntityID unitId) : unitId(unitId) {}
|
|
|
EntityID unitId;
|
|
EntityID unitId;
|
|
|
|
|
+ const char *getTypeName() const override { return "UNIT_SELECTED"; }
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
class UnitMovedEvent : public Event {
|
|
class UnitMovedEvent : public Event {
|
|
@@ -170,4 +224,36 @@ public:
|
|
|
int newOwnerId;
|
|
int newOwnerId;
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
|
|
+enum class AmbientState { PEACEFUL, TENSE, COMBAT, VICTORY, DEFEAT };
|
|
|
|
|
+
|
|
|
|
|
+class AmbientStateChangedEvent : public Event {
|
|
|
|
|
+public:
|
|
|
|
|
+ AmbientStateChangedEvent(AmbientState newState, AmbientState previousState)
|
|
|
|
|
+ : newState(newState), previousState(previousState) {}
|
|
|
|
|
+ AmbientState newState;
|
|
|
|
|
+ AmbientState previousState;
|
|
|
|
|
+ const char *getTypeName() const override { return "AMBIENT_STATE_CHANGED"; }
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+class AudioTriggerEvent : public Event {
|
|
|
|
|
+public:
|
|
|
|
|
+ AudioTriggerEvent(const std::string &soundId, float volume = 1.0f,
|
|
|
|
|
+ bool loop = false, int priority = 0)
|
|
|
|
|
+ : soundId(soundId), volume(volume), loop(loop), priority(priority) {}
|
|
|
|
|
+ std::string soundId;
|
|
|
|
|
+ float volume;
|
|
|
|
|
+ bool loop;
|
|
|
|
|
+ int priority;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+class MusicTriggerEvent : public Event {
|
|
|
|
|
+public:
|
|
|
|
|
+ MusicTriggerEvent(const std::string &musicId, float volume = 1.0f,
|
|
|
|
|
+ bool crossfade = true)
|
|
|
|
|
+ : musicId(musicId), volume(volume), crossfade(crossfade) {}
|
|
|
|
|
+ std::string musicId;
|
|
|
|
|
+ float volume;
|
|
|
|
|
+ bool crossfade;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
} // namespace Engine::Core
|
|
} // namespace Engine::Core
|