How to create an entity list from a game object list?

I want to create many types of entities from a game object list, but I found there is no way to create a List in IComponentData, how can I handle creating a list of entities from a game object list?

public class MapRespawnAuthoring : MonoBehaviour
{
         public  List<GameObject> MapPrefabList;
}

Is there a way to create an entity list like this?

public struct MapEntities : IComponentData
{
    public List<Entity> mapChunk1;//can't do this in IComponentData
}

You can use “Dynamic buffer” or NativeArray.

It is also posiible to use a FixedList of type Entity within a component:

But there are some restrictions to store Entities this way instead of using a DynamicBuffer. I am only aware of Netcode for Entities where they not get remapped between Server and Client on ghost entities. But there are maybe more restrictions.

Hi Arnold:
Thanks for your suggestions, I tried to use:

public struct MapEntities : IComponentData
{
    public NativeArray<Entity> mapChunks;
}

The error is:
ArgumentException: Blittable component type ‘MapEntities’ on GameObject ‘MapManager’ contains a (potentially nested) pointer field. Serializing bare pointers will likely lead to runtime errors. Remove this field and consider serializing the data it points to another way such as by using a BlobAssetReference or a [Serializable] ISharedComponent. If for whatever reason the pointer field should in fact be serialized, add the [ChunkSerializable] attribute to your type to bypass this error.

Could you share example codes or articles?

Thanks a lot.
Qin

Thanks for the article, the article is too abstract to me, it seems IComponentData can’t use the standard list to store data.

Types from System.Collection namespace cannot be used within unmanaged components however they can be used in managed components. In the docs it is stated:

