From 5c9452e56bd70b59b19965d07cf672b9179251b6 Mon Sep 17 00:00:00 2001 From: Mikhail <99481254+DCFApixels@users.noreply.github.com> Date: Thu, 1 Jun 2023 19:13:04 +0800 Subject: [PATCH 1/3] update EcsGroup --- src/EcsGroup.cs | 141 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 97 insertions(+), 44 deletions(-) diff --git a/src/EcsGroup.cs b/src/EcsGroup.cs index 53b4c67..1a05b0c 100644 --- a/src/EcsGroup.cs +++ b/src/EcsGroup.cs @@ -1,9 +1,11 @@ using System; +using System.Collections; +using System.Collections.Generic; using System.Diagnostics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; #if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS -using static DCFApixels.DragonECS.EcsGroup.ThrowHalper; +using static DCFApixels.DragonECS.EcsGroup.ThrowHelper; #endif namespace DCFApixels.DragonECS @@ -57,9 +59,21 @@ namespace DCFApixels.DragonECS [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Has(int entityID) => _source.Has(entityID); [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int IndexOf(int entityID) => _source.IndexOf(entityID); + [MethodImpl(MethodImplOptions.AggressiveInlining)] public EcsGroup.Enumerator GetEnumerator() => _source.GetEnumerator(); [MethodImpl(MethodImplOptions.AggressiveInlining)] public EcsGroup Clone() => _source.Clone(); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int[] Bake() => _source.Bake(); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int Bake(ref int[] entities) => _source.Bake(ref entities); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Bake(List entities) => _source.Bake(entities); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Span ToSpan() => _source.ToSpan(); + public Span ToSpan(int start, int length) => _source.ToSpan(start, length); + [MethodImpl(MethodImplOptions.AggressiveInlining)] public int First() => _source.First(); [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -95,7 +109,7 @@ namespace DCFApixels.DragonECS } [DebuggerTypeProxy(typeof(DebuggerProxy))] - public unsafe class EcsGroup : IDisposable, IEquatable + public unsafe class EcsGroup : IDisposable, IEquatable, IEnumerable { private EcsWorld _source; private int[] _dense; @@ -143,7 +157,7 @@ namespace DCFApixels.DragonECS } #endregion - #region Constrcutors/Finalizer + #region Constrcutors [MethodImpl(MethodImplOptions.AggressiveInlining)] public static EcsGroup New(EcsWorld world) { @@ -161,16 +175,12 @@ namespace DCFApixels.DragonECS } #endregion - #region Has - //TODO переименовать в Has + #region Has/IndexOf [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Has(int entityID) { return _sparse[entityID] > 0; } - #endregion - - #region IndexOf [MethodImpl(MethodImplOptions.AggressiveInlining)] public int IndexOf(int entityID) { @@ -234,7 +244,7 @@ namespace DCFApixels.DragonECS } #endregion - #region CopyFrom/Clone + #region CopyFrom/Clone/Bake/ToSpan [MethodImpl(MethodImplOptions.AggressiveInlining)] public void CopyFrom(EcsReadonlyGroup group) => CopyFrom(group.GetGroupInternal()); public void CopyFrom(EcsGroup group) @@ -253,6 +263,33 @@ namespace DCFApixels.DragonECS result.CopyFrom(this); return result; } + public int[] Bake() + { + int[] result = new int[_count]; + Array.Copy(_dense, result, _count); + return result; + } + public int Bake(ref int[] entities) + { + if(entities.Length < _count) + entities = new int[_count]; + Array.Copy(_dense, entities, _count); + return _count; + } + public void Bake(List entities) + { + entities.Clear(); + foreach (var e in this) + entities.Add(e); + } + public Span ToSpan() => new Span(_dense, 0, _count); + public Span ToSpan(int start, int length) + { +#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS + if (start + length > _count) ThrowArgumentOutOfRangeException(); +#endif + return new Span(_dense, start, length); + } #endregion #region Set operations @@ -263,7 +300,7 @@ namespace DCFApixels.DragonECS public void UnionWith(EcsGroup group) { #if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS - if (_source != group.World) throw new ArgumentException("WorldIndex != groupFilter.WorldIndex"); + if (_source != group.World) ThrowArgumentDifferentWorldsException(); #endif foreach (var item in group) if (!Has(item)) @@ -277,7 +314,7 @@ namespace DCFApixels.DragonECS public void ExceptWith(EcsGroup group) { #if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS - if (_source != group.World) throw new ArgumentException("WorldIndex != groupFilter.WorldIndex"); + if (_source != group.World) ThrowArgumentDifferentWorldsException(); #endif foreach (var item in this) if (group.Has(item)) @@ -291,7 +328,7 @@ namespace DCFApixels.DragonECS public void AndWith(EcsGroup group) { #if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS - if (World != group.World) throw new ArgumentException("WorldIndex != groupFilter.WorldIndex"); + if (World != group.World) ThrowArgumentDifferentWorldsException(); #endif foreach (var item in this) if (!group.Has(item)) @@ -305,7 +342,7 @@ namespace DCFApixels.DragonECS public void XorWith(EcsGroup group) { #if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS - if (_source != group.World) throw new ArgumentException("WorldIndex != groupFilter.WorldIndex"); + if (_source != group.World) ThrowArgumentDifferentWorldsException(); #endif foreach (var item in group) if (Has(item)) @@ -316,18 +353,31 @@ namespace DCFApixels.DragonECS #endregion #region Static Set operations + /// as Intersect sets + /// new group from pool + public static EcsGroup Union(EcsGroup a, EcsGroup b) + { +#if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS + if (a._source != b._source) ThrowArgumentDifferentWorldsException(); +#endif + EcsGroup result = a._source.GetGroupFromPool(); + foreach (var item in a) + result.AddInternal(item); + foreach (var item in b) + result.Add(item); + return result; + } /// as Except sets /// new group from pool public static EcsGroup Except(EcsGroup a, EcsGroup b) { #if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS - if (a._source != b._source) throw new ArgumentException("a.WorldIndex != b.WorldIndex"); + if (a._source != b._source) ThrowArgumentDifferentWorldsException(); #endif EcsGroup result = a._source.GetGroupFromPool(); foreach (var item in a) if (!b.Has(item)) result.AddInternal(item); - a._source.ReleaseGroup(a); return result; } /// as Intersect sets @@ -335,50 +385,57 @@ namespace DCFApixels.DragonECS public static EcsGroup And(EcsGroup a, EcsGroup b) { #if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS - if (a._source != b._source) throw new ArgumentException("a.WorldIndex != b.WorldIndex"); + if (a._source != b._source) ThrowArgumentDifferentWorldsException(); #endif EcsGroup result = a._source.GetGroupFromPool(); foreach (var item in a) if (b.Has(item)) result.AddInternal(item); - a._source.ReleaseGroup(a); return result; } - /// as Intersect sets + + /// as Symmetric Except sets /// new group from pool - public static EcsGroup Union(EcsGroup a, EcsGroup b) + public static EcsGroup Xor(EcsGroup a, EcsGroup b) { #if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS - if (a._source != b._source) throw new ArgumentException("a.WorldIndex != b.WorldIndex"); + if (a._source != b._source) ThrowArgumentDifferentWorldsException(); #endif EcsGroup result = a._source.GetGroupFromPool(); foreach (var item in a) - result.AddInternal(item); - foreach (var item in a) - result.Add(item); + if (!b.Has(item)) + result.AddInternal(item); + foreach (var item in b) + if (!a.Has(item)) + result.AddInternal(item); return result; } #endregion - #region GetEnumerator + #region Enumerator [MethodImpl(MethodImplOptions.AggressiveInlining)] public Enumerator GetEnumerator() { return new Enumerator(this); } - #endregion - - #region Enumerator - public ref struct Enumerator// : IDisposable + IEnumerator IEnumerable.GetEnumerator() + { + for (int i = 0; i < _count; i++) + yield return _dense[i]; + } + IEnumerator IEnumerable.GetEnumerator() + { + for (int i = 0; i < _count; i++) + yield return _dense[i]; + } + public ref struct Enumerator { - // private readonly EcsGroup source; private readonly int[] _dense; private readonly int _count; private int _index; [MethodImpl(MethodImplOptions.AggressiveInlining)] public Enumerator(EcsGroup group) { - // source = group; _dense = group._dense; _count = group._count; _index = 0; @@ -390,8 +447,6 @@ namespace DCFApixels.DragonECS } [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool MoveNext() => ++_index <= _count && _count < _dense.Length; // <= потму что отсчет начинается с индекса 1 //_count < _dense.Length дает среде понять что проверки на выход за границы не нужны - //[MethodImpl(MethodImplOptions.AggressiveInlining)] - //public void Dispose() => source.Unlock(); } #endregion @@ -401,12 +456,10 @@ namespace DCFApixels.DragonECS public bool Equals(EcsReadonlyGroup other) => Equals(other.GetGroupInternal()); public bool Equals(EcsGroup other) { - if (ReferenceEquals(other, null)) + if (other is null || other.Count != Count) return false; - if (other.Count != Count) - return false; - foreach (var item in other) - if (!Has(item)) + foreach (var e in other) + if (!Has(e)) return false; return true; } @@ -431,8 +484,7 @@ namespace DCFApixels.DragonECS private static bool StaticEquals(EcsGroup a, EcsReadonlyGroup b) => StaticEquals(a, b.GetGroupInternal()); private static bool StaticEquals(EcsGroup a, EcsGroup b) { - if (ReferenceEquals(a, null)) - return false; + if (a is null) return false; return a.Equals(b); } public static bool operator ==(EcsGroup a, EcsGroup b) => StaticEquals(a, b); @@ -451,15 +503,12 @@ namespace DCFApixels.DragonECS #region IDisposable/Release public void Dispose() => Release(); - public void Release() - { - _source.ReleaseGroup(this); - } + public void Release() => _source.ReleaseGroup(this); #endregion #region ThrowHalper #if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS - internal static class ThrowHalper + internal static class ThrowHelper { [MethodImpl(MethodImplOptions.NoInlining)] public static void ThrowAlreadyContains(int entityID) => throw new EcsFrameworkException($"This group already contains entity {entityID}."); @@ -467,6 +516,10 @@ namespace DCFApixels.DragonECS public static void ThrowArgumentOutOfRange() => throw new ArgumentOutOfRangeException($"index is less than 0 or is equal to or greater than Count."); [MethodImpl(MethodImplOptions.NoInlining)] public static void ThrowDoesNotContain(int entityID) => throw new EcsFrameworkException($"This group does not contain entity {entityID}."); + [MethodImpl(MethodImplOptions.NoInlining)] + public static void ThrowArgumentOutOfRangeException() => throw new ArgumentOutOfRangeException(); + [MethodImpl(MethodImplOptions.NoInlining)] + public static void ThrowArgumentDifferentWorldsException() => throw new ArgumentException("The groups belong to different worlds."); } #endif #endregion From 8c612aa94994f13f8f5511c58966fc62f30cf846 Mon Sep 17 00:00:00 2001 From: Mikhail <99481254+DCFApixels@users.noreply.github.com> Date: Thu, 1 Jun 2023 20:14:34 +0800 Subject: [PATCH 2/3] update EcsGroup --- src/EcsGroup.cs | 30 ++++++++++++++++++++++++------ src/EcsWorld.cs | 4 ++-- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/src/EcsGroup.cs b/src/EcsGroup.cs index 1a05b0c..8a02fcd 100644 --- a/src/EcsGroup.cs +++ b/src/EcsGroup.cs @@ -161,7 +161,7 @@ namespace DCFApixels.DragonECS [MethodImpl(MethodImplOptions.AggressiveInlining)] public static EcsGroup New(EcsWorld world) { - return world.GetGroupFromPool(); + return world.GetFreeGroup(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] internal EcsGroup(EcsWorld world, int denseCapacity = 64) @@ -259,7 +259,7 @@ namespace DCFApixels.DragonECS } public EcsGroup Clone() { - EcsGroup result = _source.GetGroupFromPool(); + EcsGroup result = _source.GetFreeGroup(); result.CopyFrom(this); return result; } @@ -350,6 +350,14 @@ namespace DCFApixels.DragonECS else AddInternal(item); } + public void Inverse() + { + foreach (var item in _source.Entities) + if (Has(item)) + RemoveInternal(item); + else + AddInternal(item); + } #endregion #region Static Set operations @@ -360,7 +368,7 @@ namespace DCFApixels.DragonECS #if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS if (a._source != b._source) ThrowArgumentDifferentWorldsException(); #endif - EcsGroup result = a._source.GetGroupFromPool(); + EcsGroup result = a._source.GetFreeGroup(); foreach (var item in a) result.AddInternal(item); foreach (var item in b) @@ -374,7 +382,7 @@ namespace DCFApixels.DragonECS #if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS if (a._source != b._source) ThrowArgumentDifferentWorldsException(); #endif - EcsGroup result = a._source.GetGroupFromPool(); + EcsGroup result = a._source.GetFreeGroup(); foreach (var item in a) if (!b.Has(item)) result.AddInternal(item); @@ -387,7 +395,7 @@ namespace DCFApixels.DragonECS #if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS if (a._source != b._source) ThrowArgumentDifferentWorldsException(); #endif - EcsGroup result = a._source.GetGroupFromPool(); + EcsGroup result = a._source.GetFreeGroup(); foreach (var item in a) if (b.Has(item)) result.AddInternal(item); @@ -401,7 +409,7 @@ namespace DCFApixels.DragonECS #if (DEBUG && !DISABLE_DEBUG) || !DISABLE_DRAGONECS_ASSERT_CHEKS if (a._source != b._source) ThrowArgumentDifferentWorldsException(); #endif - EcsGroup result = a._source.GetGroupFromPool(); + EcsGroup result = a._source.GetFreeGroup(); foreach (var item in a) if (!b.Has(item)) result.AddInternal(item); @@ -410,6 +418,15 @@ namespace DCFApixels.DragonECS result.AddInternal(item); return result; } + + public static EcsGroup Inverse(EcsGroup a) + { + EcsGroup result = a._source.GetFreeGroup(); + foreach (var item in a._source.Entities) + if (!a.Has(item)) + result.AddInternal(item); + return result; + } #endregion #region Enumerator @@ -545,6 +562,7 @@ namespace DCFApixels.DragonECS public int CapacityDense => _group.CapacityDense; public int CapacitySparce => _group.CapacitySparce; + public override string ToString() => _group.ToString(); public DebuggerProxy(EcsGroup group) => _group = group; } #endregion diff --git a/src/EcsWorld.cs b/src/EcsWorld.cs index ef9ec9d..20433dd 100644 --- a/src/EcsWorld.cs +++ b/src/EcsWorld.cs @@ -83,7 +83,7 @@ namespace DCFApixels.DragonECS _delEntBuffer = new int[_entitesCapacity >> DEL_ENT_BUFFER_SIZE_OFFSET]; _groups = new List>(); - _allEntites = GetGroupFromPool(); + _allEntites = GetFreeGroup(); _subjects = new EcsSubject[128]; _executors = new EcsQueryExecutor[128]; @@ -337,7 +337,7 @@ namespace DCFApixels.DragonECS { _groups.Add(new WeakReference(group)); } - internal EcsGroup GetGroupFromPool() + internal EcsGroup GetFreeGroup() { EcsGroup result = _groupsPool.Count <= 0 ? new EcsGroup(this) : _groupsPool.Pop(); result._isReleased = false; From de348fe0263ac76cf16fa366658281fc360c5cb0 Mon Sep 17 00:00:00 2001 From: Mikhail <99481254+DCFApixels@users.noreply.github.com> Date: Thu, 1 Jun 2023 23:09:07 +0800 Subject: [PATCH 3/3] Update package.json --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 606735d..4ca24ad 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,7 @@ "displayName": "DragonECS", "description": "C# Entity Component System Framework", "unity": "2020.3", - "version": "0.7.0", + "version": "0.7.1", "repository": { "type": "git", "url": "https://github.com/DCFApixels/DragonECS.git"