Current best practice for runtime instantiation of entities from a prefab database?

Hi all,

I’m interested in runtime instantiation of entities from a scriptable object database. I’ve been looking through the forums, but I was also hoping to start a new discussion. I have some things working, but it has been more trial and error than I would like. Here is about what I have so far:

public class YourSystem : SystemBase {

  // EntityDatabase is a scriptable object that contains a list of prefabs
  // Or skip this step and only load as needed
  EntityDatabase database

  protected override void OnCreate() {
    // Can also use Addressable Assets
    database = Resources.Load<EntityDatabase>("YourDatabase")
  }

  protected override void OnUpdate() {
    // Your logic here
    Entity entityToInstantiate = GameObjectConversionUtility.ConvertGameObjectHierarchy(
      database.prefabList[0],
      new GameObjectConversionSettings(
        World.DefaultGameObjectInjectionWorld,
        GameObjectConversionUtility.ConversionFlags.AssignName,
        new BlobAssetStore()
      ));

    EntityManager.Instantiate(entityToInstantiate);
    // Delete entityToInstantiate if you don't want it to stay in the World
  }
}

My concerns are:

  1. Many comments about this method being slow.
  2. Many comments about this method soon to be depreciated.
  3. Comments that the only proper way to instantiate is some non runtime approach.
  4. A creation of a prefab entity (with Prefab Tag) each time something is instantiated. If I create 10 entities across 5 minutes, I don’t need 10 prefabs entities as well.
    [Edit: Just delete the Converted prefab, or save it to use it again later.]
  5. I have no idea what I’m doing with the BlobAssetStore in this case.

I would really like to be spawn entities from a prefab database in situations where the prefab won’t be known in advance. For example, spawning a random monster in a room. I’m only interested in runtime approaches. I would also like to avoid having a prefab entity in the scene for every possible prefab type, as in the “spawn random monster” scenario, many would be completely unused.

Any thoughts on this? From what I can piece together, this is close to the correct current approach, but I do have concerns and I’m hoping there is a better method.

Hello,

I’m also interested in that subject and would love to have a Unity member share his/her point of view.
For now I think the approach you describe is the “simplest” one to go for.

I’m not sure that having all possible prefab as entities in your scene would have any impact, you loaded all data from you scriptable object anyway so memory wise it should not matter much if they are in managed memory (scriptable object) or not (entity). For systems, entities prefab are completly ignored so there should be no impact on that front.

1 Like

I know you don’t want non runtime solution but I’ve come up with a quick and dirty implementation that work in editor (probably not in build, I’ll have improve on for my project) and wanted to share here if anyone is interested or want ot provide feedback on it.

Bassically what I come up with is whenever an authoring component need to use a prefab, instead of referencing the Entity converted from the prefab, I reference a component with an int. The int is the Instance ID of the prefab.
I also create and additional entity with a component containing a unsafehashmap (I will replace this by my blobhashmap for my project beacause I’m alomsot certain the unsafe hash map will not survive build…) where I add the instanceId of the prefab as a key and the Entity converted from the prefab and a value.
I then have a system that merge all the entites referency the map component type to leave only one (singleton entity) that I can use in any system that need to instantiate a prefab.

That way I don’t have to keep a subscene with all my prefab, I can use reference them whe nI need them in the authoring component and I don’t have any duplicate.

Here are the files.

EDIT : Better approach is to add a component containing the prefab instance id to the prefab entity and have an initialization system make the singleton entity that register all prefabs.
That way you avoid both the map/build issue and any potential issue of entity reference not being the same between editor/authorind and build/runtime.

7299253–883645–Spawner.cs (1.97 KB)
7299253–883648–SpawnerSystem.cs (2.92 KB)

2 Likes

On second thought, it would make more sense to keep the prefabs in a singleton entity with a dynamic buffer of prefab references. I think this idea is a little better, but still best suited for instantiation from a known set of entities, likely to be used frequently.

References to prefabs can be stored in a dynamic buffer.

public struct PrefabBuffer : IBufferElementData {
  public Entity Prefab;
}

This MonoBehaviour is a custom authoring script to generate the singleton entity with all the prefabs.
I was thinking there was a more simple way to do this, but this is what has worked so far.

