EntityComponentMetaSystem
An implementation of an EntityComponent System with template meta-programming.
Loading...
Searching...
No Matches
Manager.hpp
1
2// This work derives from Vittorio Romeo's code used for cppcon 2015 licensed
3// under the Academic Free License.
4// His code is available here: https://github.com/SuperV1234/cppcon2015
5
6#ifndef EC_MANAGER_HPP
7#define EC_MANAGER_HPP
8
9#define EC_INIT_ENTITIES_SIZE 256
10#define EC_GROW_SIZE_AMOUNT 256
11
12#include <algorithm>
13#include <array>
14#include <atomic>
15#include <chrono>
16#include <cstddef>
17#include <deque>
18#include <functional>
19#include <map>
20#include <mutex>
21#include <set>
22#include <thread>
23#include <tuple>
24#include <type_traits>
25#include <unordered_map>
26#include <unordered_set>
27#include <utility>
28#include <vector>
29
30#ifndef NDEBUG
31#include <iostream>
32#endif
33
34#include "Bitset.hpp"
35#include "Meta/Combine.hpp"
36#include "Meta/ForEachDoubleTuple.hpp"
37#include "Meta/ForEachWithIndex.hpp"
38#include "Meta/IndexOf.hpp"
39#include "Meta/Matching.hpp"
40#include "ThreadPool.hpp"
41
42namespace EC {
68template <typename ComponentsList, typename TagsList,
69 unsigned int ThreadCount = 4>
70struct Manager {
71 public:
72 using Components = ComponentsList;
73 using Tags = TagsList;
74 using Combined = EC::Meta::Combine<ComponentsList, TagsList>;
76
77 private:
78 using ComponentsTuple = EC::Meta::Morph<ComponentsList, std::tuple<> >;
79 static_assert(std::is_default_constructible<ComponentsTuple>::value,
80 "All components must be default constructible");
81
82 template <typename... Types>
83 struct Storage {
84 using type = std::tuple<std::deque<Types>..., std::deque<char> >;
85 };
86 using ComponentsStorage =
87 typename EC::Meta::Morph<ComponentsList, Storage<> >::type;
88
89 // Entity: isAlive, ComponentsTags Info
90 using EntitiesTupleType = std::tuple<bool, BitsetType>;
91 using EntitiesType = std::deque<EntitiesTupleType>;
92
93 EntitiesType entities;
94 ComponentsStorage componentsStorage;
95 std::size_t currentCapacity = 0;
96 std::size_t currentSize = 0;
97 std::unordered_set<std::size_t> deletedSet;
98
99 std::unique_ptr<ThreadPool<ThreadCount> > threadPool;
100
101 std::atomic_uint deferringDeletions;
102 std::vector<std::size_t> deferredDeletions;
103 std::mutex deferredDeletionsMutex;
104
105 std::vector<std::size_t> idStack;
106 std::size_t idStackCounter;
107 std::mutex idStackMutex;
108
109 public:
110 // section for "temporary" structures {{{
113 std::array<std::size_t, 2> range;
114 Manager* manager;
115 EntitiesType* entities;
116 const BitsetType* signature;
117 void* userData;
118 std::unordered_set<std::size_t> dead;
119 };
121 template <typename Function>
123 std::array<std::size_t, 2> range;
124 Manager* manager;
125 EntitiesType* entities;
126 BitsetType* signature;
127 void* userData;
128 Function* fn;
129 std::unordered_set<std::size_t> dead;
130 };
133 std::array<std::size_t, 2> range;
134 Manager* manager;
135 EntitiesType* entities;
136 void* userData;
137 const std::vector<std::size_t>* matching;
138 std::unordered_set<std::size_t> dead;
139 };
142 std::array<std::size_t, 2> range;
143 Manager* manager;
144 std::vector<std::vector<std::size_t> >* matchingV;
145 const std::vector<BitsetType*>* bitsets;
146 EntitiesType* entities;
147 std::mutex* mutex;
148 std::unordered_set<std::size_t> dead;
149 };
152 std::array<std::size_t, 2> range;
153 Manager* manager;
154 std::vector<std::vector<std::size_t> >* multiMatchingEntities;
155 BitsetType* signatures;
156 std::mutex* mutex;
157 std::unordered_set<std::size_t> dead;
158 };
161 std::array<std::size_t, 2> range;
162 std::size_t index;
163 Manager* manager;
164 void* userData;
165 std::vector<std::vector<std::size_t> >* multiMatchingEntities;
166 std::unordered_set<std::size_t> dead;
167 };
170 std::array<std::size_t, 2> range;
171 Manager* manager;
172 std::vector<std::vector<std::size_t> >* multiMatchingEntities;
173 BitsetType* bitsets;
174 std::mutex* mutex;
175 std::unordered_set<std::size_t> dead;
176 };
178 template <typename Iterable>
180 std::array<std::size_t, 2> range;
181 Manager* manager;
182 EntitiesType* entities;
183 Iterable* iterable;
184 void* userData;
185 std::unordered_set<std::size_t> dead;
186 };
187 // end section for "temporary" structures }}}
188
195 Manager() : threadPool{}, idStackCounter(0) {
196 resize(EC_INIT_ENTITIES_SIZE);
197 if (ThreadCount >= 2) {
198 threadPool = std::make_unique<ThreadPool<ThreadCount> >();
199 }
200
201 deferringDeletions.store(0);
202 }
203
204 ~Manager() {
205 if (threadPool) {
206 while (!threadPool->isNotRunning()) {
207 std::this_thread::sleep_for(std::chrono::microseconds(30));
208 }
209 }
210 }
211
212 private:
213 void resize(std::size_t newCapacity) {
214 if (currentCapacity >= newCapacity) {
215 return;
216 }
217
218 EC::Meta::forEach<ComponentsList>([this, newCapacity](auto t) {
219 std::get<std::deque<decltype(t)> >(this->componentsStorage)
220 .resize(newCapacity);
221 });
222
223 entities.resize(newCapacity);
224 for (std::size_t i = currentCapacity; i < newCapacity; ++i) {
225 entities[i] = std::make_tuple(false, BitsetType{});
226 }
227
228 currentCapacity = newCapacity;
229 }
230
231 public:
237 std::size_t addEntity() {
238 if (deletedSet.empty()) {
239 if (currentSize == currentCapacity) {
240 resize(currentCapacity + EC_GROW_SIZE_AMOUNT);
241 }
242
243 std::get<bool>(entities[currentSize]) = true;
244
245 return currentSize++;
246 } else {
247 std::size_t id;
248 {
249 auto iter = deletedSet.begin();
250 id = *iter;
251 deletedSet.erase(iter);
252 }
253 std::get<bool>(entities[id]) = true;
254 return id;
255 }
256 }
257
258 private:
259 void deleteEntityImpl(std::size_t id) {
260 if (hasEntity(id)) {
261 std::get<bool>(entities.at(id)) = false;
262 std::get<BitsetType>(entities.at(id)).reset();
263 deletedSet.insert(id);
264 }
265 }
266
267 public:
275 void deleteEntity(std::size_t index) {
276 if (deferringDeletions.load() != 0) {
277 std::lock_guard<std::mutex> lock(deferredDeletionsMutex);
278 deferredDeletions.push_back(index);
279 } else {
280 deleteEntityImpl(index);
281 }
282 }
283
284 private:
285 void handleDeferredDeletions() {
286 if (deferringDeletions.fetch_sub(1) == 1) {
287 std::lock_guard<std::mutex> lock(deferredDeletionsMutex);
288 for (std::size_t id : deferredDeletions) {
289 deleteEntityImpl(id);
290 }
291 deferredDeletions.clear();
292 }
293 }
294
295 public:
302 bool hasEntity(const std::size_t& index) const {
303 return index < currentSize;
304 }
305
312 bool isAlive(const std::size_t& index) const {
313 return hasEntity(index) && std::get<bool>(entities.at(index));
314 }
315
322 std::size_t getCurrentSize() const {
323 return currentSize - deletedSet.size();
324 }
325
326 /*
327 \brief Returns the current capacity or number of entities the system
328 can hold.
329
330 Note that when capacity is exceeded, the capacity is increased by
331 EC_GROW_SIZE_AMOUNT.
332 */
333 std::size_t getCurrentCapacity() const { return currentCapacity; }
334
344 const EntitiesTupleType& getEntityInfo(const std::size_t& index) const {
345 return entities.at(index);
346 }
347
361 template <typename Component>
362 Component* getEntityData(const std::size_t& index) {
363 constexpr auto componentIndex =
365 if (componentIndex < Components::size) {
366 // Cast required due to compiler thinking that an invalid
367 // Component is needed even though the enclosing if statement
368 // prevents this from ever happening.
369 return (Component*)&std::get<componentIndex>(componentsStorage)
370 .at(index);
371 } else {
372 return nullptr;
373 }
374 }
375
391 template <typename Component>
392 Component* getEntityComponent(const std::size_t& index) {
393 return getEntityData<Component>(index);
394 }
395
409 template <typename Component>
410 const Component* getEntityData(const std::size_t& index) const {
411 constexpr auto componentIndex =
413 if (componentIndex < Components::size) {
414 // Cast required due to compiler thinking that an invalid
415 // Component is needed even though the enclosing if statement
416 // prevents this from ever happening.
417 return (Component*)&std::get<componentIndex>(componentsStorage)
418 .at(index);
419 } else {
420 return nullptr;
421 }
422 }
423
439 template <typename Component>
440 const Component* getEntityComponent(const std::size_t& index) const {
441 return getEntityData<Component>(index);
442 }
443
453 template <typename Component>
454 bool hasComponent(const std::size_t& index) const {
455 return std::get<BitsetType>(entities.at(index))
456 .template getComponentBit<Component>();
457 }
458
467 template <typename Tag>
468 bool hasTag(const std::size_t& index) const {
469 return std::get<BitsetType>(entities.at(index))
470 .template getTagBit<Tag>();
471 }
472
502 template <typename Component, typename... Args>
503 void addComponent(const std::size_t& entityID, Args&&... args) {
504 if (!EC::Meta::Contains<Component, Components>::value ||
505 !isAlive(entityID)) {
506 return;
507 }
508
509 Component component(std::forward<Args>(args)...);
510
511 std::get<BitsetType>(entities[entityID])
512 .template getComponentBit<Component>() = true;
513
515
516 // Cast required due to compiler thinking that deque<char> at
517 // index = Components::size is being used, even if the previous
518 // if statement will prevent this from ever happening.
519 (*((std::deque<Component>*)(&std::get<index>(
520 componentsStorage))))[entityID] = std::move(component);
521 }
522
534 template <typename Component>
535 void removeComponent(const std::size_t& entityID) {
536 if (!EC::Meta::Contains<Component, Components>::value ||
537 !isAlive(entityID)) {
538 return;
539 }
540
541 std::get<BitsetType>(entities[entityID])
542 .template getComponentBit<Component>() = false;
543 }
544
553 template <typename Tag>
554 void addTag(const std::size_t& entityID) {
555 if (!EC::Meta::Contains<Tag, Tags>::value || !isAlive(entityID)) {
556 return;
557 }
558
559 std::get<BitsetType>(entities[entityID]).template getTagBit<Tag>() =
560 true;
561 }
562
573 template <typename Tag>
574 void removeTag(const std::size_t& entityID) {
575 if (!EC::Meta::Contains<Tag, Tags>::value || !isAlive(entityID)) {
576 return;
577 }
578
579 std::get<BitsetType>(entities[entityID]).template getTagBit<Tag>() =
580 false;
581 }
582
590 void reset() {
592
593 currentSize = 0;
594 currentCapacity = 0;
595 deletedSet.clear();
596 resize(EC_INIT_ENTITIES_SIZE);
597
598 std::lock_guard<std::mutex> lock(deferredDeletionsMutex);
599 deferringDeletions.store(0);
600 deferredDeletions.clear();
601 }
602
603 private:
604 template <typename... Types>
605 struct ForMatchingSignatureHelper {
606 template <typename CType, typename Function>
607 static void call(const std::size_t& entityID, CType& ctype,
608 Function&& function, void* userData = nullptr) {
609 function(entityID, userData,
610 ctype.template getEntityData<Types>(entityID)...);
611 }
612
613 template <typename CType, typename Function>
614 static void callPtr(const std::size_t& entityID, CType& ctype,
615 Function* function, void* userData = nullptr) {
616 (*function)(entityID, userData,
617 ctype.template getEntityData<Types>(entityID)...);
618 }
619
620 template <typename CType, typename Function>
621 void callInstance(const std::size_t& entityID, CType& ctype,
622 Function&& function, void* userData = nullptr) const {
623 ForMatchingSignatureHelper<Types...>::call(
624 entityID, ctype, std::forward<Function>(function), userData);
625 }
626
627 template <typename CType, typename Function>
628 void callInstancePtr(const std::size_t& entityID, CType& ctype,
629 Function* function,
630 void* userData = nullptr) const {
631 ForMatchingSignatureHelper<Types...>::callPtr(entityID, ctype,
632 function, userData);
633 }
634 };
635
636 public:
676 template <typename Signature, typename Function>
677 void forMatchingSignature(Function&& function, void* userData = nullptr,
678 const bool useThreadPool = false) {
679 std::size_t current_id;
680 {
681 // push to idStack "call stack"
682 std::lock_guard<std::mutex> lock(idStackMutex);
683 current_id = idStackCounter++;
684 idStack.push_back(current_id);
685 }
686 deferringDeletions.fetch_add(1);
687 using SignatureComponents =
689 using Helper =
690 EC::Meta::Morph<SignatureComponents, ForMatchingSignatureHelper<> >;
691
692 BitsetType signatureBitset =
693 BitsetType::template generateBitset<Signature>();
694 if (!useThreadPool || !threadPool) {
695 for (std::size_t i = 0; i < currentSize; ++i) {
696 if (!std::get<bool>(entities[i])) {
697 continue;
698 }
699
700 if ((signatureBitset & std::get<BitsetType>(entities[i])) ==
701 signatureBitset) {
702 Helper::call(i, *this, std::forward<Function>(function),
703 userData);
704 }
705 }
706 } else {
707 std::array<TPFnDataStructZero, ThreadCount * 2> fnDataAr;
708
709 std::size_t s = currentSize / (ThreadCount * 2);
710 for (std::size_t i = 0; i < ThreadCount * 2; ++i) {
711 std::size_t begin = s * i;
712 std::size_t end;
713 if (i == ThreadCount * 2 - 1) {
714 end = currentSize;
715 } else {
716 end = s * (i + 1);
717 }
718 if (begin == end) {
719 continue;
720 }
721 fnDataAr[i].range = {begin, end};
722 fnDataAr[i].manager = this;
723 fnDataAr[i].entities = &entities;
724 fnDataAr[i].signature = &signatureBitset;
725 fnDataAr[i].userData = userData;
726 for (std::size_t j = begin; j < end; ++j) {
727 if (!isAlive(j)) {
728 fnDataAr[i].dead.insert(j);
729 }
730 }
731
732 threadPool->queueFn(
733 [&function](void* ud) {
734 auto* data = static_cast<TPFnDataStructZero*>(ud);
735 for (std::size_t i = data->range[0]; i < data->range[1];
736 ++i) {
737 if (data->dead.find(i) != data->dead.end()) {
738 continue;
739 }
740
741 if (((*data->signature) &
742 std::get<BitsetType>(data->entities->at(i))) ==
743 *data->signature) {
744 Helper::call(i, *data->manager,
745 std::forward<Function>(function),
746 data->userData);
747 }
748 }
749 },
750 &fnDataAr[i]);
751 }
752 threadPool->easyStartAndWait();
753 }
754
755 // pop from idStack "call stack"
756 do {
757 {
758 std::lock_guard<std::mutex> lock(idStackMutex);
759 if (idStack.back() == current_id) {
760 idStack.pop_back();
761 break;
762 }
763 }
764 std::this_thread::sleep_for(std::chrono::microseconds(15));
765 } while (true);
766
767 handleDeferredDeletions();
768 }
769
811 template <typename Signature, typename Function>
812 void forMatchingSignaturePtr(Function* function, void* userData = nullptr,
813 const bool useThreadPool = false) {
814 std::size_t current_id;
815 {
816 // push to idStack "call stack"
817 std::lock_guard<std::mutex> lock(idStackMutex);
818 current_id = idStackCounter++;
819 idStack.push_back(current_id);
820 }
821 deferringDeletions.fetch_add(1);
822 using SignatureComponents =
824 using Helper =
825 EC::Meta::Morph<SignatureComponents, ForMatchingSignatureHelper<> >;
826
827 BitsetType signatureBitset =
828 BitsetType::template generateBitset<Signature>();
829 if (!useThreadPool || !threadPool) {
830 for (std::size_t i = 0; i < currentSize; ++i) {
831 if (!std::get<bool>(entities[i])) {
832 continue;
833 }
834
835 if ((signatureBitset & std::get<BitsetType>(entities[i])) ==
836 signatureBitset) {
837 Helper::callPtr(i, *this, function, userData);
838 }
839 }
840 } else {
841 std::array<TPFnDataStructOne<Function>, ThreadCount * 2> fnDataAr;
842
843 std::size_t s = currentSize / (ThreadCount * 2);
844 for (std::size_t i = 0; i < ThreadCount * 2; ++i) {
845 std::size_t begin = s * i;
846 std::size_t end;
847 if (i == ThreadCount * 2 - 1) {
848 end = currentSize;
849 } else {
850 end = s * (i + 1);
851 }
852 if (begin == end) {
853 continue;
854 }
855 fnDataAr[i].range = {begin, end};
856 fnDataAr[i].manager = this;
857 fnDataAr[i].entities = &entities;
858 fnDataAr[i].signature = &signatureBitset;
859 fnDataAr[i].userData = userData;
860 fnDataAr[i].fn = function;
861 for (std::size_t j = begin; j < end; ++j) {
862 if (!isAlive(j)) {
863 fnDataAr[i].dead.insert(j);
864 }
865 }
866 threadPool->queueFn(
867 [](void* ud) {
868 auto* data =
869 static_cast<TPFnDataStructOne<Function>*>(ud);
870 for (std::size_t i = data->range[0]; i < data->range[1];
871 ++i) {
872 if (data->dead.find(i) != data->dead.end()) {
873 continue;
874 }
875
876 if (((*data->signature) &
877 std::get<BitsetType>(data->entities->at(i))) ==
878 *data->signature) {
879 Helper::callPtr(i, *data->manager, data->fn,
880 data->userData);
881 }
882 }
883 },
884 &fnDataAr[i]);
885 }
886 threadPool->easyStartAndWait();
887 }
888
889 // pop from idStack "call stack"
890 do {
891 {
892 std::lock_guard<std::mutex> lock(idStackMutex);
893 if (idStack.back() == current_id) {
894 idStack.pop_back();
895 break;
896 }
897 }
898 std::this_thread::sleep_for(std::chrono::microseconds(15));
899 } while (true);
900
901 handleDeferredDeletions();
902 }
903
904 private:
905 std::map<std::size_t,
906 std::tuple<BitsetType, void*,
907 std::function<void(std::size_t,
908 std::vector<std::size_t>, void*)> > >
909 forMatchingFunctions;
910 std::size_t functionIndex = 0;
911
912 public:
956 template <typename Signature, typename Function>
957 std::size_t addForMatchingFunction(Function&& function,
958 void* userData = nullptr) {
959 deferringDeletions.fetch_add(1);
960 while (forMatchingFunctions.find(functionIndex) !=
961 forMatchingFunctions.end()) {
962 ++functionIndex;
963 }
964
965 using SignatureComponents =
967 using Helper =
968 EC::Meta::Morph<SignatureComponents, ForMatchingSignatureHelper<> >;
969
970 Helper helper;
971 BitsetType signatureBitset =
972 BitsetType::template generateBitset<Signature>();
973
974 forMatchingFunctions.emplace(std::make_pair(
975 functionIndex,
976 std::make_tuple(
977 signatureBitset, userData,
978 [function, helper, this](const bool useThreadPool,
979 std::vector<std::size_t> matching,
980 void* userData) {
981 if (!useThreadPool || !threadPool) {
982 for (auto eid : matching) {
983 if (isAlive(eid)) {
984 helper.callInstancePtr(eid, *this, &function,
985 userData);
986 }
987 }
988 } else {
989 std::array<TPFnDataStructTwo, ThreadCount * 2> fnDataAr;
990
991 std::size_t s = matching.size() / (ThreadCount * 2);
992 for (std::size_t i = 0; i < ThreadCount * 2; ++i) {
993 std::size_t begin = s * i;
994 std::size_t end;
995 if (i == ThreadCount * 2 - 1) {
996 end = matching.size();
997 } else {
998 end = s * (i + 1);
999 }
1000 if (begin == end) {
1001 continue;
1002 }
1003 fnDataAr[i].range = {begin, end};
1004 fnDataAr[i].manager = this;
1005 fnDataAr[i].entities = &entities;
1006 fnDataAr[i].userData = userData;
1007 fnDataAr[i].matching = &matching;
1008 for (std::size_t j = begin; j < end; ++j) {
1009 if (!isAlive(matching.at(j))) {
1010 fnDataAr[i].dead.insert(j);
1011 }
1012 }
1013 threadPool->queueFn(
1014 [&function, helper](void* ud) {
1015 auto* data =
1016 static_cast<TPFnDataStructTwo*>(ud);
1017 for (std::size_t i = data->range[0];
1018 i < data->range[1]; ++i) {
1019 if (data->dead.find(i) ==
1020 data->dead.end()) {
1021 helper.callInstancePtr(
1022 data->matching->at(i),
1023 *data->manager, &function,
1024 data->userData);
1025 }
1026 }
1027 },
1028 &fnDataAr[i]);
1029 }
1030 threadPool->easyStartAndWait();
1031 }
1032 })));
1033
1034 handleDeferredDeletions();
1035 return functionIndex++;
1036 }
1037
1038 private:
1039 std::vector<std::vector<std::size_t> > getMatchingEntities(
1040 std::vector<BitsetType*> bitsets, const bool useThreadPool = false) {
1041 std::vector<std::vector<std::size_t> > matchingV(bitsets.size());
1042
1043 if (!useThreadPool || !threadPool) {
1044 for (std::size_t i = 0; i < currentSize; ++i) {
1045 if (!isAlive(i)) {
1046 continue;
1047 }
1048 for (std::size_t j = 0; j < bitsets.size(); ++j) {
1049 if (((*bitsets[j]) & std::get<BitsetType>(entities[i])) ==
1050 (*bitsets[j])) {
1051 matchingV[j].push_back(i);
1052 }
1053 }
1054 }
1055 } else {
1056 std::array<TPFnDataStructThree, ThreadCount * 2> fnDataAr;
1057
1058 std::size_t s = currentSize / (ThreadCount * 2);
1059 std::mutex mutex;
1060 for (std::size_t i = 0; i < ThreadCount * 2; ++i) {
1061 std::size_t begin = s * i;
1062 std::size_t end;
1063 if (i == ThreadCount * 2 - 1) {
1064 end = currentSize;
1065 } else {
1066 end = s * (i + 1);
1067 }
1068 if (begin == end) {
1069 continue;
1070 }
1071 fnDataAr[i].range = {begin, end};
1072 fnDataAr[i].manager = this;
1073 fnDataAr[i].matchingV = &matchingV;
1074 fnDataAr[i].bitsets = &bitsets;
1075 fnDataAr[i].entities = &entities;
1076 fnDataAr[i].mutex = &mutex;
1077 for (std::size_t j = begin; j < end; ++j) {
1078 if (!isAlive(j)) {
1079 fnDataAr[i].dead.insert(j);
1080 }
1081 }
1082 threadPool->queueFn(
1083 [](void* ud) {
1084 auto* data = static_cast<TPFnDataStructThree*>(ud);
1085 for (std::size_t i = data->range[0]; i < data->range[1];
1086 ++i) {
1087 if (data->dead.find(i) != data->dead.end()) {
1088 continue;
1089 }
1090 for (std::size_t j = 0; j < data->bitsets->size();
1091 ++j) {
1092 if ((*data->bitsets->at(j) &
1093 std::get<BitsetType>(data->entities->at(
1094 i))) == *data->bitsets->at(j)) {
1095 std::lock_guard<std::mutex> lock(
1096 *data->mutex);
1097 data->matchingV->at(j).push_back(i);
1098 }
1099 }
1100 }
1101 },
1102 &fnDataAr[i]);
1103 }
1104 threadPool->easyStartAndWait();
1105 }
1106
1107 return matchingV;
1108 }
1109
1110 public:
1142 void callForMatchingFunctions(const bool useThreadPool = false) {
1143 deferringDeletions.fetch_add(1);
1144 std::vector<BitsetType*> bitsets;
1145 for (auto iter = forMatchingFunctions.begin();
1146 iter != forMatchingFunctions.end(); ++iter) {
1147 bitsets.push_back(&std::get<BitsetType>(iter->second));
1148 }
1149
1150 std::vector<std::vector<std::size_t> > matching =
1151 getMatchingEntities(bitsets, useThreadPool);
1152
1153 std::size_t i = 0;
1154 for (auto iter = forMatchingFunctions.begin();
1155 iter != forMatchingFunctions.end(); ++iter) {
1156 std::get<2>(iter->second)(useThreadPool, matching[i++],
1157 std::get<1>(iter->second));
1158 }
1159
1160 handleDeferredDeletions();
1161 }
1162
1192 bool callForMatchingFunction(std::size_t id,
1193 const bool useThreadPool = false) {
1194 auto iter = forMatchingFunctions.find(id);
1195 if (iter == forMatchingFunctions.end()) {
1196 return false;
1197 }
1198 deferringDeletions.fetch_add(1);
1199 std::vector<std::vector<std::size_t> > matching = getMatchingEntities(
1200 std::vector<BitsetType*>{&std::get<BitsetType>(iter->second)},
1201 useThreadPool);
1202 std::get<2>(iter->second)(useThreadPool, matching[0],
1203 std::get<1>(iter->second));
1204
1205 handleDeferredDeletions();
1206 return true;
1207 }
1208
1232 forMatchingFunctions.clear();
1233 functionIndex = 0;
1234 }
1235
1241 bool removeForMatchingFunction(std::size_t id) {
1242 return forMatchingFunctions.erase(id) == 1;
1243 }
1244
1254 template <typename List>
1255 std::size_t keepSomeMatchingFunctions(List list) {
1256 std::size_t deletedCount = 0;
1257 for (auto iter = forMatchingFunctions.begin();
1258 iter != forMatchingFunctions.end();) {
1259 if (std::find(list.begin(), list.end(), iter->first) ==
1260 list.end()) {
1261 iter = forMatchingFunctions.erase(iter);
1262 ++deletedCount;
1263 } else {
1264 ++iter;
1265 }
1266 }
1267
1268 return deletedCount;
1269 }
1270
1280 std::initializer_list<std::size_t> list) {
1281 return keepSomeMatchingFunctions<decltype(list)>(list);
1282 }
1283
1293 template <typename List>
1294 std::size_t removeSomeMatchingFunctions(List list) {
1295 std::size_t deletedCount = 0;
1296 for (auto listIter = list.begin(); listIter != list.end(); ++listIter) {
1297 deletedCount += forMatchingFunctions.erase(*listIter);
1298 }
1299
1300 return deletedCount;
1301 }
1302
1312 std::initializer_list<std::size_t> list) {
1313 return removeSomeMatchingFunctions<decltype(list)>(list);
1314 }
1315
1321 bool changeForMatchingFunctionContext(std::size_t id, void* userData) {
1322 auto f = forMatchingFunctions.find(id);
1323 if (f != forMatchingFunctions.end()) {
1324 std::get<1>(f->second) = userData;
1325 return true;
1326 }
1327 return false;
1328 }
1329
1378 template <typename SigList, typename FTuple>
1379 void forMatchingSignatures(FTuple fTuple, void* userData = nullptr,
1380 const bool useThreadPool = false) {
1381 std::size_t current_id;
1382 {
1383 // push to idStack "call stack"
1384 std::lock_guard<std::mutex> lock(idStackMutex);
1385 current_id = idStackCounter++;
1386 idStack.push_back(current_id);
1387 }
1388 deferringDeletions.fetch_add(1);
1389 std::vector<std::vector<std::size_t> > multiMatchingEntities(
1390 SigList::size);
1391 BitsetType signatureBitsets[SigList::size];
1392
1393 // generate bitsets for each signature
1394 EC::Meta::forEachWithIndex<SigList>(
1395 [&signatureBitsets](auto signature, const auto index) {
1396 signatureBitsets[index] =
1397 BitsetType::template generateBitset<decltype(signature)>();
1398 });
1399
1400 // find and store entities matching signatures
1401 if (!useThreadPool || !threadPool) {
1402 for (std::size_t eid = 0; eid < currentSize; ++eid) {
1403 if (!isAlive(eid)) {
1404 continue;
1405 }
1406 for (std::size_t i = 0; i < SigList::size; ++i) {
1407 if ((signatureBitsets[i] &
1408 std::get<BitsetType>(entities[eid])) ==
1409 signatureBitsets[i]) {
1410 multiMatchingEntities[i].push_back(eid);
1411 }
1412 }
1413 }
1414 } else {
1415 std::array<TPFnDataStructFour, ThreadCount * 2> fnDataAr;
1416
1417 std::mutex mutex;
1418 std::size_t s = currentSize / (ThreadCount * 2);
1419 for (std::size_t i = 0; i < ThreadCount * 2; ++i) {
1420 std::size_t begin = s * i;
1421 std::size_t end;
1422 if (i == ThreadCount * 2 - 1) {
1423 end = currentSize;
1424 } else {
1425 end = s * (i + 1);
1426 }
1427 if (begin == end) {
1428 continue;
1429 }
1430 fnDataAr[i].range = {begin, end};
1431 fnDataAr[i].manager = this;
1432 fnDataAr[i].multiMatchingEntities = &multiMatchingEntities;
1433 fnDataAr[i].signatures = signatureBitsets;
1434 fnDataAr[i].mutex = &mutex;
1435 for (std::size_t j = begin; j < end; ++j) {
1436 if (!isAlive(j)) {
1437 fnDataAr[i].dead.insert(j);
1438 }
1439 }
1440
1441 threadPool->queueFn(
1442 [](void* ud) {
1443 auto* data = static_cast<TPFnDataStructFour*>(ud);
1444 for (std::size_t i = data->range[0]; i < data->range[1];
1445 ++i) {
1446 if (data->dead.find(i) != data->dead.end()) {
1447 continue;
1448 }
1449 for (std::size_t j = 0; j < SigList::size; ++j) {
1450 if ((data->signatures[j] &
1451 std::get<BitsetType>(
1452 data->manager->entities[i])) ==
1453 data->signatures[j]) {
1454 std::lock_guard<std::mutex> lock(
1455 *data->mutex);
1456 data->multiMatchingEntities->at(j)
1457 .push_back(i);
1458 }
1459 }
1460 }
1461 },
1462 &fnDataAr[i]);
1463 }
1464 threadPool->easyStartAndWait();
1465 }
1466
1467 // call functions on matching entities
1468 EC::Meta::forEachDoubleTuple(
1469 EC::Meta::Morph<SigList, std::tuple<> >{}, fTuple,
1470 [this, &multiMatchingEntities, useThreadPool, &userData](
1471 auto sig, auto func, auto index) {
1472 using SignatureComponents =
1473 typename EC::Meta::Matching<decltype(sig),
1474 ComponentsList>::type;
1475 using Helper = EC::Meta::Morph<SignatureComponents,
1476 ForMatchingSignatureHelper<> >;
1477 if (!useThreadPool || !threadPool) {
1478 for (const auto& id : multiMatchingEntities[index]) {
1479 if (isAlive(id)) {
1480 Helper::call(id, *this, func, userData);
1481 }
1482 }
1483 } else {
1484 std::array<TPFnDataStructFive, ThreadCount * 2> fnDataAr;
1485 std::size_t s =
1486 multiMatchingEntities[index].size() / (ThreadCount * 2);
1487 for (unsigned int i = 0; i < ThreadCount * 2; ++i) {
1488 std::size_t begin = s * i;
1489 std::size_t end;
1490 if (i == ThreadCount * 2 - 1) {
1491 end = multiMatchingEntities[index].size();
1492 } else {
1493 end = s * (i + 1);
1494 }
1495 if (begin == end) {
1496 continue;
1497 }
1498 fnDataAr[i].range = {begin, end};
1499 fnDataAr[i].index = index;
1500 fnDataAr[i].manager = this;
1501 fnDataAr[i].userData = userData;
1502 fnDataAr[i].multiMatchingEntities =
1503 &multiMatchingEntities;
1504 for (std::size_t j = begin; j < end; ++j) {
1505 if (!isAlive(
1506 multiMatchingEntities.at(index).at(j))) {
1507 fnDataAr[i].dead.insert(j);
1508 }
1509 }
1510 threadPool->queueFn(
1511 [&func](void* ud) {
1512 auto* data =
1513 static_cast<TPFnDataStructFive*>(ud);
1514 for (std::size_t i = data->range[0];
1515 i < data->range[1]; ++i) {
1516 if (data->dead.find(i) ==
1517 data->dead.end()) {
1518 Helper::call(data->multiMatchingEntities
1519 ->at(data->index)
1520 .at(i),
1521 *data->manager, func,
1522 data->userData);
1523 }
1524 }
1525 },
1526 &fnDataAr[i]);
1527 }
1528 threadPool->easyStartAndWait();
1529 }
1530 });
1531
1532 // pop from idStack "call stack"
1533 do {
1534 {
1535 std::lock_guard<std::mutex> lock(idStackMutex);
1536 if (idStack.back() == current_id) {
1537 idStack.pop_back();
1538 break;
1539 }
1540 }
1541 std::this_thread::sleep_for(std::chrono::microseconds(15));
1542 } while (true);
1543
1544 handleDeferredDeletions();
1545 }
1546
1598 template <typename SigList, typename FTuple>
1599 void forMatchingSignaturesPtr(FTuple fTuple, void* userData = nullptr,
1600 const bool useThreadPool = false) {
1601 std::size_t current_id;
1602 {
1603 // push to idStack "call stack"
1604 std::lock_guard<std::mutex> lock(idStackMutex);
1605 current_id = idStackCounter++;
1606 idStack.push_back(current_id);
1607 }
1608 deferringDeletions.fetch_add(1);
1609 std::vector<std::vector<std::size_t> > multiMatchingEntities(
1610 SigList::size);
1611 BitsetType signatureBitsets[SigList::size];
1612
1613 // generate bitsets for each signature
1614 EC::Meta::forEachWithIndex<SigList>(
1615 [&signatureBitsets](auto signature, const auto index) {
1616 signatureBitsets[index] =
1617 BitsetType::template generateBitset<decltype(signature)>();
1618 });
1619
1620 // find and store entities matching signatures
1621 if (!useThreadPool || !threadPool) {
1622 for (std::size_t eid = 0; eid < currentSize; ++eid) {
1623 if (!isAlive(eid)) {
1624 continue;
1625 }
1626 for (std::size_t i = 0; i < SigList::size; ++i) {
1627 if ((signatureBitsets[i] &
1628 std::get<BitsetType>(entities[eid])) ==
1629 signatureBitsets[i]) {
1630 multiMatchingEntities[i].push_back(eid);
1631 }
1632 }
1633 }
1634 } else {
1635 std::array<TPFnDataStructSix, ThreadCount * 2> fnDataAr;
1636
1637 std::mutex mutex;
1638 std::size_t s = currentSize / (ThreadCount * 2);
1639 for (std::size_t i = 0; i < ThreadCount * 2; ++i) {
1640 std::size_t begin = s * i;
1641 std::size_t end;
1642 if (i == ThreadCount * 2 - 1) {
1643 end = currentSize;
1644 } else {
1645 end = s * (i + 1);
1646 }
1647 if (begin == end) {
1648 continue;
1649 }
1650 fnDataAr[i].range = {begin, end};
1651 fnDataAr[i].manager = this;
1652 fnDataAr[i].multiMatchingEntities = &multiMatchingEntities;
1653 fnDataAr[i].bitsets = signatureBitsets;
1654 fnDataAr[i].mutex = &mutex;
1655 for (std::size_t j = begin; j < end; ++j) {
1656 if (!isAlive(j)) {
1657 fnDataAr[i].dead.insert(j);
1658 }
1659 }
1660
1661 threadPool->queueFn(
1662 [](void* ud) {
1663 auto* data = static_cast<TPFnDataStructSix*>(ud);
1664 for (std::size_t i = data->range[0]; i < data->range[1];
1665 ++i) {
1666 if (data->dead.find(i) != data->dead.end()) {
1667 continue;
1668 }
1669 for (std::size_t j = 0; j < SigList::size; ++j) {
1670 if ((data->bitsets[j] &
1671 std::get<BitsetType>(
1672 data->manager->entities[i])) ==
1673 data->bitsets[j]) {
1674 std::lock_guard<std::mutex> lock(
1675 *data->mutex);
1676 data->multiMatchingEntities->at(j)
1677 .push_back(i);
1678 }
1679 }
1680 }
1681 },
1682 &fnDataAr[i]);
1683 }
1684 threadPool->easyStartAndWait();
1685 }
1686
1687 // call functions on matching entities
1688 EC::Meta::forEachDoubleTuple(
1689 EC::Meta::Morph<SigList, std::tuple<> >{}, fTuple,
1690 [this, &multiMatchingEntities, useThreadPool, &userData](
1691 auto sig, auto func, auto index) {
1692 using SignatureComponents =
1693 typename EC::Meta::Matching<decltype(sig),
1694 ComponentsList>::type;
1695 using Helper = EC::Meta::Morph<SignatureComponents,
1696 ForMatchingSignatureHelper<> >;
1697 if (!useThreadPool || !threadPool) {
1698 for (const auto& id : multiMatchingEntities[index]) {
1699 if (isAlive(id)) {
1700 Helper::callPtr(id, *this, func, userData);
1701 }
1702 }
1703 } else {
1704 std::array<TPFnDataStructFive, ThreadCount * 2> fnDataAr;
1705 std::size_t s =
1706 multiMatchingEntities[index].size() / (ThreadCount * 2);
1707 for (unsigned int i = 0; i < ThreadCount * 2; ++i) {
1708 std::size_t begin = s * i;
1709 std::size_t end;
1710 if (i == ThreadCount * 2 - 1) {
1711 end = multiMatchingEntities[index].size();
1712 } else {
1713 end = s * (i + 1);
1714 }
1715 if (begin == end) {
1716 continue;
1717 }
1718 fnDataAr[i].range = {begin, end};
1719 fnDataAr[i].index = index;
1720 fnDataAr[i].manager = this;
1721 fnDataAr[i].userData = userData;
1722 fnDataAr[i].multiMatchingEntities =
1723 &multiMatchingEntities;
1724 for (std::size_t j = begin; j < end; ++j) {
1725 if (!isAlive(
1726 multiMatchingEntities.at(index).at(j))) {
1727 fnDataAr[i].dead.insert(j);
1728 }
1729 }
1730 threadPool->queueFn(
1731 [&func](void* ud) {
1732 auto* data =
1733 static_cast<TPFnDataStructFive*>(ud);
1734 for (std::size_t i = data->range[0];
1735 i < data->range[1]; ++i) {
1736 if (data->dead.find(i) ==
1737 data->dead.end()) {
1738 Helper::callPtr(
1739 data->multiMatchingEntities
1740 ->at(data->index)
1741 .at(i),
1742 *data->manager, func,
1743 data->userData);
1744 }
1745 }
1746 },
1747 &fnDataAr[i]);
1748 }
1749 threadPool->easyStartAndWait();
1750 }
1751 });
1752
1753 // pop from idStack "call stack"
1754 do {
1755 {
1756 std::lock_guard<std::mutex> lock(idStackMutex);
1757 if (idStack.back() == current_id) {
1758 idStack.pop_back();
1759 break;
1760 }
1761 }
1762 std::this_thread::sleep_for(std::chrono::microseconds(15));
1763 } while (true);
1764
1765 handleDeferredDeletions();
1766 }
1767
1768 typedef void ForMatchingFn(std::size_t, Manager<ComponentsList, TagsList>*,
1769 void*);
1770
1788 template <typename Signature>
1789 void forMatchingSimple(ForMatchingFn fn, void* userData = nullptr,
1790 const bool useThreadPool = false) {
1791 std::size_t current_id;
1792 {
1793 // push to idStack "call stack"
1794 std::lock_guard<std::mutex> lock(idStackMutex);
1795 current_id = idStackCounter++;
1796 idStack.push_back(current_id);
1797 }
1798 deferringDeletions.fetch_add(1);
1799 const BitsetType signatureBitset =
1800 BitsetType::template generateBitset<Signature>();
1801 if (!useThreadPool || !threadPool) {
1802 for (std::size_t i = 0; i < currentSize; ++i) {
1803 if (!std::get<bool>(entities[i])) {
1804 continue;
1805 } else if ((signatureBitset &
1806 std::get<BitsetType>(entities[i])) ==
1807 signatureBitset) {
1808 fn(i, this, userData);
1809 }
1810 }
1811 } else {
1812 std::array<TPFnDataStructZero, ThreadCount * 2> fnDataAr;
1813
1814 std::size_t s = currentSize / (ThreadCount * 2);
1815 for (std::size_t i = 0; i < ThreadCount * 2; ++i) {
1816 std::size_t begin = s * i;
1817 std::size_t end;
1818 if (i == ThreadCount * 2 - 1) {
1819 end = currentSize;
1820 } else {
1821 end = s * (i + 1);
1822 }
1823 if (begin == end) {
1824 continue;
1825 }
1826 fnDataAr[i].range = {begin, end};
1827 fnDataAr[i].manager = this;
1828 fnDataAr[i].entities = &entities;
1829 fnDataAr[i].signature = &signatureBitset;
1830 fnDataAr[i].userData = userData;
1831 for (std::size_t j = begin; j < end; ++j) {
1832 if (!isAlive(j)) {
1833 fnDataAr[i].dead.insert(j);
1834 }
1835 }
1836 threadPool->queueFn(
1837 [&fn](void* ud) {
1838 auto* data = static_cast<TPFnDataStructZero*>(ud);
1839 for (std::size_t i = data->range[0]; i < data->range[1];
1840 ++i) {
1841 if (data->dead.find(i) != data->dead.end()) {
1842 continue;
1843 } else if ((*data->signature &
1844 std::get<BitsetType>(data->entities->at(
1845 i))) == *data->signature) {
1846 fn(i, data->manager, data->userData);
1847 }
1848 }
1849 },
1850 &fnDataAr[i]);
1851 }
1852 threadPool->easyStartAndWait();
1853 }
1854
1855 // pop from idStack "call stack"
1856 do {
1857 {
1858 std::lock_guard<std::mutex> lock(idStackMutex);
1859 if (idStack.back() == current_id) {
1860 idStack.pop_back();
1861 break;
1862 }
1863 }
1864 std::this_thread::sleep_for(std::chrono::microseconds(15));
1865 } while (true);
1866
1867 handleDeferredDeletions();
1868 }
1869
1889 template <typename Iterable>
1890 void forMatchingIterable(Iterable iterable, ForMatchingFn fn,
1891 void* userData = nullptr,
1892 const bool useThreadPool = false) {
1893 std::size_t current_id;
1894 {
1895 // push to idStack "call stack"
1896 std::lock_guard<std::mutex> lock(idStackMutex);
1897 current_id = idStackCounter++;
1898 idStack.push_back(current_id);
1899 }
1900
1901 deferringDeletions.fetch_add(1);
1902 if (!useThreadPool || !threadPool) {
1903 bool isValid;
1904 for (std::size_t i = 0; i < currentSize; ++i) {
1905 if (!std::get<bool>(entities[i])) {
1906 continue;
1907 }
1908
1909 isValid = true;
1910 for (const auto& integralValue : iterable) {
1911 if (!std::get<BitsetType>(entities[i])
1912 .getCombinedBit(integralValue)) {
1913 isValid = false;
1914 break;
1915 }
1916 }
1917 if (!isValid) {
1918 continue;
1919 }
1920
1921 fn(i, this, userData);
1922 }
1923 } else {
1924 std::array<TPFnDataStructSeven<Iterable>, ThreadCount * 2> fnDataAr;
1925
1926 std::size_t s = currentSize / (ThreadCount * 2);
1927 for (std::size_t i = 0; i < ThreadCount * 2; ++i) {
1928 std::size_t begin = s * i;
1929 std::size_t end;
1930 if (i == ThreadCount * 2 - 1) {
1931 end = currentSize;
1932 } else {
1933 end = s * (i + 1);
1934 }
1935 if (begin == end) {
1936 continue;
1937 }
1938 fnDataAr[i].range = {begin, end};
1939 fnDataAr[i].manager = this;
1940 fnDataAr[i].entities = &entities;
1941 fnDataAr[i].iterable = &iterable;
1942 fnDataAr[i].userData = userData;
1943 for (std::size_t j = begin; j < end; ++j) {
1944 if (!isAlive(j)) {
1945 fnDataAr[i].dead.insert(j);
1946 }
1947 }
1948 threadPool->queueFn(
1949 [&fn](void* ud) {
1950 auto* data =
1951 static_cast<TPFnDataStructSeven<Iterable>*>(ud);
1952 bool isValid;
1953 for (std::size_t i = data->range[0]; i < data->range[1];
1954 ++i) {
1955 if (data->dead.find(i) != data->dead.end()) {
1956 continue;
1957 }
1958 isValid = true;
1959 for (const auto& integralValue : *data->iterable) {
1960 if (!std::get<BitsetType>(data->entities->at(i))
1961 .getCombinedBit(integralValue)) {
1962 isValid = false;
1963 break;
1964 }
1965 }
1966 if (!isValid) {
1967 continue;
1968 }
1969
1970 fn(i, data->manager, data->userData);
1971 }
1972 },
1973 &fnDataAr[i]);
1974 }
1975 threadPool->easyStartAndWait();
1976 }
1977
1978 // pop from idStack "call stack"
1979 do {
1980 {
1981 std::lock_guard<std::mutex> lock(idStackMutex);
1982 if (idStack.back() == current_id) {
1983 idStack.pop_back();
1984 break;
1985 }
1986 }
1987 std::this_thread::sleep_for(std::chrono::microseconds(15));
1988 } while (true);
1989
1990 handleDeferredDeletions();
1991 }
1992};
1993} // namespace EC
1994
1995#endif
Definition: Bitset.hpp:27
Temporary struct used internally by ThreadPool.
Definition: Manager.hpp:160
Temporary struct used internally by ThreadPool.
Definition: Manager.hpp:151
Temporary struct used internally by ThreadPool.
Definition: Manager.hpp:122
Temporary struct used internally by ThreadPool.
Definition: Manager.hpp:179
Temporary struct used internally by ThreadPool.
Definition: Manager.hpp:169
Temporary struct used internally by ThreadPool.
Definition: Manager.hpp:141
Temporary struct used internally by ThreadPool.
Definition: Manager.hpp:132
Temporary struct used internally by ThreadPool.
Definition: Manager.hpp:112
Manages an EntityComponent system.
Definition: Manager.hpp:70
void forMatchingSignaturesPtr(FTuple fTuple, void *userData=nullptr, const bool useThreadPool=false)
Call multiple functions with mulitple signatures on all living entities.
Definition: Manager.hpp:1599
std::size_t getCurrentSize() const
Returns the current size or number of entities in the system.
Definition: Manager.hpp:322
std::size_t removeSomeMatchingFunctions(std::initializer_list< std::size_t > list)
Removes all functions that do have the index specified in argument "list".
Definition: Manager.hpp:1311
bool hasTag(const std::size_t &index) const
Checks whether or not the given Entity has the given Tag.
Definition: Manager.hpp:468
bool changeForMatchingFunctionContext(std::size_t id, void *userData)
Sets the context pointer of a stored function.
Definition: Manager.hpp:1321
std::size_t addForMatchingFunction(Function &&function, void *userData=nullptr)
Stores a function in the manager to be called later.
Definition: Manager.hpp:957
void addTag(const std::size_t &entityID)
Adds the given Tag to the given Entity.
Definition: Manager.hpp:554
std::size_t keepSomeMatchingFunctions(List list)
Removes all functions that do not have the index specified in argument "list".
Definition: Manager.hpp:1255
void clearForMatchingFunctions()
Remove all stored functions.
Definition: Manager.hpp:1231
std::size_t addEntity()
Adds an entity to the system, returning the ID of the entity.
Definition: Manager.hpp:237
void reset()
Resets the Manager, removing all entities.
Definition: Manager.hpp:590
const Component * getEntityData(const std::size_t &index) const
Returns a const pointer to a component belonging to the given Entity.
Definition: Manager.hpp:410
void callForMatchingFunctions(const bool useThreadPool=false)
Call all stored functions.
Definition: Manager.hpp:1142
void removeComponent(const std::size_t &entityID)
Removes the given Component from the given Entity.
Definition: Manager.hpp:535
void forMatchingIterable(Iterable iterable, ForMatchingFn fn, void *userData=nullptr, const bool useThreadPool=false)
Similar to forMatchingSimple(), but with a collection of Component/Tag indices.
Definition: Manager.hpp:1890
void addComponent(const std::size_t &entityID, Args &&... args)
Adds a component to the given Entity.
Definition: Manager.hpp:503
void forMatchingSimple(ForMatchingFn fn, void *userData=nullptr, const bool useThreadPool=false)
A simple version of forMatchingSignature()
Definition: Manager.hpp:1789
bool hasComponent(const std::size_t &index) const
Checks whether or not the given Entity has the given Component.
Definition: Manager.hpp:454
Component * getEntityData(const std::size_t &index)
Returns a pointer to a component belonging to the given Entity.
Definition: Manager.hpp:362
void removeTag(const std::size_t &entityID)
Removes the given Tag from the given Entity.
Definition: Manager.hpp:574
std::size_t keepSomeMatchingFunctions(std::initializer_list< std::size_t > list)
Removes all functions that do not have the index specified in argument "list".
Definition: Manager.hpp:1279
bool callForMatchingFunction(std::size_t id, const bool useThreadPool=false)
Call a specific stored function.
Definition: Manager.hpp:1192
void forMatchingSignature(Function &&function, void *userData=nullptr, const bool useThreadPool=false)
Calls the given function on all Entities matching the given Signature.
Definition: Manager.hpp:677
void deleteEntity(std::size_t index)
Marks an entity for deletion.
Definition: Manager.hpp:275
Component * getEntityComponent(const std::size_t &index)
Returns a pointer to a component belonging to the given Entity.
Definition: Manager.hpp:392
const Component * getEntityComponent(const std::size_t &index) const
Returns a const pointer to a component belonging to the given Entity.
Definition: Manager.hpp:440
Manager()
Initializes the manager with a default capacity.
Definition: Manager.hpp:195
bool removeForMatchingFunction(std::size_t id)
Removes a function that has the given id.
Definition: Manager.hpp:1241
void forMatchingSignaturePtr(Function *function, void *userData=nullptr, const bool useThreadPool=false)
Calls the given function on all Entities matching the given Signature.
Definition: Manager.hpp:812
const EntitiesTupleType & getEntityInfo(const std::size_t &index) const
Returns a const reference to an Entity's info.
Definition: Manager.hpp:344
std::size_t removeSomeMatchingFunctions(List list)
Removes all functions that do have the index specified in argument "list".
Definition: Manager.hpp:1294
bool hasEntity(const std::size_t &index) const
Checks if the Entity with the given ID is in the system.
Definition: Manager.hpp:302
void forMatchingSignatures(FTuple fTuple, void *userData=nullptr, const bool useThreadPool=false)
Call multiple functions with mulitple signatures on all living entities.
Definition: Manager.hpp:1379
bool isAlive(const std::size_t &index) const
Checks if the Entity is not marked as deleted.
Definition: Manager.hpp:312
Definition: IndexOf.hpp:24
Definition: Matching.hpp:19
Definition: TypeList.hpp:16