#Why is my Job flagged as writing to a ComponentTypeHandle that it is not? [Solved]

1 messages · Page 1 of 1 (latest)

gleaming quarry
#

I have two Systems. SystemA and SystemB - I set SystemB to run after SystemA with the UpdateAfter attribute on the SystemB System.
In SystemA i have created an EntityQuery that only uses .WithAll( - so no RW access.

In my systemA i schedule a job with my query - that job looks like this:

public partial struct MyJob: IJobEntity {
  public void Execute([ReadOnly] ref MyProperties properties) {
    UnityEngine.Debug.Log("Run");
  }
}

I get this error:
You are trying to schedule a new job MyNewJob, which writes to the same ComponentTypeHandle<MyProperties>. To guarantee safety, you must include MyJob as a dependency of the newly scheduled job.

Clearly my Job will have to write to something at some point, so i might run into problems and need to include a dependency - but for now, i can't understand why I'm getting this error?
Btw i'm planning on (later) to write the data into a DynamicBuffer and the next System will then aggregate the data in the buffer, clear it and set the aggregated value on the component.

#

Btw - the "Run" is printed in the console - hinting that the code in SystemA is run

#

Also some info - my SystemA is using Schedule or ScheduleParallel - while my SystemB is just using Run - so i might see why the first system might need to send a signal back when it's done - but i thought that would be automatic when using UpdateAfter ?

acoustic matrix
#

public void Execute(in MyProperties properties)

#

[ReadOnly] is for when you send in a read only collection manually, e.g

#
public partial struct MyJob: IJobEntity 
{
    [ReadOnly]
    public NativeArray<Entity> EntityArray

    public void Execute() { }
}
gleaming quarry
#

Ok good point - i changed the code to use in instead of ref but the error is the same

acoustic matrix
#

need to see how you set up the jobs to see if your dependency stuff is correct

gleaming quarry
#

Ok let me clean it up a bit 🙂

#
using Unity.Burst;
using Unity.Collections;
using Unity.Entities;
using Unity.Transforms;

[BurstCompile]
[UpdateInGroup(typeof(SimulationSystemGroup))]
public partial struct ApplyRulesSystem : ISystem, ISystemStartStop
{
    private EntityQuery _jobQuery;
    private NativeList<SharedRulesGrouping> _uniqueCellTypes;

    [BurstCompile]
    public void OnCreate(ref SystemState state)
    {
        state.RequireForUpdate<WorldProperties>();
        state.RequireForUpdate<SharedRulesGrouping>();
        using var queryBuilder = new EntityQueryBuilder(Allocator.Temp)
                        .WithAll<CellProperties>()
                        .WithAll<SharedRulesGrouping>()
                        .WithAll<LocalToWorld>();
        _jobQuery = state.GetEntityQuery(queryBuilder);
    }

    [BurstCompile]
    public void OnDestroy(ref SystemState state)
    {
    }

    public void OnStartRunning(ref SystemState state)
    {
        state.EntityManager.GetAllUniqueSharedComponents(out NativeList<SharedRulesGrouping> uniqueCellRuleTypes, Allocator.Persistent);
        this._uniqueCellTypes = uniqueCellRuleTypes;
    }

    public void OnStopRunning(ref SystemState state)
    {
    }

    [BurstCompile]
    public void OnUpdate(ref SystemState state)
    {
        foreach (var cellType in _uniqueCellTypes)
        {
            _jobQuery.AddSharedComponentFilter(cellType);

            var cellCount = _jobQuery.CalculateEntityCount();
            if (cellCount == 0)
            {
                _jobQuery.ResetFilter();
                continue;
            }

            var job = new ApplyRuleJob { };
            job.ScheduleParallel(_jobQuery);
            //job.Run();

            _jobQuery.ResetFilter();
        }
    }
}

public partial struct ApplyRuleJob : IJobEntity
{
    public void Execute([ReadOnly] in CellProperties aspect)
    {
        UnityEngine.Debug.Log("Run");
    }
}
#

that system/job seem to run fine by itself - but the second job will only work if i use .Run() instead of .Schedule...

#
InvalidOperationException: The previously scheduled job ApplyRuleJob reads from the ComponentTypeHandle<CellProperties> ApplyRuleJob.JobData.__CellPropertiesComponentTypeHandle. You are trying to schedule a new job MoveCellJob, which writes to the same ComponentTypeHandle<CellProperties> (via MoveCellJob.JobData.__CellPropertiesAspectTypeHandle.cellPropertiesCth). To guarantee safety, you must include ApplyRuleJob as a dependency of the newly scheduled job.
Unity.Jobs.LowLevel.Unsafe.JobsUtility.Schedule (Unity.Jobs.LowLevel.Unsafe.JobsUtility+JobScheduleParameters& parameters) (at <bdd20210bb844b2e88e1149ea99da5ef>:0)
Unity.Entities.JobChunkExtensions.ScheduleInternal[T] (T& jobData, Unity.Entities.EntityQuery query, Unity.Jobs.JobHandle dependsOn, Unity.Jobs.LowLevel.Unsafe.ScheduleMode mode, Unity.Collections.NativeArray`1[T] chunkBaseEntityIndices) (at Library/PackageCache/com.unity.entities@1.0.0-pre.15/Unity.Entities/IJobChunk.cs:320)
Unity.Entities.JobChunkExtensions.Run[T] (T jobData, Unity.Entities.EntityQuery query) (at Library/PackageCache/com.unity.entities@1.0.0-pre.15/Unity.Entities/IJobChunk.cs:216)
MoveCellsSystem.__ScheduleViaJobChunkExtension_0 (MoveCellJob job, Unity.Entities.EntityQuery entityQuery, Unity.Jobs.JobHandle dependency, Unity.Entities.SystemState& state) (at Assets/Scripts/Systems/MoveCellsSystem.cs:38)
MoveCellsSystem.OnUpdate (Unity.Entities.SystemState& state) (at Assets/Scripts/Systems/MoveCellsSystem.cs:28)
#

Oh wait the error is the other way around?

acoustic matrix
#
    [BurstCompile]
    public void OnUpdate(ref SystemState state)
    {
        var handle = state.Dependency;

        foreach (var cellType in _uniqueCellTypes)
        {
            _jobQuery.AddSharedComponentFilter(cellType);

            var cellCount = _jobQuery.CalculateEntityCount();
            if (cellCount == 0)
            {
                _jobQuery.ResetFilter();
                continue;
            }

            var job = new ApplyRuleJob { };
            handle = job.ScheduleParallel(_jobQuery, handle);

            _jobQuery.ResetFilter();
        }

        state.Dependency = handle;
    }

Try that

gleaming quarry
#

on the next frame/update - i need the next job done before i can start this?

#

oh i need that state.Dependency?

#

ok thanks will try

acoustic matrix
#

yeah you use the state.Dependency as the initial handle for the job and then set it back at the end (at least thats what i do)

#

Also remember to put [BurstCompile] above your job structs (doesnt also need to be on the Execute)

#

and remove the [ReadOnly]

gleaming quarry
#

I get the same error - but now i get a new one just before the original error:

UnityEngine.Debug:LogError (object)```
acoustic matrix
#

paste your updated OnUpdate

gleaming quarry
#
    [BurstCompile]
    public void OnUpdate(ref SystemState state)
    {
        var handle = state.Dependency;
        // TODO: REMOVE disable system
        state.Enabled = false;


        //float deltaTime = math.min(0.05f, SystemAPI.Time.DeltaTime);
        //var allCells = _jobQuery.ToComponentDataArray<CellProperties>(Allocator.TempJob);

        foreach (var cellType in _uniqueCellTypes)
        {
            UnityEngine.Debug.Log("uniqueCellType " + cellType.Group);
            _jobQuery.AddSharedComponentFilter(cellType);

            var cellCount = _jobQuery.CalculateEntityCount();
            if (cellCount == 0)
            {
                _jobQuery.ResetFilter();
                continue;
            }

            //var map = new NativeHashMap<int, float>(cellType.Rules.Length, Allocator.TempJob);
            //foreach (var rule in cellType.Rules)
            //{
            //    map.Add(rule.Id, rule.Amount);
            //}

            var job = new ApplyRuleJob
            {
                //DeltaTime = deltaTime,
                //AllCells = allCells,
                //Rules = map,
            };
            job.ScheduleParallel(_jobQuery, handle);
            //job.Run();

            _jobQuery.ResetFilter();
        }
        state.Dependency = handle;
    }
acoustic matrix
#

job.ScheduleParallel(_jobQuery, handle); needs to be handle = job.ScheduleParallel(_jobQuery, handle);

gleaming quarry
#

aha

#

makes more sense

#

ok back to the original error as the only error

#

should i do the same for the second system - the handle stuff

acoustic matrix
#

yup

#
    [BurstCompile]
    public void OnCreate(ref SystemState state)
    {
        state.RequireForUpdate<WorldProperties>();
        state.RequireForUpdate<SharedRulesGrouping>();
        _jobQuery = SystemAPI.QueryBuilder()
                        .WithAll<CellProperties>()
                        .WithAll<SharedRulesGrouping>()
                        .WithAll<LocalToWorld>().Build();
    }

SystemAPI has a lot of handy functions you'll need to use in systems

#

So thats also an option ^ instead of your current solution. Whatever you prefer

gleaming quarry
#
using Unity.Burst;
using Unity.Entities;

[BurstCompile]
[UpdateAfter(typeof(ApplyRulesSystem))]
public partial struct MoveCellsSystem : ISystem
{
    [BurstCompile]
    public void OnCreate(ref SystemState state)
    {
    }

    [BurstCompile]
    public void OnDestroy(ref SystemState state)
    {
    }

    [BurstCompile]
    public void OnUpdate(ref SystemState state)
    {
        var deltaTime = SystemAPI.Time.DeltaTime;
        var handle = state.Dependency;

        new MoveCellJob
        {
            DeltaTime = deltaTime,
        }.Run(); // where to pass in handle?
    }
}

[BurstCompile]
public partial struct MoveCellJob: IJobEntity
{
    public float DeltaTime;
    private void Execute(ref CellPropertiesAspect aspect, [EntityIndexInQuery] int sortKey)
    {
    }
}
#

My current solution is already using SystemAPI for the QueryBuilder - are you thinking of something else? I've just started learning about DOTS so i keep running into new stuff and get nothing done 😄

acoustic matrix
#

You can also have that ScheduleParallel if you arent not writing/reading from different entities from other entities

#

Run doesnt take a handle

acoustic matrix
gleaming quarry
#

Yeah i was trying to make that job simple - since it will aggregate the calculations from the previous job and write it to the LocalTransform

gleaming quarry
acoustic matrix
#

not so much for your use. But SystemAPI code gen caches the query so theres no downsides from doing it and not putting it in a var ifs thats not needed

gleaming quarry
#

aha

acoustic matrix
#

i guess you could make it in OnUpdate instead as that would also work. Up to you

gleaming quarry
#

right... it's only done in the OnCreate so the overhead wouldn't be noticeable, but great to know for future stuff - thanks 🙂

#

ah yeah

#

because it would be cached

acoustic matrix
#

if you want a sort key for an ECB don't do [EntityIndexInQuery] int sortKey you can do [ChunkIndexInQuery] int sortKey instead

#

since it's the chunk which is threaded

gleaming quarry
#

Ok i forgot to clean that part up - and just found out about ChunckIndex - haven't read it through yet but thanks

#

ok... so that would be some kind of offset? the ChunckIndex?

acoustic matrix
#

yeah, its just the index of the chunk being processed.

gleaming quarry
#

Ok - great to know thanks... Just trying to get it to work a simple scenario - preferably with threading though

acoustic matrix
#

using [EntityIndexInQuery] would lower performance of an ECB, since it allocates based on the sort key

gleaming quarry
#

oh ok that is why - thanks

#

I updated the second system to use the handle and parallel:

    public void OnUpdate(ref SystemState state)
    {
        var deltaTime = SystemAPI.Time.DeltaTime;
        var handle = state.Dependency;

        new MoveCellJob
        {
            DeltaTime = deltaTime,
        }.Schedule(handle); // where to pass in handle?

        state.Dependency = handle;
    }
acoustic matrix
gleaming quarry
#

Still same error - but now i also get

InvalidOperationException: The previously scheduled job MoveCellJob writes to the ComponentTypeHandle<Unity.Transforms.LocalTransform> MoveCellJob.JobData.__CellPropertiesAspectTypeHandle.transform.m_LocalTransformCth. You must call JobHandle.Complete() on the job MoveCellJob, before you can deallocate the ComponentTypeHandle<Unity.Transforms.LocalTransform> safely.
#

Oh yeah my mistake

acoustic matrix
#
    public void OnUpdate(ref SystemState state)
    {
        var deltaTime = SystemAPI.Time.DeltaTime;

        state.Dependency = new MoveCellJob
            {
                DeltaTime = deltaTime,
            }.Schedule(state.Dependency);
    }

If you only have one job you can do that

gleaming quarry
acoustic matrix
#

but i prefer:

    public void OnUpdate(ref SystemState state)
    {
        var deltaTime = SystemAPI.Time.DeltaTime;

        var moveCellJobHandle = new MoveCellJob
            {
                DeltaTime = deltaTime,
            }.Schedule(state.Dependency);

        state.Dependency = moveCellJobHandle;
    }
gleaming quarry
#

It worksesses now - thanks 🙂

#

ok yeah i see the rewrite - makes it easier to understand 🙂

#

I didn't realize i had to manually create the dependencies when i was using the "UpdateAfter" attribute

acoustic matrix
#

it's because jobs don't have to complete immediately at the end/start of a system, so they can be more spread out depending on their dependecies

gleaming quarry
#

Makes a lot of sense - doing it this way opens up more possibilities instead of having the attribute forcing one system to finish

#

Ok - great thanks @acoustic matrix - I'm also kinda new to discord and/or this channel - am i supposed to do anything besides perhaps update the title - or i saw a new Post Attribute saying resolved?

acoustic matrix
#

atm i don't think you're required to do anything (the dots forum layout is quite new). But I'd edit and put [Resolved] at the start

gleaming quarry
#

Why is my Job flagged as writing to a ComponentTypeHandle that it is not? [Solved]

ruby galleon
acoustic matrix
#

then again i didnt really use IJobEntity that much in version 0.51

gleaming quarry
ruby galleon
#

Well, new MoveCellJob{...}.Schedule(state.Dependency) will definitely give you an error. You go manual as soon as you pass in a jobhandle. However the two snippets i mentioned don't have that issue as they mean exactly the same. If they don't, that's a bug and please report it to me. In anycase up to you guys, i would personally recommend using the auto injection, but that's maybe just personal preference :3

gleaming quarry
#

I would definitely like auto injection - that was what i started with - in the middle of some refactoring but i'll check again when i'm done

gleaming quarry
#

I removed the manual dependency injection and the error is back:

InvalidOperationException: The previously scheduled job MoveCellJob writes to the ComponentTypeHandle<Unity.Collections.NativeText.ReadOnly> MoveCellJob.JobData.__CellPropertiesAspectTypeHandle.transform.m_LocalTransformCth. You must call JobHandle.Complete() on the job MoveCellJob, before you can deallocate the ComponentTypeHandle<Unity.Collections.NativeText.ReadOnly> safely.

I can leave the handle part in on the last job and the error goes away:

    [BurstCompile]
    public void OnUpdate(ref SystemState state)
    {
        var deltaTime = math.min(0.05f, SystemAPI.Time.DeltaTime);

        var handle = new MoveCellJob
        {
            DeltaTime = deltaTime * Speed,
            MinX = -(Dimension.x / 2),
            MaxX = (Dimension.x / 2),
            MinY = -(Dimension.y / 2),
            MaxY= (Dimension.y / 2),
        }.ScheduleParallel(state.Dependency);  // Need to inject the Dependency here

        state.Dependency = handle; // This is needed or i get the error above
    }
#

@ruby galleon Is that enough for a bug report or am I misunderstanding this as a bug?

#

Would the correct solution be to call .Complete() on the handle instead?

ruby galleon
#

Again, like I said. If you pass anything in then it will be manual. You don't 'need' to pass it in, cause the whole point of the auto injection is that it will implicitly do: state.Dependency.

gleaming quarry
ruby galleon
gleaming quarry
#

Honestly. I was about to just change it back and paste it - but thought i'd compile and run again - just to make sure and now the error is gone? I know it sounds crazy because this was my default attempt that prompted me to create this post in the first place. I'll post it below, but I don't see any errors any more. When posting this thread - i had no ideas about state.Dependency - so trust me, i only added that part to make the error go away to begin with. I know it sounds like something else was changed, but i only did a bit of variable renaming (to comply with c# naming convensions)

    [BurstCompile]
    public void OnUpdate(ref SystemState state)
    {
        var deltaTime = math.min(0.05f, SystemAPI.Time.DeltaTime);

        new MoveCellJob
        {
            DeltaTime = deltaTime * _speed,
            MinX = -(_dimension.x / 2),
            MaxX = (_dimension.x / 2),
            MinY = -(_dimension.y / 2),
            MaxY= (_dimension.y / 2),
        }.ScheduleParallel();
    }

^ TL;RD It is suddenly working again without throwing the error.

ruby galleon
#

Awesome - now isn't that cleaner! 😄