Feedback regarding the removal of AddInputDependency/GetOutputDependency

I’ve been trying to wrap my head around this new approach with RegisterPhysicsRuntimeSystemReadOnly and RegisterPhysicsRuntimeSystemReadWrite. Interesting way to use the singleton to sync dependencies, but it feels like it’s more limited now than it used to be.

It seems harder to work against a physics world outside of ECS systems now. Some simple examples would be:

  • Static utility methods that internally fetch the PhysicsWorld and work against it.
  • Any kind of non-system code that wants to fetch the PhysicsWorld and work against it.

Previously we would just fetch the world along with GetOutputDependency and either complete the dependency or schedule jobs against it, but now it seems trickier. Especially if we want to schedule asynchronous access against the PhysicsWorld in a non-system location.

I suspect one can “solve” the synchronous access by fetching the PhysicsSystemRuntimeData singleton wherever one wants to read from the CollisionWorld as that should complete it’s dependency? It does feel like a quite un-intuitive way to work with it, but maybe it’s a question of getting used to. I guess I could make an extension method to fetch the PhysicsWorld and the singleton, and then return the PhysicsWorld.

Personally I think we will re-implement the GetOutputDependency/AddInputDependency methods in the physics library as it’s far easier for us to work with for now, it would be a quite simple modification. Maybe we’ll look at using these new workflows in potential fuure DOTS projects.

1 Like

Hey,
Thanks for the feedback.
You need to call RegisterPhysicsRuntimeSystemReadOnly() or RW() only once, in OnStartRunning() preferably.
Once it is called, a read or write dependency will always be included in the system’s OnUpdate() without requiring further calls.
If you need PhysicsWorld on the main thread right there, just call Dependency.Complete(), and it will be ready. And if you want to schedule jobs with the world, you don’t need to complete dependency.

We are working now on a way to retrieve PhysicsWorld using DOTS approach, something like GetSingleton(), which will solve dependency problems automatically and remove the need of RegisterPhysicsRuntimeSystemReadOnly / ReadWrite.

2 Likes

Personally I’m happy you have taken this approach as physics dependency handling was my biggest complaint about the physics package. I actually wrote a very similar implementation to this a while ago to handle it and I’ve found it worked very well. Glad to see something similar make it into the core package.

1 Like

Thanks for that explanation! I like this. It is much less confusing than before.

I think maybe I misinterpreted the concept.

I did this:

public partial class TestSystem : SystemBase
{
    BuildPhysicsWorld m_world;
    protected override void OnCreate()
    {
        m_world = World.GetOrCreateSystem<BuildPhysicsWorld>();
    }
    protected override void OnStartRunning()
    {
        base.OnStartRunning();
        m_world.RegisterPhysicsRuntimeSystemReadOnly(); // <---- register here doesn't fix the error
    }
    protected override void OnUpdate()
    {
        CollisionWorld world = m_world.PhysicsWorld.CollisionWorld;
        //Dependency = JobHandle.CombineDependencies(Dependency, m_world.GetOutputDependency());  <---- this used to work
        //m_world.RegisterPhysicsRuntimeSystemReadOnly(); // <---- uncommenting this will fix the error.
        Entities.ForEach((ref MyDataData mydata, in FooData foo) => { // <---- error occurs here
            // use world as read-only here
        }).WithReadOnly(world).ScheduleParallel();
    }
}

I thought you were implying that calling RegisterPhysicsRuntimeSystemReadOnly() only once in OnStartRunning() would be enough.

But the above code will give the runtime error:

error

