Search Unity

make use of Single UpdateOrder attribute instead of 3 ones

Discussion in 'Entity Component System' started by JesOb, Mar 20, 2019.

  1. JesOb

    JesOb

    Joined:
    Sep 3, 2012
    Posts:
    1,109
    Hi

    For now most of the times we need to use 3 attribute on each system to make shore it update in right order.

    Why not create one single Attribute like [UpdateOrder(...)] which will do all the thngs like:

    Code (CSharp):
    1. [UpdateOrder(typeof(InitializationSystemGroup), After = typeof(blah), Before = typeof(blah))]
    So After and Before will be optional.
    But I think most of the times users will set all 3 fields, so constructor with all fields will be good.

    And Seconds question.
    Too many times I dont want to specify ApdateAfter and Update before but to function correctly I need UpdateJustAfter and UpdateJustBefore most of the times. So for UpdateJustAfter(typeof(SpawnMobSystem)) my system will update as close as possible to SpawnMobSystem in contrast with UpdateAfter that can place my system to be last in group.
     
  2. M_R

    M_R

    Joined:
    Apr 15, 2015
    Posts:
    559
    1)
    [UpdateBefore]
    and
    [UpdateAfter]
    can be specified multiple times

    2) you can create your own group and put your systems in there
     
  3. JesOb

    JesOb

    Joined:
    Sep 3, 2012
    Posts:
    1,109
    2) Not solve actual problem at all :)

    1) What use case for specify UpdateBefore/After multiple times?
     
  4. M_R

    M_R

    Joined:
    Apr 15, 2015
    Posts:
    559
    1) you want system A to be before/after both B and C, but you don't care about order between B and C (either because they process different data, or they belong to different packages that don't know about each other)

    2) yes if you put in your group only the systems that should run together and not anything else.
    when your group run it runs all of its system, with nothing else that can run between them.
    e.g: you have group G in simulation, with A and B in it, and C also in simulation.
    when sim runs, it update G and C and everything else (in an arbitrary order, constrained by attributes)
    when G runs, it updates A and B (in your order defined by [UpdateAfter(A)] in B or the opposite)
    C and everything else runs either before G or after G => nothing can happen between A and B unless it's explicitly put inside G.
     
  5. JesOb

    JesOb

    Joined:
    Sep 3, 2012
    Posts:
    1,109
    1) Ok now I understand :)
    There my wish is to have UpdateOrder once and additional UpdateBefore/After if you need

    2) This work only with very few systems and create abnormal amount of nested groups

    For example I have ShootingGroup and there is about 10 system in it and they dont care about other systems.
    So i want to add some view and network systems inside and I can not (and dont want) create new group just for ordering.

    I know that after BulletSpawnSystem I need to insert ViewBulletSpawnSystem and I dont want to care about other systems inside
    Just want to say

    [UpdateJustAfter(typeof(BulletSpawnSystem))]
    ViewBulletSpawnSystem {...}

    and most of the time ViewBulletSpawnSystem will be just after BulletSpawnSystem and nothing inbetween.

    Today ViewBulletSpawnSystem need to know more about systems in loop and their relative order to put correct UpdateBefore and UpdateAfter attributes
     
  6. M_R

    M_R

    Joined:
    Apr 15, 2015
    Posts:
    559
    and why your ViewBulletSpawnSystem depends on nothing else running between it and BulletSpawnSystem?
    it should not matter if something unrelated runs in between. else you have implicit dependencies and that's bad.

    you can also have one system scheduling 2 or more jobs if you need strict coupling.

    also what happens if you end up with many system that have [UpdateJustAfter(typeof(BulletSpawnSystem))]? you ask for [UpdateJustJustAfter(typeof(BulletSpawnSystem))]?
     
  7. Virtuactions

    Virtuactions

    Joined:
    Jun 5, 2017
    Posts:
    13
    You can use multiple attributes in one [ ] pair:
    [UpdateInGroup(typeof(bla)), UpdateAfter(typeof(blabla)), UpdateBefore(typeof(blablabla))]
    I don't see big difference.
     
  8. JesOb

    JesOb

    Joined:
    Sep 3, 2012
    Posts:
    1,109
    This is not possible for systems like BulletSpawn and BulletSpawnView, just because they in separate assembiles

    Typical case for this:
    You have main game systems that create core of your game.
    that you want to place additional system inside a loop:

    System A
    System B
    System C

    When I want to add system A_a I want just do something with data create in system A_a and want it before any changes to that data no matter who will made it.
    So I need ability to say RunAfterA but before anything else that run after A in default loop e.g. RunJustAfter A.

    I can not say Run After A and Before B because B is not dependency. Dependency is any system that now or in future will be in place of B. If in future B and C will swap their order or there will be new system between A and B in default ordering I dont want to care about this and support all systems that was inserted JustAfter A.

    If I want few systems that must run JustAfter A than I dont care their relative order or I want to manually say somehow what order they need to be. The systems can both be from different AssetStore Packages and I want to chage their relative order on my end. For example Particle system and AssetStore modules that came from some packages their relative order matters.
     
  9. YuriyVotintsev

    YuriyVotintsev

    Joined:
    Jun 11, 2013
    Posts:
    93
    I think that if any system must start "JustAfter" other system, then this is one system, not two.
     
  10. JesOb

    JesOb

    Joined:
    Sep 3, 2012
    Posts:
    1,109
    Simple example:

    BulletSpawnSystem
    BulletSpawnViewSystem
    BulletSpawnNetworkSend

    View must execute as close as possible to actual spawn system but it can not be one system just because View and Data is separate Modules of a game and on server side View does not exist at all.

    Same with network. Data must have no dependencies on network only network know data so it in separate Assembly too and can not be in same assembly or same system.
     
  11. YuriyVotintsev

    YuriyVotintsev

    Joined:
    Jun 11, 2013
    Posts:
    93
    I just don't understand why BulletSpawnViewSystem or BulletSpawnNetworkSend must update JustAfter BulletSpawnSystem. What bad will happen if any systems updates inbetween?
     
    M_R likes this.
  12. JesOb

    JesOb

    Joined:
    Sep 3, 2012
    Posts:
    1,109
    There can be system that destroy spawn message and View and Network never see it.
    And anything else similar

    Whet I first time try to setup systems I has exactly this issue.
    System that suppose to update after actually had it update after but in the end of frame and just nothing work on that point
    I have to spend few hours to create (ghost)dependencies so systems have right update order.
     
  13. M_R

    M_R

    Joined:
    Apr 15, 2015
    Posts:
    559
    it would make more sense to force-put the destroy system last instead. or at the beginning of next frame

    btw I would organize my temp components/entities such that they are either:
    - commands: created by anyone, read and processed by a specific system and destroyed by it
    - events: fired by a specific system, read by anyone and destroyed by the owner in the next frame. this way that all system see all events for exactly one frame

    unrelated systems should not destroy stuff they don't own (or read other systems' commands)

    example:
    Code (CSharp):
    1.  
    2. public struct SpawnCommand : IComponentData { prefab, position, count }
    3. public struct SpawnEvent : IComponentData { spawnedEntity }
    4. class SpawnSystem:[Job]ComponentSystem {
    5.  
    6. OnUpdate() {
    7. ForEach(SpawnEvent => destroy it);
    8. ForEach(SpawnCommand => {spawn bullet, emit SpawnEvent});
    9. }
    10. }
    11.  
    12. OtherSystems... {
    13.  
    14. OnUpdate() {
    15. ForEach([readOnly] SpawnEvent => react to it);
    16. if (...) create SpawnCommand;
    17.  
     
  14. YuriyVotintsev

    YuriyVotintsev

    Joined:
    Jun 11, 2013
    Posts:
    93
    Agreed with M_R.
    Another aproach: you can create CleanupSystemGroup and add there all systems that destroy any commands.
    Coding convention is essential thing. It is bad practice to destroy and create stuff all around the code, no matter OOP or ECS you are using.