From 1653495dac278d4a9dd05ae5afd67b49fc59df8e Mon Sep 17 00:00:00 2001 From: Sander Mertens Date: Sun, 17 Dec 2023 13:29:29 -0800 Subject: [PATCH] #1082 Don't throw error when cloning entity with an entity name --- flecs.c | 20 +++++++++++++------- flecs.h | 4 ++++ include/flecs.h | 4 ++++ src/entity.c | 20 +++++++++++++------- test/api/project.json | 3 ++- test/api/src/Clone.c | 28 ++++++++++++++++++++++++++++ test/api/src/main.c | 7 ++++++- 7 files changed, 70 insertions(+), 16 deletions(-) diff --git a/flecs.c b/flecs.c index dcc785797..73a3b545b 100644 --- a/flecs.c +++ b/flecs.c @@ -6085,22 +6085,28 @@ ecs_entity_t ecs_clone( goto done; } - ecs_type_t src_type = src_table->type; - ecs_table_diff_t diff = { .added = src_type }; + ecs_table_t *dst_table = src_table; + if (src_table->flags & EcsTableHasName) { + dst_table = ecs_table_remove_id(world, src_table, + ecs_pair_t(EcsIdentifier, EcsName)); + } + + ecs_type_t dst_type = dst_table->type; + ecs_table_diff_t diff = { .added = dst_type }; ecs_record_t *dst_r = flecs_entities_get(world, dst); - flecs_new_entity(world, dst, dst_r, src_table, &diff, true, true); + flecs_new_entity(world, dst, dst_r, dst_table, &diff, true, true); int32_t row = ECS_RECORD_TO_ROW(dst_r->row); if (copy_value) { - flecs_table_move(world, dst, src, src_table, + flecs_table_move(world, dst, src, dst_table, row, src_table, ECS_RECORD_TO_ROW(src_r->row), true); - int32_t i, count = src_table->column_count; + int32_t i, count = dst_table->column_count; for (i = 0; i < count; i ++) { ecs_type_t type = { - .array = &src_table->data.columns[i].id, + .array = &dst_table->data.columns[i].id, .count = 1 }; - flecs_notify_on_set(world, src_table, row, 1, &type, true); + flecs_notify_on_set(world, dst_table, row, 1, &type, true); } } diff --git a/flecs.h b/flecs.h index 1b0348ae6..4274b3e48 100644 --- a/flecs.h +++ b/flecs.h @@ -5242,6 +5242,10 @@ const ecs_entity_t* ecs_bulk_new_w_id( * This operation clones the components of one entity into another entity. If * no destination entity is provided, a new entity will be created. Component * values are not copied unless copy_value is true. + * + * If the source entity has a name, it will not be copied to the destination + * entity. This is to prevent having two entities with the same name under the + * same parent, which is not allowed. * * @param world The world. * @param dst The entity to copy the components to. diff --git a/include/flecs.h b/include/flecs.h index d6c8082e8..1d4d39b03 100644 --- a/include/flecs.h +++ b/include/flecs.h @@ -2412,6 +2412,10 @@ const ecs_entity_t* ecs_bulk_new_w_id( * This operation clones the components of one entity into another entity. If * no destination entity is provided, a new entity will be created. Component * values are not copied unless copy_value is true. + * + * If the source entity has a name, it will not be copied to the destination + * entity. This is to prevent having two entities with the same name under the + * same parent, which is not allowed. * * @param world The world. * @param dst The entity to copy the components to. diff --git a/src/entity.c b/src/entity.c index ec77a147f..cd532f37b 100644 --- a/src/entity.c +++ b/src/entity.c @@ -2682,22 +2682,28 @@ ecs_entity_t ecs_clone( goto done; } - ecs_type_t src_type = src_table->type; - ecs_table_diff_t diff = { .added = src_type }; + ecs_table_t *dst_table = src_table; + if (src_table->flags & EcsTableHasName) { + dst_table = ecs_table_remove_id(world, src_table, + ecs_pair_t(EcsIdentifier, EcsName)); + } + + ecs_type_t dst_type = dst_table->type; + ecs_table_diff_t diff = { .added = dst_type }; ecs_record_t *dst_r = flecs_entities_get(world, dst); - flecs_new_entity(world, dst, dst_r, src_table, &diff, true, true); + flecs_new_entity(world, dst, dst_r, dst_table, &diff, true, true); int32_t row = ECS_RECORD_TO_ROW(dst_r->row); if (copy_value) { - flecs_table_move(world, dst, src, src_table, + flecs_table_move(world, dst, src, dst_table, row, src_table, ECS_RECORD_TO_ROW(src_r->row), true); - int32_t i, count = src_table->column_count; + int32_t i, count = dst_table->column_count; for (i = 0; i < count; i ++) { ecs_type_t type = { - .array = &src_table->data.columns[i].id, + .array = &dst_table->data.columns[i].id, .count = 1 }; - flecs_notify_on_set(world, src_table, row, 1, &type, true); + flecs_notify_on_set(world, dst_table, row, 1, &type, true); } } diff --git a/test/api/project.json b/test/api/project.json index 516fb477b..04bbdf45b 100644 --- a/test/api/project.json +++ b/test/api/project.json @@ -953,7 +953,8 @@ "tag", "tag_w_value", "1_tag_1_component", - "1_tag_1_component_w_value" + "1_tag_1_component_w_value", + "clone_w_name" ] }, { "id": "ComponentLifecycle", diff --git a/test/api/src/Clone.c b/test/api/src/Clone.c index 8235f3b02..5c2156fe0 100644 --- a/test/api/src/Clone.c +++ b/test/api/src/Clone.c @@ -348,3 +348,31 @@ void Clone_1_tag_1_component_w_value(void) { ecs_fini(world); } + +void Clone_clone_w_name(void) { + ecs_world_t *world = ecs_mini(); + + ECS_COMPONENT(world, Position); + ECS_COMPONENT(world, Velocity); + + ecs_entity_t t = ecs_new_entity(world, "template"); + ecs_set(world, t, Position, {10, 20}); + ecs_set(world, t, Velocity, {1, 2}); + + ecs_entity_t i = ecs_clone(world, 0, t, true); + test_assert(ecs_has(world, i, Position)); + test_assert(ecs_has(world, i, Velocity)); + test_assert(!ecs_has_pair(world, i, ecs_id(EcsIdentifier), EcsName)); + + const Position *p = ecs_get(world, i, Position); + test_assert(p != NULL); + test_int(p->x, 10); + test_int(p->y, 20); + + const Velocity *v = ecs_get(world, i, Velocity); + test_assert(v != NULL); + test_int(v->x, 1); + test_int(v->y, 2); + + ecs_fini(world); +} diff --git a/test/api/src/main.c b/test/api/src/main.c index 5917ef679..aa18c195a 100644 --- a/test/api/src/main.c +++ b/test/api/src/main.c @@ -903,6 +903,7 @@ void Clone_tag(void); void Clone_tag_w_value(void); void Clone_1_tag_1_component(void); void Clone_1_tag_1_component_w_value(void); +void Clone_clone_w_name(void); // Testsuite 'ComponentLifecycle' void ComponentLifecycle_setup(void); @@ -6101,6 +6102,10 @@ bake_test_case Clone_testcases[] = { { "1_tag_1_component_w_value", Clone_1_tag_1_component_w_value + }, + { + "clone_w_name", + Clone_clone_w_name } }; @@ -13139,7 +13144,7 @@ static bake_test_suite suites[] = { "Clone", NULL, NULL, - 14, + 15, Clone_testcases }, {