2#include "gaia/config/config.h"
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#include "gaia/mem/smallblock_allocator.h"
17 struct EntityContainer;
22 struct to_page_storage_id<ecs::EntityContainer> {
23 static page_storage_id
get(
const ecs::EntityContainer& item)
noexcept;
31#if GAIA_USE_WEAK_ENTITY
32 struct WeakEntityTracker;
35 struct EntityContainerCtx {
40 using EntityContainerFlagsType = uint16_t;
41 enum EntityContainerFlags : EntityContainerFlagsType {
42 OnDelete_Remove = 1 << 0,
43 OnDelete_Delete = 1 << 1,
44 OnDelete_Error = 1 << 2,
45 OnDeleteTarget_Remove = 1 << 3,
46 OnDeleteTarget_Delete = 1 << 4,
47 OnDeleteTarget_Error = 1 << 5,
49 HasCantCombine = 1 << 7,
52 IsSingleton = 1 << 10,
53 DeleteRequested = 1 << 11,
54 RefDecreased = 1 << 12,
57 IsDontFragment = 1 << 15,
60 struct EntityContainer {
77 uint32_t reserved : 1;
98#if GAIA_USE_SAFE_ENTITY
107#if GAIA_USE_WEAK_ENTITY
108 WeakEntityTracker* pWeakTracker =
nullptr;
112 Archetype* pArchetype =
nullptr;
114 Chunk* pChunk =
nullptr;
116 const Entity* pEntity =
nullptr;
119 EntityContainer() =
default;
121 GAIA_NODISCARD
static EntityContainer create(uint32_t index, uint32_t generation,
void* pCtx) {
122 auto* ctx = (EntityContainerCtx*)pCtx;
124 EntityContainer ec{};
126 ec.data.gen = generation;
127 ec.data.ent = (uint32_t)ctx->isEntity;
128 ec.data.pair = (uint32_t)ctx->isPair;
132 GAIA_NODISCARD
static Entity handle(
const EntityContainer& ec) {
133 return Entity(ec.idx, ec.data.gen, (
bool)ec.data.ent, (
bool)ec.data.pair);
137 flags |= DeleteRequested;
144 cnt::map<EntityLookupKey, EntityContainer> m_records;
155 GAIA_NODISCARD
bool contains(Entity entity)
const {
156 GAIA_ASSERT(entity.pair());
157 return m_records.contains(EntityLookupKey(entity));
163 GAIA_NODISCARD EntityContainer* find(Entity entity) {
164 GAIA_ASSERT(entity.pair());
166 const auto it = m_records.find(EntityLookupKey(entity));
167 if (it == m_records.end())
176 GAIA_NODISCARD
const EntityContainer* find(Entity entity)
const {
177 GAIA_ASSERT(entity.pair());
179 const auto it = m_records.find(EntityLookupKey(entity));
180 if (it == m_records.end())
189 void add(Entity entity, EntityContainer&& ec) {
190 GAIA_ASSERT(entity.pair());
191 m_records.emplace(EntityLookupKey(entity), GAIA_MOV(ec));
198 GAIA_NODISCARD
bool try_add(Entity entity, EntityContainer&& ec) {
199 GAIA_ASSERT(entity.pair());
201 if (contains(entity))
204 add(entity, GAIA_MOV(ec));
210 void remove(Entity entity) {
211 GAIA_ASSERT(entity.pair());
212 m_records.erase(EntityLookupKey(entity));
219 GAIA_NODISCARD
bool remove(Entity entity, EntityContainer& ec) {
220 GAIA_ASSERT(entity.pair());
222 const auto it = m_records.find(EntityLookupKey(entity));
223 if (it == m_records.end())
226 ec = GAIA_MOV(it->second);
233 GAIA_NODISCARD
auto begin() {
234 return m_records.begin();
239 GAIA_NODISCARD
auto begin()
const {
240 return m_records.begin();
245 GAIA_NODISCARD
auto end() {
246 return m_records.end();
251 GAIA_NODISCARD
auto end()
const {
252 return m_records.end();
256 struct EntityContainers {
259 PairRecords m_pairRecords;
264 cnt::paged_ilist<EntityContainer, Entity> entities;
267 void pair_records_clear() {
268 m_pairRecords.clear();
274 GAIA_NODISCARD
bool pair_record_contains(Entity entity)
const {
275 return m_pairRecords.contains(entity);
281 GAIA_NODISCARD EntityContainer* pair_record_find(Entity entity) {
282 return m_pairRecords.find(entity);
288 GAIA_NODISCARD
const EntityContainer* pair_record_find(Entity entity)
const {
289 return m_pairRecords.find(entity);
295 void pair_record_add(Entity entity, EntityContainer&& ec) {
296 m_pairRecords.add(entity, GAIA_MOV(ec));
303 GAIA_NODISCARD
bool pair_record_try_add(Entity entity, EntityContainer&& ec) {
304 return m_pairRecords.try_add(entity, GAIA_MOV(ec));
309 void pair_record_remove(Entity entity) {
310 m_pairRecords.remove(entity);
317 GAIA_NODISCARD
bool pair_record_remove(Entity entity, EntityContainer& ec) {
318 return m_pairRecords.remove(entity, ec);
323 GAIA_NODISCARD
auto pair_record_begin() {
324 return m_pairRecords.begin();
329 GAIA_NODISCARD
auto pair_record_begin()
const {
330 return m_pairRecords.begin();
335 GAIA_NODISCARD
auto pair_record_end() {
336 return m_pairRecords.end();
341 GAIA_NODISCARD
auto pair_record_end()
const {
342 return m_pairRecords.end();
345 EntityContainer& operator[](Entity entity) {
347 return entities[entity.id()];
349 auto* pPair = m_pairRecords.find(entity);
350 GAIA_ASSERT(pPair !=
nullptr);
354 const EntityContainer& operator[](Entity entity)
const {
356 return entities[entity.id()];
358 const auto* pPair = m_pairRecords.find(entity);
359 GAIA_ASSERT(pPair !=
nullptr);
368 struct ilist_handle_traits<ecs::Entity> {
369 static ecs::Entity
make(uint32_t
id, uint32_t gen,
const ecs::Entity& prev) {
370 return ecs::Entity((ecs::EntityId)
id, gen, prev.entity(), prev.pair());
377#if GAIA_USE_SAFE_ENTITY
382 World* m_w =
nullptr;
386 SafeEntity() =
default;
387 SafeEntity(World& w, Entity entity): m_w(&w), m_entity(entity) {
395 SafeEntity(
const SafeEntity& other): m_w(other.m_w), m_entity(other.m_entity) {
398 SafeEntity& operator=(
const SafeEntity& other) {
399 GAIA_ASSERT(core::addressof(other) !=
this);
403 m_entity = other.m_entity;
408 SafeEntity(SafeEntity&& other)
noexcept: m_w(other.m_w), m_entity(other.m_entity) {
410 other.m_entity = EntityBad;
412 SafeEntity& operator=(SafeEntity&& other)
noexcept {
413 GAIA_ASSERT(core::addressof(other) !=
this);
417 m_entity = other.m_entity;
420 other.m_entity = EntityBad;
427 if GAIA_UNLIKELY (m_w ==
nullptr)
430 safe_entity_acquire(*m_w, m_entity);
436 if GAIA_UNLIKELY (m_w ==
nullptr)
441 safe_entity_release(*m_w, m_entity);
445 template <typename Serializer>
446 void save(Serializer& s)
const {
449 template <
typename Serializer>
450 void load(Serializer& s) {
454 GAIA_NODISCARD Entity entity() const noexcept {
457 GAIA_NODISCARD
operator Entity() const noexcept {
461 bool operator==(
const SafeEntity& other)
const noexcept {
462 return m_entity == other.entity();
466 inline bool operator==(
const SafeEntity& e1, Entity e2)
noexcept {
467 return e1.entity() == e2;
469 inline bool operator==(Entity e1,
const SafeEntity& e2)
noexcept {
470 return e1 == e2.entity();
473 inline bool operator!=(
const SafeEntity& e1, Entity e2)
noexcept {
474 return e1.entity() != e2;
476 inline bool operator!=(Entity e1,
const SafeEntity& e2)
noexcept {
477 return e1 != e2.entity();
481#if GAIA_USE_WEAK_ENTITY
484 struct WeakEntityTracker {
485 GAIA_USE_SMALLBLOCK(WeakEntityTracker)
487 WeakEntityTracker* next =
nullptr;
488 WeakEntityTracker* prev =
nullptr;
489 WeakEntity* pWeakEntity =
nullptr;
504 friend struct WeakEntityTracker;
506 World* m_w =
nullptr;
507 WeakEntityTracker* m_pTracker =
nullptr;
511 WeakEntity() =
default;
512 WeakEntity(World& w, Entity entity): m_w(&w), m_pTracker(new WeakEntityTracker()), m_entity(entity) {
519 WeakEntity(
const WeakEntity& other): m_w(other.m_w), m_entity(other.m_entity) {
520 if (other.m_pTracker ==
nullptr)
523 m_pTracker =
new WeakEntityTracker();
526 WeakEntity& operator=(
const WeakEntity& other) {
527 GAIA_ASSERT(core::addressof(other) !=
this);
532 m_entity = other.m_entity;
534 if (other.m_pTracker !=
nullptr) {
535 m_pTracker =
new WeakEntityTracker();
542 WeakEntity(WeakEntity&& other)
noexcept: m_w(other.m_w), m_pTracker(other.m_pTracker), m_entity(other.m_entity) {
544 if (other.m_pTracker !=
nullptr)
545 other.m_pTracker->pWeakEntity =
this;
546 other.m_pTracker =
nullptr;
547 other.m_entity = EntityBad;
549 WeakEntity& operator=(WeakEntity&& other)
noexcept {
550 GAIA_ASSERT(core::addressof(other) !=
this);
555 m_pTracker = other.m_pTracker;
556 m_entity = other.m_entity;
559 if (other.m_pTracker !=
nullptr)
560 other.m_pTracker->pWeakEntity =
this;
561 other.m_pTracker =
nullptr;
562 other.m_entity = EntityBad;
567 GAIA_ASSERT(m_pTracker !=
nullptr);
568 GAIA_ASSERT(m_w !=
nullptr);
569 GAIA_ASSERT(m_entity != EntityBad);
571 m_pTracker->pWeakEntity =
this;
572 m_pTracker->prev =
nullptr;
574 auto& ec = fetch_mut(*m_w, m_entity);
575 m_pTracker->next = ec.pWeakTracker;
576 if (ec.pWeakTracker !=
nullptr)
577 ec.pWeakTracker->prev = m_pTracker;
578 ec.pWeakTracker = m_pTracker;
582 if (m_pTracker ==
nullptr)
585 if (m_pTracker->next !=
nullptr)
586 m_pTracker->next->prev = m_pTracker->prev;
587 if (m_pTracker->prev !=
nullptr)
588 m_pTracker->prev->next = m_pTracker->next;
595 if (m_pTracker->prev ==
nullptr && m_w !=
nullptr) {
596 auto* pEc = try_fetch_mut(*m_w, m_entity);
597 if (pEc !=
nullptr && pEc->pWeakTracker == m_pTracker)
598 pEc->pWeakTracker = m_pTracker->next;
602 m_pTracker =
nullptr;
605 template <
typename Serializer>
606 void save(Serializer& s)
const {
607 s.save(m_entity.val);
609 template <
typename Serializer>
610 void load(Serializer& s) {
614 m_entity = Entity(
id);
615 if (m_w !=
nullptr && m_entity != EntityBad) {
616 m_pTracker =
new WeakEntityTracker();
621 GAIA_NODISCARD Entity entity() const noexcept {
624 GAIA_NODISCARD
operator Entity() const noexcept {
628 bool operator==(
const WeakEntity& other)
const noexcept {
629 return m_entity == other.entity();
633 inline bool operator==(
const WeakEntity& e1, Entity e2)
noexcept {
634 return e1.entity() == e2;
636 inline bool operator==(Entity e1,
const WeakEntity& e2)
noexcept {
637 return e1 == e2.entity();
640 inline bool operator!=(
const WeakEntity& e1, Entity e2)
noexcept {
641 return e1.entity() != e2;
643 inline bool operator!=(Entity e1,
const WeakEntity& e2)
noexcept {
644 return e1 != e2.entity();
650 inline page_storage_id to_page_storage_id<ecs::EntityContainer>::get(
const ecs::EntityContainer& item)
noexcept {
void load(Reader &reader, T &data)
Read data using Reader at compile-time.
Definition ser_ct.h:112
void save(Writer &writer, const T &data)
Write data using Writer at compile-time.
Definition ser_ct.h:101
static TItemHandle make(uint32_t id, uint32_t gen, const TItemHandle &prev)
Rebuilds a handle after its generation changes.
Definition ilist.h:497
static page_storage_id get(const T &item) noexcept
Applies the default conversion for an item.
Definition paged_storage.h:47