Skip to content

Commit 449f1b0

Browse files
SanderMertens#1975 Fix issue with observer up traversal and parent hierarchies
1 parent 8c33e18 commit 449f1b0

5 files changed

Lines changed: 92 additions & 13 deletions

File tree

distr/flecs.c

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20836,26 +20836,28 @@ void flecs_spawner_instantiate(
2083620836
.added_flags = flags
2083720837
};
2083820838

20839-
int32_t row = ecs_table_count(table);
20840-
r->table = table;
20841-
r->row = (uint32_t)row;
20842-
flecs_table_append(world, table, entity, true, true);
20843-
flecs_actions_new(world, table, row, 1, &table_diff, 0, false, true);
20844-
2084520839
ecs_entity_t parent = parents[spawn_child->parent_index];
20840+
ecs_assert(parent != 0, ECS_INTERNAL_ERROR, NULL);
2084620841
if (parent != old_parent) {
2084720842
cr = flecs_components_ensure(world, ecs_childof(parent));
2084820843
old_parent = parent;
2084920844
}
2085020845

2085120846
ecs_assert(cr != NULL, ECS_INTERNAL_ERROR, NULL);
2085220847

20848+
int32_t row = ecs_table_count(table);
20849+
r->table = table;
20850+
r->row = (uint32_t)row;
20851+
flecs_table_append(world, table, entity, true, true);
20852+
2085320853
int32_t parent_column = table->component_map[ecs_id(EcsParent)];
2085420854
ecs_assert(parent_column != 0, ECS_INTERNAL_ERROR, NULL);
2085520855
EcsParent *parent_ptr = table->data.columns[parent_column - 1].data;
2085620856
parent_ptr = &parent_ptr[row];
2085720857
parent_ptr->value = parent;
2085820858

20859+
flecs_actions_new(world, table, row, 1, &table_diff, 0, false, true);
20860+
2085920861
if (is_prefab && spawn_child->child_name) {
2086020862
ecs_set_name(world, entity, spawn_child->child_name);
2086120863
}

src/tree_spawner.c

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -279,26 +279,28 @@ void flecs_spawner_instantiate(
279279
.added_flags = flags
280280
};
281281

282-
int32_t row = ecs_table_count(table);
283-
r->table = table;
284-
r->row = (uint32_t)row;
285-
flecs_table_append(world, table, entity, true, true);
286-
flecs_actions_new(world, table, row, 1, &table_diff, 0, false, true);
287-
288282
ecs_entity_t parent = parents[spawn_child->parent_index];
283+
ecs_assert(parent != 0, ECS_INTERNAL_ERROR, NULL);
289284
if (parent != old_parent) {
290285
cr = flecs_components_ensure(world, ecs_childof(parent));
291286
old_parent = parent;
292287
}
293288

294289
ecs_assert(cr != NULL, ECS_INTERNAL_ERROR, NULL);
295290

291+
int32_t row = ecs_table_count(table);
292+
r->table = table;
293+
r->row = (uint32_t)row;
294+
flecs_table_append(world, table, entity, true, true);
295+
296296
int32_t parent_column = table->component_map[ecs_id(EcsParent)];
297297
ecs_assert(parent_column != 0, ECS_INTERNAL_ERROR, NULL);
298298
EcsParent *parent_ptr = table->data.columns[parent_column - 1].data;
299299
parent_ptr = &parent_ptr[row];
300300
parent_ptr->value = parent;
301301

302+
flecs_actions_new(world, table, row, 1, &table_diff, 0, false, true);
303+
302304
if (is_prefab && spawn_child->child_name) {
303305
ecs_set_name(world, entity, spawn_child->child_name);
304306
}

test/core/project.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -863,6 +863,7 @@
863863
"instantiate_tree_1_child",
864864
"instantiate_tree_2_children",
865865
"instantiate_tree_3_children",
866+
"instantiate_tree_w_on_set_up_childof_observer_crash",
866867
"instantiate_w_dont_inherit",
867868
"instantiate_w_inherit",
868869
"instantiate_w_auto_override",

test/core/src/NonFragmentingChildOf.c

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,32 @@
22

33
static ECS_COMPONENT_DECLARE(Position);
44

