Skip to content

Commit d7877b0

Browse files
#1846 Don't remove DontFragment components before calling regular observers in delete
1 parent 54e2c97 commit d7877b0

File tree

5 files changed

+356
-6
lines changed

5 files changed

+356
-6
lines changed

distr/flecs.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8980,8 +8980,6 @@ void ecs_delete(
89808980
flecs_table_traversable_add(r->table, -1);
89818981
}
89828982

8983-
flecs_entity_remove_non_fragmenting(world, entity, r);
8984-
89858983
/* Merge operations before deleting entity */
89868984
flecs_defer_end(world, stage);
89878985
flecs_defer_begin(world, stage);
@@ -8998,6 +8996,7 @@ void ecs_delete(
89988996
int32_t row = ECS_RECORD_TO_ROW(r->row);
89998997
flecs_notify_on_remove(
90008998
world, table, &world->store.root, row, 1, &diff);
8999+
flecs_entity_remove_non_fragmenting(world, entity, r);
90019000
flecs_table_delete(world, table, row, true);
90029001
}
90039002

src/entity.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1704,8 +1704,6 @@ void ecs_delete(
17041704
flecs_table_traversable_add(r->table, -1);
17051705
}
17061706

1707-
flecs_entity_remove_non_fragmenting(world, entity, r);
1708-
17091707
/* Merge operations before deleting entity */
17101708
flecs_defer_end(world, stage);
17111709
flecs_defer_begin(world, stage);
@@ -1722,6 +1720,7 @@ void ecs_delete(
17221720
int32_t row = ECS_RECORD_TO_ROW(r->row);
17231721
flecs_notify_on_remove(
17241722
world, table, &world->store.root, row, 1, &diff);
1723+
flecs_entity_remove_non_fragmenting(world, entity, r);
17251724
flecs_table_delete(world, table, row, true);
17261725
}
17271726

