Compare commits
	
		
			3 Commits 
		
	
	
		
			main
			...
			storage_co
		
	
	| Author | SHA1 | Date | 
|---|---|---|
| 
							
							
								
								 | 
						94c195e920 | |
| 
							
							
								
								 | 
						cbdcca5bbf | |
| 
							
							
								
								 | 
						2adecf771a | 
| 
						 | 
					@ -3,6 +3,7 @@
 | 
				
			||||||
  <PropertyGroup>
 | 
					  <PropertyGroup>
 | 
				
			||||||
    <TargetFramework>net8.0</TargetFramework>
 | 
					    <TargetFramework>net8.0</TargetFramework>
 | 
				
			||||||
    <Nullable>enable</Nullable>
 | 
					    <Nullable>enable</Nullable>
 | 
				
			||||||
 | 
					    <Platforms>x64</Platforms>
 | 
				
			||||||
    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
 | 
					    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
 | 
				
			||||||
  </PropertyGroup>
 | 
					  </PropertyGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,8 +7,8 @@ namespace MoonTools.ECS.Collections;
 | 
				
			||||||
public unsafe class NativeArray<T> : IDisposable where T : unmanaged
 | 
					public unsafe class NativeArray<T> : IDisposable where T : unmanaged
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	private T* Elements;
 | 
						private T* Elements;
 | 
				
			||||||
	public int Count { get; private set;}
 | 
						public int Count { get; private set; }
 | 
				
			||||||
	private int Capacity;
 | 
						public int Capacity { get; private set; }
 | 
				
			||||||
	private int ElementSize;
 | 
						private int ElementSize;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public Span<T> ToSpan() => new Span<T>(Elements, Count);
 | 
						public Span<T> ToSpan() => new Span<T>(Elements, Count);
 | 
				
			||||||
| 
						 | 
					@ -61,7 +61,7 @@ public unsafe class NativeArray<T> : IDisposable where T : unmanaged
 | 
				
			||||||
		Count = 0;
 | 
							Count = 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private void ResizeTo(int size)
 | 
						public void ResizeTo(int size)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		Capacity = size;
 | 
							Capacity = size;
 | 
				
			||||||
		Elements = (T*) NativeMemory.Realloc((void*) Elements, (nuint) (ElementSize * Capacity));
 | 
							Elements = (T*) NativeMemory.Realloc((void*) Elements, (nuint) (ElementSize * Capacity));
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,8 +7,8 @@ namespace MoonTools.ECS.Collections;
 | 
				
			||||||
internal unsafe class NativeArray : IDisposable
 | 
					internal unsafe class NativeArray : IDisposable
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	private nint Elements;
 | 
						private nint Elements;
 | 
				
			||||||
	public int Count { get; private set;}
 | 
						public int Count { get; private set; }
 | 
				
			||||||
	private int Capacity;
 | 
						public int Capacity { get; private set; }
 | 
				
			||||||
	public readonly int ElementSize;
 | 
						public readonly int ElementSize;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private bool IsDisposed;
 | 
						private bool IsDisposed;
 | 
				
			||||||
| 
						 | 
					@ -44,7 +44,7 @@ internal unsafe class NativeArray : IDisposable
 | 
				
			||||||
		Elements = (nint) NativeMemory.Realloc((void*) Elements, (nuint) (ElementSize * Capacity));
 | 
							Elements = (nint) NativeMemory.Realloc((void*) Elements, (nuint) (ElementSize * Capacity));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private void ResizeTo(int capacity)
 | 
						public void ResizeTo(int capacity)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		Capacity = capacity;
 | 
							Capacity = capacity;
 | 
				
			||||||
		Elements = (nint) NativeMemory.Realloc((void*) Elements, (nuint) (ElementSize * Capacity));
 | 
							Elements = (nint) NativeMemory.Realloc((void*) Elements, (nuint) (ElementSize * Capacity));
 | 
				
			||||||
| 
						 | 
					@ -65,6 +65,11 @@ internal unsafe class NativeArray : IDisposable
 | 
				
			||||||
		Count -= 1;
 | 
							Count -= 1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public void RemoveLastElement()
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							Count -= 1;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public void Append<T>(T component) where T : unmanaged
 | 
						public void Append<T>(T component) where T : unmanaged
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		if (Count >= Capacity)
 | 
							if (Count >= Capacity)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,89 +1,104 @@
 | 
				
			||||||
using System;
 | 
					using System;
 | 
				
			||||||
using System.Collections.Generic;
 | 
					using System.Runtime.CompilerServices;
 | 
				
			||||||
 | 
					using System.Runtime.InteropServices;
 | 
				
			||||||
using MoonTools.ECS.Collections;
 | 
					using MoonTools.ECS.Collections;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace MoonTools.ECS;
 | 
					namespace MoonTools.ECS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
