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

Some Questions about SharedComponentData

Discussion in 'Entity Component System' started by nyscersul, Jul 29, 2019.

?

Can i frequently modify the numerical values held in a shared component data regularly?

  1. Yes! Do as you wish?

    18.2%
  2. No! Are you crazy man????

    81.8%
  1. nyscersul

    nyscersul

    Joined:
    Oct 17, 2018
    Posts:
    136
    Heya,

    Been using ecs a while now, but havent used shared component datas much yet.

    As far as i see it, the definitive differences between a componentData and a sharedComponentData is that the former has much harsher limitations in what it can hold, no reference types, no arrays etc, whilst the latter does not suffer the same limitations in quite the same way,
    and also will only occupy one memory instance - that is one slot in memory - per each unique data instance. As the following illustrates...

    Create five entities... For each, create a new instance of a sharedComponentData, with a single int value, and apply it via AddSharedComponentData, then set the value for the first three to 1, and the value for the last two to 2.

    My understanding is that the system then should report that there are only two unique instances of the data, in spite of having created a new instance each time.

    Also, it appears that the major usage pattern of the sharedComponentData is to represent a wide bunch of objects with the same data component, but does this mean when you change the value on a component, it will only affect the entity in question?

    lets say the example before, three 1's and two 2's, if i were to change a 1 to a 3, i then have three sharedComponentData unique instances, with the change to a 3 not affecting the other 1's?

    If, however, i wanted to change the value and have it reflect on all entities with this same component value, can this be done easily?

    If so, it would follow that it may be in fact possible to use the sharedComponentData on a smaller scale, to allow entities to talk to each other? Say you wanted to have a system which handles a custom parent/child translation behaviour, having the child always move to the position of the parent but not to turn as per the usual arrangement, you could do this by setting a shared component to both entities with a unique identifier maybe the index of the parent entity, and then each frame set the shared component value to the parent's translation position, and have a later system read the data without needing to directly request access to the other entities components or data, as it would already be in the shared data?

    This particular problem is not the most important usage case i intend, if i can achieve getting the shared component data to change on all references directly, but it is the simplest to explain.

    So, with the less stringent limits of what a sharedComponentData can hold, does it also suffer further issues if it is being regularly updated and changed? a lot of the things put in there are complex, like meshes for one, so i imagine they must take some more cpu time to manipulate, but is that something that would only matter when the data is complex? updating a mesh every frame might be slow, but the positional coordinates mentioned above, being simple, might be less noticeable?

    Please help me figure out the limitations :)
     
  2. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,647
    You should consider shared component data to be static and only changed in very rare circumstances.

    However if you want to enjoy ECS I have a simple rule for you.

    Never use shared component data.

    When thinking of a solution and you think the answer is a SCD, I promise you 99% of the time that is the wrong way. In the 18 months of using ECS and following these forums I can not recall a single time where I have seen a post involving SCD that it was a good solution to their problem. It's nearly always simply a misunderstanding on how to work with data and inexperience.

    This is not something that is obvious. I used plenty of SCD for months when I was learning, but the more I used the ECS and the more I learnt the more I felt I should never use SCD.

    I'm not saying that SCD should never be used, but really the only time you should use SCD is to group entities for batching (i.e. rendering.) Most of the times this will be useful will end up being performance critical systems.

    (P.S. sorry for rant)
     
  3. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,294
    What about Filters? I find SharedComponentData very useful as a filter for the queries.
     
    GilCat likes this.
  4. nyscersul

    nyscersul

    Joined:
    Oct 17, 2018
    Posts:
    136
    How would you go about having multiple entities sharing data? Consider them to be entities which together comprise an object, with moving parts. I can manage all the movements and stuff, all i need is a clear and reliable way for one spcific entity to be able to send data to another specific entity, and to do so without any kind of iteration or anything.

    I am already intending to use a specific shared data which defines the current location of the entity in multiple virtual worlds, that in ecs terms, all are actually inside the same world. And this, because i can filter by the shared data specifically.

    At the simplest level, i want a particular entity to be processed first, and to put its data into the data of the entities that are tied to it. There are many times i will need to do this. Most of my entities have multiple parts that need to respond to each other as well as external stimuli, and do so together.
     
    Last edited: Jul 29, 2019
  5. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,294
    Just be aware that SCD is per-chunk. Meaning if you modify the SharedData entity will be moved to the different chunk. Which may be heavy, if done on lots of entities w/o EntityQuery. So its better to alter it via query in to order to modify whole chunk.

    I might be wrong though, and you should read this one:
    https://gametorrahod.com/everything-about-isharedcomponentdata/
     
  6. nyscersul

    nyscersul

    Joined:
    Oct 17, 2018
    Posts:
    136
    @xVergilx How do you modify it by a query?
     
  7. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,294
    EntityManager.SetSharedComponentData(<yourquery>, new <yourSCD>{ *ValueField* = *Value*});
    Or via the EntityCommandBuffer.
     
  8. nyscersul

    nyscersul

    Joined:
    Oct 17, 2018
    Posts:
    136
    Nice, cool, and do you happen to know if it is still possible to set up a new command buffer, or is it expected that you would use the new PostUpdateCommands in your current system?

    I am currently attempting to rebuild a full simulation. Its spaceships, but there are LOTS of hidden entities in the background where the meat of activity is. These complex associations of entities will *not* be numerous. We are talking like a maximum of 20-30 of the multi-part objects ever.
     
  9. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,294
    If you're going to schedule a job for this one, its better to leave at the main thread. Marking whole chunks is faster than winding up a new job.

    But if you're going to do something extra, then you can use EndSimulationEntityCommandBufferSystem.CreateBuffer(...).ToConcurrent(); to get a new EntityCommandBuffer.

    JobComponentSystems do not have a PostUpdateCommands (un)fortunately, so PostUpdateCommands available only in the ComponentSystems.
     
  10. nyscersul

    nyscersul

    Joined:
    Oct 17, 2018
    Posts:
    136
    Is there any other way of getting two entities to send data to each other? I can handle one way... But if its main thread only, it could be an issue... If jobs are sheduled but not completed before a component system runs, do the jobs still continue to process whilst the component system hogs main thread, or dothey get completed before the new system starts?
     
  11. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,647
    ComponentSystem will stall main thread until any jobs in chain with dependency is complete. For performance you should avoid ComponentSystem as they usually turn into hard sync points.

    The best/easiest way to group entities is simply a one to many parent->children hierarchy.
    The parent has a list of all children entity (and optionally if required the children can have a reference to the parent entity) __ basically what the Unity Transform system does. You really can just hijack into this and use that to group your entities without SCD.

    It's also very performant if Entities only belong to 1 parent as you multi-thread it very safely.
     
    xVergilx likes this.
  12. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,294
    Okay I was wrong. EntityManager doesn't contain SetSharedData overload for the EntityQuery. So yeah
     
  13. nyscersul

    nyscersul

    Joined:
    Oct 17, 2018
    Posts:
    136
    Ok, do you know anywhere that discusses properly setting up a bi-directional parent child relationship properly? I've managed to figure out setting a parent, but have no idea how to do it for the child to reference the parent
     
  14. nyscersul

    nyscersul

    Joined:
    Oct 17, 2018
    Posts:
    136
    thanks anyways vergil :), and thanks tertle as well :)
     
  15. nyscersul

    nyscersul

    Joined:
    Oct 17, 2018
    Posts:
    136
    Is there a serious hit with complex multiple level hierarchies?
     
  16. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,294
    As long as you have only 1:1 relation, you could modify entities via jobs:
    (e.g. by adding reference data like this)
    Code (CSharp):
    1. public struct Relation : IComponentData {
    2.      public Entity Parent;
    3.      public Entity Child;
    4. }
    Although its less effective than just plain component queries. Note that you can't read what data entity has, only blindly modify it via the buffer.
     
  17. nyscersul

    nyscersul

    Joined:
    Oct 17, 2018
    Posts:
    136
    And how would you use the entity itself to reference the componentData on it in a job? I have tried to do exactly this and couldnt figure it out.
    Send in an entityManager and just dont use burst?
     
  18. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,294
    No, that will not work.

    You can't read from the buffer / and sending like that will not work.
    However, you can modify structure of the hierarchy, which will modify processing queries for the components via the buffer.

    TL;DR: Don't use hierarchies. Use a data flow.
    Imagine that your application is a database, and think about it that way.
     
  19. nyscersul

    nyscersul

    Joined:
    Oct 17, 2018
    Posts:
    136
    Im still lost hehe...

    It seems impossible to send data from one entity to another.
     
  20. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,294
    Okay, so lets say you have part A and part B. You want to modify a child of Relation by the result of A and B.

    - Query over : All = A, B, Relation;
    - Create a job, do your processing of A and B.
    (e.g. IJobForeach<A, B, Relation>, with a concurrent entity component buffer)

    - If something happens while executing, (e.g. you want to add C to the child), use EntityCommandBuffer.Concurrent.
    - Access Relation component, grab child entity (it works like an index).
    - Use ECB.Concurrent to AddComponent(jobIndex, childEntity *from the Relation*, typeof(C));
    - Use ECB.Concurrent to SetComponentData(jobIndex, childEntity, new C{ *Value * = Value* });

    And there you have an A and B resulting in a C attachement to the child and a result of the job.



    Note that there may be a different / more efficient way to do this, but I haven't found it yet myself. This just works for me.
     
    Last edited: Jul 29, 2019
  21. nyscersul

    nyscersul

    Joined:
    Oct 17, 2018
    Posts:
    136
    Ok, so that sets up the relation ship between them so they can see each other, thats fine, but what happens if i say want the parent to know the health of its children?

    Say, the parent is the main entity of a ship composed of parts, which each can be damaged individually, and when one reaches 0, the parent explodes the entire ship and all its parts.

    Again, just one example of many where they need to talk to each other hehe

    So a solution to passing just translation say, would be to have the parent use its child reference via the command buffer in the movement system to just set its data, and, assuming the commandbuffer is played back before the system that the children parts use to act on their data, then the data passing would have worked fine?

    Parent moves, parent sets child's custom componentData value via the buffer,
    subsequent system plays buffer,
    child just uses its own component data as before...

    So, this all depends on parent child relationships... But this need not actually be the case, the setup here would work for any entity that needs to send data to another, provided that it doesnt happen on the scale of 100s at once, it should suffice?

    So this could be how for example i could use the output from my functioning collision system to apply the data from a collision - ie, the response in movement - to the entity, when i create a "collision detected" entity?
     
  22. nyscersul

    nyscersul

    Joined:
    Oct 17, 2018
    Posts:
    136
    Assuming i understand correctly, great thanks virgil :)
     
  23. xVergilx

    xVergilx

    Joined:
    Dec 22, 2014
    Posts:
    3,294
    It's still A and B. Well, its rather B and A.

    You'd want to update parent when child is taking damage.
    Split it to two systems instead.

    First one get and sets a "damage" component value to both part and the ship. Part has a relation to the ship.
    (Alternatively, you can just grab all damage components that are attached to the parts, then run a system over them, and apply the sum of the damage to the ship)

    Second system, pickups that "damage" component value and applies it to the part health. It can also mark ships as destroyed by marking them as exploaded.
    Third one "explodes" the ship etc.

    This is the simplest solution that should work just fine.

    One thing that might be interesting for this one is the SystemStateComponents https://docs.unity3d.com/Packages/com.unity.entities@0.0/manual/system_state_components.html

    That can be added / removed and be detected via queries just like a common events.
     
  24. nyscersul

    nyscersul

    Joined:
    Oct 17, 2018
    Posts:
    136
    It sounds as if it doesnt necesarily require there to be a hierarchy at all.

    The key part i was missing however, it seems, is the simplest part - simply that once i have the entity reference (and i've done fine acquiring this where needed) that i dont need to be applying the data necesarily to the entity being processed now. I think i got stuck in that hehehe

    In regards to the health thing tho, there is absolutely no reason to run into a several system setup for that...

    Child takes damage, reaches 0, uses parent entity reference to signal to main entity
    next frame,
    same system thst dealt with child before now recognises the parent's health is zero, and explodes that.

    Health in particular really doesnt matter too much to be immediately timed. That one frame delay could be considered to be the time it takes for the chain reaction to blow up the ship...

    The bigger concern was visual movement coordination between entities... Which i can fix now. Fortunately, these tight considerations and requirements only apply to approximately 5% of my entities... The rest are running a much simpler mode of execution.

    Thanks again, ima go code this up hehe
     
    xVergilx likes this.
  25. soundeosdev

    soundeosdev

    Joined:
    Dec 24, 2020
    Posts:
    14
    How do you deal with the shared data? Do you use regular IComponentData or something like lookup tables?
     
  26. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,647
    This is a very old post. With unmanaged shared components there are more use cases where they are useful without biting you in the ass.

    That said I still rarely use them and most shared data is handled by blobs.
     
    elliotc-unity and soundeosdev like this.