Search Unity

Feedback Suggestions and Questions

Discussion in 'Entity Component System' started by CodeMonkeyYT, Oct 7, 2019.

  1. CodeMonkeyYT

    CodeMonkeyYT

    Joined:
    Dec 22, 2014
    Posts:
    125
    Hey there everyone!

    Over the past few weeks I was studying up on DOTS to prepare for Unite and wrote down a bunch of notes.
    So here's a bunch of Feedback, Questions and Suggestions.
    I'm loving DOTS so far and really looking forward to when it's finally Production Ready.

    First of all what was shown on the Keynote is completely awesome!
    One of the main criticisms of DOTS I've read in comments on my videos has been due to the amount of code that is necessary in order to make something very simple like a moving Sprite
    So I'm really happy to see Unity tackle that problem head on.
    Automatically Jobifying the Entities.ForEach is especially awesome. The way I would normally create a System was always first make the whole logic work with a ComponentSystem and then covert it into a JobComponentSystem. With this change I will no longer need to have two separate steps.

    What are the limitations of the Jobified Entities.ForEach?
    What happens if the job cannot be Bursted?




    Static function to create simple Job for easy testing
    In order to continue reducing the amount of code needed it would be very helpful to have a simple way of creating a simple Job.
    With the new Jobified Entities.ForEach theres a lot of code that no longer needs to be written, however you still need to create a class for a JobComponentSystem
    Having a static function to deal with that would help for quick testing and quick iteration

    Code (CSharp):
    1. JobComponentSystem.CreateJob("TestingComponentSystemName", (inputDeps) => {
    2.    float deltaTime = Time.deltaTime;
    3.    return Entities.ForEach((ref translation, ref velocity) =>
    4.        translation.Value += velocity.Value * deltaTime;
    5.    }).Schedule(inputDeps);
    6. });

    Add CreateEntity version with name parameter just like GameObject
    There is a way to Set a name to an Entity which makes it easier to find in the debugger so it would be great to add that directly into CreateEntity();
    CreateEntity(string name, params ComponentType[] types);


    RequireComponent, RequireComponentTag, ExcludeComponent
    This is a pretty confusing mix of attributes
    Previously in normal MonoBehaviours you had RequireComponent(Type);
    Then in ECS you now have RequireComponentTag(Type);
    And you also have ExcludeComponent(Type);

    The RequireComponentTag(Type) doesn't even really require an empty Tag component, it can filter for any component type.

    I would suggest changing these to:
    RequireComponentECS
    ExcludeComponentECS

    I think that would make more sense and a lot less confusing.


    Debug.Log ECS Systems AutoCreation
    Would be very useful to have a little checkbox where it would enable a Debug.Log on every System creation
    When I went back to researching DOTS 2 weeks ago I first went into the project that I was previously using for testing.
    And when I ran it just started spawning Entities and moving them around.
    I couldn't remember which were the default systems so couldn't identify which ones were running and in what files they were in.
    So a more verbose log system for the entirety of ECS could be a useful addition for debugging
    "World 1 Created"
    "System SystemName Created in World 1"
    "System SystemName (World 1) was destroyed"


    System File Finder
    This would be a great tool. With MonoBehaviours you can only have one in a single script but with DOTS you can have multiple systems written in a single file. That can make it sometimes tough to remember where a specific System is.
    You can see the name in the Entity Debugger so then it would be nice to have a simple search tool that would locate the file that System was in.
    Maybe Quick Search already supports this?


    Mixed Standards and Naming conventions
    For some reason a bunch of DOTS stuff has a completely different Naming convention from everything else.
    In a normal component, like a SpriteRenderer, you have fields like SpriteRenderer.sprite or SpriteRenderer.color
    However in the ECS default components you have Translation.Value or Rotation.Value
    Why is "Value" capitalized?
    And then the RenderMesh has its fields following the normal standard like RenderMesh.mesh and RenderMesh.layer

    The other thing with a weird naming convention is the new Math library
    The class name is lower case and the function names also start with lower case like math.floor();
    I asked this on the Expert bar and the answer I got was in order to maintain compatability with HLSL / GLSL code so I understand the goal with it.

    However would it be possible to have an alias so we could also access it following the same standard? Or would that cause performance issues?
    Something like this:
    Code (CSharp):
    1. public static class Math {
    2.     public static float Floor(float f) => math.floor(f);
    3. }

    Mesh manipulation with NativeArrays
    I've built a bunch of DOTS Rendering systems and one of the bottlenecks is always having to do the final call to mesh.vertices using Vector3[] arrays.
    There's this thread which talks about fixing that to be able to use NativeArrays instead
    https://forum.unity.com/threads/feedback-wanted-mesh-scripting-api-improvements.684670/
    However I didn't hear any more news about it, is it still coming? 2019.3?


    Will Graphics.DrawMesh become possible to use in Jobs?
    Will Graphics.DrawMeshInstanced support more than 1023 instances?



    What is the best practice for setting everything up?
    MonoBehaviour.Start? ComponentSystem.OnCreate?
    Seems like ComponentSystem.Create would be the correct way to go full ECS but won't that cause performance issues by having it stay running? Destroy on ComponentSystem.OnCreate?


    What is the maximum component count in an Entities.ForEach?
    What is the correct procedure if you need more?
    Merge various component fields into one? One component with a sub entity that contains other components?


    Should people be encouraged to mix ECS with MonoBehaviours?
    I asked this question at Unite and the answer I got was that since ECS is still in construction and many features aren't yet done then yes right now mixing the missing features using MonoBehaviours is the way to go.
    In terms of performance if a specific part of your game is running fine then keeping it as MonoBehaviour is fine.
    If on the other hand a MonoBehaviour is causing performance issues then that's a great candidate to convert to DOTS.


    How many components in one Entity is too much?
    Would it be better to have some sort of composition pattern for very large entities?
    Like one entity holds a component which holds an entity that holds all the components related to like a Attack System. Another component pointing to an entity with all components related to Pathfinding, etc.



    DOTS Communication
    In terms of communication I would say you need to really emphasize how GameObjects and MonoBehaviours aren't going anywhere.
    I've seen a lot of comments of people who are terrified that all their games will suddenly stop working because they'll be forced to use DOTS.
    It needs to be clear that if you want to make games like you've always done it will continue to be possible along with a different option for more performance.


    Another issue with communication is about the benefits to regular people.
    For me, I'm a programmer and I love large scale games like RTS and Management games so having code run 100x faster and the ability to have 100,000 units on screen is more than enough to sell me on DOTS.
    However for someone making a simple Platformer or any type of game that doesn't have massive amounts of units the benefits are harder to understand.
    I've heard plenty of times on the Keynote and several talks that one of the benefits is lower battery usage. I'm not too familiar with mobile so not too sure just how appealing that benefit is for the average person.
    And that's not really applicable to someone working on PC or Console games.

    So that always leads to the question "This looks way too complicated, why would I write all this code when it runs fine right now with GameObjects?"

    Maybe emphasize more how faster code allows you to have a lot more terrain objects, props, particle effects, post processing effects or lighting.
    As well as how the final goal is to make it all work with the conversion workflow to really get more performance by default.




    Alright that's my feedback on DOTS so far.
    Really looking forward to 2019.3 and playing around with the 3rd Person Shooter Project especially to look into that Multiplayer code.

    Thanks for reading and keep up the good work!
     
  2. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    Neither... Setup should be driven based on data. If a component exists, code should run, otherwise it shouldn't.
    SubScenes are a good way of loading data into the world.
     
    optimise likes this.
  3. Lucas-Meijer

    Lucas-Meijer

    Unity Technologies

    Joined:
    Nov 26, 2012
    Posts:
    175
    glad you liked it!

    there's a max parameter limit of 8. There's an ordering requirement that by value parameters come first, then by ref, then "in". any other order is a compiler error

    You get a burst compiler error. Then you either change the code to be burst compatible, or you write:
    Code (CSharp):
    1. Entities.WithBurst(false).ForEach((ref Translation t, in Velocity v) => t.Value += v.Value * dt).Schedule();

    I'm parsing this as a request to "give me a low-keystroke way to create a new system that runs one job.
    I don't expect this to come very soon, even though I do think the idea of having a system just be a static method is an interesting route to explore. We have lower hanging convenience features to do first though, and I'd also be a bit reluctant to add to the "here's yet another way you can do something" pile.

    Popular C# IDE's all have a "find all" feature, where you type a few letters of the system you're looking for, and it will take you right there. Is that workflow not working for you?


    Good point. not sure if we'd still be happy to change it at this point, but I agree it's not consistent.


    It wouldn't cause performance issues, but would add some ambiguity / confusion. People would be asking "ok which one should I use", we say "it doesnt matter!", they say "then why are there two things that do the same thing?!" we say: "there was this guy that preferred an uppercase version :)"


    None of these are my area of expertise. I would however recommend in the next release to take a look at the hybrid rendering package. A lot of work last few months has been going on to make exactly this workflow be performant and comfortable. (the workflow of "do all work in dots, but have Graphics.Draw* and friends be able to consume that data in a performant wa)

    Our -still-in-flux-because-we-learn-ourselves- recommendation is to do an initialization system. There is some valid concern around "but then I have a system that runs all the time while it only has to do something once". There is non-0 overhead for such a system today, but we are very eager to get the per-system overhead down dramatically, especially for systems whose entityqueries do not match on anything, so they don't have to do any work.
    I've been doing some experimentation into code hotreload. When I tried it out on a example games, the games that used an initialization system worked well out of the box, but the games that did it somehow on game load, they actually all initialized the game again when the code reload happened :).

    Today it's 8. Correct procedure to get more is to show up here with a reasonable usecase where 8 doesn't cut it.
    (The reason there's a limit of 8 is that we have to do some c# wrangling to get this syntax to work, which requires creating a ton of delegate types. Having many of these can slow down IDE's / Tools / Compilers, so I've been a bit careful to not add too many right out of the gate).

    As a fallback method, you can always go back to writing a manual IJobChunk, however when you get used to the nice syntax, it's hard togo back.

    It really depends. For productions that start from 0, and that want to use DOTS, we recommend doing all simulation (physics/networking/animation) in dots, and use the hybrid renderer. If you have a game that is already written, and you want to use a bit of dots here and there, there is nothing wrong with that, but it really depends on your game.
    In general the annoying thing is you have to move the data you want to operate on from the gameobject world into dots, and then often you need to move it back. How feasable that is depends on how easy/correct you can extract data, how easy you can move it back, etc.

    There is no golden rule for this. We like to approach a data oriented mindset to questions like these, which basically come down to "what is smart data design for my problem". First thing about which data operations need to happen.
    and then figure out a way to lay out your data to make those operations be fast.

    Roger. Agree we should do better here. Game Objects and MonoBehaviours aren't going anywhere, and nobody is going to make you write dots code yourself. In fact, at the date of this writing, we recommend that if GameObjects/MonoBehaviours let you write the game you want to write, then you should use that. The only people we recommend to give dots a shot, is if you are really really eager to get the functionality in dots, and it's basically the only reasonable way to make the project you want to make.

    The biggest benefit for most people is that the buiding blocks they build their game on (DOTS, Dots game engine features, asset store packages) become a lot faster.


    Thanks, we really appreciate it, keep the feeedback coming.
     
  4. sschoener

    sschoener

    Joined:
    Aug 18, 2014
    Posts:
    73
    I'm not sure about Graphics.DrawMesh (it's not in the 2019.3 beta) but the Mesh class got a bunch of new overloads that allow you to set vertices, colors, etc. from a NativeArray. Find them here. Specifically:
    Code (csharp):
    1. public void SetBoneWeights(NativeArray<byte> bonesPerVertex, NativeArray<BoneWeight1> weights);
    2. public void SetColors(NativeArray<T> inColors);
    3. public void SetIndexBufferData(NativeArray<T> data, int dataStart, int meshBufferStart, int count, Rendering.MeshUpdateFlags flags);
    4. public void SetIndices(NativeArray<T> indices, MeshTopology topology, int submesh, bool calculateBounds, int baseVertex);
    5. public void SetNormals(NativeArray<T> inNormals);
    6. public void SetTangents(NativeArray<T> inTangents);
    7. public void SetUVs(int channel, NativeArray<T> uvs);
    8. public void SetVertices(NativeArray<T> inVertices);
    9. public void SetVertexBufferData(NativeArray<T> data, int dataStart, int meshBufferStart, int count, int stream, Rendering.MeshUpdateFlags flags);
    10.  
    plus a variant that allows you to set a start and length parameter additionally to only use a slice of the array.
     
    CodeMonkeyYT likes this.
  5. runner78

    runner78

    Joined:
    Mar 14, 2015
    Posts:
    792
    Normally public fields not allowed by C# conventions. Public member like (static) fields, properties and methods always capitalized, includes also protected member. Protected fields/properties like m_myName are not allowed.
     
  6. CodeMonkeyYT

    CodeMonkeyYT

    Joined:
    Dec 22, 2014
    Posts:
    125
    I get that for static scenes, like you would build the entire level, place all the enemies and then just load the Subscene.
    However if I'm making a game that is a like a Roguelike with a procedurally generated map then I have to generate that map somewhere.
    Speaking of that, what would be the correct way to generate something like that during run-time? Create GameObjects and use the Conversion System to convert them into Entities or create the Entities directly?
    I have a lot of questions about how the Conversion System works which I guess will all be answered when I can finally look at the 3rd Person Shooter game.

    That does work, completely forgot about it. Part of the issue was also that I didn't know which systems were mine and which were default. Double clicking the Entity Debugger and have it open the script or show its location in the project files would be nice.

    Oh awesome! Haven't touched the beta so didn't know about that, seems like it solves all my issues.
     
  7. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    4,269
    What he is saying is that a system could respond to a query of all entities with a RequestProceduralMap component and for each one, build the procedural map. The RequestProceduralMap component would have some or all of the entity prefabs, sizes, and other constraints and parameters needed by the algorithm.
    Don't use GameObjects. You can either have a little back and forth between the main thread with EntityManager for instantiating prefabs and jobs for running the generation algorithms and initializing values, or you could use EntityCommandBuffer, or you could use ExclusiveEntityTransaction with a custom staging world.