Skip to content

Commit 3e0e43c

Browse files
authored
fixes crash when adding/removing components from a 'other' context (#31)
1 parent 6da8caa commit 3e0e43c

File tree

3 files changed

+154
-47
lines changed

3 files changed

+154
-47
lines changed

ecsact/entt/runtime.hh

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -486,14 +486,17 @@ private:
486486
using boost::mp11::mp_first;
487487
using boost::mp11::mp_flatten;
488488
using boost::mp11::mp_for_each;
489+
using boost::mp11::mp_iota_c;
489490
using boost::mp11::mp_map_find;
490491
using boost::mp11::mp_push_back;
492+
using boost::mp11::mp_size;
491493
using boost::mp11::mp_transform;
492494
using boost::mp11::mp_unique;
493495
using ecsact::entt::detail::pending_add;
494496
using ecsact::entt_mp11_util::mp_map_find_value_or;
495497

496498
using caps_info = ecsact::system_capabilities_info<SystemT>;
499+
using associations = typename caps_info::associations;
497500

498501
using system_generates = mp_transform<
499502
mp_first,
@@ -507,7 +510,7 @@ private:
507510
::ecsact::mp_list<>>,
508511
::ecsact::mp_list<>>>;
509512

510-
mp_for_each<addables>([&]<typename C>(C) {
513+
auto for_each_addable = [&]<typename C>(C) {
511514
using boost::mp11::mp_apply;
512515
using boost::mp11::mp_bind_front;
513516
using boost::mp11::mp_transform_q;
@@ -532,25 +535,52 @@ private:
532535
}
533536

534537
info.registry.template clear<pending_add<C>>();
538+
};
539+
540+
mp_for_each<addables>(for_each_addable);
541+
542+
mp_for_each<mp_iota_c<mp_size<associations>::value>>([&](auto I) {
543+
using boost::mp11::mp_at;
544+
using boost::mp11::mp_size_t;
545+
546+
using Assoc = mp_at<associations, mp_size_t<I>>;
547+
using addables = typename Assoc::adds_components;
548+
549+
mp_for_each<addables>(for_each_addable);
535550
});
536551
}
537552

538553
template<typename SystemT>
539554
void _apply_pending_removes(registry_info& info) {
540555
using boost::mp11::mp_for_each;
556+
using boost::mp11::mp_iota_c;
557+
using boost::mp11::mp_size;
541558
using ecsact::entt::detail::pending_remove;
542559
using ecsact::entt_mp11_util::mp_map_find_value_or;
543560

544561
using caps_info = ecsact::system_capabilities_info<SystemT>;
562+
using associations = typename caps_info::associations;
545563

546564
using removes_components = typename caps_info::removes_components;
547565

548-
mp_for_each<removes_components>([&]<typename C>(C) {
566+
auto for_each_removable = [&]<typename C>(C) {
549567
auto view = info.registry.template view<pending_remove<C>>();
550568
view.each([&](auto entity) { info.template remove_component<C>(entity); }
551569
);
552570

553571
info.registry.template clear<pending_remove<C>>();
572+
};
573+
574+
mp_for_each<removes_components>(for_each_removable);
575+
576+
mp_for_each<mp_iota_c<mp_size<associations>::value>>([&](auto I) {
577+
using boost::mp11::mp_at;
578+
using boost::mp11::mp_size_t;
579+
580+
using Assoc = mp_at<associations, mp_size_t<I>>;
581+
using removes_components = typename Assoc::removes_components;
582+
583+
mp_for_each<removes_components>(for_each_removable);
554584
});
555585
}
556586

@@ -677,6 +707,11 @@ private:
677707

678708
auto& assoc_view = std::get<I>(assoc_views);
679709
auto& assoc_view_itr = std::get<I>(assoc_views_itrs);
710+
if(assoc_view.begin() == assoc_view.end()) {
711+
missing_assoc_entities = true;
712+
return;
713+
}
714+
680715
assert(view.contains(entity));
681716
auto& comp = view.template get<ComponentT>(entity);
682717

runtime/test/runtime_test.cc

Lines changed: 103 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,10 @@ void runtime_test::TrivialRemove::impl(context& ctx) {
4949
std::abort();
5050
}
5151

52+
static std::atomic_bool AssocTestAction_ran = false;
53+
5254
void runtime_test::AssocTestAction::impl(context& ctx) {
55+
AssocTestAction_ran = true;
5356
ctx.add(OtherEntityComponent{
5457
.num = 42,
5558
.target = ctx.action().assoc_entity,
@@ -73,6 +76,17 @@ void runtime_test::AttackDamageWeakened::impl(context& ctx) {
7376
// target_ctx.update(target_health);
7477
}
7578

79+
static std::atomic_bool AddAssocTest_ran = false;
80+
81+
void runtime_test::AddAssocTest::impl(context& ctx) {
82+
AddAssocTest_ran = true;
83+
auto other_entity = ctx.get<OtherEntityComponent>();
84+
85+
// Get Target other context from OtherEntityComponent
86+
auto target_ctx = ctx._ctx.other(other_entity.target);
87+
target_ctx.add(AddAssocTestComponent{.num = 10});
88+
}
89+
7690
TEST(Core, CreateRegistry) {
7791
auto reg_id = ecsact_create_registry("CreateRegistry");
7892
EXPECT_NE(reg_id, ecsact_invalid_registry_id);
@@ -393,51 +407,6 @@ TEST(Core, EventCollector) {
393407
}
394408
}
395409

396-
TEST(Core, DynamicSystemImpl) {
397-
auto reg = ecsact::core::registry("DynamicSystemImpl");
398-
auto entity = reg.create_entity();
399-
auto other_entity = reg.create_entity();
400-
401-
ComponentA comp{.a = 42};
402-
reg.add_component(entity, comp);
403-
reg.add_component(other_entity, comp);
404-
405-
OtherEntityComponent other_comp{.num = 3, .target = other_entity};
406-
ASSERT_EQ(reg.add_component(entity, other_comp), ECSACT_ADD_OK);
407-
408-
// Sanity check
409-
ASSERT_TRUE(reg.has_component<ComponentA>(entity));
410-
ASSERT_EQ(reg.get_component<ComponentA>(entity), comp);
411-
ASSERT_TRUE(reg.has_component<ComponentA>(other_entity));
412-
ASSERT_EQ(reg.get_component<ComponentA>(other_entity), comp);
413-
ASSERT_TRUE(reg.has_component<OtherEntityComponent>(entity));
414-
ASSERT_EQ(reg.get_component<OtherEntityComponent>(entity), other_comp);
415-
416-
ecsact_set_system_execution_impl(
417-
ecsact_id_cast<ecsact_system_like_id>(runtime_test::SimpleSystem::id),
418-
&runtime_test__SimpleSystem
419-
);
420-
421-
ecsact_set_system_execution_impl(
422-
ecsact_id_cast<ecsact_system_like_id>(runtime_test::OtherEntitySystem::id),
423-
&runtime_test__OtherEntitySystem
424-
);
425-
426-
auto exec_err = ecsact_execute_systems(reg.id(), 1, nullptr, nullptr);
427-
ASSERT_EQ(exec_err, ECSACT_EXEC_SYS_OK);
428-
429-
// Sanity check
430-
ASSERT_TRUE(reg.has_component<ComponentA>(entity));
431-
432-
auto comp_get = reg.get_component<ComponentA>(entity);
433-
434-
EXPECT_NE(comp_get.a, comp.a);
435-
436-
// Simulate what the system should be doing.
437-
comp.a += 2;
438-
EXPECT_EQ(comp_get.a, comp.a);
439-
}
440-
441410
TEST(Core, ExecuteSystemsErrors) {
442411
auto reg = ecsact::core::registry("ExecuteSystemsErrors");
443412
auto options = ecsact_execution_options{};
@@ -476,6 +445,50 @@ TEST(Core, ExecuteSystemsAssocActionOk) {
476445
EXPECT_EQ(exec_err, ECSACT_EXEC_SYS_OK);
477446
}
478447

448+
TEST(Core, AddAssocOk) {
449+
ecsact_set_system_execution_impl(
450+
ecsact_id_cast<ecsact_system_like_id>(runtime_test::AssocTestAction::id),
451+
&runtime_test__AssocTestAction
452+
);
453+
ecsact_set_system_execution_impl(
454+
ecsact_id_cast<ecsact_system_like_id>(runtime_test::AddAssocTest::id),
455+
&runtime_test__AddAssocTest
456+
);
457+
458+
auto reg = ecsact::core::registry("AddAssocOk");
459+
auto test_entity1 = reg.create_entity();
460+
reg.add_component(
461+
test_entity1,
462+
runtime_test::ComponentA{
463+
.a = 42,
464+
}
465+
);
466+
467+
auto test_entity2 = reg.create_entity();
468+
reg.add_component<runtime_test::AddAssocTestTag>(test_entity2);
469+
470+
auto options = ecsact_execution_options{};
471+
auto test_action = runtime_test::AssocTestAction{
472+
.assoc_entity = test_entity2,
473+
};
474+
auto test_action_c = ecsact_action{
475+
.action_id = runtime_test::AssocTestAction::id,
476+
.action_data = &test_action,
477+
};
478+
479+
options.actions_length = 1;
480+
options.actions = &test_action_c;
481+
AddAssocTest_ran = false;
482+
AssocTestAction_ran = false;
483+
auto exec_err = ecsact_execute_systems(reg.id(), 1, &options, nullptr);
484+
EXPECT_TRUE(AddAssocTest_ran) << "AddAssocTest Impl Didn't Executed";
485+
EXPECT_TRUE(AssocTestAction_ran) << "AssocTestAction Impl Didn't Executed";
486+
EXPECT_EQ(exec_err, ECSACT_EXEC_SYS_OK);
487+
488+
exec_err = ecsact_execute_systems(reg.id(), 1, nullptr, nullptr);
489+
EXPECT_EQ(exec_err, ECSACT_EXEC_SYS_OK);
490+
}
491+
479492
TEST(Core, AssociationEntityCorrectness) {
480493
using runtime_test::AttackDamage;
481494
using runtime_test::AttackDamageWeakened;
@@ -585,6 +598,51 @@ TEST(Core, AssociationEntityCorrectness) {
585598
}
586599
}
587600

601+
TEST(Core, DynamicSystemImpl) {
602+
auto reg = ecsact::core::registry("DynamicSystemImpl");
603+
auto entity = reg.create_entity();
604+
auto other_entity = reg.create_entity();
605+
606+
ComponentA comp{.a = 42};
607+
reg.add_component(entity, comp);
608+
reg.add_component(other_entity, comp);
609+
610+
OtherEntityComponent other_comp{.num = 3, .target = other_entity};
611+
ASSERT_EQ(reg.add_component(entity, other_comp), ECSACT_ADD_OK);
612+
613+
// Sanity check
614+
ASSERT_TRUE(reg.has_component<ComponentA>(entity));
615+
ASSERT_EQ(reg.get_component<ComponentA>(entity), comp);
616+
ASSERT_TRUE(reg.has_component<ComponentA>(other_entity));
617+
ASSERT_EQ(reg.get_component<ComponentA>(other_entity), comp);
618+
ASSERT_TRUE(reg.has_component<OtherEntityComponent>(entity));
619+
ASSERT_EQ(reg.get_component<OtherEntityComponent>(entity), other_comp);
620+
621+
ecsact_set_system_execution_impl(
622+
ecsact_id_cast<ecsact_system_like_id>(runtime_test::SimpleSystem::id),
623+
&runtime_test__SimpleSystem
624+
);
625+
626+
ecsact_set_system_execution_impl(
627+
ecsact_id_cast<ecsact_system_like_id>(runtime_test::OtherEntitySystem::id),
628+
&runtime_test__OtherEntitySystem
629+
);
630+
631+
auto exec_err = ecsact_execute_systems(reg.id(), 1, nullptr, nullptr);
632+
ASSERT_EQ(exec_err, ECSACT_EXEC_SYS_OK);
633+
634+
// Sanity check
635+
ASSERT_TRUE(reg.has_component<ComponentA>(entity));
636+
637+
auto comp_get = reg.get_component<ComponentA>(entity);
638+
639+
EXPECT_NE(comp_get.a, comp.a);
640+
641+
// Simulate what the system should be doing.
642+
comp.a += 2;
643+
EXPECT_EQ(comp_get.a, comp.a);
644+
}
645+
588646
#ifdef ECSACT_ENTT_TEST_STATIC_SYSTEM_IMPL
589647
TEST(Core, StaticSystemImpl) {
590648
auto reg_id = ecsact_create_registry("StaticSystemImpl");

runtime/test/runtime_test.ecsact

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,20 @@ action AssocTestAction {
6161
adds OtherEntityComponent;
6262
}
6363

64+
component AddAssocTestComponent {
65+
i32 num;
66+
}
67+
68+
component AddAssocTestTag;
69+
70+
system AddAssocTest {
71+
readwrite ComponentA;
72+
readwrite OtherEntityComponent with target {
73+
include AddAssocTestTag;
74+
adds AddAssocTestComponent;
75+
}
76+
}
77+
6478
system AttackDamage {
6579
readwrite Attacking with target {
6680
readwrite Health;

0 commit comments

Comments
 (0)