[SOLVED] Can't seem to Instantiate Prefabs from Lookup of any kind [ECS 1.0.0-pre.15]

Hi as the title suggests, I currently want to load in prefabs in a baker, convert them to Entities and them store them in either a Native Array or NativeHashMap<int, Entity> but none of these approaches seems to work, the idea is just a spawn system that can take the index of the prefab and then where it should spawn but it only spawns a cube or capsule when I have specific properties for them in my Components. I feel like I’ve tried everything at this point.

They also seem to appear as these?

8760394--1187557--upload_2023-1-27_7-30-3.png

Baker:

using Unity.Collections;
using Unity.Entities;
using Unity.Mathematics;
using UnityEngine;

public class EntitySpawnManager : MonoBehaviour
{
    public GameObject PrefabToSpawn1;
    public GameObject PrefabToSpawn2;
}

public class EntitySpawnManagerBaker : Baker<EntitySpawnManager>
{
    public override void Bake(EntitySpawnManager authoring)
    {
        // todo: load data from json file database
        //var test = Resources.Load("");

        // test
        var prefab = GetEntity(authoring.PrefabToSpawn1);
        var prefab2 = GetEntity(authoring.PrefabToSpawn2);

        //prefab.

        var prefabsMap = new NativeHashMap<int, Entity>(128, Allocator.Persistent)
        {
            { 0, prefab },
            { 1, prefab2 }
        };

        var toSpawn = new NativeList<SpawnComponent>(Allocator.Persistent);

        toSpawn.Add(new SpawnComponent()
        {
            EntityToSpawnIndex = 0,
            Positions = new float3(1, 0, 1),
            Rotations = quaternion.identity
        });

        toSpawn.Add(new SpawnComponent()
        {
            EntityToSpawnIndex = 1,
            Positions = new float3(1, 0, 1),
            Rotations = quaternion.identity
        });

        AddComponent(new EntitiesToSpawnContainer()
        {
            EntitiesToSpawn = toSpawn
        });

        AddComponent(new EntityContainer()
        {
            PrefabsMap = prefabsMap
        });
    }
}

So called lookup:

using System.Collections.Generic;
using Unity.Collections;
using Unity.Entities;

public struct EntityContainer : IComponentData
{
    public NativeHashMap<int, Entity> PrefabsMap;
}

Spawn System:

using Assets.Scripts.ECS.Aspects;
using System;
using System.Diagnostics;
using Unity.Burst;
using Unity.Collections;
using Unity.Entities;
using Unity.Jobs;
using Unity.Transforms;

namespace Assets.Scripts.Systems
{
    [BurstCompile]
    //[UpdateAfter()]
    public partial struct EntitySpawnSystem : ISystem
    {
        [BurstCompile]
        public void OnCreate(ref SystemState state)
        {
            state.RequireForUpdate<EntityContainer>();
        }

        [BurstCompile]
        public void OnDestroy(ref SystemState state)
        {

        }

        [BurstCompile]
        public void OnUpdate(ref SystemState state)
        {
            var entityLookup = SystemAPI.GetSingletonEntity<EntityContainer>();
            var aspect = SystemAPI.GetAspectRW<SpawnAspect>(entityLookup);

            if (!aspect.HasToSpawn) return;

            var ecb = SystemAPI.GetSingleton<BeginInitializationEntityCommandBufferSystem.Singleton>();

            var lookup = aspect.GetJobEntityLookup();
            var componentSpawns = aspect.GetJobSpawnComponents();

            var buffer = ecb.CreateCommandBuffer(state.WorldUnmanaged).AsParallelWriter();

            var job = new EntitySpawnJob()
            {
                ECB = buffer,
                EntitiesLookup = lookup,
                SpawnComponents = componentSpawns
            }
            .Schedule(aspect.NumberToSpawn, 16);

            job.Complete();

            //lookup.Dispose();
            componentSpawns.Dispose();

            //ecb.

            //ecb.

            //ecb.Playback(state.EntityManager);
        }
    }

    public partial struct EntitySpawnJob : IJobParallelFor
    {
        [ReadOnly]
        public NativeArray<SpawnComponent> SpawnComponents;

        [ReadOnly]
        public NativeHashMap<int, Entity> EntitiesLookup;


        public EntityCommandBuffer.ParallelWriter ECB;

        public void Execute(int index)
        {
            var toSpawn = SpawnComponents[index];
            var bufferEntity = EntitiesLookup[toSpawn.EntityToSpawnIndex];

            //var entity = GetEntity()

            var entity = ECB.Instantiate(index, bufferEntity);

            ECB.AddComponent(index, entity, new LocalTransform
            {
                Position = toSpawn.Positions,
                Rotation = toSpawn.Rotations,
                Scale = 1f
            });
        }
    }
}

Aspect:

using Unity.Collections;
using Unity.Entities;

