Skip to content

Commit 325606d

Browse files
SanderMertens60k41p
authored andcommitted
SanderMertens#1973 Fix issues with adding Prefab tag after hierarchy is created
1 parent 980e783 commit 325606d

6 files changed

Lines changed: 216 additions & 18 deletions

File tree

distr/flecs.c

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -40361,15 +40361,16 @@ void flecs_component_update_childof_depth(
4036140361

4036240362
EcsParent *data = tgt_table->data.columns[column - 1].data;
4036340363
ecs_entity_t parent = data[ECS_RECORD_TO_ROW(tgt_r->row)].value;
40364-
ecs_assert(parent != 0, ECS_CYCLE_DETECTED,
40365-
"possible cycle detected in Parent hierarchy");
40366-
40367-
ecs_component_record_t *cr_parent = flecs_components_get(world,
40368-
ecs_childof(parent));
40369-
ecs_assert(cr_parent != NULL, ECS_INTERNAL_ERROR, NULL);
40370-
ecs_assert(cr_parent->pair != NULL, ECS_INTERNAL_ERROR, NULL);
40364+
if (!parent) {
40365+
new_depth = 0;
40366+
} else {
40367+
ecs_component_record_t *cr_parent = flecs_components_get(world,
40368+
ecs_childof(parent));
40369+
ecs_assert(cr_parent != NULL, ECS_INTERNAL_ERROR, NULL);
40370+
ecs_assert(cr_parent->pair != NULL, ECS_INTERNAL_ERROR, NULL);
4037140371

40372-
new_depth = cr_parent->pair->depth + 1;
40372+
new_depth = cr_parent->pair->depth + 1;
40373+
}
4037340374
} else {
4037440375
new_depth = 1;
4037540376
}
@@ -40993,6 +40994,15 @@ void flecs_on_replace_parent(ecs_iter_t *it) {
4099340994
continue;
4099440995
}
4099540996

40997+
#ifdef FLECS_DEBUG
40998+
ecs_entity_t cur = new_parent;
40999+
while (cur) {
41000+
ecs_assert(cur != e, ECS_CYCLE_DETECTED,
41001+
"cycle detected in Parent hierarchy");
41002+
cur = ecs_get_parent(world, cur);
41003+
}
41004+
#endif
41005+
4099641006
flecs_journal_begin(world, EcsJournalSetParent, e, &(ecs_type_t){
4099741007
.count = 1, .array = &new_parent
4099841008
}, NULL);

src/storage/component_index.c

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1218,15 +1218,16 @@ void flecs_component_update_childof_depth(
12181218

12191219
EcsParent *data = tgt_table->data.columns[column - 1].data;
12201220
ecs_entity_t parent = data[ECS_RECORD_TO_ROW(tgt_r->row)].value;
1221-
ecs_assert(parent != 0, ECS_CYCLE_DETECTED,
1222-
"possible cycle detected in Parent hierarchy");
1223-
1224-
ecs_component_record_t *cr_parent = flecs_components_get(world,
1225-
ecs_childof(parent));
1226-
ecs_assert(cr_parent != NULL, ECS_INTERNAL_ERROR, NULL);
1227-
ecs_assert(cr_parent->pair != NULL, ECS_INTERNAL_ERROR, NULL);
1221+
if (!parent) {
1222+
new_depth = 0;
1223+
} else {
1224+
ecs_component_record_t *cr_parent = flecs_components_get(world,
1225+
ecs_childof(parent));
1226+
ecs_assert(cr_parent != NULL, ECS_INTERNAL_ERROR, NULL);
1227+
ecs_assert(cr_parent->pair != NULL, ECS_INTERNAL_ERROR, NULL);
12281228

1229-
new_depth = cr_parent->pair->depth + 1;
1229+
new_depth = cr_parent->pair->depth + 1;
1230+
}
12301231
} else {
12311232
new_depth = 1;
12321233
}

