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

Chunk iteration filtering?

Discussion in 'Entity Component System' started by Deleted User, Nov 25, 2018.

  1. Deleted User

    Deleted User

    Guest

    Good day.

    I have a question. What would be the best approach to get an archetype and all its components based on the first component lets say Header with some value. Do I have to use SharedComponentData? Would it perform better than anything else?

    Thank you.
     
    ChrisPie likes this.
  2. Deleted User

    Deleted User

    Guest

    @5argon I will appreciate if you will help with that.
     
  3. Attatekjir

    Attatekjir

    Joined:
    Sep 17, 2018
    Posts:
    23
    5argon actually wrote a piece about using chunk iteration that filters on SharedComponentData. This, together with the documentation example from the EntityComponentSystemSamples on github can get you started in the right direction using chunk iteration with SharedComponentData.



    As far as the performance is concerned, iterating over which chunk has what SharedComponentData value is fast, but you should keep in mind that the SharedComponentData value on an entity should not change often, as this involves copying the entity between chunks.

    One possible alternative to SharedComponentData is to assign different IComponentData structs as a sort of unique marker of that archetype. Like assigning an empty IComponentData called Tree to your TreeArchetype. Then you can ofcourse get this specific Archetype with EntityArchetypeQuery with a typeof(Tree). But you can also filter this per entity and thus per chunk in a job by calling AllTreeEntities.exist(entity), where AllTreeEntities is a ComponentDataFromEntity<Tree>. If this method returns true you know the entity and thus the chunk contains an archetype that contains the IComponentData Tree. An obvious downside to this approach is that you have to create an unique IComponentData per archetype.

    Another possible alternative is to attach a sort of marker component to archetypes that have an enum field. But this is more handy differentiating entities that share the same archetype in my opinion. For example:

    Code (CSharp):
    1.  
    2. EmploymentID employmentid = Employment[j].Value;
    3. if (employmentid == EmploymentID.Builder)
    4. {
    5.        //Do things only a builder would do
    6. }
    7. else if (employmentid == EmploymentID.Lumberjack)
    8. {
    9.        //Do things only a lumberjack would do
    10. }
    11.  
     
    Deleted User likes this.
  4. Deleted User

    Deleted User

    Guest

    Much appreciate that.
     
  5. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,753
    How many components are we talking? If it's not a huge amount I'd probably just do something like

    Code (CSharp):
    1.             this.headerQuery = this.GetComponentGroup(
    2.                 new EntityArchetypeQuery
    3.                 {
    4.                     Any = new[] { ComponentType.Create<A>(), ComponentType.Create<B>(), ComponentType.Create<C>() },
    5.                     None = Array.Empty<ComponentType>(),
    6.                     All = new[] { ComponentType.ReadOnly<Header>() },
    7.                 });
    Code (CSharp):
    1. private struct HeaderJob : IJobChunk
    2.         {
    3.             [ReadOnly]
    4.             public ArchetypeChunkComponentType<Header> HeaderType;
    5.  
    6.             // ...
    7.  
    8.             public void Execute(ArchetypeChunk chunk, int chunkIndex)
    9.             {
    10.                 var headers = chunk.GetNativeArray(this.HeaderType);
    11.                 var aArray = chunk.GetNativeArray(this.AType);
    12.                 var bArray = chunk.GetNativeArray(this.BType);
    13.                 var cArray = chunk.GetNativeArray(this.CType);
    14.  
    15.                 for (var index = 0; index < chunk.Count; index++)
    16.                 {
    17.                     if(headers.Type == typeof(A))
    18.                     {
    19.                         if (aArray.Length == 0)
    20.                         {
    21.                             continue;
    22.                         }
    23.  
    24.                         // Do work on A
    25.                     }
    26.                     else if (headers.Type == typeof(B))
    27.                     {
    28.  
    29.                     }
    30.                     else if // ...
    31.                 }
    32.             }
    33.         }
    If it's more than a few, I'd consider a different approach and there are a couple of options.
     
  6. Deleted User

    Deleted User

    Guest

    Hi there. Thank you for the snippets. 64-100 per frame, for network messaging. Multiple systems will inject these entities no matter of the header value. Even thought SystemA works only with Header typeA it will get all of the headers, right?
     
  7. Deleted User

    Deleted User

    Guest


    What would be the approach if it's the large amount 10k entities per frame?
     
  8. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,555
    I am not sure what you want, you want to work with entities with Header + any other types?

    Then I believe IJobChunk mentioned already performs the best.
    - EntityArchetypeQuery All = Header Any = Any other just like that code snippet.
    - Bring a lot of ArchetypeChunkComponentType<Any other> to IJobChunk. Schedule the job with CG made from that query.
    - No need to bring ACCT Header as all chunks coming to this job are guaranteed to have Header from the query.
    - Check ac.Has(acctType) one by one to find the type that is coming with the header that you want to use. If-check the type that you think is common first.
    - Even the correct chunk is found you can further use DidChange/DidAddOrChange to skip chunks if your work is responding to changes. Bring version number from the system to the job.
    - Burst compile the job. Or use lower accuracy Burst attribute options if you want.
     
  9. SubPixelPerfect

    SubPixelPerfect

    Joined:
    Oct 14, 2015
    Posts:
    224
    not sure what you want to achieve but if you need to get all components on a given entity
    Code (csharp):
    1. public class GetChunks : ComponentSystem{
    2.   [Inject] private EndFrameBarrier _barrier;
    3.   private ComponentGroup _query;
    4.   protected override void OnCreateManager(){
    5.     _query = GetComponentGroup(ComponentType.Create<B>());
    6.   }
    7.  
    8.   protected override void OnUpdate(){
    9.     var chunks = _query.CreateArchetypeChunkArray( Allocator.TempJob ); // get chunks
    10.     if (chunks.Length == 0){ chunks.Dispose(); return; } // do nothing if no chunks found
    11.  
    12.     var entityChunkType = GetArchetypeChunkEntityType();
    13.  
    14.     foreach( var chunk in chunks ){ // for each chunk
    15.       var archetype = chunk.Archetype;
    16.       ComponentType[] types = archetype.ComponentTypes;
    17.       for( int j = 0; j < types.Length; j++ ){// list chunk component types
    18.         Debug.Log( types[j] );
    19.       }
    20.      
    21.       var entities = chunk.GetNativeArray (entityChunkType);
    22.       for( int i = 0; i < entities.Length; i++ ){ // serialize entityes with all components to json
    23.         var entity = entities[i];
    24.         var container = new EntityContainer(EntityManager, entity);
    25.         Debug.Log( JsonSerializer.Serialize(ref container) );
    26.       }
    27.     }
    28.  
    29.     chunks.Dispose(); // dealocate native container
    30.   }
    31.  
    32. }

    here is my very old post on this topic
    1) https://forum.unity.com/threads/ser...over-all-components-of-a-given-entity.524553/
    2) https://forum.unity.com/threads/serialization-again.537648/
     
    Last edited: Nov 30, 2018