diff --git a/src/DataInterfaces.cs b/src/DataInterfaces.cs index 8bc9fb5..c4fe766 100644 --- a/src/DataInterfaces.cs +++ b/src/DataInterfaces.cs @@ -8,6 +8,7 @@ namespace DCFApixels.DragonECS public interface IEcsWorldComponent { void Init(ref T component, EcsWorld world); + void OnDestroy(ref T component, EcsWorld world); } public static class EcsWorldComponentHandler { @@ -30,6 +31,7 @@ namespace DCFApixels.DragonECS { [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Init(ref T component, EcsWorld world) { } + public void OnDestroy(ref T component, EcsWorld world) { } } } internal class WorldComponentHandler : IEcsWorldComponent @@ -38,6 +40,7 @@ namespace DCFApixels.DragonECS private T _fakeInstnace; [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Init(ref T component, EcsWorld world) => _fakeInstnace.Init(ref component, world); + public void OnDestroy(ref T component, EcsWorld world) => _fakeInstnace.OnDestroy(ref component, world); } #endregion diff --git a/src/EcsWorld.cs b/src/EcsWorld.cs index 7787bff..475e986 100644 --- a/src/EcsWorld.cs +++ b/src/EcsWorld.cs @@ -4,9 +4,18 @@ using System; using System.Collections.Generic; using System.Reflection; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; namespace DCFApixels.DragonECS { + [StructLayout(LayoutKind.Sequential, Pack = 4, Size = 4)] + public struct EcsWorldDataRef where T : struct + { + private int _worldID; + public EcsWorldDataRef(int worldID) => _worldID = worldID; + public EcsWorld World => EcsWorld.GetWorld(_worldID); + public ref T Inst => ref EcsWorld.GetData(_worldID); + } public abstract partial class EcsWorld { private const short GEN_BITS = 0x7fff; @@ -16,21 +25,41 @@ namespace DCFApixels.DragonECS internal static EcsWorld[] Worlds = new EcsWorld[4]; private static IntDispenser _worldIdDispenser = new IntDispenser(0); + private static List _dataReleaseres = new List(); + + static EcsWorld() { Worlds[0] = new EcsNullWorld(); } - + private static void ReleaseData(int worldID) + { + for (int i = 0, iMax = _dataReleaseres.Count; i < iMax; i++) + _dataReleaseres[i].Release(worldID); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static EcsWorld GetWorld(int worldID) => Worlds[worldID]; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ref T GetData(int worldID) => ref WorldComponentPool.GetForWorld(worldID); + + private abstract class DataReleaser + { + public abstract void Release(int worldID); + } private static class WorldComponentPool { private static T[] _items = new T[4]; private static int[] _mapping = new int[4]; private static int _count; + private static int[] _recycledItems = new int[4]; + private static int _recycledItemsCount; private static IEcsWorldComponent _interface = EcsWorldComponentHandler.instance; + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ref T Get(int itemIndex) => ref _items[itemIndex]; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ref T GetForWorld(int worldID) => ref _items[GetItemIndex(worldID)]; public static int GetItemIndex(int worldID) { if (_mapping.Length < Worlds.Length) @@ -39,13 +68,36 @@ namespace DCFApixels.DragonECS ref int itemIndex = ref _mapping[worldID]; if (itemIndex <= 0) { - itemIndex = ++_count; + if(_recycledItemsCount > 0) + { + _count++; + itemIndex = _recycledItems[--_recycledItemsCount]; + } + else + { + itemIndex = ++_count; + } _interface.Init(ref _items[itemIndex], Worlds[worldID]); + _dataReleaseres.Add(new Releaser()); } return itemIndex; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ref T GetForWorld(int worldID) => ref _items[GetItemIndex(worldID)]; + private static void Release(int worldID) + { + ref int itemIndex = ref _mapping[worldID]; + if(itemIndex != 0) + { + _interface.OnDestroy(ref _items[itemIndex], Worlds[worldID]); + _recycledItems[_recycledItemsCount++] = itemIndex; + } + } + private sealed class Releaser : DataReleaser + { + public sealed override void Release(int worldID) + { + WorldComponentPool.Release(worldID); + } + } } } public abstract partial class EcsWorld @@ -127,6 +179,7 @@ namespace DCFApixels.DragonECS _subjects = null; _executors = null; Worlds[id] = null; + ReleaseData(id); _worldIdDispenser.Release(id); } #endregion @@ -183,7 +236,7 @@ namespace DCFApixels.DragonECS } return (TExecutor)result; } - public ref T GetComponent() where T : struct => ref WorldComponentPool.GetForWorld(id); + public ref T Get() where T : struct => ref WorldComponentPool.GetForWorld(id); #endregion #region Where Query