Search Unity

  1. How has 2019.2 and the beta been for you so far? Give us feedback in this thread.
    Dismiss Notice

ScheduleBatchedJobsAndComplete can only be called from the main thread.

Discussion in 'Data Oriented Technology Stack' started by hakankaraduman, Jun 25, 2019.

  1. hakankaraduman

    hakankaraduman

    Joined:
    Aug 27, 2012
    Posts:
    336
    Hi,

    I'm trying to get up to speed on pure ECS.

    I get the error below with the codes I have, I have pasted all of them here. The error doesn't direct me to any of my custom scripts and I couldn't find a google search for this error. Thanks in advance.

    Below is Error

    Code (CSharp):
    1. UnityException: ScheduleBatchedJobsAndComplete can only be called from the main thread.
    2. Constructors and field initializers will be executed from the loading thread when loading a scene.
    3. Don't use this function in the constructor or field initializers, instead move initialization code to the Awake or Start function.
    4. Unity.Jobs.JobHandle.Complete () (at C:/buildslave/unity/build/Runtime/Jobs/ScriptBindings/JobHandle.bindings.cs:20)
    5. Unity.Entities.ComponentJobSafetyManager.CompleteWriteDependencyNoChecks (System.Int32 type) (at Library/PackageCache/com.unity.entities@0.0.12-preview.33/Unity.Entities/ComponentJobManager.cs:352)
    6. Unity.Entities.ComponentJobSafetyManager.CompleteWriteDependency (System.Int32 type) (at Library/PackageCache/com.unity.entities@0.0.12-preview.33/Unity.Entities/ComponentJobManager.cs:377)
    7. Unity.Entities.EntityManager.GetComponentData[T] (Unity.Entities.Entity entity) (at Library/PackageCache/com.unity.entities@0.0.12-preview.33/Unity.Entities/EntityManagerAccessComponentData.cs:41)
    8. MoveToTargetJob.Execute (Unity.Entities.Entity unitEntity, System.Int32 index, Unity.Transforms.Translation& unitTranslation, HasTarget& hasTarget) (at Assets/_4/Jobs/MoveToTargetJob.cs:24)
    9. Unity.Entities.JobForEachExtensions+JobStruct_Process_ECC`3[T,T0,T1].ExecuteChunk (Unity.Entities.JobForEachExtensions+JobStruct_Process_ECC`3[T,T0,T1]& jobData, System.IntPtr bufferRangePatchData, System.Int32 begin, System.Int32 end, Unity.Entities.ArchetypeChunk* chunks, System.Int32* entityIndices) (at Library/PackageCache/com.unity.entities@0.0.12-preview.33/Unity.Entities/IJobForEach.gen.cs:2089)
    10. Unity.Entities.JobForEachExtensions+JobStruct_Process_ECC`3[T,T0,T1].Execute (Unity.Entities.JobForEachExtensions+JobStruct_Process_ECC`3[T,T0,T1]& jobData, System.IntPtr additionalPtr, System.IntPtr bufferRangePatchData, Unity.Jobs.LowLevel.Unsafe.JobRanges& ranges, System.Int32 jobIndex) (at Library/PackageCache/com.unity.entities@0.0.12-preview.33/Unity.Entities/IJobForEach.gen.cs:2059)
    11.  
    Add Target To Unit Job code

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using Unity.Entities;
    5. using Unity.Jobs;
    6. using Unity.Transforms;
    7. using Unity.Collections;
    8.  
    9. [RequireComponentTag(typeof(UnitTag))]
    10. [ExcludeComponent(typeof(HasTarget))]
    11. public struct AddTargetToUnitJob : IJobForEachWithEntity<Translation>
    12. {
    13.   [DeallocateOnJobCompletion]
    14.   [ReadOnly]
    15.   public NativeArray<Entity> closestTargetEntities;
    16.  
    17.   public EntityCommandBuffer.Concurrent entityCommandBuffer;
    18.  
    19.   public void Execute(Entity entity, int index, ref Translation c0)
    20.   {
    21.     if (closestTargetEntities[index] != Entity.Null) {
    22.       entityCommandBuffer.AddComponent(index, entity, new HasTarget { Value = closestTargetEntities[index] });
    23.     }
    24.   }
    25. }
    26.  
    Find Closest Target Job code

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using Unity.Jobs;
    5. using Unity.Entities;
    6. using Unity.Transforms;
    7. using Unity.Collections;
    8. using Unity.Mathematics;
    9. using Unity.Burst;
    10.  
    11. [RequireComponentTag(typeof(UnitTag))]
    12. [ExcludeComponent(typeof(HasTarget))]
    13. [BurstCompile]
    14. public struct FindClosestTargetJob : IJobForEachWithEntity<Translation>
    15. {
    16.   [DeallocateOnJobCompletion]
    17.   [ReadOnly]
    18.   public NativeArray<Entity> targetEntities;
    19.  
    20.   [DeallocateOnJobCompletion]
    21.   [ReadOnly]
    22.   public NativeArray<Translation> targetEntityPositions;
    23.  
    24.   public NativeArray<Entity> closestTargetEntities;
    25.  
    26.   public void Execute(Entity entity, int index, [ReadOnly] ref Translation translation)
    27.   {
    28.     var unitPosition = translation.Value;
    29.     Entity closestTarget = Entity.Null;
    30.     float closestDistance = Mathf.Infinity;
    31.     for (var i = 0; i < targetEntities.Length; i++) {
    32.       var distanceBetweenUnitAndTarget = math.distance(targetEntityPositions[i].Value, unitPosition);
    33.       if (distanceBetweenUnitAndTarget < closestDistance) {
    34.         closestDistance = distanceBetweenUnitAndTarget;
    35.         closestTarget = targetEntities[i];
    36.       }
    37.     }
    38.     if (closestTarget != Entity.Null) {
    39.       closestTargetEntities[index] = closestTarget;
    40.     }
    41.   }
    42. }
    43.  
    Move to Target Job code

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using Unity.Entities;
    5. using Unity.Jobs;
    6. using Unity.Transforms;
    7. using Unity.Collections;
    8. using Unity.Mathematics;
    9.  
    10. [RequireComponentTag(typeof(UnitTag))]
    11. public struct MoveToTargetJob : IJobForEachWithEntity<Translation, HasTarget>
    12. {
    13.   public EntityCommandBuffer.Concurrent buffer;
    14.   public float deltaTime;
    15.  
    16.   public void Execute(Entity unitEntity, int index, ref Translation unitTranslation, ref HasTarget hasTarget)
    17.   {
    18.     // if target does not exists, remove has target component from this entity
    19.     if (World.Active.EntityManager.Exists(hasTarget.Value) == false) {
    20.       buffer.RemoveComponent(index, unitEntity, typeof(HasTarget));
    21.     } else {
    22.       // add direction * speed * deltaTime to unit translation
    23.       var targetPosition = World.Active.EntityManager.GetComponentData<Translation>(hasTarget.Value);
    24.       var direction = targetPosition.Value - unitTranslation.Value;
    25.       unitTranslation.Value += direction * 5f * deltaTime;
    26.       // if distance is below 0.2f, destroy entity, remove hastarget
    27.       var distance = math.distance(unitTranslation.Value, targetPosition.Value);
    28.       if (distance < 0.2f) {
    29.         buffer.RemoveComponent(index, unitEntity, typeof(HasTarget));
    30.         buffer.DestroyEntity(index, hasTarget.Value);
    31.       }
    32.     }
    33.   }
    34. }
    Move To Target System Code

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using Unity.Entities;
    5. using Unity.Transforms;
    6. using Unity.Mathematics;
    7. using Unity.Jobs;
    8.  
    9. public class MoveToTargetSystem : JobComponentSystem
    10. {
    11.   EntityCommandBufferSystem entityCommandBufferSystem;
    12.   protected override void OnCreate(){
    13.     entityCommandBufferSystem = World.Active.GetOrCreateSystem<EndSimulationEntityCommandBufferSystem>();
    14.     base.OnCreate();
    15.   }
    16.   protected override JobHandle OnUpdate(JobHandle inputDeps)
    17.   {
    18.     var moveToTargetJob = new MoveToTargetJob {
    19.       buffer = entityCommandBufferSystem.CreateCommandBuffer().ToConcurrent(),
    20.       deltaTime = Time.deltaTime
    21.     };
    22.     var jobHandle = moveToTargetJob.Schedule(this, inputDeps);
    23.     entityCommandBufferSystem.AddJobHandleForProducer(jobHandle);
    24.     return jobHandle;
    25.   }
    26. }
    Select Target System code

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using Unity.Entities;
    5. using Unity.Transforms;
    6. using Unity.Mathematics;
    7. using Unity.Jobs;
    8. using Unity.Collections;
    9.  
    10. public class SelectTargetSystem : JobComponentSystem
    11. {
    12.   EntityCommandBufferSystem entityCommandBufferSystem;
    13.   protected override void OnCreate(){
    14.     entityCommandBufferSystem = World.Active.GetOrCreateSystem<EndSimulationEntityCommandBufferSystem>();
    15.     base.OnCreate();
    16.   }
    17.  
    18.   protected override JobHandle OnUpdate(JobHandle inputDeps)
    19.   {
    20.     var targetEntitiesQuery = GetEntityQuery(typeof(TargetTag), typeof(Translation));
    21.     NativeArray<Entity> targetEntities = targetEntitiesQuery.ToEntityArray(Allocator.TempJob);
    22.     NativeArray<Translation> targetEntityPositions = targetEntitiesQuery.ToComponentDataArray<Translation>(Allocator.TempJob);
    23.     NativeArray<Entity> closestTargetEntities = new NativeArray<Entity>(targetEntities.Length, Allocator.TempJob);
    24.     FindClosestTargetJob findClosestTargetJob = new FindClosestTargetJob {
    25.       targetEntities = targetEntities,
    26.       targetEntityPositions = targetEntityPositions,
    27.       closestTargetEntities = closestTargetEntities
    28.     };
    29.     var jobHandle = findClosestTargetJob.Schedule(this, inputDeps);
    30.     AddTargetToUnitJob addTargetToUnitJob = new AddTargetToUnitJob {
    31.       entityCommandBuffer = entityCommandBufferSystem.CreateCommandBuffer().ToConcurrent(),
    32.       closestTargetEntities = closestTargetEntities
    33.     };
    34.     jobHandle = addTargetToUnitJob.Schedule(this, jobHandle);
    35.     entityCommandBufferSystem.AddJobHandleForProducer(jobHandle);
    36.     return jobHandle;
    37.   }
    38. }
    39.  
    Scene Manager code to spawn units and targets

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. using Unity.Collections;
    5. using Unity.Entities;
    6. using Unity.Transforms;
    7. using Unity.Mathematics;
    8. using Unity.Rendering;
    9. public class SceneManager4 : MonoBehaviour
    10. {
    11.   public Mesh unitMesh;
    12.   public Material unitMaterial;
    13.   public Mesh targetMesh;
    14.   public Material targetMaterial;
    15.   EntityManager em;
    16.  
    17.   public int unitAmount = 10;
    18.   public int targetAmount = 10;
    19.   public float spawnRate = 2.0f;
    20.   float spawnTimer = 0.0f;
    21.  
    22.   void Awake () {
    23.     em = World.Active.EntityManager;
    24.   }
    25.   void Start()
    26.   {
    27.     SpawnUnits();
    28.     SpawnTargets();
    29.   }
    30.  
    31.   void Update(){
    32.     // spawnTimer += Time.deltaTime;
    33.     // if (spawnTimer >= spawnRate) {
    34.     //   SpawnTargets();
    35.     //   spawnTimer = 0.0f;
    36.     // }
    37.   }
    38.  
    39.   void SpawnUnits(){
    40.     var unitEntities = new NativeArray<Entity>(unitAmount, Allocator.Temp);
    41.     var unitArchetype = em.CreateArchetype(
    42.       typeof(RenderMesh),
    43.       typeof(LocalToWorld),
    44.       typeof(Translation),
    45.       typeof(UnitTag)
    46.     );
    47.     em.CreateEntity(unitArchetype, unitEntities);
    48.     foreach (var unit in unitEntities) {
    49.       em.SetComponentData(unit, new Translation { Value = new float3 { x = UnityEngine.Random.Range(-20, 20), y = UnityEngine.Random.Range(-20, 20), z = 0 } });
    50.       em.SetSharedComponentData(unit, new RenderMesh { mesh = unitMesh, material = unitMaterial });
    51.     }
    52.     unitEntities.Dispose();
    53.   }
    54.   void SpawnTargets(){
    55.     var targetEntities = new NativeArray<Entity>(targetAmount, Allocator.Temp);
    56.     var targetArchetype = em.CreateArchetype(
    57.       typeof(RenderMesh),
    58.       typeof(LocalToWorld),
    59.       typeof(Translation),
    60.       typeof(TargetTag)
    61.     );
    62.     em.CreateEntity(targetArchetype, targetEntities);
    63.     foreach (var target in targetEntities) {
    64.       em.SetComponentData(target, new Translation { Value = new float3 { x = UnityEngine.Random.Range(-20, 20), y = UnityEngine.Random.Range(-20, 20), z = 0 } });
    65.       em.SetSharedComponentData(target, new RenderMesh { mesh = targetMesh, material = targetMaterial });
    66.     }
    67.     targetEntities.Dispose();
    68.   }
    69. }
    70.  
    Note: project was working until I implement the move to target system
     
  2. Razmot

    Razmot

    Joined:
    Apr 27, 2013
    Posts:
    255
    do not use "World.Active.EntityManager.Exists" in a job, instead pass a ComponentDataFromEntity<HasTarget > and use its exists() method
     
    hakankaraduman likes this.
  3. hakankaraduman

    hakankaraduman

    Joined:
    Aug 27, 2012
    Posts:
    336
    Thanks for your reply. I couldn't find how to use this, all examples are using [Inject] attribute and could not find an updated implementation for this. Can you help if you have time for this?
     
  4. Razmot

    Razmot

    Joined:
    Apr 27, 2013
    Posts:
    255
    Here you are :

    Code (CSharp):
    1.  
    2.   protected override JobHandle OnUpdate(JobHandle inputDeps)
    3.         {
    4.      var endJob = new EndJob()
    5.             {
    6.                 stitchedT = GetComponentDataFromEntity<StitchT_Done>(true),
    7.                 stitchedB = GetComponentDataFromEntity<StitchB_Done>(true),
    8.                 CommandBuffer = ecb,//finishBarrier.CreateCommandBuffer().ToConcurrent()
    9.             };
    Code (CSharp):
    1.        private struct EndJob : IJobForEachWithEntity<VoxelChunk>
    2.         {
    3.             [ReadOnly] public ComponentDataFromEntity<StitchT_Done> stitchedT;
    4.             [ReadOnly] public ComponentDataFromEntity<StitchB_Done> stitchedB;
    5.  
    6.             [WriteOnly] public EntityCommandBuffer.Concurrent CommandBuffer;
    7.  
    8.             public void Execute(Entity e, int i, [ReadOnly] ref VoxelChunk chunk)
    9.             {
    10.                 bool done = true;
    11.  
    12.                 if (chunk.HasUp) done &= stitchedT.Exists(e);
    13.                 if (chunk.HasDown) done &= stitchedB.Exists(e);
    ...
     
    hakankaraduman likes this.
  5. hakankaraduman

    hakankaraduman

    Joined:
    Aug 27, 2012
    Posts:
    336
    Thanks for the help. I see, this check if the StitchT_Done component exists on the entity e, is that right?

    In my situation, I have a reference to an entity in the HasTarget component. I need to check if that referenced entity exists or not, so if it is destroyed or not.
     
  6. Razmot

    Razmot

    Joined:
    Apr 27, 2013
    Posts:
    255
    You can do exists on any entity, it does not have to be the argument of execute ( 'e' in my case)
     
    hakankaraduman likes this.