diff --git a/src/EcsAspect.cs b/src/EcsAspect.cs index 644bb4d..2bc26a1 100644 --- a/src/EcsAspect.cs +++ b/src/EcsAspect.cs @@ -184,7 +184,7 @@ namespace DCFApixels.DragonECS private TPool CachePool() where TPool : IEcsPoolImplementation, new() { var pool = _world.GetPoolInstance(); - if(_poolsBufferCount >= _poolsBuffer.Length) + if (_poolsBufferCount >= _poolsBuffer.Length) { Array.Resize(ref _poolsBuffer, _poolsBuffer.Length << 1); } diff --git a/src/EcsWorld.cache.cs b/src/EcsWorld.cache.cs index c4393d6..99b9b83 100644 --- a/src/EcsWorld.cache.cs +++ b/src/EcsWorld.cache.cs @@ -1,4 +1,5 @@ -using DCFApixels.DragonECS.PoolsCore; +using DCFApixels.DragonECS.Core; +using DCFApixels.DragonECS.PoolsCore; namespace DCFApixels.DragonECS { @@ -33,14 +34,8 @@ namespace DCFApixels.DragonECS } } - //TODO добавить сквозной кеш для инстансов TExecutor - //private readonly struct WhereCache : IEcsWorldComponent> - //{ - // private readonly SparseArray _pairs - //} - // Это не подохидт internal readonly struct WhereQueryCache : IEcsWorldComponent> - where TExecutor : EcsQueryExecutor, new() + where TExecutor : MaskQueryExecutor, new() where TAspcet : EcsAspect, new() { public readonly TExecutor Executor; @@ -52,8 +47,8 @@ namespace DCFApixels.DragonECS } void IEcsWorldComponent>.Init(ref WhereQueryCache component, EcsWorld world) { - TExecutor instance = new TExecutor(); TAspcet aspect = world.GetAspect(); + TExecutor instance = world.GetExecutorForMask(aspect.Mask); instance.Initialize(world, aspect.Mask); component = new WhereQueryCache(instance, aspect); } diff --git a/src/EcsWorld.cs b/src/EcsWorld.cs index 0b360bf..cb6a377 100644 --- a/src/EcsWorld.cs +++ b/src/EcsWorld.cs @@ -73,6 +73,34 @@ namespace DCFApixels.DragonECS private List _listeners = new List(); private List _entityListeners = new List(); + + private static Stack _configInitOnlynStack = new Stack(4); + protected internal static EcsWorldConfig Config_InitOnly + { + get + { + if (_configInitOnlynStack.TryPeek(out EcsWorldConfig result)) + { + return result; + } + Throw.UndefinedException(); + return null; + } + } + private readonly ref struct ConfigInitOnlyScope + { + private readonly Stack _stack; + public ConfigInitOnlyScope(Stack stack, EcsWorldConfig config) + { + _stack = stack; + _stack.Push(config); + } + public void Dispose() + { + _stack.Peek(); + } + } + #region Properties EcsWorld IEntityStorage.World { @@ -143,6 +171,8 @@ namespace DCFApixels.DragonECS lock (_worldLock) { if (configs == null) { configs = ConfigContainer.Empty; } + _configInitOnlynStack.Push(configs.GetWorldConfigOrDefault()); + bool nullWorld = this is NullWorld; if (nullWorld == false && worldID == NULL_WORLD_ID) { @@ -164,6 +194,7 @@ namespace DCFApixels.DragonECS if (_worlds[worldID] != null) { _worldIdDispenser.Release(worldID); + _configInitOnlynStack.Pop(); Throw.Exception("The world with the specified ID has already been created\r\n"); } } @@ -181,6 +212,8 @@ namespace DCFApixels.DragonECS _entityDispenser = new IdDispenser(entitiesCapacity, 0, OnEntityDispenserResized); GetComponentTypeID(); + + _configInitOnlynStack.Pop(); } } public void Destroy() @@ -231,7 +264,7 @@ namespace DCFApixels.DragonECS } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void GetQueryCache(out TExecutor executor, out TAspect aspect) - where TExecutor : EcsQueryExecutor, new() + where TExecutor : MaskQueryExecutor, new() where TAspect : EcsAspect, new() { ref var cmp = ref Get>(); diff --git a/src/Executors/EcsWhereExecutor.cs b/src/Executors/EcsWhereExecutor.cs index 46283cc..9162a9d 100644 --- a/src/Executors/EcsWhereExecutor.cs +++ b/src/Executors/EcsWhereExecutor.cs @@ -1,4 +1,5 @@ -using System; +using DCFApixels.DragonECS.Core; +using System; using System.Runtime.CompilerServices; #if ENABLE_IL2CPP using Unity.IL2CPP.CompilerServices; @@ -10,16 +11,16 @@ namespace DCFApixels.DragonECS.Internal [Il2CppSetOption(Option.NullChecks, false)] [Il2CppSetOption(Option.ArrayBoundsChecks, false)] #endif - internal class EcsWhereExecutor : EcsQueryExecutor + internal class EcsWhereExecutor : MaskQueryExecutor { private EcsMaskIterator _iterator; + private int[] _filteredAllEntities = new int[32]; private int _filteredAllEntitiesCount = 0; - private long _version; - private int[] _filteredEntities = null; private int _filteredEntitiesCount = 0; + private long _version; private WorldStateVersionsChecker _versionsChecker; #region Properties @@ -28,6 +29,11 @@ namespace DCFApixels.DragonECS.Internal [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return _version; } } + public sealed override bool IsCached + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return _versionsChecker.Check(); } + } #endregion #region OnInitialize/OnDestroy diff --git a/src/Executors/EcsWhereToGroupExecutor.cs b/src/Executors/EcsWhereToGroupExecutor.cs index cb2ab97..e885b18 100644 --- a/src/Executors/EcsWhereToGroupExecutor.cs +++ b/src/Executors/EcsWhereToGroupExecutor.cs @@ -1,4 +1,5 @@ -using System.Runtime.CompilerServices; +using DCFApixels.DragonECS.Core; +using System.Runtime.CompilerServices; #if ENABLE_IL2CPP using Unity.IL2CPP.CompilerServices; #endif @@ -9,14 +10,14 @@ namespace DCFApixels.DragonECS.Internal [Il2CppSetOption(Option.NullChecks, false)] [Il2CppSetOption(Option.ArrayBoundsChecks, false)] #endif - internal class EcsWhereToGroupExecutor : EcsQueryExecutor + internal class EcsWhereToGroupExecutor : MaskQueryExecutor { private EcsMaskIterator _iterator; - private EcsGroup _filteredAllGroup; - private long _version; + private EcsGroup _filteredAllGroup; private EcsGroup _filteredGroup; + private long _version; private WorldStateVersionsChecker _versionsChecker; #region Properties @@ -25,6 +26,11 @@ namespace DCFApixels.DragonECS.Internal [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return _version; } } + public sealed override bool IsCached + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return _versionsChecker.Check(); } + } #endregion #region OnInitialize/OnDestroy diff --git a/src/Executors/EcsQueryExecutor.cs b/src/Executors/MaskQueryExecutor.cs similarity index 73% rename from src/Executors/EcsQueryExecutor.cs rename to src/Executors/MaskQueryExecutor.cs index 3c275e0..7c7998d 100644 --- a/src/Executors/EcsQueryExecutor.cs +++ b/src/Executors/MaskQueryExecutor.cs @@ -8,21 +8,40 @@ namespace DCFApixels.DragonECS { public partial class EcsWorld { - private readonly Dictionary<(Type, object), EcsQueryExecutor> _executorCoures = new Dictionary<(Type, object), EcsQueryExecutor>(256); - public TExecutor GetExecutor(IComponentMask mask) - where TExecutor : EcsQueryExecutor, new() + private readonly Dictionary<(Type, object), IQueryExecutorImplementation> _executorCoures = new Dictionary<(Type, object), IQueryExecutorImplementation>(Config_InitOnly.PoolComponentsCapacity); + public TExecutor GetExecutorForMask(IComponentMask gmask) + where TExecutor : MaskQueryExecutor, new() { var coreType = typeof(TExecutor); - if (_executorCoures.TryGetValue((coreType, mask), out EcsQueryExecutor core) == false) + //проверяет ключ по абстрактной маске + if (_executorCoures.TryGetValue((coreType, gmask), out IQueryExecutorImplementation executor) == false) { - core = new TExecutor(); - core.Initialize(this, mask.ToMask(this)); - _executorCoures.Add((coreType, mask), core); + var mask = gmask.ToMask(this); + //проверяет ключ по конкретной маске, или что конкретная и абстрактая одна и таже + if (mask == gmask || + _executorCoures.TryGetValue((coreType, mask), out executor) == false) + { + TExecutor newCore = new TExecutor(); + newCore.Initialize(this, mask); + executor = newCore; + } + _executorCoures.Add((coreType, gmask), executor); } - return (TExecutor)core; + return (TExecutor)executor; } } - public abstract class EcsQueryExecutor +} + +namespace DCFApixels.DragonECS.Core +{ + public interface IQueryExecutorImplementation + { + EcsWorld World { get; } + long Version { get; } + bool IsCached { get; } + void Destroy(); + } + public abstract class MaskQueryExecutor : IQueryExecutorImplementation { private EcsWorld _source; private EcsMask _mask; @@ -42,13 +61,14 @@ namespace DCFApixels.DragonECS get { return _mask; } } public abstract long Version { get; } + public abstract bool IsCached { get; } internal void Initialize(EcsWorld world, EcsMask mask) { _source = world; _mask = mask; OnInitialize(); } - internal void Destroy() + void IQueryExecutorImplementation.Destroy() { OnDestroy(); _source = null; diff --git a/src/Executors/EcsQueryExecutor.cs.meta b/src/Executors/MaskQueryExecutor.cs.meta similarity index 100% rename from src/Executors/EcsQueryExecutor.cs.meta rename to src/Executors/MaskQueryExecutor.cs.meta diff --git a/src/Executors/Queries.cs b/src/Executors/Queries.cs index eeae60d..9950094 100644 --- a/src/Executors/Queries.cs +++ b/src/Executors/Queries.cs @@ -40,7 +40,7 @@ namespace DCFApixels.DragonECS { if (ReferenceEquals(entities, entities.World)) { - var executor = entities.World.GetExecutor(mask); + var executor = entities.World.GetExecutorForMask(mask); return executor.Execute(); } return entities.ToSpan().Where(mask); @@ -51,7 +51,7 @@ namespace DCFApixels.DragonECS } public static EcsSpan Where(this EcsSpan span, IComponentMask mask) { - var executor = span.World.GetExecutor(mask); + var executor = span.World.GetExecutorForMask(mask); return executor.ExecuteFor(span); } #endregion @@ -85,7 +85,7 @@ namespace DCFApixels.DragonECS { if (ReferenceEquals(entities, entities.World)) { - EcsWhereExecutor executor = entities.World.GetExecutor(mask); + EcsWhereExecutor executor = entities.World.GetExecutorForMask(mask); return executor.Execute(comparison); } return entities.ToSpan().Where(mask, comparison); @@ -96,7 +96,7 @@ namespace DCFApixels.DragonECS } public static EcsSpan Where(this EcsSpan span, IComponentMask mask, Comparison comparison) { - var executor = span.World.GetExecutor(mask); + var executor = span.World.GetExecutorForMask(mask); return executor.ExecuteFor(span); } #endregion @@ -130,7 +130,7 @@ namespace DCFApixels.DragonECS { if (ReferenceEquals(entities, entities.World)) { - EcsWhereToGroupExecutor executor = entities.World.GetExecutor(mask); + EcsWhereToGroupExecutor executor = entities.World.GetExecutorForMask(mask); return executor.Execute(); } return entities.ToSpan().WhereToGroup(mask); @@ -141,7 +141,7 @@ namespace DCFApixels.DragonECS } public static EcsReadonlyGroup WhereToGroup(this EcsSpan span, IComponentMask mask) { - var executor = span.World.GetExecutor(mask); + var executor = span.World.GetExecutorForMask(mask); return executor.ExecuteFor(span); } #endregion