public class PrefabLibrarySpawner : MonoBehaviour {
  // EntityDatabase is a scriptable object that contains a list of prefabs
  // Use Resources.Load or use Addressable Assets
  EntityDatabase entityDatabase = Resources.Load<EntityDatabase>("YourDatabase");
  var entityManager = World.DefaultGameObjectInjectionWorld.EntityManager;
  Entity prefabLibraryEntity = entityManager.CreateEntity(typeof(PrefabLibraryTag));
  #if UNITY_EDITOR
    entityManager.SetName(E, "PrefabLibrary");
  #endif
  // Convert all prefabs and add to list
  NativeList<PrefabBuffer> PrefabList = new NativeList<PrefabBuffer>(Allocator.Temp);
  for (int i = 0; i < entityDatabase.prefabList.Count; i++) {
    PrefabList.Add(new PrefabBuffer { Prefab = GameObjectConversionUtility.ConvertGameObjectHierarchy(
      entityDatabase.prefabList[i],
      new GameObjectConversionSettings(
        World.DefaultGameObjectInjectionWorld,
        GameObjectConversionUtility.ConversionFlags.AssignName,
        new BlobAssetStore()))});
  }
  // Copy list to dynamic buffer
  DynamicBuffer<PrefabBuffer> PBuffer = entityManager.AddBuffer<PrefabBuffer>(E);
  PBuffer.CopyFrom(PrefabList.AsArray());
  PrefabList.Dispose();
  Destroy(gameObject);
  }
}

Then just get the singleton and instantiate in your system.

public class YourSystem : SystemBase {
  protected override void OnUpdate() {
  // Get the buffer from the Prefab Singleton
  var PBuffer = GetBuffer<PrefabBuffer>(GetSingletonEntity<PrefabLibraryTag>());
  // Instantiate a prefab
  Entity instantiatedEntity = CommandBuffer.Instantiate(PBuffer[0].Prefab);
  }
}

My concerns are:

  1. Many comments about this method being slow. Since conversion is not done at runtime, this should be faster
  2. Many comments about this method soon to be depreciated.
  3. Comments that the only proper way to instantiate is some non runtime approach.
  4. A creation of a prefab entity (with Prefab Tag) each time something is instantiated. If I create 10 entities across 5 minutes, I don’t need 10 prefabs entities as well. There will be a prefab for each thing in the library, but there will only be one, and it should not require additional management.
  5. I have no idea what I’m doing with the BlobAssetStore in this case.
  6. This is really suited for keeping a buffer of known prefabs handy, not for instantiating any random prefab at any time.

WAYN_Games, it sounds like we had a lot of the same thoughts. I had some other ideas in your direction on the way to work today, but I’m going to give yours a good consideration and get back to you.

FYI here are the updated scripts for the “better appraoch” decribed in my deit in the previous post.

7301191–884092–Spawner.cs (2.04 KB)
7301191–884095–SpawnerSystem.cs (2.88 KB)

  1. Maybe not faster but is won’t impact runtime performance
  2. Using GameObjectConversionUtility.ConvertGameObjectHierarchy should be avoided, you can use the GetPrimaryEntity for the conversion system (like in my script) that won’t be deprecated.
  3. That does it
  4. yes one and only one prefab of each (works with variant too)
  5. Using GetPrimaryEntity, you won’t have to deal with it
  6. Le prefab library should be easy to query that’s why I’m suggestion a map like structure. You spanwer can reference the lists of keys to that map like structure in a buffer and pick one at random. That way you get both the option to pick exactly the prefab you need from the “library” and pic kone at random for your spawner.

Okay, I had a chance to play with your version tonight. Seems to work well. My other similar, but not tested, idea was to keep prefab data in a HashMap as system data of some spawner system. I didn’t realize you could attach UnsafeHashMaps to Entities. That looks like it could simplify things a bit. With a dynamic buffer you can refer to prefabs by index, but it only really makes sense for a full set of ordered prefabs, which may not be as flexible as some want.

Bit of a bump, would like to know what the Unity team thinks.
Would also like to know how @eizenhorn tackles this problem.

eisenhorn uses addressables and a singleton map along with blob assets and a few other things: https://discussions.unity.com/t/782077/6 .