Search Unity

How to get an Entity when using EntityCommandBuffer.CreateEntity()?

Discussion in 'Entity Component System' started by GarthSmith, Oct 24, 2018.

  1. GarthSmith

    GarthSmith

    Joined:
    Apr 26, 2012
    Posts:
    1,240
    Hello!

    This is something we've come across a few times.

    We are creating a pair of entities that we would either link to each other, or to a common parent entity.

    The problem we are having is that when we use the EntityCommandBuffer to create an entity, there is no Entity returned that we can assign to a component.

    Code (csharp):
    1.  /// Links two entities together.
    2. public struct PairComponent : IComponentData
    3. {
    4.   public Entity OtherHalf;
    5. }
    Code (csharp):
    1. // Inside OnUpdate
    2. PostUpdateCommands.CreateEntity(); // First part of the pair.
    3. PostUpdateCommands.AddComponent(new PairComponent());
    4. PostUpdateCommand.CreateEntity(); // Second part of the pair.
    5. PostUpdateCommands.AddComponent(new PairComponent());
    6. // Where do I assign OtherHalf?
    How should we assign OtherHalf when the pair of entities haven't been created yet?
     
  2. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,685
    EntityComendBuffer is just queue (in simple words) of commands which runs on Main Thread later. One of possible solution, for example, you can use some addtional component which needs only for referencing, and whics stores some unique pair index\hash\etc
    Code (CSharp):
    1. public struct PairProcessComponent : ISharedComponentData
    2. {
    3.   public int pairIndex;
    4. }
    ISharedComponentData - for combine this entities in one chunk (chunk per pair I mean). And then you can use Chunk Iteration in IJobParallelFor\IJobChunk\etc, for iterating chunks (because SharedComponentData is per chunk it means entities with same SharedComponentDataIndex will be in one chunk) inside job and referencing pairs in this chunk and remove this PairProcessComponent component.
     
  3. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,761
    I don't believe you can. Entity command buffers defer the creation of the entity so it's not possible to know the entity created

    In these cases I tend to just use a component system and entity manager to make the entities.
     
  4. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,685
    Is what I say above on practice (And video which shown that it works as expected (on video, mouse drawn a little higher than in real life, just default Windows recorder do this weird things)):

    Code (CSharp):
    1. using System;
    2. using Unity.Collections;
    3. using Unity.Entities;
    4. using Unity.Jobs;
    5.  
    6. public struct PairComponent : IComponentData
    7. {
    8.     public int referencedEntityIndexCheck;// <---- Just for check correct reference in inspector
    9.     public int referencedEntityVersionCheck;// <---- Just for check correct reference in inspector
    10.     public Entity otherHalf;
    11. }
    12.  
    13. public struct PairProcessComponent : ISharedComponentData
    14. {
    15.     public int pairIndex;
    16. }
    17.  
    18. [AlwaysUpdateSystem]
    19. public class ArchetypeChunkSystemTest : ComponentSystem
    20. {
    21.     public EntityArchetypeQuery pairsArchetypeQuery;
    22.  
    23.     public struct CreatePairsJob : IJobParallelFor
    24.     {
    25.         public EntityCommandBuffer.Concurrent ecb;
    26.  
    27.         public void Execute(int index)
    28.         {
    29.             ecb.CreateEntity(index);
    30.             ecb.AddSharedComponent(index, new PairProcessComponent() {pairIndex = index});
    31.             ecb.CreateEntity(index);
    32.             ecb.AddSharedComponent(index, new PairProcessComponent() {pairIndex = index});
    33.         }
    34.     }
    35.  
    36.     public struct FillPairsJob : IJobParallelFor
    37.     {
    38.         [ReadOnly] public NativeArray<ArchetypeChunk>                             pairsChunks;
    39.         [ReadOnly] public ArchetypeChunkSharedComponentType<PairProcessComponent> pairsChunkType;
    40.         [ReadOnly] public ArchetypeChunkEntityType                                pairsEntityChunkType;
    41.         public            EntityCommandBuffer.Concurrent                          ecb;
    42.  
    43.         public void Execute(int index)
    44.         {
    45.             NativeArray<Entity> ents = pairsChunks[index].GetNativeArray(pairsEntityChunkType);
    46.             ecb.AddComponent(index, ents[0], new PairComponent() {otherHalf = ents[1] , referencedEntityIndexCheck = ents[1] .Index, referencedEntityVersionCheck = ents[1].Version});
    47.             ecb.AddComponent(index, ents[1], new PairComponent() {otherHalf = ents[0], referencedEntityIndexCheck = ents[0].Index, referencedEntityVersionCheck = ents[0].Version });
    48.             ecb.RemoveComponent<PairProcessComponent>(index, ents[0]);
    49.             ecb.RemoveComponent<PairProcessComponent>(index, ents[1]);
    50.         }
    51.     }
    52.  
    53.     protected override void OnCreateManager()
    54.     {
    55.         base.OnCreateManager();
    56.         pairsArchetypeQuery = new EntityArchetypeQuery()
    57.         {
    58.             Any  = Array.Empty<ComponentType>(),
    59.             All  = new ComponentType[] {typeof(PairProcessComponent)},
    60.             None = Array.Empty<ComponentType>()
    61.         };
    62.     }
    63.  
    64.     private bool firstRun = true; // <---- Just for tests
    65.  
    66.     protected override void OnUpdate()
    67.     {
    68.         if (firstRun)
    69.         {
    70.             firstRun = false;
    71.             new CreatePairsJob()
    72.             {
    73.                 ecb = PostUpdateCommands.ToConcurrent()
    74.             }.Schedule(5, 5).Complete();
    75.         }
    76.         else
    77.         {
    78.             GetComponentGroup(typeof(PairComponent)); // <---- Just for show entities in EntityDebugger
    79.  
    80.             NativeArray<ArchetypeChunk> pairsChunks =
    81.                 EntityManager.CreateArchetypeChunkArray(pairsArchetypeQuery, Allocator.TempJob);
    82.             if (pairsChunks.Length == 0)
    83.             {
    84.                 pairsChunks.Dispose();
    85.                 return;
    86.             }
    87.  
    88.             ArchetypeChunkSharedComponentType<PairProcessComponent> pairsChunkType =
    89.                 GetArchetypeChunkSharedComponentType<PairProcessComponent>();
    90.             ArchetypeChunkEntityType pairsEntityChunkType = GetArchetypeChunkEntityType();
    91.  
    92.             new FillPairsJob()
    93.             {
    94.                 pairsChunks          = pairsChunks,
    95.                 pairsChunkType       = pairsChunkType,
    96.                 pairsEntityChunkType = pairsEntityChunkType,
    97.                 ecb                  = PostUpdateCommands.ToConcurrent()
    98.             }.Schedule(pairsChunks.Length, 64).Complete();
    99.  
    100.             pairsChunks.Dispose();
    101.         }
    102.     }
    103. }
     
    Last edited: Oct 24, 2018