Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

How to run a custom world only?

Discussion in 'Entity Component System' started by gilley033, Jun 9, 2019.

  1. gilley033

    gilley033

    Joined:
    Jul 10, 2012
    Posts:
    1,181
    I want to completely avoid using the Default World with its default systems/system groups, and instead use a custom world which I manually add Systems to.

    This custom world has three System groups, "Pre Sim", "Physics Sim", and "Render Sim". The Physics Sim needs to be able to be run multiple times per frame, which I believe is going to require me manually update the system groups.

    So, is this attainable with the current ECS API? I have read some stuff about using multiple Worlds in addition to the Default World, but that is not what I want to do. I just need one World, but have it be the only one that is running.

    Here is some code of what I have so far (no errors, but it is not actually working):
    Code (CSharp):
    1. void InitializeBeforeSceneLoad()
    2. {
    3.     //DefaultWorldInitialization.Initialize("MyCustomWorld", false);
    4.     _world = new World("MyCustomWorld");
    5.     World.Active = _world;
    6.     PlayerLoopManager.RegisterDomainUnload(OnDomainUnloadShutdown, 10000);
    7.  
    8.     OnRegisterSystems();
    9.     ScriptBehaviourUpdateOrder.UpdatePlayerLoop(null);
    10. }
    11.  
    12. void OnRegisterSystems()
    13. {
    14.     preSimGroup = _world.GetOrCreateSystem<PreSimGroup>();
    15.     preSimGroup.AddSystemToUpdateList(RegisterSystem<InfiniteBubbleSpawnerSystem>());
    16.      
    17.     physicsSimGroup = _world.GetOrCreateSystem<PhysicsSimGroup>();
    18.     physicsSimGroup.AddSystemToUpdateList(RegisterSystem<TickPreperationSystem>());
    19.     //...more systems added
    20.     updatePhysicsStateSystem = RegisterSystem<UpdatePhysicsStateSystem>();
    21.     physicsSimGroup.AddSystemToUpdateList(updatePhysicsStateSystem);
    22.  
    23.     renderSimGroup = _world.GetOrCreateSystem<RenderSimGroup>();
    24.     renderSimGroup.AddSystemToUpdateList(RegisterSystem<UpdateRenderPositionSystem>());
    25.     //...more systems added
    26. }
    27.  
    28. T RegisterSystem<T>() where T : ComponentSystemBase
    29. {
    30.     var system = (T)_world.CreateSystem(typeof(T));
    31.     //system.Enabled = false;
    32.     return system;
    33. }
    34.  
    35. void Update()
    36. {
    37.     preSimGroup.Update();
    38.  
    39.     while (updatePhysicsStateSystem.PhysicsState != PhysicsState.Asleep)
    40.         physicsSimGroup.Update();      
    41.  
    42.     renderSimGroup.Update();
    43. }
    All of this code is in a MonoBehaviour.

    Thank you for any help!
     
    Last edited: Jun 9, 2019
  2. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    You don't need to make the world.active if you want to manually tick it.

    1. ScriptBehaviourUpdateOrder.UpdatePlayerLoop(null); is also unnecessary

      Other than that it should work. But of course for any systems to run you need to create entities into the world for them to react to.
     
  3. gilley033

    gilley033

    Joined:
    Jul 10, 2012
    Posts:
    1,181
    Thanks! I set World.Active to my world simply so that other Systems can easily access it when creating EntityCommandBufferSystems or getting other systems. I do create entities, I just forgot to include that. The entities show up in the debugger so I am sure they are being created. I ran a simpler test and showed that with this setup the systems do run, so there must be an issue somewhere else. It is nice to know I was on the correct path.
     
  4. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    ComponentSystem.World is the correct API for use inside a system.
    World.Active is not.
     
  5. gilley033

    gilley033

    Joined:
    Jul 10, 2012
    Posts:
    1,181
    Okay, so I believe I figured out what was going on, and will post this information because I think it could be helpful in the future.

    When creating my systems and adding them to the ComponentSystemGroups, I was using the World.CreateSystem method. This is fine for regular Systems, but not for EntityCommandBufferSystems, as it seems Unity automatically creates these and you need to use the automatically created ones. If you try to use CreateSystem with an ECB system, you'll create a duplicate that does not work properly.

    So the solution is to use the "GetOrCreateSystem" method
     
  6. gilley033

    gilley033

    Joined:
    Jul 10, 2012
    Posts:
    1,181
    Okay, thanks! I will correct that mistake, however since I am only running one world, I believe using World.Active shouldn't have introduced any bugs, right? Since ComponentSystem.World and Active.World should be the same world.
     
  7. gilley033

    gilley033

    Joined:
    Jul 10, 2012
    Posts:
    1,181
    Okay, so I am having another issue. I'm not sure if it's an issue with using a custom world but I'll post it here first to see if someone else had this problem.

    I am trying to add a tag component (empty IComponentData) to a set of entities within a ComponentSystem. This tag tells other systems that these entities need to be moved. These other systems are using IJobForEach with the RequireComponentTag attribute.

    I have tried adding the "tag component" multiple ways:

    using EntityManager.AddComponent(EntityQuery, ComponentType),
    using EntityCommandBuffer.AddComponent(EntityQuery, ComponentType),
    using PostUpdateCommands(Entity, IComponentData).

    I am not sure, but I surmised that EntityManager and PostUpdateCommands did not work because I am manually updating my systems, and perhaps these systems are not run in this scenario (which makes total sense). So I decided using a EntityCommandBufferSystem and EntityCommandBuffer might work, since I can manually update these.

    When I debug the number of components on each entity before and after the system that is run which is responsible for adding the tag component, the number of components does correctly go up by one, leading me to believe the tag is being added correctly.

    However, I have some Debug Systems that are designed to print messages when specific components are detected on entities, in this case I print a message for each entity that has the tag component. These are not being triggered, leading me to believe the tag is not being added.

    And also, the systems that have the RequireComponentTag do not run.

    I also tried removing the RequireComponentTag and adding the component tag directly to the IJobForEach generic parameters, and that does not work either.

    Anyone have any experience with this particular problem?

    I do know that the system that is responsible for adding the tag is 100% running, as well as the other systems.
     
  8. gilley033

    gilley033

    Joined:
    Jul 10, 2012
    Posts:
    1,181
    As a follow up to my last post, I believe I figured out the problem. I was running my "world" manually by adding systems to three unique Component Groups and then calling Update on the groups. The systems were added via the AddSystemToUpdateList method, and I assumed that the order of addition was maintained during the update cycle.

    However, that does not appear to be the case. You have to control the order via the UpdateBefore/UpdateAfter attribute on the systems.
     
    Last edited: Aug 19, 2020