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 {
41 using EntityContainerFlagsType = uint16_t;
42 enum EntityContainerFlags : EntityContainerFlagsType {
43 OnDelete_Remove = 1 << 0,
44 OnDelete_Delete = 1 << 1,
45 OnDelete_Error = 1 << 2,
46 OnDeleteTarget_Remove = 1 << 3,
47 OnDeleteTarget_Delete = 1 << 4,
48 OnDeleteTarget_Error = 1 << 5,
50 HasCantCombine = 1 << 7,
53 IsSingleton = 1 << 10,
54 DeleteRequested = 1 << 11,
55 RefDecreased = 1 << 12,
58 IsDontFragment = 1 << 15,
61 struct EntityContainer {
99#if GAIA_USE_SAFE_ENTITY
108#if GAIA_USE_WEAK_ENTITY
109 WeakEntityTracker* pWeakTracker =
nullptr;
113 Archetype* pArchetype =
nullptr;
115 Chunk* pChunk =
nullptr;
117 const Entity* pEntity =
nullptr;
120 EntityContainer() =
default;
122 GAIA_NODISCARD
static EntityContainer create(uint32_t index, uint32_t generation,
void* pCtx) {
123 auto* ctx = (EntityContainerCtx*)pCtx;
125 EntityContainer ec{};
127 ec.data.gen = generation;
128 ec.data.ent = (uint32_t)ctx->isEntity;
129 ec.data.pair = (uint32_t)ctx->isPair;
130 ec.data.kind = (uint32_t)ctx->kind;
134 GAIA_NODISCARD
static Entity handle(
const EntityContainer& ec) {
135 return Entity(ec.idx, ec.data.gen, (
bool)ec.data.ent, (
bool)ec.data.pair, (EntityKind)ec.data.kind);
139 flags |= DeleteRequested;
146 cnt::map<EntityLookupKey, EntityContainer> m_records;
157 GAIA_NODISCARD
bool contains(Entity entity)
const {
158 GAIA_ASSERT(entity.pair());
159 return m_records.contains(EntityLookupKey(entity));
165 GAIA_NODISCARD EntityContainer* find(Entity entity) {
166 GAIA_ASSERT(entity.pair());
168 const auto it = m_records.find(EntityLookupKey(entity));
169 if (it == m_records.end())
178 GAIA_NODISCARD
const EntityContainer* find(Entity entity)
const {
179 GAIA_ASSERT(entity.pair());
181 const auto it = m_records.find(EntityLookupKey(entity));
182 if (it == m_records.end())
191 void add(Entity entity, EntityContainer&& ec) {
192 GAIA_ASSERT(entity.pair());
193 m_records.emplace(EntityLookupKey(entity), GAIA_MOV(ec));
200 GAIA_NODISCARD
bool try_add(Entity entity, EntityContainer&& ec) {
201 GAIA_ASSERT(entity.pair());
203 if (contains(entity))
206 add(entity, GAIA_MOV(ec));
212 void remove(Entity entity) {
213 GAIA_ASSERT(entity.pair());
214 m_records.erase(EntityLookupKey(entity));
221 GAIA_NODISCARD
bool remove(Entity entity, EntityContainer& ec) {
222 GAIA_ASSERT(entity.pair());
224 const auto it = m_records.find(EntityLookupKey(entity));
225 if (it == m_records.end())
228 ec = GAIA_MOV(it->second);
235 GAIA_NODISCARD
auto begin() {
236 return m_records.begin();
241 GAIA_NODISCARD
auto begin()
const {
242 return m_records.begin();
247 GAIA_NODISCARD
auto end() {
248 return m_records.end();
253 GAIA_NODISCARD
auto end()
const {
254 return m_records.end();
258 struct EntityContainers {
261 PairRecords m_pairRecords;
266 cnt::paged_ilist<EntityContainer, Entity> entities;
269 void pair_records_clear() {
270 m_pairRecords.clear();
276 GAIA_NODISCARD
bool pair_record_contains(Entity entity)
const {
277 return m_pairRecords.contains(entity);
283 GAIA_NODISCARD EntityContainer* pair_record_find(Entity entity) {
284 return m_pairRecords.find(entity);
290 GAIA_NODISCARD
const EntityContainer* pair_record_find(Entity entity)
const {
291 return m_pairRecords.find(entity);
297 void pair_record_add(Entity entity, EntityContainer&& ec) {
298 m_pairRecords.add(entity, GAIA_MOV(ec));
305 GAIA_NODISCARD
bool pair_record_try_add(Entity entity, EntityContainer&& ec) {
306 return m_pairRecords.try_add(entity, GAIA_MOV(ec));
311 void pair_record_remove(Entity entity) {
312 m_pairRecords.remove(entity);
319 GAIA_NODISCARD
bool pair_record_remove(Entity entity, EntityContainer& ec) {
320 return m_pairRecords.remove(entity, ec);
325 GAIA_NODISCARD
auto pair_record_begin() {
326 return m_pairRecords.begin();
331 GAIA_NODISCARD
auto pair_record_begin()
const {
332 return m_pairRecords.begin();
337 GAIA_NODISCARD
auto pair_record_end() {
338 return m_pairRecords.end();
343 GAIA_NODISCARD
auto pair_record_end()
const {
344 return m_pairRecords.end();
347 EntityContainer& operator[](Entity entity) {
349 return entities[entity.id()];
351 auto* pPair = m_pairRecords.find(entity);
352 GAIA_ASSERT(pPair !=
nullptr);
356 const EntityContainer& operator[](Entity entity)
const {
358 return entities[entity.id()];
360 const auto* pPair = m_pairRecords.find(entity);
361 GAIA_ASSERT(pPair !=
nullptr);
370 struct ilist_handle_traits<ecs::Entity> {
371 static ecs::Entity
make(uint32_t
id, uint32_t gen,
const ecs::Entity& prev) {
372 return ecs::Entity((ecs::EntityId)
id, gen, prev.entity(), prev.pair(), prev.kind());
379#if GAIA_USE_SAFE_ENTITY
384 World* m_w =
nullptr;
388 SafeEntity() =
default;
389 SafeEntity(World& w, Entity entity): m_w(&w), m_entity(entity) {
390 auto& ec = fetch_mut(w, entity);
397 if GAIA_UNLIKELY (m_w ==
nullptr)
400 auto& ec = fetch_mut(*m_w, m_entity);
401 GAIA_ASSERT(ec.refCnt > 0);
407 SafeEntity(const SafeEntity& other): m_w(other.m_w), m_entity(other.m_entity) {
408 auto& ec = fetch_mut(*m_w, m_entity);
411 SafeEntity& operator=(
const SafeEntity& other) {
412 GAIA_ASSERT(core::addressof(other) !=
this);
415 m_entity = other.m_entity;
417 auto& ec = fetch_mut(*m_w, m_entity);
422 SafeEntity(SafeEntity&& other)
noexcept: m_w(other.m_w), m_entity(other.m_entity) {
424 other.m_entity = EntityBad;
426 SafeEntity& operator=(SafeEntity&& other)
noexcept {
427 GAIA_ASSERT(core::addressof(other) !=
this);
430 m_entity = other.m_entity;
433 other.m_entity = EntityBad;
437 template <
typename Serializer>
438 void save(Serializer& s)
const {
441 template <
typename Serializer>
442 void load(Serializer& s) {
446 GAIA_NODISCARD Entity entity() const noexcept {
449 GAIA_NODISCARD
operator Entity() const noexcept {
453 bool operator==(
const SafeEntity& other)
const noexcept {
454 return m_entity == other.entity();
458 inline bool operator==(
const SafeEntity& e1, Entity e2)
noexcept {
459 return e1.entity() == e2;
461 inline bool operator==(Entity e1,
const SafeEntity& e2)
noexcept {
462 return e1 == e2.entity();
465 inline bool operator!=(
const SafeEntity& e1, Entity e2)
noexcept {
466 return e1.entity() != e2;
468 inline bool operator!=(Entity e1,
const SafeEntity& e2)
noexcept {
469 return e1 != e2.entity();
473#if GAIA_USE_WEAK_ENTITY
476 struct WeakEntityTracker {
477 GAIA_USE_SMALLBLOCK(WeakEntityTracker)
479 WeakEntityTracker* next =
nullptr;
480 WeakEntityTracker* prev =
nullptr;
481 WeakEntity* pWeakEntity =
nullptr;
496 friend struct WeakEntityTracker;
498 World* m_w =
nullptr;
499 WeakEntityTracker* m_pTracker =
nullptr;
503 WeakEntity() =
default;
504 WeakEntity(World& w, Entity entity): m_w(&w), m_pTracker(new WeakEntityTracker()), m_entity(entity) {
511 WeakEntity(
const WeakEntity& other): m_w(other.m_w), m_entity(other.m_entity) {
512 if (other.m_pTracker ==
nullptr)
515 m_pTracker =
new WeakEntityTracker();
518 WeakEntity& operator=(
const WeakEntity& other) {
519 GAIA_ASSERT(core::addressof(other) !=
this);
524 m_entity = other.m_entity;
526 if (other.m_pTracker !=
nullptr) {
527 m_pTracker =
new WeakEntityTracker();
534 WeakEntity(WeakEntity&& other)
noexcept: m_w(other.m_w), m_pTracker(other.m_pTracker), m_entity(other.m_entity) {
536 if (other.m_pTracker !=
nullptr)
537 other.m_pTracker->pWeakEntity =
this;
538 other.m_pTracker =
nullptr;
539 other.m_entity = EntityBad;
541 WeakEntity& operator=(WeakEntity&& other)
noexcept {
542 GAIA_ASSERT(core::addressof(other) !=
this);
547 m_pTracker = other.m_pTracker;
548 m_entity = other.m_entity;
551 if (other.m_pTracker !=
nullptr)
552 other.m_pTracker->pWeakEntity =
this;
553 other.m_pTracker =
nullptr;
554 other.m_entity = EntityBad;
559 GAIA_ASSERT(m_pTracker !=
nullptr);
560 GAIA_ASSERT(m_w !=
nullptr);
561 GAIA_ASSERT(m_entity != EntityBad);
563 m_pTracker->pWeakEntity =
this;
564 m_pTracker->prev =
nullptr;
566 auto& ec = fetch_mut(*m_w, m_entity);
567 m_pTracker->next = ec.pWeakTracker;
568 if (ec.pWeakTracker !=
nullptr)
569 ec.pWeakTracker->prev = m_pTracker;
570 ec.pWeakTracker = m_pTracker;
574 if (m_pTracker ==
nullptr)
577 if (m_pTracker->next !=
nullptr)
578 m_pTracker->next->prev = m_pTracker->prev;
579 if (m_pTracker->prev !=
nullptr)
580 m_pTracker->prev->next = m_pTracker->next;
582 if (m_w !=
nullptr && valid(*m_w, m_entity)) {
583 auto& ec = fetch_mut(*m_w, m_entity);
584 if (ec.pWeakTracker == m_pTracker)
585 ec.pWeakTracker = m_pTracker->next;
589 m_pTracker =
nullptr;
592 template <
typename Serializer>
593 void save(Serializer& s)
const {
594 s.save(m_entity.val);
596 template <
typename Serializer>
597 void load(Serializer& s) {
601 m_entity = Entity(
id);
602 if (m_w !=
nullptr && m_entity != EntityBad) {
603 m_pTracker =
new WeakEntityTracker();
608 GAIA_NODISCARD Entity entity() const noexcept {
611 GAIA_NODISCARD
operator Entity() const noexcept {
615 bool operator==(
const WeakEntity& other)
const noexcept {
616 return m_entity == other.entity();
620 inline bool operator==(
const WeakEntity& e1, Entity e2)
noexcept {
621 return e1.entity() == e2;
623 inline bool operator==(Entity e1,
const WeakEntity& e2)
noexcept {
624 return e1 == e2.entity();
627 inline bool operator!=(
const WeakEntity& e1, Entity e2)
noexcept {
628 return e1.entity() != e2;
630 inline bool operator!=(Entity e1,
const WeakEntity& e2)
noexcept {
631 return e1 != e2.entity();
637 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