Search Unity

Disposing of NativeArrays that are passed into Jobs

Discussion in 'Entity Component System' started by MadboyJames, Sep 27, 2019.

  1. MadboyJames

    MadboyJames

    Joined:
    Oct 28, 2017
    Posts:
    262
    I am getting the infamous "A Native Collection has not been disposed, resulting in a memory leak. Enable Full StackTraces to get more details." error, and I'm fairly sure I know why, but I 'm not sure how to fix it. I'm working on a jobified unit selection system, where I build a native array of Entities to pass into the job. Afterwards I dispose of the array. But I do not dispose of copy of the array inside the job. And quite frankly, I'm not sure how I would manage to. I'm using the array as a list which holds the currently selected units. This is necessary because I switch which units are being selected based on a "hostility-priority gauge". The player can select, either their own units, the enemy units, or neutral units, but never a combination of the three. I'll post the job for reference.
    Code (CSharp):
    1.  public struct SelectionJob : IJobForEachWithEntity<SelectableComponent, Translation>
    2.     {
    3.  
    4.         public EntityCommandBuffer.Concurrent buffer;
    5.         public float3 lowerLeftPosition;
    6.         public float3 upperRightPosition;
    7.         public int selectingHostileLevel;//set to 0
    8.         public int numberOfCurrentSelected;//set to 0
    9.         public NativeArray<Entity> currentSelectedTemp;
    10.         public float3 camPos;
    11.         public float4x4 camProjMaxtrix;
    12.         public float3 camUp;
    13.         public float3 camRight;
    14.         public float3 camForward;
    15.         public float screenWidth;
    16.         public float screenHeight;
    17.         public int myID;
    18.         public NativeArray<bool> teamMatrix;
    19.         public void Execute(Entity entity, int index, ref SelectableComponent selectionData, ref Translation translation)
    20.         {
    21.             float2 entityPosition = ConvertWorldToScreenCoordinates(translation.Value, camPos, camProjMaxtrix, camUp, camRight, camForward, screenWidth, screenHeight, 1);
    22.             if (entityPosition.x >= lowerLeftPosition.x &&
    23.                entityPosition.y >= lowerLeftPosition.y &&
    24.                entityPosition.x <= upperRightPosition.x &&
    25.                entityPosition.y <= upperRightPosition.y)
    26.             {
    27.                 int ownerID = selectionData.ownerID;
    28.                 int ownerHostilityGauge = DeterminTeam(ownerID, myID, teamMatrix);
    29.  
    30.                 if (ownerHostilityGauge == selectingHostileLevel)
    31.                 {
    32.  
    33.                     buffer.AddComponent<SelectedComponent>(index, entity);
    34.                     if (selectingHostileLevel != 1)
    35.                     {
    36.                         currentSelectedTemp[numberOfCurrentSelected] = entity;
    37.                         numberOfCurrentSelected++;
    38.                     }
    39.                 }
    40.                 else if (selectingHostileLevel != 1)
    41.                 {
    42.                     if ((selectingHostileLevel == 0 && ownerHostilityGauge != 0) || (selectingHostileLevel == -1 && ownerHostilityGauge == 1))
    43.                     {
    44.                         selectingHostileLevel = ownerHostilityGauge;
    45.  
    46.                         int length = numberOfCurrentSelected;
    47.                         for (int i = 0; i < length; i++)
    48.                         {
    49.                             buffer.RemoveComponent<SelectedComponent>(index, currentSelectedTemp[i]);
    50.                         }
    51.  
    52.                         numberOfCurrentSelected = 0;
    53.  
    54.                         buffer.AddComponent<SelectedComponent>(index, entity);
    55.                         if (selectingHostileLevel != 1)
    56.                         {
    57.                             currentSelectedTemp[numberOfCurrentSelected] = entity;
    58.                             numberOfCurrentSelected++;
    59.                         }
    60.                     }
    61.                 }
    62.             }
    63.         }
    64.  
    65.  
    66.         int DeterminTeam(int unitTeam, int myID, NativeArray<bool> teamMatrix)
    67.         {
    68.              //var teamMatrix = sceneManager.playerList[myID].playerTeamMatrix;
    69.  
    70.             if (myID == unitTeam)
    71.             {
    72.                 return 1;
    73.             }
    74.             else if (teamMatrix[unitTeam])
    75.             {
    76.                 return -1;
    77.             }
    78.             else if (!teamMatrix[unitTeam])
    79.             {
    80.                 return 0;
    81.             }
    82.  
    83.             return 0;
    84.  
    85.         }
    86.  
    87.         public static float2 ConvertWorldToScreenCoordinates(float3 point, float3 cameraPos, float4x4 camProjMatrix, float3 camUp, float3 camRight, float3 camForward, float pixelWidth, float pixelHeight, float scaleFactor)
    88.         {
    89.             /*
    90.             * 1 convert P_world to P_camera
    91.             */
    92.             float4 pointInCameraCoodinates = ConvertWorldToCameraCoordinates(point, cameraPos, camUp, camRight, camForward);
    93.  
    94.  
    95.             /*
    96.             * 2 convert P_camera to P_clipped
    97.             */
    98.             float4 pointInClipCoordinates = math.mul(camProjMatrix, pointInCameraCoodinates);
    99.  
    100.             /*
    101.             * 3 convert P_clipped to P_ndc
    102.             * Normalized Device Coordinates
    103.             */
    104.             float4 pointInNdc = pointInClipCoordinates / pointInClipCoordinates.w;
    105.  
    106.  
    107.             /*
    108.             * 4 convert P_ndc to P_screen
    109.             */
    110.             float2 pointInScreenCoordinates;
    111.             pointInScreenCoordinates.x = pixelWidth / 2.0f * (pointInNdc.x + 1);
    112.             pointInScreenCoordinates.y = pixelHeight / 2.0f * (pointInNdc.y + 1);
    113.  
    114.  
    115.             // return screencoordinates with canvas scale factor (if canvas coords required)
    116.             return pointInScreenCoordinates / scaleFactor;
    117.         }
    118.  
    119.         private static float4 ConvertWorldToCameraCoordinates(float3 point, float3 cameraPos, float3 camUp, float3 camRight, float3 camForward)
    120.         {
    121.             // translate the point by the negative camera-offset
    122.             //and convert to Vector4
    123.             float4 translatedPoint = new float4(point - cameraPos, 1f);
    124.  
    125.             // create transformation matrix
    126.             float4x4 transformationMatrix = float4x4.identity;
    127.             transformationMatrix.c0 = new float4(camRight.x, camUp.x, -camForward.x, 0);
    128.             transformationMatrix.c1 = new float4(camRight.y, camUp.y, -camForward.y, 0);
    129.             transformationMatrix.c2 = new float4(camRight.z, camUp.z, -camForward.z, 0);
    130.  
    131.             float4 transformedPoint = math.mul(transformationMatrix, translatedPoint);
    132.  
    133.             return transformedPoint;
    134.         }
    135.  
    136.  
    137.     }
    If anyone has any ideas on how to dispose of this implementation of native array, your help will be appreciated.
     
  2. MadboyJames

    MadboyJames

    Joined:
    Oct 28, 2017
    Posts:
    262
    On another error note, This job runs before the selection job

    Code (CSharp):
    1.  [BurstCompile][RequireComponentTag(typeof(SelectedComponent))]//if no shift is down, run this Job
    2.     public struct RemovedSelectedJob : IJobForEachWithEntity<Translation>
    3.     {
    4.         public EntityCommandBuffer.Concurrent buffer;
    5.         public void Execute(Entity entity, int index, [ReadOnly] ref Translation trans)
    6.         {
    7.             buffer.RemoveComponent<SelectedComponent>(index, entity);
    8.         }
    9.     }
    and is giving me a "Cannot find the field `TypeInfos` required for supporting TypeManager intrinsics in burst" error at line
    buffer.RemoveComponent<SelectedComponent>(index, entity);
    , so can I not use the buffer with burst? or am I just using it incorrectly? if the former, will that be fixed at some point? is there a better way to do selection?
     
  3. thelebaron

    thelebaron

    Joined:
    Jun 2, 2013
    Posts:
    857
    Use
    Code (CSharp):
    1. [DeallocateOnJobCompletion] public NativeArray<bool> teamMatrix;
    Also burst is not yet compatible with adding or removing components, try running it without burst and see what it says
     
    MadboyJames likes this.
  4. MadboyJames

    MadboyJames

    Joined:
    Oct 28, 2017
    Posts:
    262
    Okay, Thanks! That is what I was looking for. Sadly it did not help, as a matter of fact, it made things worse. So I guess my next question is what is the path to find ThreadsafeLinearAllocator.cpp to enable full stack trace?
     
  5. ndesy

    ndesy

    Joined:
    Jul 22, 2019
    Posts:
    20
    Can you show part of the code in the system that schedule the SelectionJob?
     
    MadboyJames likes this.
  6. MadboyJames

    MadboyJames

    Joined:
    Oct 28, 2017
    Posts:
    262
    Sure! This is in the OnUpdate method.
    Code (CSharp):
    1.  if (Input.GetMouseButtonUp(0))
    2.         {
    3.             sceneManager.selectionAreaTransform.gameObject.SetActive(false);
    4.             float3 endPosition = Input.mousePosition;
    5.             isSelecting = false;
    6.             if (CheckChatBoxMode()) { return nullHandle; }
    7.          
    8.             float3 lowerLeftPosition = new float3(math.min(graphicStartPosition.x, endPosition.x), math.min(graphicStartPosition.y, endPosition.y), 0);
    9.             float3 UpperRightPosition = new float3(math.max(graphicStartPosition.x, endPosition.x), math.max(graphicStartPosition.y, endPosition.y), 0);
    10.  
    11.             if (!Input.GetKey(KeyCode.LeftShift) && !Input.GetKey(KeyCode.RightShift))
    12.             {
    13.                 var removeSelectedJob = new RemovedSelectedJob
    14.                 {
    15.                     buffer = buffer.CreateCommandBuffer().ToConcurrent()
    16.                 }.Schedule(this, inputDeps);
    17.                 removeSelectedJob.Complete();
    18.             }
    19.  
    20.             float selectionAreaMinSize = 5f;
    21.             float selectionAreaSize = math.distance(lowerLeftPosition, UpperRightPosition);
    22.  
    23.             Entity clickedEntity = Entity.Null;
    24.  
    25.             if (selectionAreaSize < selectionAreaMinSize)
    26.             {
    27.                 clickedEntity = DetermineClickedEntity(sceneManager.groundLayer);
    28.                 var tempBuffer = buffer.CreateCommandBuffer();
    29.                 tempBuffer.AddComponent<SelectedComponent>(clickedEntity);
    30.             }
    31.             else
    32.             {
    33. ///////////////////////////////////////////////This is where the job is scheduled///////////////////////////////////////////
    34.                 NativeArray<Entity> currentSelectedTemp = new NativeArray<Entity>(1000, Allocator.TempJob);
    35.                 NativeArray<bool> teamMatrixTemp = new NativeArray<bool>(sceneManager.PlayerTeamMatrixOutput(sceneManager.me.playerID), Allocator.TempJob);
    36.                 var selectionJob = new SelectionJob
    37.                 {
    38.                     buffer = buffer.CreateCommandBuffer().ToConcurrent(),
    39.                     lowerLeftPosition = lowerLeftPosition,
    40.                     upperRightPosition = UpperRightPosition,
    41.                     selectingHostileLevel = 0,
    42.                     numberOfCurrentSelected=0,
    43.                     currentSelectedTemp = currentSelectedTemp,
    44.                     camPos = mainCam.transform.position,
    45.                     camProjMaxtrix = mainCam.projectionMatrix,
    46.                     camUp = mainCam.transform.up,
    47.                     camRight = mainCam.transform.right,
    48.                     camForward = mainCam.transform.forward,
    49.                     screenWidth = mainCam.pixelWidth,
    50.                     screenHeight = mainCam.pixelHeight,
    51.                     myID = sceneManager.me.playerID,
    52.                     teamMatrix = teamMatrixTemp
    53.                 }.Schedule(this, inputDeps);
    54.                 currentSelectedTemp.Dispose();
    55.                 teamMatrixTemp.Dispose();
    56.                 selectionJob.Complete();
    57.  
    58.                 return selectionJob;
    59.  
    60.             }
    61.  
    62.         }
     
  7. ndesy

    ndesy

    Joined:
    Jul 22, 2019
    Posts:
    20
    You are disposing your NativeArrays before you job get executed! I'm not sure, but I think the error in your first post is a cascade effect of another error you are getting because your job is using a disposed array.

    You should either :

    1) move your Dispose() after selectionJob.Complete()
    2) remove the Dispose() and selectionJob.Complete() and add [DeallocateOnJobCompletion] before the NativeArray in your job.


    That being said, you should try to never call Complete() on JobHandle (if possible), because this is blocking the main thread until the job get executed.
     
    MadboyJames likes this.
  8. MadboyJames

    MadboyJames

    Joined:
    Oct 28, 2017
    Posts:
    262
    Okay, this is my new job input
    Code (CSharp):
    1.  public EntityCommandBuffer.Concurrent buffer;
    2.         public float3 lowerLeftPosition;
    3.         public float3 upperRightPosition;
    4.         public int selectingHostileLevel;//set to 0
    5.         public int numberOfCurrentSelected;//set to 0
    6.         [DeallocateOnJobCompletion] public NativeArray<Entity> currentSelectedTemp;
    7.         public float3 camPos;
    8.         public float4x4 camProjMaxtrix;
    9.         public float3 camUp;
    10.         public float3 camRight;
    11.         public float3 camForward;
    12.         public float screenWidth;
    13.         public float screenHeight;
    14.         public int myID;
    15.         [DeallocateOnJobCompletion] public NativeArray<bool> teamMatrix;
    and I removed the job.complete() and disposes. I'm still getting the same error. I think enabling the full stack trace would at least tell me where my issues are. Any idea where that file is?
     
  9. mukultictoc

    mukultictoc

    Joined:
    Sep 24, 2016
    Posts:
    15
    Your code should look something like this. Keep the [DeAllocateOnJobCompletion] in the job itself on native arrays.

    Code (CSharp):
    1. NativeArray<Entity> currentSelectedTemp = new NativeArray<Entity>(1000, Allocator.TempJob);
    2. NativeArray<bool> teamMatrixTemp = new NativeArray<bool>(sceneManager.PlayerTeamMatrixOutput(sceneManager.me.playerID), Allocator.TempJob);
    3.                 var selectionJob = new SelectionJob
    4.                 {
    5.                     buffer = buffer.CreateCommandBuffer().ToConcurrent(),
    6.                     lowerLeftPosition = lowerLeftPosition,
    7.                     upperRightPosition = UpperRightPosition,
    8.                     selectingHostileLevel = 0,
    9.                     numberOfCurrentSelected=0,
    10.                     currentSelectedTemp = currentSelectedTemp,
    11.                     camPos = mainCam.transform.position,
    12.                     camProjMaxtrix = mainCam.projectionMatrix,
    13.                     camUp = mainCam.transform.up,
    14.                     camRight = mainCam.transform.right,
    15.                     camForward = mainCam.transform.forward,
    16.                     screenWidth = mainCam.pixelWidth,
    17.                     screenHeight = mainCam.pixelHeight,
    18.                     myID = sceneManager.me.playerID,
    19.                     teamMatrix = teamMatrixTemp
    20.                 }.Schedule(this, inputDeps);
    21.  
    22.                buffer.AddJobHandleForProducer(selectionJob)
    23.                 return selectionJob;
     
    MadboyJames likes this.
  10. MadboyJames

    MadboyJames

    Joined:
    Oct 28, 2017
    Posts:
    262
    That certainly helped! There are still aparently a couple issues. One is I am calling the removeSelected job before the SelectionJob, and it doesn't like that I'm not return a jobhandle. Any way to handle this without creating a new system? Here is my whole OnUpdate Method, seeing as its apparently much worse than I thought (I recently jobified the code, although it was working fine on the main thread).
    Code (CSharp):
    1. protected override JobHandle OnUpdate(JobHandle inputDeps)
    2.     {
    3.         JobHandle nullHandle = new JobHandle { };
    4.  
    5.         if (Input.GetMouseButtonDown(0))//reset the start position of the selection area
    6.         {
    7.             sceneManager.selectionAreaTransform.gameObject.SetActive(true);
    8.             graphicStartPosition = Input.mousePosition;
    9.             sceneManager.selectionAreaTransform.position = graphicStartPosition;
    10.             isSelecting = true;
    11.  
    12.         }
    13.  
    14.         if (Input.GetMouseButton(0))//keep resizing the area while the mouse is held down
    15.         {
    16.  
    17.             float3 graphicSelectionAreaSize = (float3)Input.mousePosition - graphicStartPosition;
    18.             sceneManager.selectionAreaTransform.localScale = graphicSelectionAreaSize;
    19.             if (CheckChatBoxMode()) { return nullHandle; }
    20.         }
    21.  
    22.         if (Input.GetMouseButtonUp(0))
    23.         {
    24.             sceneManager.selectionAreaTransform.gameObject.SetActive(false);
    25.             float3 endPosition = Input.mousePosition;
    26.             isSelecting = false;
    27.             if (CheckChatBoxMode()) { return nullHandle; }
    28.          
    29.             float3 lowerLeftPosition = new float3(math.min(graphicStartPosition.x, endPosition.x), math.min(graphicStartPosition.y, endPosition.y), 0);
    30.             float3 UpperRightPosition = new float3(math.max(graphicStartPosition.x, endPosition.x), math.max(graphicStartPosition.y, endPosition.y), 0);
    31.  
    32.             if (!Input.GetKey(KeyCode.LeftShift) && !Input.GetKey(KeyCode.RightShift))
    33.             {
    34.                 var removeSelectedJob = new RemovedSelectedJob
    35.                 {
    36.                     buffer = buffer.CreateCommandBuffer().ToConcurrent()
    37.                 }.Schedule(this, inputDeps);
    38.                 buffer.AddJobHandleForProducer(removeSelectedJob);
    39.                // return removeSelectedJob;
    40.             }
    41.  
    42.             float selectionAreaMinSize = 5f;
    43.             float selectionAreaSize = math.distance(lowerLeftPosition, UpperRightPosition);
    44.  
    45.             Entity clickedEntity = Entity.Null;
    46.  
    47.             if (selectionAreaSize < selectionAreaMinSize)
    48.             {
    49.                 clickedEntity = DetermineClickedEntity(sceneManager.groundLayer);
    50.                 var tempBuffer = buffer.CreateCommandBuffer();
    51.                 tempBuffer.AddComponent<SelectedComponent>(clickedEntity);
    52.             }
    53.             else
    54.             {
    55.  
    56.                 NativeArray<Entity> currentSelectedTemp = new NativeArray<Entity>(1000, Allocator.TempJob);
    57.                 NativeArray<bool> teamMatrixTemp = new NativeArray<bool>(sceneManager.PlayerTeamMatrixOutput(sceneManager.me.playerID), Allocator.TempJob);
    58.                 var selectionJob = new SelectionJob
    59.                 {
    60.                     buffer = buffer.CreateCommandBuffer().ToConcurrent(),
    61.                     lowerLeftPosition = lowerLeftPosition,
    62.                     upperRightPosition = UpperRightPosition,
    63.                     selectingHostileLevel = 0,
    64.                     numberOfCurrentSelected=0,
    65.                     currentSelectedTemp = currentSelectedTemp,
    66.                     camPos = mainCam.transform.position,
    67.                     camProjMaxtrix = mainCam.projectionMatrix,
    68.                     camUp = mainCam.transform.up,
    69.                     camRight = mainCam.transform.right,
    70.                     camForward = mainCam.transform.forward,
    71.                     screenWidth = mainCam.pixelWidth,
    72.                     screenHeight = mainCam.pixelHeight,
    73.                     myID = sceneManager.me.playerID,
    74.                     teamMatrix = teamMatrixTemp
    75.                 }.Schedule(this, inputDeps);
    76.                 buffer.AddJobHandleForProducer(selectionJob);
    77.  
    78.  
    79.                 return selectionJob;
    80.  
    81.             }
    82.  
    83.         }
    84.  
    85.  
    86.  
    87.         return nullHandle;
    88.     }
     
  11. thelebaron

    thelebaron

    Joined:
    Jun 2, 2013
    Posts:
    857
    just return inputDeps if the criteria for job scheduling isnt met. no need for the null handle.

    also full stack tracing is in the menu toolbar: jobs>leak detection> full stack tracing
     
    MadboyJames likes this.
  12. mukultictoc

    mukultictoc

    Joined:
    Sep 24, 2016
    Posts:
    15
    Try something like this. This will create the proper dependencies required.

    Code (CSharp):
    1. protected override JobHandle OnUpdate(JobHandle inputDeps)
    2.     {
    3.     if (Input.GetMouseButtonDown(0))//reset the start position of the selection area
    4.         {
    5.             sceneManager.selectionAreaTransform.gameObject.SetActive(true);
    6.             graphicStartPosition = Input.mousePosition;
    7.             sceneManager.selectionAreaTransform.position = graphicStartPosition;
    8.             isSelecting = true;
    9.         }
    10.         if (Input.GetMouseButton(0))//keep resizing the area while the mouse is held down
    11.         {
    12.             float3 graphicSelectionAreaSize = (float3)Input.mousePosition - graphicStartPosition;
    13.             sceneManager.selectionAreaTransform.localScale = graphicSelectionAreaSize;
    14.             if (CheckChatBoxMode()) { return inputDeps; }
    15.         }
    16.         if (Input.GetMouseButtonUp(0))
    17.         {
    18.             sceneManager.selectionAreaTransform.gameObject.SetActive(false);
    19.             float3 endPosition = Input.mousePosition;
    20.             isSelecting = false;
    21.             if (CheckChatBoxMode()) { return inputDeps; }
    22.        
    23.             float3 lowerLeftPosition = new float3(math.min(graphicStartPosition.x, endPosition.x), math.min(graphicStartPosition.y, endPosition.y), 0);
    24.             float3 UpperRightPosition = new float3(math.max(graphicStartPosition.x, endPosition.x), math.max(graphicStartPosition.y, endPosition.y), 0);
    25.             if (!Input.GetKey(KeyCode.LeftShift) && !Input.GetKey(KeyCode.RightShift))
    26.             {
    27.                 var removeSelectedJob = new RemovedSelectedJob
    28.                 {
    29.                     buffer = buffer.CreateCommandBuffer().ToConcurrent()
    30.                 };
    31.                 inputDeps = removeSelectedJob.Schedule(inputDeps);
    32.                 buffer.AddJobHandleForProducer(removeSelectedJob);
    33.             }
    34.             float selectionAreaMinSize = 5f;
    35.             float selectionAreaSize = math.distance(lowerLeftPosition, UpperRightPosition);
    36.             Entity clickedEntity = Entity.Null;
    37.             if (selectionAreaSize < selectionAreaMinSize)
    38.             {
    39.                 clickedEntity = DetermineClickedEntity(sceneManager.groundLayer);
    40.                 var tempBuffer = buffer.CreateCommandBuffer();
    41.                 tempBuffer.AddComponent<SelectedComponent>(clickedEntity);
    42.             }
    43.             else
    44.             {
    45.                 NativeArray<Entity> currentSelectedTemp = new NativeArray<Entity>(1000, Allocator.TempJob);
    46.                 NativeArray<bool> teamMatrixTemp = new NativeArray<bool>(sceneManager.PlayerTeamMatrixOutput(sceneManager.me.playerID), Allocator.TempJob);
    47.                 var selectionJob = new SelectionJob
    48.                 {
    49.                     buffer = buffer.CreateCommandBuffer().ToConcurrent(),
    50.                     lowerLeftPosition = lowerLeftPosition,
    51.                     upperRightPosition = UpperRightPosition,
    52.                     selectingHostileLevel = 0,
    53.                     numberOfCurrentSelected=0,
    54.                     currentSelectedTemp = currentSelectedTemp,
    55.                     camPos = mainCam.transform.position,
    56.                     camProjMaxtrix = mainCam.projectionMatrix,
    57.                     camUp = mainCam.transform.up,
    58.                     camRight = mainCam.transform.right,
    59.                     camForward = mainCam.transform.forward,
    60.                     screenWidth = mainCam.pixelWidth,
    61.                     screenHeight = mainCam.pixelHeight,
    62.                     myID = sceneManager.me.playerID,
    63.                     teamMatrix = teamMatrixTemp
    64.                 };
    65.                 inputDeps = removeSelectedJob.Schedule(inputDeps);
    66.                 buffer.AddJobHandleForProducer(selectionJob);
    67.  
    68.             }
    69.         }
    70.         return inputDeps;
    71.     }
     
    MadboyJames likes this.
  13. MadboyJames

    MadboyJames

    Joined:
    Oct 28, 2017
    Posts:
    262
    That did it! Okay, thank you for clearing that up for me. Sadly I still have another issue. I'm receiving a "IndexOutOfRangeException: Index 2 is out of restricted IJobParallelFor range [518...2] in ReadWriteBuffer." error when I select units that are not owned by the player. The error is thrown from the DeterminTeam() method in the selection job.
    Code below
    Code (CSharp):
    1.  public struct SelectionJob : IJobForEachWithEntity<SelectableComponent, Translation>
    2.     {
    3.  
    4.         public EntityCommandBuffer.Concurrent buffer;
    5.         public float3 lowerLeftPosition;
    6.         public float3 upperRightPosition;
    7.         public int selectingHostileLevel;//set to 0
    8.         public int numberOfCurrentSelected;//set to 0
    9.         [DeallocateOnJobCompletion] public NativeArray<Entity> currentSelectedTemp;
    10.         public float3 camPos;
    11.         public float4x4 camProjMaxtrix;
    12.         public float3 camUp;
    13.         public float3 camRight;
    14.         public float3 camForward;
    15.         public float screenWidth;
    16.         public float screenHeight;
    17.         public int myID;
    18.         [DeallocateOnJobCompletion] public NativeArray<bool> teamMatrix;
    19.         public void Execute(Entity entity, int index, [ReadOnly] ref SelectableComponent selectionData, [ReadOnly] ref Translation translation)
    20.         {
    21.             float2 entityPosition = ConvertWorldToScreenCoordinates(translation.Value, camPos, camProjMaxtrix, camUp, camRight, camForward, screenWidth, screenHeight, 1);
    22.             if (entityPosition.x >= lowerLeftPosition.x &&
    23.                entityPosition.y >= lowerLeftPosition.y &&
    24.                entityPosition.x <= upperRightPosition.x &&
    25.                entityPosition.y <= upperRightPosition.y)
    26.             {
    27.                 int ownerID = selectionData.ownerID;
    28.                 int ownerHostilityGauge = DeterminTeam(ownerID, myID, teamMatrix);
    29.  
    30.                 if (ownerHostilityGauge == selectingHostileLevel)
    31.                 {
    32.  
    33.                     buffer.AddComponent<SelectedComponent>(index, entity);
    34.                     if (selectingHostileLevel != 1)
    35.                     {
    36.                         currentSelectedTemp[numberOfCurrentSelected] = entity;
    37.                         numberOfCurrentSelected++;
    38.                     }
    39.                 }
    40.                 else if (selectingHostileLevel != 1)
    41.                 {
    42.                     if ((selectingHostileLevel == 0 && ownerHostilityGauge != 0) || (selectingHostileLevel == -1 && ownerHostilityGauge == 1))
    43.                     {
    44.                         selectingHostileLevel = ownerHostilityGauge;
    45.  
    46.                         int length = numberOfCurrentSelected;
    47.                         for (int i = 0; i < length; i++)
    48.                         {
    49.                             buffer.RemoveComponent<SelectedComponent>(index, currentSelectedTemp[i]);
    50.                         }
    51.  
    52.                         numberOfCurrentSelected = 0;
    53.  
    54.                         buffer.AddComponent<SelectedComponent>(index, entity);
    55.                         if (selectingHostileLevel != 1)
    56.                         {
    57.                             currentSelectedTemp[numberOfCurrentSelected] = entity;
    58.                             numberOfCurrentSelected++;
    59.                         }
    60.                     }
    61.                 }
    62.             }
    63.         }
    64.  
    65.  
    66.         int DeterminTeam(int unitTeam, int myID, NativeArray<bool> teamMatrix)
    67.         {
    68.              //var teamMatrix = sceneManager.playerList[myID].playerTeamMatrix;
    69.  
    70.             if (myID == unitTeam)
    71.             {
    72.                 //teamMatrix.Dispose();
    73.                 return 1;
    74.             }
    75.             else if (teamMatrix[unitTeam])
    76.             {
    77.                // teamMatrix.Dispose();
    78.                 return -1;
    79.             }
    80.             else if (!teamMatrix[unitTeam])
    81.             {
    82.                 //teamMatrix.Dispose();
    83.                 return 0;
    84.             }
    85.             //teamMatrix.Dispose();
    86.             return 0;
    87.  
    88.         }
    89.  
    90.         public static float2 ConvertWorldToScreenCoordinates(float3 point, float3 cameraPos, float4x4 camProjMatrix, float3 camUp, float3 camRight, float3 camForward, float pixelWidth, float pixelHeight, float scaleFactor)
    91.         {
    92.             /*
    93.             * 1 convert P_world to P_camera
    94.             */
    95.             float4 pointInCameraCoodinates = ConvertWorldToCameraCoordinates(point, cameraPos, camUp, camRight, camForward);
    96.  
    97.  
    98.             /*
    99.             * 2 convert P_camera to P_clipped
    100.             */
    101.             float4 pointInClipCoordinates = math.mul(camProjMatrix, pointInCameraCoodinates);
    102.  
    103.             /*
    104.             * 3 convert P_clipped to P_ndc
    105.             * Normalized Device Coordinates
    106.             */
    107.             float4 pointInNdc = pointInClipCoordinates / pointInClipCoordinates.w;
    108.  
    109.  
    110.             /*
    111.             * 4 convert P_ndc to P_screen
    112.             */
    113.             float2 pointInScreenCoordinates;
    114.             pointInScreenCoordinates.x = pixelWidth / 2.0f * (pointInNdc.x + 1);
    115.             pointInScreenCoordinates.y = pixelHeight / 2.0f * (pointInNdc.y + 1);
    116.  
    117.  
    118.             // return screencoordinates with canvas scale factor (if canvas coords required)
    119.             return pointInScreenCoordinates / scaleFactor;
    120.         }
    121.  
    122.         private static float4 ConvertWorldToCameraCoordinates(float3 point, float3 cameraPos, float3 camUp, float3 camRight, float3 camForward)
    123.         {
    124.             // translate the point by the negative camera-offset
    125.             //and convert to Vector4
    126.             float4 translatedPoint = new float4(point - cameraPos, 1f);
    127.  
    128.             // create transformation matrix
    129.             float4x4 transformationMatrix = float4x4.identity;
    130.             transformationMatrix.c0 = new float4(camRight.x, camUp.x, -camForward.x, 0);
    131.             transformationMatrix.c1 = new float4(camRight.y, camUp.y, -camForward.y, 0);
    132.             transformationMatrix.c2 = new float4(camRight.z, camUp.z, -camForward.z, 0);
    133.  
    134.             float4 transformedPoint = math.mul(transformationMatrix, translatedPoint);
    135.  
    136.             return transformedPoint;
    137.         }
    138.  
    139.  
    140.     }
    Is there any way to multithread this? or create a switch by some other means?
    Essentially what I'm doing is I look at the hostility level of the selected unit (either neutral (0), Enemy (-1) or friendly (1)), if it is neutral, I add it to a List<Entity> currentlySelected. Then if an entity in the selection area is an enemy, I use the currentlySelected list to do a lookup on all the neutral entities I was selecting this frame, and remove their selected component. Then I start only adding Enemy units. Repeat this for Enemy-> Friendly. The problem arises that the list I am using (which is a native array) needs to be shared across jobs. I suppose my question would then be, "is there a different way to do this?"
     
    Last edited: Sep 28, 2019