Search Unity

Only run a system when all of its [Inject] are satisfied?

Discussion in 'Entity Component System' started by 5argon, May 24, 2018.

  1. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,555
    Currently the system does not run when there are no entity match in all [Inject]s. But if even one struct group was injected the system will run with other unmatched injects having length 0.

    My current problem is I have some entities holding very important data (game states, deltaTime for everyone, etc.) that is going to be almost always available. And now there are some system which I want them to only run when a certain component tags are attached to my other entities.

    That entity runs all the time since I have 2 [Injects] and one of them is always available. What I do is I always have to explicitly check the length of the second one should it really continue the system or not but I would prefer if the system automatically AND 2 injects together in the first place. How do you approach this problem?

    I tried removing the always occurring [Inject] out, and use GetComponentGroup inside the OnUpdate logic instead. It works only before the first OnUpdate trigger, then from that point it *seems* like GetComponentGroup somehow adds to the system's Inject permanently and does not stop running ever again? (Like I have 2 [Inject] in the first place, only delayed. Things works according to my wish until after the first OnUpdate)

    (I think about `ISharedComponentData` before, but it seems to be for sharing the same data for many entity and for a "rarely changed" data as the doc says, but this data changes in every frame.)
     
    Last edited: May 24, 2018
    S_Darkwell and starikcetin like this.
  2. JooleanLogic

    JooleanLogic

    Joined:
    Mar 1, 2018
    Posts:
    447
    I'm curious as to what is a good design pattern for storing global data as well. Whether we should store it in Components and inject into every system or whether it's better to store it in static classes or injected systems.

    Injecting the same group into every system feels a bit like multiple inheritance. It effectively keeps all systems on all the time.
    But then maybe storing settings in components is the best way for working with the job system mechanics?

    In any event, I agree that it might be useful to have ability to require all groups before running a system. I have systems which process a parent group and a related child group. In some cases if there's no parents, there's no point iterating the children so it would be useful to be able to specify that criteria on injection groups.
     
    5argon and S_Darkwell like this.
  3. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,555
    By the way what's working right now for me is to access the global data not via Inject, but by remembering its Entity ID on a static variable then I could use `EntityManager` built in variable in `ComponentSystem` to access it while in `OnUpdate`, (run when system already triggered) without adding to the system activation requirement.

    And in the latest 0.0.6 build I could use `ArchetypeChunkArray` to get the data without static variables from outside without affecting system activation, making the system more modular.

    I blogged both ways in more details here : https://medium.com/gametorrahod/unity-ecs-the-system-is-always-running-ed3cdd60f885

    Anyways seems like touching anything related to `ComponentGroup` magically makes the system "Inject" the group forever. Both static entity ID and ACA avoids that BUT with that I believe the automatic dependency management would not work anymore against the type I "cheated". Really needs an inject-based way to do this?
     
    Last edited: May 25, 2018
    vanxining likes this.
  4. LazyGameDevZA

    LazyGameDevZA

    Joined:
    Nov 10, 2016
    Posts:
    143
    I haven't really looked into this myself, but I suspect putting this global state in a SharedComponent should suffice. This way you won't be requiring two different arrays to be injected, but rather only one, which if there aren't any entities it will be ignored.
     
  5. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    Right now the recommended approach is to simply have an early out at the beginning of the OnUpdate function if your requirement is that all injected groups must be present.
     
    vanxining and 5argon like this.
  6. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    GetComponentGroup caches the component on a per system basis and thus enabling / disabling. same with injection.

    The default behaviour is that if any component group has entities, then the system will run. Also if there are no groups injected it will run (In order to ensure GetComponentGroup calls in OnUpdate dont prevent the system from ever running). (I dislike this, so we might disallow GetComponentGroup calls in OnUpdate - which for performance is a good rule to have anyway)


    The behaviour works well for 95% of all code, at least our samples. If it doesn't then the right approach is to simply

    [AlwaysUpdateSystem] on the system to make it always execute and then have manual early outs checking the exact requirements you have for running the system manually at the top of to OnUpdate method.

    I don't think you should use CreateArchetypeChunkArray in this case, its overkill and a workaround since it doesn't create a component group.
     
    wang37921, psuong, vanxining and 2 others like this.