Execution Order

Hey,

I can’t seem to find anything about the order of execution when working with Monobehaviours and System at the same time.

I have a Monobehaviour that needs to do some Spherecasts (I’m using the dots physics) at the start of the game.
When I try to do it in the Start function it seems that the entites haven’t been converted yet.
I then tried just waiting for 1s before running the SphereCast function and it worked fine.
Is there a recommended or good way to wait for things like the entities to convert, before running a Monobehaviour function I would normally run through Start?

I also tried calling the function from OnCreate of one my systems, but then Awake hasn’t run yet and the singletons aren’t initialized yet.
Using a coroutine delay works but seems quite hacky.

Thanks for any help :slight_smile:

There isn’t a built-in way to do so, but most robust way I found is to run Update / other callbacks after ECS simulation.
This can be achieved by creating a custom manager which runs via SystemBase system. Order of which is set to be after SimulationGroup.

E.g.

using Unity.Entities;

namespace EntitiesExt.SystemGroups {
   /// <summary>
   /// Update group that runs in the simulation group, but after all ECS system / jobs ran / scheduled.
   /// This is done in PreLateUpdate
   /// Use this one for the hybrid / MonoBehaviour bridged systems
   /// </summary>
   [UpdateInGroup(typeof(SimulationSystemGroup), OrderLast = true)]
   [UpdateAfter(typeof(EndSimulationEntityCommandBufferSystem))]
   public class AfterSimulationGroup : ComponentSystemGroup { }
}

So in your case it would be best to wait for conversion to complete, then run ECS update, and run MonoBehaviour Update afterwords in AfterSimulationGroup.

TL;DR:

  • Queue up an entity from MonoBehaviour either via conversion or manually. (Attach your MonoBehaviour script via EntityManager.AddComponentObject(this) or via conversion). Plus add some component tag to filter already initialized entities.
  • Run an initialization (spherecast) system with logic you need in AfterSimulationGroup with .WithoutBurst().Run();
  • Remove tag via query or ECB;

This will align execution order without hacks. And if you’d need to run MonoBehaviour logic from ECS side, you can implement any system in AfterSimulationGroup just fine. E.g. query filtered callbacks / notifications, direct update logic etc.

I’ve got entities extension / hybrid utility for this type of cases, and it simplifies usage of both MonoBehaviours and Entities in the same project. Though it doesn’t use conversion, and relies on authoring entities from MonoBehaviours instead. Which is a bit slower, than conversion workflow, but much more user-friendlier to use (relies on generation of archetypes in editor and generating entities from archetypes in runtime). And it already has custom update manager with other utilities. I’ll upload it github at some point if interested.

You can check the entire PlayerLoop in the System window, basically what happens every frame is the following:

InitializationSystemGroup.OnUpdate
MonoBehaviour.Update
SimulationSystemGroup.OnUpdate
MonoBehaviour.LateUpdate
PresentationSystemGroup.OnUpdate

For the initialization, I am not totally sure as I never needed to debug it, but I think the following is true:

SubsystemRegistration
SystemBase.OnCreate
BeforeSceneLoad
MonoBehaviour.Awake
AfterSceneLoad
MonoBehaviour.Start

If I am not mistaken, the conversion process occurs inside the InitializationSystemGroup. If so, then yes, it happens after Start gets called.

1 Like

MonoBehaviours spawned via Update / Coroutines etc would run callbacks before conversion happens, so that is why this is an issue. (And also before ECS physics ran / initialized)

Thanks for both of your answers.
I’m sorry my reply comes so late.

I just implemented that and it’s working perfectly.
Hadn’t seen AddComponentObject before, so thank you very much.

1 Like