#Order of Job Scheduling vs Non-Job Systems

1 messages · Page 1 of 1 (latest)

winter nexus
#

Having an odd issue where I have two systems setting the LocalTransform scale. However, the first system to execute always seems to overwrite the last one.

What I'm trying to do:

  • Clear all mouse-hover circles
  • Show hovering circle for the one entity (hover circle) closest to the mouse cursor

https://paste.mod.gg/etwlvnynbyuw // Latest version
(Screenshots also added for highlighting)

I've divided this into two systems (Screenshots 1 & 2). One that quickly executes on all entities with a job. The other system uses an EntityQuery and a loop to determine which entity is closest and should show the circle.

Basically, one system can freely parallel-operate all entities, while the other has to compare them all and will only change one. It seems to make sense to keep them separate.

The latter system calls EntityManager.SetComponentData to overwrite the changes supposedly done by the earlier job for a single one of those entities. I've also attempted using an ECB here to perform this change at the EndSimulationEntityCommandBufferSystem.

While writing this I've found my best guess to be that the automatic Job Dependency doesn't take EM and ECB component calls into account, and that the scheduled jobs are executed later than the second system.
https://docs.unity3d.com/Packages/com.unity.entities@1.0/manual/scheduling-jobs-dependencies.html
(To be fair, the second system is executed right after the first one, but again ECB usage didn't seem to fix it)

The systems' OnUpdate calls are happening in the correct order. This I've confirmed with logs, and the entity profiler (Screenshot 3). I've also added UpdateBefore and UpdateAfter attributes to ensure this.

So I'm wondering what would be a good way to approach this:

  1. Make the second system use a job and count on the automatic job dependencies.
  2. Combine the two systems and complete the "clearing" jobs before setting the single "hover" circle.
  3. Combine the two systems and make both operations use jobs. Set the first job as a dependency of the first.
  4. Find a way to store the first system's job handle. On the second system, get the handle and ask the job to complete. If so, what's a good way of doing this?
  5. Avoid changing the same property in multiple systems.

(I should probably space out these systems in time so there's more time for the first jobs to finish before I have to force complete them)

Am I missing something obvious? 😅 If not, any inputs on which approach is better and maybe some tips on how to achieve it? I'll appreciate any insights into the ECS "best practices" while I'm learning and testing things.

#

Option 6: I should probably not create jobs to set a single property to 0 and another flag to false. Probably better to just run a ForEach. But for the sake of practice and learning, if we assume the process hypothetically warrants the use of Jobs.

winter nexus
#

I'm no longer sure what's happening PepoThink I attempted option 4 by storing the job handle in a static field so I could reach it from the second job. I'm calling complete while stile in the first system's OnUpdate. Then in the second system, double-checking that it's completed, which it is. But the circles are still invisible (scale = 0).

I don't know how to best get the job handle since most overloads just return void. I provided the SystemState.Dependency and then I got a handle in return. Is this ideal?

Basically, if the jobs have completed their work, what else could it be?

The rendering system should be reading the LocalTransform after the entire Simulation Group has completed all work, right?

hollow timber
#
  1. You must understand that systems and jobs are independent in terms of executing and updating. The only link between them is the dependency chain passed through SystemState.
  2. In the OP, your system works the way you code them. But what you actually want is not that code. If you want the code of OnUpdate2 depends on the result of the Job1 scheduled in OnUpdate1, you have to move the code of OnUpdate2 into Job2. And pass the state.Dependency into Job2.Schedule (if Job2 is not IJobEntity).
#
  1. Or, if you don't want to make Job2, you have to move the code from Job1 back into OnUpdate1 and use idiomatic foreach to loop through your entities.
hollow timber
#
  1. To understand point (4), you have to understand that IJobEntity is code-gened and when you schedule it inside a system, that system's code will be rewritten and the state.Dependency will be passed into the job.Schedule call for you, automatically.

These 2 code blocks are the same, they will be rewritten either way:
1.

public void OnUpdate(ref SystemState state)
{
    new MyEntityJob().Schedule();
}
public void OnUpdate(ref SystemState state)
{
    state.Dependency = new MyEntityJob().Schedule(state.Dependency);
}
#

If you remove the keyword partial from your system and your IJobEntity, and get a compiler error, you'll know that there is code generation behind the scene.

winter nexus
#

Thanks for the insights. I appreciate that. So basically don't mix and match OnUpdate and IJobEntity for overlapping purposes.

I ended up solving it by doing all the scaling in class 1, and using an enableable component to message from class 2 which ones is the hovered ones and which aren't. So It still got both Job and non-Job execution but opting for my option 5.

Fyi, I'm aware that there's code gen, but I don't intend to dive into the details of that as the Unity ECS is already a mouthfull, but good to know the bit about the dependency being injected. I'll remember that.

hollow timber
#

If I'm not very wrong, the updated document in v1.3+ should cover things you really should know.

winter nexus
#

Gotcha, I'll keep using that version from now. Seems I've been reading on the 1.4, but I'm using 1.3.14 in my project after all PepoThink
Thanks for all the help.