InvalidOperationException: The previously scheduled job Broadphase:prepareStaticBodyDataJob writes to the Unity.Collections.NativeArray1[Unity.Physics.CollisionFilter] PrepareStaticBodyDataJob.FiltersOut. You are trying to schedule a new job UnitTargeterSystem:UnitTargeterSystem_LambdaJob_0_Job, which reads from the same Unity.Collections.NativeArray1[Unity.Physics.CollisionFilter] (via UnitTargeterSystem_LambdaJob_0_Job.JobData.world.Broadphase.m_StaticTree.BodyFilters). To guarantee safety, you must include Broadphase:prepareStaticBodyDataJob as a dependency of the newly scheduled job.
Unity.Jobs.LowLevel.Unsafe.JobsUtility.ScheduleParallelFor (Unity.Jobs.LowLevel.Unsafe.JobsUtility+JobScheduleParameters& parameters, System.Int32 arrayLength, System.Int32 innerloopBatchCount) (at <3be1a7ff939c43f181c0a10b5a0189ac>:0)
Unity.Entities.JobEntityBatchExtensions.ScheduleInternal[T] (T& jobData, Unity.Entities.EntityQuery query, Unity.Jobs.JobHandle dependsOn, Unity.Jobs.LowLevel.Unsafe.ScheduleMode mode, System.Boolean isParallel) (at Library/PackageCache/com.unity.entities@0.50.0-preview.24/Unity.Entities/IJobEntityBatch.cs:660)
Unity.Entities.JobEntityBatchExtensions.ScheduleParallel[T] (T jobData, Unity.Entities.EntityQuery query, Unity.Jobs.JobHandle dependsOn) (at Library/PackageCache/com.unity.entities@0.50.0-preview.24/Unity.Entities/IJobEntityBatch.cs:279)
UnitTargeterSystem.UnitTargeterSystem_LambdaJob_0_Execute (FactionMatrix factionMatrix, Unity.Physics.CollisionWorld world) (at Temp/GeneratedCode/Assembly-CSharp/UnitTargeterSystem__System_264805703.g.cs:323)
UnitTargeterSystem.OnUpdate () (at Assets/Scripts/Systems/UnitTargeterSystem.cs:50)
Unity.Entities.SystemBase.Update () (at Library/PackageCache/com.unity.entities@0.50.0-preview.24/Unity.Entities/SystemBase.cs:409)
Unity.Entities.ComponentSystemGroup.UpdateAllSystems () (at Library/PackageCache/com.unity.entities@0.50.0-preview.24/Unity.Entities/ComponentSystemGroup.cs:583)
UnityEngine.Debug:LogException(Exception)
Unity.Debug:LogException(Exception) (at Library/PackageCache/com.unity.entities@0.50.0-preview.24/Unity.Entities/Stubs/Unity/Debug.cs:19)
Unity.Entities.ComponentSystemGroup:UpdateAllSystems() (at Library/PackageCache/com.unity.entities@0.50.0-preview.24/Unity.Entities/ComponentSystemGroup.cs:588)
Unity.Entities.ComponentSystemGroup:OnUpdate() (at Library/PackageCache/com.unity.entities@0.50.0-preview.24/Unity.Entities/ComponentSystemGroup.cs:523)
Unity.Entities.ComponentSystem:Update() (at Library/PackageCache/com.unity.entities@0.50.0-preview.24/Unity.Entities/ComponentSystem.cs:114)
Unity.Entities.DummyDelegateWrapper:TriggerUpdate() (at Library/PackageCache/com.unity.entities@0.50.0-preview.24/Unity.Entities/ScriptBehaviourUpdateOrder.cs:426)

What what’s even more confusing… super duper confusing… I have a totally unrelated system… which doesn’t use physics at all - not one single bit. It’s a very simple system. Yet…

InvalidOperationException: The previously scheduled job PhysicsWorldExporter:ExportDynamicBodiesJob writes to the ComponentTypeHandle<Unity.Transforms.Translation> ExportDynamicBodiesJob.JobData.PositionType. You must call JobHandle.Complete() on the job PhysicsWorldExporter:ExportDynamicBodiesJob, before you can read from the ComponentTypeHandle<Unity.Transforms.Translation> safely.

So strange…

I don’t even know how to fix it. I put RegisterPhysicsRuntimeSystemReadOnly() in every OnStartRunning() and in every Update() where I use the physics world, and it’s still giving the error in my job that doesn’t use physics at all.

Where on earth would one start when trying to fix an error that points to a completely innocent file that has nothing to do with the error?? This error-in-wrong-file issue is what happened before and why I had to put in JobHandle.CombineDependencies() everywhere I used the physics world. Somehow I got lucky and got that working fine in 0.17, but now with 0.50 I don’t know what to do.

You also need to put proper [UpdateAfter]/[UpdateBefore] and [UpdateInGroup] attributes on system, as was done before.
To fix your problem, I think this would solve it.
Put [UpdateInGroup(typeof(FixedStepSimulationGroup))], [UpdateAfter(typeof(ExportPhysicsWorld))], [UpdateBefore(typeof(EndFramePhysicsSystem))]

And also, don’t call m_world.RegisterPhysicsSystemsReadOnly()
You should call this.RegisterPhysicsSystemsReadOnly()

