diff --git a/docs/ComponentTraits.md b/docs/ComponentTraits.md new file mode 100644 index 000000000..91477ca32 --- /dev/null +++ b/docs/ComponentTraits.md @@ -0,0 +1,1395 @@ +# Component Traits +Component traits are tags and pairs that can be added to components to modify their behavior. This manual contains an overview of all component traits supported by Flecs. + +## Cleanup traits +When entities that are used as tags, components, relationships or relationship targets are deleted, cleanup traits ensure that the store does not contain any dangling references. Any cleanup policy provides this guarantee, so while they are configurable, applications cannot configure traits that allows for dangling references. + +**Note**: this only applies to entities (like tags, components, relationships) that are added _to_ other entities. It does not apply to components that store an entity value, so: + +
+ +
+ +The default policy is that any references to the entity will be **removed**. For example, when the tag `Archer` is deleted, it will be removed from all entities that have it, which is similar to invoking the `remove_all` operation: + +
+ +
+ +Since entities can be used in relationship pairs, just calling `remove_all` on just the entity itself does not guarantee that no dangling references are left. A more comprehensive description of what happens is: + +
+ +
+ +This succeeds in removing all possible references to `Archer`. Sometimes this behavior is not what we want however. Consider a parent-child hierarchy, where we want to delete the child entities when the parent is deleted. Instead of removing `(ChildOf, parent)` from all children, we need to _delete_ the children. + +We also want to specify this per relationship. If an entity has `(Likes, parent)` we may not want to delete that entity, meaning the cleanup we want to perform for `Likes` and `ChildOf` may not be the same. + +This is what cleanup traits are for: to specify which action needs to be executed under which condition. They are applied _to_ entities that have a reference to the entity being deleted: if I delete the `Archer` tag I remove the tag _from_ all entities that have it. + +To configure a cleanup policy for an entity, a `(Condition, Action)` pair can be added to it. If no policy is specified, the default cleanup action (`Remove`) is performed. + +There are three cleanup actions: + +- `Remove`: as if doing `remove_all(entity)` (default) +- `Delete`: as if doing `delete_with(entity)` +- `Panic`: throw a fatal error (default for components) + +There are two cleanup conditions: + +- `OnDelete`: the component, tag or relationship is deleted +- `OnDeleteTarget`: a target used with the relationship is deleted + +Policies apply to both regular and pair instances, so to all entities with `T` as well as `(T, *)`. + +### Examples +The following examples show how to use cleanup traits + +#### (OnDelete, Remove) + +
+ +
+ +#### (OnDelete, Delete) + +
+ +
+ +#### (OnDeleteTarget, Delete) + +
+ +
+ +### Cleanup order +While cleanup actions allow for specifying what needs to happen when a particular entity is deleted, or when an entity used with a particular relationship is deleted, they do not enforce a strict cleanup _order_. The reason for this is that there can be many orderings that satisfy the cleanup traits. + +This is important to consider especially when writing `OnRemove` triggers or hooks, as the order in which they are invoked highly depends on the order in which entities are cleaned up. + +Take an example with a parent and a child that both have the `Node` tag: + +
+ +
+ +In this example, when calling `p.destruct()` the observer is first invoked for the child, and then for the parent, which is to be expected as the child is deleted before the parent. Cleanup traits do not however guarantee that this is always the case. + +An application could also call `world.component().destruct()` which would delete the `Node` component and all of its instances. In this scenario the cleanup traits for the `ChildOf` relationship are not considered, and therefore the ordering is undefined. Another typical scenario in which ordering is undefined is when an application has cyclical relationships with a `Delete` cleanup action. + +#### Cleanup order during world teardown +Cleanup issues often show up during world teardown as the ordering in which entities are deleted is controlled by the application. While world teardown respects cleanup traits, there can be many entity delete orderings that are valid according to the cleanup traits, but not all of them are equally useful. There are ways to organize entities that helps world cleanup to do the right thing. These are: + +**Organize components, triggers, observers and systems in modules.** +Storing these entities in modules ensures that they stay alive for as long as possible. This leads to more predictable cleanup ordering as components will be deleted as their entities are, vs. when the component is deleted. It also ensures that triggers and observers are not deleted while matching events are still being generated. + +**Avoid organizing components, triggers, observers and systems under entities that are not modules**. If a non-module entity with children is stored in the root, it will get cleaned up along with other regular entities. If you have entities such as these organized in a non-module scope, consider adding the `EcsModule`/`flecs::Module`/`Ecs.Module` tag to the root of that scope. + +The next section goes into more detail on why this improves cleanup behavior and what happens during world teardown. + +#### World teardown sequence +To understand why some ways to organize entities work better than others, having an overview of what happens during world teardown is useful. Here is a list of the steps that happen when a world is deleted: + +1. **Find all root entities** +World teardown starts by finding all root entities, which are entities that do not have the builtin `ChildOf` relationship. Note that empty entities (entities without any components) are not found during this step. + +2. **Query out modules, components, observers and systems** +This ensures that components are not cleaned up before the entities that use them, and triggers, observers and systems are not cleaned up while there are still conditions under which they could be invoked. + +3. **Query out entities that have no children** +If entities have no children they cannot cause complex cleanup logic. This also decreases the likelihood of initiating cleanup actions that could impact other entities. + +4. **Delete root entities** +The root entities that were not filtered out will be deleted. + +5. **Delete everything else** +The last step will delete all remaining entities. At this point cleanup traits are no longer considered and cleanup order is undefined. + +## Trait trait +The trait trait marks an entity as a trait, which is any tag that is added to another tag/component/relationship to modify its behavior. All properties in this section are marked as trait. It is not required to mark a trait as a trait before adding it to another tag/component/relationship. The main reason for the trait trait is to ease some of the constraints on relationships (see the Relationship trait). + +```c +ECS_TAG(world, Serializable); + +ecs_add_id(world, Serializable, EcsTrait); +``` + + +
  • C++ + +```cpp +struct Serializable { }; + +world.component().add(flecs::Trait); +``` + +
  • +
  • C# + +```cs +public struct Serializable { } + +world.Component().Entity.Add(Ecs.Trait); +``` + +
  • + + + +## Relationship trait +The relationship trait enforces that an entity can only be used as relationship. Consider the following example: + +```c +ECS_TAG(world, Likes); +ECS_TAG(world, Apples); + +ecs_add_id(world, Likes, EcsRelationship); + +ecs_entity_t e = ecs_new_id(world); +ecs_add(world, Likes); // Panic, 'Likes' is not used as relationship +ecs_add_pair(world, Apples, Likes); // Panic, 'Likes' is not used as relationship +ecs_add_pair(world, Likes, Apples); // OK +``` + + +
  • C++ + +```cpp +struct Likes { }; +struct Apples { }; + +world.component().add(flecs::Relationship); + +flecs::entity e = world.entity() + .add() // Panic, 'Likes' is not used as relationship + .add() // Panic, 'Likes' is not used as relationship + .add(); // OK +``` + +
  • +
  • C# + +```cs +public struct Likes { } +public struct Apples { } + +world.Component().Entity.Add(Ecs.Relationship); + +Entity e = ecs.Entity() + .Add() // Panic, 'Likes' is not used as relationship + .Add() // Panic, 'Likes' is not used as relationship + .add(); // OK +``` + +
  • + + + +Entities marked with `Relationship` may still be used as target if the relationship part of the pair has the `Trait` trait. This ensures the relationship can still be used to configure the behavior of other entities. Consider the following code example: + +```c +ECS_TAG(world, Likes); +ECS_TAG(world, Loves); + +ecs_add_id(world, Likes, EcsRelationship); + +// Even though Likes is marked as relationship and used as target here, this +// won't panic as With is marked as trait. +ecs_add_pair(world, Loves, EcsWith, Likes); +``` + + +
  • C++ + +```cpp +struct Likes { }; +struct Loves { }; + +world.component().add(flecs::Relationship); + +// Even though Likes is marked as relationship and used as target here, this +// won't panic as With is marked as trait. +world.component().add(flecs::With, world.component()); +``` + +
  • +
  • C# + +```cs +public struct Likes { } +public struct Loves { } + +world.Component().Entity.Add(Ecs.Relationship); + +world.Component().Entity.Add(Ecs.With, world.Component().Entity); +``` + +
  • + + + +## Target trait +The target trait enforces that an entity can only be used as relationship target. Consider the following example: + +```c +ECS_TAG(world, Likes); +ECS_TAG(world, Apples); + +ecs_add_id(world, Apples, EcsTarget); + +ecs_entity_t e = ecs_new_id(world); +ecs_add(world, Apples); // Panic, 'Apples' is not used as target +ecs_add_pair(world, Apples, Likes); // Panic, 'Apples' is not used as target +ecs_add_pair(world, Likes, Apples); // OK +``` + + +
  • C++ + +```cpp +struct Likes { }; +struct Apples { }; + +world.component().add(flecs::Target); + +flecs::entity e = world.entity() + .add() // Panic, 'Apples' is not used as target + .add() // Panic, 'Apples' is not used as target + .add(); // OK +``` + +
  • +
  • C# + +```cs +public struct Likes { } +public struct Apples { } + +world.Component().Entity.Add(Ecs.Target); + +Entity e = ecs.Entity() + .Add() // Panic, 'Apples' is not used as target + .Add() // Panic, 'Apples' is not used as target + .add(); // OK +``` + +
  • + + + +## PairIsTag trait +A relationship can be marked with PairIsTag in which case a pair with the relationship will never contain data. By default the data associated with a pair is determined by whether either the relationship or target are components. For some relationships however, even if the target is a component, no data should be added to the relationship. Consider the following example: + +
    + +
    + +To prevent data from being associated with pairs that can apply to components, the `Tag` trait can be added to relationships: + +
    + +
    + +The `Tag` trait is only interpreted when it is added to the relationship part of a pair. + +## Final trait +Entities can be annotated with the `Final` trait, which prevents using them with `IsA` relationship. This is similar to the concept of a final class as something that cannot be extended. The following example shows how use `Final`: + +
    + +
    + +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). By default, all components are created as final. + +## OnInstantiate trait +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. + +By default, when an entity is instantiated, the components from the base entity (the `IsA` target) are copied to the instance. This behavior can be modified with the `OnInstantiate` trait, which can be used as pair in combination with three targets: + +| Target | C | C++ | C# | Description | +|-------------|------------------|----------------------|-------------------|-------------| +| Override | `EcsOverride` | `flecs::Override` | `Ecs.Override` | Copy component from base to instance (default) | +| Inherit | `EcsInherit` | `flecs::Inherit` | `Ecs.Inherit` | Inherit component from base | +| DontInherit | `EcsDontInherit` | `flecs::DontInherit` | `Ecs.DontInherit` | Don't inherit (and don't copy) component from base | + +### Override +The default behavior for `OnInstantiate` is `Override`, which means that the component is copied to the instance. This means that after instantiation, the instance has an owned copy for the component that masks the base component (the "override"). + +Note that for an override to work correctly, a component has to be copyable. + +The following example shows how to use the `Override` trait: + +
    + +
    + +### Inherit +Components with the `Inherit` trait are inherited from a base entity (the `IsA` target) on instantiation. Inherited components are not copied to the instance, and are only stored once in memory. Operations such as `get` and `has`, and queries will automatically lookup inheritable components by following the `IsA` relationship. + +Inheritable components can be overridden manually by adding the component to the instance. This results in the same behavior as the `Override` trait, where the component is copied from the base entity. + +The following example shows how to use the `Inherit` trait: + +
    + +
    + +### DontInherit +Components with the `DontInherit` trait are not inherited from a base entity (the `IsA` target) on instantiation, and are not copied to the instance. Operations such as `has` and `get` will not find the component, and queries will not match it. + +Components with the `DontInherit` cannot be overridden manually. When a component is added to an instance and the base also has the component, the base component is ignored and its value is not copied to the instance. + +The following example shows how to use the `DontInherit` trait: + +
    + +
    + +## Transitive trait +Relationships can be marked as transitive. A formal-ish definition if transitivity in the context of relationships is: + +``` +If Relationship(EntityA, EntityB) +And Relationship(EntityB, EntityC) +Then Relationship(EntityA, EntityC) +``` + +What this means becomes more obvious when translated to a real-life example: + +> If Manhattan is located in New York, and New York is located in the USA, then Manhattan is located in the USA. + +In this example, `LocatedIn` is the relationship and `Manhattan`, `New York` and `USA` are entities `A`, `B` and `C`. Another common example of transitivity is found in OOP inheritance: + +> If a Square is a Rectangle and a Rectangle is a Shape, then a Square is a Shape. + +In this example `IsA` is the relationship and `Square`, `Rectangle` and `Shape` are the entities. + +When relationships in Flecs are marked as transitive, queries can follow the transitive relationship to see if an entity matches. Consider this example dataset: + +
    + +
    + +If we were now to query for `(LocatedIn, USA)` we would only match `NewYork`, because we never added `(LocatedIn, USA)` to `Manhattan`. To make sure queries `Manhattan` as well we have to make the `LocatedIn` relationship transitive. We can simply do this by adding the transitive trait to the relationship entity: + +
    + +
    + +When now querying for `(LocatedIn, USA)`, the query will follow the `LocatedIn` relationship and return both `NewYork` and `Manhattan`. For more details on how queries use transitivity, see the [Transitive Relationships section in the query manual](Queries.md#transitive-relationships). + +## Reflexive trait +A relationship can be marked reflexive which means that a query like `Relationship(Entity, Entity)` should evaluate to true. The utility of `Reflexive` becomes more obvious with an example: + +Given this dataset: +``` +IsA(Oak, Tree) +``` + +we can ask whether an oak is a tree: +``` +IsA(Oak, Tree) +- Yes, an Oak is a tree (Oak has (IsA, Tree)) +``` + +We can also ask whether a tree is a tree, which it obviously is: +``` +IsA(Tree, Tree) +- Yes, even though Tree does not have (IsA, Tree) +``` + +However, this does not apply to all relationships. Consider a dataset with a `LocatedIn` relationship: + +``` +LocatedIn(SanFrancisco, UnitedStates) +``` + +we can now ask whether SanFrancisco is located in SanFrancisco, which it is not: +``` +LocatedIn(SanFrancisco, SanFrancisco) +- No +``` + +In these examples, `IsA` is a reflexive relationship, whereas `LocatedIn` is not. + +## Acyclic trait +A relationship can be marked with the `Acyclic` trait to indicate that it cannot contain cycles. Both the builtin `ChildOf` and `IsA` relationships are marked acyclic. Knowing whether a relationship is acyclic allows the storage to detect and throw errors when a cyclic relationship is introduced by accident. + +Note that because cycle detection requires expensive algorithms, adding `Acyclic` to a relationship does not guarantee that an error will be thrown when a cycle is accidentally introduced. While detection may improve over time, an application that runs without errors is no guarantee that it does not contain acyclic relationships with cycles. + +## Traversable trait +Traversable relationships are allowed to be traversed automatically by queries, for example using the `up` bitflag (upwards traversal, see [query traversal flags](Queries.md#traversal-flags)). Traversable relationships are also marked as `Acyclic`, which ensures a query won't accidentally attempt to traverse a relationship that contains cycles. + +Events are propagated along the edges of traversable relationships. A typical example of this is when a component value is changed on a prefab. The event of this change will be propagated by traversing the `IsA` relationship downwards, for all instances of the prefab. Event propagation does not happen for relationships that are not marked with `Traversable`. + +## Exclusive trait +The `Exclusive` trait enforces that an entity can have only a single instance of a relationship. When a second instance is added, it replaces the first instance. An example of a relationship with the `Exclusive` trait is the builtin `ChildOf` relationship: + +
    + +
    + +To create a custom exclusive relationship, add the `Exclusive` trait: + +
    + +
    + +## Union trait +The `Union` is similar to `Exclusive` in that it enforces that an entity can have only a single instance of a relationship. The difference between `Exclusive` and `Union` is that `Union` combines different relationship targets in a single table. This reduces table fragmentation, and as a result speeds up add/remove operations. This increase in add/remove speed does come at a cost: iterating a query with union terms is more expensive than iterating a regular relationship. + +The API for using the `Union` trait is similar to regular relationships, as this example shows: + +
    + +
    + +When compared to regular relationships, union relationships have some differences and limitations: +- Relationship cleanup does not work yet for union relationships +- Removing a union relationship removes any target, even if the specified target is different +- Querys and rules do not support union relationships +- Union relationships cannot have data +- Union relationship query terms can use only the `And` operator +- Queries with a `(R, *)` term will return `(R, *)` as term id for each entity + +## Symmetric trait +The `Symmetric` trait enforces that when a relationship `(R, Y)` is added to entity `X`, the relationship `(R, X)` will be added to entity `Y`. The reverse is also true, if relationship `(R, Y)` is removed from `X`, relationship `(R, X)` will be removed from `Y`. + +The symmetric trait is useful for relationships that do not make sense unless they are bidirectional. Examples of such relationships are `AlliesWith`, `MarriedTo`, `TradingWith` and so on. An example: + +
    + +
    + +## With trait +The `With` relationship can be added to components to indicate that it must always come together with another component. The following example shows how `With` can be used with regular components/tags: + +
    + +
    + +When the `With` relationship is added to a relationship, the additional id added to the entity will be a relationship pair as well, with the same target as the original relationship: + +
    + +
    + +## OneOf trait +The `OneOf` trait enforces that the target of the relationship is a child of a specified entity. `OneOf` can be used to indicate that the target needs to be either a child of the relationship (common for enum relationships), or of another entity. + +The following example shows how to constrain the relationship target to a child of the relationship: + +
    + +
    + +The following example shows how `OneOf` can be used to enforce that the relationship target is the child of an entity other than the relationship: + +
    + +
    diff --git a/docs/Docs.md b/docs/Docs.md index 42a01b807..05306d852 100644 --- a/docs/Docs.md +++ b/docs/Docs.md @@ -10,7 +10,10 @@ ## Manuals - [Manual](Manual.md) - [Query Manual](Queries.md) +- [Query Language Manual](FlecsQueryLanguage.md) +- [Flecs Script Manual](FlecsScriptManual.md) - [Systems Manual](Systems.md) +- [Component Traits Manual](ComponentTraits.md) - [Relationships Manual](Relationships.md) - [JSON Format Manual](JsonFormat.md) - [REST API Manual](RestApi.md) diff --git a/docs/Relationships.md b/docs/Relationships.md index 704385eab..27306ca40 100644 --- a/docs/Relationships.md +++ b/docs/Relationships.md @@ -1431,1335 +1431,6 @@ Entity parent = world.Entity().Scope(() => Scopes are the mechanism that ensure contents of a module are created as children of the module, without having to explicitly add the module as a parent. -## Cleanup properties -When entities that are used as tags, components, relationships or relationship targets are deleted, cleanup policies ensure that the store does not contain any dangling references. Any cleanup policy provides this guarantee, so while they are configurable, applications cannot configure policies that allows for dangling references. - -**Note**: this only applies to entities (like tags, components, relationships) that are added _to_ other entities. It does not apply to components that store an entity value, so: - -
    - -
    - -The default policy is that any references to the entity will be **removed**. For example, when the tag `Archer` is deleted, it will be removed from all entities that have it, which is similar to invoking the `remove_all` operation: - -
    - -
    - -Since entities can be used in relationship pairs, just calling `remove_all` on just the entity itself does not guarantee that no dangling references are left. A more comprehensive description of what happens is: - -
    - -
    - -This succeeds in removing all possible references to `Archer`. Sometimes this behavior is not what we want however. Consider a parent-child hierarchy, where we want to delete the child entities when the parent is deleted. Instead of removing `(ChildOf, parent)` from all children, we need to _delete_ the children. - -We also want to specify this per relationship. If an entity has `(Likes, parent)` we may not want to delete that entity, meaning the cleanup we want to perform for `Likes` and `ChildOf` may not be the same. - -This is what cleanup policies are for: to specify which action needs to be executed under which condition. They are applied _to_ entities that have a reference to the entity being deleted: if I delete the `Archer` tag I remove the tag _from_ all entities that have it. - -To configure a cleanup policy for an entity, a `(Condition, Action)` pair can be added to it. If no policy is specified, the default cleanup action (`Remove`) is performed. - -There are three cleanup actions: - -- `Remove`: as if doing `remove_all(entity)` (default) -- `Delete`: as if doing `delete_with(entity)` -- `Panic`: throw a fatal error (default for components) - -There are two cleanup conditions: - -- `OnDelete`: the component, tag or relationship is deleted -- `OnDeleteTarget`: a target used with the relationship is deleted - -Policies apply to both regular and pair instances, so to all entities with `T` as well as `(T, *)`. - -### Examples -The following examples show how to use cleanup policies - -#### (OnDelete, Remove) - -
    - -
    - -#### (OnDelete, Delete) - -
    - -
    - -#### (OnDeleteTarget, Delete) - -
    - -
    - -### Cleanup order -While cleanup actions allow for specifying what needs to happen when a particular entity is deleted, or when an entity used with a particular relationship is deleted, they do not enforce a strict cleanup _order_. The reason for this is that there can be many orderings that satisfy the cleanup policies. - -This is important to consider especially when writing `OnRemove` triggers or hooks, as the order in which they are invoked highly depends on the order in which entities are cleaned up. - -Take an example with a parent and a child that both have the `Node` tag: - -
    - -
    - -In this example, when calling `p.destruct()` the observer is first invoked for the child, and then for the parent, which is to be expected as the child is deleted before the parent. Cleanup policies do not however guarantee that this is always the case. - -An application could also call `world.component().destruct()` which would delete the `Node` component and all of its instances. In this scenario the cleanup policies for the `ChildOf` relationship are not considered, and therefore the ordering is undefined. Another typical scenario in which ordering is undefined is when an application has cyclical relationships with a `Delete` cleanup action. - -#### Cleanup order during world teardown -Cleanup issues often show up during world teardown as the ordering in which entities are deleted is controlled by the application. While world teardown respects cleanup policies, there can be many entity delete orderings that are valid according to the cleanup policies, but not all of them are equally useful. There are ways to organize entities that helps world cleanup to do the right thing. These are: - -**Organize components, triggers, observers and systems in modules.** -Storing these entities in modules ensures that they stay alive for as long as possible. This leads to more predictable cleanup ordering as components will be deleted as their entities are, vs. when the component is deleted. It also ensures that triggers and observers are not deleted while matching events are still being generated. - -**Avoid organizing components, triggers, observers and systems under entities that are not modules**. If a non-module entity with children is stored in the root, it will get cleaned up along with other regular entities. If you have entities such as these organized in a non-module scope, consider adding the `EcsModule`/`flecs::Module`/`Ecs.Module` tag to the root of that scope. - -The next section goes into more detail on why this improves cleanup behavior and what happens during world teardown. - -#### World teardown sequence -To understand why some ways to organize entities work better than others, having an overview of what happens during world teardown is useful. Here is a list of the steps that happen when a world is deleted: - -1. **Find all root entities** -World teardown starts by finding all root entities, which are entities that do not have the builtin `ChildOf` relationship. Note that empty entities (entities without any components) are not found during this step. - -2. **Query out modules, components, observers and systems** -This ensures that components are not cleaned up before the entities that use them, and triggers, observers and systems are not cleaned up while there are still conditions under which they could be invoked. - -3. **Query out entities that have no children** -If entities have no children they cannot cause complex cleanup logic. This also decreases the likelihood of initiating cleanup actions that could impact other entities. - -4. **Delete root entities** -The root entities that were not filtered out will be deleted. - -5. **Delete everything else** -The last step will delete all remaining entities. At this point cleanup policies are no longer considered and cleanup order is undefined. - -## Relationship properties -Relationship properties are tags that can be added to relationships to modify their behavior. - -## Trait property -The trait property marks an entity as a trait, which is any tag that is added to another tag/component/relationship to modify its behavior. All properties in this section are marked as trait. It is not required to mark a property as a trait before adding it to another tag/component/relationship. The main reason for the trait property is to ease some of the constraints on relationships (see the Relationship property). - -```c -ECS_TAG(world, Serializable); - -ecs_add_id(world, Serializable, EcsTrait); -``` - - -
  • C++ - -```cpp -struct Serializable { }; - -world.component().add(flecs::Trait); -``` - -
  • -
  • C# - -```cs -public struct Serializable { } - -world.Component().Entity.Add(Ecs.Trait); -``` - -
  • - - - -## Relationship property -The relationship property enforces that an entity can only be used as relationship. Consider the following example: - -```c -ECS_TAG(world, Likes); -ECS_TAG(world, Apples); - -ecs_add_id(world, Likes, EcsRelationship); - -ecs_entity_t e = ecs_new_id(world); -ecs_add(world, Likes); // Panic, 'Likes' is not used as relationship -ecs_add_pair(world, Apples, Likes); // Panic, 'Likes' is not used as relationship -ecs_add_pair(world, Likes, Apples); // OK -``` - - -
  • C++ - -```cpp -struct Likes { }; -struct Apples { }; - -world.component().add(flecs::Relationship); - -flecs::entity e = world.entity() - .add() // Panic, 'Likes' is not used as relationship - .add() // Panic, 'Likes' is not used as relationship - .add(); // OK -``` - -
  • -
  • C# - -```cs -public struct Likes { } -public struct Apples { } - -world.Component().Entity.Add(Ecs.Relationship); - -Entity e = ecs.Entity() - .Add() // Panic, 'Likes' is not used as relationship - .Add() // Panic, 'Likes' is not used as relationship - .add(); // OK -``` - -
  • - - - -Entities marked with `Relationship` may still be used as target if the relationship part of the pair has the `Trait` property. This ensures the relationship can still be used to configure the behavior of other entities. Consider the following code example: - -```c -ECS_TAG(world, Likes); -ECS_TAG(world, Loves); - -ecs_add_id(world, Likes, EcsRelationship); - -// Even though Likes is marked as relationship and used as target here, this -// won't panic as With is marked as trait. -ecs_add_pair(world, Loves, EcsWith, Likes); -``` - - -
  • C++ - -```cpp -struct Likes { }; -struct Loves { }; - -world.component().add(flecs::Relationship); - -// Even though Likes is marked as relationship and used as target here, this -// won't panic as With is marked as trait. -world.component().add(flecs::With, world.component()); -``` - -
  • -
  • C# - -```cs -public struct Likes { } -public struct Loves { } - -world.Component().Entity.Add(Ecs.Relationship); - -world.Component().Entity.Add(Ecs.With, world.Component().Entity); -``` - -
  • - - - -## Target property -The target property enforces that an entity can only be used as relationship target. Consider the following example: - -```c -ECS_TAG(world, Likes); -ECS_TAG(world, Apples); - -ecs_add_id(world, Apples, EcsTarget); - -ecs_entity_t e = ecs_new_id(world); -ecs_add(world, Apples); // Panic, 'Apples' is not used as target -ecs_add_pair(world, Apples, Likes); // Panic, 'Apples' is not used as target -ecs_add_pair(world, Likes, Apples); // OK -``` - - -
  • C++ - -```cpp -struct Likes { }; -struct Apples { }; - -world.component().add(flecs::Target); - -flecs::entity e = world.entity() - .add() // Panic, 'Apples' is not used as target - .add() // Panic, 'Apples' is not used as target - .add(); // OK -``` - -
  • -
  • C# - -```cs -public struct Likes { } -public struct Apples { } - -world.Component().Entity.Add(Ecs.Target); - -Entity e = ecs.Entity() - .Add() // Panic, 'Apples' is not used as target - .Add() // Panic, 'Apples' is not used as target - .add(); // OK -``` - -
  • - - - -### PairIsTag property -A relationship can be marked with PairIsTag in which case a pair with the relationship will never contain data. By default the data associated with a pair is determined by whether either the relationship or target are components. For some relationships however, even if the target is a component, no data should be added to the relationship. Consider the following example: - -
    -
      -
    • C - -```c -typedef struct { - float x; - float y; -} Position; - -ECS_TAG(world, Serializable); -ECS_COMPONENT(world, Position); - -ecs_entity_t e = ecs_new(world); -ecs_set(world, e, Position, {10, 20}); -ecs_add_pair(world, e, Serializable, ecs_id(Position)); - -// Gets value from Position component -const Position *p = ecs_get(world, e, Position); - -// Gets (unintended) value from (Serializable, Position) pair -const Position *p = ecs_get_pair_second(world, e, Serializable, Position); -``` - -
    • -
    • C++ - -```cpp -struct Serializable { }; // Tag, contains no data - -struct Position { - float x, y; -}; - -auto e = ecs.entity() - .set({10, 20}) - .add(); // Because Serializable is a tag, the pair - // has a value of type Position - -// Gets value from Position component -const Position *p = e.get(); - -// Gets (unintended) value from (Serializable, Position) pair -const Position *p = e.get(); -``` - -
    • -
    • C# - -```cs -public struct Serializable { } // Tag, contains no data - -public record struct Position(float X, float Y); - -Entity e = ecs.Entity() - .Set(new(10, 20)) - .Add(); // Because Serializable is a tag, the pair - // has a value of type Position - -// Gets value from Position component -ref readonly Position p = ref e.Get(); - -// Gets (unintended) value from (Serializable, Position) pair -ref readonly Position p = ref e.GetSecond(); -``` - -
    • -
    -
    - -To prevent data from being associated with pairs that can apply to components, the `Tag` property can be added to relationships: - -
    -
      -
    • C - -```c -// Ensure that Serializable never contains data -ecs_add_id(world, Serializable, EcsPairIsTag); - -// Because Serializable is marked as a Tag, no data is added for the pair -// even though Position is a component -ecs_add_pair(world, e, Serializable, ecs_id(Position)); - -// This is still OK -const Position *p = ecs_get(world, e, Position); - -// This no longer works, the pair has no data -const Position *p = ecs_get_pair_second(world, e, Serializable, Position); -``` - -
    • -
    • C++ - -```cpp -// Ensure that Serializable never contains data -ecs.component() - .add(); - -auto e = ecs.entity() - .set({10, 20}) - .add(); // Because Serializable marked as a Tag, no - // data is added for the pair even though - // Position is a component - -// Gets value from Position component -const Position *p = e.get(); - -// This no longer works, the pair has no data -const Position *p = e.get(); -``` - -
    • -
    • C# - -```cs -// Ensure that Serializable never contains data -ecs.Component().Entity - .Add(); - -Entity e = ecs.Entity() - .Set(new(10, 20)) - .Add(); // Because Serializable marked as a Tag, no - // data is added for the pair even though - // Position is a component - -// Gets value from Position component -ref readonly Position p = ref e.Get(); - -// This no longer works, the pair has no data -ref readonly Position p = ref e.GetSecond(); -``` - -
    • -
    -
    - -The `Tag` property is only interpreted when it is added to the relationship part of a pair. - -### Final property -Entities can be annotated with the `Final` property, which prevents using them with `IsA` relationship. This is similar to the concept of a final class as something that cannot be extended. The following example shows how use `Final`: - -
    -
      -
    • C - -```c -ecs_entity_t e = ecs_new(world); -ecs_add_id(world, e, EcsFinal); - -ecs_entity_t i = ecs_new(world); -ecs_add_pair(world, e, i, EcsIsA, e); // not allowed -``` - -
    • -
    • C++ - -```cpp -auto e = ecs.entity() - .add(flecs::Final); - -auto i = ecs.entity() - .is_a(e); // not allowed -``` - -
    • -
    • C# - -```cs -Entity e = ecs.Entity() - .Add(Ecs.Final); - -Entity i = ecs.Entity() - .IsA(e); // not allowed -``` - -
    • -
    -
    - -Queries may use the final property 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). By default, all components are created as final. - -### DontInherit property -The `DontInherit` property prevents inheriting a component from a base entity (`IsA` target). Consider the following example: - -
    -
      -
    • C - -```c -ecs_entity_t TagA = ecs_new(world); -ecs_entity_t TagB = ecs_new(world); -ecs_add_id(world, TagB, EcsDontInherit); - -ecs_entity_t base = ecs_new(world); -ecs_add_id(world, base, TagA); -ecs_add_id(world, base, TagB); - -ecs_entity_t inst = ecs_new_w_pair(world, base); -ecs_has_id(world, inst, TagA); // true -ecs_has_id(world, inst, TagB); // false -``` - -
    • -
    • C++ - -```cpp -struct TagA = { }; -struct TagB = { }; - -world.component().add(flecs::DontInherit); - -auto base = world.entity() - .add() - .add(); - -auto inst = world.entity().is_a(base); -inst.has(); // true -inst.has(); // false -``` - -
    • -
    • C# - -```cs -public struct TagA { } -public struct TagB { } - -world.Component().Entity.Add(Ecs.DontInherit); - -Entity @base = world.Entity() - .Add() - .Add(); - -Entity inst = world.Entity().IsA(@base); -inst.Has(); // true -inst.Has(); // false -``` - -
    • -
    -
    - -The builtin `Prefab`, `Disabled`, `Identifier` and `ChildOf` tags/relationships are marked as `DontInherit`. - -### AlwaysOverride property -The `AlwaysOverride` property ensures that a component is always automatically overridden when an inheritance (`IsA`) relationship is added. The behavior of this property is as if `auto_override | Component` is always added together with `Component`. - -
    -
      -
    • C - -```c -ECS_COMPONENT(world, Position); -ECS_COMPONENT(world, Velocity); - -ecs_add_id(world, ecs_id(Position), EcsAlwaysOverride); - -ecs_entity_t base = ecs_new(world); -ecs_set(world, base, Position, {10, 20}); -ecs_set(world, base, Velocity, {1, 2}); - -ecs_entity_t inst = ecs_new_w_pair(world, base); -ecs_has(world, inst, Position); // true -ecs_has(world, inst, Velocity); // true -ecs_owns(world, inst, Position); // true -ecs_owns(world, inst, Velocity); // false -``` - -
    • -
    • C++ - -```cpp -world.component().add(flecs::AlwaysOverride); - -auto base = world.entity() - .set({10, 20}) - .add({1, 2}) - -auto inst = world.entity().is_a(base); -inst.has(); // true -inst.has(); // true -inst.owns(); // true -inst.owns(); // false -``` - -
    • -
    • C# - -```cs -world.Component().Entity.Add(Ecs.AlwaysOverride); - -Entity @base = world.Entity() - .Set(new(10, 20)) - .Add(new(1, 2)) - -Entity inst = world.Entity().IsA(@base); -inst.Has(); // true -inst.Has(); // true -inst.Owns(); // true -inst.Owns(); // false -``` - -
    • -
    -
    - -### Transitive property -Relationships can be marked as transitive. A formal-ish definition if transitivity in the context of relationships is: - -``` -If Relationship(EntityA, EntityB) And Relationship(EntityB, EntityC) Then Relationship(EntityA, EntityC) -``` - -What this means becomes more obvious when translated to a real-life example: - -``` -If Manhattan is located in New York, and New York is located in the USA, then Manhattan is located in the USA. -``` - -In this example, `LocatedIn` is the relationship and `Manhattan`, `New York` and `USA` are entities `A`, `B` and `C`. Another common example of transitivity is found in OOP inheritance: - -``` -If a Square is a Rectangle and a Rectangle is a Shape, then a Square is a Shape. -``` - -In this example `IsA` is the relationship and `Square`, `Rectangle` and `Shape` are the entities. - -When relationships in Flecs are marked as transitive, queries can follow the transitive relationship to see if an entity matches. Consider this example dataset: - -
    -
      -
    • C - -```c -ecs_entity_t LocatedIn = ecs_new(world); -ecs_entity_t Manhattan = ecs_new(world); -ecs_entity_t NewYork = ecs_new(world); -ecs_entity_t USA = ecs_new(world); - -ecs_add_pair(world, Manhattan, LocatedIn, NewYork); -ecs_add_pair(world, NewYork, LocatedIn, USA); -``` - -
    • -
    • C++ - -```cpp -auto LocatedIn = world.entity(); -auto Manhattan = world.entity(); -auto NewYork = world.entity(); -auto USA = world.entity(); - -Manhattan.add(LocatedIn, NewYork); -NewYork.add(LocatedIn, USA); -``` - -
    • -
    • C# - -```cs -Entity LocatedIn = world.Entity(); -Entity Manhattan = world.Entity(); -Entity NewYork = world.Entity(); -Entity USA = world.Entity(); - -Manhattan.Add(LocatedIn, NewYork); -NewYork.Add(LocatedIn, USA); -``` - -
    • -
    -
    - -If we were now to query for `(LocatedIn, USA)` we would only match `NewYork`, because we never added `(LocatedIn, USA)` to `Manhattan`. To make sure queries `Manhattan` as well we have to make the `LocatedIn` relationship transitive. We can simply do this by adding the transitive property to the relationship entity: - -
    -
      -
    • C - -```c -ecs_add_id(world, LocatedIn, Transitive); -``` - -
    • -
    • C++ - -```cpp -LocatedIn.add(flecs::Transitive); -``` - -
    • -
    • C# - -```cs -LocatedIn.Add(Ecs.Transitive); -``` - -
    • -
    -
    - -When now querying for `(LocatedIn, USA)`, the query will follow the `LocatedIn` relationship and return both `NewYork` and `Manhattan`. For more details on how queries use transitivity, see the [Transitive Relationships section in the query manual](Queries.md#transitive-relationships). - -### Reflexive property -A relationship can be marked reflexive which means that a query like `Relationship(Entity, Entity)` should evaluate to true. The utility of `Reflexive` becomes more obvious with an example: - -Given this dataset: -``` -IsA(Oak, Tree) -``` - -we can ask whether an oak is a tree: -``` -IsA(Oak, Tree) -- Yes, an Oak is a tree (Oak has (IsA, Tree)) -``` - -We can also ask whether a tree is a tree, which it obviously is: -``` -IsA(Tree, Tree) -- Yes, even though Tree does not have (IsA, Tree) -``` - -However, this does not apply to all relationships. Consider a dataset with a `LocatedIn` relationship: - -``` -LocatedIn(SanFrancisco, UnitedStates) -``` - -we can now ask whether SanFrancisco is located in SanFrancisco, which it is not: -``` -LocatedIn(SanFrancisco, SanFrancisco) -- No -``` - -In these examples, `IsA` is a reflexive relationship, whereas `LocatedIn` is not. - -### Acyclic property -A relationship can be marked with the `Acyclic` property to indicate that it cannot contain cycles. Both the builtin `ChildOf` and `IsA` relationships are marked acyclic. Knowing whether a relationship is acyclic allows the storage to detect and throw errors when a cyclic relationship is introduced by accident. - -Note that because cycle detection requires expensive algorithms, adding `Acyclic` to a relationship does not guarantee that an error will be thrown when a cycle is accidentally introduced. While detection may improve over time, an application that runs without errors is no guarantee that it does not contain acyclic relationships with cycles. - -### Traversable property -Traversable relationships are allowed to be traversed automatically by queries, for example using the `up` bitflag (upwards traversal, see [query traversal flags](Queries.md#traversal-flags)). Traversable relationships are also marked as `Acyclic`, which ensures a query won't accidentally attempt to traverse a relationship that contains cycles. - -Events are propagated along the edges of traversable relationships. A typical example of this is when a component value is changed on a prefab. The event of this change will be propagated by traversing the `IsA` relationship downwards, for all instances of the prefab. Event propagation does not happen for relationships that are not marked with `Traversable`. - -### Exclusive property -The `Exclusive` property enforces that an entity can have only a single instance of a relationship. When a second instance is added, it replaces the first instance. An example of a relationship with the `Exclusive` property is the builtin `ChildOf` relationship: - -
    -
      -
    • C - -```c -ecs_add_pair(world, child, EcsChildOf, parent_a); -ecs_add_pair(world, child, EcsChildOf, parent_b); // replaces (ChildOf, parent_a) -``` - -
    • -
    • C++ - -```cpp -e.child_of(parent_a); -e.child_of(parent_b); // replaces (ChildOf, parent_a) -``` - -
    • -
    • C# - -```cs -e.ChildOf(parentA); -e.ChildOf(parentB); // replaces (ChildOf, parentA) -``` - -
    • -
    -
    - -To create a custom exclusive relationship, add the `Exclusive` property: - -
    -
      -
    • C - -```c -ecs_entity_t MarriedTo = ecs_new(world); -ecs_add_id(world, MarriedTo, EcsExclusive); -``` - -
    • -
    • C++ - -```cpp -flecs::entity MarriedTo = world.entity() - .add(flecs::Exclusive); -``` - -
    • -
    • C# - -```cs -Entity MarriedTo = world.Entity() - .Add(Ecs.Exclusive); -``` - -
    • -
    -
    - -### Union property -The `Union` is similar to `Exclusive` in that it enforces that an entity can have only a single instance of a relationship. The difference between `Exclusive` and `Union` is that `Union` combines different relationship targets in a single table. This reduces table fragmentation, and as a result speeds up add/remove operations. This increase in add/remove speed does come at a cost: iterating a query with union terms is more expensive than iterating a regular relationship. - -The API for using the `Union` property is similar to regular relationships, as this example shows: - -
    -
      -
    • C - -```c -ecs_entity_t Movement = ecs_new(world); -ecs_add_id(world, Movement, EcsUnion); - -ecs_entity_t Walking = ecs_new(world); -ecs_entity_t Running = ecs_new(world); - -ecs_entity_t e = ecs_new(world); -ecs_add_pair(world, e, Movement, Running); -ecs_add_pair(world, e, Movement, Walking); // replaces (Movement, Running) -``` - -
    • -
    • C++ - -```cpp -flecs::entity Movement = world.entity().add(flecs::Union); -flecs::entity Walking = world.entity(); -flecs::entity Running = world.entity(); - -flecs::entity e = world.entity().add(Movement, Running); -e.add(Movement, Walking); // replaces (Movement, Running) -``` - -
    • -
    • C# - -```cs -Entity Movement = world.Entity().Add(Ecs.Union); -Entity Walking = world.Entity(); -Entity Running = world.Entity(); - -Entity e = world.Entity().Add(Movement, Running); -e.Add(Movement, Walking); // replaces (Movement, Running) -``` - -
    • -
    -
    - -When compared to regular relationships, union relationships have some differences and limitations: -- Relationship cleanup does not work yet for union relationships -- Removing a union relationship removes any target, even if the specified target is different -- Querys and rules do not support union relationships -- Union relationships cannot have data -- Union relationship query terms can use only the `And` operator -- Queries with a `(R, *)` term will return `(R, *)` as term id for each entity - -### Symmetric property -The `Symmetric` property enforces that when a relationship `(R, Y)` is added to entity `X`, the relationship `(R, X)` will be added to entity `Y`. The reverse is also true, if relationship `(R, Y)` is removed from `X`, relationship `(R, X)` will be removed from `Y`. - -The symmetric property is useful for relationships that do not make sense unless they are bidirectional. Examples of such relationships are `AlliesWith`, `MarriedTo`, `TradingWith` and so on. An example: - -
    -
      -
    • C - -```c -ecs_entity_t MarriedTo = ecs_new_w_id(world, EcsSymmetric); -ecs_entity_t Bob = ecs_new(world); -ecs_entity_t Alice = ecs_new(world); -ecs_add_pair(world, Bob, MarriedTo, Alice); // Also adds (MarriedTo, Bob) to Alice -``` - -
    • -
    • C++ - -```cpp -auto MarriedTo = world.entity().add(flecs::Symmetric); -auto Bob = ecs.entity(); -auto Alice = ecs.entity(); -Bob.add(MarriedTo, Alice); // Also adds (MarriedTo, Bob) to Alice -``` - -
    • -
    • C# - -```cs -Entity MarriedTo = world.Entity().Add(Ecs.Symmetric); -Entity Bob = ecs.Entity(); -Entity Alice = ecs.Entity(); -Bob.Add(MarriedTo, Alice); // Also adds (MarriedTo, Bob) to Alice -``` - -
    • -
    -
    - -### With property -The `With` relationship can be added to components to indicate that it must always come together with another component. The following example shows how `With` can be used with regular components/tags: - -
    -
      -
    • C - -```c -ecs_entity_t Responsibility = ecs_new(world); -ecs_entity_t Power = ecs_new_w_pair(world, EcsWith, Responsibility); - -// Create new entity that has both Power and Responsibility -ecs_entity_t e = ecs_new_w_id(world, Power); -``` - -
    • -
    • C++ - -```cpp -auto Responsibility = world.entity(); -auto Power = world.entity().add(flecs::With, Responsibility); - -// Create new entity that has both Power and Responsibility -auto e = world.entity().add(Power); -``` - -
    • -
    • C# - -```cs -Entity Responsibility = world.Entity(); -Entity Power = world.Entity().Add(Ecs.With, Responsibility); - -// Create new entity that has both Power and Responsibility -Entity e = world.Entity().Add(Power); -``` - -
    • -
    -
    - -When the `With` relationship is added to a relationship, the additional id added to the entity will be a relationship pair as well, with the same target as the original relationship: - -
    -
      -
    • C - -```c -ecs_entity_t Likes = ecs_new(world); -ecs_entity_t Loves = ecs_new_w_pair(world, EcsWith, Likes); -ecs_entity_t Pears = ecs_new(world); - -// Create new entity with both (Loves, Pears) and (Likes, Pears) -ecs_entity_t e = ecs_new_w_pair(world, Loves, Pears); -``` - -
    • -
    • C++ - -```cpp -auto Likes = world.entity(); -auto Loves = world.entity().add(flecs::With, Likes); -auto Pears = world.entity(); - -// Create new entity with both (Loves, Pears) and (Likes, Pears) -auto e = world.entity().add(Loves, Pears); -``` - -
    • -
    • C# - -```cs -Entity Likes = world.Entity(); -Entity Loves = world.Entity().Add(Ecs.With, Likes); -Entity Pears = world.Entity(); - -// Create new entity with both (Loves, Pears) and (Likes, Pears) -Entity e = world.Entity().Add(Loves, Pears); -``` - -
    • -
    -
    - -### OneOf property -The `OneOf` property enforces that the target of the relationship is a child of a specified entity. `OneOf` can be used to indicate that the target needs to be either a child of the relationship (common for enum relationships), or of another entity. - -The following example shows how to constrain the relationship target to a child of the relationship: - -
    -
      -
    • C - -```c -ecs_entity_t Food = ecs_new(world); - -// Enforce that target of relationship is child of Food -ecs_add_id(world, Food, EcsOneOf); - -ecs_entity_t Apples = ecs_new_w_pair(world, EcsChildOf, Food); -ecs_entity_t Fork = ecs_new(world); - -// This is ok, Apples is a child of Food -ecs_entity_t a = ecs_new_w_pair(world, Food, Apples); - -// This is not ok, Fork is not a child of Food -ecs_entity_t b = ecs_new_w_pair(world, Food, Fork); -``` - -
    • -
    • C++ - -```cpp -// Enforce that target of relationship is child of Food -auto Food = world.entity().add(flecs::OneOf); -auto Apples = world.entity().child_of(Food); -auto Fork = world.entity(); - -// This is ok, Apples is a child of Food -auto a = world.entity().add(Food, Apples); - -// This is not ok, Fork is not a child of Food -auto b = world.entity().add(Food, Fork); -``` - -
    • -
    • C# - -```cs -// Enforce that target of relationship is child of Food -Entity Food = world.Entity().Add(Ecs.OneOf); -Entity Apples = world.Entity().ChildOf(Food); -Entity Fork = world.Entity(); - -// This is ok, Apples is a child of Food -Entity a = world.Entity().Add(Food, Apples); - -// This is not ok, Fork is not a child of Food -Entity b = world.Entity().Add(Food, Fork); -``` - -
    • -
    -
    - -The following example shows how `OneOf` can be used to enforce that the relationship target is the child of an entity other than the relationship: - -
    -
      -
    • C - -```c -ecs_entity_t Food = ecs_new(world); -ecs_entity_t Eats = ecs_new(world); - -// Enforce that target of relationship is child of Food -ecs_add_pair(world, Eats, EcsOneOf, Food); - -ecs_entity_t Apples = ecs_new_w_pair(world, EcsChildOf, Food); -ecs_entity_t Fork = ecs_new(world); - -// This is ok, Apples is a child of Food -ecs_entity_t a = ecs_new_w_pair(world, Eats, Apples); - -// This is not ok, Fork is not a child of Food -ecs_entity_t b = ecs_new_w_pair(world, Eats, Fork); -``` - -
    • -
    • C++ - -```cpp -// Enforce that target of relationship is child of Food -auto Food = world.entity(); -auto Eats = world.entity().add(flecs::OneOf, Food); -auto Apples = world.entity().child_of(Food); -auto Fork = world.entity(); - -// This is ok, Apples is a child of Food -auto a = world.entity().add(Eats, Apples); - -// This is not ok, Fork is not a child of Food -auto b = world.entity().add(Eats, Fork); -``` - -
    • -
    • C# - -```cs -// Enforce that target of relationship is child of Food -Entity Food = world.Entity(); -Entity Eats = world.Entity().Add(Ecs.OneOf, Food); -Entity Apples = world.Entity().ChildOf(Food); -Entity Fork = world.Entity(); - -// This is ok, Apples is a child of Food -Entity a = world.Entity().Add(Eats, Apples); - -// This is not ok, Fork is not a child of Food -Entity b = world.Entity().Add(Eats, Fork); -``` - -
    • -
    -
    - ## Relationship performance This section goes over the performance implications of using relationships. diff --git a/docs/cfg/Doxyfile b/docs/cfg/Doxyfile index e2957f875..e6e048cc9 100644 --- a/docs/cfg/Doxyfile +++ b/docs/cfg/Doxyfile @@ -948,9 +948,12 @@ INPUT = include/flecs.h \ docs/FAQ.md \ docs/DesignWithFlecs.md \ docs/FlecsScriptTutorial.md \ + docs/FlecsScriptManual.md \ docs/Manual.md \ docs/Queries.md \ + docs/FlecsQueryLanguage.md \ docs/Systems.md \ + docs/ComponentTraits.md \ docs/Relationships.md \ docs/RestApi.md \ docs/JsonFormat.md diff --git a/flecs.h b/flecs.h index cbd8ea50b..da7360b81 100644 --- a/flecs.h +++ b/flecs.h @@ -3258,7 +3258,7 @@ typedef enum ecs_oper_kind_t { typedef enum ecs_query_cache_kind_t { EcsQueryCacheDefault, /**< Behavior determined by query creation context */ EcsQueryCacheAuto, /**< Cache query terms that are cacheable */ - EcsQueryCacheAll, /**< Require that all query terms are cached */ + EcsQueryCacheAll, /**< Require that all query terms can be cached */ EcsQueryCacheNone, /**< No caching */ } ecs_query_cache_kind_t; @@ -28046,14 +28046,14 @@ struct term_ref_builder_i { /* The self flag indicates the term identifier itself is used */ Base& self() { - this->assert_term_id(); + this->assert_term_ref(); term_ref_->id |= flecs::Self; return *this; } /* Specify value of identifier by id */ Base& id(flecs::entity_t id) { - this->assert_term_id(); + this->assert_term_ref(); term_ref_->id = id; return *this; } @@ -28067,14 +28067,14 @@ struct term_ref_builder_i { * both id(entity_t) and id(const char*). */ Base& entity(flecs::entity_t entity) { - this->assert_term_id(); + this->assert_term_ref(); term_ref_->id = entity | flecs::IsEntity; return *this; } /* Specify value of identifier by name */ Base& name(const char *name) { - this->assert_term_id(); + this->assert_term_ref(); term_ref_->id |= flecs::IsEntity; term_ref_->name = const_cast(name); return *this; @@ -28082,7 +28082,7 @@ struct term_ref_builder_i { /* Specify identifier is a variable (resolved at query evaluation time) */ Base& var(const char *var_name) { - this->assert_term_id(); + this->assert_term_ref(); term_ref_->id |= flecs::IsVariable; term_ref_->name = const_cast(var_name); return *this; @@ -28090,7 +28090,7 @@ struct term_ref_builder_i { /* Override term id flags */ Base& flags(flecs::flags32_t flags) { - this->assert_term_id(); + this->assert_term_ref(); term_ref_->id = flags; return *this; } @@ -28100,7 +28100,7 @@ struct term_ref_builder_i { protected: virtual flecs::world_t* world_v() = 0; - void assert_term_id() { + void assert_term_ref() { ecs_assert(term_ref_ != NULL, ECS_INVALID_PARAMETER, "no active term (call .term() first)"); } @@ -28237,7 +28237,7 @@ struct term_builder_i : term_ref_builder_i { * traversing a relationship upwards. For example: substitute the identifier * with its parent by traversing the ChildOf relationship. */ Base& up(flecs::entity_t trav = 0) { - this->assert_term_id(); + this->assert_term_ref(); ecs_check(this->term_ref_ != &term_->first, ECS_INVALID_PARAMETER, "up traversal can only be applied to term source"); ecs_check(this->term_ref_ != &term_->second, ECS_INVALID_PARAMETER, @@ -28258,7 +28258,7 @@ struct term_builder_i : term_ref_builder_i { /* The cascade flag is like up, but returns results in breadth-first order. * Only supported for flecs::query */ Base& cascade(flecs::entity_t trav = 0) { - this->assert_term_id(); + this->assert_term_ref(); this->up(); this->term_ref_->id |= flecs::Cascade; if (trav) { @@ -28274,7 +28274,7 @@ struct term_builder_i : term_ref_builder_i { /* Use with cascade to iterate results in descending (bottom -> top) order */ Base& desc() { - this->assert_term_id(); + this->assert_term_ref(); this->term_ref_->id |= flecs::Desc; return *this; } @@ -28286,7 +28286,7 @@ struct term_builder_i : term_ref_builder_i { /* Specify relationship to traverse, and flags to indicate direction */ Base& trav(flecs::entity_t trav, flecs::flags32_t flags = 0) { - this->assert_term_id(); + this->assert_term_ref(); term_->trav = trav; this->term_ref_->id |= flags; return *this; @@ -28688,7 +28688,7 @@ struct query_builder_i : term_builder_i { return *this; } - Base& flags(ecs_flags32_t flags) { + Base& query_flags(ecs_flags32_t flags) { desc_->flags |= flags; return *this; }