Search Unity

When are systems not running?

Discussion in 'Entity Component System' started by Cell-i-Zenit, Jan 18, 2020.

  1. Cell-i-Zenit

    Cell-i-Zenit

    Joined:
    Mar 11, 2016
    Posts:
    290
    Hi,

    I have a strange problem currently: If i uncomment some code in SystemA, it somehow makes SystemA and SystemB not running anymore.

    I wonder what needs to happen to "deactivate" a JobComponentSystem..

    I used the OnUpdate() Method from JobComponentSystems to have basic "Update" logic like in the old monobehaviour days.. sometimes executing a job when its needs, but i wonder now if this is the way to go if sometimes the system is not running anymore...
     
  2. RoughSpaghetti3211

    RoughSpaghetti3211

    Joined:
    Aug 11, 2015
    Posts:
    1,709
    As far as I know if a query does not find anything a system will not run , are you using filters ? Or removing entities ?
     
  3. Cell-i-Zenit

    Cell-i-Zenit

    Joined:
    Mar 11, 2016
    Posts:
    290
    I have code like this:

    Code (CSharp):
    1. protected override JobHandle OnUpdate(JobHandle inputDeps){
    2.     if(OtherSystem.ValueA > 0){
    3.         inputDeps = Entities.ForEach( xx => yy).Schedule(inputDeps);
    4.     }
    5.  
    6.     return inputDeps;
    7. }
    Is something like this not intended?
     
  4. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,555
    It's unconventional to refer to other systems in the code. (*except on UpdateBefore/After) Does work or not should depends on solely data availability. Your pattern above could be replaced by a singleton entity solely written from that other system, then this system GetSingleton and check it. It may sounds involving and roundabout to write now but it's more "in line" and reduce other problems.

    System running or not depends on its registered EntityQuery. If no EQ registered then it always run. You should check with Entity Debugger. Check show inactive system in the world dropdown. Then see the inactive system why it didn't activate.

    There are 2 kinds : implicit and required/explicit. If you have even 1 required, it overshadows all implicit ones.

    When on implicit : when one EQ among those matches then system updates.
    To register implicit EQ : Use GetEntityQuery (Usually in OnCreate, so it is kind of the definition of system), or with Entities.ForEach which add to the implicit list at runtime because they stay in OnUpdate. So if you write a system with only ForEach, then the first update is an empty implicit 100% update then when it hit ForEach first time it is added to implicit list. Then next update would require more conditions. (If you put your ForEach in if(false) for example, then that ForEach would never be added to the implicit list)

    When on required : all required must match before the system could update. Ignores all other implicit EQ.
    To register required EQ : RequireForUpdate / RequireSingletonForUpdate

    RequireForUpdate uses EntityQuery. If you already used ForEach and would like to turn that ForEach into a "required" level, you can take the EQ out with .WithStoreEntityQueryInField then use it with RequireForUpdate. (It appears to work even in OnCreate, where the system hadn't update even once yet. So this WithStoreEntityQueryInField seems to contain some compiler magic in it?)

    Your case above could be implemented by having prior system make entity with tag ValueAOverZero available or destroy it and then this system use RequireSingletonForUpdate<ValueAOverZero> so there is no need for early out in your update. It depends on your game if singleton entity create/destroy worth it or not.
     
    Last edited: Jan 19, 2020
  5. Cell-i-Zenit

    Cell-i-Zenit

    Joined:
    Mar 11, 2016
    Posts:
    290
    First of all thanks for your answer

    Iam trying to do this now. I setup an entity as a singleton. My systems now run perfectly fine when the singleton exists.

    I now wonder how i can remove such a singleton now. If i do

    Code (CSharp):
    1. EntityManager.DestroyEntity(GetSingletonEntity<LerpSingleton>());
    The code throws an error:

    InvalidOperationException: GetSingleton<Assets.Classes.LerpSingleton>() requires that exactly one Assets.Classes.LerpSingleton exists but there are 0.

    EDIT: i feel like since this code is happening in the middle of the frame, that other systems that will execute later, will still run since the singleton existed at the start of the frame ... is there a way to stop executing other systems when the singleton got destroyed?

    EDIT2: this singleton api is pretty S***ty..

    I get this error:

    Code (CSharp):
    1. InvalidOperationException: Trying to get iterator for Assets.Classes.SingletonFlags.WeatherSingleton but the required component type was not declared in the EntityQuery.
    2. Unity.Entities.EntityQuery.GetIndexInEntityQuery (System.Int32 componentType) (at Library/PackageCache/com.unity.entities@0.5.0-preview.17/Unity.Entities/Iterators/EntityQuery.cs:531)
    3. Unity.Entities.EntityQuery.GetSingleton[T] () (at Library/PackageCache/com.unity.entities@0.5.0-preview.17/Unity.Entities/Iterators/EntityQuery.cs:825)
    But i created the entity in the on create method like this:

    Code (CSharp):
    1. protected override void OnCreate()
    2.         {
    3.             RequireSingletonForUpdate<WeatherSingleton>();
    4.  
    5.             EntityManager.CreateEntity(typeof(WeatherSingleton));
    6.            
    7.             SetSingleton(new WeatherSingleton(Weather.CreateSunWeather(), Weather.CreateSunWeather()));
    8.         }
    I dont know what iam doing wrong here
     
    Last edited: Jan 19, 2020
  6. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,555
    The API help ensure you have 1 entity that match such query so destroying like that will not work the 2nd time when it is already destroyed. What I do is always keep the singleton entity around with component A but rather tag/untag additional tag component B. The system that perform the tag/untag (singleton's "owner") should have require A. Other "users" of the singleton have require B and stop working accordingly when the singleton is untagged.

    I have a music player of sorts with this pattern. A singleton entity is attached with TransportControl. Then I could additionally attach Playing/Paused/Forwarding/Rewinding then a system that deal with playing (e.g. add delta time normally each frame) has require singleton <Playing>. No system refer directly to TransportControl component except the system that could add remove additional tags.

    I think there is a bug introduced in 0.5.0 for singleton. A fix is probably coming so you should downgrade to 0.4.0 for now.
     
    Last edited: Jan 19, 2020
  7. PublicEnumE

    PublicEnumE

    Joined:
    Feb 3, 2019
    Posts:
    729
    what 5argon is telling you is good advice. Please don’t take this comment as a counter to it. But it’s interesting to note that Unity itself breaks this pattern with EntityCommandBufferSystems. Their established pattern with those is to directly refer to those systems from other systems, and to call AddJobHandleForProducer() on them to conditions like their behavior.

    the Singleton approach also won’t work if the data you need to store won’t work in an IComponentData format (such as an array or other collection).
     
    Last edited: Jan 19, 2020
  8. Cell-i-Zenit

    Cell-i-Zenit

    Joined:
    Mar 11, 2016
    Posts:
    290
    Thanks. This is a nice idea. I will try to switch to such a version.