internal class ComponentStorage : IDisposable
 | 
					public class ComponentStorage : IDisposable
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	internal readonly Dictionary<Entity, int> EntityIDToStorageIndex = new Dictionary<Entity, int>(16);
 | 
						internal readonly NativeArray<Entity> DenseArray = new NativeArray<Entity>();
 | 
				
			||||||
	internal readonly NativeArray Components;
 | 
						internal readonly NativeArray<int> SparseArray = new NativeArray<int>();
 | 
				
			||||||
	internal readonly NativeArray<Entity> EntityIDs;
 | 
						internal nint ElementArray;
 | 
				
			||||||
	internal readonly TypeId TypeId;
 | 
						internal int ElementArrayCapacity;
 | 
				
			||||||
	internal readonly int ElementSize;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	private bool IsDisposed;
 | 
						private bool IsDisposed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public ComponentStorage(TypeId typeId, int elementSize)
 | 
						public int ElementSize { get; private set; }
 | 
				
			||||||
 | 
						public int Count => DenseArray.Count;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public unsafe ComponentStorage(int elementSize)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
 | 
							for (var i = 0; i < 16; i += 1)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								SparseArray.Append(Entity.Null.ID); // sentinel value
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							ElementArrayCapacity = 16;
 | 
				
			||||||
 | 
							ElementArray = (nint) NativeMemory.Alloc((nuint) (elementSize * ElementArrayCapacity));
 | 
				
			||||||
		ElementSize = elementSize;
 | 
							ElementSize = elementSize;
 | 
				
			||||||
		Components = new NativeArray(elementSize);
 | 
					 | 
				
			||||||
		EntityIDs = new NativeArray<Entity>();
 | 
					 | 
				
			||||||
		TypeId = typeId;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public bool Any()
 | 
						public bool Any() => DenseArray.Count > 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public unsafe ref T Get<T>(Entity entity) where T : unmanaged
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		return Components.Count > 0;
 | 
							return ref ((T*) ElementArray)[SparseArray[entity.ID]];
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public bool Has(Entity entity)
 | 
						public unsafe ref T GetFirst<T>() where T : unmanaged
 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return EntityIDToStorageIndex.ContainsKey(entity);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public ref T Get<T>(in Entity entity) where T : unmanaged
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return ref Components.Get<T>(EntityIDToStorageIndex[entity]);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public ref T GetFirst<T>() where T : unmanaged
 | 
					 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
#if DEBUG
 | 
					#if DEBUG
 | 
				
			||||||
		if (Components.Count == 0)
 | 
							if (DenseArray.Count == 0)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			throw new IndexOutOfRangeException("Component storage is empty!");
 | 
								throw new IndexOutOfRangeException("Component storage is empty!");
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
		return ref Components.Get<T>(0);
 | 
							return ref ((T*) ElementArray)[0];
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Returns true if the entity had this component.
 | 
						public unsafe bool Set<T>(Entity entity, T component) where T : unmanaged
 | 
				
			||||||
	public bool Set<T>(in Entity entity, in T component) where T : unmanaged
 | 
					 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		if (EntityIDToStorageIndex.TryGetValue(entity, out var index))
 | 
							var newEntity = entity.ID >= SparseArray.Count || SparseArray[entity.ID] == Entity.Null.ID;
 | 
				
			||||||
 | 
							if (newEntity)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			Components.Set(index, component);
 | 
								// the entity is being added! let's do some record keeping
 | 
				
			||||||
			return true;
 | 
								var index = DenseArray.Count;
 | 
				
			||||||
		}
 | 
								DenseArray.Append(entity);
 | 
				
			||||||
		else
 | 
								if (entity.ID >= SparseArray.Count)
 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			EntityIDToStorageIndex[entity] = Components.Count;
 | 
					 | 
				
			||||||
			EntityIDs.Append(entity);
 | 
					 | 
				
			||||||
			Components.Append(component);
 | 
					 | 
				
			||||||
			return false;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// Returns true if the entity had this component.
 | 
					 | 
				
			||||||
	public bool Remove(in Entity entity)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		if (EntityIDToStorageIndex.TryGetValue(entity, out int index))
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			var lastElementIndex = Components.Count - 1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			var lastEntity = EntityIDs[lastElementIndex];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			// move a component into the hole to maintain contiguous memory
 | 
					 | 
				
			||||||
			Components.Delete(index);
 | 
					 | 
				
			||||||
			EntityIDs.Delete(index);
 | 
					 | 
				
			||||||
			EntityIDToStorageIndex.Remove(entity);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			// update the index if it changed
 | 
					 | 
				
			||||||
			if (lastElementIndex != index)
 | 
					 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				EntityIDToStorageIndex[lastEntity] = index;
 | 
									var oldCount = SparseArray.Count;
 | 
				
			||||||
 | 
									SparseArray.ResizeTo(entity.ID + 1);
 | 
				
			||||||
 | 
									for (var i = oldCount; i < SparseArray.Capacity; i += 1)
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										SparseArray.Append(Entity.Null.ID); // sentinel value
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
								SparseArray[entity.ID] = index;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (entity.ID >= ElementArrayCapacity)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									ElementArrayCapacity = entity.ID + 1;
 | 
				
			||||||
 | 
									ElementArray = (nint) NativeMemory.Realloc((void*) ElementArray, (nuint) (ElementArrayCapacity * ElementSize));
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							Unsafe.Write((void*) (ElementArray + ElementSize * SparseArray[entity.ID]), component);
 | 
				
			||||||
 | 
							return !newEntity;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public bool Has(Entity entity)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							return entity.ID < SparseArray.Count && SparseArray[entity.ID] != Entity.Null.ID;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						public unsafe bool Remove(Entity entity)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							if (Has(entity))
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								var denseIndex = SparseArray[entity.ID];
 | 
				
			||||||
 | 
								var lastItem = DenseArray[DenseArray.Count - 1];
 | 
				
			||||||
 | 
							 	DenseArray[denseIndex] = lastItem;
 | 
				
			||||||
 | 
								SparseArray[lastItem.ID] = denseIndex;
 | 
				
			||||||
 | 
								SparseArray[entity.ID] = Entity.Null.ID; // sentinel value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (denseIndex != DenseArray.Count - 1)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									NativeMemory.Copy((void*) (ElementArray + ElementSize * (DenseArray.Count - 1)), (void*) (ElementArray + ElementSize * denseIndex), (nuint) ElementSize);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								DenseArray.RemoveLastElement();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			return true;
 | 
								return true;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -93,46 +108,47 @@ internal class ComponentStorage : IDisposable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public void Clear()
 | 
						public void Clear()
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		Components.Clear();
 | 
							DenseArray.Clear();
 | 
				
			||||||
		EntityIDs.Clear();
 | 
							for (var i = 0; i < SparseArray.Capacity; i += 1)
 | 
				
			||||||
		EntityIDToStorageIndex.Clear();
 | 
							{
 | 
				
			||||||
 | 
								SparseArray[i] = Entity.Null.ID;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public Entity FirstEntity()
 | 
						public Entity FirstEntity()
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
#if DEBUG
 | 
					#if DEBUG
 | 
				
			||||||
		if (EntityIDs.Count == 0)
 | 
							if (DenseArray.Count == 0)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			throw new IndexOutOfRangeException("Component storage is empty!");
 | 
								throw new IndexOutOfRangeException("Component storage is empty!");
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
		return EntityIDs[0];
 | 
							return DenseArray[0];
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if DEBUG
 | 
					#if DEBUG
 | 
				
			||||||
	internal IEnumerable<Entity> Debug_GetEntities()
 | 
						internal Span<Entity> Debug_GetEntities()
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		return EntityIDToStorageIndex.Keys;
 | 
							return DenseArray.ToSpan();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	protected virtual void Dispose(bool disposing)
 | 
						protected unsafe virtual void Dispose(bool disposing)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		if (!IsDisposed)
 | 
							if (!IsDisposed)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			Components.Dispose();
 | 
								if (disposing)
 | 
				
			||||||
			EntityIDs.Dispose();
 | 
								{
 | 
				
			||||||
 | 
									DenseArray.Dispose();
 | 
				
			||||||
 | 
									SparseArray.Dispose();
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								NativeMemory.Free((void*) ElementArray);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			IsDisposed = true;
 | 
								IsDisposed = true;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// ~ComponentStorage()
 | 
					 | 
				
			||||||
	// {
 | 
					 | 
				
			||||||
	// 	// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
 | 
					 | 
				
			||||||
	// 	Dispose(disposing: false);
 | 
					 | 
				
			||||||
	// }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public void Dispose()
 | 
						public void Dispose()
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
 | 
							// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,7 +11,7 @@ public abstract class DebugSystem : System
 | 
				
			||||||
	protected DebugSystem(World world) : base(world) { }
 | 
						protected DebugSystem(World world) : base(world) { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	protected World.ComponentTypeEnumerator Debug_GetAllComponentTypes(Entity entity) => World.Debug_GetAllComponentTypes(entity);
 | 
						protected World.ComponentTypeEnumerator Debug_GetAllComponentTypes(Entity entity) => World.Debug_GetAllComponentTypes(entity);
 | 
				
			||||||
	protected IEnumerable<Entity> Debug_GetEntities(Type componentType) => World.Debug_GetEntities(componentType);
 | 
						protected Span<Entity> Debug_GetEntities(Type componentType) => World.Debug_GetEntities(componentType);
 | 
				
			||||||
	protected IEnumerable<Type> Debug_SearchComponentType(string typeString) => World.Debug_SearchComponentType(typeString);
 | 
						protected IEnumerable<Type> Debug_SearchComponentType(string typeString) => World.Debug_SearchComponentType(typeString);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,3 +1,6 @@
 | 
				
			||||||
namespace MoonTools.ECS;
 | 
					namespace MoonTools.ECS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public readonly record struct Entity(uint ID);
 | 
					public readonly record struct Entity(int ID)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						public static readonly Entity Null = new Entity(int.MaxValue);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,12 +5,12 @@ namespace MoonTools.ECS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
internal class IdAssigner : IDisposable
 | 
					internal class IdAssigner : IDisposable
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	uint Next;
 | 
						int Next = 0;
 | 
				
			||||||
	NativeArray<uint> AvailableIds = new NativeArray<uint>();
 | 
						NativeArray<int> AvailableIds = new NativeArray<int>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private bool IsDisposed;
 | 
						private bool IsDisposed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public uint Assign()
 | 
						public int Assign()
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		if (AvailableIds.TryPop(out var id))
 | 
							if (AvailableIds.TryPop(out var id))
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
| 
						 | 
					@ -22,7 +22,7 @@ internal class IdAssigner : IDisposable
 | 
				
			||||||
		return id;
 | 
							return id;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public void Unassign(uint id)
 | 
						public void Unassign(int id)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		AvailableIds.Append(id);
 | 
							AvailableIds.Append(id);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -46,13 +46,6 @@ internal class IdAssigner : IDisposable
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// // TODO: override finalizer only if 'Dispose(bool disposing)' has code to free unmanaged resources
 | 
					 | 
				
			||||||
	// ~IdAssigner()
 | 
					 | 
				
			||||||
	// {
 | 
					 | 
				
			||||||
	//     // Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
 | 
					 | 
				
			||||||
	//     Dispose(disposing: false);
 | 
					 | 
				
			||||||
	// }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public void Dispose()
 | 
						public void Dispose()
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
 | 
							// Do not change this code. Put cleanup code in 'Dispose(bool disposing)' method
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -15,6 +15,4 @@ public abstract class Manipulator : EntityComponentReader
 | 
				
			||||||
	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);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	protected void Send<TMessage>(in TMessage message) where TMessage : unmanaged => World.Send(message);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -39,7 +39,7 @@ public static class RandomManager
 | 
				
			||||||
			x = Primes[Random.Next(Primes.Length - 1)];
 | 
								x = Primes[Random.Next(Primes.Length - 1)];
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return new LinearCongruentialEnumerator(Random.Next(n + 1), x, n);
 | 
							return new LinearCongruentialEnumerator(Random.Next(n), x, n);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -65,7 +65,7 @@ public struct LinearCongruentialEnumerator
 | 
				
			||||||
	public bool MoveNext()
 | 
						public bool MoveNext()
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		current += 1;
 | 
							current += 1;
 | 
				
			||||||
		if (current <= start + count)
 | 
							if (current < start + count)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			return true;
 | 
								return true;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										127
									
								
								src/Snapshot.cs
								
								
								
								
							
							
						
						
									
										127
									
								
								src/Snapshot.cs
								
								
								
								
							| 
						 | 
					@ -1,6 +1,7 @@
 | 
				
			||||||
using System;
 | 
					using System;
 | 
				
			||||||
using System.Collections.Generic;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
using System.Runtime.CompilerServices;
 | 
					using System.Runtime.CompilerServices;
 | 
				
			||||||
 | 
					using System.Runtime.InteropServices;
 | 
				
			||||||
using MoonTools.ECS.Collections;
 | 
					using MoonTools.ECS.Collections;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace MoonTools.ECS;
 | 
					namespace MoonTools.ECS;
 | 
				
			||||||
| 
						 | 
					@ -15,11 +16,11 @@ public class Snapshot : IDisposable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private List<RelationSnapshot> RelationSnapshots = new List<RelationSnapshot>();
 | 
						private List<RelationSnapshot> RelationSnapshots = new List<RelationSnapshot>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private List<IndexableSet<TypeId>> EntityRelationIndex =
 | 
						private Dictionary<Entity, IndexableSet<TypeId>> EntityRelationIndex =
 | 
				
			||||||
		new List<IndexableSet<TypeId>>();
 | 
							new Dictionary<Entity, IndexableSet<TypeId>>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private List<IndexableSet<TypeId>> EntityComponentIndex =
 | 
						private Dictionary<Entity, IndexableSet<TypeId>> EntityComponentIndex =
 | 
				
			||||||
		new List<IndexableSet<TypeId>>();
 | 
							new Dictionary<Entity, IndexableSet<TypeId>>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private List<string> EntityTags = new List<string>();
 | 
						private List<string> EntityTags = new List<string>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -60,7 +61,7 @@ public class Snapshot : IDisposable
 | 
				
			||||||
			relationStorage.Clear();
 | 
								relationStorage.Clear();
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for (var i = 0; i < ComponentSnapshots.Count; i += 1)
 | 
							for (var i = 0; i < world.ComponentIndex.Count; i += 1)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			var componentStorage = world.ComponentIndex[i];
 | 
								var componentStorage = world.ComponentIndex[i];
 | 
				
			||||||
			ComponentSnapshots[i].Restore(componentStorage);
 | 
								ComponentSnapshots[i].Restore(componentStorage);
 | 
				
			||||||
| 
						 | 
					@ -76,43 +77,40 @@ public class Snapshot : IDisposable
 | 
				
			||||||
		// restore entity relation index state
 | 
							// restore entity relation index state
 | 
				
			||||||
		// FIXME: arghhhh this is so slow
 | 
							// FIXME: arghhhh this is so slow
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		foreach (var relationTypeSet in world.EntityRelationIndex)
 | 
							foreach (var (id, relationTypeSet) in world.EntityRelationIndex)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			relationTypeSet.Clear();
 | 
								relationTypeSet.Clear();
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for (var i = 0; i < EntityRelationIndex.Count; i += 1)
 | 
							foreach (var (id, relationTypeSet) in EntityRelationIndex)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			var relationTypeSet = EntityRelationIndex[i];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			foreach (var typeId in relationTypeSet)
 | 
								foreach (var typeId in relationTypeSet)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				world.EntityRelationIndex[i].Add(typeId);
 | 
									world.EntityRelationIndex[id].Add(typeId);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// restore entity component index state
 | 
							// restore entity component index state
 | 
				
			||||||
		// FIXME: arrghghhh this is so slow
 | 
							// FIXME: arrghghhh this is so slow
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		foreach (var componentTypeSet in world.EntityComponentIndex)
 | 
							foreach (var (id, componentTypeSet) in world.EntityComponentIndex)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			componentTypeSet.Clear();
 | 
								componentTypeSet.Clear();
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		for (var i = 0; i < EntityComponentIndex.Count; i += 1)
 | 
							foreach (var (id, componentTypeSet) in EntityComponentIndex)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			var componentTypeSet = EntityComponentIndex[i];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			foreach (var typeId in componentTypeSet)
 | 
								foreach (var typeId in componentTypeSet)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				world.EntityComponentIndex[i].Add(typeId);
 | 
									world.EntityComponentIndex[id].Add(typeId);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// restore entity tags
 | 
							// restore entity tags
 | 
				
			||||||
		for (var i = 0; i < EntityTags.Count; i += 1)
 | 
							world.EntityTags.Clear();
 | 
				
			||||||
 | 
							foreach (var s in EntityTags)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			world.EntityTags[i] = EntityTags[i];
 | 
								world.EntityTags.Add(s);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -149,39 +147,37 @@ public class Snapshot : IDisposable
 | 
				
			||||||
			RelationSnapshots[i].Take(world.RelationIndex[i]);
 | 
								RelationSnapshots[i].Take(world.RelationIndex[i]);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// fill in missing index structures
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		for (var i = EntityComponentIndex.Count; i < world.EntityComponentIndex.Count; i += 1)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			EntityComponentIndex.Add(new IndexableSet<TypeId>());
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		for (var i = EntityRelationIndex.Count; i < world.EntityRelationIndex.Count; i += 1)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			EntityRelationIndex.Add(new IndexableSet<TypeId>());
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// copy entity relation index
 | 
							// copy entity relation index
 | 
				
			||||||
		// FIXME: arghhhh this is so slow
 | 
							// FIXME: arghhhh this is so slow
 | 
				
			||||||
		for (var i = 0; i < world.EntityRelationIndex.Count; i += 1)
 | 
							foreach (var (id, relationTypeSet) in world.EntityRelationIndex)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			EntityRelationIndex[i].Clear();
 | 
								if (!EntityRelationIndex.ContainsKey(id))
 | 
				
			||||||
 | 
					 | 
				
			||||||
			foreach (var typeId in world.EntityRelationIndex[i])
 | 
					 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				EntityRelationIndex[i].Add(typeId);
 | 
									EntityRelationIndex.Add(id, new IndexableSet<TypeId>());
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								EntityRelationIndex[id].Clear();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								foreach (var typeId in relationTypeSet)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									EntityRelationIndex[id].Add(typeId);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// copy entity component index
 | 
							// copy entity component index
 | 
				
			||||||
		// FIXME: arghhhh this is so slow
 | 
							// FIXME: arghhhh this is so slow
 | 
				
			||||||
		for (var i = 0; i < world.EntityComponentIndex.Count; i += 1)
 | 
							foreach (var (id, componentTypeSet) in world.EntityComponentIndex)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			EntityComponentIndex[i].Clear();
 | 
								if (!EntityComponentIndex.ContainsKey(id))
 | 
				
			||||||
 | 
					 | 
				
			||||||
			foreach (var typeId in world.EntityComponentIndex[i])
 | 
					 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				EntityComponentIndex[i].Add(typeId);
 | 
									EntityComponentIndex.Add(id, new IndexableSet<TypeId>());
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								EntityComponentIndex[id].Clear();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								foreach (var typeId in componentTypeSet)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									EntityComponentIndex[id].Add(typeId);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -211,46 +207,51 @@ public class Snapshot : IDisposable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private class ComponentSnapshot : IDisposable
 | 
						private class ComponentSnapshot : IDisposable
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		private readonly NativeArray Components;
 | 
							private readonly NativeArray<Entity> DenseArray;
 | 
				
			||||||
		private readonly NativeArray<Entity> EntityIDs;
 | 
							private readonly NativeArray<int> SparseArray;
 | 
				
			||||||
 | 
							private nint ElementArray;
 | 
				
			||||||
 | 
							private int ElementArrayCapacity;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		private bool IsDisposed;
 | 
							private bool IsDisposed;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		public ComponentSnapshot(int elementSize)
 | 
							public unsafe ComponentSnapshot(int elementSize)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			Components = new NativeArray(elementSize);
 | 
								ElementArray = (nint) NativeMemory.Alloc((nuint) (16 * elementSize));
 | 
				
			||||||
			EntityIDs = new NativeArray<Entity>();
 | 
								DenseArray = new NativeArray<Entity>(elementSize);
 | 
				
			||||||
 | 
								SparseArray = new NativeArray<int>(elementSize);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		public void Take(ComponentStorage componentStorage)
 | 
							public unsafe void Take(ComponentStorage componentStorage)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			componentStorage.Components.CopyAllTo(Components);
 | 
								componentStorage.DenseArray.CopyTo(DenseArray);
 | 
				
			||||||
			componentStorage.EntityIDs.CopyTo(EntityIDs);
 | 
								componentStorage.SparseArray.CopyTo(SparseArray);
 | 
				
			||||||
		}
 | 
								if (componentStorage.ElementArrayCapacity > ElementArrayCapacity)
 | 
				
			||||||
 | 
					 | 
				
			||||||
		public void Restore(ComponentStorage componentStorage)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			Components.CopyAllTo(componentStorage.Components);
 | 
					 | 
				
			||||||
			EntityIDs.CopyTo(componentStorage.EntityIDs);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			componentStorage.EntityIDToStorageIndex.Clear();
 | 
					 | 
				
			||||||
			for (int i = 0; i < EntityIDs.Count; i += 1)
 | 
					 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				var entityID = EntityIDs[i];
 | 
									ElementArrayCapacity = componentStorage.ElementArrayCapacity;
 | 
				
			||||||
				componentStorage.EntityIDToStorageIndex[entityID] = i;
 | 
									NativeMemory.Realloc((void*) ElementArray, (nuint) (componentStorage.ElementSize * ElementArrayCapacity));
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
								NativeMemory.Copy((void*) componentStorage.ElementArray, (void*) ElementArray, (nuint) (ElementArrayCapacity * componentStorage.ElementSize));
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		protected virtual void Dispose(bool disposing)
 | 
							public unsafe void Restore(ComponentStorage componentStorage)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								DenseArray.CopyTo(componentStorage.DenseArray);
 | 
				
			||||||
 | 
								SparseArray.CopyTo(componentStorage.SparseArray);
 | 
				
			||||||
 | 
								NativeMemory.Copy((void*) ElementArray, (void*) componentStorage.ElementArray, (nuint) (ElementArrayCapacity * componentStorage.ElementSize));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							protected unsafe virtual void Dispose(bool disposing)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			if (!IsDisposed)
 | 
								if (!IsDisposed)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				if (disposing)
 | 
									if (disposing)
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					Components.Dispose();
 | 
										DenseArray.Dispose();
 | 
				
			||||||
					EntityIDs.Dispose();
 | 
										SparseArray.Dispose();
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									NativeMemory.Free((void*) ElementArray);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				IsDisposed = true;
 | 
									IsDisposed = true;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -352,12 +353,12 @@ public class Snapshot : IDisposable
 | 
				
			||||||
					relationSnapshot.Dispose();
 | 
										relationSnapshot.Dispose();
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				foreach (var componentSet in EntityComponentIndex)
 | 
									foreach (var componentSet in EntityComponentIndex.Values)
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					componentSet.Dispose();
 | 
										componentSet.Dispose();
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				foreach (var relationSet in EntityRelationIndex)
 | 
									foreach (var relationSet in EntityRelationIndex.Values)
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					relationSet.Dispose();
 | 
										relationSet.Dispose();
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -16,12 +16,12 @@ public readonly record struct TypeId(uint Value) : IComparable<TypeId>
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
internal class ComponentTypeIdAssigner
 | 
					public class ComponentTypeIdAssigner
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	protected static ushort Counter;
 | 
						protected static ushort Counter;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
internal class ComponentTypeIdAssigner<T> : ComponentTypeIdAssigner
 | 
					public class ComponentTypeIdAssigner<T> : ComponentTypeIdAssigner
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	public static readonly ushort Id;
 | 
						public static readonly ushort Id;
 | 
				
			||||||
	public static readonly int Size;
 | 
						public static readonly int Size;
 | 
				
			||||||
| 
						 | 
					@ -41,12 +41,12 @@ internal class ComponentTypeIdAssigner<T> : ComponentTypeIdAssigner
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
internal class RelationTypeIdAssigner
 | 
					public class RelationTypeIdAssigner
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	protected static ushort Counter;
 | 
						protected static ushort Counter;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
internal class RelationTypeIdAssigner<T> : RelationTypeIdAssigner
 | 
					public class RelationTypeIdAssigner<T> : RelationTypeIdAssigner
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	public static readonly ushort Id;
 | 
						public static readonly ushort Id;
 | 
				
			||||||
	public static readonly int Size;
 | 
						public static readonly int Size;
 | 
				
			||||||
| 
						 | 
					@ -61,12 +61,12 @@ internal class RelationTypeIdAssigner<T> : RelationTypeIdAssigner
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
internal class MessageTypeIdAssigner
 | 
					public class MessageTypeIdAssigner
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	protected static ushort Counter;
 | 
						protected static ushort Counter;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
internal class MessageTypeIdAssigner<T> : MessageTypeIdAssigner
 | 
					public class MessageTypeIdAssigner<T> : MessageTypeIdAssigner
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	public static readonly ushort Id;
 | 
						public static readonly ushort Id;
 | 
				
			||||||
	public static readonly int Size;
 | 
						public static readonly int Size;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										67
									
								
								src/World.cs
								
								
								
								
							
							
						
						
									
										67
									
								
								src/World.cs
								
								
								
								
							| 
						 | 
					@ -3,10 +3,6 @@ using System.Collections.Generic;
 | 
				
			||||||
using System.Runtime.CompilerServices;
 | 
					using System.Runtime.CompilerServices;
 | 
				
			||||||
using MoonTools.ECS.Collections;
 | 
					using MoonTools.ECS.Collections;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if DEBUG
 | 
					 | 
				
			||||||
using System.Reflection;
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
namespace MoonTools.ECS;
 | 
					namespace MoonTools.ECS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class World : IDisposable
 | 
					public class World : IDisposable
 | 
				
			||||||
| 
						 | 
					@ -30,7 +26,7 @@ public class World : IDisposable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Relation Storages
 | 
						// Relation Storages
 | 
				
			||||||
	internal List<RelationStorage> RelationIndex = new List<RelationStorage>();
 | 
						internal List<RelationStorage> RelationIndex = new List<RelationStorage>();
 | 
				
			||||||
	internal List<IndexableSet<TypeId>> EntityRelationIndex = new List<IndexableSet<TypeId>>();
 | 
						internal Dictionary<Entity, IndexableSet<TypeId>> EntityRelationIndex = new Dictionary<Entity, IndexableSet<TypeId>>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Message Storages
 | 
						// Message Storages
 | 
				
			||||||
	private List<MessageStorage> MessageIndex = new List<MessageStorage>();
 | 
						private List<MessageStorage> MessageIndex = new List<MessageStorage>();
 | 
				
			||||||
| 
						 | 
					@ -38,7 +34,7 @@ public class World : IDisposable
 | 
				
			||||||
	public FilterBuilder FilterBuilder => new FilterBuilder(this);
 | 
						public FilterBuilder FilterBuilder => new FilterBuilder(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	internal readonly List<ComponentStorage> ComponentIndex = new List<ComponentStorage>();
 | 
						internal readonly List<ComponentStorage> ComponentIndex = new List<ComponentStorage>();
 | 
				
			||||||
	internal List<IndexableSet<TypeId>> EntityComponentIndex = new List<IndexableSet<TypeId>>();
 | 
						internal Dictionary<Entity, IndexableSet<TypeId>> EntityComponentIndex = new Dictionary<Entity, IndexableSet<TypeId>>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	internal IdAssigner EntityIdAssigner = new IdAssigner();
 | 
						internal IdAssigner EntityIdAssigner = new IdAssigner();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -55,8 +51,7 @@ public class World : IDisposable
 | 
				
			||||||
		// add missing storages, it's possible for there to be multiples in multi-world scenarios
 | 
							// add missing storages, it's possible for there to be multiples in multi-world scenarios
 | 
				
			||||||
		for (var i = ComponentIndex.Count; i <= typeId; i += 1)
 | 
							for (var i = ComponentIndex.Count; i <= typeId; i += 1)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			var missingTypeId = new TypeId((uint) i);
 | 
								var componentStorage = new ComponentStorage(ComponentTypeElementSizes[i]);
 | 
				
			||||||
			var componentStorage = new ComponentStorage(missingTypeId, ComponentTypeElementSizes[i]);
 | 
					 | 
				
			||||||
			ComponentIndex.Add(componentStorage);
 | 
								ComponentIndex.Add(componentStorage);
 | 
				
			||||||
			ComponentTypeToFilter.Add(new List<Filter>());
 | 
								ComponentTypeToFilter.Add(new List<Filter>());
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -101,10 +96,10 @@ public class World : IDisposable
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		var entity = new Entity(EntityIdAssigner.Assign());
 | 
							var entity = new Entity(EntityIdAssigner.Assign());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (entity.ID == EntityComponentIndex.Count)
 | 
							if (!EntityComponentIndex.ContainsKey(entity))
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			EntityRelationIndex.Add(new IndexableSet<TypeId>());
 | 
								EntityRelationIndex.Add(entity, new IndexableSet<TypeId>());
 | 
				
			||||||
			EntityComponentIndex.Add(new IndexableSet<TypeId>());
 | 
								EntityComponentIndex.Add(entity, new IndexableSet<TypeId>());
 | 
				
			||||||
			EntityTags.Add(tag);
 | 
								EntityTags.Add(tag);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -123,11 +118,8 @@ public class World : IDisposable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public void Destroy(in Entity entity)
 | 
						public void Destroy(in Entity entity)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		var componentSet = EntityComponentIndex[(int) entity.ID];
 | 
					 | 
				
			||||||
		var relationSet = EntityRelationIndex[(int) entity.ID];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// remove all components from storages
 | 
							// remove all components from storages
 | 
				
			||||||
		foreach (var componentTypeIndex in componentSet)
 | 
							foreach (var componentTypeIndex in EntityComponentIndex[entity])
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			var componentStorage = ComponentIndex[componentTypeIndex];
 | 
								var componentStorage = ComponentIndex[componentTypeIndex];
 | 
				
			||||||
			componentStorage.Remove(entity);
 | 
								componentStorage.Remove(entity);
 | 
				
			||||||
| 
						 | 
					@ -139,32 +131,29 @@ public class World : IDisposable
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// remove all relations from storage
 | 
							// remove all relations from storage
 | 
				
			||||||
		foreach (var relationTypeIndex in relationSet)
 | 
							foreach (var relationTypeIndex in EntityRelationIndex[entity])
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			var relationStorage = RelationIndex[relationTypeIndex];
 | 
								var relationStorage = RelationIndex[relationTypeIndex];
 | 
				
			||||||
			relationStorage.RemoveEntity(entity);
 | 
								relationStorage.RemoveEntity(entity);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		componentSet.Clear();
 | 
							EntityComponentIndex[entity].Clear();
 | 
				
			||||||
		relationSet.Clear();
 | 
							EntityRelationIndex[entity].Clear();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// recycle ID
 | 
							// recycle ID
 | 
				
			||||||
		EntityIdAssigner.Unassign(entity.ID);
 | 
							EntityIdAssigner.Unassign(entity.ID);
 | 
				
			||||||
 | 
					 | 
				
			||||||
		EntityTags[(int) entity.ID] = "";
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// COMPONENTS
 | 
						// COMPONENTS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public bool Has<T>(in Entity entity) where T : unmanaged
 | 
						public bool Has<T>(in Entity entity) where T : unmanaged
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		var storage = GetComponentStorage<T>();
 | 
							return GetComponentStorage<T>().Has(entity);
 | 
				
			||||||
		return storage.Has(entity);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	internal bool Has(in Entity entity, in TypeId typeId)
 | 
						internal bool Has(in Entity entity, in TypeId typeId)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		return EntityComponentIndex[(int) entity.ID].Contains(typeId);
 | 
							return ComponentIndex[(int) typeId.Value].Has(entity);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public bool Some<T>() where T : unmanaged
 | 
						public bool Some<T>() where T : unmanaged
 | 
				
			||||||
| 
						 | 
					@ -194,12 +183,13 @@ public class World : IDisposable
 | 
				
			||||||
	public void Set<T>(in Entity entity, in T component) where T : unmanaged
 | 
						public void Set<T>(in Entity entity, in T component) where T : unmanaged
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		var componentStorage = GetComponentStorage<T>();
 | 
							var componentStorage = GetComponentStorage<T>();
 | 
				
			||||||
 | 
							var typeId = new TypeId(ComponentTypeIdAssigner<T>.Id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (!componentStorage.Set(entity, component))
 | 
							if (!componentStorage.Set(entity, component))
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			EntityComponentIndex[(int) entity.ID].Add(componentStorage.TypeId);
 | 
								EntityComponentIndex[entity].Add(typeId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			foreach (var filter in ComponentTypeToFilter[componentStorage.TypeId])
 | 
								foreach (var filter in ComponentTypeToFilter[typeId])
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				filter.Check(entity);
 | 
									filter.Check(entity);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
| 
						 | 
					@ -209,12 +199,13 @@ public class World : IDisposable
 | 
				
			||||||
	public void Remove<T>(in Entity entity) where T : unmanaged
 | 
						public void Remove<T>(in Entity entity) where T : unmanaged
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		var componentStorage = GetComponentStorage<T>();
 | 
							var componentStorage = GetComponentStorage<T>();
 | 
				
			||||||
 | 
							var typeId = new TypeId(ComponentTypeIdAssigner<T>.Id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (componentStorage.Remove(entity))
 | 
							if (componentStorage.Remove(entity))
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			EntityComponentIndex[(int) entity.ID].Remove(componentStorage.TypeId);
 | 
								EntityComponentIndex[entity].Remove(typeId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			foreach (var filter in ComponentTypeToFilter[componentStorage.TypeId])
 | 
								foreach (var filter in ComponentTypeToFilter[typeId])
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				filter.Check(entity);
 | 
									filter.Check(entity);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
| 
						 | 
					@ -244,8 +235,8 @@ public class World : IDisposable
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		var relationStorage = GetRelationStorage<T>();
 | 
							var relationStorage = GetRelationStorage<T>();
 | 
				
			||||||
		relationStorage.Set(entityA, entityB, relation);
 | 
							relationStorage.Set(entityA, entityB, relation);
 | 
				
			||||||
		EntityRelationIndex[(int) entityA.ID].Add(new TypeId(RelationTypeIdAssigner<T>.Id));
 | 
							EntityRelationIndex[entityA].Add(new TypeId(RelationTypeIdAssigner<T>.Id));
 | 
				
			||||||
		EntityRelationIndex[(int) entityB.ID].Add(new TypeId(RelationTypeIdAssigner<T>.Id));
 | 
							EntityRelationIndex[entityB].Add(new TypeId(RelationTypeIdAssigner<T>.Id));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public void Unrelate<T>(in Entity entityA, in Entity entityB) where T : unmanaged
 | 
						public void Unrelate<T>(in Entity entityA, in Entity entityB) where T : unmanaged
 | 
				
			||||||
| 
						 | 
					@ -397,15 +388,13 @@ public class World : IDisposable
 | 
				
			||||||
#if DEBUG
 | 
					#if DEBUG
 | 
				
			||||||
	public ComponentTypeEnumerator Debug_GetAllComponentTypes(Entity entity)
 | 
						public ComponentTypeEnumerator Debug_GetAllComponentTypes(Entity entity)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		return new ComponentTypeEnumerator(this, EntityComponentIndex[(int) entity.ID]);
 | 
							return new ComponentTypeEnumerator(this, EntityComponentIndex[entity]);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public IEnumerable<Entity> Debug_GetEntities(Type componentType)
 | 
						public Span<Entity> Debug_GetEntities(Type componentType)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		var baseGetComponentStorageMethod = typeof(World).GetMethod(nameof(World.GetComponentStorage), BindingFlags.NonPublic | BindingFlags.Instance)!;
 | 
							var storage = ComponentIndex[ComponentTypeToId[componentType]];
 | 
				
			||||||
		var genericGetComponentStorageMethod = baseGetComponentStorageMethod.MakeGenericMethod(componentType);
 | 
							return storage.Debug_GetEntities();
 | 
				
			||||||
		var storage = genericGetComponentStorageMethod.Invoke(this, null) as ComponentStorage;
 | 
					 | 
				
			||||||
		return storage!.Debug_GetEntities();
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public IEnumerable<Type> Debug_SearchComponentType(string typeString)
 | 
						public IEnumerable<Type> Debug_SearchComponentType(string typeString)
 | 
				
			||||||
| 
						 | 
					@ -468,14 +457,14 @@ public class World : IDisposable
 | 
				
			||||||
					messageStorage.Dispose();
 | 
										messageStorage.Dispose();
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				foreach (var componentSet in EntityComponentIndex)
 | 
									foreach (var typeSet in EntityComponentIndex.Values)
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					componentSet.Dispose();
 | 
										typeSet.Dispose();
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				foreach (var relationSet in EntityRelationIndex)
 | 
									foreach (var typeSet in EntityRelationIndex.Values)
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					relationSet.Dispose();
 | 
										typeSet.Dispose();
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				foreach (var filter in FilterIndex.Values)
 | 
									foreach (var filter in FilterIndex.Values)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue