Search Unity

  1. Unity 2019.1 is now released.
    Dismiss Notice

How to fix dependency error when your system ?

Discussion in 'Entity Component System and C# Job system' started by Tazadar66, Oct 20, 2018.

  1. Tazadar66

    Tazadar66

    Joined:
    Aug 27, 2013
    Posts:
    54
    Hello there I have this error and I don't know how I can fix this...

    InvalidOperationException: The previously scheduled job CopyTransformFromGameObjectSystem:CopyTransforms writes to the NativeArray CopyTransforms.positions. You are trying to schedule a new job AddUpdatedUnitsInSubgridSystem:MyJob, which reads from the same NativeArray (via MyJob.positions). To guarantee safety, you must include CopyTransformFromGameObjectSystem:CopyTransforms as a dependency of the newly scheduled job.

    Here is my code and I don't really know why it is not working :(

    Code (CSharp):
    1. using Unity.Entities;
    2. using Unity.Collections;
    3. using Unity.Jobs;
    4. using Unity.Transforms;
    5. using Unity.Burst;
    6.  
    7. [UpdateAfter(typeof(CopyTransformFromGameObjectSystem))]
    8. public class AddUpdatedUnitsInSubgridSystem : JobComponentSystem
    9. {
    10.     public struct GridData
    11.     {
    12.         public readonly int Length;
    13.         public BufferArray<SubGridUnitComponent> subgridUnits;
    14.         public BufferArray<SubGridNeighborComponent> subgridNeighbors;
    15.         public ComponentDataArray<SubGridComponent> subgridComponents;
    16.     }
    17.  
    18.     [Inject] GridData m_gridData;
    19.  
    20.     [BurstCompile]
    21.     public struct MyJob : IJobParallelFor
    22.     {
    23.         [ReadOnly]
    24.         public ComponentDataFromEntity<Position> positions;
    25.         [ReadOnly]
    26.         public BufferFromEntity<SubGridUnitComponent> subGridUnitBuffers;
    27.  
    28.         [ReadOnly]
    29.         public BufferArray<SubGridNeighborComponent> subgridNeighbors;
    30.         [ReadOnly]
    31.         public ComponentDataArray<SubGridComponent> subgridComponents;
    32.  
    33.         public BufferArray<SubGridUnitComponent> subgridUnits;
    34.  
    35.         public void Execute(int j)
    36.         {
    37.             for(int i = 0; i < subgridNeighbors[j].Length; ++i)
    38.             {
    39.                 int size = subGridUnitBuffers[subgridNeighbors[j][i].neighborEntity].Length;
    40.                 for(int k = 0; k < size; ++k)
    41.                 {
    42.                     Entity e = subGridUnitBuffers[subgridNeighbors[j][i].neighborEntity][k].entity;
    43.                     Position pos = positions[e];
    44.  
    45.                     if(pos.Value.y >= subgridComponents[j].bottomLeft.y &&
    46.                     pos.Value.y < subgridComponents[j].topRight.y &&
    47.                     pos.Value.x >= subgridComponents[j].bottomLeft.x &&
    48.                     pos.Value.x < subgridComponents[j].topRight.x)
    49.                     {
    50.                         subgridUnits[j].Add(new SubGridUnitComponent(e));
    51.                     }
    52.                 }
    53.             }
    54.         }
    55.     }
    56.  
    57.     protected override JobHandle OnUpdate(JobHandle inputDeps)
    58.     {
    59.         // Get all we need first
    60.         EntityManager entityManager = World.Active.GetExistingManager<EntityManager>();
    61.         ComponentDataFromEntity<Position> unitPositions = entityManager.GetComponentDataFromEntity<Position>(true);
    62.         BufferFromEntity<SubGridUnitComponent> subGridUnitBuffers = entityManager.GetBufferFromEntity<SubGridUnitComponent>(true);
    63.        
    64.         // Compute stuff here
    65.         MyJob job = new MyJob()
    66.         {
    67.             positions = unitPositions,
    68.             subGridUnitBuffers = subGridUnitBuffers,
    69.             subgridComponents = m_gridData.subgridComponents,
    70.             subgridNeighbors = m_gridData.subgridNeighbors,
    71.             subgridUnits = m_gridData.subgridUnits
    72.         };
    73.         return job.Schedule(m_gridData.Length, 64, inputDeps);
    74.     }
    75. }

    Thank you :)
     
  2. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    130
    Don't use EntityManager.GetComponentDataFromEntity. Use JobComponentSystem.GetComponentDataFromEntity. That version sets up R/W dependencies and then calls the EntityManager version. I ran into the same issue with Chunk Iteration a few weeks ago. As a rule always use the ComponentSystem methods over EntityManager methods if they have them. It is a bit confusing.

    Also, you don't need to fetch EntityManager. JobComponentSystem has an auto-assigned property named EntityManager that uses the world the system is part of.
     
    Tazadar66 likes this.
  3. Tazadar66

    Tazadar66

    Joined:
    Aug 27, 2013
    Posts:
    54
    That's what I was looking for !

    Thanks for your help :)
     
  4. mitaywalle

    mitaywalle

    Joined:
    Jul 1, 2013
    Posts:
    72
    Hi guys!
    Have similar error and don't undestand how can I get data from this native array

    Here's code
    Code (CSharp):
    1. [BurstCompile,UpdateAfter(typeof(CopyTransformFromGameObjectSystem))]
    2.     public sealed class SA_manager : JobComponentSystem
    3.     {
    4.         public struct Components
    5.         {
    6.             public EntityArray Entities;
    7.             public ComponentDataArray<SA_data> source;
    8.             public readonly ComponentDataArray<Position> p;
    9.  
    10.             public readonly int Length;
    11.         }
    12.  
    13.         [Inject] Components data;
    14.  
    15.         protected override JobHandle OnUpdate(JobHandle inputDeps)
    16.         {
    17.             var listeners = GetComponentGroup(typeof(SA_ListenerData), typeof(Position)).GetComponentDataArray<Position>();
    18.          
    19.             SA_ProcessingJob job = new SA_ProcessingJob
    20.             {
    21.                 listenerPos = listeners.Length == 0 ? float3(0f,0f,0f): listeners[0].Value
    22.             };
    23.          
    24.             return job.Schedule(this, inputDeps);
    25.         }
    26.  
    27.         [BurstCompile]
    28.         struct SA_ProcessingJob : IJobProcessComponentData<SA_data, Position>
    29.         {
    30.             internal float3 listenerPos;
    31.          
    32.             public void Execute(ref SA_data source, [ReadOnly]ref Position p)
    33.             {
    34.                 // processing
    35.             }
    36.         }
    37.     }
     
  5. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    1,153
  6. mitaywalle

    mitaywalle

    Joined:
    Jul 1, 2013
    Posts:
    72
    Hi, thanks for advise, but best practices also tolds to use IJobProcessComponentData for many entities. Why should I choose more complicated chunk iteration?

    May be in this case more important to use GetComponentGroup instead of [Inject] ComponentDataArray ?

    Or May be I missunderstood something in your answer...
     
  7. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    1,153
    Yes you should use IJobProcessComponentData, but if you're iterating 2 separate queries you need to use chunk iterations on at least the secondary SA_ListenerData group.

    Anyway your actual issue is this listeners[0] is not safe without completing your job dependencies which don't happen automatically in a JobComponentGroup.