diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index 2bb00c8..7e16ff2 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -1,11 +1,12 @@ SET(HDRS) SET(SRCS) -add_subdirectory(core) add_subdirectory(config) +add_subdirectory(core) +add_subdirectory(ecs) +add_subdirectory(eventsystem) add_subdirectory(utility) add_subdirectory(sim) -add_subdirectory(ecs) SET(HDRS ${HDRS} diff --git a/src/lib/eventsystem/CMakeLists.txt b/src/lib/eventsystem/CMakeLists.txt new file mode 100644 index 0000000..0f887ef --- /dev/null +++ b/src/lib/eventsystem/CMakeLists.txt @@ -0,0 +1,23 @@ +add_subdirectory(event) + +SET(HDRS + ${HDRS} + ${CMAKE_CURRENT_SOURCE_DIR}/Event.h + ${CMAKE_CURRENT_SOURCE_DIR}/EventHandler.h + ${CMAKE_CURRENT_SOURCE_DIR}/EventHandlerBase.h + ${CMAKE_CURRENT_SOURCE_DIR}/EventManager.h + PARENT_SCOPE +) + +SET(SRCS + ${SRCS} + ${CMAKE_CURRENT_SOURCE_DIR}/EventHandlerBase.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/EventManager.cpp + PARENT_SCOPE +) + +SET(LIB_INCLUDE_PATH + ${LIB_INCLUDE_PATH} + ${CMAKE_CURRENT_SOURCE_DIR} + PARENT_SCOPE +) diff --git a/src/lib/eventsystem/Event.h b/src/lib/eventsystem/Event.h new file mode 100644 index 0000000..8f4970f --- /dev/null +++ b/src/lib/eventsystem/Event.h @@ -0,0 +1,10 @@ +#ifndef EVENT_H +#define EVENT_H + +class Event +{ +public: + virtual ~Event() = default; +}; + +#endif // EVENT_H diff --git a/src/lib/eventsystem/EventHandler.h b/src/lib/eventsystem/EventHandler.h new file mode 100644 index 0000000..8a349f3 --- /dev/null +++ b/src/lib/eventsystem/EventHandler.h @@ -0,0 +1,80 @@ +#ifndef EVENT_HANDLER_H +#define EVENT_HANDLER_H + +#include + +#include "EventHandlerBase.h" +#include "EventManager.h" + +template +class EventHandler: public EventHandlerBase +{ +public: + void registerForEvent() + { + EventManager::getInstance()->registerEventHandler(this); + } + + void unregisterForEvent() + { + EventManager::getInstance()->unregisterEventHandler(this); + } + + void handleBaseEvent(std::shared_ptr event) override + { + std::shared_ptr specificEvent = std::dynamic_pointer_cast(event); + if (specificEvent) + { + handleEvent(specificEvent); + } + } + +private: + virtual void handleEvent(std::shared_ptr event) = 0; +}; + + +template class CombinedEventHandlerHelper +{ +protected: + void registerForEventsHelper() {} + void unregisterForEventsHelper() {} +}; + + +template +class CombinedEventHandlerHelper + : public EventHandler + , public CombinedEventHandlerHelper +{ +protected: + void registerForEventsHelper() + { + EventHandler::registerForEvent(); + CombinedEventHandlerHelper::registerForEventsHelper(); + } + + void unregisterForEventsHelper() + { + EventHandler::unregisterForEvent(); + CombinedEventHandlerHelper::unregisterForEventsHelper(); + } +}; + + +template +class CombinedEventHandler: public CombinedEventHandlerHelper +{ +protected: + void registerForEvents() + { + CombinedEventHandlerHelper::registerForEventsHelper(); + } + + void unregisterForEvents() + { + CombinedEventHandlerHelper::unregisterForEventsHelper(); + } +}; + +#endif // EVENT_HANDLER_H diff --git a/src/lib/eventsystem/EventHandlerBase.cpp b/src/lib/eventsystem/EventHandlerBase.cpp new file mode 100644 index 0000000..2f6748e --- /dev/null +++ b/src/lib/eventsystem/EventHandlerBase.cpp @@ -0,0 +1,7 @@ +#include "EventHandlerBase.h" + +unsigned int EventHandlerBase::s_nextId = 0; + +EventHandlerBase::EventHandlerBase(): m_id(s_nextId++) +{ +} diff --git a/src/lib/eventsystem/EventHandlerBase.h b/src/lib/eventsystem/EventHandlerBase.h new file mode 100644 index 0000000..af1fc77 --- /dev/null +++ b/src/lib/eventsystem/EventHandlerBase.h @@ -0,0 +1,25 @@ +#ifndef EVENT_HANDLER_BASE_H +#define EVENT_HANDLER_BASE_H + +#include + +class Event; +class EventManager; + +class EventHandlerBase +{ +private: + static unsigned int s_nextId; + +public: + EventHandlerBase(); + virtual ~EventHandlerBase() = default; + virtual void handleBaseEvent(std::shared_ptr event) = 0; + +private: + const unsigned int m_id; + + friend EventManager; +}; + +#endif // EVENT_HANDLER_BASE_H diff --git a/src/lib/eventsystem/EventManager.cpp b/src/lib/eventsystem/EventManager.cpp new file mode 100644 index 0000000..9c27070 --- /dev/null +++ b/src/lib/eventsystem/EventManager.cpp @@ -0,0 +1,123 @@ +#include "EventManager.h" + +#include + +#include "EventHandlerBase.h" + +std::shared_ptr EventManager::getInstance() +{ + if (!s_instance) + { + s_instance = std::shared_ptr(new EventManager()); + } + return s_instance; +} + +void EventManager::destroyInstance() +{ + if (s_instance) + { + s_instance.reset(); + } +} + +std::shared_ptr EventManager::s_instance = std::shared_ptr(); + +void EventManager::registerEventHandler(EventHandlerBase *eventHandler) +{ + std::scoped_lock lock(m_eventHandlersMutex); + m_eventHandlers[eventHandler->m_id] = eventHandler; +} + +void EventManager::unregisterEventHandler(EventHandlerBase *eventHandler) +{ + std::scoped_lock lock(m_eventHandlersMutex); + m_eventHandlers.erase(eventHandler->m_id); +} + +void EventManager::sendEventImmediately(std::shared_ptr event) +{ + if (event) + { + std::set eventHandlerIds; + { + std::scoped_lock lock(m_eventHandlersMutex); + for (auto it : m_eventHandlers) + { + eventHandlerIds.insert(it.first); + } + } + + for (unsigned int id : eventHandlerIds) + { + // this is necessary to allow HandleBaseEvent() to remove event handlers without causing a crash + EventHandlerBase *eventHandler = nullptr; + { + std::scoped_lock lock(m_eventHandlersMutex); + auto it = m_eventHandlers.find(id); + if (it != m_eventHandlers.end()) + { + eventHandler = it->second; + } + } + if (eventHandler) + { + eventHandler->handleBaseEvent(event); + } + } + } +} + +void EventManager::addEvent(std::shared_ptr event) +{ + if (event) + { + std::scoped_lock lock(m_eventsMutex); + m_events.push_back(event); + } +} + +void EventManager::processEvents() +{ + std::vector> events; + { + std::scoped_lock lock(m_eventsMutex); + events = m_events; + m_events.clear(); + } + + std::set eventHandlerIds; + { + std::scoped_lock lock(m_eventHandlersMutex); + for (auto it : m_eventHandlers) + { + eventHandlerIds.insert(it.first); + } + } + + for (std::shared_ptr event : events) + { + for (unsigned int id : eventHandlerIds) + { + // this is necessary to allow HandleBaseEvent() to remove event handlers without causing a crash + EventHandlerBase *eventHandler = nullptr; + { + std::scoped_lock lock(m_eventHandlersMutex); + auto it = m_eventHandlers.find(id); + if (it != m_eventHandlers.end()) + { + eventHandler = it->second; + } + } + if (eventHandler) + { + eventHandler->handleBaseEvent(event); + } + } + } +} + +bool EventManager::hasEvents() const +{ + return !m_events.empty(); +} diff --git a/src/lib/eventsystem/EventManager.h b/src/lib/eventsystem/EventManager.h new file mode 100644 index 0000000..2654afb --- /dev/null +++ b/src/lib/eventsystem/EventManager.h @@ -0,0 +1,43 @@ +#ifndef EVENT_MANAGER_H +#define EVENT_MANAGER_H + +#include +#include +#include +#include + +#include "Event.h" + +class EventHandlerBase; + +class EventManager +{ +public: + static std::shared_ptr getInstance(); + static void destroyInstance(); + +private: + static std::shared_ptr s_instance; + +public: + EventManager(EventManager const &) = delete; + void operator=(EventManager const &) = delete; + + void registerEventHandler(EventHandlerBase *eventHandler); + void unregisterEventHandler(EventHandlerBase *eventHandler); + void sendEventImmediately(std::shared_ptr event); + void addEvent(std::shared_ptr event); + void processEvents(); + + bool hasEvents() const; + +private: + EventManager() = default; + + std::map m_eventHandlers; + std::vector> m_events; + std::mutex m_eventHandlersMutex; + std::mutex m_eventsMutex; +}; + +#endif // EVENT_MANAGER_H diff --git a/src/lib/eventsystem/event/CMakeLists.txt b/src/lib/eventsystem/event/CMakeLists.txt new file mode 100644 index 0000000..3ec8c7a --- /dev/null +++ b/src/lib/eventsystem/event/CMakeLists.txt @@ -0,0 +1,17 @@ +SET(HDRS + ${HDRS} + ${CMAKE_CURRENT_SOURCE_DIR}/TracePrintRequestedEvent.h + PARENT_SCOPE +) + +SET(SRCS + ${SRCS} + ${CMAKE_CURRENT_SOURCE_DIR}/TracePrintRequestedEvent.cpp + PARENT_SCOPE +) + +set(LIB_INCLUDE_PATH + ${LIB_INCLUDE_PATH} + ${CMAKE_CURRENT_SOURCE_DIR} + PARENT_SCOPE +) diff --git a/src/lib/eventsystem/event/TracePrintRequestedEvent.cpp b/src/lib/eventsystem/event/TracePrintRequestedEvent.cpp new file mode 100644 index 0000000..364d1ca --- /dev/null +++ b/src/lib/eventsystem/event/TracePrintRequestedEvent.cpp @@ -0,0 +1 @@ +#include "TracePrintRequestedEvent.h" diff --git a/src/lib/eventsystem/event/TracePrintRequestedEvent.h b/src/lib/eventsystem/event/TracePrintRequestedEvent.h new file mode 100644 index 0000000..196d777 --- /dev/null +++ b/src/lib/eventsystem/event/TracePrintRequestedEvent.h @@ -0,0 +1,10 @@ +#ifndef TRACE_PRINT_REQUESTED_EVENT_H +#define TRACE_PRINT_REQUESTED_EVENT_H + +#include "Event.h" + +class TracePrintRequestedEvent : public Event +{ +}; + +#endif // TRACE_PRINT_REQUESTED_EVENT_H diff --git a/src/lib/sim/Simulation.cpp b/src/lib/sim/Simulation.cpp index 26ef183..ff75f28 100644 --- a/src/lib/sim/Simulation.cpp +++ b/src/lib/sim/Simulation.cpp @@ -7,6 +7,7 @@ #include "CombatSystem.h" #include "DynamicBodySystem.h" #include "FactionComponent.h" +#include "EventManager.h" #include "HealthComponent.h" #include "ModuleOwnerComponent.h" #include "MovementIntentSystem.h" @@ -71,9 +72,13 @@ Simulation::Simulation(GameConfig config, unsigned int seed) } placeInitialStructures(); + registerForEvents(); } -Simulation::~Simulation() = default; +Simulation::~Simulation() +{ + unregisterForEvents(); +} const GameConfig& Simulation::config() const { @@ -88,6 +93,7 @@ void Simulation::reset(GameConfig newConfig, unsigned int seed) void Simulation::reset(unsigned int seed) { + EventManager::destroyInstance(); m_rng.seed(seed); m_currentTick = 0; m_nextDepartureTick = secondsToTicks(m_config.world.departureIntervalSeconds); @@ -147,6 +153,8 @@ void Simulation::reset(unsigned int seed) void Simulation::tick() { + EventManager::getInstance()->processEvents(); + // Step 1: wave scheduler m_waveSystem->tickWaveScheduler(m_currentTick, *m_shipSystem, m_config.world.heightTiles); @@ -199,8 +207,6 @@ void Simulation::tick() m_scrapSystem->tickDespawn(m_currentTick); ++m_currentTick; - - PRINT_TRACES(); } // --------------------------------------------------------------------------- @@ -642,6 +648,11 @@ const EntityAdmin& Simulation::admin() const return m_admin; } +void Simulation::handleEvent(std::shared_ptr event) +{ + PRINT_TRACES(); +} + BuildingId Simulation::allocateBuildingId() { return m_nextBuildingId++; diff --git a/src/lib/sim/Simulation.h b/src/lib/sim/Simulation.h index 0475986..5edc2dd 100644 --- a/src/lib/sim/Simulation.h +++ b/src/lib/sim/Simulation.h @@ -10,15 +10,16 @@ #include "BeltSystem.h" #include "EntityAdmin.h" - #include "entt/entity/entity.hpp" #include "SchematicDropEvent.h" #include "BuildingType.h" #include "BuildingId.h" +#include "EventHandler.h" #include "FireEvent.h" #include "GameConfig.h" #include "Rotation.h" #include "Tick.h" +#include "TracePrintRequestedEvent.h" class AiSystem; class BuildingSystem; @@ -29,7 +30,7 @@ class ShipSystem; class ScrapSystem; class WaveSystem; -class Simulation +class Simulation: public CombinedEventHandler { public: explicit Simulation(GameConfig config, unsigned int seed = 0); @@ -83,6 +84,8 @@ public: const EntityAdmin& admin() const; private: + void handleEvent(std::shared_ptr event) override; + BuildingId allocateBuildingId(); // Strictly increasing; never returns kInvalidBuildingId. // Populate HQ, player defence stations, and the first enemy station set. diff --git a/src/ui/GameWorldView.cpp b/src/ui/GameWorldView.cpp index 32e6b53..2781ff0 100644 --- a/src/ui/GameWorldView.cpp +++ b/src/ui/GameWorldView.cpp @@ -20,6 +20,7 @@ #include "BeltSystem.h" #include "Building.h" #include "BuildingSystem.h" +#include "EventManager.h" #include "FacingComponent.h" #include "FactionComponent.h" #include "HealthComponent.h" @@ -32,6 +33,7 @@ #include "StationBodyComponent.h" #include "SurfaceMask.h" #include "Tick.h" +#include "TracePrintRequestedEvent.h" namespace { @@ -1132,9 +1134,12 @@ void GameWorldView::keyPressEvent(QKeyEvent* event) case Qt::Key_Backspace: toggleDemolishMode(); break; - case Qt::Key_M: - m_debugDraw = !m_debugDraw; - break; + case Qt::Key_M: + m_debugDraw = !m_debugDraw; + break; + case Qt::Key_L: + EventManager::getInstance()->addEvent(std::make_shared()); + break; default: QOpenGLWidget::keyPressEvent(event); break;