summary refs log tree commit diff stats
path: root/src/entity_manager.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/entity_manager.h')
-rw-r--r--src/entity_manager.h279
1 files changed, 279 insertions, 0 deletions
diff --git a/src/entity_manager.h b/src/entity_manager.h new file mode 100644 index 0000000..74e758c --- /dev/null +++ b/src/entity_manager.h
@@ -0,0 +1,279 @@
1#ifndef ENTITY_MANAGER_H_C5832F11
2#define ENTITY_MANAGER_H_C5832F11
3
4#include <map>
5#include <typeindex>
6#include <set>
7#include <cassert>
8#include "component.h"
9
10class EntityManager {
11 private:
12 struct EntityData {
13 int parent = -1;
14 std::map<std::type_index, std::unique_ptr<Component>> components;
15 };
16
17 std::map<int, EntityData> entities;
18 std::map<int, std::set<int>> cachedChildren;
19 std::map<std::set<std::type_index>, std::set<int>> cachedComponents;
20
21 int nextEntityID = 0;
22
23 bool ensureNoParentCycles(int entity, int parent)
24 {
25 EntityData& data = entities[parent];
26 if (data.parent == entity)
27 {
28 return false;
29 } else if (data.parent == -1)
30 {
31 return true;
32 }
33
34 return ensureNoParentCycles(entity, data.parent);
35 }
36
37 std::set<int> getEntitiesWithComponents(std::set<std::type_index>& componentTypes)
38 {
39 if (cachedComponents.count(componentTypes) == 1)
40 {
41 return cachedComponents[componentTypes];
42 }
43
44 std::set<int>& cache = cachedComponents[componentTypes];
45 for (auto& entity : entities)
46 {
47 EntityData& data = entity.second;
48 bool cacheEntity = true;
49
50 for (auto& componentType : componentTypes)
51 {
52 if (data.components.count(componentType) == 0)
53 {
54 cacheEntity = false;
55 break;
56 }
57 }
58
59 if (cacheEntity)
60 {
61 cache.insert(entity.first);
62 }
63 }
64
65 return cache;
66 }
67
68 template <class T, class... R> std::set<int> getEntitiesWithComponents(std::set<std::type_index>& componentTypes)
69 {
70 componentTypes.insert(typeid(T));
71
72 return getEntitiesWithComponents<R...>(componentTypes);
73 }
74
75 public:
76 EntityManager() = default;
77 EntityManager(const EntityManager& copy) = delete;
78
79 int emplaceEntity()
80 {
81 // Find a suitable entity ID
82 while ((entities.count(nextEntityID) == 1) && (nextEntityID >= 0))
83 {
84 nextEntityID++;
85 }
86
87 if (nextEntityID < 0)
88 {
89 nextEntityID = 0;
90
91 while ((entities.count(nextEntityID) == 1) && (nextEntityID >= 0))
92 {
93 nextEntityID++;
94 }
95
96 assert(nextEntityID >= 0);
97 }
98
99 // Initialize the data
100 int id = nextEntityID++;
101 entities[id];
102
103 return id;
104 }
105
106 void deleteEntity(int entity)
107 {
108 assert(entities.count(entity) == 1);
109
110 EntityData& data = entities[entity];
111
112 // Destroy the children
113 std::set<int> children = getChildren(entity);
114 for (int child : children)
115 {
116 EntityData& childData = entities[child];
117 childData.parent = -1;
118
119 deleteEntity(child);
120 }
121
122 // Uncache children
123 cachedChildren.erase(entity);
124
125 if ((data.parent != -1) && (cachedChildren.count(data.parent) == 1))
126 {
127 cachedChildren[data.parent].erase(entity);
128 }
129
130 // Uncache components
131 for (auto& cache : cachedComponents)
132 {
133 cache.second.erase(entity);
134 }
135
136 // Destroy the data
137 entities.erase(entity);
138 }
139
140 std::set<int> getChildren(int parent)
141 {
142 assert(entities.count(parent) == 1);
143
144 if (cachedChildren.count(parent) == 1)
145 {
146 return cachedChildren[parent];
147 }
148
149 std::set<int>& cache = cachedChildren[parent];
150 for (auto& entity : entities)
151 {
152 EntityData& data = entity.second;
153 if (data.parent == parent)
154 {
155 cache.insert(entity.first);
156 }
157 }
158
159 return cache;
160 }
161
162 void setParent(int entity, int parent)
163 {
164 assert(entities.count(entity) == 1);
165 assert(entities.count(parent) == 1);
166 assert(ensureNoParentCycles(entity, parent));
167
168 EntityData& data = entities[entity];
169
170 // Remove from old parent
171 if (data.parent != -1)
172 {
173 if (cachedChildren.count(data.parent) == 1)
174 {
175 cachedChildren[data.parent].erase(entity);
176 }
177 }
178
179 data.parent = parent;
180
181 // Cache new parent
182 if (cachedChildren.count(parent) == 1)
183 {
184 cachedChildren[parent].insert(entity);
185 }
186 }
187
188 void setNoParent(int entity)
189 {
190 assert(entities.count(entity) == 1);
191
192 EntityData& data = entities[entity];
193
194 // Remove from old parent
195 if (data.parent != -1)
196 {
197 if (cachedChildren.count(data.parent) == 1)
198 {
199 cachedChildren[data.parent].erase(entity);
200 }
201 }
202
203 data.parent = -1;
204 }
205
206 int getParent(int entity)
207 {
208 assert(entities.count(entity) == 1);
209
210 EntityData& data = entities[entity];
211 return data.parent;
212 }
213
214 template <class T, class... Args> T& emplaceComponent(int entity, Args&&... args)
215 {
216 assert(entities.count(entity) == 1);
217
218 EntityData& data = entities[entity];
219 std::type_index componentType = typeid(T);
220
221 assert(data.components.count(componentType) == 0);
222
223 // Initialize the component
224 std::unique_ptr<T> ptr = std::unique_ptr<T>(new T(std::forward<Args>(args)...));
225 T& component = *ptr;
226 data.components[componentType] = std::move(ptr);
227
228 // Invalidate related caches
229 std::remove_if(begin(cachedComponents), end(cachedComponents), [&] (std::pair<std::set<std::type_index>, int>& cache) {
230 return cache.first.count(componentType) == 1;
231 });
232
233 return component;
234 }
235
236 template <class T> void removeComponent(int entity)
237 {
238 assert(entities.count(entity) == 1);
239
240 EntityData& data = entities[entity];
241 std::type_index componentType = typeid(T);
242
243 assert(data.components.count(componentType) == 1);
244
245 // Destroy the component
246 data.components.erase(componentType);
247
248 // Uncache the component
249 for (auto& cache : cachedComponents)
250 {
251 if (cache.first.count(componentType) == 1)
252 {
253 cache.second.erase(entity);
254 }
255 }
256 }
257
258 template <class T> T& getComponent(int entity)
259 {
260 assert(entities.count(entity) == 1);
261
262 EntityData& data = entities[entity];
263 std::type_index componentType = typeid(T);
264
265 assert(data.components.count(componentType) == 1);
266
267 return *(data.components[componentType]);
268 }
269
270 template <class T, class... R> std::set<int> getEntitiesWithComponents()
271 {
272 std::set<std::type_index> componentTypes;
273 componentTypes.insert(typeid(T));
274
275 return getEntitiesWithComponents<R...>(componentTypes);
276 }
277};
278
279#endif /* end of include guard: ENTITY_MANAGER_H_C5832F11 */