From 70cf1be4082ba59f5972a6be20404d91d6a0ca32 Mon Sep 17 00:00:00 2001 From: Mikhail <99481254+DCFApixels@users.noreply.github.com> Date: Sun, 24 Dec 2023 15:40:19 +0800 Subject: [PATCH] update --- src/Builtin/BaseProcesses.cs | 4 ++ src/Collections/EcsGroup.cs | 58 +++++++++++++-------- src/Collections/EcsSpan.cs | 81 +++++++++++++++++++++++++++++ src/EcsAspect.cs | 28 +++++++++- src/EcsRunner.cs | 2 +- src/EcsWorld.cs | 4 ++ src/Executors/EcsQueryExecutor.cs | 28 +++++++--- src/Executors/EcsWhereExecutor.cs | 85 ++++++++++++++++++++++++++++--- src/Utils/GenericEnumerable.cs | 21 ++++++++ src/Utils/ReadOnlySpanDummy.cs | 2 +- 10 files changed, 275 insertions(+), 38 deletions(-) create mode 100644 src/Collections/EcsSpan.cs create mode 100644 src/Utils/GenericEnumerable.cs diff --git a/src/Builtin/BaseProcesses.cs b/src/Builtin/BaseProcesses.cs index 6176df0..8697b95 100644 --- a/src/Builtin/BaseProcesses.cs +++ b/src/Builtin/BaseProcesses.cs @@ -7,24 +7,28 @@ namespace DCFApixels.DragonECS { #region Interfaces [MetaName(nameof(PreInit))] + [MetaColor(MetaColor.Orange)] [BindWithEcsRunner(typeof(EcsPreInitProcessRunner))] public interface IEcsPreInitProcess : IEcsProcess { void PreInit(); } [MetaName(nameof(Init))] + [MetaColor(MetaColor.Orange)] [BindWithEcsRunner(typeof(EcsInitProcessRunner))] public interface IEcsInitProcess : IEcsProcess { void Init(); } [MetaName(nameof(Run))] + [MetaColor(MetaColor.Orange)] [BindWithEcsRunner(typeof(EcsRunProcessRunner))] public interface IEcsRunProcess : IEcsProcess { void Run(); } [MetaName(nameof(Destroy))] + [MetaColor(MetaColor.Orange)] [BindWithEcsRunner(typeof(EcsDestroyProcessRunner))] public interface IEcsDestroyProcess : IEcsProcess { diff --git a/src/Collections/EcsGroup.cs b/src/Collections/EcsGroup.cs index 4f71c6b..09eb1dd 100644 --- a/src/Collections/EcsGroup.cs +++ b/src/Collections/EcsGroup.cs @@ -23,6 +23,11 @@ namespace DCFApixels.DragonECS #region Properties public bool IsNull => _source == null; + public int WorldID + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _source.World.id; + } public EcsWorld World { [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -116,6 +121,11 @@ namespace DCFApixels.DragonECS internal bool _isReleased = true; #region Properties + public int WorldID + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _source.id; + } public EcsWorld World { [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -619,7 +629,7 @@ namespace DCFApixels.DragonECS yield return _dense[i]; } public LongsIterator GetLongs() => new LongsIterator(this); - public ref struct Enumerator + public struct Enumerator : IEnumerator { private readonly int[] _dense; private readonly int _count; @@ -636,8 +646,13 @@ namespace DCFApixels.DragonECS [MethodImpl(MethodImplOptions.AggressiveInlining)] get => _dense[_index]; } + object IEnumerator.Current => Current; [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool MoveNext() => ++_index <= _count; // <= потму что отсчет начинается с индекса 1 //_count < _dense.Length дает среде понять что проверки на выход за границы не нужны + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() { } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Reset() { } } public readonly struct LongsIterator : IEnumerable { @@ -680,25 +695,6 @@ namespace DCFApixels.DragonECS } #endregion - #region Object - public override string ToString() => $"group{{{string.Join(", ", _dense.Skip(1).Take(_count))}}}"; - #endregion - - #region OtherMethods - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public int First() => _dense[1]; - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public int Last() => _dense[_count]; - #endregion - - #region OnWorldResize - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void OnWorldResize(int newSize) - { - Array.Resize(ref _sparse, newSize); - } - #endregion - #region Convertions [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator EcsReadonlyGroup(EcsGroup a) => a.Readonly; @@ -706,7 +702,26 @@ namespace DCFApixels.DragonECS public static implicit operator ReadOnlySpan(EcsGroup a) => a.ToSpan(); #endregion - #region DebuggerProxy + #region Other + public override string ToString() + { + return $"group{{{string.Join(", ", _dense.Skip(1).Take(_count))}}}"; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int First() + { + return _dense[1]; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int Last() + { + return _dense[_count]; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void OnWorldResize(int newSize) + { + Array.Resize(ref _sparse, newSize); + } internal class DebuggerProxy { private EcsGroup _group; @@ -726,7 +741,6 @@ namespace DCFApixels.DragonECS public int Count => _group.Count; public int CapacityDense => _group.CapacityDense; public int CapacitySparce => _group.CapacitySparce; - public override string ToString() => _group.ToString(); public DebuggerProxy(EcsGroup group) => _group = group; } diff --git a/src/Collections/EcsSpan.cs b/src/Collections/EcsSpan.cs new file mode 100644 index 0000000..f7b011f --- /dev/null +++ b/src/Collections/EcsSpan.cs @@ -0,0 +1,81 @@ +using System; +using System.ComponentModel; +using System.Runtime.CompilerServices; + +namespace DCFApixels.DragonECS +{ + public readonly ref struct EcsSpan + { + private readonly int _worldID; + private readonly ReadOnlySpan _values; + + #region Properties + public int WorldID => _worldID; + public EcsWorld World => EcsWorld.GetWorld(_worldID); + public int Length => _values.Length; + public bool IsEmpty => _values.IsEmpty; + public readonly int this[int index] + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _values[index]; + } + #endregion + + #region Constructors + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal EcsSpan(int worldID, ReadOnlySpan span) + { + _worldID = worldID; + _values = span; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal EcsSpan(int worldID, int[] array) + { + _worldID = worldID; + _values = array; + } + internal EcsSpan(int worldID, int[] array, int length) + { + _worldID = worldID; + _values = new ReadOnlySpan(array, 0, length); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal EcsSpan(int worldID, int[] array, int start, int length) + { + _worldID = worldID; + _values = new ReadOnlySpan(array, start, length); + } + #endregion + + #region Object +#pragma warning disable CS0809 // Устаревший член переопределяет неустаревший член + [Obsolete($"Equals() on {nameof(EcsSpan)} will always throw an exception. Use the equality operator instead.")] + [EditorBrowsable(EditorBrowsableState.Never)] + public override bool Equals(object obj) => throw new NotSupportedException(); + [Obsolete($"GetHashCode() on {nameof(EcsSpan)} will always throw an exception.")] + [EditorBrowsable(EditorBrowsableState.Never)] + public override int GetHashCode() => throw new NotSupportedException(); +#pragma warning restore CS0809 // Устаревший член переопределяет неустаревший член + public override string ToString() => _values.ToString(); + #endregion + + #region operators + public static bool operator ==(EcsSpan left, EcsSpan right) => left._values == right._values; + public static bool operator !=(EcsSpan left, EcsSpan right) => left._values != right._values; + #endregion + + #region Enumerator + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ReadOnlySpan.Enumerator GetEnumerator() => _values.GetEnumerator(); + #endregion + + #region Other + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public EcsSpan Slice(int start) => new EcsSpan(_worldID, _values.Slice(start)); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public EcsSpan Slice(int start, int length) => new EcsSpan(_worldID, _values.Slice(start, length)); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public int[] ToArray() => _values.ToArray(); + #endregion + } +} diff --git a/src/EcsAspect.cs b/src/EcsAspect.cs index bea4d3e..b7c7411 100644 --- a/src/EcsAspect.cs +++ b/src/EcsAspect.cs @@ -334,13 +334,15 @@ namespace DCFApixels.DragonECS #region Iterator public ref struct EcsAspectIterator { + public readonly int worldID; public readonly EcsMask mask; private EcsReadonlyGroup _sourceGroup; private Enumerator _enumerator; public EcsAspectIterator(EcsAspect aspect, EcsReadonlyGroup sourceGroup) { - mask = aspect.mask; + worldID = aspect.World.id; + mask = aspect.mask; _sourceGroup = sourceGroup; _enumerator = default; } @@ -361,6 +363,30 @@ namespace DCFApixels.DragonECS while (enumerator.MoveNext()) group.AddInternal(enumerator.Current); } + public int CopyTo(ref int[] array) + { + var enumerator = GetEnumerator(); + int count = 0; + while (enumerator.MoveNext()) + { + if(array.Length <= count) + Array.Resize(ref array, array.Length << 1); + array[count++] = enumerator.Current; + } + return count; + } + public EcsSpan CopyToSpan(ref int[] array) + { + var enumerator = GetEnumerator(); + int count = 0; + while (enumerator.MoveNext()) + { + if (array.Length <= count) + Array.Resize(ref array, array.Length << 1); + array[count++] = enumerator.Current; + } + return new EcsSpan(worldID, array, count); + } #region object public override string ToString() diff --git a/src/EcsRunner.cs b/src/EcsRunner.cs index b0d4470..e229c4d 100644 --- a/src/EcsRunner.cs +++ b/src/EcsRunner.cs @@ -239,7 +239,7 @@ namespace DCFApixels.DragonECS _filter = null; OnDestroy(); } - protected virtual void OnSetup() { } + protected virtual void OnSetup() { } //rename to OnInitialize protected virtual void OnDestroy() { } } } diff --git a/src/EcsWorld.cs b/src/EcsWorld.cs index 021ccbf..cae19ab 100644 --- a/src/EcsWorld.cs +++ b/src/EcsWorld.cs @@ -141,6 +141,10 @@ namespace DCFApixels.DragonECS { return GetExecutor>().Execute(); } + public EcsSpan WhereSpan() where TAspect : EcsAspect + { + return GetExecutor>().Execute(); + } #endregion #region Entity diff --git a/src/Executors/EcsQueryExecutor.cs b/src/Executors/EcsQueryExecutor.cs index c33cb3f..fdbf56a 100644 --- a/src/Executors/EcsQueryExecutor.cs +++ b/src/Executors/EcsQueryExecutor.cs @@ -1,16 +1,32 @@ -namespace DCFApixels.DragonECS +using System.Runtime.CompilerServices; + +namespace DCFApixels.DragonECS { public abstract class EcsQueryExecutor { - private EcsWorld _world; - public EcsWorld World => _world; + private EcsWorld _source; + public int WorldID + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _source.id; + } + public EcsWorld World + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _source; + } + public abstract long Version { get; } internal void Initialize(EcsWorld world) { - _world = world; + _source = world; OnInitialize(); } - internal void Destroy() => OnDestroy(); + internal void Destroy() + { + OnDestroy(); + _source = null; + } protected abstract void OnInitialize(); protected abstract void OnDestroy(); } -} +} \ No newline at end of file diff --git a/src/Executors/EcsWhereExecutor.cs b/src/Executors/EcsWhereExecutor.cs index 89a45ac..a1be62a 100644 --- a/src/Executors/EcsWhereExecutor.cs +++ b/src/Executors/EcsWhereExecutor.cs @@ -1,19 +1,29 @@ -namespace DCFApixels.DragonECS +using System.Runtime.CompilerServices; + +namespace DCFApixels.DragonECS { public sealed class EcsWhereExecutor : EcsQueryExecutor where TAspect : EcsAspect { private TAspect _aspect; private EcsGroup _filteredGroup; - private long _executeVersion; + private long _version; #if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS - private EcsProfilerMarker _executeWhere = new EcsProfilerMarker("Where"); + private readonly EcsProfilerMarker _executeMarker = new EcsProfilerMarker("Where"); #endif #region Properties - public TAspect Aspect => _aspect; - internal long ExecuteVersion => _executeVersion; + public TAspect Aspect + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _aspect; + } + public sealed override long Version + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _version; + } #endregion #region OnInitialize/OnDestroy @@ -29,19 +39,80 @@ #endregion #region Methods + [MethodImpl(MethodImplOptions.AggressiveInlining)] public EcsReadonlyGroup Execute() => ExecuteFor(_aspect.World.Entities); + [MethodImpl(MethodImplOptions.AggressiveInlining)] public EcsReadonlyGroup ExecuteFor(EcsReadonlyGroup sourceGroup) { #if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS - _executeWhere.Begin(); + _executeMarker.Begin(); if (sourceGroup.IsNull) throw new System.ArgumentNullException();//TODO составить текст исключения. + if (sourceGroup.WorldID != WorldID) throw new System.ArgumentException();//TODO составить текст исключения. #endif + unchecked { _version++; } _aspect.GetIteratorFor(sourceGroup).CopyTo(_filteredGroup); #if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS - _executeWhere.End(); + _executeMarker.End(); #endif return _filteredGroup.Readonly; } #endregion } + + + + + public sealed class EcsWhereSpanExecutor : EcsQueryExecutor where TAspect : EcsAspect + { + private TAspect _aspect; + private int[] _filteredEntities; + + private long _version; + +#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS + private readonly EcsProfilerMarker _executeMarker = new EcsProfilerMarker("Where"); +#endif + + #region Properties + public TAspect Aspect + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _aspect; + } + public sealed override long Version + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => _version; + } + #endregion + + #region OnInitialize/OnDestroy + protected sealed override void OnInitialize() + { + _aspect = World.GetAspect(); + _filteredEntities = new int[32]; + } + protected sealed override void OnDestroy() { } + #endregion + + #region Methods + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public EcsSpan Execute() => ExecuteFor(_aspect.World.Entities); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public EcsSpan ExecuteFor(EcsReadonlyGroup sourceGroup) + { +#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS + _executeMarker.Begin(); + if (sourceGroup.IsNull) throw new System.ArgumentNullException();//TODO составить текст исключения. + if (sourceGroup.WorldID != WorldID) throw new System.ArgumentException();//TODO составить текст исключения. +#endif + unchecked { _version++; } + EcsSpan result = _aspect.GetIteratorFor(sourceGroup).CopyToSpan(ref _filteredEntities); +#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS + _executeMarker.End(); +#endif + return result; + } + #endregion + } } diff --git a/src/Utils/GenericEnumerable.cs b/src/Utils/GenericEnumerable.cs new file mode 100644 index 0000000..a03a71d --- /dev/null +++ b/src/Utils/GenericEnumerable.cs @@ -0,0 +1,21 @@ +using System.Collections; +using System.Collections.Generic; +using System.Runtime.CompilerServices; + +namespace DCFApixels.DragonECS.Internal +{ + public readonly struct GenericEnumerable : IEnumerable where TEnumerator : IEnumerator + { + public readonly TEnumerator _enumerator; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public GenericEnumerable(TEnumerator enumerator) => _enumerator = enumerator; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public TEnumerator GetEnumerator() => _enumerator; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + IEnumerator IEnumerable.GetEnumerator() => _enumerator; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + IEnumerator IEnumerable.GetEnumerator() => _enumerator; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator GenericEnumerable(TEnumerator enumerator) => new GenericEnumerable(enumerator); + } +} \ No newline at end of file diff --git a/src/Utils/ReadOnlySpanDummy.cs b/src/Utils/ReadOnlySpanDummy.cs index 74ddd8b..508b375 100644 --- a/src/Utils/ReadOnlySpanDummy.cs +++ b/src/Utils/ReadOnlySpanDummy.cs @@ -38,13 +38,13 @@ namespace DCFApixels.DragonECS #endregion #region Constructors + [MethodImpl(MethodImplOptions.AggressiveInlining)] public ReadOnlySpan(T[] array) { _array = array ?? Array.Empty(); _start = 0; _length = array.Length; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] public ReadOnlySpan(T[] array, int start, int length) {