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

Preview 26, Component systems and hybrid ecs just lost alot of expressiveness

Discussion in 'Entity Component System' started by kstothert, Mar 5, 2019.

  1. kstothert

    kstothert

    Joined:
    Dec 8, 2016
    Posts:
    68
    Losing all the common sense ways of accessing data like GetComponenetDataArray and GetEntityArray is really dissapointing. To me performance by default shouldn't have to come at the cost of less expressive and boilerplate heavy code. I realize alot of code was being run in the background everytime people used those methods/data structures and I also realize that it often came with performance hits that weren't obvious. But I think it's necessary to create a dead simple way of writing ECS that can be performance enhanced later on while not impeeding a rapid development process. It's not always ideal to be focusing on the complexities of managing jobs when all you really want to do is figure out how to solve a problem in ECS that you could do blindfolded in OO. It's not enough just to create the most performant data oriented ecosystem, Unity also has to build a path that leads it's pilgrams from the darkness of OOP. The way to do that is to sell them on the merits of ECS first and leave the rest of the performance focused parts of the tech stack as something folks can grow into.

    Async await has the potential to resolve alot of these issues and make learning and using multithreaded jobs a breeze. If they haven't already, Unity engineers should take a look at the remarkably composable and expressive code that the open source web community has written using redux-saga's. This model of composing async code feels like a really good fit for the dependency management side of jobs.

    I also want to add that ECS is big enough now that more complete documentation feels critical, most of the preview packages such as the SRP and visual effects graph can be learned through experimentation but something like ecs deserves some really thoughtful documentation and more relatable examples.

    upload_2019-3-5_20-36-2.jpeg
     
    futurlab_peterh likes this.
  2. Piefayth

    Piefayth

    Joined:
    Feb 7, 2017
    Posts:
    61
    Can't you replace those calls 1:1 with ComponentGroup.ToComponentDataArray()?
     
  3. Ryetoast

    Ryetoast

    Joined:
    Mar 8, 2015
    Posts:
    48
    I actually found using those arrays cumbersome and I'm glad they are going away. Scaffolding like IJobProcessComponentData is way easier to read and faster to work with.

    The main issue I have is that chunk iteration is a lot more painful than it should be right now. Having to essentially declare the same set of data 4 times in order to make an IJobChunk really kills it (once for the ComponentGroup, once to pass in the type accessors, once to actually hold the accessors in the job struct, and once more to access the arrays from the chunk).

    The 2018 LA unite video talking about the evolution of the API talks about all these issues though, so they are aware of it, and hopefully will be able to find cleaner solutions.
     
    futurlab_peterh and Cynicat like this.
  4. kstothert

    kstothert

    Joined:
    Dec 8, 2016
    Posts:
    68
    well you have to dispose and the only alternative for transformAccessArray or sharedComponentDataArrays are job systems
     
  5. Mordus

    Mordus

    Joined:
    Jun 18, 2015
    Posts:
    174

    How would that work with job component systems? I've only had a brief fiddle with this so i may be wrong but in order to actually change anything you need to read that back out of the array to the componentgroup using copyfromcomponentdataarray. So you can't modify any data in the job and have subsequently chained jobs see the modified data without first having to sync back to the main thread somewhere to copy out the data (and also dispose the array). Whereas with componentdataarrays you just created the array, gave it to the job and wrote to it.
     
  6. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    Cynicat likes this.
  7. kstothert

    kstothert

    Joined:
    Dec 8, 2016
    Posts:
    68
    Doesn't that have a 3 component limitation? and does it work as a hybrid solution?

    The ideal i'm rooting for is a single, simple, and idiomatic approach that works in all cases even if it isn't necessarily the most performant. Again just as a pathway for developing solutions in ECS and learning the data oriented approach.
     
  8. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    ForEach is exactly that approach. For what you want, it's what we recommend.

    It has up to 6 components. Supports dynamic buffer, class based as well as struct based components.
    We are soon coming out with improved syntax for defining the queries in C# fluent style.

    If we are missing specific overloads you'd like to see, we will add more.
     
    kstothert likes this.
  9. Mordus

    Mordus

    Joined:
    Jun 18, 2015
    Posts:
    174
    i may be out of the loop, i haven't checked in on ecs for a few versions now.
    what are class based components? i thought the whole premise was that components are all value types.
     
  10. kstothert

    kstothert

    Joined:
    Dec 8, 2016
    Posts:
    68
    he's just saying the new IComponentData and Monobehaviours are supported with the foreach approach. Which makes them an ideal hybrid ecs solution.
     
  11. Vanamerax

    Vanamerax

    Joined:
    Jan 12, 2012
    Posts:
    937
    I think he meant monobehaviours or builtin components when using hybrid ECS
     
  12. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,554
    EntityManager.SetComponentObject <- This method became public for a while ago. You can get your MonoBehaviour to be ECS component. Various conversion also migrate all your mono to ECS as class component.
     
  13. BanJaxe

    BanJaxe

    Joined:
    Nov 20, 2017
    Posts:
    47
    Looks like it's still internal to me? Only Add/Get are public.
     
  14. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,554
    Oh right, the Add just became public. Set is pointless as you can Get then modify things since it is a class/reference type.
     
  15. vitautart

    vitautart

    Joined:
    May 3, 2018
    Posts:
    29
    I like new way. As for me I like more explicit code (boilerplate as you say) then implicit magic like Inject (I never use this, when I had alternatives), and therefore I appreciate new more clear way of doing things with only NativeArray without tons of magical arrays like EntityArray, ComponentDataArray etc. Just my taste.
     
  16. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    EntityManager.AddComponentObject is public now.
     
    pahe likes this.
  17. yossi_horowitz_artie

    yossi_horowitz_artie

    Joined:
    Jan 30, 2019
    Posts:
    87
    Isn't it a problem, though, that when ForEach is used a new delegate is allocated on the managed heap during each `OnUpdate()` call? (You can, of course, cache the delegate in `OnCreateManager()`, but since that's not the approach the sample code is taking, I'm wondering if it's not as big a deal as it seems.)
     
  18. Ryetoast

    Ryetoast

    Joined:
    Mar 8, 2015
    Posts:
    48
    Things that happen once a frame have to be quite expensive to really become much of an issue in the grand scheme of things. It's also possible that the compiler could optimize this out from being an issue in the first place. I believe this falls under the category of "write it the readable and clean way, then optimize if profiling shows it's needed."
     
  19. Vanamerax

    Vanamerax

    Joined:
    Jan 12, 2012
    Posts:
    937
    What I gathered earlier from @Joachim_Ante's comments in other threads and the Unite talks, the delegates get compiled down to direct function calls by the compiler. So there is probably no managed memory or garbage collector involved at all here, although Joachim will probably be able to tell the finer details of it.
     
  20. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    That is not what ForEach does right now. But that's the plan. We want ForEach to be high performance in the long run.
     
  21. M_R

    M_R

    Joined:
    Apr 15, 2015
    Posts:
    558
    @Vanamerax delegates are compiled as methods with no GC if they don't capture local variables (e.g. don't do
    var dt = Time.deltaTime; ForEach((...)=> {use dt});
    ).

    but there is no way currently to enforce that at compile time
     
  22. Chiv

    Chiv

    Joined:
    Mar 6, 2014
    Posts:
    10
    I need a quick clarification regarding ForEach -> It is only useable from
    ComponentSystem
    , not
    JobComponentSystem,
    correct? So all the talk in this thread about ForEach and how it simplifies things is only for MainThread systems and not Job based ones, am I getting this right?
     
  23. sngdan

    sngdan

    Joined:
    Feb 7, 2014
    Posts:
    1,131
    Yes. (IJobProcessComponentData... is kind of the equivalent for JobComponentSystem)

    Although, I would find it beneficial if they also enabled ForEach in JobComponentSystem - I forgot what it was, but I had a case, where I wanted to use it in preparation for a 2nd job that started after calling complete on the previous one
     
  24. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    The concept is this.

    ComponentSystem is about writing convenient ECS code.
    JobComponentSystem is about writing highly optimized code.

    If your goal is to write performant code, don't use ComponentSystem. Main thread code by definition of that it processes things only on one core is not performant.

    There is nothing wrong with writing simple & convenient code, not all code has to be highly optimized. Clearly Unity users have shipped big games using almost exclusively main thread code. It's a choice.

    If you prefer convenience use ComponentSystem and ForEach. But we want keep the API's very clear that in JobComponentSystem the default is writing performance by default code. So that those who want to write performant code have a path with no performance traps.
     
  25. sngdan

    sngdan

    Joined:
    Feb 7, 2014
    Posts:
    1,131
    Yes, I completely get that.

    The reason I asked was only for convenience as there are some things that currently only work on the main thread, say you have a JCS with the update loop:
    Job1 (expensive) & complete
    Main Thread code (depends on job 1)
    Job 2 (expensive)


    No one stops me from doing this today, I just have to use chunk iteration instead of ForEach

    - - -

    But this is not a pressing issue - this was more an observation