messages + rearranging
							parent
							
								
									9032eff699
								
							
						
					
					
						commit
						3d2261f739
					
				|  | @ -60,12 +60,27 @@ namespace MoonTools.ECS.Collections | |||
| 				return false; | ||||
| 			} | ||||
| 
 | ||||
| 			/* | ||||
| 			var lastElement = array[Count - 1]; | ||||
| 			var index = indices[element]; | ||||
| 			array[index] = lastElement; | ||||
| 			indices[lastElement] = index; | ||||
| 			count -= 1; | ||||
| 			indices.Remove(element); | ||||
| 			*/ | ||||
| 
 | ||||
| 			// FIXME: we can probably undo this change | ||||
| 
 | ||||
| 			var index = indices[element]; | ||||
| 
 | ||||
| 			for (var i = index; i < Count - 1; i += 1) | ||||
| 			{ | ||||
| 				array[i] = array[i + 1]; | ||||
| 				indices[array[i]] = i; | ||||
| 			} | ||||
| 
 | ||||
| 			indices.Remove(element); | ||||
| 			count -= 1; | ||||
| 
 | ||||
| 			return true; | ||||
| 		} | ||||
|  | @ -0,0 +1,110 @@ | |||
| using System; | ||||
| using System.Runtime.CompilerServices; | ||||
| using System.Runtime.InteropServices; | ||||
| 
 | ||||
| namespace MoonTools.ECS.Collections; | ||||
| 
 | ||||
