Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Building Games in ECS with Entity Relationships

Discussion in 'Entity Component System' started by davenirline, Apr 8, 2022.

  1. davenirline

    davenirline

    Joined:
    Jul 7, 2010
    Posts:
    943
    Article here. Relationships are added as partner components and they can be queried. Just find it interesting.
     
    JoNax97, mikaelK, Micz84 and 7 others like this.
  2. JesOb

    JesOb

    Joined:
    Sep 3, 2012
    Posts:
    1,081
    Submited it as Idea to DOTS roadmap with link to this thread
     
    Radivarig likes this.
  3. JesOb

    JesOb

    Joined:
    Sep 3, 2012
    Posts:
    1,081
    davenirline likes this.
  4. JesOb

    JesOb

    Joined:
    Sep 3, 2012
    Posts:
    1,081
  5. vectorized-runner

    vectorized-runner

    Joined:
    Jan 22, 2018
    Posts:
    383
    This looks like Shared Components in DOTS, but worse. What happens to the data layout when a component is added multiple times, does it move to different archetype? It looks like there isn't much focus on Data layout here, just adding some shiny features to a ECS engine
     
    Opeth001, RaL and Luxxuor like this.
  6. JesOb

    JesOb

    Joined:
    Sep 3, 2012
    Posts:
    1,081
    I thought that it looks like SCD too but it dont
    It is simple ComponentData just more powerful and most shine is not component at all but query system that can query not only based on one archetype but based by different archetype relations like in relational DBs (query through few tables)

    And from work of author it is as performant as simple query touching one archetype

    All this very interesting but what pros and cons would be in context of Unity ECS is not fully understandable for now.
     
    Vacummus likes this.
  7. Vacummus

    Vacummus

    Joined:
    Dec 18, 2013
    Posts:
    191
    May want to give it another read. It's very different from Shared Components (SharedComponents is a grouping/optimization technique, this is a data relationship technique) and the author talks a lot about data layout.

    That's where I stand on this right now. I like it, BUT I would need to see or play around with more examples to see what benefits this offers over traditional ways of dealing with data relationships in ECS. But as with many things in DOD, the pros and cons often vary based on the use case.
     
    davenirline, JesOb and RaL like this.
  8. Krooq

    Krooq

    Joined:
    Jan 30, 2013
    Posts:
    180
    +1 for this. This pattern is used everywhere, it would be great to have first class support for it.
     
  9. vectorized-runner

    vectorized-runner

    Joined:
    Jan 22, 2018
    Posts:
    383
    How are they stored after adding relationships (archetypes)? I still don't know after giving it another read.
     
  10. JesOb

    JesOb

    Joined:
    Sep 3, 2012
    Posts:
    1,081
    As I understand they have both variants of store
    - one is unique component type id for every relationship (entity id used as component type) it is more like SCD
    - second more relaxed where it more like simple CD with single field Entity value

    Most power comes from query system that can do more complicated lookup across different archetypes using relations like in relational DBs. To do this in DB you need index on primary key and as I understand every relation is exactly index. ECS internals tracks all entities that belong to index (has some relation) same as entities belonging to some archetype but in relation to relation component :)
    because of this request through relation is fast.

    May be we can create logic like this by creating system that will react to every relation component added and keep track of index + new JobType to filter by relation before processing

    But really want Unity Team to learn from this idea and find best way to implement it for Unity Entities
     
    davenirline likes this.
  11. ElliotB

    ElliotB

    Joined:
    Aug 11, 2013
    Posts:
    215
    Out of interest, what advantages does this give over storing the links as entities themselves? Eg an entity with Attack, Source and Target components can still be queried as first class (e.g. 'get all attacks')
     
  12. scottjdaley

    scottjdaley

    Joined:
    Aug 1, 2013
    Posts:
    152
    Any time you need more information about the attack's source or target you'll need random memory access to fetch the components from those entities. For example, you would probably want to retrieve the sources damage and the target's health, and then write a new value to the health on the target.

    There is also no easy way to access all of the attacks the correspond with a particular source or target. The feature described in the article is able to efficiently lookup all attacks from a particular source and then even do a chained lookup to get all health components on those targets.

    I really like the ideas from this article, especially the powerful queries that can be performed. A lot of the systems I write in unity ECS have to iterate a bunch of entities with entity references and then fetch components from those references using ComponentDataFromEntity (unfortunately). Apart from making these kinds of queries more efficient, I would love to have an easier and less verbose way to express these kinds of queries.

    I'm also wondering this. If it is implemented the same was as SCD, then this would explode the number of archetypes (or "tables" in Flecs terminology) and lead to greatly increased memory fragmentation. In my game, an entity will typically have a maximum of one child. I would love to be able to be able to query for "ChildOf(someEntity)", but not if that puts every entity in its own chunk.
     
    ElliotB, JesOb and RaL like this.
  13. SanderMertens

    SanderMertens

    Joined:
    Jul 8, 2017
    Posts:
    11
    Hi all, article author here. Relations are treated as regular components/tags and as a result they do fragment tables/archetypes. A few things to keep in mind:

    - Archetypes in Flecs are cheap. A single application can easily have tens of thousands of archetypes and still perform well (as shown in this example: https://twitter.com/ajmmertens/status/1480120659913052160)

    - Flecs archetypes don't use chunked storage, which reduces RAM overhead for small archetypes by a lot (no need to allocate an entire chunk if an archetype just contains a handful of entities)

    - While iterating packed arrays can give a (N)x boost, relationship queries (https://bit.ly/3OdeI45) reduce the need for doing quadratic searches which can provide a (NxNxNx...)x boost (each N = a term in a query)

    - Multiple exclusive relationships (relationships w/max a single instance per entity) can be stored on a single archetype, which can reduce fragmentation by a lot (technique described here https://ajmmertens.medium.com/why-storing-state-machines-in-ecs-is-a-bad-idea-742de7a18e59).

    Having said that, I dislike fragmentation just like anyone else, so I'm working on a storage improvement that separates archetypes from tables. The 30.000ft idea is that a table only stores components, and N archetypes can index into one table. That way you can have your cake and eat it too: a query that's only interested in components can do fast unfragmented iteration, while a query for (relationship) tags eats a small overhead.
     
  14. Micz84

    Micz84

    Joined:
    Jul 21, 2012
    Posts:
    436
    Your blog is pure gold. I do not understand one thing about relation storage. How it is ok not to store generation in relation. Is there some automatic cleanup? For example I have entieties A(Id:0,Gen:1), B(1,1), C(2,1), D(3,1), E(4,1), F(5,1). I add to A reation (B,C) and (D,C),to entiety E I add relation (F,C). Then I destroy entiety C, it gets reused as C(2,2). Do you have wild card search like this (*,C)? So you can remove all relations automatically, when entiety is destroyed?
     
  15. SanderMertens

    SanderMertens

    Joined:
    Jul 8, 2017
    Posts:
    11
    Yep that's right. What happens during clean up is:
    - A query for "E" (in case E is used as a component/tag)
    - A query for "(E, *)" (in case E is used as a relationship)
    - A query for "(*, E)" (in case E is used as a relationship target)

    By default these components/tags/relationships are bulk-removed from all tables, but you can also configure a property on the relationship to delete entities with (R, E). This is used heavily by hierarchies: if I remove P I'll also want to delete all entities with (ChildOf, P).

    If you're interested, this has more info on cleanup behavior: https://flecs.docsforge.com/master/relations-manual/#cleanup-properties

    EDIT: I should note that these queries are only ran for entities that are flagged, which happens when an entity is added to another entity. If an entity has never been used as component/tag/relationship/relationship target I just do a simple delete.
     
    Last edited: Apr 15, 2022
    JoNax97 and Micz84 like this.
  16. mikaelK

    mikaelK

    Joined:
    Oct 2, 2013
    Posts:
    281
    uff, little late to the party, :) but after reading the article I ended up wondering how is this different than database?
    Why would I need this and not a database to model these relationships?

    Just wondering.
     
  17. Opeth001

    Opeth001

    Joined:
    Jan 28, 2017
    Posts:
    1,068
    I think this can be represented by a simple Generic SCD. Entities will be separated in different chunks by both the scd types and values.
    Wildcard queries are simply queries by values.
     
  18. Micz84

    Micz84

    Joined:
    Jul 21, 2012
    Posts:
    436
    Not exactly, because you can't do this style wildcard (*,entity)
     
    Opeth001 and SanderMertens like this.
  19. SanderMertens

    SanderMertens

    Joined:
    Jul 8, 2017
    Posts:
    11
    The short answer is that this is * much * faster than a regular database. Databases are optimized for persisting and storing large (terabytes) amounts of data. ECS relationships give you database-like functionality (though queries look more like prolog than SQL) but for the amount of data and performance you need in a game.

    This is not how Flecs works, and would not be very efficient as it requires iterating and comparing each individual value (shared or not shared), which is O(n). Finding all entities for (R, *) or (*, E) in Flecs is O(1). This ensures that queries have predictable performance and are feasible, no matter how many different relationships you have.
     
  20. unity-freestyle

    unity-freestyle

    Joined:
    Aug 26, 2015
    Posts:
    45
    This seems very powerful.

    I think it may remove the necessity for the so called "events" in ECS and standardize the way this kind of logic is structured.

    Would be great to have this in Unity ECS.
     
    SanderMertens likes this.
  21. Lhawika

    Lhawika

    Joined:
    May 27, 2015
    Posts:
    53
    To build up on the last comment: I think it would also make ECS much more suitable for systems like Inventories that are usualy told to be better implemented in OOP (which is kind of true with the current Unity ECS).

    Also, as someone who like to write complex SQL queries, this concept of Relationship looks juicy.
     
    SanderMertens likes this.
  22. SanderMertens

    SanderMertens

    Joined:
    Jul 8, 2017
    Posts:
    11
    Radivarig and Lhawika like this.