Gaia-ECS v0.9.3
A simple and powerful entity component system
Loading...
Searching...
No Matches
entity_container.h
1#pragma once
2#include "gaia/config/config.h"
3
4#include <cstdint>
5#include <type_traits>
6
7#include "gaia/cnt/ilist.h"
8#include "gaia/cnt/map.h"
9#include "gaia/cnt/paged_storage.h"
10#include "gaia/ecs/api.h"
11#include "gaia/ecs/id.h"
12
13namespace gaia {
14 namespace ecs {
15 struct EntityContainer;
16 }
17
18 namespace cnt {
19 template <>
20 struct to_page_storage_id<ecs::EntityContainer> {
21 static page_storage_id get(const ecs::EntityContainer& item) noexcept;
22 };
23 } // namespace cnt
24
25 namespace ecs {
26 class Chunk;
27 class Archetype;
28 class World;
29#if GAIA_USE_WEAK_ENTITY
30 struct WeakEntityTracker;
31#endif
32
34 bool isEntity;
35 bool isPair;
36 EntityKind kind;
37 };
38
39 using EntityContainerFlagsType = uint16_t;
40 enum EntityContainerFlags : EntityContainerFlagsType {
41 OnDelete_Remove = 1 << 0,
42 OnDelete_Delete = 1 << 1,
43 OnDelete_Error = 1 << 2,
44 OnDeleteTarget_Remove = 1 << 3,
45 OnDeleteTarget_Delete = 1 << 4,
46 OnDeleteTarget_Error = 1 << 5,
47 HasAcyclic = 1 << 6,
48 HasCantCombine = 1 << 7,
49 IsExclusive = 1 << 8,
50 HasAliasOf = 1 << 9,
51 IsSingleton = 1 << 10,
52 DeleteRequested = 1 << 11,
53 RefDecreased = 1 << 12, // GAIA_USE_SAFE_ENTITY
54 Load = 1 << 13, // EntityContainer is being loaded from a file
55 };
56
60 uint32_t idx;
61
63 // Bits in this section need to be 1:1 with Entity internal data
65
66 struct EntityData {
68 uint32_t gen : 28;
70 uint32_t ent : 1;
72 uint32_t pair : 1;
74 uint32_t kind : 1;
80 uint32_t dis : 1;
81 };
82
83 union {
84 EntityData data;
85 uint32_t dataRaw;
86 };
87
89
91 uint16_t row;
93 uint16_t flags = 0;
94
95#if GAIA_USE_SAFE_ENTITY
98 uint32_t refCnt = 1;
99#else
101 uint32_t unused = 0;
102#endif
103
104#if GAIA_USE_WEAK_ENTITY
105 WeakEntityTracker* pWeakTracker = nullptr;
106#endif
107
112
113 // uint8_t depthDependsOn = 0;
114
115 EntityContainer() = default;
116
117 GAIA_NODISCARD static EntityContainer create(uint32_t index, uint32_t generation, void* pCtx) {
118 auto* ctx = (EntityContainerCtx*)pCtx;
119
120 EntityContainer ec{};
121 ec.idx = index;
122 ec.data.gen = generation;
123 ec.data.ent = (uint32_t)ctx->isEntity;
124 ec.data.pair = (uint32_t)ctx->isPair;
125 ec.data.kind = (uint32_t)ctx->kind;
126 return ec;
127 }
128
129 GAIA_NODISCARD static Entity handle(const EntityContainer& ec) {
130 return Entity(ec.idx, ec.data.gen, (bool)ec.data.ent, (bool)ec.data.pair, (EntityKind)ec.data.kind);
131 }
132
133 void req_del() {
134 flags |= DeleteRequested;
135 }
136 };
137
138#if GAIA_USE_PAGED_ENTITY_CONTAINER
139 struct EntityContainer_paged_ilist_storage: public cnt::page_storage<EntityContainer> {
140 void add_item(EntityContainer&& container) {
141 this->add(GAIA_MOV(container));
142 }
143
144 void del_item([[maybe_unused]] EntityContainer& container) {
145 // TODO: This would also invalidate the ilist item itself. Don't use for now
146 // this->del(container);
147 }
148 };
149#endif
150
154#if GAIA_USE_PAGED_ENTITY_CONTAINER
156#else
158#endif
162
163 EntityContainer& operator[](Entity entity) {
164 return entity.pair() //
165 ? pairs.find(EntityLookupKey(entity))->second
166 : entities[entity.id()];
167 }
168
169 const EntityContainer& operator[](Entity entity) const {
170 return entity.pair() //
171 ? pairs.find(EntityLookupKey(entity))->second
172 : entities[entity.id()];
173 }
174 };
175
176#if GAIA_USE_SAFE_ENTITY
180 class SafeEntity {
181 World* m_w = nullptr;
182 Entity m_entity;
183
184 public:
185 SafeEntity() = default;
186 SafeEntity(World& w, Entity entity): m_w(&w), m_entity(entity) {
187 auto& ec = fetch_mut(w, entity);
188 ++ec.refCnt;
189 }
190
191 ~SafeEntity() {
192 // EntityContainer can be null only from moved-from SharedEntities.
193 // This is not a common occurrence.
194 if GAIA_UNLIKELY (m_w == nullptr)
195 return;
196
197 auto& ec = fetch_mut(*m_w, m_entity);
198 GAIA_ASSERT(ec.refCnt > 0);
199 --ec.refCnt;
200 if (ec.refCnt == 0)
201 del(*m_w, m_entity);
202 }
203
204 SafeEntity(const SafeEntity& other): m_w(other.m_w), m_entity(other.m_entity) {
205 auto& ec = fetch_mut(*m_w, m_entity);
206 ++ec.refCnt;
207 }
208 SafeEntity& operator=(const SafeEntity& other) {
209 GAIA_ASSERT(core::addressof(other) != this);
210
211 m_w = other.m_w;
212 m_entity = other.m_entity;
213
214 auto& ec = fetch_mut(*m_w, m_entity);
215 ++ec.refCnt;
216 return *this;
217 }
218
219 SafeEntity(SafeEntity&& other) noexcept: m_w(other.m_w), m_entity(other.m_entity) {
220 other.m_w = nullptr;
221 other.m_entity = EntityBad;
222 }
223 SafeEntity& operator=(SafeEntity&& other) noexcept {
224 GAIA_ASSERT(core::addressof(other) != this);
225
226 m_w = other.m_w;
227 m_entity = other.m_entity;
228
229 other.m_w = nullptr;
230 other.m_entity = EntityBad;
231 return *this;
232 }
233
234 template <typename Serializer>
235 void save(Serializer& s) const {
236 s.save(m_entity.val);
237 }
238 template <typename Serializer>
239 void load(Serializer& s) {
240 Identifier id{};
241 s.load(id);
242 m_entity = Entity(id);
243 }
244
245 GAIA_NODISCARD Entity entity() const noexcept {
246 return m_entity;
247 }
248 GAIA_NODISCARD operator Entity() const noexcept {
249 return m_entity;
250 }
251
252 bool operator==(const SafeEntity& other) const noexcept {
253 return m_entity == other.entity();
254 }
255 };
256
257 inline bool operator==(const SafeEntity& e1, Entity e2) noexcept {
258 return e1.entity() == e2;
259 }
260 inline bool operator==(Entity e1, const SafeEntity& e2) noexcept {
261 return e1 == e2.entity();
262 }
263
264 inline bool operator!=(const SafeEntity& e1, Entity e2) noexcept {
265 return e1.entity() != e2;
266 }
267 inline bool operator!=(Entity e1, const SafeEntity& e2) noexcept {
268 return e1 != e2.entity();
269 }
270#endif
271
272#if GAIA_USE_WEAK_ENTITY
273 class WeakEntity;
274
275 struct WeakEntityTracker {
276 WeakEntityTracker* next = nullptr;
277 WeakEntityTracker* prev = nullptr;
278 WeakEntity* pWeakEntity = nullptr;
279 };
280
291 class WeakEntity {
292 friend class World;
293 friend struct WeakEntityTracker;
294
295 World* m_w = nullptr;
296 WeakEntityTracker* m_pTracker = nullptr;
297 Entity m_entity;
298
299 public:
300 WeakEntity() = default;
301 WeakEntity(World& w, Entity entity): m_w(&w), m_pTracker(new WeakEntityTracker()), m_entity(entity) {
302 set_tracker();
303 }
304 ~WeakEntity() {
305 del_tracker();
306 }
307
308 WeakEntity(const WeakEntity& other): m_w(other.m_w), m_entity(other.m_entity) {
309 if (other.m_entity == EntityBad)
310 return;
311
312 m_pTracker = new WeakEntityTracker();
313 m_pTracker->pWeakEntity = this;
314
315 auto& ec = fetch_mut(*other.m_w, other.m_entity);
316 if (ec.pWeakTracker != nullptr) {
317 ec.pWeakTracker->prev = m_pTracker;
318 m_pTracker->next = ec.pWeakTracker;
319 } else
320 ec.pWeakTracker = m_pTracker;
321 }
322 WeakEntity& operator=(const WeakEntity& other) {
323 GAIA_ASSERT(core::addressof(other) != this);
324
325 m_w = other.m_w;
326 m_entity = other.m_entity;
327
328 if (other.m_entity != EntityBad) {
329 m_pTracker = new WeakEntityTracker();
330 m_pTracker->pWeakEntity = this;
331
332 auto& ec = fetch_mut(*other.m_w, other.m_entity);
333 if (ec.pWeakTracker != nullptr) {
334 ec.pWeakTracker->prev = m_pTracker;
335 m_pTracker->next = ec.pWeakTracker;
336 } else
337 ec.pWeakTracker = m_pTracker;
338 }
339
340 return *this;
341 }
342
343 WeakEntity(WeakEntity&& other) noexcept: m_w(other.m_w), m_pTracker(other.m_pTracker), m_entity(other.m_entity) {
344 other.m_w = nullptr;
345 other.m_pTracker->pWeakEntity = this;
346 other.m_pTracker = nullptr;
347 other.m_entity = EntityBad;
348 }
349 WeakEntity& operator=(WeakEntity&& other) noexcept {
350 GAIA_ASSERT(core::addressof(other) != this);
351
352 m_w = other.m_w;
353 m_pTracker = other.m_pTracker;
354 m_entity = other.m_entity;
355
356 other.m_w = nullptr;
357 other.m_pTracker->pWeakEntity = this;
358 other.m_pTracker = nullptr;
359 other.m_entity = EntityBad;
360 return *this;
361 }
362
363 void set_tracker() {
364 GAIA_ASSERT(m_pTracker != nullptr);
365 m_pTracker->pWeakEntity = this;
366
367 auto& ec = fetch_mut(*m_w, m_entity);
368 if (ec.pWeakTracker != nullptr) {
369 ec.pWeakTracker->prev = m_pTracker;
370 m_pTracker->next = ec.pWeakTracker;
371 } else
372 ec.pWeakTracker = m_pTracker;
373 }
374
375 void del_tracker() {
376 if (m_pTracker == nullptr)
377 return;
378
379 if (m_pTracker->next != nullptr)
380 m_pTracker->next->prev = m_pTracker->prev;
381 if (m_pTracker->prev != nullptr)
382 m_pTracker->prev->next = m_pTracker->next;
383
384 auto& ec = fetch_mut(*m_w, m_entity);
385 if (ec.pWeakTracker == m_pTracker)
386 ec.pWeakTracker = nullptr;
387
388 delete m_pTracker;
389 m_pTracker = nullptr;
390 }
391
392 template <typename Serializer>
393 void save(Serializer& s) const {
394 s.save(m_entity.val);
395 }
396 template <typename Serializer>
397 void load(Serializer& s) {
398 del_tracker();
399 Identifier id{};
400 s.load(id);
401 m_entity = Entity(id);
402 set_tracker();
403 }
404
405 GAIA_NODISCARD Entity entity() const noexcept {
406 return m_entity;
407 }
408 GAIA_NODISCARD operator Entity() const noexcept {
409 return entity();
410 }
411
412 bool operator==(const WeakEntity& other) const noexcept {
413 return m_entity == other.entity();
414 }
415 };
416
417 inline bool operator==(const WeakEntity& e1, Entity e2) noexcept {
418 return e1.entity() == e2;
419 }
420 inline bool operator==(Entity e1, const WeakEntity& e2) noexcept {
421 return e1 == e2.entity();
422 }
423
424 inline bool operator!=(const WeakEntity& e1, Entity e2) noexcept {
425 return e1.entity() != e2;
426 }
427 inline bool operator!=(Entity e1, const WeakEntity& e2) noexcept {
428 return e1 != e2.entity();
429 }
430#endif
431 } // namespace ecs
432
433 namespace cnt {
434 inline page_storage_id to_page_storage_id<ecs::EntityContainer>::get(const ecs::EntityContainer& item) noexcept {
435 return item.idx;
436 }
437 } // namespace cnt
438} // namespace gaia
Definition archetype.h:82
Definition chunk.h:29
Definition robin_hood.h:720
Checks if endianess was detected correctly at compile-time.
Definition bitset.h:9
Definition ilist.h:12
Implicit list. Rather than with pointers, items.
Definition ilist.h:76
Definition paged_storage.h:37
Definition entity_container.h:33
Definition entity_container.h:66
uint32_t ent
0-component, 1-entity
Definition entity_container.h:70
uint32_t gen
Generation ID of the record.
Definition entity_container.h:68
uint32_t kind
Component kind.
Definition entity_container.h:74
uint32_t dis
Disabled Entity does not use this bit (always zero) so we steal it for special purposes....
Definition entity_container.h:80
uint32_t pair
0-ordinary, 1-pair
Definition entity_container.h:72
Definition entity_container.h:57
uint32_t unused
Currently unused area.
Definition entity_container.h:101
uint16_t row
Row at which the entity is stored in the chunk.
Definition entity_container.h:91
uint16_t flags
Flags.
Definition entity_container.h:93
uint32_t idx
Allocated items: Index in the list. Deleted items: Index of the next deleted item in the list.
Definition entity_container.h:60
Archetype * pArchetype
Archetype (stable address)
Definition entity_container.h:109
Chunk * pChunk
Chunk the entity currently resides in (stable address)
Definition entity_container.h:111
Definition entity_container.h:151
cnt::ilist< EntityContainer, Entity > entities
Implicit list of entities. Used for look-ups only when searching for entities in chunks + data valida...
Definition entity_container.h:157
cnt::map< EntityLookupKey, EntityContainer > pairs
Just like m_recs.entities, but stores pairs. Needs to be a map because pair ids are huge numbers.
Definition entity_container.h:161
Hashmap lookup structure used for Entity.
Definition id.h:336
Definition id.h:225