Merge branch 'dev' into unsafe_pool

This commit is contained in:
Mikhail 2026-03-17 15:25:02 +08:00
commit 015c6be9f0
37 changed files with 1679 additions and 1409 deletions

View File

@ -89,12 +89,12 @@ DragonECS - это [ECS](https://en.wikipedia.org/wiki/Entity_component_system)
Обязательные требования:
+ Минимальная версия C# 7.3;
Опционально:
+ Поддержка NativeAOT
Поддерживает:
+ NativeAOT;
+ Игровые движки с C#: Unity, Godot, MonoGame и т.д.
Протестировано:
+ **Unity:** Минимальная версия 2020.3.0;
+ **Unity:** Минимальная версия 2021.2.0;
## Установка для Unity
> Рекомендуется так же установить расширение [Интеграция с движком Unity](https://github.com/DCFApixels/DragonECS-Unity)
@ -125,6 +125,7 @@ https://github.com/DCFApixels/DragonECS.git
* [Графы](https://github.com/DCFApixels/DragonECS-Graphs)
* Утилиты:
* [Упрощенный синтаксис](https://gist.github.com/DCFApixels/d7bfbfb8cb70d141deff00be24f28ff0)
* [EcsRefPool](https://gist.github.com/DCFApixels/73e392ccabdd98b3d4a517017d8a3f22)
* [Таймеры](https://gist.github.com/DCFApixels/71a416275660c465ece76242290400df)
* [Однокадровые компоненты](https://gist.github.com/DCFApixels/46d512dbcf96c115b94c3af502461f60)
* [Шаблоны кода IDE](https://gist.github.com/ctzcs/0ba948b0e53aa41fe1c87796a401660b) и [для Unity](https://gist.github.com/ctzcs/d4c7730cf6cd984fe6f9e0e3f108a0f1)
@ -612,9 +613,9 @@ class Aspect : EcsAspect
public EcsPool<Velocity> velocities;
protected override void Init(Builder b)
{
poses = b.IncludePool<Pose>();
velocities = b.IncludePool<Velocity>();
b.ExcludePool<FreezedTag>();
poses = b.Inc<Pose>();
velocities = b.Inc<Velocity>();
b.Exc<FreezedTag>();
}
}
```
@ -638,8 +639,8 @@ class Aspect : EcsAspect
otherAspect1 = b.Combine<OtherAspect1>(1);
// Хотя для OtherAspect1 метод Combine был вызван раньше, сначала будет скомбинирован с OtherAspect2, так как по умолчанию order = 0.
otherAspect2 = b.Combine<OtherAspect2>();
// Если в OtherAspect1 или в OtherAspect2 было условие b.Exclude<Pose>() тут оно будет заменено на b.Include<Pose>().
poses = b.Include<Pose>();
// Если в OtherAspect1 или в OtherAspect2 было условие b.Exc<Pose>() тут оно будет заменено на b.Inc<Pose>().
poses = b.Inc<Pose>();
}
}
```
@ -963,7 +964,6 @@ using (_marker.Auto())
+ `DRAGONECS_DISABLE_CATH_EXCEPTIONS` - Выключает поведение по умолчанию по обработке исключений. По умолчанию фреймворк будет ловить исключения с выводом информации из исключений через EcsDebug и продолжать работу.
+ `REFLECTION_DISABLED` - Полностью ограничивает работу фреймворка с Reflection.
+ `DISABLE_DEBUG` - Для среды где не поддерживается ручное отключение DEBUG, например Unity.
+ `ENABLE_DUMMY_SPAN` - На случай если в среде не поддерживаются Span типы, включает его замену.
</br>
@ -1123,13 +1123,6 @@ public struct WorldComponent : IEcsWorldComponent<WorldComponent>
# FAQ
## 'ReadOnlySpan<>' could not be found
В версии Unity 2020.1.х в консоли может выпадать ошибка:
```
The type or namespace name 'ReadOnlySpan<>' could not be found (are you missing a using directive or an assembly reference?)
```
Чтобы починить добавьте директиву `ENABLE_DUMMY_SPAN` в `Project Settings/Player/Other Settings/Scripting Define Symbols`.
## Как Выключать/Включать системы?
Напрямую - никак. </br>
Обычно потребность выключить/включить систему появляется когда поменялось общее состояние игры, это может так же значить что нужно переключить сразу группу систем, все это в совокупности можно рассматривать как изменения процессов. Есть 2 решения:</br>

View File

@ -196,7 +196,7 @@ namespace DCFApixels.DragonECS
{
if (_groupSparsePagePoolCount <= 0)
{
return MemoryAllocator.AllocAndInit<int>(EcsGroup.PAGE_SIZE).As<int>();
return MemoryAllocator.AllocAndInit<int>(EcsGroup.PAGE_SIZE).Ptr;
}
var takedPage = _groupSparsePagePool[--_groupSparsePagePoolCount];
_groupSparsePagePool[_groupSparsePagePoolCount] = MemoryAllocator.Handler.Empty;
@ -228,7 +228,7 @@ namespace DCFApixels.DragonECS
for (int i = 0; i < _groupSparsePagePoolCount; i++)
{
ref var page = ref _groupSparsePagePool[i];
if (page.IsEmpty == false)
if (page.IsCreated)
{
MemoryAllocator.FreeAndClear(ref page);
}
@ -291,7 +291,7 @@ namespace DCFApixels.DragonECS
private int _count = 0;
internal bool _isReleased = true;
internal static readonly int* _nullPage = MemoryAllocator.AllocAndInit<int>(PageSlot.SIZE).As<int>();
internal static readonly int* _nullPage = MemoryAllocator.AllocAndInit<int>(PageSlot.SIZE).Ptr;
internal static readonly long _nullPagePtrFake = (long)_nullPage;
#region Properties
@ -344,17 +344,6 @@ namespace DCFApixels.DragonECS
#endif
return _dense[++index];
}
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
// set
// {
// // TODO добавить лок енумератора на изменение
//#if DEBUG || DRAGONECS_STABILITY_MODE
// if (index < 0 || index >= Count) { Throw.ArgumentOutOfRange(); }
//#endif
// var oldValue = _dense[index];
// _dense[index] = value;
// _sparse[oldValue] = 0;
// }
}
#endregion
@ -394,7 +383,7 @@ namespace DCFApixels.DragonECS
page.IndexesXOR = 0;
page.Count = 0;
}
_sparsePagesHandler.Dispose();
_sparsePagesHandler.DisposeAndReset();
}
}
public void Dispose()
@ -555,7 +544,6 @@ namespace DCFApixels.DragonECS
ref PageSlot page = ref _sparsePages[i];
if (page.Indexes != _nullPage)
{
//TODO тут надо оптимизировать отчисткой не всего а по dense списку
for (int j = 0; j < PageSlot.SIZE; j++)
{
page.Indexes[j] = 0;

View File

@ -1,6 +1,7 @@
#if DISABLE_DEBUG
#undef DEBUG
#endif
using DCFApixels.DragonECS.Core;
using DCFApixels.DragonECS.Core.Internal;
using DCFApixels.DragonECS.Core.Unchecked;
using System;
@ -50,7 +51,7 @@ namespace DCFApixels.DragonECS
public bool IsSourceEntities
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return this == EcsWorld.GetWorld(_worldID).GetCurrentEntities_Internal(); }
get { return _values == EcsWorld.GetWorld(_worldID).GetCurrentEntities_Internal()._values; }
}
#if ENABLE_IL2CPP
[Il2CppSetOption(Option.ArrayBoundsChecks, true)]
@ -117,8 +118,8 @@ namespace DCFApixels.DragonECS
#endregion
#region operators
public static bool operator ==(EcsSpan left, EcsSpan right) { return left._values == right._values; }
public static bool operator !=(EcsSpan left, EcsSpan right) { return left._values != right._values; }
public static bool operator ==(EcsSpan left, EcsSpan right) { return left._values == right._values && left._worldID == right._worldID; }
public static bool operator !=(EcsSpan left, EcsSpan right) { return left._values != right._values || left._worldID != right._worldID; }
#endregion
#region Enumerator
@ -127,6 +128,7 @@ namespace DCFApixels.DragonECS
#endregion
#region Other
public ReadOnlySpan<int> AsSystemSpan() { return _values; }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int First() { return _values[0]; }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@ -170,6 +172,7 @@ namespace DCFApixels.DragonECS
_worldID = span._worldID;
}
public DebuggerProxy(EcsLongsSpan span) : this(span.ToSpan()) { }
public DebuggerProxy(EcsUnsafeSpan span) : this(span.ToSpan()) { }
}
#endregion
}
@ -316,4 +319,166 @@ namespace DCFApixels.DragonECS
#pragma warning restore CS0809 // Устаревший член переопределяет неустаревший член
#endregion
}
}
namespace DCFApixels.DragonECS.Core
{
#if ENABLE_IL2CPP
using Unity.IL2CPP.CompilerServices;
[Il2CppSetOption(Option.NullChecks, false)]
[Il2CppSetOption(Option.ArrayBoundsChecks, false)]
#endif
[DebuggerTypeProxy(typeof(EcsSpan.DebuggerProxy))]
public unsafe readonly struct EcsUnsafeSpan
{
private readonly int* _values;
private readonly int _length;
private readonly short _worldID;
#region Properties
public bool IsNull
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _worldID == 0; }
}
public short WorldID
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _worldID; }
}
public EcsWorld World
{
get { return EcsWorld.GetWorld(_worldID); }
}
public int Count
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _length; }
}
public EcsLongsSpan Longs
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return ToSpan().Longs; }
}
public bool IsSourceEntities
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return ToSpan().IsSourceEntities; }
}
public int this[int index]
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
#if DEBUG
if ((uint)index >= (uint)_length || (uint)index < 0)
{
ThrowHelper.ThrowIndexOutOfRangeException();
}
#elif DRAGONECS_STABILITY_MODE
return EcsConsts.NULL_ENTITY_ID;
#endif
return _values[index];
}
}
#endregion
#region Constructors
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal EcsUnsafeSpan(short worldID, int* array, int length)
{
_worldID = worldID;
_values = array;
_length = length;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal EcsUnsafeSpan(short worldID, int* array, int start, int length)
{
_worldID = worldID;
_values = array + start;
_length = length;
}
#endregion
#region Slice/ToArray
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public EcsUnsafeSpan Slice(int start)
{
if ((uint)start > (uint)_length)
{
ThrowHelper.ThrowArgumentOutOfRangeException();
}
return new EcsUnsafeSpan(_worldID, _values, start, _length - start);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public EcsUnsafeSpan Slice(int start, int length)
{
if ((uint)start > (uint)_length || (uint)length > (uint)(_length - start))
{
ThrowHelper.ThrowArgumentOutOfRangeException();
}
return new EcsUnsafeSpan(_worldID, _values, start, length);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public EcsSpan ToSpan() { return new EcsSpan(_worldID, new ReadOnlySpan<int>(_values, _length)); }
public int[] ToArray() { return new ReadOnlySpan<int>(_values, _length).ToArray(); }
public int ToArray(ref int[] dynamicBuffer)
{
if (dynamicBuffer.Length < _length)
{
Array.Resize(ref dynamicBuffer, ArrayUtility.CeilPow2(_length));
}
int i = 0;
foreach (var e in this)
{
dynamicBuffer[i++] = e;
}
return i;
}
public void ToCollection(ICollection<int> collection)
{
foreach (var e in this)
{
collection.Add(e);
}
}
#endregion
#region operators
public static bool operator ==(EcsUnsafeSpan left, EcsUnsafeSpan right) { return left._values == right._values && left._length == right._length && left._worldID == right._worldID; }
public static bool operator !=(EcsUnsafeSpan left, EcsUnsafeSpan right) { return left._values != right._values || left._length != right._length || left._worldID != right._worldID; }
public static implicit operator EcsSpan(EcsUnsafeSpan a) { return a.ToSpan(); }
#endregion
#region Enumerator
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ReadOnlySpan<int>.Enumerator GetEnumerator() { return new ReadOnlySpan<int>(_values, _length).GetEnumerator(); }
#endregion
#region Other
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int First() { return _values[0]; }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int Last() { return _values[_length - 1]; }
public override string ToString()
{
return CollectionUtility.EntitiesToString(ToArray(), "span");
}
public override bool Equals(object obj)
{
return obj is EcsUnsafeSpan other && other == this;
}
public override int GetHashCode()
{
return *_values ^ _length ^ (_worldID << 16);
}
private static class ThrowHelper
{
public static void ThrowIndexOutOfRangeException() => throw new IndexOutOfRangeException();
public static void ThrowArgumentOutOfRangeException() => throw new ArgumentOutOfRangeException();
public static void ThrowInvalidOperationException() => throw new InvalidOperationException();
}
#endregion
}
}

View File

@ -88,42 +88,6 @@ namespace DCFApixels.DragonECS
true;
#else
false;
#endif
public const bool ENABLE_DUMMY_SPAN =
#if ENABLE_DUMMY_SPAN
true;
#else
false;
#endif
[Obsolete("DRAGONECS_ENABLE_DEBUG_SERVICE")]
public const bool ENABLE_DRAGONECS_DEBUGGER =
#if ENABLE_DRAGONECS_DEBUGGER
true;
#else
false;
#endif
[Obsolete("DRAGONECS_DISABLE_POOLS_EVENTS")]
public const bool DISABLE_POOLS_EVENTS =
#if DISABLE_POOLS_EVENTS
true;
#else
false;
#endif
[Obsolete("DRAGONECS_DISABLE_CATH_EXCEPTIONS")]
public const bool DISABLE_CATH_EXCEPTIONS =
#if DISABLE_CATH_EXCEPTIONS
true;
#else
false;
#endif
[Obsolete("DRAGONECS_STABILITY_MODE")]
public const bool ENABLE_DRAGONECS_ASSERT_CHEKS =
#if ENABLE_DRAGONECS_ASSERT_CHEKS
true;
#else
false;
#endif
}
}

View File

