tracking for non-immediate components

pull/5/head
Evan Hemsley 2019-12-28 13:53:02 -08:00
parent e3343e4a00
commit 41e9dd4451
7 changed files with 151 additions and 29 deletions

View File

@ -11,6 +11,8 @@ namespace Encompass
private readonly ComponentStore componentStore;
private readonly HashSet<int> entitiesMarkedForRemoval = new HashSet<int>();
internal ComponentBitSet ComponentBitSet { get { return componentStore.ComponentBitSet; } }
public ComponentManager(DrawLayerManager drawLayerManager, ComponentUpdateManager componentUpdateManager, Dictionary<Type, int> typeToIndex)
{
this.drawLayerManager = drawLayerManager;

View File

@ -38,9 +38,13 @@ namespace Encompass
private ComponentManager componentManager;
private ComponentUpdateManager componentUpdateManager;
private TimeManager timeManager;
private TrackingManager trackingManager;
private EntitySetQuery entityQuery;
private HashSet<Entity> _trackedEntities = new HashSet<Entity>();
protected IEnumerable<Entity> TrackedEntities { get { return _trackedEntities; } }
protected Engine()
{
ID = Guid.NewGuid();
@ -146,6 +150,11 @@ namespace Encompass
this.timeManager = timeManager;
}
internal void AssignTrackingManager(TrackingManager trackingManager)
{
this.trackingManager = trackingManager;
}
/// <summary>
/// Runs once per World update with the calculated delta-time.
/// </summary>
@ -422,13 +431,18 @@ namespace Encompass
bool written;
if (writeImmediateTypes.Contains(typeof(TComponent)))
{
written = AddImmediateComponent(entity, component, priority);
written = componentUpdateManager.AddImmediateComponent(entity, component, priority);
}
else
{
written = componentUpdateManager.UpdateComponent(entity, component, priority);
}
if (!componentUpdateManager.HasExistingComponent<TComponent>(entity))
{
trackingManager.RegisterAddition(entity, typeof(TComponent));
}
if (written && component is IDrawableComponent drawableComponent)
{
componentManager.RegisterDrawableComponent(entity, component, drawableComponent.Layer);
@ -474,11 +488,6 @@ namespace Encompass
componentUpdateManager.AddExistingComponent(entity, component);
}
internal bool AddImmediateComponent<TComponent>(Entity entity, TComponent component, int priority) where TComponent : struct, IComponent
{
return componentUpdateManager.AddImmediateComponent(entity, component, priority);
}
/// <summary>
/// Reads all messages of the specified Type.
/// </summary>
@ -574,6 +583,11 @@ namespace Encompass
{
componentManager.Remove<TComponent>(entity, priority);
}
if (componentUpdateManager.HasExistingComponent<TComponent>(entity))
{
trackingManager.RegisterRemoval(entity, typeof(TComponent));
}
}
/// <summary>
@ -636,11 +650,19 @@ namespace Encompass
timeManager.ActivateTimeDilation(factor, easeInTime, easeInFunction, activeTime, easeOutTime, easeOutFunction);
}
protected IEnumerable<Entity> QueryEntities()
internal void CheckTrackEntity(Entity entity)
{
foreach (var entity in entityQuery.FilterEntities(entityManager.Entities, componentUpdateManager.ImmediateBits, componentUpdateManager.ExistingBits))
if (entityQuery.CheckEntity(entity, componentManager.ComponentBitSet))
{
yield return entity;
_trackedEntities.Add(entity);
}
}
internal void CheckUntrackEntity(Entity entity)
{
if (!entityQuery.CheckEntity(entity, componentManager.ComponentBitSet))
{
_trackedEntities.Remove(entity);
}
}

View File

@ -21,23 +21,30 @@ namespace Encompass
NotWithMask = notWithMask;
}
public IEnumerable<Entity> FilterEntities(IEnumerable<Entity> entities, ComponentBitSet immediateBitLookup, ComponentBitSet existingBitLookup)
public bool CheckEntity(Entity entity, ComponentBitSet componentBitSet)
{
foreach (var entity in entities)
{
var immediateBits = immediateBitLookup.EntityBitArray(entity.ID);
var existingBits = existingBitLookup.EntityBitArray(entity.ID);
var existingBits = componentBitSet.EntityBitArray(entity.ID);
var existing = WithExistingMask.And(existingBits).Or(NotWithMask);
var immediate = WithImmediateMask.And(immediateBits);
var existing = WithExistingMask.And(existingBits);
var withCheck = immediate.Or(existing).Or(NotWithMask);
var existingForbidden = WithoutExistingMask.And(existingBits).Not();
var immediateForbidden = WithoutImmediateMask.And(immediateBits).Not();
var existingForbidden = WithoutExistingMask.And(existingBits).Not();
var withoutCheck = immediateForbidden.And(existingForbidden);
return existing.And(existingForbidden).AllTrue();
}
if (withCheck.And(withoutCheck).AllTrue()) { yield return entity; }
}
public bool CheckEntityImmediate(Entity entity, ComponentBitSet immediateBitLookup, ComponentBitSet existingBitLookup)
{
var immediateBits = immediateBitLookup.EntityBitArray(entity.ID);
var existingBits = existingBitLookup.EntityBitArray(entity.ID);
var immediate = WithImmediateMask.And(immediateBits);
var existing = WithExistingMask.And(existingBits);
var withCheck = immediate.Or(existing).Or(NotWithMask);
var immediateForbidden = WithoutImmediateMask.And(immediateBits).Not();
var existingForbidden = WithoutExistingMask.And(existingBits).Not();
var withoutCheck = immediateForbidden.And(existingForbidden);
return withCheck.And(withoutCheck).AllTrue();
}
}
}

View File

@ -0,0 +1,72 @@
using System;
using System.Collections.Generic;
namespace Encompass
{
internal class TrackingManager
{
private Dictionary<Type, HashSet<Engine>> _pendingComponentTypesToEngines = new Dictionary<Type, HashSet<Engine>>();
private Dictionary<Type, HashSet<Engine>> _componentTypesToEngines = new Dictionary<Type, HashSet<Engine>>();
private HashSet<(Entity, Type)> _additions = new HashSet<(Entity, Type)>();
private HashSet<(Entity, Type)> _removals = new HashSet<(Entity, Type)>();
public void RegisterComponentTypeToEngine(Type type, Engine engine)
{
if (!_componentTypesToEngines.ContainsKey(type)) { _componentTypesToEngines.Add(type, new HashSet<Engine>()); }
_componentTypesToEngines[type].Add(engine);
}
public void RegisterAddition(Entity entity, Type type)
{
_additions.Add((entity, type));
}
public void RegisterRemoval(Entity entity, Type type)
{
_removals.Add((entity, type));
}
public void InitializeTracking(IEnumerable<Entity> entities)
{
foreach (var entity in entities)
{
foreach (var engineSet in _componentTypesToEngines.Values)
{
foreach (var engine in engineSet)
{
engine.CheckTrackEntity(entity);
}
}
}
}
public void UpdateTracking()
{
// TODO: optimize so we only check each entity/engine pair once
foreach (var (entity, componentType) in _additions)
{
if (_componentTypesToEngines.ContainsKey(componentType))
{
foreach (var engine in _componentTypesToEngines[componentType])
{
engine.CheckTrackEntity(entity);
}
}
}
_additions.Clear();
foreach (var (entity, componentType) in _removals)
{
if (_componentTypesToEngines.ContainsKey(componentType))
{
foreach (var engine in _componentTypesToEngines[componentType])
{
engine.CheckUntrackEntity(entity);
}
}
}
_removals.Clear();
}
}
}

View File

