Helios Engine 0.1.0
A modular ECS based data-oriented C++23 game engine
 
Loading...
Searching...
No Matches
helios::ecs::details::EventManager Class Reference

Manages event lifecycle with double buffering and registration tracking. More...

#include <event_manager.hpp>

Public Member Functions

 EventManager ()=default
 
 EventManager (const EventManager &)=delete
 
 EventManager (EventManager &&) noexcept=default
 
 ~EventManager ()=default
 
EventManageroperator= (const EventManager &)=delete
 
EventManageroperator= (EventManager &&) noexcept=default
 
void Clear () noexcept
 Clears all events and registration data.
 
void ClearAllQueues () noexcept
 Clears all event queues without removing registration data.
 
template<EventTrait T>
void ManualClear ()
 Manually clears events of a specific type from current and previous queues.
 
void Update ()
 Updates event lifecycle - swaps buffers and clears old events.
 
template<EventTrait T>
void RegisterEvent ()
 Registers an event type for use.
 
template<EventTrait... Events>
requires (sizeof...(Events) > 1)
void RegisterEvents ()
 Registers multiple event types for use.
 
template<EventTrait T>
void Write (const T &event)
 Writes a single event to the current queue.
 
template<std::ranges::sized_range R>
requires EventTrait<std::ranges::range_value_t<R>>
void WriteBulk (const R &events)
 Writes multiple events to the queue in bulk.
 
template<EventTrait T>
auto Read () const -> std::vector< T >
 Reads all events of a specific type from current and previous queues.
 
template<EventTrait T, typename OutIt >
requires std::output_iterator<std::remove_reference_t<OutIt>, T>
void ReadInto (OutIt out) const
 Reads events of a specific type into a provided output iterator.
 
void Merge (EventQueue &other)
 Merges events from another EventQueue into the current queue.
 
template<EventTrait T>
bool IsRegistered () const noexcept
 Checks if an event type is registered.
 
bool Empty () const noexcept
 Checks if both queues are empty.
 
template<EventTrait T>
bool HasEvents () const
 Checks if events of a specific type exist in either queue.
 
template<EventTrait T>
const EventMetadataGetMetadata () const noexcept
 Gets metadata for a registered event.
 
size_t GetCurrentFrame () const noexcept
 Gets the current frame number.
 
size_t RegisteredEventCount () const noexcept
 Gets the number of registered event types.
 
const EventQueueGetCurrentQueue () const noexcept
 Gets reference to current event queue (for testing/debugging).
 
const EventQueueGetPreviousQueue () const noexcept
 Gets reference to previous event queue (for testing/debugging).
 

Detailed Description

Manages event lifecycle with double buffering and registration tracking.

Implements Bevy-style event management with:

  • Double buffering: events persist for one full update cycle
  • Explicit registration: events must be registered before use
  • Automatic clearing: events are cleared after their lifecycle expires
  • Manual control: users can opt-out of auto-clearing for custom events

Event Lifecycle:

  • Frame N: Events written to current queue
  • Frame N+1: Events readable from previous queue (after swap)
  • Frame N+2: Events cleared from previous queue
Note
Not thread-safe.

Definition at line 47 of file event_manager.hpp.

Constructor & Destructor Documentation

◆ EventManager() [1/3]

helios::ecs::details::EventManager::EventManager ( )
default

◆ EventManager() [2/3]

helios::ecs::details::EventManager::EventManager ( const EventManager )
delete

◆ EventManager() [3/3]

helios::ecs::details::EventManager::EventManager ( EventManager &&  )
defaultnoexcept

◆ ~EventManager()

helios::ecs::details::EventManager::~EventManager ( )
default

Member Function Documentation

◆ Clear()

void helios::ecs::details::EventManager::Clear ( )
inlinenoexcept

Clears all events and registration data.

Definition at line 221 of file event_manager.hpp.

221 {
222 registered_events_.clear();
223 current_queue_.Clear();
224 previous_queue_.Clear();
225 current_frame_ = 0;
226}
void Clear() noexcept
Clears all events from the queue and removes registrations.

◆ ClearAllQueues()

void helios::ecs::details::EventManager::ClearAllQueues ( )
inlinenoexcept