Thanks for the information @papopov , however, I added those groups and changed to using the “this” version and I’m still getting runtime errors.

I get the error in my EnemyTargeter system. A stripped down version of it looks like this:

[UpdateInGroup(typeof(FixedStepSimulationSystemGroup))]
[UpdateAfter(typeof(ExportPhysicsWorld))]
[UpdateBefore(typeof(EndFramePhysicsSystem))]
public partial class EnemyTargeterSystem : SystemBase
{
    BuildPhysicsWorld m_world;

    protected override void OnCreate()
    {
        base.OnCreate();
        m_world = World.GetOrCreateSystem<BuildPhysicsWorld>();
    }

    protected override void OnStartRunning()
    {
        base.OnStartRunning();
        this.RegisterPhysicsRuntimeSystemReadOnly();
    }

    protected override void OnUpdate()
    {
        CollisionWorld world = m_world.PhysicsWorld.CollisionWorld;

        EntityQuery query = GetEntityQuery(ComponentType.ReadOnly<CommandCenterTag>(), ComponentType.ReadOnly<Translation>());
        NativeArray<Translation> homePosDataArray = query.ToComponentDataArray<Translation>(Allocator.TempJob);
        NativeArray<Entity> homeEntityArray = query.ToEntityArray(Allocator.TempJob);

        Entities.ForEach((ref TargetData target, ref TargetDistanceData distance, in Translation pos) => {
            //............. perform target searching here using world ...........
        }).WithReadOnly(homePosDataArray).WithReadOnly(homeEntityArray).WithReadOnly(world)
        .WithDisposeOnCompletion(homePosDataArray).WithDisposeOnCompletion(homeEntityArray).ScheduleParallel();
    }
}

If I comment out the GetEntityQuery(), the error goes away… so it seems that the ForEach() works fine, but there is something about that GetEntityQuery that breaks it.

If I comment out GetEntityQuery() above, then my EnemyTargeterSystem runs fine, but then I get the error in my LinearMovementAndCollisionSystem, which looks like this:

[UpdateInGroup(typeof(FixedStepSimulationSystemGroup))]
[UpdateAfter(typeof(ExportPhysicsWorld))]
[UpdateBefore(typeof(EndFramePhysicsSystem))]
public partial class LinearMovementAndCollisionSystem : SystemBase
{
    BuildPhysicsWorld m_world;

    protected override void OnCreate()
    {
        m_world = World.GetOrCreateSystem<BuildPhysicsWorld>();
    }

    protected override void OnStartRunning()
    {
        base.OnStartRunning();
        this.RegisterPhysicsRuntimeSystemReadOnly();
    }

    protected override void OnUpdate()
    {
        CollisionWorld world = m_world.PhysicsWorld.CollisionWorld;

        Entities.ForEach((int entityInQueryIndex, Entity entity, ref Translation translation, in LinearVelocityData velocity) => {
            // .........move object forward, changing translation.........
            //..........world is used to do a raycast..........
            //..........i also use an ecb buffer here to add a component and append to a buffer.........
        }).WithReadOnly(world).ScheduleParallel();
    }
}

The exact error that this one gives is: linearmovementsystem error

