vecs
Fast, flexible ecs in C++ with ergonomic API
Loading...
Searching...
No Matches
vecs.h
Go to the documentation of this file.
1
5#ifndef __VECS_H__
6#define __VECS_H__
7
8#include <cassert>
9#include <chrono>
10#include <cstdio>
11#include <functional>
12#include <memory>
13#include <typeindex>
14#include <unordered_map>
15#include <variant>
16
17#include "bundle.h"
18#include "dense_map.h"
19#include "type_id.h"
20
21namespace vecs {
22
23template<typename T>
24class Optional;
25
26template<typename T>
27struct With {};
28
29template<typename T>
30struct Without {};
31
32template<typename... Filters>
33class Filter {};
34
35template<typename T>
36struct ComponentHooks;
37
38class World;
39
40namespace _traits {
41
42 template<typename T>
43 struct function_traits;
44
45 // Specialization for function types
46 template<typename R, typename... Args>
47 struct function_traits<R(Args...)> {
48 using result_type = R;
49 using args_tuple = std::tuple<Args...>;
50 };
51
52 // Specialization for function pointers
53 template<typename R, typename... Args>
54 struct function_traits<R (*)(Args...)>: function_traits<R(Args...)> {};
55
56 // Specialization for function references
57 template<typename R, typename... Args>
58 struct function_traits<R (&)(Args...)>: function_traits<R(Args...)> {};
59
60 // Specialization for member function pointers
61 template<typename C, typename R, typename... Args>
62 struct function_traits<R (C::*)(Args...)>: function_traits<R(Args...)> {};
63
64 // Specialization for const member function pointers
65 template<typename C, typename R, typename... Args>
66 struct function_traits<R (C::*)(Args...) const>:
67 function_traits<R(Args...)> {};
68
69 // Specialization for functors and lambdas
70 template<typename T>
71 struct function_traits: function_traits<decltype(&T::operator())> {};
72
73 template<typename T, typename... Ts>
74 struct contains;
75
76 template<typename T>
77 struct contains<T>: std::false_type {};
78
79 template<typename T, typename U, typename... Ts>
80 struct contains<T, U, Ts...>: contains<T, Ts...> {};
81
82 template<typename T, typename... Ts>
83 struct contains<T, T, Ts...>: std::true_type {};
84
85 template<typename T>
86 struct is_optional: std::false_type {};
87
88 template<typename T>
89 struct is_optional<Optional<T>>: std::true_type {};
90
91} // namespace _traits
92
93namespace _traits::query {
94
95 template<typename T>
97 using StorageType = T*;
98 using IterationType = T&;
99 using IterationPointerType = T*;
100
101 static IterationType dereference(StorageType arg) {
102 return *arg;
103 }
104 };
105
106 template<>
107 struct QueryTypeTraits<Entity> {
108 using StorageType = Entity;
109 using IterationType = Entity;
110 using IterationPointerType = Entity*;
111
112 static IterationType dereference(StorageType arg) {
113 return arg;
114 }
115 };
116
117 template<typename T>
119 using StorageType = Optional<T>;
120 using IterationType = Optional<T>;
121 using IterationPointerType = Optional<T>*;
122
123 static IterationType dereference(StorageType arg) {
124 return arg;
125 }
126 };
127
128 template<typename T>
130 static constexpr bool is_with = false;
131 static constexpr bool is_without = false;
132 using component_type = void;
133 };
134
135 template<typename T>
136 struct filter_traits<With<T>> {
137 static constexpr bool is_with = true;
138 static constexpr bool is_without = false;
139 using component_type = T;
140 };
141
142 template<typename T>
144 static constexpr bool is_with = false;
145 static constexpr bool is_without = true;
146 using component_type = T;
147 };
148
149} // namespace _traits::query
150
151namespace _traits::component_hooks {
152 enum class HookType { Add, Insert, Remove };
153
154 // Static detection
155 template<typename T, typename = void>
156 struct has_static_on_add: std::false_type {};
157
158 template<typename T, typename = void>
159 struct has_static_on_insert: std::false_type {};
160
161 template<typename T, typename = void>
162 struct has_static_on_remove: std::false_type {};
163
164 template<typename T>
165 struct has_static_on_add<T, std::void_t<decltype(T::on_add)>>:
166 std::true_type {};
167
168 template<typename T>
169 struct has_static_on_insert<T, std::void_t<decltype(T::on_insert)>>:
170 std::true_type {};
171
172 template<typename T>
173 struct has_static_on_remove<T, std::void_t<decltype(T::on_remove)>>:
174 std::true_type {};
175
176 // ComponentHooks specialization detection
177 template<typename T, typename = void>
178 struct has_component_hooks_on_add: std::false_type {};
179
180 template<typename T, typename = void>
181 struct has_component_hooks_on_insert: std::false_type {};
182
183 template<typename T, typename = void>
184 struct has_component_hooks_on_remove: std::false_type {};
185
186 template<typename T>
188 T,
189 std::void_t<decltype(ComponentHooks<T>::on_add)>>: std::true_type {};
190
191 template<typename T>
193 T,
194 std::void_t<decltype(ComponentHooks<T>::on_insert)>>: std::true_type {};
195
196 template<typename T>
198 T,
199 std::void_t<decltype(ComponentHooks<T>::on_remove)>>: std::true_type {};
200
201 // Instance member detection
202 template<typename T, typename = void>
203 struct has_instance_on_add: std::false_type {};
204
205 template<typename T>
206 struct has_instance_on_add<T, std::void_t<decltype(&T::on_add)>>:
207 std::true_type {};
208
209 template<typename T, typename = void>
210 struct has_instance_on_insert: std::false_type {};
211
212 template<typename T>
213 struct has_instance_on_insert<T, std::void_t<decltype(&T::on_insert)>>:
214 std::true_type {};
215
216 template<typename T, HookType Type>
218
219 template<typename T>
220 struct has_static_hook<T, HookType::Add>: has_static_on_add<T> {};
221
222 template<typename T>
223 struct has_static_hook<T, HookType::Insert>: has_static_on_insert<T> {};
224
225 template<typename T>
226 struct has_static_hook<T, HookType::Remove>: has_static_on_remove<T> {};
227
228 template<typename T, HookType Type>
230
231 template<typename T>
232 struct has_component_hook<T, HookType::Add>:
234
235 template<typename T>
236 struct has_component_hook<T, HookType::Insert>:
238
239 template<typename T>
240 struct has_component_hook<T, HookType::Remove>:
242
243 template<typename T, HookType Type>
245
246 template<typename T>
247 struct has_instance_hook<T, HookType::Add>: has_instance_on_add<T> {};
248
249 template<typename T>
250 struct has_instance_hook<T, HookType::Insert>: has_instance_on_insert<T> {};
251
252 // Instance hooks do not support on_remove
253 template<typename T>
254 struct has_instance_hook<T, HookType::Remove>: std::false_type {};
255
256 template<typename T, HookType Type>
257 struct hook_traits {
258 static constexpr bool has_static = has_static_hook<T, Type>::value;
259 static constexpr bool has_component =
261 static constexpr bool has_instance = has_instance_hook<T, Type>::value;
262
263 static constexpr bool has_any =
264 has_static || has_component || has_instance;
265 };
266
267 template<HookType Type, typename T, typename... Args>
268 constexpr void inline invoke_hook_impl(Args&&... args) {
269 if constexpr (has_static_hook<T, Type>::value) {
270 if constexpr (Type == HookType::Add) {
271 T::on_add(std::forward<Args>(args)...);
272 } else if constexpr (Type == HookType::Insert) {
273 T::on_insert(std::forward<Args>(args)...);
274 } else if constexpr (Type == HookType::Remove) {
275 T::on_remove(std::forward<Args>(args)...);
276 }
277 } else if constexpr (has_component_hook<T, Type>::value) {
278 if constexpr (Type == HookType::Add) {
279 ComponentHooks<T>::on_add(std::forward<Args>(args)...);
280 } else if constexpr (Type == HookType::Insert) {
281 ComponentHooks<T>::on_insert(std::forward<Args>(args)...);
282 } else if constexpr (Type == HookType::Remove) {
283 ComponentHooks<T>::on_remove(std::forward<Args>(args)...);
284 }
285 }
286 }
287
288 template<HookType Type, typename T, typename... Args>
289 constexpr void inline invoke_hook(Args&&... args) {
290 invoke_hook_impl<Type, typename std::decay<T>::type>(
291 std::forward<Args>(args)...
292 );
293 }
294
295 template<HookType Type, typename... Ts, typename... Args>
296 constexpr void inline invoke_hooks(Args&&... args) {
297 (invoke_hook<Type, Ts>(std::forward<Args>(args)...), ...);
298 }
299
300 template<typename... Ts, typename... Args>
301 constexpr void inline invoke_on_add_hooks(Args&&... args) {
302 invoke_hooks<HookType::Add, Ts...>(std::forward<Args>(args)...);
303 }
304
305 template<typename... Ts, typename... Args>
306 constexpr void inline invoke_on_insert_hooks(Args&&... args) {
307 invoke_hooks<HookType::Insert, Ts...>(std::forward<Args>(args)...);
308 }
309
310 template<typename... Ts, typename... Args>
311 constexpr void inline invoke_on_remove_hooks(Args&&... args) {
312 invoke_hooks<HookType::Remove, Ts...>(std::forward<Args>(args)...);
313 }
314
315 template<HookType Type, typename T, typename WorldType>
316 constexpr void inline invoke_instance_hook_impl(
317 WorldType& world,
318 Entity e
319 ) {
320 if constexpr (has_instance_hook<T, Type>::value) {
321 auto component_ptr = world.entity(e).template get_component<T>();
322
323 if constexpr (Type == HookType::Add) {
324 if (component_ptr) {
325 component_ptr->on_add(world, e);
326 }
327 } else if constexpr (Type == HookType::Insert) {
328 if (component_ptr) {
329 component_ptr->on_insert(world, e);
330 }
331 }
332 }
333 }
334
335 template<HookType Type, typename T, typename WorldType>
336 constexpr void inline invoke_instance_hook(WorldType& world, Entity e) {
337 invoke_instance_hook_impl<Type, typename std::decay<T>::type>(world, e);
338 }
339
340 template<HookType Type, typename... Ts, typename... Args>
341 constexpr void inline invoke_instance_hooks(Args&&... args) {
342 (invoke_instance_hook<Type, Ts>(std::forward<Args>(args)...), ...);
343 }
344
345 template<typename... Ts, typename... Args>
346 constexpr void inline invoke_on_add_instance_hooks(Args&&... args) {
347 (invoke_instance_hook<HookType::Add, Ts>(std::forward<Args>(args)...),
348 ...);
349 }
350
351 template<typename... Ts, typename... Args>
352 constexpr void inline invoke_on_insert_instance_hooks(Args&&... args) {
353 (invoke_instance_hook<HookType::Insert, Ts>(std::forward<Args>(args)...
354 ),
355 ...);
356 }
357
358} // namespace _traits::component_hooks
359
360struct Parent {
361 Entity entity;
362
363 operator Entity() {
364 return entity;
365 }
366};
367
372enum class ScheduleLabel {
373 Startup,
374 PreUpdate,
375 Update,
376 Validate,
377 PostUpdate,
378 PreStore,
379 Store
380};
381
382// Forward declare
383class World;
384template<typename... Components>
385struct Bundle;
386template<typename... Components>
387class Observer;
388class Commands;
389
390template<typename Tuple>
391auto get_system_params(World& world);
392
394 virtual ~TypeErasedResource() = default;
395};
396
406template<typename T>
412 explicit Resource(T* ptr) : m_ptr(ptr) {}
413
414 T& operator*() const {
415 return *m_ptr;
416 }
417
418 T* operator->() const {
419 return m_ptr;
420 }
421
422 T* get() const {
423 return m_ptr;
424 }
425
426 T* get_mut() {
427 return m_ptr;
428 }
429
430 private:
431 T* m_ptr {nullptr};
432};
433
435 public:
436 virtual ~TypeErasedObserver() = default;
437 virtual const std::vector<Entity>& added() const = 0;
438 virtual const std::vector<Entity>& inserted() const = 0;
439 virtual const std::vector<Entity>& removed() const = 0;
440
441 private:
442 friend class World;
443 virtual const ComponentMask& mask() const = 0;
444 virtual void insert(Entity entity) = 0;
445 virtual void remove(Entity entity) = 0;
446 virtual void add(Entity entity) = 0;
447 virtual void clear() = 0;
448};
449
474template<typename... Components>
476 public:
482 Observer() : m_mask(compute_mask<Components...>()) {}
483
484 Observer(const Observer&) = delete;
485 Observer& operator=(const Observer&) = delete;
486 Observer(Observer&&) = delete;
487 Observer& operator=(Observer&&) = delete;
488
497 const std::vector<Entity>& added() const override {
498 return get_entities(Added);
499 }
500
509 const std::vector<Entity>& inserted() const override {
510 return get_entities(Inserted);
511 }
512
521 const std::vector<Entity>& removed() const override {
522 return get_entities(Removed);
523 }
524
525 private:
526 ComponentMask m_mask;
527
528 using kind = unsigned int;
529
530 constexpr static kind Added = 0;
531 constexpr static kind Inserted = 1;
532 constexpr static kind Removed = 2;
533
534 inline const std::vector<Entity>& get_entities(kind kind) const {
535 static const std::vector<Entity> empty;
536 auto it = m_entities.find(kind);
537 return (it != m_entities.end()) ? it->second : empty;
538 }
539
540 const ComponentMask& mask() const override {
541 return m_mask;
542 }
543
544 void add(Entity entity) override {
545 m_entities[Added].push_back(entity);
546 }
547
548 void insert(Entity entity) override {
549 m_entities[Inserted].push_back(entity);
550 }
551
552 void remove(Entity entity) override {
553 m_entities[Removed].push_back(entity);
554 }
555
556 void clear() override {
557 m_entities.clear();
558 }
559
560 storage::dense_map<kind, std::vector<Entity>> m_entities;
561};
562
563class EntityBuilder;
564template<typename... Components>
565class Query;
566
567struct Time {
568 float delta {0.f};
569};
570
575class World {
576 public:
577 World() :
578 m_last_time(std::chrono::high_resolution_clock::now()),
579 m_commands(std::make_unique<Commands>(*this)) {
580 add_resource(&m_time);
581 }
582
592 template<typename T>
593 World& add_resource(T* resource) {
594 m_resources[typeid(T)] = std::make_unique<Resource<T>>(resource);
595 return *this;
596 }
597
607 template<typename T>
609 auto it = m_resources.find(typeid(T));
610
611 assert(it != m_resources.end() && "Requested resource not found");
612
613 return *static_cast<Resource<T>*>(it->second.get());
614 }
615
631 template<typename Func>
632 void add_system(ScheduleLabel label, Func&& func) {
633 get_systems(label).emplace_back(
634 std::make_unique<System<std::decay_t<Func>>>(
635 std::forward<Func>(func),
636 *this
637 )
638 );
639 }
640
656 template<typename Func>
657 void add_system(Func&& func) {
658 add_system(ScheduleLabel::Update, std::forward<Func>(func));
659 }
660
664 inline void progress() {
665 auto current_time = std::chrono::high_resolution_clock::now();
666 std::chrono::duration<float> delta = current_time - m_last_time;
667 m_time.delta = delta.count();
668 m_last_time = current_time;
669 execute_progress();
670 }
671
677 inline void progress(float delta_time) {
678 m_time.delta = delta_time;
679 execute_progress();
680 }
681
682 EntityBuilder spawn();
683 EntityBuilder entity(Entity entity);
684
685 template<typename... Components>
686 inline Query<Components...> query() {
687 return Query<Components...>(this);
688 }
689
690 template<typename... Components>
691 Observer<Components...>& observe() {
692 auto observer = std::make_unique<Observer<Components...>>();
693 auto new_observer = observer.get();
694 m_observers.push_back(std::move(observer));
695 return *new_observer;
696 }
697
698 inline Commands& commands();
699
700 void despawn(Entity entity) {
701 auto entity_it = m_entity_archetype_map.find(entity);
702 if (entity_it == m_entity_archetype_map.end()) {
703 // can't despawn non-existant entity
704 return;
705 }
706
707 Archetype* archetype = entity_it->second;
708 archetype->remove_entity(entity);
709 m_entity_archetype_map.erase(entity_it);
710 notify_remove(archetype->m_mask, entity);
711 m_free_list.push_back(entity);
712 ++m_query_version;
713 }
714
715 void log_archetypes() {
716 printf("--- Logging Archetypes ---\n");
717 for (const auto& archetype : m_archetypes) {
718 printf(
719 "Archetype with mask: %s\n",
720 archetype->m_mask.to_string().c_str()
721 );
722
723 if (archetype->m_entity_to_index.empty()) {
724 printf("No entities in this archetype (empty)\n");
725 } else {
726 printf("Entities in this archetype: ");
727 for (const auto& entity : archetype->m_entity_to_index) {
728 printf("Entity(%zu) ", entity.first);
729 }
730 printf("(total = %zu)\n", archetype->m_entity_to_index.size());
731 }
732 }
733 printf("--- End of Archetypes Log ---\n");
734 }
735
736 private:
737 template<typename... Components>
738 friend class Query;
739 friend class EntityBuilder;
740 friend class EntityCommands;
741
742 // System implementation details
743 struct TypeErasedSystem {
744 virtual ~TypeErasedSystem() = default;
745 virtual void execute(World& world) = 0;
746 };
747
748 template<typename Func>
749 struct System: TypeErasedSystem {
750 Func func;
751
752 System(Func&& f, World& world) :
753 params(get_system_params<
754 typename _traits::function_traits<Func>::args_tuple>(world)),
755 func(std::forward<Func>(f)) {}
756
757 void execute(World& world) override {
758 std::apply(func, params);
759 }
760
761 private:
762 using Params =
763 decltype(get_system_params<
764 typename _traits::function_traits<Func>::args_tuple>(
765 std::declval<World&>()
766 ));
767 Params params;
768 };
769
770 // Archetype storage implementation details
771 class Archetype {
772 private:
773 template<typename... Components>
774 friend class Query;
775 friend class World;
776 friend class EntityBuilder;
777
778 template<typename T>
779 T* get_component(Entity entity) {
780 auto it = m_entity_to_index.find(entity);
781 if (it == m_entity_to_index.end()) {
782 return nullptr;
783 }
784 return get_row<T>(it->second);
785 }
786
787 template<typename T>
788 T* get_row(size_t row) {
789 static const ComponentId id = TypeIDGenerator::get_type_id<T>();
790 auto it = m_type_to_column.find(id);
791 if (it == m_type_to_column.end()) {
792 // Component type does not exist in the archetype
793 return nullptr;
794 }
795
796 auto* column =
797 static_cast<ComponentColumn<T>*>(m_columns[it->second].get());
798 if (row >= column->data.size()) {
799 // Row index is out of range
800 return nullptr;
801 }
802
803 return &column->data[row];
804 }
805
806 template<typename Component>
807 static auto
808 get_component_or_entity(Archetype* archetype, const Entity& entity) {
809 if constexpr (std::is_same_v<Component, Entity>) {
810 return entity;
811 } else if constexpr (_traits::is_optional<Component>()) {
812 using UnderlyingType = typename Component::value_type;
813 return Optional<UnderlyingType>(
814 archetype->template get_component<UnderlyingType>(entity)
815 );
816 } else {
817 return archetype->template get_component<Component>(entity);
818 }
819 }
820
821 template<typename... Components>
822 static auto
823 make_component_tuple(Archetype* archetype, const Entity& entity) {
824 return std::make_tuple(
825 get_component_or_entity<Components>(archetype, entity)...
826 );
827 }
828
829 Archetype(const ComponentMask& mask) : m_mask(mask) {}
830
831 template<typename... Components>
832 static std::unique_ptr<Archetype> from_columns() {
833 ComponentMask mask = compute_mask<Components...>();
834 auto archetype = std::make_unique<Archetype>(Archetype(mask));
835 (archetype->add_column<Components>(), ...);
836 return std::move(archetype);
837 }
838
839 template<typename... NewComponents>
840 static std::unique_ptr<Archetype>
841 from_archetype(const Archetype& old_archetype) {
842 ComponentMask new_components_mask =
843 compute_mask<NewComponents...>();
844 ComponentMask combined_mask =
845 old_archetype.m_mask | new_components_mask;
846
847 auto new_archetype =
848 std::make_unique<Archetype>(Archetype(combined_mask));
849
850 for (const auto& [component_id, column_index] :
851 old_archetype.m_type_to_column) {
852 auto& component = old_archetype.m_columns[column_index];
853 new_archetype->m_columns.emplace_back(component->clone_empty());
854 new_archetype->m_type_to_column[component_id] =
855 new_archetype->m_columns.size() - 1;
856 }
857
858 (new_archetype->add_column<NewComponents>(), ...);
859
860 return new_archetype;
861 }
862
863 template<typename T>
864 void add_column() {
865 ComponentId id = TypeIDGenerator::get_type_id<T>();
866 m_columns.push_back(std::make_unique<ComponentColumn<T>>());
867 m_type_to_column[id] = m_columns.size() - 1;
868 }
869
870 template<typename T>
871 void add_row(size_t row, T&& component) {
872 static const ComponentId id = TypeIDGenerator::get_type_id<T>();
873
874 auto it = m_type_to_column.find(id);
875 if (it == m_type_to_column.end()) {
876 printf("Error: column does not exist in archetype\n");
877 std::abort();
878 }
879
880 auto* column = static_cast<ComponentColumn<T>*>(
881 m_columns[m_type_to_column[id]].get()
882 );
883
884 if (column->data.size() <= row) {
885 column->data.resize(row + 1);
886 }
887
888 column->data[row] = std::forward<T>(component);
889 }
890
891 template<typename... Components>
892 void update_components(Entity entity, Components&&... components) {
893 (update_row<Components>(entity, components), ...);
894 }
895
896 template<typename T>
897 void update_row(Entity entity, T&& component) {
898 static const ComponentId id = TypeIDGenerator::get_type_id<T>();
899
900 auto it = m_type_to_column.find(id);
901 if (it == m_type_to_column.end()) {
902 printf("error: coulmn does not exist in archetype\n");
903 std::abort();
904 }
905
906 auto* column = static_cast<ComponentColumn<T>*>(
907 m_columns[m_type_to_column[id]].get()
908 );
909
910 auto row_it = m_entity_to_index.find(entity);
911
912 if (row_it == m_entity_to_index.end()) {
913 printf("error: row does not exist in archetype\n");
914 std::abort();
915 }
916
917 column->data[row_it->second] = std::forward<T>(component);
918 }
919
920 template<typename... Components>
921 bool has_components() const {
922 auto mask = compute_mask<Components...>();
923 return has_components(mask);
924 }
925
926 bool has_components(ComponentMask mask) const {
927 // return (m_mask & mask) == mask;
928 return m_mask.contains(mask);
929 }
930
931 template<typename... Components>
932 void add_entity(Entity entity, Components&&... components) {
933 size_t row = m_next_available_row;
934 m_entity_to_index[entity] = row;
935 (add_row<Components>(row, std::forward<Components>(components)),
936 ...);
937 ++m_next_available_row;
938 }
939
940 void remove_entity(Entity entity) {
941 auto it = m_entity_to_index.find(entity);
942 if (it == m_entity_to_index.end()) {
943 return;
944 }
945 size_t row = it->second;
946 size_t last_row = m_next_available_row - 1;
947 if (row != last_row) {
948 for (auto& column : m_columns) {
949 column->swap(row, last_row);
950 }
951 for (auto& pair : m_entity_to_index) {
952 if (pair.second == last_row) {
953 pair.second = row;
954 break;
955 }
956 }
957 }
958
959 --m_next_available_row;
960
961 for (auto& column : m_columns) {
962 column->pop_back();
963 }
964
965 m_entity_to_index.erase(it);
966 }
967
968 struct TypeErasedComponentColumn {
969 virtual ~TypeErasedComponentColumn() = default;
970 virtual std::unique_ptr<TypeErasedComponentColumn>
971 clone_empty() const = 0;
972 virtual void copy_component_to(
973 TypeErasedComponentColumn* target_column,
974 size_t from_index,
975 size_t to_index
976 ) = 0;
977 virtual void swap(size_t index1, size_t index2) = 0;
978 virtual void pop_back() = 0;
979 };
980
981 template<typename T>
982 struct ComponentColumn: TypeErasedComponentColumn {
983 using StorageType = typename std::decay<T>::type;
984
985 std::vector<StorageType> data;
986
987 std::unique_ptr<TypeErasedComponentColumn>
988 clone_empty() const override {
989 return std::make_unique<ComponentColumn<T>>();
990 }
991
992 void copy_component_to(
993 TypeErasedComponentColumn* target_column,
994 size_t from_index,
995 size_t to_index
996 ) override {
997 auto* target = static_cast<ComponentColumn<T>*>(target_column);
998 if (target->data.size() <= to_index) {
999 target->data.resize(to_index + 1);
1000 }
1001 target->data[to_index] = this->data[from_index];
1002 }
1003
1004 void swap(size_t index1, size_t index2) override {
1005 std::swap(data[index1], data[index2]);
1006 }
1007
1008 void pop_back() override {
1009 data.pop_back();
1010 }
1011 };
1012
1013 template<typename... NewComponents>
1014 void move_entity(
1015 Archetype* target_archetype,
1016 Entity entity,
1017 NewComponents&&... new_components
1018 ) {
1019 auto it = m_entity_to_index.find(entity);
1020 if (it == m_entity_to_index.end()) {
1021 printf("Error: Entity not found in archetype during move.\n");
1022 std::abort();
1023 }
1024 size_t source_row = it->second;
1025 size_t target_row = target_archetype->m_next_available_row;
1026 target_archetype->m_entity_to_index[entity] = target_row;
1027
1028 for (const auto& [component_id, column_index] : m_type_to_column) {
1029 auto& src_column = m_columns[column_index];
1030 auto target_it =
1031 target_archetype->m_type_to_column.find(component_id);
1032 if (target_it != target_archetype->m_type_to_column.end()) {
1033 size_t target_column_index = target_it->second;
1034 auto& target_column =
1035 target_archetype->m_columns[target_column_index];
1036
1037 // Move the component data
1038 src_column->copy_component_to(
1039 target_column.get(),
1040 source_row,
1041 target_row
1042 );
1043 }
1044 }
1045
1046 // Add new components
1047 (target_archetype->add_row<NewComponents>(
1048 target_row,
1049 std::forward<NewComponents>(new_components)
1050 ),
1051 ...);
1052
1053 // Increment the target archetype's row count
1054 ++target_archetype->m_next_available_row;
1055 }
1056
1057 ComponentMask m_mask;
1058
1059 size_t m_next_available_row {0};
1060 storage::dense_map<ComponentId, size_t> m_type_to_column;
1061 storage::dense_map<Entity, size_t> m_entity_to_index;
1062 std::vector<std::unique_ptr<TypeErasedComponentColumn>> m_columns;
1063 };
1064
1065 void notify_add(const ComponentMask& mask, Entity entity) {
1066 for (const auto& observer : m_observers) {
1067 if (mask.contains(observer->mask())) {
1068 observer->add(entity);
1069 }
1070 }
1071 }
1072
1073 void notify_insert(const ComponentMask& mask, Entity entity) {
1074 for (const auto& observer : m_observers) {
1075 if (mask.contains(observer->mask())) {
1076 observer->insert(entity);
1077 }
1078 }
1079 }
1080
1081 void notify_remove(const ComponentMask& mask, Entity entity) {
1082 for (const auto& observer : m_observers) {
1083 if (mask.contains(observer->mask())) {
1084 observer->remove(entity);
1085 }
1086 }
1087 }
1088
1089 enum class AddFlags { None = 0, Add = 1 << 0, Insert = 1 << 1 };
1090
1091 friend inline AddFlags operator|(AddFlags a, AddFlags b) {
1092 return static_cast<AddFlags>(static_cast<int>(a) | static_cast<int>(b));
1093 }
1094
1095 friend inline AddFlags operator&(AddFlags a, AddFlags b) {
1096 return static_cast<AddFlags>(static_cast<int>(a) & static_cast<int>(b));
1097 }
1098
1099 template<typename... Components>
1100 AddFlags add_components(Entity entity, Components&&... components) {
1101 auto new_components_mask = compute_mask<Components...>();
1102 ComponentMask combined_mask = new_components_mask;
1103
1104 AddFlags flags = AddFlags::None;
1105
1106 Archetype* current_archetype = nullptr;
1107 auto entity_it = m_entity_archetype_map.find(entity);
1108 if (entity_it != m_entity_archetype_map.end()) {
1109 current_archetype = entity_it->second;
1110 combined_mask = current_archetype->m_mask | new_components_mask;
1111
1112 // Check if the current archetype can accommodate the new components
1113 if (current_archetype->m_mask.contains(new_components_mask)) {
1114 current_archetype->update_components(entity, components...);
1115 notify_insert(combined_mask, entity);
1116 return AddFlags::Insert;
1117 }
1118 }
1119
1120 // Find or create an archetype with the combined mask
1121 Archetype* target_archetype = nullptr;
1122 auto archetype_it = m_archetype_map.find(combined_mask);
1123 if (archetype_it != m_archetype_map.end()) {
1124 // Use existing archetype
1125 target_archetype = archetype_it->second;
1126 } else {
1127 // Create a new archetype with combined components
1128 if (current_archetype == nullptr) {
1129 auto new_archetype = Archetype::from_columns<Components...>();
1130 target_archetype = new_archetype.get();
1131 m_archetypes.push_back(std::move(new_archetype));
1132 m_archetype_map[combined_mask] = target_archetype;
1133 } else {
1134 auto new_archetype =
1135 Archetype::from_archetype<Components...>(*current_archetype
1136 );
1137 target_archetype = new_archetype.get();
1138 m_archetypes.push_back(std::move(new_archetype));
1139 m_archetype_map[combined_mask] = target_archetype;
1140 }
1141 }
1142
1143 if (current_archetype != nullptr) {
1144 current_archetype->move_entity(
1145 target_archetype,
1146 entity,
1147 std::forward<Components>(components)...
1148 );
1149 notify_add(combined_mask, entity);
1150 notify_insert(combined_mask, entity);
1151 flags = AddFlags::Add | AddFlags::Insert;
1152 // Remove the entity from the current archetype
1153 current_archetype->remove_entity(entity);
1154 } else {
1155 target_archetype->add_entity(
1156 entity,
1157 std::forward<Components>(components)...
1158 );
1159 notify_add(combined_mask, entity);
1160 notify_insert(combined_mask, entity);
1161
1162 flags = AddFlags::Add | AddFlags::Insert;
1163 }
1164 m_entity_archetype_map[entity] = target_archetype;
1165 ++m_query_version;
1166
1167 return flags;
1168 }
1169
1170 template<typename Component>
1171 void remove_component(Entity entity) {
1172 auto entity_it = m_entity_archetype_map.find(entity);
1173 if (entity_it == m_entity_archetype_map.end()) {
1174 return;
1175 }
1176
1177 Archetype* current_archetype = entity_it->second;
1178
1179 ComponentMask new_mask = current_archetype->m_mask;
1180 ComponentId component_id = TypeIDGenerator::get_type_id<Component>();
1181
1182 if (!new_mask.test(component_id)) {
1183 return;
1184 }
1185
1186 new_mask.reset(component_id);
1187
1188 // Check if an archetype with this mask already exists
1189 Archetype* target_archetype = nullptr;
1190 auto archetype_it = m_archetype_map.find(new_mask);
1191 if (archetype_it != m_archetype_map.end()) {
1192 target_archetype = archetype_it->second;
1193 } else {
1194 // Create a new archetype based on the current one minus the target component
1195 target_archetype = new Archetype(new_mask);
1196
1197 // Clone empty columns for all components except the removed one
1198 for (const auto& [type_id, column_idx] :
1199 current_archetype->m_type_to_column) {
1200 if (type_id != component_id) {
1201 size_t new_idx = target_archetype->m_columns.size();
1202 target_archetype->m_columns.push_back(
1203 current_archetype->m_columns[column_idx]->clone_empty()
1204 );
1205 target_archetype->m_type_to_column[type_id] = new_idx;
1206 }
1207 }
1208 m_archetypes.push_back(std::unique_ptr<Archetype>(target_archetype)
1209 );
1210 m_archetype_map[new_mask] = target_archetype;
1211 }
1212
1213 // Get entity data indices
1214 size_t entity_index = current_archetype->m_entity_to_index[entity];
1215 size_t target_index = target_archetype->m_entity_to_index.size();
1216
1217 // Copy component data to the target archetype except for removed one
1218 for (const auto& [type_id, src_column_idx] :
1219 current_archetype->m_type_to_column) {
1220 if (type_id != component_id) {
1221 auto target_column_idx =
1222 target_archetype->m_type_to_column[type_id];
1223 current_archetype->m_columns[src_column_idx]->copy_component_to(
1224 target_archetype->m_columns[target_column_idx].get(),
1225 entity_index,
1226 target_index
1227 );
1228 }
1229 }
1230
1231 notify_remove(current_archetype->m_mask, entity);
1232
1233 target_archetype->m_entity_to_index[entity] = target_index;
1234 current_archetype->remove_entity(entity);
1235 m_entity_archetype_map[entity] = target_archetype;
1236 ++m_query_version;
1237 }
1238
1239 inline void execute_schedule(ScheduleLabel label) {
1240 for (const auto& system : get_systems(label)) {
1241 system->execute(*this);
1242 }
1243 }
1244
1245 inline void execute_commands();
1246
1247 inline void execute_progress() {
1248 execute_schedule(ScheduleLabel::Startup);
1249 execute_schedule(ScheduleLabel::PreUpdate);
1250 execute_schedule(ScheduleLabel::Update);
1251 execute_schedule(ScheduleLabel::Validate);
1252 execute_schedule(ScheduleLabel::PostUpdate);
1253 execute_schedule(ScheduleLabel::PreStore);
1254 execute_schedule(ScheduleLabel::Store);
1255
1256 for (const auto& observer : m_observers) {
1257 observer->clear();
1258 }
1259
1260 execute_commands();
1261
1262 get_systems(ScheduleLabel::Startup).clear();
1263 }
1264
1265 Time m_time;
1266 std::chrono::high_resolution_clock::time_point m_last_time;
1267
1268 inline std::vector<std::unique_ptr<TypeErasedSystem>>&
1269 get_systems(ScheduleLabel label) {
1270 return m_systems[static_cast<std::underlying_type_t<ScheduleLabel>>(
1271 label
1272 )];
1273 }
1274
1275 storage::dense_map<
1276 std::underlying_type_t<ScheduleLabel>,
1277 std::vector<std::unique_ptr<TypeErasedSystem>>>
1278 m_systems;
1279
1280 // std::unordered_map<
1281 // ScheduleLabel,
1282 // std::vector<std::unique_ptr<TypeErasedSystem>>>
1283 // m_systems;
1284
1285 std::unordered_map<std::type_index, std::unique_ptr<TypeErasedResource>>
1286 m_resources;
1287
1288 Entity m_current_entity_id {0};
1289 unsigned int m_query_version {0};
1290 std::vector<std::unique_ptr<Archetype>> m_archetypes;
1291 std::unordered_map<ComponentMask, Archetype*> m_archetype_map;
1292 storage::dense_map<Entity, Archetype*> m_entity_archetype_map;
1293 std::vector<std::unique_ptr<TypeErasedObserver>> m_observers;
1294 std::unique_ptr<Commands> m_commands;
1295 std::vector<Entity> m_free_list;
1296};
1297
1298template<typename... Filters>
1300 static ComponentMask evaluate(ComponentMask mask) {
1301 QueryFilter<Filters...> filter;
1302 (Filters::evaluate(mask), ...);
1303 return mask;
1304 }
1305};
1306
1307// template<typename... Components>
1308// struct With {
1309// static void evaluate(ComponentMask& mask) {
1310// mask |= compute_mask<Components...>();
1311// }
1312// };
1313
1314// template<typename... Components>
1315// struct Without {
1316// static void evaluate(ComponentMask& mask) {
1317// mask &= ~compute_mask<Components...>();
1318// }
1319// };
1320
1339template<typename T>
1341 public:
1342 using value_type = T;
1343
1347 Optional() : m_ptr(nullptr) {}
1348
1354 explicit Optional(T* ptr) : m_ptr(ptr) {}
1355
1361 operator bool() const {
1362 return has_value();
1363 }
1364
1370 T& operator*() const {
1371 return get();
1372 }
1373
1379 T& get() const {
1380 assert(has_value() && "Optional is none");
1381 return *m_ptr;
1382 }
1383
1384 T* operator->() {
1385 return m_ptr;
1386 }
1387
1388 T* operator->() const {
1389 return m_ptr;
1390 }
1391
1397 bool has_value() const {
1398 return m_ptr != nullptr;
1399 }
1400
1401 private:
1402 T* m_ptr;
1403};
1404
1405// Forward declaration of primary template
1406template<typename... Args>
1407class Test;
1408
1409// Specialization for Filter version
1410template<typename... Filters, typename... Components>
1411class Test<Filter<Filters...>, Components...> {
1412 private:
1413 template<typename T>
1414 using filter_traits = _traits::query::filter_traits<T>;
1415
1416 static ComponentMask compute_mask() {
1417 ComponentMask mask;
1418 (add_component_to_mask<Components>(mask), ...);
1419 (apply_filter<Filters>(mask), ...);
1420 return mask;
1421 }
1422
1423 template<typename Component>
1424 static void add_component_to_mask(ComponentMask& mask) {
1426 && !std::is_same_v<Component, Entity>) {
1427 ComponentId id = TypeIDGenerator::get_type_id<Component>();
1428 if (id >= mask.size()) {
1429 mask.resize(id + 1);
1430 }
1431 mask.set(id);
1432 }
1433 }
1434
1435 template<typename Filter>
1436 static void apply_filter(ComponentMask& mask) {
1437 using Traits = filter_traits<Filter>;
1438 if constexpr (Traits::is_with) {
1439 add_component_to_mask<typename Traits::component_type>(mask);
1440 } else if constexpr (Traits::is_without) {
1441 ComponentId id =
1442 TypeIDGenerator::get_type_id<typename Traits::component_type>();
1443 if (id >= mask.size()) {
1444 mask.resize(id + 1);
1445 }
1446 mask.reset(id);
1447 }
1448 }
1449
1450 public:
1451 void describe() {
1452 printf("Components: ");
1453 ((printf("%s ", typeid(Components).name())), ...);
1454 printf("\n");
1455 printf("Filters: ");
1456 ((printf("%s ", typeid(Filters).name())), ...);
1457 printf("\n");
1458
1459 auto mask = compute_mask();
1460 printf("Mask: ");
1461 for (size_t i = 0; i < mask.size(); ++i) {
1462 printf("%d", mask.test(i) ? 1 : 0);
1463 }
1464 printf("\n");
1465 }
1466};
1467
1468// New specialization for components-only version
1469template<typename... Components>
1470class Test {
1471 private:
1472 static ComponentMask compute_mask() {
1473 ComponentMask mask;
1474 (add_component_to_mask<Components>(mask), ...);
1475 return mask;
1476 }
1477
1478 template<typename Component>
1479 static void add_component_to_mask(ComponentMask& mask) {
1481 && !std::is_same_v<Component, Entity>) {
1482 ComponentId id = TypeIDGenerator::get_type_id<Component>();
1483 if (id >= mask.size()) {
1484 mask.resize(id + 1);
1485 }
1486 mask.set(id);
1487 }
1488 }
1489
1490 public:
1491 void describe() {
1492 printf("Components: ");
1493 ((printf("%s ", typeid(Components).name())), ...);
1494 printf("\n");
1495
1496 auto mask = compute_mask();
1497 printf("Mask: ");
1498 for (size_t i = 0; i < mask.size(); ++i) {
1499 printf("%d", mask.test(i) ? 1 : 0);
1500 }
1501 printf("\n");
1502 }
1503};
1504
1505// Deduction guides
1506template<typename... Filters, typename... Components>
1507Test(Filter<Filters...>, Components...)
1508 -> Test<Filter<Filters...>, Components...>;
1509
1510template<typename... Components>
1511Test(Components...) -> Test<Components...>;
1512
1521template<typename... Components>
1522class Query {
1523 public:
1524 template<typename T>
1525 using QueryTypeTraits = _traits::query::QueryTypeTraits<T>;
1526
1527 template<typename T>
1528 using ComponentStorageType = typename QueryTypeTraits<T>::StorageType;
1529
1530 using QueryComponents =
1531 std::vector<std::tuple<ComponentStorageType<Components>...>>;
1532
1538 Query(World* world) : m_world(world) {
1539 prepare_query();
1540 }
1541
1542 static ComponentMask compute_mask() {
1543 ComponentMask mask;
1544 (add_component_to_mask<Components>(mask), ...);
1545 return mask;
1546 }
1547
1553 class Iterator {
1554 public:
1555 using iterator_category = std::forward_iterator_tag;
1556 using value_type =
1557 std::tuple<typename QueryTypeTraits<Components>::IterationType...>;
1558 using difference_type = std::ptrdiff_t;
1559 using pointer = std::tuple<
1560 typename QueryTypeTraits<Components>::IterationPointerType...>;
1561 using reference = value_type;
1562
1570 typename QueryComponents::iterator current,
1571 typename QueryComponents::iterator end
1572 ) :
1573 m_current(current),
1574 m_end(end) {}
1575
1582 ++m_current;
1583 return *this;
1584 }
1585
1591 reference operator*() const {
1592 return dereference_tuple(std::index_sequence_for<Components...> {});
1593 }
1594
1601 bool operator!=(const Iterator& other) const {
1602 return m_current != other.m_current;
1603 }
1604
1605 private:
1606 typename QueryComponents::iterator m_current;
1607 typename QueryComponents::iterator m_end;
1608
1609 template<size_t... Is>
1610 reference dereference_tuple(std::index_sequence<Is...>) const {
1611 return std::tuple<
1612 typename QueryTypeTraits<Components>::IterationType...>(
1613 dereference_element<Components>(std::get<Is>(*m_current))...
1614 );
1615 }
1616
1617 template<typename T>
1618 typename QueryTypeTraits<T>::IterationType
1619 dereference_element(typename QueryTypeTraits<T>::StorageType elem
1620 ) const {
1621 return QueryTypeTraits<T>::dereference(elem);
1622 }
1623 };
1624
1631 ensure_up_to_date();
1632 return Iterator(m_components.begin(), m_components.end());
1633 }
1634
1641 return Iterator(m_components.end(), m_components.end());
1642 }
1643
1650 struct Single {
1654 Single() = default;
1655
1661 Single(const std::tuple<Components*...>& components) :
1662 m_state(dereference_tuple(components)) {}
1663
1670 inline std::tuple<Components&...> operator*() {
1671 assert(is_valid() && "Attempted to dereference an invalid Single.");
1672 return std::get<std::tuple<Components&...>>(m_state);
1673 }
1674
1680 inline operator bool() const {
1681 return is_valid();
1682 }
1683
1684 private:
1685 friend class Query;
1686 std::variant<std::monostate, std::tuple<Components&...>> m_state;
1687
1688 template<typename... Ts>
1689 static inline std::tuple<Ts&...>
1690 dereference_tuple(const std::tuple<Ts*...>& pointers) {
1691 return std::apply(
1692 [](auto*... ptrs) { return std::tie(*ptrs...); },
1693 pointers
1694 );
1695 }
1696
1697 inline bool is_valid() const {
1698 return std::holds_alternative<std::tuple<Components&...>>(m_state);
1699 }
1700 };
1701
1707 struct Record {
1708 using RecordComponents =
1709 std::tuple<ComponentStorageType<Components>...>;
1710
1711 Record() = default;
1712
1718 operator bool() const {
1719 return is_valid();
1720 }
1721
1727 inline bool is_valid() const {
1728 return std::holds_alternative<RecordComponents>(m_state);
1729 }
1730
1737 inline auto operator*() const {
1738 assert(is_valid() && "Attempted to dereference an invalid Record.");
1739 return dereference_tuple(std::index_sequence_for<Components...> {});
1740 }
1741
1742 inline auto operator*() {
1743 assert(is_valid() && "Attempted to dereference an invalid Record.");
1744 return dereference_tuple(std::index_sequence_for<Components...> {});
1745 }
1746
1747 private:
1748 friend struct Query;
1749 std::variant<std::monostate, RecordComponents> m_state;
1750
1751 explicit Record(const RecordComponents& components) :
1752 m_state(components) {}
1753
1754 template<size_t... Is>
1755 auto dereference_tuple(std::index_sequence<Is...>) {
1756 auto& components = std::get<RecordComponents>(m_state);
1757 return std::tuple<decltype(QueryTypeTraits<Components>::dereference(
1758 std::get<Is>(components)
1759 ))...>(
1760 QueryTypeTraits<Components>::dereference(std::get<Is>(components
1761 ))...
1762 );
1763 }
1764
1765 template<size_t... Is>
1766 auto dereference_tuple(std::index_sequence<Is...>) const {
1767 const auto& components = std::get<RecordComponents>(m_state);
1768 return std::tuple<
1769 const decltype(QueryTypeTraits<Components>::dereference(
1770 std::get<Is>(components)
1771 ))...>(
1772 QueryTypeTraits<Components>::dereference(std::get<Is>(components
1773 ))...
1774 );
1775 }
1776
1777 template<typename T>
1778 static auto
1779 dereference_element(typename QueryTypeTraits<T>::StorageType elem) {
1780 return QueryTypeTraits<T>::dereference(elem);
1781 }
1782 };
1783
1808 inline Record get(Entity entity) {
1809 auto archetype_it = m_world->m_entity_archetype_map.find(entity);
1810 if (archetype_it == m_world->m_entity_archetype_map.end()) {
1811 return {};
1812 }
1813
1814 World::Archetype* archetype = archetype_it->second;
1815
1816 ComponentMask record_mask = Query<Components...>::compute_mask();
1817 if (!archetype->has_components(record_mask)) {
1818 return {};
1819 }
1820
1821 return Record(World::Archetype::make_component_tuple<Components...>(
1822 archetype,
1823 entity
1824 ));
1825 }
1826
1849 ensure_up_to_date();
1850
1851 if (m_components.size() != 1) {
1852 return {};
1853 }
1854
1855 return Record(m_components.at(0));
1856 }
1857
1858 inline size_t count() const {
1859 return m_components.size();
1860 }
1861
1862 private:
1863 World* m_world {nullptr};
1864 QueryComponents m_components;
1865 unsigned int m_query_version {0};
1866
1867 void ensure_up_to_date();
1868
1869 void prepare_query();
1870
1871 template<typename Component>
1872 static void add_component_to_mask(ComponentMask& mask) {
1873 if constexpr (!_traits::is_optional<Component>::value
1874 && !std::is_same_v<Component, Entity>) {
1875 ComponentId id = TypeIDGenerator::get_type_id<Component>();
1876 if (id >= mask.size()) {
1877 mask.resize(id + 1);
1878 }
1879 mask.set(id);
1880 }
1881 }
1882
1883 template<typename T>
1884 static decltype(auto) dereference_if_needed(T&& arg) {
1885 return QueryTypeTraits<std::remove_reference_t<T>>::dereference(
1886 std::forward<T>(arg)
1887 );
1888 }
1889};
1890
1896 public:
1900 EntityBuilder() = delete;
1901
1907 template<typename... Components>
1908 bool has() const {
1909 auto it = m_world->m_entity_archetype_map.find(m_id);
1910 if (it == m_world->m_entity_archetype_map.end()) {
1911 return false;
1912 }
1913 auto archetype = it->second;
1914 return archetype->has_components<Components...>();
1915 }
1916
1917 template<typename Component>
1918 Component* get_component() {
1919 auto it = m_world->m_entity_archetype_map.find(m_id);
1920 if (it == m_world->m_entity_archetype_map.end()) {
1921 return nullptr;
1922 }
1923 auto archetype = it->second;
1924 return archetype->get_component<Component>(m_id);
1925 }
1926
1931 operator Entity() {
1932 return m_id;
1933 }
1934
1935 void despawn() {
1936 m_world->despawn(m_id);
1937 }
1938
1945 template<typename... Components>
1946 EntityBuilder& insert(Components&&... components) {
1947 auto components_tuple =
1948 std::make_tuple(std::forward<Components>(components)...);
1949 auto flat_tuple = flatten_tuple(std::move(components_tuple));
1950
1951 using namespace _traits::component_hooks;
1952
1953 // m_world->add_components(m_id, std::forward<Components>(components)...);
1954 std::apply(
1955 [this](auto&&... flat_comps) {
1956 World::AddFlags flags = m_world->add_components(
1957 m_id,
1958 std::forward<decltype(flat_comps)>(flat_comps)...
1959 );
1960 if ((flags & World::AddFlags::Add) != World::AddFlags::None) {
1961 invoke_on_add_hooks<Components...>(*m_world, m_id);
1962 invoke_on_add_instance_hooks<Components...>(*m_world, m_id);
1963 }
1964 if ((flags & World::AddFlags::Insert)
1965 != World::AddFlags::None) {
1966 invoke_on_insert_hooks<Components...>(*m_world, m_id);
1967 invoke_on_insert_instance_hooks<Components...>(
1968 *m_world,
1969 m_id
1970 );
1971 }
1972 },
1973 flat_tuple
1974 );
1975 return *this;
1976 }
1977
1978 template<typename Component>
1979 EntityBuilder& remove() {
1980 m_world->remove_component<Component>(m_id);
1981 return *this;
1982 }
1983
1990 template<typename Func>
1992 EntityBuilder new_builder = m_world->spawn();
1993 EntityBuilder ret_builder = func(new_builder);
1994 ret_builder.insert(Parent {m_id});
1995
1996 return *this;
1997 }
1998
2004 EntityBuilder& add_child(Entity entity) {
2005 EntityBuilder(m_world, entity).insert(Parent {m_id});
2006 return *this;
2007 }
2008
2015 template<typename... Components>
2016 EntityBuilder& insert_child(Components&&... components) {
2017 auto child =
2018 m_world->spawn().insert(std::forward<Components>(components)...);
2019 add_child(child);
2020 return *this;
2021 }
2022
2023 private:
2024 friend class World;
2025 friend class EntityCommands;
2026
2027 EntityBuilder(World* world, Entity entity) : m_id(entity), m_world(world) {}
2028
2029 // Used for flattening bundle component
2030 template<typename Tuple>
2031 static auto flatten_tuple(Tuple&& t) {
2032 return flatten_tuple_impl(
2033 std::forward<Tuple>(t),
2034 std::make_index_sequence<
2035 std::tuple_size<std::decay_t<Tuple>>::value> {}
2036 );
2037 }
2038
2039 template<typename Tuple, std::size_t... Is>
2040 static auto flatten_tuple_impl(Tuple&& t, std::index_sequence<Is...>) {
2041 return std::tuple_cat(
2042 flatten_element(std::get<Is>(std::forward<Tuple>(t)))...
2043 );
2044 }
2045
2046 template<typename T>
2047 static auto flatten_element(T&& t) {
2048 if constexpr (_traits::is_bundle_v<T>) {
2049 return flatten_tuple(std::forward<T>(t).components);
2050 } else {
2051 return std::make_tuple(std::forward<T>(t));
2052 }
2053 }
2054
2055 World* m_world {nullptr};
2056 Entity m_id;
2057};
2058
2065class EntityCommands {
2066 public:
2076 template<typename... Components>
2077 EntityCommands& insert(Components&&... components);
2078
2079 template<typename Component>
2080 EntityCommands& remove();
2081
2082 operator Entity() {
2083 return m_entity;
2084 }
2085
2086 EntityCommands& add_child(Entity entity);
2087
2088 template<typename... Components>
2089 EntityCommands& insert_child(Components&&... components);
2090
2091 template<typename Func>
2092 EntityCommands& with_children(Func&& func);
2093
2099 void despawn();
2100
2101 private:
2102 friend class Commands;
2103
2104 EntityCommands(Commands& commands, Entity entity) :
2105 m_commands(commands),
2106 m_entity(entity) {}
2107
2108 Commands& m_commands;
2109 Entity m_entity;
2110};
2111
2112class Command {
2113 public:
2114 template<typename F>
2115 explicit Command(F&& f) :
2116 m_cmd(std::make_unique<Model<std::decay_t<F>>>(std::forward<F>(f))) {}
2117
2118 Command(const Command&) = delete;
2119 Command& operator=(const Command&) = delete;
2120 Command(Command&&) noexcept = default;
2121 Command& operator=(Command&&) noexcept = default;
2122
2123 void execute(World& world) {
2124 m_cmd->execute(world);
2125 }
2126
2127 private:
2128 struct Concept {
2129 virtual ~Concept() = default;
2130 virtual void execute(World& world) = 0;
2131 };
2132
2133 template<typename F>
2134 struct Model: Concept {
2135 F f;
2136
2137 explicit Model(F&& f_) : f(std::move(f_)) {}
2138
2139 void execute(World& world) override {
2140 f(world);
2141 }
2142 };
2143
2144 std::unique_ptr<Concept> m_cmd;
2145};
2146
2154class Commands {
2155 public:
2156 Commands(World& world) : m_world(world) {}
2157
2158 Commands(const Commands&) = delete;
2159 Commands& operator=(const Commands&) = delete;
2160 Commands(Commands&&) noexcept = default;
2161 Commands& operator=(Commands&&) noexcept = delete;
2162
2168 template<typename Func>
2169 void add(Func&& func) {
2170 m_commands.emplace_back(std::forward<Func>(func));
2171 }
2172
2182 Entity entity = m_world.spawn();
2183 return EntityCommands(*this, entity);
2184 }
2185
2196 return EntityCommands(*this, entity);
2197 }
2198
2199 private:
2200 friend class World;
2201
2202 void apply() {
2203 std::vector<Command> commands_to_execute;
2204 std::swap(commands_to_execute, m_commands);
2205
2206 for (auto& command : commands_to_execute) {
2207 command.execute(m_world);
2208 }
2209 }
2210
2211 private:
2212 World& m_world;
2213 std::vector<Command> m_commands;
2214};
2215
2216template<typename... Components>
2217EntityCommands& EntityCommands::insert(Components&&... components) {
2218 m_commands.add([entity = m_entity,
2219 tuple_components =
2220 std::make_tuple(std::forward<Components>(components)...
2221 )](World& world) mutable {
2222 std::apply(
2223 [&world, entity](auto&&... comps) {
2224 EntityBuilder(&world, entity).insert(std::move(comps)...);
2225 },
2226 tuple_components
2227 );
2228 });
2229 return *this;
2230}
2231
2232template<typename Component>
2233EntityCommands& EntityCommands::remove() {
2234 m_commands.add([our_entity = m_entity](World& world) {
2235 EntityBuilder(&world, our_entity).remove<Component>();
2236 });
2237 return *this;
2238}
2239
2240// template<typename... Components>
2241// EntityCommands& EntityCommands::insert(Components&&... components) {
2242// Entity entity = m_entity;
2243
2244// std::tuple<std::decay_t<Components>...> components_copy(
2245// std::forward<Components>(components)...
2246// );
2247
2248// m_commands.add([entity = m_entity,
2249// components_copy =
2250// std::move(components_copy)](World& world) mutable {
2251// std::apply(
2252// [&world, entity](auto&&... comps) {
2253// EntityBuilder(&world, entity).insert(std::move(comps)...);
2254// },
2255// components_copy
2256// );
2257// });
2258
2259// return *this;
2260// }
2261
2262template<typename Func>
2263EntityCommands& EntityCommands::with_children(Func&& func) {
2264 m_commands.add([entity = m_entity,
2265 func = std::forward<Func>(func)](World& world) mutable {
2266 EntityBuilder(&world, entity).with_children(std::forward<Func>(func));
2267 });
2268
2269 return *this;
2270}
2271
2272template<typename... Components>
2273EntityCommands& EntityCommands::insert_child(Components&&... components) {
2274 std::tuple<std::decay_t<Components>...> components_copy(
2275 std::forward<Components>(components)...
2276 );
2277
2278 m_commands.add([entity = m_entity,
2279 components_copy =
2280 std::move(components_copy)](World& world) {
2281 std::apply(
2282 [&world, entity](auto&&... comps) {
2283 EntityBuilder(&world, entity).insert_child(std::move(comps)...);
2284 },
2285 components_copy
2286 );
2287 });
2288 return *this;
2289}
2290
2291inline Commands& World::commands() {
2292 return *m_commands.get();
2293}
2294
2295inline void World::execute_commands() {
2296 m_commands->apply();
2297}
2298
2299template<typename... Components>
2300void Query<Components...>::prepare_query() {
2301 ComponentMask query_mask = Query<Components...>::compute_mask();
2302
2303 m_components.clear();
2304 for (const auto& archetype : m_world->m_archetypes) {
2305 if (archetype->m_mask.contains(query_mask)) {
2306 for (const auto& [entity, index] : archetype->m_entity_to_index) {
2307 m_components.emplace_back(
2308 World::Archetype::make_component_tuple<Components...>(
2309 archetype.get(),
2310 entity
2311 )
2312 );
2313 }
2314 }
2315 }
2316 m_query_version = m_world->m_query_version;
2317}
2318
2319template<typename... Components>
2320void Query<Components...>::ensure_up_to_date() {
2321 if (m_query_version != m_world->m_query_version) {
2322 prepare_query();
2323 }
2324}
2325
2338template<typename T>
2340 static_assert(
2341 sizeof(T) == -1,
2342 "into_system_param not specialized for this type"
2343 );
2344};
2345
2354template<typename T>
2356
2365template<typename T>
2367
2368// Built-in system parameters
2369
2381template<typename T>
2382struct Local {
2389 return m_data;
2390 }
2391
2392 private:
2393 T m_data;
2394};
2395
2405template<typename T>
2418 static Local<T> get(World&) {
2419 return Local<T> {};
2420 }
2421};
2422
2423template<>
2424struct into_system_param<const Time&> {
2425 static const Time& get(World& world) {
2426 auto time = world.get_resource<Time>();
2427 return *time;
2428 }
2429};
2430
2439template<typename T>
2446 static Resource<T> get(World& world) {
2447 return world.get_resource<T>();
2448 }
2449};
2450
2460template<typename... Components>
2461struct into_system_param<Query<Components...>> {
2471 static Query<Components...> get(World& world) {
2472 return Query<Components...>(&world);
2473 }
2474};
2475
2485template<typename... Components>
2486struct into_system_param<const Observer<Components...>&> {
2487 static const Observer<Components...>& get(World& world) {
2498 return world.observe<Components...>();
2499 }
2500};
2501
2502template<>
2504 static Commands& get(World& world) {
2505 return world.commands();
2506 }
2507};
2508
2509template<typename Tuple>
2511
2512template<typename... Args>
2513struct get_system_params_helper<std::tuple<Args...>> {
2514 static auto get(World& world) {
2515 return std::make_tuple(
2516 wrap_param<Args>(into_system_param<Args>::get(world))...
2517 );
2518 }
2519
2520 private:
2521 template<typename T, typename ParamT>
2522 static auto wrap_param(ParamT&& param) {
2523 if constexpr (std::is_reference_v<ParamT>) {
2524 return std::ref(param);
2525 } else {
2526 return std::forward<ParamT>(param);
2527 }
2528 }
2529};
2530
2531template<typename Tuple>
2532auto get_system_params(World& world) {
2534}
2535
2536template<typename T>
2538
2539} // namespace vecs
2540
2541#endif
Provides a deferred command interface to manage entity operations within the ECS world.
Definition vecs.h:2154
EntityCommands entity(Entity entity)
Provides an EntityCommands interface to manage commands for an existing entity.
Definition vecs.h:2195
void add(Func &&func)
Adds a deferred command to be executed on the world.
Definition vecs.h:2169
EntityCommands spawn()
Spawns a new entity and provides a deferred interface to add components to it.
Definition vecs.h:2181
Provides methods to construct and modify entities within the ECS world.
Definition vecs.h:1895
bool has() const
Checks if the entity has all specified components.
Definition vecs.h:1908
EntityBuilder & with_children(Func &&func)
Spawns a new entity, allows modifications via a function, and assigns it as a child of the current en...
Definition vecs.h:1991
EntityBuilder & add_child(Entity entity)
Adds an existing entity as a child of the current entity.
Definition vecs.h:2004
EntityBuilder & insert_child(Components &&... components)
Spawns a new entity, inserts components, and assigns it as a child of the current entity.
Definition vecs.h:2016
EntityBuilder()=delete
Deleted default constructor to prevent creating an EntityBuilder without parameters.
EntityBuilder & insert(Components &&... components)
Inserts components into the entity.
Definition vecs.h:1946
Provides a deferred command interface for managing a specific entity's state within the ECS world.
Definition vecs.h:2065
EntityCommands & insert(Components &&... components)
Adds a deferred command to insert components into the entity.
Definition vecs.h:2217
void despawn()
Adds a deferred command to despawn the entity.
Definition vecs.h:33
Observer class for tracking component changes within a system.
Definition vecs.h:475
const std::vector< Entity > & removed() const override
Retrieves the entities that have been had the observed components removed.
Definition vecs.h:521
Observer()
Constructs an Observer for the specified components.
Definition vecs.h:482
const std::vector< Entity > & inserted() const override
Retrieves the entities that have been inserted with the observed components.
Definition vecs.h:509
const std::vector< Entity > & added() const override
Retrieves the entities that have been added for the first time with the observed components.
Definition vecs.h:497
Provides an interface for interacting with optional components.
Definition vecs.h:1340
Optional()
Constructs an empty Optional with no value.
Definition vecs.h:1347
bool has_value() const
Checks if a value is present.
Definition vecs.h:1397
T & get() const
Returns a reference to the contained value.
Definition vecs.h:1379
Optional(T *ptr)
Constructs an Optional that holds a pointer to a value.
Definition vecs.h:1354
T & operator*() const
Dereferences the contained value.
Definition vecs.h:1370
Iterator for iterating over entities matching the query.
Definition vecs.h:1553
Iterator(typename QueryComponents::iterator current, typename QueryComponents::iterator end)
Constructs an iterator for the query.
Definition vecs.h:1569
Iterator & operator++()
Advances the iterator to the next entity.
Definition vecs.h:1581
reference operator*() const
Dereferences the iterator to access the current entity's components.
Definition vecs.h:1591
bool operator!=(const Iterator &other) const
Compares two iterators for inequality.
Definition vecs.h:1601
Represents a query for components within the ECS world.
Definition vecs.h:1522
Record get_single()
Retrieves the components of a single entity matching the query.
Definition vecs.h:1848
Record get(Entity entity)
Retrieves the components of an entity matching the query.
Definition vecs.h:1808
Iterator begin()
Returns an iterator to the beginning of the query results.
Definition vecs.h:1630
Iterator end()
Returns an iterator to the end of the query results.
Definition vecs.h:1640
Query(World *world)
Constructs a Query to search for entities with specified components.
Definition vecs.h:1538
Definition vecs.h:1470
Definition vecs.h:434
The ECS world.
Definition vecs.h:575
void progress(float delta_time)
Progresses the ECS world by one tick, with a supplied delta time.
Definition vecs.h:677
Resource< T > & get_resource() const
Retrieves a non-owned resource of type T.
Definition vecs.h:608
World & add_resource(T *resource)
Adds a non-owned resource to the world.
Definition vecs.h:593
void add_system(Func &&func)
Adds a system to the Update schedule.
Definition vecs.h:657
void add_system(ScheduleLabel label, Func &&func)
Adds a system to the specified schedule.
Definition vecs.h:632
void progress()
Progresses the ECS world by one tick, with automatically calculated delta time.
Definition vecs.h:664
Definition vecs.h:74
Definition vecs.h:71
Definition vecs.h:86
Definition vecs.h:2537
A container for local data specific to a system.
Definition vecs.h:2382
T & operator*()
Dereferences the local data, providing access to the stored value.
Definition vecs.h:2388
Definition vecs.h:360
A container for a single record and its components, as a result of a query.
Definition vecs.h:1707
auto operator*() const
Dereferences the record.
Definition vecs.h:1737
bool is_valid() const
Checks if the Record is valid.
Definition vecs.h:1727
Single(const std::tuple< Components *... > &components)
Constructs a valid Single result from a tuple of component pointers.
Definition vecs.h:1661
std::tuple< Components &... > operator*()
Dereferences the components.
Definition vecs.h:1670
Single()=default
Default constructor for an invalid state.
Definition vecs.h:1299
A non-owning wrapper around a resource of type T.
Definition vecs.h:407
Resource(T *ptr)
Constructs a non-owning Resource wrapper for a given pointer.
Definition vecs.h:412
Definition vecs.h:567
Definition vecs.h:393
Definition vecs.h:27
Definition vecs.h:30
Definition vecs.h:2510
static Local< T > get(World &)
Retrieves a persistent instance of Local<T> for system use.
Definition vecs.h:2418
static Query< Components... > get(World &world)
Retrieves a Query<Components...> from the world.
Definition vecs.h:2471
static Resource< T > get(World &world)
Fetches Resource<T> from the world.
Definition vecs.h:2446
static const Observer< Components... > & get(World &world)
Definition vecs.h:2487
A template for converting types into system parameters.
Definition vecs.h:2339
ScheduleLabel
Labels for predefined execution phases of systems within the ECS World
Definition vecs.h:372