Search Unity

Can't understand this error of ComponentDataFromEntity

Discussion in 'Entity Component System' started by zephyr831125, Mar 25, 2019.

  1. zephyr831125

    zephyr831125

    Joined:
    Mar 4, 2017
    Posts:
    54
    Hi, I have a JobComponentSystem, in its job, I have 2 ComponentDataFromEntity "Requests" and "TransferRequests", When there's only "TransferRequests" it runs fine. But the "Requests" always cause this error:
    Code (CSharp):
    1. [15:07:29:190] InvalidOperationException: The system TaoHuaYuan.System.Game.Tasks.GetTransferRequestValuesTaskSystem reads TaoHuaYuan.ComponentData.Game.Request.Request via GatherComponentDataJob`1 but that type was not returned as a job dependency. To ensure correct behavior of other systems, the job or a dependency of it must be returned from the OnUpdate method.
    These two ComponentDataFromEntity seems nothing different to me.

    Here is the whole class codes:
    Code (CSharp):
    1. using Common.ECS;
    2. using Common.Flow;
    3. using Common.Flow.ComponentData;
    4. using Common.Flow.System;
    5. using TaoHuaYuan.ComponentData.Game.Request;
    6. using TaoHuaYuan.Flows;
    7. using Unity.Collections;
    8. using Unity.Entities;
    9. using Unity.Jobs;
    10. using Task = Common.Flow.ComponentData.Task;
    11.  
    12. namespace TaoHuaYuan.System.Game.Tasks
    13. {
    14.     [UpdateInGroup(typeof(FlowSystemGroup))]
    15.     public class GetTransferRequestValuesTaskSystem : JobComponentSystem
    16.     {
    17.  
    18.         [RequireComponentTag(typeof(GetTransferRequestValuesTask),
    19.             typeof(TaskInputPort), typeof(TaskOutputPort))]
    20.         public struct TaskJob : IJobProcessComponentDataWithEntity<Task>
    21.         {
    22.             [NativeDisableParallelForRestriction]
    23.             public BufferFromEntity<TaskInputPort> BuffersInput;
    24.  
    25.             [ReadOnly]
    26.             public BufferFromEntity<TaskOutputPort> BuffersOutput;
    27.          
    28.             [ReadOnly]
    29.             public ComponentDataFromEntity<Request> Requests;
    30.  
    31.             [ReadOnly]
    32.             public ComponentDataFromEntity<TransferRequest> TransferRequests;
    33.  
    34.             public void Execute(Entity entity, int index, ref Task task)
    35.             {
    36.                 var bufferInput = BuffersInput[entity];
    37.                 if (!JobUtils.CheckTaskAvailable(task, bufferInput)) return;
    38.  
    39.                 var requestEntity = bufferInput.Find(port =>
    40.                     port.PortName == GetTransferRequestValues.InputPortRequestName).EntityValue;
    41.  
    42.                 var request = Requests[requestEntity];
    43.                 var transferRequest = TransferRequests[requestEntity];
    44.  
    45.                 //output values
    46.                 JobUtils.OutputFlowAndVariables(entity, ref BuffersOutput, ref BuffersInput,
    47.                     (outputPortName, nextInputPort) =>
    48.                     {
    49.                         if(outputPortName == GetTransferRequestValues.OutputPortItemName)
    50.                         {
    51.                             nextInputPort.EntityValue = transferRequest.ItemEntity;
    52.                         }else if (outputPortName == GetTransferRequestValues.OutputPortContainerName)
    53.                         {
    54.                             nextInputPort.EntityValue = transferRequest.TargetContainerEntity;
    55.                         }else if (outputPortName == GetTransferRequestValues.OutputPortCountName)
    56.                         {
    57.                             nextInputPort.FloatValue = transferRequest.Count;
    58.                         }else if (outputPortName == GetTransferRequestValues.OutputPortExecuterName)
    59.                         {
    60.                             nextInputPort.EntityValue = request.ExecutorEntity;
    61.                         }
    62.                         return nextInputPort;
    63.                     });
    64.                 //task done
    65.                 task.Status = TaskStatus.Done;
    66.             }
    67.         }
    68.  
    69.         protected override JobHandle OnUpdate(JobHandle inputDeps)
    70.         {
    71.             var job = new TaskJob
    72.             {
    73.                 BuffersInput = GetBufferFromEntity<TaskInputPort>(),
    74.                 BuffersOutput = GetBufferFromEntity<TaskOutputPort>(true),
    75.                 Requests = GetComponentDataFromEntity<Request>(true),
    76.                 TransferRequests = GetComponentDataFromEntity<TransferRequest>(true)
    77.             };
    78.             var handle = job.Schedule(this, inputDeps);
    79.             return handle;
    80.         }
    81.     }
    82. }
     
  2. zephyr831125

    zephyr831125

    Joined:
    Mar 4, 2017
    Posts:
    54
    And the Request ComponentData:
    Code (CSharp):
    1. using Unity.Entities;
    2.  
    3.     public struct Request : IComponentData
    4.     {
    5.         public RequestStatus Status;
    6.         public Entity ExecutorEntity;
    7.     }
    8.  
    the TransferRequest ComponentData:
    Code (CSharp):
    1. using Unity.Entities;
    2. public struct TransferRequest : IComponentData
    3.     {
    4.         public Entity ItemEntity;
    5.         public Entity TargetContainerEntity;
    6.         public float Count;
    7.     }
    8.  
     
  3. digitaliliad

    digitaliliad

    Joined:
    Jul 1, 2018
    Posts:
    64
    This is just a shot in the dark, but I think your issue is that your job component system doesn't have any stated dependencies (for example, by creating a component group of relevant component types). The safety systems can't infer dependencies, so they need to be more explicitly stated.
     
  4. zephyr831125

    zephyr831125

    Joined:
    Mar 4, 2017
    Posts:
    54
    Thank you for your reply, but how to explicitly state the job dependency of GetComponentDataFromEntity? It has not any other parmeters other than a bool readonly.
     
  5. digitaliliad

    digitaliliad

    Joined:
    Jul 1, 2018
    Posts:
    64
    I think what you need to do is specify the dependencies of the job component system. You can do this by defining a component group that the job system works with, and passing that group to your job. That should only take minor refactoring, and might clear up your dependency issue.
     
  6. zephyr831125

    zephyr831125

    Joined:
    Mar 4, 2017
    Posts:
    54
    Yeah, exactly what I am doing, thank you very much! Although I still don't fully understand how this issue happened.
     
  7. digitaliliad

    digitaliliad

    Joined:
    Jul 1, 2018
    Posts:
    64
    Oh, good. I think numerous issues arise due to the safety systems being very sensitive, and yet unintuitive, so you have to be extra careful not to aggravate them.
     
  8. zephyr831125

    zephyr831125

    Joined:
    Mar 4, 2017
    Posts:
    54
    I am even more confused now, I have changed to ComponentGroup and scheduled ToNativeArray job before my job, but still give me the same error:
    Code (CSharp):
    1. [14:08:53:552] InvalidOperationException: The system TaoHuaYuan.System.Game.Tasks.GetTransferRequestValuesTaskSystem reads TaoHuaYuan.ComponentData.Game.Request.Request via GatherComponentDataJob`1 but that type was not returned as a job dependency. To ensure correct behavior of other systems, the job or a dependency of it must be returned from the OnUpdate method.
     
  9. zephyr831125

    zephyr831125

    Joined:
    Mar 4, 2017
    Posts:
    54
    The new code:
    Code (CSharp):
    1.  
    2. ....
    3.  
    4. namespace TaoHuaYuan.System.Game.Tasks
    5. {
    6.     [UpdateInGroup(typeof(FlowSystemGroup))]
    7.     public class GetTransferRequestValuesTaskSystem : JobComponentSystem
    8.     {
    9.         private ComponentGroup _requestGroup;
    10.  
    11.         protected override void OnCreateManager()
    12.         {
    13.             _requestGroup = GetComponentGroup(
    14.                 ComponentType.ReadOnly<Request>(),
    15.                 ComponentType.ReadOnly<TransferRequest>());
    16.         }
    17.  
    18.         [RequireComponentTag(typeof(GetTransferRequestValuesTask),
    19.             typeof(TaskInputPort), typeof(TaskOutputPort))]
    20.         public struct TaskJob : IJobProcessComponentDataWithEntity<Task>
    21.         {
    22.             [NativeDisableParallelForRestriction]
    23.             public BufferFromEntity<TaskInputPort> BuffersInput;
    24.  
    25.             [ReadOnly]
    26.             public BufferFromEntity<TaskOutputPort> BuffersOutput;
    27.            
    28.             [ReadOnly]
    29.             [DeallocateOnJobCompletion]
    30.             public NativeArray<Entity> RequestEntities;
    31.             [ReadOnly]
    32.             [DeallocateOnJobCompletion]
    33.             public NativeArray<Request> Requests;
    34.             [ReadOnly]
    35.             [DeallocateOnJobCompletion]
    36.             public NativeArray<TransferRequest> TransferRequests;
    37.  
    38.             public void Execute(Entity taskEntity, int index, ref Task task)
    39.             {
    40.                 var bufferInput = BuffersInput[taskEntity];
    41.                 if (!JobUtils.CheckTaskAvailable(task, bufferInput)) return;
    42.  
    43.                 var requestEntity = bufferInput.Find(port =>
    44.                     port.PortName == GetTransferRequestValues.InputPortRequestName).EntityValue;
    45.  
    46.                 var requestId = NativeArrayExtensions.IndexOf(RequestEntities, requestEntity);
    47.                
    48.                 var request = Requests[requestId];
    49.                 var transferRequest = TransferRequests[requestId];
    50.  
    51.                 JobUtils.OutputFlowAndVariables(taskEntity, ref BuffersOutput, ref BuffersInput,
    52.                     (outputPortName, nextInputPort) =>
    53.                     {
    54.                         if(outputPortName == GetTransferRequestValues.OutputPortItemName)
    55.                         {
    56.                             nextInputPort.EntityValue = transferRequest.ItemEntity;
    57.                         }else if (outputPortName == GetTransferRequestValues.OutputPortContainerName)
    58.                         {
    59.                             nextInputPort.EntityValue = transferRequest.TargetContainerEntity;
    60.                         }else if (outputPortName == GetTransferRequestValues.OutputPortCountName)
    61.                         {
    62.                             nextInputPort.FloatValue = transferRequest.Count;
    63.                         }else
    64.                         if (outputPortName == GetTransferRequestValues.OutputPortExecuterName)
    65.                         {
    66.                             nextInputPort.EntityValue = request.ExecutorEntity;
    67.                         }
    68.                         return nextInputPort;
    69.                     });
    70.  
    71.                 task.Status = TaskStatus.Done;
    72.             }
    73.         }
    74.  
    75.         protected override JobHandle OnUpdate(JobHandle inputDeps)
    76.         {
    77.             var requestEntities = _requestGroup.ToEntityArray(Allocator.TempJob,
    78.                 out var initRequestEntitiesHandle);
    79.             var requests = _requestGroup.ToComponentDataArray<Request>(Allocator.TempJob,
    80.                 out var initRequestsHandle);
    81.             var transferRequests = _requestGroup.ToComponentDataArray<TransferRequest>(
    82.                 Allocator.TempJob, out var initTransferRequestsHandle);
    83.             var requestHandle = JobHandle.CombineDependencies(
    84.                 initRequestEntitiesHandle, initRequestsHandle, initTransferRequestsHandle);
    85.             var initHandle = JobHandle.CombineDependencies(inputDeps, requestHandle);
    86.            
    87.             var job = new TaskJob
    88.             {
    89.                 BuffersInput = GetBufferFromEntity<TaskInputPort>(),
    90.                 BuffersOutput = GetBufferFromEntity<TaskOutputPort>(true),
    91.                 RequestEntities = requestEntities,
    92.                 Requests = requests,
    93.                 TransferRequests = transferRequests
    94.             };
    95.             var handle = job.Schedule(this, initHandle);
    96.             return handle;
    97.         }
    98.     }
    99. }
     
  10. zephyr831125

    zephyr831125

    Joined:
    Mar 4, 2017
    Posts:
    54
    And there is one thing maybe important: When I run the unit tests of this system, tests passed and no error log. Only when playing in editor, comes that error log.
     
  11. digitaliliad

    digitaliliad

    Joined:
    Jul 1, 2018
    Posts:
    64
    I am sorry that didn't resolve the dependency issues. The error you're getting in the editor is just a warning from the safety system that if another system tries accessing this container, the resulting behavior could be an issue. If no other system accesses this container, you could possibly ignore this issue until it's better documented.
     
  12. zephyr831125

    zephyr831125

    Joined:
    Mar 4, 2017
    Posts:
    54
    You are very kind. I eventually separate the variable I care about to a new ComponentData, out of Request. Which finally walk around this issue.