mirror of
https://github.com/DCFApixels/DragonECS.git
synced 2025-11-13 00:55:55 +08:00
Merge branch 'new_dev'
This commit is contained in:
commit
0958a55495
@ -8,7 +8,7 @@
|
|||||||
"displayName": "DragonECS",
|
"displayName": "DragonECS",
|
||||||
"description": "C# Entity Component System Framework",
|
"description": "C# Entity Component System Framework",
|
||||||
"unity": "2020.3",
|
"unity": "2020.3",
|
||||||
"version": "0.8.3",
|
"version": "0.8.5",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/DCFApixels/DragonECS.git"
|
"url": "https://github.com/DCFApixels/DragonECS.git"
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
using DCFApixels.DragonECS.Internal;
|
using DCFApixels.DragonECS.Internal;
|
||||||
|
using DCFApixels.DragonECS.Utils;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
@ -12,7 +14,7 @@ namespace DCFApixels.DragonECS
|
|||||||
//_dense заполняется с индекса 1
|
//_dense заполняется с индекса 1
|
||||||
//в операциях изменяющих состояние группы нельзя итерироваться по this, либо осторожно учитывать этот момент
|
//в операциях изменяющих состояние группы нельзя итерироваться по this, либо осторожно учитывать этот момент
|
||||||
[StructLayout(LayoutKind.Sequential, Pack = 0, Size = 8)]
|
[StructLayout(LayoutKind.Sequential, Pack = 0, Size = 8)]
|
||||||
[DebuggerTypeProxy(typeof(DebuggerProxy))]
|
[DebuggerTypeProxy(typeof(EcsGroup.DebuggerProxy))]
|
||||||
public readonly ref struct EcsReadonlyGroup
|
public readonly ref struct EcsReadonlyGroup
|
||||||
{
|
{
|
||||||
private readonly EcsGroup _source;
|
private readonly EcsGroup _source;
|
||||||
@ -111,10 +113,6 @@ namespace DCFApixels.DragonECS
|
|||||||
public bool IsSupersetOf(EcsGroup group) => _source.IsSupersetOf(group);
|
public bool IsSupersetOf(EcsGroup group) => _source.IsSupersetOf(group);
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Object
|
|
||||||
public override string ToString() => _source != null ? _source.ToString() : "NULL";
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Internal
|
#region Internal
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
internal EcsGroup GetGroupInternal() => _source;
|
internal EcsGroup GetGroupInternal() => _source;
|
||||||
@ -122,12 +120,25 @@ namespace DCFApixels.DragonECS
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Other
|
#region Other
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return _source != null ? _source.ToString() : "NULL";
|
||||||
|
}
|
||||||
|
#pragma warning disable CS0809 // Устаревший член переопределяет неустаревший член
|
||||||
|
[Obsolete("Equals() on EcsGroup 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 EcsGroup will always throw an exception.")]
|
||||||
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||||
|
public override int GetHashCode() => throw new NotSupportedException();
|
||||||
|
#pragma warning restore CS0809 // Устаревший член переопределяет неустаревший член
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static implicit operator EcsSpan(EcsReadonlyGroup a) => a.ToSpan();
|
public static implicit operator EcsSpan(EcsReadonlyGroup a) => a.ToSpan();
|
||||||
internal class DebuggerProxy : EcsGroup.DebuggerProxy
|
//internal class DebuggerProxy : EcsGroup.DebuggerProxy
|
||||||
{
|
//{
|
||||||
public DebuggerProxy(EcsReadonlyGroup group) : base(group._source) { }
|
// public DebuggerProxy(EcsReadonlyGroup group) : base(group._source) { }
|
||||||
}
|
//}
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -503,7 +514,7 @@ namespace DCFApixels.DragonECS
|
|||||||
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
|
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
|
||||||
if (_source != group.World) Throw.Group_ArgumentDifferentWorldsException();
|
if (_source != group.World) Throw.Group_ArgumentDifferentWorldsException();
|
||||||
#endif
|
#endif
|
||||||
if(group.Count > Count)
|
if (group.Count > Count)
|
||||||
{
|
{
|
||||||
foreach (var item in this)
|
foreach (var item in this)
|
||||||
if (group.Has(item))
|
if (group.Has(item))
|
||||||
@ -710,7 +721,8 @@ namespace DCFApixels.DragonECS
|
|||||||
#region Other
|
#region Other
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return $"group{{{string.Join(", ", _dense.Skip(1).Take(_count).OrderBy(o => o))}}}";
|
return CollectionUtility.EntitiesToString(_dense.Skip(1).Take(_count), "group");
|
||||||
|
//return $"group({_count}) {{{string.Join(", ", _dense.Skip(1).Take(_count).OrderBy(o => o))}}}";
|
||||||
}
|
}
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public int First()
|
public int First()
|
||||||
@ -752,6 +764,7 @@ namespace DCFApixels.DragonECS
|
|||||||
public int CapacitySparce => _group.CapacitySparce;
|
public int CapacitySparce => _group.CapacitySparce;
|
||||||
public override string ToString() => _group.ToString();
|
public override string ToString() => _group.ToString();
|
||||||
public DebuggerProxy(EcsGroup group) => _group = group;
|
public DebuggerProxy(EcsGroup group) => _group = group;
|
||||||
|
public DebuggerProxy(EcsReadonlyGroup group) : this(group.GetGroupInternal()) { }
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,10 +1,13 @@
|
|||||||
using System;
|
using DCFApixels.DragonECS.Utils;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace DCFApixels.DragonECS
|
namespace DCFApixels.DragonECS
|
||||||
{
|
{
|
||||||
|
[DebuggerTypeProxy(typeof(DebuggerProxy))]
|
||||||
public readonly ref struct EcsSpan
|
public readonly ref struct EcsSpan
|
||||||
{
|
{
|
||||||
private readonly int _worldID;
|
private readonly int _worldID;
|
||||||
@ -34,7 +37,7 @@ namespace DCFApixels.DragonECS
|
|||||||
{
|
{
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
get => _values.IsEmpty;
|
get => _values.IsEmpty;
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Constructors
|
#region Constructors
|
||||||
@ -91,18 +94,6 @@ namespace DCFApixels.DragonECS
|
|||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Object
|
|
||||||
#pragma warning disable CS0809 // Устаревший член переопределяет неустаревший член
|
|
||||||
[Obsolete("Equals() on EcsSpan will always throw an exception. Use the equality operator instead.")]
|
|
||||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
||||||
public override bool Equals(object obj) => throw new NotSupportedException();
|
|
||||||
[Obsolete("GetHashCode() on EcsSpan will always throw an exception.")]
|
|
||||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
|
||||||
public override int GetHashCode() => throw new NotSupportedException();
|
|
||||||
#pragma warning restore CS0809 // Устаревший член переопределяет неустаревший член
|
|
||||||
public override string ToString() => _values.ToString();
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region operators
|
#region operators
|
||||||
public static bool operator ==(EcsSpan left, EcsSpan right) => left._values == right._values;
|
public static bool operator ==(EcsSpan left, EcsSpan right) => left._values == right._values;
|
||||||
public static bool operator !=(EcsSpan left, EcsSpan right) => left._values != right._values;
|
public static bool operator !=(EcsSpan left, EcsSpan right) => left._values != right._values;
|
||||||
@ -120,6 +111,45 @@ namespace DCFApixels.DragonECS
|
|||||||
public EcsSpan Slice(int start, int length) => new EcsSpan(_worldID, _values.Slice(start, length));
|
public EcsSpan Slice(int start, int length) => new EcsSpan(_worldID, _values.Slice(start, length));
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public int[] ToArray() => _values.ToArray();
|
public int[] ToArray() => _values.ToArray();
|
||||||
|
|
||||||
|
#pragma warning disable CS0809 // Устаревший член переопределяет неустаревший член
|
||||||
|
[Obsolete("Equals() on EcsSpan will always throw an exception. Use the equality operator instead.")]
|
||||||
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||||
|
public override bool Equals(object obj) => throw new NotSupportedException();
|
||||||
|
[Obsolete("GetHashCode() on EcsSpan will always throw an exception.")]
|
||||||
|
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||||
|
public override int GetHashCode() => throw new NotSupportedException();
|
||||||
|
#pragma warning restore CS0809 // Устаревший член переопределяет неустаревший член
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return CollectionUtility.EntitiesToString(_values.ToArray(), "span");
|
||||||
|
//return $"span({_values.Length}) {{{string.Join(", ", _values.ToArray().OrderBy(o => o))}}}";
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class DebuggerProxy
|
||||||
|
{
|
||||||
|
private int[] _values;
|
||||||
|
private int _worldID;
|
||||||
|
public EcsWorld World => EcsWorld.GetWorld(_worldID);
|
||||||
|
public entlong[] Entities
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
entlong[] result = new entlong[_values.Length];
|
||||||
|
int i = 0;
|
||||||
|
foreach (var e in _values)
|
||||||
|
result[i++] = World.GetEntityLong(e);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public int Count => _values.Length;
|
||||||
|
public DebuggerProxy(EcsSpan span)
|
||||||
|
{
|
||||||
|
_values = new int[span.Length];
|
||||||
|
span._values.CopyTo(_values);
|
||||||
|
_worldID = span._worldID;
|
||||||
|
}
|
||||||
|
}
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,5 +17,7 @@
|
|||||||
public const string POST_END_LAYER = nameof(POST_END_LAYER);
|
public const string POST_END_LAYER = nameof(POST_END_LAYER);
|
||||||
|
|
||||||
public const string META_HIDDEN_TAG = "HiddenInDebagging";
|
public const string META_HIDDEN_TAG = "HiddenInDebagging";
|
||||||
|
|
||||||
|
public const int MAGIC_PRIME = 314159;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -37,7 +37,7 @@ namespace DCFApixels.DragonECS
|
|||||||
internal class WorldComponentHandler<T> : IEcsWorldComponent<T>
|
internal class WorldComponentHandler<T> : IEcsWorldComponent<T>
|
||||||
where T : IEcsWorldComponent<T>
|
where T : IEcsWorldComponent<T>
|
||||||
{
|
{
|
||||||
private T _fakeInstnace;
|
private T _fakeInstnace = default;
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public void Init(ref T component, EcsWorld world) => _fakeInstnace.Init(ref component, world);
|
public void Init(ref T component, EcsWorld world) => _fakeInstnace.Init(ref component, world);
|
||||||
public void OnDestroy(ref T component, EcsWorld world) => _fakeInstnace.OnDestroy(ref component, world);
|
public void OnDestroy(ref T component, EcsWorld world) => _fakeInstnace.OnDestroy(ref component, world);
|
||||||
@ -75,7 +75,7 @@ namespace DCFApixels.DragonECS
|
|||||||
internal sealed class ComponentResetHandler<T> : IEcsComponentReset<T>
|
internal sealed class ComponentResetHandler<T> : IEcsComponentReset<T>
|
||||||
where T : IEcsComponentReset<T>
|
where T : IEcsComponentReset<T>
|
||||||
{
|
{
|
||||||
private T _fakeInstnace;
|
private T _fakeInstnace = default;
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public void Reset(ref T component) => _fakeInstnace.Reset(ref component);
|
public void Reset(ref T component) => _fakeInstnace.Reset(ref component);
|
||||||
}
|
}
|
||||||
@ -112,7 +112,7 @@ namespace DCFApixels.DragonECS
|
|||||||
internal sealed class ComponentCopyHandler<T> : IEcsComponentCopy<T>
|
internal sealed class ComponentCopyHandler<T> : IEcsComponentCopy<T>
|
||||||
where T : IEcsComponentCopy<T>
|
where T : IEcsComponentCopy<T>
|
||||||
{
|
{
|
||||||
private T _fakeInstnace;
|
private T _fakeInstnace = default;
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public void Copy(ref T from, ref T to) => _fakeInstnace.Copy(ref from, ref to);
|
public void Copy(ref T from, ref T to) => _fakeInstnace.Copy(ref from, ref to);
|
||||||
}
|
}
|
||||||
|
|||||||
433
src/EcsAspect.cs
433
src/EcsAspect.cs
@ -1,27 +1,31 @@
|
|||||||
using DCFApixels.DragonECS.Internal;
|
using DCFApixels.DragonECS.Internal;
|
||||||
|
using DCFApixels.DragonECS.Utils;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace DCFApixels.DragonECS
|
namespace DCFApixels.DragonECS
|
||||||
{
|
{
|
||||||
public abstract class EcsAspect
|
public abstract class EcsAspect
|
||||||
{
|
{
|
||||||
internal EcsWorld source;
|
internal EcsWorld _source;
|
||||||
internal EcsMask mask;
|
internal EcsMask _mask;
|
||||||
private bool _isInit;
|
private bool _isInit;
|
||||||
|
|
||||||
|
internal UnsafeArray<int> _sortIncBuffer;
|
||||||
|
internal UnsafeArray<int> _sortExcBuffer;
|
||||||
|
internal UnsafeArray<EcsMaskChunck> _sortIncChunckBuffer;
|
||||||
|
internal UnsafeArray<EcsMaskChunck> _sortExcChunckBuffer;
|
||||||
|
|
||||||
#region Properties
|
#region Properties
|
||||||
public EcsMask Mask => mask;
|
public EcsMask Mask => _mask;
|
||||||
public EcsWorld World => source;
|
public EcsWorld World => _source;
|
||||||
public bool IsInit => _isInit;
|
public bool IsInit => _isInit;
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Methods
|
#region Methods
|
||||||
public bool IsMatches(int entityID) => source.IsMatchesMask(mask, entityID);
|
public bool IsMatches(int entityID) => _source.IsMatchesMask(_mask, entityID);
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Builder
|
#region Builder
|
||||||
@ -29,20 +33,16 @@ namespace DCFApixels.DragonECS
|
|||||||
public sealed class Builder : EcsAspectBuilderBase
|
public sealed class Builder : EcsAspectBuilderBase
|
||||||
{
|
{
|
||||||
private EcsWorld _world;
|
private EcsWorld _world;
|
||||||
private HashSet<int> _inc;
|
private EcsMask.Builder _maskBuilder;
|
||||||
private HashSet<int> _exc;
|
|
||||||
private List<Combined> _combined;
|
|
||||||
|
|
||||||
public EcsWorld World => _world;
|
public EcsWorld World => _world;
|
||||||
|
|
||||||
private Builder(EcsWorld world)
|
private Builder(EcsWorld world)
|
||||||
{
|
{
|
||||||
_world = world;
|
_world = world;
|
||||||
_combined = new List<Combined>();
|
_maskBuilder = new EcsMask.Builder(world);
|
||||||
_inc = new HashSet<int>();
|
|
||||||
_exc = new HashSet<int>();
|
|
||||||
}
|
}
|
||||||
internal static TAspect Build<TAspect>(EcsWorld world) where TAspect : EcsAspect
|
internal static unsafe TAspect New<TAspect>(EcsWorld world) where TAspect : EcsAspect
|
||||||
{
|
{
|
||||||
Builder builder = new Builder(world);
|
Builder builder = new Builder(world);
|
||||||
Type aspectType = typeof(TAspect);
|
Type aspectType = typeof(TAspect);
|
||||||
@ -57,13 +57,37 @@ namespace DCFApixels.DragonECS
|
|||||||
newAspect = (EcsAspect)Activator.CreateInstance(typeof(TAspect));
|
newAspect = (EcsAspect)Activator.CreateInstance(typeof(TAspect));
|
||||||
newAspect.Init(builder);
|
newAspect.Init(builder);
|
||||||
}
|
}
|
||||||
newAspect.source = world;
|
newAspect._source = world;
|
||||||
builder.End(out newAspect.mask);
|
builder.Build(out newAspect._mask);
|
||||||
newAspect._isInit = true;
|
newAspect._isInit = true;
|
||||||
|
|
||||||
|
newAspect._sortIncBuffer = new UnsafeArray<int>(newAspect._mask.inc.Length, true);
|
||||||
|
newAspect._sortExcBuffer = new UnsafeArray<int>(newAspect._mask.exc.Length, true);
|
||||||
|
newAspect._sortIncChunckBuffer = new UnsafeArray<EcsMaskChunck>(newAspect._mask.incChunckMasks.Length, true);
|
||||||
|
newAspect._sortExcChunckBuffer = new UnsafeArray<EcsMaskChunck>(newAspect._mask.excChunckMasks.Length, true);
|
||||||
|
|
||||||
|
for (int i = 0; i < newAspect._sortIncBuffer.Length; i++)
|
||||||
|
{
|
||||||
|
newAspect._sortIncBuffer.ptr[i] = newAspect._mask.inc[i];
|
||||||
|
}
|
||||||
|
for (int i = 0; i < newAspect._sortExcBuffer.Length; i++)
|
||||||
|
{
|
||||||
|
newAspect._sortExcBuffer.ptr[i] = newAspect._mask.exc[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < newAspect._sortIncChunckBuffer.Length; i++)
|
||||||
|
{
|
||||||
|
newAspect._sortIncChunckBuffer.ptr[i] = newAspect._mask.incChunckMasks[i];
|
||||||
|
}
|
||||||
|
for (int i = 0; i < newAspect._sortExcChunckBuffer.Length; i++)
|
||||||
|
{
|
||||||
|
newAspect._sortExcChunckBuffer.ptr[i] = newAspect._mask.excChunckMasks[i];
|
||||||
|
}
|
||||||
|
|
||||||
return (TAspect)newAspect;
|
return (TAspect)newAspect;
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Include/Exclude/Optional
|
#region Include/Exclude/Optional/Combine
|
||||||
public sealed override TPool Include<TPool>()
|
public sealed override TPool Include<TPool>()
|
||||||
{
|
{
|
||||||
IncludeImplicit(typeof(TPool).GetGenericArguments()[0]);
|
IncludeImplicit(typeof(TPool).GetGenericArguments()[0]);
|
||||||
@ -80,27 +104,16 @@ namespace DCFApixels.DragonECS
|
|||||||
}
|
}
|
||||||
private void IncludeImplicit(Type type)
|
private void IncludeImplicit(Type type)
|
||||||
{
|
{
|
||||||
int id = _world.GetComponentID(type);
|
_maskBuilder.Include(type);
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
|
|
||||||
if (_inc.Contains(id) || _exc.Contains(id)) Throw.ConstraintIsAlreadyContainedInMask(type);
|
|
||||||
#endif
|
|
||||||
_inc.Add(id);
|
|
||||||
}
|
}
|
||||||
private void ExcludeImplicit(Type type)
|
private void ExcludeImplicit(Type type)
|
||||||
{
|
{
|
||||||
int id = _world.GetComponentID(type);
|
_maskBuilder.Exclude(type);
|
||||||
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
|
|
||||||
if (_inc.Contains(id) || _exc.Contains(id)) Throw.ConstraintIsAlreadyContainedInMask(type);
|
|
||||||
#endif
|
|
||||||
_exc.Add(id);
|
|
||||||
}
|
}
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Combine
|
|
||||||
public TOtherAspect Combine<TOtherAspect>(int order = 0) where TOtherAspect : EcsAspect
|
public TOtherAspect Combine<TOtherAspect>(int order = 0) where TOtherAspect : EcsAspect
|
||||||
{
|
{
|
||||||
var result = _world.GetAspect<TOtherAspect>();
|
var result = _world.GetAspect<TOtherAspect>();
|
||||||
_combined.Add(new Combined(result, order));
|
_maskBuilder.CombineWith(result.Mask);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
@ -110,72 +123,9 @@ namespace DCFApixels.DragonECS
|
|||||||
return new EcsWorldCmp<T>(_world.id);
|
return new EcsWorldCmp<T>(_world.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void End(out EcsMask mask)
|
private void Build(out EcsMask mask)
|
||||||
{
|
{
|
||||||
HashSet<int> maskInc;
|
mask = _maskBuilder.Build();
|
||||||
HashSet<int> maskExc;
|
|
||||||
if (_combined.Count > 0)
|
|
||||||
{
|
|
||||||
maskInc = new HashSet<int>();
|
|
||||||
maskExc = new HashSet<int>();
|
|
||||||
_combined.Sort((a, b) => a.order - b.order);
|
|
||||||
foreach (var item in _combined)
|
|
||||||
{
|
|
||||||
EcsMask submask = item.aspect.mask;
|
|
||||||
maskInc.ExceptWith(submask.exc);//удаляю конфликтующие ограничения
|
|
||||||
maskExc.ExceptWith(submask.inc);//удаляю конфликтующие ограничения
|
|
||||||
maskInc.UnionWith(submask.inc);
|
|
||||||
maskExc.UnionWith(submask.exc);
|
|
||||||
}
|
|
||||||
maskInc.ExceptWith(_exc);//удаляю конфликтующие ограничения
|
|
||||||
maskExc.ExceptWith(_inc);//удаляю конфликтующие ограничения
|
|
||||||
maskInc.UnionWith(_inc);
|
|
||||||
maskExc.UnionWith(_exc);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
maskInc = _inc;
|
|
||||||
maskExc = _exc;
|
|
||||||
}
|
|
||||||
|
|
||||||
Dictionary<int, int> r = new Dictionary<int, int>();
|
|
||||||
foreach (var id in maskInc)
|
|
||||||
{
|
|
||||||
var bit = EcsMaskBit.FromID(id);
|
|
||||||
if (r.ContainsKey(bit.chankIndex))
|
|
||||||
{
|
|
||||||
r[bit.chankIndex] = r[bit.chankIndex] | bit.mask;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
r[bit.chankIndex] = bit.mask;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
EcsMaskBit[] incMasks = r.Select(o => new EcsMaskBit(o.Key, o.Value)).ToArray();
|
|
||||||
r.Clear();
|
|
||||||
foreach (var id in maskExc)
|
|
||||||
{
|
|
||||||
var bit = EcsMaskBit.FromID(id);
|
|
||||||
if (r.ContainsKey(bit.chankIndex))
|
|
||||||
{
|
|
||||||
r[bit.chankIndex] = r[bit.chankIndex] | bit.mask;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
r[bit.chankIndex] = bit.mask;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
EcsMaskBit[] excMasks = r.Select(o => new EcsMaskBit(o.Key, o.Value)).ToArray();
|
|
||||||
|
|
||||||
var inc = maskInc.ToArray();
|
|
||||||
Array.Sort(inc);
|
|
||||||
var exc = maskExc.ToArray();
|
|
||||||
Array.Sort(exc);
|
|
||||||
|
|
||||||
mask = new EcsMask(_world.id, inc, exc, incMasks, excMasks);
|
|
||||||
_world = null;
|
|
||||||
_inc = null;
|
|
||||||
_exc = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#region SupportReflectionHack
|
#region SupportReflectionHack
|
||||||
@ -194,10 +144,20 @@ namespace DCFApixels.DragonECS
|
|||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region Destructor
|
||||||
|
unsafe ~EcsAspect()
|
||||||
|
{
|
||||||
|
_sortIncBuffer.Dispose();
|
||||||
|
_sortExcBuffer.Dispose();
|
||||||
|
_sortIncChunckBuffer.Dispose();
|
||||||
|
_sortExcChunckBuffer.Dispose();
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region Iterator
|
#region Iterator
|
||||||
public EcsAspectIterator GetIterator()
|
public EcsAspectIterator GetIterator()
|
||||||
{
|
{
|
||||||
return new EcsAspectIterator(this, source.Entities);
|
return new EcsAspectIterator(this, _source.Entities);
|
||||||
}
|
}
|
||||||
public EcsAspectIterator GetIteratorFor(EcsSpan span)
|
public EcsAspectIterator GetIteratorFor(EcsSpan span)
|
||||||
{
|
{
|
||||||
@ -205,6 +165,7 @@ namespace DCFApixels.DragonECS
|
|||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region Combined
|
||||||
private readonly struct Combined
|
private readonly struct Combined
|
||||||
{
|
{
|
||||||
public readonly EcsAspect aspect;
|
public readonly EcsAspect aspect;
|
||||||
@ -215,6 +176,7 @@ namespace DCFApixels.DragonECS
|
|||||||
this.order = order;
|
this.order = order;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
#region BuilderBase
|
#region BuilderBase
|
||||||
@ -226,147 +188,19 @@ namespace DCFApixels.DragonECS
|
|||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Mask
|
|
||||||
public readonly struct EcsMaskBit
|
|
||||||
{
|
|
||||||
private const int BITS = 32;
|
|
||||||
private const int DIV_SHIFT = 5;
|
|
||||||
private const int MOD_MASK = BITS - 1;
|
|
||||||
|
|
||||||
public readonly int chankIndex;
|
|
||||||
public readonly int mask;
|
|
||||||
public EcsMaskBit(int chankIndex, int mask)
|
|
||||||
{
|
|
||||||
this.chankIndex = chankIndex;
|
|
||||||
this.mask = mask;
|
|
||||||
}
|
|
||||||
public static EcsMaskBit FromID(int id)
|
|
||||||
{
|
|
||||||
return new EcsMaskBit(id >> DIV_SHIFT, 1 << (id & MOD_MASK)); //аналогично new EcsMaskBit(id / BITS, 1 << (id % BITS)) но быстрее
|
|
||||||
}
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
return $"bit({chankIndex}, {mask})";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[DebuggerTypeProxy(typeof(DebuggerProxy))]
|
|
||||||
public sealed class EcsMask
|
|
||||||
{
|
|
||||||
internal readonly int worldID;
|
|
||||||
internal readonly EcsMaskBit[] incChunckMasks;
|
|
||||||
internal readonly EcsMaskBit[] excChunckMasks;
|
|
||||||
internal readonly int[] inc;
|
|
||||||
internal readonly int[] exc;
|
|
||||||
public int WorldID => worldID;
|
|
||||||
/// <summary>Including constraints</summary>
|
|
||||||
public ReadOnlySpan<int> Inc => inc;
|
|
||||||
/// <summary>Excluding constraints</summary>
|
|
||||||
public ReadOnlySpan<int> Exc => exc;
|
|
||||||
internal EcsMask(int worldID, int[] inc, int[] exc, EcsMaskBit[] incChunckMasks, EcsMaskBit[] excChunckMasks)
|
|
||||||
{
|
|
||||||
#if DEBUG
|
|
||||||
CheckConstraints(inc, exc);
|
|
||||||
#endif
|
|
||||||
this.inc = inc;
|
|
||||||
this.exc = exc;
|
|
||||||
this.worldID = worldID;
|
|
||||||
this.incChunckMasks = incChunckMasks;
|
|
||||||
this.excChunckMasks = excChunckMasks;
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Object
|
|
||||||
public override string ToString() => CreateLogString(worldID, inc, exc);
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Debug utils
|
|
||||||
#if DEBUG
|
|
||||||
private static HashSet<int> _dummyHashSet = new HashSet<int>();
|
|
||||||
private void CheckConstraints(int[] inc, int[] exc)
|
|
||||||
{
|
|
||||||
lock (_dummyHashSet)
|
|
||||||
{
|
|
||||||
if (CheckRepeats(inc)) throw new EcsFrameworkException("The values in the Include constraints are repeated.");
|
|
||||||
if (CheckRepeats(exc)) throw new EcsFrameworkException("The values in the Exclude constraints are repeated.");
|
|
||||||
_dummyHashSet.Clear();
|
|
||||||
_dummyHashSet.UnionWith(inc);
|
|
||||||
if (_dummyHashSet.Overlaps(exc)) throw new EcsFrameworkException("Conflicting Include and Exclude constraints.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
private bool CheckRepeats(int[] array)
|
|
||||||
{
|
|
||||||
_dummyHashSet.Clear();
|
|
||||||
foreach (var item in array)
|
|
||||||
{
|
|
||||||
if (_dummyHashSet.Contains(item)) return true;
|
|
||||||
_dummyHashSet.Add(item);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
private static string CreateLogString(int worldID, int[] inc, int[] exc)
|
|
||||||
{
|
|
||||||
#if (DEBUG && !DISABLE_DEBUG)
|
|
||||||
string converter(int o) => EcsDebugUtility.GetGenericTypeName(EcsWorld.GetWorld(worldID).AllPools[o].ComponentType, 1);
|
|
||||||
return $"Inc({string.Join(", ", inc.Select(converter))}) Exc({string.Join(", ", exc.Select(converter))})";
|
|
||||||
#else
|
|
||||||
return $"Inc({string.Join(", ", inc)}) Exc({string.Join(", ", exc)})"; // Release optimization
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
internal class DebuggerProxy
|
|
||||||
{
|
|
||||||
public readonly EcsWorld world;
|
|
||||||
public readonly int worldID;
|
|
||||||
public readonly EcsMaskBit[] includedChunkMasks;
|
|
||||||
public readonly EcsMaskBit[] excludedChunkMasks;
|
|
||||||
public readonly int[] included;
|
|
||||||
public readonly int[] excluded;
|
|
||||||
public readonly Type[] includedTypes;
|
|
||||||
public readonly Type[] excludedTypes;
|
|
||||||
|
|
||||||
public DebuggerProxy(EcsMask mask)
|
|
||||||
{
|
|
||||||
world = EcsWorld.GetWorld(mask.worldID);
|
|
||||||
worldID = mask.worldID;
|
|
||||||
includedChunkMasks = mask.incChunckMasks;
|
|
||||||
excludedChunkMasks = mask.excChunckMasks;
|
|
||||||
included = mask.inc;
|
|
||||||
excluded = mask.exc;
|
|
||||||
Type converter(int o) => world.GetComponentType(o);
|
|
||||||
includedTypes = included.Select(converter).ToArray();
|
|
||||||
excludedTypes = excluded.Select(converter).ToArray();
|
|
||||||
}
|
|
||||||
public override string ToString() => CreateLogString(worldID, included, excluded);
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Iterator
|
#region Iterator
|
||||||
public ref struct EcsAspectIterator
|
public ref struct EcsAspectIterator
|
||||||
{
|
{
|
||||||
public readonly int worldID;
|
public readonly int worldID;
|
||||||
public readonly EcsMask mask;
|
public readonly EcsAspect aspect;
|
||||||
private EcsSpan _span;
|
private EcsSpan _span;
|
||||||
private Enumerator _enumerator;
|
|
||||||
|
|
||||||
public EcsAspectIterator(EcsAspect aspect, EcsSpan span)
|
public EcsAspectIterator(EcsAspect aspect, EcsSpan span)
|
||||||
{
|
{
|
||||||
worldID = aspect.World.id;
|
worldID = aspect.World.id;
|
||||||
mask = aspect.mask;
|
|
||||||
_span = span;
|
_span = span;
|
||||||
_enumerator = default;
|
this.aspect = aspect;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int Current
|
|
||||||
{
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
get => _enumerator.Current;
|
|
||||||
}
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public void Begin() => _enumerator = GetEnumerator();
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
public bool Next() => _enumerator.MoveNext();
|
|
||||||
public void CopyTo(EcsGroup group)
|
public void CopyTo(EcsGroup group)
|
||||||
{
|
{
|
||||||
group.Clear();
|
group.Clear();
|
||||||
@ -380,7 +214,7 @@ namespace DCFApixels.DragonECS
|
|||||||
int count = 0;
|
int count = 0;
|
||||||
while (enumerator.MoveNext())
|
while (enumerator.MoveNext())
|
||||||
{
|
{
|
||||||
if(array.Length <= count)
|
if (array.Length <= count)
|
||||||
Array.Resize(ref array, array.Length << 1);
|
Array.Resize(ref array, array.Length << 1);
|
||||||
array[count++] = enumerator.Current;
|
array[count++] = enumerator.Current;
|
||||||
}
|
}
|
||||||
@ -402,58 +236,163 @@ namespace DCFApixels.DragonECS
|
|||||||
#region object
|
#region object
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
StringBuilder result = new StringBuilder();
|
List<int> ints = new List<int>();
|
||||||
foreach (var e in this)
|
foreach (var e in this)
|
||||||
{
|
{
|
||||||
result.Append(e);
|
ints.Add(e);
|
||||||
result.Append(", ");
|
|
||||||
}
|
}
|
||||||
return result.ToString();
|
return CollectionUtility.EntitiesToString(ints, "it");
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Enumerator
|
#region Enumerator
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public Enumerator GetEnumerator() => new Enumerator(_span, mask);
|
public Enumerator GetEnumerator() => new Enumerator(_span, aspect);
|
||||||
|
|
||||||
public ref struct Enumerator
|
public unsafe ref struct Enumerator
|
||||||
{
|
{
|
||||||
|
#region CountComparers
|
||||||
|
private readonly struct IncCountComparer : IComparerX<int>
|
||||||
|
{
|
||||||
|
public readonly int[] counts;
|
||||||
|
public IncCountComparer(int[] counts)
|
||||||
|
{
|
||||||
|
this.counts = counts;
|
||||||
|
}
|
||||||
|
public int Compare(int a, int b)
|
||||||
|
{
|
||||||
|
return counts[a] - counts[b];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private readonly struct ExcCountComparer : IComparerX<int>
|
||||||
|
{
|
||||||
|
public readonly int[] counts;
|
||||||
|
public ExcCountComparer(int[] counts)
|
||||||
|
{
|
||||||
|
this.counts = counts;
|
||||||
|
}
|
||||||
|
public int Compare(int a, int b)
|
||||||
|
{
|
||||||
|
return counts[b] - counts[a];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
private ReadOnlySpan<int>.Enumerator _span;
|
private ReadOnlySpan<int>.Enumerator _span;
|
||||||
private readonly EcsMaskBit[] _incChunckMasks;
|
|
||||||
private readonly EcsMaskBit[] _excChunckMasks;
|
|
||||||
private readonly int[][] _entitiesComponentMasks;
|
private readonly int[][] _entitiesComponentMasks;
|
||||||
|
|
||||||
public Enumerator(EcsSpan span, EcsMask mask)
|
private static EcsMaskChunck* _preSortedIncBuffer;
|
||||||
|
private static EcsMaskChunck* _preSortedExcBuffer;
|
||||||
|
|
||||||
|
private UnsafeArray<EcsMaskChunck> _sortIncChunckBuffer;
|
||||||
|
private UnsafeArray<EcsMaskChunck> _sortExcChunckBuffer;
|
||||||
|
|
||||||
|
//private EcsAspect aspect;
|
||||||
|
|
||||||
|
public unsafe Enumerator(EcsSpan span, EcsAspect aspect)
|
||||||
{
|
{
|
||||||
|
//this.aspect = aspect;
|
||||||
_span = span.GetEnumerator();
|
_span = span.GetEnumerator();
|
||||||
_incChunckMasks = mask.incChunckMasks;
|
_entitiesComponentMasks = aspect.World._entitiesComponentMasks;
|
||||||
_excChunckMasks = mask.excChunckMasks;
|
_sortIncChunckBuffer = aspect._sortIncChunckBuffer;
|
||||||
_entitiesComponentMasks = span.World._entitiesComponentMasks;
|
_sortExcChunckBuffer = aspect._sortExcChunckBuffer;
|
||||||
|
|
||||||
|
#region Sort
|
||||||
|
UnsafeArray<int> _sortIncBuffer = aspect._sortIncBuffer;
|
||||||
|
UnsafeArray<int> _sortExcBuffer = aspect._sortExcBuffer;
|
||||||
|
int[] counts = aspect.World._poolComponentCounts;
|
||||||
|
|
||||||
|
if (_preSortedIncBuffer == null)
|
||||||
|
{
|
||||||
|
_preSortedIncBuffer = UnmanagedArrayUtility.New<EcsMaskChunck>(256);
|
||||||
|
_preSortedExcBuffer = UnmanagedArrayUtility.New<EcsMaskChunck>(256);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_sortIncChunckBuffer.Length > 1)
|
||||||
|
{
|
||||||
|
IncCountComparer incComparer = new IncCountComparer(counts);
|
||||||
|
UnsafeArraySortHalperX<int>.InsertionSort(_sortIncBuffer.ptr, _sortIncBuffer.Length, ref incComparer);
|
||||||
|
for (int i = 0; i < _sortIncBuffer.Length; i++)
|
||||||
|
{
|
||||||
|
_preSortedIncBuffer[i] = EcsMaskChunck.FromID(_sortIncBuffer.ptr[i]);
|
||||||
|
}
|
||||||
|
for (int i = 0, ii = 0; ii < _sortIncChunckBuffer.Length; ii++)
|
||||||
|
{
|
||||||
|
EcsMaskChunck bas = _preSortedIncBuffer[i];
|
||||||
|
int chankIndexX = bas.chankIndex;
|
||||||
|
int maskX = bas.mask;
|
||||||
|
|
||||||
|
for (int j = i + 1; j < _sortIncBuffer.Length; j++)
|
||||||
|
{
|
||||||
|
if (_preSortedIncBuffer[j].chankIndex == chankIndexX)
|
||||||
|
{
|
||||||
|
maskX |= _preSortedIncBuffer[j].mask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_sortIncChunckBuffer.ptr[ii] = new EcsMaskChunck(chankIndexX, maskX);
|
||||||
|
while (++i < _sortIncBuffer.Length && _preSortedIncBuffer[i].chankIndex == chankIndexX)
|
||||||
|
{
|
||||||
|
// skip
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_sortExcChunckBuffer.Length > 1)
|
||||||
|
{
|
||||||
|
ExcCountComparer excComparer = new ExcCountComparer(counts);
|
||||||
|
UnsafeArraySortHalperX<int>.InsertionSort(_sortExcBuffer.ptr, _sortExcBuffer.Length, ref excComparer);
|
||||||
|
for (int i = 0; i < _sortExcBuffer.Length; i++)
|
||||||
|
{
|
||||||
|
_preSortedExcBuffer[i] = EcsMaskChunck.FromID(_sortExcBuffer.ptr[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0, ii = 0; ii < _sortExcChunckBuffer.Length; ii++)
|
||||||
|
{
|
||||||
|
EcsMaskChunck bas = _preSortedExcBuffer[i];
|
||||||
|
int chankIndexX = bas.chankIndex;
|
||||||
|
int maskX = bas.mask;
|
||||||
|
|
||||||
|
for (int j = i + 1; j < _sortExcBuffer.Length; j++)
|
||||||
|
{
|
||||||
|
if (_preSortedExcBuffer[j].chankIndex == chankIndexX)
|
||||||
|
{
|
||||||
|
maskX |= _preSortedExcBuffer[j].mask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_sortExcChunckBuffer.ptr[ii] = new EcsMaskChunck(chankIndexX, maskX);
|
||||||
|
while (++i < _sortExcBuffer.Length && _preSortedExcBuffer[i].chankIndex == chankIndexX)
|
||||||
|
{
|
||||||
|
// skip
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
public int Current
|
public int Current
|
||||||
{
|
{
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
get => _span.Current;
|
get => _span.Current;
|
||||||
}
|
}
|
||||||
|
//public entlong CurrentLong
|
||||||
|
//{
|
||||||
|
// [MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
// get => aspect.World.GetEntityLong(_span.Current);
|
||||||
|
//}
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public bool MoveNext()
|
public bool MoveNext()
|
||||||
{
|
{
|
||||||
while (_span.MoveNext())
|
while (_span.MoveNext())
|
||||||
{
|
{
|
||||||
int e = _span.Current;
|
int e = _span.Current;
|
||||||
EcsMaskBit bit;
|
for (int i = 0; i < _sortIncChunckBuffer.Length; i++)
|
||||||
for (int i = 0, iMax = _incChunckMasks.Length; i < iMax; i++)
|
|
||||||
{
|
{
|
||||||
bit = _incChunckMasks[i];
|
var bit = _sortIncChunckBuffer.ptr[i];
|
||||||
if ((_entitiesComponentMasks[e][bit.chankIndex] & bit.mask) != bit.mask)
|
if ((_entitiesComponentMasks[e][bit.chankIndex] & bit.mask) != bit.mask)
|
||||||
goto skip;
|
goto skip;
|
||||||
}
|
}
|
||||||
for (int i = 0, iMax = _excChunckMasks.Length; i < iMax; i++)
|
for (int i = 0; i < _sortExcChunckBuffer.Length; i++)
|
||||||
{
|
{
|
||||||
bit = _excChunckMasks[i];
|
var bit = _sortExcChunckBuffer.ptr[i];
|
||||||
if ((_entitiesComponentMasks[e][bit.chankIndex] & bit.mask) > 0)
|
if ((_entitiesComponentMasks[e][bit.chankIndex] & bit.mask) > 0)
|
||||||
goto skip;
|
goto skip;
|
||||||
}
|
}
|
||||||
|
|||||||
376
src/EcsMask.cs
Normal file
376
src/EcsMask.cs
Normal file
@ -0,0 +1,376 @@
|
|||||||
|
using DCFApixels.DragonECS.Internal;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace DCFApixels.DragonECS
|
||||||
|
{
|
||||||
|
public abstract partial class EcsWorld
|
||||||
|
{
|
||||||
|
private Dictionary<EcsMask.BuilderMaskKey, EcsMask> _masks = new Dictionary<EcsMask.BuilderMaskKey, EcsMask>(256);
|
||||||
|
internal EcsMask GetMask_Internal(EcsMask.BuilderMaskKey maskKey)
|
||||||
|
{
|
||||||
|
if (!_masks.TryGetValue(maskKey, out EcsMask result))
|
||||||
|
{
|
||||||
|
result = new EcsMask(_masks.Count, id, maskKey.inc, maskKey.exc);
|
||||||
|
_masks.Add(maskKey, result);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[DebuggerTypeProxy(typeof(DebuggerProxy))]
|
||||||
|
public sealed class EcsMask : IEquatable<EcsMask>
|
||||||
|
{
|
||||||
|
internal readonly int id;
|
||||||
|
internal readonly int worldID;
|
||||||
|
internal readonly EcsMaskChunck[] incChunckMasks;
|
||||||
|
internal readonly EcsMaskChunck[] excChunckMasks;
|
||||||
|
internal readonly int[] inc;
|
||||||
|
internal readonly int[] exc;
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
public int ID => id;
|
||||||
|
public int WorldID => worldID;
|
||||||
|
public EcsWorld World => EcsWorld.GetWorld(worldID);
|
||||||
|
/// <summary>Including constraints</summary>
|
||||||
|
public ReadOnlySpan<int> Inc => inc;
|
||||||
|
/// <summary>Excluding constraints</summary>
|
||||||
|
public ReadOnlySpan<int> Exc => exc;
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
internal EcsMask(int id, int worldID, int[] inc, int[] exc)
|
||||||
|
{
|
||||||
|
#if DEBUG
|
||||||
|
CheckConstraints(inc, exc);
|
||||||
|
#endif
|
||||||
|
this.id = id;
|
||||||
|
this.inc = inc;
|
||||||
|
this.exc = exc;
|
||||||
|
this.worldID = worldID;
|
||||||
|
|
||||||
|
incChunckMasks = MakeMaskChuncsArray(inc);
|
||||||
|
excChunckMasks = MakeMaskChuncsArray(exc);
|
||||||
|
}
|
||||||
|
|
||||||
|
private unsafe EcsMaskChunck[] MakeMaskChuncsArray(int[] sortedArray)
|
||||||
|
{
|
||||||
|
EcsMaskChunck* buffer = stackalloc EcsMaskChunck[sortedArray.Length];
|
||||||
|
|
||||||
|
int resultLength = 0;
|
||||||
|
for (int i = 0; i < sortedArray.Length;)
|
||||||
|
{
|
||||||
|
int chankIndexX = sortedArray[i] >> EcsMaskChunck.DIV_SHIFT;
|
||||||
|
int maskX = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
EcsMaskChunck bitJ = EcsMaskChunck.FromID(sortedArray[i]);
|
||||||
|
if (bitJ.chankIndex != chankIndexX)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
maskX |= bitJ.mask;
|
||||||
|
i++;
|
||||||
|
} while (i < sortedArray.Length);
|
||||||
|
buffer[resultLength++] = new EcsMaskChunck(chankIndexX, maskX);
|
||||||
|
}
|
||||||
|
|
||||||
|
EcsMaskChunck[] result = new EcsMaskChunck[resultLength];
|
||||||
|
for (int i = 0; i < resultLength; i++)
|
||||||
|
{
|
||||||
|
result[i] = buffer[i];
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Object
|
||||||
|
public override string ToString() => CreateLogString(worldID, inc, exc);
|
||||||
|
public bool Equals(EcsMask mask)
|
||||||
|
{
|
||||||
|
return id == mask.id && worldID == mask.worldID;
|
||||||
|
}
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
return obj is EcsMask mask && id == mask.id && Equals(mask);
|
||||||
|
}
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return unchecked(id ^ (worldID * EcsConsts.MAGIC_PRIME));
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Debug utils
|
||||||
|
#if DEBUG
|
||||||
|
private static HashSet<int> _dummyHashSet = new HashSet<int>();
|
||||||
|
private void CheckConstraints(int[] inc, int[] exc)
|
||||||
|
{
|
||||||
|
lock (_dummyHashSet)
|
||||||
|
{
|
||||||
|
if (CheckRepeats(inc)) throw new EcsFrameworkException("The values in the Include constraints are repeated.");
|
||||||
|
if (CheckRepeats(exc)) throw new EcsFrameworkException("The values in the Exclude constraints are repeated.");
|
||||||
|
_dummyHashSet.Clear();
|
||||||
|
_dummyHashSet.UnionWith(inc);
|
||||||
|
if (_dummyHashSet.Overlaps(exc)) throw new EcsFrameworkException("Conflicting Include and Exclude constraints.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private bool CheckRepeats(int[] array)
|
||||||
|
{
|
||||||
|
_dummyHashSet.Clear();
|
||||||
|
foreach (var item in array)
|
||||||
|
{
|
||||||
|
if (_dummyHashSet.Contains(item)) return true;
|
||||||
|
_dummyHashSet.Add(item);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
private static string CreateLogString(int worldID, int[] inc, int[] exc)
|
||||||
|
{
|
||||||
|
#if (DEBUG && !DISABLE_DEBUG)
|
||||||
|
string converter(int o) => EcsDebugUtility.GetGenericTypeName(EcsWorld.GetWorld(worldID).AllPools[o].ComponentType, 1);
|
||||||
|
return $"Inc({string.Join(", ", inc.Select(converter))}) Exc({string.Join(", ", exc.Select(converter))})";
|
||||||
|
#else
|
||||||
|
return $"Inc({string.Join(", ", inc)}) Exc({string.Join(", ", exc)})"; // Release optimization
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class DebuggerProxy
|
||||||
|
{
|
||||||
|
public readonly int ID;
|
||||||
|
public readonly EcsWorld world;
|
||||||
|
private readonly int _worldID;
|
||||||
|
public readonly EcsMaskChunck[] includedChunkMasks;
|
||||||
|
public readonly EcsMaskChunck[] excludedChunkMasks;
|
||||||
|
public readonly int[] included;
|
||||||
|
public readonly int[] excluded;
|
||||||
|
public readonly Type[] includedTypes;
|
||||||
|
public readonly Type[] excludedTypes;
|
||||||
|
|
||||||
|
public DebuggerProxy(EcsMask mask)
|
||||||
|
{
|
||||||
|
ID = mask.id;
|
||||||
|
world = EcsWorld.GetWorld(mask.worldID);
|
||||||
|
_worldID = mask.worldID;
|
||||||
|
includedChunkMasks = mask.incChunckMasks;
|
||||||
|
excludedChunkMasks = mask.excChunckMasks;
|
||||||
|
included = mask.inc;
|
||||||
|
excluded = mask.exc;
|
||||||
|
Type converter(int o) => world.GetComponentType(o);
|
||||||
|
includedTypes = included.Select(converter).ToArray();
|
||||||
|
excludedTypes = excluded.Select(converter).ToArray();
|
||||||
|
}
|
||||||
|
public override string ToString() => CreateLogString(_worldID, included, excluded);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Builder
|
||||||
|
public readonly struct BuilderMaskKey : IEquatable<BuilderMaskKey>
|
||||||
|
{
|
||||||
|
public readonly int[] inc;
|
||||||
|
public readonly int[] exc;
|
||||||
|
public readonly int hash;
|
||||||
|
public BuilderMaskKey(int[] inc, int[] exc, int hash)
|
||||||
|
{
|
||||||
|
this.inc = inc;
|
||||||
|
this.exc = exc;
|
||||||
|
this.hash = hash;
|
||||||
|
}
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public bool Equals(BuilderMaskKey other)
|
||||||
|
{
|
||||||
|
if (inc.Length != other.inc.Length)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (exc.Length != other.exc.Length)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < inc.Length; i++)
|
||||||
|
{
|
||||||
|
if (inc[i] != other.inc[i])
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i = 0; i < exc.Length; i++)
|
||||||
|
{
|
||||||
|
if (exc[i] != other.exc[i])
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if DEBUG
|
||||||
|
if (other.hash != hash)
|
||||||
|
{
|
||||||
|
throw new Exception("other.hash != hash");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public override int GetHashCode() => hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Builder
|
||||||
|
{
|
||||||
|
private readonly EcsWorld _world;
|
||||||
|
private readonly HashSet<int> _inc = new HashSet<int>();
|
||||||
|
private readonly HashSet<int> _exc = new HashSet<int>();
|
||||||
|
private readonly List<Combined> _combined = new List<Combined>();
|
||||||
|
|
||||||
|
internal Builder(EcsWorld world)
|
||||||
|
{
|
||||||
|
_world = world;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Include<T>()
|
||||||
|
{
|
||||||
|
int id = _world.GetComponentID<T>();
|
||||||
|
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
|
||||||
|
if (_inc.Contains(id) || _exc.Contains(id)) Throw.ConstraintIsAlreadyContainedInMask(typeof(T));
|
||||||
|
#endif
|
||||||
|
_inc.Add(id);
|
||||||
|
}
|
||||||
|
public void Exclude<T>()
|
||||||
|
{
|
||||||
|
int id = _world.GetComponentID<T>();
|
||||||
|
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
|
||||||
|
if (_inc.Contains(id) || _exc.Contains(id)) Throw.ConstraintIsAlreadyContainedInMask(typeof(T));
|
||||||
|
#endif
|
||||||
|
_exc.Add(id);
|
||||||
|
}
|
||||||
|
public void Include(Type type)
|
||||||
|
{
|
||||||
|
int id = _world.GetComponentID(type);
|
||||||
|
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
|
||||||
|
if (_inc.Contains(id) || _exc.Contains(id)) Throw.ConstraintIsAlreadyContainedInMask(type);
|
||||||
|
#endif
|
||||||
|
_inc.Add(id);
|
||||||
|
}
|
||||||
|
public void Exclude(Type type)
|
||||||
|
{
|
||||||
|
int id = _world.GetComponentID(type);
|
||||||
|
#if (DEBUG && !DISABLE_DEBUG) || ENABLE_DRAGONECS_ASSERT_CHEKS
|
||||||
|
if (_inc.Contains(id) || _exc.Contains(id)) Throw.ConstraintIsAlreadyContainedInMask(type);
|
||||||
|
#endif
|
||||||
|
_exc.Add(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CombineWith(EcsMask mask, int order = 0)
|
||||||
|
{
|
||||||
|
_combined.Add(new Combined(mask, order));
|
||||||
|
}
|
||||||
|
|
||||||
|
public EcsMask Build()
|
||||||
|
{
|
||||||
|
HashSet<int> combinedInc;
|
||||||
|
HashSet<int> combinedExc;
|
||||||
|
if (_combined.Count > 0)
|
||||||
|
{
|
||||||
|
combinedInc = new HashSet<int>();
|
||||||
|
combinedExc = new HashSet<int>();
|
||||||
|
_combined.Sort((a, b) => a.order - b.order);
|
||||||
|
foreach (var item in _combined)
|
||||||
|
{
|
||||||
|
EcsMask submask = item.mask;
|
||||||
|
combinedInc.ExceptWith(submask.exc);//удаляю конфликтующие ограничения
|
||||||
|
combinedExc.ExceptWith(submask.inc);//удаляю конфликтующие ограничения
|
||||||
|
combinedInc.UnionWith(submask.inc);
|
||||||
|
combinedExc.UnionWith(submask.exc);
|
||||||
|
}
|
||||||
|
combinedInc.ExceptWith(_exc);//удаляю конфликтующие ограничения
|
||||||
|
combinedExc.ExceptWith(_inc);//удаляю конфликтующие ограничения
|
||||||
|
combinedInc.UnionWith(_inc);
|
||||||
|
combinedExc.UnionWith(_exc);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
combinedInc = _inc;
|
||||||
|
combinedExc = _exc;
|
||||||
|
}
|
||||||
|
|
||||||
|
var inc = combinedInc.ToArray();
|
||||||
|
Array.Sort(inc);
|
||||||
|
var exc = combinedExc.ToArray();
|
||||||
|
Array.Sort(exc);
|
||||||
|
|
||||||
|
unchecked
|
||||||
|
{
|
||||||
|
int keyHash = inc.Length + exc.Length;
|
||||||
|
for (int i = 0, iMax = inc.Length; i < iMax; i++)
|
||||||
|
{
|
||||||
|
keyHash = keyHash * EcsConsts.MAGIC_PRIME + inc[i];
|
||||||
|
}
|
||||||
|
for (int i = 0, iMax = exc.Length; i < iMax; i++)
|
||||||
|
{
|
||||||
|
keyHash = keyHash * EcsConsts.MAGIC_PRIME - exc[i];
|
||||||
|
}
|
||||||
|
BuilderMaskKey key = new BuilderMaskKey(inc, exc, keyHash);
|
||||||
|
return _world.GetMask_Internal(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly struct Combined
|
||||||
|
{
|
||||||
|
public readonly EcsMask mask;
|
||||||
|
public readonly int order;
|
||||||
|
public Combined(EcsMask mask, int order)
|
||||||
|
{
|
||||||
|
this.mask = mask;
|
||||||
|
this.order = order;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
#region EcsMaskChunck
|
||||||
|
[DebuggerTypeProxy(typeof(DebuggerProxy))]
|
||||||
|
public readonly struct EcsMaskChunck
|
||||||
|
{
|
||||||
|
internal const int BITS = 32;
|
||||||
|
internal const int DIV_SHIFT = 5;
|
||||||
|
internal const int MOD_MASK = BITS - 1;
|
||||||
|
|
||||||
|
public readonly int chankIndex;
|
||||||
|
public readonly int mask;
|
||||||
|
public EcsMaskChunck(int chankIndex, int mask)
|
||||||
|
{
|
||||||
|
this.chankIndex = chankIndex;
|
||||||
|
this.mask = mask;
|
||||||
|
}
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static EcsMaskChunck FromID(int id)
|
||||||
|
{
|
||||||
|
return new EcsMaskChunck(id >> DIV_SHIFT, 1 << (id & MOD_MASK));
|
||||||
|
}
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"mask({chankIndex}, {mask}, {BitsUtility.CountBits(mask)})";
|
||||||
|
}
|
||||||
|
internal class DebuggerProxy
|
||||||
|
{
|
||||||
|
public int chunk;
|
||||||
|
public uint mask;
|
||||||
|
public int[] values = Array.Empty<int>();
|
||||||
|
public string bits;
|
||||||
|
public DebuggerProxy(EcsMaskChunck maskbits)
|
||||||
|
{
|
||||||
|
chunk = maskbits.chankIndex;
|
||||||
|
mask = (uint)maskbits.mask;
|
||||||
|
BitsUtility.GetBitNumbersNoAlloc(mask, ref values);
|
||||||
|
for (int i = 0; i < values.Length; i++)
|
||||||
|
{
|
||||||
|
values[i] += (chunk) << 5;
|
||||||
|
}
|
||||||
|
bits = BitsUtility.ToBitsString(mask, '_', 8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
11
src/EcsMask.cs.meta
Normal file
11
src/EcsMask.cs.meta
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: e1975c74e7ab50e4dba6bf01902e26e9
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@ -138,12 +138,12 @@ namespace DCFApixels.DragonECS
|
|||||||
throw new Exception();
|
throw new Exception();
|
||||||
}
|
}
|
||||||
|
|
||||||
Type GetRunnerBaseType(Type typeX)
|
Type GetRunnerBaseType(Type inType)
|
||||||
{
|
{
|
||||||
if (typeX.IsGenericType && typeX.GetGenericTypeDefinition() == typeof(EcsRunner<>))
|
if (inType.IsGenericType && inType.GetGenericTypeDefinition() == typeof(EcsRunner<>))
|
||||||
return typeX;
|
return inType;
|
||||||
if (typeX.BaseType != null)
|
if (inType.BaseType != null)
|
||||||
return GetRunnerBaseType(typeX.BaseType);
|
return GetRunnerBaseType(inType.BaseType);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
Type baseType = GetRunnerBaseType(type);
|
Type baseType = GetRunnerBaseType(type);
|
||||||
@ -291,7 +291,7 @@ namespace DCFApixels.DragonECS
|
|||||||
name = Regex.Replace(name, @"\bEcs|Process\b", "");
|
name = Regex.Replace(name, @"\bEcs|Process\b", "");
|
||||||
if (Regex.IsMatch(name, "`\\w{1,}$"))
|
if (Regex.IsMatch(name, "`\\w{1,}$"))
|
||||||
{
|
{
|
||||||
var s = name.Split("`".ToCharArray());
|
var s = name.Split('`');
|
||||||
name = s[0] + $"<{s[1]}>";
|
name = s[0] + $"<{s[1]}>";
|
||||||
}
|
}
|
||||||
_processes.Add(type, new ProcessInterface(type, name));
|
_processes.Add(type, new ProcessInterface(type, name));
|
||||||
|
|||||||
@ -23,7 +23,7 @@
|
|||||||
public AspectCache(T instance) => this.instance = instance;
|
public AspectCache(T instance) => this.instance = instance;
|
||||||
void IEcsWorldComponent<AspectCache<T>>.Init(ref AspectCache<T> component, EcsWorld world)
|
void IEcsWorldComponent<AspectCache<T>>.Init(ref AspectCache<T> component, EcsWorld world)
|
||||||
{
|
{
|
||||||
component = new AspectCache<T>(EcsAspect.Builder.Build<T>(world));
|
component = new AspectCache<T>(EcsAspect.Builder.New<T>(world));
|
||||||
}
|
}
|
||||||
void IEcsWorldComponent<AspectCache<T>>.OnDestroy(ref AspectCache<T> component, EcsWorld world)
|
void IEcsWorldComponent<AspectCache<T>>.OnDestroy(ref AspectCache<T> component, EcsWorld world)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -66,7 +66,9 @@ namespace DCFApixels.DragonECS
|
|||||||
|
|
||||||
_entityDispenser = new IntDispenser(0);
|
_entityDispenser = new IntDispenser(0);
|
||||||
_pools = new IEcsPoolImplementation[POOLS_CAPACITY];
|
_pools = new IEcsPoolImplementation[POOLS_CAPACITY];
|
||||||
//_poolComponentCounts = new int[POOLS_CAPACITY];
|
_poolComponentCounts = new int[POOLS_CAPACITY];
|
||||||
|
//_sortedPoolIds = new int[POOLS_CAPACITY];
|
||||||
|
//_sortedPoolIdsMapping = new int[POOLS_CAPACITY];
|
||||||
ArrayUtility.Fill(_pools, _nullPool);
|
ArrayUtility.Fill(_pools, _nullPool);
|
||||||
|
|
||||||
_gens = new short[_entitesCapacity];
|
_gens = new short[_entitesCapacity];
|
||||||
@ -74,7 +76,6 @@ namespace DCFApixels.DragonECS
|
|||||||
|
|
||||||
ArrayUtility.Fill(_gens, DEATH_GEN_BIT);
|
ArrayUtility.Fill(_gens, DEATH_GEN_BIT);
|
||||||
_delEntBufferCount = 0;
|
_delEntBufferCount = 0;
|
||||||
//_delEntBuffer = new int[_entitesCapacity >> DEL_ENT_BUFFER_SIZE_OFFSET];
|
|
||||||
_delEntBuffer = new int[_entitesCapacity];
|
_delEntBuffer = new int[_entitesCapacity];
|
||||||
_entitiesComponentMasks = new int[_entitesCapacity][];
|
_entitiesComponentMasks = new int[_entitesCapacity][];
|
||||||
for (int i = 0; i < _entitesCapacity; i++)
|
for (int i = 0; i < _entitesCapacity; i++)
|
||||||
@ -141,7 +142,7 @@ namespace DCFApixels.DragonECS
|
|||||||
#region Where Query
|
#region Where Query
|
||||||
public EcsReadonlyGroup WhereToGroupFor<TAspect>(EcsSpan span, out TAspect aspect) where TAspect : EcsAspect
|
public EcsReadonlyGroup WhereToGroupFor<TAspect>(EcsSpan span, out TAspect aspect) where TAspect : EcsAspect
|
||||||
{
|
{
|
||||||
if(_isEnableReleaseDelEntBuffer)
|
if (_isEnableReleaseDelEntBuffer)
|
||||||
{
|
{
|
||||||
ReleaseDelEntityBufferAll();
|
ReleaseDelEntityBufferAll();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,7 +12,9 @@ namespace DCFApixels.DragonECS
|
|||||||
private SparseArray<int> _componentIds = new SparseArray<int>();
|
private SparseArray<int> _componentIds = new SparseArray<int>();
|
||||||
private int _poolsCount;
|
private int _poolsCount;
|
||||||
internal IEcsPoolImplementation[] _pools;
|
internal IEcsPoolImplementation[] _pools;
|
||||||
//internal int[] _poolComponentCounts;
|
//private int[] _sortedPoolIds;
|
||||||
|
//private int[] _sortedPoolIdsMapping;
|
||||||
|
internal int[] _poolComponentCounts;
|
||||||
|
|
||||||
private static EcsNullPool _nullPool = EcsNullPool.instance;
|
private static EcsNullPool _nullPool = EcsNullPool.instance;
|
||||||
|
|
||||||
@ -26,6 +28,13 @@ namespace DCFApixels.DragonECS
|
|||||||
|
|
||||||
#region Getters
|
#region Getters
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public TPool TestGetPool<TPool>() where TPool : IEcsPoolImplementation, new()
|
||||||
|
{
|
||||||
|
return Get<PoolCache<TPool>>().instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#if UNITY_2020_3_OR_NEWER
|
#if UNITY_2020_3_OR_NEWER
|
||||||
[UnityEngine.Scripting.Preserve]
|
[UnityEngine.Scripting.Preserve]
|
||||||
#endif
|
#endif
|
||||||
@ -94,7 +103,9 @@ namespace DCFApixels.DragonECS
|
|||||||
{
|
{
|
||||||
int oldCapacity = _pools.Length;
|
int oldCapacity = _pools.Length;
|
||||||
Array.Resize(ref _pools, _pools.Length << 1);
|
Array.Resize(ref _pools, _pools.Length << 1);
|
||||||
//Array.Resize(ref _poolComponentCounts, _pools.Length);
|
Array.Resize(ref _poolComponentCounts, _pools.Length);
|
||||||
|
//Array.Resize(ref _sortedPoolIds, _pools.Length);
|
||||||
|
//Array.Resize(ref _sortedPoolIdsMapping, _pools.Length);
|
||||||
ArrayUtility.Fill(_pools, _nullPool, oldCapacity, oldCapacity - _pools.Length);
|
ArrayUtility.Fill(_pools, _nullPool, oldCapacity, oldCapacity - _pools.Length);
|
||||||
|
|
||||||
for (int i = 0; i < _entitesCapacity; i++)
|
for (int i = 0; i < _entitesCapacity; i++)
|
||||||
@ -111,18 +122,19 @@ namespace DCFApixels.DragonECS
|
|||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
#region Pools mediation
|
#region Pools mediation
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private void RegisterEntityComponent(int entityID, int componentTypeID, EcsMaskBit maskBit)
|
private void RegisterEntityComponent(int entityID, int componentTypeID, EcsMaskChunck maskBit)
|
||||||
{
|
{
|
||||||
//_poolComponentCounts[componentTypeID]++;
|
_poolComponentCounts[componentTypeID]++;
|
||||||
_componentCounts[entityID]++;
|
_componentCounts[entityID]++;
|
||||||
_entitiesComponentMasks[entityID][maskBit.chankIndex] |= maskBit.mask;
|
_entitiesComponentMasks[entityID][maskBit.chankIndex] |= maskBit.mask;
|
||||||
}
|
}
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private void UnregisterEntityComponent(int entityID, int componentTypeID, EcsMaskBit maskBit)
|
private void UnregisterEntityComponent(int entityID, int componentTypeID, EcsMaskChunck maskBit)
|
||||||
{
|
{
|
||||||
//_poolComponentCounts[componentTypeID]--;
|
_poolComponentCounts[componentTypeID]--;
|
||||||
var count = --_componentCounts[entityID];
|
var count = --_componentCounts[entityID];
|
||||||
_entitiesComponentMasks[entityID][maskBit.chankIndex] &= ~maskBit.mask;
|
_entitiesComponentMasks[entityID][maskBit.chankIndex] &= ~maskBit.mask;
|
||||||
|
|
||||||
@ -133,7 +145,7 @@ namespace DCFApixels.DragonECS
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private bool HasEntityComponent(int entityID, EcsMaskBit maskBit)
|
private bool HasEntityComponent(int entityID, EcsMaskChunck maskBit)
|
||||||
{
|
{
|
||||||
return (_entitiesComponentMasks[entityID][maskBit.chankIndex] & maskBit.mask) != maskBit.mask;
|
return (_entitiesComponentMasks[entityID][maskBit.chankIndex] & maskBit.mask) != maskBit.mask;
|
||||||
}
|
}
|
||||||
@ -152,17 +164,17 @@ namespace DCFApixels.DragonECS
|
|||||||
_world = world;
|
_world = world;
|
||||||
}
|
}
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public void RegisterComponent(int entityID, int componentTypeID, EcsMaskBit maskBit)
|
public void RegisterComponent(int entityID, int componentTypeID, EcsMaskChunck maskBit)
|
||||||
{
|
{
|
||||||
_world.RegisterEntityComponent(entityID, componentTypeID, maskBit);
|
_world.RegisterEntityComponent(entityID, componentTypeID, maskBit);
|
||||||
}
|
}
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public void UnregisterComponent(int entityID, int componentTypeID, EcsMaskBit maskBit)
|
public void UnregisterComponent(int entityID, int componentTypeID, EcsMaskChunck maskBit)
|
||||||
{
|
{
|
||||||
_world.UnregisterEntityComponent(entityID, componentTypeID, maskBit);
|
_world.UnregisterEntityComponent(entityID, componentTypeID, maskBit);
|
||||||
}
|
}
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public bool HasComponent(int entityID, EcsMaskBit maskBit)
|
public bool HasComponent(int entityID, EcsMaskChunck maskBit)
|
||||||
{
|
{
|
||||||
return _world.HasEntityComponent(entityID, maskBit);
|
return _world.HasEntityComponent(entityID, maskBit);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -96,7 +96,7 @@ namespace DCFApixels.DragonECS
|
|||||||
{
|
{
|
||||||
itemIndex = ++_count;
|
itemIndex = ++_count;
|
||||||
}
|
}
|
||||||
if(_items.Length <= itemIndex)
|
if (_items.Length <= itemIndex)
|
||||||
{
|
{
|
||||||
Array.Resize(ref _items, _items.Length << 1);
|
Array.Resize(ref _items, _items.Length << 1);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,7 +21,7 @@ namespace DCFApixels.DragonECS
|
|||||||
{
|
{
|
||||||
private EcsWorld _source;
|
private EcsWorld _source;
|
||||||
private int _componentTypeID;
|
private int _componentTypeID;
|
||||||
private EcsMaskBit _maskBit;
|
private EcsMaskChunck _maskBit;
|
||||||
|
|
||||||
private int[] _mapping;// index = entityID / value = itemIndex;/ value = 0 = no entityID
|
private int[] _mapping;// index = entityID / value = itemIndex;/ value = 0 = no entityID
|
||||||
private T[] _items; //dense
|
private T[] _items; //dense
|
||||||
@ -175,7 +175,7 @@ namespace DCFApixels.DragonECS
|
|||||||
_source = world;
|
_source = world;
|
||||||
_mediator = mediator;
|
_mediator = mediator;
|
||||||
_componentTypeID = componentTypeID;
|
_componentTypeID = componentTypeID;
|
||||||
_maskBit = EcsMaskBit.FromID(componentTypeID);
|
_maskBit = EcsMaskChunck.FromID(componentTypeID);
|
||||||
|
|
||||||
const int capacity = 512;
|
const int capacity = 512;
|
||||||
|
|
||||||
|
|||||||
@ -11,7 +11,7 @@ namespace DCFApixels.DragonECS
|
|||||||
{
|
{
|
||||||
private EcsWorld _source;
|
private EcsWorld _source;
|
||||||
private int _componentTypeID;
|
private int _componentTypeID;
|
||||||
private EcsMaskBit _maskBit;
|
private EcsMaskChunck _maskBit;
|
||||||
|
|
||||||
private int[] _mapping;// index = entityID / value = itemIndex;/ value = 0 = no entityID
|
private int[] _mapping;// index = entityID / value = itemIndex;/ value = 0 = no entityID
|
||||||
private T[] _items; //dense
|
private T[] _items; //dense
|
||||||
@ -141,7 +141,7 @@ namespace DCFApixels.DragonECS
|
|||||||
_source = world;
|
_source = world;
|
||||||
_mediator = mediator;
|
_mediator = mediator;
|
||||||
_componentTypeID = componentTypeID;
|
_componentTypeID = componentTypeID;
|
||||||
_maskBit = EcsMaskBit.FromID(componentTypeID);
|
_maskBit = EcsMaskChunck.FromID(componentTypeID);
|
||||||
|
|
||||||
const int capacity = 512;
|
const int capacity = 512;
|
||||||
|
|
||||||
|
|||||||
@ -11,7 +11,7 @@ namespace DCFApixels.DragonECS
|
|||||||
{
|
{
|
||||||
private EcsWorld _source;
|
private EcsWorld _source;
|
||||||
private int _componentTypeID;
|
private int _componentTypeID;
|
||||||
private EcsMaskBit _maskBit;
|
private EcsMaskChunck _maskBit;
|
||||||
|
|
||||||
private bool[] _mapping;// index = entityID / value = itemIndex;/ value = 0 = no entityID
|
private bool[] _mapping;// index = entityID / value = itemIndex;/ value = 0 = no entityID
|
||||||
private int _count;
|
private int _count;
|
||||||
@ -124,7 +124,7 @@ namespace DCFApixels.DragonECS
|
|||||||
_source = world;
|
_source = world;
|
||||||
_mediator = mediator;
|
_mediator = mediator;
|
||||||
_componentTypeID = componentTypeID;
|
_componentTypeID = componentTypeID;
|
||||||
_maskBit = EcsMaskBit.FromID(componentTypeID);
|
_maskBit = EcsMaskChunck.FromID(componentTypeID);
|
||||||
|
|
||||||
_mapping = new bool[world.Capacity];
|
_mapping = new bool[world.Capacity];
|
||||||
_count = 0;
|
_count = 0;
|
||||||
|
|||||||
179
src/Utils/ArraySortHalperX.cs
Normal file
179
src/Utils/ArraySortHalperX.cs
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
using System;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
|
||||||
|
namespace DCFApixels.DragonECS.Internal
|
||||||
|
{
|
||||||
|
internal interface IComparerX<T>
|
||||||
|
{
|
||||||
|
// a > b = return > 0
|
||||||
|
int Compare(T a, T b);
|
||||||
|
}
|
||||||
|
internal static class ArraySortHalperX<T>
|
||||||
|
{
|
||||||
|
private const int IntrosortSizeThreshold = 16;
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void SwapIfGreater<TComparer>(T[] items, ref TComparer comparer, int i, int j) where TComparer : IComparerX<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 : IComparerX<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 : IComparerX<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;
|
||||||
|
}
|
||||||
|
IComparerX<T> packed = comparer;
|
||||||
|
Array.Sort(items, comparer.Compare);
|
||||||
|
comparer = (TComparer)packed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 : IComparerX<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 : IComparerX<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 : 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
11
src/Utils/ArraySortHalperX.cs.meta
Normal file
11
src/Utils/ArraySortHalperX.cs.meta
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: a591de1858028504d819333121bfddd6
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@ -1,6 +1,9 @@
|
|||||||
using System.Runtime.CompilerServices;
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System;
|
|
||||||
|
|
||||||
namespace DCFApixels.DragonECS.Utils
|
namespace DCFApixels.DragonECS.Utils
|
||||||
{
|
{
|
||||||
@ -16,7 +19,46 @@ namespace DCFApixels.DragonECS.Utils
|
|||||||
array[i] = value;
|
array[i] = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
internal readonly struct EnumerableInt : IEnumerable<int>
|
||||||
|
{
|
||||||
|
public readonly int start;
|
||||||
|
public readonly int length;
|
||||||
|
private EnumerableInt(int start, int length)
|
||||||
|
{
|
||||||
|
this.start = start;
|
||||||
|
this.length = length;
|
||||||
|
}
|
||||||
|
public static EnumerableInt Range(int start, int length) => new EnumerableInt(start, length);
|
||||||
|
public static EnumerableInt StartEnd(int start, int end) => new EnumerableInt(start, end - start);
|
||||||
|
IEnumerator<int> IEnumerable<int>.GetEnumerator() => GetEnumerator();
|
||||||
|
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public Enumerator GetEnumerator() => new Enumerator(start, start + length);
|
||||||
|
public struct Enumerator : IEnumerator<int>
|
||||||
|
{
|
||||||
|
private readonly int _max;
|
||||||
|
private int _current;
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public Enumerator(int max, int current)
|
||||||
|
{
|
||||||
|
_max = max;
|
||||||
|
_current = current - 1;
|
||||||
|
}
|
||||||
|
public int Current
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get => _current;
|
||||||
|
}
|
||||||
|
object IEnumerator.Current => Current;
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public bool MoveNext() => ++_current < _max;
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public void Reset() { }
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public void Dispose() { }
|
||||||
|
}
|
||||||
|
}
|
||||||
internal static unsafe class UnmanagedArrayUtility
|
internal static unsafe class UnmanagedArrayUtility
|
||||||
{
|
{
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
@ -24,6 +66,11 @@ namespace DCFApixels.DragonECS.Utils
|
|||||||
{
|
{
|
||||||
return (T*)Marshal.AllocHGlobal(Marshal.SizeOf<T>() * capacity).ToPointer();
|
return (T*)Marshal.AllocHGlobal(Marshal.SizeOf<T>() * capacity).ToPointer();
|
||||||
}
|
}
|
||||||
|
[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();
|
||||||
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static T* NewAndInit<T>(int capacity) where T : unmanaged
|
public static T* NewAndInit<T>(int capacity) where T : unmanaged
|
||||||
@ -36,12 +83,39 @@ namespace DCFApixels.DragonECS.Utils
|
|||||||
|
|
||||||
return (T*)newPointer;
|
return (T*)newPointer;
|
||||||
}
|
}
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void NewAndInit<T>(out T* ptr, int capacity) where T : unmanaged
|
||||||
|
{
|
||||||
|
int newSize = Marshal.SizeOf(typeof(T)) * capacity;
|
||||||
|
byte* newPointer = (byte*)Marshal.AllocHGlobal(newSize).ToPointer();
|
||||||
|
|
||||||
|
for (int i = 0; i < newSize; i++)
|
||||||
|
*(newPointer + i) = 0;
|
||||||
|
|
||||||
|
ptr = (T*)newPointer;
|
||||||
|
}
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static void Free(void* pointer)
|
public static void Free(void* pointer)
|
||||||
{
|
{
|
||||||
Marshal.FreeHGlobal(new IntPtr(pointer));
|
Marshal.FreeHGlobal(new IntPtr(pointer));
|
||||||
}
|
}
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static void Free<T>(ref T* pointer, ref int length) where T : unmanaged
|
||||||
|
{
|
||||||
|
Marshal.FreeHGlobal(new IntPtr(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)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static T* Resize<T>(void* oldPointer, int newCount) where T : unmanaged
|
public static T* Resize<T>(void* oldPointer, int newCount) where T : unmanaged
|
||||||
@ -51,4 +125,16 @@ namespace DCFApixels.DragonECS.Utils
|
|||||||
new IntPtr(Marshal.SizeOf(typeof(T)) * newCount))).ToPointer();
|
new IntPtr(Marshal.SizeOf(typeof(T)) * newCount))).ToPointer();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
public static class CollectionUtility
|
||||||
|
{
|
||||||
|
public static string EntitiesToString(IEnumerable<int> range, string name)
|
||||||
|
{
|
||||||
|
return $"{name}({range.Count()}) {{{string.Join(", ", range.OrderBy(o => o))}}})";
|
||||||
|
}
|
||||||
|
public static string AutoToString<T>(IEnumerable<T> range, string name)
|
||||||
|
{
|
||||||
|
return $"{name}({range.Count()}) {{{string.Join(", ", range.Select(o => o.ToString()))}}})";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
1079
src/Utils/BitsUtility.cs
Normal file
1079
src/Utils/BitsUtility.cs
Normal file
File diff suppressed because it is too large
Load Diff
11
src/Utils/BitsUtility.cs.meta
Normal file
11
src/Utils/BitsUtility.cs.meta
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 06a40460050b1ef4fa037b3a3cac9a8b
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@ -157,6 +157,18 @@ namespace DCFApixels.DragonECS
|
|||||||
// }
|
// }
|
||||||
// return retVal;
|
// 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];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void CopyTo(T[] array)
|
public void CopyTo(T[] array)
|
||||||
{
|
{
|
||||||
|
|||||||
95
src/Utils/UnsafeArray.cs
Normal file
95
src/Utils/UnsafeArray.cs
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
using DCFApixels.DragonECS.Utils;
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace DCFApixels.DragonECS.Internal
|
||||||
|
{
|
||||||
|
[DebuggerTypeProxy(typeof(UnsafeArray<>.DebuggerProxy))]
|
||||||
|
internal unsafe struct UnsafeArray<T> : IDisposable, IEnumerable<T>
|
||||||
|
where T : unmanaged
|
||||||
|
{
|
||||||
|
internal T* ptr;
|
||||||
|
internal int Length;
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public UnsafeArray(int length)
|
||||||
|
{
|
||||||
|
UnmanagedArrayUtility.New(out ptr, length);
|
||||||
|
Length = length;
|
||||||
|
}
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public UnsafeArray(int length, bool isInit)
|
||||||
|
{
|
||||||
|
UnmanagedArrayUtility.NewAndInit(out ptr, length);
|
||||||
|
Length = length;
|
||||||
|
}
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private UnsafeArray(T* ptr, int length)
|
||||||
|
{
|
||||||
|
this.ptr = ptr;
|
||||||
|
Length = length;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public UnsafeArray<T> Clone()
|
||||||
|
{
|
||||||
|
return new UnsafeArray<T>(UnmanagedArrayUtility.Clone(ptr, Length), Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
UnmanagedArrayUtility.Free(ref ptr, ref Length);
|
||||||
|
}
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
T* ptr = this.ptr;
|
||||||
|
return CollectionUtility.AutoToString(EnumerableInt.Range(0, Length).Select(i => ptr[i]), "ua");
|
||||||
|
}
|
||||||
|
|
||||||
|
IEnumerator<T> IEnumerable<T>.GetEnumerator() => GetEnumerator();
|
||||||
|
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public Enumerator GetEnumerator() => new Enumerator(ptr, Length);
|
||||||
|
public struct Enumerator : IEnumerator<T>
|
||||||
|
{
|
||||||
|
private readonly T* _ptr;
|
||||||
|
private readonly int _length;
|
||||||
|
private int _index;
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public Enumerator(T* ptr, int length)
|
||||||
|
{
|
||||||
|
_ptr = ptr;
|
||||||
|
_length = length;
|
||||||
|
_index = -1;
|
||||||
|
}
|
||||||
|
public T Current
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get => _ptr[_index];
|
||||||
|
}
|
||||||
|
object IEnumerator.Current => Current;
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public bool MoveNext() => ++_index < _length;
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public void Reset() { }
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public void Dispose() { }
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class DebuggerProxy
|
||||||
|
{
|
||||||
|
public T[] elements;
|
||||||
|
public int length;
|
||||||
|
public DebuggerProxy(UnsafeArray<T> instance)
|
||||||
|
{
|
||||||
|
elements = EnumerableInt.Range(0, instance.Length).Select(i => instance.ptr[i]).ToArray();
|
||||||
|
length = instance.Length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
src/Utils/UnsafeArray.cs.meta
Normal file
11
src/Utils/UnsafeArray.cs.meta
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 5d8f3c5034bb040478b60d7421a38ef8
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
Loading…
Reference in New Issue
Block a user