Skip to content

Instantly share code, notes, and snippets.

@jeffvella
Last active April 23, 2020 00:09
Show Gist options
  • Select an option

  • Save jeffvella/c8bcd49ee29fb2c85ab21aca9f5a9734 to your computer and use it in GitHub Desktop.

Select an option

Save jeffvella/c8bcd49ee29fb2c85ab21aca9f5a9734 to your computer and use it in GitHub Desktop.
using System;
using UnityEngine;
[CreateAssetMenu(menuName = "Data/" + nameof(Ingredient))]
public unsafe class Ingredient : ScriptableObjectDataProvider<Ingredient.IngredientData>
{
public enum Id
{
None = 0,
Carrot,
Potato,
ChickenThigh,
ChickenStock,
}
[Serializable]
public struct IngredientData : IScriptableObjectData
{
public Id Id;
public int Quantity;
public float Tastyness;
}
}
using System;
using System.Collections.Generic;
using Unity.Collections;
using Unity.Entities;
using UnityEngine;
public enum RecipeId
{
None = 0,
Stew,
StuffedPotatoes
}
[CreateAssetMenu(menuName = "Data/" + nameof(Recipe))]
public unsafe class Recipe : ScriptableObjectDataProvider
{
public RecipeId Id;
public string Description;
public List<Ingredient> Ingredients;
public int Value;
protected override IEnumerable<IComponentDataContainer> DeclareChildren()
{
return Ingredients;
}
public override void Convert(EntityManager em, Entity entity)
{
em.AddComponent<RecipeData>(entity);
em.SetComponentData(entity, new RecipeData
{
Id = Id,
Description = Description,
SomeValue = Value,
});
}
public override ComponentType GetDataComponentType()
=> ComponentType.ReadWrite<RecipeData>();
}
public struct RecipeData : IScriptableObjectData
{
public RecipeId Id;
public FixedString64 Description;
public int SomeValue;
}
using System;
using System.Collections;
using System.Collections.Generic;
using Unity.Entities;
using UnityEngine;
using Object = UnityEngine.Object;
public class ScriptableObjectAdapter : MonoBehaviour
{
public List<ScriptableObject> Data;
}
public class ScriptableObjectConversionSystem : GameObjectConversionSystem
{
private Dictionary<Guid, ConvertablesEntry> _entityByGuid = new Dictionary<Guid, ConvertablesEntry>();
private List<IComponentDataContainer> _convertables = new List<IComponentDataContainer>();
internal struct ConvertablesEntry
{
public Guid Id;
public Entity Entity;
public int ChildStartIndex;
public int ChildCount;
public int Depth;
public int Index;
}
protected override void OnUpdate()
{
_entityByGuid.Clear();
_convertables.Clear();
Entities.ForEach(delegate (ScriptableObjectAdapter adapter)
{
AddHybridComponent(adapter);
Entity adapterEntity = GetPrimaryEntity(adapter);
DstEntityManager.RemoveComponent<Transform>(adapterEntity);
for (int i = 0; i < adapter.Data.Count; i++)
{
if (adapter.Data[i] is IComponentDataContainer convertable)
{
_convertables.Add(convertable);
CollectRecursively(adapter, convertable, _entityByGuid.Count);
}
}
foreach (var item in _entityByGuid.Values)
{
var container = _convertables[item.Index];
var componentType = container.GetDataComponentType();
DeclareAssetDependency(adapter.gameObject, container.AsObject());
DstEntityManager.AddComponentData(item.Entity, new ScriptableObjectComponent
{
Id = item.Id,
Type = componentType
});
container.Convert(DstEntityManager, item.Entity);
if (item.ChildCount > 0)
{
var buffer = DstEntityManager.AddBuffer<LinkedChild>(item.Entity);
var len = item.ChildStartIndex + item.ChildCount;
for (int i = item.ChildStartIndex; i < len; i++)
{
var childContainer = _convertables[i];
var childItem = _entityByGuid[childContainer.Id];
buffer.Add(new LinkedChild
{
Id = childContainer.Id,
Entity = childItem.Entity
});
}
}
DstEntityManager.SetName(item.Entity, container.Name);
}
});
}
public struct LinkedChild : IBufferElementData
{
public Guid Id;
public Entity Entity;
}
private void CollectRecursively(ScriptableObjectAdapter adapter, IComponentDataContainer convertable, int index, int depth = 0)
{
if (depth > 5)
throw new InvalidOperationException();
var id = convertable.Id;
var previousCount = _convertables.Count;
if (!_entityByGuid.ContainsKey(id))
{
var children = convertable.DeclareChildren();
if (children == null)
{
_entityByGuid[id] = new ConvertablesEntry
{
Id = id,
Index = index,
Entity = CreateAdditionalEntity(adapter.gameObject),
Depth = depth
};
return;
}
_convertables.AddRange(children);
_entityByGuid[id] = new ConvertablesEntry
{
Id = id,
Index = index,
Entity = CreateAdditionalEntity(adapter.gameObject),
ChildStartIndex = previousCount,
ChildCount = _convertables.Count - previousCount,
Depth = depth
};
var i = 1;
foreach (var child in children)
{
CollectRecursively(adapter, child, index + i++, ++depth);
}
}
}
}
public struct ScriptableObjectComponent : IComponentData
{
public ComponentType Type;
public Guid Id;
public Entity Parent;
}
public interface IComponentDataContainer<T> : IComponentDataContainer where T : struct, IScriptableObjectData
{
T Data { get; }
}
public interface IComponentDataContainer
{
Guid Id { get; }
string Name { get; }
ComponentType GetDataComponentType();
void Convert(EntityManager em, Entity entity);
IEnumerable<IComponentDataContainer> DeclareChildren();
Object AsObject();
}
public unsafe abstract class ScriptableObjectDataProvider<T> : ScriptableObjectDataProvider, IComponentDataContainer<T> where T : unmanaged, IScriptableObjectData
{
public T Data;
T IComponentDataContainer<T>.Data => Data;
public override ComponentType GetDataComponentType()
=> ComponentType.ReadWrite<T>();
public override void Convert(EntityManager em, Entity entity)
{
em.AddComponent(entity, typeof(T));
em.SetComponentData(entity, Data);
}
}
public unsafe abstract class ScriptableObjectDataProvider : ScriptableObject, IComponentDataContainer
{
[HideInInspector, SerializeField]
protected Guid _id = Guid.NewGuid();
string IComponentDataContainer.Name => name;
Guid IComponentDataContainer.Id => _id;
public abstract ComponentType GetDataComponentType();
protected virtual IEnumerable<IComponentDataContainer> DeclareChildren() => default;
IEnumerable<IComponentDataContainer> IComponentDataContainer.DeclareChildren() => DeclareChildren();
Object IComponentDataContainer.AsObject() => this;
public abstract void Convert(EntityManager em, Entity entity);
}
public interface IScriptableObjectData : IComponentData
{
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment