forked from Misaki/GhostEngine
Major ECS API overhaul: added ComponentSet, refactored ComponentRegistry, and updated all entity/component creation methods. Introduced robust custom serialization infrastructure and per-component source generators for registration and (de)serialization. Updated editor, engine, and test code to use new APIs. Improved code quality, naming, and performance throughout. Removed obsolete code and updated dependencies.
257 lines
6.6 KiB
C#
257 lines
6.6 KiB
C#
#if false
|
|
using Ghost.Core;
|
|
using Misaki.HighPerformance.Collections;
|
|
using System.Runtime.CompilerServices;
|
|
|
|
namespace Ghost.Entities;
|
|
|
|
public interface IManagedComponent;
|
|
public interface IManagedWrapper;
|
|
|
|
public readonly struct Managed<T> : IComponent, IManagedWrapper
|
|
where T : IManagedComponent
|
|
{
|
|
public readonly int id;
|
|
public readonly int generation;
|
|
|
|
internal Managed(int id, int generation)
|
|
{
|
|
this.id = id;
|
|
this.generation = generation;
|
|
}
|
|
}
|
|
|
|
public static class ManagedComponemtnID<T>
|
|
where T : IManagedComponent
|
|
{
|
|
public static readonly Identifier<IManagedComponent> value = ManagedComponentRegistry.GetOrRegisterComponent<T>();
|
|
}
|
|
|
|
internal struct ManagedComponentInfo
|
|
{
|
|
public int id;
|
|
public bool isScriptComponent;
|
|
}
|
|
|
|
internal static class ManagedComponentRegistry
|
|
{
|
|
private static readonly List<ManagedComponentInfo> s_registeredComponents = new();
|
|
private static readonly Dictionary<IntPtr, int> s_typeHandleToID = new();
|
|
private static readonly Dictionary<string, int> s_nameToRuntimeID = new();
|
|
#if DEBUG || GHOST_EDITOR
|
|
internal static readonly Dictionary<int, Type> s_runtimeIDToType = new();
|
|
#endif
|
|
|
|
public static Identifier<IManagedComponent> GetOrRegisterComponent<T>()
|
|
where T : IManagedComponent
|
|
{
|
|
var typeHandle = typeof(T).TypeHandle.Value;
|
|
|
|
lock (s_registeredComponents)
|
|
{
|
|
if (s_typeHandleToID.TryGetValue(typeHandle, out var existingID))
|
|
{
|
|
return existingID;
|
|
}
|
|
|
|
var newID = new Identifier<IManagedComponent>(s_registeredComponents.Count);
|
|
var stableName = typeof(T).FullName ?? typeof(T).Name;
|
|
var info = new ManagedComponentInfo
|
|
{
|
|
id = newID,
|
|
isScriptComponent = typeof(ScriptComponent).IsAssignableFrom(typeof(T)),
|
|
};
|
|
|
|
s_registeredComponents.Add(info);
|
|
|
|
s_typeHandleToID[typeHandle] = newID;
|
|
s_nameToRuntimeID[stableName] = newID;
|
|
#if DEBUG || GHOST_EDITOR
|
|
s_runtimeIDToType[newID.value] = typeof(T);
|
|
#endif
|
|
|
|
return newID;
|
|
}
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static Identifier<IManagedComponent> GetComponentID(Type type)
|
|
{
|
|
var typeHandle = type.TypeHandle.Value;
|
|
lock (s_registeredComponents)
|
|
{
|
|
if (s_typeHandleToID.TryGetValue(typeHandle, out var existingID))
|
|
{
|
|
return existingID;
|
|
}
|
|
}
|
|
|
|
return Identifier<IManagedComponent>.Invalid;
|
|
}
|
|
|
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
public static ManagedComponentInfo GetComponentInfo(Identifier<IManagedComponent> typeId)
|
|
{
|
|
lock (s_registeredComponents)
|
|
{
|
|
return s_registeredComponents[typeId];
|
|
}
|
|
}
|
|
}
|
|
|
|
internal interface IManagedComponentStorage
|
|
{
|
|
public Identifier<IManagedComponent> TypeID { get; }
|
|
}
|
|
|
|
internal class ManagedComponentStorage<T> : IManagedComponentStorage
|
|
where T : IManagedComponent
|
|
{
|
|
private readonly SlotMap<T> _storage = new(16);
|
|
|
|
public Identifier<IManagedComponent> TypeID => ManagedComponemtnID<T>.value;
|
|
|
|
public Managed<T> Add(T component)
|
|
{
|
|
var id = _storage.Add(component, out var generation);
|
|
return new Managed<T>(id, generation);
|
|
}
|
|
|
|
public void Remove(Managed<T> managed)
|
|
{
|
|
_storage.Remove(managed.id, managed.generation);
|
|
}
|
|
|
|
public ref T GetComponentReference(Managed<T> managed)
|
|
{
|
|
return ref _storage.GetElementReferenceAt(managed.id, managed.generation, out _);
|
|
}
|
|
}
|
|
|
|
public abstract class ScriptComponent : IManagedComponent
|
|
{
|
|
internal World _world = null!;
|
|
internal Entity _entity;
|
|
|
|
public World World => _world;
|
|
public Entity Entity => _entity;
|
|
|
|
protected ref T GetComponent<T>()
|
|
where T : unmanaged, IComponent
|
|
{
|
|
return ref _world.EntityManager.GetComponent<T>(_entity);
|
|
}
|
|
|
|
public virtual void OnCreate()
|
|
{
|
|
}
|
|
|
|
public virtual void OnDestroy()
|
|
{
|
|
}
|
|
|
|
public virtual void OnEnable()
|
|
{
|
|
}
|
|
|
|
public virtual void OnDisable()
|
|
{
|
|
}
|
|
|
|
public virtual void Start()
|
|
{
|
|
}
|
|
|
|
public virtual void Update()
|
|
{
|
|
}
|
|
|
|
public virtual void FixedUpdate()
|
|
{
|
|
}
|
|
|
|
public virtual void LateUpdate()
|
|
{
|
|
}
|
|
}
|
|
|
|
public partial class EntityManager
|
|
{
|
|
private IManagedComponentStorage[] _storages;
|
|
|
|
internal IManagedComponentStorage[] Storages => _storages;
|
|
|
|
private ManagedComponentStorage<T> GetOrCreateManagedComponentStorage<T>()
|
|
where T : IManagedComponent
|
|
{
|
|
var id = ManagedComponemtnID<T>.value;
|
|
if (_storages == null || _storages.Length <= id.value)
|
|
{
|
|
Array.Resize(ref _storages, id.value + 1);
|
|
}
|
|
|
|
ref var storage = ref _storages[id.value];
|
|
storage ??= new ManagedComponentStorage<T>();
|
|
|
|
return (ManagedComponentStorage<T>)storage;
|
|
}
|
|
|
|
public Managed<T> AddManagedComponent<T>(Entity entity)
|
|
where T : IManagedComponent, new()
|
|
{
|
|
var instance = new T();
|
|
if (instance is ScriptComponent scriptComponent)
|
|
{
|
|
scriptComponent._world = _world;
|
|
scriptComponent._entity = entity;
|
|
scriptComponent.OnCreate();
|
|
}
|
|
|
|
var managed = GetOrCreateManagedComponentStorage<T>().Add(instance);
|
|
AddComponent(entity, managed);
|
|
|
|
return managed;
|
|
}
|
|
|
|
public bool RemoveManagedComponent<T>(Entity entity)
|
|
where T : IManagedComponent
|
|
{
|
|
ref var component = ref GetComponent<Managed<T>>(entity);
|
|
if (!Unsafe.IsNullRef(ref component))
|
|
{
|
|
var storage = GetOrCreateManagedComponentStorage<T>();
|
|
var componentRef = storage.GetComponentReference(component);
|
|
if (componentRef is ScriptComponent scriptComponent)
|
|
{
|
|
scriptComponent.OnDestroy();
|
|
}
|
|
|
|
RemoveComponent<Managed<T>>(entity);
|
|
storage.Remove(component);
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public ref T GetManagedComponent<T>(Entity entity)
|
|
where T : IManagedComponent
|
|
{
|
|
ref var component = ref GetComponent<Managed<T>>(entity);
|
|
if (Unsafe.IsNullRef(ref component))
|
|
{
|
|
return ref Unsafe.NullRef<T>();
|
|
}
|
|
|
|
return ref GetOrCreateManagedComponentStorage<T>().GetComponentReference(component);
|
|
}
|
|
|
|
public ref T GetManagedComponent<T>(Managed<T> managedComponent)
|
|
where T : IManagedComponent
|
|
{
|
|
return ref GetOrCreateManagedComponentStorage<T>().GetComponentReference(managedComponent);
|
|
}
|
|
}
|
|
#endif
|