5+
typedef struct ReproObserverCtx {
6+
int32_t invoked;
7+
ecs_entity_t entity;
8+
ecs_entity_t source;
9+
Position child_position;
10+
Position parent_position;
11+
} ReproObserverCtx;
12+
13+
static ReproObserverCtx repro_observer_ctx;
14+
15+
static
16+
void ReproDummyObserver(ecs_iter_t *it) {
17+
test_int(it->count, 1);
18+
19+
Position *child_position = ecs_field(it, Position, 0);
20+
Position *parent_position = ecs_field(it, Position, 1);
21+
test_assert(child_position != NULL);
22+
test_assert(parent_position != NULL);
23+
24+
repro_observer_ctx.invoked ++;
25+
repro_observer_ctx.entity = it->entities[0];
26+
repro_observer_ctx.source = it->sources[1];
27+
repro_observer_ctx.child_position = child_position[0];
28+
repro_observer_ctx.parent_position = parent_position[0];
29+
}
30+
531
void NonFragmentingChildOf_set_parent_no_ordered_children(void) {
632
ecs_world_t *world = ecs_mini();
733

@@ -3147,6 +3173,49 @@ void NonFragmentingChildOf_instantiate_tree_3_children(void) {
31473173
ecs_fini(world);
31483174
}
31493175

3176+
void NonFragmentingChildOf_instantiate_tree_w_on_set_up_childof_observer_crash(void) {
3177+
ecs_world_t *world = ecs_init();
3178+
3179+
ECS_COMPONENT(world, Position);
3180+
3181+
ecs_entity_t prefab = ecs_new_w_id(world, EcsPrefab);
3182+
ecs_set(world, prefab, Position, {10, 20});
3183+
3184+
ecs_entity_t prefab_child = ecs_new_w_parent(world, prefab, "Child");
3185+
ecs_set(world, prefab_child, Position, {11, 21});
3186+
3187+
ecs_os_zeromem(&repro_observer_ctx);
3188+
3189+
ecs_observer(world, {
3190+
.query.expr = "Position, Position(up ChildOf)",
3191+
.events = { EcsOnSet },
3192+
.callback = ReproDummyObserver
3193+
});
3194+
3195+
ecs_entity_t instance = ecs_new_w_pair(world, EcsIsA, prefab);
3196+
test_assert(instance != 0);
3197+
3198+
ecs_entities_t children = ecs_get_ordered_children(world, instance);
3199+
test_int(children.count, 1);
3200+
ecs_entity_t instance_child = children.ids[0];
3201+
test_assert(instance_child != 0);
3202+
3203+
const Position *p = ecs_get(world, instance_child, Position);
3204+
test_assert(p != NULL);
3205+
test_int(p->x, 11);
3206+
test_int(p->y, 21);
3207+
3208+
test_int(repro_observer_ctx.invoked, 1);
3209+
test_uint(repro_observer_ctx.entity, instance_child);
3210+
test_uint(repro_observer_ctx.source, instance);
3211+
test_int(repro_observer_ctx.child_position.x, 11);
3212+
test_int(repro_observer_ctx.child_position.y, 21);
3213+
test_int(repro_observer_ctx.parent_position.x, 10);
3214+
test_int(repro_observer_ctx.parent_position.y, 20);
3215+
3216+
ecs_fini(world);
3217+
}
3218+
31503219
void NonFragmentingChildOf_instantiate_w_dont_inherit(void) {
31513220
ecs_world_t *world = ecs_mini();
31523221

test/core/src/main.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -831,6 +831,7 @@ void NonFragmentingChildOf_prefab_variant_w_nested_children(void);
831831
void NonFragmentingChildOf_instantiate_tree_1_child(void);
832832
void NonFragmentingChildOf_instantiate_tree_2_children(void);
833833
void NonFragmentingChildOf_instantiate_tree_3_children(void);
834+
void NonFragmentingChildOf_instantiate_tree_w_on_set_up_childof_observer_crash(void);
834835
void NonFragmentingChildOf_instantiate_w_dont_inherit(void);
835836
void NonFragmentingChildOf_instantiate_w_inherit(void);
836837
void NonFragmentingChildOf_instantiate_w_auto_override(void);
@@ -6428,6 +6429,10 @@ bake_test_case NonFragmentingChildOf_testcases[] = {
64286429
"instantiate_tree_3_children",
64296430
NonFragmentingChildOf_instantiate_tree_3_children
64306431
},
6432+
{
6433+
"instantiate_tree_w_on_set_up_childof_observer_crash",
6434+
NonFragmentingChildOf_instantiate_tree_w_on_set_up_childof_observer_crash
6435+
},
64316436
{
64326437
"instantiate_w_dont_inherit",
64336438
NonFragmentingChildOf_instantiate_w_dont_inherit
@@ -15795,7 +15800,7 @@ static bake_test_suite suites[] = {
1579515800
"NonFragmentingChildOf",
1579615801
NULL,
1579715802
NULL,
15798-
235,
15803+
236,
1579915804
NonFragmentingChildOf_testcases
1580015805
},
1580115806
{

0 commit comments

Comments
 (0)