Search Unity

Official API usability

Discussion in 'Entity Component System' started by Adam-Mechtley, Sep 4, 2018.

  1. Deleted User

    Deleted User

    Guest

    I was talking about replacing Array.Empty. Sorry, didn't get you that time. Now I see what do you mean.
     
    sirxeno likes this.
  2. Ofx360

    Ofx360

    Joined:
    Apr 30, 2013
    Posts:
    155
    Hmm, i'm not getting errors when i did this:

    Code (CSharp):
    1. ComponentGroup updateGroup;
    2.  
    3. protected override void OnCreateManager()
    4. {
    5.     updateGroup = GetComponentGroup(new EntityArchetypeQuery()
    6.     {
    7.         All = new ComponentType[] { typeof(Position) },
    8.         Any = new ComponentType[] { typeof(HitBox), typeof(HitBoxType) }
    9.     });
    10. }
     
  3. SamOld

    SamOld

    Joined:
    Aug 17, 2018
    Posts:
    333
    My apologies, I posted a while ago with some suggestions and said that I would post a full repo of where I was going with it, then I disappeared. I got drawn towards other projects, sorry. Would it still be useful for me to put that up? I'd have to tidy up the code and throw a README together which I would be happy to do, but it may be too late to be worth discussing more radical changes now?

    To recap, the API I was proposing was basically a re-work of an old design for my own C# ECS framework. It relies heavily on generics and allows systems to look something a little like the following, with component read/write permissions being compile-time errors. This example system may contain embarrassing bugs.

    Code (CSharp):
    1.  
    2. class SnapNearestAgentToCursor : ComponentSystem
    3. {
    4.     // Only runs when the system is first enabled. Sets up phases, which run every frame.
    5.     // Phases are minimal bits of code to which dependencies are scoped.
    6.     // Jobs are completed when a phase needs them to be, rather than the whole system.
    7.     // This allows for (slightly) more overlap.
    8.     protected override void OnEnable(InitialisationContext setup)
    9.     {
    10.         var inputSystem = this.FetchSystem<InputSystem>();
    11.         float2 cursorPos;
    12.         NativeArray<EntityKey> nearest = new NativeArray<EntityKey>(1);
    13.         // Phase with no component dependencies.
    14.         setup.Phase().Build(() =>
    15.         {
    16.             cursorPos = inputSystem.GetProjectedCursorPos();
    17.             nearest[0] = EntityKey.Null;
    18.         });
    19.         // Any dependencies that are writing to the relevant entities' Position component get completed before this.
    20.         setup.Phase().WithGroup<Included<AgentTag>, Included<Moveable>, Readable<Position>>().Build(agentsGroup =>
    21.         {
    22.             float nearestDistSqr = float.PositiveInfinity;
    23.             foreach (var agent in agentsGroup.Entities)
    24.             {
    25.                 var distSqr = (agent.Read<Position>().pos - cursorPos).LengthSquared;
    26.                 if (distSqr < nearestDistSqr)
    27.                 {
    28.                     nearest[0] = agent.Entity;
    29.                     nearestDistSqr = distSqr;
    30.                 }
    31.             }
    32.         });
    33.         // Dependencies reading from only the single relevant entity's Position component get completed before this.
    34.         setup.Phase().WithGroup<Included<AgentTag>, Included<Moveable>, Writeable<Position>>(from: nearest).Build(agentsGroup =>
    35.         {
    36.             foreach (var agent in agentsGroup.Entities) agent.Write(new Position(cursorPos));
    37.         });
    38.     }
    39. }
    40.  
     
    Last edited: Nov 14, 2018
    noio likes this.
  4. simsoll

    simsoll

    Joined:
    Aug 28, 2017
    Posts:
    1
    I think the data-oriented design of the ECS is really nice. However, I have a few suggestions on how to create ComponentSystems in a simpler way. My main pain points are
    • The use of inheritance which leads to “protected override void” in every method signatur, which can be hard to grasp for a beginner. I havn’t read all things related to the current ECS implementation, so I don’t know if using inheritance somehow is the key to “make it work”.
    • OnUpdate has a lot of boilerplate with setting filters, getting data out of the group, define shared data used across all items in the group and iterating over each item in the group.
    • You are forced to thinking in “groups”, but I think it’s more intuitive and simple to think in term of each how each entity should be updated and then let Unity do the handling of groups behind the scenes.
    My solution to these pain points are under the assumption that you will only use data for index “i” when updating item “i”. I havn’t seen any examples that breaks this assumption, so I think it’s safe to assume.

    Instead of inheriting from ComponentSystem when creating a ComponentSystem I instead suggest to implement the following interface

    Code (CSharp):
    1. public interface IComponentSystem<TEntity, TSharedData>
    2. {
    3.     public ISharedComponentData Filter();
    4.     public TSharedData SharedData();
    5.     public void OnUpdate(TEntity entity, TSharedData sharedData);
    6. }
    An implementation of this interface could look like the following

    Code (CSharp):
    1. public struct PlayerMovementEntity
    2. {
    3.     [ReadOnly]
    4.     public Rigidbody Rigidbodies;
    5.  
    6.     // made-up class, should implement IComponentData
    7.     public InputComponentData Input;
    8. }
    9.  
    10. public struct SharedData
    11. {
    12.     public Time DeltaTime;
    13. }
    14.  
    15. public struct SharedGrouping : ISharedComponentData
    16. {
    17.     public int Group;
    18. }
    19.  
    20. public class PlayerMovementSystem : IComponentSystem<PlayerMovementEntity, SharedData>
    21. {
    22.     public ISharedComponentData Filter()
    23.     {
    24.         return new SharedGrouping { Group = 1 };
    25.     }
    26.  
    27.     public SharedData SharedData()
    28.     {
    29.         return new SharedData {DeltaTime = Time.deltaTime};
    30.     }
    31.  
    32.  
    33.     public PlayerMovementEntity OnUpdate(PlayerMovementEntity entity, SharedData sharedData)
    34.     {
    35.         // do something with the entity using deltaTime and return it
    36.     }
    37. }
    Behind the scenes Unity could take implementations of IComponentSystem and do all the wirering to make the system work. Something like the following

    Code (CSharp):
    1. public class ComponentSystemManager<TEntity, TSharedData> : ComponentSystem
    2. {
    3.     // somehow inject a component system
    4.     IComponentSystem<TEntity, TSharedData> componentSystem;
    5.  
    6.     // made up Group class
    7.     Group<TEntity> group;
    8.  
    9.     protected override void OnCreateManager(int capacity)
    10.     {
    11.         group = GetComponentGroup(typeof(TEntity));
    12.     }
    13.  
    14.     protected override void OnUpdate()
    15.     {
    16.         group.SetFilter(this.componentSystem.Filter());
    17.      
    18.         var entities = group.GetEntities();
    19.         var sharedData = this.componentSystem.SharedData();
    20.  
    21.         for (int i = 0; i < entities.Length; i++)
    22.         {
    23.             entities[i] = this.componentSystem.OnUpdate(entities[i], sharedData);
    24.         }
    25.     }
    26. }
    In the above suggestion it’s not possible to exclude entities that contain a particular component (SubtractiveComponent does that at the moment when specifying the group). Instead I suggest extending the filter to handle such needs.

    Furthermore, you could add more interfaces for implementing simpler systems that don't need filters and shared data, eg.

    Code (CSharp):
    1. public interface ISimpleComponentSystem<TEntity>
    2. {
    3.     public void OnUpdate(TEntity entity);
    4. }
     
    Last edited: Nov 14, 2018
  5. Micz84

    Micz84

    Joined:
    Jul 21, 2012
    Posts:
    451
    Your solution is very similar to Inject API. I see two main draw backs. First it would need reflection to figure out needed components and right now systems have access to entity manager from it's base class. JobProcessComponentData and JobProcessComponentDataWithEntity have very simple to use API.
     
    noio likes this.
  6. Xerioz

    Xerioz

    Joined:
    Aug 13, 2013
    Posts:
    104
    Would be nice to have something like:
    Code (CSharp):
    1. [UpdateFrequency(10, PlayerLoop.Update)]
    2. public class UpdateGroup {}
    3.  
    4. [UpdateInGroup(typeof(UpdateGroup), order: 100)]
    5. class MySystem : ComponentSystem
    Instead of the current awkward UpdateBefore/After api
     
    illinar and JesOb like this.
  7. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,555
    Hi, if barriers in Entity Debugger displays all the incoming commands from all instances of its ECB that would be very useful. (To optimize MinimumChunkSize or debug command ordering problems etc.) Currently it is just time taken to run the barrier and left me wonder why it is taking so long.
     
  8. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,555
    Also should be great if you rename StreamBinaryWriter to FileBinaryWriter and make a new StreamBinaryWriter that accept Stream as a constructor? I wish to add my own encryption and compression as a chain of stream before finally giving to it.
     
    JesOb and elcionap like this.
  9. Arowx

    Arowx

    Joined:
    Nov 12, 2009
    Posts:
    8,194
    Could you get an ECS system down to one line of code?

    e.g.

    Code (CSharp):
    1. MoveSystem : ECS { Vector3 Move( Vector3 pos, forward, float speed) { return pos + forward * speed * Time.deltaTime; }}
     
    xCyborg and florianhanke like this.
  10. You can write your Skyrim-sized game in one .cs file also... but why would you do that?
     
    Peter77, noio, 5argon and 1 other person like this.
  11. Arowx

    Arowx

    Joined:
    Nov 12, 2009
    Posts:
    8,194
    It's an extreme example of removing all of the boilerplate code from ECS, in an attempt to make it easier to use.
     
  12. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,555
    It just boils down to is it a C# or not. If we are making a new scrpting language then of course anything is possible, yes you could. But is it flexible enough for just about anything? That's a merit in sticking to C#, an established programming language. But if we are sticking to C#? It would need stay in C#'s rule at the same time as going towards the desired design. Things like "protected override", etc. you are trying to avoid, that make things works.

    I think in C# "1 line" support is at its best by expression body => operator, so definitely not in class level. At best it would be expression-bodied method as a system/as a job.
     
  13. illinar

    illinar

    Joined:
    Apr 6, 2011
    Posts:
    863
    Would something like this be a good idea or possible to have in IProcessComponentData?

    Code (CSharp):
    1. public struct OptionalComponent<T> where T : struct, IComponentData
    2. {
    3.     public T Component;
    4.     public Bool Exists;
    5.  
    6.     public static implicit operator T(OptionalComponent<T> c) { return c.Component; }
    7.     public static implicit operator OptionalComponent<T>(T c) { return new OptionalComponent<T> { Component = c }; }
    8.     public static implicit operator bool(OptionalComponent<T> c) { return c.Exists; }
    9. }
    Code (CSharp):
    1.     [BurstCompile]
    2.     struct Job : IJobProcessComponentData<Cooldown, OptionalComponent<SwitchedOn>>
    3.     {
    4.         public float deltaTime;
    5.         public void Execute(ref Cooldown cooldown, ref OptionalComponent<SwitchedOn> switchedOn)
    6.         {
    7.             if (cooldown.Value > 0)
    8.             {
    9.                 cooldown.Value -= deltaTime;
    10.             }
    11.             else if (switchedOn)
    12.             {
    13.                 switchedOn.Component.Value = true;
    14.             }
    15.         }
    16.     }
     
    Last edited: Dec 26, 2018
    florianhanke and Guerro323 like this.
  14. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    This thread gave me some AMAL (AMOS) flashbacks. But the problem with the API usability right now is as always boilerplate.

    But as the boilerplate is pretty much always needed I'm wondering if we're looking at the problem in the right direction. Instead of trying to inject functionality, why don't we queue our logic with "boilerplate templates" ? Essentially the behaviour needs all this supporting stuff, when really our desired behaviours are at the basic level, not so different from command buffers with small programs.

    I understand that's quite limiting but it offers a potential of looking at the problem as something of a stack rather than all these loose ends we keep tying up with preventative measures.

    Edit: I guess this wouldn't be a million miles away from LINQ as a syntax anyway and I'm not sure how well that goes down.
     
  15. Cynicat

    Cynicat

    Joined:
    Jun 12, 2013
    Posts:
    290
    I'd love to see a simple LINQ like api, something like:

    Systems.Filter<Rigidbody>
    .OnStart(etc...)
    .OnUpdate(etc...)
    .OnDestroy(etc...)

    But burst optimizing this and handling all the edge cases for delegates would be super hard i think. =<
     
    NotaNaN, Vacummus and hippocoder like this.
  16. Vacummus

    Vacummus

    Joined:
    Dec 18, 2013
    Posts:
    191
    Oh yeah, I too would love a more LINQ like api (aka functional programming), cause it's way more declarative. Though I would imagine the query selectors to be more so for component groups instead of for systems since you can query multiple component groups per system. Here is an example of a simple MovementSystem.
    Code (CSharp):
    1. public class MovementSystem: ComponentSystem
    2. {
    3.     protected override void OnUpdate()
    4.     {
    5.         ComponentQuery
    6.             .Select<Position>() // Read/write declaration
    7.             .SelectReadOnly<Heading, MovementSpeed>()
    8.             .Exclude<Frozen>()
    9.             .ForEach((ref Position pos, ref Heading heading, ref MovementSpeed speed) => {
    10.                 pos.value += heading.value * speed.value * Time.deltaTime;
    11.             });
    12.     }
    13. }
    And this can also be easily jobified while not being a hinderance for Burst:
    Code (CSharp):
    1. public class MovementSystem: ComponentSystem
    2. {
    3.     [BurstCompile]
    4.     struct Job: IJobProcessQuery<Position, Heading, MovementSpeed>
    5.     {
    6.         public float deltaTime;
    7.  
    8.         public void Execute(ref Position pos, ref Heading heading, ref MovementSpeed speed)
    9.         {
    10.             pos.value += heading.value * speed.value * deltaTime;
    11.         }
    12.     }
    13.  
    14.     protected override void OnUpdate()
    15.     {
    16.         ComponentQuery
    17.             .Select<Position>()
    18.             .SelectReadOnly<Heading, MovementSpeed>()
    19.             .Exclude<Frozen>()
    20.             .ExecuteInJob((JobHandle inputDeps) =>
    21.                   new Job { deltaTime = Time.deltaTime }.Schedule(this, inputDeps)
    22.             );
    23.     }
    24. }
    No need to inherit from JobComponentSystem since "ExecuteInJob" provides you with the JobHandle. And this would allow us to write more consistent multi-threaded and non-multithreaded code (thus more easily refactor between the two).

    This kind of api would also scale easily since Unity can easily add support for different kinds of query selectors. Like provide a "Where" function for filtering SharedComponentData. Or a "ForEachChunk" function for chunk iteration.
     
    Last edited: Dec 31, 2018
    NotaNaN, PanMadzior, Orimay and 5 others like this.
  17. Cynicat

    Cynicat

    Joined:
    Jun 12, 2013
    Posts:
    290
    Yep, that's what i was going for but i'm bad at explaining things when i'm tired X3. One option as well would be removing the whole "Inherit from this class" pattern. Just subscribe stuff through a static constructor or similar. UpdateBefore and UpdateAfter could be LINQ functions instead of reflection attributes. EG:

    Code (CSharp):
    1. public static class MySystems {
    2.     static MySystems() {
    3.         var first = Components
    4.             .Filter<Position>()
    5.             .FilterReadOnly<Rotation>()
    6.             .Execute(MyFirstSystem);
    7.         var before = first.UpdateBefore(MyBeforeSystem);
    8.         var after = first.UpdateAfter(MyAfterSystem);
    9.     }
    10.     static void MyFirstSystem(ref Position position, Rotation rotation) { etc... }
    11.     static void MyBeforeSystem(ref Position position, Rotation rotation) { etc... }
    12.     static void MyAfterSystem(ref Position position, Rotation rotation) { etc... }
    13. }
    This would let us have many small modular functions that only depend on the component structs. Which could mean we could also just call this logic from a job as well if we wanted to jobify it (barring the normal requirements for jobs, etc...). I used a similar setup for my old ECS system, but i wasn't using burst and such so idk how hard this would be for the unity team =/
     
    Last edited: Jan 1, 2019
  18. Singtaa

    Singtaa

    Joined:
    Dec 14, 2010
    Posts:
    492
    These LINQ-like api flow so naturally with DOD, because if you think about it, we are really just cherrypicking what data we want to work on, just like querying a database.

    Also a crazy idea: what do you guys think about making ComponentSystem ScriptableObjects? Created system SO's can be inspected and wired up in the editor. Tooling for systems may be more straightforward this way.
     
    Alverik, Orimay, rudypoo and 2 others like this.
  19. daschatten

    daschatten

    Joined:
    Jul 16, 2015
    Posts:
    208
    From time to time i get this error:

    Code (CSharp):
    1. ArgumentException: The component has not been added to the entity.
    because i wrote a new component and filled it with SetComponent() but forgot to adjust the archetype. It sometimes takes some time to find out which component causes this error. It would be helpful if the error prints the name of the component.
     
    pahe and Antypodish like this.
  20. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,780
    Yep,.there are quite few errors, which become nightmare in searching cause, if having multiple systems. So far best solution is making.small steps. Update code, test, repeat.
     
  21. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    Does the callstack not give you all context you need? Am i missing something here?
     
  22. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,780
    Some are giving rough idea. Maybe indicate a system. Good if error mentioning variable, or component.
    I think main issue is, when error occurs in BurstCompiled job. As there is little of indication, what is going on.

    One thing which could be useful, at least if can not pinpoint exact line number of issue, error could allow double click, lead to system. Some errors does work like that. Some don't.

    For example most recent error I got, is:
    A Native Collection has not been disposed, resulting in a memory leak. It was allocated at C:\Users\...EvaluatorSystem.cs:152.
    Which in this case is fine, easy to track, since I got system name and line #. But double click don't work on it.

    Some errors throw bunch of lines, and to find the relevant system, I need look for name of system, which is somewhere in middle, of error log. Again it may have line #. But double click often don't work.

    I will post another example, if I catch error, at next occasion.
    Thx
     
    Sylmerria likes this.
  23. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,780
    Here another example, where double click don't work. There is no line #.
    For small and straight forward system is easy to track, as I can look for any point, where Position component is added.
    ArgumentException: It is not allowed to have two components of the same type on the same entity. (Position and Position)
    EntityCommandBuffer was recorded in ECS.Blocks.AddBlockSystem and played back in ECS.Blocks.AddBlockBarrier.
    ...
    (rest of stack, but irrelevant to track the line #.)

    upload_2019-1-18_12-6-57.png

    But in this case, which is error came, before the above,
    ArgumentException: The component has not been added to the entity.
    Unity.Entities.EntityDataManager.AssertEntityHasComponent ....

    Double click works.
    Few lines down, I can see where is exactly

    /LoadSavedConstructDataSystem.cs:510

    But here is the thing
    upload_2019-1-18_12-1-48.png
    Is hard notice at first, specially when error log window is smaller
    But here is marked important information.
    upload_2019-1-18_12-2-59.png

    If I got smaller window, is even harder to find.
    upload_2019-1-18_12-5-32.png

    My point is, it would be nice, having this marked line on the top, when possible.

    Btw.
    Using Unity 2018.3.0b.10, Entities 0.0.12-preview.21
     
  24. illinar

    illinar

    Joined:
    Apr 6, 2011
    Posts:
    863
    I've posted complaints about stack trace after I started working with ECS. It's a complete nightmare to use. It almost never will point me to the exact problem right away. I have to read through just to find class (pretty hard to find them) names, and then I have to go manually open a file and find a given line of code.

    There is a lot of excessive info in the stack. I just need
    Namespace.Class.Method : line, char
    And to have them all clickable. All other info I would hide into tooltips for each entry.
     
    JesOb and Antypodish like this.
  25. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    4,271
    The new singleton API is interesting, but it is main thread only and seems to use "planned to be deprecated" API internally.

    Can we get a singleton API that works exactly like ComponentDataFromEntity, except that users do not have to pass in the entity? I often update such singletons early in the frame in IJobs and then need to read their values in a ton of jobs throughout the rest of the frame. I really don't care what entity singletons are attached to or if they are even attached to an entity at all. R/W dependencies, an
    Exists() 
    method, and a
    Value
    accessor to the actual component data would be perfect.

    Also, can we get a way to manually bind or update the ComponentGroup associated with an IJPCD type? Even if it was restricted to access on system creation, that would be good enough for my use case. I would like to be able to add subtractive components to jobs after loading assemblies and performing some other initialization work.
     
  26. Jay-Pavlina

    Jay-Pavlina

    Joined:
    Feb 19, 2012
    Posts:
    195
    I agree singleton API is too limiting. It also doesn't support IBufferElementData. For now, it's easier just to pass around a singleton entity and use that everywhere.
     
  27. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,780
    Another case
    ArgumentException: All entities passed to EntityManager must exist. One of the entities has already been destroyed or was never created.
    EntityCommandBuffer was recorded in ECS.Octree.GetCollidingRayInstancesSystem_Octrees2Ray and played back in ECS.Octree.GetCollidingRayInstancesBarrier.


    I got multiple job in a system. Double click don't work. There is nothing useful in this trace, to track a bug, other than telling me, which system is issue in, and is related to missing entity and.
    upload_2019-1-19_7-24-41.png
     
  28. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,780
    Let say we got error like this (double click works)

    ArgumentException: It is not allowed to have two components of the same type on the same entity. (AddInstanceBufferElement[B 4] and AddInstanceBufferElement[B 4])

    Would it be possible, to have in trace, entity index and version?
    Could help tracking down problems.
    Not only for buffers, but in any form, where entity is manipulated and throw exceptions.
     
  29. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,761
    The issues you're having @Antypodish is why I advocate for only ever having 1 system add and remove a specific component.

    Otherwise you end up needing to have a lot of seperate barriers and worry way to much about system order.
     
    Last edited: Jan 19, 2019
  30. JesOb

    JesOb

    Joined:
    Sep 3, 2012
    Posts:
    1,109
    (PNG Image, 938 × 211 pixels).png

    Another error that is just mostly unable to say what is happens and why.
    So all errors in internals dont say what system they belong to.
     
  31. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,780
    I have only one system add and one separate to remove. I follow Single Responsibility Principle, if that what you mean.
    Which does not change the fact, that is possible to have request system to to execute (add/remove component), from multiple systems.

    Imagine for example mesh highlighting system, which changes colors of mesh accordingly.
    But that system, can be requested either from mouse action in one system, or via other mechanics in another.

    I generally try find issue, rather building fail safe around, when applicable.
     
    Last edited: Jan 19, 2019
  32. Lars-Steenhoff

    Lars-Steenhoff

    Joined:
    Aug 7, 2007
    Posts:
    3,527
    Since I don't understand any of this, I'm hopefull that the visual scripting interface will allow me to make use of the api without having to understand all the sintax.
     
  33. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,780
    Officials would need to confirm, but as far I remember, Visual Scripting is not on the near time agenda.
    Maybe in few years time, after ECS enter stable iteration.
     
  34. Lars-Steenhoff

    Lars-Steenhoff

    Joined:
    Aug 7, 2007
    Posts:
    3,527
    Its coming in preview in 2019.2 according to the roadmap, anyway its not the focus of this topic, but Im excited to see how it will make things like ECS easier to use.

    It just came to my mind if we are talking about usability
     
  35. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,780
    Oh that is interesting. I haven't been tracking road map.
    But I wouldn't be surprised, if this feature would be pushed to later version.
    Not sure if is point making Visual Scripting, where core system still is in work. For example we still have EntityCommandBuffer with injection, which suppose to go away and we have no replacement yet.
     
    Lars-Steenhoff likes this.
  36. Jay-Pavlina

    Jay-Pavlina

    Joined:
    Feb 19, 2012
    Posts:
    195
    IJobProcessComponentData should support dynamic buffers. It's tedious having to use BufferFromEntity with IJobProcessComponentDataWithEntity.
     
  37. Arowx

    Arowx

    Joined:
    Nov 12, 2009
    Posts:
    8,194
    Could a higher level SQL query syntax make using ECS a lot simpler and faster and also open the door for easy to use visual ECS tools.

    For example a query to find all enemies within 1km and line of sight of the player to update them could look like this:

    Code (CSharp):
    1. Select ID, Position
    2. from Enemy
    3. where Alive = TRUE and
    4. Range(Position, PlayerPosition) < 1000 and
    5. LineOfSight(Position, PlayerPosition) = True;
    This data could then be worked through with a simple [ECS] ForEach.

    Benefits would be simpler syntax less boilerplate and the ability for the ECS system developers to optimise more complex queries and filters within Unity e.g. under the hood this query could only look through new enemy or enemy that have moved or when the player has moved, massively reducing the work/processing needed to run what otherwise would be at least 1 or 3 or more ECS systems that could become tightly coupled and none atomic due to their interdependence.
     
    e199 likes this.
  38. Cynicat

    Cynicat

    Joined:
    Jun 12, 2013
    Posts:
    290
    While i dig the concise syntax, the multiple languages thing is giving me shaderlab flashbacks in not a good way 0_0
     
    MookeeDev, Alverik and johnnyt like this.
  39. M_R

    M_R

    Joined:
    Apr 15, 2015
    Posts:
    559
    c# has LINQ, so you could be something like
    Code (CSharp):
    1. myComponentGroup = GetComponentGroup (from e in EntityArchetypes
    2. where e.Has<Position>() || e.Has<Rotation>() && e.Filter<SomeSharedComp>().Value == 42
    3. select new{position: e.ComponentData<Position>(readonly:true), rotation: e.ComponentData<Rotation>()});
    the hard part should be converting that (it's created dynamically at runtime) into static typing & query information without too much overhead

    (you can define your types to be LINQ-compatible, with your own semantic. all LINQ requires is SelectMany(), Where(), etc. implementations with the proper signatures)
     
  40. MostHated

    MostHated

    Joined:
    Nov 29, 2015
    Posts:
    1,235
    Some of those Fluent systems out there could be used for something like that probably? That could be pretty nice.
     
  41. e199

    e199

    Joined:
    Mar 24, 2015
    Posts:
    101
    Please add ability to duplicate entity arrays.

    Something like this would be great:
    Code (CSharp):
    1. EntityManager.Instantiate(NativeArray<Entity> srcEntities, NativeArray<Entity> outputEntities)
    This is extremely useful when dealing with rewinding
     
  42. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,555
    Now that ToComponentDataArray linearize is a thing, there are a lot of JobHandle to combine leading to the main job.

    To combine more than 3 JobHandle it requires creating a NativeArray<JobHandle> for JobHandle.CombineDependencies just to dispose it shortly after. I wish there are something simpler like params overload or if that is inefficient maybe making a lot of combines of up to around 10 JobHandles, or maybe if I could new NativeArray<JobHandle>(Allocator.Temp) { jh1, jh2, jh3, jh4, jh5 }; it would be fine too. (I would then wrap it with `using`)
     
    pcysl5edgo likes this.
  43. Sylmerria

    Sylmerria

    Joined:
    Jul 2, 2012
    Posts:
    369
    I just tried the method GetKeyArray and this method returns not keys but a key by value.
    It's not at all the comportment waiting from this method name :/

    So if I have :
    [
    [0] : Val1,Val2,Val3
    [1] : Valx
    ]

    This will return me : [ 0,0,0,1 ] and I'm waiting [ 0,1 ]
     
    Last edited: Mar 20, 2019
    e199 likes this.
  44. e199

    e199

    Joined:
    Mar 24, 2015
    Posts:
    101
    Make API for duplicating chunk with Entity remapping
    OR
    API for copying all components from one chunk onto another (as we already can create chunk with needed archetype and entity count)

    Currently there is SwapComponents method for chunks, which does something similar.
    I need it for faster snapshot creation.
     
  45. e199

    e199

    Joined:
    Mar 24, 2015
    Posts:
    101
    EntityManager.CreateArchetype should work with NativeArrays, not only with params
    or
    have an overload to pass array and count, so it will be possible to use single array instead of creating new each time

    Useful for networking
     
  46. Sylmerria

    Sylmerria

    Joined:
    Jul 2, 2012
    Posts:
    369
    I just see the extension GetUniqueKeyArray which is nice but can you add a summary to this two method Unity team for avoid confusion ?
     
  47. Cynicat

    Cynicat

    Joined:
    Jun 12, 2013
    Posts:
    290
    Oh, little additive to my last post on a fluent API. I found a really neat naming convention for querying entities, here's a little example.

    Code (CSharp):
    1. public static class MyRules {
    2.     static MyRules() {
    3.         // with and without for requiring and rejecting components
    4.         Entities
    5.             .With<Health, Damage>()
    6.             .OnUpdate(DamageRule);
    7.         Entities
    8.             .With<Transform, Rigidbody>()
    9.             .Without<IgnoreGravity>()
    10.             .OnFixedUpdate(GravityRule);
    11.  
    12.         // of course readonly permissions for jobified versions
    13.         Entities
    14.             .WithReadOnly<Transform>()
    15.             .With<Rigidbody>()
    16.             .Without<IgnoreGravity>()
    17.             .OnFixedUpdate(GravityRule);
    18.        
    19.         // OnAdded could let us poll for newly added components at a certain time.
    20.         Entities
    21.             .With<Health>()
    22.             .OnAdded<Hit>()
    23.             .OnUpdate(DamageOnHitRule);
    24.         // there could also be an OnAdded(myRule)
    25.         // for if you want a rule to run immediatly after every barrier.
    26.         // this is very similar to event behavior without the perf degredation.
    27.         Entities
    28.             .With<Health>()
    29.             .OnAdded<Hit>(DamageOnHitRule);
    30.     }
    31.     static void DamageRule(Transform transform, Damage damage) { etc... }
    32.     static void DamageOnHitRule(Transform transform, Hit hit) { etc... }
    33.     static void GravityRule(Transform transform, Rigidbody rigidbody) { etc... }
    34. }
    Obviously this is an idealized example, but I really like the With/Without pattern since it reads mostly as english while being logically sound. Also i like Rule instead of system since it's more descriptive of the format, plus it doesn't share a name with the system API, but i know it's probably too late to change that name. The hard part as always with fluent APIs is trying to fit a hard type system through C# generics. Anyway, this is just my 2 cents and i'm looking forward to how unity improves the api over time =3
     
    dadude123, Sylmerria, leni8ec and 4 others like this.
  48. tbg10101_

    tbg10101_

    Joined:
    Mar 13, 2011
    Posts:
    192
    I saw something like this when Blackbird Interactive did a GDC presentation about Homeworld: Deserts of Kharak.

    edit:
     
    Alverik likes this.
  49. Cynicat

    Cynicat

    Joined:
    Jun 12, 2013
    Posts:
    290
    Oh yeah! I hadn't see that but it's very similar, neat!
     
  50. Shinyclef

    Shinyclef

    Joined:
    Nov 20, 2013
    Posts:
    505
    A little piece of feedback I'd like to give as someone exploring ECS for the first time.
    It's been about 10 days or so working with ECS now. I think I have the basics down but there are 2 small annoyances I have trying to learn this system.

    1. In a typical job, let's say an IJobForEach, I still haven't figured out how to access a value from an IComponentSharedData. How do you do it!? If it's there and I've missed, either I'm blind to something obvious, or it needs to become easier and more transparent how to do so.

    2. As I've started adding several system, I can see that I'm going to end up with a lot, and system order is important. I really hate these "UpdateInGroup" and "UpdateBefore/After" attributes. My order is defined ALL OVER my code?? To understand my order from code, I have to open all the systems? The practical way now is to hit play, open the entity debugger, and take a screenshot, remember to click to display inactive systems.
    I attempted to put ordering logic into my own group components and manually call Update on them, but then they were no longer visible in the Entity Debugger. If there is a solution, it should be more transparent.

    Other than that, I'm really quite enjoying the new paradigm and looking forward to updates!
     
    Cynicat and NotaNaN like this.