DragonECS/src/EcsAspect.cs

535 lines
20 KiB
C#
Raw Normal View History

2024-01-07 18:52:54 +08:00
using DCFApixels.DragonECS.Internal;
2023-06-26 02:53:55 +08:00
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.CompilerServices;
namespace DCFApixels.DragonECS
{
2023-06-22 14:31:13 +08:00
public abstract class EcsAspect
{
2024-01-07 18:52:54 +08:00
internal EcsWorld _source;
internal EcsMask _mask;
2024-03-26 16:06:03 +08:00
private bool _isBuilt = false;
[ThreadStatic]
2024-03-26 18:09:13 +08:00
private static Stack<Builder> _constructorBuildersStack = null;
private static Stack<Builder> GetBuildersStack()
{
2024-04-09 00:19:43 +08:00
if (_constructorBuildersStack == null)
2024-03-26 18:09:13 +08:00
{
_constructorBuildersStack = new Stack<Builder>();
}
return _constructorBuildersStack;
}
2024-03-26 16:06:03 +08:00
protected static IncludeMarker Inc
{
get
{
2024-03-26 18:09:13 +08:00
var buildersStack = GetBuildersStack();
if (buildersStack.Count <= 0)
2024-03-26 16:06:03 +08:00
{ //TODO перевести
throw new InvalidOperationException($"{nameof(Inc)} можно использовать только во время инициализации полей и в конструкторе");//TODO Перевести
}
2024-03-26 18:09:13 +08:00
return buildersStack.Peek().Inc;
2024-03-26 16:06:03 +08:00
}
}
protected static ExcludeMarker Exc
{
get
{
2024-03-26 18:09:13 +08:00
var buildersStack = GetBuildersStack();
if (buildersStack.Count <= 0)
2024-03-26 16:06:03 +08:00
{ //TODO перевести
throw new InvalidOperationException($"{nameof(Exc)} можно использовать только во время инициализации полей и в конструкторе");//TODO Перевести
}
2024-03-26 18:09:13 +08:00
return buildersStack.Peek().Exc;
2024-03-26 16:06:03 +08:00
}
}
protected static OptionalMarker Opt
{
get
{
2024-03-26 18:09:13 +08:00
var buildersStack = GetBuildersStack();
if (buildersStack.Count <= 0)
2024-03-26 16:06:03 +08:00
{ //TODO перевести
throw new InvalidOperationException($"{nameof(Opt)} можно использовать только во время инициализации полей и в конструкторе");//TODO Перевести
}
2024-03-26 18:09:13 +08:00
return buildersStack.Peek().Opt;
2024-03-26 16:06:03 +08:00
}
}
2024-01-07 18:52:54 +08:00
private UnsafeArray<int> _sortIncBuffer;
private UnsafeArray<int> _sortExcBuffer;
private UnsafeArray<EcsMaskChunck> _sortIncChunckBuffer;
private UnsafeArray<EcsMaskChunck> _sortExcChunckBuffer;
2024-01-07 18:52:54 +08:00
#region Properties
2024-03-02 21:45:09 +08:00
public EcsMask Mask
{
get { return _mask; }
}
public EcsWorld World
{
get { return _source; }
}
public bool IsInit
{
2024-03-26 16:06:03 +08:00
get { return _isBuilt; }
2024-03-02 21:45:09 +08:00
}
#endregion
#region Methods
2024-02-13 21:00:01 +08:00
public bool IsMatches(int entityID)
{
return _source.IsMatchesMask(_mask, entityID);
}
#endregion
#region Builder
protected virtual void Init(Builder b) { }
2024-02-11 01:28:18 +08:00
public sealed class Builder
{
private EcsWorld _world;
2024-01-07 19:32:16 +08:00
private EcsMask.Builder _maskBuilder;
2024-03-26 16:06:03 +08:00
private bool _isBuilt = false;
2024-03-08 20:40:19 +08:00
public IncludeMarker Inc
{
get { return new IncludeMarker(this); }
}
public ExcludeMarker Exc
{
get { return new ExcludeMarker(this); }
}
public OptionalMarker Opt
{
get { return new OptionalMarker(this); }
}
public EcsWorld World => _world;
private Builder(EcsWorld world)
{
_world = world;
2024-01-11 00:48:39 +08:00
_maskBuilder = EcsMask.New(world);
}
2024-01-07 19:32:16 +08:00
internal static unsafe TAspect New<TAspect>(EcsWorld world) where TAspect : EcsAspect
{
Builder builder = new Builder(world);
2023-06-22 14:31:13 +08:00
Type aspectType = typeof(TAspect);
EcsAspect newAspect;
//TODO добавить оповещение что инициализация через конструктор не работает
#if !REFLECTION_DISABLED
ConstructorInfo constructorInfo = aspectType.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new Type[] { typeof(Builder) }, null);
2024-03-26 16:06:03 +08:00
2024-03-26 18:09:13 +08:00
var buildersStack = GetBuildersStack();
buildersStack.Push(builder);
if (constructorInfo != null)
{
2023-06-22 14:31:13 +08:00
newAspect = (EcsAspect)constructorInfo.Invoke(new object[] { builder });
}
else
#endif
{
#pragma warning disable IL2091 // Target generic argument does not satisfy 'DynamicallyAccessedMembersAttribute' in target method or type. The generic parameter of the source method or type does not have matching annotations.
newAspect = Activator.CreateInstance<TAspect>();
#pragma warning restore IL2091
}
2024-03-26 18:09:13 +08:00
newAspect.Init(builder);
buildersStack.Pop();
2024-01-07 18:52:54 +08:00
newAspect._source = world;
2024-01-07 19:32:16 +08:00
builder.Build(out newAspect._mask);
2024-03-26 16:06:03 +08:00
newAspect._isBuilt = true;
2024-01-07 18:52:54 +08:00
newAspect._sortIncBuffer = new UnsafeArray<int>(newAspect._mask.inc.Length, true);
newAspect._sortExcBuffer = new UnsafeArray<int>(newAspect._mask.exc.Length, true);
newAspect._sortIncChunckBuffer = new UnsafeArray<EcsMaskChunck>(newAspect._mask.incChunckMasks.Length, true);
newAspect._sortExcChunckBuffer = new UnsafeArray<EcsMaskChunck>(newAspect._mask.excChunckMasks.Length, true);
for (int i = 0; i < newAspect._sortIncBuffer.Length; i++)
{
newAspect._sortIncBuffer.ptr[i] = newAspect._mask.inc[i];
}
for (int i = 0; i < newAspect._sortExcBuffer.Length; i++)
{
newAspect._sortExcBuffer.ptr[i] = newAspect._mask.exc[i];
}
for (int i = 0; i < newAspect._sortIncChunckBuffer.Length; i++)
{
newAspect._sortIncChunckBuffer.ptr[i] = newAspect._mask.incChunckMasks[i];
}
for (int i = 0; i < newAspect._sortExcChunckBuffer.Length; i++)
{
newAspect._sortExcChunckBuffer.ptr[i] = newAspect._mask.excChunckMasks[i];
}
2023-06-22 14:31:13 +08:00
return (TAspect)newAspect;
}
2024-04-18 22:14:50 +08:00
#region Include/Exclude/Optional/Combine/Except
2024-03-07 03:40:06 +08:00
public TPool IncludePool<TPool>() where TPool : IEcsPoolImplementation, new()
{
2024-03-07 03:30:18 +08:00
var pool = _world.GetPoolInstance<TPool>();
IncludeImplicit(pool.ComponentType);
return pool;
}
2024-03-07 03:40:06 +08:00
public TPool ExcludePool<TPool>() where TPool : IEcsPoolImplementation, new()
{
2024-03-07 03:30:18 +08:00
var pool = _world.GetPoolInstance<TPool>();
ExcludeImplicit(pool.ComponentType);
return pool;
}
2024-03-07 03:40:06 +08:00
public TPool OptionalPool<TPool>() where TPool : IEcsPoolImplementation, new()
{
2024-03-07 03:30:18 +08:00
return _world.GetPoolInstance<TPool>();
}
private void IncludeImplicit(Type type)
{
2024-01-07 19:32:16 +08:00
_maskBuilder.Include(type);
}
private void ExcludeImplicit(Type type)
{
2024-01-07 19:32:16 +08:00
_maskBuilder.Exclude(type);
}
2023-06-22 14:31:13 +08:00
public TOtherAspect Combine<TOtherAspect>(int order = 0) where TOtherAspect : EcsAspect
2023-06-03 01:58:54 +08:00
{
2023-06-22 14:31:13 +08:00
var result = _world.GetAspect<TOtherAspect>();
2024-01-11 00:48:39 +08:00
_maskBuilder.Combine(result.Mask);
2023-06-03 01:58:54 +08:00
return result;
}
2024-04-18 22:14:50 +08:00
public TOtherAspect Except<TOtherAspect>(int order = 0) where TOtherAspect : EcsAspect
{
var result = _world.GetAspect<TOtherAspect>();
_maskBuilder.Except(result.Mask);
return result;
}
2023-06-03 01:58:54 +08:00
#endregion
2024-01-07 19:32:16 +08:00
private void Build(out EcsMask mask)
{
2024-01-07 19:32:16 +08:00
mask = _maskBuilder.Build();
2024-03-26 16:06:03 +08:00
_isBuilt = true;
}
2023-05-28 05:53:08 +08:00
#region SupportReflectionHack
#if UNITY_2020_3_OR_NEWER
[UnityEngine.Scripting.Preserve]
#endif
private void SupportReflectionHack<TPool>() where TPool : IEcsPoolImplementation, new()
2023-05-28 05:53:08 +08:00
{
2024-03-07 03:40:06 +08:00
IncludePool<TPool>();
ExcludePool<TPool>();
OptionalPool<TPool>();
IncludeImplicit(null);
ExcludeImplicit(null);
2023-05-28 05:53:08 +08:00
}
#endregion
}
#endregion
2024-03-02 21:45:09 +08:00
#region Finalizator
2024-01-07 18:52:54 +08:00
unsafe ~EcsAspect()
{
_sortIncBuffer.Dispose();
_sortExcBuffer.Dispose();
_sortIncChunckBuffer.Dispose();
_sortExcChunckBuffer.Dispose();
}
#endregion
2023-06-02 04:00:08 +08:00
#region Iterator
public Iterator GetIterator()
{
return new Iterator(this, _source.Entities);
}
public Iterator GetIteratorFor(EcsSpan span)
{
return new Iterator(this, span);
}
2023-06-02 04:00:08 +08:00
#endregion
2023-06-05 22:09:34 +08:00
2024-01-07 18:52:54 +08:00
#region Combined
2023-06-25 23:13:51 +08:00
private readonly struct Combined
2023-06-05 22:09:34 +08:00
{
2023-06-25 23:13:51 +08:00
public readonly EcsAspect aspect;
public readonly int order;
2023-06-22 14:31:13 +08:00
public Combined(EcsAspect aspect, int order)
2023-06-05 22:09:34 +08:00
{
2023-06-22 14:31:13 +08:00
this.aspect = aspect;
2023-06-05 22:09:34 +08:00
this.order = order;
}
}
2024-01-07 18:52:54 +08:00
#endregion
#region Iterator
public ref struct Iterator
2023-12-24 15:40:19 +08:00
{
2024-04-16 12:46:09 +08:00
public readonly short worldID;
public readonly EcsAspect aspect;
private EcsSpan _span;
public Iterator(EcsAspect aspect, EcsSpan span)
2023-12-24 15:40:19 +08:00
{
worldID = aspect.World.id;
_span = span;
this.aspect = aspect;
2023-12-24 15:40:19 +08:00
}
2024-04-18 00:36:05 +08:00
#region CopyTo
public void CopyTo(EcsGroup group)
2023-12-24 15:40:19 +08:00
{
group.Clear();
var enumerator = GetEnumerator();
while (enumerator.MoveNext())
2024-03-02 21:45:09 +08:00
{
2024-03-02 04:20:34 +08:00
group.Add_Internal(enumerator.Current);
2024-03-02 21:45:09 +08:00
}
2023-12-24 15:40:19 +08:00
}
public int CopyTo(ref int[] array)
{
int count = 0;
2024-03-02 21:45:09 +08:00
var enumerator = GetEnumerator();
while (enumerator.MoveNext())
2024-01-07 18:52:54 +08:00
{
if (array.Length <= count)
2024-03-02 21:45:09 +08:00
{
Array.Resize(ref array, array.Length << 1);
2024-03-02 21:45:09 +08:00
}
array[count++] = enumerator.Current;
2024-01-07 18:52:54 +08:00
}
return count;
2024-01-07 18:52:54 +08:00
}
public EcsSpan CopyToSpan(ref int[] array)
2024-01-07 18:52:54 +08:00
{
2024-03-02 21:45:09 +08:00
int count = CopyTo(ref array);
return new EcsSpan(worldID, array, count);
}
2024-04-18 00:36:05 +08:00
#endregion
2024-03-02 21:45:09 +08:00
#region Other
public override string ToString()
{
List<int> ints = new List<int>();
foreach (var e in this)
2024-01-07 18:52:54 +08:00
{
ints.Add(e);
2024-01-07 18:52:54 +08:00
}
return CollectionUtility.EntitiesToString(ints, "it");
2024-01-07 18:52:54 +08:00
}
2024-01-07 23:19:18 +08:00
#endregion
#region Enumerator
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-03-02 21:45:09 +08:00
public Enumerator GetEnumerator() { return new Enumerator(_span, aspect); }
2024-01-07 18:52:54 +08:00
public unsafe ref struct Enumerator
{
#region CountComparers
private readonly struct IncCountComparer : IComparerX<int>
{
public readonly int[] counts;
public IncCountComparer(int[] counts)
{
this.counts = counts;
}
public int Compare(int a, int b)
{
return counts[a] - counts[b];
}
}
private readonly struct ExcCountComparer : IComparerX<int>
{
public readonly int[] counts;
public ExcCountComparer(int[] counts)
2024-01-07 23:19:18 +08:00
{
this.counts = counts;
2024-01-07 23:19:18 +08:00
}
public int Compare(int a, int b)
{
return counts[b] - counts[a];
}
}
#endregion
private ReadOnlySpan<int>.Enumerator _span;
2024-02-16 21:17:20 +08:00
private readonly int[] _entityComponentMasks;
private static EcsMaskChunck* _preSortedIncBuffer;
private static EcsMaskChunck* _preSortedExcBuffer;
private UnsafeArray<EcsMaskChunck> _sortIncChunckBuffer;
private UnsafeArray<EcsMaskChunck> _sortExcChunckBuffer;
2024-04-18 00:36:05 +08:00
private readonly int _entityComponentMaskLengthBitShift;
public unsafe Enumerator(EcsSpan span, EcsAspect aspect)
{
2024-02-16 21:17:20 +08:00
_entityComponentMasks = aspect.World._entityComponentMasks;
_sortIncChunckBuffer = aspect._sortIncChunckBuffer;
_sortExcChunckBuffer = aspect._sortExcChunckBuffer;
2024-04-18 00:36:05 +08:00
_entityComponentMaskLengthBitShift = aspect.World._entityComponentMaskLengthBitShift;
2024-02-16 21:17:20 +08:00
2024-04-18 22:14:50 +08:00
if (aspect.Mask.IsBroken)
{
_span = span.Slice(0, 0).GetEnumerator();
return;
}
#region Sort
UnsafeArray<int> _sortIncBuffer = aspect._sortIncBuffer;
UnsafeArray<int> _sortExcBuffer = aspect._sortExcBuffer;
int[] counts = aspect.World._poolComponentCounts;
if (_preSortedIncBuffer == null)
2024-01-07 23:19:18 +08:00
{
_preSortedIncBuffer = UnmanagedArrayUtility.New<EcsMaskChunck>(256);
_preSortedExcBuffer = UnmanagedArrayUtility.New<EcsMaskChunck>(256);
2024-01-07 23:19:18 +08:00
}
if (_sortIncChunckBuffer.Length > 1)
{
IncCountComparer incComparer = new IncCountComparer(counts);
UnsafeArraySortHalperX<int>.InsertionSort(_sortIncBuffer.ptr, _sortIncBuffer.Length, ref incComparer);
for (int i = 0; i < _sortIncBuffer.Length; i++)
{
_preSortedIncBuffer[i] = EcsMaskChunck.FromID(_sortIncBuffer.ptr[i]);
}
for (int i = 0, ii = 0; ii < _sortIncChunckBuffer.Length; ii++)
{
2024-04-18 22:14:50 +08:00
EcsMaskChunck chunkX = _preSortedIncBuffer[i];
int chankIndexX = chunkX.chankIndex;
int maskX = chunkX.mask;
for (int j = i + 1; j < _sortIncBuffer.Length; j++)
{
if (_preSortedIncBuffer[j].chankIndex == chankIndexX)
{
maskX |= _preSortedIncBuffer[j].mask;
}
}
_sortIncChunckBuffer.ptr[ii] = new EcsMaskChunck(chankIndexX, maskX);
while (++i < _sortIncBuffer.Length && _preSortedIncBuffer[i].chankIndex == chankIndexX)
{
// skip
}
}
}
2024-04-08 23:49:56 +08:00
if (_sortIncChunckBuffer.Length > 0 && counts[_sortIncBuffer.ptr[0]] <= 0)
{
_span = span.Slice(0, 0).GetEnumerator();
return;
}
if (_sortExcChunckBuffer.Length > 1)
{
ExcCountComparer excComparer = new ExcCountComparer(counts);
UnsafeArraySortHalperX<int>.InsertionSort(_sortExcBuffer.ptr, _sortExcBuffer.Length, ref excComparer);
for (int i = 0; i < _sortExcBuffer.Length; i++)
{
_preSortedExcBuffer[i] = EcsMaskChunck.FromID(_sortExcBuffer.ptr[i]);
}
for (int i = 0, ii = 0; ii < _sortExcChunckBuffer.Length; ii++)
{
EcsMaskChunck bas = _preSortedExcBuffer[i];
int chankIndexX = bas.chankIndex;
int maskX = bas.mask;
for (int j = i + 1; j < _sortExcBuffer.Length; j++)
{
if (_preSortedExcBuffer[j].chankIndex == chankIndexX)
{
maskX |= _preSortedExcBuffer[j].mask;
}
}
_sortExcChunckBuffer.ptr[ii] = new EcsMaskChunck(chankIndexX, maskX);
while (++i < _sortExcBuffer.Length && _preSortedExcBuffer[i].chankIndex == chankIndexX)
{
// skip
}
}
}
#endregion
2024-04-18 00:36:05 +08:00
2024-04-08 23:49:56 +08:00
_span = span.GetEnumerator();
}
public int Current
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
2024-03-02 21:45:09 +08:00
get { return _span.Current; }
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool MoveNext()
{
while (_span.MoveNext())
2023-11-22 17:35:03 +08:00
{
2024-04-18 00:36:05 +08:00
int chunck = _span.Current << _entityComponentMaskLengthBitShift;
for (int i = 0; i < _sortIncChunckBuffer.Length; i++)
{
var bit = _sortIncChunckBuffer.ptr[i];
2024-04-08 23:49:56 +08:00
if ((_entityComponentMasks[chunck + bit.chankIndex] & bit.mask) != bit.mask)
2024-03-02 21:45:09 +08:00
{
goto skip;
2024-03-02 21:45:09 +08:00
}
}
for (int i = 0; i < _sortExcChunckBuffer.Length; i++)
{
var bit = _sortExcChunckBuffer.ptr[i];
2024-04-08 23:49:56 +08:00
if ((_entityComponentMasks[chunck + bit.chankIndex] & bit.mask) != 0)
2024-03-02 21:45:09 +08:00
{
goto skip;
2024-03-02 21:45:09 +08:00
}
}
return true;
skip: continue;
2023-11-22 17:35:03 +08:00
}
return false;
}
}
#endregion
}
2023-06-02 04:00:08 +08:00
#endregion
}
2024-03-08 20:40:19 +08:00
public readonly ref struct IncludeMarker
{
private readonly EcsAspect.Builder _builder;
public IncludeMarker(EcsAspect.Builder builder)
{
_builder = builder;
}
2024-03-09 21:33:44 +08:00
public T GetInstance<T>()
2024-03-08 20:40:19 +08:00
where T : IEcsPoolImplementation, new()
{
return _builder.IncludePool<T>();
}
}
public readonly ref struct ExcludeMarker
{
private readonly EcsAspect.Builder _builder;
public ExcludeMarker(EcsAspect.Builder builder)
{
_builder = builder;
}
public T GetInstance<T>()
where T : IEcsPoolImplementation, new()
{
return _builder.ExcludePool<T>();
}
}
public readonly ref struct OptionalMarker
{
private readonly EcsAspect.Builder _builder;
public OptionalMarker(EcsAspect.Builder builder)
{
_builder = builder;
}
public T GetInstance<T>()
where T : IEcsPoolImplementation, new()
{
return _builder.OptionalPool<T>();
}
}
}