Helios Engine
A modular ECS based data-oriented C++23 game engine framework
Loading...
Searching...
No Matches
world.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <helios/assert.hpp>
9#include <helios/ecs/details/profile.hpp>
22
23#include <array>
24#include <concepts>
25#include <cstddef>
26#include <ranges>
27#include <string>
28#include <type_traits>
29
30namespace helios::ecs {
31
32/**
33 * @brief The World class manages entities with their components and systems.
34 * @details All modifications to the world (adding/removing entities or
35 * components) should be done via command buffers to defer changes until the
36 * next update.
37 * @note Partially thread safe.
38 */
39class World {
40public:
42 World(const World&) = delete;
43 World(World&&) noexcept = default;
44 ~World() = default;
45
46 World& operator=(const World&) = delete;
47 World& operator=(World&&) noexcept = default;
48
49 /**
50 * @brief Flushes buffer of pending operations.
51 * @note Not thread-safe.
52 */
53 void Update();
54
55 /**
56 * @brief Flushes entity reservations and executes pending commands.
57 * @details Does not advance the message lifecycle. Call `Update()` to also
58 * swap message buffers and clear aged automatic messages.
59 * @note Not thread-safe.
60 */
61 void Flush();
62
63 /**
64 * @brief Clears the world, removing all data.
65 * @note Not thread-safe.
66 */
67 void Clear();
68
69 /**
70 * @brief Clears all entities and components from the world.
71 * @note Not thread-safe.
72 */
73 void ClearEntities() noexcept;
74
75 /**
76 * @brief Creates new entity.
77 * @note Not thread-safe.
78 * @return Newly created entity.
79 */
80 [[nodiscard]] Entity CreateEntity();
81
82 /**
83 * @brief Reserves an entity ID for deferred creation.
84 * @details The actual entity creation is deferred until `Update()` is called.
85 * @note Thread-safe.
86 * @return Reserved entity ID
87 */
88 [[nodiscard]] Entity ReserveEntity() {
89 return entity_manager_.ReserveEntity();
90 }
91
92 /**
93 * @brief Destroys entity and removes it from the world.
94 * @note Not thread-safe.
95 * @warning Triggers assertion in next cases:
96 * - Entity is invalid.
97 * - World does not own entity.
98 * @param entity Entity to destroy
99 */
100 void DestroyEntity(Entity entity);
101
102 /**
103 * @brief Tries to destroy entity if it exists in the world.
104 * @note Not thread-safe.
105 * @warning Triggers assertion if entity is invalid.
106 * @param entity Entity to destroy
107 */
108 void TryDestroyEntity(Entity entity);
109
110 /**
111 * @brief Destroys entities and removes them from the world.
112 * @note Not thread-safe.
113 * @warning Triggers assertion in next cases:
114 * - Any entity is invalid.
115 * - Any entity does not exist in the world.
116 * @tparam R Range type containing `Entity` elements
117 * @param entities Entities to destroy
118 */
119 template <std::ranges::input_range R>
120 requires std::same_as<std::ranges::range_value_t<R>, Entity>
121 void DestroyEntities(const R& entities);
122
123 /**
124 * @brief Tries to destroy entities if they exist in the world.
125 * @note Not thread-safe.
126 * @warning Triggers assertion only if any entity is invalid (non-existing
127 * entities are skipped).
128 * @tparam R Range type containing `Entity` elements
129 * @param entities Entities to destroy
130 */
131 template <std::ranges::input_range R>
132 requires std::same_as<std::ranges::range_value_t<R>, Entity>
133 void TryDestroyEntities(const R& entities);
134
135 /**
136 * @brief Creates a query over entities matching the specified component
137 * criteria.
138 * @details Component filters (`With<>`, `Without<>`) and access types
139 * (`T&`, `const T&`, `T*`, ...) are all specified as template arguments.
140 * @note Not thread-safe.
141 * @tparam Args Component access types and optional With/Without filters
142 * @tparam Allocator Allocator type for internal query storage
143 * @param alloc Allocator instance
144 * @return Query object over entities matching the specified criteria
145 *
146 * @code
147 * // Default allocator — no argument needed
148 * auto query = world.Query<Transform&, const Velocity&,
149 * const Gravity*, With<Player>,
150 * Without<Dead>>();
151 *
152 * for (auto&& [transform, velocity, gravity] : query) {
153 * transform.position += velocity.direction * velocity.speed;
154 * if (gravity) {
155 * transform.position.y += gravity->force;
156 * }
157 * }
158 * @endcode
159 */
160 template <QueryArg... Args,
161 typename Allocator = std::allocator<ComponentTypeIndex>>
162 [[nodiscard]] auto Query(Allocator alloc = {}) noexcept
164 return BasicQuery<World, Allocator, Args...>(component_manager_,
165 std::move(alloc));
166 }
167
168 /**
169 * @brief Creates a query using a PMR memory resource.
170 * @details Equivalent to the allocator overload but accepts a
171 * `pmr::memory_resource*` directly, constructing a
172 * `pmr::polymorphic_allocator` internally.
173 *
174 * @note Not thread-safe.
175 * @tparam Args Component access types and optional With/Without filters
176 * @param resource Memory resource for internal query storage
177 * @return Query object over entities matching the specified criteria
178 *
179 * @code
180 * auto query = world.Query<Transform&, const Velocity&>(&resource);
181 *
182 * for (auto&& [transform, velocity] : query) {
183 * transform.position += velocity.direction * velocity.speed;
184 * }
185 * @endcode
186 */
187 template <QueryArg... Args>
188 [[nodiscard]] auto Query(std::pmr::memory_resource* resource) noexcept
191 component_manager_, resource);
192 }
193
194 template <QueryArg... Args>
195 auto Query(std::nullptr_t)
197
198 /**
199 * @brief Creates a read-only query over entities matching the specified
200 * component criteria.
201 * @details All component accesses must be const-qualified or be values (being
202 * copied) — `T&` and `T*` are rejected at compile time.
203 * @note Not thread-safe.
204 * @tparam Args Component access types and optional With/Without filters
205 * @tparam Allocator Allocator type for internal query storage
206 * @param alloc Allocator instance
207 * @return Query object over entities matching the specified criteria
208 *
209 * @code
210 * // Default allocator — no argument needed
211 * auto query = world.ReadOnlyQuery<Health, const Status*,
212 * With<Player>, Without<Dead>>();
213 *
214 * for (auto&& [health, status] : query) {
215 * if (status) {
216 * helios::log::Trace("health: {}, status: {}", health, *status);
217 * }
218 * }
219 * @endcode
220 */
221 template <QueryArg... Args,
222 typename Allocator = std::allocator<ComponentTypeIndex>>
223 requires details::ValidWorldComponentAccessFromTuple<
224 const World,
225 typename details::QueryArgSplit<Args...>::Components>::kValue
226 [[nodiscard]] auto ReadOnlyQuery(Allocator alloc = {}) const noexcept
228 return BasicQuery<const World, Allocator, Args...>(component_manager_,
229 std::move(alloc));
230 }
231
232 /**
233 * @brief Creates a read-only query using a PMR memory resource.
234 * @details All component accesses must be const-qualified — see the allocator
235 * overload for details.
236 *
237 * @note Not thread-safe.
238 * @tparam Args Component access types and optional With/Without filters
239 * @param resource Memory resource for internal query storage
240 * @return Query object over entities matching the specified criteria
241 *
242 * @code
243 * auto query = world.ReadOnlyQuery<Health, const Status*>(&resource);
244 *
245 * for (auto&& [health, status] : query) {
246 * if (status) {
247 * helios::log::Trace("health: {}, status: {}", health, *status);
248 * }
249 * }
250 * @endcode
251 */
252 template <QueryArg... Args>
253 requires details::ValidWorldComponentAccessFromTuple<
254 const World,
255 typename details::QueryArgSplit<Args...>::Components>::kValue
256 [[nodiscard]] auto ReadOnlyQuery(
257 std::pmr::memory_resource* resource) const noexcept
260 component_manager_, resource);
261 }
262
263 template <QueryArg... Args>
264 requires details::ValidWorldComponentAccessFromTuple<
265 const World,
266 typename details::QueryArgSplit<Args...>::Components>::kValue
267 auto ReadOnlyQuery(std::nullptr_t) const
269 delete;
270
271 /**
272 * @brief Adds components to the entity.
273 * @details If entity already has component of provided type then it will be
274 * replaced.
275 * @note Not thread-safe.
276 * @warning Triggers assertion in next cases:
277 * - Entity is invalid.
278 * - World does not own entity.
279 * @tparam Ts Components types to add
280 * @param entity Entity to add components to
281 * @param components Components to add
282 */
283 template <ComponentTrait... Ts>
284 requires utils::UniqueTypes<Ts...> && (sizeof...(Ts) > 0)
285 void AddComponents(Entity entity, Ts&&... components);
286
287 /**
288 * @brief Tries to add components to the entity if they don't exist.
289 * @note Not thread-safe.
290 * @warning Triggers assertion in next cases:
291 * - Entity is invalid.
292 * - World does not own entity.
293 * @tparam Ts Components types to add
294 * @param entity Entity to add components to
295 * @param components Components to add
296 * @return Array of bools indicating whether each component was added (true if
297 * added, false otherwise) if more than one component was added, otherwise
298 * returns a single bool indicating whether the component was added.
299 */
300 template <ComponentTrait... Ts>
301 requires utils::UniqueTypes<Ts...> && (sizeof...(Ts) > 0)
302 auto TryAddComponents(Entity entity, Ts&&... components)
303 -> std::conditional_t<sizeof...(Ts) == 1, bool,
304 std::array<bool, sizeof...(Ts)>>;
305
306 /**
307 * @brief Emplaces component for the entity.
308 * @details Constructs component in-place. If entity already has component of
309 * provided type then it will be replaced.
310 * @note Not thread-safe.
311 * @warning Triggers assertion in next cases:
312 * - Entity is invalid.
313 * - World does not own entity.
314 * @tparam T Component type to emplace
315 * @tparam Args Argument types to forward to `T`'s constructor
316 * @param entity Entity to emplace component to
317 * @param args Arguments to forward to component constructor
318 */
319 template <ComponentTrait T, typename... Args>
320 requires std::constructible_from<T, Args...>
321 void EmplaceComponent(Entity entity, Args&&... args);
322
323 /**
324 * @brief Tries to emplace component for the entity.
325 * @details Constructs component in-place. Returns false if component is
326 * already on the entity.
327 * @note Not thread-safe.
328 * @warning Triggers assertion in next cases:
329 * - Entity is invalid.
330 * - World does not own entity.
331 * @tparam T Component type to emplace
332 * @tparam Args Argument types to forward to `T`'s constructor
333 * @param entity Entity to emplace component to
334 * @param args Arguments to forward to component constructor
335 * @return True if component was emplaced, false otherwise
336 */
337 template <ComponentTrait T, typename... Args>
338 requires std::constructible_from<T, Args...>
339 bool TryEmplaceComponent(Entity entity, Args&&... args);
340
341 /**
342 * @brief Removes components from the entity.
343 * @note Not thread-safe.
344 * @warning Triggers assertion in next cases:
345 * - Entity is invalid.
346 * - World does not own entity.
347 * - Entity does not have any of the components.
348 * @tparam Ts Components types to remove
349 * @param entity Entity to remove components from
350 */
351 template <ComponentTrait... Ts>
352 requires utils::UniqueTypes<Ts...> && (sizeof...(Ts) > 0)
353 void RemoveComponents(Entity entity);
354
355 /**
356 * @brief Tries to remove components from the entity if they exist.
357 * @note Not thread-safe.
358 * @warning Triggers assertion in next cases:
359 * - Entity is invalid.
360 * - World does not own entity.
361 * @tparam Ts Components types to remove
362 * @param entity Entity to remove components from
363 * @return Array of bools indicating whether each component was removed if
364 * more than one component was passed, otherwise returns a single bool
365 * indicating whether the component was removed.
366 */
367 template <ComponentTrait... Ts>
368 requires utils::UniqueTypes<Ts...> && (sizeof...(Ts) > 0)
369 auto TryRemoveComponents(Entity entity)
370 -> std::conditional_t<sizeof...(Ts) == 1, bool,
371 std::array<bool, sizeof...(Ts)>>;
372
373 /**
374 * @brief Removes all components from the entity.
375 * @note Not thread-safe.
376 * @warning Triggers assertion in next cases:
377 * - Entity is invalid.
378 * - World does not own entity.
379 * @param entity Entity to remove all components from
380 */
381 void ClearComponents(Entity entity);
382
383 /**
384 * @brief Gets a mutable reference to a component.
385 * @note Not thread-safe.
386 * @warning Triggers assertion in next cases:
387 * - Entity is invalid.
388 * - World does not own entity.
389 * - Entity does not have the component.
390 * @tparam T Component type
391 * @param entity Entity to get component from
392 * @return Mutable reference to component
393 */
394 template <ComponentTrait T>
395 [[nodiscard]] T& WriteComponent(Entity entity);
396
397 /**
398 * @brief Gets a const reference to a component.
399 * @note Thread-safe for read operations.
400 * @warning Triggers assertion in next cases:
401 * - Entity is invalid.
402 * - World does not own entity.
403 * - Entity does not have the component.
404 * @tparam T Component type
405 * @param entity Entity to get component from
406 * @return Const reference to component
407 */
408 template <ComponentTrait T>
409 [[nodiscard]] const T& ReadComponent(Entity entity) const;
410
411 /**
412 * @brief Tries to get a mutable pointer to a component.
413 * @note Not thread-safe.
414 * @tparam T Component type
415 * @param entity Entity to get component from
416 * @return Pointer to component, or `nullptr` if not found
417 */
418 template <ComponentTrait T>
419 [[nodiscard]] T* TryWriteComponent(Entity entity);
420
421 /**
422 * @brief Tries to get a const pointer to a component.
423 * @note Thread-safe for read operations.
424 * @tparam T Component type
425 * @param entity Entity to get component from
426 * @return Const pointer to component, or `nullptr` if not found
427 */
428 template <ComponentTrait T>
429 [[nodiscard]] const T* TryReadComponent(Entity entity) const;
430
431 /**
432 * @brief Inserts a resource into the world.
433 * @details Replaces existing resource if present.
434 * @note Not thread-safe.
435 * @tparam T Resource type
436 * @param resource Resource to insert
437 */
438 template <ResourceTrait T>
439 void InsertResources(T&& resource);
440
441 /**
442 * @brief Inserts resources into the world.
443 * @details Replaces existing resources if present.
444 * @note Not thread-safe.
445 * @tparam Ts Resource types
446 * @param resources Resources to insert
447 */
448 template <ResourceTrait... Ts>
449 requires utils::UniqueTypes<Ts...> && (sizeof...(Ts) > 1)
450 void InsertResources(Ts&&... resources) {
451 (InsertResources(std::forward<Ts>(resources)), ...);
452 }
453
454 /**
455 * @brief Tries to insert resource if not present.
456 * @note Not thread-safe.
457 * @tparam T Resource type
458 * @param resource Resource to insert
459 * @return True if inserted, false if resource already exists
460 */
461 template <ResourceTrait T>
462 bool TryInsertResources(T&& resource);
463
464 /**
465 * @brief Tries to insert resources if not present.
466 * @note Not thread-safe.
467 * @tparam Ts Resource types
468 * @param resources Resources to insert
469 * @return Array of bools indicating whether each resource was inserted
470 */
471 template <ResourceTrait... Ts>
472 auto TryInsertResources(Ts&&... resources)
473 -> std::array<bool, sizeof...(Ts)> {
474 return {TryInsertResources(std::forward<Ts>(resources))...};
475 }
476
477 /**
478 * @brief Emplaces a resource in-place.
479 * @note Not thread-safe.
480 * @tparam T Resource type
481 * @tparam Args Constructor argument types
482 * @param args Arguments to forward to resource constructor
483 */
484 template <ResourceTrait T, typename... Args>
485 requires std::constructible_from<T, Args...>
486 void EmplaceResource(Args&&... args);
487
488 /**
489 * @brief Tries to emplace a resource if not present.
490 * @note Not thread-safe.
491 * @tparam T Resource type
492 * @tparam Args Constructor argument types
493 * @param args Arguments to forward to resource constructor
494 * @return True if emplaced, false if resource already exists
495 */
496 template <ResourceTrait T, typename... Args>
497 requires std::constructible_from<T, Args...>
498 bool TryEmplaceResource(Args&&... args);
499
500 /**
501 * @brief Removes resources from the world.
502 * @note Not thread-safe.
503 * @warning Triggers assertion if resource does not exist.
504 * @tparam Ts Resource types
505 */
506 template <ResourceTrait... Ts>
507 requires utils::UniqueTypes<Ts...> && (sizeof...(Ts) > 0)
508 void RemoveResources();
509
510 /**
511 * @brief Tries to remove resource.
512 * @note Not thread-safe.
513 * @tparam T Resource type
514 * @return True if removed, false if resource didn't exist
515 */
516 template <ResourceTrait T>
517 bool TryRemoveResources();
518
519 /**
520 * @brief Tries to remove resources.
521 * @note Not thread-safe.
522 * @tparam Ts Resource types
523 * @return Array of bools indicating whether each resource was removed
524 */
525 template <ResourceTrait... Ts>
526 requires utils::UniqueTypes<Ts...> && (sizeof...(Ts) > 1)
527 auto TryRemoveResources() -> std::array<bool, sizeof...(Ts)> {
528 return {TryRemoveResources<Ts>()...};
529 }
530
531 /**
532 * @brief Gets reference to a resource.
533 * @note Not thread-safe.
534 * @warning Triggers assertion if resource does not exist.
535 * @tparam T Resource type
536 * @return Reference to resource
537 */
538 template <ResourceTrait T>
539 [[nodiscard]] T& WriteResource() noexcept;
540
541 /**
542 * @brief Gets const reference to a resource.
543 * @note Thread-safe for read operations.
544 * @warning Triggers assertion if resource doesn't exist.
545 * @tparam T Resource type
546 * @return Const reference to resource
547 */
548 template <ResourceTrait T>
549 [[nodiscard]] const T& ReadResource() const noexcept;
550
551 /**
552 * @brief Tries to get mutable pointer to a resource.
553 * @note Thread-safe for read operations.
554 * @tparam T Resource type
555 * @return Pointer to resource, or `nullptr` if not found
556 */
557 template <ResourceTrait T>
558 [[nodiscard]] T* TryWriteResource() noexcept {
559 return resources_.TryGet<T>();
560 }
561
562 /**
563 * @brief Tries to get const pointer to a resource.
564 * @note Thread-safe for read operations.
565 * @tparam T Resource type
566 * @return Const pointer to resource, or `nullptr` if not found
567 */
568 template <ResourceTrait T>
569 [[nodiscard]] const T* TryReadResource() const noexcept {
570 return resources_.TryGet<T>();
571 }
572
573 /**
574 * @brief Registers an message type for use.
575 * @note Not thread-safe.
576 * Should be called during initialization.
577 * @tparam T Message type
578 */
579 template <AnyMessageTrait T>
580 void AddMessage();
581
582 /**
583 * @brief Registers multiple message types for use.
584 * @note Not thread-safe.
585 * Should be called during initialization.
586 * @tparam Ts Message types to add
587 */
588 template <AnyMessageTrait... Ts>
589 requires(sizeof...(Ts) > 0)
590 void AddMessages() {
591 (AddMessage<Ts>(), ...);
592 }
593
594 /**
595 * @brief Registers all built-in non-template message types.
596 * @details This is called automatically during `World` construction.
597 * @note Not thread-safe.
598 */
599 void AddBuiltinMessages();
600
601 /**
602 * @brief Clears all messages without removing registration.
603 * @details Messages can still be written/read after calling this method.
604 * To completely reset the message system including registration, use
605 * `Clear()`.
606 * @note Not thread-safe.
607 */
608 void ClearMessages() noexcept { messages_.ClearAllQueues(); }
609
610 /**
611 * @brief Manually clears messages of specific types from both queues.
612 * @details Should only be used for manually-managed messages (auto_clear =
613 * false).
614 * @note Thread-safe if message is async, not thread-safe otherwise.
615 * @warning Triggers assertion if message type is not added.
616 * @tparam Ts Message types
617 */
618 template <AnyMessageTrait... Ts>
619 requires(sizeof...(Ts) > 0)
620 void ClearMessages();
621
622 /**
623 * @brief Gets a reader for messages of type `T` without consume support.
624 * @note Thread-safe.
625 * @warning Triggers assertion if message type is not added.
626 * @tparam T Message type
627 * @return Message reader for type `T`
628 */
629 template <MessageTrait T>
630 [[nodiscard]] auto ReadMessages() const noexcept -> MessageReader<T>;
631
632 /**
633 * @brief Gets a consumable reader for messages of type `T` without consume
634 * support.
635 * @note Thread-safe.
636 * @warning Triggers assertion if message type is not added.
637 * @tparam T Consumable message type
638 * @return Consumable message reader for type `T`
639 */
640 template <ConsumableMessageTrait T>
641 [[nodiscard]] auto ReadConsumableMessages() noexcept
643
644 /**
645 * @brief Gets a writer for messages of type `T`.
646 * @note Not thread-safe.
647 * @warning Triggers assertion if message type is not added.
648 * @tparam T Message type
649 * @return Message writer for type `T`
650 */
651 template <MessageTrait T>
652 [[nodiscard]] auto WriteMessages() noexcept -> BasicMessageWriter<T>;
653
654 /**
655 * @brief Gets a reader for messages of type `T`.
656 * @note Thread-safe.
657 * @warning Triggers assertion if message type is not added.
658 * @tparam T Async message type
659 * @return Async message reader for type `T`
660 */
661 template <AsyncMessageTrait T>
662 [[nodiscard]] auto ReadAsyncMessages() noexcept -> AsyncMessageReader<T>;
663
664 /**
665 * @brief Gets a writer for messages of type `T`.
666 * @note Thread-safe.
667 * @warning Triggers assertion if message type is not added.
668 * @tparam T Async message type
669 * @return Async message writer for type `T`
670 */
671 template <AsyncMessageTrait T>
672 [[nodiscard]] auto WriteAsyncMessages() noexcept -> AsyncMessageWriter<T>;
673
674 /**
675 * @brief Reserves capacity in the command queue to avoid reallocations.
676 * @note Not thread-safe.
677 * @param count Number of commands to reserve space for
678 */
679 void ReserveCommands(size_t count) { command_queue_.Reserve(count); }
680
681 /**
682 * @brief Enqueues a command to be executed during the next `Update()`.
683 * @note Not thread-safe.
684 * @tparam Cmd Command type, must satisfy `CommandTrait`
685 * @param command Command to enqueue
686 */
687 template <CommandTrait Cmd>
688 void EnqueueCommand(Cmd&& command) {
689 command_queue_.Enqueue(std::forward<Cmd>(command));
690 }
691
692 /**
693 * @brief Enqueues multiple commands to be executed during the next
694 * `Update()`.
695 * @note Not thread-safe.
696 * @tparam R Range type containing command elements that must satisfy and
697 * `CommandTrait`
698 * @param range Commands to enqueue
699 */
700 template <std::ranges::input_range R>
702 void EnqueueCommandBulk(R&& range) {
703 command_queue_.EnqueueBulk(std::forward<R>(range));
704 }
705
706 /**
707 * @brief Checks if entity exists in the world.
708 * @note Thread-safe for read operations.
709 * @warning Triggers assertion if entity is invalid.
710 * @param entity Entity to check
711 * @return True if entity exists, false otherwise
712 */
713 [[nodiscard]] bool Exists(Entity entity) const noexcept;
714
715 /**
716 * @brief Checks if entity has component.
717 * @note Thread-safe for read operations.
718 * @warning Triggers assertion in next cases:
719 * - Entity is invalid.
720 * - World does not own entity.
721 * @tparam T Component type to check
722 * @param entity Entity to check
723 * @return True if entity has the component
724 */
725 template <ComponentTrait T>
726 [[nodiscard]] bool HasComponent(Entity entity) const;
727
728 /**
729 * @brief Checks if entity has components.
730 * @note Thread-safe for read operations.
731 * @warning Triggers assertion if entity is invalid.
732 * @tparam Ts Components types
733 * @param entity Entity to check
734 * @return Array of bools indicating whether entity has each component (true
735 * if entity has component, false otherwise)
736 */
737 template <ComponentTrait... Ts>
738 requires utils::UniqueTypes<Ts...> && (sizeof...(Ts) > 0)
739 [[nodiscard]] auto HasComponents(Entity entity) const
740 -> std::array<bool, sizeof...(Ts)>;
741
742 /**
743 * @brief Checks if a resource exists.
744 * @note Thread-safe for read operations.
745 * @tparam T Resource type
746 * @return True if resource exists, false otherwise
747 */
748 template <ResourceTrait T>
749 [[nodiscard]] bool HasResource() const {
750 return resources_.Has<T>();
751 }
752
753 /**
754 * @brief Checks if a message added.
755 * @note Thread-safe for read operations.
756 * @tparam T Message type
757 * @return True if message exists, false otherwise
758 */
759 template <AnyMessageTrait T>
760 [[nodiscard]] bool HasMessage() const noexcept {
761 return messages_.IsRegistered<T>();
762 }
763
764 /**
765 * @brief Checks if messages of a specific type exist in message queue.
766 * @note Thread-safe for read operations.
767 * @tparam T Message type
768 * @return True if messages exist, false otherwise
769 */
770 template <AnyMessageTrait T>
771 [[nodiscard]] bool HasMessages() const noexcept {
772 return messages_.HasMessages<T>();
773 }
774
775 /**
776 * @brief Checks if there are any pending commands in the command queue.
777 * @note Thread-safe for read operations.
778 * @return True if there are pending commands, false otherwise
779 */
780 [[nodiscard]] bool HasCommands() const noexcept {
781 return !command_queue_.Empty();
782 }
783
784 /**
785 * @brief Gets the number of entities in the world.
786 * @note Thread-safe for read operations.
787 * @return Number of entities in the world
788 */
789 [[nodiscard]] size_t EntityCount() const noexcept {
790 return entity_manager_.Count();
791 }
792
793 /**
794 * @brief Gets the number of resources in the world.
795 * @note Thread-safe for read operations.
796 * @return Number of resources in the world
797 */
798 [[nodiscard]] size_t ResourceCount() const noexcept {
799 return resources_.Count();
800 }
801
802 /**
803 * @brief Gets the number of pending commands in the command queue.
804 * @note Thread-safe for read operations.
805 * @return Number of pending commands in the command queue
806 */
807 [[nodiscard]] size_t CommandCount() const noexcept {
808 return command_queue_.Size();
809 }
810
811 /**
812 * @brief Gets the entity manager.
813 * @note Thread-safe.
814 * @return Reference to entity manager
815 */
816 [[nodiscard]] EntityManager& Entities() noexcept { return entity_manager_; }
817
818 /**
819 * @brief Gets the entity manager.
820 * @note Thread-safe.
821 * @return Const reference to entity manager
822 */
823 [[nodiscard]] const EntityManager& Entities() const noexcept {
824 return entity_manager_;
825 }
826
827 /**
828 * @brief Gets the component manager.
829 * @note Thread-safe.
830 * @return Mutable reference to component manager
831 */
832 [[nodiscard]] ComponentManager& Components() noexcept {
833 return component_manager_;
834 }
835
836 /**
837 * @brief Gets the component manager (const).
838 * @note Thread-safe.
839 * @return Const reference to component manager
840 */
841 [[nodiscard]] const ComponentManager& Components() const noexcept {
842 return component_manager_;
843 }
844
845 /**
846 * @brief Gets the resource manager.
847 * @note Thread-safe.
848 * @return Mutable reference to resource manager
849 */
850 [[nodiscard]] ResourceManager& Resources() noexcept { return resources_; }
851
852 /**
853 * @brief Gets the resource manager (const).
854 * @note Thread-safe.
855 * @return Const reference to resource manager
856 */
857 [[nodiscard]] const ResourceManager& Resources() const noexcept {
858 return resources_;
859 }
860
861 /**
862 * @brief Gets the message manager.
863 * @note Thread-safe.
864 * @return Mutable reference to message manager
865 */
866 [[nodiscard]] MessageManager& Messages() noexcept { return messages_; }
867
868 /**
869 * @brief Gets the message manager (const).
870 * @note Thread-safe.
871 * @return Const reference to message manager
872 */
873 [[nodiscard]] const MessageManager& Messages() const noexcept {
874 return messages_;
875 }
876
877private:
878 EntityManager entity_manager_; ///< Entity manager that handles entity
879 ///< creation, destruction, and validation.
880
881 ComponentManager component_manager_; ///< Component manager that handles
882 ///< storage and access of components.
883
884 ResourceManager resources_; ///< Resource manager that handles storage and
885 ///< access of resources.
886
887 MessageManager messages_; ///< Message manager that handles registration and
888 ///< storage of messages.
889
890 CmdQueue<> command_queue_; ///< Command queue for deferred operations on the
891 ///< world, executed during `Flush()`.
892};
893
894inline void World::Update() {
895 HELIOS_ECS_PROFILE_SCOPE_N("helios::ecs::World::Update");
896
897 Flush();
898 messages_.Update();
899}
900
901inline void World::Flush() {
902 HELIOS_ECS_PROFILE_SCOPE_N("helios::ecs::World::Flush");
903
904 entity_manager_.Flush(
905 [this](Entity entity) { component_manager_.InitEntity(entity); });
906 command_queue_.ExecuteAll(*this);
907}
908
909inline void World::Clear() {
910 command_queue_.Clear();
911 component_manager_.Clear();
912 entity_manager_.Clear();
913 resources_.Clear();
914 messages_.Clear();
916}
917
918inline void World::ClearEntities() noexcept {
919 component_manager_.ClearData();
920 entity_manager_.Clear();
921}
922
924 Entity entity = entity_manager_.Create();
925 component_manager_.InitEntity(entity);
926 messages_.Write(EntityAddedMsg(entity));
927 return entity;
928}
929
930inline void World::DestroyEntity(Entity entity) {
931 HELIOS_ASSERT(entity.Valid(), "Entity '{}' is invalid!", entity);
932 HELIOS_ASSERT(entity_manager_.Validate(entity),
933 "World does not own entity '{}'!", entity);
934
935 component_manager_.RemoveEntity(entity);
936 entity_manager_.Destroy(entity);
937 messages_.Write(EntityDestroyedMsg(entity));
938}
939
940inline void World::TryDestroyEntity(Entity entity) {
941 HELIOS_ASSERT(entity.Valid(), "Entity '{}' is invalid!", entity);
942 if (!entity_manager_.Validate(entity)) {
943 return;
944 }
945
946 component_manager_.TryRemoveEntity(entity);
947 entity_manager_.Destroy(entity);
948 messages_.Write(EntityDestroyedMsg(entity));
949}
950
951template <std::ranges::input_range R>
952 requires std::same_as<std::ranges::range_value_t<R>, Entity>
953inline void World::DestroyEntities(const R& entities) {
954 for (const auto& entity : entities) {
955 HELIOS_ASSERT(entity.Valid(), "Entity '{}' is invalid!", entity);
956 HELIOS_ASSERT(entity_manager_.Validate(entity),
957 "World does not own entity '{}'!", entity);
958 DestroyEntity(entity);
959 }
960}
961
962template <std::ranges::input_range R>
963 requires std::same_as<std::ranges::range_value_t<R>, Entity>
964inline void World::TryDestroyEntities(const R& entities) {
965 for (const auto& entity : entities) {
966 TryDestroyEntity(entity);
967 }
968}
969
970template <ComponentTrait... Ts>
971 requires utils::UniqueTypes<Ts...> && (sizeof...(Ts) > 0)
972inline void World::AddComponents(Entity entity, Ts&&... components) {
973 HELIOS_ASSERT(entity.Valid(), "Entity '{}' is invalid!", entity);
974 HELIOS_ASSERT(entity_manager_.Validate(entity),
975 "World does not own entity '{}'!", entity);
976
978 component_manager_.template Add<std::remove_cvref_t<Ts>...>(
979 entity, std::forward<Ts>(components)...);
980 (messages_.Write(ComponentAddedMsg<std::remove_cvref_t<Ts>>(entity)), ...);
981}
982
983template <ComponentTrait... Ts>
984 requires utils::UniqueTypes<Ts...> && (sizeof...(Ts) > 0)
985inline auto World::TryAddComponents(Entity entity, Ts&&... components)
986 -> std::conditional_t<sizeof...(Ts) == 1, bool,
987 std::array<bool, sizeof...(Ts)>> {
988 HELIOS_ASSERT(entity.Valid(), "Entity '{}' is invalid!", entity);
989 HELIOS_ASSERT(entity_manager_.Validate(entity),
990 "World does not own entity '{}'!", entity);
991
993
994 auto added = component_manager_.template TryAdd<std::remove_cvref_t<Ts>...>(
995 entity, std::forward<Ts>(components)...);
996
997 if constexpr (sizeof...(Ts) == 1) {
998 if (added) {
999 (messages_.Write(ComponentAddedMsg<std::remove_cvref_t<Ts>>(entity)),
1000 ...);
1001 }
1002 } else {
1003 [this, entity, &added]<size_t... Is>(std::index_sequence<Is...>) {
1004 ((added[Is] &&
1005 (messages_.Write(ComponentAddedMsg<std::remove_cvref_t<Ts>>(entity)),
1006 true)),
1007 ...);
1008 }(std::index_sequence_for<Ts...>{});
1009 }
1010
1011 return added;
1012}
1013
1014template <ComponentTrait T, typename... Args>
1015 requires std::constructible_from<T, Args...>
1016inline void World::EmplaceComponent(Entity entity, Args&&... args) {
1017 HELIOS_ASSERT(entity.Valid(), "Entity '{}' is invalid!", entity);
1018 HELIOS_ASSERT(entity_manager_.Validate(entity),
1019 "World does not own entity '{}'!", entity);
1020
1022 component_manager_.template Emplace<T>(entity, std::forward<Args>(args)...);
1023 messages_.Write(ComponentAddedMsg<T>(entity));
1024}
1025
1026template <ComponentTrait T, typename... Args>
1027 requires std::constructible_from<T, Args...>
1028inline bool World::TryEmplaceComponent(Entity entity, Args&&... args) {
1029 HELIOS_ASSERT(entity.Valid(), "Entity '{}' is invalid!", entity);
1030 HELIOS_ASSERT(entity_manager_.Validate(entity),
1031 "World does not own entity '{}'!", entity);
1032
1034 const bool added = component_manager_.template TryEmplace<T>(
1035 entity, std::forward<Args>(args)...);
1036 if (added) {
1037 messages_.Write(ComponentAddedMsg<T>(entity));
1038 }
1039 return added;
1040}
1041
1042template <ComponentTrait... Ts>
1043 requires utils::UniqueTypes<Ts...> && (sizeof...(Ts) > 0)
1044inline void World::RemoveComponents(Entity entity) {
1045 HELIOS_ASSERT(entity.Valid(), "Entity '{}' is invalid!", entity);
1046 HELIOS_ASSERT(entity_manager_.Validate(entity),
1047 "World does not own entity '{}'!", entity);
1048
1050 component_manager_.template Remove<Ts...>(entity);
1051 (messages_.Write(ComponentRemovedMsg<Ts>(entity)), ...);
1052}
1053
1054template <ComponentTrait... Ts>
1055 requires utils::UniqueTypes<Ts...> && (sizeof...(Ts) > 0)
1057 -> std::conditional_t<sizeof...(Ts) == 1, bool,
1058 std::array<bool, sizeof...(Ts)>> {
1059 HELIOS_ASSERT(entity.Valid(), "Entity '{}' is invalid!", entity);
1060 HELIOS_ASSERT(entity_manager_.Validate(entity),
1061 "World does not own entity '{}'!", entity);
1062
1064 auto removed = component_manager_.template TryRemove<Ts...>(entity);
1065
1066 const auto results = [&removed]()->std::array<bool, sizeof...(Ts)> {
1067 if constexpr (sizeof...(Ts) == 1) {
1068 return {removed};
1069 } else {
1070 return removed;
1071 }
1072 }
1073 ();
1074
1075 // Apply to each component type using index_sequence
1076 [this, entity, &results]<size_t... Is>(std::index_sequence<Is...>) {
1077 ((results[Is] ? messages_.Write(ComponentRemovedMsg<Ts>(entity)) : void()),
1078 ...);
1079 }(std::index_sequence_for<Ts...>{});
1080
1081 return removed;
1082}
1083
1084inline void World::ClearComponents(Entity entity) {
1085 HELIOS_ASSERT(entity.Valid(), "Entity '{}' is invalid!", entity);
1086 HELIOS_ASSERT(entity_manager_.Validate(entity),
1087 "World does not own entity '{}'!", entity);
1088
1089 component_manager_.Clear(entity);
1090 messages_.Write(ComponentsClearedMsg(entity));
1091}
1092
1093template <ComponentTrait T>
1095 HELIOS_ASSERT(entity.Valid(), "Entity '{}' is invalid!", entity);
1096 HELIOS_ASSERT(entity_manager_.Validate(entity),
1097 "World does not own entity '{}'!", entity);
1098 return component_manager_.template Get<T>(entity);
1099}
1100
1101template <ComponentTrait T>
1102inline const T& World::ReadComponent(Entity entity) const {
1103 HELIOS_ASSERT(entity.Valid(), "Entity '{}' is invalid!", entity);
1104 HELIOS_ASSERT(entity_manager_.Validate(entity),
1105 "World does not own entity '{}'!", entity);
1106 return component_manager_.template Get<T>(entity);
1107}
1108
1109template <ComponentTrait T>
1111 HELIOS_ASSERT(entity.Valid(), "Entity '{}' is invalid!", entity);
1112 HELIOS_ASSERT(entity_manager_.Validate(entity),
1113 "World does not own entity '{}'!", entity);
1114 return component_manager_.template TryGet<T>(entity);
1115}
1116
1117template <ComponentTrait T>
1118inline const T* World::TryReadComponent(Entity entity) const {
1119 HELIOS_ASSERT(entity.Valid(), "Entity '{}' is invalid!", entity);
1120 HELIOS_ASSERT(entity_manager_.Validate(entity),
1121 "World does not own entity '{}'!", entity);
1122 return component_manager_.template TryGet<T>(entity);
1123}
1124
1125template <ResourceTrait T>
1126inline void World::InsertResources(T&& resource) {
1128
1129 resources_.Insert(std::forward<T>(resource));
1130 ResourceCallOnInsert(resources_.template Get<T>(), *this);
1131 messages_.Write(ResourceInsertedMsg<T>());
1132}
1133
1134template <ResourceTrait T>
1135inline bool World::TryInsertResources(T&& resource) {
1137
1138 const bool inserted = resources_.TryInsert(std::forward<T>(resource));
1139 if (inserted) {
1140 auto& inserted_resource = resources_.template Get<T>();
1141 ResourceCallOnInsert(inserted_resource, *this);
1142 messages_.Write(ResourceInsertedMsg<T>());
1143 }
1144 return inserted;
1145}
1146
1147template <ResourceTrait T, typename... Args>
1148 requires std::constructible_from<T, Args...>
1149inline void World::EmplaceResource(Args&&... args) {
1151
1152 resources_.template Emplace<T>(std::forward<Args>(args)...);
1153 auto& inserted_resource = resources_.template Get<T>();
1154 ResourceCallOnInsert(inserted_resource, *this);
1155 messages_.Write(ResourceInsertedMsg<T>());
1156}
1157
1158template <ResourceTrait T, typename... Args>
1159 requires std::constructible_from<T, Args...>
1160inline bool World::TryEmplaceResource(Args&&... args) {
1162
1163 const bool emplaced =
1164 resources_.template TryEmplace<T>(std::forward<Args>(args)...);
1165 if (emplaced) {
1166 auto& inserted_resource = resources_.template Get<T>();
1167 ResourceCallOnInsert(inserted_resource, *this);
1168 messages_.Write(ResourceInsertedMsg<T>());
1169 }
1170 return emplaced;
1171}
1172
1173template <ResourceTrait... Ts>
1174 requires utils::UniqueTypes<Ts...> && (sizeof...(Ts) > 0)
1176#ifdef HELIOS_ENABLE_ASSERTS
1177 const auto has_resource = std::to_array({HasResource<Ts>()...});
1178 constexpr auto names = std::to_array({ResourceNameOf<Ts>()...});
1179
1180 const bool all_has_resource =
1181 std::ranges::all_of(has_resource, std::identity{});
1182 if (!all_has_resource) [[unlikely]] {
1183 std::string missing;
1184 for (size_t i = 0; i < has_resource.size(); ++i) {
1185 if (has_resource[i]) {
1186 continue;
1187 }
1188 missing.append(names[i]);
1189 if (i < has_resource.size() - 1) {
1190 missing.append(", ");
1191 }
1192 }
1193 HELIOS_ASSERT(missing.empty(), "Resource(s) '{}' do not exist!", missing);
1194 }
1195#endif
1196
1198 (ResourceCallOnRemove(resources_.template Get<Ts>(), *this), ...);
1199 (resources_.template Remove<Ts>(), ...);
1200 (messages_.Write(ResourceRemovedMsg<Ts>()), ...);
1201}
1202
1203template <ResourceTrait T>
1206
1207 bool removed = false;
1208
1209 if (T* resource = resources_.template TryGet<T>(); resource != nullptr) {
1210 ResourceCallOnRemove(*resource, *this);
1211 removed = resources_.template TryRemove<T>();
1212 messages_.Write(ResourceRemovedMsg<T>());
1213 }
1214 return removed;
1215}
1216
1217template <ResourceTrait T>
1218inline T& World::WriteResource() noexcept {
1219 HELIOS_ASSERT(HasResource<T>(), "Resource of type '{}' does not exist!",
1221 return resources_.template Get<T>();
1222}
1223
1224template <ResourceTrait T>
1225inline const T& World::ReadResource() const noexcept {
1226 HELIOS_ASSERT(HasResource<T>(), "Resource of type '{}' does not exist!",
1228 return resources_.template Get<T>();
1229}
1230
1231template <AnyMessageTrait T>
1232inline void World::AddMessage() {
1233 if (!HasMessage<T>()) {
1234 messages_.template Register<T>();
1235 }
1236}
1237
1243
1244template <AsyncMessageTrait T>
1245inline auto World::ReadAsyncMessages() noexcept -> AsyncMessageReader<T> {
1246 HELIOS_ASSERT(HasMessage<T>(), "Message of type '{}' is not registered!",
1248 return AsyncMessageReader<T>(messages_);
1249}
1250
1251template <AsyncMessageTrait T>
1252inline auto World::WriteAsyncMessages() noexcept -> AsyncMessageWriter<T> {
1253 HELIOS_ASSERT(HasMessage<T>(), "Message of type '{}' is not registered!",
1255 return AsyncMessageWriter<T>(messages_);
1256}
1257
1258template <AnyMessageTrait... Ts>
1259 requires(sizeof...(Ts) > 0)
1261#ifdef HELIOS_ENABLE_ASSERTS
1262 const auto has_message = std::to_array({HasMessage<Ts>()...});
1263 constexpr auto names = std::to_array({MessageNameOf<Ts>()...});
1264
1265 const bool all_has_message =
1266 std::ranges::all_of(has_message, std::identity{});
1267 if (!all_has_message) [[unlikely]] {
1268 std::string missing;
1269 for (size_t i = 0; i < has_message.size(); ++i) {
1270 if (has_message[i]) {
1271 continue;
1272 }
1273 missing.append(names[i]);
1274 if (i < has_message.size() - 1) {
1275 missing.append(", ");
1276 }
1277 }
1278 HELIOS_ASSERT(missing.empty(), "Message(s) '{}' not registered!", missing);
1279 }
1280#endif
1281
1282 (messages_.template ManualClear<Ts>(), ...);
1283}
1284
1285template <MessageTrait T>
1286inline auto World::ReadMessages() const noexcept -> MessageReader<T> {
1287 HELIOS_ASSERT(HasMessage<T>(), "Message of type '{}' is not registered!",
1289 return MessageReader<T>(messages_);
1290}
1291
1292template <ConsumableMessageTrait T>
1293inline auto World::ReadConsumableMessages() noexcept
1295 HELIOS_ASSERT(HasMessage<T>(), "Message of type '{}' is not registered!",
1297 return ConsumableMessageReader<T>(messages_);
1298}
1299
1300template <MessageTrait T>
1301inline auto World::WriteMessages() noexcept -> BasicMessageWriter<T> {
1302 HELIOS_ASSERT(HasMessage<T>(), "Message of type '{}' is not registered!",
1304 return BasicMessageWriter<T>(messages_.CurrentQueue());
1305}
1306
1307inline bool World::Exists(Entity entity) const noexcept {
1308 HELIOS_ASSERT(entity.Valid(), "Entity '{}' is invalid!", entity);
1309 return entity_manager_.Validate(entity);
1310}
1311
1312template <ComponentTrait T>
1313inline bool World::HasComponent(Entity entity) const {
1314 HELIOS_ASSERT(entity.Valid(), "Entity '{}' is invalid!", entity);
1315 HELIOS_ASSERT(entity_manager_.Validate(entity),
1316 "World does not own entity '{}'!", entity);
1317 return component_manager_.template Has<T>(entity);
1318}
1319
1320template <ComponentTrait... Ts>
1321 requires utils::UniqueTypes<Ts...> && (sizeof...(Ts) > 0)
1322inline auto World::HasComponents(Entity entity) const
1323 -> std::array<bool, sizeof...(Ts)> {
1324 HELIOS_ASSERT(entity.Valid(), "Entity '{}' is invalid!", entity);
1325 HELIOS_ASSERT(entity_manager_.Validate(entity),
1326 "World does not own entity '{}'!", entity);
1327 return component_manager_.template Has<Ts...>(entity);
1328}
1329
1330} // namespace helios::ecs
#define HELIOS_ASSERT(condition,...)
Assertion macro that aborts execution in debug builds.
Definition assert.hpp:259
Type-safe, move-based reader for async messages.
Type-safe writer for async messages.
Type-safe writer for regular messages with a configurable queue allocator.
Definition writer.hpp:26
Query result object for iterating over matching entities and components.
Definition query.hpp:659
Command queue for deferred ECS operations.
Definition queue.hpp:26
Message sent when a component is added.
Central manager for all component storage (archetype and sparse-set).
Definition manager.hpp:133
Message sent when a component is removed.
Message sent when all components are cleared from an entity.
Type-safe, zero-copy reader for consumable messages with consume support.
Definition reader.hpp:877
Message sent when an entity is added.
Message sent when an entity is destroyed.
Entity manager responsible for entity creation, destruction, and validation.
Definition manager.hpp:26
Unique identifier for entities with generation counter to handle recycling.
Definition entity.hpp:22
constexpr bool Valid() const noexcept
Checks if the entity is valid.
Definition entity.hpp:64
Central coordinator for message lifecycle with double buffering and consumed message removal.
Definition manager.hpp:54
Type-safe, zero-copy reader for regular messages.
Definition reader.hpp:771
Resource manager for storing and managing resources of various types.
Definition manager.hpp:21
The World class manages entities with their components and systems.
Definition world.hpp:39
void DestroyEntity(Entity entity)
Destroys entity and removes it from the world.
Definition world.hpp:930
auto ReadOnlyQuery(std::pmr::memory_resource *resource) const noexcept -> BasicQuery< const World, std::pmr::polymorphic_allocator<>, Args... >
Creates a read-only query using a PMR memory resource.
Definition world.hpp:256
const T & ReadResource() const noexcept
Gets const reference to a resource.
Definition world.hpp:1225
void TryDestroyEntity(Entity entity)
Tries to destroy entity if it exists in the world.
Definition world.hpp:940
bool TryEmplaceResource(Args &&... args)
Tries to emplace a resource if not present.
Definition world.hpp:1160
void EnqueueCommandBulk(R &&range)
Enqueues multiple commands to be executed during the next Update().
Definition world.hpp:702
const MessageManager & Messages() const noexcept
Gets the message manager (const).
Definition world.hpp:873
const ResourceManager & Resources() const noexcept
Gets the resource manager (const).
Definition world.hpp:857
ResourceManager & Resources() noexcept
Gets the resource manager.
Definition world.hpp:850
void EmplaceResource(Args &&... args)
Emplaces a resource in-place.
Definition world.hpp:1149
T & WriteResource() noexcept
Gets reference to a resource.
Definition world.hpp:1218
World(const World &)=delete
bool HasResource() const
Checks if a resource exists.
Definition world.hpp:749
bool TryInsertResources(T &&resource)
Tries to insert resource if not present.
Definition world.hpp:1135
bool TryRemoveResources()
Tries to remove resource.
Definition world.hpp:1204
auto WriteAsyncMessages() noexcept -> AsyncMessageWriter< T >
Gets a writer for messages of type T.
Definition world.hpp:1252
void Flush()
Flushes entity reservations and executes pending commands.
Definition world.hpp:901
auto ReadConsumableMessages() noexcept -> ConsumableMessageReader< T >
Gets a consumable reader for messages of type T without consume support.
Definition world.hpp:1293
auto ReadOnlyQuery(std::nullptr_t) const -> BasicQuery< const World, std::pmr::polymorphic_allocator<>, Args... >=delete
auto TryRemoveResources() -> std::array< bool, sizeof...(Ts)>
Tries to remove resources.
Definition world.hpp:527
void ClearMessages() noexcept
Clears all messages without removing registration.
Definition world.hpp:608
auto TryInsertResources(Ts &&... resources) -> std::array< bool, sizeof...(Ts)>
Tries to insert resources if not present.
Definition world.hpp:472
Entity ReserveEntity()
Reserves an entity ID for deferred creation.
Definition world.hpp:88
World(World &&) noexcept=default
bool HasMessages() const noexcept
Checks if messages of a specific type exist in message queue.
Definition world.hpp:771
const EntityManager & Entities() const noexcept
Gets the entity manager.
Definition world.hpp:823
auto Query(Allocator alloc={}) noexcept -> BasicQuery< World, Allocator, Args... >
Creates a query over entities matching the specified component criteria.
Definition world.hpp:162
T * TryWriteResource() noexcept
Tries to get mutable pointer to a resource.
Definition world.hpp:558
auto Query(std::pmr::memory_resource *resource) noexcept -> BasicQuery< World, std::pmr::polymorphic_allocator<>, Args... >
Creates a query using a PMR memory resource.
Definition world.hpp:188
void AddComponents(Entity entity, Ts &&... components)
Adds components to the entity.
Definition world.hpp:972
auto ReadMessages() const noexcept -> MessageReader< T >
Gets a reader for messages of type T without consume support.
Definition world.hpp:1286
void ClearComponents(Entity entity)
Removes all components from the entity.
Definition world.hpp:1084
auto Query(std::nullptr_t) -> BasicQuery< World, std::pmr::polymorphic_allocator<>, Args... >=delete
MessageManager & Messages() noexcept
Gets the message manager.
Definition world.hpp:866
bool HasCommands() const noexcept
Checks if there are any pending commands in the command queue.
Definition world.hpp:780
void DestroyEntities(const R &entities)
Destroys entities and removes them from the world.
Definition world.hpp:953
size_t CommandCount() const noexcept
Gets the number of pending commands in the command queue.
Definition world.hpp:807
auto WriteMessages() noexcept -> BasicMessageWriter< T >
Gets a writer for messages of type T.
Definition world.hpp:1301
ComponentManager & Components() noexcept
Gets the component manager.
Definition world.hpp:832
void Update()
Flushes buffer of pending operations.
Definition world.hpp:894
auto TryAddComponents(Entity entity, Ts &&... components) -> std::conditional_t< sizeof...(Ts)==1, bool, std::array< bool, sizeof...(Ts)> >
Tries to add components to the entity if they don't exist.
Definition world.hpp:985
void TryDestroyEntities(const R &entities)
Tries to destroy entities if they exist in the world.
Definition world.hpp:964
size_t ResourceCount() const noexcept
Gets the number of resources in the world.
Definition world.hpp:798
Entity CreateEntity()
Creates new entity.
Definition world.hpp:923
auto ReadOnlyQuery(Allocator alloc={}) const noexcept -> BasicQuery< const World, Allocator, Args... >
Creates a read-only query over entities matching the specified component criteria.
Definition world.hpp:226
bool TryEmplaceComponent(Entity entity, Args &&... args)
Tries to emplace component for the entity.
Definition world.hpp:1028
const ComponentManager & Components() const noexcept
Gets the component manager (const).
Definition world.hpp:841
void EnqueueCommand(Cmd &&command)
Enqueues a command to be executed during the next Update().
Definition world.hpp:688
void EmplaceComponent(Entity entity, Args &&... args)
Emplaces component for the entity.
Definition world.hpp:1016
bool HasComponent(Entity entity) const
Checks if entity has component.
Definition world.hpp:1313
auto HasComponents(Entity entity) const -> std::array< bool, sizeof...(Ts)>
Checks if entity has components.
Definition world.hpp:1322
void AddMessages()
Registers multiple message types for use.
Definition world.hpp:590
T * TryWriteComponent(Entity entity)
Tries to get a mutable pointer to a component.
Definition world.hpp:1110
const T * TryReadResource() const noexcept
Tries to get const pointer to a resource.
Definition world.hpp:569
bool HasMessage() const noexcept
Checks if a message added.
Definition world.hpp:760
size_t EntityCount() const noexcept
Gets the number of entities in the world.
Definition world.hpp:789
void RemoveResources()
Removes resources from the world.
Definition world.hpp:1175
auto ReadAsyncMessages() noexcept -> AsyncMessageReader< T >
Gets a reader for messages of type T.
Definition world.hpp:1245
void AddMessage()
Registers an message type for use.
Definition world.hpp:1232
void InsertResources(T &&resource)
Inserts a resource into the world.
Definition world.hpp:1126
EntityManager & Entities() noexcept
Gets the entity manager.
Definition world.hpp:816
T & WriteComponent(Entity entity)
Gets a mutable reference to a component.
Definition world.hpp:1094
void AddBuiltinMessages()
Registers all built-in non-template message types.
Definition world.hpp:1238
const T * TryReadComponent(Entity entity) const
Tries to get a const pointer to a component.
Definition world.hpp:1118
void ReserveCommands(size_t count)
Reserves capacity in the command queue to avoid reallocations.
Definition world.hpp:679
void Clear()
Clears the world, removing all data.
Definition world.hpp:909
void ClearEntities() noexcept
Clears all entities and components from the world.
Definition world.hpp:918
void InsertResources(Ts &&... resources)
Inserts resources into the world.
Definition world.hpp:450
const T & ReadComponent(Entity entity) const
Gets a const reference to a component.
Definition world.hpp:1102
auto TryRemoveComponents(Entity entity) -> std::conditional_t< sizeof...(Ts)==1, bool, std::array< bool, sizeof...(Ts)> >
Tries to remove components from the entity if they exist.
Definition world.hpp:1056
bool Exists(Entity entity) const noexcept
Checks if entity exists in the world.
Definition world.hpp:1307
void RemoveComponents(Entity entity)
Removes components from the entity.
Definition world.hpp:1044
Concept for any valid message type.
Definition message.hpp:55
Concept for valid async message types.
Definition message.hpp:44
Concept that defines the requirements for a command trait.
Definition command.hpp:18
Concept to check if a type can be used as a component.
Definition component.hpp:31
Concept for consumable message types.
Definition message.hpp:86
Concept for valid message types.
Definition message.hpp:29
Concept for valid resource types.
Definition resource.hpp:25
Concept that checks if all types in a pack are unique (after removing cv/ref qualifiers).
constexpr void ResourceCallOnInsert(T &resource, World &world) noexcept
Calls insertion callback for a resource type if it exists.
Definition resource.hpp:142
constexpr void ResourceCallOnRemove(T &resource, World &world) noexcept
Calls removal callback for a resource type if it exists.
Definition resource.hpp:155
constexpr std::string_view ResourceNameOf() noexcept
Gets name for a resource type.
Definition resource.hpp:93
constexpr std::string_view MessageNameOf() noexcept
Gets the name of an message.
Definition message.hpp:97
Message sent when a resource is inserted.
Message sent when a resource is removed.