Something like this was recently mentioned here, but nothing was said about a more automatic system for handling ScriptableObjects:
In my case, I use ScriptableObjects to describe a “species”. This contains GameObject lists for instances, and other shared data applied to the GameObject. Doing it this way makes it easier to query for species entities and propagate instances, and also saves time because I don’t need to set up monobehaviour(s) for every instance.
In my scene I have a MonoBehaviour referencing these ScriptableObjects. The problem with this is IConvertGameObjectToEntity(specifically DeclareReferencedAsset), does not declare any nested ScriptableObjects. So you need to either explicitly declare any other nested assets/gameobjects contained in a ScriptableObject(for every conversion script?), or add your own IDeclareReferencedAssets/IConvertObjectToEntity interfaces and conversion systems.
I’ve done the latter and created a hacky recursive referencing system, but it will only work for that specific MonoBehaviour.
So my questions are:
Is there a more robust system planned for converting ScriptableObjects into entity assets?
For my systems, is there currently a way to find only ScriptableObjects that are referenced in the scene? Or is there something about the conversion I’m missing? Object.FindObjectsOfType doesn’t find assets and Resources.FindObjectsOfTypeAll finds all loaded assets, not just ones in the current scene.
I’ve put together something that is working for me and is pretty generic. Probably not very robust, but it should convert any ScriptableObject referenced by a MonoBehaviour implementing IDeclareReferencedAssets(and the ScriptableObjects themselves can declare their own assets/prefabs).
using System.Collections.Generic;
using System.Linq;
using Unity.Entities;
using UnityEngine;
namespace WOM.ObjectConversion {
public interface IConvertObjectToEntity {
void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem);
}
public interface IDeclareReferencedAssets {
void DeclareReferencedAssets(List<ScriptableObject> referencedAssets);
}
[UpdateInGroup(typeof(GameObjectConversionGroup))]
public class ScriptableObjectConversionSystem : GameObjectConversionSystem {
protected override void OnUpdate() {
Entities.WithAll<Asset>().ForEach(entity => {
using(var types = EntityManager.GetComponentTypes(entity)) {
var derivedType = types.FirstOrDefault(
t => typeof(IConvertObjectToEntity).IsAssignableFrom(t.GetManagedType()));
Object asset = EntityManager.GetComponentObject<Object>(entity, derivedType);
Entity e = GetPrimaryEntity(asset);
((IConvertObjectToEntity)asset).Convert(e, dstManager:smile:stEntityManager, conversionSystem:this);
}
});
}
}
}
using System.Collections.Generic;
using System.Linq;
using Unity.Entities;
using UnityEngine;
namespace WOM.ObjectConversion {
/// <summary>
/// Declares references to all scriptable objects referenced by a monobehaviour.
/// </summary>
[UpdateInGroup(typeof(GameObjectDeclareReferencedObjectsGroup))]
public class ScriptableObjectReferenceSystem : GameObjectConversionSystem {
protected override void OnUpdate() {
var monobehaviours = GameObject.FindObjectsOfType<MonoBehaviour>().OfType<IDeclareReferencedAssets>();
foreach(IDeclareReferencedAssets referencer in monobehaviours) {
var references = new List<ScriptableObject>();
referencer.DeclareReferencedAssets(references);
foreach(ScriptableObject reference in references) {
DeclareReferencesRecursive(reference);
}
}
}
void DeclareReferencesRecursive(ScriptableObject asset) {
DeclareReferencedAsset(asset);
if(asset is IDeclareReferencedAssets) {
var referencedAssets = new List<ScriptableObject>();
((IDeclareReferencedAssets)asset).DeclareReferencedAssets(referencedAssets);
foreach(var assetChild in referencedAssets) {
DeclareReferencesRecursive(assetChild);
}
}
if(asset is IDeclareReferencedPrefabs) {
var referencedPrefabs = new List<GameObject>();
((IDeclareReferencedPrefabs)asset).DeclareReferencedPrefabs(referencedPrefabs);
foreach(var prefab in referencedPrefabs) {
DeclareReferencedPrefab(prefab);
}
}
}
}
}