@ -10,6 +10,7 @@ namespace Encompass
private readonly List<Engine> enginesInOrder;
private readonly EntityManager entityManager;
private readonly ComponentManager componentManager;
private readonly TrackingManager trackingManager;
private readonly MessageManager messageManager;
private readonly ComponentUpdateManager componentUpdateManager;
private readonly TimeManager timeManager;
@ -19,6 +20,7 @@ namespace Encompass
List<Engine> enginesInOrder,
EntityManager entityManager,
ComponentManager componentManager,
TrackingManager trackingManager,
MessageManager messageManager,
ComponentUpdateManager componentUpdateManager,
TimeManager timeManager,
@ -28,6 +30,7 @@ namespace Encompass
this.enginesInOrder = enginesInOrder;
this.entityManager = entityManager;
this.componentManager = componentManager;
this.trackingManager = trackingManager;
this.messageManager = messageManager;
this.componentUpdateManager = componentUpdateManager;
this.timeManager = timeManager;
@ -40,6 +43,7 @@ namespace Encompass
/// <param name="dt">The time in seconds that has passed since the previous frame.</param>
public void Update(double dt)
{
trackingManager.UpdateTracking();
messageManager.ProcessDelayedMessages(dt);
timeManager.Update(dt);

View File

@ -31,6 +31,7 @@ namespace Encompass
private readonly TimeManager timeManager;
private readonly DrawLayerManager drawLayerManager;
private readonly RenderManager renderManager;
private readonly TrackingManager trackingManager;
private readonly Dictionary<Type, HashSet<Engine>> typeToReaders = new Dictionary<Type, HashSet<Engine>>();
@ -52,6 +53,7 @@ namespace Encompass
messageManager = new MessageManager(timeManager);
entityManager = new EntityManager(componentManager, entityCapacity);
renderManager = new RenderManager(entityManager, drawLayerManager);
trackingManager = new TrackingManager();
startingComponentStoreForComponentManager = new ComponentStore(typeToIndex);
startingComponentStoreForComponentUpdateManager = new ComponentStore(typeToIndex);
@ -132,6 +134,7 @@ namespace Encompass
engine.AssignMessageManager(messageManager);
engine.AssignComponentUpdateManager(componentUpdateManager);
engine.AssignTimeManager(timeManager);
engine.AssignTrackingManager(trackingManager);
engines.Add(engine);
engineGraph.AddNode(engine);
@ -156,6 +159,11 @@ namespace Encompass
senders.Add(engine);
}
foreach (var componentType in engine.queryWithTypes.Union(engine.queryWithoutTypes))
{
trackingManager.RegisterComponentTypeToEngine(componentType, engine);
}
foreach (var componentType in engine.readTypes.Union(engine.writeTypes).Union(engine.readImmediateTypes))
{
AddComponentTypeToRegister(componentType);
@ -381,6 +389,7 @@ namespace Encompass
engineOrder,
entityManager,
componentManager,
trackingManager,
messageManager,
componentUpdateManager,
timeManager,
@ -390,6 +399,8 @@ namespace Encompass
componentUpdateManager.SetStartingComponentStore(startingComponentStoreForComponentUpdateManager);
componentManager.SetComponentStore(startingComponentStoreForComponentManager);
trackingManager.InitializeTracking(entityManager.Entities);
return world;
}
@ -406,6 +417,7 @@ namespace Encompass
var dummyDrawLayerManager = new DrawLayerManager(typeToIndex);
var dummyComponentUpdateManager = new ComponentUpdateManager(typeToIndex);
var dummyComponentManager = new ComponentManager(dummyDrawLayerManager, dummyComponentUpdateManager, typeToIndex);
var dummyTrackingManager = new TrackingManager();
var dummyEntityManager = new EntityManager(dummyComponentManager, entityCapacity);
var dummyRenderManager = new RenderManager(dummyEntityManager, dummyDrawLayerManager);
@ -418,6 +430,7 @@ namespace Encompass
uberEngine.AssignMessageManager(dummyMessageManager);
uberEngine.AssignComponentUpdateManager(dummyComponentUpdateManager);
uberEngine.AssignTimeManager(dummyTimeManager);
uberEngine.AssignTrackingManager(dummyTrackingManager);
var uberRenderer = new UberRenderer(componentTypes);
uberRenderer.AssignComponentManager(dummyComponentManager);
@ -446,6 +459,7 @@ namespace Encompass
emitterEngine.AssignMessageManager(dummyMessageManager);
emitterEngine.AssignComponentUpdateManager(dummyComponentUpdateManager);
emitterEngine.AssignTimeManager(dummyTimeManager);
emitterEngine.AssignTrackingManager(dummyTrackingManager);
prepEngineOrder.Add(emitterEngine);
}
@ -456,6 +470,7 @@ namespace Encompass
prepEngineOrder,
dummyEntityManager,
dummyComponentManager,
dummyTrackingManager,
dummyMessageManager,
dummyComponentUpdateManager,
dummyTimeManager,

View File

@ -1116,7 +1116,7 @@ namespace Tests
public override void Update(double dt)
{
entities.Clear();
foreach (var entity in QueryEntities())
foreach (var entity in TrackedEntities)
{
entities.Add(entity);
}
@ -1164,7 +1164,7 @@ namespace Tests
public override void Update(double dt)
{
entities.Clear();
entities.AddRange(QueryEntities());
entities.AddRange(TrackedEntities);
}
}
@ -1211,7 +1211,7 @@ namespace Tests
{
entities.Clear();
entities.AddRange(QueryEntities());
entities.AddRange(TrackedEntities);
}
}
@ -1278,7 +1278,7 @@ namespace Tests
public override void Update(double dt)
{
entities.Clear();
entities.AddRange(QueryEntities());
entities.AddRange(TrackedEntities);
}
}
@ -1317,7 +1317,7 @@ namespace Tests
public override void Update(double dt)
{
entities.Clear();
entities.AddRange(QueryEntities());
entities.AddRange(TrackedEntities);
}
}
@ -1379,7 +1379,7 @@ namespace Tests
{
entities.Clear();
entities.AddRange(QueryEntities());
entities.AddRange(TrackedEntities);
}
}
@ -1435,7 +1435,7 @@ namespace Tests
public override void Update(double dt)
{
entities.Clear();
entities.AddRange(QueryEntities());
entities.AddRange(TrackedEntities);
}
}