InvalidOperationException: The previously scheduled job LinearMovementAndCollisionSystem:LinearMovementAndCollisionSystem_LambdaJob_0_Job writes to the ComponentTypeHandle<Unity.Transforms.Translation> LinearMovementAndCollisionSystem_LambdaJob_0_Job.JobData.__translationTypeHandle. You must call JobHandle.Complete() on the job LinearMovementAndCollisionSystem:LinearMovementAndCollisionSystem_LambdaJob_0_Job, before you can read from the ComponentTypeHandle<Unity.Transforms.Translation> safely.
Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle.CheckReadAndThrowNoEarlyOut (Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle handle) (at <3be1a7ff939c43f181c0a10b5a0189ac>:0)
Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle.CheckReadAndThrow (Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle handle) (at <3be1a7ff939c43f181c0a10b5a0189ac>:0)
Unity.Entities.EntityQueryImpl.ToComponentDataArray[T] (Unity.Collections.Allocator allocator, Unity.Entities.EntityQuery outer) (at Library/PackageCache/com.unity.entities@0.50.0-preview.24/Unity.Entities/Iterators/EntityQuery.cs:800)
Unity.Entities.EntityQuery.ToComponentDataArray[T] (Unity.Collections.Allocator allocator) (at Library/PackageCache/com.unity.entities@0.50.0-preview.24/Unity.Entities/Iterators/EntityQuery.cs:1804)
HealthStationScanSystem.OnUpdate () (at Assets/Scripts/Systems/HealthStationScanSystem.cs:25)
Unity.Entities.SystemBase.Update () (at Library/PackageCache/com.unity.entities@0.50.0-preview.24/Unity.Entities/SystemBase.cs:409)
Unity.Entities.ComponentSystemGroup.UpdateAllSystems () (at Library/PackageCache/com.unity.entities@0.50.0-preview.24/Unity.Entities/ComponentSystemGroup.cs:583)
UnityEngine.Debug:LogException(Exception)
Unity.Debug:LogException(Exception) (at Library/PackageCache/com.unity.entities@0.50.0-preview.24/Unity.Entities/Stubs/Unity/Debug.cs:19)
Unity.Entities.ComponentSystemGroup:UpdateAllSystems() (at Library/PackageCache/com.unity.entities@0.50.0-preview.24/Unity.Entities/ComponentSystemGroup.cs:588)
Unity.Entities.ComponentSystemGroup:OnUpdate() (at Library/PackageCache/com.unity.entities@0.50.0-preview.24/Unity.Entities/ComponentSystemGroup.cs:523)
Unity.Entities.ComponentSystem:Update() (at Library/PackageCache/com.unity.entities@0.50.0-preview.24/Unity.Entities/ComponentSystem.cs:114)
Unity.Entities.DummyDelegateWrapper:TriggerUpdate() (at Library/PackageCache/com.unity.entities@0.50.0-preview.24/Unity.Entities/ScriptBehaviourUpdateOrder.cs:426)

What’s strange is that the above error mentions “HealthStationScanSystem.OnUpdate ()”, which has nothing to do with physics and looks like this:

public partial class HealthStationScanSystem : SystemBase
{
    protected override void OnUpdate()
    {
        if (!EntityUtils.Exists<HealthRechargeData>(EntityManager)) { return; }

        EntityQuery query = GetEntityQuery(ComponentType.ReadOnly<HealthRechargeData>(), ComponentType.ReadOnly<Translation>());
        NativeArray<Translation> stationPosDataArray = query.ToComponentDataArray<Translation>(Allocator.TempJob);
        NativeArray<Entity> stationEntityArray = query.ToEntityArray(Allocator.TempJob);

        Entities.ForEach((ref NearestHealthStationData nearest, in Translation pos, in FactionData faction) => {
         //......... do non-physics stuff here ....
        }).WithReadOnly(stationPosDataArray).WithReadOnly(stationEntityArray).WithDisposeOnCompletion(stationPosDataArray).WithDisposeOnCompletion(stationEntityArray).ScheduleParallel();
    }
}

I think the “common thing” between the two errors is the use of Translation and GetEntityQuery(). I know that previously things worked fine when I was using 0.17 with Dependency = JobHandle.CombineDependencies(Dependency, m_world.GetOutputDependency()); in the updates wherever I used CollisionWorld.

Somehow I forgot to include it in my compilation post, but I found with ToEntityArray and ToComponentDataArray you need to call query.CompleteDependency() now to be safe
I’d recommend you use ToEntityArrayAsync and ToComponentDataArrayAsync instead

1 Like

I found a “fix”… but it seems pretty hacky. [EDIT - Better fix below thanks to tertle’s observation]

So in HealthStationScanSystem… I put this.CompleteDependency(); right before GetEntityQuery(). I also put this.CompleteDependency(); right before GetEntityQuery() in EnemyTargeterSystem.

The hacky part is that HealthStationScanSystem has NOTHING to do with physics other than it queries for READ-ONLY position data. I don’t see why my physics systems would care if I’m reading position data in another system.

This is the error that comes up when I don’t have the complete-dependency call in the HealthStationScanSystem:

error