(Source: https://docs.unity3d.com/Packages/com.unity.entities@1.0/manual/components-managed.html)

A managed component uses “class” instead of “struct” in its declaration. But as stated in the docs that managed components cannot be used in C# Job System and are not Burst compatible, also their usage is generally less performant because not part of the ECS archetype chunks and subject to Garbage Collection. It is recommended using unmanaged components as much as possible. Still managed components have their use cases, especially when using ECS Entities and GameObjects/MonoBehaviors together. But in your use case it sounds like being possible to achieve using DynamicBuffer or FixedListXyzBytes.

There is a lot of demo code here:
https://discussions.unity.com/t/895774

And more theoretical info here:
https://discussions.unity.com/t/912107

Hi FaithlessOne:

Thanks let me know the difference between managed and unmanaged data types. I tried

Hi FaithlessOne:

Thanks let me know the reference type and value type, I tried

public struct MapEntities : IComponentData
{

    public DynamicBuffer<Entity> mapDynamicBuffer;//NullReferenceException: Object reference not set to an instance of an object when creating entity
    public FixedList512Bytes<Entity> mapFixedList512Bytes; //no error, but no entity created
}

I bake them like this in Baker:

mapEntities.mapDynamicBuffer = new DynamicBuffer<Entity>();
mapEntities.mapDynamicBuffer.Add(GetEntity(authoring.MapPrefabList[0], TransformUsageFlags.Dynamic));


mapEntities.mapFixedList512Bytes = new FixedList512Bytes<Entity>();
mapEntities.mapFixedList512Bytes.Add(GetEntity(authoring.MapPrefabList[0], TransformUsageFlags.Dynamic));

I initiate them like this ISystem:

var instance = state.EntityManager.Instantiate(mapEntities.mapDynamicBuffer[0]);
var instance = state.EntityManager.Instantiate(mapEntities.mapFixedList512Bytes[0]);

Thanks for these articles, I watched all videos from them, but they only provided the example of Baking entity like:

public struct MapEntities : IComponentData
{
    public Entity mapChunk1;
}

If I want to bake a list of entities, I have to write like this:

public struct MapEntities : IComponentData
{
    public Entity mapChunk1;
    public Entity mapChunk2;
    public Entity mapChunk3;
}

I am not sure if there has a smart way to bake all entities into a list, I tried:

public struct MapEntities : IComponentData
{
   
       public DynamicBuffer<Entity> mapDynamicBuffer;//Null reference error
       public FixedList512Bytes<Entity> mapFixedList512Bytes; //can't see entity but no error
       public NativeArray<Entity> nativeArray; //compile error
}

I bake them like this in Baker:

public class MapRespawnAuthoring : MonoBehaviour
{
    [SerializeField] List<GameObject> MapPrefabList;
    class Baker : Baker<MapRespawnAuthoring>
    {
        public override void Bake(MapRespawnAuthoring authoring)
        {
            MapEntities mapEntities = new MapEntities();

            mapEntities.mapDynamicBuffer = new DynamicBuffer<Entity>();
            mapEntities.mapDynamicBuffer.Add(GetEntity(authoring.MapPrefabList[0], TransformUsageFlags.Dynamic));
            mapEntities.mapDynamicBuffer.Add(GetEntity(authoring.MapPrefabList[1], TransformUsageFlags.Dynamic));
            mapEntities.mapDynamicBuffer.Add(GetEntity(authoring.MapPrefabList[2], TransformUsageFlags.Dynamic));

            mapEntities.mapFixedList512Bytes = new FixedList512Bytes<Entity>();
            mapEntities.mapFixedList512Bytes.Add(GetEntity(authoring.MapPrefabList[0], TransformUsageFlags.Dynamic));
            mapEntities.mapFixedList512Bytes.Add(GetEntity(authoring.MapPrefabList[1], TransformUsageFlags.Dynamic));
            mapEntities.mapFixedList512Bytes.Add(GetEntity(authoring.MapPrefabList[2], TransformUsageFlags.Dynamic));

            mapEntities.nativeArray = new NativeArray<Entity>(3, Allocator.Persistent);
            mapEntities.nativeArray[0] = GetEntity(authoring.MapPrefabList[0], TransformUsageFlags.Dynamic);
            mapEntities.nativeArray[1] = GetEntity(authoring.MapPrefabList[1], TransformUsageFlags.Dynamic);
            mapEntities.nativeArray[2] = GetEntity(authoring.MapPrefabList[2], TransformUsageFlags.Dynamic);


            AddComponent(GetEntity(TransformUsageFlags.None), mapEntities);
        }
    }
}

Initial them like this in ISystem:

public partial struct MapRespawnSystem : ISystem
{
    [BurstCompile]
    public void OnCreate(ref SystemState state)
    {
        state.RequireForUpdate<MapEntities>();
    }
    [BurstCompile]
    public void OnUpdate(ref SystemState state)
    {
        //**run once when code start
        state.Enabled = false;
        var mapEntities = SystemAPI.GetSingleton<MapEntities>();
        state.EntityManager.Instantiate(mapEntities.nativeArray[0]);
        state.EntityManager.Instantiate(mapEntities.nativeArray[1]);
        state.EntityManager.Instantiate(mapEntities.nativeArray[2]);
        state.EntityManager.Instantiate(mapEntities.mapDynamicBuffer[0]);
        state.EntityManager.Instantiate(mapEntities.mapDynamicBuffer[1]);
        state.EntityManager.Instantiate(mapEntities.mapDynamicBuffer[2]);
    }
}

A dynamicbuffer is a type of component, but it acts as a buffer/list of elements. It’s use was odd to me when I was starting out but here is a general implementation of what I think you are after.

Dynamic buffer components | Entities | 1.0.16 has more information on how and why behind their use.

public class MapAuthoring : MonoBehaviour
    {
        public List<GameObject> MapPrefabs;

        public class MapAuthoringBaker : Baker<MapAuthoring>
        {
            public override void Bake(MapAuthoring authoring)
            {
                var entity = GetEntity(TransformUsageFlags.Dynamic);
                var buffer = AddBuffer<MapElement>(entity);
                for (int i = 0; i < authoring.MapPrefabs.Count; i++)
                {
                    buffer.Add(new MapElement
                    {
                        MapEntity = GetEntity(authoring.MapPrefabs[i], TransformUsageFlags.Dynamic)
                    });
                }
                AddComponent<MapEntities>(entity);
            }
        }
    }
// Regular component
    public struct MapEntities : IComponentData
    {
    
    }
 
// The Dynamic buffer component
    public struct MapElement : IBufferElementData
    {
        public Entity MapEntity;
    }
    public partial struct MapRespawnSystem : ISystem
    {
        [BurstCompile]
        public void OnUpdate(ref SystemState state)
        {
            foreach (var (mapBuffer, entity) in SystemAPI.Query<DynamicBuffer<MapElement>>().WithAll<MapEntities>().WithEntityAccess())
            {
                for (int i = 0; i < mapBuffer.Length; i++)
                {
                    state.EntityManager.Instantiate(mapBuffer[i].MapEntity);
                }
            }
            state.Enabled = false;
        }
    }

@qinyupeng
I tested FixedListXyzBytes in my project and unfortunately it does NOT work. This clearly indicates that there is more handling to the Entity type while baking. So then you have to stick to the other approaches in this case.

Entities inside of fixed lists wont be remapped, only stored as plain entities inside components or dynamic buffers. Fine to use at runtime, but any serialization is up to you to figure out. I think dynamic buffer is the preferable fit for this use case(and most others).

Thanks!!!
It works! hope other guys who have similar questions can see this answer!

thelebaron gives a solution:

public struct MapElementBuffer : IBufferElementData
{
    public Entity MapEntity;
}

Why would you even need something like List inside your component?
just add some tag component to Entities and query them

While I do not know the intentions of the OP, Entity references in a component can be very useful for finding components of related entities directly without iterating through all entities of an archetype. For example this is used by the ECS packages itself for Parent/Child relations. So it definitely has its use case.