namespace Assets.Scripts.ECS.Aspects
{
    public readonly partial struct SpawnAspect : IAspect
    {
        public readonly Entity Entity;

        public readonly RefRO<EntityContainer> EntitiesLookup;
        public readonly RefRW<EntitiesToSpawnContainer> EntitiesToSpawn;


        #region Properties

        public NativeHashMap<int, Entity> EntityMap
        {
            get => EntitiesLookup.ValueRO.PrefabsMap;
        }

        public NativeList<SpawnComponent> SpawnComponents
        {
            get => EntitiesToSpawn.ValueRO.EntitiesToSpawn;
        }

        #endregion

        public NativeHashMap<int, Entity> GetJobEntityLookup()
        {
            return EntityMap;
        }

        public NativeArray<SpawnComponent> GetJobSpawnComponents()
        {
            var array = SpawnComponents.ToArray(Allocator.TempJob);

            return array;
        }

        /// <summary>
        /// There are currently values in entities to spawn
        /// </summary>
        public bool HasToSpawn => EntitiesToSpawn.ValueRO.EntitiesToSpawn.Length > 0;

        /// <summary>
        /// The number of entities we should be spawning
        /// </summary>
        public int NumberToSpawn => EntitiesToSpawn.ValueRO.EntitiesToSpawn.Length;

        /// <summary>
        /// Get an entity by it's lookup index
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        public Entity GetEntityByIndex(int index)
        {
            var entity = EntitiesLookup.ValueRO.PrefabsMap[index];

            return entity;
        }

        public SpawnComponent GetSpawnComponentByIndex(int index)
        {
            var spawnComponent = EntitiesToSpawn.ValueRO.EntitiesToSpawn[index];

            return spawnComponent;
        }

        /// <summary>
        /// Clear all entities to spawn, since we are done using it
        /// </summary>
        public void Clear()
        {
            //EntitiesToSpawn.ValueRW.EntitiesToSpawn.Clear();
        }
    }
}

Have you tried storing the Prefabs in a DynamicBuffer instead of a NativeList? Might be an entities remapping issue with NativeContainers.

The entities you do see are SystemEntities. Each System spawns one of those automatically in 1.0.

2 Likes

Hey, I will try and let you know thank you :slight_smile:

You can’t save native containers in components in baker as baking process serializes entities to disk and native containers not the part of that process, after deserializing you’ll have default initialized container (not even allocated memory and IsCreated will return false) instead of what you expect, not to say you already have memory leak in baker (as you never dispose prefabsMap and toSpawn). What you should use here is as mentioned above - DynamicBuffer or just plain Entity field on component.

3 Likes

Thank you for the amazing replies, the DynamicBuffer works :slight_smile: was on this for days!

@eizenhorn , I had a feeling the containers in the components was wonky I’ll keep that in mind, thank you

New Component Buffer:

public struct EntityBufferLookup : IBufferElementData
{
    public Entity Entity;
}

Baker Changes:

var buffer = AddBuffer<EntityBufferLookup>();
buffer.Add(new EntityBufferLookup()
{
    Entity = prefab
});
buffer.Add(new EntityBufferLookup()
{
    Entity = prefab2
});

System Changes:

        [BurstCompile]
        public void OnUpdate(ref SystemState state)
        {
            var entityLookup = SystemAPI.GetSingletonEntity<EntityContainer>();
            var aspect = SystemAPI.GetAspectRW<SpawnAspect>(entityLookup);
            var buffer = SystemAPI.GetBuffer<EntityBufferLookup>(entityLookup);

            if (!aspect.HasToSpawn) return;

            var ecb = SystemAPI.GetSingleton<BeginInitializationEntityCommandBufferSystem.Singleton>();

            var lookup = aspect.GetJobEntityLookup();
            var componentSpawns = aspect.GetJobSpawnComponents();

            var ecbParallel = ecb.CreateCommandBuffer(state.WorldUnmanaged).AsParallelWriter();

            var job = new EntitySpawnJob()
            {
                BufferLookup = buffer,
                ECB = ecbParallel,
                EntitiesLookup = lookup,
                SpawnComponents = componentSpawns
            }
            .Schedule(aspect.NumberToSpawn, 16);

            job.Complete();

            //lookup.Dispose();
            componentSpawns.Dispose();
        }
    }

Job Changes:

public partial struct EntitySpawnJob : IJobParallelFor
    {
        [ReadOnly]
        public NativeArray<SpawnComponent> SpawnComponents;

        [ReadOnly]
        public NativeHashMap<int, Entity> EntitiesLookup;

        [ReadOnly] public DynamicBuffer<EntityBufferLookup> BufferLookup;

        public EntityCommandBuffer.ParallelWriter ECB;

        public void Execute(int index)
        {
            var toSpawn = SpawnComponents[index];
            var bufferEntity = BufferLookup[index];

            //var entity = GetEntity()

            var entity = ECB.Instantiate(index, bufferEntity.Entity);

            ECB.AddComponent(index, entity, new LocalTransform
            {
                Position = toSpawn.Positions,
                Rotation = toSpawn.Rotations,
                Scale = 1f
            });
        }
    }

8760586--1187590--upload_2023-1-27_9-49-37.png

2 Likes