Search Unity

Tying Systems to Scenes

Discussion in 'Data Oriented Technology Stack' started by Enoch, Oct 11, 2019.

  1. Enoch

    Enoch

    Joined:
    Mar 19, 2013
    Posts:
    189
    I am pretty new to ECS so perhaps I am not thinking correctly about the problem and how it should be solved in an ECS way. But I really want to tie my Systems to certain Scenes in Unity. This seems logical to me, why would I want my startup Scene Systems running while I am in my Game Scene, etc.

    Perhaps I should think of Systems as more expressly tied to Data but even still, there is likely data that is only in the Startup Scene and not in the Game Scene and vice versa. Why run systems on data that I know wont be present.

    Has anyone else had an issue with managing Systems (when and where they should run)?

    To accomplish this it looks like I really should declare all of my systems [DisableAutoCreation] and then in the Start() method of a monobehavioir attached to the Scene manually insert the systems I want. I am not precisely sure how to do this but roughly I think I just need to get SimulationSystemGroup from World.Active and then just do a SimulationSystemGroup.AddSystemToUpdateList for all systems (or more likely SystemGroups) that I want to add to the scene.

    As an aside I am not sure I really like the whole instantiate every system from the assembly as the default way of doing things. It means that if any asset creator implements a system, that system is running in my scene whether I declare it to or not. Just by way of adding something from the asset store to the project its now running in all active scenes.I think I would have rather had something more explicitly declared.
     
  2. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    5,743
    There are no DOTS asset yet on asset store. So that is not really an issue at current state.

    I think you current issue is, that you stil think OOP rather than data oriented. Systems dont work on scene basis. They got own execution loop.

    There is however GameObject to entity conversion workflow. Scenes can be converted to entities like prefabs. See for example megacity demo.

    If you really need keep separate entities, you can create worlds. Still any of entity matching system query, will execute. But worlds will keep entities apart.
     
  3. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    498
    I plan to release a framework in the next couple of weeks that solves the proposed problems quite elegantly. It allows systems to determine whether or not they should run based on which scene they are in. Entities can be destroyed or stashed when the scene changes. There is also a mechanism for declaring which systems run where in your loop. You can declare everything explicitly using hierarchical instantiation, or you can declare individual namespaces or assemblies to auto-inject. You can even mix and match.

    It works using an ICustomBootstrap that adds some scene management smarts into the world, and then provides an API for building the world.
     
  4. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    1,720
    I have a similar system but I specifically avoided forcing the use of ICustomBootstrap as to not hijack it so they can use their own.

    Having spent some time writing custom packages/plugins, support for multiple ICustomBootstrap would actually be very handy.
     
    Last edited: Oct 12, 2019 at 8:07 PM
  5. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    498
    I mimic the default initialization's detection of custom bootstraps in my custom bootstrap and hand over control to the other bootstrap if one exists. This is the only way I expose the custom world gen API on startup, otherwise it just uses a default behaviour of auto-injecting everything that contains "Unity" in the namespace or is one oftwo base class types the framework defines. I haven't figured out a way to detect ping-pong loops without the use of a static variable yet.
     
  6. Enoch

    Enoch

    Joined:
    Mar 19, 2013
    Posts:
    189
    This sounds good, I will be interested in seeing how you do this. I took a look at ICustomBootstrap I had issues with the fact that I still can't define a bootstrap that will only run in a given scene. You're right I could probably do this with some static data but I just didn't want to do it that way, I'd rather just manually handle it the scene and have ICustomBootstrap kill everything that is mine (so I can manually insert them later).
     
  7. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    498
    I don't have a ICustomBootstrap per scene. Instead I have a mechanism to turn on or off ComponentSystemGroups based on what scene is active among other possible criteria.
     
  8. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    1,720
    So this was my 'simple' solution for a package I created where I wanted to completely rebuild systems for a few separate demos.

    Code (CSharp):
    1.         /// <summary>
    2.         /// Initializes the vision system onto a world, replacing any existing systems.
    3.         /// </summary>
    4.         /// <param name="world">The world to initialize on.</param>
    5.         public void Initialize(World world)
    6.         {
    7.             var visionGroup = GetEmptyGroup<VisionGroup>(world);
    8.  
    9.             // Create and initialize all our vision systems
    10.             var systems = new List<ComponentSystemBase>();
    11.             this.Initialize(world, systems);
    12.  
    13.             // Add our systems to the vision group
    14.             foreach (var system in systems)
    15.             {
    16.                 visionGroup.AddSystemToUpdateList(system);
    17.             }
    18.  
    19.             visionGroup.SortSystemUpdateList();
    20.         }
    21.  
    22.         private static T GetEmptyGroup<T>(World world)
    23.             where T :ComponentSystemGroup
    24.         {
    25.             var group = world.GetOrCreateSystem<T>();
    26.  
    27.             // Remove existing vision systems so we can re-create them
    28.             var existingSystems = group.Systems.ToArray();
    29.             foreach (var system in existingSystems)
    30.             {
    31.                 group.RemoveSystemFromUpdateList(system);
    32.             }
    33.  
    34.             // Required for destroyed systems to be removed, works for this, might not work for you
    35.             group.Update();
    36.  
    37.             foreach (var system in existingSystems)
    38.             {
    39.                 world.DestroySystem(system);
    40.             }
    41.  
    42.             return group;
    43.         }
    44.  
    this.Initialize(world, systems) is where your systems are created. It was actually setup this way with the system list so it could also be used in ICustomBootstrap

    This is actually within a settings file for a ScriptableObject and can just be called in MonoBehaviour.Start(), letting you use different settings files per scene.

    I'm actually curious if someone has a cleaner way to remove a set of systems (from a group) and recreate them. I wrote this specific setup quite a while ago now so not sure if anything has changed/improved.
     
    florianhanke likes this.