src/storage/non_fragmenting_childof.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,15 @@ void flecs_on_replace_parent(ecs_iter_t *it) {
202202
continue;
203203
}
204204

205+
#ifdef FLECS_DEBUG
206+
ecs_entity_t cur = new_parent;
207+
while (cur) {
208+
ecs_assert(cur != e, ECS_CYCLE_DETECTED,
209+
"cycle detected in Parent hierarchy");
210+
cur = ecs_get_parent(world, cur);
211+
}
212+
#endif
213+
205214
flecs_journal_begin(world, EcsJournalSetParent, e, &(ecs_type_t){
206215
.count = 1, .array = &new_parent
207216
}, NULL);

test/core/project.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -968,7 +968,11 @@
968968
"delete_mixed_tree_3",
969969
"delete_mixed_tree_4",
970970
"delete_mixed_tree_5",
971-
"instantiate_parent_w_has_in_hook"
971+
"instantiate_parent_w_has_in_hook",
972+
"add_prefab_tag_after_hierarchy_creation",
973+
"defer_add_prefab_tag_after_hierarchy_creation",
974+
"add_prefab_tag_after_hierarchy_creation_2",
975+
"defer_add_prefab_tag_after_hierarchy_creation_2"
972976
]
973977
}, {
974978
"id": "Hierarchies",

test/core/src/NonFragmentingChildOf.c

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5903,3 +5903,157 @@ void NonFragmentingChildOf_instantiate_parent_w_has_in_hook(void) {
59035903

59045904
ecs_fini(world);
59055905
}
5906+
5907+
void NonFragmentingChildOf_add_prefab_tag_after_hierarchy_creation(void) {
5908+
ecs_world_t* world = ecs_mini();
5909+
5910+
ecs_entity_t mom = ecs_new(world);
5911+
ecs_entity_t daughter = ecs_new(world);
5912+
ecs_entity_t granddaughter = ecs_new(world);
5913+
5914+
ecs_add_id(world, mom, EcsOrderedChildren);
5915+
ecs_add_id(world, daughter, EcsOrderedChildren);
5916+
5917+
ecs_set(world, daughter, EcsParent, {mom});
5918+
ecs_set(world, granddaughter, EcsParent, {daughter});
5919+
5920+
ecs_add_id(world, mom, EcsPrefab);
5921+
5922+
ecs_entity_t a = ecs_new(world);
5923+
ecs_add_pair(world, a, EcsIsA, mom);
5924+
5925+
{
5926+
ecs_entities_t children = ecs_get_ordered_children(world, a);
5927+
test_int(children.count, 1);
5928+
ecs_entity_t a_child = children.ids[0];
5929+
test_assert(ecs_has_pair(world, a_child, EcsIsA, daughter));
5930+
test_int(ecs_get_target(world, a_child, EcsParentDepth, 0), 1);
5931+
5932+
ecs_entities_t gchildren = ecs_get_ordered_children(world, a_child);
5933+
test_int(gchildren.count, 1);
5934+
ecs_entity_t a_gchild = gchildren.ids[0];
5935+
test_assert(ecs_has_pair(world, a_gchild, EcsIsA, granddaughter));
5936+
test_int(ecs_get_target(world, a_gchild, EcsParentDepth, 0), 2);
5937+
}
5938+
5939+
ecs_fini(world);
5940+
}
5941+
5942+
void NonFragmentingChildOf_defer_add_prefab_tag_after_hierarchy_creation(void) {
5943+
ecs_world_t* world = ecs_mini();
5944+
5945+
ecs_entity_t mom = ecs_new(world);
5946+
ecs_entity_t daughter = ecs_new(world);
5947+
ecs_entity_t granddaughter = ecs_new(world);
5948+
5949+
ecs_add_id(world, mom, EcsOrderedChildren);
5950+
ecs_add_id(world, daughter, EcsOrderedChildren);
5951+
5952+
ecs_set(world, daughter, EcsParent, {mom});
5953+
ecs_set(world, granddaughter, EcsParent, {daughter});
5954+
5955+
ecs_add_id(world, mom, EcsPrefab);
5956+
5957+
ecs_defer_begin(world);
5958+
ecs_entity_t a = ecs_new(world);
5959+
ecs_add_pair(world, a, EcsIsA, mom);
5960+
ecs_defer_end(world);
5961+
5962+
{
5963+
ecs_entities_t children = ecs_get_ordered_children(world, a);
5964+
test_int(children.count, 1);
5965+
ecs_entity_t a_child = children.ids[0];
5966+
test_assert(ecs_has_pair(world, a_child, EcsIsA, daughter));
5967+
test_int(ecs_get_target(world, a_child, EcsParentDepth, 0), 1);
5968+
5969+
ecs_entities_t gchildren = ecs_get_ordered_children(world, a_child);
5970+
test_int(gchildren.count, 1);
5971+
ecs_entity_t a_gchild = gchildren.ids[0];
5972+
test_assert(ecs_has_pair(world, a_gchild, EcsIsA, granddaughter));
5973+
test_int(ecs_get_target(world, a_gchild, EcsParentDepth, 0), 2);
5974+
}
5975+
5976+
ecs_fini(world);
5977+
}
5978+
5979+
void NonFragmentingChildOf_add_prefab_tag_after_hierarchy_creation_2(void) {
5980+
ecs_world_t* world = ecs_mini();
5981+
5982+
ECS_TAG(world, Foo);
5983+
ECS_TAG(world, Bar);
5984+
5985+
ecs_entity_t mom = ecs_new(world);
5986+
ecs_entity_t daughter = ecs_new_w(world, Foo);
5987+
ecs_entity_t granddaughter = ecs_new_w(world, Bar);
5988+
5989+
ecs_add_id(world, mom, EcsOrderedChildren);
5990+
ecs_add_id(world, daughter, EcsOrderedChildren);
5991+
5992+
ecs_set(world, daughter, EcsParent, {mom});
5993+
ecs_set(world, granddaughter, EcsParent, {daughter});
5994+
5995+
ecs_add_id(world, mom, EcsPrefab);
5996+
5997+
ecs_entity_t a = ecs_new(world);
5998+
ecs_add_pair(world, a, EcsIsA, mom);
5999+
6000+
{
6001+
ecs_entities_t children = ecs_get_ordered_children(world, a);
6002+
test_int(children.count, 1);
6003+
ecs_entity_t a_child = children.ids[0];
6004+
test_assert(ecs_has_pair(world, a_child, EcsIsA, daughter));
6005+
test_assert(ecs_has(world, a_child, Foo));
6006+
test_int(ecs_get_target(world, a_child, EcsParentDepth, 0), 1);
6007+
6008+
ecs_entities_t gchildren = ecs_get_ordered_children(world, a_child);
6009+
test_int(gchildren.count, 1);
6010+
ecs_entity_t a_gchild = gchildren.ids[0];
6011+
test_assert(ecs_has_pair(world, a_gchild, EcsIsA, granddaughter));
6012+
test_assert(ecs_has(world, a_gchild, Bar));
6013+
test_int(ecs_get_target(world, a_gchild, EcsParentDepth, 0), 2);
6014+
}
6015+
6016+
ecs_fini(world);
6017+
}
6018+
6019+
void NonFragmentingChildOf_defer_add_prefab_tag_after_hierarchy_creation_2(void) {
6020+
ecs_world_t* world = ecs_mini();
6021+
6022+
ECS_TAG(world, Foo);
6023+
ECS_TAG(world, Bar);
6024+
6025+
ecs_entity_t mom = ecs_new(world);
6026+
ecs_entity_t daughter = ecs_new_w(world, Foo);
6027+
ecs_entity_t granddaughter = ecs_new_w(world, Bar);
6028+
6029+
ecs_add_id(world, mom, EcsOrderedChildren);
6030+
ecs_add_id(world, daughter, EcsOrderedChildren);
6031+
6032+
ecs_set(world, daughter, EcsParent, {mom});
6033+
ecs_set(world, granddaughter, EcsParent, {daughter});
6034+
6035+
ecs_add_id(world, mom, EcsPrefab);
6036+
6037+
ecs_defer_begin(world);
6038+
ecs_entity_t a = ecs_new(world);
6039+
ecs_add_pair(world, a, EcsIsA, mom);
6040+
ecs_defer_end(world);
6041+
6042+
{
6043+
ecs_entities_t children = ecs_get_ordered_children(world, a);
6044+
test_int(children.count, 1);
6045+
ecs_entity_t a_child = children.ids[0];
6046+
test_assert(ecs_has_pair(world, a_child, EcsIsA, daughter));
6047+
test_assert(ecs_has(world, a_child, Foo));
6048+
test_int(ecs_get_target(world, a_child, EcsParentDepth, 0), 1);
6049+
6050+
ecs_entities_t gchildren = ecs_get_ordered_children(world, a_child);
6051+
test_int(gchildren.count, 1);
6052+
ecs_entity_t a_gchild = gchildren.ids[0];
6053+
test_assert(ecs_has_pair(world, a_gchild, EcsIsA, granddaughter));
6054+
test_assert(ecs_has(world, a_gchild, Bar));
6055+
test_int(ecs_get_target(world, a_gchild, EcsParentDepth, 0), 2);
6056+
}
6057+
6058+
ecs_fini(world);
6059+
}

test/core/src/main.c

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -937,6 +937,10 @@ void NonFragmentingChildOf_delete_mixed_tree_3(void);
937937
void NonFragmentingChildOf_delete_mixed_tree_4(void);
938938
void NonFragmentingChildOf_delete_mixed_tree_5(void);
939939
void NonFragmentingChildOf_instantiate_parent_w_has_in_hook(void);
940+
void NonFragmentingChildOf_add_prefab_tag_after_hierarchy_creation(void);
941+
void NonFragmentingChildOf_defer_add_prefab_tag_after_hierarchy_creation(void);
942+
void NonFragmentingChildOf_add_prefab_tag_after_hierarchy_creation_2(void);
943+
void NonFragmentingChildOf_defer_add_prefab_tag_after_hierarchy_creation_2(void);
940944

941945
// Testsuite 'Hierarchies'
942946
void Hierarchies_setup(void);
@@ -6847,6 +6851,22 @@ bake_test_case NonFragmentingChildOf_testcases[] = {
68476851
{
68486852
"instantiate_parent_w_has_in_hook",
68496853
NonFragmentingChildOf_instantiate_parent_w_has_in_hook
6854+
},
6855+
{
6856+
"add_prefab_tag_after_hierarchy_creation",
6857+
NonFragmentingChildOf_add_prefab_tag_after_hierarchy_creation
6858+
},
6859+
{
6860+
"defer_add_prefab_tag_after_hierarchy_creation",
6861+
NonFragmentingChildOf_defer_add_prefab_tag_after_hierarchy_creation
6862+
},
6863+
{
6864+
"add_prefab_tag_after_hierarchy_creation_2",
6865+
NonFragmentingChildOf_add_prefab_tag_after_hierarchy_creation_2
6866+
},
6867+
{
6868+
"defer_add_prefab_tag_after_hierarchy_creation_2",
6869+
NonFragmentingChildOf_defer_add_prefab_tag_after_hierarchy_creation_2
68506870
}
68516871
};
68526872

@@ -15775,7 +15795,7 @@ static bake_test_suite suites[] = {
1577515795
"NonFragmentingChildOf",
1577615796
NULL,
1577715797
NULL,
15778-
231,
15798+
235,
1577915799
NonFragmentingChildOf_testcases
1578015800
},
1578115801
{

0 commit comments

Comments
 (0)