@ -11,63 +11,84 @@ namespace DCFApixels.DragonECS.Core
void Init(ref T component, EcsWorld world);
void OnDestroy(ref T component, EcsWorld world);
}
public static class EcsWorldComponentHandler<T>
public static class EcsWorldComponent<T>
{
public static readonly IEcsWorldComponent<T> instance;
public static readonly bool isHasHandler;
static EcsWorldComponentHandler()
public static readonly IEcsWorldComponent<T> CustomHandler;
public static readonly bool IsCustom;
static EcsWorldComponent()
{
T def = default;
if (def is IEcsWorldComponent<T> intrf)
T raw = default;
if (raw is IEcsWorldComponent<T> handler)
{
isHasHandler = true;
instance = intrf;
IsCustom = true;
CustomHandler = handler;
}
else
{
isHasHandler = false;
instance = new DummyHandler();
IsCustom = false;
CustomHandler = new DummyHandler();
}
}
private class DummyHandler : IEcsWorldComponent<T>
private sealed class DummyHandler : IEcsWorldComponent<T>
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Init(ref T component, EcsWorld world) { }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void OnDestroy(ref T component, EcsWorld world) { }
}
}
#endregion
#region IEcsComponentReset
#region IEcsComponentLifecycle
public interface IEcsComponentLifecycle<T>
{
void Enable(ref T component);
void Disable(ref T component);
void OnAdd(ref T component, short worldID, int entityID);
void OnDel(ref T component, short worldID, int entityID);
}
public static class EcsComponentLifecycleHandler<T>
public static class EcsComponentLifecycle<T> where T : struct
{
public static readonly IEcsComponentLifecycle<T> instance;
public static readonly bool isHasHandler;
static EcsComponentLifecycleHandler()
public static readonly IEcsComponentLifecycle<T> CustomHandler;
public static readonly bool IsCustom;
static EcsComponentLifecycle()
{
T def = default;
if (def is IEcsComponentLifecycle<T> intrf)
T raw = default;
if (raw is IEcsComponentLifecycle<T> handler)
{
isHasHandler = true;
instance = intrf;
IsCustom = true;
CustomHandler = handler;
}
else
{
isHasHandler = false;
instance = new DummyHandler();
IsCustom = false;
CustomHandler = new DummyHandler();
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void OnAdd(bool isCustom, IEcsComponentLifecycle<T> custom, ref T component, short worldID, int entityID)
{
if (isCustom)
{
custom.OnAdd(ref component, worldID, entityID);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void OnDel(bool isCustom, IEcsComponentLifecycle<T> custom, ref T component, short worldID, int entityID)
{
if (isCustom)
{
custom.OnDel(ref component, worldID, entityID);
}
else
{
component = default;
}
}
private sealed class DummyHandler : IEcsComponentLifecycle<T>
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Enable(ref T component) { component = default; }
public void OnAdd(ref T component, short worldID, int entityID) { component = default; }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Disable(ref T component) { component = default; }
public void OnDel(ref T component, short worldID, int entityID) { component = default; }
}
}
#endregion
@ -77,22 +98,34 @@ namespace DCFApixels.DragonECS.Core
{
void Copy(ref T from, ref T to);
}
public static class EcsComponentCopyHandler<T>
public static class EcsComponentCopy<T> where T : struct
{
public static readonly IEcsComponentCopy<T> instance;
public static readonly bool isHasHandler;
static EcsComponentCopyHandler()
public static readonly IEcsComponentCopy<T> CustomHandler;
public static readonly bool IsCustom;
static EcsComponentCopy()
{
T def = default;
if (def is IEcsComponentCopy<T> intrf)
T raw = default;
if (raw is IEcsComponentCopy<T> handler)
{
isHasHandler = true;
instance = intrf;
IsCustom = true;
CustomHandler = handler;
}
else
{
isHasHandler = false;
instance = new DummyHandler();
IsCustom = false;
CustomHandler = new DummyHandler();
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Copy(bool isCustom, IEcsComponentCopy<T> custom, ref T from, ref T to)
{
if (isCustom)
{
custom.Copy(ref from, ref to);
}
else
{
to = from;
}
}
private sealed class DummyHandler : IEcsComponentCopy<T>
@ -102,4 +135,4 @@ namespace DCFApixels.DragonECS.Core
}
}
#endregion
}
}

View File

@ -285,7 +285,7 @@ namespace DCFApixels.DragonECS
public static TypeMeta GetTypeMeta(object obj)
{
if (obj == null) { return TypeMeta.NullTypeMeta; }
return TypeMeta.Get(GetTypeMetaSource(obj).GetType());
return TypeMeta.Get(Type.GetTypeHandle(GetTypeMetaSource(obj)));
}
public static TypeMeta GetTypeMeta<T>()
{
@ -295,6 +295,10 @@ namespace DCFApixels.DragonECS
{
return TypeMeta.Get(type);
}
public static TypeMeta GetTypeMeta(RuntimeTypeHandle typeHandle)
{
return TypeMeta.Get(typeHandle);
}
#endregion
#region TypeMetaProvider
@ -318,7 +322,11 @@ namespace DCFApixels.DragonECS
#endif
return EcsDebugUtility.GetTypeMeta(self);
}
public static TypeMeta ToMeta(this Type self)
public static TypeMeta GetMeta(this Type self)
{
return EcsDebugUtility.GetTypeMeta(self);
}
public static TypeMeta GetMeta(this RuntimeTypeHandle self)
{
return EcsDebugUtility.GetTypeMeta(self);
}

View File

@ -46,7 +46,7 @@ namespace DCFApixels.DragonECS
public static readonly TypeMeta NullTypeMeta;
private static readonly object _lock = new object();
private static readonly Dictionary<Type, TypeMeta> _metaCache = new Dictionary<Type, TypeMeta>();
private static readonly Dictionary<RuntimeTypeHandle, TypeMeta> _metaCache = new Dictionary<RuntimeTypeHandle, TypeMeta>();
private static int _increment = 1;
private readonly int _uniqueID;
@ -93,16 +93,17 @@ namespace DCFApixels.DragonECS
_initFlags = InitFlag.All,
};
_metaCache.Add(typeof(void), NullTypeMeta);
_metaCache.Add(typeof(void).TypeHandle, NullTypeMeta);
}
public static TypeMeta Get(Type type)
public static TypeMeta Get(Type type) { return Get(type.TypeHandle); }
public static TypeMeta Get(RuntimeTypeHandle typeHandle)
{
lock (_lock) //TODO посмотреть можно ли тут убрать лок
lock (_lock)
{
if (_metaCache.TryGetValue(type, out TypeMeta result) == false)
if (_metaCache.TryGetValue(typeHandle, out TypeMeta result) == false)
{
result = new TypeMeta(type);
_metaCache.Add(type, result);
result = new TypeMeta(Type.GetTypeFromHandle(typeHandle));
_metaCache.Add(typeHandle, result);
}
return result;
}
@ -375,7 +376,7 @@ namespace DCFApixels.DragonECS
lock (_lock)
{
_metaCache.Clear();
_metaCache.Add(typeof(void), NullTypeMeta);
_metaCache.Add(typeof(void).TypeHandle, NullTypeMeta);
}
}
ITypeMeta ITypeMeta.BaseMeta
@ -395,7 +396,7 @@ namespace DCFApixels.DragonECS
{
if (IsHasCustomMeta(type))
{
meta = type.ToMeta();
meta = type.GetMeta();
return true;
}
meta = null;
@ -469,15 +470,6 @@ namespace DCFApixels.DragonECS
}
#endregion
#region Obsolete
[Obsolete("Use TryGetCustomMeta(type)")]
[EditorBrowsable(EditorBrowsableState.Never)]
public static bool IsHasMeta(Type type)
{
return IsHasCustomMeta(type);
}
#endregion
#region MetaGenerator
private static class MetaGenerator
{

View File

@ -418,52 +418,6 @@ namespace DCFApixels.DragonECS
EcsMask IComponentMask.ToMask(EcsWorld world) { return _mask; }
#endregion
#region Obsolete
[Obsolete("Use EcsMask.GetIterator()")]
public Iterator GetIterator()
{
return new Iterator(Mask.GetIterator(), _source.Entities);
}
[Obsolete("Use EcsMask.GetIterator().Iterate(span)")]
public Iterator GetIteratorFor(EcsSpan span)
{
return new Iterator(Mask.GetIterator(), span);
}
[Obsolete("Use EcsMaskIterator")]
public ref struct Iterator
{
public readonly short worldID;
public readonly EcsMaskIterator.Enumerable iterator;
public Iterator(EcsMaskIterator iterator, EcsSpan span)
{
worldID = iterator.World.ID;
this.iterator = iterator.Iterate(span);
}
#region CopyTo
public void CopyTo(EcsGroup group)
{
iterator.CopyTo(group);
}
public int CopyTo(ref int[] array)
{
return iterator.CopyTo(ref array);
}
public EcsSpan CopyToSpan(ref int[] array)
{
int count = CopyTo(ref array);
return new EcsSpan(worldID, array, count);
}
#endregion
public EcsMaskIterator.Enumerable.Enumerator GetEnumerator()
{
return iterator.GetEnumerator();
}
}
#endregion
#region Events
public delegate void OnInitApectHandler(object aspect, Builder builder);
public static event OnInitApectHandler OnInit = delegate { };

View File

@ -5,7 +5,6 @@ using DCFApixels.DragonECS.Core;
using DCFApixels.DragonECS.Core.Internal;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
@ -34,6 +33,7 @@ namespace DCFApixels.DragonECS
{
public readonly int ID;
public readonly short WorldID;
public readonly EcsWorld World;
internal readonly EcsStaticMask _staticMask;
internal readonly EcsMaskChunck[] _incChunckMasks;
@ -51,11 +51,6 @@ namespace DCFApixels.DragonECS
private EcsMaskIterator _iterator;
#region Properties
public EcsWorld World
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return EcsWorld.GetWorld(WorldID); }
}
/// <summary> Sorted set excluding constraints. </summary>
public ReadOnlySpan<int> Incs
{
@ -74,6 +69,25 @@ namespace DCFApixels.DragonECS
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _anys; }
}
/// <summary> Sorted set including constraints presented as global type codes. </summary>
public ReadOnlySpan<EcsTypeCode> IncTypeCodes
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return ToStatic().IncTypeCodes; }
}
/// <summary> Sorted set excluding constraints presented as global type codes. </summary>
public ReadOnlySpan<EcsTypeCode> ExcTypeCodes
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return ToStatic().ExcTypeCodes; }
}
/// <summary> Sorted set any constraints presented as global type codes. </summary>
public ReadOnlySpan<EcsTypeCode> AnyTypeCodes
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return ToStatic().AnyTypeCodes; }
}
public EcsMaskFlags Flags
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@ -116,6 +130,7 @@ namespace DCFApixels.DragonECS
_staticMask = staticMask;
ID = id;
WorldID = worldID;
World = EcsWorld.GetWorld(worldID);
_flags = staticMask.Flags;
EcsWorld world = EcsWorld.GetWorld(worldID);
@ -345,8 +360,6 @@ namespace DCFApixels.DragonECS
internal EcsMask ConvertFromStatic(EcsStaticMask staticMask)
{
if (_staticMasks.TryGetValue(staticMask.ID, out EcsMask result) == false)
{
result = new EcsMask(staticMask, _staticMasks.Count, _world.ID);
@ -367,20 +380,42 @@ namespace DCFApixels.DragonECS
_world = world;
_builder = EcsStaticMask.New();
}
public Builder Inc() { return this; }
public Builder Exc() { return this; }
public Builder Any() { return this; }
public Builder Inc<T>() { _builder.Inc<T>(); return this; }
public Builder Exc<T>() { _builder.Exc<T>(); return this; }
public Builder Any<T>() { _builder.Any<T>(); 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(params Type[] types) { _builder.Inc(types); return this; }
public Builder Exc(params Type[] types) { _builder.Exc(types); return this; }
public Builder Any(params Type[] types) { _builder.Any(types); return this; }
public Builder Inc(ReadOnlySpan<Type> types) { _builder.Inc(types); return this; }
public Builder Exc(ReadOnlySpan<Type> types) { _builder.Exc(types); return this; }
public Builder Any(ReadOnlySpan<Type> types) { _builder.Any(types); return this; }
public Builder Inc(IEnumerable<Type> types) { _builder.Inc(types); return this; }
public Builder Exc(IEnumerable<Type> types) { _builder.Exc(types); return this; }
public Builder Any(IEnumerable<Type> types) { _builder.Any(types); 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 Inc(params EcsTypeCode[] typeCodes) { _builder.Inc(typeCodes); return this; }
public Builder Exc(params EcsTypeCode[] typeCodes) { _builder.Exc(typeCodes); return this; }
public Builder Any(params EcsTypeCode[] typeCodes) { _builder.Any(typeCodes); return this; }
public Builder Inc(ReadOnlySpan<EcsTypeCode> typeCodes) { _builder.Inc(typeCodes); return this; }
public Builder Exc(ReadOnlySpan<EcsTypeCode> typeCodes) { _builder.Exc(typeCodes); return this; }
public Builder Any(ReadOnlySpan<EcsTypeCode> typeCodes) { _builder.Any(typeCodes); return this; }
public Builder Inc(IEnumerable<EcsTypeCode> typeCodes) { _builder.Inc(typeCodes); return this; }
public Builder Exc(IEnumerable<EcsTypeCode> typeCodes) { _builder.Exc(typeCodes); return this; }
public Builder Any(IEnumerable<EcsTypeCode> typeCodes) { _builder.Any(typeCodes); return this; }
public Builder Combine(EcsMask mask) { _builder.Combine(mask._staticMask); return this; }
public Builder Except(EcsMask mask) { _builder.Except(mask._staticMask); return this; }
public EcsMask Build() { return _world.Get<WorldMaskComponent>().ConvertFromStatic(_builder.Build()); }
public static implicit operator EcsMask(Builder a) { return a.Build(); }
}
#endregion
@ -402,15 +437,18 @@ namespace DCFApixels.DragonECS
public readonly int ID;
public readonly EcsWorld world;
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 readonly EcsMaskChunck[] incsChunkMasks;
public readonly EcsMaskChunck[] excsChunkMasks;
public readonly EcsMaskChunck[] anysChunkMasks;
public readonly int[] incs;
public readonly int[] excs;
public readonly int[] anys;
public readonly Type[] incsTypes;
public readonly Type[] excsTypes;
public readonly Type[] anysTypes;
public readonly IEcsPool[] incsPools;
public readonly IEcsPool[] excsPools;
public readonly IEcsPool[] anysPools;
public bool IsEmpty { get { return _source.IsEmpty; } }
public bool IsBroken { get { return _source.IsBroken; } }
@ -422,51 +460,27 @@ namespace DCFApixels.DragonECS
ID = mask.ID;
world = EcsWorld.GetWorld(mask.WorldID);
_worldID = mask.WorldID;
includedChunkMasks = mask._incChunckMasks;
excludedChunkMasks = mask._excChunckMasks;
anyChunkMasks = mask._anyChunckMasks;
included = mask._incs;
excluded = mask._excs;
any = mask._anys;
incsChunkMasks = mask._incChunckMasks;
excsChunkMasks = mask._excChunckMasks;
anysChunkMasks = mask._anyChunckMasks;
incs = mask._incs;
excs = mask._excs;
anys = 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();
IEcsPool converterPool(int o) { return world.FindPoolInstance(o); }
incsTypes = incs.Select(converter).ToArray();
excsTypes = excs.Select(converter).ToArray();
anysTypes = anys.Select(converter).ToArray();
incsPools = incs.Select(converterPool).ToArray();
excsPools = excs.Select(converterPool).ToArray();
anysPools = anys.Select(converterPool).ToArray();
}
public override string ToString()
{
return CreateLogString(_worldID, included, excluded, any);
return CreateLogString(_worldID, incs, excs, anys);
}
}
#endregion
#region Obsolete
/// <summary> Sorted set including constraints. </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("Use Incs")]
public ReadOnlySpan<int> Inc
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _incs; }
}
/// <summary> Sorted set excluding constraints. </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("Use Excs")]
public ReadOnlySpan<int> Exc
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _excs; }
}
public partial struct Builder
{
[EditorBrowsable(EditorBrowsableState.Never)][Obsolete] public Builder Include<T>() { return Inc<T>(); }
[EditorBrowsable(EditorBrowsableState.Never)][Obsolete] public Builder Exclude<T>() { return Exc<T>(); }
[EditorBrowsable(EditorBrowsableState.Never)][Obsolete] public Builder Include(Type type) { return Inc(type); }
[EditorBrowsable(EditorBrowsableState.Never)][Obsolete] public Builder Exclude(Type type) { return Exc(type); }
[EditorBrowsable(EditorBrowsableState.Never)][Obsolete] public Builder Inc(int componentTypeID) { Inc(_world.GetComponentType(componentTypeID)); return this; }
[EditorBrowsable(EditorBrowsableState.Never)][Obsolete] public Builder Exc(int componentTypeID) { Exc(_world.GetComponentType(componentTypeID)); return this; }
}
#endregion
}
[Flags]
@ -607,8 +621,8 @@ namespace DCFApixels.DragonECS
}
private void Cleanup(bool disposing)
{
_bufferHandler.Dispose();
_chunckBufferHandler.Dispose();
_bufferHandler.DisposeAndReset();
_chunckBufferHandler.DisposeAndReset();
}
#endregion
@ -636,8 +650,7 @@ namespace DCFApixels.DragonECS
if (_sortIncChunckBuffer.Length > 1)
{
var comparer = new IncCountComparer(counts);
UnsafeArraySortHalperX<int>.InsertionSort(sortIncBuffer.ptr, sortIncBuffer.Length, ref comparer);
SortHalper.Sort(sortIncBuffer.AsSpan(), new IncCountComparer(counts));
ConvertToChuncks(preSortingBuffer, sortIncBuffer, _sortIncChunckBuffer);
}
if (_sortIncChunckBuffer.Length > 0)
@ -651,8 +664,7 @@ namespace DCFApixels.DragonECS
if (_sortExcChunckBuffer.Length > 1)
{
ExcCountComparer comparer = new ExcCountComparer(counts);
UnsafeArraySortHalperX<int>.InsertionSort(sortExcBuffer.ptr, sortExcBuffer.Length, ref comparer);
SortHalper.Sort(sortExcBuffer.AsSpan(), new ExcCountComparer(counts));
ConvertToChuncks(preSortingBuffer, sortExcBuffer, _sortExcChunckBuffer);
}
// Выражение IncCount < (AllEntitesCount - ExcCount) мало вероятно будет истинным.
@ -662,8 +674,7 @@ namespace DCFApixels.DragonECS
if (_sortAnyChunckBuffer.Length > 1)
{
ExcCountComparer comparer = new ExcCountComparer(counts);
UnsafeArraySortHalperX<int>.InsertionSort(sortAnyBuffer.ptr, sortAnyBuffer.Length, ref comparer);
SortHalper.Sort(sortAnyBuffer.AsSpan(), new ExcCountComparer(counts));
ConvertToChuncks(preSortingBuffer, sortAnyBuffer, _sortAnyChunckBuffer);
}
// Any не влияет на maxEntites если есть Inc и сложно высчитывается если нет Inc
@ -691,9 +702,13 @@ namespace DCFApixels.DragonECS
#endregion
#region IterateTo
//TODO Перемеиноваться в CacheTo
public EcsMaskFlags MaskFlags
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _maskFlags; }
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void IterateTo(EcsSpan source, EcsGroup group)
public void CacheTo(EcsSpan source, EcsGroup group)
{
switch (_maskFlags)
{
@ -701,7 +716,7 @@ namespace DCFApixels.DragonECS
group.CopyFrom(source);
break;
case EcsMaskFlags.Inc:
IterateOnlyInc(source).CopyTo(group);
IterateOnlyInc(source).CacheTo(group);
break;
case EcsMaskFlags.Exc:
case EcsMaskFlags.Any:
@ -709,7 +724,7 @@ namespace DCFApixels.DragonECS
case EcsMaskFlags.IncAny:
case EcsMaskFlags.ExcAny:
case EcsMaskFlags.IncExcAny:
Iterate(source).CopyTo(group);
Iterate(source).CacheTo(group);
break;
case EcsMaskFlags.Broken:
group.Clear();
@ -720,21 +735,21 @@ namespace DCFApixels.DragonECS
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int IterateTo(EcsSpan source, ref int[] array)
public int CacheTo(EcsSpan source, ref int[] array)
{
switch (_maskFlags)
{
case EcsMaskFlags.Empty:
return source.ToArray(ref array);
case EcsMaskFlags.Inc:
return IterateOnlyInc(source).CopyTo(ref array);
return IterateOnlyInc(source).CacheTo(ref array);
case EcsMaskFlags.Exc:
case EcsMaskFlags.Any:
case EcsMaskFlags.IncExc:
case EcsMaskFlags.IncAny:
case EcsMaskFlags.ExcAny:
case EcsMaskFlags.IncExcAny:
return Iterate(source).CopyTo(ref array);
return Iterate(source).CacheTo(ref array);
case EcsMaskFlags.Broken:
return new EcsSpan(World.ID, Array.Empty<int>()).ToArray(ref array);
default:
@ -764,7 +779,7 @@ namespace DCFApixels.DragonECS
#region CopyTo
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void CopyTo(EcsGroup group)
public void CacheTo(EcsGroup group)
{
group.Clear();
var enumerator = GetEnumerator();
@ -774,7 +789,7 @@ namespace DCFApixels.DragonECS
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int CopyTo(ref int[] array)
public int CacheTo(ref int[] array)
{
int count = 0;
var enumerator = GetEnumerator();
@ -920,7 +935,7 @@ namespace DCFApixels.DragonECS
#region CopyTo
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void CopyTo(EcsGroup group)
public void CacheTo(EcsGroup group)
{
group.Clear();
var enumerator = GetEnumerator();
@ -930,7 +945,7 @@ namespace DCFApixels.DragonECS
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int CopyTo(ref int[] array)
public int CacheTo(ref int[] array)
{
int count = 0;
var enumerator = GetEnumerator();
@ -1077,7 +1092,7 @@ namespace DCFApixels.DragonECS.Core.Internal
[Il2CppSetOption(Option.NullChecks, false)]
[Il2CppSetOption(Option.ArrayBoundsChecks, false)]
#endif
internal readonly struct IncCountComparer : IStructComparer<int>
internal readonly struct IncCountComparer : IComparer<int>
{
public readonly EcsWorld.PoolSlot[] counts;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@ -1096,7 +1111,7 @@ namespace DCFApixels.DragonECS.Core.Internal
[Il2CppSetOption(Option.NullChecks, false)]
[Il2CppSetOption(Option.ArrayBoundsChecks, false)]
#endif
internal readonly struct ExcCountComparer : IStructComparer<int>
internal readonly struct ExcCountComparer : IComparer<int>
{
public readonly EcsWorld.PoolSlot[] counts;
[MethodImpl(MethodImplOptions.AggressiveInlining)]

View File

@ -122,7 +122,6 @@ namespace DCFApixels.DragonECS
}
private void InsertAfterNode_Internal(int insertAfterIndex, IEcsProcess system, string layer, int sortOrder, bool isUnique)
{
//TODO нужно потестить
if (isUnique && _uniqueSystemsSet.Add(system.GetType()) == false)
{
//EcsDebug.PrintWarning($"The pipeline already contains a unique instance of {system.GetType().Name}");
@ -600,20 +599,6 @@ namespace DCFApixels.DragonECS
}
}
#endregion
#region Obsolete
[Obsolete("Use " + nameof(Injections))]
public readonly InitInjectionList Injector;
[Obsolete("Use LayersMap")]
public class LayerList : LayersMap
{
//public LayerList(Builder source, string basicLayerName) : base(source, basicLayerName) { }
//public LayerList(Builder source, string preBeginlayer, string beginlayer, string basicLayer, string endLayer, string postEndLayer) : base(source, preBeginlayer, beginlayer, basicLayer, endLayer, postEndLayer) { }
public LayerList(IDependencyGraph<string> graph, Builder pipelineBuilder) : base(graph, pipelineBuilder)
{
}
}
#endregion
}
}

View File

@ -148,7 +148,7 @@ namespace DCFApixels.DragonECS
#region Constructors
public RunHelper(EcsRunner<TProcess> runner) : this(runner,
#if DEBUG
typeof(TProcess).ToMeta().Name)
typeof(TProcess).GetMeta().Name)
#else
string.Empty)
#endif
@ -298,7 +298,7 @@ namespace DCFApixels.DragonECS
#region Constructors
public RunHelperWithFinally(EcsRunner<TProcess> runner) : this(runner,
#if DEBUG
typeof(TProcess).ToMeta().Name)
typeof(TProcess).GetMeta().Name)
#else
string.Empty)
#endif

View File

@ -65,7 +65,7 @@ namespace DCFApixels.DragonECS
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return _excs; }
}
/// <summary> Sorted set excluding constraints presented as global type codes. </summary>
/// <summary> Sorted set any constraints presented as global type codes. </summary>
public ReadOnlySpan<EcsTypeCode> AnyTypeCodes
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@ -109,9 +109,15 @@ namespace DCFApixels.DragonECS
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(params Type[] types) { return Builder.New().Inc(types); }
public static Builder Exc(params Type[] types) { return Builder.New().Exc(types); }
public static Builder Any(params Type[] types) { return Builder.New().Any(types); }
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); }
public static Builder Inc(params EcsTypeCode[] typeCodes) { return Builder.New().Inc(typeCodes); }
public static Builder Exc(params EcsTypeCode[] typeCodes) { return Builder.New().Exc(typeCodes); }
public static Builder Any(params EcsTypeCode[] typeCodes) { return Builder.New().Any(typeCodes); }
private static EcsStaticMask CreateMask(Key key)
{
if (_ids.TryGetValue(key, out EcsStaticMask result) == false)
@ -305,12 +311,24 @@ namespace DCFApixels.DragonECS
#endregion
#region Inc/Exc/Combine/Except
public Builder Inc() { return this; }
public Builder Exc() { return this; }
public Builder Any() { return this; }
public Builder Inc<T>() { return Inc(EcsTypeCodeManager.Get<T>()); }
public Builder Exc<T>() { return Exc(EcsTypeCodeManager.Get<T>()); }
public Builder Any<T>() { return Any(EcsTypeCodeManager.Get<T>()); }
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(params Type[] types) { foreach (var type in types) { Inc(type); } return this; }
public Builder Exc(params Type[] types) { foreach (var type in types) { Exc(type); } return this; }
public Builder Any(params Type[] types) { foreach (var type in types) { Any(type); } return this; }
public Builder Inc(ReadOnlySpan<Type> types) { foreach (var type in types) { Inc(type); } return this; }
public Builder Exc(ReadOnlySpan<Type> types) { foreach (var type in types) { Exc(type); } return this; }
public Builder Any(ReadOnlySpan<Type> types) { foreach (var type in types) { Any(type); } return this; }
public Builder Inc(IEnumerable<Type> types) { foreach (var type in types) { Inc(type); } return this; }
public Builder Exc(IEnumerable<Type> types) { foreach (var type in types) { Exc(type); } return this; }
public Builder Any(IEnumerable<Type> types) { foreach (var type in types) { Any(type); } return this; }
public Builder Inc(EcsTypeCode typeCode)
{
if (_version != _builder._version) { Throw.CantReuseBuilder(); }
@ -329,6 +347,15 @@ namespace DCFApixels.DragonECS
_builder.Any(typeCode);
return this;
}
public Builder Inc(params EcsTypeCode[] typeCodes) { foreach (var typeCode in typeCodes) { Inc(typeCode); } return this; }
public Builder Exc(params EcsTypeCode[] typeCodes) { foreach (var typeCode in typeCodes) { Exc(typeCode); } return this; }
public Builder Any(params EcsTypeCode[] typeCodes) { foreach (var typeCode in typeCodes) { Any(typeCode); } return this; }
public Builder Inc(ReadOnlySpan<EcsTypeCode> typeCodes) { foreach (var typeCode in typeCodes) { Inc(typeCode); } return this; }
public Builder Exc(ReadOnlySpan<EcsTypeCode> typeCodes) { foreach (var typeCode in typeCodes) { Exc(typeCode); } return this; }
public Builder Any(ReadOnlySpan<EcsTypeCode> typeCodes) { foreach (var typeCode in typeCodes) { Any(typeCode); } return this; }
public Builder Inc(IEnumerable<EcsTypeCode> typeCodes) { foreach (var typeCode in typeCodes) { Inc(typeCode); } return this; }
public Builder Exc(IEnumerable<EcsTypeCode> typeCodes) { foreach (var typeCode in typeCodes) { Exc(typeCode); } return this; }
public Builder Any(IEnumerable<EcsTypeCode> typeCodes) { foreach (var typeCode in typeCodes) { Any(typeCode); } return this; }
public Builder Combine(EcsStaticMask mask)
{
if (_version != _builder._version) { Throw.CantReuseBuilder(); }
@ -354,6 +381,7 @@ namespace DCFApixels.DragonECS
return result;
}
}
public static implicit operator EcsStaticMask(Builder a) { return a.Build(); }
public void Cancel()
{
if (_version != _builder._version) { Throw.CantReuseBuilder(); }

View File

@ -71,6 +71,7 @@ namespace DCFApixels.DragonECS
private int[] _delEntBuffer = Array.Empty<int>();
private int _delEntBufferCount = 0;
private int[] _emptyEntities = Array.Empty<int>();
private int _emptyEntitiesLength = 0;
private int _emptyEntitiesCount = 0;
private bool _isEnableAutoReleaseDelEntBuffer = true;
@ -441,20 +442,37 @@ namespace DCFApixels.DragonECS
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void MoveToEmptyEntities(int entityID)
{
_emptyEntities[_emptyEntitiesCount++] = entityID;
_emptyEntities[_emptyEntitiesLength++] = entityID;
_emptyEntitiesCount++;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private bool RemoveFromEmptyEntities(int entityID)
private void RemoveFromEmptyEntities(int entityID)
{
for (int i = _emptyEntitiesCount - 1; i >= 0; i--)
const int THRESHOLD = 16;
_emptyEntitiesCount--;
if (_emptyEntitiesLength < THRESHOLD)
{
if (_emptyEntities[i] == entityID)
for (int i = _emptyEntitiesLength - 1; i >= 0; i--)
{
_emptyEntities[i] = _emptyEntities[--_emptyEntitiesCount];
return true;
if (_emptyEntities[i] == entityID)
{
_emptyEntities[i] = _emptyEntities[--_emptyEntitiesLength];
}
}
}
return false;
#if DRAGONECS_DEEP_DEBUG
if (_emptyEntitiesCount < 0)
{
Throw.DeepDebugException();
}
#endif
if (_emptyEntitiesCount == 0)
{
_emptyEntitiesCount = 0;
_emptyEntitiesLength = 0;
}
}
#endregion
@ -698,7 +716,7 @@ namespace DCFApixels.DragonECS
}
else
{
poolIdsPtr = UnmanagedArrayUtility.New<int>(count);
poolIdsPtr = MemoryAllocator.Alloc<int>(count).Ptr;
}
UnsafeArray<int> ua = UnsafeArray<int>.Manual(poolIdsPtr, count);
@ -711,7 +729,7 @@ namespace DCFApixels.DragonECS
if (count >= BUFFER_THRESHOLD)
{
UnmanagedArrayUtility.Free(poolIdsPtr);
MemoryAllocator.Free(poolIdsPtr);
}
@ -748,7 +766,7 @@ namespace DCFApixels.DragonECS
}
else
{
poolIdsPtr = UnmanagedArrayUtility.New<int>(count);
poolIdsPtr = MemoryAllocator.Alloc<int>(count).Ptr;
}
GetComponentTypeIDsFor_Internal(fromEntityID, poolIdsPtr, count);
@ -759,7 +777,7 @@ namespace DCFApixels.DragonECS
if (count >= BUFFER_THRESHOLD)
{
UnmanagedArrayUtility.Free(poolIdsPtr);
MemoryAllocator.Free(poolIdsPtr);
}
//foreach (var pool in _pools)
@ -890,16 +908,21 @@ namespace DCFApixels.DragonECS
{
ReleaseDelEntityBuffer(-1);
}
public unsafe void ReleaseDelEntityBuffer(int count)
public void ReleaseDelEntityBuffer(int count)
{
if (_emptyEntitiesCount <= 0 && _delEntBufferCount <= 0) { return; }
if (_emptyEntitiesLength <= 0 && _delEntBufferCount <= 0) { return; }
unchecked { _version++; }
for (int i = 0; i < _emptyEntitiesCount; i++)
for (int i = 0; i < _emptyEntitiesLength; i++)
{
TryDelEntity(_emptyEntities[i]);
var entityID = _emptyEntities[i];
if (IsUsed(entityID) && _entities[entityID].componentsCount == 0)
{
DelEntity(entityID);
}
}
_emptyEntitiesCount = 0;
_emptyEntitiesLength = 0;
if (count < 0)
{
@ -1082,7 +1105,7 @@ namespace DCFApixels.DragonECS
}
else
{
poolIdsPtr = UnmanagedArrayUtility.New<int>(count);
poolIdsPtr = MemoryAllocator.Alloc<int>(count).Ptr;
}
GetComponentTypeIDsFor_Internal(entityID, poolIdsPtr, count);
@ -1105,7 +1128,7 @@ namespace DCFApixels.DragonECS
if (count >= BUFFER_THRESHOLD)
{
UnmanagedArrayUtility.Free(poolIdsPtr);
MemoryAllocator.Free(poolIdsPtr);
}
}
public ReadOnlySpan<object> GetComponentsFor(int entityID)

View File

@ -127,7 +127,6 @@ namespace DCFApixels.DragonECS
{
return _cmpTypeCode_2_CmpTypeIDs.Contains((int)EcsTypeCodeManager.Get(componentType));
}
//TODO пересмотреть нейминг или функцию
public bool IsComponentTypeDeclared(int componentTypeID)
{
if (componentTypeID >= 0 && componentTypeID < _pools.Length)

View File

@ -5,7 +5,6 @@ using DCFApixels.DragonECS.Core;
using DCFApixels.DragonECS.Core.Internal;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
@ -26,12 +25,15 @@ namespace DCFApixels.DragonECS
private static EcsWorld[] _worlds = Array.Empty<EcsWorld>();
private static readonly IdDispenser _worldIdDispenser = new IdDispenser(4, 0, n => Array.Resize(ref _worlds, n));
private static StructList<WorldComponentPoolAbstract> _allWorldComponentPools = new StructList<WorldComponentPoolAbstract>(64);
private static readonly object _worldLock = new object();
private StructList<WorldComponentPoolAbstract> _worldComponentPools;
private int _builtinWorldComponentsCount = 0;
public static int AllWorldsCount
{
get { return _worldIdDispenser.Count; }
}
static EcsWorld()
{
_worlds[NULL_WORLD_ID] = new NullWorld();
@ -145,7 +147,7 @@ namespace DCFApixels.DragonECS
private static short _count;
private static short[] _recycledItems = new short[4];
private static short _recycledItemsCount;
private static readonly IEcsWorldComponent<T> _interface = EcsWorldComponentHandler<T>.instance;
private static readonly IEcsWorldComponent<T> _interface = EcsWorldComponent<T>.CustomHandler;
private static readonly Abstract _controller = new Abstract();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@ -321,27 +323,5 @@ namespace DCFApixels.DragonECS
}
}
#endregion
#region Obsolete
[EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("Use EcsWorld.ID")]
public short id
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return ID; }
}
[EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("The GetPoolInstance(int componentTypeID) method will be removed in future updates, use FindPoolInstance(Type componentType)")]
public IEcsPool GetPoolInstance(int componentTypeID)
{
return FindPoolInstance(componentTypeID);
}
[EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("The GetPoolInstance(Type componentType) method will be removed in future updates, use FindPoolInstance(Type componentType)")]
public IEcsPool GetPoolInstance(Type componentType)
{
return FindPoolInstance(componentType);
}
#endregion
}
}

View File

