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.h235
1 files changed, 140 insertions, 95 deletions
diff --git a/src/entity_manager.h b/src/entity_manager.h index a36d720..9068fe3 100644 --- a/src/entity_manager.h +++ b/src/entity_manager.h
@@ -2,151 +2,196 @@
2#define ENTITY_MANAGER_H_C5832F11 2#define ENTITY_MANAGER_H_C5832F11
3 3
4#include <map> 4#include <map>
5#include <vector>
5#include <typeindex> 6#include <typeindex>
6#include <set> 7#include <set>
7#include <cassert> 8#include <stdexcept>
8#include "component.h" 9#include "component.h"
9#include "algorithms.h" 10#include "algorithms.h"
10 11
11class EntityManager { 12class EntityManager {
12 private: 13private:
13 struct EntityData {
14 std::map<std::type_index, std::unique_ptr<Component>> components;
15 };
16 14
17 std::map<int, EntityData> entities; 15 struct EntityData {
18 std::map<std::set<std::type_index>, std::set<int>> cachedComponents; 16 std::map<std::type_index, std::unique_ptr<Component>> components;
17 };
19 18
20 int nextEntityID = 0; 19 using database_type = std::vector<EntityData>;
21 20
22 template <class T, class... R> 21public:
23 std::set<int> getEntitiesWithComponentsHelper(std::set<std::type_index>& componentTypes)
24 {
25 componentTypes.insert(typeid(T));
26 22
27 return getEntitiesWithComponents<R...>(componentTypes); 23 using id_type = database_type::size_type;
28 }
29 24
30 template <class... R> 25private:
31 std::set<int> getEntitiesWithComponents(std::set<std::type_index>& componentTypes)
32 {
33 return getEntitiesWithComponentsHelper<R...>(componentTypes);
34 }
35 26
36 public: 27 database_type entities;
37 EntityManager() = default; 28 std::vector<bool> slotAvailable;
38 EntityManager(const EntityManager& copy) = delete; 29 std::map<std::set<std::type_index>, std::set<id_type>> cachedComponents;
39 30
40 int emplaceEntity() 31 id_type nextEntityID = 0;
41 {
42 // Find a suitable entity ID
43 while ((entities.count(nextEntityID) == 1) && (nextEntityID >= 0))
44 {
45 nextEntityID++;
46 }
47 32
48 if (nextEntityID < 0) 33 template <class T, class... R>
49 { 34 std::set<id_type> getEntitiesWithComponentsHelper(
50 nextEntityID = 0; 35 std::set<std::type_index>& componentTypes)
36 {
37 componentTypes.insert(typeid(T));
51 38
52 while ((entities.count(nextEntityID) == 1) && (nextEntityID >= 0)) 39 return getEntitiesWithComponents<R...>(componentTypes);
53 { 40 }
54 nextEntityID++;
55 }
56 41
57 assert(nextEntityID >= 0); 42 template <class... R>
58 } 43 std::set<id_type> getEntitiesWithComponents(
44 std::set<std::type_index>& componentTypes)
45 {
46 return getEntitiesWithComponentsHelper<R...>(componentTypes);
47 }
59 48
60 // Initialize the data 49public:
61 int id = nextEntityID++;
62 entities[id];
63 50
64 return id; 51 EntityManager() = default;
65 }
66 52
67 void deleteEntity(int entity) 53 EntityManager(const EntityManager& copy) = delete;
68 {
69 assert(entities.count(entity) == 1);
70 54
71 // Uncache components 55 id_type emplaceEntity()
72 for (auto& cache : cachedComponents) 56 {
57 if (nextEntityID >= entities.size())
58 {
59 // If the database is saturated, add a new element for the new entity.
60 entities.emplace_back();
61 slotAvailable.push_back(false);
62
63 return nextEntityID++;
64 } else {
65 // If there is an available slot in the database, use it.
66 id_type id = nextEntityID++;
67 slotAvailable[id] = false;
68
69 // Fast forward the next available slot pointer to an available slot.
70 while ((nextEntityID < entities.size()) && !slotAvailable[nextEntityID])
73 { 71 {
74 cache.second.erase(entity); 72 nextEntityID++;
75 } 73 }
76 74
77 // Destroy the data 75 return id;
78 entities.erase(entity); 76 }
77 }
78
79 void deleteEntity(id_type entity)
80 {
81 if ((entity >= entities.size()) || slotAvailable[entity])
82 {
83 throw std::invalid_argument("Cannot delete non-existent entity");
79 } 84 }
80 85
81 template <class T, class... Args> 86 // Uncache components
82 T& emplaceComponent(int entity, Args&&... args) 87 for (auto& cache : cachedComponents)
83 { 88 {
84 assert(entities.count(entity) == 1); 89 cache.second.erase(entity);
90 }
91
92 // Destroy the data
93 entities[entity].components.clear();
85 94
86 EntityData& data = entities[entity]; 95 // Mark the slot as available
87 std::type_index componentType = typeid(T); 96 slotAvailable[entity] = true;
88 97
89 assert(data.components.count(componentType) == 0); 98 if (entity < nextEntityID)
99 {
100 nextEntityID = entity;
101 }
102 }
90 103
91 // Initialize the component 104 template <class T, class... Args>
92 std::unique_ptr<T> ptr = std::unique_ptr<T>(new T(std::forward<Args>(args)...)); 105 T& emplaceComponent(id_type entity, Args&&... args)
93 T& component = *ptr; 106 {
94 data.components[componentType] = std::move(ptr); 107 if ((entity >= entities.size()) || slotAvailable[entity])
108 {
109 throw std::invalid_argument("Cannot delete non-existent entity");
110 }
95 111
96 // Invalidate related caches 112 EntityData& data = entities[entity];
97 erase_if(cachedComponents, [&componentType] (std::pair<const std::set<std::type_index>, std::set<int>>& cache) { 113 std::type_index componentType = typeid(T);
98 return cache.first.count(componentType) == 1;
99 });
100 114
101 return component; 115 if (data.components.count(componentType))
116 {
117 throw std::invalid_argument("Cannot emplace already-existent component");
102 } 118 }
103 119
104 template <class T> 120 // Initialize the component
105 void removeComponent(int entity) 121 std::unique_ptr<T> ptr(new T(std::forward<Args>(args)...));
122 T& component = *ptr;
123 data.components[componentType] = std::move(ptr);
124
125 // Invalidate related caches
126 erase_if(
127 cachedComponents,
128 [&componentType] (
129 std::pair<const std::set<std::type_index>, std::set<id_type>>& cache) {
130 return cache.first.count(componentType) == 1;
131 });
132
133 return component;
134 }
135
136 template <class T>
137 void removeComponent(id_type entity)
138 {
139 if ((entity >= entities.size()) || slotAvailable[entity])
106 { 140 {
107 assert(entities.count(entity) == 1); 141 throw std::invalid_argument("Cannot delete non-existent entity");
142 }
108 143
109 EntityData& data = entities[entity]; 144 EntityData& data = entities[entity];
110 std::type_index componentType = typeid(T); 145 std::type_index componentType = typeid(T);
111 146
112 assert(data.components.count(componentType) == 1); 147 if (!data.components.count(componentType))
148 {
149 throw std::invalid_argument("Cannot delete non-existent component");
150 }
113 151
114 // Destroy the component 152 // Destroy the component
115 data.components.erase(componentType); 153 data.components.erase(componentType);
116 154
117 // Uncache the component 155 // Uncache the component
118 for (auto& cache : cachedComponents) 156 for (auto& cache : cachedComponents)
157 {
158 if (cache.first.count(componentType) == 1)
119 { 159 {
120 if (cache.first.count(componentType) == 1) 160 cache.second.erase(entity);
121 {
122 cache.second.erase(entity);
123 }
124 } 161 }
125 } 162 }
163 }
126 164
127 template <class T> 165 template <class T>
128 T& getComponent(int entity) 166 T& getComponent(id_type entity)
167 {
168 if ((entity >= entities.size()) || slotAvailable[entity])
129 { 169 {
130 assert(entities.count(entity) == 1); 170 throw std::invalid_argument("Cannot delete non-existent entity");
131 171 }
132 EntityData& data = entities[entity];
133 std::type_index componentType = typeid(T);
134 172
135 assert(data.components.count(componentType) == 1); 173 EntityData& data = entities[entity];
174 std::type_index componentType = typeid(T);
136 175
137 return *((T*)data.components[componentType].get()); 176 if (!data.components.count(componentType))
177 {
178 throw std::invalid_argument("Cannot get non-existent component");
138 } 179 }
139 180
140 template <class... R> 181 return *dynamic_cast<T*>(data.components[componentType].get());
141 std::set<int> getEntitiesWithComponents() 182 }
142 {
143 std::set<std::type_index> componentTypes;
144 183
145 return getEntitiesWithComponentsHelper<R...>(componentTypes); 184 template <class... R>
146 } 185 std::set<id_type> getEntitiesWithComponents()
186 {
187 std::set<std::type_index> componentTypes;
188
189 return getEntitiesWithComponentsHelper<R...>(componentTypes);
190 }
147}; 191};
148 192
149template <> 193template <>
150std::set<int> EntityManager::getEntitiesWithComponents<>(std::set<std::type_index>& componentTypes); 194std::set<EntityManager::id_type> EntityManager::getEntitiesWithComponents<>(
195 std::set<std::type_index>& componentTypes);
151 196
152#endif /* end of include guard: ENTITY_MANAGER_H_C5832F11 */ 197#endif /* end of include guard: ENTITY_MANAGER_H_C5832F11 */