Clears all event queues without removing registration data.

Useful for manually clearing events while preserving event types. Events can still be written/read after calling this method. Registration metadata and frame counter are preserved.

Definition at line 228 of file event_manager.hpp.

228 {
229 current_queue_.Clear();
230 previous_queue_.Clear();
231}

◆ Empty()

bool helios::ecs::details::EventManager::Empty ( ) const
inlinenoexcept

Checks if both queues are empty.

Returns
True if no events exist in either queue, false otherwise

Definition at line 168 of file event_manager.hpp.

168{ return current_queue_.Empty() && previous_queue_.Empty(); }
bool Empty() const noexcept
Checks if the queue is empty.

◆ GetCurrentFrame()

size_t helios::ecs::details::EventManager::GetCurrentFrame ( ) const
inlinenoexcept

Gets the current frame number.

Returns
Current frame counter value

Definition at line 192 of file event_manager.hpp.

192{ return current_frame_; }

◆ GetCurrentQueue()

const EventQueue & helios::ecs::details::EventManager::GetCurrentQueue ( ) const
inlinenoexcept

Gets reference to current event queue (for testing/debugging).

Returns
Const reference to current queue

Definition at line 204 of file event_manager.hpp.

204{ return current_queue_; }

◆ GetMetadata()

template<EventTrait T>
const EventMetadata * helios::ecs::details::EventManager::GetMetadata ( ) const
inlinenoexcept

Gets metadata for a registered event.

Template Parameters
TEvent type
Returns
Pointer to metadata, or nullptr if not registered

Definition at line 350 of file event_manager.hpp.

350 {
351 constexpr EventTypeId type_id = EventTypeIdOf<T>();
352 const auto it = registered_events_.find(type_id);
353 return it != registered_events_.end() ? &it->second : nullptr;
354}
size_t EventTypeId
Type ID for events.
Definition event.hpp:18
BasicQuery< World, Allocator, Components... > Query
Type alias for query with mutable world access.
Definition query.hpp:2481

◆ GetPreviousQueue()

const EventQueue & helios::ecs::details::EventManager::GetPreviousQueue ( ) const
inlinenoexcept

Gets reference to previous event queue (for testing/debugging).

Returns
Const reference to previous queue

Definition at line 210 of file event_manager.hpp.

210{ return previous_queue_; }

◆ HasEvents()

template<EventTrait T>
bool helios::ecs::details::EventManager::HasEvents ( ) const
inline

Checks if events of a specific type exist in either queue.

Template Parameters
TEvent type
Returns
True if events of type T exist, false otherwise
Examples
/home/runner/work/HeliosEngine/HeliosEngine/src/core/include/helios/core/ecs/event_reader.hpp.

Definition at line 176 of file event_manager.hpp.

176 {
177 return current_queue_.HasEvents<T>() || previous_queue_.HasEvents<T>();
178 }
bool HasEvents() const
Checks if events of a specific type exist in the queue.

◆ IsRegistered()

template<EventTrait T>
bool helios::ecs::details::EventManager::IsRegistered ( ) const
inlinenoexcept

Checks if an event type is registered.

Template Parameters
TEvent type
Returns
True if event is registered, false otherwise

Definition at line 357 of file event_manager.hpp.

357 {
358 constexpr EventTypeId type_id = EventTypeIdOf<T>();
359 return registered_events_.contains(type_id);
360}

◆ ManualClear()

template<EventTrait T>
void helios::ecs::details::EventManager::ManualClear ( )
inline

Manually clears events of a specific type from current and previous queues.

Should be used for manually-managed events (clear_policy = kManual). Can also be used as an override for automatic events if needed.

Warning
Triggers assertion if event is not registered.
Template Parameters
TEvent type

Definition at line 338 of file event_manager.hpp.

338 {
339 HELIOS_ASSERT(registered_events_.contains(EventTypeIdOf<T>()),
340 "Failed to manual clear events '{}': Event is not registered!", EventNameOf<T>());
341
342 // Note: We allow manual clearing for all events (automatic or manual) as an override
343 // This can be useful for debugging or special cases
344
345 current_queue_.Clear<T>();
346 previous_queue_.Clear<T>();
347}
#define HELIOS_ASSERT(condition,...)
Assertion macro that aborts execution in debug builds.
Definition assert.hpp:140

◆ Merge()

void helios::ecs::details::EventManager::Merge ( EventQueue other)
inline

Merges events from another EventQueue into the current queue.

Parameters
otherEvent queue to merge from (typically from SystemLocalStorage)

Definition at line 332 of file event_manager.hpp.

332 {
333 current_queue_.Merge(other);
334 other.Clear();
335}
void Merge(EventQueue &other)
Merges events from another EventQueue into this one.

◆ operator=() [1/2]

EventManager & helios::ecs::details::EventManager::operator= ( const EventManager )
delete

◆ operator=() [2/2]

EventManager & helios::ecs::details::EventManager::operator= ( EventManager &&  )
defaultnoexcept

◆ Read()

template<EventTrait T>
auto helios::ecs::details::EventManager::Read ( ) const -> std::vector<T>
inline

Reads all events of a specific type from current and previous queues.

Events from the current frame and previous frame are returned, implementing double buffering for reliable event delivery.

Warning
Triggers assertion if event is not registered.
Template Parameters
TEvent type
Returns
Vector containing all events of type T from both buffers

Definition at line 306 of file event_manager.hpp.

306 {
307 HELIOS_ASSERT(registered_events_.contains(EventTypeIdOf<T>()), "Failed to read events '{}': Event is not registered!",
309
310 std::vector<T> result;
311 result.reserve(previous_queue_.TypeCount() + current_queue_.TypeCount());
312
313 // Read from previous queue (events from last frame)
314 previous_queue_.ReadInto<T>(std::back_inserter(result));
315
316 // Read from current queue (events from this frame)
317 current_queue_.ReadInto<T>(std::back_inserter(result));
318
319 return result;
320}
void ReadInto(OutIt out) const
Reads events of a specific type into a provided output iterator.
size_t TypeCount() const noexcept
Gets the number of event types stored.

◆ ReadInto()

template<EventTrait T, typename OutIt >
requires std::output_iterator<std::remove_reference_t<OutIt>, T>
void helios::ecs::details::EventManager::ReadInto ( OutIt  out) const
inline

Reads events of a specific type into a provided output iterator.

Reads from current and previous queues without intermediate allocations.

Warning
Triggers assertion if event is not registered.
Template Parameters
TEvent type
OutItOutput iterator type
Parameters
outOutput iterator to write events into
Examples
/home/runner/work/HeliosEngine/HeliosEngine/src/core/include/helios/core/ecs/event_reader.hpp.

Definition at line 324 of file event_manager.hpp.

324 {
325 HELIOS_ASSERT(registered_events_.contains(EventTypeIdOf<T>()),
326 "Failed to read events '{}' into: Event is not registered!", EventNameOf<T>());
327
328 previous_queue_.ReadInto<T>(out);
329 current_queue_.ReadInto<T>(std::move(out));
330}

◆ RegisteredEventCount()

size_t helios::ecs::details::EventManager::RegisteredEventCount ( ) const
inlinenoexcept

Gets the number of registered event types.

Returns
Count of registered events

Definition at line 198 of file event_manager.hpp.

198{ return registered_events_.size(); }

◆ RegisterEvent()

template<EventTrait T>
void helios::ecs::details::EventManager::RegisterEvent ( )
inline

Registers an event type for use.

Uses the event's GetClearPolicy() if available, otherwise defaults to kAutomatic.

Warning
Triggers assertion if event is already registered.
Template Parameters
TEvent type

Definition at line 268 of file event_manager.hpp.

268 {
269 constexpr EventTypeId type_id = EventTypeIdOf<T>();
270 constexpr std::string_view name = EventNameOf<T>();
271 constexpr EventClearPolicy clear_policy = EventClearPolicyOf<T>();
272
273 HELIOS_ASSERT(!registered_events_.contains(type_id), "Failed to register event '{}': Event already registered!",
274 name);
275
276 registered_events_.emplace(
277 type_id, EventMetadata{
278 .type_id = type_id, .name = name, .clear_policy = clear_policy, .frame_registered = current_frame_});
279
280 current_queue_.Register<T>();
281 previous_queue_.Register<T>();
282
283 constexpr std::string_view policy_str = (clear_policy == EventClearPolicy::kAutomatic) ? "automatic" : "manual";
284 HELIOS_DEBUG("Registered event '{}' (clear_policy: {})", name, policy_str);
285}
void Register()
Registers an event type with the queue.
#define HELIOS_DEBUG(...)
Definition logger.hpp:667
EventClearPolicy
Policy for event clearing behavior.
Definition event.hpp:23
@ kAutomatic
Events are automatically cleared after double buffer cycle.

◆ RegisterEvents()

template<EventTrait... Events>
requires (sizeof...(Events) > 1)
void helios::ecs::details::EventManager::RegisterEvents ( )
inline

Registers multiple event types for use.

Each event uses its own GetClearPolicy() if available.

Warning
Triggers assertion if any event is already registered.
Template Parameters
EventsEvent types to register

Definition at line 104 of file event_manager.hpp.

104 {
105 (RegisterEvent<Events>(), ...);
106 }

◆ Update()

void helios::ecs::details::EventManager::Update ( )
inline

Updates event lifecycle - swaps buffers and clears old events.

Should be called at the end of each update cycle. Clears previous queue, moves current to previous, creates new current queue.

Definition at line 233 of file event_manager.hpp.

233 {
234 // Double-queue double buffering implementation with selective clearing:
235 // 1. Selectively clear auto_clear events from previous_queue_ (events that are now 2 frames old)
236 // 2. Merge current queue into previous queue (preserving non-auto_clear events)
237 // 3. Create new empty current queue for next frame
238 //
239 // This ensures:
240 // - auto_clear=true events persist for exactly 1 full update cycle
241 // - auto_clear=false events persist indefinitely until manually cleared
242 //
243 // Frame lifecycle:
244 // - Frame N: Event written to current_queue_
245 // - Frame N+1: Event readable from previous_queue_ (after merge)
246 // - Frame N+2: auto_clear=true events cleared, auto_clear=false events remain
247
248 // Step 1: Clear automatic events from previous queue (events that are 2+ frames old)
249 for (const auto& [type_id, metadata] : registered_events_) {
250 if (metadata.clear_policy == EventClearPolicy::kAutomatic) {
251 previous_queue_.ClearByTypeId(type_id);
252 }
253 }
254
255 // Step 2: Merge current queue into previous queue
256 // This preserves non-auto_clear events from previous queue while adding current frame's events
257 previous_queue_.Merge(current_queue_);
258
259 // Step 3: Clear current queue for next frame (clear each registered type individually)
260 for (const auto& [type_id, metadata] : registered_events_) {
261 current_queue_.ClearByTypeId(type_id);
262 }
263
264 ++current_frame_;
265}
void ClearByTypeId(EventTypeId type_id)
Clears events of a specific type by type ID (runtime).

◆ Write()

template<EventTrait T>
void helios::ecs::details::EventManager::Write ( const T &  event)
inline

Writes a single event to the current queue.

Warning
Triggers assertion if event is not registered.
Template Parameters
TEvent type
Parameters
eventEvent to write

Definition at line 288 of file event_manager.hpp.

288 {
289 HELIOS_ASSERT(registered_events_.contains(EventTypeIdOf<T>()), "Failed to write event '{}': Event is not registered!",
291
292 current_queue_.Write(event);
293}
void Write(const T &event)
Writes a single event to the queue.

◆ WriteBulk()

template<std::ranges::sized_range R>
requires EventTrait<std::ranges::range_value_t<R>>
void helios::ecs::details::EventManager::WriteBulk ( const R events)
inline

Writes multiple events to the queue in bulk.

Warning
Triggers assertion if event type does not exist.
Template Parameters
RRange of events
Parameters
eventsRange of events to store

Definition at line 297 of file event_manager.hpp.

297 {
298 using EventType = std::ranges::range_value_t<R>;
299 HELIOS_ASSERT(registered_events_.contains(EventTypeIdOf<EventType>()),
300 "Failed to write bulk event '{}': Event is not registered!", EventNameOf<EventType>());
301
302 current_queue_.WriteBulk(events);
303}
void WriteBulk(const R &events)
Writes multiple events to the queue in bulk.