Search Unity

At a loss regarding this exception. Can anyone help?

Discussion in 'Entity Component System' started by gilley033, Jul 1, 2019.

  1. gilley033

    gilley033

    Joined:
    Jul 10, 2012
    Posts:
    1,191
    I am at a loss as to why this exception is occurring.

    code=CSharp]InvalidOperationException: The system BroadPhaseCollisionDetectionSystem reads PhysicsLayerNonShared 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.[/code]
    The code is rather long, which I apologize for, but it's necessary to post it all. I am only posting the OnUpdate method; if you think I need to post the rest of the code from this JobComponentSystem, please let me know.
    Code (CSharp):
    1. protected override JobHandle OnUpdate(JobHandle inputDeps)
    2. {
    3.     if (clearPreviousExecution)
    4.         ClearPreviousExecution();
    5.  
    6.     if (buildStaticGeometryCollisionGrid)
    7.         inputDeps = CreateStaticGeometryStuff(inputDeps);
    8.  
    9.     int length;
    10.        
    11.     NativeArray<ProjectedAABB> aabbSet = default;
    12.     NativeArray<PhysicsLayerNonShared> physicsLayersNonShared = default;
    13.     NativeArray<Entity> entities = default;
    14.  
    15.     JobHandle aabbSetCreation = default, physicsLayersNonSharedCreation = default, entitiesCreation = default;
    16.     if (physicsStateSystem.PhysicsState == PhysicsState.Full_Tick_Non_Movement_Collision_Resolution)
    17.     {
    18.         length = nonGeometryPhysicsObjects.CalculateLength();
    19.  
    20.         if (length != 0)
    21.         {
    22.             aabbSet = nonGeometryPhysicsObjects.ToComponentDataArray<ProjectedAABB>(Allocator.TempJob, out aabbSetCreation);
    23.             physicsLayersNonShared = nonGeometryPhysicsObjects.ToComponentDataArray<PhysicsLayerNonShared>(Allocator.TempJob, out physicsLayersNonSharedCreation);
    24.             entities = nonGeometryPhysicsObjects.ToEntityArray(Allocator.TempJob, out entitiesCreation);
    25.         }
    26.         else
    27.             return inputDeps;
    28.     }
    29.     else
    30.     {
    31.         length = movingNonGeometryPhysicsObjects.CalculateLength();
    32.         if (length != 0)
    33.         {
    34.             aabbSet = movingNonGeometryPhysicsObjects.ToComponentDataArray<ProjectedAABB>(Allocator.TempJob, out aabbSetCreation);
    35.             physicsLayersNonShared = movingNonGeometryPhysicsObjects.ToComponentDataArray<PhysicsLayerNonShared>(Allocator.TempJob, out physicsLayersNonSharedCreation);
    36.             entities = movingNonGeometryPhysicsObjects.ToEntityArray(Allocator.TempJob, out entitiesCreation);
    37.         }
    38.         else
    39.             return inputDeps;
    40.     }
    41.        
    42.     JobHandle jobSet1 = JobHandle.CombineDependencies(inputDeps, aabbSetCreation, physicsLayersNonSharedCreation);
    43.  
    44.     JobHandle initialCreationJobs = JobHandle.CombineDependencies(jobSet1, entitiesCreation);
    45.  
    46.     int countOfHowManyLayersInteratForNonMovingCollisionCheck = 0;
    47.  
    48.     EntityManager.GetAllUniqueSharedComponentData(physicsLayers);
    49.     if (physicsStateSystem.PhysicsState == PhysicsState.Full_Tick_Non_Movement_Collision_Resolution)
    50.     {
    51.         for (int i = 1, j = 1; i < physicsLayers.Count; i++)
    52.         {
    53.             var layer1 = physicsLayers[i].Layer;
    54.             for (; j < physicsLayers.Count; j++)
    55.             {
    56.                 var layer2 = physicsLayers[j].Layer;
    57.                 if (!Physics2D.GetIgnoreLayerCollision(layer1, layer2))
    58.                 {
    59.                     countOfHowManyLayersInteratForNonMovingCollisionCheck++;
    60.                 }
    61.             }
    62.             j = i + 1;
    63.         }
    64.  
    65.         if (countOfHowManyLayersInteratForNonMovingCollisionCheck == 0)
    66.         {
    67.             physicsLayers.Clear();
    68.             return inputDeps;
    69.         }
    70.     }
    71.  
    72.     clearPreviousExecution = true;
    73.  
    74.  
    75.     //* 4 because each aabb can possibly be in 4 cells. Though this is probably not going to happen that much,
    76.     //if we don't prepare for the possibility then we may get into trouble later.
    77.     //If we have objects that are bigger than our cell radius we will need to increase this value.
    78.     var collisionGrid = new NativeMultiHashMap<int, int>(length * 4, Allocator.TempJob);
    79.  
    80.     previousExecution = new PrevExecution()
    81.     {
    82.         collisionGrid = collisionGrid,
    83.         copyAABBSet = aabbSet,
    84.         copyEntities = entities
    85.     };
    86.        
    87.     var buildCollisionGridJobHandle = new BuildMovingGeometryCollisionGrid()
    88.     {
    89.         collisionGrid = collisionGrid.ToConcurrent(),
    90.         aabbSet = aabbSet,
    91.         physicsLayers = physicsLayersNonShared,
    92.         cellSize = 2
    93.     }.Schedule(length, 64, initialCreationJobs);
    94.  
    95.     //buildCollisionGridJobHandle.Complete();
    96.        
    97.     if (physicsStateSystem.PhysicsState == PhysicsState.Full_Tick_Non_Movement_Collision_Resolution)
    98.     {
    99.         var jobList = new NativeList<JobHandle>(GridHash.FIXED_SPACE_HEIGHT * GridHash.FIXED_SPACE_WIDTH * countOfHowManyLayersInteratForNonMovingCollisionCheck, Allocator.Temp);
    100.  
    101.         for (int row = 0; row < GridHash.FIXED_SPACE_HEIGHT; row++)
    102.         {
    103.             for (int column = 0; column < GridHash.FIXED_SPACE_WIDTH; column++)
    104.             {
    105.                 //skip i = 0 (default case) as it's useless
    106.                 for (int i = 1, j = 1; i < physicsLayers.Count; i++)
    107.                 {
    108.                     var layer1 = physicsLayers[i].Layer;
    109.                     int hash1 = GridHash.Hash(new int3(column, row, layer1));
    110.                     //NativeMultiHashMapIterator<int> iterator;
    111.                     //int value;
    112.  
    113.                     //Make sure collision grid cell [Column, Row] at Layer i has objects in it
    114.                     //if (!collisionGrid.TryGetFirstValue(hash1, out value, out iterator))
    115.                     //    continue;
    116.  
    117.                     //Now loop through all physics layers to run the collision check
    118.                     //Note, however, if we were to loop through the physics layers in full, we would run
    119.                     //duplicate comparisons, for instance we'd compare layer 2 and 1 after already comparing
    120.                     //1 and 2. To avoid this, after each inner loop, we set the next start index to
    121.                     //i + 1
    122.                     for (; j < physicsLayers.Count; j++)
    123.                     {
    124.                         var layer2 = physicsLayers[j].Layer;
    125.  
    126.                         //Actually make sure layer1 and layer2 objects can collide with each other.
    127.                         if (Physics2D.GetIgnoreLayerCollision(layer1, layer2))
    128.                             continue;
    129.  
    130.                         //Make sure collision grid cell [column, row] at layer j has objects in it
    131.                         int hash2 = GridHash.Hash(new int3(column, row, layer2));
    132.  
    133.                         //NativeMultiHashMapIterator<int> iterator2;
    134.                         //int value2;
    135.  
    136.                         ////Make sure collision grid cell [Column, Row] at Layer i has objects in it
    137.                         //if (!collisionGrid.TryGetFirstValue(hash2, out value2, out iterator2))
    138.                         //    continue;
    139.  
    140.                         jobList.Add((new CheckForPotentialNonMovingCollisions()
    141.                         {
    142.                             collisionGrid = collisionGrid,
    143.                             entities = entities,
    144.                             aabbSet = aabbSet,
    145.                             buffer = broadPhaseBarrierSystem.CreateCommandBuffer(),
    146.                             potentialCollisionArchetype = potentialNonMovingCollisionArchetype,
    147.                             hash1 = hash1,
    148.                             hash2 = hash2
    149.                         }).Schedule(buildCollisionGridJobHandle));
    150.                     }
    151.                     j = i + 1;
    152.                 }
    153.             }
    154.         }
    155.  
    156.         var returnHandle = buildCollisionGridJobHandle;
    157.         if (jobList.Length > 0)
    158.         {
    159.             NativeArray<JobHandle> jobHandleArray = new NativeArray<JobHandle>(jobList.Length, Allocator.Temp, NativeArrayOptions.UninitializedMemory);
    160.             for (int i = 0; i < jobHandleArray.Length; i++)
    161.                 jobHandleArray[i] = jobList[i];
    162.  
    163.             returnHandle = JobHandle.CombineDependencies(jobHandleArray);
    164.             jobHandleArray.Dispose();
    165.         }
    166.  
    167.         jobList.Dispose();
    168.  
    169.         physicsLayers.Clear();
    170.  
    171.         broadPhaseBarrierSystem.AddJobHandleForProducer(returnHandle);
    172.  
    173.         return returnHandle;
    174.     }
    175.     else
    176.     {
    177.         NativeArray<int> movingLayers = new NativeArray<int>(physicsLayers.Count-1, Allocator.TempJob, NativeArrayOptions.UninitializedMemory);
    178.            
    179.         for (int i = 0; i < movingLayers.Length; i++)
    180.             movingLayers[i] = physicsLayers[i+1].Layer;
    181.  
    182.         physicsLayers.Clear();
    183.  
    184.         var finalJob = new CheckForPotentialMovingCollisions()
    185.         {
    186.             nonStaticGeometryCollisionGrid = collisionGrid,
    187.             staticEntities = staticEntitySetCopy,
    188.             nonStaticEntities = entities,
    189.             staticAABBSet = staticAABBSetCopy,
    190.             nonStaticAABBSet = aabbSet,
    191.             physicsLayersToCompare = movingLayers,
    192.             buffer = broadPhaseBarrierSystem.CreateCommandBuffer().ToConcurrent(),
    193.             potentialCollisionArchetype = potentialMovingCollisionArchetype
    194.  
    195.         }.Schedule(staticGeometryCollisionGrid, 64, buildCollisionGridJobHandle);
    196.  
    197.         broadPhaseBarrierSystem.AddJobHandleForProducer(finalJob);
    198.         return finalJob;
    199.     }
    200. }
    The job dependencies are chained such that the final returned dependency should include the job that produces physicsLayerNonShared. In fact, physicsLayerNonShared is created in exactly the same manner as the aabbSet and entities array, so I don't understand why it's producing an error only for physicsLayerNonShared.

    If you're curious, this system is the Broad Phase collision detection system for a custom physics simulation. I know it's not real clear what's going on here; hopefully that is not a hindrance to someone being able to follow the dependency chain to determine if I've made a mistake somewhere.
     
  2. snacktime

    snacktime

    Joined:
    Apr 15, 2013
    Posts:
    3,356
    Maybe another case of they haven't exposed enough dependencies to handle all use cases. I ran into that with BuildPhysicsWorld where they provide a jobhandle to combine with, but not to set back to. There are still a lot of rough edges, I have more then one customization to get around job dependency handling not being completely thought through.
     
  3. gilley033

    gilley033

    Joined:
    Jul 10, 2012
    Posts:
    1,191
    Well, I love the idea that the offense is with code I haven't created (yay ego!), but I don't see why the error pops up for (I assume this is the offending code at least)
    Code (CSharp):
    1. ToComponentDataArray<PhysicsLayerNonShared>
    and not the other ToComponentDataArray calls.

    All of the ToComponentDataArray JobHandles are combined, so you'd think they would all create errors if the was an issue.
     
  4. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    4,271
    Can you share the stack trace of the exception from the throw site to the line in your class?
     
  5. gilley033

    gilley033

    Joined:
    Jul 10, 2012
    Posts:
    1,191
    I can give the full stack trace, but part of the problem with tracking this down is that it doesn't give me a line in my System where the offending code is. But here is the stack trace anyway.
    Code (CSharp):
    1. InvalidOperationException: The system BroadPhaseCollisionDetectionSystem reads PhysicsLayerNonShared 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.
    2. Unity.Entities.JobComponentSystem.AfterOnUpdate (Unity.Jobs.JobHandle outputJob, System.Boolean throwException) (at Library/PackageCache/com.unity.entities@0.0.12-preview.33/Unity.Entities/ComponentSystem.cs:918)
    3. Unity.Entities.JobComponentSystem.InternalUpdate () (at Library/PackageCache/com.unity.entities@0.0.12-preview.33/Unity.Entities/ComponentSystem.cs:954)
    4. Unity.Entities.ComponentSystemBase.Update () (at Library/PackageCache/com.unity.entities@0.0.12-preview.33/Unity.Entities/ComponentSystem.cs:287)
    5. Unity.Entities.ComponentSystemGroup.OnUpdate () (at Library/PackageCache/com.unity.entities@0.0.12-preview.33/Unity.Entities/ComponentSystemGroup.cs:451)
    6. UnityEngine.Debug:LogException(Exception)
    7. Unity.Debug:LogException(Exception) (at Library/PackageCache/com.unity.entities@0.0.12-preview.33/Unity.Entities/Stubs/Unity/Debug.cs:25)
    8. Unity.Entities.ComponentSystemGroup:OnUpdate() (at Library/PackageCache/com.unity.entities@0.0.12-preview.33/Unity.Entities/ComponentSystemGroup.cs:455)
    9. Unity.Entities.ComponentSystem:InternalUpdate() (at Library/PackageCache/com.unity.entities@0.0.12-preview.33/Unity.Entities/ComponentSystem.cs:818)
    10. Unity.Entities.ComponentSystemBase:Update() (at Library/PackageCache/com.unity.entities@0.0.12-preview.33/Unity.Entities/ComponentSystem.cs:287)
    11. TestLevelBootstrapper:Update() (at Assets/MyAssets/ECS/BootstrapAbstraction/TestLevelBootstrapper.cs:266)
     
  6. gilley033

    gilley033

    Joined:
    Jul 10, 2012
    Posts:
    1,191
    Immediately after posting the stack trace I think I may have found the issue.

    Code (CSharp):
    1. int countOfHowManyLayersInteratForNonMovingCollisionCheck = 0;
    2.     EntityManager.GetAllUniqueSharedComponentData(physicsLayers);
    3.     if (physicsStateSystem.PhysicsState == PhysicsState.Full_Tick_Non_Movement_Collision_Resolution)
    4.     {
    5.         for (int i = 1, j = 1; i < physicsLayers.Count; i++)
    6.         {
    7.             var layer1 = physicsLayers[i].Layer;
    8.             for (; j < physicsLayers.Count; j++)
    9.             {
    10.                 var layer2 = physicsLayers[j].Layer;
    11.                 if (!Physics2D.GetIgnoreLayerCollision(layer1, layer2))
    12.                 {
    13.                     countOfHowManyLayersInteratForNonMovingCollisionCheck++;
    14.                 }
    15.             }
    16.             j = i + 1;
    17.         }
    18.         if (countOfHowManyLayersInteratForNonMovingCollisionCheck == 0)
    19.         {
    20.             physicsLayers.Clear();
    21.             return inputDeps;
    22.         }
    23.     }
    The if statement returns just the inputDeps even though the ToComponentDataArray jobs are run. Not sure why it only throws an error on physicsLayersNonShared, but when I move this code to before the ToComponentDataArray calls, the error goes away (though I have several other errors).

    Sorry for posting this!
     
  7. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    4,271
    It is throwing the error because the specific API you were using gave the system enough information to determine that you weren't returning the correct JobHandle. That only works for certain types of scheduled jobs.

    This is hardly a beginner issue. So don't feel bad about posting about it. Someone else is going to find this thread and see they made the same mistake and be able to fix it.

    Just out of curiosity, what's the custom physics simulation for? I'm doing a bunch of custom physics stuff too and this looks like a very complicated solution to one of the simpler problems.
     
  8. gilley033

    gilley033

    Joined:
    Jul 10, 2012
    Posts:
    1,191
    It's for a game inspired by the classic bubble popping game Super Buster Bros. I created the custom physics simulation outside of DOTS a couple years ago because in order for the bubbles to stay in sync as in the classic game, a deterministic simulation was required. It is also useful since if I ever release the game, it will be a multiplayer and having deterministic physics makes networking easier.

    I am now attempting to convert everything to DOTS in an attempt to become familiar with what I think is the future of Unity. It's very likely that I am over complicating things, however I wanted to try and get the system up and running before going back and trying to see if there was a different way to do things.

    The particular system I'm posting about is for the broad phase collision detection phase. Since my levels are small and of a fixed size, I am using a uniform grid system for the physics, where every physics object is assigned to up to four cells in the grid. The broad phase is just going through every pair of (potentially interacting) physics objects and determining whether they share a cell, and then performing a basic AABB check on the two objects to see if they might overlap. A "potential collision" entity is created if so, and later in the narrow phase (a different system) I run a more precise collision check.

    I was working on this before Unity announced there new physics technology, and though I've thought about just using that, I decided to keep working my tech in order to further my knowledge of DOTS. Plus, my needs are far less complicated physically speaking, and I figure having a custom solution will make things easier if I ever decide to build a full game out of this stuff.

    I am no expert when it comes to physics, multi-threading, DOTS, etc. so I do not claim the way I am doing things is what's best. Why it may seem a little complicated is that I am resolving collisions between moving stuff and static geometry a little differently than the collisions between moving stuff with other moving stuff. I can't remember exactly why (I designed most of these core systems years ago), except that it was important to do things this way (or perhaps easier).

    There's more to why my system is more complicated, which I can get into if you're interested.
     
  9. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    4,271
    If you are checking every potential pair to see if they are in the same cell, you might as well skip the fixed grid and just AABB vs AABB every potential pair.

    If you want to actually take advantage of a fixed grid, then after assigning objects to the grid you only want to compare objects that share a grid. A lot of people on these forums have been attempting this with NativeMultiHashMap or a DynamicBuffer of entities each having a DynamicBuffer of other entities. I personally use a counting sort to group items sharing cells while keeping everything in a single array (this is for a multi-box pruner).
     
  10. gilley033

    gilley033

    Joined:
    Jul 10, 2012
    Posts:
    1,191
    Sorry, I didn't explain that right. What you describe is exactly what I am doing, using a NativeMultiHashMap to only do an AABB test on objects that are in the same cell.
     
  11. sngdan

    sngdan

    Joined:
    Feb 7, 2014
    Posts:
    1,154
    And do you still have issues or did you figure it out?
     
  12. gilley033

    gilley033

    Joined:
    Jul 10, 2012
    Posts:
    1,191
    The error I was seeing is gone, but I still have other issues. I'll try to work through them before asking for help though.