InvalidOperationException: The previously scheduled job PhysicsWorldExporter:ExportDynamicBodiesJob writes to the ComponentTypeHandle<Unity.Transforms.Translation> ExportDynamicBodiesJob.JobData.PositionType. You must call JobHandle.Complete() on the job PhysicsWorldExporter:ExportDynamicBodiesJob, before you can read from the ComponentTypeHandle<Unity.Transforms.Translation> safely.
Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle.CheckReadAndThrowNoEarlyOut (Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle handle) (at <3be1a7ff939c43f181c0a10b5a0189ac>:0)
Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle.CheckReadAndThrow (Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle handle) (at <3be1a7ff939c43f181c0a10b5a0189ac>:0)
Unity.Entities.EntityQueryImpl.ToComponentDataArray[T] (Unity.Collections.Allocator allocator, Unity.Entities.EntityQuery outer) (at Library/PackageCache/com.unity.entities@0.50.0-preview.24/Unity.Entities/Iterators/EntityQuery.cs:800)
Unity.Entities.EntityQuery.ToComponentDataArray[T] (Unity.Collections.Allocator allocator) (at Library/PackageCache/com.unity.entities@0.50.0-preview.24/Unity.Entities/Iterators/EntityQuery.cs:1804)
HealthStationScanSystem.OnUpdate () (at Assets/Scripts/Systems/HealthStationScanSystem.cs:28)
Unity.Entities.SystemBase.Update () (at Library/PackageCache/com.unity.entities@0.50.0-preview.24/Unity.Entities/SystemBase.cs:409)
Unity.Entities.ComponentSystemGroup.UpdateAllSystems () (at Library/PackageCache/com.unity.entities@0.50.0-preview.24/Unity.Entities/ComponentSystemGroup.cs:583)
UnityEngine.Debug:LogException(Exception)
Unity.Debug:LogException(Exception) (at Library/PackageCache/com.unity.entities@0.50.0-preview.24/Unity.Entities/Stubs/Unity/Debug.cs:19)
Unity.Entities.ComponentSystemGroup:UpdateAllSystems() (at Library/PackageCache/com.unity.entities@0.50.0-preview.24/Unity.Entities/ComponentSystemGroup.cs:588)
Unity.Entities.ComponentSystemGroup:OnUpdate() (at Library/PackageCache/com.unity.entities@0.50.0-preview.24/Unity.Entities/ComponentSystemGroup.cs:523)
Unity.Entities.ComponentSystem:Update() (at Library/PackageCache/com.unity.entities@0.50.0-preview.24/Unity.Entities/ComponentSystem.cs:114)
Unity.Entities.DummyDelegateWrapper:TriggerUpdate() (at Library/PackageCache/com.unity.entities@0.50.0-preview.24/Unity.Entities/ScriptBehaviourUpdateOrder.cs:426)

The only class of mine that the error points to is HealthStationScanSystem.

It is very disturbing that physics can cause errors in totally unrelated classes that normally would work fine. I was hoping this new system would improve the confusion but to be honest I’m just as confused as ever.

Ah, that is good to know! query.CompleteDependency() certainly does the trick. I went through all my code wherever I had ToComponentDataArray() and ToEntityArray() and added the query complete. Nice find!!

If anyone is wondering about the async mode… Something like this works great:

        EntityQuery query = GetEntityQuery(ComponentType.ReadOnly<CommandCenterTag>(), ComponentType.ReadOnly<Translation>(), ComponentType.ReadOnly<FactionData>());
        NativeArray<Translation> homePosDataArray = query.ToComponentDataArrayAsync<Translation>(Allocator.TempJob, out JobHandle h1);
        NativeArray<Entity> homeEntityArray = query.ToEntityArrayAsync(Allocator.TempJob, out JobHandle h2);
        NativeArray<FactionData> homeFactionArray = query.ToComponentDataArrayAsync<FactionData>(Allocator.TempJob, out JobHandle h3);
        Dependency = JobHandle.CombineDependencies(Dependency, JobHandle.CombineDependencies(h1, h2, h3));

On a slightly separate topic… I changed my systems that are only ever reading from the world to use:

[UpdateInGroup(typeof(FixedStepSimulationSystemGroup))]
[UpdateAfter(typeof(BuildPhysicsWorld))]

