Skip to content

Instantly share code, notes, and snippets.

@jeffvella
Created October 9, 2019 18:08
Show Gist options
  • Save jeffvella/aaa4f8faf7bf384c85079343868eb32b to your computer and use it in GitHub Desktop.
Save jeffvella/aaa4f8faf7bf384c85079343868eb32b to your computer and use it in GitHub Desktop.
Experiment with ScriptableObject entity conversion
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Entities;
using Unity.Mathematics;
using UnityEngine;
public struct LevelDataComponent : IComponentData
{
public int Id;
public NativeString512 Text;
}
[CreateAssetMenu]
public class LevelData : EcsScriptableObject<LevelDataComponent>
{
public int Id;
public string Text;
public override LevelDataComponent Convert(EntityManager dstEntityManager, Entity entity)
{
return new LevelDataComponent
{
Id = Id,
Text = new NativeString512(Text)
};
}
}
[Serializable]
public struct SomeGameData : IComponentData
{
public UnsafeList Stuff;
public NativeString512 Text;
public bool GodMode;
}
[CreateAssetMenu]
public class GameData : EcsScriptableObject<SomeGameData>
{
public List<int> ManagedStuff;
public string Text;
public bool GodMode;
public override SomeGameData Convert(EntityManager dstEntityManager, Entity entity)
{
var unmanagedStuff = new UnsafeList(Allocator.Persistent); // yummy leaks
for (int i = 0; i < ManagedStuff.Count; i++)
unmanagedStuff.Add(ManagedStuff[i]);
return new SomeGameData
{
Stuff = unmanagedStuff,
Text = new NativeString512(Text),
GodMode = GodMode,
};
}
}
public abstract class EcsScriptableObject : ScriptableObject
{
public static Dictionary<int, ScriptableObjectAccessor> ByInstanceId = new Dictionary<int, ScriptableObjectAccessor>();
public static ConcurrentQueue<ScriptableObjectAccessor> PendingConversion = new ConcurrentQueue<ScriptableObjectAccessor>();
public abstract void Convert(EntityManager dstEntityManager, ScriptableObjectAccessor accessor);
public abstract string GetComponentTypeName();
}
public class ScriptableObjectAccessor
{
public Entity Entity;
public EcsScriptableObject Instance;
}
public abstract class EcsScriptableObject<TComponentData> : EcsScriptableObject where TComponentData : unmanaged, IComponentData
{
protected EcsScriptableObject()
{
var accessor = new ScriptableObjectAccessor
{
Instance = this,
Entity = Entity.Null,
};
PendingConversion.Enqueue(accessor);
ByInstanceId.Add(GetInstanceID(), accessor);
}
public override void Convert(EntityManager dstEntityManager, ScriptableObjectAccessor accessor)
{
var component = Convert(dstEntityManager, accessor.Entity);
dstEntityManager.AddComponentData(accessor.Entity, component);
}
public override string GetComponentTypeName() => typeof(TComponentData).Name;
public abstract TComponentData Convert(EntityManager dstEntityManager, Entity entity);
}
public class ScriptableObjectConversion : GameObjectConversionSystem
{
protected override void OnUpdate()
{
while (EcsScriptableObject.PendingConversion.Count > 0)
{
if (EcsScriptableObject.PendingConversion.TryDequeue(out var so))
{
so.Entity = DstEntityManager.CreateEntity();
so.Instance.Convert(DstEntityManager, so);
DstEntityManager.SetName(so.Entity, $"SO: {so.Instance.GetType().Name}<{so.Instance.GetComponentTypeName()}>");
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment