Search Unity

Can I stick a NativeContainer into an ISharedComponentData?

Discussion in 'Entity Component System' started by Mr-Mechanical, Mar 23, 2019.

  1. Mr-Mechanical

    Mr-Mechanical

    Joined:
    May 31, 2015
    Posts:
    507
    Is this ok? Exploring design options for something specific.

    Thanks.
     
  2. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    4,269
    I store them in class objects attached to ISCDs. Especially on a singleton entity. Though I might change that once I wrap my head around the new blob API.
     
    Mr-Mechanical likes this.
  3. Mr-Mechanical

    Mr-Mechanical

    Joined:
    May 31, 2015
    Posts:
    507
    interesting. what's the new blob api?
     
  4. MostHated

    MostHated

    Joined:
    Nov 29, 2015
    Posts:
    1,235
    ComponentData structs unfortunately can't contain containers. I certainly wish they could, I would have finished what I am currently working on a good while ago instead of trying to find workarounds for things.

    The thing you can do though is you can attach a Dynamic Buffer ( which would be a struct derived from IBufferElementData) to an Entity that can act as an Array. It can hold anything that is blittable I believe. Technically the dynamic buffer itself only holds a single value type but becomes an array because it essentially stacks (at least that is how I choose to believe that it works, lol).

    You create a new struct for your buffer:

    Code (CSharp):
    1.     // This can just be its own new file, such as MyDataBufferComponent.cs or if you wanted you can add this code to another already created component
    2.  
    3.     // This limits the number of actual items that the buffer will contain. Keep it as low as you can while making sure you have enough,
    4.     // it can grow but not get resized  back down again unless you get rid of the one on the entity and create/add a new one
    5.     [InternalBufferCapacity(3)]
    6.     public struct MyDataBuffer : IBufferElementData
    7.     {
    8.         // This can be pretty much whatever, such as int, float, or a custom struct you have created which can contain additional data fields, as long as that struct is blittable and contains no containers
    9.         public MyData mydata;
    10.     }
    Then you can do this somewhere to add the new buffer to your entity and populate it with data

    Code (CSharp):
    1.     // Creates a new list of the type of your buffer (doesn't have to be a list, can be a single item)
    2.     public List<MyDataBuffer> dataBufferList = new List<MyDataBuffer>();
    3.  
    4.     // Just example, this would usually be in a ComponentSystem, or if its IJobProcessComponentDataWithEntity the Entity would be there already
    5.     void AddBufferItems(Entity entity, MyData myDataForBuffer)
    6.     {
    7.         // Get access to the EntityManager so you can work with Entities
    8.         manager = World.Active.GetOrCreateManager<EntityManager>();
    9.  
    10.         // Adds the actual buffer component to your entity
    11.         manager.AddBuffer<MyDataBuffer>(entity);
    12.  
    13.         // Gets the buffer you just added to your Entity so you can then add the data to it
    14.         var myBuffer = manager.GetBuffer<MyDataBuffer>(entity);
    15.  
    16.         // This is just whatever data you are going to actually add into the buffer/array attached to the entity
    17.         var myData = myDataForBuffer;
    18.  
    19.         // This creates a new buffer object and passes the actual data you want to have on the entity into the new buffer object and adds it to the list we created
    20.         dataBufferList.Add(new MyDataBuffer(myData));
    21.  
    22.         // Since we made a list of the things we wanted to add, we just iterate over that list and add them to the buffer
    23.         for (int i = 0; i < dataBufferList.Count; i++)
    24.         {
    25.             // Adds each element of the list we created that contains the buffer objects which hold the data we want to add, to the actual buffer in which we used GetBuffer to gain access via the manager
    26.             myBuffer.Add(dataBufferList[i]);
    27.         }
    28.     }
    There is also a way, using DynamicBufferProxy, to add a buffer ahead of time in the inspector instead of having to do it all through code.
     
    Last edited: Mar 23, 2019
    Mr-Mechanical likes this.
  5. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    4,269
    The Blob API has a Blob allocator, BlobAssetReference, and BlobArrays and seems to be usable inside jobs. It's basically like Asset tables, though it remains unclear to me what their mutability properties and allocation properties inside and outside a job are. It has only been mildly referenced in the release notes but is used quite a bit in Unity.Physics.

    But ISharedComponentData can, as well as other non-blittable types like classes and Scriptable Objects. You just have to be careful about not calling EntityManager.SetSharedComponentData to swap NativeContainers. If you need double buffer swapping, just put the NativeContainer inside a wrapper class so that you just have to update the wrapper instance rather than the ISCD.
     
    Mr-Mechanical likes this.
  6. MostHated

    MostHated

    Joined:
    Nov 29, 2015
    Posts:
    1,235
    Oh, well shoot. I didn't know that. Thought I could finally answer on correctly on my own, lol. >_< My apologies, I thought that no ComponentData could. Well, that is neat then. Thanks for the info.
     
    Last edited: Mar 23, 2019
    Mr-Mechanical likes this.