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. Dismiss Notice

Question You must call JobHandle.Complete() before you can write to the EntityCommandBuffer

Discussion in 'Entity Component System' started by Cell-i-Zenit, Dec 19, 2020.

  1. Cell-i-Zenit

    Cell-i-Zenit

    Joined:
    Mar 11, 2016
    Posts:
    288
    Hi

    i get this error lots of times and iam not sure why this happens:

    Code (CSharp):
    1. ArgumentException: The previously scheduled job ResetMapSystem:Update_LambdaJob0 writes to the Unity.Entities.EntityCommandBuffer Update_LambdaJob0.JobData.commandBuffer. You must call JobHandle.Complete() on the job ResetMapSystem:Update_LambdaJob0, before you can write to the Unity.Entities.EntityCommandBuffer safely.
    Does this error happen because i have lots of systems which write to the same commandbuffer and DONT have a dependency on each other?

    This is my code:

    Code (CSharp):
    1.  
    2. protected sealed override void OnUpdate()
    3. {
    4.   var commandBuffer = _commandBufferSystem.CreateCommandBuffer();
    5.   Update(commandBuffer);
    6.   _commandBufferSystem.AddJobHandleForProducer(Dependency);
    7. }
    8.  
    Code (CSharp):
    1.  protected override void Update(EntityCommandBuffer commandBuffer)
    2.     {
    3.       Dependency = Entities.ForEach((Entity entity, ref Scale scale) =>
    4.         {
    5.           scale.Value = 1;
    6.           commandBuffer.RemoveComponent<Visited>(entity);
    7.         })
    8.         .WithAll<Visited>()
    9.         .Schedule(Dependency);
    10.  
    11.       commandBuffer.DestroyEntity(GetSingletonEntity<ResetMessage>());
    12.     }
    Thanks :)
     
  2. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    3,984
    You are scheduling a job that uses the ECB and then right after also writing to the ECB on the main thread. That is what it is complaining about.
     
    Cell-i-Zenit likes this.
  3. Cell-i-Zenit

    Cell-i-Zenit

    Joined:
    Mar 11, 2016
    Posts:
    288
    aah this makes totally sense.

    so the solution is to use the EntityManager to destroy the entity?

    EDIT: no this doesnt work and results in the same error, but additionally in this:

    Code (CSharp):
    1. InvalidOperationException: The previously scheduled job ResetMapSystem:Update_LambdaJob0 reads from the Unity.Entities.EntityTypeHandle Update_LambdaJob0.JobData._lambdaParameterValueProviders.forParameter_entity._typeHandle. You must call JobHandle.Complete() on the job ResetMapSystem:Update_LambdaJob0, before you can deallocate the Unity.Entities.EntityTypeHandle safely.
     
    Last edited: Dec 19, 2020
  4. Lieene-Guo

    Lieene-Guo

    Joined:
    Aug 20, 2013
    Posts:
    547
    You can create a second command buffer to destroy the entity.
    or you can destroy entity first like this:
    Code (CSharp):
    1.  protected override void Update(EntityCommandBuffer commandBuffer)
    2.     {
    3.       commandBuffer.DestroyEntity(GetSingletonEntity<ResetMessage>());
    4.       Dependency = Entities.ForEach((Entity entity, ref Scale scale) =>
    5.         {
    6.           scale.Value = 1;
    7.           commandBuffer.RemoveComponent<Visited>(entity);
    8.         })
    9.         .WithAll<Visited>()
    10.         .Schedule(Dependency);  
    11.     }
    when command is deferred, in most of the cases including your case, the order of the commands does not matter. Because your data processing job is done.
     
    Last edited: Dec 19, 2020
    charleshendry likes this.
  5. Cell-i-Zenit

    Cell-i-Zenit

    Joined:
    Mar 11, 2016
    Posts:
    288
    ah this works as expected thanks for the help :)

    but why cant i just use the entitymanager here? i think iam missing a concept here
     
  6. Lieene-Guo

    Lieene-Guo

    Joined:
    Aug 20, 2013
    Posts:
    547
    EntityManager's DestroyEntity will create a syncpoint right away. Invalidating all queries (including the one you use for the job). Command buffer defer the syncpoint to playback time.
    It should still work if you use EntityManager.DestroyEntity first, before job schduale. But that's an undesierd syncpoint/structrual change. using command buffer is just better.
     
    Cell-i-Zenit likes this.
  7. xXvladosXX

    xXvladosXX

    Joined:
    May 28, 2020
    Posts:
    1
    I have the same problem, but the script is a little different. What I am doing wrong?

    Code (CSharp):
    1. public partial class DeathCleanupSystem : SystemBase
    2.     {
    3.         private EndSimulationEntityCommandBufferSystem _ecbSystem;
    4.  
    5.         protected override void OnCreate()
    6.         {
    7.             _ecbSystem = World.GetOrCreateSystem<EndSimulationEntityCommandBufferSystem>();
    8.         }
    9.  
    10.         protected override void OnUpdate()
    11.         {
    12.             Dependency.Complete();
    13.  
    14.             EntityCommandBuffer ecb = _ecbSystem.CreateCommandBuffer();
    15.             Entities.WithBurst().WithAll<DeadData>().ForEach((Entity e) =>
    16.             {
    17.                 ecb.DestroyEntity(e);
    18.             }).Schedule(Dependency);
    19.            
    20.             _ecbSystem.AddJobHandleForProducer(Dependency);
    21.         }
    22.        
    23.     }
     
  8. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,627
    You're passing dependency to your job but not writing it back. Remove dependency from your schedule or write back to it from your job.

    You don't need that complete.