Help with Translating SystemAPI.Query into IJobEntity

Hi everyone,

I have a system and I’m trying to convert it into a parallel job. I’m struggling for days now as I don’t manage to translate the query correctly.

This is the foreach query that works well:

foreach ((
    RefRW<LocalTransform> localTransform,
    RefRW<ShootAttack> shootAttack,
    RefRO<Target> target,
    RefRW<TargetPositionPathQueued> targetPositionPathQueued,
    EnabledRefRW<TargetPositionPathQueued> targetPositionPathQueuedEnabled,
    RefRW<UnitMover> unitMover,
    Entity entity)
    in SystemAPI.Query<
        RefRW<LocalTransform>,
        RefRW<ShootAttack>,
        RefRO<Target>,
        RefRW<TargetPositionPathQueued>,
        EnabledRefRW<TargetPositionPathQueued>,
        RefRW<UnitMover>>().WithDisabled<MoveOverride>().WithPresent<TargetPositionPathQueued>().WithEntityAccess())

and I’m trying to convert it in the job:

[BurstCompile]
//[WithDisabled(typeof(MoveOverride))]
public partial struct PositioningAttackJob : IJobEntity
{
    public float deltaTime; // Store DeltaTime inside the job

    [NativeDisableParallelForRestriction] public ComponentLookup<LocalTransform> localTransformComponentLookup;
    //[ReadOnly] public NativeArray<MoveOverride> moveOverrideArray;



    public void Execute(
        RefRW<ShootAttack> shootAttack,
        RefRO<Target> target,
        RefRW<TargetPositionPathQueued> targetPositionPathQueued,
        EnabledRefRW<TargetPositionPathQueued> targetPositionPathQueuedEnabled,
        RefRW<UnitMover> unitMover,
        EnabledRefRO<MoveOverride> moveOverrideEnabled, // Checks if MoveOverride is enabled
        Entity entity)

{
    // Only execute logic if MoveOverride is DISABLED
    if (moveOverrideEnabled.ValueRO)
    {
        return;
    }
    Debug.Log("Entity: "+entity);
    if (target.ValueRO.targetEntity == Entity.Null)
    {
        return;
    }
}

I’m pretty sure the problem is because I fail to translate the WithDisabled into the job as I can see with debug that the job does not run continuously for my entities. While if I debug in the foreach query I can see it running continuously.

I really need help here as I’m stuck after trying all sorts of options.

Thank you

I could do it in IJobChunk:

public partial struct PositioningAttackSystem : ISystem
{
    private EntityQuery query;
    
    private EntityTypeHandle entityType;
    private ComponentTypeHandle<Target> targetType;
    private ComponentTypeHandle<TargetPositionPathQueued> pathQueuedType;
    private ComponentTypeHandle<UnitMover> unitMoverType;
    private ComponentTypeHandle<MoveOverride> moveOverrideType;
    
    [BurstCompile]
    public void OnCreate(ref SystemState state)
    {
        this.query = new EntityQueryBuilder(Allocator.Temp)
            .WithAll<LocalTransform>()
            .WithAll<ShootAttack>()
            .WithAll<Target>()
            .WithAll<TargetPositionPathQueued>()
            .WithAll<UnitMover>()
            .WithDisabled<MoveOverride>()
            .Build(ref state);

        this.entityType = state.GetEntityTypeHandle();
        this.targetType = state.GetComponentTypeHandle<Target>();
        this.pathQueuedType = state.GetComponentTypeHandle<TargetPositionPathQueued>();
        this.unitMoverType = state.GetComponentTypeHandle<UnitMover>();
        this.moveOverrideType = state.GetComponentTypeHandle<MoveOverride>();
    }

    [BurstCompile]
    public void OnUpdate(ref SystemState state)
    {
        // Update handles
        this.entityType.Update(ref state);
        this.targetType.Update(ref state);
        this.pathQueuedType.Update(ref state);
        this.unitMoverType.Update(ref state);
        this.moveOverrideType.Update(ref state);
        
        PositioningAttackJob positioningAttackJob = new()
        {
            entityType = this.entityType,
            targetType = this.targetType,
            pathQueuedType = this.pathQueuedType,
            unitMoverType = this.unitMoverType,
            moveOverrideType = this.moveOverrideType,
        };
        state.Dependency = positioningAttackJob.ScheduleParallel(this.query, state.Dependency);
    }
    
