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
{
public static class EcsGraphExtensions
public static class EntityGraphExtensions
{
private static EntityGraph[] _worldGraphs = new EntityGraph[4];

View File

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

View File

@ -1,7 +1,4 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@ -46,64 +43,18 @@ namespace DCFApixels.DragonECS.Graphs.Internal
{
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
{
private static class MetaCache<T>
{
public readonly static int Size;
static MetaCache()
{
T def = default;
Size = Marshal.SizeOf(def);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static T* New<T>(int capacity) where T : unmanaged
{
@ -112,28 +63,32 @@ namespace DCFApixels.DragonECS.Graphs.Internal
[MethodImpl(MethodImplOptions.AggressiveInlining)]
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)]
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();
for (int i = 0; i < newSize; i++)
{
*(newPointer + i) = 0;
}
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;
int newSize = MetaCache<T>.Size * capacity;
byte* newPointer = (byte*)Marshal.AllocHGlobal(newSize).ToPointer();
for (int i = 0; i < newSize; i++)
{
*(newPointer + i) = 0;
}
ptr = (T*)newPointer;
}
@ -167,12 +122,12 @@ namespace DCFApixels.DragonECS.Graphs.Internal
{
return (T*)Marshal.ReAllocHGlobal(
new IntPtr(oldPointer),
new IntPtr(Marshal.SizeOf<T>(default) * newCount)).ToPointer();
new IntPtr(MetaCache<T>.Size * newCount)).ToPointer();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
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(
new IntPtr(oldPointer),
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)]
public bool Equals(RelationInfo other) { return this == other; }
[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})"; }
#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: