mirror of
https://github.com/DCFApixels/DragonECS.git
synced 2026-04-22 01:45:55 +08:00
Merge branch 'dev' into unsafe_pool
This commit is contained in:
commit
015c6be9f0
25
README-RU.md
25
README-RU.md
@ -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>
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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
|
||||
{
|
||||
|
||||
@ -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 { };
|
||||
|
||||
169
src/EcsMask.cs
169
src/EcsMask.cs
@ -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)]
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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(); }
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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)]
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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
631
src/Internal/SortHalper.cs
Normal 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);
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a591de1858028504d819333121bfddd6
|
||||
guid: 7e60048b7c58cdf4ba044b7c832bd6a4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
@ -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)]
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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)]
|
||||
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bfb00ad58c175a84388c316daf9b03ae
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -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)
|
||||
{
|
||||
|
||||
136
src/entlong.cs
136
src/entlong.cs
@ -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)]
|
||||
|
||||
Loading…
Reference in New Issue
Block a user