Skip to content

Commit 3f3e2cc

Browse files
committed
Add documentation for Inheritable trait
1 parent c34aba9 commit 3f3e2cc

File tree

7 files changed

+128
-6
lines changed

7 files changed

+128
-6
lines changed

distr/flecs.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34186,7 +34186,7 @@ int flecs_term_finalize(
3418634186
}
3418734187
}
3418834188

34189-
if (first_entity) {
34189+
if (first_entity && !ecs_term_match_0(term)) {
3419034190
bool first_is_self = (first_flags & EcsTraverseFlags) == EcsSelf;
3419134191
ecs_record_t *first_record = flecs_entities_get(world, first_entity);
3419234192
ecs_table_t *first_table = first_record ? first_record->table : NULL;
@@ -72724,7 +72724,7 @@ void flecs_query_validate_final_fields(
7272472724
ecs_term_t *term = &terms[i];
7272572725
ecs_id_t id = term->id;
7272672726

72727-
if (!(impl->final_terms & (1 << i))) {
72727+
if (!(impl->final_terms & (1ull << i))) {
7272872728
continue;
7272972729
}
7273072730

docs/ComponentTraits.md

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -939,6 +939,88 @@ let i = world.entity().is_a_id(e); // not allowed
939939

940940
Queries may use the final trait to optimize, as they do not have to explore subsets of a final entity. For more information on how queries interpret final, see the [Query manual](Queries.md).
941941

942+
## Inheritable trait
943+
The `Inheritable` trait indicates that a component can be inherited from (it can be used as target of an `IsA` relationship). It is not required to add this trait to components before using them as target of an `IsA` pair, but it can be used to ensure that queries for the component take into account component inheritance.
944+
945+
<div class="flecs-snippet-tabs">
946+
<ul>
947+
<li><b class="tab-title">C</b>
948+
949+
```c
950+
ECS_TAG(world, Unit);
951+
ecs_add_id(world, Unit, EcsInheritable);
952+
953+
ecs_query_t *q = ecs_query(world, {
954+
.terms = {{ Unit }}
955+
});
956+
957+
ECS_TAG(world, Warrior);
958+
ecs_add_pair(world, Warrior, EcsIsA, Unit);
959+
960+
ecs_iter_t it = ecs_query_iter(world, q);
961+
// iterate query
962+
```
963+
964+
</li>
965+
<li><b class="tab-title">C++</b>
966+
967+
```cpp
968+
world.component<Unit>().add(flecs::Inheritable);
969+
970+
auto q = world.query_builder()
971+
.with<Unit>()
972+
.build();
973+
974+
world.component<Warrior>().is_a<Unit>();
975+
976+
q.each([](flecs::entity unit) {
977+
// ...
978+
});
979+
```
980+
981+
</li>
982+
<li><b class="tab-title">C#</b>
983+
984+
```cs
985+
world.Component<Unit>().Add(Ecs.Inheritable);
986+
987+
auto q = world.QueryBuilder()
988+
.With<Unit>()
989+
.Build();
990+
991+
q.Each([](Entity unit) {
992+
// ...
993+
});
994+
```
995+
996+
</li>
997+
<li><b class="tab-title">Rust</b>
998+
999+
```rust
1000+
world.component::<Unit>().add_trait::<flecs::Inheritable>();
1001+
1002+
auto q = world.query()
1003+
.with::<Unit>()
1004+
.build();
1005+
1006+
world.component<Warrior>().is_a<Unit>();
1007+
1008+
q.each_entity(|e| {
1009+
// ...
1010+
});
1011+
```
1012+
1013+
</li>
1014+
</ul>
1015+
</div>
1016+
1017+
Queries must be aware of (potential) inheritance relationships when they are created. A query will be created with support for inheritance under the following conditions:
1018+
- If the component has the `Inheritable` trait
1019+
- If the component is inherited from
1020+
- If the component inherits from another component and is not `Final`
1021+
1022+
If a query was not aware of inheritance relationships at creation time and one or more of the components in the query were inherited from, query iteration will fail in debug mode.
1023+
9421024
## OnInstantiate trait
9431025
The `OnInstantiate` trait configures the behavior of components when an entity is instantiated from another entity (usually a prefab). Instantiation happens when an `IsA` pair is added to an entity.
9441026

src/query/engine/eval_iter.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,7 @@ void flecs_query_validate_final_fields(
288288
ecs_term_t *term = &terms[i];
289289
ecs_id_t id = term->id;
290290

291-
if (!(impl->final_terms & (1 << i))) {
291+
if (!(impl->final_terms & (1ull << i))) {
292292
continue;
293293
}
294294

src/query/validator.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -841,7 +841,7 @@ int flecs_term_finalize(
841841
}
842842
}
843843

844-
if (first_entity) {
844+
if (first_entity && !ecs_term_match_0(term)) {
845845
bool first_is_self = (first_flags & EcsTraverseFlags) == EcsSelf;
846846
ecs_record_t *first_record = flecs_entities_get(world, first_entity);
847847
ecs_table_t *first_table = first_record ? first_record->table : NULL;

test/query/project.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1296,7 +1296,8 @@
12961296
"inheritable_trait",
12971297
"query_before_isa_relationship_1st_term",
12981298
"query_before_isa_relationship_2nd_term",
1299-
"query_before_isa_relationship_subtype"
1299+
"query_before_isa_relationship_subtype",
1300+
"query_before_isa_relationship_0_src"
13001301
]
13011302
}, {
13021303
"id": "Recycled",

test/query/src/ComponentInheritance.c

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3479,3 +3479,37 @@ void ComponentInheritance_query_before_isa_relationship_subtype(void) {
34793479

34803480
ecs_fini(world);
34813481
}
3482+
3483+
void ComponentInheritance_query_before_isa_relationship_0_src(void) {
3484+
ecs_world_t *world = ecs_mini();
3485+
3486+
ECS_TAG(world, Foo);
3487+
ECS_TAG(world, Unit);
3488+
3489+
ecs_query_t *q = ecs_query(world, {
3490+
.expr = "Foo, Unit()"
3491+
});
3492+
3493+
test_assert(q != NULL);
3494+
3495+
ECS_ENTITY(world, Warrior, (IsA, Unit));
3496+
3497+
ecs_entity_t e1 = ecs_new_w(world, Foo);
3498+
3499+
ecs_iter_t it = ecs_query_iter(world, q);
3500+
test_bool(true, ecs_query_next(&it));
3501+
test_uint(1, it.count);
3502+
test_uint(e1, it.entities[0]);
3503+
test_uint(Foo, ecs_field_id(&it, 0));
3504+
test_uint(Unit, ecs_field_id(&it, 1));
3505+
test_uint(0, ecs_field_src(&it, 0));
3506+
test_uint(0, ecs_field_src(&it, 1));
3507+
test_bool(true, ecs_field_is_set(&it, 0));
3508+
test_bool(false, ecs_field_is_set(&it, 1));
3509+
3510+
test_bool(false, ecs_query_next(&it));
3511+
3512+
ecs_query_fini(q);
3513+
3514+
ecs_fini(world);
3515+
}

test/query/src/main.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1258,6 +1258,7 @@ void ComponentInheritance_inheritable_trait(void);
12581258
void ComponentInheritance_query_before_isa_relationship_1st_term(void);
12591259
void ComponentInheritance_query_before_isa_relationship_2nd_term(void);
12601260
void ComponentInheritance_query_before_isa_relationship_subtype(void);
1261+
void ComponentInheritance_query_before_isa_relationship_0_src(void);
12611262

12621263
// Testsuite 'Recycled'
12631264
void Recycled_setup(void);
@@ -7096,6 +7097,10 @@ bake_test_case ComponentInheritance_testcases[] = {
70967097
{
70977098
"query_before_isa_relationship_subtype",
70987099
ComponentInheritance_query_before_isa_relationship_subtype
7100+
},
7101+
{
7102+
"query_before_isa_relationship_0_src",
7103+
ComponentInheritance_query_before_isa_relationship_0_src
70997104
}
71007105
};
71017106

@@ -10751,7 +10756,7 @@ static bake_test_suite suites[] = {
1075110756
"ComponentInheritance",
1075210757
NULL,
1075310758
NULL,
10754-
35,
10759+
36,
1075510760
ComponentInheritance_testcases
1075610761
},
1075710762
{

0 commit comments

Comments
 (0)