In the OnUpdate Method i start multiple Jobs of the same Type "PlexusVertexMovementJob". (when only 1 job is started everything works fine, but when its multiple then the errors occur)
every Jobs Query only differes by a SharedComponentFilter . so that every job has its own set of entities and no Job should end up with writing to the same Compontent Data in parrallel.
I am not sure what triggers the problem, but the error mesages point to dependency issues. but i even try to set the dependencies so that the system will wait for all jobs to finish, but not all jobs have to wait for each other.
short version, see full code more below
NativeArray<JobHandle> jobHandles = new NativeArray<JobHandle>(plexusObjectEntities.Length, Allocator.Temp);
for (int i =0; i < plexusObjectEntities.Length; i++) {
//...
jobHandles[i] = job.ScheduleParallel(plexusPointsByPlexusObjectIdEntityQuery, state.Dependency);
}
JobHandle combinedJobsDependecies = JobHandle.CombineDependencies(jobHandles);
state.Dependency = JobHandle.CombineDependencies(state.Dependency, combinedJobsDependecies);
First Error
Second Error
using Unity.Burst;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Entities;
using Unity.Jobs;
using Unity.Mathematics;
using Unity.Transforms;
using UnityEngine;
namespace WireframePlexus {
[UpdateAfter(typeof(SyncEntityToGameobjectPositionSystem))]
public partial struct VertexMoveSystem : ISystem {
EntityQuery plexusObjectEntityQuery;
EntityQuery plexusPointsByPlexusObjectIdEntityQuery;
public void OnCreate(ref SystemState state) {
state.RequireForUpdate<VertexMovementData>();
plexusObjectEntityQuery = new EntityQueryBuilder(Allocator.Temp).WithAll<PlexusObjectData, LocalTransform, LocalToWorld>().Build(ref state);
plexusPointsByPlexusObjectIdEntityQuery = new EntityQueryBuilder(Allocator.Temp).WithAll<LocalTransform, VertexMovementData, LocalToWorld, PlexusObjectIdData>().Build(ref state);
}
public void OnUpdate(ref SystemState state) {
var plexusObjectEntities = plexusObjectEntityQuery.ToEntityArray(Allocator.Temp);
NativeArray<JobHandle> jobHandles = new NativeArray<JobHandle>(plexusObjectEntities.Length, Allocator.Temp);
for (int i =0; i < plexusObjectEntities.Length; i++) {
var plexusObjectData = state.EntityManager.GetComponentData<PlexusObjectData>(plexusObjectEntities[i]);
var plexusObjectTransform = state.EntityManager.GetComponentData<LocalTransform>(plexusObjectEntities[i]);
plexusPointsByPlexusObjectIdEntityQuery.ResetFilter();
plexusPointsByPlexusObjectIdEntityQuery.SetSharedComponentFilter(new PlexusObjectIdData { ObjectId = plexusObjectData.WireframePlexusObjectId });
PlexusVertexMovementJob job = new PlexusVertexMovementJob {
DeltaTime = SystemAPI.Time.DeltaTime,
PointPositions = plexusObjectData.VertexPositions,
MaxVertexMoveDistance = plexusObjectData.MaxVertexMoveDistance,
MaxVertexMovementSpeed = plexusObjectData.MaxVertexMoveSpeed,
MinVertexMovementSpeed = plexusObjectData.MinVertexMoveSpeed,
CameraWolrdPos = (float3)Camera.main.transform.position,
ParentRotation = plexusObjectTransform.Rotation
};
jobHandles[i] = job.ScheduleParallel(plexusPointsByPlexusObjectIdEntityQuery, state.Dependency);
}
JobHandle combinedJobsDependecies = JobHandle.CombineDependencies(jobHandles);
state.Dependency = JobHandle.CombineDependencies(state.Dependency, combinedJobsDependecies);
}
[BurstCompile]
public partial struct PlexusVertexMovementJob : IJobEntity {
[ReadOnly] public quaternion ParentRotation;
[ReadOnly] public float3 CameraWolrdPos;
[ReadOnly] public float DeltaTime;
[ReadOnly] public float MinVertexMovementSpeed;
[ReadOnly] public float MaxVertexMovementSpeed;
[ReadOnly] public float MaxVertexMoveDistance;
[NativeDisableContainerSafetyRestriction] public NativeArray<float3> PointPositions;
public void Execute(ref LocalTransform localTransform, ref VertexMovementData movementData, in LocalToWorld localToWorld) {
if ((MinVertexMovementSpeed == 0 && MaxVertexMovementSpeed == 0) || MaxVertexMoveDistance == 0) {
localTransform.Position = movementData.Position;
PointPositions[movementData.PointId] = localTransform.Position;
} else {
if (movementData.CurrentMovementDuration <= 0) {
localTransform = localTransform.WithPosition(movementData.PositionTarget);
movementData.MoveSpeed = movementData.Random.NextFloat(MinVertexMovementSpeed, MaxVertexMovementSpeed);
movementData.PositionOrigin = movementData.PositionTarget;
movementData.PositionTarget = movementData.Position + movementData.Random.NextFloat3(-MaxVertexMoveDistance, MaxVertexMoveDistance);
movementData.CurrentMovementDuration = math.distance(movementData.PositionTarget, movementData.PositionOrigin) / movementData.MoveSpeed;
movementData.TotalMovementDuration = movementData.CurrentMovementDuration;
} else {
movementData.CurrentMovementDuration -= DeltaTime;
float interpolationPercent = 1 - (movementData.CurrentMovementDuration / movementData.TotalMovementDuration);
float3 newPosition = math.lerp(movementData.PositionOrigin, movementData.PositionTarget, interpolationPercent);
localTransform = localTransform.WithPosition(newPosition);
}
PointPositions[movementData.PointId] = localTransform.Position;
}
// make vertex face camera
float3 relativePos = CameraWolrdPos - localToWorld.Position;
// quaternion.LookRotationSafe cannot handle vectors that are collinear so for the case of the edge faceing directly up or down hardcoded a 90 degree rotation
if (relativePos.y == 1 || relativePos.y == -1) {
localTransform.Rotation = math.mul(quaternion.RotateX(math.PIHALF) , math.inverse(ParentRotation));
} else {
quaternion end = quaternion.LookRotationSafe(-relativePos, math.up());
localTransform.Rotation = math.mul(end.value, math.inverse(ParentRotation));
}
}
}
}
}