diff --git a/src/EcsAspect.cs b/src/EcsAspect.cs index b2fc09b..b96e091 100644 --- a/src/EcsAspect.cs +++ b/src/EcsAspect.cs @@ -2,7 +2,7 @@ using DCFApixels.DragonECS.PoolsCore; using System; using System.Collections.Generic; -using System.Runtime.CompilerServices; +using static DCFApixels.DragonECS.EcsAspect; namespace DCFApixels.DragonECS { @@ -138,29 +138,6 @@ namespace DCFApixels.DragonECS builder.Build(out newAspect._mask); newAspect._isBuilt = true; - newAspect._sortIncBuffer = new UnsafeArray(newAspect._mask._inc.Length, true); - newAspect._sortExcBuffer = new UnsafeArray(newAspect._mask._exc.Length, true); - newAspect._sortIncChunckBuffer = new UnsafeArray(newAspect._mask._incChunckMasks.Length, true); - newAspect._sortExcChunckBuffer = new UnsafeArray(newAspect._mask._excChunckMasks.Length, true); - - for (int i = 0; i < newAspect._sortIncBuffer.Length; i++) - { - newAspect._sortIncBuffer.ptr[i] = newAspect._mask._inc[i]; - } - for (int i = 0; i < newAspect._sortExcBuffer.Length; i++) - { - newAspect._sortExcBuffer.ptr[i] = newAspect._mask._exc[i]; - } - - for (int i = 0; i < newAspect._sortIncChunckBuffer.Length; i++) - { - newAspect._sortIncChunckBuffer.ptr[i] = newAspect._mask._incChunckMasks[i]; - } - for (int i = 0; i < newAspect._sortExcChunckBuffer.Length; i++) - { - newAspect._sortExcChunckBuffer.ptr[i] = newAspect._mask._excChunckMasks[i]; - } - return (TAspect)newAspect; } @@ -224,27 +201,6 @@ namespace DCFApixels.DragonECS } #endregion - #region Finalizator - unsafe ~EcsAspect() - { - _sortIncBuffer.Dispose(); - _sortExcBuffer.Dispose(); - _sortIncChunckBuffer.Dispose(); - _sortExcChunckBuffer.Dispose(); - } - #endregion - - #region Iterator - public Iterator GetIterator() - { - return new Iterator(this, _source.Entities); - } - public Iterator GetIteratorFor(EcsSpan span) - { - return new Iterator(this, span); - } - #endregion - #region Combined private readonly struct Combined { @@ -259,17 +215,48 @@ namespace DCFApixels.DragonECS #endregion #region Iterator + [Obsolete("Use EcsMask.GetIterator()")] + public Iterator GetIterator() + { + return new Iterator(Mask.GetIterator(), _source.Entities); + } + [Obsolete("Use EcsMask.GetIterator().Iterate(span)")] + public Iterator GetIteratorFor(EcsSpan span) + { + return new Iterator(Mask.GetIterator(), span); + } + [Obsolete("Use EcsMaskIterator")] public ref struct Iterator { public readonly short worldID; - public readonly EcsAspect aspect; + public readonly EcsMaskIterator.Enumerable iterator; private EcsSpan _span; - public Iterator(EcsAspect aspect, EcsSpan span) + public Iterator(EcsMaskIterator iterator, EcsSpan span) { - worldID = aspect.World.id; + worldID = iterator.World.id; _span = span; - this.aspect = aspect; + this.iterator = iterator.Iterate(span); + } + + #region CopyTo + public void CopyTo(EcsGroup group) + { + iterator.CopyTo(group); + } + public int CopyTo(ref int[] array) + { + return iterator.CopyTo(ref array); + } + public EcsSpan CopyToSpan(ref int[] array) + { + return iterator.CopyToSpan(ref array); + } + #endregion + + public EcsMaskIterator.Enumerable.Enumerator GetEnumerator() + { + return iterator.GetEnumerator(); } } #endregion diff --git a/src/EcsMask.cs b/src/EcsMask.cs index 1e7434e..af5a6db 100644 --- a/src/EcsMask.cs +++ b/src/EcsMask.cs @@ -651,6 +651,11 @@ namespace DCFApixels.DragonECS } #endregion + #region EcsMaskIterator +#if ENABLE_IL2CPP + [Il2CppSetOption (Option.NullChecks, false)] + [Il2CppSetOption(Option.ArrayBoundsChecks, false)] +#endif public class EcsMaskIterator { #region CountStructComparers @@ -689,10 +694,43 @@ namespace DCFApixels.DragonECS private UnsafeArray _sortExcChunckBuffer; #region Constructors - public EcsMaskIterator(EcsWorld source, EcsMask mask) + public unsafe EcsMaskIterator(EcsWorld source, EcsMask mask) { _source = source; _mask = mask; + + _sortIncBuffer = new UnsafeArray(_mask._inc.Length, true); + _sortExcBuffer = new UnsafeArray(_mask._exc.Length, true); + _sortIncChunckBuffer = new UnsafeArray(_mask._incChunckMasks.Length, true); + _sortExcChunckBuffer = new UnsafeArray(_mask._excChunckMasks.Length, true); + + for (int i = 0; i < _sortIncBuffer.Length; i++) + { + _sortIncBuffer.ptr[i] = _mask._inc[i]; + } + for (int i = 0; i < _sortExcBuffer.Length; i++) + { + _sortExcBuffer.ptr[i] = _mask._exc[i]; + } + + for (int i = 0; i < _sortIncChunckBuffer.Length; i++) + { + _sortIncChunckBuffer.ptr[i] = _mask._incChunckMasks[i]; + } + for (int i = 0; i < _sortExcChunckBuffer.Length; i++) + { + _sortExcChunckBuffer.ptr[i] = _mask._excChunckMasks[i]; + } + } + #endregion + + #region Finalizator + unsafe ~EcsMaskIterator() + { + _sortIncBuffer.Dispose(); + _sortExcBuffer.Dispose(); + _sortIncChunckBuffer.Dispose(); + _sortExcChunckBuffer.Dispose(); } #endregion @@ -911,4 +949,5 @@ namespace DCFApixels.DragonECS } #endregion } + #endregion } diff --git a/src/EcsWorld.cache.cs b/src/EcsWorld.cache.cs index 57ad1ab..8ee4d57 100644 --- a/src/EcsWorld.cache.cs +++ b/src/EcsWorld.cache.cs @@ -32,18 +32,18 @@ namespace DCFApixels.DragonECS component = default; } } - internal readonly struct ExcecutorCache : IEcsWorldComponent> + internal readonly struct ExeccutorCache : IEcsWorldComponent> where T : EcsQueryExecutor, new() { public readonly T instance; - public ExcecutorCache(T instance) => this.instance = instance; - void IEcsWorldComponent>.Init(ref ExcecutorCache component, EcsWorld world) + public ExeccutorCache(T instance) => this.instance = instance; + void IEcsWorldComponent>.Init(ref ExeccutorCache component, EcsWorld world) { T instance = new T(); - instance.Initialize(world); - component = new ExcecutorCache(instance); + instance.Initialize(world, world._executorsMediator); + component = new ExeccutorCache(instance); } - void IEcsWorldComponent>.OnDestroy(ref ExcecutorCache component, EcsWorld world) + void IEcsWorldComponent>.OnDestroy(ref ExeccutorCache component, EcsWorld world) { component = default; } diff --git a/src/EcsWorld.cs b/src/EcsWorld.cs index 947623a..398c05e 100644 --- a/src/EcsWorld.cs +++ b/src/EcsWorld.cs @@ -166,10 +166,11 @@ namespace DCFApixels.DragonECS _worlds[worldID] = this; _poolsMediator = new PoolsMediator(this); + _executorsMediator = new ExecutorMediator(this); int poolsCapacity = ArrayUtility.NormalizeSizeToPowerOfTwo(config.PoolsCapacity); _pools = new IEcsPoolImplementation[poolsCapacity]; - _poolSlots = new int[poolsCapacity]; + _poolSlots = new PoolSlot[poolsCapacity]; ArrayUtility.Fill(_pools, _nullPool); int entitiesCapacity = ArrayUtility.NormalizeSizeToPowerOfTwo(config.EntitiesCapacity); @@ -218,7 +219,7 @@ namespace DCFApixels.DragonECS [MethodImpl(MethodImplOptions.AggressiveInlining)] public TExecutor GetExecutor() where TExecutor : EcsQueryExecutor, new() { - return Get>().instance; + return Get>().instance; } [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/Executors/EcsQueryExecutor.cs b/src/Executors/EcsQueryExecutor.cs index fc7b1b5..4e3470f 100644 --- a/src/Executors/EcsQueryExecutor.cs +++ b/src/Executors/EcsQueryExecutor.cs @@ -1,8 +1,39 @@ -using System.Runtime.CompilerServices; +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; namespace DCFApixels.DragonECS { - public abstract class EcsQueryExecutor + public partial class EcsWorld + { + private readonly Dictionary<(Type, Type), EcsQueryExecutorCore> _executorCoures = new Dictionary<(Type, Type), EcsQueryExecutorCore>(); + private readonly ExecutorMediator _executorsMediator; + public readonly struct ExecutorMediator + { + public readonly EcsWorld World; + internal ExecutorMediator(EcsWorld world) + { + if (world == null || world._executorsMediator.World != null) + { + throw new InvalidOperationException(); + } + World = world; + } + public TExecutorCore GetCore(Type aspectType) + where TExecutorCore : EcsQueryExecutorCore, new() + { + var coreType = typeof(EcsQueryExecutorCore); + if(World._executorCoures.TryGetValue((aspectType, coreType), out EcsQueryExecutorCore core)) + { + core = new TExecutorCore(); + core.Initialize(World); + World._executorCoures.Add((aspectType, coreType), core); + } + return (TExecutorCore)core; + } + } + } + public abstract class EcsQueryExecutorCore { private EcsWorld _source; public short WorldID @@ -15,7 +46,6 @@ namespace DCFApixels.DragonECS [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return _source; } } - public abstract long Version { get; } internal void Initialize(EcsWorld world) { _source = world; @@ -29,13 +59,47 @@ namespace DCFApixels.DragonECS protected abstract void OnInitialize(); protected abstract void OnDestroy(); } + public abstract class EcsQueryExecutor + { + private EcsWorld _source; + private EcsWorld.ExecutorMediator _mediator; + public short WorldID + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return _source.id; } + } + public EcsWorld World + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return _source; } + } + protected EcsWorld.ExecutorMediator Mediator + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return _mediator; } + } + public abstract long Version { get; } + internal void Initialize(EcsWorld world, EcsWorld.ExecutorMediator mediator) + { + _source = world; + _mediator = mediator; + OnInitialize(); + } + internal void Destroy() + { + OnDestroy(); + _source = null; + } + protected abstract void OnInitialize(); + protected abstract void OnDestroy(); + } public readonly struct PoolVersionsChecker { private readonly EcsMask _mask; private readonly long[] _versions; - public PoolVersionsChecker(EcsMask mask) : this() + public PoolVersionsChecker(EcsMask mask) { _mask = mask; _versions = new long[mask._inc.Length + mask._exc.Length]; diff --git a/src/Executors/EcsWhereExecutor.cs b/src/Executors/EcsWhereExecutor.cs index 72fa2ee..0d20c42 100644 --- a/src/Executors/EcsWhereExecutor.cs +++ b/src/Executors/EcsWhereExecutor.cs @@ -1,51 +1,89 @@ using DCFApixels.DragonECS.Internal; +using System; using System.Runtime.CompilerServices; +#if ENABLE_IL2CPP +using Unity.IL2CPP.CompilerServices; +#endif -namespace DCFApixels.DragonECS +namespace DCFApixels.DragonECS.Internal { #if ENABLE_IL2CPP - using Unity.IL2CPP.CompilerServices; [Il2CppSetOption(Option.NullChecks, false)] [Il2CppSetOption(Option.ArrayBoundsChecks, false)] #endif - public sealed class EcsWhereExecutor : EcsQueryExecutor where TAspect : EcsAspect, new() + internal readonly struct EcsWhereExecutorCoreList : IEcsWorldComponent { - private TAspect _aspect; - private int[] _filteredEntities; - private int _filteredEntitiesCount; + internal readonly EcsWhereExecutorCore[] _cores; + public EcsWhereExecutorCoreList(EcsWhereExecutorCore[] cores) + { + _cores = cores; + } + public void Init(ref EcsWhereExecutorCoreList component, EcsWorld world) + { + component = new EcsWhereExecutorCoreList(new EcsWhereExecutorCore[64]); + } + public void OnDestroy(ref EcsWhereExecutorCoreList component, EcsWorld world) + { + component = default; + } + } - private long _lastWorldVersion; +#if ENABLE_IL2CPP + [Il2CppSetOption(Option.NullChecks, false)] + [Il2CppSetOption(Option.ArrayBoundsChecks, false)] +#endif + internal class EcsWhereExecutorCore + { + private EcsWorld _source; + + private EcsMaskIterator _iterator; + private int[] _filteredEntities = new int[32]; + private int _filteredEntitiesCount = 0; + + private long _lastWorldVersion = 0; private PoolVersionsChecker _versionsChecker; #region Properties - public TAspect Aspect + public long Version { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => _aspect; - } - public sealed override long Version - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => _lastWorldVersion; + get { return _lastWorldVersion; } } #endregion - #region OnInitialize/OnDestroy - protected sealed override void OnInitialize() + #region Constructors + public EcsWhereExecutorCore(EcsWorld source, EcsAspect aspect) { - _aspect = World.GetAspect(); - _filteredEntities = new int[32]; - _versionsChecker = new PoolVersionsChecker(_aspect._mask); + _source = source; + _versionsChecker = new PoolVersionsChecker(aspect.Mask); } - protected sealed override void OnDestroy() { } #endregion #region Methods [MethodImpl(MethodImplOptions.AggressiveInlining)] private void Filter(EcsSpan span) { - _filteredEntitiesCount = _aspect.GetIteratorFor(span).CopyTo(ref _filteredEntities); - _lastWorldVersion = World.Version; + _filteredEntitiesCount = _iterator.Iterate(span).CopyTo(ref _filteredEntities); + _lastWorldVersion = _source.Version; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public EcsSpan Execute() + { + return ExecuteFor(_source.Entities); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public EcsSpan ExecuteFor(EcsSpan span) + { +#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS + if (span.IsNull) { Throw.ArgumentNull(nameof(span)); } + if (span.WorldID != _source.id) { Throw.Quiery_ArgumentDifferentWorldsException(); } +#endif + _source.ReleaseDelEntityBufferAllAuto(); + if (_lastWorldVersion != _source.Version || _versionsChecker.NextEquals() == false) + { + Filter(span); + } + return new EcsSpan(_source.id, _filteredEntities, _filteredEntitiesCount); } // [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -67,25 +105,66 @@ namespace DCFApixels.DragonECS // } // Array.Sort(_filteredEntities, 0, _filteredEntitiesCount, comparison); // } + #endregion + } +} +namespace DCFApixels.DragonECS +{ +#if ENABLE_IL2CPP + [Il2CppSetOption(Option.NullChecks, false)] + [Il2CppSetOption(Option.ArrayBoundsChecks, false)] +#endif + public sealed class EcsWhereExecutor : EcsQueryExecutor where TAspect : EcsAspect, new() + { + private TAspect _aspect; + private EcsWhereExecutorCore _core; + + #region Properties + public TAspect Aspect + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return _aspect; } + } + public sealed override long Version + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return _core.Version; } + } + #endregion + + #region OnInitialize/OnDestroy + protected sealed override void OnInitialize() + { + _aspect = World.GetAspect(); + int maskID = _aspect.Mask.ID; + ref var list = ref World.Get(); + var cores = list._cores; + if (maskID >= list._cores.Length) + { + Array.Resize(ref cores, cores.Length << 1); + list = new EcsWhereExecutorCoreList(cores); + } + ref var coreRef = ref cores[maskID]; + if (coreRef == null) + { + coreRef = new EcsWhereExecutorCore(World, _aspect); + } + _core = coreRef; + } + protected sealed override void OnDestroy() { } + #endregion + + #region Methods [MethodImpl(MethodImplOptions.AggressiveInlining)] public EcsSpan Execute() { - return ExecuteFor(_aspect.World.Entities); + return _core.Execute(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public EcsSpan ExecuteFor(EcsSpan span) { -#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS - if (span.IsNull) { Throw.ArgumentNull(nameof(span)); } - if (span.WorldID != WorldID) { Throw.Quiery_ArgumentDifferentWorldsException(); } -#endif - World.ReleaseDelEntityBufferAllAuto(); - if (_lastWorldVersion != World.Version || _versionsChecker.NextEquals() == false) - { - Filter(span); - } - return new EcsSpan(WorldID, _filteredEntities, _filteredEntitiesCount); + return _core.ExecuteFor(span); } #endregion } diff --git a/src/Executors/EcsWhereToGroupExecutor.cs b/src/Executors/EcsWhereToGroupExecutor.cs index 357fd49..79ff3e0 100644 --- a/src/Executors/EcsWhereToGroupExecutor.cs +++ b/src/Executors/EcsWhereToGroupExecutor.cs @@ -1,35 +1,117 @@ using DCFApixels.DragonECS.Internal; using System.Runtime.CompilerServices; +#if ENABLE_IL2CPP +using Unity.IL2CPP.CompilerServices; +#endif + +namespace DCFApixels.DragonECS.Internal +{ +#if ENABLE_IL2CPP + [Il2CppSetOption(Option.NullChecks, false)] + [Il2CppSetOption(Option.ArrayBoundsChecks, false)] +#endif + internal readonly struct EcsWhereToGroupExecutorCoreList : IEcsWorldComponent + { + internal readonly EcsWhereToGroupExecutorCore[] _cores; + public EcsWhereToGroupExecutorCoreList(EcsWhereToGroupExecutorCore[] cores) + { + _cores = cores; + } + public void Init(ref EcsWhereToGroupExecutorCoreList component, EcsWorld world) + { + component = new EcsWhereToGroupExecutorCoreList(new EcsWhereToGroupExecutorCore[64]); + } + public void OnDestroy(ref EcsWhereToGroupExecutorCoreList component, EcsWorld world) + { + component = default; + } + } + +#if ENABLE_IL2CPP + [Il2CppSetOption(Option.NullChecks, false)] + [Il2CppSetOption(Option.ArrayBoundsChecks, false)] +#endif + internal class EcsWhereToGroupExecutorCore + { + private EcsWorld _source; + + private EcsMaskIterator _iterator; + private EcsGroup _filteredGroup; + + private long _lastWorldVersion; + private PoolVersionsChecker _versionsChecker; + + #region Properties + public long Version + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return _lastWorldVersion; } + } + #endregion + + #region Constructors/Destroy + public EcsWhereToGroupExecutorCore(EcsWorld source, EcsAspect aspect) + { + _source = source; + _versionsChecker = new PoolVersionsChecker(aspect.Mask); + } + public void Destroy() + { + _filteredGroup.Dispose(); + } + #endregion + + #region Methods + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void Filter(EcsSpan span) + { + _iterator.Iterate(span).CopyTo(_filteredGroup); + _lastWorldVersion = _source.Version; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public EcsSpan Execute() + { + return ExecuteFor(_source.Entities); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public EcsSpan ExecuteFor(EcsSpan span) + { +#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS + if (span.IsNull) { Throw.ArgumentNull(nameof(span)); } + if (span.WorldID != _source.id) { Throw.Quiery_ArgumentDifferentWorldsException(); } +#endif + _source.ReleaseDelEntityBufferAllAuto(); + if (_lastWorldVersion != _source.Version || _versionsChecker.NextEquals() == false) + { + Filter(span); + } + return _filteredGroup.Readonly; + } + #endregion + } +} namespace DCFApixels.DragonECS { #if ENABLE_IL2CPP - using Unity.IL2CPP.CompilerServices; [Il2CppSetOption(Option.NullChecks, false)] [Il2CppSetOption(Option.ArrayBoundsChecks, false)] #endif public sealed class EcsWhereToGroupExecutor : EcsQueryExecutor where TAspect : EcsAspect, new() { private TAspect _aspect; - private EcsGroup _filteredGroup; - - private long _lastWorldVersion; - private PoolVersionsChecker _versionsChecker; - -#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS - private readonly EcsProfilerMarker _executeMarker = new EcsProfilerMarker("Where"); -#endif + private EcsWhereToGroupExecutorCore _core; #region Properties public TAspect Aspect { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => _aspect; + get { return _aspect; } } public sealed override long Version { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => _lastWorldVersion; + get { return _core.Version; } } #endregion @@ -42,39 +124,20 @@ namespace DCFApixels.DragonECS } protected sealed override void OnDestroy() { - _filteredGroup.Dispose(); + _core.Destroy(); } #endregion #region Methods [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void Filter(EcsSpan span) + public EcsSpan Execute() { - _aspect.GetIteratorFor(span).CopyTo(_filteredGroup); - _lastWorldVersion = World.Version; + return _core.Execute(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public EcsReadonlyGroup Execute() + public EcsSpan ExecuteFor(EcsSpan span) { - return ExecuteFor(_aspect.World.Entities); - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public EcsReadonlyGroup ExecuteFor(EcsSpan span) - { -#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS - _executeMarker.Begin(); - if (span.IsNull) { Throw.ArgumentNull(nameof(span)); } - if (span.WorldID != WorldID) { Throw.Quiery_ArgumentDifferentWorldsException(); } -#endif - World.ReleaseDelEntityBufferAllAuto(); - if (_lastWorldVersion != World.Version || _versionsChecker.NextEquals() == false) - { - Filter(span); - } -#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS - _executeMarker.End(); -#endif - return _filteredGroup.Readonly; + return _core.ExecuteFor(span); } #endregion }