After a day of struggling, I’m convinced that EntityCommandBuffer.Instantiate() is not copying ComponentObject from prefabs.
Here’s a simplified version of my system that instantiates and then reads an entity with ComponentObject.
I’m using the HelloCube_06 convert style (IDeclareReferencedPrefabs), with a GameObjectConversionSystem to convert my MonoBehaviour.
public class FeaturesSpawnSystem : ComponentSystem
{
protected override void OnUpdate()
{
Entities.ForEach((Entity entity, ref FeatureSpawnerRequestData request) =>
{
var proto = EntityManager.GetComponentObject<FeaturePrototype>(request.Spawner.Prefab);
Debug.LogWarning("PREFAB Prototype object = "+ proto);
for (int i = 0; i < request.Count; ++i)
{
var instance = PostUpdateCommands.Instantiate(request.Spawner.Prefab);
var spawnedData = new FeatureSpawnedData { Index = request.Index + i };
PostUpdateCommands.SetComponent(instance, spawnedData);
Debug.Log("FeaturesSpawnSystem: Spawning [" + spawnedData.Index + "]...");
}
PostUpdateCommands.DestroyEntity(entity);
});
}
[UpdateAfter(typeof(FeaturesSpawnSystem))]
public class FeaturesSpawnedSystem : ComponentSystem
{
protected override void OnUpdate()
{
Entities.ForEach((Entity entity, ref FeatureSpawnedData spawned) =>
{
Debug.Log("FeaturesSpawnedSystem: Spawned [" + spawned.Index + "]...");
var proto = EntityManager.GetComponentObject<FeaturePrototype>(entity);
Debug.LogWarning("Prototype [" + proto + "]");
});
}
}
}
EntityCommandBuffer.Instantiate is only capable of creating pure entities. However, you can instantiate an entity, and then add Component Objects from your scene to it via EntityManager.AddComponentObject.
Too bad, that breaks some of my jobs.
I now have to keep an eye on prefabs that have Objects, and to iterate one by one afterwards just to instantiate the Objects. Or make all the MonoBehaviours check eternally on Update(), something we’re trying to get rid of.
Anyone knows if that’s a permanent limitation or will be available on the final release?
I have been working on a way to add Hybrid Components (i.e. MonoBehaviours) to otherwise pure entities, and my current implementation of this is posted on another thread: Animator and CharacterController with ECS?
I came across your solution, but I thought it was too much code to do so little work of just copying an object reference.
Instantiating a prefab should bring everything, and if it doesn’t there’s a flaw, imo.
My systems changed a less than I expected to copy that object reference.
I save a reference to the original prefab and copy from it on the Spawned system
public class FeaturesSpawnSystem : ComponentSystem
{
protected override void OnUpdate()
{
Entities.ForEach((Entity entity, ref FeatureSpawnerRequestData request) =>
{
for (int i = 0; i < request.Count; ++i)
{
var instance = PostUpdateCommands.Instantiate(request.Spawner.Prefab);
var spawnedData = new FeatureSpawnedData {
Prefab = request.Spawner.Prefab
Index = request.Index + i,
};
PostUpdateCommands.SetComponent(instance, spawnedData);
}
PostUpdateCommands.DestroyEntity(entity);
});
}
[UpdateAfter(typeof(FeaturesSpawnSystem))]
public class FeaturesSpawnedSystem : ComponentSystem
{
protected override void OnUpdate()
{
Entities.ForEach((Entity entity, ref FeatureSpawnedData spawned) =>
{
// Copy the dam object!
var proto = EntityManager.GetComponentObject<FeaturePrototype>(spawned.Prefab);
EntityManager.AddComponentObject(entity, proto);
proto = EntityManager.GetComponentObject<FeaturePrototype>(entity);
Debug.LogWarning("Prototype [" + proto + "]");
});
}
}
}
It’s hard to switch our mind to ECS and get rid of MonoBehaviours.
What can we gain from having an object reference? It’s no more a MonoBehaviour, will respond to any events, so we can use only it’s data and methods. And that’s what ECS is good for, data and logic. The converter also makes more sense now. My proxy class was getting complicated, them I realized everything I was doing before converting was actually a GameObjectConversionSystem. Now it’s clean and simple.
Then why have the object at all? To hold strings! And send stuff to the UI.
At the moment I do everything purely through ECS, so my UI’s just hold a reverse reference to a Entity to look at and conditionally check for existence, then pull data. I’ve profiled them checking every frame from monobehaviours to populate the UI is actually pretty reasonable. As for strings, if you can accept a fixed limit in size there is NativeString in 64, 512, 4096 size limits if I’m remembering the numbers right.
Don’t know if your using sharedcomponents as those can hold managed references just fine (with tradeoffs of course)