remove implicit usings
							parent
							
								
									1123ef5662
								
							
						
					
					
						commit
						37d10db955
					
				| 
						 | 
					@ -2,7 +2,6 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <PropertyGroup>
 | 
					  <PropertyGroup>
 | 
				
			||||||
    <TargetFramework>net6.0</TargetFramework>
 | 
					    <TargetFramework>net6.0</TargetFramework>
 | 
				
			||||||
    <ImplicitUsings>enable</ImplicitUsings>
 | 
					 | 
				
			||||||
    <Nullable>enable</Nullable>
 | 
					    <Nullable>enable</Nullable>
 | 
				
			||||||
  </PropertyGroup>
 | 
					  </PropertyGroup>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,259 +1,263 @@
 | 
				
			||||||
namespace MoonTools.ECS;
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
internal class ComponentDepot
 | 
					namespace MoonTools.ECS
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	private Dictionary<Type, ComponentStorage> storages = new Dictionary<Type, ComponentStorage>();
 | 
						internal class ComponentDepot
 | 
				
			||||||
 | 
					 | 
				
			||||||
	private Dictionary<FilterSignature, IndexableSet<int>> filterSignatureToEntityIDs = new Dictionary<FilterSignature, IndexableSet<int>>();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	private Dictionary<Type, HashSet<FilterSignature>> typeToFilterSignatures = new Dictionary<Type, HashSet<FilterSignature>>();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	private Dictionary<int, HashSet<Type>> entityComponentMap = new Dictionary<int, HashSet<Type>>();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	#if DEBUG
 | 
					 | 
				
			||||||
	private Dictionary<Type, Filter> singleComponentFilters = new Dictionary<Type, Filter>();
 | 
					 | 
				
			||||||
	#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	internal void Register<TComponent>() where TComponent : struct
 | 
					 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		if (!storages.ContainsKey(typeof(TComponent)))
 | 
							private Dictionary<Type, ComponentStorage> storages = new Dictionary<Type, ComponentStorage>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							private Dictionary<FilterSignature, IndexableSet<int>> filterSignatureToEntityIDs = new Dictionary<FilterSignature, IndexableSet<int>>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							private Dictionary<Type, HashSet<FilterSignature>> typeToFilterSignatures = new Dictionary<Type, HashSet<FilterSignature>>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							private Dictionary<int, HashSet<Type>> entityComponentMap = new Dictionary<int, HashSet<Type>>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if DEBUG
 | 
				
			||||||
 | 
							private Dictionary<Type, Filter> singleComponentFilters = new Dictionary<Type, Filter>();
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							internal void Register<TComponent>() where TComponent : struct
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			storages.Add(typeof(TComponent), new ComponentStorage<TComponent>());
 | 
								if (!storages.ContainsKey(typeof(TComponent)))
 | 
				
			||||||
			#if DEBUG
 | 
					 | 
				
			||||||
			singleComponentFilters.Add(typeof(TComponent), CreateFilter(new HashSet<Type>() { typeof(TComponent) }, new HashSet<Type>()));
 | 
					 | 
				
			||||||
			#endif
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	private ComponentStorage Lookup(Type type)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return storages[type];
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	private ComponentStorage<TComponent> Lookup<TComponent>() where TComponent : struct
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		// TODO: is it possible to optimize this?
 | 
					 | 
				
			||||||
		Register<TComponent>();
 | 
					 | 
				
			||||||
		return storages[typeof(TComponent)] as ComponentStorage<TComponent>;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public bool Some<TComponent>() where TComponent : struct
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return Lookup<TComponent>().Any();
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public bool Has<TComponent>(int entityID) where TComponent : struct
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return Lookup<TComponent>().Has(entityID);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	private bool Has(Type type, int entityID)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return Lookup(type).Has(entityID);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public ref readonly TComponent Get<TComponent>(int entityID) where TComponent : struct
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return ref Lookup<TComponent>().Get(entityID);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public ref readonly TComponent Get<TComponent>() where TComponent : struct
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return ref Lookup<TComponent>().Get();
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public void Set<TComponent>(int entityID, in TComponent component) where TComponent : struct
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		Lookup<TComponent>().Set(entityID, component);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (!entityComponentMap.ContainsKey(entityID))
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			entityComponentMap.Add(entityID, new HashSet<Type>());
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		var notFound = entityComponentMap[entityID].Add(typeof(TComponent));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// update filters
 | 
					 | 
				
			||||||
		if (notFound)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			if (typeToFilterSignatures.TryGetValue(typeof(TComponent), out var filterSignatures))
 | 
					 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				foreach (var filterSignature in filterSignatures)
 | 
									storages.Add(typeof(TComponent), new ComponentStorage<TComponent>());
 | 
				
			||||||
 | 
					#if DEBUG
 | 
				
			||||||
 | 
									singleComponentFilters.Add(typeof(TComponent), CreateFilter(new HashSet<Type>() { typeof(TComponent) }, new HashSet<Type>()));
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							private ComponentStorage Lookup(Type type)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return storages[type];
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							private ComponentStorage<TComponent> Lookup<TComponent>() where TComponent : struct
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								// TODO: is it possible to optimize this?
 | 
				
			||||||
 | 
								Register<TComponent>();
 | 
				
			||||||
 | 
								return storages[typeof(TComponent)] as ComponentStorage<TComponent>;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public bool Some<TComponent>() where TComponent : struct
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return Lookup<TComponent>().Any();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public bool Has<TComponent>(int entityID) where TComponent : struct
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return Lookup<TComponent>().Has(entityID);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							private bool Has(Type type, int entityID)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return Lookup(type).Has(entityID);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public ref readonly TComponent Get<TComponent>(int entityID) where TComponent : struct
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return ref Lookup<TComponent>().Get(entityID);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public ref readonly TComponent Get<TComponent>() where TComponent : struct
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return ref Lookup<TComponent>().Get();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public void Set<TComponent>(int entityID, in TComponent component) where TComponent : struct
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								Lookup<TComponent>().Set(entityID, component);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!entityComponentMap.ContainsKey(entityID))
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									entityComponentMap.Add(entityID, new HashSet<Type>());
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								var notFound = entityComponentMap[entityID].Add(typeof(TComponent));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// update filters
 | 
				
			||||||
 | 
								if (notFound)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									if (typeToFilterSignatures.TryGetValue(typeof(TComponent), out var filterSignatures))
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					CheckFilter(filterSignature, entityID);
 | 
										foreach (var filterSignature in filterSignatures)
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											CheckFilter(filterSignature, entityID);
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public Entity GetSingletonEntity<TComponent>() where TComponent : struct
 | 
							public Entity GetSingletonEntity<TComponent>() where TComponent : struct
 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return Lookup<TComponent>().FirstEntity();
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public ReadOnlySpan<TComponent> ReadComponents<TComponent>() where TComponent : struct
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return Lookup<TComponent>().AllComponents();
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	private void Remove(Type type, int entityID)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		Lookup(type).Remove(entityID);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		var found = entityComponentMap[entityID].Remove(type);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// update filters
 | 
					 | 
				
			||||||
		if (found)
 | 
					 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			if (typeToFilterSignatures.TryGetValue(type, out var filterSignatures))
 | 
								return Lookup<TComponent>().FirstEntity();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public ReadOnlySpan<TComponent> ReadComponents<TComponent>() where TComponent : struct
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return Lookup<TComponent>().AllComponents();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							private void Remove(Type type, int entityID)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								Lookup(type).Remove(entityID);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								var found = entityComponentMap[entityID].Remove(type);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// update filters
 | 
				
			||||||
 | 
								if (found)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				foreach (var filterSignature in filterSignatures)
 | 
									if (typeToFilterSignatures.TryGetValue(type, out var filterSignatures))
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					CheckFilter(filterSignature, entityID);
 | 
										foreach (var filterSignature in filterSignatures)
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											CheckFilter(filterSignature, entityID);
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public void Remove<TComponent>(int entityID) where TComponent : struct
 | 
							public void Remove<TComponent>(int entityID) where TComponent : struct
 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		Lookup<TComponent>().Remove(entityID);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		var found = entityComponentMap[entityID].Remove(typeof(TComponent));
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
		// update filters
 | 
					 | 
				
			||||||
		if (found)
 | 
					 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			if (typeToFilterSignatures.TryGetValue(typeof(TComponent), out var filterSignatures))
 | 
								Lookup<TComponent>().Remove(entityID);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								var found = entityComponentMap[entityID].Remove(typeof(TComponent));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// update filters
 | 
				
			||||||
 | 
								if (found)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				foreach (var filterSignature in filterSignatures)
 | 
									if (typeToFilterSignatures.TryGetValue(typeof(TComponent), out var filterSignatures))
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					CheckFilter(filterSignature, entityID);
 | 
										foreach (var filterSignature in filterSignatures)
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											CheckFilter(filterSignature, entityID);
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public void OnEntityDestroy(int entityID)
 | 
							public void OnEntityDestroy(int entityID)
 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		if (entityComponentMap.ContainsKey(entityID))
 | 
					 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			foreach (var type in entityComponentMap[entityID])
 | 
								if (entityComponentMap.ContainsKey(entityID))
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				Remove(type, entityID);
 | 
									foreach (var type in entityComponentMap[entityID])
 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			entityComponentMap.Remove(entityID);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public Filter CreateFilter(HashSet<Type> included, HashSet<Type> excluded)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		var filterSignature = new FilterSignature(included, excluded);
 | 
					 | 
				
			||||||
		if (!filterSignatureToEntityIDs.ContainsKey(filterSignature))
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			filterSignatureToEntityIDs.Add(filterSignature, new IndexableSet<int>());
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			foreach (var type in included)
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				if (!typeToFilterSignatures.ContainsKey(type))
 | 
					 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					typeToFilterSignatures.Add(type, new HashSet<FilterSignature>());
 | 
										Remove(type, entityID);
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				typeToFilterSignatures[type].Add(filterSignature);
 | 
									entityComponentMap.Remove(entityID);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			foreach (var type in excluded)
 | 
							public Filter CreateFilter(HashSet<Type> included, HashSet<Type> excluded)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								var filterSignature = new FilterSignature(included, excluded);
 | 
				
			||||||
 | 
								if (!filterSignatureToEntityIDs.ContainsKey(filterSignature))
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				if (!typeToFilterSignatures.ContainsKey(type))
 | 
									filterSignatureToEntityIDs.Add(filterSignature, new IndexableSet<int>());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									foreach (var type in included)
 | 
				
			||||||
				{
 | 
									{
 | 
				
			||||||
					typeToFilterSignatures.Add(type, new HashSet<FilterSignature>());
 | 
										if (!typeToFilterSignatures.ContainsKey(type))
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											typeToFilterSignatures.Add(type, new HashSet<FilterSignature>());
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										typeToFilterSignatures[type].Add(filterSignature);
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
				typeToFilterSignatures[type].Add(filterSignature);
 | 
									foreach (var type in excluded)
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										if (!typeToFilterSignatures.ContainsKey(type))
 | 
				
			||||||
 | 
										{
 | 
				
			||||||
 | 
											typeToFilterSignatures.Add(type, new HashSet<FilterSignature>());
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										typeToFilterSignatures[type].Add(filterSignature);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
								return new Filter(this, included, excluded);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		return new Filter(this, included, excluded);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// FIXME: this dictionary should probably just store entities
 | 
							// FIXME: this dictionary should probably just store entities
 | 
				
			||||||
	public IEnumerable<Entity> FilterEntities(Filter filter)
 | 
							public IEnumerable<Entity> FilterEntities(Filter filter)
 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		foreach (var id in filterSignatureToEntityIDs[filter.Signature])
 | 
					 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			yield return new Entity(id);
 | 
								foreach (var id in filterSignatureToEntityIDs[filter.Signature])
 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public IEnumerable<Entity> FilterEntitiesRandom(Filter filter)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		foreach (var index in RandomGenerator.LinearCongruentialGenerator(FilterCount(filter)))
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			yield return new Entity(filterSignatureToEntityIDs[filter.Signature][index]);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public Entity FilterRandomEntity(Filter filter)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		var randomIndex = RandomGenerator.Next(FilterCount(filter));
 | 
					 | 
				
			||||||
		return new Entity(filterSignatureToEntityIDs[filter.Signature][randomIndex]);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public int FilterCount(Filter filter)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return filterSignatureToEntityIDs[filter.Signature].Count;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	private void CheckFilter(FilterSignature filterSignature, int entityID)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		foreach (var type in filterSignature.Included)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			if (!Has(type, entityID))
 | 
					 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				filterSignatureToEntityIDs[filterSignature].Remove(entityID);
 | 
									yield return new Entity(id);
 | 
				
			||||||
				return;
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		foreach (var type in filterSignature.Excluded)
 | 
							public IEnumerable<Entity> FilterEntitiesRandom(Filter filter)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			if (Has(type, entityID))
 | 
								foreach (var index in RandomGenerator.LinearCongruentialGenerator(FilterCount(filter)))
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				filterSignatureToEntityIDs[filterSignature].Remove(entityID);
 | 
									yield return new Entity(filterSignatureToEntityIDs[filter.Signature][index]);
 | 
				
			||||||
				return;
 | 
					 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		filterSignatureToEntityIDs[filterSignature].Add(entityID);
 | 
							public Entity FilterRandomEntity(Filter filter)
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	#if DEBUG
 | 
					 | 
				
			||||||
	public IEnumerable<object> Debug_GetAllComponents(int entityID)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		foreach (var (type, storage) in storages)
 | 
					 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			if (storage.Has(entityID))
 | 
								var randomIndex = RandomGenerator.Next(FilterCount(filter));
 | 
				
			||||||
			{
 | 
								return new Entity(filterSignatureToEntityIDs[filter.Signature][randomIndex]);
 | 
				
			||||||
				yield return storage.Debug_Get(entityID);
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public IEnumerable<Entity> Debug_GetEntities(Type componentType)
 | 
							public int FilterCount(Filter filter)
 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return singleComponentFilters[componentType].Entities;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public IEnumerable<Type> Debug_SearchComponentType(string typeString)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		foreach (var type in storages.Keys)
 | 
					 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			if (type.ToString().ToLower().Contains(typeString.ToLower()))
 | 
								return filterSignatureToEntityIDs[filter.Signature].Count;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							private void CheckFilter(FilterSignature filterSignature, int entityID)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								foreach (var type in filterSignature.Included)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				yield return type;
 | 
									if (!Has(type, entityID))
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										filterSignatureToEntityIDs[filterSignature].Remove(entityID);
 | 
				
			||||||
 | 
										return;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								foreach (var type in filterSignature.Excluded)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									if (Has(type, entityID))
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										filterSignatureToEntityIDs[filterSignature].Remove(entityID);
 | 
				
			||||||
 | 
										return;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								filterSignatureToEntityIDs[filterSignature].Add(entityID);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if DEBUG
 | 
				
			||||||
 | 
							public IEnumerable<object> Debug_GetAllComponents(int entityID)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								foreach (var (type, storage) in storages)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									if (storage.Has(entityID))
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										yield return storage.Debug_Get(entityID);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public IEnumerable<Entity> Debug_GetEntities(Type componentType)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return singleComponentFilters[componentType].Entities;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public IEnumerable<Type> Debug_SearchComponentType(string typeString)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								foreach (var type in storages.Keys)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									if (type.ToString().ToLower().Contains(typeString.ToLower()))
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										yield return type;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	#endif
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,106 +1,110 @@
 | 
				
			||||||
namespace MoonTools.ECS;
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
internal abstract class ComponentStorage
 | 
					namespace MoonTools.ECS
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	public abstract bool Has(int entityID);
 | 
						internal abstract class ComponentStorage
 | 
				
			||||||
	public abstract void Remove(int entityID);
 | 
					 | 
				
			||||||
	public abstract object Debug_Get(int entityID);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// FIXME: we can probably get rid of this weird entity storage system by using filters
 | 
					 | 
				
			||||||
internal class ComponentStorage<TComponent> : ComponentStorage where TComponent : struct
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	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];
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public bool Any()
 | 
					 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		return nextID > 0;
 | 
							public abstract bool Has(int entityID);
 | 
				
			||||||
 | 
							public abstract void Remove(int entityID);
 | 
				
			||||||
 | 
							public abstract object Debug_Get(int entityID);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public override bool Has(int entityID)
 | 
						// FIXME: we can probably get rid of this weird entity storage system by using filters
 | 
				
			||||||
 | 
						internal class ComponentStorage<TComponent> : ComponentStorage where TComponent : struct
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		return entityIDToStorageIndex.ContainsKey(entityID);
 | 
							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];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public ref readonly TComponent Get(int entityID)
 | 
							public bool Any()
 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return ref components[entityIDToStorageIndex[entityID]];
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public override object Debug_Get(int entityID)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return components[entityIDToStorageIndex[entityID]];
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public ref readonly TComponent Get()
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		#if DEBUG
 | 
					 | 
				
			||||||
		if (nextID == 0)
 | 
					 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			throw new ArgumentOutOfRangeException("Component storage is empty!");
 | 
								return nextID > 0;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		#endif
 | 
					 | 
				
			||||||
		return ref components[0];
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public void Set(int entityID, in TComponent component)
 | 
							public override bool Has(int entityID)
 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		if (!entityIDToStorageIndex.ContainsKey(entityID))
 | 
					 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			var index = nextID;
 | 
								return entityIDToStorageIndex.ContainsKey(entityID);
 | 
				
			||||||
			nextID += 1;
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (index >= components.Length)
 | 
							public ref readonly TComponent Get(int entityID)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return ref components[entityIDToStorageIndex[entityID]];
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public override object Debug_Get(int entityID)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return components[entityIDToStorageIndex[entityID]];
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public ref readonly TComponent Get()
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
					#if DEBUG
 | 
				
			||||||
 | 
								if (nextID == 0)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				Array.Resize(ref components, components.Length * 2);
 | 
									throw new ArgumentOutOfRangeException("Component storage is empty!");
 | 
				
			||||||
				Array.Resize(ref entityIDs, entityIDs.Length * 2);
 | 
								}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
								return ref components[0];
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public void Set(int entityID, in TComponent component)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (!entityIDToStorageIndex.ContainsKey(entityID))
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									var index = nextID;
 | 
				
			||||||
 | 
									nextID += 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (index >= components.Length)
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										Array.Resize(ref components, components.Length * 2);
 | 
				
			||||||
 | 
										Array.Resize(ref entityIDs, entityIDs.Length * 2);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									entityIDToStorageIndex[entityID] = index;
 | 
				
			||||||
 | 
									entityIDs[index] = entityID;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			entityIDToStorageIndex[entityID] = index;
 | 
								components[entityIDToStorageIndex[entityID]] = component;
 | 
				
			||||||
			entityIDs[index] = entityID;
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		components[entityIDToStorageIndex[entityID]] = component;
 | 
							public override void Remove(int entityID)
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public override void Remove(int entityID)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		if (entityIDToStorageIndex.ContainsKey(entityID))
 | 
					 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			var storageIndex = entityIDToStorageIndex[entityID];
 | 
								if (entityIDToStorageIndex.ContainsKey(entityID))
 | 
				
			||||||
			entityIDToStorageIndex.Remove(entityID);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			var lastElementIndex = nextID - 1;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			// move a component into the hole to maintain contiguous memory
 | 
					 | 
				
			||||||
			if (lastElementIndex != storageIndex)
 | 
					 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				var lastEntityID = entityIDs[lastElementIndex];
 | 
									var storageIndex = entityIDToStorageIndex[entityID];
 | 
				
			||||||
				entityIDToStorageIndex[lastEntityID] = storageIndex;
 | 
									entityIDToStorageIndex.Remove(entityID);
 | 
				
			||||||
				components[storageIndex] = components[lastElementIndex];
 | 
					
 | 
				
			||||||
				entityIDs[storageIndex] = lastEntityID;
 | 
									var lastElementIndex = nextID - 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									// move a component into the hole to maintain contiguous memory
 | 
				
			||||||
 | 
									if (lastElementIndex != storageIndex)
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										var lastEntityID = entityIDs[lastElementIndex];
 | 
				
			||||||
 | 
										entityIDToStorageIndex[lastEntityID] = storageIndex;
 | 
				
			||||||
 | 
										components[storageIndex] = components[lastElementIndex];
 | 
				
			||||||
 | 
										entityIDs[storageIndex] = lastEntityID;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									nextID -= 1;
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					 | 
				
			||||||
			nextID -= 1;
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public void Clear()
 | 
							public void Clear()
 | 
				
			||||||
	{
 | 
							{
 | 
				
			||||||
		nextID = 0;
 | 
								nextID = 0;
 | 
				
			||||||
		entityIDToStorageIndex.Clear();
 | 
								entityIDToStorageIndex.Clear();
 | 
				
			||||||
	}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public ReadOnlySpan<TComponent> AllComponents()
 | 
							public ReadOnlySpan<TComponent> AllComponents()
 | 
				
			||||||
	{
 | 
							{
 | 
				
			||||||
		return new ReadOnlySpan<TComponent>(components, 0, nextID);
 | 
								return new ReadOnlySpan<TComponent>(components, 0, nextID);
 | 
				
			||||||
	}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public Entity FirstEntity()
 | 
							public Entity FirstEntity()
 | 
				
			||||||
	{
 | 
							{
 | 
				
			||||||
		return new Entity(entityIDs[0]);
 | 
								return new Entity(entityIDs[0]);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,7 +1,10 @@
 | 
				
			||||||
// NOTE: these methods are very inefficient
 | 
					// NOTE: these methods are very inefficient
 | 
				
			||||||
// this class should only be used in debugging contexts!!
 | 
					// this class should only be used in debugging contexts!!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if DEBUG
 | 
					#if DEBUG
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace MoonTools.ECS
 | 
					namespace MoonTools.ECS
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	public abstract class DebugSystem : System
 | 
						public abstract class DebugSystem : System
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,26 +1,29 @@
 | 
				
			||||||
namespace MoonTools.ECS;
 | 
					using System;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public struct Entity : IEquatable<Entity>
 | 
					namespace MoonTools.ECS
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	public int ID { get; }
 | 
						public struct Entity : IEquatable<Entity>
 | 
				
			||||||
 | 
					 | 
				
			||||||
	internal Entity(int id)
 | 
					 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		ID = id;
 | 
							public int ID { get; }
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public override bool Equals(object? obj)
 | 
							internal Entity(int id)
 | 
				
			||||||
	{
 | 
							{
 | 
				
			||||||
		return obj is Entity entity && Equals(entity);
 | 
								ID = id;
 | 
				
			||||||
	}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public override int GetHashCode()
 | 
							public override bool Equals(object? obj)
 | 
				
			||||||
	{
 | 
							{
 | 
				
			||||||
		return HashCode.Combine(ID);
 | 
								return obj is Entity entity && Equals(entity);
 | 
				
			||||||
	}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public bool Equals(Entity other)
 | 
							public override int GetHashCode()
 | 
				
			||||||
	{
 | 
							{
 | 
				
			||||||
		return ID == other.ID;
 | 
								return HashCode.Combine(ID);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public bool Equals(Entity other)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return ID == other.ID;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,79 +1,83 @@
 | 
				
			||||||
namespace MoonTools.ECS;
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public abstract class EntityComponentReader
 | 
					namespace MoonTools.ECS
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	internal EntityStorage EntityStorage;
 | 
						public abstract class EntityComponentReader
 | 
				
			||||||
	internal ComponentDepot ComponentDepot;
 | 
					 | 
				
			||||||
	internal RelationDepot RelationDepot;
 | 
					 | 
				
			||||||
	protected FilterBuilder FilterBuilder => new FilterBuilder(ComponentDepot);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	internal void RegisterEntityStorage(EntityStorage entityStorage)
 | 
					 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		EntityStorage = entityStorage;
 | 
							internal EntityStorage EntityStorage;
 | 
				
			||||||
	}
 | 
							internal ComponentDepot ComponentDepot;
 | 
				
			||||||
 | 
							internal RelationDepot RelationDepot;
 | 
				
			||||||
 | 
							protected FilterBuilder FilterBuilder => new FilterBuilder(ComponentDepot);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	internal void RegisterComponentDepot(ComponentDepot componentDepot)
 | 
							internal void RegisterEntityStorage(EntityStorage entityStorage)
 | 
				
			||||||
	{
 | 
							{
 | 
				
			||||||
		ComponentDepot = componentDepot;
 | 
								EntityStorage = entityStorage;
 | 
				
			||||||
	}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	internal void RegisterRelationDepot(RelationDepot relationDepot)
 | 
							internal void RegisterComponentDepot(ComponentDepot componentDepot)
 | 
				
			||||||
	{
 | 
							{
 | 
				
			||||||
		RelationDepot = relationDepot;
 | 
								ComponentDepot = componentDepot;
 | 
				
			||||||
	}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	protected ReadOnlySpan<TComponent> ReadComponents<TComponent>() where TComponent : struct
 | 
							internal void RegisterRelationDepot(RelationDepot relationDepot)
 | 
				
			||||||
	{
 | 
							{
 | 
				
			||||||
		return ComponentDepot.ReadComponents<TComponent>();
 | 
								RelationDepot = relationDepot;
 | 
				
			||||||
	}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	protected bool Has<TComponent>(in Entity entity) where TComponent : struct
 | 
							protected ReadOnlySpan<TComponent> ReadComponents<TComponent>() where TComponent : struct
 | 
				
			||||||
	{
 | 
							{
 | 
				
			||||||
		return ComponentDepot.Has<TComponent>(entity.ID);
 | 
								return ComponentDepot.ReadComponents<TComponent>();
 | 
				
			||||||
	}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	protected bool Some<TComponent>() where TComponent : struct
 | 
							protected bool Has<TComponent>(in Entity entity) where TComponent : struct
 | 
				
			||||||
	{
 | 
							{
 | 
				
			||||||
		return ComponentDepot.Some<TComponent>();
 | 
								return ComponentDepot.Has<TComponent>(entity.ID);
 | 
				
			||||||
	}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	protected ref readonly TComponent Get<TComponent>(in Entity entity) where TComponent : struct
 | 
							protected bool Some<TComponent>() where TComponent : struct
 | 
				
			||||||
	{
 | 
							{
 | 
				
			||||||
		return ref ComponentDepot.Get<TComponent>(entity.ID);
 | 
								return ComponentDepot.Some<TComponent>();
 | 
				
			||||||
	}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	protected ref readonly TComponent GetSingleton<TComponent>() where TComponent : struct
 | 
							protected ref readonly TComponent Get<TComponent>(in Entity entity) where TComponent : struct
 | 
				
			||||||
	{
 | 
							{
 | 
				
			||||||
		return ref ComponentDepot.Get<TComponent>();
 | 
								return ref ComponentDepot.Get<TComponent>(entity.ID);
 | 
				
			||||||
	}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	protected Entity GetSingletonEntity<TComponent>() where TComponent : struct
 | 
							protected ref readonly TComponent GetSingleton<TComponent>() where TComponent : struct
 | 
				
			||||||
	{
 | 
							{
 | 
				
			||||||
		return ComponentDepot.GetSingletonEntity<TComponent>();
 | 
								return ref ComponentDepot.Get<TComponent>();
 | 
				
			||||||
	}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	protected bool Exists(in Entity entity)
 | 
							protected Entity GetSingletonEntity<TComponent>() where TComponent : struct
 | 
				
			||||||
	{
 | 
							{
 | 
				
			||||||
		return EntityStorage.Exists(entity);
 | 
								return ComponentDepot.GetSingletonEntity<TComponent>();
 | 
				
			||||||
	}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	protected IEnumerable<Relation> Relations<TRelationKind>()
 | 
							protected bool Exists(in Entity entity)
 | 
				
			||||||
	{
 | 
							{
 | 
				
			||||||
		return RelationDepot.Relations<TRelationKind>();
 | 
								return EntityStorage.Exists(entity);
 | 
				
			||||||
	}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	protected bool Related<TRelationKind>(in Entity a, in Entity b)
 | 
							protected IEnumerable<Relation> Relations<TRelationKind>()
 | 
				
			||||||
	{
 | 
							{
 | 
				
			||||||
		return RelationDepot.Related<TRelationKind>(a.ID, b.ID);
 | 
								return RelationDepot.Relations<TRelationKind>();
 | 
				
			||||||
	}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	protected IEnumerable<Entity> RelatedToA<TRelationKind>(in Entity entity)
 | 
							protected bool Related<TRelationKind>(in Entity a, in Entity b)
 | 
				
			||||||
	{
 | 
							{
 | 
				
			||||||
		return RelationDepot.RelatedToA<TRelationKind>(entity.ID);
 | 
								return RelationDepot.Related<TRelationKind>(a.ID, b.ID);
 | 
				
			||||||
	}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	protected IEnumerable<Entity> RelatedToB<TRelationKind>(in Entity entity)
 | 
							protected IEnumerable<Entity> RelatedToA<TRelationKind>(in Entity entity)
 | 
				
			||||||
	{
 | 
							{
 | 
				
			||||||
		return RelationDepot.RelatedToB<TRelationKind>(entity.ID);
 | 
								return RelationDepot.RelatedToA<TRelationKind>(entity.ID);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							protected IEnumerable<Entity> RelatedToB<TRelationKind>(in Entity entity)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return RelationDepot.RelatedToB<TRelationKind>(entity.ID);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,21 +1,22 @@
 | 
				
			||||||
namespace MoonTools.ECS;
 | 
					namespace MoonTools.ECS
 | 
				
			||||||
 | 
					 | 
				
			||||||
internal class EntityStorage
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	public IDStorage idStorage = new IDStorage();
 | 
						internal class EntityStorage
 | 
				
			||||||
 | 
					 | 
				
			||||||
	public Entity Create()
 | 
					 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		return new Entity(idStorage.NextID());
 | 
							public IDStorage idStorage = new IDStorage();
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public bool Exists(in Entity entity)
 | 
							public Entity Create()
 | 
				
			||||||
	{
 | 
							{
 | 
				
			||||||
		return idStorage.Taken(entity.ID);
 | 
								return new Entity(idStorage.NextID());
 | 
				
			||||||
	}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public void Destroy(in Entity entity)
 | 
							public bool Exists(in Entity entity)
 | 
				
			||||||
	{
 | 
							{
 | 
				
			||||||
		idStorage.Release(entity.ID);
 | 
								return idStorage.Taken(entity.ID);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public void Destroy(in Entity entity)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								idStorage.Release(entity.ID);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,20 +1,24 @@
 | 
				
			||||||
namespace MoonTools.ECS;
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public class Filter
 | 
					namespace MoonTools.ECS
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	internal FilterSignature Signature;
 | 
						public class Filter
 | 
				
			||||||
	private ComponentDepot ComponentDepot;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	internal Filter(ComponentDepot componentDepot, HashSet<Type> included, HashSet<Type> excluded)
 | 
					 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		ComponentDepot = componentDepot;
 | 
							internal FilterSignature Signature;
 | 
				
			||||||
		Signature = new FilterSignature(included, excluded);
 | 
							private ComponentDepot ComponentDepot;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							internal Filter(ComponentDepot componentDepot, HashSet<Type> included, HashSet<Type> excluded)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								ComponentDepot = componentDepot;
 | 
				
			||||||
 | 
								Signature = new FilterSignature(included, excluded);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public IEnumerable<Entity> Entities => ComponentDepot.FilterEntities(this);
 | 
				
			||||||
 | 
							public IEnumerable<Entity> EntitiesInRandomOrder => ComponentDepot.FilterEntitiesRandom(this);
 | 
				
			||||||
 | 
							public Entity RandomEntity => ComponentDepot.FilterRandomEntity(this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public int Count => ComponentDepot.FilterCount(this);
 | 
				
			||||||
 | 
							public bool Empty => Count == 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					 | 
				
			||||||
	public IEnumerable<Entity> Entities => ComponentDepot.FilterEntities(this);
 | 
					 | 
				
			||||||
	public IEnumerable<Entity> EntitiesInRandomOrder => ComponentDepot.FilterEntitiesRandom(this);
 | 
					 | 
				
			||||||
	public Entity RandomEntity => ComponentDepot.FilterRandomEntity(this);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public int Count => ComponentDepot.FilterCount(this);
 | 
					 | 
				
			||||||
	public bool Empty => Count == 0;
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,41 +1,45 @@
 | 
				
			||||||
namespace MoonTools.ECS;
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public struct FilterBuilder
 | 
					namespace MoonTools.ECS
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	private ComponentDepot ComponentDepot;
 | 
						public struct FilterBuilder
 | 
				
			||||||
	private HashSet<Type> Included;
 | 
					 | 
				
			||||||
	private HashSet<Type> Excluded;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	internal FilterBuilder(ComponentDepot componentDepot)
 | 
					 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		ComponentDepot = componentDepot;
 | 
							private ComponentDepot ComponentDepot;
 | 
				
			||||||
		Included = new HashSet<Type>();
 | 
							private HashSet<Type> Included;
 | 
				
			||||||
		Excluded = new HashSet<Type>();
 | 
							private HashSet<Type> Excluded;
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private FilterBuilder(ComponentDepot componentDepot, HashSet<Type> included, HashSet<Type> excluded)
 | 
							internal FilterBuilder(ComponentDepot componentDepot)
 | 
				
			||||||
	{
 | 
							{
 | 
				
			||||||
		ComponentDepot = componentDepot;
 | 
								ComponentDepot = componentDepot;
 | 
				
			||||||
		Included = included;
 | 
								Included = new HashSet<Type>();
 | 
				
			||||||
		Excluded = excluded;
 | 
								Excluded = new HashSet<Type>();
 | 
				
			||||||
	}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public FilterBuilder Include<TComponent>() where TComponent : struct
 | 
							private FilterBuilder(ComponentDepot componentDepot, HashSet<Type> included, HashSet<Type> excluded)
 | 
				
			||||||
	{
 | 
							{
 | 
				
			||||||
		ComponentDepot.Register<TComponent>();
 | 
								ComponentDepot = componentDepot;
 | 
				
			||||||
		Included.Add(typeof(TComponent));
 | 
								Included = included;
 | 
				
			||||||
		return new FilterBuilder(ComponentDepot, Included, Excluded);
 | 
								Excluded = excluded;
 | 
				
			||||||
	}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public FilterBuilder Exclude<TComponent>() where TComponent : struct
 | 
							public FilterBuilder Include<TComponent>() where TComponent : struct
 | 
				
			||||||
	{
 | 
							{
 | 
				
			||||||
		ComponentDepot.Register<TComponent>();
 | 
								ComponentDepot.Register<TComponent>();
 | 
				
			||||||
		Excluded.Add(typeof(TComponent));
 | 
								Included.Add(typeof(TComponent));
 | 
				
			||||||
		return new FilterBuilder(ComponentDepot, Included, Excluded);
 | 
								return new FilterBuilder(ComponentDepot, Included, Excluded);
 | 
				
			||||||
	}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public Filter Build()
 | 
							public FilterBuilder Exclude<TComponent>() where TComponent : struct
 | 
				
			||||||
	{
 | 
							{
 | 
				
			||||||
		return ComponentDepot.CreateFilter(Included, Excluded);
 | 
								ComponentDepot.Register<TComponent>();
 | 
				
			||||||
 | 
								Excluded.Add(typeof(TComponent));
 | 
				
			||||||
 | 
								return new FilterBuilder(ComponentDepot, Included, Excluded);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public Filter Build()
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return ComponentDepot.CreateFilter(Included, Excluded);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,47 +1,51 @@
 | 
				
			||||||
namespace MoonTools.ECS;
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public struct FilterSignature
 | 
					namespace MoonTools.ECS
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	private const int HASH_FACTOR = 97;
 | 
						public struct FilterSignature
 | 
				
			||||||
 | 
					 | 
				
			||||||
	public HashSet<Type> Included;
 | 
					 | 
				
			||||||
	public HashSet<Type> Excluded;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public FilterSignature(HashSet<Type> included, HashSet<Type> excluded)
 | 
					 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		Included = included;
 | 
							private const int HASH_FACTOR = 97;
 | 
				
			||||||
		Excluded = excluded;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public override bool Equals(object? obj)
 | 
							public HashSet<Type> Included;
 | 
				
			||||||
	{
 | 
							public HashSet<Type> Excluded;
 | 
				
			||||||
		return obj is FilterSignature signature && Equals(signature);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public bool Equals(FilterSignature other)
 | 
							public FilterSignature(HashSet<Type> included, HashSet<Type> excluded)
 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return Included.SetEquals(other.Included) && Excluded.SetEquals(other.Excluded);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	private int GuidToInt(Guid guid)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return BitConverter.ToInt32(guid.ToByteArray());
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public override int GetHashCode()
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		int result = 1;
 | 
					 | 
				
			||||||
		foreach (var type in Included)
 | 
					 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			result *= HASH_FACTOR + GuidToInt(type.GUID);
 | 
								Included = included;
 | 
				
			||||||
 | 
								Excluded = excluded;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// FIXME: Is there a way to avoid collisions when this is the same set as included?
 | 
							public override bool Equals(object? obj)
 | 
				
			||||||
		foreach (var type in Excluded)
 | 
					 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			result *= HASH_FACTOR + GuidToInt(type.GUID);
 | 
								return obj is FilterSignature signature && Equals(signature);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return result;
 | 
							public bool Equals(FilterSignature other)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return Included.SetEquals(other.Included) && Excluded.SetEquals(other.Excluded);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							private int GuidToInt(Guid guid)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return BitConverter.ToInt32(guid.ToByteArray());
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public override int GetHashCode()
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								int result = 1;
 | 
				
			||||||
 | 
								foreach (var type in Included)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									result *= HASH_FACTOR + GuidToInt(type.GUID);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								// FIXME: Is there a way to avoid collisions when this is the same set as included?
 | 
				
			||||||
 | 
								foreach (var type in Excluded)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									result *= HASH_FACTOR + GuidToInt(type.GUID);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return result;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,36 +1,39 @@
 | 
				
			||||||
namespace MoonTools.ECS;
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
internal class IDStorage
 | 
					namespace MoonTools.ECS
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	private int nextID = 0;
 | 
						internal class IDStorage
 | 
				
			||||||
 | 
					 | 
				
			||||||
	private readonly Stack<int> availableIDs = new Stack<int>();
 | 
					 | 
				
			||||||
	private readonly HashSet<int> availableIDHash = new HashSet<int>();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public int NextID()
 | 
					 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		if (availableIDs.Count > 0)
 | 
							private int nextID = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							private readonly Stack<int> availableIDs = new Stack<int>();
 | 
				
			||||||
 | 
							private readonly HashSet<int> availableIDHash = new HashSet<int>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public int NextID()
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			var id = availableIDs.Pop();
 | 
								if (availableIDs.Count > 0)
 | 
				
			||||||
			availableIDHash.Remove(id);
 | 
								{
 | 
				
			||||||
			return id;
 | 
									var id = availableIDs.Pop();
 | 
				
			||||||
 | 
									availableIDHash.Remove(id);
 | 
				
			||||||
 | 
									return id;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								else
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									var id = nextID;
 | 
				
			||||||
 | 
									nextID += 1;
 | 
				
			||||||
 | 
									return id;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		else
 | 
					
 | 
				
			||||||
 | 
							public bool Taken(int id)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			var id = nextID;
 | 
								return !availableIDHash.Contains(id) && id < nextID;
 | 
				
			||||||
			nextID += 1;
 | 
					 | 
				
			||||||
			return id;
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public bool Taken(int id)
 | 
							public void Release(int id)
 | 
				
			||||||
	{
 | 
							{
 | 
				
			||||||
		return !availableIDHash.Contains(id) && id < nextID;
 | 
								availableIDs.Push(id);
 | 
				
			||||||
	}
 | 
								availableIDHash.Add(id);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	public void Release(int id)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		availableIDs.Push(id);
 | 
					 | 
				
			||||||
		availableIDHash.Add(id);
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,7 @@
 | 
				
			||||||
namespace MoonTools.ECS;
 | 
					namespace MoonTools.ECS
 | 
				
			||||||
 | 
					 | 
				
			||||||
public interface IHasEntity
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	Entity Entity { get; }
 | 
						public interface IHasEntity
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							Entity Entity { get; }
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,4 +1,6 @@
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
using System.Collections;
 | 
					using System.Collections;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace MoonTools.ECS
 | 
					namespace MoonTools.ECS
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,59 +1,63 @@
 | 
				
			||||||
namespace MoonTools.ECS;
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
internal class MessageDepot
 | 
					namespace MoonTools.ECS
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	private Dictionary<Type, MessageStorage> storages = new Dictionary<Type, MessageStorage>();
 | 
						internal class MessageDepot
 | 
				
			||||||
 | 
					 | 
				
			||||||
	private MessageStorage<TMessage> Lookup<TMessage>() where TMessage : struct
 | 
					 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		if (!storages.ContainsKey(typeof(TMessage)))
 | 
							private Dictionary<Type, MessageStorage> storages = new Dictionary<Type, MessageStorage>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							private MessageStorage<TMessage> Lookup<TMessage>() where TMessage : struct
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			storages.Add(typeof(TMessage), new MessageStorage<TMessage>());
 | 
								if (!storages.ContainsKey(typeof(TMessage)))
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									storages.Add(typeof(TMessage), new MessageStorage<TMessage>());
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								return storages[typeof(TMessage)] as MessageStorage<TMessage>;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		return storages[typeof(TMessage)] as MessageStorage<TMessage>;
 | 
							public void Add<TMessage>(in TMessage message) where TMessage : struct
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public void Add<TMessage>(in TMessage message) where TMessage : struct
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		Lookup<TMessage>().Add(message);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public bool Some<TMessage>() where TMessage : struct
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return Lookup<TMessage>().Some();
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public ReadOnlySpan<TMessage> All<TMessage>() where TMessage : struct
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return Lookup<TMessage>().All();
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public TMessage First<TMessage>() where TMessage : struct
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return Lookup<TMessage>().First();
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public IEnumerable<TMessage> WithEntity<TMessage>(int entityID) where TMessage : struct, IHasEntity
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return Lookup<TMessage>().WithEntity(entityID);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public ref readonly TMessage FirstWithEntity<TMessage>(int entityID) where TMessage : struct, IHasEntity
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return ref Lookup<TMessage>().FirstWithEntity(entityID);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public bool SomeWithEntity<TMessage>(int entityID) where TMessage : struct, IHasEntity
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return Lookup<TMessage>().SomeWithEntity(entityID);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public void Clear()
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		foreach (var storage in storages.Values)
 | 
					 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			storage.Clear();
 | 
								Lookup<TMessage>().Add(message);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public bool Some<TMessage>() where TMessage : struct
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return Lookup<TMessage>().Some();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public ReadOnlySpan<TMessage> All<TMessage>() where TMessage : struct
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return Lookup<TMessage>().All();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public TMessage First<TMessage>() where TMessage : struct
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return Lookup<TMessage>().First();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public IEnumerable<TMessage> WithEntity<TMessage>(int entityID) where TMessage : struct, IHasEntity
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return Lookup<TMessage>().WithEntity(entityID);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public ref readonly TMessage FirstWithEntity<TMessage>(int entityID) where TMessage : struct, IHasEntity
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return ref Lookup<TMessage>().FirstWithEntity(entityID);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public bool SomeWithEntity<TMessage>(int entityID) where TMessage : struct, IHasEntity
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return Lookup<TMessage>().SomeWithEntity(entityID);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public void Clear()
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								foreach (var storage in storages.Values)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									storage.Clear();
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,87 +1,91 @@
 | 
				
			||||||
namespace MoonTools.ECS;
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
internal abstract class MessageStorage
 | 
					namespace MoonTools.ECS
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	public abstract void Clear();
 | 
						internal abstract class MessageStorage
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
internal class MessageStorage<TMessage> : MessageStorage where TMessage : struct
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	private int count = 0;
 | 
					 | 
				
			||||||
	private int capacity = 128;
 | 
					 | 
				
			||||||
	private TMessage[] messages;
 | 
					 | 
				
			||||||
	private Dictionary<int, List<int>> entityToIndices = new Dictionary<int, List<int>>();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public MessageStorage()
 | 
					 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		messages = new TMessage[capacity];
 | 
							public abstract void Clear();
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public void Add(in TMessage message)
 | 
						internal class MessageStorage<TMessage> : MessageStorage where TMessage : struct
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		if (count == capacity)
 | 
							private int count = 0;
 | 
				
			||||||
 | 
							private int capacity = 128;
 | 
				
			||||||
 | 
							private TMessage[] messages;
 | 
				
			||||||
 | 
							private Dictionary<int, List<int>> entityToIndices = new Dictionary<int, List<int>>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public MessageStorage()
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			capacity *= 2;
 | 
								messages = new TMessage[capacity];
 | 
				
			||||||
			Array.Resize(ref messages, capacity);
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		messages[count] = message;
 | 
							public void Add(in TMessage message)
 | 
				
			||||||
 | 
					 | 
				
			||||||
		if (message is IHasEntity entityMessage)
 | 
					 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			if (!entityToIndices.ContainsKey(entityMessage.Entity.ID))
 | 
								if (count == capacity)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				entityToIndices.Add(entityMessage.Entity.ID, new List<int>());
 | 
									capacity *= 2;
 | 
				
			||||||
 | 
									Array.Resize(ref messages, capacity);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			entityToIndices[entityMessage.Entity.ID].Add(count);
 | 
								messages[count] = message;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (message is IHasEntity entityMessage)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									if (!entityToIndices.ContainsKey(entityMessage.Entity.ID))
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										entityToIndices.Add(entityMessage.Entity.ID, new List<int>());
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									entityToIndices[entityMessage.Entity.ID].Add(count);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								count += 1;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		count += 1;
 | 
							public bool Some()
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public bool Some()
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return count > 0;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public ReadOnlySpan<TMessage> All()
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return new ReadOnlySpan<TMessage>(messages, 0, count);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public TMessage First()
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return messages[0];
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public IEnumerable<TMessage> WithEntity(int entityID)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		if (entityToIndices.ContainsKey(entityID))
 | 
					 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			foreach (var index in entityToIndices[entityID])
 | 
								return count > 0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public ReadOnlySpan<TMessage> All()
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return new ReadOnlySpan<TMessage>(messages, 0, count);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public TMessage First()
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return messages[0];
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public IEnumerable<TMessage> WithEntity(int entityID)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								if (entityToIndices.ContainsKey(entityID))
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				yield return messages[index];
 | 
									foreach (var index in entityToIndices[entityID])
 | 
				
			||||||
 | 
									{
 | 
				
			||||||
 | 
										yield return messages[index];
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public ref readonly TMessage FirstWithEntity(int entityID)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return ref messages[entityToIndices[entityID][0]];
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public bool SomeWithEntity(int entityID)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								return entityToIndices.ContainsKey(entityID) && entityToIndices[entityID].Count > 0;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public override void Clear()
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								count = 0;
 | 
				
			||||||
 | 
								foreach (var set in entityToIndices.Values)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									set.Clear();
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					 | 
				
			||||||
	public ref readonly TMessage FirstWithEntity(int entityID)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return ref messages[entityToIndices[entityID][0]];
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public bool SomeWithEntity(int entityID)
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return entityToIndices.ContainsKey(entityID) && entityToIndices[entityID].Count > 0;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public override void Clear()
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		count = 0;
 | 
					 | 
				
			||||||
		foreach (var set in entityToIndices.Values)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			set.Clear();
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,3 +1,6 @@
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace MoonTools.ECS
 | 
					namespace MoonTools.ECS
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	internal static class RandomGenerator
 | 
						internal static class RandomGenerator
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,3 +1,5 @@
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace MoonTools.ECS
 | 
					namespace MoonTools.ECS
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	public struct Relation : IEquatable<Relation>
 | 
						public struct Relation : IEquatable<Relation>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,3 +1,6 @@
 | 
				
			||||||
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace MoonTools.ECS
 | 
					namespace MoonTools.ECS
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	internal class RelationDepot
 | 
						internal class RelationDepot
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,3 +1,5 @@
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace MoonTools.ECS
 | 
					namespace MoonTools.ECS
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	internal class RelationStorage
 | 
						internal class RelationStorage
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,9 +1,10 @@
 | 
				
			||||||
namespace MoonTools.ECS;
 | 
					namespace MoonTools.ECS
 | 
				
			||||||
 | 
					 | 
				
			||||||
public abstract class Renderer : EntityComponentReader
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	public Renderer(World world)
 | 
						public abstract class Renderer : EntityComponentReader
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		world.AddRenderer(this);
 | 
							public Renderer(World world)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								world.AddRenderer(this);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										150
									
								
								src/System.cs
								
								
								
								
							
							
						
						
									
										150
									
								
								src/System.cs
								
								
								
								
							| 
						 | 
					@ -1,92 +1,96 @@
 | 
				
			||||||
namespace MoonTools.ECS;
 | 
					using System;
 | 
				
			||||||
 | 
					using System.Collections.Generic;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
public abstract class System : EntityComponentReader
 | 
					namespace MoonTools.ECS
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	internal MessageDepot MessageDepot;
 | 
						public abstract class System : EntityComponentReader
 | 
				
			||||||
 | 
					 | 
				
			||||||
	internal void RegisterMessageDepot(MessageDepot messageDepot)
 | 
					 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		MessageDepot = messageDepot;
 | 
							internal MessageDepot MessageDepot;
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public System(World world)
 | 
							internal void RegisterMessageDepot(MessageDepot messageDepot)
 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		world.AddSystem(this);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	public abstract void Update(TimeSpan delta);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	protected Entity CreateEntity()
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return EntityStorage.Create();
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	protected void Set<TComponent>(in Entity entity, in TComponent component) where TComponent : struct
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		#if DEBUG
 | 
					 | 
				
			||||||
		// check for use after destroy
 | 
					 | 
				
			||||||
		if (!Exists(entity))
 | 
					 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			throw new ArgumentException("This entity is not valid!");
 | 
								MessageDepot = messageDepot;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		#endif
 | 
					 | 
				
			||||||
		ComponentDepot.Set<TComponent>(entity.ID, component);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	protected void Remove<TComponent>(in Entity entity) where TComponent : struct
 | 
							public System(World world)
 | 
				
			||||||
	{
 | 
							{
 | 
				
			||||||
		ComponentDepot.Remove<TComponent>(entity.ID);
 | 
								world.AddSystem(this);
 | 
				
			||||||
	}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	protected ReadOnlySpan<TMessage> ReadMessages<TMessage>() where TMessage : struct
 | 
							public abstract void Update(TimeSpan delta);
 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		return MessageDepot.All<TMessage>();
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	protected TMessage ReadMessage<TMessage>() where TMessage : struct
 | 
							protected Entity CreateEntity()
 | 
				
			||||||
	{
 | 
							{
 | 
				
			||||||
		return MessageDepot.First<TMessage>();
 | 
								return EntityStorage.Create();
 | 
				
			||||||
	}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	protected bool SomeMessage<TMessage>() where TMessage : struct
 | 
							protected void Set<TComponent>(in Entity entity, in TComponent component) where TComponent : struct
 | 
				
			||||||
	{
 | 
							{
 | 
				
			||||||
		return MessageDepot.Some<TMessage>();
 | 
					#if DEBUG
 | 
				
			||||||
	}
 | 
								// check for use after destroy
 | 
				
			||||||
 | 
								if (!Exists(entity))
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									throw new ArgumentException("This entity is not valid!");
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
								ComponentDepot.Set<TComponent>(entity.ID, component);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	protected IEnumerable<TMessage> ReadMessagesWithEntity<TMessage>(in Entity entity) where TMessage : struct, IHasEntity
 | 
							protected void Remove<TComponent>(in Entity entity) where TComponent : struct
 | 
				
			||||||
	{
 | 
							{
 | 
				
			||||||
		return MessageDepot.WithEntity<TMessage>(entity.ID);
 | 
								ComponentDepot.Remove<TComponent>(entity.ID);
 | 
				
			||||||
	}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	protected ref readonly TMessage ReadMessageWithEntity<TMessage>(in Entity entity) where TMessage : struct, IHasEntity
 | 
							protected ReadOnlySpan<TMessage> ReadMessages<TMessage>() where TMessage : struct
 | 
				
			||||||
	{
 | 
							{
 | 
				
			||||||
		return ref MessageDepot.FirstWithEntity<TMessage>(entity.ID);
 | 
								return MessageDepot.All<TMessage>();
 | 
				
			||||||
	}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	protected bool SomeMessageWithEntity<TMessage>(in Entity entity) where TMessage : struct, IHasEntity
 | 
							protected TMessage ReadMessage<TMessage>() where TMessage : struct
 | 
				
			||||||
	{
 | 
							{
 | 
				
			||||||
		return MessageDepot.SomeWithEntity<TMessage>(entity.ID);
 | 
								return MessageDepot.First<TMessage>();
 | 
				
			||||||
	}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	protected void Send<TMessage>(in TMessage message) where TMessage : struct
 | 
							protected bool SomeMessage<TMessage>() where TMessage : struct
 | 
				
			||||||
	{
 | 
							{
 | 
				
			||||||
		MessageDepot.Add(message);
 | 
								return MessageDepot.Some<TMessage>();
 | 
				
			||||||
	}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	protected void Relate<TRelationKind>(in Entity entityA, in Entity entityB)
 | 
							protected IEnumerable<TMessage> ReadMessagesWithEntity<TMessage>(in Entity entity) where TMessage : struct, IHasEntity
 | 
				
			||||||
	{
 | 
							{
 | 
				
			||||||
		RelationDepot.Add<TRelationKind>(new Relation(entityA, entityB));
 | 
								return MessageDepot.WithEntity<TMessage>(entity.ID);
 | 
				
			||||||
	}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	protected void Unrelate<TRelationKind>(in Entity entityA, in Entity entityB)
 | 
							protected ref readonly TMessage ReadMessageWithEntity<TMessage>(in Entity entity) where TMessage : struct, IHasEntity
 | 
				
			||||||
	{
 | 
							{
 | 
				
			||||||
		RelationDepot.Remove<TRelationKind>(new Relation(entityA, entityB));
 | 
								return ref MessageDepot.FirstWithEntity<TMessage>(entity.ID);
 | 
				
			||||||
	}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	protected void Destroy(in Entity entity)
 | 
							protected bool SomeMessageWithEntity<TMessage>(in Entity entity) where TMessage : struct, IHasEntity
 | 
				
			||||||
	{
 | 
							{
 | 
				
			||||||
		ComponentDepot.OnEntityDestroy(entity.ID);
 | 
								return MessageDepot.SomeWithEntity<TMessage>(entity.ID);
 | 
				
			||||||
		RelationDepot.OnEntityDestroy(entity.ID);
 | 
							}
 | 
				
			||||||
		EntityStorage.Destroy(entity);
 | 
					
 | 
				
			||||||
 | 
							protected void Send<TMessage>(in TMessage message) where TMessage : struct
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								MessageDepot.Add(message);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							protected void Relate<TRelationKind>(in Entity entityA, in Entity entityB)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								RelationDepot.Add<TRelationKind>(new Relation(entityA, entityB));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							protected void Unrelate<TRelationKind>(in Entity entityA, in Entity entityB)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								RelationDepot.Remove<TRelationKind>(new Relation(entityA, entityB));
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							protected void Destroy(in Entity entity)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								ComponentDepot.OnEntityDestroy(entity.ID);
 | 
				
			||||||
 | 
								RelationDepot.OnEntityDestroy(entity.ID);
 | 
				
			||||||
 | 
								EntityStorage.Destroy(entity);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										79
									
								
								src/World.cs
								
								
								
								
							
							
						
						
									
										79
									
								
								src/World.cs
								
								
								
								
							| 
						 | 
					@ -1,49 +1,50 @@
 | 
				
			||||||
namespace MoonTools.ECS;
 | 
					namespace MoonTools.ECS
 | 
				
			||||||
 | 
					 | 
				
			||||||
public class World
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	private readonly EntityStorage EntityStorage = new EntityStorage();
 | 
						public class World
 | 
				
			||||||
	private readonly ComponentDepot ComponentDepot = new ComponentDepot();
 | 
					 | 
				
			||||||
	private readonly MessageDepot MessageDepot = new MessageDepot();
 | 
					 | 
				
			||||||
	private readonly RelationDepot RelationDepot = new RelationDepot();
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	internal void AddSystem(System system)
 | 
					 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		system.RegisterEntityStorage(EntityStorage);
 | 
							private readonly EntityStorage EntityStorage = new EntityStorage();
 | 
				
			||||||
		system.RegisterComponentDepot(ComponentDepot);
 | 
							private readonly ComponentDepot ComponentDepot = new ComponentDepot();
 | 
				
			||||||
		system.RegisterMessageDepot(MessageDepot);
 | 
							private readonly MessageDepot MessageDepot = new MessageDepot();
 | 
				
			||||||
		system.RegisterRelationDepot(RelationDepot);
 | 
							private readonly RelationDepot RelationDepot = new RelationDepot();
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	internal void AddRenderer(Renderer renderer)
 | 
							internal void AddSystem(System system)
 | 
				
			||||||
	{
 | 
							{
 | 
				
			||||||
		renderer.RegisterEntityStorage(EntityStorage);
 | 
								system.RegisterEntityStorage(EntityStorage);
 | 
				
			||||||
		renderer.RegisterComponentDepot(ComponentDepot);
 | 
								system.RegisterComponentDepot(ComponentDepot);
 | 
				
			||||||
		renderer.RegisterRelationDepot(RelationDepot);
 | 
								system.RegisterMessageDepot(MessageDepot);
 | 
				
			||||||
	}
 | 
								system.RegisterRelationDepot(RelationDepot);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public void AddRelationKind<TRelationKind>()
 | 
							internal void AddRenderer(Renderer renderer)
 | 
				
			||||||
	{
 | 
							{
 | 
				
			||||||
		RelationDepot.Register<TRelationKind>();
 | 
								renderer.RegisterEntityStorage(EntityStorage);
 | 
				
			||||||
	}
 | 
								renderer.RegisterComponentDepot(ComponentDepot);
 | 
				
			||||||
 | 
								renderer.RegisterRelationDepot(RelationDepot);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public Entity CreateEntity()
 | 
							public void AddRelationKind<TRelationKind>()
 | 
				
			||||||
	{
 | 
							{
 | 
				
			||||||
		return EntityStorage.Create();
 | 
								RelationDepot.Register<TRelationKind>();
 | 
				
			||||||
	}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public void Set<TComponent>(Entity entity, in TComponent component) where TComponent : struct
 | 
							public Entity CreateEntity()
 | 
				
			||||||
	{
 | 
							{
 | 
				
			||||||
		ComponentDepot.Set(entity.ID, component);
 | 
								return EntityStorage.Create();
 | 
				
			||||||
	}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public void Send<TMessage>(in TMessage message) where TMessage : struct
 | 
							public void Set<TComponent>(Entity entity, in TComponent component) where TComponent : struct
 | 
				
			||||||
	{
 | 
							{
 | 
				
			||||||
		MessageDepot.Add(message);
 | 
								ComponentDepot.Set(entity.ID, component);
 | 
				
			||||||
	}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	public void FinishUpdate()
 | 
							public void Send<TMessage>(in TMessage message) where TMessage : struct
 | 
				
			||||||
	{
 | 
							{
 | 
				
			||||||
		MessageDepot.Clear();
 | 
								MessageDepot.Add(message);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							public void FinishUpdate()
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								MessageDepot.Clear();
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue