Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

EntityManager.AddComponents API taking an EntityArchetype

Discussion in 'Entity Component System' started by Justin_Larrabee, Jun 4, 2019.

  1. Justin_Larrabee

    Justin_Larrabee

    Joined:
    Apr 24, 2018
    Posts:
    106
    I have a use-case where I need to create an empty entity and defer creation of its components until a point later in the frame. I know the archetype ahead of time so in my system I have that stored for later usage. I cannot call CreateEntity(archetype) because my other systems would operate on this deferred Entity with default value IComponentData.

    Right now there is a call on EntityManager to add components to an Entity with a ComponentTypes object, but there is no method for adding components from an Archetype. Could this be added? ComponentTypes has a hard limit of 15 types and so I'm forced to split up my usage of the API into multiple calls to AddComponents(ComponentTypes) and pay the price of the Entity being moved across chunks more than once.
     
    JesOb likes this.
  2. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,555
    If it is an add not set, you could create empty entities with an archetype of a tag component (like
    Deferred : IComponentData
    ) then later you could use
    EntityQuery
    overload to add components successively without moving across chunks where the query refers to
    Deferred
    .
     
  3. Justin_Larrabee

    Justin_Larrabee

    Joined:
    Apr 24, 2018
    Posts:
    106
    I should have clarified, I have already implemented the deferred creation system. It's the actual action of adding to the Entity all the component types from the archetype that is the issue. Right now I have to call AddComponents(ComponentTypes) N times where N=ceil(num_components_in_archetype/15). This causes N chunk moves for the Entity (assuming no ISharedComponentData).
     
  4. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,555
    You only have 1 Entity which need to do this? Or more? It seems like you are using this overload

    public void AddComponents(Entity entity, ComponentTypes types)

    Which supports multiple types but only for 1 entity. But I was talking about

    public void AddComponent(EntityQuery entityQuery, ComponentType componentType)

    With 1 type but take chunks from query, and I meant you may want to try EQ overload num_components_in_archetype times rather than your overload N times per entity, so you move/rearrange chunk data num_components_in_archetype*chunk_count times rather than N*entity_count times.

    However I am not sure about performance comparison for 1 or low amount of Entity. Your overload is the only place that use a section of code in EntityManagerChangeArchetypeUtility.cs, that make me think it is specialized and might be better for single entity.

    (I was talking about something like this)

    Code (CSharp):
    1. EntityArchetype archetype = EntityManager.CreateArchetype(
    2.     ComponentType.ReadOnly<T1>(),
    3.     ComponentType.ReadOnly<T2>(),
    4.     ComponentType.ReadOnly<T3>(),
    5.     ...
    6.     ComponentType.ReadOnly<T30>()
    7. );
    8.  
    9. EntityArchetype deferredArchetype = EntityManager.CreateArchetype( ComponentType.ReadOnly<Deferred>() );
    10.  
    11. NativeArray<Entity> ea = new NativeArray<Entity>(100, Allocator.Temp);
    12. EntityManager.CreateEntity(deferredArchetype, ea);
    13.  
    14. //later
    15.  
    16. var eq = EntityManager.CreateEntityQuery(ComponentType.ReadOnly<Deferred>());
    17. using(var types =  archetype.GetComponentTypes(Allocator.Temp))
    18. {
    19.     foreach(var type in types)
    20.     {
    21.         EntityManager.AddComponent(eq, type);
    22.     }
    23. }
     
    Last edited: Jun 5, 2019
  5. Justin_Larrabee

    Justin_Larrabee

    Joined:
    Apr 24, 2018
    Posts:
    106
    This example doesn't address the problem, it just moves the chunk moves (of which you have 30 here) into the AddComponent(EntityQuery, ComponentType) call. Additionally, the deferred entities I create can have any archetype they wish.

    The concrete example of why I am doing this is a gameplay Entity spawning system. I require that some entities be fully constructed at a specific point late in the frame, but when a gameplay system spawns an Entity I want to be able to return the Entity that is spawned so if the caller wishes to they can store a reference (with the caveat of course that the Entity will not be constructed until the end of the frame).
     
  6. sngdan

    sngdan

    Joined:
    Feb 7, 2014
    Posts:
    1,154
    Why don’t you just add a tag “deferred” and use it as a subtractive component for all your systems. And you remove this tag at the point you want the entities to “go live”

    Ie you have 2 arechetypes
    1- with all your components
    2- as 1, but in addition the deferred” tag
     
  7. Justin_Larrabee

    Justin_Larrabee

    Joined:
    Apr 24, 2018
    Posts:
    106
    That's an option I had considered, but it means that every single system and job has to remember to specify that component as an exclusion criteria. It's a very, very easy source of bugs.

    My current implementation of using multiple AddComponents(ComponentTypes) calls fully solves my problem. The entire point of this post is that AddComponents(EntityArchetype) is a much more elegant solution and one that is seemingly trivial to add based on my inspection of the source.
     
    JesOb likes this.