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