I did this because the 0.50 documentation section for collisions ( https://docs.unity3d.com/Packages/com.unity.physics@0.50/manual/collision_queries.html ), states:

“Collision queries use physics simulation data (read-only access), more precisely an internal structure called broadphase, which is built by a job scheduled in BuildPhysicsWorld. Collision queries can be performed any time before or after BuildPhysicsWorld, but if you do it before make sure you provide your job handle to BuildPhysicsWorld.AddInputDependencyToComplete()”

If you are only ever reading with collision queries, [UpdateAfter(typeof(BuildPhysicsWorld))] ensures that your systems run after BuildPhysicsWorld so you don’t have to worry about calling AddInputDependencyToComplete(). The documentation on the collision page doesn’t discuss putting “this.RegisterPhysicsRuntimeSystemReadOnly();” in OnStartRunning(), but I’m pretty sure it’s necessary because without it I get errors all over the place. I’m not an expert in this, so if this theory is wrong, hopefully someone can point out my mistake.

There’s no reason to do async like that. The whole point of async is to not have a sync point. If you need to cause a sync point just use the non-async versions.

var h4 =JobHandle.CombineDependencies(h1, h2, h3);
Dependency =JobHandle.CombineDependencies(Dependency, h4);

then just read the arrays in the job and it’ll be fine.

1 Like

This got me interested, so I made a repro similar to EnemyTargeterSystem that you showed here, and here’s what I found. In the next code snippet, I’ve commented out all code that doesn’t seem to introduce your problem.

[UpdateInGroup(typeof(FixedStepSimulationSystemGroup))]
[UpdateAfter(typeof(ExportPhysicsWorld))]
[UpdateBefore(typeof(EndFramePhysicsSystem))]
public partial class EnemyTargeterSystem : SystemBase
{
    BuildPhysicsWorld m_world;

    protected override void OnCreate()
    {
        base.OnCreate();
        m_world = World.GetOrCreateSystem<BuildPhysicsWorld>();
    }

    protected override void OnStartRunning()
    {
        //base.OnStartRunning();
        //this.RegisterPhysicsRuntimeSystemReadOnly();
    }

    protected override void OnUpdate()
    {
        //CollisionWorld world = m_world.PhysicsWorld.CollisionWorld;

        EntityQuery query = GetEntityQuery(ComponentType.ReadOnly<Translation>());
        NativeArray<Translation> homePosDataArray = query.ToComponentDataArray<Translation>(Allocator.TempJob);
        NativeArray<Entity> homeEntityArray = query.ToEntityArray(Allocator.TempJob);

        // Entities
        //     //.WithReadOnly(world)
        //     .ForEach((ref DummyTestComponentData dtc, in Translation pos) =>
        // {
        //     RaycastInput input = new RaycastInput
        //     {
        //         Start = Unity.Mathematics.float3.zero,
        //         End = new Unity.Mathematics.float3(10, 10, 10),
        //         Filter = CollisionFilter.Default
        //     };

        //     dtc.Value += 1;

        //     //if (world.CastRay(input))
        //     //{
        //     //    dtc.Value += 1;
        //     //}

        // })
        //.ScheduleParallel(Dependency);

        Dependency.Complete();
        homePosDataArray.Dispose();
        homeEntityArray.Dispose();
    }
}

So here, as you said, the problem seems to be query.ToComponentDataArray() call. Previously scheduled job ExportPhysicsWorld is writng to Translation data (which it is), and that is causing problems. I would expect when one calls ToComponentDataArray(), that the dependencies which write to Translation component data would be completed automatically by the ToComponentDataArray() function. Looks like that is not the case, and it seems to be a bug in the entities/jobs/collections.
Calling Dependency.Complete() or query.CompleteDependency() makes the problem go away, but you lose a lot of perf that way, since you force the sync point on main thread, and potentially a lot of jobs could be writing to Translation component data.

The real fix here seems to use async component data arrays, as mentioned above.
Here’s a working sample that I got working and I’ve uncommented all the commented code above.

[UpdateInGroup(typeof(FixedStepSimulationSystemGroup))]
[UpdateAfter(typeof(ExportPhysicsWorld))]
[UpdateBefore(typeof(EndFramePhysicsSystem))]
public partial class EnemyTargeterSystem : SystemBase
{
    BuildPhysicsWorld m_world;

    protected override void OnCreate()
    {
        base.OnCreate();
        m_world = World.GetOrCreateSystem<BuildPhysicsWorld>();
    }

    protected override void OnStartRunning()
    {
        base.OnStartRunning();
        this.RegisterPhysicsRuntimeSystemReadOnly();
    }

    protected override void OnUpdate()
    {
        CollisionWorld world = m_world.PhysicsWorld.CollisionWorld;

        EntityQuery query = GetEntityQuery(ComponentType.ReadOnly<Translation>());
        NativeArray<Translation> homePosDataArray = query.ToComponentDataArrayAsync<Translation>(Allocator.TempJob, out JobHandle jbh1);
        NativeArray<Entity> homeEntityArray = query.ToEntityArrayAsync(Allocator.TempJob, out JobHandle jbh2);

        Dependency = JobHandle.CombineDependencies(Dependency, jbh1);
        Dependency = JobHandle.CombineDependencies(Dependency, jbh2);

        Entities
            .WithReadOnly(world)
            .WithReadOnly(homePosDataArray)
            .WithReadOnly(homeEntityArray)
            .ForEach((ref DummyTestComponentData dtc, in Translation pos) =>
        {
            RaycastInput input = new RaycastInput
            {
                Start = Unity.Mathematics.float3.zero,
                End = new Unity.Mathematics.float3(10, 10, 10),
                Filter = CollisionFilter.Default
            };

            for (int i = 0; i < homePosDataArray.Length + homeEntityArray.Length; i++)
            {
                if (world.CastRay(input))
                {
                    dtc.Value += 1;
                }
            }
        })
            .WithDisposeOnCompletion(homePosDataArray)
            .WithDisposeOnCompletion(homeEntityArray)
            .ScheduleParallel();
    }
}
1 Like

Nice work!!! Thanks so much for verifying that - it’s good to have another person reach the same conclusion. The async versions that @tertle suggested seem to be working well for me.

I don’t mind using the async versions as a fix in 0.50. The thing that bothers me is having to use the async versions (or using this.CompleteDependency()) everywhere - even in systems that have nothing to do with physics. It is really confusing because it can be a perfectly valid system that was working just fine and then suddenly after doing some physics stuff in a totally unrelated system, the previously working system breaks. Or it could be the other way around - you have a working physics system and then you add a new system that uses ToEntityDataArray() and suddenly you’re getting a cryptic physics error that doesn’t reference any of your code except for the new system you just added.

One thing I don’t get…

I’m doing these 3 things for the physics systems:

  • calling this.RegisterPhysicsRuntimeSystemReadOnly() in OnStart().
  • ordering execution to be [UpdateAfter(typeof(BuildPhysicsWorld))]
  • using .WithReadOnly(world) in the Entities.ForEach() call.

Three things that are saying - READ ONLY… I don’t have any desire to write. I just want to see if a ray or aabb box intersects things.

So why is it complaining about writing to Translation anyway???

All the steps you’ve mentioned 1-3 are correct, and you don’t have a problem with that.
Physics systems are writing to a Translation component, and you’re calling .ToComponentDataArray() (which isn’t automatically completing required dependencies), and that is giving you the trouble.

Here’s a repro of the same problem that you’re facing, in simple code.

[UpdateInGroup(typeof(FixedStepSimulationSystemGroup))]
public partial class WriteTranslationSystem : SystemBase
{
    protected override void OnUpdate()
    {
        Entities
            .ForEach((ref Translation t) =>
            {
                t.Value = t.Value + float3.zero;
            })
            .Schedule();
    }
}

[UpdateInGroup(typeof(FixedStepSimulationSystemGroup))]
[UpdateAfter(typeof(WriteTranslationSystem))]
public partial class ReadTranslationSystem : SystemBase
{
    protected override void OnUpdate()
    {
        var query = GetEntityQuery(ComponentType.ReadOnly<Translation>());
        var arr = query.ToComponentDataArray<Translation>(Unity.Collections.Allocator.TempJob);
        arr.Dispose();
    }
}

This also gives you the same error, because ReadTranslationSystem is calling ToComponentDataArray(), without completing the previous dependency, or using an async version.

Just found out, Unity has put a good explanation regarding new dependency management here:
https://docs.unity3d.com/Packages/com.unity.physics@0.50/manual/modifying_simulation_data.html

Hope it will help a future lurker.

1 Like

Yeah it’s a good resource. I quoted from it in an earlier post above.

I think I figured out where I was going wrong. I was thinking that all of my systems that perform raycast and aabb did not write to translation so they are all read-only. However, I just realized that my building-placement system’s foreach does raycasts and it also has a parameter of “ref Translation pos” that is used to clamp the building to the ground. I think that if I removed that system the errors from using ToComponentDataArray (without completing the previous dependency) in my other systems would go away.

Thanks for all your help @papopov !

1 Like

Is there any way to continue using the AddInputDependency/GetOutputDependency?

1 Like