Hello fellow Dotsers,
Can I get a sanity check on this idea…
TL;DR: I’m trying to bake prefabs and a lookup map into a subscene instead of converting it at runtime.
Currently I have a PrefabRegistryAuthoring
which basically holds a list of prefabs to be converted to Entities.
public class PrefabRegistryAuthoring : MonoBehaviour, IConvertGameObjectToEntity, IDeclareReferencedPrefabs {
public List<PrefabRegistryEntryAuthoring> PrefabRegistryEntries = new List<PrefabRegistryEntryAuthoring>();
public void DeclareReferencedPrefabs(List<GameObject> referencedPrefabs) {
referencedPrefabs.AddRange(PrefabRegistryEntries.ConvertAll(prefab => prefab.gameObject));
}
public void Convert(Entity entity, EntityManager entityManager, GameObjectConversionSystem gameObjectConversionSystem) {
var prefabRegistryEntries = PrefabRegistryEntries;
var prefabRegistrySystem = entityManager.World.GetOrCreateSystem<PrefabRegistrySystem>();
for (var i = 0; i < prefabRegistryEntries.Count; i++) {
var prefab = prefabRegistryEntries[i];
var prefabEntity = gameObjectConversionSystem.GetPrimaryEntity(prefab);
prefabRegistrySystem.Add(prefabRegistryIdentifier, prefabEntity);
}
}
}
this class effectively shoves the Entity references into a NativeHashMap
of a small PrefabRegistrySystem
:
public class PrefabRegistrySystem : SystemBase {
public NativeHashMap<int, Entity> Registry;
protected override void OnCreate() {
Registry = new NativeHashMap<int, Entity>(300, Allocator.Persistent);
}
protected override void OnDestroy() {
Registry.Dispose();
}
public void Add(PrefabRegistryIdentifier identifier, Entity prefabEntity) {
Registry.Add((int) identifier, prefabEntity);
}
public Entity Get(PrefabRegistryIdentifier identifier) {
return Registry.TryGetValue((int) identifier, out var entity) ? entity : Entity.Null;
}
}
so that in a SpawnSystem
I can look up prefab entities by identifier and instantiate them like so:
public class SpawnSystem : SystemBase {
private PrefabRegistrySystem prefabRegistrySystem;
private BeginSimulationEntityCommandBufferSystem beginSimulationEntityCommandBufferSystem;
protected override void OnCreate() {
prefabRegistrySystem = World.GetOrCreateSystem<PrefabRegistrySystem>();
beginSimulationEntityCommandBufferSystem = World.GetOrCreateSystem<BeginSimulationEntityCommandBufferSystem>();
}
protected override void OnUpdate() {
var beginSimulationEntityCommandBuffer = beginSimulationEntityCommandBufferSystem.CreateCommandBuffer().AsParallelWriter();
var prefabRegistrySystemRegistry = prefabRegistrySystem.Registry;
Entities.WithReadOnly(prefabRegistrySystemRegistry).ForEach((Entity entity, int entityInQueryIndex, in UnitSpawnCommand unitSpawnCommand) => {
if (!prefabRegistrySystemRegistry.TryGetValue((int) unitSpawnCommand.PrefabRegistryIdentifier, out var prefabEntity)) {
var prefabEntityInstance = beginSimulationEntityCommandBuffer.Instantiate(entityInQueryIndex, prefabEntity);
// Hooray
}
}).ScheduleParallel();
beginSimulationEntityCommandBufferSystem.AddJobHandleForProducer(Dependency);
}
}
All this works without problems
The “issue” is that this conversion happens at runtime which is why I can just get the PrefabRegistrySystem
and shove entries into the NativeHashMap
.
So now, I’m thinking of putting the conversion into a SubScene, because that should be more efficient to load, as opposed to doing the runtime conversion every time I’m opening my game scene, right?
So I’m thinking of somehow storing a NativeHashMap in a BlobAsset where I’d store the same PrefabIdentifier → Entity mapping. The BlobAssets gets serialized into the subscene and should load very quickly.
So this is where my plan gets a little blurry…
Is a BlobAsset the only/correct way of approaching this? Because there doesn’t seem to be a BlobHashMap (?) in the collections/entities code
I was thinking something like this might make sense?
public struct PrefabAssetRegistryComponent : IComponentData {
public BlobAssetReference<BlobHashMap<int, Entity>> HashMap;
}
and in my PrefabRegistryAuthoring.Convert
method I’d do something like this:
entityManager.AddComponentData(entity, new PrefabAssetRegistryV2 {
BlobHashMapAssetReference = BlobHashMapAssetReferenceThatISomehowConstructed
});
Is it even a valid approach to persist Entities for lookup like that? (It feels like the Entity, which to my knowledge is basically just an index, wouldn’t be valid once the blob asset was deserialized from the subscene?)
And if/once I got this to work, what would be a good way to pluck out that BlobAsset?
Something like this:
var entityQuery = EntityManager.CreateEntityQuery(typeof(PrefabAssetRegistryComponent));
var entity = entityQuery.GetSingletonEntity();
if (entity != Entity.Null) {
var prefabAssetRegistry = entityQuery.GetSingleton<PrefabAssetRegistryComponent>();
if (prefabAssetRegistry.BlobHashMapAssetReference.Value.TryGetValue((int) PrefabRegistryIdentifier.Foo, out var fooPrefabEntity)) {
// Hooray
}
}
It would be immensely appreciated if someone could give me feedback if this is going into the right direction.
I’m not 100% sure if this “bake into subscene” is a desired approach in the first place.
Happy holidays