Search Unity

[Solved] NativeArray of struct containing NativeArray

Discussion in 'Data Oriented Technology Stack' started by mkandersson, Mar 24, 2019.

  1. mkandersson

    mkandersson

    Joined:
    Oct 5, 2012
    Posts:
    18
    Hi, I'm having a problem with a native array of structs containing a native array, inside a job.
    I get a "InvalidOperationException: must be unmanaged (contain no managed types)" when I try this.

    Code (CSharp):
    1. public struct SpawnerData {
    2.     public NativeArray<PrefabData> prefabs;
    3.     //...spawner settings
    4. }
    5. public struct PrefabData {
    6.     public NativeArray<Entity> variations;
    7.    //...prefab group settings
    8. }
    Does anyone have an idea of how to get around this, or if this will be fixed/allowed later?
    My current prefab structure is very much dependent on this.
     
  2. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    1,432
    You can’t use native container inside native container. You can use Native Multi Hash Map to mimic array of arrays. Or (if you need array on entity) use DynamicBuffer.
     
    mkandersson likes this.
  3. mkandersson

    mkandersson

    Joined:
    Oct 5, 2012
    Posts:
    18
    Thanks, I didnt know about the NativeMultiHashMap. Still learning what is possible with ECS and the job system. Hmm how do one go about using the DynamicBuffer for this? I'd love to see an example if you have the time.
     
  4. sngdan

    sngdan

    Joined:
    Feb 7, 2014
    Posts:
    918
    There are examples for both here in this forum.

    In your example above you would create an entity for each element in the "NativeArray<PrefabData>" of "Spawner Data" and attach to each entity the "NativeArray<Entity>" in form of a buffer like this
    Code (CSharp):
    1. [InternalBufferCapacity(###)]
    2. public struct PrefabData : IBufferElementData
    3. {
    4. public Entity Value;
    5. }
    edit: pre allocating the buffer capacity allows it to be allocated within the chunk (provided it fits, obviously) and not grow on the heap
     
    mkandersson likes this.
  5. Abbrew

    Abbrew

    Joined:
    Jan 1, 2018
    Posts:
    149
    Use a flattened array if each NativeArray in your NativeArray has the same "max size". To do so, store all your NativeArrays' data in one NativeArray. Thus, instead of having [[a,a,a],[b,b,b],[c,c,c]] (a NativeArray of NativeArrays) you have [a,a,a,b,b,b,c,c,c] (one NativeArray holding all the data). To process them in parallel, multiple the "index" integer inside the execute method of IJobParallelFor by the max size to get the index of the first element of that virtual NativeArray, and iterate max size times.
     
    mkandersson likes this.
  6. mkandersson

    mkandersson

    Joined:
    Oct 5, 2012
    Posts:
    18
    Thanks for the help :)

    *EDIT* I finally landed on this solution.
    The entity count varies per PrefabData but it never changes.

    Code (CSharp):
    1. public struct SpawnerData {
    2.     public NativeArray<PrefabData> data;
    3.     public NativeArray<PrefabLookup> lookup;
    4.     public NativeArray<Entity> prefabs;
    5.     //...spawner settings
    6. }
    7. public struct PrefabLookup {
    8.     public int startIndex, prefabCount;
    9. }
     
    Last edited: Mar 25, 2019