refactor collections to use NativeMemory
							parent
							
								
									231575757e
								
							
						
					
					
						commit
						4722445f11
					
				|  | @ -89,7 +89,7 @@ namespace MoonTools.ECS | |||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		// these methods used to implement snapshots, templates, and debugging | ||||
| 		// these methods used to implement transfers and debugging | ||||
| 
 | ||||
| 		internal unsafe void* UntypedGet(int entityID, int componentTypeIndex) | ||||
| 		{ | ||||
|  |  | |||
|  | @ -1,5 +1,7 @@ | |||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Runtime.CompilerServices; | ||||
| using System.Runtime.InteropServices; | ||||
| 
 | ||||
| namespace MoonTools.ECS | ||||
| { | ||||
|  | @ -19,16 +21,24 @@ namespace MoonTools.ECS | |||
| #endif | ||||
| 	} | ||||
| 
 | ||||
| 	internal class ComponentStorage<TComponent> : ComponentStorage where TComponent : unmanaged | ||||
| 	internal unsafe class ComponentStorage<TComponent> : ComponentStorage, IDisposable where TComponent : unmanaged | ||||
| 	{ | ||||
| 		private int nextID; | ||||
| 		private readonly Dictionary<int, int> entityIDToStorageIndex = new Dictionary<int, int>(16); | ||||
| 		private int[] entityIDs = new int[16]; | ||||
| 		private TComponent[] components = new TComponent[16]; | ||||
| 		private TComponent* components; | ||||
| 		private int* entityIDs; | ||||
| 		private int count = 0; | ||||
| 		private int capacity = 16; | ||||
| 		private bool disposed; | ||||
| 
 | ||||
| 		public ComponentStorage() | ||||
| 		{ | ||||
| 			components = (TComponent*) NativeMemory.Alloc((nuint) (capacity * Unsafe.SizeOf<TComponent>())); | ||||
| 			entityIDs = (int*) NativeMemory.Alloc((nuint) (capacity * Unsafe.SizeOf<int>())); | ||||
| 		} | ||||
| 
 | ||||
| 		public bool Any() | ||||
| 		{ | ||||
| 			return nextID > 0; | ||||
| 			return count > 0; | ||||
| 		} | ||||
| 
 | ||||
| 		public ref readonly TComponent Get(int entityID) | ||||
|  | @ -38,16 +48,13 @@ namespace MoonTools.ECS | |||
| 
 | ||||
| 		internal override unsafe void* UntypedGet(int entityID) | ||||
| 		{ | ||||
| 			fixed (void* p = &components[entityIDToStorageIndex[entityID]]) | ||||
| 			{ | ||||
| 				return p; | ||||
| 			} | ||||
| 			return &components[entityIDToStorageIndex[entityID]]; | ||||
| 		} | ||||
| 
 | ||||
| 		public ref readonly TComponent GetFirst() | ||||
| 		{ | ||||
| #if DEBUG | ||||
| 			if (nextID == 0) | ||||
| 			if (count == 0) | ||||
| 			{ | ||||
| 				throw new IndexOutOfRangeException("Component storage is empty!"); | ||||
| 			} | ||||
|  | @ -59,13 +66,14 @@ namespace MoonTools.ECS | |||
| 		{ | ||||
| 			if (!entityIDToStorageIndex.ContainsKey(entityID)) | ||||
| 			{ | ||||
| 				var index = nextID; | ||||
| 				nextID += 1; | ||||
| 				var index = count; | ||||
| 				count += 1; | ||||
| 
 | ||||
| 				if (index >= components.Length) | ||||
| 				if (index >= capacity) | ||||
| 				{ | ||||
| 					Array.Resize(ref components, components.Length * 2); | ||||
| 					Array.Resize(ref entityIDs, entityIDs.Length * 2); | ||||
| 					capacity *= 2; | ||||
| 					components = (TComponent*) NativeMemory.Realloc(components, (nuint) (capacity * Unsafe.SizeOf<TComponent>())); | ||||
| 					entityIDs = (int*) NativeMemory.Realloc(entityIDs, (nuint) (capacity * Unsafe.SizeOf<int>())); | ||||
| 				} | ||||
| 
 | ||||
| 				entityIDToStorageIndex[entityID] = index; | ||||
|  | @ -77,7 +85,7 @@ namespace MoonTools.ECS | |||
| 
 | ||||
| 		internal override unsafe void Set(int entityID, void* component) | ||||
| 		{ | ||||
| 			Set(entityID, *((TComponent*) component)); | ||||
| 			Set(entityID, *(TComponent*) component); | ||||
| 		} | ||||
| 
 | ||||
| 		// Returns true if the entity had this component. | ||||
|  | @ -87,7 +95,7 @@ namespace MoonTools.ECS | |||
| 			{ | ||||
| 				entityIDToStorageIndex.Remove(entityID); | ||||
| 
 | ||||
| 				var lastElementIndex = nextID - 1; | ||||
| 				var lastElementIndex = count - 1; | ||||
| 
 | ||||
| 				// move a component into the hole to maintain contiguous memory | ||||
| 				if (lastElementIndex != storageIndex) | ||||
|  | @ -98,7 +106,7 @@ namespace MoonTools.ECS | |||
| 					entityIDs[storageIndex] = lastEntityID; | ||||
| 				} | ||||
| 
 | ||||
| 				nextID -= 1; | ||||
| 				count -= 1; | ||||
| 
 | ||||
| 				return true; | ||||
| 			} | ||||
|  | @ -108,19 +116,19 @@ namespace MoonTools.ECS | |||
| 
 | ||||
| 		public override void Clear() | ||||
| 		{ | ||||
| 			nextID = 0; | ||||
| 			count = 0; | ||||
| 			entityIDToStorageIndex.Clear(); | ||||
| 		} | ||||
| 
 | ||||
| 		public ReadOnlySpan<TComponent> AllComponents() | ||||
| 		{ | ||||
| 			return new ReadOnlySpan<TComponent>(components, 0, nextID); | ||||
| 			return new ReadOnlySpan<TComponent>(components, count); | ||||
| 		} | ||||
| 
 | ||||
| 		public Entity FirstEntity() | ||||
| 		{ | ||||
| #if DEBUG | ||||
| 			if (nextID == 0) | ||||
| 			if (count == 0) | ||||
| 			{ | ||||
| 				throw new IndexOutOfRangeException("Component storage is empty!"); | ||||
| 			} | ||||
|  | @ -143,6 +151,32 @@ namespace MoonTools.ECS | |||
| 		{ | ||||
| 			return entityIDToStorageIndex.Keys; | ||||
| 		} | ||||
| 
 | ||||
| 		protected virtual void Dispose(bool disposing) | ||||
| 		{ | ||||
| 			if (!disposed) | ||||
| 			{ | ||||
| 				NativeMemory.Free(components); | ||||
| 				NativeMemory.Free(entityIDs); | ||||
| 				components = null; | ||||
| 				entityIDs = null; | ||||
| 
 | ||||
| 				disposed = true; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		~ComponentStorage() | ||||
| 		{ | ||||
| 			// 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); | ||||
| 		} | ||||
| #endif | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -1,40 +1,69 @@ | |||
| using System; | ||||
| using System.Runtime.CompilerServices; | ||||
| using System.Runtime.InteropServices; | ||||
| 
 | ||||
| namespace MoonTools.ECS | ||||
| namespace MoonTools.ECS.Collections | ||||
| { | ||||
| 	public class DynamicArray<T> where T : unmanaged | ||||
| 	public unsafe class NativeArray<T> : IDisposable where T : unmanaged | ||||
| 	{ | ||||
| 		private T[] Array; | ||||
| 		public int Count { get; private set; } | ||||
| 		private T* Array; | ||||
| 		private int count; | ||||
| 		private int capacity; | ||||
| 
 | ||||
| 		public Span<T> ToSpan() => new Span<T>(Array, 0, Count); | ||||
| 		public ReverseSpanEnumerator<T> GetEnumerator() => new ReverseSpanEnumerator<T>(new Span<T>(Array, 0, Count)); | ||||
| 		public int Count => count; | ||||
| 
 | ||||
| 		public DynamicArray(int capacity = 16) | ||||
| 		public ReverseSpanEnumerator<T> GetEnumerator() => new ReverseSpanEnumerator<T>(new Span<T>(Array, Count)); | ||||
| 
 | ||||
| 		private bool disposed; | ||||
| 
 | ||||
| 		public NativeArray(int capacity = 16) | ||||
| 		{ | ||||
| 			Array = new T[capacity]; | ||||
| 			Count = 0; | ||||
| 			this.capacity = capacity; | ||||
| 			Array = (T*) NativeMemory.Alloc((nuint) (capacity * Unsafe.SizeOf<T>())); | ||||
| 			count = 0; | ||||
| 		} | ||||
| 
 | ||||
| 		public ref T this[int i] | ||||
| 		{ | ||||
| 			get { return ref Array[i]; } | ||||
| 		} | ||||
| 		public ref T this[int i] => ref Array[i]; | ||||
| 
 | ||||
| 		public void Add(T item) | ||||
| 		{ | ||||
| 			if (Count >= Array.Length) | ||||
| 			if (count >= capacity) | ||||
| 			{ | ||||
| 				global::System.Array.Resize(ref Array, Array.Length * 2); | ||||
| 				capacity *= 2; | ||||
| 				Array = (T*) NativeMemory.Realloc(Array, (nuint) (capacity * Unsafe.SizeOf<T>())); | ||||
| 			} | ||||
| 
 | ||||
| 			Array[Count] = item; | ||||
| 			Count += 1; | ||||
| 			Array[count] = item; | ||||
| 			count += 1; | ||||
| 		} | ||||
| 
 | ||||
| 		public void Clear() | ||||
| 		{ | ||||
| 			Count = 0; | ||||
| 			count = 0; | ||||
| 		} | ||||
| 
 | ||||
| 		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); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -1,5 +1,6 @@ | |||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using MoonTools.ECS.Collections; | ||||
| 
 | ||||
| namespace MoonTools.ECS | ||||
| { | ||||
|  |  | |||
|  | @ -1,26 +1,31 @@ | |||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Runtime.CompilerServices; | ||||
| using System.Runtime.InteropServices; | ||||
| 
 | ||||
| namespace MoonTools.ECS | ||||
| namespace MoonTools.ECS.Collections | ||||
| { | ||||
| 	internal class IndexableSet<T> where T : unmanaged | ||||
| 	public unsafe class IndexableSet<T> : IDisposable where T : unmanaged | ||||
| 	{ | ||||
| 		private Dictionary<T, int> indices; | ||||
| 		private T[] array; | ||||
| 		public int Count { get; private set; } | ||||
| 		public ReverseSpanEnumerator<T> GetEnumerator() => new ReverseSpanEnumerator<T>(new Span<T>(array, 0, Count)); | ||||
| 		private T* array; | ||||
| 		private int count; | ||||
| 		private int capacity; | ||||
| 		private bool disposed; | ||||
| 
 | ||||
| 		public IndexableSet(int size = 32) | ||||
| 		public int Count => count; | ||||
| 		public ReverseSpanEnumerator<T> GetEnumerator() => new ReverseSpanEnumerator<T>(new Span<T>(array, count)); | ||||
| 
 | ||||
| 		public IndexableSet(int capacity = 32) | ||||
| 		{ | ||||
| 			indices = new Dictionary<T, int>(size); | ||||
| 			array = new T[size]; | ||||
| 			this.capacity = capacity; | ||||
| 			count = 0; | ||||
| 
 | ||||
| 			indices = new Dictionary<T, int>(capacity); | ||||
| 			array = (T*) NativeMemory.Alloc((nuint) (capacity * Unsafe.SizeOf<T>())); | ||||
| 		} | ||||
| 
 | ||||
| 		public T this[int i] | ||||
| 		{ | ||||
| 			get { return array[i]; } | ||||
| 		} | ||||
| 		public T this[int i] => array[i]; | ||||
| 
 | ||||
| 		public bool Contains(T element) | ||||
| 		{ | ||||
|  | @ -31,15 +36,16 @@ namespace MoonTools.ECS | |||
| 		{ | ||||
| 			if (!Contains(element)) | ||||
| 			{ | ||||
| 				indices.Add(element, Count); | ||||
| 				indices.Add(element, count); | ||||
| 
 | ||||
| 				if (Count >= array.Length) | ||||
| 				if (count >= capacity) | ||||
| 				{ | ||||
| 					Array.Resize(ref array, array.Length * 2); | ||||
| 					capacity *= 2; | ||||
| 					array = (T*) NativeMemory.Realloc(array, (nuint) (capacity * Unsafe.SizeOf<T>())); | ||||
| 				} | ||||
| 
 | ||||
| 				array[Count] = element; | ||||
| 				Count += 1; | ||||
| 				array[count] = element; | ||||
| 				count += 1; | ||||
| 
 | ||||
| 				return true; | ||||
| 			} | ||||
|  | @ -58,7 +64,7 @@ namespace MoonTools.ECS | |||
| 			var index = indices[element]; | ||||
| 			array[index] = lastElement; | ||||
| 			indices[lastElement] = index; | ||||
| 			Count -= 1; | ||||
| 			count -= 1; | ||||
| 			indices.Remove(element); | ||||
| 
 | ||||
| 			return true; | ||||
|  | @ -66,45 +72,32 @@ namespace MoonTools.ECS | |||
| 
 | ||||
| 		public void Clear() | ||||
| 		{ | ||||
| 			Count = 0; | ||||
| 			indices.Clear(); | ||||
| 			count = 0; | ||||
| 		} | ||||
| 
 | ||||
| 		public struct Enumerator | ||||
| 		protected virtual void Dispose(bool disposing) | ||||
| 		{ | ||||
| 			/// <summary>The set being enumerated.</summary> | ||||
| 			private readonly IndexableSet<T> _set; | ||||
| 			/// <summary>The next index to yield.</summary> | ||||
| 			private int _index; | ||||
| 
 | ||||
| 			/// <summary>Initialize the enumerator.</summary> | ||||
| 			/// <param name="set">The set to enumerate.</param> | ||||
| 			[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||||
| 			internal Enumerator(IndexableSet<T> set) | ||||
| 			if (!disposed) | ||||
| 			{ | ||||
| 				_set = set; | ||||
| 				_index = _set.Count; | ||||
| 			} | ||||
| 				NativeMemory.Free(array); | ||||
| 				array = null; | ||||
| 
 | ||||
| 			/// <summary>Advances the enumerator to the next element of the span.</summary> | ||||
| 			[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||||
| 			public bool MoveNext() | ||||
| 			{ | ||||
| 				int index = _index - 1; | ||||
| 				if (index >= 0) | ||||
| 				{ | ||||
| 					_index = index; | ||||
| 					return true; | ||||
| 				} | ||||
| 
 | ||||
| 				return false; | ||||
| 				disposed = true; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 			/// <summary>Gets the element at the current position of the enumerator.</summary> | ||||
| 			public T Current | ||||
| 			{ | ||||
| 				[MethodImpl(MethodImplOptions.AggressiveInlining)] | ||||
| 				get => _set[_index]; | ||||
| 			} | ||||
| 		~IndexableSet() | ||||
| 		{ | ||||
| 			// 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,5 +1,8 @@ | |||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Runtime.CompilerServices; | ||||
| using System.Runtime.InteropServices; | ||||
| using MoonTools.ECS.Collections; | ||||
| 
 | ||||
| namespace MoonTools.ECS | ||||
| { | ||||
|  | @ -8,17 +11,18 @@ namespace MoonTools.ECS | |||
| 		public abstract void Clear(); | ||||
| 	} | ||||
| 
 | ||||
| 	internal class MessageStorage<TMessage> : MessageStorage where TMessage : unmanaged | ||||
| 	internal unsafe class MessageStorage<TMessage> : MessageStorage, IDisposable where TMessage : unmanaged | ||||
| 	{ | ||||
| 		private int count = 0; | ||||
| 		private int capacity = 128; | ||||
| 		private TMessage[] messages; | ||||
| 		private TMessage* messages; | ||||
| 		// duplicating storage here for fast iteration | ||||
| 		private Dictionary<int, DynamicArray<TMessage>> entityToMessages = new Dictionary<int, DynamicArray<TMessage>>(); | ||||
| 		private Dictionary<int, NativeArray<TMessage>> entityToMessages = new Dictionary<int, NativeArray<TMessage>>(); | ||||
| 		private bool disposed; | ||||
| 
 | ||||
| 		public MessageStorage() | ||||
| 		{ | ||||
| 			messages = new TMessage[capacity]; | ||||
| 			messages = (TMessage*) NativeMemory.Alloc((nuint) (capacity * Unsafe.SizeOf<TMessage>())); | ||||
| 		} | ||||
| 
 | ||||
| 		public void Add(in TMessage message) | ||||
|  | @ -26,7 +30,7 @@ namespace MoonTools.ECS | |||
| 			if (count == capacity) | ||||
| 			{ | ||||
| 				capacity *= 2; | ||||
| 				Array.Resize(ref messages, capacity); | ||||
| 				messages = (TMessage*) NativeMemory.Realloc(messages, (nuint) (capacity * Unsafe.SizeOf<TMessage>())); | ||||
| 			} | ||||
| 
 | ||||
| 			messages[count] = message; | ||||
|  | @ -37,7 +41,7 @@ namespace MoonTools.ECS | |||
| 		{ | ||||
| 			if (!entityToMessages.ContainsKey(entityID)) | ||||
| 			{ | ||||
| 				entityToMessages.Add(entityID, new DynamicArray<TMessage>()); | ||||
| 				entityToMessages.Add(entityID, new NativeArray<TMessage>()); | ||||
| 			} | ||||
| 			entityToMessages[entityID].Add(message); | ||||
| 
 | ||||
|  | @ -51,7 +55,7 @@ namespace MoonTools.ECS | |||
| 
 | ||||
| 		public ReadOnlySpan<TMessage> All() | ||||
| 		{ | ||||
| 			return new ReadOnlySpan<TMessage>(messages, 0, count); | ||||
| 			return new ReadOnlySpan<TMessage>(messages, count); | ||||
| 		} | ||||
| 
 | ||||
| 		public TMessage First() | ||||
|  | @ -89,5 +93,39 @@ namespace MoonTools.ECS | |||
| 				set.Clear(); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		protected virtual void Dispose(bool disposing) | ||||
| 		{ | ||||
| 			if (!disposed) | ||||
| 			{ | ||||
| 				Clear(); | ||||
| 
 | ||||
| 				if (disposing) | ||||
| 				{ | ||||
| 					foreach (var array in entityToMessages.Values) | ||||
| 					{ | ||||
| 						array.Dispose(); | ||||
| 					} | ||||
| 				} | ||||
| 
 | ||||
| 				NativeMemory.Free(messages); | ||||
| 				messages = null; | ||||
| 
 | ||||
| 				disposed = 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,5 +1,8 @@ | |||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Runtime.CompilerServices; | ||||
| using System.Runtime.InteropServices; | ||||
| using MoonTools.ECS.Collections; | ||||
| 
 | ||||
| namespace MoonTools.ECS | ||||
| { | ||||
|  | @ -16,19 +19,28 @@ namespace MoonTools.ECS | |||
| 
 | ||||
| 	// Relation is the two entities, A related to B. | ||||
| 	// TRelation is the data attached to the relation. | ||||
| 	internal class RelationStorage<TRelation> : RelationStorage where TRelation : unmanaged | ||||
| 	internal unsafe class RelationStorage<TRelation> : RelationStorage, IDisposable where TRelation : unmanaged | ||||
| 	{ | ||||
| 		private int count = 0; | ||||
| 		private int capacity = 16; | ||||
| 		private (Entity, Entity)* relations; | ||||
| 		private TRelation* relationDatas; | ||||
| 		private Dictionary<(Entity, Entity), int> indices = new Dictionary<(Entity, Entity), int>(16); | ||||
| 		private (Entity, Entity)[] relations = new (Entity, Entity)[16]; | ||||
| 		private TRelation[] relationDatas = new TRelation[16]; | ||||
| 		private Dictionary<int, IndexableSet<Entity>> outRelations = new Dictionary<int, IndexableSet<Entity>>(16); | ||||
| 		private Dictionary<int, IndexableSet<Entity>> inRelations = new Dictionary<int, IndexableSet<Entity>>(16); | ||||
| 		private Stack<IndexableSet<Entity>> listPool = new Stack<IndexableSet<Entity>>(); | ||||
| 
 | ||||
| 		private bool disposed; | ||||
| 
 | ||||
| 		public RelationStorage() | ||||
| 		{ | ||||
| 			relations = ((Entity, Entity)*) NativeMemory.Alloc((nuint) (capacity * Unsafe.SizeOf<(Entity, Entity)>())); | ||||
| 			relationDatas = (TRelation*) NativeMemory.Alloc((nuint) (capacity * Unsafe.SizeOf<TRelation>())); | ||||
| 		} | ||||
| 
 | ||||
| 		public ReverseSpanEnumerator<(Entity, Entity)> All() | ||||
| 		{ | ||||
| 			return new ReverseSpanEnumerator<(Entity, Entity)>(new Span<(Entity, Entity)>(relations, 0, count)); | ||||
| 			return new ReverseSpanEnumerator<(Entity, Entity)>(new Span<(Entity, Entity)>(relations, count)); | ||||
| 		} | ||||
| 
 | ||||
| 		public void Set(in Entity entityA, in Entity entityB, TRelation relationData) | ||||
|  | @ -56,10 +68,11 @@ namespace MoonTools.ECS | |||
| 			} | ||||
| 			inRelations[idB].Add(idA); | ||||
| 
 | ||||
| 			if (count >= relationDatas.Length) | ||||
| 			if (count >= capacity) | ||||
| 			{ | ||||
| 				Array.Resize(ref relations, relations.Length * 2); | ||||
| 				Array.Resize(ref relationDatas, relationDatas.Length * 2); | ||||
| 				capacity *= 2; | ||||
| 				relations = ((Entity, Entity)*) NativeMemory.Realloc(relations, (nuint) (capacity * Unsafe.SizeOf<(Entity, Entity)>())); | ||||
| 				relationDatas = (TRelation*) NativeMemory.Realloc(relationDatas, (nuint) (capacity * Unsafe.SizeOf<TRelation>())); | ||||
| 			} | ||||
| 
 | ||||
| 			relations[count] = relation; | ||||
|  | @ -219,7 +232,7 @@ namespace MoonTools.ECS | |||
| 
 | ||||
| 		public override unsafe void Set(int entityA, int entityB, void* relationData) | ||||
| 		{ | ||||
| 			Set(entityA, entityB, *((TRelation*) relationData)); | ||||
| 			Set(entityA, entityB, *(TRelation*) relationData); | ||||
| 		} | ||||
| 
 | ||||
| 		public override int GetStorageIndex(int entityA, int entityB) | ||||
|  | @ -229,10 +242,7 @@ namespace MoonTools.ECS | |||
| 
 | ||||
| 		public override unsafe void* Get(int relationStorageIndex) | ||||
| 		{ | ||||
| 			fixed (void* p = &relationDatas[relationStorageIndex]) | ||||
| 			{ | ||||
| 				return p; | ||||
| 			} | ||||
| 			return &relationDatas[relationStorageIndex]; | ||||
| 		} | ||||
| 
 | ||||
| 		public override void UnrelateAll(int entityID) | ||||
|  | @ -282,5 +292,41 @@ namespace MoonTools.ECS | |||
| 			} | ||||
| 			outRelations.Clear(); | ||||
| 		} | ||||
| 
 | ||||
| 		protected virtual void Dispose(bool disposing) | ||||
| 		{ | ||||
| 			if (!disposed) | ||||
| 			{ | ||||
| 				Clear(); | ||||
| 
 | ||||
| 				if (disposing) | ||||
| 				{ | ||||
| 					foreach (var set in listPool) | ||||
| 					{ | ||||
| 						set.Dispose(); | ||||
| 					} | ||||
| 				} | ||||
| 
 | ||||
| 				NativeMemory.Free(relations); | ||||
| 				NativeMemory.Free(relationDatas); | ||||
| 				relations = null; | ||||
| 				relationDatas = null; | ||||
| 
 | ||||
| 				disposed = true; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		~RelationStorage() | ||||
| 		{ | ||||
| 			// 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); | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue