diff --git a/src/EcsAspect.cs b/src/EcsAspect.cs index b2e69c8..fa0ab91 100644 --- a/src/EcsAspect.cs +++ b/src/EcsAspect.cs @@ -79,6 +79,10 @@ namespace DCFApixels.DragonECS { get { return EcsAspect.CurrentBuilder.Exc; } } + public static AnyMarker Any + { + get { return EcsAspect.CurrentBuilder.Any; } + } public static OptionalMarker Opt { get { return EcsAspect.CurrentBuilder.Opt; } @@ -114,6 +118,10 @@ namespace DCFApixels.DragonECS { get { return B.Exc; } } + protected static AnyMarker Any + { + get { return B.Any; } + } protected static OptionalMarker Opt { get { return B.Opt; } @@ -181,6 +189,10 @@ namespace DCFApixels.DragonECS { get { return new ExcludeMarker(this); } } + public AnyMarker Any + { + get { return new AnyMarker(this); } + } public OptionalMarker Opt { get { return new OptionalMarker(this); } @@ -281,6 +293,12 @@ namespace DCFApixels.DragonECS SetMaskExclude(pool.ComponentType); return pool; } + public TPool AnyPool() where TPool : IEcsPoolImplementation, new() + { + var pool = CachePool(); + SetMaskAny(pool.ComponentType); + return pool; + } public TPool OptionalPool() where TPool : IEcsPoolImplementation, new() { return CachePool(); @@ -305,6 +323,13 @@ namespace DCFApixels.DragonECS _maskBuilder.Exc(type); } } + public void SetMaskAny(Type type) + { + if (_maskBuilder.IsNull == false) + { + _maskBuilder.Any(type); + } + } public TOtherAspect Combine(int order = 0) where TOtherAspect : EcsAspect, new() { var result = _world.GetAspect(); @@ -495,6 +520,18 @@ namespace DCFApixels.DragonECS.Core return _builder.ExcludePool(); } } + public readonly ref struct AnyMarker + { + private readonly EcsAspect.Builder _builder; + public AnyMarker(EcsAspect.Builder builder) + { + _builder = builder; + } + public T GetInstance() where T : IEcsPoolImplementation, new() + { + return _builder.AnyPool(); + } + } public readonly ref struct OptionalMarker { private readonly EcsAspect.Builder _builder; diff --git a/src/EcsMask.cs b/src/EcsMask.cs index 761f007..a8f843e 100644 --- a/src/EcsMask.cs +++ b/src/EcsMask.cs @@ -38,10 +38,13 @@ namespace DCFApixels.DragonECS internal readonly EcsStaticMask _staticMask; internal readonly EcsMaskChunck[] _incChunckMasks; internal readonly EcsMaskChunck[] _excChunckMasks; + internal readonly EcsMaskChunck[] _anyChunckMasks; /// Sorted internal readonly int[] _incs; /// Sorted internal readonly int[] _excs; + /// Sorted + internal readonly int[] _anys; private EcsMaskIterator _iterator; @@ -78,22 +81,24 @@ namespace DCFApixels.DragonECS public static Builder New(EcsWorld world) { return new Builder(world); } internal static EcsMask CreateEmpty(int id, short worldID) { - return new EcsMask(EcsStaticMask.Empty, id, worldID, new int[0], new int[0]); + return new EcsMask(EcsStaticMask.Empty, id, worldID, new int[0], new int[0], new int[0]); } internal static EcsMask CreateBroken(int id, short worldID) { - return new EcsMask(EcsStaticMask.Broken, id, worldID, new int[1] { 1 }, new int[1] { 1 }); + return new EcsMask(EcsStaticMask.Broken, id, worldID, new int[1] { 1 }, new int[1] { 1 }, new int[0]); } - private EcsMask(EcsStaticMask staticMask, int id, short worldID, int[] inc, int[] exc) + private EcsMask(EcsStaticMask staticMask, int id, short worldID, int[] incs, int[] excs, int[] anys) { _staticMask = staticMask; ID = id; - _incs = inc; - _excs = exc; + _incs = incs; + _excs = excs; + _anys = anys; WorldID = worldID; - _incChunckMasks = MakeMaskChuncsArray(inc); - _excChunckMasks = MakeMaskChuncsArray(exc); + _incChunckMasks = MakeMaskChuncsArray(incs); + _excChunckMasks = MakeMaskChuncsArray(excs); + _anyChunckMasks = MakeMaskChuncsArray(anys); } private unsafe EcsMaskChunck[] MakeMaskChuncsArray(int[] sortedArray) @@ -145,7 +150,7 @@ namespace DCFApixels.DragonECS #region Object public override string ToString() { - return CreateLogString(WorldID, _incs, _excs); + return CreateLogString(WorldID, _incs, _excs, _anys); } public bool Equals(EcsMask mask) { @@ -324,8 +329,9 @@ namespace DCFApixels.DragonECS { int[] incs = ConvertTypeCodeToComponentTypeID(staticMask.IncTypeCodes, _world); int[] excs = ConvertTypeCodeToComponentTypeID(staticMask.ExcTypeCodes, _world); + int[] anys = ConvertTypeCodeToComponentTypeID(staticMask.AnyTypeCodes, _world); - result = new EcsMask(staticMask, _staticMasks.Count, _world.ID, incs, excs); + result = new EcsMask(staticMask, _staticMasks.Count, _world.ID, incs, excs, anys); _staticMasks.Add(staticMask.ID, result); } @@ -347,10 +353,13 @@ namespace DCFApixels.DragonECS public Builder Inc() { _builder.Inc(); return this; } public Builder Exc() { _builder.Exc(); return this; } + public Builder Any() { _builder.Any(); return this; } public Builder Inc(Type type) { _builder.Inc(type); return this; } public Builder Exc(Type type) { _builder.Exc(type); return this; } + public Builder Any(Type type) { _builder.Any(type); return this; } public Builder Inc(EcsTypeCode typeCode) { _builder.Inc(typeCode); return this; } public Builder Exc(EcsTypeCode typeCode) { _builder.Exc(typeCode); return this; } + public Builder Any(EcsTypeCode typeCode) { _builder.Any(typeCode); return this; } public Builder Combine(EcsMask mask) { _builder.Combine(mask._staticMask); return this; } public Builder Except(EcsMask mask) { _builder.Except(mask._staticMask); return this; } @@ -359,11 +368,12 @@ namespace DCFApixels.DragonECS #endregion #region Debug utils - private static string CreateLogString(short worldID, int[] inc, int[] exc) + //TODO доработать дебаг с учетом Any + private static string CreateLogString(short worldID, int[] incs, int[] excs, int[] anys) { #if DEBUG string converter(int o) { return EcsDebugUtility.GetGenericTypeName(EcsWorld.GetWorld(worldID).AllPools[o].ComponentType, 1); } - return $"Inc({string.Join(", ", inc.Select(converter))}) Exc({string.Join(", ", exc.Select(converter))})"; + return $"Inc({string.Join(", ", incs.Select(converter))}) Exc({string.Join(", ", excs.Select(converter))}) Any({string.Join(", ", anys.Select(converter))})"; #else return $"Inc({string.Join(", ", inc)}) Exc({string.Join(", ", exc)})"; // Release optimization #endif @@ -378,10 +388,13 @@ namespace DCFApixels.DragonECS private readonly short _worldID; public readonly EcsMaskChunck[] includedChunkMasks; public readonly EcsMaskChunck[] excludedChunkMasks; + public readonly EcsMaskChunck[] anyChunkMasks; public readonly int[] included; public readonly int[] excluded; + public readonly int[] any; public readonly Type[] includedTypes; public readonly Type[] excludedTypes; + public readonly Type[] anyTypes; public bool IsEmpty { get { return _source.IsEmpty; } } public bool IsBroken { get { return _source.IsBroken; } } @@ -395,15 +408,18 @@ namespace DCFApixels.DragonECS _worldID = mask.WorldID; includedChunkMasks = mask._incChunckMasks; excludedChunkMasks = mask._excChunckMasks; + anyChunkMasks = mask._anyChunckMasks; included = mask._incs; excluded = mask._excs; + any = mask._anys; Type converter(int o) { return world.GetComponentType(o); } includedTypes = included.Select(converter).ToArray(); excludedTypes = excluded.Select(converter).ToArray(); + anyTypes = any.Select(converter).ToArray(); } public override string ToString() { - return CreateLogString(_worldID, included, excluded); + return CreateLogString(_worldID, included, excluded, any); } } #endregion @@ -498,12 +514,12 @@ namespace DCFApixels.DragonECS public readonly EcsMask Mask; private readonly UnsafeArray _sortIncBuffer; - /// slised _sortIncBuffer private readonly UnsafeArray _sortExcBuffer; + private readonly UnsafeArray _sortAnyBuffer; private readonly UnsafeArray _sortIncChunckBuffer; - /// slised _sortIncChunckBuffer private readonly UnsafeArray _sortExcChunckBuffer; + private readonly UnsafeArray _sortAnyChunckBuffer; private MemoryAllocator.Handler _bufferHandler; private MemoryAllocator.Handler _chunckBufferHandler; @@ -525,8 +541,8 @@ namespace DCFApixels.DragonECS World = source; Mask = mask; - int bufferLength = mask._incs.Length + mask._excs.Length; - int chunckBufferLength = mask._incChunckMasks.Length + mask._excChunckMasks.Length; + int bufferLength = mask._incs.Length + mask._excs.Length + mask._anys.Length; + int chunckBufferLength = mask._incChunckMasks.Length + mask._excChunckMasks.Length + mask._anyChunckMasks.Length; _bufferHandler = MemoryAllocator.AllocAndInit(bufferLength); _chunckBufferHandler = MemoryAllocator.AllocAndInit(chunckBufferLength); var sortBuffer = UnsafeArray.Manual(_bufferHandler.As(), bufferLength); @@ -536,6 +552,8 @@ namespace DCFApixels.DragonECS _sortIncBuffer.CopyFromArray_Unchecked(mask._incs); _sortExcBuffer = sortBuffer.Slice(mask._incs.Length, mask._excs.Length); _sortExcBuffer.CopyFromArray_Unchecked(mask._excs); + _sortAnyBuffer = sortBuffer.Slice(mask._incs.Length + mask._excs.Length, mask._anys.Length); + _sortAnyBuffer.CopyFromArray_Unchecked(mask._anys); //EcsDebug.PrintError(_sortIncBuffer.ToArray()); //EcsDebug.PrintError(new Span(_bufferHandler.GetPtrAs(), _sortIncBuffer.Length).ToArray()); @@ -544,6 +562,8 @@ namespace DCFApixels.DragonECS _sortIncChunckBuffer.CopyFromArray_Unchecked(mask._incChunckMasks); _sortExcChunckBuffer = sortChunckBuffer.Slice(mask._incChunckMasks.Length, mask._excChunckMasks.Length); _sortExcChunckBuffer.CopyFromArray_Unchecked(mask._excChunckMasks); + _sortAnyChunckBuffer = sortChunckBuffer.Slice(mask._incChunckMasks.Length + mask._excChunckMasks.Length, mask._anyChunckMasks.Length); + _sortAnyChunckBuffer.CopyFromArray_Unchecked(mask._anyChunckMasks); _isHasAnyEntityStorage = false; var pools = source.AllPools; @@ -555,13 +575,13 @@ namespace DCFApixels.DragonECS } _isSingleIncPoolWithEntityStorage = Mask.Excs.Length <= 0 && Mask.Incs.Length == 1; - if (_sortExcBuffer.Length <= 0) + if (_sortIncBuffer.Length > 0 && _sortExcBuffer.Length == 0 && _sortAnyBuffer.Length == 0) { - _maskType = mask.IsEmpty ? MaskType.Empty : MaskType.OnlyInc; + _maskType = MaskType.OnlyInc; } else { - _maskType = MaskType.IncExc; + _maskType = mask.IsEmpty ? MaskType.Empty : MaskType.IncExc; } } unsafe ~EcsMaskIterator() @@ -577,8 +597,6 @@ namespace DCFApixels.DragonECS { _bufferHandler.Dispose(); _chunckBufferHandler.Dispose(); - //_sortIncBuffer.ReadonlyDispose(); // использует общую памяять с _sortExcBuffer; - //_sortIncChunckBuffer.ReadonlyDispose(); // использует общую памяять с _sortExcChunckBuffer; } #endregion @@ -587,9 +605,10 @@ namespace DCFApixels.DragonECS { UnsafeArray sortIncBuffer = _sortIncBuffer; UnsafeArray sortExcBuffer = _sortExcBuffer; + UnsafeArray sortAnyBuffer = _sortAnyBuffer; EcsWorld.PoolSlot[] counts = World._poolSlots; - int maxBufferSize = sortIncBuffer.Length > sortExcBuffer.Length ? sortIncBuffer.Length : sortExcBuffer.Length; + int maxBufferSize = Math.Max(Math.Max(sortIncBuffer.Length, sortExcBuffer.Length), sortAnyBuffer.Length); int maxEntites = int.MaxValue; EcsMaskChunck* preSortingBuffer; @@ -625,9 +644,18 @@ namespace DCFApixels.DragonECS UnsafeArraySortHalperX.InsertionSort(sortExcBuffer.ptr, sortExcBuffer.Length, ref comparer); ConvertToChuncks(preSortingBuffer, sortExcBuffer, _sortExcChunckBuffer); } - // Выражение мало IncCount < (AllEntitesCount - ExcCount) вероятно будет истинным. + // Выражение IncCount < (AllEntitesCount - ExcCount) мало вероятно будет истинным. // ExcCount = максимальное количество ентитей с исключеющим ограничением и IncCount = минимальоне количество ентитей с включающим ограничением // Поэтому исключающее ограничение игнорируется для maxEntites. + + + if (_sortAnyChunckBuffer.Length > 1) + { + //TODO проверить для Any + ExcCountComparer comparer = new ExcCountComparer(counts); + UnsafeArraySortHalperX.InsertionSort(sortAnyBuffer.ptr, sortAnyBuffer.Length, ref comparer); + ConvertToChuncks(preSortingBuffer, sortAnyBuffer, _sortAnyChunckBuffer); + } return maxEntites; } private unsafe bool TryGetEntityStorage(out IEntityStorage storage) @@ -776,6 +804,7 @@ namespace DCFApixels.DragonECS private readonly UnsafeArray _sortIncChunckBuffer; private readonly UnsafeArray _sortExcChunckBuffer; + private readonly UnsafeArray _sortAnyChunckBuffer; private readonly int[] _entityComponentMasks; private readonly int _entityComponentMaskLengthBitShift; @@ -784,6 +813,7 @@ namespace DCFApixels.DragonECS { _sortIncChunckBuffer = iterator._sortIncChunckBuffer; _sortExcChunckBuffer = iterator._sortExcChunckBuffer; + _sortAnyChunckBuffer = iterator._sortAnyChunckBuffer; _entityComponentMasks = iterator.World._entityComponentMasks; _entityComponentMaskLengthBitShift = iterator.World._entityComponentMaskLengthBitShift; @@ -817,6 +847,25 @@ namespace DCFApixels.DragonECS goto skip; } } + + //можно подумать над оптимизацией через кеширование bool значения, if с bool работает быстрее прочего + if(_sortAnyChunckBuffer.Length > 0) + { + int anyCount = 0; + for (int i = 0; i < _sortAnyChunckBuffer.Length; i++) + { + var bit = _sortAnyChunckBuffer.ptr[i]; + if ((_entityComponentMasks[entityLineStartIndex + bit.chunkIndex] & bit.mask) == bit.mask) + { + anyCount++; + } + } + if (anyCount == 0) + { + goto skip; + } + } + return true; skip: continue; } diff --git a/src/EcsStaticMask.cs b/src/EcsStaticMask.cs index 90062f5..67234f8 100644 --- a/src/EcsStaticMask.cs +++ b/src/EcsStaticMask.cs @@ -38,8 +38,8 @@ namespace DCFApixels.DragonECS _ids[key] = result; return result; } - Empty = createMask(0, new Key(new EcsTypeCode[0], new EcsTypeCode[0])); - Broken = createMask(_idDIspenser.UseFree(), new Key(new EcsTypeCode[1] { (EcsTypeCode)1 }, new EcsTypeCode[1] { (EcsTypeCode)1 })); + Empty = createMask(0, new Key(new EcsTypeCode[0], new EcsTypeCode[0], new EcsTypeCode[0])); + Broken = createMask(_idDIspenser.UseFree(), new Key(new EcsTypeCode[1] { (EcsTypeCode)1 }, new EcsTypeCode[1] { (EcsTypeCode)1 }, new EcsTypeCode[0])); } public readonly int ID; @@ -47,6 +47,8 @@ namespace DCFApixels.DragonECS private readonly EcsTypeCode[] _incs; /// Sorted private readonly EcsTypeCode[] _excs; + /// Sorted + private readonly EcsTypeCode[] _anys; #region Properties /// Sorted set including constraints presented as global type codes. @@ -61,6 +63,12 @@ namespace DCFApixels.DragonECS [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return _excs; } } + /// Sorted set excluding constraints presented as global type codes. + public ReadOnlySpan AnyTypeCodes + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get { return _anys; } + } public bool IsEmpty { [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -78,14 +86,18 @@ namespace DCFApixels.DragonECS ID = id; _incs = key.Incs; _excs = key.Excs; + _anys = key.Anys; } public static Builder New() { return Builder.New(); } public static Builder Inc() { return Builder.New().Inc(); } public static Builder Exc() { return Builder.New().Exc(); } + public static Builder Any() { return Builder.New().Any(); } public static Builder Inc(Type type) { return Builder.New().Inc(type); } public static Builder Exc(Type type) { return Builder.New().Exc(type); } + public static Builder Any(Type type) { return Builder.New().Any(type); } public static Builder Inc(EcsTypeCode typeCode) { return Builder.New().Inc(typeCode); } public static Builder Exc(EcsTypeCode typeCode) { return Builder.New().Exc(typeCode); } + public static Builder Any(EcsTypeCode typeCode) { return Builder.New().Any(typeCode); } private static EcsStaticMask CreateMask(Key key) { if (_ids.TryGetValue(key, out EcsStaticMask result) == false) @@ -95,7 +107,7 @@ namespace DCFApixels.DragonECS if (_ids.TryGetValue(key, out result) == false) { #if DEBUG - CheckConstraints(key.Incs, key.Excs); + CheckConstraints(key.Incs, key.Excs); //TODO сделать прроверку для key.Anys #endif result = new EcsStaticMask(_idDIspenser.UseFree(), key); _ids[key] = result; @@ -200,23 +212,29 @@ namespace DCFApixels.DragonECS { public readonly EcsTypeCode[] Incs; public readonly EcsTypeCode[] Excs; + public readonly EcsTypeCode[] Anys; public readonly int Hash; #region Constructors - public Key(EcsTypeCode[] inc, EcsTypeCode[] exc) + public Key(EcsTypeCode[] incs, EcsTypeCode[] excs, EcsTypeCode[] anys) { - this.Incs = inc; - this.Excs = exc; + this.Incs = incs; + this.Excs = excs; + this.Anys = anys; unchecked { - Hash = inc.Length + exc.Length; - for (int i = 0, iMax = inc.Length; i < iMax; i++) + Hash = incs.Length + excs.Length; + for (int i = 0, iMax = incs.Length; i < iMax; i++) { - Hash = Hash * EcsConsts.MAGIC_PRIME + (int)inc[i]; + Hash = Hash * EcsConsts.MAGIC_PRIME + (int)incs[i]; } - for (int i = 0, iMax = exc.Length; i < iMax; i++) + for (int i = 0, iMax = excs.Length; i < iMax; i++) { - Hash = Hash * EcsConsts.MAGIC_PRIME - (int)exc[i]; + Hash = Hash * EcsConsts.MAGIC_PRIME - (int)excs[i]; + } + for (int i = 0, iMax = anys.Length; i < iMax; i++) + { + Hash = Hash * EcsConsts.MAGIC_PRIME + (int)anys[i]; } } } @@ -228,6 +246,7 @@ namespace DCFApixels.DragonECS { if (Incs.Length != other.Incs.Length) { return false; } if (Excs.Length != other.Excs.Length) { return false; } + if (Anys.Length != other.Anys.Length) { return false; } for (int i = 0; i < Incs.Length; i++) { if (Incs[i] != other.Incs[i]) { return false; } @@ -236,6 +255,10 @@ namespace DCFApixels.DragonECS { if (Excs[i] != other.Excs[i]) { return false; } } + for (int i = 0; i < Anys.Length; i++) + { + if (Anys[i] != other.Anys[i]) { return false; } + } return true; } public override bool Equals(object obj) { return Equals((Key)obj); } @@ -277,8 +300,10 @@ namespace DCFApixels.DragonECS #region Inc/Exc/Combine/Except public Builder Inc() { return Inc(EcsTypeCodeManager.Get()); } public Builder Exc() { return Exc(EcsTypeCodeManager.Get()); } + public Builder Any() { return Any(EcsTypeCodeManager.Get()); } public Builder Inc(Type type) { return Inc(EcsTypeCodeManager.Get(type)); } public Builder Exc(Type type) { return Exc(EcsTypeCodeManager.Get(type)); } + public Builder Any(Type type) { return Any(EcsTypeCodeManager.Get(type)); } public Builder Inc(EcsTypeCode typeCode) { if (_version != _builder._version) { Throw.CantReuseBuilder(); } @@ -291,6 +316,12 @@ namespace DCFApixels.DragonECS _builder.Exc(typeCode); return this; } + public Builder Any(EcsTypeCode typeCode) + { + if (_version != _builder._version) { Throw.CantReuseBuilder(); } + _builder.Any(typeCode); + return this; + } public Builder Combine(EcsStaticMask mask) { if (_version != _builder._version) { Throw.CantReuseBuilder(); } @@ -327,8 +358,9 @@ namespace DCFApixels.DragonECS } private class BuilderInstance { - private readonly HashSet _inc = new HashSet(); - private readonly HashSet _exc = new HashSet(); + private readonly HashSet _incsSet = new HashSet(); + private readonly HashSet _excsSet = new HashSet(); + private readonly HashSet _anysSet = new HashSet(); private readonly List _combineds = new List(); private bool _sortedCombinedChecker = true; private readonly List _excepteds = new List(); @@ -343,20 +375,29 @@ namespace DCFApixels.DragonECS public void Inc(EcsTypeCode typeCode) { #if DEBUG - if (_inc.Contains(typeCode) || _exc.Contains(typeCode)) { Throw.ConstraintIsAlreadyContainedInMask(typeCode); } + if (_incsSet.Contains(typeCode) || _excsSet.Contains(typeCode) || _anysSet.Contains(typeCode)) { Throw.ConstraintIsAlreadyContainedInMask(typeCode); } #elif DRAGONECS_STABILITY_MODE - if (_inc.Contains(typeCode) || _exc.Contains(typeCode)) { return; } + if (_incsSet.Contains(typeCode) || _excsSet.Contains(typeCode) || _anysSet.Contains(typeCode)) { return; } #endif - _inc.Add(typeCode); + _incsSet.Add(typeCode); } public void Exc(EcsTypeCode typeCode) { #if DEBUG - if (_inc.Contains(typeCode) || _exc.Contains(typeCode)) { Throw.ConstraintIsAlreadyContainedInMask(typeCode); } + if (_incsSet.Contains(typeCode) || _excsSet.Contains(typeCode) || _anysSet.Contains(typeCode)) { Throw.ConstraintIsAlreadyContainedInMask(typeCode); } #elif DRAGONECS_STABILITY_MODE - if (_inc.Contains(typeCode) || _exc.Contains(typeCode)) { return; } + if (_incsSet.Contains(typeCode) || _excsSet.Contains(typeCode) || _anysSet.Contains(typeCode)) { return; } #endif - _exc.Add(typeCode); + _excsSet.Add(typeCode); + } + public void Any(EcsTypeCode typeCode) + { +#if DEBUG + if (_incsSet.Contains(typeCode) || _excsSet.Contains(typeCode) || _anysSet.Contains(typeCode)) { Throw.ConstraintIsAlreadyContainedInMask(typeCode); } +#elif DRAGONECS_STABILITY_MODE + if (_incsSet.Contains(typeCode) || _excsSet.Contains(typeCode) || _anysSet.Contains(typeCode)) { return; } +#endif + _anysSet.Add(typeCode); } public void Combine(EcsStaticMask mask, int order = 0) { @@ -376,13 +417,15 @@ namespace DCFApixels.DragonECS #region Build public EcsStaticMask Build() { - HashSet combinedIncs = _inc; - HashSet combinedExcs = _exc; + HashSet combinedIncs = _incsSet; + HashSet combinedExcs = _excsSet; + HashSet combinedAnys = _anysSet; if (_combineds.Count > 0) { combinedIncs = new HashSet(); combinedExcs = new HashSet(); + //combinedAnys = new HashSet(); //TODO разработать комбинацию для any if (_sortedCombinedChecker == false) { _combineds.Sort((a, b) => a.order - b.order); @@ -395,20 +438,22 @@ namespace DCFApixels.DragonECS combinedIncs.UnionWith(submask._incs); combinedExcs.UnionWith(submask._excs); } - combinedIncs.ExceptWith(_exc);//удаляю конфликтующие ограничения - combinedExcs.ExceptWith(_inc);//удаляю конфликтующие ограничения - combinedIncs.UnionWith(_inc); - combinedExcs.UnionWith(_exc); + combinedIncs.ExceptWith(_excsSet);//удаляю конфликтующие ограничения + combinedExcs.ExceptWith(_incsSet);//удаляю конфликтующие ограничения + combinedIncs.UnionWith(_incsSet); + combinedExcs.UnionWith(_excsSet); _combineds.Clear(); } else { - combinedIncs = _inc; - combinedExcs = _exc; + combinedIncs = _incsSet; + combinedExcs = _excsSet; + combinedAnys = _anysSet; } if (_excepteds.Count > 0) { + //TODO разработать вычитание для any foreach (var item in _excepteds) { //if (combinedIncs.Overlaps(item.mask._exc) || combinedExcs.Overlaps(item.mask._inc)) @@ -426,12 +471,15 @@ namespace DCFApixels.DragonECS Array.Sort(inc); var exc = combinedExcs.ToArray(); Array.Sort(exc); + var any = combinedAnys.ToArray(); + Array.Sort(any); - var key = new Key(inc, exc); + var key = new Key(inc, exc, any); EcsStaticMask result = CreateMask(key); - _inc.Clear(); - _exc.Clear(); + _incsSet.Clear(); + _excsSet.Clear(); + _anysSet.Clear(); _version++; return result; diff --git a/src/EcsWorld.cs b/src/EcsWorld.cs index 182e8e5..a4cdaf4 100644 --- a/src/EcsWorld.cs +++ b/src/EcsWorld.cs @@ -556,6 +556,24 @@ namespace DCFApixels.DragonECS return false; } } + + //TODO оптимизировать + if (mask_._anys.Length != 0) + { + int count = 0; + for (int i = 0, iMax = mask_._anys.Length; i < iMax; i++) + { + if (_pools[mask_._anys[i]].Has(entityID_)) + { + count++; + } + } + if(count == 0) + { + return false; + } + } + return true; } bool deepDebug = IsMatchesMaskDeepDebug(mask, entityID); @@ -563,6 +581,7 @@ namespace DCFApixels.DragonECS var incChuncks = mask._incChunckMasks; var excChuncks = mask._excChunckMasks; + var anyChuncks = mask._anyChunckMasks; var componentMaskStartIndex = entityID << _entityComponentMaskLengthBitShift; for (int i = 0; i < incChuncks.Length; i++) @@ -587,6 +606,27 @@ namespace DCFApixels.DragonECS return false; } } + //TODO оптимизировать + if (anyChuncks.Length > 0) + { + int count = 0; + for (int i = 0; i < anyChuncks.Length; i++) + { + var bit = anyChuncks[i]; + if ((_entityComponentMasks[componentMaskStartIndex + bit.chunkIndex] & bit.mask) == bit.mask) + { + count++; + } + } + if (count == 0) + { +#if DEBUG && DRAGONECS_DEEP_DEBUG + if (false != deepDebug) { Throw.DeepDebugException(); } +#endif + return false; + } + } + #if DEBUG && DRAGONECS_DEEP_DEBUG if (true != deepDebug) { Throw.DeepDebugException(); } diff --git a/src/Pools/EcsPool.cs b/src/Pools/EcsPool.cs index 8d2c18d..8e11780 100644 --- a/src/Pools/EcsPool.cs +++ b/src/Pools/EcsPool.cs @@ -392,6 +392,7 @@ namespace DCFApixels.DragonECS #region Convertors public static implicit operator EcsPool(IncludeMarker a) { return a.GetInstance>(); } public static implicit operator EcsPool(ExcludeMarker a) { return a.GetInstance>(); } + public static implicit operator EcsPool(AnyMarker a) { return a.GetInstance>(); } public static implicit operator EcsPool(OptionalMarker a) { return a.GetInstance>(); } public static implicit operator EcsPool(EcsWorld.GetPoolInstanceMarker a) { return a.GetInstance>(); } #endregion @@ -477,6 +478,7 @@ namespace DCFApixels.DragonECS public static implicit operator ReadonlyEcsPool(EcsPool a) { return new ReadonlyEcsPool(a); } public static implicit operator ReadonlyEcsPool(IncludeMarker a) { return a.GetInstance>(); } public static implicit operator ReadonlyEcsPool(ExcludeMarker a) { return a.GetInstance>(); } + public static implicit operator ReadonlyEcsPool(AnyMarker a) { return a.GetInstance>(); } public static implicit operator ReadonlyEcsPool(OptionalMarker a) { return a.GetInstance>(); } public static implicit operator ReadonlyEcsPool(EcsWorld.GetPoolInstanceMarker a) { return a.GetInstance>(); } #endregion @@ -511,6 +513,11 @@ namespace DCFApixels.DragonECS { return self.OptionalPool>(); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static EcsPool Any(this EcsAspect.Builder self) where TComponent : struct, IEcsComponent + { + return self.AnyPool>(); + } #region Obsolete [Obsolete("Use " + nameof(EcsAspect) + "." + nameof(EcsAspect.Builder) + "." + nameof(Inc) + "()")] diff --git a/src/Pools/EcsTagPool.cs b/src/Pools/EcsTagPool.cs index 84b6adb..885184c 100644 --- a/src/Pools/EcsTagPool.cs +++ b/src/Pools/EcsTagPool.cs @@ -314,6 +314,7 @@ namespace DCFApixels.DragonECS #region Convertors public static implicit operator EcsTagPool(IncludeMarker a) { return a.GetInstance>(); } public static implicit operator EcsTagPool(ExcludeMarker a) { return a.GetInstance>(); } + public static implicit operator EcsTagPool(AnyMarker a) { return a.GetInstance>(); } public static implicit operator EcsTagPool(OptionalMarker a) { return a.GetInstance>(); } public static implicit operator EcsTagPool(EcsWorld.GetPoolInstanceMarker a) { return a.GetInstance>(); } #endregion @@ -401,6 +402,7 @@ namespace DCFApixels.DragonECS public static implicit operator ReadonlyEcsTagPool(EcsTagPool a) { return new ReadonlyEcsTagPool(a); } public static implicit operator ReadonlyEcsTagPool(IncludeMarker a) { return a.GetInstance>(); } public static implicit operator ReadonlyEcsTagPool(ExcludeMarker a) { return a.GetInstance>(); } + public static implicit operator ReadonlyEcsTagPool(AnyMarker a) { return a.GetInstance>(); } public static implicit operator ReadonlyEcsTagPool(OptionalMarker a) { return a.GetInstance>(); } public static implicit operator ReadonlyEcsTagPool(EcsWorld.GetPoolInstanceMarker a) { return a.GetInstance>(); } #endregion @@ -430,6 +432,11 @@ namespace DCFApixels.DragonECS return self.ExcludePool>(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static EcsTagPool Any(this EcsAspect.Builder self) where TTagComponent : struct, IEcsTagComponent + { + return self.AnyPool>(); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static EcsTagPool Opt(this EcsAspect.Builder self) where TTagComponent : struct, IEcsTagComponent { return self.OptionalPool>();