using DCFApixels.DragonECS.Internal; using System; using System.Collections.Generic; using System.Linq; using System.Runtime.CompilerServices; namespace DCFApixels.DragonECS { public interface IEcsPool { #region Properties int ComponentID { get; } Type ComponentType { get; } EcsWorld World { get; } int Count { get; } int Capacity { get; } #endregion #region Methods bool Has(int entityID); void Del(int entityID); void AddRaw(int entityID, object dataRaw); object GetRaw(int entityID); void SetRaw(int entityID, object dataRaw); void Copy(int fromEntityID, int toEntityID); void Copy(int fromEntityID, EcsWorld toWorld, int toEntityID); #endregion #region Add/Remove Listeners void AddListener(IEcsPoolEventListener listener); void RemoveListener(IEcsPoolEventListener listener); #endregion } public interface IEcsPool { ref T Add(int entityID); ref readonly T Read(int entityID); ref T Get(int entityID); } /// Only used to implement a custom pool. In other contexts use IEcsPool or IEcsPool. public interface IEcsPoolImplementation : IEcsPool { void OnInit(EcsWorld world, int componentID); void OnWorldResize(int newSize); void OnReleaseDelEntityBuffer(ReadOnlySpan buffer); void OnWorldDestroy(); } /// Only used to implement a custom pool. In other contexts use IEcsPool or IEcsPool. /// Component type public interface IEcsPoolImplementation : IEcsPool, IEcsPoolImplementation { } public static class EcsPoolThrowHalper { public static void ThrowAlreadyHasComponent(int entityID) { throw new EcsFrameworkException($"Entity({entityID}) already has component {typeof(T).Name}."); } public static void ThrowNotHaveComponent(int entityID) { throw new EcsFrameworkException($"Entity({entityID}) has no component {typeof(T).Name}."); } } public static class IEcsPoolImplementationExtensions { [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void IncrementEntityComponentCount(this IEcsPoolImplementation self, int entityID) { self.World.IncrementEntityComponentCount(entityID); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void DecrementEntityComponentCount(this IEcsPoolImplementation self, int entityID) { self.World.DecrementEntityComponentCount(entityID); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsNullOrDummy(this IEcsPool self) { return self == null || self == EcsNullPool.instance; } } #region Dummy EcsNullPool namespace Internal { public struct NullComponent { } public sealed class EcsNullPool : IEcsPoolImplementation { public static EcsNullPool instance => new EcsNullPool(); #region Properties int IEcsPool.ComponentID => -1; Type IEcsPool.ComponentType => typeof(NullComponent); EcsWorld IEcsPool.World => throw new NotImplementedException(); public int Count => -1; public int Capacity => -1; #endregion #region Methods bool IEcsPool.Has(int index) => false; void IEcsPool.Del(int entityID) => throw new NotImplementedException(); void IEcsPool.AddRaw(int entityID, object dataRaw) => throw new NotImplementedException(); object IEcsPool.GetRaw(int entityID) => throw new NotImplementedException(); void IEcsPool.SetRaw(int entity, object dataRaw) => throw new NotImplementedException(); void IEcsPool.Copy(int fromEntityID, int toEntityID) => throw new NotImplementedException(); void IEcsPool.Copy(int fromEntityID, EcsWorld toWorld, int toEntityID) => throw new NotImplementedException(); ref NullComponent IEcsPool.Add(int entityID) => throw new NotImplementedException(); ref readonly NullComponent IEcsPool.Read(int entityID) => throw new NotImplementedException(); ref NullComponent IEcsPool.Get(int entityID) => throw new NotImplementedException(); #endregion #region Callbacks void IEcsPoolImplementation.OnInit(EcsWorld world, int componentID) { } void IEcsPoolImplementation.OnWorldDestroy() { } void IEcsPoolImplementation.OnWorldResize(int newSize) { } void IEcsPoolImplementation.OnReleaseDelEntityBuffer(ReadOnlySpan buffer) { } #endregion #region Listeners public void AddListener(IEcsPoolEventListener listener) { } public void RemoveListener(IEcsPoolEventListener listener) { } #endregion } } #endregion #region Reset/Copy interfaces public interface IEcsComponentReset { void Reset(ref T component); } public static class EcsComponentResetHandler { public static readonly IEcsComponentReset instance; public static readonly bool isHasHandler; static EcsComponentResetHandler() { Type targetType = typeof(T); if (targetType.GetInterfaces().Contains(typeof(IEcsComponentReset<>).MakeGenericType(targetType))) { instance = (IEcsComponentReset)Activator.CreateInstance(typeof(ComponentResetHandler<>).MakeGenericType(targetType)); isHasHandler = true; } else { instance = new ComponentResetDummyHandler(); isHasHandler = false; } } } internal sealed class ComponentResetDummyHandler : IEcsComponentReset { [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Reset(ref T component) => component = default; } internal sealed class ComponentResetHandler : IEcsComponentReset where T : IEcsComponentReset { private T _fakeInstnace = default; [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Reset(ref T component) => _fakeInstnace.Reset(ref component); } public interface IEcsComponentCopy { void Copy(ref T from, ref T to); } public static class EcsComponentCopyHandler { public static readonly IEcsComponentCopy instance; public static readonly bool isHasHandler; static EcsComponentCopyHandler() { Type targetType = typeof(T); if (targetType.GetInterfaces().Contains(typeof(IEcsComponentCopy<>).MakeGenericType(targetType))) { instance = (IEcsComponentCopy)Activator.CreateInstance(typeof(ComponentCopyHandler<>).MakeGenericType(targetType)); isHasHandler = true; } else { instance = new ComponentCopyDummyHandler(); isHasHandler = false; } } } internal sealed class ComponentCopyDummyHandler : IEcsComponentCopy { [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Copy(ref T from, ref T to) => to = from; } internal sealed class ComponentCopyHandler : IEcsComponentCopy where T : IEcsComponentCopy { private T _fakeInstnace = default; [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Copy(ref T from, ref T to) => _fakeInstnace.Copy(ref from, ref to); } #endregion #region Callbacks Interface public interface IEcsPoolEventListener { /// Called after adding an entity to the pool, but before changing values void OnAdd(int entityID); /// Is called when EcsPool.Get or EcsPool.Add is called, but before changing values void OnGet(int entityID); /// Called after deleting an entity from the pool void OnDel(int entityID); } public static class PoolEventListExtensions { [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InvokeOnAdd(this List self, int entityID) { for (int i = 0, iMax = self.Count; i < iMax; i++) self[i].OnAdd(entityID); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InvokeOnAddAndGet(this List self, int entityID) { for (int i = 0, iMax = self.Count; i < iMax; i++) { self[i].OnAdd(entityID); self[i].OnGet(entityID); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InvokeOnGet(this List self, int entityID) { for (int i = 0, iMax = self.Count; i < iMax; i++) self[i].OnGet(entityID); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void InvokeOnDel(this List self, int entityID) { for (int i = 0, iMax = self.Count; i < iMax; i++) self[i].OnDel(entityID); } } #endregion }