@ -3,6 +3,7 @@
#endif
using System;
using System.Runtime.CompilerServices;
using static DCFApixels.DragonECS.Core.Internal.MemoryAllocator;
#if ENABLE_IL2CPP
using Unity.IL2CPP.CompilerServices;
#endif
@ -13,13 +14,13 @@ namespace DCFApixels.DragonECS.Core.Internal
[Il2CppSetOption(Option.NullChecks, false)]
[Il2CppSetOption(Option.ArrayBoundsChecks, false)]
#endif
internal sealed class EcsWhereExecutor : MaskQueryExecutor
internal sealed unsafe class EcsWhereExecutor : MaskQueryExecutor
{
private EcsMaskIterator _iterator;
private int[] _filteredAllEntities = new int[32];
private HMem<int> _filteredAllEntities = Alloc<int>(32);
private int _filteredAllEntitiesCount = 0;
private int[] _filteredEntities = null;
private HMem<int> _filteredEntities = default;
private int _filteredEntitiesCount = 0;
private long _version;
@ -54,6 +55,14 @@ namespace DCFApixels.DragonECS.Core.Internal
protected sealed override void OnDestroy()
{
if (_isDestroyed) { return; }
if (_filteredAllEntities.IsCreated)
{
_filteredAllEntities.DisposeAndReset();
}
if (_filteredEntities.IsCreated)
{
_filteredEntities.DisposeAndReset();
}
_isDestroyed = true;
_versionsChecker.Dispose();
}
@ -67,7 +76,7 @@ namespace DCFApixels.DragonECS.Core.Internal
if (_versionsChecker.CheckAndNext() == false)
{
_version++;
_filteredAllEntitiesCount = _iterator.IterateTo(World.Entities, ref _filteredAllEntities);
_filteredAllEntitiesCount = _iterator.CacheTo(World.Entities, ref _filteredAllEntities);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@ -77,19 +86,19 @@ namespace DCFApixels.DragonECS.Core.Internal
if (span.IsNull) { Throw.ArgumentNull(nameof(span)); }
if (span.WorldID != World.ID) { Throw.Quiery_ArgumentDifferentWorldsException(); }
#endif
if (_filteredEntities == null)
if (_filteredEntities.IsCreated == false)
{
_filteredEntities = new int[32];
_filteredEntities = Alloc<int>(32);
}
_filteredEntitiesCount = _iterator.IterateTo(span, ref _filteredEntities);
_filteredEntitiesCount = _iterator.CacheTo(span, ref _filteredEntities);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public EcsSpan Execute()
public EcsUnsafeSpan Execute()
{
Execute_Iternal();
#if DEBUG && DRAGONECS_DEEP_DEBUG
var newSpan = new EcsSpan(World.ID, _filteredAllEntities, _filteredAllEntitiesCount);
var result = new EcsUnsafeSpan(World.ID, _filteredAllEntities.Ptr, _filteredAllEntitiesCount);
using (EcsGroup group = EcsGroup.New(World))
{
foreach (var e in World.Entities)
@ -100,20 +109,20 @@ namespace DCFApixels.DragonECS.Core.Internal
}
}
if (group.SetEquals(newSpan) == false)
if (group.SetEquals(result.ToSpan()) == false)
{
int[] array = new int[_filteredAllEntities.Length];
var count = _iterator.IterateTo(World.Entities, ref array);
var count = _iterator.CacheTo(World.Entities, ref array);
EcsDebug.PrintError(newSpan.ToString() + "\r\n" + group.ToSpan().ToString());
EcsDebug.PrintError(result.ToString() + "\r\n" + group.ToSpan().ToString());
Throw.DeepDebugException();
}
}
#endif
return new EcsSpan(World.ID, _filteredAllEntities, _filteredAllEntitiesCount);
return new EcsUnsafeSpan(World.ID, _filteredAllEntities.Ptr, _filteredAllEntitiesCount); ;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public EcsSpan ExecuteFor(EcsSpan span)
public EcsUnsafeSpan ExecuteFor(EcsSpan span)
{
if (span.IsSourceEntities)
{
@ -121,8 +130,8 @@ namespace DCFApixels.DragonECS.Core.Internal
}
ExecuteFor_Iternal(span);
#if DEBUG && DRAGONECS_DEEP_DEBUG
var newSpan = new EcsSpan(World.ID, _filteredEntities, _filteredEntitiesCount);
foreach (var e in newSpan)
var result = new EcsUnsafeSpan(World.ID, _filteredEntities.Ptr, _filteredEntitiesCount);
foreach (var e in result)
{
if (World.IsMatchesMask(Mask, e) == false)
{
@ -130,26 +139,26 @@ namespace DCFApixels.DragonECS.Core.Internal
}
}
#endif
return new EcsSpan(World.ID, _filteredEntities, _filteredEntitiesCount);
return new EcsUnsafeSpan(World.ID, _filteredEntities.Ptr, _filteredEntitiesCount); ;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public EcsSpan Execute(Comparison<int> comparison)
public EcsUnsafeSpan Execute(Comparison<int> comparison)
{
Execute_Iternal();
ArraySortHalperX<int>.Sort(_filteredAllEntities, comparison, _filteredAllEntitiesCount);
return new EcsSpan(World.ID, _filteredAllEntities, _filteredAllEntitiesCount);
SortHalper.Sort(_filteredAllEntities.AsSpan(_filteredAllEntitiesCount), comparison);
return new EcsUnsafeSpan(World.ID, _filteredAllEntities.Ptr, _filteredAllEntitiesCount);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public EcsSpan ExecuteFor(EcsSpan span, Comparison<int> comparison)
public EcsUnsafeSpan ExecuteFor(EcsSpan source, Comparison<int> comparison)
{
if (span.IsSourceEntities)
if (source.IsSourceEntities)
{
return Execute(comparison);
}
ExecuteFor_Iternal(span);
ArraySortHalperX<int>.Sort(_filteredEntities, comparison, _filteredEntitiesCount);
return new EcsSpan(World.ID, _filteredEntities, _filteredEntitiesCount);
ExecuteFor_Iternal(source);
SortHalper.Sort(_filteredEntities.AsSpan(_filteredEntitiesCount), comparison);
return new EcsUnsafeSpan(World.ID, _filteredEntities.Ptr, _filteredEntitiesCount);
}
#endregion
}

View File

@ -66,7 +66,7 @@ namespace DCFApixels.DragonECS.Core.Internal
if (_versionsChecker.CheckAndNext() == false)
{
_version++;
_iterator.IterateTo(World.Entities, _filteredAllGroup);
_iterator.CacheTo(World.Entities, _filteredAllGroup);
#if DEBUG && DRAGONECS_DEEP_DEBUG
if (_filteredGroup == null)
{
@ -98,7 +98,7 @@ namespace DCFApixels.DragonECS.Core.Internal
{
_filteredGroup = EcsGroup.New(World);
}
_iterator.IterateTo(span, _filteredGroup);
_iterator.CacheTo(span, _filteredGroup);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]

View File

@ -84,6 +84,76 @@ namespace DCFApixels.DragonECS
}
#endregion
#region WhereUnsafe
public static EcsUnsafeSpan WhereUnsafe<TCollection, TAspect>(this TCollection entities, out TAspect aspect)
where TAspect : new()
where TCollection : IEntityStorage
{
return entities.ToSpan().WhereUnsafe(out aspect);
}
public static EcsUnsafeSpan WhereUnsafe<TAspect>(this EcsReadonlyGroup group, out TAspect aspect)
where TAspect : new()
{
return group.ToSpan().WhereUnsafe(out aspect);
}
public static EcsUnsafeSpan WhereUnsafe<TAspect>(this EcsSpan span, out TAspect aspect)
where TAspect : new()
{
span.World.GetQueryCache(out EcsWhereExecutor executor, out aspect);
return executor.ExecuteFor(span);
}
public static EcsUnsafeSpan WhereUnsafe<TCollection>(this TCollection entities, IComponentMask mask)
where TCollection : IEntityStorage
{
return entities.ToSpan().WhereUnsafe(mask);
}
public static EcsUnsafeSpan WhereUnsafe(this EcsReadonlyGroup group, IComponentMask mask)
{
return group.ToSpan().WhereUnsafe(mask);
}
public static EcsUnsafeSpan WhereUnsafe(this EcsSpan span, IComponentMask mask)
{
var executor = span.World.GetExecutorForMask<EcsWhereExecutor>(mask);
return executor.ExecuteFor(span);
}
#endregion
#region WhereUnsafe with sort
public static EcsUnsafeSpan WhereUnsafe<TCollection, TAspect>(this TCollection entities, out TAspect aspect, Comparison<int> comparison)
where TAspect : new()
where TCollection : IEntityStorage
{
return entities.ToSpan().WhereUnsafe(out aspect, comparison);
}
public static EcsUnsafeSpan WhereUnsafe<TAspect>(this EcsReadonlyGroup group, out TAspect aspect, Comparison<int> comparison)
where TAspect : new()
{
return group.ToSpan().WhereUnsafe(out aspect, comparison);
}
public static EcsUnsafeSpan WhereUnsafe<TAspect>(this EcsSpan span, out TAspect aspect, Comparison<int> comparison)
where TAspect : new()
{
span.World.GetQueryCache(out EcsWhereExecutor executor, out aspect);
return executor.ExecuteFor(span, comparison);
}
public static EcsUnsafeSpan WhereUnsafe<TCollection>(this TCollection entities, IComponentMask mask, Comparison<int> comparison)
where TCollection : IEntityStorage
{
return entities.ToSpan().WhereUnsafe(mask, comparison);
}
public static EcsUnsafeSpan WhereUnsafe(this EcsReadonlyGroup group, IComponentMask mask, Comparison<int> comparison)
{
return group.ToSpan().WhereUnsafe(mask, comparison);
}
public static EcsUnsafeSpan WhereUnsafe(this EcsSpan span, IComponentMask mask, Comparison<int> comparison)
{
var executor = span.World.GetExecutorForMask<EcsWhereExecutor>(mask);
return executor.ExecuteFor(span);
}
#endregion
#region WhereToGroup
public static EcsReadonlyGroup WhereToGroup<TCollection, TAspect>(this TCollection entities, out TAspect aspect)
where TAspect : new()

View File

@ -126,7 +126,7 @@ namespace DCFApixels.DragonECS
{
return (T)Extract_Internal(typeof(T));
}
private object Extract_Internal(Type type)//TODO проверить
private object Extract_Internal(Type type)
{
if (_nodes.TryGetValue(type, out InjectionNodeBase node))
{
@ -192,7 +192,7 @@ namespace DCFApixels.DragonECS
FindMonoWorld(obj);
_injections.Add(new Injection<T>(obj));
}
public void Extract<T>(ref T obj) // TODO проверить
public void Extract<T>(ref T obj)
{
Type type = typeof(T);
for (int i = _injections.Count - 1; i >= 0; i--)
@ -272,7 +272,7 @@ namespace DCFApixels.DragonECS
}
public void InjectTo(Injector injector, EcsPipeline pipeline)
{
var monoWorldProcess = pipeline.GetProcess<IMonoWorldInject>(); // TODO Проверить IMonoWorldInject
var monoWorldProcess = pipeline.GetProcess<IMonoWorldInject>();
foreach (var monoWorldSystem in monoWorldProcess)
{
monoWorldSystem.World = _monoWorld;

View File

@ -1,25 +1,89 @@
using System;
using System.Runtime.CompilerServices;
using static DCFApixels.DragonECS.Core.Internal.MemoryAllocator;
namespace DCFApixels.DragonECS.Core.Internal
{
internal static class AllocatorUtility
internal static unsafe class AllocatorUtility
{
public static unsafe void ClearAllocatedMemory(IntPtr ptr, int startByte, int lengthInBytes)
public static void ClearAllocatedMemory(IntPtr ptr, int startByte, int lengthInBytes)
{
ClearAllocatedMemory((byte*)ptr, startByte, lengthInBytes);
}
public static unsafe void ClearAllocatedMemory(byte* ptr, int startByte, int lengthInBytes)
public static void ClearAllocatedMemory(byte* ptr, int startByte, int lengthInBytes)
{
#if ENABLE_DUMMY_SPAN
lengthInBytes += startByte;
for (int i = startByte; i < lengthInBytes; i++)
{
ptr[i] = 0;
}
#else
Span<byte> memorySpan = new Span<byte>(ptr + startByte, lengthInBytes);
memorySpan.Clear();
#endif
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int CacheTo(this EcsMaskIterator it, EcsSpan source, ref HMem<int> array)
{
switch (it.MaskFlags)
{
case EcsMaskFlags.Empty:
{
if(array.Length < source.Count)
{
array = Realloc<int>(array, source.Count);
}
source.AsSystemSpan().CopyTo(array.AsSpan());
return source.Count;
}
case EcsMaskFlags.Inc:
{
return it.IterateOnlyInc(source).CacheTo(ref array);
}
case EcsMaskFlags.Exc:
case EcsMaskFlags.Any:
case EcsMaskFlags.IncExc:
case EcsMaskFlags.IncAny:
case EcsMaskFlags.ExcAny:
case EcsMaskFlags.IncExcAny:
{
return it.Iterate(source).CacheTo(ref array);
}
case EcsMaskFlags.Broken:
{
return 0;
}
default:
{
Throw.UndefinedException();
return 0;
}
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int CacheTo(this EcsMaskIterator.OnlyIncEnumerable e, ref HMem<int> array)
{
int count = 0;
var enumerator = e.GetEnumerator();
while (enumerator.MoveNext())
{
if (array.Length <= count)
{
array = Realloc<int>(array, array.Length << 1);
}
array.Ptr[count++] = enumerator.Current;
}
return count;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int CacheTo(this EcsMaskIterator.Enumerable e, ref HMem<int> array)
{
int count = 0;
var enumerator = e.GetEnumerator();
while (enumerator.MoveNext())
{
if (array.Length <= count)
{
array = Realloc<int>(array, array.Length << 1);
}
array.Ptr[count++] = enumerator.Current;
}
return count;
}
}
}

View File

@ -3,6 +3,7 @@
#endif
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace DCFApixels.DragonECS.Core.Internal
@ -27,30 +28,30 @@ namespace DCFApixels.DragonECS.Core.Internal
}
#region AllocAndInit
public static Handler AllocAndInit<T>(int count) where T : unmanaged
public static HMem<T> AllocAndInit<T>(int count) where T : unmanaged
{
return AllocAndInit_Internal(Marshal.SizeOf<T>() * count, typeof(T));
return new HMem<T>(AllocAndInit_Internal(Marshal.SizeOf<T>() * count, typeof(T)), count);
}
public static Handler AllocAndInit(int byteLength)
public static HMem<byte> AllocAndInit(int byteLength)
{
return AllocAndInit_Internal(byteLength, null);
return new HMem<byte>(AllocAndInit_Internal(byteLength, null), byteLength);
}
public static Handler AllocAndInit_Internal(int byteLength, Type type)
{
Handler handler = Alloc_Internal(byteLength, type);
AllocatorUtility.ClearAllocatedMemory(handler.Ptr, 0, byteLength);
AllocatorUtility.ClearAllocatedMemory(handler.RawPtr, 0, byteLength);
return handler;
}
#endregion
#region Alloc
public static Handler Alloc<T>(int count) where T : unmanaged
public static HMem<T> Alloc<T>(int count) where T : unmanaged
{
return Alloc_Internal(Marshal.SizeOf<T>() * count, typeof(T));
return new HMem<T>(Alloc_Internal(Marshal.SizeOf<T>() * count, typeof(T)), count);
}
public static Handler Alloc(int byteLength)
public static HMem<byte> Alloc(int byteLength)
{
return Alloc_Internal(byteLength, null);
return new HMem<byte>(Alloc_Internal(byteLength, null), byteLength); ;
}
public static Handler Alloc_Internal(int byteLength, Type type)
{
@ -85,69 +86,78 @@ namespace DCFApixels.DragonECS.Core.Internal
#endregion
#region ReallocAndInit
public static Handler ReallocAndInit<T>(void* target, int oldCount, int newCount) where T : unmanaged
public static HMem<T> ReallocAndInit<T>(void* target, int oldCount, int newCount) where T : unmanaged
{
return ReallocAndInit<T>(Handler.FromDataPtr(target), oldCount, newCount);
}
public static Handler ReallocAndInit(void* target, int oldByteLength, int newByteLength)
public static HMem<byte> ReallocAndInit(void* target, int oldByteLength, int newByteLength)
{
return ReallocAndInit(Handler.FromDataPtr(target), oldByteLength, newByteLength);
}
public static Handler ReallocAndInit<T>(Handler target, int oldCount, int newCount) where T : unmanaged
public static HMem<T> ReallocAndInit<T>(HMem<T> target, int newCount) where T : unmanaged
{
var size = Marshal.SizeOf<T>();
return ReallocAndInit_Internal(target, size * oldCount, size * newCount, typeof(T));
return new HMem<T>(ReallocAndInit_Internal(target, size * target.Length, size * newCount, typeof(T)), newCount);
}
public static Handler ReallocAndInit(Handler target, int oldByteLength, int newByteLength)
public static HMem<T> ReallocAndInit<T>(Handler target, int oldCount, int newCount) where T : unmanaged
{
return ReallocAndInit_Internal(target, oldByteLength, newByteLength, null);
var size = Marshal.SizeOf<T>();
return new HMem<T>(ReallocAndInit_Internal(target, size * oldCount, size * newCount, typeof(T)), newCount);
}
public static HMem<byte> ReallocAndInit(Handler target, int oldByteLength, int newByteLength)
{
return new HMem<byte>(ReallocAndInit_Internal(target, oldByteLength, newByteLength, null), newByteLength);
}
private static Handler ReallocAndInit_Internal(Handler target, int oldByteLength, int newByteLength, Type newType)
{
Handler handler = Realloc_Internal(target, newByteLength, newType);
AllocatorUtility.ClearAllocatedMemory(handler.Ptr, oldByteLength, newByteLength - oldByteLength);
AllocatorUtility.ClearAllocatedMemory(handler.RawPtr, oldByteLength, newByteLength - oldByteLength);
return handler;
}
#endregion
#region Realloc
public static Handler ReallocOrAlloc<T>(void* target, int newCount) where T : unmanaged
{
if (target == null) { return Alloc<T>(newCount); }
return Realloc<T>(Handler.FromDataPtr(target), Marshal.SizeOf<T>() * newCount);
}
public static Handler ReallocOrAlloc(void* target, int newByteLength)
{
if (target == null) { return Alloc(newByteLength); }
return Realloc(Handler.FromDataPtr(target), newByteLength);
}
public static Handler ReallocOrAlloc<T>(Handler target, int newCount) where T : unmanaged
{
if (target.IsEmpty) { return Alloc<T>(newCount); }
return Realloc_Internal(target, Marshal.SizeOf<T>() * newCount, typeof(T));
}
public static Handler Realloc<T>(void* target, int newCount) where T : unmanaged
public static HMem<T> Realloc<T>(void* target, int newCount) where T : unmanaged
{
return Realloc<T>(Handler.FromDataPtr(target), Marshal.SizeOf<T>() * newCount);
}
public static Handler Realloc(void* target, int newByteLength)
public static HMem<byte> Realloc(void* target, int newByteLength)
{
return Realloc(Handler.FromDataPtr(target), newByteLength);
return new HMem<byte>(Realloc(Handler.FromDataPtr(target), newByteLength), newByteLength);
}
public static Handler Realloc<T>(Handler target, int newCount) where T : unmanaged
public static HMem<T> Realloc<T>(Handler target, int newCount) where T : unmanaged
{
return Realloc_Internal(target, Marshal.SizeOf<T>() * newCount, typeof(T));
return new HMem<T>(Realloc_Internal(target, Marshal.SizeOf<T>() * newCount, typeof(T)), newCount);
}
public static Handler Realloc(Handler target, int newByteLength)
public static HMem<byte> Realloc(Handler target, int newByteLength)
{
return Realloc_Internal(target, newByteLength, null);
return new HMem<byte>(Realloc_Internal(target, newByteLength, null), newByteLength);
}
private static Handler Realloc_Internal(Handler target, int newByteLength, Type newType)
{
newByteLength = newByteLength == 0 ? 1 : newByteLength;
Meta* newHandledPtr = (Meta*)Marshal.ReAllocHGlobal((IntPtr)target.GetHandledPtr(), (IntPtr)newByteLength + sizeof(Meta));
if (target.IsCreated == false)
{
return Alloc_Internal(newByteLength, newType);
}
#if DEBUG
int id = 0;
lock (_idDispenser)
{
if (_debugInfos.Length <= _idDispenser.Count)
{
Array.Resize(ref _debugInfos, ArrayUtility.NextPow2(_idDispenser.Count));
}
id = _idDispenser.UseFree();
}
#endif
Meta* newHandledPtr = (Meta*)Marshal.ReAllocHGlobal(
(IntPtr)target.GetHandledPtr(),
(IntPtr)newByteLength + sizeof(Meta));
Handler handler = Handler.FromHandledPtr(newHandledPtr);
#if DEBUG
newHandledPtr->ID = id;
newHandledPtr->ByteLength = newByteLength;
#if DRAGONECS_DEEP_DEBUG
_debugInfos[newHandledPtr->ID].stackTrace = new System.Diagnostics.StackTrace();
#endif
@ -158,11 +168,44 @@ namespace DCFApixels.DragonECS.Core.Internal
}
#endregion
#region Clone
public static HMem<T> From<T>(HMem<T> source)
where T : unmanaged
{
var result = Alloc<T>(source.Length);
source.AsSpan().CopyTo(result.AsSpan());
return result;
}
public static HMem<T> From<T>(T* ptr, int length)
where T : unmanaged
{
return From<T>(new ReadOnlySpan<T>(ptr, length));
}
public static HMem<T> From<T>(T[] source)
where T : unmanaged
{
return From(new ReadOnlySpan<T>(source));
}
public static HMem<T> From<T>(ReadOnlySpan<T> source)
where T : unmanaged
{
var result = Alloc<T>(source.Length);
source.CopyTo(result.AsSpan());
return result;
}
#endregion
#region Free
public static void Free(Handler target)
{
Free_Internal(target.GetHandledPtr());
}
public static void FreeAndClear<T>(ref HMem<T> target)
where T : unmanaged
{
Free_Internal(target.Handler.GetHandledPtr());
target = default;
}
public static void FreeAndClear(ref Handler target)
{
Free_Internal(target.GetHandledPtr());
@ -175,6 +218,10 @@ namespace DCFApixels.DragonECS.Core.Internal
private static void Free_Internal(Meta* handledPtr)
{
#if DEBUG
if (handledPtr == null)
{
throw new ArgumentNullException();
}
lock (_idDispenser)
{
_idDispenser.Release(handledPtr->ID);
@ -226,11 +273,96 @@ namespace DCFApixels.DragonECS.Core.Internal
}
#endregion
public readonly struct HMem<T> : IDisposable, IEquatable<HMem<T>>
where T : unmanaged
{
public readonly T* Ptr;
public readonly int Length;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal HMem(Handler handler, int length)
{
Ptr = handler.As<T>();
Length = length;
}
public bool IsCreated
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return Ptr != null; }
}
public IntPtr RawPtr
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return new IntPtr(Ptr); }
}
public Handler Handler
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return Handler.FromDataPtr(Ptr); }
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public HMem<U> As<U>() where U : unmanaged
{
if (IsCreated)
{
return default;
}
long totalBytes = (long)Length * sizeof(T);
long newLengthLong = totalBytes / sizeof(U);
#if DEBUG
if (totalBytes % sizeof(U) != 0)
{
throw new InvalidOperationException($"Cannot cast Memory<{typeof(T).Name}> to Memory<{typeof(U).Name}> because the size of the underlying memory ({totalBytes} bytes) is not a multiple of the size of {typeof(U).Name} ({sizeof(U)} bytes).");
}
if (newLengthLong > int.MaxValue)
{
throw new InvalidOperationException($"Resulting length ({newLengthLong}) exceeds int.MaxValue.");
}
#endif
return new HMem<U>(Handler, (int)newLengthLong);
}
public void Dispose()
{
Handler.Dispose();
}
#if DEBUG
public override string ToString() { return Handler.DebuggerDisplay(); }
#endif
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override int GetHashCode() { return RawPtr.GetHashCode(); }
public override bool Equals(object obj) { return obj is Handler h && h == this; }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(HMem<T> other) { return other.Ptr == Ptr; }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(HMem<T> a, HMem<T> b) { return a.Ptr == b.Ptr; }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(HMem<T> a, HMem<T> b) { return a.Ptr != b.Ptr; }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Span<T> AsSpan() { return new Span<T>(Ptr, Length); }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Span<T> AsSpan(int length)
{
#if DEBUG
if (length > Length) { Throw.UndefinedException(); }
#endif
return new Span<T>(Ptr, length);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator Handler(HMem<T> memory) { return memory.Handler; }
}
#if DEBUG
[System.Diagnostics.DebuggerDisplay("{DebuggerDisplay()}")]
[System.Diagnostics.DebuggerTypeProxy(typeof(DebuggerProxy))]
#endif
public readonly struct Handler : IDisposable
public readonly struct Handler : IDisposable, IEquatable<Handler>
{
public static readonly Handler Empty = new Handler();
internal readonly Meta* Data; // Data[-1] is meta;
@ -255,16 +387,39 @@ namespace DCFApixels.DragonECS.Core.Internal
#endif
}
public bool IsEmpty { get { return Data == null; } }
public IntPtr Ptr { get { return (IntPtr)Data; } }
public T* As<T>() where T : unmanaged { return (T*)Ptr; }
public bool IsCreated
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return Data != null; }
}
public IntPtr RawPtr
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return (IntPtr)Data; }
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public T* As<T>() where T : unmanaged { return (T*)RawPtr; }
void IDisposable.Dispose() { Free((void*)Ptr); }
public void Dispose() { Free((void*)RawPtr); }
#if DEBUG
public override string ToString() { return DebuggerDisplay(); }
#endif
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override int GetHashCode() { return RawPtr.GetHashCode(); }
public override bool Equals(object obj) { return obj is Handler h && h == this; }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(Handler other) { return other.Data == Data; }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Handler a, Handler b) { return a.Data == b.Data; }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Handler a, Handler b) { return a.Data != b.Data; }
#region Debugger
#if DEBUG
#pragma warning disable IL3050 // Calling members annotated with 'RequiresDynamicCodeAttribute' may break functionality when AOT compiling.
internal unsafe string DebuggerDisplay()
internal string DebuggerDisplay()
{
if (Data == null)
{
@ -298,6 +453,7 @@ namespace DCFApixels.DragonECS.Core.Internal
}
return array;
}
[StructLayout(LayoutKind.Explicit)]
private unsafe struct Union
{
@ -319,13 +475,13 @@ namespace DCFApixels.DragonECS.Core.Internal
public HandlerDebugInfo[] OtherHandlersInfo;
public unsafe DebuggerProxy(Handler handler)
public DebuggerProxy(Handler handler)
{
IsAlive = handler.Ptr.ToPointer() != null;
IsAlive = handler.RawPtr.ToPointer() != null;
if (IsAlive == false) { return; }
Meta = handler.GetHandledPtr()[0];
_data = (byte*)handler.Ptr;
_data = (byte*)handler.RawPtr;
DebugInfo = _debugInfos[Meta.ID];
if (DebugInfo.type == null)
@ -397,9 +553,15 @@ namespace DCFApixels.DragonECS.Core.Internal
internal static class MemoryAllocatorHandlerExtensions
{
public static void Dispose(this ref MemoryAllocator.Handler self)
public static void DisposeAndReset(this ref MemoryAllocator.Handler self)
{
MemoryAllocator.FreeAndClear(ref self);
}
public static void DisposeAndReset<T>(this ref MemoryAllocator.HMem<T> self)
where T : unmanaged
{
self.Dispose();
self = default;
}
}
}

View File

@ -54,7 +54,7 @@ namespace DCFApixels.DragonECS.Core.Internal
{
MemoryAllocator.Free(_ptr);
}
_ptr = MemoryAllocator.Alloc<byte>(byteSize).As<byte>();
_ptr = MemoryAllocator.Alloc<byte>(byteSize).Ptr;
_byteSize = byteSize;
}
return (T*)_ptr;

View File

@ -1,272 +0,0 @@
#if DISABLE_DEBUG
#undef DEBUG
#endif
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
#if ENABLE_IL2CPP
using Unity.IL2CPP.CompilerServices;
#endif
namespace DCFApixels.DragonECS.Core.Internal
{
internal interface IStructComparer<T> : IComparer<T>
{
// a > b = return > 0
// int Compare(T a, T b);
}
#if ENABLE_IL2CPP
[Il2CppSetOption(Option.NullChecks, false)]
[Il2CppSetOption(Option.ArrayBoundsChecks, false)]
#endif
internal static class ArraySortHalperX<T>
{
private const int IntrosortSizeThreshold = 16;
#region IStructComparer
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void SwapIfGreater<TComparer>(T[] items, ref TComparer comparer, int i, int j) where TComparer : IStructComparer<T>
{
if (comparer.Compare(items[i], items[j]) > 0)
{
T key = items[i];
items[i] = items[j];
items[j] = key;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void InsertionSort<TComparer>(T[] items, ref TComparer comparer) where TComparer : IStructComparer<T>
{
for (int i = 0; i < items.Length - 1; i++)
{
T t = items[i + 1];
int j = i;
while (j >= 0 && comparer.Compare(t, items[j]) < 0)
{
items[j + 1] = items[j];
j--;
}
items[j + 1] = t;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Sort<TComparer>(T[] items, ref TComparer comparer) where TComparer : IStructComparer<T>
{
int length = items.Length;
if (length == 1)
{
return;
}
if (length <= IntrosortSizeThreshold)
{
if (length == 2)
{
SwapIfGreater(items, ref comparer, 0, 1);
return;
}
if (length == 3)
{
SwapIfGreater(items, ref comparer, 0, 1);
SwapIfGreater(items, ref comparer, 0, 2);
SwapIfGreater(items, ref comparer, 1, 2);
return;
}
InsertionSort(items, ref comparer);
return;
}
IStructComparer<T> packed = comparer;
Array.Sort(items, 0, items.Length, packed);
comparer = (TComparer)packed;
}
#endregion
#region Comparison
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void SwapIfGreater(T[] items, Comparison<T> comparison, int i, int j)
{
if (comparison(items[i], items[j]) > 0)
{
T key = items[i];
items[i] = items[j];
items[j] = key;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void InsertionSort(T[] items, int length, Comparison<T> comparison)
{
for (int i = 0; i < length - 1; i++)
{
T t = items[i + 1];
int j = i;
while (j >= 0 && comparison(t, items[j]) < 0)
{
items[j + 1] = items[j];
j--;
}
items[j + 1] = t;
}
}
#if ENABLE_IL2CPP
[Il2CppSetOption(Option.NullChecks, false)]
[Il2CppSetOption(Option.ArrayBoundsChecks, false)]
#endif
private class ComparisonHach : IComparer<T>
{
public static readonly ComparisonHach Instance = new ComparisonHach();
public Comparison<T> comparison;
private ComparisonHach() { }
public int Compare(T x, T y) { return comparison(x, y); }
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Sort(T[] items, Comparison<T> comparison)
{
Sort(items, comparison, items.Length);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Sort(T[] items, Comparison<T> comparison, int length)
{
if (length <= IntrosortSizeThreshold)
{
if (length == 1)
{
return;
}
if (length == 2)
{
SwapIfGreater(items, comparison, 0, 1);
return;
}
if (length == 3)
{
SwapIfGreater(items, comparison, 0, 1);
SwapIfGreater(items, comparison, 0, 2);
SwapIfGreater(items, comparison, 1, 2);
return;
}
InsertionSort(items, length, comparison);
return;
}
ComparisonHach.Instance.comparison = comparison;
Array.Sort(items, 0, length, ComparisonHach.Instance);
}
#endregion
}
#if ENABLE_IL2CPP
[Il2CppSetOption(Option.NullChecks, false)]
[Il2CppSetOption(Option.ArrayBoundsChecks, false)]
#endif
internal static unsafe class UnsafeArraySortHalperX<T> where T : unmanaged
{
private const int IntrosortSizeThreshold = 16;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void SwapIfGreater<TComparer>(T* items, ref TComparer comparer, int i, int j) where TComparer : IStructComparer<T>
{
if (comparer.Compare(items[i], items[j]) > 0)
{
T key = items[i];
items[i] = items[j];
items[j] = key;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void InsertionSort_Unchecked<TComparer>(T* items, int length, ref TComparer comparer) where TComparer : IStructComparer<T>
{
for (int i = 0; i < length - 1; i++)
{
T t = items[i + 1];
int j = i;
while (j >= 0 && comparer.Compare(t, items[j]) < 0)
{
items[j + 1] = items[j];
j--;
}
items[j + 1] = t;
}
}
//[MethodImpl(MethodImplOptions.AggressiveInlining)]
//public static void OptimizedBubbleSort_Unchecked<TComparer>(T* items, int length, ref TComparer comparer) where TComparer : IComparerX<T>
//{
// for (int i = 0, n = length - 1; i < n; i++)
// {
// bool noSwaped = true;
// for (int j = 0; j < n - i;)
// {
// ref T j0 = ref items[j++];
// if(comparer.Compare(j0, items[j]) < 0)
// {
// T tmp = items[j];
// items[j] = j0;
// j0 = tmp;
// noSwaped = false;
// }
// }
// if (noSwaped)
// break;
// }
//}
public static void InsertionSort<TComparer>(T* items, int length, ref TComparer comparer) where TComparer : IStructComparer<T>
{
if (length == 1)
{
return;
}
if (length == 2)
{
SwapIfGreater(items, ref comparer, 0, 1);
return;
}
if (length == 3)
{
SwapIfGreater(items, ref comparer, 0, 1);
SwapIfGreater(items, ref comparer, 0, 2);
SwapIfGreater(items, ref comparer, 1, 2);
return;
}
InsertionSort_Unchecked(items, length, ref comparer);
}
//public static void OptimizedBubbleSort<TComparer>(T* items, int length, ref TComparer comparer) where TComparer : IComparerX<T>
//{
// if (length == 1)
// {
// return;
// }
//
// if (length == 2)
// {
// SwapIfGreater(items, ref comparer, 0, 1);
// return;
// }
//
// if (length == 3)
// {
// SwapIfGreater(items, ref comparer, 0, 1);
// SwapIfGreater(items, ref comparer, 0, 2);
// SwapIfGreater(items, ref comparer, 1, 2);
// return;
// }
//
// OptimizedBubbleSort_Unchecked(items, length, ref comparer);
//}
}
}

View File

@ -6,7 +6,6 @@ using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace DCFApixels.DragonECS.Core.Internal
{
@ -270,114 +269,6 @@ namespace DCFApixels.DragonECS.Core.Internal
}
}
internal static unsafe class UnmanagedArrayUtility
{
private static class MetaCache<T>
{
public readonly static int Size;
static MetaCache()
{
T def = default;
Size = Marshal.SizeOf(def);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T* New<T>(int capacity) where T : unmanaged
{
//Console.WriteLine($"{typeof(T).Name} - {Marshal.SizeOf<T>()} - {capacity} - {Marshal.SizeOf<T>() * capacity}");
//return (T*)Marshal.AllocHGlobal(Marshal.SizeOf<T>() * capacity).ToPointer();
return MemoryAllocator.Alloc<T>(capacity).As<T>();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void New<T>(out T* ptr, int capacity) where T : unmanaged
{
//ptr = (T*)Marshal.AllocHGlobal(Marshal.SizeOf<T>() * capacity).ToPointer();
ptr = MemoryAllocator.Alloc<T>(capacity).As<T>();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T* NewAndInit<T>(int capacity) where T : unmanaged
{
//int newSize = MetaCache<T>.Size * capacity;
//byte* newPointer = (byte*)Marshal.AllocHGlobal(newSize).ToPointer();
//
//for (int i = 0; i < newSize; i++)
//{
// *(newPointer + i) = 0;
//}
//
//return (T*)newPointer;
return MemoryAllocator.AllocAndInit<T>(capacity).As<T>();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void NewAndInit<T>(out T* ptr, int capacity) where T : unmanaged
{
//int newSize = MetaCache<T>.Size * capacity;
//byte* newPointer = (byte*)Marshal.AllocHGlobal(newSize).ToPointer();
//
//for (int i = 0; i < newSize; i++)
//{
// *(newPointer + i) = 0;
//}
//
//ptr = (T*)newPointer;
ptr = MemoryAllocator.AllocAndInit<T>(capacity).As<T>();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Free(void* pointer)
{
//Marshal.FreeHGlobal(new IntPtr(pointer));
MemoryAllocator.Free(dataPtr: pointer);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Free<T>(ref T* pointer, ref int length) where T : unmanaged
{
//Marshal.FreeHGlobal(new IntPtr(pointer));
MemoryAllocator.Free(dataPtr: pointer);
pointer = null;
length = 0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T* Clone<T>(T* sourcePtr, int length) where T : unmanaged
{
T* clone = New<T>(length);
for (int i = 0; i < length; i++)
{
clone[i] = sourcePtr[i];
}
return clone;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T* Resize<T>(void* oldPointer, int newCount) where T : unmanaged
{
//return (T*)(Marshal.ReAllocHGlobal(
// new IntPtr(oldPointer),
// new IntPtr(MetaCache<T>.Size * newCount))).ToPointer();
return MemoryAllocator.Realloc<T>(MemoryAllocator.Handler.FromDataPtr(oldPointer), newCount).As<T>();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T* ResizeAndInit<T>(void* oldPointer, int oldSize, int newSize) where T : unmanaged
{
//int sizeT = MetaCache<T>.Size;
//T* result = (T*)Marshal.ReAllocHGlobal(
// new IntPtr(oldPointer),
// new IntPtr(sizeT * newSize)).ToPointer();
//Init((byte*)result, sizeT * oldSize, sizeT * newSize);
//return result;
return MemoryAllocator.ReallocAndInit<T>(MemoryAllocator.Handler.FromDataPtr(oldPointer), oldSize, newSize).As<T>();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void Init(byte* pointer, int startByteIndex, int endByteIndex)
{
for (int i = startByteIndex; i < endByteIndex; i++)
{
*(pointer + i) = 0;
}
}
}
public static class CollectionUtility
{

631
src/Internal/SortHalper.cs Normal file
View File

@ -0,0 +1,631 @@
#if DISABLE_DEBUG
#undef DEBUG
#endif
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.CompilerServices;
#if ENABLE_IL2CPP
using Unity.IL2CPP.CompilerServices;
#endif
namespace DCFApixels.DragonECS.Core.Internal
{
#if ENABLE_IL2CPP
[Il2CppSetOption(Option.NullChecks, false)]
[Il2CppSetOption(Option.ArrayBoundsChecks, false)]
#endif
internal static unsafe class SortHalper
{
#region Span
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Sort<T>(Span<T> span)
{
var c = new ComparerWrapper<T>(Comparer<T>.Default);
SortHalper<T, ComparerWrapper<T>>.Sort(span, ref c);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Sort<T>(Span<T> span, bool _ = false)
where T : IComparable<T>
{
var c = new ComparableWrapper<T>();
SortHalper<T, ComparableWrapper<T>>.Sort(span, ref c);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Sort<T>(Span<T> span, Comparer<T> comparer)
{
var c = new ComparerWrapper<T>(comparer);
SortHalper<T, ComparerWrapper<T>>.Sort(span, ref c);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Sort<T>(Span<T> span, Comparison<T> comparison)
{
var c = new ComparisonWrapper<T>(comparison);
SortHalper<T, ComparisonWrapper<T>>.Sort(span, ref c);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Sort<T, TComparer>(Span<T> span, ref TComparer comparer)
where TComparer : struct, IComparer<T>
{
SortHalper<T, TComparer>.Sort(span, ref comparer);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Sort<T, TComparer>(Span<T> span, TComparer comparer)
where TComparer : struct, IComparer<T>
{
SortHalper<T, TComparer>.Sort(span, ref comparer);
}
#endregion
#region Utils
// Таблица для De Bruijn-умножения (позиция старшего бита для чисел 0..31)
private const int Log2DeBruijn32_Length = 32;
private static readonly uint* Log2DeBruijn32 = MemoryAllocator.From(new uint[Log2DeBruijn32_Length]
{
0, 9, 1, 10, 13, 21, 2, 29, 11, 14, 16, 18, 22, 25, 3, 30,
8, 12, 20, 28, 15, 17, 24, 7, 19, 27, 23, 6, 26, 5, 4, 31
}).Ptr;
/// <summary>32-битный логарифм по основанию 2 (округление вниз). Для value = 0 возвращает 0.</summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int Log2(uint value)
{
// Для нуля сразу возвращаем 0 (по договорённости, чтобы избежать исключения)
if (value == 0) return 0;
// Заполняем все биты справа от старшего единицей: превращаем число в 2^n - 1
value |= value >> 1;
value |= value >> 2;
value |= value >> 4;
value |= value >> 8;
value |= value >> 16;
// Умножение на константу De Bruijn и сдвиг для получения индекса в таблице
return (int)Log2DeBruijn32[(value * 0x07C4ACDDu) >> 27];
}
/// <summary>64-битный логарифм по основанию 2 (округление вниз). Для value = 0 возвращает 0.</summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int Log2(ulong value)
{
if (value == 0) { return 0; }
uint high = (uint)(value >> 32);
if (high == 0)
{
return Log2((uint)value);
}
else
{
return 32 + Log2(high);
}
}
#endregion
}
// a > b = return > 0
// int Compare(T a, T b);
//IComparer<T> comparer
//if (comparer == null)
//{
// comparer = Comparer<T>.Default;
//}
#if ENABLE_IL2CPP
[Il2CppSetOption(Option.NullChecks, false)]
[Il2CppSetOption(Option.ArrayBoundsChecks, false)]
#endif
internal static class SortHalper<T, TComparer>
where TComparer : struct, IComparer<T>
{
private const int IntrosortSizeThreshold = 16;
#region Public
public static void Sort(Span<T> keys, ref TComparer comparer)
{
// Add a try block here to detect IComparers (or their
// underlying IComparables, etc) that are bogus.
IntrospectiveSort(keys, ref comparer);
}
public static int BinarySearch(T[] array, int index, int length, T value, ref TComparer comparer)
{
Debug.Assert(array != null, "Check the arguments in the caller!");
Debug.Assert(index >= 0 && length >= 0 && (array.Length - index >= length), "Check the arguments in the caller!");
int lo = index;
int hi = index + length - 1;
while (lo <= hi)
{
int i = lo + ((hi - lo) >> 1);
int order = comparer.Compare(array[i], value);
if (order == 0) return i;
if (order < 0)
{
lo = i + 1;
}
else
{
hi = i - 1;
}
}
return ~lo;
}
#endregion
#region Internal
internal static void IntrospectiveSort(Span<T> keys, ref TComparer comparer)
{
//Debug.Assert(comparer != null);
if (keys.Length > 1)
{
IntroSort(keys, 2 * (SortHalper.Log2((uint)keys.Length) + 1), ref comparer);
}
}
// IntroSort is recursive; block it from being inlined into itself as
// this is currenly not profitable.
[MethodImpl(MethodImplOptions.NoInlining)]
private static void IntroSort(Span<T> keys, int depthLimit, ref TComparer comparer)
{
Debug.Assert(!keys.IsEmpty);
Debug.Assert(depthLimit >= 0);
//Debug.Assert(comparer != null);
int partitionSize = keys.Length;
while (partitionSize > 1)
{
if (partitionSize <= IntrosortSizeThreshold)
{
if (partitionSize == 2)
{
SwapIfGreater(keys, ref comparer, 0, 1);
return;
}
if (partitionSize == 3)
{
SwapIfGreater(keys, ref comparer, 0, 1);
SwapIfGreater(keys, ref comparer, 0, 2);
SwapIfGreater(keys, ref comparer, 1, 2);
return;
}
InsertionSort(keys.Slice(0, partitionSize), ref comparer);
return;
}
if (depthLimit == 0)
{
HeapSort(keys.Slice(0, partitionSize), ref comparer);
return;
}
depthLimit--;
int p = PickPivotAndPartition(keys.Slice(0, partitionSize), ref comparer);
// Note we've already partitioned around the pivot and do not have to move the pivot again.
IntroSort(keys.Slice(p + 1, partitionSize - (p + 1)), depthLimit, ref comparer);
partitionSize = p;
}
}
private static int PickPivotAndPartition(Span<T> keys, ref TComparer comparer)
{
Debug.Assert(keys.Length >= IntrosortSizeThreshold);
//Debug.Assert(comparer != null);
int hi = keys.Length - 1;
// Compute median-of-three. But also partition them, since we've done the comparison.
int middle = hi >> 1;
// Sort lo, mid and hi appropriately, then pick mid as the pivot.
SwapIfGreater(keys, ref comparer, 0, middle); // swap the low with the mid point
SwapIfGreater(keys, ref comparer, 0, hi); // swap the low with the high
SwapIfGreater(keys, ref comparer, middle, hi); // swap the middle with the high
T pivot = keys[middle];
Swap(keys, middle, hi - 1);
int left = 0, right = hi - 1; // We already partitioned lo and hi and put the pivot in hi - 1. And we pre-increment & decrement below.
while (left < right)
{
while (comparer.Compare(keys[++left], pivot) < 0) ;
while (comparer.Compare(pivot, keys[--right]) < 0) ;
if (left >= right)
break;
Swap(keys, left, right);
}
// Put pivot in the right location.
if (left != hi - 1)
{
Swap(keys, left, hi - 1);
}
return left;
}
private static void HeapSort(Span<T> keys, ref TComparer comparer)
{
Debug.Assert(!keys.IsEmpty);
//Debug.Assert(comparer != null);
int n = keys.Length;
for (int i = n >> 1; i >= 1; i--)
{
DownHeap(keys, i, n, ref comparer);
}
for (int i = n; i > 1; i--)
{
Swap(keys, 0, i - 1);
DownHeap(keys, 1, i - 1, ref comparer);
}
}
private static void DownHeap(Span<T> keys, int i, int n, ref TComparer comparer)
{
//Debug.Assert(comparer != null);
T d = keys[i - 1];
while (i <= n >> 1)
{
int child = 2 * i;
if (child < n && comparer.Compare(keys[child - 1], keys[child]) < 0)
{
child++;
}
if (!(comparer.Compare(d, keys[child - 1]) < 0))
break;
keys[i - 1] = keys[child - 1];
i = child;
}
keys[i - 1] = d;
}
private static void InsertionSort(Span<T> keys, ref TComparer comparer)
{
for (int i = 0; i < keys.Length - 1; i++)
{
T t = keys[i + 1];
int j = i;
while (j >= 0 && comparer.Compare(t, keys[j]) < 0)
{
keys[j + 1] = keys[j];
j--;
}
keys[j + 1] = t;
}
}
#endregion
#region Swaps
private static void SwapIfGreater(Span<T> keys, ref TComparer comparer, int i, int j)
{
Debug.Assert(i != j);
if (comparer.Compare(keys[i], keys[j]) > 0)
{
T key = keys[i];
keys[i] = keys[j];
keys[j] = key;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void Swap(Span<T> a, int i, int j)
{
Debug.Assert(i != j);
T t = a[i];
a[i] = a[j];
a[j] = t;
}
#endregion
}
#region Wrappers
#if ENABLE_IL2CPP
[Il2CppSetOption(Option.NullChecks, false)]
[Il2CppSetOption(Option.ArrayBoundsChecks, false)]
#endif
internal readonly struct ComparableWrapper<T> : IComparer<T>
where T : IComparable<T>
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int Compare(T x, T y) { return x.CompareTo(y); }
}
#if ENABLE_IL2CPP
[Il2CppSetOption(Option.NullChecks, false)]
[Il2CppSetOption(Option.ArrayBoundsChecks, false)]
#endif
internal readonly struct ComparisonWrapper<T> : IComparer<T>
{
public readonly Comparison<T> Comparison;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ComparisonWrapper(Comparison<T> comparison)
{
Comparison = comparison;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int Compare(T x, T y)
{
return Comparison(x, y);
}
}
#if ENABLE_IL2CPP
[Il2CppSetOption(Option.NullChecks, false)]
[Il2CppSetOption(Option.ArrayBoundsChecks, false)]
#endif
internal readonly struct ComparerWrapper<T> : IComparer<T>
{
public readonly Comparer<T> Comparer;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ComparerWrapper(Comparer<T> comparer)
{
Comparer = comparer;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int Compare(T x, T y)
{
return Comparer.Compare(x, y);
}
}
#endregion
}
//namespace DCFApixels.DragonECS.Core.Internal
//{
// internal interface IStructComparer<T> : IComparer<T>
// {
// // a > b = return > 0
// // int Compare(T a, T b);
// }
//
//#if ENABLE_IL2CPP
// [Il2CppSetOption(Option.NullChecks, false)]
// [Il2CppSetOption(Option.ArrayBoundsChecks, false)]
//#endif
// internal static class ArraySortHalperX<T>
// {
// private const int IntrosortSizeThreshold = 16;
//
// #region IStructComparer
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
// public static void SwapIfGreater<TComparer>(T[] items, ref TComparer comparer, int i, int j) where TComparer : IStructComparer<T>
// {
// if (comparer.Compare(items[i], items[j]) > 0)
// {
// T key = items[i];
// items[i] = items[j];
// items[j] = key;
// }
// }
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
// public static void InsertionSort<TComparer>(T[] items, ref TComparer comparer) where TComparer : IStructComparer<T>
// {
// for (int i = 0; i < items.Length - 1; i++)
// {
// T t = items[i + 1];
//
// int j = i;
// while (j >= 0 && comparer.Compare(t, items[j]) < 0)
// {
// items[j + 1] = items[j];
// j--;
// }
//
// items[j + 1] = t;
// }
// }
//
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
// public static void Sort<TComparer>(T[] items, ref TComparer comparer) where TComparer : IStructComparer<T>
// {
// int length = items.Length;
// if (length == 1)
// {
// return;
// }
//
// if (length <= IntrosortSizeThreshold)
// {
//
// if (length == 2)
// {
// SwapIfGreater(items, ref comparer, 0, 1);
// return;
// }
//
// if (length == 3)
// {
// SwapIfGreater(items, ref comparer, 0, 1);
// SwapIfGreater(items, ref comparer, 0, 2);
// SwapIfGreater(items, ref comparer, 1, 2);
// return;
// }
//
// InsertionSort(items, ref comparer);
// return;
// }
//
// IStructComparer<T> packed = comparer;
// Array.Sort(items, 0, items.Length, packed);
// comparer = (TComparer)packed;
// }
// #endregion
//
// #region Comparison
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
// public static void SwapIfGreater(T[] items, Comparison<T> comparison, int i, int j)
// {
// if (comparison(items[i], items[j]) > 0)
// {
// T key = items[i];
// items[i] = items[j];
// items[j] = key;
// }
// }
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
// public static void InsertionSort(T[] items, int length, Comparison<T> comparison)
// {
// for (int i = 0; i < length - 1; i++)
// {
// T t = items[i + 1];
//
// int j = i;
// while (j >= 0 && comparison(t, items[j]) < 0)
// {
// items[j + 1] = items[j];
// j--;
// }
//
// items[j + 1] = t;
// }
// }
//
//#if ENABLE_IL2CPP
// [Il2CppSetOption(Option.NullChecks, false)]
// [Il2CppSetOption(Option.ArrayBoundsChecks, false)]
//#endif
// private class ComparisonHach : IComparer<T>
// {
// public static readonly ComparisonHach Instance = new ComparisonHach();
// public Comparison<T> comparison;
// private ComparisonHach() { }
// public int Compare(T x, T y) { return comparison(x, y); }
// }
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
// public static void Sort(T[] items, Comparison<T> comparison)
// {
// Sort(items, comparison, items.Length);
// }
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
// public static void Sort(T[] items, Comparison<T> comparison, int length)
// {
// if (length <= IntrosortSizeThreshold)
// {
// if (length == 1)
// {
// return;
// }
// if (length == 2)
// {
// SwapIfGreater(items, comparison, 0, 1);
// return;
// }
// if (length == 3)
// {
// SwapIfGreater(items, comparison, 0, 1);
// SwapIfGreater(items, comparison, 0, 2);
// SwapIfGreater(items, comparison, 1, 2);
// return;
// }
// InsertionSort(items, length, comparison);
// return;
// }
// ComparisonHach.Instance.comparison = comparison;
// Array.Sort(items, 0, length, ComparisonHach.Instance);
// }
// #endregion
// }
//
//#if ENABLE_IL2CPP
// [Il2CppSetOption(Option.NullChecks, false)]
// [Il2CppSetOption(Option.ArrayBoundsChecks, false)]
//#endif
// internal static unsafe class UnsafeArraySortHalperX<T> where T : unmanaged
// {
// private const int IntrosortSizeThreshold = 16;
//
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
// public static void SwapIfGreater<TComparer>(T* items, ref TComparer comparer, int i, int j) where TComparer : IStructComparer<T>
// {
// if (comparer.Compare(items[i], items[j]) > 0)
// {
// T key = items[i];
// items[i] = items[j];
// items[j] = key;
// }
// }
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
// public static void InsertionSort_Unchecked<TComparer>(T* items, int length, ref TComparer comparer) where TComparer : IStructComparer<T>
// {
// for (int i = 0; i < length - 1; i++)
// {
// T t = items[i + 1];
//
// int j = i;
// while (j >= 0 && comparer.Compare(t, items[j]) < 0)
// {
// items[j + 1] = items[j];
// j--;
// }
//
// items[j + 1] = t;
// }
// }
// public static void InsertionSort<TComparer>(T* items, int length, ref TComparer comparer) where TComparer : IStructComparer<T>
// {
// if (length == 1)
// {
// return;
// }
//
// if (length == 2)
// {
// SwapIfGreater(items, ref comparer, 0, 1);
// return;
// }
//
// if (length == 3)
// {
// SwapIfGreater(items, ref comparer, 0, 1);
// SwapIfGreater(items, ref comparer, 0, 2);
// SwapIfGreater(items, ref comparer, 1, 2);
// return;
// }
//
// InsertionSort_Unchecked(items, length, ref comparer);
// }
// }
//}

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: a591de1858028504d819333121bfddd6
guid: 7e60048b7c58cdf4ba044b7c832bd6a4
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@ -38,13 +38,13 @@ namespace DCFApixels.DragonECS.Core.Internal
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public UnsafeArray(int length)
{
UnmanagedArrayUtility.New(out ptr, length);
ptr = MemoryAllocator.Alloc<T>(length).Ptr;
Length = length;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public UnsafeArray(int length, bool isInit)
{
UnmanagedArrayUtility.NewAndInit(out ptr, length);
ptr = MemoryAllocator.AllocAndInit<T>(length).Ptr;
Length = length;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@ -90,18 +90,20 @@ namespace DCFApixels.DragonECS.Core.Internal
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public UnsafeArray<T> Clone()
{
return new UnsafeArray<T>(UnmanagedArrayUtility.Clone(ptr, Length), Length);
return new UnsafeArray<T>(MemoryAllocator.From(ptr, Length).Ptr, Length);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Dispose()
{
UnmanagedArrayUtility.Free(ref ptr, ref Length);
MemoryAllocator.Free(ptr);
ptr = default;
Length = default;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ReadonlyDispose()
{
UnmanagedArrayUtility.Free(ptr);
MemoryAllocator.Free(ptr);
}
public override string ToString()
{
@ -114,6 +116,9 @@ namespace DCFApixels.DragonECS.Core.Internal
return CollectionUtility.AutoToString(elements, "ua");
}
public Span<T> AsSpan() { return new Span<T>(ptr, Length); }
public T[] ToArray() { return AsSpan().ToArray(); }
IEnumerator<T> IEnumerable<T>.GetEnumerator() { return GetEnumerator(); }
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
[MethodImpl(MethodImplOptions.AggressiveInlining)]

View File

@ -35,7 +35,8 @@ namespace DCFApixels.DragonECS
public sealed class EcsPool<T> : IEcsPoolImplementation<T>, IEcsStructPool<T>, IEnumerable<T> //IEnumerable<T> - IntelliSense hack
where T : struct, IEcsComponent
{
private EcsWorld _source;
private short _worldID;
private EcsWorld _world;
private int _componentTypeID;
private EcsMaskChunck _maskBit;
@ -45,14 +46,14 @@ namespace DCFApixels.DragonECS
private int[] _recycledItems;
private int _recycledItemsCount = 0;
private readonly IEcsComponentLifecycle<T> _componentLifecycleHandler = EcsComponentLifecycleHandler<T>.instance;
private readonly bool _isHasComponentLifecycleHandler = EcsComponentLifecycleHandler<T>.isHasHandler;
private readonly IEcsComponentCopy<T> _componentCopyHandler = EcsComponentCopyHandler<T>.instance;
private readonly bool _isHasComponentCopyHandler = EcsComponentCopyHandler<T>.isHasHandler;
private readonly IEcsComponentLifecycle<T> _customLifecycle = EcsComponentLifecycle<T>.CustomHandler;
private readonly bool _isCustomLifecycle = EcsComponentLifecycle<T>.IsCustom;
private readonly IEcsComponentCopy<T> _customCopy = EcsComponentCopy<T>.CustomHandler;
private readonly bool _isCustomCopy = EcsComponentCopy<T>.IsCustom;
#if !DRAGONECS_DISABLE_POOLS_EVENTS
private StructList<IEcsPoolEventListener> _listeners = new StructList<IEcsPoolEventListener>(2);
private int _listenersCachedCount = 0;
private bool _hasAnyListener = false;
#endif
private bool _isLocked;
@ -77,7 +78,7 @@ namespace DCFApixels.DragonECS
}
public EcsWorld World
{
get { return _source; }
get { return _world; }
}
public bool IsReadOnly
{
@ -104,7 +105,8 @@ namespace DCFApixels.DragonECS
}
void IEcsPoolImplementation.OnInit(EcsWorld world, EcsWorld.PoolsMediator mediator, int componentTypeID)
{
_source = world;
_world = world;
_worldID = world.ID;
_mediator = mediator;
_componentTypeID = componentTypeID;
_maskBit = EcsMaskChunck.FromID(componentTypeID);
@ -128,13 +130,13 @@ namespace DCFApixels.DragonECS
{
ref int itemIndex = ref _mapping[entityID];
#if DEBUG
if (entityID == EcsConsts.NULL_ENTITY_ID) { EcsPoolThrowHelper.ThrowEntityIsNotAlive(_source, entityID); }
if (_source.IsUsed(entityID) == false) { EcsPoolThrowHelper.ThrowEntityIsNotAlive(_source, entityID); }
if (entityID == EcsConsts.NULL_ENTITY_ID) { EcsPoolThrowHelper.ThrowEntityIsNotAlive(_world, entityID); }
if (_world.IsUsed(entityID) == false) { EcsPoolThrowHelper.ThrowEntityIsNotAlive(_world, entityID); }
if (itemIndex > 0) { EcsPoolThrowHelper.ThrowAlreadyHasComponent<T>(entityID); }
if (_isLocked) { EcsPoolThrowHelper.ThrowPoolLocked(); }
#elif DRAGONECS_STABILITY_MODE
if (itemIndex > 0) { return ref Get(entityID); }
if (_isLocked | _source.IsUsed(entityID) == false) { return ref _items[0]; }
if (_isLocked | _world.IsUsed(entityID) == false) { return ref _items[0]; }
#endif
if (_recycledItemsCount > 0)
{
@ -151,9 +153,9 @@ namespace DCFApixels.DragonECS
}
_mediator.RegisterComponent(entityID, _componentTypeID, _maskBit);
ref T result = ref _items[itemIndex];
EnableComponent(ref result);
EcsComponentLifecycle<T>.OnAdd( _isCustomLifecycle, _customLifecycle, ref result, _worldID, entityID);
#if !DRAGONECS_DISABLE_POOLS_EVENTS
_listeners.InvokeOnAddAndGet(entityID, _listenersCachedCount);
if (_hasAnyListener) { _listeners.InvokeOnAddAndGet(entityID); }
#endif
return ref result;
}
@ -164,7 +166,7 @@ namespace DCFApixels.DragonECS
if (!Has(entityID)) { EcsPoolThrowHelper.ThrowNotHaveComponent<T>(entityID); }
#endif
#if !DRAGONECS_DISABLE_POOLS_EVENTS
_listeners.InvokeOnGet(entityID, _listenersCachedCount);
if (_hasAnyListener) { _listeners.InvokeOnGet(entityID); }
#endif
return ref _items[_mapping[entityID]];
}
@ -179,7 +181,7 @@ namespace DCFApixels.DragonECS
public ref T TryAddOrGet(int entityID)
{
#if DEBUG
if (entityID == EcsConsts.NULL_ENTITY_ID) { EcsPoolThrowHelper.ThrowEntityIsNotAlive(_source, entityID); }
if (entityID == EcsConsts.NULL_ENTITY_ID) { EcsPoolThrowHelper.ThrowEntityIsNotAlive(_world, entityID); }
#endif
ref int itemIndex = ref _mapping[entityID];
if (itemIndex <= 0)
@ -203,13 +205,13 @@ namespace DCFApixels.DragonECS
}
}
_mediator.RegisterComponent(entityID, _componentTypeID, _maskBit);
EnableComponent(ref _items[itemIndex]);
EcsComponentLifecycle<T>.OnAdd(_isCustomLifecycle, _customLifecycle, ref _items[itemIndex], _worldID, entityID);
#if !DRAGONECS_DISABLE_POOLS_EVENTS
_listeners.InvokeOnAdd(entityID, _listenersCachedCount);
if (_hasAnyListener) { _listeners.InvokeOnAdd(entityID); }
#endif
} //Add block end
#if !DRAGONECS_DISABLE_POOLS_EVENTS
_listeners.InvokeOnGet(entityID, _listenersCachedCount);
if (_hasAnyListener) { _listeners.InvokeOnGet(entityID); }
#endif
return ref _items[itemIndex];
}
@ -222,14 +224,14 @@ namespace DCFApixels.DragonECS
{
ref int itemIndex = ref _mapping[entityID];
#if DEBUG
if (entityID == EcsConsts.NULL_ENTITY_ID) { EcsPoolThrowHelper.ThrowEntityIsNotAlive(_source, entityID); }
if (entityID == EcsConsts.NULL_ENTITY_ID) { EcsPoolThrowHelper.ThrowEntityIsNotAlive(_world, entityID); }
if (itemIndex <= 0) { EcsPoolThrowHelper.ThrowNotHaveComponent<T>(entityID); }
if (_isLocked) { EcsPoolThrowHelper.ThrowPoolLocked(); }
#elif DRAGONECS_STABILITY_MODE
if (itemIndex <= 0) { return; }
if (_isLocked) { return; }
#endif
DisableComponent(ref _items[itemIndex]);
EcsComponentLifecycle<T>.OnDel( _isCustomLifecycle, _customLifecycle, ref _items[itemIndex], _worldID, entityID);
if (_recycledItemsCount >= _recycledItems.Length)
{
Array.Resize(ref _recycledItems, ArrayUtility.NextPow2Safe(_recycledItemsCount));
@ -239,7 +241,7 @@ namespace DCFApixels.DragonECS
_itemsCount--;
_mediator.UnregisterComponent(entityID, _componentTypeID, _maskBit);
#if !DRAGONECS_DISABLE_POOLS_EVENTS
_listeners.InvokeOnDel(entityID, _listenersCachedCount);
if (_hasAnyListener) { _listeners.InvokeOnDel(entityID); }
#endif
}
public void TryDel(int entityID)
@ -256,7 +258,7 @@ namespace DCFApixels.DragonECS
#elif DRAGONECS_STABILITY_MODE
if (!Has(fromEntityID)) { return; }
#endif
CopyComponent(ref Get(fromEntityID), ref TryAddOrGet(toEntityID));
EcsComponentCopy<T>.Copy(_isCustomCopy, _customCopy, ref Get(fromEntityID), ref TryAddOrGet(toEntityID));
}
public void Copy(int fromEntityID, EcsWorld toWorld, int toEntityID)
{
@ -265,7 +267,7 @@ namespace DCFApixels.DragonECS
#elif DRAGONECS_STABILITY_MODE
if (!Has(fromEntityID)) { return; }
#endif
CopyComponent(ref Get(fromEntityID), ref toWorld.GetPool<T>().TryAddOrGet(toEntityID));
EcsComponentCopy<T>.Copy(_isCustomCopy, _customCopy, ref Get(fromEntityID), ref toWorld.GetPool<T>().TryAddOrGet(toEntityID));
}
public void ClearAll()
@ -277,15 +279,15 @@ namespace DCFApixels.DragonECS
#endif
_recycledItemsCount = 0; // ñïåðåäè ÷òîáû îáíóëÿëîñü, òàê êàê Del íå îáíóëÿåò
if (_itemsCount <= 0) { return; }
var span = _source.Where(out SingleAspect<T> _);
var span = _world.Where(out SingleAspect<T> _);
foreach (var entityID in span)
{
ref int itemIndex = ref _mapping[entityID];
DisableComponent(ref _items[itemIndex]);
EcsComponentLifecycle<T>.OnDel(_isCustomLifecycle, _customLifecycle, ref _items[itemIndex], _worldID, entityID);
itemIndex = 0;
_mediator.UnregisterComponent(entityID, _componentTypeID, _maskBit);
#if !DRAGONECS_DISABLE_POOLS_EVENTS
_listeners.InvokeOnDel(entityID, _listenersCachedCount);
if (_hasAnyListener) { _listeners.InvokeOnDel(entityID); }
#endif
}
_itemsCount = 0;
@ -332,58 +334,19 @@ namespace DCFApixels.DragonECS
{
if (listener == null) { EcsPoolThrowHelper.ThrowNullListener(); }
_listeners.Add(listener);
_listenersCachedCount++;
_hasAnyListener = _listeners.Count > 0;
}
public void RemoveListener(IEcsPoolEventListener listener)
{
if (listener == null) { EcsPoolThrowHelper.ThrowNullListener(); }
if (_listeners.RemoveWithOrder(listener))
{
_listenersCachedCount--;
_hasAnyListener = _listeners.Count > 0;
}
}
#endif
#endregion
#region Enable/Disable/Copy
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void EnableComponent(ref T component)
{
if (_isHasComponentLifecycleHandler)
{
_componentLifecycleHandler.Enable(ref component);
}
else
{
component = default;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void DisableComponent(ref T component)
{
if (_isHasComponentLifecycleHandler)
{
_componentLifecycleHandler.Disable(ref component);
}
else
{
component = default;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void CopyComponent(ref T from, ref T to)
{
if (_isHasComponentCopyHandler)
{
_componentCopyHandler.Copy(ref from, ref to);
}
else
{
to = from;
}
}
#endregion
#region IEnumerator - IntelliSense hack
IEnumerator<T> IEnumerable<T>.GetEnumerator() { throw new NotImplementedException(); }
IEnumerator IEnumerable.GetEnumerator() { throw new NotImplementedException(); }
@ -484,7 +447,6 @@ namespace DCFApixels.DragonECS
#endregion
}
public static class EcsPoolExtensions
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@ -518,29 +480,5 @@ namespace DCFApixels.DragonECS
{
return self.AnyPool<EcsPool<TComponent>>();
}
#region Obsolete
[Obsolete("Use " + nameof(EcsAspect) + "." + nameof(EcsAspect.Builder) + "." + nameof(Inc) + "<T>()")]
[EditorBrowsable(EditorBrowsableState.Never)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static EcsPool<TComponent> Include<TComponent>(this EcsAspect.Builder self) where TComponent : struct, IEcsComponent
{
return self.IncludePool<EcsPool<TComponent>>();
}
[Obsolete("Use " + nameof(EcsAspect) + "." + nameof(EcsAspect.Builder) + "." + nameof(Exc) + "<T>()")]
[EditorBrowsable(EditorBrowsableState.Never)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static EcsPool<TComponent> Exclude<TComponent>(this EcsAspect.Builder self) where TComponent : struct, IEcsComponent
{
return self.ExcludePool<EcsPool<TComponent>>();
}
[Obsolete("Use " + nameof(EcsAspect) + "." + nameof(EcsAspect.Builder) + "." + nameof(Opt) + "<T>()")]
[EditorBrowsable(EditorBrowsableState.Never)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static EcsPool<TComponent> Optional<TComponent>(this EcsAspect.Builder self) where TComponent : struct, IEcsComponent
{
return self.OptionalPool<EcsPool<TComponent>>();
}
#endregion
}
}
}

View File

@ -62,7 +62,12 @@ namespace DCFApixels.DragonECS.PoolsCore
[MethodImpl(MethodImplOptions.NoInlining)]
public static void ThrowNullListener()
{
throw new ArgumentNullException("listener is null");
throw new ArgumentNullException("Listener is null");
}
[MethodImpl(MethodImplOptions.NoInlining)]
public static void ThrowNullComponent()
{
throw new ArgumentNullException("Component is null");
}
[MethodImpl(MethodImplOptions.NoInlining)]
public static void ThrowPoolLocked()
@ -291,67 +296,11 @@ namespace DCFApixels.DragonECS
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void InvokeOnAdd(this List<IEcsPoolEventListener> self, int entityID)
{
self.InvokeOnAdd(entityID, self.Count);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void InvokeOnAdd(this List<IEcsPoolEventListener> self, int entityID, int cachedCount)
{
for (int i = 0; i < cachedCount; i++) { self[i].OnAdd(entityID); }
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void InvokeOnAddAndGet(this List<IEcsPoolEventListener> self, int entityID)
{
self.InvokeOnAddAndGet(entityID, self.Count);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void InvokeOnAddAndGet(this List<IEcsPoolEventListener> self, int entityID, int cachedCount)
{
for (int i = 0; i < cachedCount; i++)
{
self[i].OnAdd(entityID);
self[i].OnGet(entityID);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void InvokeOnGet(this List<IEcsPoolEventListener> self, int entityID)
{
self.InvokeOnGet(entityID, self.Count);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void InvokeOnGet(this List<IEcsPoolEventListener> self, int entityID, int cachedCount)
{
for (int i = 1; i < cachedCount; i++) { self[i].OnGet(entityID); }
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void InvokeOnDel(this List<IEcsPoolEventListener> self, int entityID)
{
self.InvokeOnDel(entityID, self.Count);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void InvokeOnDel(this List<IEcsPoolEventListener> self, int entityID, int cachedCount)
{
for (int i = 0; i < cachedCount; i++) { self[i].OnDel(entityID); }
}
//
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void InvokeOnAdd(ref this StructList<IEcsPoolEventListener> self, int entityID)
{
for (int i = 0; i < self.Count; i++) { self[i].OnAdd(entityID); }
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void InvokeOnAdd(ref this StructList<IEcsPoolEventListener> self, int entityID, int cachedCount)
{
for (int i = 0; i < cachedCount; i++) { self[i].OnAdd(entityID); }
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void InvokeOnAddAndGet(ref this StructList<IEcsPoolEventListener> self, int entityID)
public static void InvokeOnAddAndGet(this List<IEcsPoolEventListener> self, int entityID)
{
for (int i = 0; i < self.Count; i++)
{
@ -360,34 +309,43 @@ namespace DCFApixels.DragonECS
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void InvokeOnAddAndGet(ref this StructList<IEcsPoolEventListener> self, int entityID, int cachedCount)
public static void InvokeOnGet(this List<IEcsPoolEventListener> self, int entityID)
{
for (int i = 0; i < cachedCount; i++)
for (int i = 1; i < self.Count; i++) { self[i].OnGet(entityID); }
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void InvokeOnDel(this List<IEcsPoolEventListener> self, int entityID)
{
for (int i = 0; i < self.Count; i++) { self[i].OnDel(entityID); }
}
//
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void InvokeOnAdd(this StructList<IEcsPoolEventListener> self, int entityID)
{
for (int i = 0; i < self.Count; i++) { self[i].OnAdd(entityID); }
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void InvokeOnAddAndGet(this StructList<IEcsPoolEventListener> self, int entityID)
{
for (int i = 0; i < self.Count; i++)
{
self[i].OnAdd(entityID);
self[i].OnGet(entityID);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void InvokeOnGet(ref this StructList<IEcsPoolEventListener> self, int entityID)
internal static void InvokeOnGet(this StructList<IEcsPoolEventListener> self, int entityID)
{
for (int i = 1; i < self.Count; i++) { self[i].OnGet(entityID); }
for (int i = 0; i < self.Count; i++) { self[i].OnGet(entityID); }
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void InvokeOnGet(ref this StructList<IEcsPoolEventListener> self, int entityID, int cachedCount)
{
for (int i = 1; i < cachedCount; i++) { self[i].OnGet(entityID); }
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void InvokeOnDel(ref this StructList<IEcsPoolEventListener> self, int entityID)
internal static void InvokeOnDel(this StructList<IEcsPoolEventListener> self, int entityID)
{
for (int i = 0; i < self.Count; i++) { self[i].OnDel(entityID); }
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void InvokeOnDel(ref this StructList<IEcsPoolEventListener> self, int entityID, int cachedCount)
{
for (int i = 0; i < cachedCount; i++) { self[i].OnDel(entityID); }
}
}
#endif
#endregion

View File

@ -35,7 +35,7 @@ namespace DCFApixels.DragonECS
public sealed class EcsTagPool<T> : IEcsPoolImplementation<T>, IEcsStructPool<T>, IEnumerable<T> //IEnumerable<T> - IntelliSense hack
where T : struct, IEcsTagComponent
{
private EcsWorld _source;
private EcsWorld _world;
private int _componentTypeID;
private EcsMaskChunck _maskBit;
@ -44,7 +44,7 @@ namespace DCFApixels.DragonECS
#if !DRAGONECS_DISABLE_POOLS_EVENTS
private StructList<IEcsPoolEventListener> _listeners = new StructList<IEcsPoolEventListener>(2);
private int _listenersCachedCount = 0;
private bool _hasAnyListener = false;
#endif
private bool _isLocked;
@ -78,7 +78,7 @@ namespace DCFApixels.DragonECS
}
public EcsWorld World
{
get { return _source; }
get { return _world; }
}
public bool IsReadOnly
{
@ -102,7 +102,7 @@ namespace DCFApixels.DragonECS
}
void IEcsPoolImplementation.OnInit(EcsWorld world, EcsWorld.PoolsMediator mediator, int componentTypeID)
{
_source = world;
_world = world;
_mediator = mediator;
_componentTypeID = componentTypeID;
_maskBit = EcsMaskChunck.FromID(componentTypeID);
@ -116,17 +116,18 @@ namespace DCFApixels.DragonECS
public void Add(int entityID)
{
#if DEBUG
if (_source.IsUsed(entityID) == false) { EcsPoolThrowHelper.ThrowEntityIsNotAlive(_source, entityID); }
if (entityID == EcsConsts.NULL_ENTITY_ID) { EcsPoolThrowHelper.ThrowEntityIsNotAlive(_world, entityID); }
if (_world.IsUsed(entityID) == false) { EcsPoolThrowHelper.ThrowEntityIsNotAlive(_world, entityID); }
if (Has(entityID)) { EcsPoolThrowHelper.ThrowAlreadyHasComponent<T>(entityID); }
if (_isLocked) { EcsPoolThrowHelper.ThrowPoolLocked(); }
#elif DRAGONECS_STABILITY_MODE
if (Has(entityID) | _source.IsUsed(entityID) == false | _isLocked) { return; }
if (Has(entityID) | _world.IsUsed(entityID) == false | _isLocked) { return; }
#endif
_count++;
_mapping[entityID] = true;
_mediator.RegisterComponent(entityID, _componentTypeID, _maskBit);
#if !DRAGONECS_DISABLE_POOLS_EVENTS
_listeners.InvokeOnAdd(entityID, _listenersCachedCount);
if (_hasAnyListener) { _listeners.InvokeOnAdd(entityID); }
#endif
}
public void TryAdd(int entityID)
@ -144,6 +145,7 @@ namespace DCFApixels.DragonECS
public void Del(int entityID)
{
#if DEBUG
if (entityID == EcsConsts.NULL_ENTITY_ID) { EcsPoolThrowHelper.ThrowEntityIsNotAlive(_world, entityID); }
if (!Has(entityID)) { EcsPoolThrowHelper.ThrowNotHaveComponent<T>(entityID); }
if (_isLocked) { EcsPoolThrowHelper.ThrowPoolLocked(); }
#elif DRAGONECS_STABILITY_MODE
@ -153,7 +155,7 @@ namespace DCFApixels.DragonECS
_count--;
_mediator.UnregisterComponent(entityID, _componentTypeID, _maskBit);
#if !DRAGONECS_DISABLE_POOLS_EVENTS
_listeners.InvokeOnDel(entityID, _listenersCachedCount);
if (_hasAnyListener) { _listeners.InvokeOnDel(entityID); }
#endif
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@ -216,14 +218,14 @@ namespace DCFApixels.DragonECS
if (_isLocked) { return; }
#endif
if (_count <= 0) { return; }
var span = _source.Where(out SingleTagAspect<T> _);
var span = _world.Where(out SingleTagAspect<T> _);
_count = 0;
foreach (var entityID in span)
{
_mapping[entityID] = false;
_mediator.UnregisterComponent(entityID, _componentTypeID, _maskBit);
#if !DRAGONECS_DISABLE_POOLS_EVENTS
_listeners.InvokeOnDel(entityID, _listenersCachedCount);
if (_hasAnyListener) { _listeners.InvokeOnDel(entityID); }
#endif
}
}
@ -293,14 +295,14 @@ namespace DCFApixels.DragonECS
{
if (listener == null) { EcsPoolThrowHelper.ThrowNullListener(); }
_listeners.Add(listener);
_listenersCachedCount++;
_hasAnyListener = _listeners.Count > 0;
}
public void RemoveListener(IEcsPoolEventListener listener)
{
if (listener == null) { EcsPoolThrowHelper.ThrowNullListener(); }
if (_listeners.RemoveWithOrder(listener))
{
_listenersCachedCount--;
_hasAnyListener = _listeners.Count > 0;
}
}
#endif
@ -407,7 +409,6 @@ namespace DCFApixels.DragonECS
public static implicit operator ReadonlyEcsTagPool<T>(EcsWorld.GetPoolInstanceMarker a) { return a.GetInstance<EcsTagPool<T>>(); }
#endregion
}
public static class EcsTagPoolExtensions
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@ -441,68 +442,5 @@ namespace DCFApixels.DragonECS
{
return self.OptionalPool<EcsTagPool<TTagComponent>>();
}
#region Obsolete
[Obsolete("Use " + nameof(EcsAspect) + "." + nameof(EcsAspect.Builder) + "." + nameof(Inc) + "<T>()")]
[EditorBrowsable(EditorBrowsableState.Never)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static EcsTagPool<TTagComponent> Include<TTagComponent>(this EcsAspect.Builder self) where TTagComponent : struct, IEcsTagComponent
{
return self.IncludePool<EcsTagPool<TTagComponent>>();
}
[Obsolete("Use " + nameof(EcsAspect) + "." + nameof(EcsAspect.Builder) + "." + nameof(Exc) + "<T>()")]
[EditorBrowsable(EditorBrowsableState.Never)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static EcsTagPool<TTagComponent> Exclude<TTagComponent>(this EcsAspect.Builder self) where TTagComponent : struct, IEcsTagComponent
{
return self.ExcludePool<EcsTagPool<TTagComponent>>();
}
[Obsolete("Use " + nameof(EcsAspect) + "." + nameof(EcsAspect.Builder) + "." + nameof(Opt) + "<T>()")]
[EditorBrowsable(EditorBrowsableState.Never)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static EcsTagPool<TTagComponent> Optional<TTagComponent>(this EcsAspect.Builder self) where TTagComponent : struct, IEcsTagComponent
{
return self.OptionalPool<EcsTagPool<TTagComponent>>();
}
//---------------------------------------------------
[Obsolete("Use " + nameof(EcsWorld) + "." + nameof(GetPool) + "<T>()")]
[EditorBrowsable(EditorBrowsableState.Never)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static EcsTagPool<TTagComponent> GetTagPool<TTagComponent>(this EcsWorld self) where TTagComponent : struct, IEcsTagComponent
{
return self.GetPoolInstance<EcsTagPool<TTagComponent>>();
}
[Obsolete("Use " + nameof(EcsWorld) + "." + nameof(GetPoolUnchecked) + "<T>()")]
[EditorBrowsable(EditorBrowsableState.Never)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static EcsTagPool<TTagComponent> GetTagPoolUnchecked<TTagComponent>(this EcsWorld self) where TTagComponent : struct, IEcsTagComponent
{
return self.GetPoolInstanceUnchecked<EcsTagPool<TTagComponent>>();
}
[Obsolete("Use " + nameof(EcsAspect) + "." + nameof(EcsAspect.Builder) + "." + nameof(Inc) + "<T>()")]
[EditorBrowsable(EditorBrowsableState.Never)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static EcsTagPool<TTagComponent> IncludeTag<TTagComponent>(this EcsAspect.Builder self) where TTagComponent : struct, IEcsTagComponent
{
return self.IncludePool<EcsTagPool<TTagComponent>>();
}
[Obsolete("Use " + nameof(EcsAspect) + "." + nameof(EcsAspect.Builder) + "." + nameof(Exc) + "<T>()")]
[EditorBrowsable(EditorBrowsableState.Never)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static EcsTagPool<TTagComponent> ExcludeTag<TTagComponent>(this EcsAspect.Builder self) where TTagComponent : struct, IEcsTagComponent
{
return self.ExcludePool<EcsTagPool<TTagComponent>>();
}
[Obsolete("Use " + nameof(EcsAspect) + "." + nameof(EcsAspect.Builder) + "." + nameof(Opt) + "<T>()")]
[EditorBrowsable(EditorBrowsableState.Never)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static EcsTagPool<TTagComponent> OptionalTag<TTagComponent>(this EcsAspect.Builder self) where TTagComponent : struct, IEcsTagComponent
{
return self.OptionalPool<EcsTagPool<TTagComponent>>();
}
#endregion
}
}
}

View File

@ -37,7 +37,7 @@ namespace DCFApixels.DragonECS
return;
}
}
throw new InvalidOperationException($"Using component {componentType.ToMeta().TypeName} is not allowed in the {worldType.ToMeta().TypeName} world.");
throw new InvalidOperationException($"Using component {componentType.GetMeta().TypeName} is not allowed in the {worldType.GetMeta().TypeName} world.");
}
}
}

View File

@ -139,12 +139,12 @@ namespace DCFApixels.DragonECS.Core.Internal
[MethodImpl(MethodImplOptions.NoInlining)]
internal static void Quiery_ArgumentDifferentWorldsException()
{
throw new ArgumentException("The groups belong to different worlds.");
ArgumentDifferentWorldsException();
}
[MethodImpl(MethodImplOptions.NoInlining)]
internal static void ArgumentDifferentWorldsException()
{
throw new ArgumentException("The groups belong to different worlds.");
throw new ArgumentException("World ID mismatch: the expected and actual world identifiers do not match.");
}
[MethodImpl(MethodImplOptions.NoInlining)]

View File

@ -252,74 +252,5 @@ namespace DCFApixels.DragonECS.Core
return _graph.Sort();
}
#endregion
#region Obsolete
[Obsolete("Use " + nameof(LayersMap) + ".Add(layer).Before(targetLayer).Back;")]
public EcsPipeline.Builder Insert(string targetLayer, string newLayer)
{
Add(newLayer).Before(targetLayer);
return _pipelineBuilder;
}
[Obsolete("Use " + nameof(LayersMap) + ".Add(layer).After(targetLayer).Back;")]
public EcsPipeline.Builder InsertAfter(string targetLayer, string newLayer)
{
Add(newLayer).After(targetLayer);
return _pipelineBuilder;
}
[Obsolete("Use " + nameof(LayersMap) + ".Move(layer).Before(targetLayer).Back;")]
public EcsPipeline.Builder Move(string targetLayer, string newLayer)
{
Move(newLayer).Before(targetLayer);
return _pipelineBuilder;
}
[Obsolete("Use " + nameof(LayersMap) + ".Move(layer).After(targetLayer).Back;")]
public EcsPipeline.Builder MoveAfter(string targetLayer, string newLayer)
{
Move(newLayer).After(targetLayer);
return _pipelineBuilder;
}
[Obsolete("Use " + nameof(LayersMap) + ".Add(layers).Before(targetLayer).Back;")]
public EcsPipeline.Builder Insert(string targetLayer, params string[] newLayers)
{
Add(newLayers).Before(targetLayer);
return _pipelineBuilder;
}
[Obsolete("Use " + nameof(LayersMap) + ".Add(layers).After(targetLayer).Back;")]
public EcsPipeline.Builder InsertAfter(string targetLayer, params string[] newLayers)
{
Add(newLayers).After(targetLayer);
return _pipelineBuilder;
}
[Obsolete("Use " + nameof(LayersMap) + ".Move(layers).Before(targetLayer).Back;")]
public EcsPipeline.Builder Move(string targetLayer, params string[] movingLayers)
{
Move(movingLayers).Before(targetLayer);
return _pipelineBuilder;
}
[Obsolete("Use " + nameof(LayersMap) + ".Move(layers).After(targetLayer).Back;")]
public EcsPipeline.Builder MoveAfter(string targetLayer, params string[] movingLayers)
{
Move(movingLayers).After(targetLayer);
return _pipelineBuilder;
}
[Obsolete]
public object this[int index]
{
get
{
int i = 0;
foreach (var item in this)
{
if (i == index)
{
return item;
}
i++;
}
return null;
}
}
#endregion
}
}

View File

@ -1,202 +0,0 @@
#if ENABLE_DUMMY_SPAN
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using EditorBrowsableAttribute = System.ComponentModel.EditorBrowsableAttribute;
using EditorBrowsableState = System.ComponentModel.EditorBrowsableState;
namespace DCFApixels.DragonECS
{
internal static class ThrowHelper
{
public static void ThrowIndexOutOfRangeException() => throw new IndexOutOfRangeException();
public static void ThrowArgumentOutOfRangeException() => throw new ArgumentOutOfRangeException();
public static void ThrowInvalidOperationException() => throw new InvalidOperationException();
}
[DebuggerDisplay("{ToString(),raw}")]
public readonly ref struct ReadOnlySpan<T>
{
public static ReadOnlySpan<T> Empty => new ReadOnlySpan<T>(null);
internal readonly T[] _array;
private readonly int _start;
private readonly int _length;
#region Properties
public int Length => _length;
public bool IsEmpty => _length == 0;
public ref readonly T this[int index]
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
if ((uint)index >= (uint)_length || (uint)index < 0)
ThrowHelper.ThrowIndexOutOfRangeException();
return ref _array[index + _start];
}
}
#endregion
#region Constructors
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ReadOnlySpan(T[] array)
{
_array = array ?? Array.Empty<T>();
_start = 0;
_length = array.Length;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ReadOnlySpan(T[] array, int start, int length)
{
if (array == null)
{
if (start != 0 || length != 0)
ThrowHelper.ThrowArgumentOutOfRangeException();
_array = Array.Empty<T>();
_start = 0;
_length = 0;
return;
}
if ((uint)start > (uint)array.Length || (uint)length > (uint)(array.Length - start))
ThrowHelper.ThrowArgumentOutOfRangeException();
_array = array;
_start = start;
_length = length;
}
#endregion
#region Object
#pragma warning disable CS0809 // Óñòàðåâøèé ÷ëåí ïåðåîïðåäåëÿåò íåóñòàðåâøèé ÷ëåí
[Obsolete("Equals() on ReadOnlySpan 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 ReadOnlySpan will always throw an exception.")]
[EditorBrowsable(EditorBrowsableState.Never)]
public override int GetHashCode() => throw new NotSupportedException();
#pragma warning restore CS0809 // Óñòàðåâøèé ÷ëåí ïåðåîïðåäåëÿåò íåóñòàðåâøèé ÷ëåí
public override string ToString()
{
//if (typeof(T) == typeof(char))
// return new string(new ReadOnlySpan<char>(ref Unsafe.As<T, char>(ref _reference), _length));
return $"System.ReadOnlySpan<{typeof(T).Name}>[{_length}]";
}
#endregion
#region operators
public static bool operator !=(ReadOnlySpan<T> left, ReadOnlySpan<T> right) => !(left == right);
public static implicit operator ReadOnlySpan<T>(T[] array) => new ReadOnlySpan<T>(array);
public static implicit operator ReadOnlySpan<T>(ArraySegment<T> segment) => new ReadOnlySpan<T>(segment.Array, segment.Offset, segment.Count);
public static bool operator ==(ReadOnlySpan<T> left, ReadOnlySpan<T> right) => left._length == right._length && left._array == right._array;
#endregion
#region Enumerator
public Enumerator GetEnumerator() => new Enumerator(this);
public ref struct Enumerator
{
private readonly ReadOnlySpan<T> _span;
private int _index;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal Enumerator(ReadOnlySpan<T> span)
{
_span = span;
_index = span._start - 1;
}
public ref readonly T Current
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => ref _span[_index];
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool MoveNext()
{
int index = _index + 1;
if (index < _span.Length)
{
_index = index;
return true;
}
return false;
}
}
#endregion
#region Other
[EditorBrowsable(EditorBrowsableState.Never)]
public ref readonly T GetPinnableReference()
{
if (_length != 0) ThrowHelper.ThrowInvalidOperationException();
return ref _array[0];
}
//[MethodImpl(MethodImplOptions.AggressiveInlining)]
//public void CopyTo(Span<T> destination)
//{
// if ((uint)_length <= (uint)destination.Length)
// {
// Buffer.Memmove(ref destination._reference, ref _reference, (uint)_length);
// }
// else
// {
// ThrowHelper.ThrowArgumentException_DestinationTooShort();
// }
//}
//public bool TryCopyTo(Span<T> destination)
//{
// bool retVal = false;
// if ((uint)_length <= (uint)destination.Length)
// {
// Buffer.Memmove(ref destination._reference, ref _reference, (uint)_length);
// retVal = true;
// }
// return retVal;
//}
public void CopyTo(T[] array)
{
if (_length > array.Length)
{
throw new ArgumentOutOfRangeException();
}
for (int i = 0; i < _length; i++)
{
array[i] = _array[i];
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ReadOnlySpan<T> Slice(int start)
{
if ((uint)start > (uint)_length)
ThrowHelper.ThrowArgumentOutOfRangeException();
return new ReadOnlySpan<T>(_array, _start + start, _length - start);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ReadOnlySpan<T> Slice(int start, int length)
{
if ((uint)start > (uint)_length || (uint)length > (uint)(_length - start))
ThrowHelper.ThrowArgumentOutOfRangeException();
return new ReadOnlySpan<T>(_array, _start + start, length);
}
public T[] ToArray()
{
if (_length == 0)
return Array.Empty<T>();
var result = new T[_length];
Array.Copy(_array, _start, result, 0, _length);
return result;
}
#endregion
}
}
#endif

View File

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: bfb00ad58c175a84388c316daf9b03ae
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -5,73 +5,6 @@ using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
namespace DCFApixels.DragonECS.UncheckedCore
{
[Obsolete("Use DCFApixels.DragonECS.Core.UncheckedUtility")]
public static class UncheckedCoreUtility
{
#region CreateEntLong
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static entlong CreateEntLong(int entityID, short gen, short worldID)
{
return new entlong(entityID, gen, worldID);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static entlong CreateEntLong(long entityGenWorld)
{
return new entlong(entityGenWorld);
}
#endregion
#region CreateSpan
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static EcsSpan CreateSpan(short worldID, ReadOnlySpan<int> entitesArray)
{
return new EcsSpan(worldID, entitesArray);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static EcsSpan CreateSpan(short worldID, int[] entitesArray, int startIndex, int length)
{
return new EcsSpan(worldID, entitesArray, startIndex, length);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static EcsSpan CreateSpan(short worldID, int[] entitesArray, int length)
{
return new EcsSpan(worldID, entitesArray, length);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static EcsSpan CreateSpan(short worldID, int[] entitesArray)
{
return new EcsSpan(worldID, entitesArray);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static EcsSpan CreateEmptySpan(short worldID)
{
return new EcsSpan(worldID, Array.Empty<int>());
}
public static bool CheckSpanValideDebug(EcsSpan span)
{
HashSet<int> set = new HashSet<int>();
foreach (var e in span)
{
if (set.Add(e) == false)
{
return false;
}
}
return true;
}
#endregion
#region EcsGroup
public static EcsGroup GetSourceInstance(EcsReadonlyGroup group)
{
return group.GetSource_Internal();
}
#endregion
}
}
namespace DCFApixels.DragonECS.Core.Unchecked
{
public static class UncheckedUtility
@ -129,6 +62,14 @@ namespace DCFApixels.DragonECS.Core.Unchecked
}
#endregion
#region Unsafe Span
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe EcsUnsafeSpan CreateUnsafeSpan(short worldID, int* ptr, int length)
{
return new EcsUnsafeSpan(worldID, ptr, length);
}
#endregion
#region EcsGroup
public static EcsGroup GetSourceInstance(EcsReadonlyGroup group)
{

View File

@ -116,6 +116,48 @@ namespace DCFApixels.DragonECS
#endregion
#region Constructors
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public entlong(EcsWorld world, int id) : this()
{
if (world == null)
{
_id = 0;
_gen = 0;
_world = 0;
}
else
{
_id = id;
_gen = world.GetGen(id);
_world = world.ID;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public entlong(int id, EcsWorld world) : this(world, id) { }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public entlong(EcsWorld world, entlong entity) : this()
{
#if DEBUG
if (world.ID != entity.WorldID) { Throw.ArgumentDifferentWorldsException(); }
#elif DRAGONECS_STABILITY_MODE
if (world.ID != entity.WorldID) { world = null; }
#endif
if (world == null)
{
_id = 0;
_gen = 0;
_world = 0;
}
else
{
_id = entity._id;
_gen = entity._gen;
_world = entity._world;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public entlong(entlong entity, EcsWorld world) : this(world, entity) { }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public entlong(int id, short gen, short world) : this()
{
@ -128,12 +170,6 @@ namespace DCFApixels.DragonECS
{
_full = full;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static unsafe entlong NewUnsafe(long id, long gen, long world)
{
long x = id << 48 | gen << 32 | id;
return *(entlong*)&x;
}
#endregion
#region Unpacking Try
@ -155,6 +191,13 @@ namespace DCFApixels.DragonECS
worldID = _world;
return IsAlive;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryGetGen(out short gen)
{
gen = _gen;
return IsAlive;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryUnpack(out int id)
@ -192,17 +235,24 @@ namespace DCFApixels.DragonECS
id = _id;
return IsAlive;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryUnpack(EcsWorld world)
{
if (world.ID != _world) { return false; }
return world.IsAlive(_id, _gen);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryUnpack(EcsWorld world, out int id)
{
if (world.ID != _world) { Throw.ArgumentDifferentWorldsException(); }
if (world.ID != _world) { id = EcsConsts.NULL_ENTITY_ID; return false; }
id = _id;
return world.IsAlive(_id, _gen);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryUnpack(EcsWorld world, out int id, out short gen)
{
if (world.ID != _world) { Throw.ArgumentDifferentWorldsException(); }
if (world.ID != _world) { gen = 0; id = EcsConsts.NULL_ENTITY_ID; return false; }
gen = _gen;
id = _id;
return world.IsAlive(_id, _gen);
@ -210,14 +260,14 @@ namespace DCFApixels.DragonECS
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryUnpack(EcsMask mask, out int id)
{
if (mask.WorldID != _world) { Throw.ArgumentDifferentWorldsException(); }
if (mask.WorldID != _world) { id = EcsConsts.NULL_ENTITY_ID; return false; }
id = _id;
return mask.World.IsAlive(_id, _gen) && mask.World.IsMatchesMask(mask, _id);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryUnpack(EcsMask mask, out int id, out short gen)
{
if (mask.WorldID != _world) { Throw.ArgumentDifferentWorldsException(); }
if (mask.WorldID != _world) { gen = 0; id = EcsConsts.NULL_ENTITY_ID; return false; }
gen = _gen;
id = _id;
return mask.World.IsAlive(_id, _gen) && mask.World.IsMatchesMask(mask, _id);
@ -225,14 +275,14 @@ namespace DCFApixels.DragonECS
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryUnpack(EcsAspect aspect, out int id)
{
if (aspect.World.ID != _world) { Throw.ArgumentDifferentWorldsException(); }
if (aspect.World.ID != _world) { id = EcsConsts.NULL_ENTITY_ID; return false; }
id = _id;
return aspect.World.IsAlive(_id, _gen) && aspect.IsMatches(_id);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool TryUnpack(EcsAspect aspect, out int id, out short gen)
{
if (aspect.World.ID != _world) { Throw.ArgumentDifferentWorldsException(); }
if (aspect.World.ID != _world) { gen = 0; id = EcsConsts.NULL_ENTITY_ID; return false; }
gen = _gen;
id = _id;
return aspect.World.IsAlive(_id, _gen) && aspect.IsMatches(_id);
@ -323,9 +373,39 @@ namespace DCFApixels.DragonECS
id = _id;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Deconstruct(out int id, out short gen, out short worldID) { Unpack(out id, out gen, out worldID); }
public void Deconstruct(out int id, out short gen, out short worldID)
{
#if DEBUG
if (IsAlive == false) { Throw.Ent_ThrowIsNotAlive(this); }
#elif DRAGONECS_STABILITY_MODE
if (IsAlive == false)
{
worldID = EcsConsts.NULL_WORLD_ID;
gen = default;
id = EcsConsts.NULL_ENTITY_ID;
return;
}
#endif
worldID = _world;
gen = _gen;
id = _id;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Deconstruct(out int id, out EcsWorld world) { Unpack(out id, out world); }
public void Deconstruct(out int id, out EcsWorld world)
{
#if DEBUG
if (IsAlive == false) { Throw.Ent_ThrowIsNotAlive(this); }
#elif DRAGONECS_STABILITY_MODE
if (IsAlive == false)
{
world = EcsWorld.GetWorld(EcsConsts.NULL_WORLD_ID);
id = EcsConsts.NULL_ENTITY_ID;
return;
}
#endif
world = EcsWorld.GetWorld(_world);
id = _id;
}
#endregion
#region Unpacking Unchecked
@ -384,16 +464,10 @@ namespace DCFApixels.DragonECS
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator entlong((EcsWorld world, int entityID) a) { return Combine_Internal(a.entityID, a.world); }
//[MethodImpl(MethodImplOptions.AggressiveInlining)]
//public static implicit operator entlong((entlong entity, EcsWorld world) a) { return Combine_Internal(a.entity._id, a.world); }
//[MethodImpl(MethodImplOptions.AggressiveInlining)]
//public static implicit operator entlong((EcsWorld world, entlong entity) a) { return Combine_Internal(a.entity._id, a.world); }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static entlong Combine_Internal(int entityID, EcsWorld world)
{
return world == null ? new entlong(entityID, 0, 0) : world.GetEntityLong(entityID);
}
public static implicit operator entlong((entlong entity, EcsWorld world) a) { return Combine_Internal(a.entity, a.world); }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static implicit operator entlong((EcsWorld world, entlong entity) a) { return Combine_Internal(a.entity, a.world); }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static explicit operator long(entlong a) { return a._full; }
@ -405,6 +479,21 @@ namespace DCFApixels.DragonECS
#region Other
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static entlong Combine_Internal(int entityID, EcsWorld world)
{
return world == null ? new entlong(entityID, 0, 0) : world.GetEntityLong(entityID);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static entlong Combine_Internal(entlong entity, EcsWorld world)
{
#if DEBUG
if (world.ID != entity.WorldID) { Throw.ArgumentDifferentWorldsException(); }
#elif DRAGONECS_STABILITY_MODE
if (world.ID != entity.WorldID) { return default; }
#endif
return entity;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private EcsWorld GetWorld_Internal()
{
#if DRAGONECS_STABILITY_MODE
@ -412,6 +501,7 @@ namespace DCFApixels.DragonECS
#endif
return EcsWorld.GetWorld(_world);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override int GetHashCode() { return unchecked((int)_full) ^ (int)(_full >> 32); }
[MethodImpl(MethodImplOptions.AggressiveInlining)]