This commit is contained in:
DCFApixels 2024-11-17 21:17:06 +08:00
parent e2b68d2b08
commit cde2952bf9
9 changed files with 53 additions and 1399 deletions

View File

@ -3,7 +3,7 @@ using System;
namespace DCFApixels.DragonECS namespace DCFApixels.DragonECS
{ {
public static class EcsGraphExtensions public static class EntityGraphExtensions
{ {
private static EntityGraph[] _worldGraphs = new EntityGraph[4]; private static EntityGraph[] _worldGraphs = new EntityGraph[4];

View File

@ -27,12 +27,15 @@ namespace DCFApixels.DragonECS
private LinkedList _linkedList; private LinkedList _linkedList;
private LinkedListHead[] _linkedListSourceHeads; private LinkedListHead[] _linkedListSourceHeads;
private int[] _startEntities; private int[] _sourceEntities;
private int _startEntitiesCount; private int _sourceEntitiesCount;
private int _targetWorldCapacity = -1; private int _targetWorldCapacity = -1;
private EcsProfilerMarker _executeMarker = new EcsProfilerMarker("Join"); private EcsProfilerMarker _executeMarker = new EcsProfilerMarker("Join");
public bool _isDestroyed = false;
#region Properties #region Properties
public sealed override long Version public sealed override long Version
{ {
@ -62,13 +65,17 @@ namespace DCFApixels.DragonECS
_versionsChecker = new WorldStateVersionsChecker(Mask); _versionsChecker = new WorldStateVersionsChecker(Mask);
_linkedList = new OnlyAppendHeadLinkedList(World.Capacity); _linkedList = new OnlyAppendHeadLinkedList(World.Capacity);
_linkedListSourceHeads = new LinkedListHead[World.Capacity]; _linkedListSourceHeads = new LinkedListHead[World.Capacity];
_sourceEntities = new int[World.Capacity * 2];
World.AddListener(this); World.AddListener(this);
_graph = World.GetGraph(); _graph = World.GetGraph();
_iterator = Mask.GetIterator(); _iterator = Mask.GetIterator();
} }
protected override void OnDestroy() protected override void OnDestroy()
{ {
if (_isDestroyed) { return; }
_isDestroyed = true;
World.RemoveListener(this); World.RemoveListener(this);
_versionsChecker.Dispose();
} }
#endregion #endregion
@ -79,24 +86,16 @@ namespace DCFApixels.DragonECS
World.ReleaseDelEntityBufferAllAuto(); World.ReleaseDelEntityBufferAllAuto();
if (Mask.IsEmpty) if (Mask.IsEmpty || _versionsChecker.CheckAndNext() == false)
{
_filteredAllEntitiesCount = World.Entities.ToArray(ref _filteredAllEntities);
}
else
{
if (_versionsChecker.CheckAndNext() == false)
{ {
_filteredAllEntitiesCount = _iterator.IterateTo(World.Entities, ref _filteredAllEntities); _filteredAllEntitiesCount = _iterator.IterateTo(World.Entities, ref _filteredAllEntities);
////Подготовка массивов //Подготовка массивов
//if (_startEntities.Length < _filteredAllEntitiesCount * 2) if (_sourceEntities.Length < _filteredAllEntitiesCount * 2)
//{ {
// _startEntities = new int[_filteredAllEntitiesCount * 2]; _sourceEntities = new int[_filteredAllEntitiesCount * 2];
//}
} }
} }
//установка текущего массива //установка текущего массива
_currentFilteredEntities = _filteredAllEntities; _currentFilteredEntities = _filteredAllEntities;
_currentFilteredEntitiesCount = _filteredAllEntitiesCount; _currentFilteredEntitiesCount = _filteredAllEntitiesCount;
@ -106,13 +105,17 @@ namespace DCFApixels.DragonECS
{ {
_targetWorldCapacity = World.Capacity; _targetWorldCapacity = World.Capacity;
_linkedListSourceHeads = new LinkedListHead[_targetWorldCapacity]; _linkedListSourceHeads = new LinkedListHead[_targetWorldCapacity];
_startEntities = new int[_targetWorldCapacity]; //_startEntities = new int[_targetWorldCapacity];
} }
else else
{ {
ArrayUtility.Fill(_linkedListSourceHeads, default); //TODO оптимизировать, сделав не полную отчистку а только по элементов с прошлого раза //ArrayUtility.Fill(_linkedListSourceHeads, default); //TODO оптимизировать, сделав не полную отчистку а только по элементов с прошлого раза
for (int i = 0; i < _sourceEntitiesCount; i++)
{
_linkedListSourceHeads[_sourceEntities[i]] = default;
} }
_startEntitiesCount = 0; }
_sourceEntitiesCount = 0;
_linkedList.Clear(); _linkedList.Clear();
//Заполнение массивов //Заполнение массивов
@ -249,7 +252,7 @@ namespace DCFApixels.DragonECS
ref var basket = ref _linkedListSourceHeads[sourceEntityID]; ref var basket = ref _linkedListSourceHeads[sourceEntityID];
if (basket.head == 0) if (basket.head == 0)
{ {
_startEntities[_startEntitiesCount++] = sourceEntityID; _sourceEntities[_sourceEntitiesCount++] = sourceEntityID;
basket.head = _linkedList.NewHead(relationEntityID); basket.head = _linkedList.NewHead(relationEntityID);
} }
else else
@ -309,7 +312,7 @@ namespace DCFApixels.DragonECS
#region GetEntites #region GetEntites
internal EcsSpan GetSourceEntities() internal EcsSpan GetSourceEntities()
{ {
return UncheckedCoreUtility.CreateSpan(WorldID, _startEntities, _startEntitiesCount); return UncheckedCoreUtility.CreateSpan(WorldID, _sourceEntities, _sourceEntitiesCount);
} }
internal EcsSpan GetRelEntities() internal EcsSpan GetRelEntities()
{ {

View File

@ -1,7 +1,4 @@
using System; using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
@ -46,64 +43,18 @@ namespace DCFApixels.DragonECS.Graphs.Internal
{ {
return 1 << (GetHighBitNumber((uint)minSize - 1u) + 1); return 1 << (GetHighBitNumber((uint)minSize - 1u) + 1);
} }
public static void Fill<T>(T[] array, T value, int startIndex = 0, int length = -1)
{
if (length < 0)
{
length = array.Length;
}
else
{
length = startIndex + length;
}
for (int i = startIndex; i < length; i++)
{
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
{ {
private static class MetaCache<T>
{
public readonly static int Size;
static MetaCache()
{
T def = default;
Size = Marshal.SizeOf(def);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T* New<T>(int capacity) where T : unmanaged public static T* New<T>(int capacity) where T : unmanaged
{ {
@ -112,28 +63,32 @@ namespace DCFApixels.DragonECS.Graphs.Internal
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void New<T>(out T* ptr, int capacity) where T : unmanaged public static void New<T>(out T* ptr, int capacity) where T : unmanaged
{ {
ptr = (T*)Marshal.AllocHGlobal(Marshal.SizeOf<T>(default) * capacity).ToPointer(); 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
{ {
int newSize = Marshal.SizeOf(typeof(T)) * capacity; int newSize = MetaCache<T>.Size * capacity;
byte* newPointer = (byte*)Marshal.AllocHGlobal(newSize).ToPointer(); byte* newPointer = (byte*)Marshal.AllocHGlobal(newSize).ToPointer();
for (int i = 0; i < newSize; i++) for (int i = 0; i < newSize; i++)
{
*(newPointer + i) = 0; *(newPointer + i) = 0;
}
return (T*)newPointer; return (T*)newPointer;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void NewAndInit<T>(out T* ptr, int capacity) where T : unmanaged public static void NewAndInit<T>(out T* ptr, int capacity) where T : unmanaged
{ {
int newSize = Marshal.SizeOf(typeof(T)) * capacity; int newSize = MetaCache<T>.Size * capacity;
byte* newPointer = (byte*)Marshal.AllocHGlobal(newSize).ToPointer(); byte* newPointer = (byte*)Marshal.AllocHGlobal(newSize).ToPointer();
for (int i = 0; i < newSize; i++) for (int i = 0; i < newSize; i++)
{
*(newPointer + i) = 0; *(newPointer + i) = 0;
}
ptr = (T*)newPointer; ptr = (T*)newPointer;
} }
@ -167,12 +122,12 @@ namespace DCFApixels.DragonECS.Graphs.Internal
{ {
return (T*)Marshal.ReAllocHGlobal( return (T*)Marshal.ReAllocHGlobal(
new IntPtr(oldPointer), new IntPtr(oldPointer),
new IntPtr(Marshal.SizeOf<T>(default) * newCount)).ToPointer(); new IntPtr(MetaCache<T>.Size * newCount)).ToPointer();
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T* ResizeAndInit<T>(void* oldPointer, int oldSize, int newSize) where T : unmanaged public static T* ResizeAndInit<T>(void* oldPointer, int oldSize, int newSize) where T : unmanaged
{ {
int sizeT = Marshal.SizeOf<T>(default); int sizeT = MetaCache<T>.Size;
T* result = (T*)Marshal.ReAllocHGlobal( T* result = (T*)Marshal.ReAllocHGlobal(
new IntPtr(oldPointer), new IntPtr(oldPointer),
new IntPtr(sizeT * newSize)).ToPointer(); new IntPtr(sizeT * newSize)).ToPointer();
@ -189,16 +144,4 @@ namespace DCFApixels.DragonECS.Graphs.Internal
} }
} }
} }
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()))}}})";
}
}
} }

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -55,7 +55,17 @@ namespace DCFApixels.DragonECS.Graphs.Internal
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(RelationInfo other) { return this == other; } public bool Equals(RelationInfo other) { return this == other; }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public override int GetHashCode() { return start ^ BitsUtility.NextXorShiftState(end); } public override int GetHashCode()
{
unchecked
{
uint endHash = (uint)end;
endHash ^= endHash << 13;
endHash ^= endHash >> 17;
endHash ^= endHash << 5;
return start ^ (int)endHash;
}
}
public override string ToString() { return $"arc({start} -> {end})"; } public override string ToString() { return $"arc({start} -> {end})"; }
#endregion #endregion
} }

View File

@ -1,217 +0,0 @@
//SparseArray. Analogous to Dictionary<int, T>, but faster.
//Benchmark result of indexer.get speed test with 300 elements:
//[Dictinary: 5.786us] [SparseArray: 2.047us].
using System;
using System.Diagnostics.Contracts;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace DCFApixels.DragonECS.Graphs.Internal
{
internal class SparseArray<TValue>
{
public const int MIN_CAPACITY_BITS_OFFSET = 4;
public const int MIN_CAPACITY = 1 << MIN_CAPACITY_BITS_OFFSET;
private const int EMPTY = -1;
private int[] _buckets = Array.Empty<int>();
private Entry[] _entries = Array.Empty<Entry>();
private int _count;
private int _freeList;
private int _freeCount;
private int _modBitMask;
#region Properties
public TValue this[int keyX, int keyY]
{
get => _entries[FindEntry((keyX << 32) | keyY)].value;
set => Insert(keyX + (keyY << 32), value);
}
public TValue this[int key]
{
get => _entries[FindEntry(key)].value;
set => Insert(key, value);
}
public int Count => _count;
#endregion
#region Constructors
public SparseArray(int minCapacity = MIN_CAPACITY)
{
minCapacity = NormalizeCapacity(minCapacity);
_buckets = new int[minCapacity];
for (int i = 0; i < minCapacity; i++)
_buckets[i] = EMPTY;
_entries = new Entry[minCapacity];
_modBitMask = (minCapacity - 1) & 0x7FFFFFFF;
}
#endregion
#region Add/Contains/Remove
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Add(int keyX, int keyY, TValue value) => Add((keyX << 32) | keyY, value);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Add(int key, TValue value)
{
#if DEBUG
if (Contains(key))
throw new ArgumentException("Contains(hashKey) is true");
#endif
Insert(key, value);
}
public bool Contains(int keyX, int keyY) => FindEntry((keyX << 32) | keyY) >= 0;
public bool Contains(int key) => FindEntry(key) >= 0;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Remove(int keyX, int keyY) => Remove((keyX << 32) | keyY);
public bool Remove(int key)
{
int bucket = key & _modBitMask;
int last = -1;
for (int i = _buckets[bucket]; i >= 0; last = i, i = _entries[i].next)
{
if (_entries[i].hashKey == key)
{
if (last < 0)
{
_buckets[bucket] = _entries[i].next;
}
else
{
_entries[last].next = _entries[i].next;
}
_entries[i].next = _freeList;
_entries[i].hashKey = -1;
_entries[i].value = default;
_freeList = i;
_freeCount++;
return true;
}
}
return false;
}
#endregion
#region Find/Insert
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private int FindEntry(int key)
{
for (int i = _buckets[key & _modBitMask]; i >= 0; i = _entries[i].next)
if (_entries[i].hashKey == key) return i;
return -1;
}
private void Insert(int key, TValue value)
{
int targetBucket = key & _modBitMask;
for (int i = _buckets[targetBucket]; i >= 0; i = _entries[i].next)
{
if (_entries[i].hashKey == key)
{
_entries[i].value = value;
return;
}
}
int index;
if (_freeCount > 0)
{
index = _freeList;
_freeList = _entries[index].next;
_freeCount--;
}
else
{
if (_count == _entries.Length)
{
Resize();
targetBucket = key & _modBitMask;
}
index = _count++;
}
_entries[index].next = _buckets[targetBucket];
_entries[index].hashKey = key;
_entries[index].value = value;
_buckets[targetBucket] = index;
}
#endregion
#region TryGetValue
public bool TryGetValue(int key, out TValue value)
{
int index = FindEntry(key);
if (index < 0)
{
value = default;
return false;
}
value = _entries[index].value;
return true;
}
#endregion
#region Clear
public void Clear()
{
if (_count > 0)
{
for (int i = 0; i < _buckets.Length; i++)
{
_buckets[i] = -1;
}
Array.Clear(_entries, 0, _count);
_count = 0;
}
}
#endregion
#region Resize
private void Resize()
{
int newSize = _buckets.Length << 1;
_modBitMask = (newSize - 1) & 0x7FFFFFFF;
Contract.Assert(newSize >= _entries.Length);
int[] newBuckets = new int[newSize];
for (int i = 0; i < newBuckets.Length; i++)
newBuckets[i] = EMPTY;
Entry[] newEntries = new Entry[newSize];
Array.Copy(_entries, 0, newEntries, 0, _count);
for (int i = 0; i < _count; i++)
{
if (newEntries[i].hashKey >= 0)
{
int bucket = newEntries[i].hashKey % newSize;
newEntries[i].next = newBuckets[bucket];
newBuckets[bucket] = i;
}
}
_buckets = newBuckets;
_entries = newEntries;
}
private int NormalizeCapacity(int capacity)
{
int result = MIN_CAPACITY;
while (result < capacity) result <<= 1;
return result;
}
#endregion
#region Utils
[StructLayout(LayoutKind.Sequential, Pack = 4)]
private struct Entry
{
public int next; // Index of next entry, -1 if last
public int hashKey;
public TValue value;
}
#endregion
}
}

View File

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