| public unsafe class NativeArray<T> : IDisposable where T : unmanaged | ||||
| { | ||||
| 	private T* Array; | ||||
| 	private int count; | ||||
| 	private int capacity; | ||||
| 	private int elementSize; | ||||
| 
 | ||||
| 	public int Count => count; | ||||
| 
 | ||||
| 	public Span<T>.Enumerator GetEnumerator() => new Span<T>(Array, count).GetEnumerator(); | ||||
| 
 | ||||
| 	private bool disposed; | ||||
| 
 | ||||
| 	public NativeArray(int capacity = 16) | ||||
| 	{ | ||||
| 		this.capacity = capacity; | ||||
| 		elementSize = Unsafe.SizeOf<T>(); | ||||
| 		Array = (T*) NativeMemory.Alloc((nuint) (capacity * elementSize)); | ||||
| 		count = 0; | ||||
| 	} | ||||
| 
 | ||||
| 	public ref T this[int i] => ref Array[i]; | ||||
| 
 | ||||
| 	public void Add(T item) | ||||
| 	{ | ||||
| 		if (count >= capacity) | ||||
| 		{ | ||||
| 			capacity *= 2; | ||||
| 			Array = (T*) NativeMemory.Realloc(Array, (nuint) (capacity * Unsafe.SizeOf<T>())); | ||||
| 		} | ||||
| 
 | ||||
| 		Array[count] = item; | ||||
| 		count += 1; | ||||
| 	} | ||||
| 
 | ||||
| 	public void RemoveLastElement() | ||||
| 	{ | ||||
| 		count -= 1; | ||||
| 	} | ||||
| 
 | ||||
| 	public bool TryPop(out T element) | ||||
| 	{ | ||||
| 		if (count > 0) | ||||
| 		{ | ||||
| 			element = Array[count - 1]; | ||||
| 			count -= 1; | ||||
| 			return true; | ||||
| 		} | ||||
| 
 | ||||
| 		element = default; | ||||
| 		return false; | ||||
| 	} | ||||
| 
 | ||||
| 	public void Clear() | ||||
| 	{ | ||||
| 		count = 0; | ||||
| 	} | ||||
| 
 | ||||
| 	private void ResizeTo(int size) | ||||
| 	{ | ||||
| 		capacity = size; | ||||
| 		Array = (T*) NativeMemory.Realloc((void*) Array, (nuint) (elementSize * capacity)); | ||||
| 	} | ||||
| 
 | ||||
| 	public void CopyTo(NativeArray<T> other) | ||||
| 	{ | ||||
| 		if (count >= other.capacity) | ||||
| 		{ | ||||
| 			other.ResizeTo(Count); | ||||
| 		} | ||||
| 
 | ||||
| 		NativeMemory.Copy( | ||||
| 			(void*) Array, | ||||
| 			(void*) other.Array, | ||||
| 			(nuint) (elementSize * Count) | ||||
| 		); | ||||
| 
 | ||||
| 		other.count = count; | ||||
| 	} | ||||
| 
 | ||||
| 	protected virtual void Dispose(bool disposing) | ||||
| 	{ | ||||
| 		if (!disposed) | ||||
| 		{ | ||||
| 			NativeMemory.Free(Array); | ||||
| 			Array = null; | ||||
| 
 | ||||
| 			disposed = true; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	~NativeArray() | ||||
| 	{ | ||||
| 		// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method | ||||
| 		Dispose(disposing: false); | ||||
| 	} | ||||
| 
 | ||||
| 	public void Dispose() | ||||
| 	{ | ||||
| 		// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method | ||||
| 		Dispose(disposing: true); | ||||
| 		GC.SuppressFinalize(this); | ||||
| 	} | ||||
| } | ||||
|  | @ -0,0 +1,128 @@ | |||
| using System; | ||||
| using System.Runtime.CompilerServices; | ||||
| using System.Runtime.InteropServices; | ||||
| 
 | ||||
| namespace MoonTools.ECS.Collections; | ||||
| 
 | ||||
| internal unsafe class NativeArray : IDisposable | ||||
| { | ||||
| 	public nint Elements; | ||||
| 	public int Count; | ||||
| 
 | ||||
| 	private int Capacity; | ||||
| 	public readonly int ElementSize; | ||||
| 
 | ||||
| 	private bool IsDisposed; | ||||
| 
 | ||||
| 	public NativeArray(int elementSize) | ||||
| 	{ | ||||
| 		Capacity = 16; | ||||
| 		Count = 0; | ||||
| 		ElementSize = elementSize; | ||||
| 
 | ||||
| 		Elements = (nint) NativeMemory.Alloc((nuint) (ElementSize * Capacity)); | ||||
| 	} | ||||
| 
 | ||||
| 	public Span<T> ToSpan<T>() | ||||
| 	{ | ||||
| 		return new Span<T>((void*) Elements, Count); | ||||
| 	} | ||||
| 
 | ||||
| 	[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||||
| 	public ref T Get<T>(int i) where T : unmanaged | ||||
| 	{ | ||||
| 		return ref ((T*) Elements)[i]; | ||||
| 	} | ||||
| 
 | ||||
| 	private void Resize() | ||||
| 	{ | ||||
| 		Capacity *= 2; | ||||
| 		Elements = (nint) NativeMemory.Realloc((void*) Elements, (nuint) (ElementSize * Capacity)); | ||||
| 	} | ||||
| 
 | ||||
| 	private void ResizeTo(int capacity) | ||||
| 	{ | ||||
| 		Capacity = capacity; | ||||
| 		Elements = (nint) NativeMemory.Realloc((void*) Elements, (nuint) (ElementSize * Capacity)); | ||||
| 	} | ||||
| 
 | ||||
| 	// Fills gap by copying final element to the deleted index | ||||
| 	public void Delete(int index) | ||||
| 	{ | ||||
| 		if (Count > 1) | ||||
| 		{ | ||||
| 			NativeMemory.Copy( | ||||
| 				(void*) (Elements + ((Count - 1) * ElementSize)), | ||||
| 				(void*) (Elements + (index * ElementSize)), | ||||
| 				(nuint) ElementSize | ||||
| 			); | ||||
| 		} | ||||
| 
 | ||||
| 		Count -= 1; | ||||
| 	} | ||||
| 
 | ||||
| 	public void Append<T>(T component) where T : unmanaged | ||||
| 	{ | ||||
| 		if (Count >= Capacity) | ||||
| 		{ | ||||
| 			Resize(); | ||||
| 		} | ||||
| 
 | ||||
| 		((T*) Elements)[Count] = component; | ||||
| 		Count += 1; | ||||
| 	} | ||||
| 
 | ||||
| 	public void CopyElementToEnd(int index, NativeArray other) | ||||
| 	{ | ||||
| 		if (other.Count >= other.Capacity) | ||||
| 		{ | ||||
| 			other.Resize(); | ||||
| 		} | ||||
| 
 | ||||
| 		NativeMemory.Copy( | ||||
| 			(void*) (Elements + (index * ElementSize)), | ||||
| 			(void*) (other.Elements + (other.Count * ElementSize)), | ||||
| 			(nuint) ElementSize | ||||
| 		); | ||||
| 
 | ||||
| 		other.Count += 1; | ||||
| 	} | ||||
| 
 | ||||
| 	public void CopyAllTo(NativeArray other) | ||||
| 	{ | ||||
| 		if (Count >= other.Capacity) | ||||
| 		{ | ||||
| 			other.ResizeTo(Count); | ||||
| 		} | ||||
| 
 | ||||
| 		NativeMemory.Copy( | ||||
| 			(void*) Elements, | ||||
| 			(void*) other.Elements, | ||||
| 			(nuint) (ElementSize * Count) | ||||
| 		); | ||||
| 
 | ||||
| 		other.Count = Count; | ||||
| 	} | ||||
| 
 | ||||
| 	protected virtual void Dispose(bool disposing) | ||||
| 	{ | ||||
| 		if (!IsDisposed) | ||||
| 		{ | ||||
| 			NativeMemory.Free((void*) Elements); | ||||
| 			IsDisposed = true; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	~NativeArray() | ||||
| 	{ | ||||
| 		// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method | ||||
| 		Dispose(disposing: false); | ||||
| 	} | ||||
| 
 | ||||
| 	public void Dispose() | ||||
| 	{ | ||||
| 		// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method | ||||
| 		Dispose(disposing: true); | ||||
| 		GC.SuppressFinalize(this); | ||||
| 	} | ||||
| } | ||||
|  | @ -43,7 +43,7 @@ namespace MoonTools.ECS | |||
| 			return Lookup<TComponent>().Any(); | ||||
| 		} | ||||
| 
 | ||||
| 		public ref readonly TComponent Get<TComponent>(int entityID) where TComponent : unmanaged | ||||
| 		public ref TComponent Get<TComponent>(int entityID) where TComponent : unmanaged | ||||
| 		{ | ||||
| 			return ref Lookup<TComponent>().Get(entityID); | ||||
| 		} | ||||
|  |  | |||
|  | @ -41,7 +41,7 @@ namespace MoonTools.ECS | |||
| 			return count > 0; | ||||
| 		} | ||||
| 
 | ||||
| 		public ref readonly TComponent Get(int entityID) | ||||
| 		public ref TComponent Get(int entityID) | ||||
| 		{ | ||||
| 			return ref components[entityIDToStorageIndex[entityID]]; | ||||
| 		} | ||||
|  | @ -151,6 +151,7 @@ namespace MoonTools.ECS | |||
| 		{ | ||||
| 			return entityIDToStorageIndex.Keys; | ||||
| 		} | ||||
| #endif | ||||
| 
 | ||||
| 		protected virtual void Dispose(bool disposing) | ||||
| 		{ | ||||
|  | @ -177,6 +178,5 @@ namespace MoonTools.ECS | |||
| 			Dispose(disposing: true); | ||||
| 			GC.SuppressFinalize(this); | ||||
| 		} | ||||
| #endif | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -42,7 +42,7 @@ namespace MoonTools.ECS | |||
| 			return Lookup<TMessage>().First(); | ||||
| 		} | ||||
| 
 | ||||
| 		public ReverseSpanEnumerator<TMessage> WithEntity<TMessage>(int entityID) where TMessage : unmanaged | ||||
| 		public Span<TMessage>.Enumerator WithEntity<TMessage>(int entityID) where TMessage : unmanaged | ||||
| 		{ | ||||
| 			return Lookup<TMessage>().WithEntity(entityID); | ||||
| 		} | ||||
|  |  | |||
|  | @ -63,7 +63,7 @@ namespace MoonTools.ECS | |||
| 			return messages[0]; | ||||
| 		} | ||||
| 
 | ||||
| 		public ReverseSpanEnumerator<TMessage> WithEntity(int entityID) | ||||
| 		public Span<TMessage>.Enumerator WithEntity(int entityID) | ||||
| 		{ | ||||
| 			if (entityToMessages.TryGetValue(entityID, out var messages)) | ||||
| 			{ | ||||
|  | @ -71,7 +71,7 @@ namespace MoonTools.ECS | |||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 				return ReverseSpanEnumerator<TMessage>.Empty; | ||||
| 				return Span<TMessage>.Empty.GetEnumerator(); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,111 +0,0 @@ | |||
| using System; | ||||
| using System.Runtime.CompilerServices; | ||||
| using System.Runtime.InteropServices; | ||||
| 
 | ||||
| namespace MoonTools.ECS.Collections | ||||
| { | ||||
| 	public unsafe class NativeArray<T> : IDisposable where T : unmanaged | ||||
| 	{ | ||||
| 		private T* Array; | ||||
| 		private int count; | ||||
| 		private int capacity; | ||||
| 		private int elementSize; | ||||
| 
 | ||||
| 		public int Count => count; | ||||
| 
 | ||||
| 		public Span<T>.Enumerator GetEnumerator() => new Span<T>(Array, count).GetEnumerator(); | ||||
| 
 | ||||
| 		private bool disposed; | ||||
| 
 | ||||
| 		public NativeArray(int capacity = 16) | ||||
| 		{ | ||||
| 			this.capacity = capacity; | ||||
| 			elementSize = Unsafe.SizeOf<T>(); | ||||
| 			Array = (T*) NativeMemory.Alloc((nuint) (capacity * elementSize)); | ||||
| 			count = 0; | ||||
| 		} | ||||
| 
 | ||||
| 		public ref T this[int i] => ref Array[i]; | ||||
| 
 | ||||
| 		public void Add(T item) | ||||
| 		{ | ||||
| 			if (count >= capacity) | ||||
| 			{ | ||||
| 				capacity *= 2; | ||||
| 				Array = (T*) NativeMemory.Realloc(Array, (nuint) (capacity * Unsafe.SizeOf<T>())); | ||||
| 			} | ||||
| 
 | ||||
| 			Array[count] = item; | ||||
| 			count += 1; | ||||
| 		} | ||||
| 
 | ||||
| 		public void RemoveLastElement() | ||||
| 		{ | ||||
| 			count -= 1; | ||||
| 		} | ||||
| 
 | ||||
| 		public bool TryPop(out T element) | ||||
| 		{ | ||||
| 			if (count > 0) | ||||
| 			{ | ||||
| 				element = Array[count - 1]; | ||||
| 				count -= 1; | ||||
| 				return true; | ||||
| 			} | ||||
| 
 | ||||
| 			element = default; | ||||
| 			return false; | ||||
| 		} | ||||
| 
 | ||||
| 		public void Clear() | ||||
| 		{ | ||||
| 			count = 0; | ||||
| 		} | ||||
| 
 | ||||
| 		private void ResizeTo(int size) | ||||
| 		{ | ||||
| 			capacity = size; | ||||
| 			Array = (T*) NativeMemory.Realloc((void*) Array, (nuint) (elementSize * capacity)); | ||||
| 		} | ||||
| 
 | ||||
| 		public void CopyTo(NativeArray<T> other) | ||||
| 		{ | ||||
| 			if (count >= other.capacity) | ||||
| 			{ | ||||
| 				other.ResizeTo(Count); | ||||
| 			} | ||||
| 
 | ||||
| 			NativeMemory.Copy( | ||||
| 				(void*) Array, | ||||
| 				(void*) other.Array, | ||||
| 				(nuint) (elementSize * Count) | ||||
| 			); | ||||
| 
 | ||||
| 			other.count = count; | ||||
| 		} | ||||
| 
 | ||||
| 		protected virtual void Dispose(bool disposing) | ||||
| 		{ | ||||
| 			if (!disposed) | ||||
| 			{ | ||||
| 				NativeMemory.Free(Array); | ||||
| 				Array = null; | ||||
| 
 | ||||
| 				disposed = true; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		~NativeArray() | ||||
| 		{ | ||||
| 			// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method | ||||
| 			Dispose(disposing: false); | ||||
| 		} | ||||
| 
 | ||||
| 		public void Dispose() | ||||
| 		{ | ||||
| 			// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method | ||||
| 			Dispose(disposing: true); | ||||
| 			GC.SuppressFinalize(this); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | @ -7,7 +7,7 @@ internal class Archetype | |||
| { | ||||
| 	public World World; | ||||
| 	public ArchetypeSignature Signature; | ||||
| 	public Column[] ComponentColumns; | ||||
| 	public NativeArray[] ComponentColumns; | ||||
| 	public NativeArray<Id> RowToEntity = new NativeArray<Id>(); | ||||
| 
 | ||||
| 	public Dictionary<Id, int> ComponentToColumnIndex = | ||||
|  | @ -20,7 +20,7 @@ internal class Archetype | |||
| 	{ | ||||
| 		World = world; | ||||
| 		Signature = signature; | ||||
| 		ComponentColumns = new Column[signature.Count]; | ||||
| 		ComponentColumns = new NativeArray[signature.Count]; | ||||
| 	} | ||||
| 
 | ||||
| 	public void ClearAll() | ||||
|  |  | |||
|  | @ -1,4 +1,3 @@ | |||
| namespace MoonTools.ECS.Rev2 | ||||
| { | ||||
| namespace MoonTools.ECS.Rev2; | ||||
| 
 | ||||
| internal readonly record struct ArchetypeEdge(Archetype Add, Archetype Remove); | ||||
| } | ||||
|  |  | |||
|  | @ -1,8 +1,8 @@ | |||
| using System; | ||||
| using System.Collections.Generic; | ||||
| 
 | ||||
| namespace MoonTools.ECS.Rev2 | ||||
| { | ||||
| namespace MoonTools.ECS.Rev2; | ||||
| 
 | ||||
| internal class ArchetypeSignature : IEquatable<ArchetypeSignature> | ||||
| { | ||||
| 	public static ArchetypeSignature Empty = new ArchetypeSignature(0); | ||||
|  | @ -89,4 +89,3 @@ namespace MoonTools.ECS.Rev2 | |||
| 		return hashcode; | ||||
| 	} | ||||
| } | ||||
| } | ||||
|  |  | |||
|  | @ -1,129 +0,0 @@ | |||
| using System; | ||||
| using System.Runtime.CompilerServices; | ||||
| using System.Runtime.InteropServices; | ||||
| 
 | ||||
| namespace MoonTools.ECS.Rev2 | ||||
| { | ||||
| 	internal unsafe class Column : IDisposable | ||||
| 	{ | ||||
| 		public nint Elements; | ||||
| 		public int Count; | ||||
| 
 | ||||
| 		private int Capacity; | ||||
| 		public readonly int ElementSize; | ||||
| 
 | ||||
| 		private bool IsDisposed; | ||||
| 
 | ||||
| 		public Column(int elementSize) | ||||
| 		{ | ||||
| 			Capacity = 16; | ||||
| 			Count = 0; | ||||
| 			ElementSize = elementSize; | ||||
| 
 | ||||
| 			Elements = (nint) NativeMemory.Alloc((nuint) (ElementSize * Capacity)); | ||||
| 		} | ||||
| 
 | ||||
| 		public Span<T> ToSpan<T>() | ||||
| 		{ | ||||
| 			return new Span<T>((void*) Elements, Count); | ||||
| 		} | ||||
| 
 | ||||
| 		[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||||
| 		public ref T Get<T>(int i) where T : unmanaged | ||||
| 		{ | ||||
| 			return ref ((T*) Elements)[i]; | ||||
| 		} | ||||
| 
 | ||||
| 		public void Resize() | ||||
| 		{ | ||||
| 			Capacity *= 2; | ||||
| 			Elements = (nint) NativeMemory.Realloc((void*) Elements, (nuint) (ElementSize * Capacity)); | ||||
| 		} | ||||
| 
 | ||||
| 		public void ResizeTo(int capacity) | ||||
| 		{ | ||||
| 			Capacity = capacity; | ||||
| 			Elements = (nint) NativeMemory.Realloc((void*) Elements, (nuint) (ElementSize * Capacity)); | ||||
| 		} | ||||
| 
 | ||||
| 		// Fills gap by copying final element to the deleted index | ||||
| 		public void Delete(int index) | ||||
| 		{ | ||||
| 			if (Count > 1) | ||||
| 			{ | ||||
| 				NativeMemory.Copy( | ||||
| 					(void*) (Elements + ((Count - 1) * ElementSize)), | ||||
| 					(void*) (Elements + (index * ElementSize)), | ||||
| 					(nuint) ElementSize | ||||
| 				); | ||||
| 			} | ||||
| 
 | ||||
| 			Count -= 1; | ||||
| 		} | ||||
| 
 | ||||
| 		public void Append<T>(T component) where T : unmanaged | ||||
| 		{ | ||||
| 			if (Count >= Capacity) | ||||
| 			{ | ||||
| 				Resize(); | ||||
| 			} | ||||
| 
 | ||||
| 			((T*) Elements)[Count] = component; | ||||
| 			Count += 1; | ||||
| 		} | ||||
| 
 | ||||
| 		public void CopyElementToEnd(int index, Column other) | ||||
| 		{ | ||||
| 			if (other.Count >= other.Capacity) | ||||
| 			{ | ||||
| 				other.Resize(); | ||||
| 			} | ||||
| 
 | ||||
| 			NativeMemory.Copy( | ||||
| 				(void*) (Elements + (index * ElementSize)), | ||||
| 				(void*) (other.Elements + (other.Count * ElementSize)), | ||||
| 				(nuint) ElementSize | ||||
| 			); | ||||
| 
 | ||||
| 			other.Count += 1; | ||||
| 		} | ||||
| 
 | ||||
| 		public void CopyAllTo(Column other) | ||||
| 		{ | ||||
| 			if (Count >= other.Capacity) | ||||
| 			{ | ||||
| 				other.ResizeTo(Count); | ||||
| 			} | ||||
| 
 | ||||
| 			NativeMemory.Copy( | ||||
| 				(void*) Elements, | ||||
| 				(void*) other.Elements, | ||||
| 				(nuint) (ElementSize * Count) | ||||
| 			); | ||||
| 
 | ||||
| 			other.Count = Count; | ||||
| 		} | ||||
| 
 | ||||
| 		protected virtual void Dispose(bool disposing) | ||||
| 		{ | ||||
| 			if (!IsDisposed) | ||||
| 			{ | ||||
| 				NativeMemory.Free((void*) Elements); | ||||
| 				IsDisposed = true; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		~Column() | ||||
| 		{ | ||||
| 		    // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method | ||||
| 		    Dispose(disposing: false); | ||||
| 		} | ||||
| 
 | ||||
| 		public void Dispose() | ||||
| 		{ | ||||
| 			// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method | ||||
| 			Dispose(disposing: true); | ||||
| 			GC.SuppressFinalize(this); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | @ -1,8 +1,8 @@ | |||
| using System; | ||||
| using System.Collections.Generic; | ||||
| 
 | ||||
| namespace MoonTools.ECS.Rev2 | ||||
| { | ||||
| namespace MoonTools.ECS.Rev2; | ||||
| 
 | ||||
| // TODO: do we want to get fancy with queries beyond Include and Exclude? | ||||
| public class Filter | ||||
| { | ||||
|  | @ -201,4 +201,3 @@ namespace MoonTools.ECS.Rev2 | |||
| 		public Id Current => Filter.NthEntity(LinearCongruentialEnumerator.Current); | ||||
| 	} | ||||
| } | ||||
| } | ||||
|  |  | |||
|  | @ -1,7 +1,7 @@ | |||
| using System.Collections.Generic; | ||||
| 
 | ||||
| namespace MoonTools.ECS.Rev2 | ||||
| { | ||||
| namespace MoonTools.ECS.Rev2; | ||||
| 
 | ||||
| public ref struct FilterBuilder | ||||
| { | ||||
| 	World World; | ||||
|  | @ -24,14 +24,14 @@ namespace MoonTools.ECS.Rev2 | |||
| 
 | ||||
| 	public FilterBuilder Include<T>() where T : unmanaged | ||||
| 	{ | ||||
| 			World.TryRegisterTypeId<T>(); | ||||
| 		World.GetTypeId<T>(); | ||||
| 		Included.Add(World.TypeToId[typeof(T)]); | ||||
| 		return new FilterBuilder(World, Included, Excluded); | ||||
| 	} | ||||
| 
 | ||||
| 	public FilterBuilder Exclude<T>() where T : unmanaged | ||||
| 	{ | ||||
| 			World.TryRegisterTypeId<T>(); | ||||
| 		World.GetTypeId<T>(); | ||||
| 		Excluded.Add(World.TypeToId[typeof(T)]); | ||||
| 		return new FilterBuilder(World, Included, Excluded); | ||||
| 	} | ||||
|  | @ -41,4 +41,3 @@ namespace MoonTools.ECS.Rev2 | |||
| 		return new Filter(World.EmptyArchetype, Included, Excluded); | ||||
| 	} | ||||
| } | ||||
| } | ||||
|  |  | |||
|  | @ -1,6 +0,0 @@ | |||
| namespace MoonTools.ECS.Rev2; | ||||
| 
 | ||||
| public interface IHasId | ||||
| { | ||||
| 	public int Id { get; init; } | ||||
| } | ||||
|  | @ -0,0 +1,63 @@ | |||
| using System; | ||||
| using MoonTools.ECS.Collections; | ||||
| 
 | ||||
| namespace MoonTools.ECS.Rev2; | ||||
| 
 | ||||
| public class MessageStorage : IDisposable | ||||
| { | ||||
| 	private NativeArray Messages; | ||||
| 
 | ||||
| 	private bool IsDisposed; | ||||
| 
 | ||||
| 	public MessageStorage(int elementSize) | ||||
| 	{ | ||||
| 		Messages = new NativeArray(elementSize); | ||||
| 	} | ||||
| 
 | ||||
| 	public void Add<T>(in T message) where T : unmanaged | ||||
| 	{ | ||||
| 		Messages.Append(message); | ||||
| 	} | ||||
| 
 | ||||
| 	public bool Some() | ||||
| 	{ | ||||
| 		return Messages.Count > 0; | ||||
| 	} | ||||
| 
 | ||||
| 	public ReadOnlySpan<T> All<T>() where T : unmanaged | ||||
| 	{ | ||||
| 		return Messages.ToSpan<T>(); | ||||
| 	} | ||||
| 
 | ||||
| 	public T First<T>() where T : unmanaged | ||||
| 	{ | ||||
| 		return Messages.Get<T>(0); | ||||
| 	} | ||||
| 
 | ||||
| 	public void Clear() | ||||
| 	{ | ||||
| 		Messages.Count = 0; | ||||
| 	} | ||||
| 
 | ||||
| 	protected virtual void Dispose(bool disposing) | ||||
| 	{ | ||||
| 		if (!IsDisposed) | ||||
| 		{ | ||||
| 			Messages.Dispose(); | ||||
| 			IsDisposed = true; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// ~MessageStorage() | ||||
| 	// { | ||||
| 	// 	// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method | ||||
| 	// 	Dispose(disposing: false); | ||||
| 	// } | ||||
| 
 | ||||
| 	public void Dispose() | ||||
| 	{ | ||||
| 		// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method | ||||
| 		Dispose(disposing: true); | ||||
| 		GC.SuppressFinalize(this); | ||||
| 	} | ||||
| } | ||||
|  | @ -1,4 +1,3 @@ | |||
| namespace MoonTools.ECS.Rev2 | ||||
| { | ||||
| namespace MoonTools.ECS.Rev2; | ||||
| 
 | ||||
| internal readonly record struct Record(Archetype Archetype, int Row); | ||||
| } | ||||
|  |  | |||
|  | @ -8,8 +8,8 @@ namespace MoonTools.ECS.Rev2; | |||
| // TODO: implement this entire class with NativeMemory equivalents, can just memcpy for snapshots | ||||
| internal class RelationStorage | ||||
| { | ||||
| 	internal Column relations; | ||||
| 	internal Column relationDatas; | ||||
| 	internal NativeArray relations; | ||||
| 	internal NativeArray relationDatas; | ||||
| 	internal Dictionary<(Id, Id), int> indices = new Dictionary<(Id, Id), int>(16); | ||||
| 	internal Dictionary<Id, IndexableSet<Id>> outRelations = new Dictionary<Id, IndexableSet<Id>>(16); | ||||
| 	internal Dictionary<Id, IndexableSet<Id>> inRelations = new Dictionary<Id, IndexableSet<Id>>(16); | ||||
|  | @ -19,8 +19,8 @@ internal class RelationStorage | |||
| 
 | ||||
| 	public RelationStorage(int relationDataSize) | ||||
| 	{ | ||||
| 		relations = new Column(Unsafe.SizeOf<(Id, Id)>()); | ||||
| 		relationDatas = new Column(relationDataSize); | ||||
| 		relations = new NativeArray(Unsafe.SizeOf<(Id, Id)>()); | ||||
| 		relationDatas = new NativeArray(relationDataSize); | ||||
| 	} | ||||
| 
 | ||||
| 	public ReverseSpanEnumerator<(Id, Id)> All() | ||||
|  |  | |||
|  | @ -139,20 +139,20 @@ public class Snapshot | |||
| 
 | ||||
| 	private class ArchetypeSnapshot | ||||
| 	{ | ||||
| 		private readonly Column[] ComponentColumns; | ||||
| 		private readonly NativeArray[] ComponentColumns; | ||||
| 		private readonly NativeArray<Id> RowToEntity; | ||||
| 
 | ||||
| 		public int Count => RowToEntity.Count; | ||||
| 
 | ||||
| 		public ArchetypeSnapshot(ArchetypeSignature signature) | ||||
| 		{ | ||||
| 			ComponentColumns = new Column[signature.Count]; | ||||
| 			ComponentColumns = new NativeArray[signature.Count]; | ||||
| 			RowToEntity = new NativeArray<Id>(); | ||||
| 
 | ||||
| 			for (int i = 0; i < signature.Count; i += 1) | ||||
| 			{ | ||||
| 				var componentId = signature[i]; | ||||
| 				ComponentColumns[i] = new Column(World.ElementSizes[componentId]); | ||||
| 				ComponentColumns[i] = new NativeArray(World.ElementSizes[componentId]); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
|  | @ -180,13 +180,13 @@ public class Snapshot | |||
| 
 | ||||
| 	private class RelationSnapshot | ||||
| 	{ | ||||
| 		private Column Relations; | ||||
| 		private Column RelationDatas; | ||||
| 		private NativeArray Relations; | ||||
| 		private NativeArray RelationDatas; | ||||
| 
 | ||||
| 		public RelationSnapshot(int elementSize) | ||||
| 		{ | ||||
| 			Relations = new Column(Unsafe.SizeOf<(Id, Id)>()); | ||||
| 			RelationDatas = new Column(elementSize); | ||||
| 			Relations = new NativeArray(Unsafe.SizeOf<(Id, Id)>()); | ||||
| 			RelationDatas = new NativeArray(elementSize); | ||||
| 		} | ||||
| 
 | ||||
| 		public void Take(RelationStorage relationStorage) | ||||
|  |  | |||
|  | @ -1,11 +1,10 @@ | |||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Runtime.CompilerServices; | ||||
| using System.Runtime.InteropServices; | ||||
| using MoonTools.ECS.Collections; | ||||
| 
 | ||||
| namespace MoonTools.ECS.Rev2 | ||||
| { | ||||
| namespace MoonTools.ECS.Rev2; | ||||
| 
 | ||||
| public class World : IDisposable | ||||
| { | ||||
| 	// Get ComponentId from a Type | ||||
|  | @ -30,6 +29,10 @@ namespace MoonTools.ECS.Rev2 | |||
| 	internal Dictionary<Id, IndexableSet<Id>> EntityRelationIndex = | ||||
| 		new Dictionary<Id, IndexableSet<Id>>(); | ||||
| 
 | ||||
| 	// Message Storages | ||||
| 	private Dictionary<Id, MessageStorage> MessageIndex = | ||||
| 		new Dictionary<Id, MessageStorage>(); | ||||
| 
 | ||||
| 	// ID Management | ||||
| 	// FIXME: Entity and Type Ids should be separated | ||||
| 	internal IdAssigner IdAssigner = new IdAssigner(); | ||||
|  | @ -59,7 +62,7 @@ namespace MoonTools.ECS.Rev2 | |||
| 			var componentId = signature[i]; | ||||
| 			ComponentIndex[componentId].Add(archetype); | ||||
| 			archetype.ComponentToColumnIndex.Add(componentId, i); | ||||
| 				archetype.ComponentColumns[i] = new Column(ElementSizes[componentId]); | ||||
| 			archetype.ComponentColumns[i] = new NativeArray(ElementSizes[componentId]); | ||||
| 		} | ||||
| 
 | ||||
| 		return archetype; | ||||
|  | @ -79,29 +82,25 @@ namespace MoonTools.ECS.Rev2 | |||
| 		return entityId; | ||||
| 	} | ||||
| 
 | ||||
| 		internal void TryRegisterTypeId<T>() where T : unmanaged | ||||
| 	internal Id GetTypeId<T>() where T : unmanaged | ||||
| 	{ | ||||
| 			if (!TypeToId.ContainsKey(typeof(T))) | ||||
| 		if (TypeToId.ContainsKey(typeof(T))) | ||||
| 		{ | ||||
| 			return TypeToId[typeof(T)]; | ||||
| 		} | ||||
| 
 | ||||
| 		var typeId = IdAssigner.Assign(); | ||||
| 		TypeToId.Add(typeof(T), typeId); | ||||
| 		ElementSizes.Add(typeId, Unsafe.SizeOf<T>()); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		// FIXME: would be much more efficient to do all this at load time somehow | ||||
| 		private void RegisterComponent(Id typeId) | ||||
| 		{ | ||||
| 			ComponentIndex.Add(typeId, new List<Archetype>()); | ||||
| 		return typeId; | ||||
| 	} | ||||
| 
 | ||||
| 	private void TryRegisterComponentId<T>() where T : unmanaged | ||||
| 	{ | ||||
| 			TryRegisterTypeId<T>(); | ||||
| 			var typeId = TypeToId[typeof(T)]; | ||||
| 		var typeId = GetTypeId<T>(); | ||||
| 		if (!ComponentIndex.ContainsKey(typeId)) | ||||
| 		{ | ||||
| 				RegisterComponent(typeId); | ||||
| 			ComponentIndex.Add(typeId, new List<Archetype>()); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|  | @ -118,8 +117,7 @@ namespace MoonTools.ECS.Rev2 | |||
| 
 | ||||
| 	private void TryRegisterRelationType<T>() where T : unmanaged | ||||
| 	{ | ||||
| 			TryRegisterTypeId<T>(); | ||||
| 			var typeId = TypeToId[typeof(T)]; | ||||
| 		var typeId = GetTypeId<T>(); | ||||
| 		if (!RelationIndex.ContainsKey(typeId)) | ||||
| 		{ | ||||
| 			RegisterRelationType(typeId); | ||||
|  | @ -132,6 +130,53 @@ namespace MoonTools.ECS.Rev2 | |||
| 		return RelationIndex[TypeToId[typeof(T)]]; | ||||
| 	} | ||||
| 
 | ||||
| 	// Messages | ||||
| 
 | ||||
| 	private Id GetMessageTypeId<T>() where T : unmanaged | ||||
| 	{ | ||||
| 		var typeId = GetTypeId<T>(); | ||||
| 
 | ||||
| 		if (!MessageIndex.ContainsKey(typeId)) | ||||
| 		{ | ||||
| 			MessageIndex.Add(typeId, new MessageStorage(Unsafe.SizeOf<T>())); | ||||
| 		} | ||||
| 
 | ||||
| 		return typeId; | ||||
| 	} | ||||
| 
 | ||||
| 	public void Send<T>(in T message) where T : unmanaged | ||||
| 	{ | ||||
| 		var typeId = GetMessageTypeId<T>(); | ||||
| 		MessageIndex[typeId].Add(message); | ||||
| 	} | ||||
| 
 | ||||
| 	public bool SomeMessage<T>() where T : unmanaged | ||||
| 	{ | ||||
| 		var typeId = GetMessageTypeId<T>(); | ||||
| 		return MessageIndex[typeId].Some(); | ||||
| 	} | ||||
| 
 | ||||
| 	public ReadOnlySpan<T> ReadMessages<T>() where T : unmanaged | ||||
| 	{ | ||||
| 		var typeId = GetMessageTypeId<T>(); | ||||
| 		return MessageIndex[typeId].All<T>(); | ||||
| 	} | ||||
| 
 | ||||
| 	public T ReadMessage<T>() where T : unmanaged | ||||
| 	{ | ||||
| 		var typeId = GetMessageTypeId<T>(); | ||||
| 		return MessageIndex[typeId].First<T>(); | ||||
| 	} | ||||
| 
 | ||||
| 	public void ClearMessages() | ||||
| 	{ | ||||
| 		foreach (var (_, messageStorage) in MessageIndex) | ||||
| 		{ | ||||
| 			messageStorage.Clear(); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// Components | ||||
| 	public bool Has<T>(Id entityId) where T : unmanaged | ||||
| 	{ | ||||
| 		var componentId = GetComponentId<T>(); | ||||
|  | @ -475,4 +520,3 @@ namespace MoonTools.ECS.Rev2 | |||
| 		GC.SuppressFinalize(this); | ||||
| 	} | ||||
| } | ||||
| } | ||||
|  |  | |||
|  | @ -25,7 +25,7 @@ namespace MoonTools.ECS | |||
| 			return MessageDepot.Some<TMessage>(); | ||||
| 		} | ||||
| 
 | ||||
| 		protected ReverseSpanEnumerator<TMessage> ReadMessagesWithEntity<TMessage>(in Entity entity) where TMessage : unmanaged | ||||
| 		protected Span<TMessage>.Enumerator ReadMessagesWithEntity<TMessage>(in Entity entity) where TMessage : unmanaged | ||||
| 		{ | ||||
| 			return MessageDepot.WithEntity<TMessage>(entity.ID); | ||||
| 		} | ||||
|  |  | |||
|  | @ -36,6 +36,11 @@ namespace MoonTools.ECS | |||
| 			return EntityStorage.Tag(entity); | ||||
| 		} | ||||
| 
 | ||||
| 		public ref TComponent Get<TComponent>(in Entity entity) where TComponent : unmanaged | ||||
| 		{ | ||||
| 			return ref ComponentDepot.Get<TComponent>(entity.ID); | ||||
| 		} | ||||
| 
 | ||||
| 		public void Set<TComponent>(Entity entity, in TComponent component) where TComponent : unmanaged | ||||
| 		{ | ||||
| #if DEBUG | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue