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

List/Array data in IComponentData

Discussion in 'Entity Component System' started by Init33, Jul 6, 2019.

  1. Init33

    Init33

    Joined:
    Aug 30, 2017
    Posts:
    67
    I am working through an implementation of A* path finding using DOTS and am coming stuck.

    The basic idea so far is that anything that wants to find a path creates a PathRequest IComponent that gets processed by a JobComponentSystem, calculating the path and returning the path way-points. Entities with PathRequest come into a IJobForEachWithEntity like below:

    Code (CSharp):
    1. public struct AStarJob : IJobForEachWithEntity<PathRequest>
    2. {
    3.             // calculate path
    4. }
    Where I am coming stuck is returning an array of way-points. My initial thought was to create a list in the PathRequest with a bool to indicate whether the path has been found:

    Code (CSharp):
    1. public struct PathRequest : IComponentData
    2. {
    3.     public int startIndex;
    4.     public int endIndex;
    5.     public bool pathComplete;
    6.     public NativeList<int> path;
    7. }
    but I am unable to use the NativeList<int> type in an IComponentData. Is the only way I can return individual arrays of way-points by using unsafe code with fixed arrays?
    Any other ideas?
     
  2. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,683
    DynamicBuffer for mutable data arrays.
     
  3. Init33

    Init33

    Joined:
    Aug 30, 2017
    Posts:
    67
    I set up a dynamic buffer and passed the
    BufferFromEntity
    to the job:

    Code (CSharp):
    1. public struct AStarJob : IJobForEachWithEntity<PathRequest>
    2.     {
    3.         // ...
    4.         public BufferFromEntity<PathCompleteBuffer> pathCompleteBuffer;
    5.  
    6.         public void Execute(Entity entity, int index, ref PathRequest p)
    7.         {
    8.             // ...
    9.         }
    10. }
    11. }
    I'm now getting an error:
    validOperationException: AStarJob.Data.pathCompleteBuffer is not declared [ReadOnly] in a IJobParallelFor job. The container does not support parallel writing. Please use a more suitable container type.

    which I understand, but looking through what other people have used in the past leads me to think I should use
    IJobProcessComponentDataWithEntity
    except that its now deprecated to use
    IJobForEachWithEntity
    So the only job option i have is parallel and therefore cannot use dynamic buffers?
     
  4. Guerro323

    Guerro323

    Joined:
    Sep 2, 2014
    Posts:
    25
    When you schedule a IJobForEach job, you have the choice between parallelism (job.Schedule(...)) and single-threaded (job.ScheduleSingle(...)).
    If you still want parallelism and you are sure there is no race condition, you can add the attribute [NativeDisableParallelForRestriction] to your buffer variable 'pathCompleteBuffer'.
     
    Init33 likes this.
  5. GilCat

    GilCat

    Joined:
    Sep 21, 2013
    Posts:
    676
    I'm not sure if that is the case but if your buffer is in the same entity of PathRequest you can use IJobForEachWithEntity with DynamicBuffers -> IJobForEachWithEntity_EBC<T0, T1>

    Code (CSharp):
    1.     public struct AStarJob : IJobForEachWithEntity_EBC<PathCompleteBuffer, PathRequest> {
    2.  
    3.       public void Execute(Entity entity, int index, DynamicBuffer<PathCompleteBuffer> buffer, ref PathRequest p) {
    4.         // ...
    5.       }
    6.     }
     
    Init33 likes this.
  6. Init33

    Init33

    Joined:
    Aug 30, 2017
    Posts:
    67
    This worked a treat, I can easily pull in buffer types and write to them in the job (not sure if this is parallel or not though).
     
  7. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,753
    IJobForEach is parallel
     
  8. fholm

    fholm

    Joined:
    Aug 20, 2011
    Posts:
    2,052
    I found that currently the best solution for working around this is to implement your own collections based on only memory allocated via UnsafeUtility.Malloc since you can stick these into components. Its a bit of work but currently i have most common collections implemented