Skip to content

Commit

Permalink
feat(ecs): move relations on archetype change
Browse files Browse the repository at this point in the history
  • Loading branch information
RiscadoA committed Jan 24, 2024
1 parent b7e765d commit b10c4fd
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 2 deletions.
58 changes: 56 additions & 2 deletions core/src/cubos/core/ecs/world.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,34 @@ auto World::Components::add(const reflection::Type& type, void* value) -> Compon
newTable.column(columnId).pushMove(value);

// For each sparse relation table the entity is on, move its relations to the new corresponding one.
// TODO
for (const auto& [_, index] : mWorld.mTables.sparseRelation())
{
// For each table where the entity's archetype is the 'from' archetype.
if (index.from().contains(oldArchetype))
{
for (const auto& oldTableId : index.from().at(oldArchetype))
{
// Move all occurrences of the entity in the 'from' column to the new table.
auto newTableId = oldTableId;
newTableId.from = newArchetype;
auto& newTable = mWorld.mTables.sparseRelation().create(newTableId, mWorld.mTypes);
mWorld.mTables.sparseRelation().at(oldTableId).moveFrom(mEntity.index, newTable);
}
}

// For each table where the entity's archetype is the 'to' archetype.
if (index.to().contains(oldArchetype))
{
for (const auto& oldTableId : index.to().at(oldArchetype))
{
// Move all occurrences of the entity in the 'to' column to the new table.
auto newTableId = oldTableId;
newTableId.to = newArchetype;
auto& newTable = mWorld.mTables.sparseRelation().create(newTableId, mWorld.mTypes);
mWorld.mTables.sparseRelation().at(oldTableId).moveTo(mEntity.index, newTable);
}
}
}

CUBOS_DEBUG("Added component {} to entity {}", type.name(), mEntity, mEntity);
return *this;
Expand Down Expand Up @@ -288,7 +315,34 @@ auto World::Components::remove(const reflection::Type& type) -> Components&
oldTable.swapMove(mEntity.index, newTable);

// For each sparse relation table the entity is on, move its relations to the new corresponding one.
// TODO
for (const auto& [_, index] : mWorld.mTables.sparseRelation())
{
// For each table where the entity's archetype is the 'from' archetype.
if (index.from().contains(oldArchetype))
{
for (const auto& oldTableId : index.from().at(oldArchetype))
{
// Move all occurrences of the entity in the 'from' column to the new table.
auto newTableId = oldTableId;
newTableId.from = newArchetype;
auto& newTable = mWorld.mTables.sparseRelation().create(newTableId, mWorld.mTypes);
mWorld.mTables.sparseRelation().at(oldTableId).moveFrom(mEntity.index, newTable);
}
}

// For each table where the entity's archetype is the 'to' archetype.
if (index.to().contains(oldArchetype))
{
for (const auto& oldTableId : index.to().at(oldArchetype))
{
// Move all occurrences of the entity in the 'to' column to the new table.
auto newTableId = oldTableId;
newTableId.to = newArchetype;
auto& newTable = mWorld.mTables.sparseRelation().create(newTableId, mWorld.mTypes);
mWorld.mTables.sparseRelation().at(oldTableId).moveTo(mEntity.index, newTable);
}
}
}

CUBOS_DEBUG("Removed component {} from entity {}", type.name(), mEntity);
return *this;
Expand Down
33 changes: 33 additions & 0 deletions core/tests/ecs/world.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -209,4 +209,37 @@ TEST_CASE("ecs::World")

CHECK(destroyed);
}

SUBCASE("relations are moved correctly between archetypes")
{
bool destroyed = false;
auto foo = world.create();
auto bar = world.create();

// Add a relation between foo and bar.
REQUIRE_FALSE(world.related<DetectDestructorRelation>(foo, bar));
world.relate(foo, bar, DetectDestructorRelation{{&destroyed}});
REQUIRE(world.related<DetectDestructorRelation>(foo, bar));
REQUIRE_FALSE(destroyed);

// Change the archetype of foo. The entities should still be related.
world.components(foo).add(IntegerComponent{0});
REQUIRE(world.related<DetectDestructorRelation>(foo, bar));
REQUIRE_FALSE(destroyed);

// Change the archetype of bar. The entities should still be related.
world.components(bar).add(IntegerComponent{0});
REQUIRE(world.related<DetectDestructorRelation>(foo, bar));
REQUIRE_FALSE(destroyed);

// Change the archetypes once again.
world.components(foo).remove<IntegerComponent>();
world.components(bar).remove<IntegerComponent>();
REQUIRE(world.related<DetectDestructorRelation>(foo, bar));
REQUIRE_FALSE(destroyed);

// Destroy foo. The relation should be destroyed.
world.destroy(foo);
REQUIRE(destroyed);
}
}

0 comments on commit b10c4fd

Please sign in to comment.