Search Unity

Proper way to destroy systems

Discussion in 'Entity Component System' started by Fido789, Aug 6, 2018.

  1. Fido789

    Fido789

    Joined:
    Feb 26, 2013
    Posts:
    343
    At the level unloading I would like to remove level only systems from the world, something like this:

    Code (CSharp):
    1.         private void OnDestroy()
    2.         {
    3.             foreach (var system in systems)
    4.             {
    5.                 world.DestroyManager(system);
    6.             }
    7.  
    8.             ScriptBehaviourUpdateOrder.UpdatePlayerLoop(world);
    9.         }
    But I am getting this exception

    Code (CSharp):
    1. NullReferenceException: Object reference not set to an instance of an object
    2. Unity.Entities.ComponentSystemBase.BeforeUpdateVersioning () (at C:/.../com.unity.entities@0.0.12-preview.8/Unity.Entities/ComponentSystem.cs:140)
    3. Unity.Entities.ComponentSystem.BeforeOnUpdate () (at C:/.../com.unity.entities@0.0.12-preview.8/Unity.Entities/ComponentSystem.cs:263)
    4. Unity.Entities.ComponentSystem.InternalUpdate () (at C:/.../com.unity.entities@0.0.12-preview.8/Unity.Entities/ComponentSystem.cs:290)
    5. Unity.Entities.ScriptBehaviourManager.Update () (at C:/.../com.unity.entities@0.0.12-preview.8/Unity.Entities/ScriptBehaviourManager.cs:82)
    6. Unity.Entities.ScriptBehaviourUpdateOrder+DummyDelagateWrapper.TriggerUpdate () (at C:/.../com.unity.entities@0.0.12-preview.8/Unity.Entities/ScriptBehaviourUpdateOrder.cs:734)
    It looks like Unity tries to run the removed systems once again.

    So what is the proper way to remove systems from the world?
     
  2. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    Generally speaking removing systems is something i wouldn't be doing based on level load. The presence of components drives whether or not a system runs.

    This should work correctly though. We'll take a look at this exception.
     
  3. Fido789

    Fido789

    Joined:
    Feb 26, 2013
    Posts:
    343
    What is very unclear to me in ECS is how to handle things like for example level settings and how to pass them to the systems. You know, all the "singleton" objects.

    I have implemented a factory class that creates the systems and injects (through the contructor) dependencies like level settings to them. But naturally such a system should live only through the level and no longer, that is why I am trying to destroy it. (Well, on second thought this probably isn't the correct way.)

    The other way could be to have an entity with the LevelSettings component, but it means writing much more code than what I was used to:
    Code (CSharp):
    1. [Zenject.Inject] LevelSetting levelSettings;
    In your TwoStickShooter example you use a static class for settings, but static class is not probably something you would like to use in a real game.

    So how would you "inject" things like level settings to the system in some scalable and maintenable way?
     
  4. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,778
    I wouldn't say my answer is the best approach, but I would simply have system class, with static properties, of which you assign relevant values, when level is started/restarted/ended.
     
  5. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    >So how would you "inject" things like level settings to the system in some scalable and maintenable way?
    Use an entity with component data on it.
     
  6. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,761
  7. Fido789

    Fido789

    Joined:
    Feb 26, 2013
    Posts:
    343
    I am not going to use static properties.

    Yes, I am using similar approach, but now I am not sure about it. As I wrote above, with constructor injection I would need to create/destroy systems with level loading and it doesn't seem too effective.

    Well, I will probably do so. I generally like the idea of ECS to "let the systems pick what they need", it is just that for such a simple (single) things it feels like a hack.
     
  8. Xisor

    Xisor

    Joined:
    Jan 30, 2016
    Posts:
    8
    Problem is still here in 21 preview. Deleting a system causes an exception in the next player loop update, when this system is accessed from the native. System is disposed but looks like native had not cleared an update hook registration for it. Player loop updates correctly inside the `
    ScriptBehaviourUpdateOrder.UpdatePlayerLoop(world);`.
     
  9. julian-moschuering

    julian-moschuering

    Joined:
    Apr 15, 2014
    Posts:
    529
    I had a similar problem when destroying a world during the PlayerLoop resuling in some systems still getting updates for the current frame. My workaround for this was to set all the systems to Enabled=false before deleting the world.
     
  10. cort_of_unity

    cort_of_unity

    Unity Technologies

    Joined:
    Aug 15, 2018
    Posts:
    98
    As of earlier this year, systems are no longer added directly to the player loop; instead, they're part of the ComponentSystemGroup hierarchy. If you really want to destroy an individual system at runtime (and I agree with Joachim that this should not be a common use case), the component system group hierarchy will continue to attempt to update it, and you'll get an exception about the system already being deleted. The next release of the Entities package (preview33) will include the necessary function,
    ComponentSystemGroup.RemoveSystemFromUpdateList()
    , which (unsurprisingly) removes the specified system from the group & prevents it from participating in further updates. The system can then be safely destroyed.
     
  11. mikaelK

    mikaelK

    Joined:
    Oct 2, 2013
    Posts:
    284
    But how do I do this?
    I'm writing a plugin that support both entities and gameobjects and I'm creating the system in a way that its easy to use and works similar to the gameobjects. Under the hood it does ecs stuff so for example settings are added outside the ecs componensystem component.

    so if I call.
    Code (CSharp):
    1. plugin.EntityWorld.DestroySystem((ComponentSystemBase) targetinginstruction.TargetingSystemEntities);
    How do I use the:
    Code (CSharp):
    1. ComponentSystemGroup.RemoveSystemFromUpdateList()
    Because it say I cannot use it outside the static context meaning I guess that I should get reference to the object else where.
     
  12. GameDeveloper1111

    GameDeveloper1111

    Joined:
    Jul 24, 2020
    Posts:
    100
    World.GetOrCreateSystem
    will give you a reference.

    For example, you could use
    initializationSystemGroup = World.GetOrCreateSystem<InitializationSystemGroup>();
    in the
    OnCreate
    method, and then call
    initializationSystemGroup.RemoveSystemFromUpdateList(systemToBeDestroyed);
    and then
    World.DestroySystem(systemToBeDestroyed);


    GetOrCreateSystem
    works because:

    upload_2021-2-15_20-28-57.png