Search Unity

Help with Adding Components and Destroying Entities

Discussion in 'Entity Component System' started by Vwy29, Feb 2, 2019.

  1. Vwy29

    Vwy29

    Joined:
    Jul 11, 2018
    Posts:
    6
    Hi, I'm still a beginner in Unity and Unity ECS but I chose to give it a try but I'm having some difficulties when I tried to add a component to a entity and then destroy that entity. I created 2 systems, one to keep track of the entities HP and if it gets under 0 it should add a component called Delete (Delete is just a IComponentData with a float timeCount inside) and the other system is called DeleteSystem and it runs over all entities with the Delete component and removes the entity if the Delete.timeCount is less than the actual time.
    Code (CSharp):
    1.  
    2. public class HealthSystem : JobComponentSystem
    3. {
    4.  
    5.     public class HealthBarrier : BarrierSystem
    6.     {
    7.  
    8.     }
    9.  
    10.     [Inject] public HealthBarrier barrier;
    11.  
    12.     private struct HealthJob : IJobProcessComponentDataWithEntity<Health>
    13.     {
    14.         public float deltaTime;
    15.  
    16.         public EntityCommandBuffer.Concurrent commandBuffer;
    17.  
    18.         public void Execute(Entity entity, int i, ref Health health)
    19.         {
    20.             health.currentHealth -= health.damage;
    21.             if(health.currentHealth < 0)
    22.             {
    23.                 Debug.Log("StartAdd" + i.ToString());
    24.                 Delete delete = new Delete(0);
    25.                 commandBuffer.AddComponent(i, entity, delete);
    26.                 Debug.Log("EndAdd");
    27.             }
    28.         }
    29.     }
    30.  
    31.     protected override JobHandle OnUpdate(JobHandle inputDeps)
    32.     {
    33.         JobHandle healthSetupJobHandle = healthSetupJob.Schedule(this, inputDeps);
    34.         var healthJob = new HealthJob
    35.         {
    36.             deltaTime = Time.deltaTime,
    37.             commandBuffer = barrier.CreateCommandBuffer().ToConcurrent(),
    38.         };
    39.         return healthJob.Schedule(this, healthSetupJobHandle);
    40.     }
    41. }
    and

    Code (CSharp):
    1. [UpdateAfter(typeof(HealthSystem))]
    2. [UpdateAfter(typeof(HealthSystem.HealthBarrier))]
    3. public class DeleteSystem : JobComponentSystem
    4. {
    5.     public class DeleteBarrier : BarrierSystem
    6.     {
    7.  
    8.     }
    9.     [Inject] public DeleteBarrier barrier;
    10.  
    11.     private struct DeleteJob : IJobProcessComponentDataWithEntity<Delete>
    12.     {
    13.         [ReadOnly]
    14.         public float time;
    15.  
    16.         public EntityCommandBuffer.Concurrent commandBuffer;
    17.        
    18.         public void Execute(Entity entity, int i, ref Delete delete)
    19.         {
    20.             Debug.Log("DeleteStart");
    21.             if(delete.timeCount <= time)
    22.             {
    23.                 commandBuffer.DestroyEntity(i, entity);
    24.             }
    25.             Debug.Log("DeleteEnd");
    26.         }
    27.     }
    28.  
    29.     protected override JobHandle OnUpdate(JobHandle inputDeps)
    30.     {
    31.         var deleteJob = new DeleteJob
    32.         {
    33.             time = Time.time,
    34.             commandBuffer = barrier.CreateCommandBuffer().ToConcurrent(),
    35.         };
    36.         return deleteJob.Schedule(this, inputDeps);
    37.     }
    38. }
    I tried many different things to fix this but I still don't understand why is the Console giving me:
    1. StartAdd0
    2. EndAdd
    3. StartAdd0
    4. EndAdd
    5. DeleteStart
    6. DeleteEnd
    7. ArgumentException: All entities passed must exist.
    FullLog
    ArgumentException: All entities passed to EntityManager must exist. One of the entities has already been destroyed or was never created.
    EntityCommandBuffer was recorded in HealthSystem and played back in HealthSystem+HealthBarrier.
    at Unity.Entities.EntityDataManager.AssertEntitiesExist (Unity.Entities.Entity* entities, System.Int32 count) [0x0005a] in C:\Users\dragon\Desktop\Codes\NoName(ECS)\Library\PackageCache\com.unity.entities@0.0.12-preview.20\Unity.Entities\EntityDataManager.cs:326
    at Unity.Entities.EntityManager.AddComponent (Unity.Entities.Entity entity, Unity.Entities.ComponentType type) [0x00008] in C:\Users\dragon\Desktop\Codes\NoName(ECS)\Library\PackageCache\com.unity.entities@0.0.12-preview.20\Unity.Entities\EntityManager.cs:386
    at Unity.Entities.EntityCommandBuffer.PlaybackChain (Unity.Entities.EntityManager mgr, Unity.Entities.ECBSharedPlaybackState& playbackState, Unity.Collections.NativeArray`1[T] chainStates, System.Int32 currentChain, System.Int32 nextChain) [0x002a3] in C:\Users\dragon\Desktop\Codes\NoName(ECS)\Library\PackageCache\com.unity.entities@0.0.12-preview.20\Unity.Entities\EntityCommandBuffer.cs:971
    at Unity.Entities.EntityCommandBuffer.Playback (Unity.Entities.EntityManager mgr) [0x00252] in C:\Users\dragon\Desktop\Codes\NoName(ECS)\Library\PackageCache\com.unity.entities@0.0.12-preview.20\Unity.Entities\EntityCommandBuffer.cs:872
    at Unity.Entities.BarrierSystem.FlushBuffers (System.Boolean playBack) [0x00045] in C:\Users\dragon\Desktop\Codes\NoName(ECS)\Library\PackageCache\com.unity.entities@0.0.12-preview.20\Unity.Entities\ComponentSystem.cs:667
    Unity.Entities.BarrierSystem.FlushBuffers (System.Boolean playBack) (at Library/PackageCache/com.unity.entities@0.0.12-preview.20/Unity.Entities/ComponentSystem.cs:688)
    Unity.Entities.BarrierSystem.OnUpdate () (at Library/PackageCache/com.unity.entities@0.0.12-preview.20/Unity.Entities/ComponentSystem.cs:641)
    Unity.Entities.ComponentSystem.InternalUpdate () (at Library/PackageCache/com.unity.entities@0.0.12-preview.20/Unity.Entities/ComponentSystem.cs:375)
    Unity.Entities.ScriptBehaviourManager.Update () (at
    Library/PackageCache/com.unity.entities@0.0.12-preview.20/Unity.Entities/ScriptBehaviourManager.cs:77)
    Unity.Entities.ScriptBehaviourUpdateOrder+DummyDelagateWrapper.TriggerUpdate () (at

    I expected to have this as a behavior:
    1. StartAdd0
    2. EndAdd
    3. DeleteStart
    4. DeleteEnd
    and no error at all. Am I doing anything wrong? And if I am, what should I do instead?
     
  2. RecursiveEclipse

    RecursiveEclipse

    Joined:
    Sep 6, 2018
    Posts:
    298
    What is the actual order of the systems in the profiler/entity debugger? Barriers are not guaranteed to execute after the system they're defined in. This could be what is happening(or a similar order):

    DeleteBarrier->HealthBarrier->HealthSystem->DeleteSystem

    First frame:
    DeleteBarrier: Nothing to playback.
    HealthBarrier: Nothing to playback.
    HealthSystem: Queues AddComponent to HealthBarrier.
    DeleteSystem: Does nothing yet.

    Second frame:
    DeleteBarrier: Nothing to playback.
    HealthBarrier: Plays back previous HealthSystem Adds.
    HealthSystem: Queues AddComponent to HealthBarrier again.
    DeleteSystem: Queues DestroyEntity to DeleteBarrier.

    Third frame:
    DeleteBarrier: Plays back previous frames deletions.
    HealthBarrier: Plays back previous HealthSystem Adds, but the entities no longer exist.

    You should be able to specify barrier order the same way as your systems, also you can just inject EndFrameBarrier instead of creating a new one and it will play back at the end of the frame.
     
  3. RecursiveEclipse

    RecursiveEclipse

    Joined:
    Sep 6, 2018
    Posts:
    298
  4. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,761
    Deleted mine, you can have it ^^
     
  5. RecursiveEclipse

    RecursiveEclipse

    Joined:
    Sep 6, 2018
    Posts:
    298
    Ah it was fine, you and I must've posted within seconds of each other, the moment I hit reply I got an alert:p, nearly identical posts it looked like too.
     
  6. Vwy29

    Vwy29

    Joined:
    Jul 11, 2018
    Posts:
    6
    Oh, I thought barriers were always execute after the System they are define in. Thanks, that helps a lot @RecursiveEclipse . I checked the profiler, the order of what you said was really right. The order was DeleteBarrier => HealthBarrier => Health => Delete.
     
    Last edited: Feb 2, 2019
  7. RecursiveEclipse

    RecursiveEclipse

    Joined:
    Sep 6, 2018
    Posts:
    298
    Neat, glad I was right on.:)

    Working off the same logic, if you swapped the DeleteBarrier and Health barrier it would still fail, but because you'd be adding two components to the same entity. Try to place creation/addition systems & barriers at the start of the frame and deletions at the end, that way you can just use EndFrameBarrier for deletions if you don't need a specific sync point(you just want them gone before the next frame starts) and entities are guaranteed to not exist next time the previous systems run. Also DestroyEntity is Burst compilable, but the other commands(and your Debugs) are not atm.
     
    Vwy29 likes this.