Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Question How to change execution order of systems from scripts

Discussion in 'Entity Component System' started by carlos_truong, Aug 31, 2023.

  1. carlos_truong

    carlos_truong

    Joined:
    May 9, 2023
    Posts:
    38
    Hi everyone,

    I have numerous systems in my hobby project and their functionality relies on specific execution order. Currently, I'm using the attributes: UpdateInGroup, UpdateAfter, and UpdateBefore to manage their execution order. But then my game logic frequently requires changing the execution order. So, how can I adjust the execution order of systems through scripts using Unity ECS?

    There are many features in games that require constant changes to the execution order of systems, and I think many of you have encountered this issue before. How do you guys deal with it?
     
    LingoCreator likes this.
  2. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,294
    If the question is about reordering in runtime / during gameplay:
    Short answer - you can't [without hacks].

    Separate systems & groups can be updated manually, though its a bit more complicated.
    Real question is - what are you trying to do? Cause I don't think constant changes is required in any game to be honest.

    Approach problem from a different side. What kind of data you can't sort into proper order by using single system?

    Otherwise - custom bootstrap is the way.
    But its more complicated as you kinda loose attribute ease of use.
    Its easier to group logic per feature together, then order groups vs groups.
    Also, use minimum logical requirements instead writing down all requirements for the system for the attributes.
     
    Last edited: Aug 31, 2023
  3. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    3,993
    This is how I personally deal with it:
    https://github.com/Dreaming381/Lati...ore/Super Systems.md#explicit-system-ordering

    An example of what this actually looks like:
    https://github.com/Dreaming381/lsss...Code/SuperSystems/GameplaySuperSystems.cs#L60

    In this style, the order listed is the order updated, and I only use attributes to position the base groups relative to unity and other library systems:
    https://github.com/Dreaming381/lsss...Code/SuperSystems/LsssRootSuperSystems.cs#L41
     
  4. carlos_truong

    carlos_truong

    Joined:
    May 9, 2023
    Posts:
    38
    Sorry if my English is bad, I'm not a native English speaker. Perhaps you guys have misunderstood me.

    For example, my AI Monsters have many abilities, each of these abilities will be handled by a dedicated AbilitySystem and they will be executed in an order like: AbilitySystem1, AbilitySystem2, AbilitySystem3, AbilitySystem4...
    But sometimes they will be executed in another order, for example, AbilitySystem2, AbilitySystem1, AbilitySystem4, AbilitySystem3, ... based on their internal state and external conditions.

    This requires constant changes to the execution order of these ability systems.
    How do you guys handle this situation?
     
    Last edited: Aug 31, 2023
  5. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,294
    A few options:
    1. If abilities are "OOP" based typed abilities - don't split them into separate systems.
    Handle them as a "decision tree".
    - Use megastruct for the ability data (store everything in the same struct);
    - Add sort key per "ability";
    - Sort all running abilities;
    - Process them one-by-one;
    Generate decisions based on type / huge switch inside the same job.
    (or use something like Polymorphic structs)
    - Move actual "do something" logic to the systems after decision making system.

    Performance wise if its not the most demanding path - it wouldn't matter.
    And probably would be faster since less scheduling - more work compared to lots of systems per each separate ability.

    2. Hacky way:
    - Make a custom group;
    - Override OnUpdate;
    - In OnUpdate use custom sorting algorithm or call manually Update on each added system.
    (See ComponentSystemGroup.UpdateAllSystems() sources).

    3. Rewrite it as DOD order independent systems.
    Logic shouldn't depend on each other. It should depend on data only.
    That means either your systems are coupled, or data isn't defined well enough to determine order of execution.
    There are plenty of examples and thoughts how to do ability system on the forum.
    Search for unity dots ability system or skill system.

    1 & 3 is the easiest ones to do in the long run.
    Maintaining proper system ordering with lots of abilities would be a real pain.
     
    carlos_truong and Richay like this.
  6. Laicasaane

    Laicasaane

    Joined:
    Apr 15, 2015
    Posts:
    293
    System ordering can't be changed once the world is fully initialized and running. We don't deal with it because there was hardly a reason to do this. Everything should be decided upfront.

    Don't do this. If you are thinking in "System1, ... , SystemN", then you're doing it wrong. Most of these abilities can be generalized into common data structures and logic. Try doing this instead.

    Don't belittle yourself. Your English is OK.
     
    xVergilx and carlos_truong like this.
  7. carlos_truong

    carlos_truong

    Joined:
    May 9, 2023
    Posts:
    38
    Hi, xVergilx

    Thanks for your solutions!
    I will try your option 1 & 3

    1. So to implement option 1, I need to make a DecisionMakingSystem to decide which AbilitySystem will be run after that and the running order will be like this, right?
    DecisionMakingSystem -> Other AbilitySytems

    3. Do you know any resources about this? I couldn't find any posts in this forum that can help me handle my case. It seems that no one needs to change the execution order of systems after the game runs like me :(
     
    Last edited: Sep 1, 2023
  8. carlos_truong

    carlos_truong

    Joined:
    May 9, 2023
    Posts:
    38
    Hi Laicasaane,

    Thanks for your advice.
    I will try to re-design my systems.
     
    Last edited: Sep 1, 2023
  9. Laicasaane

    Laicasaane

    Joined:
    Apr 15, 2015
    Posts:
    293
    In ECS the design of your data really matters. You have to put serious thoughts on them before anything else. Whatever data structures you come up with will determine the design of your systems later on.

    Re-analyze the abilities to find out all of necessary data. Ask the questions like "What does this ability really do? What are its behaviours? Which are the input and output data to each behaviour?" etc to extract information out as much as you can. Some abilities might also be a combination of multiple simple ones, don't hesitate and break them down into simpler pieces of data.

    Let's study a fairly simple case:

    A "Dash" requires a direction, a speed, the current position, a duration, an ID for the animation, and a delay before triggering the actual translation logic.

    A "Slash" also requires a direction, a speed, the current position, a duration, an ID for the animation, and a delay before triggering the actual damaging logic.

    You see, the seemingly unrelated abilities turn out to share the same initialization and animation systems.

    You can go further and say that "Dash can also damage the surrounding upon arrival", and "Slash can also move the character a bit towards that direction". With some components added, you can totally unify the systems for those 2 (and more) abilities. At that, you will hardly need any specialized like "DashSystem", "SlashSystem", etc.

    Of course, not everything can be generalized. When that time comes, you will need other strategy then.
     
    Last edited: Sep 1, 2023
    carlos_truong likes this.
  10. dreed-sd

    dreed-sd

    Joined:
    May 24, 2022
    Posts:
    1
    I think it should be possible to dynamically control system order. I agree with all the comments on this thread that there is rarely a reason to do so, but there are always exceptions. System attributes are convenient, but in general they should be convenience over programatic methods, not the only way, unless there's a good reason why not. A game that employs dynamic interpreted scripting might have a need to inject systems in a particular order based on the scripts that exist. Or there could be tooling that allows for fine tuning at runtime to optimize workflows.
     
    carlos_truong likes this.
  11. carlos_truong

    carlos_truong

    Joined:
    May 9, 2023
    Posts:
    38
    I agree with the opinion of @dreed-sd. It's more flexible if we can control the execution order of systems after the game runs, although such cases are rare. Not all logic can be designed in an order-independent way. And it often takes much more time to design systems like that. Moreover, not every member of a team can handle these cases well. Sometimes the system design will be overly complex, over-engineering and making it hard to maintain simply due to bad handling.

    In my opinion, in cases where the harm of changing the running order of systems is small and within our control, why not do so?
    I think the engine should be more flexible, it doesn't need to be so rigid like that.
     
    Last edited: Sep 4, 2023
  12. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    3,993
    I'm not a huge fan of Unity's attribute-based ordering, which is why I wrote my own workflow. So I agree that there should be more lower-level scaffolds that are better supported. However...
    This is a terrible idea. Unless you can heavily constrain the inputs and outputs of your scripting, your scripts should be dispatched by a single system that schedules a single-threaded job. You'll run into pain otherwise.
    Optimization in this case is choosing to not run systems, not change the order. And we already have good tools to do that (and I've even added more).
    In that case, you should design a single static order which works for your game.
    While I generally agree with this sentiment, all of the use cases proposed are quite bad and will only result in pain. So for today, the reason is that it is a double-barreled foot gun and no one who has shown to be capable of using the gun properly has asked for this feature.

    I suggest you instead describe the problem you are trying to solve in detail, and we may be able to provide solutions that don't result in foot injuries.
     
  13. carlos_truong

    carlos_truong

    Joined:
    May 9, 2023
    Posts:
    38
    Thank you guys for taking the time to answer my question!

    I've solved my problem by adding a DecisionMakingSystem. It works well for me right now.

    But I still think that hard-coding the execution order at compile-time and not being able to change it at runtime is not a good pattern. It's too rigid.
    I will return to this thread after I encounter other cases related to the running order of systems.
     
  14. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,594
    You new to think about performance, and what system actually does behind the scene.

    There is scheduling mechanism for jobs.
    And this scheduling somehow sorts parallel jobs based on duration of jobs and other aspects, to get optimal performance. Some magic low level stuff.

    Switching orders of systems in a runtime, would ruin you performance.

    What you need instead, define which system run before and after other systems. And which one can run in parallel with others. Put them in groups. And you can set orders that way.
     
    carlos_truong likes this.
  15. carlos_truong

    carlos_truong

    Joined:
    May 9, 2023
    Posts:
    38
    Thanks for your good answer!

    I haven't thought about the problem of the systems with parallel jobs yet.
    What I want simply is a way to change the order of the systems that only run on the main thread.

    It's not a big deal, right?