using DCFApixels.DragonECS.Core; using DCFApixels.DragonECS.Internal; using System; using System.Collections.Generic; using System.Runtime.CompilerServices; namespace DCFApixels.DragonECS { public partial class EcsWorld { private readonly Dictionary<(Type, object), IQueryExecutorImplementation> _executorCoures; public TExecutor GetExecutorForMask(IComponentMask gmask) where TExecutor : MaskQueryExecutor, new() { var executorType = typeof(TExecutor); //проверяет ключ по абстрактной маске if (_executorCoures.TryGetValue((executorType, gmask), out IQueryExecutorImplementation executor) == false) { var mask = gmask.ToMask(this); //проверяет ключ по конкретной маске, или что конкретная и абстрактая одна и таже if (mask == gmask || _executorCoures.TryGetValue((executorType, mask), out executor) == false) { TExecutor executorCore = new TExecutor(); executorCore.Initialize(this, mask); executor = executorCore; } _executorCoures.Add((executorType, gmask), executor); } return (TExecutor)executor; } public void GetMaskQueryExecutors(List result, ref int version) { if(_executorCoures == null || version == _executorCoures.Count) { return; } result.Clear(); foreach (var item in _executorCoures) { if(item.Value is MaskQueryExecutor x) { result.Add(x); } } version = _executorCoures.Count; } } } namespace DCFApixels.DragonECS.Core { public interface IQueryExecutorImplementation { EcsWorld World { get; } long Version { get; } bool IsCached { get; } int LastCachedCount { get; } void Destroy(); } public abstract class MaskQueryExecutor : IQueryExecutorImplementation { private EcsWorld _source; private EcsMask _mask; public short WorldID { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return _source.ID; } } public EcsWorld World { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return _source; } } protected EcsMask Mask { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return _mask; } } public abstract long Version { get; } public abstract bool IsCached { get; } public abstract int LastCachedCount { get; } internal void Initialize(EcsWorld world, EcsMask mask) { _source = world; _mask = mask; OnInitialize(); } void IQueryExecutorImplementation.Destroy() { OnDestroy(); _source = null; } protected abstract void OnInitialize(); protected abstract void OnDestroy(); } public readonly unsafe struct WorldStateVersionsChecker : IDisposable { private readonly EcsWorld _world; private readonly int[] _maskInc; private readonly int[] _maskExc; // [0] world version // [-> _maskInc.Length] inc versions // [-> _maskExc.Length] exc versions private readonly long* _versions; public long Version { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return _versions[0]; } } public WorldStateVersionsChecker(EcsMask mask) { _world = mask.World; _maskInc = mask._incs; _maskExc = mask._excs; _versions = UnmanagedArrayUtility.New(1 + mask._incs.Length + mask._excs.Length); } public bool Check() { if (*_versions == _world.Version) { return true; } long* versionsPtr = _versions; var slots = _world._poolSlots; foreach (var slotIndex in _maskInc) { versionsPtr++; if (*versionsPtr != slots[slotIndex].version) { return false; } } foreach (var slotIndex in _maskExc) { versionsPtr++; if (*versionsPtr != slots[slotIndex].version) { return false; } } return true; } public void Next() { *_versions = _world.Version; long* ptr = _versions; var slots = _world._poolSlots; foreach (var slotIndex in _maskInc) { ptr++; *ptr = slots[slotIndex].version; } foreach (var slotIndex in _maskExc) { ptr++; *ptr = slots[slotIndex].version; } } public bool CheckAndNext() { if (*_versions == _world.Version) { return true; } *_versions = _world.Version; long* ptr = _versions; var slots = _world._poolSlots; bool result = true; foreach (var slotIndex in _maskInc) { ptr++; if (*ptr != slots[slotIndex].version) { result = false; *ptr = slots[slotIndex].version; } } foreach (var slotIndex in _maskExc) { ptr++; if (*ptr != slots[slotIndex].version) { result = false; *ptr = slots[slotIndex].version; } } return result; } public void Dispose() { } } }