Search Unity

Errors with running Jobs

Discussion in 'Entity Component System' started by e199, Nov 28, 2018.

  1. e199

    e199

    Joined:
    Mar 24, 2015
    Posts:
    101
    Hey

    I'm making a simple test to see how it all works.

    In the project I have Monobehaviour which is adding components when some physics interaction happens.
    Then I will have systems which are acting on that "Event".
    And on the last step those "Event" components are removed in the jobs.

    And that Job is throwing errors to me, which are unclear as hell. I don't want to call Complete and wait on main thread.

    Code (CSharp):
    1. using System.Collections.Generic;
    2. using Unity.Entities;
    3. using UnityEngine;
    4.  
    5. public class PhysicsEmitter : MonoBehaviour
    6. {
    7.     private static readonly Dictionary<Collider, GameObjectEntity> Cache = new Dictionary<Collider, GameObjectEntity>(256);
    8.  
    9.     public GameObjectEntity Entity;
    10.     private PhysicsEventEmissionBarrier _barrier;
    11.  
    12.     private void Start()
    13.     {
    14.         _barrier = World.Active.GetOrCreateManager<PhysicsEventEmissionBarrier>();
    15.     }
    16.  
    17.     private GameObjectEntity GetEntity(Collider other)
    18.     {
    19.         GameObjectEntity e;
    20.         var found = Cache.TryGetValue(other, out e);
    21.      
    22.         if (!found)
    23.         {
    24.             e = other.GetComponent<GameObjectEntity>();
    25.             Cache.Add(other, e);
    26.         }
    27.  
    28.         return e;
    29.     }
    30.  
    31.     private void OnTriggerEnter(Collider other)
    32.     {
    33.         var e = GetEntity(other);
    34.         if (e != null)
    35.         {
    36.             var buffer = _barrier.CreateCommandBuffer();
    37.             buffer.AddComponent(Entity.Entity, new TriggerEnter{Trigger = e.Entity});
    38.         }
    39.     }
    40.  
    41.     private void OnTriggerExit(Collider other)
    42.     {
    43.         var e = GetEntity(other);
    44.         if (e != null)
    45.         {
    46.             var buffer = _barrier.CreateCommandBuffer();
    47.             buffer.AddComponent(Entity.Entity, new TriggerExit{Trigger = e.Entity});
    48.         }
    49.     }
    50.  
    51.     private void OnCollisionEnter(Collision other)
    52.     {
    53.      
    54.     }
    55.  
    56.     private void OnCollisionExit(Collision other)
    57.     {
    58.      
    59.     }
    60. }

    Code (CSharp):
    1. using Unity.Entities;
    2. using Unity.Jobs;
    3.  
    4. [UpdateAfter(typeof(PhysicsEventRemoveBarrier))]
    5. public class PhysicsEventRemoveSystem : JobComponentSystem
    6. {
    7.     private BarrierSystem _barrier;
    8.  
    9.     protected override void OnCreateManager()
    10.     {
    11.         _barrier = World.GetOrCreateManager<EndFrameBarrier>();
    12.     }
    13.  
    14.     private struct RemoveTriggerEnter : IJobProcessComponentDataWithEntity<TriggerEnter>
    15.     {
    16.         public EntityCommandBuffer.Concurrent Commands;
    17.         public void Execute(Entity entity, int index, ref TriggerEnter data)
    18.         {
    19.             Commands.RemoveComponent<TriggerEnter>(index, entity);
    20.         }
    21.     }
    22.  
    23.     private struct RemoveTriggerExit : IJobProcessComponentDataWithEntity<TriggerExit>
    24.     {
    25.         public EntityCommandBuffer.Concurrent Commands;
    26.         public void Execute(Entity entity, int index, ref TriggerExit data)
    27.         {
    28.             Commands.RemoveComponent<TriggerExit>(index, entity);
    29.         }
    30.     }
    31.     protected override JobHandle OnUpdate(JobHandle inputDeps)
    32.     {
    33.         var handle = new RemoveTriggerEnter {Commands = _barrier.CreateCommandBuffer().ToConcurrent()}
    34.                 .Schedule(this, inputDeps);
    35.         handle = new RemoveTriggerExit {Commands = _barrier.CreateCommandBuffer().ToConcurrent()}
    36.             .Schedule(this, handle);
    37.         return handle;
    38.     }
    39. }

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using Unity.Entities;
    4. using Unity.Mathematics;
    5. using UnityEngine;
    6.  
    7. [UpdateBefore(typeof(EndFrameBarrier))]
    8. public class PhysicsEventRemoveBarrier : BarrierSystem{}
    9.  
    10. [UpdateBefore(typeof(PhysicsEventRemoveBarrier))]
    11. public class PhysicsEventEmissionBarrier : BarrierSystem{}
    12.  
    13. public struct TriggerEnter : IComponentData
    14. {
    15.     public Entity Trigger;
    16. }
    17.  
    18. public struct TriggerExit : IComponentData
    19. {
    20.     public Entity Trigger;
    21. }
    22.  
    23. public struct CollisionEnter : IComponentData
    24. {
    25.     public Entity Trigger;
    26.     public float3 Position;
    27.     public float3 Normal;
    28. }
    29.  
    30. public struct CollisionExit : IComponentData
    31. {
    32.     public Entity Trigger;
    33. }

     
  2. SubPixelPerfect

    SubPixelPerfect

    Joined:
    Oct 14, 2015
    Posts:
    224
    e199 likes this.
  3. e199

    e199

    Joined:
    Mar 24, 2015
    Posts:
    101
    Yes, that worked. Thanks.

    Too bad there is no single place with all those inconveniences listed :(
     
  4. SubPixelPerfect

    SubPixelPerfect

    Joined:
    Oct 14, 2015
    Posts:
    224
    read all posts in this forom,and this single place will be in your head )
    I made a habit to write down notes with link to source, when see something interestin or usefull
     
  5. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,761
    I'm not really sure why you're even using a barrier in a MonoBehaviour.
     
  6. e199

    e199

    Joined:
    Mar 24, 2015
    Posts:
    101
    That way I'm sure when components are added and can update dependent systems after that barrier
     
  7. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,761
    But physics events happens in PreUpdate before all your systems are going to run so they'll always be added/updated beforehand.

    -edit-

    What I'm saying is, I think you should just use EntityManager.Set|Add|etc within MonoBehaviour.
     
  8. e199

    e199

    Joined:
    Mar 24, 2015
    Posts:
    101
    That code would execute each time I add component with EntityManager. When I use barrier - it will do it once, right?
    Code (CSharp):
    1.         private void BeforeStructuralChange()
    2.         {
    3. #if ENABLE_UNITY_COLLECTIONS_CHECKS
    4.             if (ComponentJobSafetyManager.IsInTransaction)
    5.                 throw new InvalidOperationException(
    6.                     "Access to EntityManager is not allowed after EntityManager.BeginExclusiveEntityTransaction(); has been called.");
    7. #endif
    8.             ComponentJobSafetyManager.CompleteAllJobsAndInvalidateArrays();
    9.         }
     
  9. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,761
    Well

    Code (CSharp):
    1. #if ENABLE_UNITY_COLLECTIONS_CHECKS
    2.             if (ComponentJobSafetyManager.IsInTransaction)
    3.                 throw new InvalidOperationException(
    4.                     "Access to EntityManager is not allowed after EntityManager.BeginExclusiveEntityTransaction(); has been called.");
    5. #endif
    Is stripped out at runtime.

    ComponentJobSafetyManager.CompleteAllJobsAndInvalidateArrays();


    Won't do anything after the first run (even then I don't think it'll do much, jobs should be finished by this stage.)

    Where as, you are allocating a new EntityCommandBuffer every time you add a component.

    _barrier.CreateCommandBuffer();


    While it's mostly only a malloc, they do start adding up if you have a lot of objects.
     
    e199 likes this.
  10. e199

    e199

    Joined:
    Mar 24, 2015
    Posts:
    101
    Thanks, I'll leave it as is until I would hit a roadblock then,
    Can you please stick around for 10 mins, I gonna post a new thread