Skip to content

ref counting the association internal compnent #32

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jan 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ecsact/entt/detail/internal_markers.hh
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ template<typename C, std::size_t FieldOffset>
struct association {
using component = C;
static constexpr auto field_offset = FieldOffset;
std::int_fast16_t ref_count = 0;
};

template<typename Assoc>
Expand Down
25 changes: 21 additions & 4 deletions ecsact/entt/detail/registry_info.hh
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,17 @@ struct registry_info {

auto entity_field = field.template get<ecsact_entity_id>(&component);
auto entity_field_entt = entities_map.at(entity_field);
mp_with_index<64>(field.offset, [&](auto I) {
registry.emplace<association<C, I>>(entity_field_entt);
// TODO(zaucy): Increasing the mp_with_index number causes really long
// compile times. Iterating over the available associations
// would perform better here.
assert(field.offset < 32);
mp_with_index<32>(field.offset, [&](auto I) {
if(registry.all_of<association<C, I>>(entity_field_entt)) {
auto& assoc_comp = registry.get<association<C, I>>(entity_field_entt);
assoc_comp.ref_count += 1;
} else {
registry.emplace<association<C, I>>(entity_field_entt, 1);
}
});
}

Expand All @@ -77,8 +86,16 @@ struct registry_info {

auto entity_field = field.template get<ecsact_entity_id>(&component);
auto entity_field_entt = entities_map.at(entity_field);
mp_with_index<64>(field.offset, [&](auto I) {
registry.erase<association<C, I>>(entity_field_entt);
assert(field.offset < 32);
// TODO(zaucy): Increasing the mp_with_index number causes really long
// compile times. Iterating over the available associations
// would perform better here.
mp_with_index<32>(field.offset, [&](auto I) {
auto& assoc_comp = registry.get<association<C, I>>(entity_field_entt);
assoc_comp.ref_count -= 1;
if(assoc_comp.ref_count == 0) {
registry.erase<association<C, I>>(entity_field_entt);
}
});
}

Expand Down
6 changes: 4 additions & 2 deletions ecsact/entt/detail/system_execution_context.hh
Original file line number Diff line number Diff line change
Expand Up @@ -188,10 +188,12 @@ struct system_execution_context : system_execution_context_base {
}
}

info.registry.template emplace<pending_remove<C>>(entity);
// TODO(zaucy): Look into if emplace_or_replace is necessary instead of
// just replace.
info.registry.template emplace_or_replace<pending_remove<C>>(entity);

if constexpr(!C::transient) {
info.registry.template emplace<component_removed<C>>(entity);
info.registry.template emplace_or_replace<component_removed<C>>(entity);
}
}

Expand Down
74 changes: 74 additions & 0 deletions runtime/test/runtime_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,17 @@ void runtime_test::AddAssocTest::impl(context& ctx) {
target_ctx.add(AddAssocTestComponent{.num = 10});
}

static std::atomic_bool RemoveAssocTest_ran = false;

void runtime_test::RemoveAssocTest::impl(context& ctx) {
RemoveAssocTest_ran = true;
auto other_entity = ctx.get<OtherEntityComponent>();

// Get Target other context from OtherEntityComponent
auto target_ctx = ctx._ctx.other(other_entity.target);
target_ctx.remove<RemoveAssocTestComponent>();
}

TEST(Core, CreateRegistry) {
auto reg_id = ecsact_create_registry("CreateRegistry");
EXPECT_NE(reg_id, ecsact_invalid_registry_id);
Expand Down Expand Up @@ -489,6 +500,69 @@ TEST(Core, AddAssocOk) {
EXPECT_EQ(exec_err, ECSACT_EXEC_SYS_OK);
}

TEST(Core, RemoveAssocOk) {
ecsact_set_system_execution_impl(
ecsact_id_cast<ecsact_system_like_id>(runtime_test::AssocTestAction::id),
&runtime_test__AssocTestAction
);
ecsact_set_system_execution_impl(
ecsact_id_cast<ecsact_system_like_id>(runtime_test::RemoveAssocTest::id),
&runtime_test__RemoveAssocTest
);

auto reg = ecsact::core::registry("RemoveAssocOk");
auto test_entity2 = reg.create_entity();
reg.add_component<runtime_test::RemoveAssocTestTag>(test_entity2);
reg.add_component(
test_entity2,
runtime_test::RemoveAssocTestComponent{
.num = 42,
}
);

auto test_entity1 = reg.create_entity();
reg.add_component(
test_entity1,
runtime_test::OtherEntityComponent{
.target = test_entity2,
}
);

auto test_entity3 = reg.create_entity();
reg.add_component(
test_entity3,
runtime_test::OtherEntityComponent{
.target = test_entity2,
}
);

RemoveAssocTest_ran = false;
auto exec_err = ecsact_execute_systems(reg.id(), 1, nullptr, nullptr);
EXPECT_TRUE(RemoveAssocTest_ran) << "RemoveAssocTest Impl Didn't Executed";
EXPECT_EQ(exec_err, ECSACT_EXEC_SYS_OK);

ASSERT_FALSE(
reg.has_component<runtime_test::RemoveAssocTestComponent>(test_entity2)
);

exec_err = ecsact_execute_systems(reg.id(), 1, nullptr, nullptr);
EXPECT_EQ(exec_err, ECSACT_EXEC_SYS_OK);

reg.add_component(
test_entity2,
runtime_test::RemoveAssocTestComponent{
.num = 42,
}
);

exec_err = ecsact_execute_systems(reg.id(), 1, nullptr, nullptr);
EXPECT_EQ(exec_err, ECSACT_EXEC_SYS_OK);

ASSERT_FALSE(
reg.has_component<runtime_test::RemoveAssocTestComponent>(test_entity2)
);
}

TEST(Core, AssociationEntityCorrectness) {
using runtime_test::AttackDamage;
using runtime_test::AttackDamageWeakened;
Expand Down
13 changes: 13 additions & 0 deletions runtime/test/runtime_test.ecsact
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,19 @@ system AddAssocTest {
}
}

component RemoveAssocTestComponent {
i32 num;
}

component RemoveAssocTestTag;

system RemoveAssocTest {
readwrite OtherEntityComponent with target {
include RemoveAssocTestTag;
removes RemoveAssocTestComponent;
}
}

system AttackDamage {
readwrite Attacking with target {
readwrite Health;
Expand Down