test/core/project.json

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -678,7 +678,15 @@
678678
"instantiate_prefab_w_component_w_with_sparse",
679679
"children_for_sparse",
680680
"children_for_sparse_no_children",
681-
"children_for_sparse_after_delete_children"
681+
"children_for_sparse_after_delete_children",
682+
"on_remove_before_hook_before_dtor",
683+
"on_remove_before_hook_before_dtor_pair",
684+
"check_sparse_in_regular_observer",
685+
"check_sparse_target_in_regular_observer",
686+
"check_sparse_exclusive_target_in_regular_observer",
687+
"check_regular_in_sparse_observer",
688+
"check_regular_target_in_sparse_observer",
689+
"check_regular_exclusive_target_in_sparse_observer"
682690
]
683691
}, {
684692
"id": "Hierarchies",

test/core/src/Sparse.c

Lines changed: 304 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6482,3 +6482,307 @@ void Sparse_children_for_sparse_after_delete_children(void) {
64826482

64836483
ecs_fini(world);
64846484
}
6485+
6486+
static ecs_id_t dummy_component_id = 0;
6487+
static int dummy_dtor_invoked = 0;
6488+
static int dummy_hook_invoked = 0;
6489+
static int dummy_observer_invoked = 0;
6490+
static int check_observer_invoked = 0;
6491+
6492+
static void DummyDtor(void *ptr, ecs_size_t count, const ecs_type_info_t *ti) {
6493+
test_assert(!dummy_dtor_invoked);
6494+
dummy_dtor_invoked ++;
6495+
test_assert(dummy_observer_invoked);
6496+
test_assert(dummy_hook_invoked);
6497+
}
6498+
6499+
static void DummyHook(ecs_iter_t *it) {
6500+
test_assert(!dummy_hook_invoked);
6501+
dummy_hook_invoked ++;
6502+
test_assert(dummy_observer_invoked);
6503+
test_assert(!dummy_dtor_invoked);
6504+
6505+
test_int(it->count, 1);
6506+
6507+
Position *p = ecs_field_at(it, Position, 0, 0);
6508+
test_assert(p != NULL);
6509+
6510+
test_assert(ecs_has_id(it->world, it->entities[0], dummy_component_id));
6511+
}
6512+
6513+
static void DummyObserver(ecs_iter_t *it) {
6514+
test_assert(!dummy_observer_invoked);
6515+
dummy_observer_invoked ++;
6516+
test_assert(!dummy_hook_invoked);
6517+
test_assert(!dummy_dtor_invoked);
6518+
6519+
test_int(it->count, 1);
6520+
6521+
Position *p = ecs_field_at(it, Position, 0, 0);
6522+
test_assert(p != NULL);
6523+
6524+
ecs_world_t *world = it->world;
6525+
ecs_entity_t e = it->entities[0];
6526+
6527+
test_assert(ecs_has_id(world, e, dummy_component_id));
6528+
6529+
if (ecs_id_is_pair(dummy_component_id)) {
6530+
ecs_entity_t rel = ecs_pair_first(world, dummy_component_id);
6531+
ecs_entity_t tgt = ecs_pair_second(world, dummy_component_id);
6532+
test_assert(ecs_get_target(world, e, rel, 0) == tgt);
6533+
}
6534+
}
6535+
6536+
static void CheckObserver(ecs_iter_t *it) {
6537+
check_observer_invoked ++;
6538+
test_assert(ecs_has_id(it->world, it->entities[0], dummy_component_id));
6539+
}
6540+
6541+
static void CheckTargetObserver(ecs_iter_t *it) {
6542+
check_observer_invoked ++;
6543+
test_assert(ecs_has_id(it->world, it->entities[0], dummy_component_id));
6544+
6545+
ecs_entity_t rel = ecs_pair_first(it->world, dummy_component_id);
6546+
ecs_entity_t tgt = ecs_pair_second(it->world, dummy_component_id);
6547+
test_assert(tgt != 0);
6548+
6549+
test_assert(ecs_get_target(it->world, it->entities[0], rel, 0) == tgt);
6550+
}
6551+
6552+
void Sparse_on_remove_before_hook_before_dtor(void) {
6553+
ecs_world_t *world = ecs_mini();
6554+
6555+
ECS_COMPONENT(world, Position);
6556+
6557+
ecs_add_id(world, ecs_id(Position), EcsSparse);
6558+
if (!fragment) ecs_add_id(world, ecs_id(Position), EcsDontFragment);
6559+
6560+
ecs_set_hooks(world, Position, {
6561+
.dtor = DummyDtor,
6562+
.on_remove = DummyHook
6563+
});
6564+
6565+
ecs_observer(world, {
6566+
.query.terms = {{ ecs_id(Position) }},
6567+
.events = { EcsOnRemove },
6568+
.callback = DummyObserver
6569+
});
6570+
6571+
dummy_component_id = ecs_id(Position);
6572+
6573+
ecs_entity_t e = ecs_insert(world, ecs_value(Position, {10, 20}));
6574+
test_int(dummy_observer_invoked, 0);
6575+
test_int(dummy_hook_invoked, 0);
6576+
test_int(dummy_dtor_invoked, 0);
6577+
6578+
ecs_delete(world, e);
6579+
test_int(dummy_observer_invoked, 1);
6580+
test_int(dummy_hook_invoked, 1);
6581+
test_int(dummy_dtor_invoked, 1);
6582+
6583+
ecs_fini(world);
6584+
}
6585+
6586+
void Sparse_on_remove_before_hook_before_dtor_pair(void) {
6587+
ecs_world_t *world = ecs_mini();
6588+
6589+
ECS_COMPONENT(world, Position);
6590+
ECS_TAG(world, Tgt);
6591+
6592+
ecs_add_id(world, ecs_id(Position), EcsSparse);
6593+
if (!fragment) ecs_add_id(world, ecs_id(Position), EcsDontFragment);
6594+
6595+
ecs_set_hooks(world, Position, {
6596+
.dtor = DummyDtor,
6597+
.on_remove = DummyHook
6598+
});
6599+
6600+
ecs_observer(world, {
6601+
.query.terms = {{ ecs_pair_t(Position, Tgt) }},
6602+
.events = { EcsOnRemove },
6603+
.callback = DummyObserver
6604+
});
6605+
6606+
dummy_component_id = ecs_pair_t(Position, Tgt);
6607+
6608+
ecs_entity_t e = ecs_new(world);
6609+
ecs_set_pair(world, e, Position, Tgt, {10, 20});
6610+
test_int(dummy_observer_invoked, 0);
6611+
test_int(dummy_hook_invoked, 0);
6612+
test_int(dummy_dtor_invoked, 0);
6613+
6614+
ecs_delete(world, e);
6615+
test_int(dummy_observer_invoked, 1);
6616+
test_int(dummy_hook_invoked, 1);
6617+
test_int(dummy_dtor_invoked, 1);
6618+
6619+
ecs_fini(world);
6620+
}
6621+
6622+
void Sparse_check_sparse_in_regular_observer(void) {
6623+
ecs_world_t *world = ecs_mini();
6624+
6625+
ECS_COMPONENT(world, Position);
6626+
ECS_COMPONENT(world, Velocity);
6627+
6628+
ecs_add_id(world, ecs_id(Position), EcsSparse);
6629+
if (!fragment) ecs_add_id(world, ecs_id(Position), EcsDontFragment);
6630+
6631+
ecs_observer(world, {
6632+
.query.terms = {{ ecs_id(Velocity) }},
6633+
.events = { EcsOnRemove },
6634+
.callback = CheckObserver
6635+
});
6636+
6637+
dummy_component_id = ecs_id(Position);
6638+
6639+
ecs_entity_t e = ecs_insert(world, ecs_value(Position, {10, 20}));
6640+
ecs_set(world, e, Velocity, {10, 20});
6641+
test_int(check_observer_invoked, 0);
6642+
6643+
ecs_delete(world, e);
6644+
test_int(check_observer_invoked, 1);
6645+
6646+
ecs_fini(world);
6647+
}
6648+
6649+
void Sparse_check_sparse_target_in_regular_observer(void) {
6650+
ecs_world_t *world = ecs_mini();
6651+
6652+
ECS_TAG(world, Rel);
6653+
ECS_TAG(world, Tgt);
6654+
ECS_COMPONENT(world, Velocity);
6655+
6656+
ecs_add_id(world, Rel, EcsSparse);
6657+
if (!fragment) ecs_add_id(world, Rel, EcsDontFragment);
6658+
6659+
ecs_observer(world, {
6660+
.query.terms = {{ ecs_id(Velocity) }},
6661+
.events = { EcsOnRemove },
6662+
.callback = CheckTargetObserver
6663+
});
6664+
6665+
dummy_component_id = ecs_pair(Rel, Tgt);
6666+
6667+
ecs_entity_t e = ecs_new_w_pair(world, Rel, Tgt);
6668+
ecs_set(world, e, Velocity, {10, 20});
6669+
test_int(check_observer_invoked, 0);
6670+
6671+
ecs_delete(world, e);
6672+
test_int(check_observer_invoked, 1);
6673+
6674+
ecs_fini(world);
6675+
}
6676+
6677+
void Sparse_check_sparse_exclusive_target_in_regular_observer(void) {
6678+
ecs_world_t *world = ecs_mini();
6679+
6680+
ECS_TAG(world, Rel);
6681+
ECS_TAG(world, Tgt);
6682+
ECS_COMPONENT(world, Velocity);
6683+
6684+
ecs_add_id(world, Rel, EcsSparse);
6685+
if (!fragment) ecs_add_id(world, Rel, EcsDontFragment);
6686+
ecs_add_id(world, Rel, EcsExclusive);
6687+
6688+
ecs_observer(world, {
6689+
.query.terms = {{ ecs_id(Velocity) }},
6690+
.events = { EcsOnRemove },
6691+
.callback = CheckTargetObserver
6692+
});
6693+
6694+
dummy_component_id = ecs_pair(Rel, Tgt);
6695+
6696+
ecs_entity_t e = ecs_new_w_pair(world, Rel, Tgt);
6697+
ecs_set(world, e, Velocity, {10, 20});
6698+
test_int(check_observer_invoked, 0);
6699+
6700+
ecs_delete(world, e);
6701+
test_int(check_observer_invoked, 1);
6702+
6703+
ecs_fini(world);
6704+
}
6705+
6706+
void Sparse_check_regular_in_sparse_observer(void) {
6707+
ecs_world_t *world = ecs_mini();
6708+
6709+
ECS_COMPONENT(world, Position);
6710+
ECS_COMPONENT(world, Velocity);
6711+
6712+
ecs_add_id(world, ecs_id(Position), EcsSparse);
6713+
if (!fragment) ecs_add_id(world, ecs_id(Position), EcsDontFragment);
6714+
6715+
ecs_observer(world, {
6716+
.query.terms = {{ ecs_id(Position) }},
6717+
.events = { EcsOnRemove },
6718+
.callback = CheckObserver
6719+
});
6720+
6721+
dummy_component_id = ecs_id(Velocity);
6722+
6723+
ecs_entity_t e = ecs_insert(world, ecs_value(Position, {10, 20}));
6724+
ecs_set(world, e, Velocity, {10, 20});
6725+
test_int(check_observer_invoked, 0);
6726+
6727+
ecs_delete(world, e);
6728+
test_int(check_observer_invoked, 1);
6729+
6730+
ecs_fini(world);
6731+
}
6732+
6733+
void Sparse_check_regular_target_in_sparse_observer(void) {
6734+
ecs_world_t *world = ecs_mini();
6735+
6736+
ECS_TAG(world, Rel);
6737+
ECS_TAG(world, Tgt);
6738+
ECS_COMPONENT(world, Velocity);
6739+
6740+
ecs_add_id(world, ecs_id(Velocity), EcsSparse);
6741+
if (!fragment) ecs_add_id(world, ecs_id(Velocity), EcsDontFragment);
6742+
6743+
ecs_observer(world, {
6744+
.query.terms = {{ ecs_id(Velocity) }},
6745+
.events = { EcsOnRemove },
6746+
.callback = CheckTargetObserver
6747+
});
6748+
6749+
dummy_component_id = ecs_pair(Rel, Tgt);
6750+
6751+
ecs_entity_t e = ecs_new_w_pair(world, Rel, Tgt);
6752+
ecs_set(world, e, Velocity, {10, 20});
6753+
test_int(check_observer_invoked, 0);
6754+
6755+
ecs_delete(world, e);
6756+
test_int(check_observer_invoked, 1);
6757+
6758+
ecs_fini(world);
6759+
}
6760+
6761+
void Sparse_check_regular_exclusive_target_in_sparse_observer(void) {
6762+
ecs_world_t *world = ecs_mini();
6763+
6764+
ECS_TAG(world, Rel);
6765+
ECS_TAG(world, Tgt);
6766+
ECS_COMPONENT(world, Velocity);
6767+
6768+
ecs_add_id(world, ecs_id(Velocity), EcsSparse);
6769+
if (!fragment) ecs_add_id(world, ecs_id(Velocity), EcsDontFragment);
6770+
ecs_add_id(world, ecs_id(Velocity), EcsExclusive);
6771+
6772+
ecs_observer(world, {
6773+
.query.terms = {{ ecs_id(Velocity) }},
6774+
.events = { EcsOnRemove },
6775+
.callback = CheckTargetObserver
6776+
});
6777+
6778+
dummy_component_id = ecs_pair(Rel, Tgt);
6779+
6780+
ecs_entity_t e = ecs_new_w_pair(world, Rel, Tgt);
6781+
ecs_set(world, e, Velocity, {10, 20});
6782+
test_int(check_observer_invoked, 0);
6783+
6784+
ecs_delete(world, e);
6785+
test_int(check_observer_invoked, 1);
6786+
6787+
ecs_fini(world);
6788+
}

0 commit comments

Comments
 (0)