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. Join us on March 30, 2023, between 5 am & 1 pm EST, in the Performance Profiling Dev Blitz Day 2023 - Q&A forum and Discord where you can connect with our teams behind the Memory and CPU Profilers.
    Dismiss Notice

CollisionWorld.m_Bodies has been deallocated. All containers must be valid when scheduling a job.

Discussion in 'Physics for ECS' started by sstrong, Dec 9, 2019.

  1. sstrong

    sstrong

    Joined:
    Oct 16, 2013
    Posts:
    2,133
    Whether I use a single IJob or a IJobForEach with I can't get past the following error:
    Code (CSharp):
    1. InvalidOperationException: The NativeContainer ProjectilePhysicsRayJob.Data.physicsWorldInJob.CollisionWorld.m_Bodies has been deallocated. All containers must be valid when scheduling a job.
    2. Unity.Entities.JobForEachExtensions.Schedule (System.Void* fullData, Unity.Collections.NativeArray`1[T] prefilterData, System.Int32 unfilteredLength, System.Int32 innerloopBatchCount, System.Boolean isParallelFor, System.Boolean isFiltered, Unity.Entities.JobForEachExtensions+JobForEachCache& cache, System.Void* deferredCountData, Unity.Jobs.JobHandle dependsOn, Unity.Jobs.LowLevel.Unsafe.ScheduleMode mode) (at Library/PackageCache/com.unity.entities@0.3.0-preview.4/Unity.Entities/IJobForEach.cs:433)
    3. Unity.Entities.JobForEachExtensions.ScheduleInternal_CC[T] (T& jobData, Unity.Entities.ComponentSystemBase system, Unity.Entities.EntityQuery query, System.Int32 innerloopBatchCount, Unity.Jobs.JobHandle dependsOn, Unity.Jobs.LowLevel.Unsafe.ScheduleMode mode) (at Library/PackageCache/com.unity.entities@0.3.0-preview.4/Unity.Entities/IJobForEach.gen.cs:1915)
    4. Unity.Entities.JobForEachExtensions.Schedule[T] (T jobData, Unity.Entities.ComponentSystemBase system, Unity.Jobs.JobHandle dependsOn) (at Library/PackageCache/com.unity.entities@0.3.0-preview.4/Unity.Entities/IJobForEach.gen.cs:811)
    I'm not sure how this is happening.

    Code (CSharp):
    1.     public class TestPhysicsCollision : MonoBehaviour
    2.     {
    3.         public GameObject startObject;
    4.         public float distance = 50f;
    5.  
    6.         private Unity.Physics.PhysicsWorld physicsWorld;
    7.         private NativeArray<Unity.Physics.RaycastHit> physicsraycastResults;
    8.         private bool isInitialised = false;
    9.         Unity.Physics.RaycastInput raycastInput;
    10.  
    11.         public struct RaycastJob : IJob
    12.         {
    13.             public Unity.Physics.RaycastInput RaycastInput;
    14.             public NativeArray<Unity.Physics.RaycastHit> raycastResults;
    15.  
    16.             [ReadOnly] public Unity.Physics.PhysicsWorld world;
    17.  
    18.             public void Execute()
    19.             {
    20.                 if (world.CastRay(RaycastInput, out Unity.Physics.RaycastHit hit))
    21.                 {
    22.                     if (raycastResults.Length == 1)
    23.                     {
    24.                         raycastResults[0] = hit;
    25.                     }
    26.                 }
    27.             }
    28.         }
    29.  
    30.         private void Awake()
    31.         {
    32.            
    33.             DOTSHelper.GetPhysicsWorld(DOTSHelper.GetDefaultWorld(), ref physicsWorld);
    34.             isInitialised = true;
    35.         }
    36.  
    37.         private void RunQuery()
    38.         {
    39.             float3 origin = startObject.transform.position;
    40.             float3 direction = (startObject.transform.rotation * startObject.transform.forward) * distance;
    41.  
    42.             if (!physicsraycastResults.IsCreated)
    43.             {
    44.                 physicsraycastResults = new NativeArray<Unity.Physics.RaycastHit>(1, Allocator.TempJob);
    45.             }
    46.  
    47.             if (physicsraycastResults.IsCreated)
    48.             {
    49.                 Debug.Log("[DEBUG] runquery");
    50.  
    51.                 raycastInput = new Unity.Physics.RaycastInput()
    52.                 {
    53.                     Start = origin,
    54.                     End = origin + direction,
    55.                     Filter = Unity.Physics.CollisionFilter.Default
    56.                 };
    57.  
    58.                 new RaycastJob
    59.                 {
    60.                     RaycastInput = raycastInput,
    61.                     raycastResults = physicsraycastResults,
    62.                     world = physicsWorld,
    63.                 }.Schedule().Complete();
    64.             }
    65.  
    66.  
    67.             if (physicsraycastResults.IsCreated) { physicsraycastResults.Dispose(); }
    68.         }
    69.  
    70.         void OnDrawGizmos()
    71.         {
    72.             if (!isInitialised) { return; }
    73.             RunQuery();
    74.  
    75.             if (physicsraycastResults.IsCreated)
    76.             {
    77.                 Gizmos.color = Color.magenta;
    78.  
    79.                 Gizmos.color = Color.blue;
    80.                 Gizmos.DrawRay(raycastInput.Start, raycastInput.End);
    81.  
    82.                 foreach (Unity.Physics.RaycastHit hit in physicsraycastResults)
    83.                 {
    84.                     Gizmos.color = Color.magenta;
    85.                     Gizmos.DrawRay(raycastInput.Start, hit.Position - raycastInput.Start);
    86.                 }
    87.             }
    88.         }
    89.     }
     
  2. steveeHavok

    steveeHavok

    Joined:
    Mar 19, 2019
    Posts:
    481
    The main problem is that you need to grab the BuildPhysicsWorld and grab the PhysicsWorld handle from there. Grabbing the PhysicsWorld itself is making a copy of an empty world. The following works:
    Code (CSharp):
    1. using Unity.Collections;
    2. using Unity.Entities;
    3. using Unity.Jobs;
    4. using Unity.Mathematics;
    5. using Unity.Physics.Systems;
    6. using UnityEngine;
    7.  
    8. public class TestPhysicsCollision : MonoBehaviour
    9. {
    10.     public GameObject startObject;
    11.     public float distance = 50f;
    12.  
    13.     private BuildPhysicsWorld buildPhysicsWorld;
    14.     private NativeArray<Unity.Physics.RaycastHit> physicsraycastResults;
    15.     private bool isInitialised = false;
    16.     Unity.Physics.RaycastInput raycastInput;
    17.  
    18.     public struct RaycastJob : IJob
    19.     {
    20.         public Unity.Physics.RaycastInput RaycastInput;
    21.         public NativeArray<Unity.Physics.RaycastHit> raycastResults;
    22.  
    23.         [ReadOnly] public Unity.Physics.CollisionWorld world;
    24.  
    25.         public void Execute()
    26.         {
    27.             if (world.CastRay(RaycastInput, out Unity.Physics.RaycastHit hit))
    28.             {
    29.                 if (raycastResults.Length == 1)
    30.                 {
    31.                     raycastResults[0] = hit;
    32.                 }
    33.             }
    34.         }
    35.     }
    36.  
    37.     private void OnDestroy()
    38.     {
    39.         if (physicsraycastResults.IsCreated)
    40.         {
    41.             physicsraycastResults.Dispose();
    42.         }
    43.     }
    44.  
    45.     private void Awake()
    46.     {
    47.         buildPhysicsWorld = World.DefaultGameObjectInjectionWorld.GetExistingSystem<BuildPhysicsWorld>();
    48.         isInitialised = true;
    49.         if (startObject == null)
    50.             startObject = this.gameObject;
    51.     }
    52.  
    53.     private void RunQuery()
    54.     {
    55.         float3 origin = startObject.transform.position;
    56.         float3 direction = (startObject.transform.rotation * startObject.transform.forward) * distance;
    57.  
    58.         if (!physicsraycastResults.IsCreated)
    59.         {
    60.             physicsraycastResults = new NativeArray<Unity.Physics.RaycastHit>(1, Allocator.TempJob);
    61.         }
    62.  
    63.         if (physicsraycastResults.IsCreated)
    64.         {
    65.             Debug.Log("[DEBUG] runquery");
    66.  
    67.             raycastInput = new Unity.Physics.RaycastInput()
    68.             {
    69.                 Start = origin,
    70.                 End = origin + direction,
    71.                 Filter = Unity.Physics.CollisionFilter.Default
    72.             };
    73.  
    74.             new RaycastJob
    75.             {
    76.                 RaycastInput = raycastInput,
    77.                 raycastResults = physicsraycastResults,
    78.                 world = buildPhysicsWorld.PhysicsWorld.CollisionWorld,
    79.             }.Schedule().Complete();
    80.  
    81.             Debug.Log($"[DEBUG] post runquery : {physicsraycastResults[0].SurfaceNormal}");
    82.         }
    83.     }
    84.  
    85.     void OnDrawGizmos()
    86.     {
    87.         if (!isInitialised) { return; }
    88.         RunQuery();
    89.  
    90.         if (physicsraycastResults.IsCreated)
    91.         {
    92.             Gizmos.color = Color.magenta;
    93.  
    94.             Gizmos.color = Color.blue;
    95.             Gizmos.DrawRay(raycastInput.Start, raycastInput.End);
    96.  
    97.             foreach (Unity.Physics.RaycastHit hit in physicsraycastResults)
    98.             {
    99.                 Gizmos.color = Color.magenta;
    100.                 Gizmos.DrawRay(raycastInput.Start, hit.Position - raycastInput.Start);
    101.             }
    102.         }
    103.     }
    104. }
    The only other thing I changed was the results Dispose. I assumed you needed actually want it Disposed in the RunQuery function as you were using it later on?
     
    nicolasgramlich likes this.
  3. sstrong

    sstrong

    Joined:
    Oct 16, 2013
    Posts:
    2,133
    Great, thanks.
    Should CollisionWorld be accessed every update or can it be cached like the BuildPhysicsWorld and does it make a difference if all objects are static or there is a mixture of static and moving objects?
    Code (CSharp):
    1. world = buildPhysicsWorld.PhysicsWorld.CollisionWorld
     
    nicolasgramlich likes this.
  4. steveeHavok

    steveeHavok

    Joined:
    Mar 19, 2019
    Posts:
    481
    I really do need to confirm exactly what is going on there. Copy by values errors do could creep in in a few place (e.g. colliders should be passed by ref), and it seems Worlds are the same I just got into a habit of not caching the world itself and just the build system instead rather than thinking about it! During testing of your system, I was seeing a physicsWorld with 0 rigid bodies, and early demos that did grab the world also grabbed a ref of the world, so I suspect its still an issue. You're setup did throw up a few problems with querying a world with 0 bodies so there are still a few edges case bugs I need to log of the back of this.
    This use case when the world was cached had the bodies array of length zero, so the mixture of body types was irrelevant. FYI the worlds bodies array is shared anyway with dynamic bodies at the front of the array.
     
    nicolasgramlich likes this.