Search Unity

[SOLVED] Error in previously working code. Need [ReadOnly] attrib, but where?

Discussion in 'Entity Component System' started by JamesWjRose, Sep 10, 2020.

  1. JamesWjRose

    JamesWjRose

    Joined:
    Apr 13, 2017
    Posts:
    687
    So... a couple of months ago I had to stop working on my game and do other things, among them reformat and reinstall everything on my dev machine. I updated to the most recent version of Unity (2020.1.4f1) and the latest versions of DOTS. Now I am getting the following error mentioning that I need to set an object to ReadOnly. Cool, fine, sure... which one?!

    Code (CSharp):
    1.  
    2. InvalidOperationException: The ComponentDataFromEntity<RoadDetails> <>c__DisplayClass_OnUpdate_LambdaJob0.JobData.RoadDetailsFromEntity must be marked [ReadOnly] in the job ER3D_TrafficSystem:<>c__DisplayClass_OnUpdate_LambdaJob0, because the container itself is marked read only.
    3.  
    4. Unity.Entities.JobChunkExtensions.FinalizeScheduleChecked (System.Boolean isParallel, System.Int32 unfilteredChunkCount, Unity.Jobs.JobHandle prefilterHandle, Unity.Collections.NativeArray`1[T] prefilterData, System.Void* deferredCountData, System.Boolean useFiltering, Unity.Jobs.LowLevel.Unsafe.JobsUtility+JobScheduleParameters& scheduleParams, System.Boolean& executed, Unity.Jobs.JobHandle& result) (at Library/PackageCache/com.unity.entities@0.14.0-preview.18/Unity.Entities/IJobChunk.cs:270)
    5. Unity.Entities.JobChunkExtensions.ScheduleInternal[T] (T& jobData, Unity.Entities.EntityQuery query, Unity.Jobs.JobHandle dependsOn, Unity.Jobs.LowLevel.Unsafe.ScheduleMode mode, System.Boolean isParallel) (at Library/PackageCache/com.unity.entities@0.14.0-preview.18/Unity.Entities/IJobChunk.cs:246)
    6. Unity.Entities.JobChunkExtensions.ScheduleSingle[T] (T jobData, Unity.Entities.EntityQuery query, Unity.Jobs.JobHandle dependsOn) (at Library/PackageCache/com.unity.entities@0.14.0-preview.18/Unity.Entities/IJobChunk.cs:131)
    7. ER3D_TrafficSystem.OnUpdate () (at Assets/HBC/Scripts/ER3D_TrafficSystem.cs:49)
    8.  
    Ok, so it's talking about line 49 (see the entire class below) and specifically this line:
    Code (CSharp):
    1. RoadDetails roadDetails = RoadDetailsFromEntity[roads[i]];
    at line 79. I know this because if I comment it out, the code runs without error (not completely true, it moves on to screaming about the same issue with ConnectionDetailsFromEntity, but you get my point)

    Within the OnUpdate there are the declarations for the ...FromEntity", however when I attempt to place a "[ReadOnly]" attribute, that too screams at me.

    So... what changed with the process and does anyone care to point me in the right direction?

    Thank you very much.

    Code (CSharp):
    1. using Unity.Burst;
    2. using Unity.Collections;
    3. using Unity.Entities;
    4. using Unity.Jobs;
    5. using Unity.Mathematics;
    6. using Unity.Transforms;
    7. using UnityEngine;
    8.  
    9. public class ER3D_TrafficSystem : SystemBase
    10. {
    11.     private NativeArray<Entity> roadEntities;
    12.     private NativeArray<Entity> connectionEntities;
    13.    
    14.     protected override void OnStartRunning()
    15.     {
    16.         EntityQuery allRoadsQuery = GetEntityQuery(
    17.             typeof(ERRoadTag),
    18.             ComponentType.ReadOnly<RoadDetails>(),
    19.             ComponentType.ReadOnly<LanePoints>());
    20.  
    21.  
    22.         roadEntities = allRoadsQuery.ToEntityArray(Allocator.Persistent);
    23.  
    24.         EntityQuery allConnectionsQuery = GetEntityQuery(
    25.             typeof(ERConnectionTag),
    26.             ComponentType.ReadOnly<ConnectionDetails>(),
    27.             ComponentType.ReadOnly<LanePoints>());
    28.  
    29.         connectionEntities = allConnectionsQuery.ToEntityArray(Allocator.Persistent);
    30.     }
    31.  
    32.     [BurstCompile]
    33.     protected override void OnUpdate()
    34.     {
    35.         System.Random random = new System.Random();
    36.         uint randomSeed = (uint)random.Next(88, 1000000);
    37.         float dt = Time.DeltaTime;
    38.         float reachedPositionDistance = 2.5f;
    39.         NativeArray<Entity> roads = roadEntities;
    40.         NativeArray<Entity> connections = connectionEntities;
    41.  
    42.         ComponentDataFromEntity<RoadDetails> RoadDetailsFromEntity = GetComponentDataFromEntity<RoadDetails>(true);
    43.         ComponentDataFromEntity<ConnectionDetails> ConnectionDetailsFromEntity = GetComponentDataFromEntity<ConnectionDetails>(true);
    44.  
    45.         BufferFromEntity<LanePoints> LanePointsFromEntity = GetBufferFromEntity<LanePoints>(true);
    46.  
    47.  
    48.         Entities.WithAll<ERAutoTag>()
    49.             .ForEach((
    50.             DynamicBuffer<AutoLanePoints> autoLanePoints,
    51.             ref AutoDetails autoDetails,
    52.             ref AutoPosition autoPosition,
    53.             ref Translation translation,
    54.             ref Rotation rotation) =>
    55.             {
    56.                 var distance = math.distance(autoPosition.Destination, translation.Value);
    57.  
    58.                 if (distance <= reachedPositionDistance)
    59.                 {
    60.                     autoPosition.CurrentPositionIndex += 1;
    61.  
    62.                     if (autoPosition.CurrentPositionIndex >= autoLanePoints.Length)
    63.                     {
    64.                         autoPosition.CurrentPositionIndex = 0;
    65.                         autoLanePoints.Clear();
    66.  
    67.                         int laneIndex = 0;
    68.                         int roadIdentity = 0;
    69.                         int connectionIdentityEnd = 0;
    70.  
    71.                         for (int i = 0; i < roads.Length; i++)
    72.                         {
    73.                             RoadDetails roadDetails = RoadDetailsFromEntity[roads[i]];
    74.  
    75.                             if ((roadDetails.RoadIdentity == autoPosition.RoadIdentity) &&
    76.                             (roadDetails.LaneIndex == autoPosition.LaneIndex) &&
    77.                             (roadDetails.ConnectionIdentityStart == autoPosition.ConnectionIdentity) &&
    78.                             (roadDetails.ConnectionIndexStart == autoPosition.ConnectionIndex)
    79.                             )
    80.                             {
    81.                                 laneIndex = roadDetails.LaneIndex;
    82.                                 roadIdentity = roadDetails.RoadIdentity;
    83.                                 connectionIdentityEnd = roadDetails.ConnectionIdentityEnd;
    84.  
    85.                                 var roadLanePointsBuffer = LanePointsFromEntity[roads[i]];
    86.                                 var roadLanePoints = roadLanePointsBuffer.ToNativeArray(Allocator.Temp);
    87.                                 var lanePointAuto = new AutoLanePoints();
    88.                                 for (int pointIndex = 0; pointIndex < roadLanePoints.Length; pointIndex++)
    89.                                 {
    90.                                     lanePointAuto.value = roadLanePoints[pointIndex].value;
    91.                                     autoLanePoints.Add(lanePointAuto);
    92.                                 }
    93.                                 break;
    94.                             }
    95.                         }
    96.  
    97.                         //Get the Connection's Lane's points
    98.                         //First find all options that have the same Idenity and Index.
    99.                         //Then we can randomly select one of the routes through the connection
    100.                         NativeList<Entity> availableConnections = new NativeList<Entity>(Allocator.Temp);
    101.  
    102.                         for (int i = 0; i < connections.Length; i++)
    103.                         {
    104.                             var connectionDetails = ConnectionDetailsFromEntity[connections[i]];
    105.  
    106.                             if ((connectionDetails.ConnectionIdentity == connectionIdentityEnd) &&
    107.                                 (connectionDetails.LaneIndexStart == laneIndex) &&
    108.                                 (connectionDetails.RoadIdentityStart == roadIdentity) &&
    109.                                 (connectionDetails.ConnectionIndexStart == autoPosition.ConnectionIndex))
    110.                             {
    111.                                 availableConnections.Add(connections[i]);
    112.                             }
    113.                         }
    114.  
    115.                         Unity.Mathematics.Random mathRandom = new Unity.Mathematics.Random(randomSeed);
    116.                         int randomValue = mathRandom.NextInt(0, availableConnections.Length);
    117.                         var connectionDetailsNew = ConnectionDetailsFromEntity[availableConnections[randomValue]];
    118.                         var connectionLanePointsBuffer = LanePointsFromEntity[availableConnections[randomValue]];
    119.                         var connectionLanePoints = connectionLanePointsBuffer.ToNativeArray(Allocator.Temp);
    120.                         var lanePoint = new AutoLanePoints();
    121.  
    122.                         for (int x = 0; x < connectionLanePoints.Length; x++)
    123.                         {
    124.                             lanePoint.value = connectionLanePoints[x].value;
    125.                             autoLanePoints.Add(lanePoint);
    126.                         }
    127.  
    128.                         //Reset the Auto's variables for the next Road/Connection selection
    129.                         autoPosition.LaneIndex = connectionDetailsNew.LaneIndexEnd;
    130.                         autoPosition.RoadIdentity = connectionDetailsNew.RoadIdentityEnd;
    131.                         autoPosition.ConnectionIdentity = connectionDetailsNew.ConnectionIdentity;
    132.                         autoPosition.ConnectionIndex = connectionDetailsNew.ConnectionIndexEnd;
    133.  
    134.                         availableConnections.Dispose();
    135.                     }
    136.  
    137.                     autoPosition.Destination = autoLanePoints[autoPosition.CurrentPositionIndex].value;
    138.                     autoPosition.Destination.y += autoDetails.yOffset;
    139.                 }
    140.  
    141.  
    142.                 float3 lookVector = autoPosition.Destination - translation.Value;
    143.                 if (!lookVector.Equals(float3.zero))
    144.                 {
    145.                     Quaternion rotationLookAt = Quaternion.LookRotation(lookVector);
    146.                     rotation.Value = rotationLookAt;
    147.                 }
    148.  
    149.                 float3 smoothedPosition = math.lerp(translation.Value, autoPosition.Destination, autoDetails.speed * dt);
    150.                 translation.Value = smoothedPosition;
    151.  
    152.             }).Schedule();
    153.     }
    154. }
     
  2. brunocoimbra

    brunocoimbra

    Joined:
    Sep 2, 2015
    Posts:
    679
    When you pass "true" in GetComponentDataFromEntity you need also to use WithReadOnly in Entities.ForEach:
    Code (CSharp):
    1. Entities.WithReadOnly(RoadDetailsFromEntity).WithReadOnly(ConnectionDetailsFromEntity).WithAll.........
    Another option is to not use GetComponentDataFromEntity at all and just use Get/Has/SetComponent directly (SystemBase codegens it to GetComponentDataFromEntity with the correct read/write access for you)
     
    lclemens likes this.
  3. JamesWjRose

    JamesWjRose

    Joined:
    Apr 13, 2017
    Posts:
    687
    Thank you very much, I'll check this out in the morning. You rule.

    Have a great weekend
     
    brunocoimbra likes this.
  4. lclemens

    lclemens

    Joined:
    Feb 15, 2020
    Posts:
    761
    How do you do that with a Job instead of Entities.ForEach()? Like for example...

    Code (CSharp):
    1. protected override void OnUpdate()
    2.     {
    3.         Dependency = new CollisionEventImpulseJob {
    4.             ColliderEventImpulseGroup = GetComponentDataFromEntity<HealthData>(true),
    5.             PhysicsVelocityGroup = GetComponentDataFromEntity<PhysicsVelocity>(),
    6.         }.Schedule(m_StepPhysicsWorldSystem.Simulation, ref m_BuildPhysicsWorldSystem.PhysicsWorld, Dependency);
    7.     }
     
  5. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    4,271
    You use the [ReadOnly] attribute like you would a NativeArray.
     
  6. lclemens

    lclemens

    Joined:
    Feb 15, 2020
    Posts:
    761
    You mean like this?

    Code (CSharp):
    1.     struct CollisionEventImpulseJob : ICollisionEventsJob
    2.     {
    3.         [ReadOnly] public ComponentDataFromEntity<HealthData> ColliderEventImpulseGroup;
    4.          ...
    5.     }
    Putting [ReadOnly] there still causes the error: "InvalidOperationException: The ComponentDataFromEntity<HealthData> CollisionEventImpulseJob.UserJobData.ColliderEventImpulseGroup must be marked [ReadOnly] in the job CollisionEventImpulseSystem:CollisionEventImpulseJob, because the container itself is marked read only."

    I can't think of where else to put [ReadOnly]....
     
  7. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,685
    Make sure you're using Unity.Collections.ReadOnly and not something like System.ComponentModel.ReadOnly
     
  8. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    4,271
    Yes. But your error suggests there may be an additional level of nesting than what your code snippet shows, which means I am not seeing the real code and consequently not seeing the real problem.
     
  9. lclemens

    lclemens

    Joined:
    Feb 15, 2020
    Posts:
    761
    OMG!! eizenhorn you are a LEGEND!! Changing [ReadOnly] to [Unity.Collections.ReadOnly] fixed it. It was using a ReadOnly attribute from an editor utility that I had imported. I can't thank you enough man! I spent 12 hours trying to track down that problem yesterday and you fixed it in 20 seconds. Wish I could buy you a beer or something.