    [BurstCompile]
    private struct PositioningAttackJob : IJobChunk
    {
        public EntityTypeHandle entityType;
        
        [ReadOnly]
        public ComponentTypeHandle<Target> targetType;
        
        public ComponentTypeHandle<TargetPositionPathQueued> pathQueuedType;
        public ComponentTypeHandle<UnitMover> unitMoverType;
        public ComponentTypeHandle<MoveOverride> moveOverrideType;
        
        public void Execute(in ArchetypeChunk chunk, int unfilteredChunkIndex, bool useEnabledMask, in v128 chunkEnabledMask)
        {
            NativeArray<Entity> entities = chunk.GetNativeArray(entityType);
            NativeArray<Target> targets = chunk.GetNativeArray(ref targetType);
            NativeArray<TargetPositionPathQueued> pathQueueds = chunk.GetNativeArray(ref pathQueuedType);
            NativeArray<UnitMover> unitMovers = chunk.GetNativeArray(ref unitMoverType);
            NativeArray<MoveOverride> moveOverrides = chunk.GetNativeArray(ref moveOverrideType);

            ChunkEntityEnumerator enumerator = new(useEnabledMask, chunkEnabledMask, chunk.Count);
            while (enumerator.NextEntityIndex(out int i))
            {
                // You don't have to check for disabled since it was already done in the query
                // All entities here have disabled MoveOverride
                
                // To access target or any of the components that you need
                Target target = targets[i];
            }
        }
    }
}

Thank you Daven.
It’s not clear to me how can I afterwards reference for example the LocalTransform of target.entity with this structure.

Hope this can help.

public partial struct SampleSystem : ISystem
{
    private EntityQuery _query;

    [BurstCompile]
    public void OnCreate(ref SystemState state)
    {
        _query = SystemAPI.QueryBuilder()
            .WithAllRW<LocalTransform>()
            .WithAllRW<ShootAttack>()
            .WithAllRW<UnitMover>()
            .WithPresentRW<TargetPositionPathQueued>()
            .WithAll<Target>()
            .WithDisabled<MoveOverride>()
            .Build();
    }

    [BurstCompile]
    public void OnUpdate(ref SystemState state)
    {
        state.Dependency = new SampleJob().ScheduleParallel(_query, state.Dependency);
    }

    private partial struct SampleJob : IJobEntity
    {
        private void Execute(
            in Entity entity,
            ref LocalTransform transform,
            ref ShootAttack shootAttack,
            ref UnitMover unitMover,
            ref TargetPositionPathQueued targetPositionPathQueued,
            EnabledRefRW<TargetPositionPathQueued> targetPositionPathQueuedEnabled,
            in Target target
        )
        {
        }
    }
}

Tested with some entities produced by this authoring:

internal sealed class SampleAuthoring : MonoBehaviour
{
    private class Baker : Baker<SampleAuthoring>
    {
        public override void Bake(SampleAuthoring authoring)
        {
            var entity = GetEntity(TransformUsageFlags.Dynamic);
            AddComponent<ShootAttack>(entity);
            AddComponent<Target>(entity);
            AddComponent<TargetPositionPathQueued>(entity);
            AddComponent<UnitMover>(entity);
            AddComponent<MoveOverride>(entity);
            SetComponentEnabled<MoveOverride>(entity, false);
        }
    }
}

I used Unity 6000.0.35, Entities 1.3.9.

You need a ComponentLookup to the job. It’s like a dictionary of your entities to LocalTransform. You can use target.entity as the key to that.

Thank you Lais. It worked like that. So I need to use a query first and then add it to the job via state.dependency. My god how much time I wasted trying to figure the proper way.

Thank you and thank you @davenirline as well!