2022-03-05 02:01:44 +00:00
|
|
|
|
namespace MoonTools.ECS;
|
|
|
|
|
|
|
|
|
|
internal class ComponentDepot
|
|
|
|
|
{
|
|
|
|
|
private Dictionary<Type, ComponentStorage> storages = new Dictionary<Type, ComponentStorage>();
|
|
|
|
|
|
2022-03-06 06:12:27 +00:00
|
|
|
|
private Dictionary<FilterSignature, HashSet<int>> filterSignatureToEntityIDs = new Dictionary<FilterSignature, HashSet<int>>();
|
|
|
|
|
|
|
|
|
|
private Dictionary<Type, HashSet<FilterSignature>> typeToFilterSignatures = new Dictionary<Type, HashSet<FilterSignature>>();
|
|
|
|
|
|
2022-03-05 02:01:44 +00:00
|
|
|
|
private Dictionary<int, HashSet<Type>> entityComponentMap = new Dictionary<int, HashSet<Type>>();
|
|
|
|
|
|
2022-03-07 20:05:06 +00:00
|
|
|
|
internal void Register<TComponent>() where TComponent : struct
|
|
|
|
|
{
|
|
|
|
|
if (!storages.ContainsKey(typeof(TComponent)))
|
|
|
|
|
{
|
|
|
|
|
storages.Add(typeof(TComponent), new ComponentStorage<TComponent>());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-06 06:12:27 +00:00
|
|
|
|
private ComponentStorage Lookup(Type type)
|
|
|
|
|
{
|
|
|
|
|
return storages[type];
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-05 02:01:44 +00:00
|
|
|
|
private ComponentStorage<TComponent> Lookup<TComponent>() where TComponent : struct
|
|
|
|
|
{
|
|
|
|
|
// TODO: is it possible to optimize this?
|
2022-03-07 20:05:06 +00:00
|
|
|
|
Register<TComponent>();
|
2022-03-05 02:01:44 +00:00
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-06 06:12:27 +00:00
|
|
|
|
private bool Has(Type type, int entityID)
|
|
|
|
|
{
|
|
|
|
|
return Lookup(type).Has(entityID);
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-05 02:01:44 +00:00
|
|
|
|
public ref readonly TComponent Get<TComponent>(int entityID) where TComponent : struct
|
|
|
|
|
{
|
|
|
|
|
return ref Lookup<TComponent>().Get(entityID);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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>());
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-07 19:46:17 +00:00
|
|
|
|
var notFound = entityComponentMap[entityID].Add(typeof(TComponent));
|
2022-03-06 06:12:27 +00:00
|
|
|
|
|
|
|
|
|
// update filters
|
2022-03-07 19:46:17 +00:00
|
|
|
|
if (notFound)
|
2022-03-06 06:12:27 +00:00
|
|
|
|
{
|
|
|
|
|
if (typeToFilterSignatures.TryGetValue(typeof(TComponent), out var filterSignatures))
|
|
|
|
|
{
|
|
|
|
|
foreach (var filterSignature in filterSignatures)
|
|
|
|
|
{
|
2022-03-07 20:05:06 +00:00
|
|
|
|
CheckFilter(filterSignature, entityID);
|
2022-03-06 06:12:27 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-03-05 02:01:44 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public ReadOnlySpan<Entity> ReadEntities<TComponent>() where TComponent : struct
|
|
|
|
|
{
|
|
|
|
|
return Lookup<TComponent>().AllEntities();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public ReadOnlySpan<TComponent> ReadComponents<TComponent>() where TComponent : struct
|
|
|
|
|
{
|
|
|
|
|
return Lookup<TComponent>().AllComponents();
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-07 06:43:53 +00:00
|
|
|
|
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))
|
|
|
|
|
{
|
|
|
|
|
foreach (var filterSignature in filterSignatures)
|
|
|
|
|
{
|
2022-03-07 20:05:06 +00:00
|
|
|
|
CheckFilter(filterSignature, entityID);
|
2022-03-07 06:43:53 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-05 02:01:44 +00:00
|
|
|
|
public void Remove<TComponent>(int entityID) where TComponent : struct
|
|
|
|
|
{
|
|
|
|
|
Lookup<TComponent>().Remove(entityID);
|
|
|
|
|
|
2022-03-06 06:12:27 +00:00
|
|
|
|
var found = entityComponentMap[entityID].Remove(typeof(TComponent));
|
|
|
|
|
|
|
|
|
|
// update filters
|
|
|
|
|
if (found)
|
|
|
|
|
{
|
|
|
|
|
if (typeToFilterSignatures.TryGetValue(typeof(TComponent), out var filterSignatures))
|
|
|
|
|
{
|
|
|
|
|
foreach (var filterSignature in filterSignatures)
|
|
|
|
|
{
|
|
|
|
|
CheckFilter(filterSignature, entityID);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-03-05 02:01:44 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void OnEntityDestroy(int entityID)
|
|
|
|
|
{
|
|
|
|
|
if (entityComponentMap.ContainsKey(entityID))
|
|
|
|
|
{
|
|
|
|
|
foreach (var type in entityComponentMap[entityID])
|
|
|
|
|
{
|
2022-03-07 06:43:53 +00:00
|
|
|
|
Remove(type, entityID);
|
2022-03-05 02:01:44 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
entityComponentMap.Remove(entityID);
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-03-06 06:12:27 +00:00
|
|
|
|
|
|
|
|
|
public Filter CreateFilter(HashSet<Type> included, HashSet<Type> excluded)
|
|
|
|
|
{
|
|
|
|
|
var filterSignature = new FilterSignature(included, excluded);
|
|
|
|
|
if (!filterSignatureToEntityIDs.ContainsKey(filterSignature))
|
|
|
|
|
{
|
|
|
|
|
filterSignatureToEntityIDs.Add(filterSignature, new HashSet<int>());
|
|
|
|
|
|
|
|
|
|
foreach (var type in included)
|
|
|
|
|
{
|
|
|
|
|
if (!typeToFilterSignatures.ContainsKey(type))
|
|
|
|
|
{
|
|
|
|
|
typeToFilterSignatures.Add(type, new HashSet<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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public IEnumerable<Entity> FilterEntities(Filter filter)
|
|
|
|
|
{
|
|
|
|
|
foreach (var id in filterSignatureToEntityIDs[filter.Signature])
|
|
|
|
|
{
|
|
|
|
|
yield return new Entity(id);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-07 20:05:06 +00:00
|
|
|
|
private void CheckFilter(FilterSignature filterSignature, int entityID)
|
2022-03-06 06:12:27 +00:00
|
|
|
|
{
|
|
|
|
|
foreach (var type in filterSignature.Included)
|
|
|
|
|
{
|
|
|
|
|
if (!Has(type, entityID))
|
|
|
|
|
{
|
2022-03-07 20:05:06 +00:00
|
|
|
|
filterSignatureToEntityIDs[filterSignature].Remove(entityID);
|
|
|
|
|
return;
|
2022-03-06 06:12:27 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach (var type in filterSignature.Excluded)
|
|
|
|
|
{
|
|
|
|
|
if (Has(type, entityID))
|
|
|
|
|
{
|
2022-03-07 20:05:06 +00:00
|
|
|
|
filterSignatureToEntityIDs[filterSignature].Remove(entityID);
|
|
|
|
|
return;
|
2022-03-06 06:12:27 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-07 20:05:06 +00:00
|
|
|
|
filterSignatureToEntityIDs[filterSignature].Add(entityID);
|
2022-03-06 06:12:27 +00:00
|
|
|
|
}
|
2022-03-05 02:01:44 +00:00
|
|
|
|
}
|