276 lines
11 KiB
C#
276 lines
11 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
|
|
namespace Encompass
|
|
{
|
|
internal class ComponentUpdateManager
|
|
{
|
|
private readonly ComponentStore existingAndPendingComponentStore;
|
|
private readonly ComponentStore existingComponentStore;
|
|
private readonly ComponentStore pendingComponentStore;
|
|
private readonly Dictionary<Type, Dictionary<Entity, int>> typeToEntityToPendingComponentPriority = new Dictionary<Type, Dictionary<Entity, int>>(128);
|
|
private Dictionary<Type, int> typeToIndex;
|
|
public ComponentStore UpToDateComponentStore { get; private set; }
|
|
|
|
// bitarray references to avoid garbage collection
|
|
BitArray pendingMask;
|
|
BitArray readMask;
|
|
BitArray withMask;
|
|
BitArray withoutMask;
|
|
BitArray notWithMask;
|
|
BitArray solverArrayA;
|
|
BitArray solverArrayB;
|
|
BitArray solverArrayC;
|
|
|
|
public ComponentUpdateManager(Dictionary<Type, int> typeToIndex)
|
|
{
|
|
existingAndPendingComponentStore = new ComponentStore(typeToIndex);
|
|
existingComponentStore = new ComponentStore(typeToIndex);
|
|
pendingComponentStore = new ComponentStore(typeToIndex);
|
|
UpToDateComponentStore = new ComponentStore(typeToIndex);
|
|
this.typeToIndex = typeToIndex;
|
|
}
|
|
|
|
public void RegisterComponentType<TComponent>() where TComponent : struct, IComponent
|
|
{
|
|
existingAndPendingComponentStore.RegisterComponentType<TComponent>();
|
|
existingComponentStore.RegisterComponentType<TComponent>();
|
|
pendingComponentStore.RegisterComponentType<TComponent>();
|
|
UpToDateComponentStore.RegisterComponentType<TComponent>();
|
|
}
|
|
|
|
public void FinishRegistering()
|
|
{
|
|
existingAndPendingComponentStore.FinishRegistering();
|
|
existingComponentStore.FinishRegistering();
|
|
pendingComponentStore.FinishRegistering();
|
|
UpToDateComponentStore.FinishRegistering();
|
|
|
|
pendingMask = new BitArray(typeToIndex.Count);
|
|
readMask = new BitArray(typeToIndex.Count);
|
|
withMask = new BitArray(typeToIndex.Count);
|
|
withoutMask = new BitArray(typeToIndex.Count);
|
|
notWithMask = new BitArray(typeToIndex.Count);
|
|
solverArrayA = new BitArray(typeToIndex.Count);
|
|
solverArrayB = new BitArray(typeToIndex.Count);
|
|
solverArrayC = new BitArray(typeToIndex.Count);
|
|
}
|
|
|
|
internal void Clear()
|
|
{
|
|
existingAndPendingComponentStore.ClearAll();
|
|
existingComponentStore.ClearAll();
|
|
pendingComponentStore.ClearAll();
|
|
UpToDateComponentStore.ClearAll();
|
|
|
|
foreach (var dictionary in typeToEntityToPendingComponentPriority.Values)
|
|
{
|
|
dictionary.Clear();
|
|
}
|
|
}
|
|
|
|
internal void SetStartingComponentStore(ComponentStore componentStore)
|
|
{
|
|
UpToDateComponentStore = componentStore;
|
|
}
|
|
|
|
internal void AddExistingComponent<TComponent>(Entity entity, TComponent component) where TComponent : struct, IComponent
|
|
{
|
|
RegisterExistingOrPendingComponentMessage(entity, component);
|
|
|
|
existingComponentStore.Set(entity, component);
|
|
}
|
|
|
|
internal bool AddPendingComponent<TComponent>(Entity entity, TComponent component, int priority) where TComponent : struct, IComponent
|
|
{
|
|
if (pendingComponentStore.Set(entity, component, priority))
|
|
{
|
|
RegisterExistingOrPendingComponentMessage(entity, component);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private void RegisterExistingOrPendingComponentMessage<TComponent>(Entity entity, TComponent component) where TComponent : struct, IComponent
|
|
{
|
|
existingAndPendingComponentStore.Set(entity, component);
|
|
UpToDateComponentStore.Set(entity, component);
|
|
}
|
|
|
|
public bool UpdateComponent<TComponent>(Entity entity, TComponent component, int priority) where TComponent : struct, IComponent
|
|
{
|
|
return UpToDateComponentStore.Set<TComponent>(entity, component, priority);
|
|
}
|
|
|
|
// general component reads by type
|
|
|
|
internal IEnumerable<(TComponent, Entity)> ReadExistingAndPendingComponentsByType<TComponent>() where TComponent : struct, IComponent
|
|
{
|
|
return existingAndPendingComponentStore.All<TComponent>();
|
|
}
|
|
|
|
internal IEnumerable<(TComponent, Entity)> ReadExistingComponentsByType<TComponent>() where TComponent : struct, IComponent
|
|
{
|
|
return existingComponentStore.All<TComponent>();
|
|
}
|
|
|
|
internal IEnumerable<(TComponent, Entity)> ReadPendingComponentsByType<TComponent>() where TComponent : struct, IComponent
|
|
{
|
|
return pendingComponentStore.All<TComponent>();
|
|
}
|
|
|
|
// singular component reads by type
|
|
|
|
internal (TComponent, Entity) ReadFirstExistingOrPendingComponentByType<TComponent>() where TComponent : struct, IComponent
|
|
{
|
|
if (!SomeExistingOrPendingComponent<TComponent>()) { throw new Exceptions.NoComponentOfTypeException($"No Component with type {typeof(TComponent)} exists"); }
|
|
var enumerator = ReadExistingAndPendingComponentsByType<TComponent>().GetEnumerator();
|
|
enumerator.MoveNext();
|
|
return enumerator.Current;
|
|
}
|
|
|
|
internal (TComponent, Entity) ReadFirstExistingComponentByType<TComponent>() where TComponent : struct, IComponent
|
|
{
|
|
if (!SomeExistingComponent<TComponent>()) { throw new Exceptions.NoComponentOfTypeException($"No Component with type {typeof(TComponent)} exists"); }
|
|
var enumerator = ReadExistingComponentsByType<TComponent>().GetEnumerator();
|
|
enumerator.MoveNext();
|
|
return enumerator.Current;
|
|
}
|
|
|
|
internal (TComponent, Entity) ReadFirstPendingComponentByType<TComponent>() where TComponent : struct, IComponent
|
|
{
|
|
if (!SomePendingComponent<TComponent>()) { throw new Exceptions.NoComponentOfTypeException($"No Component with type {typeof(TComponent)} exists"); }
|
|
var enumerator = ReadPendingComponentsByType<TComponent>().GetEnumerator();
|
|
enumerator.MoveNext();
|
|
return enumerator.Current;
|
|
}
|
|
|
|
// check if some component of type exists in the world
|
|
|
|
internal bool SomeExistingOrPendingComponent<TComponent>() where TComponent : struct, IComponent
|
|
{
|
|
return existingAndPendingComponentStore.Any<TComponent>();
|
|
}
|
|
|
|
internal bool SomeExistingComponent<TComponent>() where TComponent : struct, IComponent
|
|
{
|
|
return existingComponentStore.Any<TComponent>();
|
|
}
|
|
|
|
internal bool SomePendingComponent<TComponent>() where TComponent : struct, IComponent
|
|
{
|
|
return pendingComponentStore.Any<TComponent>();
|
|
}
|
|
|
|
// read components by entity and type
|
|
|
|
internal TComponent ReadExistingComponentByEntityAndType<TComponent>(Entity entity) where TComponent : struct, IComponent
|
|
{
|
|
return existingComponentStore.Get<TComponent>(entity);
|
|
}
|
|
|
|
internal TComponent ReadPendingComponentByEntityAndType<TComponent>(Entity entity) where TComponent : struct, IComponent
|
|
{
|
|
return pendingComponentStore.Get<TComponent>(entity);
|
|
}
|
|
|
|
// check if entity has component of type
|
|
|
|
internal bool HasExistingOrPendingComponent<TComponent>(Entity entity) where TComponent : struct, IComponent
|
|
{
|
|
return existingAndPendingComponentStore.Has<TComponent>(entity);
|
|
}
|
|
|
|
internal bool HasExistingOrPendingComponent(Entity entity, Type type)
|
|
{
|
|
return existingAndPendingComponentStore.Has(type, entity);
|
|
}
|
|
|
|
internal bool HasExistingComponent<TComponent>(Entity entity) where TComponent : struct, IComponent
|
|
{
|
|
return existingComponentStore.Has<TComponent>(entity);
|
|
}
|
|
|
|
internal bool HasExistingComponent(Entity entity, Type type)
|
|
{
|
|
return existingComponentStore.Has(type, entity);
|
|
}
|
|
|
|
internal bool HasPendingComponent<TComponent>(Entity entity) where TComponent : struct, IComponent
|
|
{
|
|
return pendingComponentStore.Has<TComponent>(entity);
|
|
}
|
|
|
|
internal bool HasPendingComponent(Entity entity, Type type)
|
|
{
|
|
return pendingComponentStore.Has(type, entity);
|
|
}
|
|
|
|
internal void Remove<TComponent>(Entity entity) where TComponent : struct, IComponent
|
|
{
|
|
UpToDateComponentStore.Remove<TComponent>(entity);
|
|
}
|
|
|
|
internal IEnumerable<Entity> QueryEntities(IEnumerable<Entity> entities, HashSet<Type> readTypes, HashSet<Type> readPendingTypes, IEnumerable<Type> withTypes, IEnumerable<Type> withoutTypes)
|
|
{
|
|
pendingMask.SetAll(false);
|
|
foreach (var type in readPendingTypes)
|
|
{
|
|
pendingMask.Set(typeToIndex[type], true);
|
|
}
|
|
|
|
readMask.SetAll(false);
|
|
foreach (var type in readTypes)
|
|
{
|
|
readMask.Set(typeToIndex[type], true);
|
|
}
|
|
|
|
withMask.SetAll(false);
|
|
foreach (var type in withTypes)
|
|
{
|
|
withMask.Set(typeToIndex[type], true);
|
|
}
|
|
|
|
withoutMask.SetAll(false);
|
|
foreach (var type in withoutTypes)
|
|
{
|
|
withoutMask.Set(typeToIndex[type], true);
|
|
}
|
|
|
|
notWithMask.SetAll(false);
|
|
notWithMask.Or(withMask).Not();
|
|
|
|
foreach (var entity in entities)
|
|
{
|
|
var pendingEntity = pendingComponentStore.EntityBitArray(entity);
|
|
var existingEntity = existingComponentStore.EntityBitArray(entity);
|
|
|
|
if (VerifyTypes(pendingEntity, existingEntity, readMask, pendingMask, withMask, withoutMask, notWithMask)) { yield return entity; }
|
|
}
|
|
}
|
|
|
|
internal bool VerifyTypes(BitArray pendingEntity, BitArray existingEntity, BitArray readMask, BitArray pendingMask, BitArray withMask, BitArray withoutMask, BitArray notWithMask)
|
|
{
|
|
solverArrayA.SetAll(false);
|
|
solverArrayB.SetAll(false);
|
|
solverArrayC.SetAll(false);
|
|
|
|
solverArrayA.Or(pendingMask).And(withMask).And(pendingEntity);
|
|
solverArrayB.Or(readMask).And(withMask).And(existingEntity);
|
|
solverArrayA.Or(solverArrayB).Or(notWithMask);
|
|
|
|
solverArrayB.SetAll(false);
|
|
solverArrayB.Or(pendingMask).And(withoutMask).And(pendingEntity).Not();
|
|
solverArrayC.Or(readMask).And(withoutMask).And(existingEntity).Not();
|
|
solverArrayB.And(solverArrayC);
|
|
|
|
solverArrayA.And(solverArrayB);
|
|
|
|
return !solverArrayA.Cast<bool>().Contains(false);
|
|
}
|
|
}
|
|
}
|