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. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Issue writing to Dynamic Buffer from Job

Discussion in 'Entity Component System' started by rjohnson06, Nov 15, 2018.

  1. rjohnson06

    rjohnson06

    Joined:
    May 27, 2017
    Posts:
    17
    I'm getting an error trying to write to an entity's dynamicBuffer from within an IJob : "InvalidOperationException: The native container has been declared as [ReadOnly] in the job, but you are writing to it."
    I'm confused, I don't think I'm declaring it as readonly.

    This is the offending line :
    woodCutterBuffer.Add(new WoodCutterBufferElement { Value = woodCutterEntity });


    Code (CSharp):
    1. public struct ProcessUnAssignedWoodCutters : IJob
    2.         {
    3.             [ReadOnly]
    4.             [DeallocateOnJobCompletion]
    5.             public NativeArray<ArchetypeChunk> unAssignedWoodCutters;
    6.            
    7.             [DeallocateOnJobCompletion]
    8.             public NativeArray<ArchetypeChunk> woodCutterBuildingChunks;
    9.  
    10.             public ArchetypeChunkBufferType<WoodCutterBufferElement> woodCutterBufferType;
    11.            
    12.             public ArchetypeChunkComponentType<WoodCutterBuilding> woodCutterBuildingType;
    13.            
    14.             [ReadOnly]
    15.             public ArchetypeChunkEntityType entityType;
    16.  
    17.             public EntityCommandBuffer buffer;
    18.  
    19.             public void Execute()
    20.             {
    21.                 for (var i = 0; i < unAssignedWoodCutters.Length; i++)
    22.                 {
    23.                     var chunk = unAssignedWoodCutters[i];
    24.                     var chunkCount = chunk.Count;
    25.                     var woodCutterEntities = chunk.GetNativeArray(entityType);
    26.  
    27.                     for (var j = 0; j < chunkCount; j++)
    28.                     {
    29.                         var woodCutterEntity = woodCutterEntities[j];
    30.  
    31.                         for (var x = 0; x < woodCutterBuildingChunks.Length; x++)
    32.                         {
    33.                             var buildingChunk = woodCutterBuildingChunks[x];
    34.                             var buildingChunkCount = buildingChunk.Count;
    35.                             var buildingWoodCutterBuffers = buildingChunk.GetBufferAccessor(woodCutterBufferType);
    36.                             var buildingDataArray = buildingChunk.GetNativeArray(woodCutterBuildingType);
    37.  
    38.                             for (var y = 0; y < buildingWoodCutterBuffers.Length; y++)
    39.                             {
    40.                                 var woodCutterBuffer = buildingWoodCutterBuffers[y];
    41.                                 var buildingData = buildingDataArray[y];
    42.                                 if (woodCutterBuffer.Length == buildingData.maxWorkers)
    43.                                 {
    44.                                     continue;
    45.                                 }
    46.  
    47.                                 woodCutterBuffer.Add(new WoodCutterBufferElement { Value = woodCutterEntity });
    48.                                 buffer.RemoveComponent(woodCutterEntity, typeof(NotAssignedToBuilding));
    49.                             }
    50.                         }
    51.                     }
    52.                 }
    53.             }
    54.         }
    55.  
    56.  
    57.  
    58. private JobHandle ScheduleUnAssignedWorkersJob(JobHandle inputDeps)
    59.         {
    60.             var entityType = EntityManager.GetArchetypeChunkEntityType();
    61.            
    62.             // process un-assigned woodcutters
    63.             var unassignedWoodCuttersQuery = new EntityArchetypeQuery
    64.             {
    65.                 Any = new ComponentType[0],
    66.                 None = new ComponentType[0],
    67.                 All = new ComponentType[] { typeof(WoodCutterOccupation), typeof(NotAssignedToBuilding) }
    68.             };
    69.  
    70.             var woodCutterBuildingQuery = new EntityArchetypeQuery
    71.             {
    72.                 Any = new ComponentType[0],
    73.                 None = new ComponentType[0],
    74.                 All = new ComponentType[] { typeof(WoodCutterBuilding) }
    75.             };
    76.  
    77.             woodCutterBuildingChunks = EntityManager.CreateArchetypeChunkArray(woodCutterBuildingQuery, Allocator.TempJob);
    78.             unassignedWoodCutterChunks = EntityManager.CreateArchetypeChunkArray(unassignedWoodCuttersQuery, Allocator.TempJob);
    79.             var woodCutterBuildingBufferType = EntityManager.GetArchetypeChunkBufferType<WoodCutterBufferElement>(false);
    80.             var woodCutterBuildingType = EntityManager.GetArchetypeChunkComponentType<WoodCutterBuilding>(false);
    81.  
    82.             var processUnAssignedWoodCuttersJob = new ProcessUnAssignedWoodCutters
    83.             {
    84.                 unAssignedWoodCutters = unassignedWoodCutterChunks,
    85.                 woodCutterBuildingChunks = woodCutterBuildingChunks,
    86.                 woodCutterBufferType = woodCutterBuildingBufferType,
    87.                 woodCutterBuildingType = woodCutterBuildingType,
    88.                 buffer = unassignedWorkersBarrier.CreateCommandBuffer(),
    89.                 entityType = entityType
    90.             };
    91.  
    92.             return processUnAssignedWoodCuttersJob.Schedule(inputDeps);
    93.         }
    94.  
    95.  
    96.  
    97. [InternalBufferCapacity(8)]
    98.     public struct WoodCutterBufferElement : IBufferElementData
    99.     {
    100.         // These implicit conversions are optional, but can help reduce typing.
    101.         public static implicit operator Entity(WoodCutterBufferElement e) { return e.Value; }
    102.         public static implicit operator WoodCutterBufferElement(Entity e) { return new WoodCutterBufferElement { Value = e }; }
    103.  
    104.         // Actual value each buffer element will store.
    105.         public Entity Value;
    106.     }
     
  2. dartriminis

    dartriminis

    Joined:
    Feb 3, 2017
    Posts:
    157
    hmm... if you're calling this within a component system, you shouldn't be using the EntityManager.Get/CreateArchetypeChunk... types, you should be using the [Job]ComponentSystem variants. This may be what's causing your issue.
     
  3. rjohnson06

    rjohnson06

    Joined:
    May 27, 2017
    Posts:
    17
    What are the [Job]ComponentSystem variants ?
     
  4. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,647
    Posted the same thing here: https://forum.unity.com/threads/bug...-used-differently-in-multiple-systems.583141/

    Seems to be an issue when declared readonly in one system and writeable in another.

    If the readonly job occurs before the write job the error will throw.
    If it occurs the other way it'll work fine.

    As a workaround, either order your systems by ones that do writing ones first or call Complete() on the handle before the write jobs.