Skip to content

Commit

Permalink
Fixed: Dangling archetypes possible in the entity->archetype map
Browse files Browse the repository at this point in the history
  • Loading branch information
richardbiely committed Apr 10, 2024
1 parent 66f56ed commit 4d33eed
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 28 deletions.
42 changes: 28 additions & 14 deletions include/gaia/ecs/world.h
Original file line number Diff line number Diff line change
Expand Up @@ -1926,27 +1926,41 @@ namespace gaia {
//! \param pArchetype Linked archetype
void add_entity_archetype_pair(Entity entity, Archetype* pArchetype) {
const auto it = m_entityToArchetypeMap.find(EntityLookupKey(entity));
if (it == m_entityToArchetypeMap.end())
if (it == m_entityToArchetypeMap.end()) {
m_entityToArchetypeMap.try_emplace(EntityLookupKey(entity), ArchetypeDArray{pArchetype});
else if (!core::has(it->second, pArchetype))
it->second.push_back(pArchetype);
return;
}

auto& archetypes = it->second;
if (!core::has(archetypes, pArchetype))
archetypes.push_back(pArchetype);
}

//! Deletes an archetype to <entity, archetype> record
//! \param entity Entity getting deleted
void del_entity_archetype_pair(Entity entity) {
auto it = m_entityToArchetypeMap.find(EntityLookupKey(entity));
//! Deletes an archetype from the <pairEntity, archetype> map
//! \param pairKey Pair entity used as a key in the map
//! \param entityToRemove Entity used to identify archetypes we are removing from the archetype array
void del_entity_archetype_pair(Pair pairKey, Entity entityToRemove) {
auto it = m_entityToArchetypeMap.find(EntityLookupKey(pairKey));
auto& archetypes = it->second;

// Remove any reference to the found archetype from the array.
// We don't know the archetype so we remove any archetype that contains our entity.
for (int i = (int)archetypes.size() - 1; i >= 0; --i) {
const auto* pArchetype = archetypes[(uint32_t)i];
if (pArchetype->has(entity))
if (!pArchetype->has(entityToRemove))
continue;

core::erase_fast_unsafe(archetypes, i);
}

// NOTE: No need to delete keys with empty archetype arrays.
// There are only 3 such keys: (*, tgt), (src, *), (*, *)
// If no more items are present in the array, remove the map key.
// if (archetypes.empty())
// m_entityToArchetypeMap.erase(it); DON'T
}

//! Deletes an archetype to <entity, archetype> record
//! Deletes an archetype from the <entity, archetype> map
//! \param entity Entity getting deleted
void del_entity_archetype_pairs(Entity entity) {
// TODO: Optimize. Either switch to an array or add an index to the map value.
Expand All @@ -1956,16 +1970,16 @@ namespace gaia {

if (entity.pair()) {
// Fake entities instantiated for both ids.
// We are find with it because to build a pair all we need are valid entity ids.
// We are fine with it because to build a pair all we need are valid entity ids.
const auto first = Entity(entity.id(), 0, false, false, EntityKind::EK_Gen);
const auto second = Entity(entity.gen(), 0, false, false, EntityKind::EK_Gen);

// (*, tgt)
del_entity_archetype_pair(Pair(All, second));
del_entity_archetype_pair(Pair(All, second), entity);
// (src, *)
del_entity_archetype_pair(Pair(first, All));
del_entity_archetype_pair(Pair(first, All), entity);
// (*, *)
del_entity_archetype_pair(Pair(All, All));
del_entity_archetype_pair(Pair(All, All), entity);
}
}

Expand All @@ -1982,7 +1996,7 @@ namespace gaia {
// as well so wildcard queries can find the archetype.
if (entity.pair()) {
// Fake entities instantiated for both ids.
// We are find with it because to build a pair all we need are valid entity ids.
// We are fine with it because to build a pair all we need are valid entity ids.
const auto first = Entity(entity.id(), 0, false, false, EntityKind::EK_Gen);
const auto second = Entity(entity.gen(), 0, false, false, EntityKind::EK_Gen);

Expand Down
42 changes: 28 additions & 14 deletions single_include/gaia.h
Original file line number Diff line number Diff line change
Expand Up @@ -23974,27 +23974,41 @@ namespace gaia {
//! \param pArchetype Linked archetype
void add_entity_archetype_pair(Entity entity, Archetype* pArchetype) {
const auto it = m_entityToArchetypeMap.find(EntityLookupKey(entity));
if (it == m_entityToArchetypeMap.end())
if (it == m_entityToArchetypeMap.end()) {
m_entityToArchetypeMap.try_emplace(EntityLookupKey(entity), ArchetypeDArray{pArchetype});
else if (!core::has(it->second, pArchetype))
it->second.push_back(pArchetype);
return;
}

auto& archetypes = it->second;
if (!core::has(archetypes, pArchetype))
archetypes.push_back(pArchetype);
}

//! Deletes an archetype to <entity, archetype> record
//! \param entity Entity getting deleted
void del_entity_archetype_pair(Entity entity) {
auto it = m_entityToArchetypeMap.find(EntityLookupKey(entity));
//! Deletes an archetype from the <pairEntity, archetype> map
//! \param pairKey Pair entity used as a key in the map
//! \param entityToRemove Entity used to identify archetypes we are removing from the archetype array
void del_entity_archetype_pair(Pair pairKey, Entity entityToRemove) {
auto it = m_entityToArchetypeMap.find(EntityLookupKey(pairKey));
auto& archetypes = it->second;

// Remove any reference to the found archetype from the array.
// We don't know the archetype so we remove any archetype that contains our entity.
for (int i = (int)archetypes.size() - 1; i >= 0; --i) {
const auto* pArchetype = archetypes[(uint32_t)i];
if (pArchetype->has(entity))
if (!pArchetype->has(entityToRemove))
continue;

core::erase_fast_unsafe(archetypes, i);
}

// NOTE: No need to delete keys with empty archetype arrays.
// There are only 3 such keys: (*, tgt), (src, *), (*, *)
// If no more items are present in the array, remove the map key.
// if (archetypes.empty())
// m_entityToArchetypeMap.erase(it); DON'T
}

//! Deletes an archetype to <entity, archetype> record
//! Deletes an archetype from the <entity, archetype> map
//! \param entity Entity getting deleted
void del_entity_archetype_pairs(Entity entity) {
// TODO: Optimize. Either switch to an array or add an index to the map value.
Expand All @@ -24004,16 +24018,16 @@ namespace gaia {

if (entity.pair()) {
// Fake entities instantiated for both ids.
// We are find with it because to build a pair all we need are valid entity ids.
// We are fine with it because to build a pair all we need are valid entity ids.
const auto first = Entity(entity.id(), 0, false, false, EntityKind::EK_Gen);
const auto second = Entity(entity.gen(), 0, false, false, EntityKind::EK_Gen);

// (*, tgt)
del_entity_archetype_pair(Pair(All, second));
del_entity_archetype_pair(Pair(All, second), entity);
// (src, *)
del_entity_archetype_pair(Pair(first, All));
del_entity_archetype_pair(Pair(first, All), entity);
// (*, *)
del_entity_archetype_pair(Pair(All, All));
del_entity_archetype_pair(Pair(All, All), entity);
}
}

Expand All @@ -24030,7 +24044,7 @@ namespace gaia {
// as well so wildcard queries can find the archetype.
if (entity.pair()) {
// Fake entities instantiated for both ids.
// We are find with it because to build a pair all we need are valid entity ids.
// We are fine with it because to build a pair all we need are valid entity ids.
const auto first = Entity(entity.id(), 0, false, false, EntityKind::EK_Gen);
const auto second = Entity(entity.gen(), 0, false, false, EntityKind::EK_Gen);

Expand Down

0 comments on commit 4d33eed

Please sign in to comment.