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

How to get component data from entity of DynamicBuffer?

Discussion in 'Entity Component System' started by kumay611, May 10, 2019.

  1. kumay611

    kumay611

    Joined:
    Mar 18, 2019
    Posts:
    3
    The buffer like this.
    Code (CSharp):
    1. public struct MapData:IBufferElementData{
    2.     public Entity TileMap;
    3. }
    4.  
    I try to use EntityManager.GetComponentData, but got the error.
    ArgumentException: All entities created using EntityCommandBuffer.CreateEntity must be realized via playback(). One of the entities is still deferred (Index: -1)
     
  2. TLRMatthew

    TLRMatthew

    Joined:
    Apr 10, 2019
    Posts:
    65
    This sounds to me not like a problem with the IBufferElementData, but like you have entities being queued for creation on an EntityCommandBuffer and you're not waiting for it to be replayed before trying to access that entity.

    I'm guessing you have something like this:

    Code (CSharp):
    1. struct MyJob : IJobForEachWithEntity<T>
    2. {
    3.         public EntityCommandBuffer.Concurrent CommandBuffer;
    4.  
    5.         public void Execute(Entity entity, int index, ref T component)
    6.         {
    7.             var newEntity = CommandBuffer.CreateEntity(index);
    8.             // then trying to access IBufferElementData on newEntity immediately
    9.         }
    10. }
    11.  
    When creating Entities like this, you need to use EntityCommandBufferSystem.AddJobHandleForProducer(JobHandle) and then JobHandle.Complete() before you can access any of the changes made on the EntityCommandBuffer.
     
    kumay611 likes this.
  3. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,653
    Show full code
     
  4. siggigg

    siggigg

    Joined:
    Apr 11, 2018
    Posts:
    247
  5. kumay611

    kumay611

    Joined:
    Mar 18, 2019
    Posts:
    3
    trying to make the code clear, here is.
    Code (CSharp):
    1. public struct Coord : IComponentData{
    2.     public int x;
    3.     public int y;
    4. }
    5. public struct TileMap : IComponentData{
    6.     public bool isTrap;
    7. }
    8. public struct MapData:IBufferElementData{
    9.     public Entity TileMap;
    10. }
    11.  
    12. public class PathFindingSystem:ComponentSystem{
    13.     public EntityQuery mapSpawner;
    14.     public int mapWidth=10;
    15.     public int mapLength = 10;  
    16.     protected override void OnCreate(){
    17.         mapSpawner = GetEntityQuery(typeof(MapSpawner));
    18.     }
    19.  
    20.     protected override void OnUpdate(){
    21.         var spawner = mapSpawner.GetSingletonEntity();
    22.         var mapBuffer = EntityManager.GetBuffer<MapData>(spawner);      
    23.         Entities.WithAll<Selecting>().ForEach((Entity entity, ref Coord coord) => {
    24.             var tileMapEntity = mapBuffer[coord.x * mapWidth + coord.y].TileMap;
    25.             var isTrap = EntityManager.GetComponentData<TileMap>(tileMapEntity).isTrap;
    26.             // other code to avoid the trap
    27.         });
    28.     }
    29. }
     
  6. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,653
    It's not full code, there is nothing which related on you error with EntityCommandBuffer.
     
  7. kumay611

    kumay611

    Joined:
    Mar 18, 2019
    Posts:
    3
    I guess it's related to the tile map entity created in spawner system, here is.
    Code (CSharp):
    1. [UpdateInGroup(typeof(SimulationSystemGroup))]
    2. class MapSpawnerSystem : JobComponentSystem{
    3.     BeginInitializationEntityCommandBufferSystem m_EntityCommandBufferSystem;
    4.     protected override void OnCreate()
    5.     {
    6.         m_EntityCommandBufferSystem = World.GetOrCreateSystem<BeginInitializationEntityCommandBufferSystem>();
    7.     }
    8.  
    9.     [RequireComponentTag ( typeof (ReadyToGen ) ) ]
    10.     struct Job:IJobForEachWithEntity<MapSpawner>{
    11.         public EntityCommandBuffer ECB;
    12.         public BufferFromEntity <MapData> mapBufferLookUp ;
    13.      
    14.         public void Execute(Entity entity, int index, ref MapSpawner spawner){
    15.             var mapBuffer = mapBufferLookUp[entity];
    16.             var tiles = new int[spawner.mapWidth, spawner.mapLength];
    17.          
    18.  
    19.             for (int x = 0; x < spawner.mapWidth; x++){
    20.                 for (int y = 0; y < spawner.mapLength; y++){
    21.                     Entity src = spawner.Prefab;
    22.  
    23.                     var clone = ECB.Instantiate(src);
    24.                     ECB.SetComponent(clone, new Translation{Value = new float3(x,-1f,y)});
    25.                  
    26.                     var element = new MapData{TileMap = clone};
    27.                     // Adding to buffer by order to store the coordinate
    28.                     mapBuffer.Add(elelement);
    29.                  
    30.                 }
    31.             }
    32.  
    33.             ECB.RemoveComponent<ReadyToGen>(entity);
    34.         }
    35.     }
    36.     protected override JobHandle OnUpdate(JobHandle inputDeps){
    37.         var job = new Job
    38.         {
    39.             ECB = m_EntityCommandBufferSystem.CreateCommandBuffer(),
    40.             mapBufferLookUp =  GetBufferFromEntity<MapData>(false),
    41.          
    42.         }.ScheduleSingle(this, inputDeps);
    43.         m_EntityCommandBufferSystem.AddJobHandleForProducer(job);
    44.  
    45.         return job;
    46.     }
    47. }
     
  8. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,653
    You can't do this. Because ECB has temporary entities when you create entities, they replaces only after ECB playback. And it's not update any other places where you put this temporary entities.
     
    alvinwan and kumay611 like this.
  9. jeremyco

    jeremyco

    Unity Technologies

    Joined:
    Oct 17, 2018
    Posts:
    38
    Also, you may need to use ECB.ToConcurrent() to make a thread-safe version of it.
     
  10. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,653
    Not necessary, he scheduling it as ScheduleSingle, there is no concurrency afaik.
     
    deus0 likes this.
  11. mike1997

    mike1997

    Joined:
    Jul 1, 2016
    Posts:
    25
    According to the example, if I want to use ecb to create entity and then store it in a native array after creating it, how would I get the right reference?
     
  12. PeppeJ2

    PeppeJ2

    Joined:
    May 13, 2014
    Posts:
    41
    1. Attach a component 'A' to your newly created Entity.
    2. Have a job look for entities with 'A'
    3. Make said job remove 'A' and then add the entity to your array.

    Note that this will have a 1 frame delay if you're doing it in the same system. If you need it the same frame run it ASAP after your ECB has played back.

    If you need some data like index to be kept you could just put it in 'A' with ECB.SetComponentData();
     
  13. mike1997

    mike1997

    Joined:
    Jul 1, 2016
    Posts:
    25
    Thanks for the reply, seems easy enought, Ill try it out
     
  14. yifanchu183

    yifanchu183

    Joined:
    Jul 4, 2019
    Posts:
    41
    access the entity in another system and add to the dynamicbuffer is work
     
    Last edited: Oct 5, 2021