file-scoped namespaces + formatting
parent
b27875b9a8
commit
3b1dafdebd
|
@ -3,50 +3,49 @@ using System.Collections.Generic;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace MoonTools.ECS.Collections
|
namespace MoonTools.ECS.Collections;
|
||||||
{
|
|
||||||
public unsafe class IndexableSet<T> : IDisposable where T : unmanaged
|
|
||||||
{
|
|
||||||
private Dictionary<T, int> indices;
|
|
||||||
private T* array;
|
|
||||||
private int count;
|
|
||||||
private int capacity;
|
|
||||||
private bool disposed;
|
|
||||||
|
|
||||||
public int Count => count;
|
public unsafe class IndexableSet<T> : IDisposable where T : unmanaged
|
||||||
public Span<T> AsSpan() => new Span<T>(array, count);
|
{
|
||||||
public ReverseSpanEnumerator<T> GetEnumerator() => new ReverseSpanEnumerator<T>(new Span<T>(array, count));
|
private Dictionary<T, int> Indices;
|
||||||
|
private T* Array;
|
||||||
|
public int Count { get; private set; }
|
||||||
|
private int Capacity;
|
||||||
|
private bool IsDisposed;
|
||||||
|
|
||||||
|
public Span<T> AsSpan() => new Span<T>(Array, Count);
|
||||||
|
public ReverseSpanEnumerator<T> GetEnumerator() => new ReverseSpanEnumerator<T>(new Span<T>(Array, Count));
|
||||||
|
|
||||||
public IndexableSet(int capacity = 32)
|
public IndexableSet(int capacity = 32)
|
||||||
{
|
{
|
||||||
this.capacity = capacity;
|
this.Capacity = capacity;
|
||||||
count = 0;
|
Count = 0;
|
||||||
|
|
||||||
indices = new Dictionary<T, int>(capacity);
|
Indices = new Dictionary<T, int>(capacity);
|
||||||
array = (T*) NativeMemory.Alloc((nuint) (capacity * Unsafe.SizeOf<T>()));
|
Array = (T*) NativeMemory.Alloc((nuint) (capacity * Unsafe.SizeOf<T>()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public T this[int i] => array[i];
|
public T this[int i] => Array[i];
|
||||||
|
|
||||||
public bool Contains(T element)
|
public bool Contains(T element)
|
||||||
{
|
{
|
||||||
return indices.ContainsKey(element);
|
return Indices.ContainsKey(element);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Add(T element)
|
public bool Add(T element)
|
||||||
{
|
{
|
||||||
if (!Contains(element))
|
if (!Contains(element))
|
||||||
{
|
{
|
||||||
indices.Add(element, count);
|
Indices.Add(element, Count);
|
||||||
|
|
||||||
if (count >= capacity)
|
if (Count >= Capacity)
|
||||||
{
|
{
|
||||||
capacity *= 2;
|
Capacity *= 2;
|
||||||
array = (T*) NativeMemory.Realloc(array, (nuint) (capacity * Unsafe.SizeOf<T>()));
|
Array = (T*) NativeMemory.Realloc(Array, (nuint) (Capacity * Unsafe.SizeOf<T>()));
|
||||||
}
|
}
|
||||||
|
|
||||||
array[count] = element;
|
Array[Count] = element;
|
||||||
count += 1;
|
Count += 1;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -61,34 +60,34 @@ namespace MoonTools.ECS.Collections
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var index = indices[element];
|
var index = Indices[element];
|
||||||
|
|
||||||
for (var i = index; i < Count - 1; i += 1)
|
for (var i = index; i < Count - 1; i += 1)
|
||||||
{
|
{
|
||||||
array[i] = array[i + 1];
|
Array[i] = Array[i + 1];
|
||||||
indices[array[i]] = i;
|
Indices[Array[i]] = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
indices.Remove(element);
|
Indices.Remove(element);
|
||||||
count -= 1;
|
Count -= 1;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Clear()
|
public void Clear()
|
||||||
{
|
{
|
||||||
indices.Clear();
|
Indices.Clear();
|
||||||
count = 0;
|
Count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void Dispose(bool disposing)
|
protected virtual void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
if (!disposed)
|
if (!IsDisposed)
|
||||||
{
|
{
|
||||||
NativeMemory.Free(array);
|
NativeMemory.Free(Array);
|
||||||
array = null;
|
Array = null;
|
||||||
|
|
||||||
disposed = true;
|
IsDisposed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,5 +103,4 @@ namespace MoonTools.ECS.Collections
|
||||||
Dispose(disposing: true);
|
Dispose(disposing: true);
|
||||||
GC.SuppressFinalize(this);
|
GC.SuppressFinalize(this);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ public unsafe class NativeArray<T> : IDisposable where T : unmanaged
|
||||||
public Span<T> ToSpan() => new Span<T>(Elements, Count);
|
public Span<T> ToSpan() => new Span<T>(Elements, Count);
|
||||||
public Span<T>.Enumerator GetEnumerator() => new Span<T>(Elements, Count).GetEnumerator();
|
public Span<T>.Enumerator GetEnumerator() => new Span<T>(Elements, Count).GetEnumerator();
|
||||||
|
|
||||||
private bool disposed;
|
private bool IsDisposed;
|
||||||
|
|
||||||
public NativeArray(int capacity = 16)
|
public NativeArray(int capacity = 16)
|
||||||
{
|
{
|
||||||
|
@ -96,12 +96,12 @@ public unsafe class NativeArray<T> : IDisposable where T : unmanaged
|
||||||
|
|
||||||
protected virtual void Dispose(bool disposing)
|
protected virtual void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
if (!disposed)
|
if (!IsDisposed)
|
||||||
{
|
{
|
||||||
NativeMemory.Free(Elements);
|
NativeMemory.Free(Elements);
|
||||||
Elements = null;
|
Elements = null;
|
||||||
|
|
||||||
disposed = true;
|
IsDisposed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,16 +2,16 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using MoonTools.ECS.Collections;
|
using MoonTools.ECS.Collections;
|
||||||
|
|
||||||
namespace MoonTools.ECS
|
namespace MoonTools.ECS;
|
||||||
|
|
||||||
|
internal class ComponentStorage : IDisposable
|
||||||
{
|
{
|
||||||
internal unsafe class ComponentStorage : IDisposable
|
|
||||||
{
|
|
||||||
internal readonly Dictionary<Entity, int> EntityIDToStorageIndex = new Dictionary<Entity, int>(16);
|
internal readonly Dictionary<Entity, int> EntityIDToStorageIndex = new Dictionary<Entity, int>(16);
|
||||||
internal readonly NativeArray Components;
|
internal readonly NativeArray Components;
|
||||||
internal readonly NativeArray<Entity> EntityIDs;
|
internal readonly NativeArray<Entity> EntityIDs;
|
||||||
internal readonly TypeId TypeId;
|
internal readonly TypeId TypeId;
|
||||||
|
|
||||||
private bool disposed;
|
private bool IsDisposed;
|
||||||
|
|
||||||
public ComponentStorage(TypeId typeId, int elementSize)
|
public ComponentStorage(TypeId typeId, int elementSize)
|
||||||
{
|
{
|
||||||
|
@ -116,12 +116,12 @@ namespace MoonTools.ECS
|
||||||
|
|
||||||
protected virtual void Dispose(bool disposing)
|
protected virtual void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
if (!disposed)
|
if (!IsDisposed)
|
||||||
{
|
{
|
||||||
Components.Dispose();
|
Components.Dispose();
|
||||||
EntityIDs.Dispose();
|
EntityIDs.Dispose();
|
||||||
|
|
||||||
disposed = true;
|
IsDisposed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,5 +137,4 @@ namespace MoonTools.ECS
|
||||||
Dispose(disposing: true);
|
Dispose(disposing: true);
|
||||||
GC.SuppressFinalize(this);
|
GC.SuppressFinalize(this);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,3 @@
|
||||||
using System;
|
namespace MoonTools.ECS;
|
||||||
|
|
||||||
namespace MoonTools.ECS
|
public readonly record struct Entity(uint ID);
|
||||||
{
|
|
||||||
public readonly record struct Entity
|
|
||||||
{
|
|
||||||
public uint ID { get; }
|
|
||||||
|
|
||||||
internal Entity(uint id)
|
|
||||||
{
|
|
||||||
ID = id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,23 +1,23 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace MoonTools.ECS
|
namespace MoonTools.ECS;
|
||||||
|
|
||||||
|
public ref struct ReverseSpanEnumerator<T>
|
||||||
{
|
{
|
||||||
public ref struct ReverseSpanEnumerator<T>
|
|
||||||
{
|
|
||||||
private ReadOnlySpan<T> Span;
|
private ReadOnlySpan<T> Span;
|
||||||
private int index;
|
private int Index;
|
||||||
|
|
||||||
public ReverseSpanEnumerator<T> GetEnumerator() => this;
|
public ReverseSpanEnumerator<T> GetEnumerator() => this;
|
||||||
|
|
||||||
public T Current => Span[index];
|
public T Current => Span[Index];
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public bool MoveNext()
|
public bool MoveNext()
|
||||||
{
|
{
|
||||||
if (index > 0)
|
if (Index > 0)
|
||||||
{
|
{
|
||||||
index -= 1;
|
Index -= 1;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,9 +28,8 @@ namespace MoonTools.ECS
|
||||||
public ReverseSpanEnumerator(Span<T> span)
|
public ReverseSpanEnumerator(Span<T> span)
|
||||||
{
|
{
|
||||||
Span = span;
|
Span = span;
|
||||||
index = span.Length;
|
Index = span.Length;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ReverseSpanEnumerator<T> Empty => new ReverseSpanEnumerator<T>();
|
public static ReverseSpanEnumerator<T> Empty => new ReverseSpanEnumerator<T>();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
using System.Collections.Generic;
|
using MoonTools.ECS.Collections;
|
||||||
using MoonTools.ECS.Collections;
|
|
||||||
|
|
||||||
namespace MoonTools.ECS
|
namespace MoonTools.ECS
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
using System;
|
using System;
|
||||||
using MoonTools.ECS.Collections;
|
using MoonTools.ECS.Collections;
|
||||||
|
|
||||||
namespace MoonTools.ECS
|
namespace MoonTools.ECS;
|
||||||
|
|
||||||
|
public struct FilterSignature : IEquatable<FilterSignature>
|
||||||
{
|
{
|
||||||
public struct FilterSignature : IEquatable<FilterSignature>
|
|
||||||
{
|
|
||||||
public readonly IndexableSet<TypeId> Included;
|
public readonly IndexableSet<TypeId> Included;
|
||||||
public readonly IndexableSet<TypeId> Excluded;
|
public readonly IndexableSet<TypeId> Excluded;
|
||||||
|
|
||||||
|
@ -66,5 +66,4 @@ namespace MoonTools.ECS
|
||||||
{
|
{
|
||||||
return !(left == right);
|
return !(left == right);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
namespace MoonTools.ECS
|
namespace MoonTools.ECS;
|
||||||
|
|
||||||
|
public abstract class Manipulator : EntityComponentReader
|
||||||
{
|
{
|
||||||
public abstract class Manipulator : EntityComponentReader
|
|
||||||
{
|
|
||||||
public Manipulator(World world) : base(world)
|
public Manipulator(World world) : base(world)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -15,5 +15,4 @@ namespace MoonTools.ECS
|
||||||
protected void Unrelate<TRelationKind>(in Entity entityA, in Entity entityB) where TRelationKind : unmanaged => World.Unrelate<TRelationKind>(entityA, entityB);
|
protected void Unrelate<TRelationKind>(in Entity entityA, in Entity entityB) where TRelationKind : unmanaged => World.Unrelate<TRelationKind>(entityA, entityB);
|
||||||
protected void UnrelateAll<TRelationKind>(in Entity entity) where TRelationKind : unmanaged => World.UnrelateAll<TRelationKind>(entity);
|
protected void UnrelateAll<TRelationKind>(in Entity entity) where TRelationKind : unmanaged => World.UnrelateAll<TRelationKind>(entity);
|
||||||
protected void Destroy(in Entity entity) => World.Destroy(entity);
|
protected void Destroy(in Entity entity) => World.Destroy(entity);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@ public class MessageStorage : IDisposable
|
||||||
Messages.Clear();
|
Messages.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void Dispose(bool disposing)
|
private void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
if (!IsDisposed)
|
if (!IsDisposed)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace MoonTools.ECS
|
namespace MoonTools.ECS;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This class implements the well equidistributed long-period linear pseudorandom number generator.
|
||||||
|
/// Code taken from Chris Lomont: http://lomont.org/papers/2008/Lomont_PRNG_2008.pdf
|
||||||
|
/// </summary>
|
||||||
|
public class Random
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// This class implements the well equidistributed long-period linear pseudorandom number generator.
|
|
||||||
/// Code taken from Chris Lomont: http://lomont.org/papers/2008/Lomont_PRNG_2008.pdf
|
|
||||||
/// </summary>
|
|
||||||
public class Random
|
|
||||||
{
|
|
||||||
public const int STATE_BYTE_COUNT = 68; // 16 state ints + 1 index int
|
public const int STATE_BYTE_COUNT = 68; // 16 state ints + 1 index int
|
||||||
|
|
||||||
uint[] State = new uint[16];
|
uint[] State = new uint[16];
|
||||||
|
@ -67,12 +67,12 @@ namespace MoonTools.ECS
|
||||||
/// <exception cref="ArgumentException">Thrown if the byte span is too short.</exception>
|
/// <exception cref="ArgumentException">Thrown if the byte span is too short.</exception>
|
||||||
public unsafe void SaveState(Span<byte> bytes)
|
public unsafe void SaveState(Span<byte> bytes)
|
||||||
{
|
{
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
if (bytes.Length < STATE_BYTE_COUNT)
|
if (bytes.Length < STATE_BYTE_COUNT)
|
||||||
{
|
{
|
||||||
throw new ArgumentException("Byte span too short!");
|
throw new ArgumentException("Byte span too short!");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
fixed (byte* ptr = bytes)
|
fixed (byte* ptr = bytes)
|
||||||
{
|
{
|
||||||
|
@ -94,12 +94,12 @@ namespace MoonTools.ECS
|
||||||
/// <exception cref="ArgumentException">Thrown if the byte span is too short.</exception>
|
/// <exception cref="ArgumentException">Thrown if the byte span is too short.</exception>
|
||||||
public unsafe void LoadState(Span<byte> bytes)
|
public unsafe void LoadState(Span<byte> bytes)
|
||||||
{
|
{
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
if (bytes.Length < STATE_BYTE_COUNT)
|
if (bytes.Length < STATE_BYTE_COUNT)
|
||||||
{
|
{
|
||||||
throw new ArgumentException("Byte span too short!");
|
throw new ArgumentException("Byte span too short!");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
fixed (byte* ptr = bytes)
|
fixed (byte* ptr = bytes)
|
||||||
{
|
{
|
||||||
|
@ -205,5 +205,4 @@ namespace MoonTools.ECS
|
||||||
var n = NextInternal();
|
var n = NextInternal();
|
||||||
return ((double) n) / uint.MaxValue;
|
return ((double) n) / uint.MaxValue;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
namespace MoonTools.ECS
|
namespace MoonTools.ECS;
|
||||||
|
|
||||||
|
public static class RandomManager
|
||||||
{
|
{
|
||||||
public static class RandomManager
|
|
||||||
{
|
|
||||||
private static Random Random = new Random();
|
private static Random Random = new Random();
|
||||||
|
|
||||||
private static int[] Primes =
|
private static int[] Primes =
|
||||||
|
@ -41,10 +41,10 @@ namespace MoonTools.ECS
|
||||||
|
|
||||||
return new LinearCongruentialEnumerator(Random.Next(n), x, n);
|
return new LinearCongruentialEnumerator(Random.Next(n), x, n);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public struct LinearCongruentialEnumerator
|
public struct LinearCongruentialEnumerator
|
||||||
{
|
{
|
||||||
private readonly int start;
|
private readonly int start;
|
||||||
private readonly int count;
|
private readonly int count;
|
||||||
private readonly int prime;
|
private readonly int prime;
|
||||||
|
@ -78,5 +78,4 @@ namespace MoonTools.ECS
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
get => (current * prime) % count;
|
get => (current * prime) % count;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,67 +8,67 @@ namespace MoonTools.ECS;
|
||||||
// TODO: implement this entire class with NativeMemory equivalents, can just memcpy for snapshots
|
// TODO: implement this entire class with NativeMemory equivalents, can just memcpy for snapshots
|
||||||
internal class RelationStorage
|
internal class RelationStorage
|
||||||
{
|
{
|
||||||
internal NativeArray relations;
|
internal NativeArray Relations;
|
||||||
internal NativeArray relationDatas;
|
internal NativeArray RelationDatas;
|
||||||
internal Dictionary<(Entity, Entity), int> indices = new Dictionary<(Entity, Entity), int>(16);
|
internal Dictionary<(Entity, Entity), int> Indices = new Dictionary<(Entity, Entity), int>(16);
|
||||||
internal Dictionary<Entity, IndexableSet<Entity>> outRelations = new Dictionary<Entity, IndexableSet<Entity>>(16);
|
internal Dictionary<Entity, IndexableSet<Entity>> OutRelationSets = new Dictionary<Entity, IndexableSet<Entity>>(16);
|
||||||
internal Dictionary<Entity, IndexableSet<Entity>> inRelations = new Dictionary<Entity, IndexableSet<Entity>>(16);
|
internal Dictionary<Entity, IndexableSet<Entity>> InRelationSets = new Dictionary<Entity, IndexableSet<Entity>>(16);
|
||||||
private Stack<IndexableSet<Entity>> listPool = new Stack<IndexableSet<Entity>>();
|
private Stack<IndexableSet<Entity>> ListPool = new Stack<IndexableSet<Entity>>();
|
||||||
|
|
||||||
private bool disposed;
|
private bool IsDisposed;
|
||||||
|
|
||||||
public RelationStorage(int relationDataSize)
|
public RelationStorage(int relationDataSize)
|
||||||
{
|
{
|
||||||
relations = new NativeArray(Unsafe.SizeOf<(Entity, Entity)>());
|
Relations = new NativeArray(Unsafe.SizeOf<(Entity, Entity)>());
|
||||||
relationDatas = new NativeArray(relationDataSize);
|
RelationDatas = new NativeArray(relationDataSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReverseSpanEnumerator<(Entity, Entity)> All()
|
public ReverseSpanEnumerator<(Entity, Entity)> All()
|
||||||
{
|
{
|
||||||
return new ReverseSpanEnumerator<(Entity, Entity)>(relations.ToSpan<(Entity, Entity)>());
|
return new ReverseSpanEnumerator<(Entity, Entity)>(Relations.ToSpan<(Entity, Entity)>());
|
||||||
}
|
}
|
||||||
|
|
||||||
public unsafe void Set<T>(in Entity entityA, in Entity entityB, in T relationData) where T : unmanaged
|
public unsafe void Set<T>(in Entity entityA, in Entity entityB, in T relationData) where T : unmanaged
|
||||||
{
|
{
|
||||||
var relation = (entityA, entityB);
|
var relation = (entityA, entityB);
|
||||||
|
|
||||||
if (indices.TryGetValue(relation, out var index))
|
if (Indices.TryGetValue(relation, out var index))
|
||||||
{
|
{
|
||||||
relationDatas.Set(index, relationData);
|
RelationDatas.Set(index, relationData);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!outRelations.ContainsKey(entityA))
|
if (!OutRelationSets.ContainsKey(entityA))
|
||||||
{
|
{
|
||||||
outRelations[entityA] = AcquireHashSetFromPool();
|
OutRelationSets[entityA] = AcquireHashSetFromPool();
|
||||||
}
|
}
|
||||||
outRelations[entityA].Add(entityB);
|
OutRelationSets[entityA].Add(entityB);
|
||||||
|
|
||||||
if (!inRelations.ContainsKey(entityB))
|
if (!InRelationSets.ContainsKey(entityB))
|
||||||
{
|
{
|
||||||
inRelations[entityB] = AcquireHashSetFromPool();
|
InRelationSets[entityB] = AcquireHashSetFromPool();
|
||||||
}
|
}
|
||||||
inRelations[entityB].Add(entityA);
|
InRelationSets[entityB].Add(entityA);
|
||||||
|
|
||||||
relations.Append(relation);
|
Relations.Append(relation);
|
||||||
relationDatas.Append(relationData);
|
RelationDatas.Append(relationData);
|
||||||
indices.Add(relation, relations.Count - 1);
|
Indices.Add(relation, Relations.Count - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ref T Get<T>(in Entity entityA, in Entity entityB) where T : unmanaged
|
public ref T Get<T>(in Entity entityA, in Entity entityB) where T : unmanaged
|
||||||
{
|
{
|
||||||
var relationIndex = indices[(entityA, entityB)];
|
var relationIndex = Indices[(entityA, entityB)];
|
||||||
return ref relationDatas.Get<T>(relationIndex);
|
return ref RelationDatas.Get<T>(relationIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Has(Entity entityA, Entity entityB)
|
public bool Has(Entity entityA, Entity entityB)
|
||||||
{
|
{
|
||||||
return indices.ContainsKey((entityA, entityB));
|
return Indices.ContainsKey((entityA, entityB));
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReverseSpanEnumerator<Entity> OutRelations(Entity Entity)
|
public ReverseSpanEnumerator<Entity> OutRelations(Entity Entity)
|
||||||
{
|
{
|
||||||
if (outRelations.TryGetValue(Entity, out var entityOutRelations))
|
if (OutRelationSets.TryGetValue(Entity, out var entityOutRelations))
|
||||||
{
|
{
|
||||||
return entityOutRelations.GetEnumerator();
|
return entityOutRelations.GetEnumerator();
|
||||||
}
|
}
|
||||||
|
@ -86,27 +86,27 @@ internal class RelationStorage
|
||||||
public Entity OutNth(Entity Entity, int n)
|
public Entity OutNth(Entity Entity, int n)
|
||||||
{
|
{
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
if (!outRelations.ContainsKey(Entity) || outRelations[Entity].Count == 0)
|
if (!OutRelationSets.ContainsKey(Entity) || OutRelationSets[Entity].Count == 0)
|
||||||
{
|
{
|
||||||
throw new KeyNotFoundException("No out relations to this entity!");
|
throw new KeyNotFoundException("No out relations to this entity!");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return outRelations[Entity][n];
|
return OutRelationSets[Entity][n];
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool HasOutRelation(Entity Entity)
|
public bool HasOutRelation(Entity Entity)
|
||||||
{
|
{
|
||||||
return outRelations.ContainsKey(Entity) && outRelations[Entity].Count > 0;
|
return OutRelationSets.ContainsKey(Entity) && OutRelationSets[Entity].Count > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int OutRelationCount(Entity Entity)
|
public int OutRelationCount(Entity Entity)
|
||||||
{
|
{
|
||||||
return outRelations.TryGetValue(Entity, out var entityOutRelations) ? entityOutRelations.Count : 0;
|
return OutRelationSets.TryGetValue(Entity, out var entityOutRelations) ? entityOutRelations.Count : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReverseSpanEnumerator<Entity> InRelations(Entity Entity)
|
public ReverseSpanEnumerator<Entity> InRelations(Entity Entity)
|
||||||
{
|
{
|
||||||
if (inRelations.TryGetValue(Entity, out var entityInRelations))
|
if (InRelationSets.TryGetValue(Entity, out var entityInRelations))
|
||||||
{
|
{
|
||||||
return entityInRelations.GetEnumerator();
|
return entityInRelations.GetEnumerator();
|
||||||
}
|
}
|
||||||
|
@ -124,23 +124,23 @@ internal class RelationStorage
|
||||||
public Entity InNth(Entity Entity, int n)
|
public Entity InNth(Entity Entity, int n)
|
||||||
{
|
{
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
if (!inRelations.ContainsKey(Entity) || inRelations[Entity].Count == 0)
|
if (!InRelationSets.ContainsKey(Entity) || InRelationSets[Entity].Count == 0)
|
||||||
{
|
{
|
||||||
throw new KeyNotFoundException("No in relations to this entity!");
|
throw new KeyNotFoundException("No in relations to this entity!");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return inRelations[Entity][n];
|
return InRelationSets[Entity][n];
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool HasInRelation(Entity Entity)
|
public bool HasInRelation(Entity Entity)
|
||||||
{
|
{
|
||||||
return inRelations.ContainsKey(Entity) && inRelations[Entity].Count > 0;
|
return InRelationSets.ContainsKey(Entity) && InRelationSets[Entity].Count > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int InRelationCount(Entity Entity)
|
public int InRelationCount(Entity Entity)
|
||||||
{
|
{
|
||||||
return inRelations.TryGetValue(Entity, out var entityInRelations) ? entityInRelations.Count : 0;
|
return InRelationSets.TryGetValue(Entity, out var entityInRelations) ? entityInRelations.Count : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public (bool, bool) Remove(in Entity entityA, in Entity entityB)
|
public (bool, bool) Remove(in Entity entityA, in Entity entityB)
|
||||||
|
@ -149,39 +149,39 @@ internal class RelationStorage
|
||||||
var bEmpty = false;
|
var bEmpty = false;
|
||||||
var relation = (entityA, entityB);
|
var relation = (entityA, entityB);
|
||||||
|
|
||||||
if (outRelations.TryGetValue(entityA, out var entityOutRelations))
|
if (OutRelationSets.TryGetValue(entityA, out var entityOutRelations))
|
||||||
{
|
{
|
||||||
entityOutRelations.Remove(entityB);
|
entityOutRelations.Remove(entityB);
|
||||||
if (outRelations[entityA].Count == 0)
|
if (OutRelationSets[entityA].Count == 0)
|
||||||
{
|
{
|
||||||
aEmpty = true;
|
aEmpty = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inRelations.TryGetValue(entityB, out var entityInRelations))
|
if (InRelationSets.TryGetValue(entityB, out var entityInRelations))
|
||||||
{
|
{
|
||||||
entityInRelations.Remove(entityA);
|
entityInRelations.Remove(entityA);
|
||||||
if (inRelations[entityB].Count == 0)
|
if (InRelationSets[entityB].Count == 0)
|
||||||
{
|
{
|
||||||
bEmpty = true;
|
bEmpty = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (indices.TryGetValue(relation, out var index))
|
if (Indices.TryGetValue(relation, out var index))
|
||||||
{
|
{
|
||||||
var lastElementIndex = relations.Count - 1;
|
var lastElementIndex = Relations.Count - 1;
|
||||||
|
|
||||||
// move an element into the hole
|
// move an element into the hole
|
||||||
if (index != lastElementIndex)
|
if (index != lastElementIndex)
|
||||||
{
|
{
|
||||||
var lastRelation = relations.Get<(Entity, Entity)>(lastElementIndex);
|
var lastRelation = Relations.Get<(Entity, Entity)>(lastElementIndex);
|
||||||
indices[lastRelation] = index;
|
Indices[lastRelation] = index;
|
||||||
}
|
}
|
||||||
|
|
||||||
relationDatas.Delete(index);
|
RelationDatas.Delete(index);
|
||||||
relations.Delete(index);
|
Relations.Delete(index);
|
||||||
|
|
||||||
indices.Remove(relation);
|
Indices.Remove(relation);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (aEmpty, bEmpty);
|
return (aEmpty, bEmpty);
|
||||||
|
@ -189,7 +189,7 @@ internal class RelationStorage
|
||||||
|
|
||||||
public void RemoveEntity(in Entity entity)
|
public void RemoveEntity(in Entity entity)
|
||||||
{
|
{
|
||||||
if (outRelations.TryGetValue(entity, out var entityOutRelations))
|
if (OutRelationSets.TryGetValue(entity, out var entityOutRelations))
|
||||||
{
|
{
|
||||||
foreach (var entityB in entityOutRelations)
|
foreach (var entityB in entityOutRelations)
|
||||||
{
|
{
|
||||||
|
@ -197,10 +197,10 @@ internal class RelationStorage
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnHashSetToPool(entityOutRelations);
|
ReturnHashSetToPool(entityOutRelations);
|
||||||
outRelations.Remove(entity);
|
OutRelationSets.Remove(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inRelations.TryGetValue(entity, out var entityInRelations))
|
if (InRelationSets.TryGetValue(entity, out var entityInRelations))
|
||||||
{
|
{
|
||||||
foreach (var entityA in entityInRelations)
|
foreach (var entityA in entityInRelations)
|
||||||
{
|
{
|
||||||
|
@ -208,64 +208,64 @@ internal class RelationStorage
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnHashSetToPool(entityInRelations);
|
ReturnHashSetToPool(entityInRelations);
|
||||||
inRelations.Remove(entity);
|
InRelationSets.Remove(entity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal IndexableSet<Entity> AcquireHashSetFromPool()
|
internal IndexableSet<Entity> AcquireHashSetFromPool()
|
||||||
{
|
{
|
||||||
if (listPool.Count == 0)
|
if (ListPool.Count == 0)
|
||||||
{
|
{
|
||||||
listPool.Push(new IndexableSet<Entity>());
|
ListPool.Push(new IndexableSet<Entity>());
|
||||||
}
|
}
|
||||||
|
|
||||||
return listPool.Pop();
|
return ListPool.Pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ReturnHashSetToPool(IndexableSet<Entity> hashSet)
|
private void ReturnHashSetToPool(IndexableSet<Entity> hashSet)
|
||||||
{
|
{
|
||||||
hashSet.Clear();
|
hashSet.Clear();
|
||||||
listPool.Push(hashSet);
|
ListPool.Push(hashSet);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Clear()
|
public void Clear()
|
||||||
{
|
{
|
||||||
indices.Clear();
|
Indices.Clear();
|
||||||
|
|
||||||
foreach (var set in inRelations.Values)
|
foreach (var set in InRelationSets.Values)
|
||||||
{
|
{
|
||||||
ReturnHashSetToPool(set);
|
ReturnHashSetToPool(set);
|
||||||
}
|
}
|
||||||
inRelations.Clear();
|
InRelationSets.Clear();
|
||||||
|
|
||||||
foreach (var set in outRelations.Values)
|
foreach (var set in OutRelationSets.Values)
|
||||||
{
|
{
|
||||||
ReturnHashSetToPool(set);
|
ReturnHashSetToPool(set);
|
||||||
}
|
}
|
||||||
outRelations.Clear();
|
OutRelationSets.Clear();
|
||||||
|
|
||||||
relations.Clear();
|
Relations.Clear();
|
||||||
relationDatas.Clear();
|
RelationDatas.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void Dispose(bool disposing)
|
protected virtual void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
if (!disposed)
|
if (!IsDisposed)
|
||||||
{
|
{
|
||||||
Clear();
|
Clear();
|
||||||
|
|
||||||
if (disposing)
|
if (disposing)
|
||||||
{
|
{
|
||||||
foreach (var set in listPool)
|
foreach (var set in ListPool)
|
||||||
{
|
{
|
||||||
set.Dispose();
|
set.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
relations.Dispose();
|
Relations.Dispose();
|
||||||
relationDatas.Dispose();
|
RelationDatas.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
disposed = true;
|
IsDisposed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
namespace MoonTools.ECS
|
namespace MoonTools.ECS;
|
||||||
|
|
||||||
|
public abstract class Renderer : EntityComponentReader
|
||||||
{
|
{
|
||||||
public abstract class Renderer : EntityComponentReader
|
|
||||||
{
|
|
||||||
public Renderer(World world) : base(world) { }
|
public Renderer(World world) : base(world) { }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -205,7 +205,7 @@ public class Snapshot
|
||||||
{
|
{
|
||||||
if (!RelationSnapshots.TryGetValue(typeId, out var snapshot))
|
if (!RelationSnapshots.TryGetValue(typeId, out var snapshot))
|
||||||
{
|
{
|
||||||
snapshot = new RelationSnapshot(relationStorage.relationDatas.ElementSize);
|
snapshot = new RelationSnapshot(relationStorage.RelationDatas.ElementSize);
|
||||||
RelationSnapshots.Add(typeId, snapshot);
|
RelationSnapshots.Add(typeId, snapshot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -256,39 +256,39 @@ public class Snapshot
|
||||||
|
|
||||||
public void Take(RelationStorage relationStorage)
|
public void Take(RelationStorage relationStorage)
|
||||||
{
|
{
|
||||||
relationStorage.relations.CopyAllTo(Relations);
|
relationStorage.Relations.CopyAllTo(Relations);
|
||||||
relationStorage.relationDatas.CopyAllTo(RelationDatas);
|
relationStorage.RelationDatas.CopyAllTo(RelationDatas);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Restore(RelationStorage relationStorage)
|
public void Restore(RelationStorage relationStorage)
|
||||||
{
|
{
|
||||||
relationStorage.Clear();
|
relationStorage.Clear();
|
||||||
|
|
||||||
Relations.CopyAllTo(relationStorage.relations);
|
Relations.CopyAllTo(relationStorage.Relations);
|
||||||
RelationDatas.CopyAllTo(relationStorage.relationDatas);
|
RelationDatas.CopyAllTo(relationStorage.RelationDatas);
|
||||||
|
|
||||||
for (int index = 0; index < Relations.Count; index += 1)
|
for (int index = 0; index < Relations.Count; index += 1)
|
||||||
{
|
{
|
||||||
var relation = Relations.Get<(Entity, Entity)>(index);
|
var relation = Relations.Get<(Entity, Entity)>(index);
|
||||||
relationStorage.indices[relation] = index;
|
relationStorage.Indices[relation] = index;
|
||||||
|
|
||||||
relationStorage.indices[relation] = index;
|
relationStorage.Indices[relation] = index;
|
||||||
|
|
||||||
if (!relationStorage.outRelations.ContainsKey(relation.Item1))
|
if (!relationStorage.OutRelationSets.ContainsKey(relation.Item1))
|
||||||
{
|
{
|
||||||
relationStorage.outRelations[relation.Item1] =
|
relationStorage.OutRelationSets[relation.Item1] =
|
||||||
relationStorage.AcquireHashSetFromPool();
|
relationStorage.AcquireHashSetFromPool();
|
||||||
}
|
}
|
||||||
|
|
||||||
relationStorage.outRelations[relation.Item1].Add(relation.Item2);
|
relationStorage.OutRelationSets[relation.Item1].Add(relation.Item2);
|
||||||
|
|
||||||
if (!relationStorage.inRelations.ContainsKey(relation.Item2))
|
if (!relationStorage.InRelationSets.ContainsKey(relation.Item2))
|
||||||
{
|
{
|
||||||
relationStorage.inRelations[relation.Item2] =
|
relationStorage.InRelationSets[relation.Item2] =
|
||||||
relationStorage.AcquireHashSetFromPool();
|
relationStorage.AcquireHashSetFromPool();
|
||||||
}
|
}
|
||||||
|
|
||||||
relationStorage.inRelations[relation.Item2].Add(relation.Item1);
|
relationStorage.InRelationSets[relation.Item2].Add(relation.Item1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
21
src/World.cs
21
src/World.cs
|
@ -3,16 +3,16 @@ using System.Collections.Generic;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using MoonTools.ECS.Collections;
|
using MoonTools.ECS.Collections;
|
||||||
|
|
||||||
namespace MoonTools.ECS
|
namespace MoonTools.ECS;
|
||||||
|
|
||||||
|
public class World : IDisposable
|
||||||
{
|
{
|
||||||
public class World : IDisposable
|
|
||||||
{
|
|
||||||
// Get TypeId from a Type
|
// Get TypeId from a Type
|
||||||
private readonly Dictionary<Type, TypeId> TypeToId = new Dictionary<Type, TypeId>();
|
private readonly Dictionary<Type, TypeId> TypeToId = new Dictionary<Type, TypeId>();
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
private Dictionary<TypeId, Type> IdToType = new Dictionary<TypeId, Type>();
|
private Dictionary<TypeId, Type> IdToType = new Dictionary<TypeId, Type>();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Get element size from a TypeId
|
// Get element size from a TypeId
|
||||||
private readonly Dictionary<TypeId, int> ElementSizes = new Dictionary<TypeId, int>();
|
private readonly Dictionary<TypeId, int> ElementSizes = new Dictionary<TypeId, int>();
|
||||||
|
@ -52,9 +52,9 @@ namespace MoonTools.ECS
|
||||||
TypeToId.Add(typeof(T), typeId);
|
TypeToId.Add(typeof(T), typeId);
|
||||||
ElementSizes.Add(typeId, Unsafe.SizeOf<T>());
|
ElementSizes.Add(typeId, Unsafe.SizeOf<T>());
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
IdToType.Add(typeId, typeof(T));
|
IdToType.Add(typeId, typeof(T));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return typeId;
|
return typeId;
|
||||||
}
|
}
|
||||||
|
@ -409,7 +409,7 @@ namespace MoonTools.ECS
|
||||||
// DEBUG
|
// DEBUG
|
||||||
// NOTE: these methods are very inefficient
|
// NOTE: these methods are very inefficient
|
||||||
// they should only be used in debugging contexts!!
|
// they should only be used in debugging contexts!!
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
public ComponentTypeEnumerator Debug_GetAllComponentTypes(Entity entity)
|
public ComponentTypeEnumerator Debug_GetAllComponentTypes(Entity entity)
|
||||||
{
|
{
|
||||||
return new ComponentTypeEnumerator(this, EntityComponentIndex[entity]);
|
return new ComponentTypeEnumerator(this, EntityComponentIndex[entity]);
|
||||||
|
@ -456,9 +456,9 @@ namespace MoonTools.ECS
|
||||||
return ComponentIndex < Types.Count;
|
return ComponentIndex < Types.Count;
|
||||||
}
|
}
|
||||||
|
|
||||||
public unsafe Type Current => World.IdToType[Types[ComponentIndex]];
|
public Type Current => World.IdToType[Types[ComponentIndex]];
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
protected virtual void Dispose(bool disposing)
|
protected virtual void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
|
@ -517,5 +517,4 @@ namespace MoonTools.ECS
|
||||||
Dispose(disposing: true);
|
Dispose(disposing: true);
|
||||||
GC.SuppressFinalize(this);
|
GC.SuppressFinalize(this);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue