#`EntityQuery` to run a job while not causing aliasing issues with an existing `ComponentLookup`?

1 messages · Page 1 of 1 (latest)

willow prairie
#

Situation here's a little weird. I'm basically trying to schedule a big bunch of jobs, with no sync points in between, so World.Update can complete and give Unity the main thread back while all those jobs are processed in the background.

To enable that I've had to prepare some ComponentLookups as some systems do arbitrary non-structural modifications.

However, on a different thread just now (#1138412523691970602 message) I found myself using an IJobEntity which had a parameter with the same type as one of those ComponentLookups, and that's got Unity throwing an error about aliasing.

        partial struct DoMovementJibJob : IJobEntity
        {
            public void Execute(ref MovementData movementData)
            {
                // ...

Just by movementData existing there, ECS creates an internal ComponentLookup<MovementData>, and that's clashing with the one that already exists.

I'm trying to find a way to use the existing one in this job (which is of course a lot more complex than above). This is my current theory:

        partial struct DoMovementJibJob : IJobEntity
        {
            public void Execute(ref Context ctx /* the place I store my lookups */, Entity entity)
            {
                ctx.Lookups.MovementDatas[entity] = // ...

If I can combine that with an entity query like this to get the elements _without creating a new ComponentLookup...

            EntityManager.CreateEntityQuery(new EntityQueryDesc
            {
                All = new ComponentType[] { typeof(StaticDestinationMovementData) },
            });

... then maybe it'll all work fine? But I dunno how to schedule a IJobEntity given an EntityQuery 🤔 Is there a similar API to what I'm imagining elsewhere, or is there another approach I should be considering here?

willow prairie
#

Err well I just tried to produce a minimal example of what I'm trying to do and... it worked lol

using Unity.Collections;
using Unity.Entities;
using Unity.Jobs;

namespace FrankenStorm
{
    public partial class TestSystem : SystemBase
    {
        struct DoMovementJibJob : IJobParallelFor
        {
            [NativeDisableParallelForRestriction]
            public ECSContext Ctx;
            public NativeArray<Entity> Entities;

            public void Execute(int index)
            {
                ref var movementData = ref Ctx.Lookups.MovementData.GetRefRW(Entities[index]).ValueRW;
                --movementData.BaseMoveSpeedMM;
                UnityEngine.Debug.Log($"GOT IT {movementData.BaseMoveSpeedMM}");
            }
        }

        EntityQuery _query;

        protected override void OnCreate()
        {
            base.OnCreate();
            _query = EntityManager.CreateEntityQuery(new EntityQueryDesc
            {
                All = new ComponentType[] { typeof(MovementData) },
            });
        }

        protected override void OnUpdate()
        {
            var entities = _query.ToEntityArray(Allocator.TempJob);

            var ctx = World.GetExistingSystemManaged<TCBSystem2>().PrepareTCB();

            new DoMovementJibJob
            {
                Ctx = ctx,
                Entities = entities,
            }.Schedule(arrayLength: entities.Length, innerloopBatchCount: 5).Complete();
        }
    }
}
#

So something else must be causing that aliasing in the non-minimal case 🤔 Damn

#

The error is weird: InvalidOperationException: The ComponentLookup<FrankenStorm.MovementData> has been declared as [ReadOnly] in the job, but you are writing to it.

I've not declared it in the job at all 🤔

willow prairie
#

But I didn't declare it [ReadOnly] in there

#
        public struct LookupHelper
        {
            [MarshalAs(UnmanagedType.U1)] public bool IsSet;
            public ComponentLookup<ExistenceDependsOnEntityData> ExistenceDependsOnEntityData;
            public ComponentLookup<ExpirationData> ExpirationData;
            public ComponentLookup<GridPresenceData> GridPresenceData;
            public ComponentLookup<LifeData> LifeData;
            public ComponentLookup<MovementData> MovementData;
            public ComponentLookup<ObjectData> ObjectData;
            public ComponentLookup<RootActionCooldownData> RootActionCooldownData;
            public ComponentLookup<RootActionPtrData> RootActionPtrData;
            public ComponentLookup<RootActionTargetingData> RootActionTargetingData;
            public BufferLookup<SideEffectBufferData> SideEffectBufferData;
            public BufferLookup<StampedVariableBufferData> StampedVariableBufferData;
            public ComponentLookup<StaticDestinationMovementData> StaticDestinationMovementData;
            public BufferLookup<StatusEffectApplicationToBeReversedBufferData>
                StatusEffectApplicationToBeReversedBufferData;
            public ComponentLookup<StatusEffectData> StatusEffectData;
        }

That's Ctx.Lookups

#

And that's actually working fine in the minimal example I pasted above, but just not in reality for some reason

undone moth
willow prairie
#

I could bypass that with a [NativeDisableContainerSafetyRestriction] but it keeps chaining to another container that was used with the same error. Does it slap [ReadOnly] on to things automatically?

undone moth
#

and pass read only value to job struct

willow prairie
#

Lol I'm a clown, I literally had [ReadOnly] public ECSContext Ctx 🤦 Looked everywhere else but there

#

Thanks Issue!

#

❤️ tests passing

undone moth
willow prairie
#
        partial struct DoMovementJibJob : IJobParallelFor
        {
            [NativeDisableParallelForRestriction] public ECSContext Ctx;

😅

My systems mostly run 1 by 1 anyway so I'm not too concerned. I'm just trying to move them to run 1 by 1 without blocking the main thread

#

It never actually executed with the [ReadOnly] there anyway, that was an accident 🤔

undone moth