restructuring entity set query system for caching benefits
parent
9a1a210039
commit
4e3aaa7d47
|
@ -12,7 +12,8 @@ namespace Encompass
|
||||||
private readonly ComponentStore existingComponentStore;
|
private readonly ComponentStore existingComponentStore;
|
||||||
private readonly ComponentStore pendingComponentStore;
|
private readonly ComponentStore pendingComponentStore;
|
||||||
private readonly Dictionary<Type, Dictionary<Entity, int>> typeToEntityToPendingComponentPriority = new Dictionary<Type, Dictionary<Entity, int>>(128);
|
private readonly Dictionary<Type, Dictionary<Entity, int>> typeToEntityToPendingComponentPriority = new Dictionary<Type, Dictionary<Entity, int>>(128);
|
||||||
private Dictionary<Type, int> typeToIndex;
|
public Dictionary<Type, int> TypeToIndex { get; }
|
||||||
|
|
||||||
public ComponentStore UpToDateComponentStore { get; private set; }
|
public ComponentStore UpToDateComponentStore { get; private set; }
|
||||||
|
|
||||||
public ComponentUpdateManager(Dictionary<Type, int> typeToIndex)
|
public ComponentUpdateManager(Dictionary<Type, int> typeToIndex)
|
||||||
|
@ -21,7 +22,7 @@ namespace Encompass
|
||||||
existingComponentStore = new ComponentStore(typeToIndex);
|
existingComponentStore = new ComponentStore(typeToIndex);
|
||||||
pendingComponentStore = new ComponentStore(typeToIndex);
|
pendingComponentStore = new ComponentStore(typeToIndex);
|
||||||
UpToDateComponentStore = new ComponentStore(typeToIndex);
|
UpToDateComponentStore = new ComponentStore(typeToIndex);
|
||||||
this.typeToIndex = typeToIndex;
|
TypeToIndex = typeToIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RegisterComponentType<TComponent>() where TComponent : struct, IComponent
|
public void RegisterComponentType<TComponent>() where TComponent : struct, IComponent
|
||||||
|
@ -196,54 +197,14 @@ namespace Encompass
|
||||||
UpToDateComponentStore.Remove<TComponent>(entity);
|
UpToDateComponentStore.Remove<TComponent>(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal IEnumerable<Entity> QueryEntities(IEnumerable<Entity> entities, HashSet<Type> readTypes, HashSet<Type> readPendingTypes, IEnumerable<Type> withTypes, IEnumerable<Type> withoutTypes)
|
internal BitSet1024 PendingBits(Entity entity)
|
||||||
{
|
{
|
||||||
var pendingMask = BitSet1024Builder.Zeroes();
|
return pendingComponentStore.EntityBitArray(entity);
|
||||||
foreach (var type in readPendingTypes)
|
|
||||||
{
|
|
||||||
pendingMask = pendingMask.Set(typeToIndex[type]);
|
|
||||||
}
|
|
||||||
|
|
||||||
var readMask = BitSet1024Builder.Zeroes();
|
|
||||||
foreach (var type in readTypes)
|
|
||||||
{
|
|
||||||
readMask = readMask.Set(typeToIndex[type]);
|
|
||||||
}
|
|
||||||
|
|
||||||
var withMask = BitSet1024Builder.Zeroes();
|
|
||||||
foreach (var type in withTypes)
|
|
||||||
{
|
|
||||||
withMask = withMask.Set(typeToIndex[type]);
|
|
||||||
}
|
|
||||||
|
|
||||||
var withoutMask = BitSet1024Builder.Zeroes();
|
|
||||||
foreach (var type in withoutTypes)
|
|
||||||
{
|
|
||||||
withoutMask = withoutMask.Set(typeToIndex[type]);
|
|
||||||
}
|
|
||||||
|
|
||||||
var notWithMask = 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(BitSet1024 pendingEntity, BitSet1024 existingEntity, BitSet1024 readMask, BitSet1024 pendingMask, BitSet1024 withMask, BitSet1024 withoutMask, BitSet1024 notWithMask)
|
internal BitSet1024 ExistingBits(Entity entity)
|
||||||
{
|
{
|
||||||
var pending = pendingMask.And(withMask).And(pendingEntity);
|
return existingComponentStore.EntityBitArray(entity);
|
||||||
var existing = readMask.And(withMask).And(existingEntity);
|
|
||||||
var withCheck = pending.Or(existing).Or(notWithMask);
|
|
||||||
|
|
||||||
var pendingForbidden = pendingMask.And(withoutMask).And(pendingEntity).Not();
|
|
||||||
var existingForbidden = readMask.And(withoutMask).And(existingEntity).Not();
|
|
||||||
var withoutCheck = pendingForbidden.And(existingForbidden);
|
|
||||||
|
|
||||||
return withCheck.And(withoutCheck).AllTrue();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -615,9 +615,14 @@ namespace Encompass
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns an empty EntitySetQuery. Can be modified and iterated over to obtain Entities that fit the given criteria.
|
/// Returns an empty EntitySetQuery. Can be modified and iterated over to obtain Entities that fit the given criteria.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected EntitySetQuery QueryEntities()
|
protected EntitySetQueryBuilder EntityQueryBuilder()
|
||||||
{
|
{
|
||||||
return new EntitySetQuery(entityManager, componentUpdateManager, readTypes, readPendingTypes);
|
return new EntitySetQueryBuilder(
|
||||||
|
entityManager,
|
||||||
|
componentUpdateManager,
|
||||||
|
readPendingTypes,
|
||||||
|
readTypes
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,61 +1,47 @@
|
||||||
using System;
|
using System.Collections;
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Immutable;
|
using Encompass.Collections;
|
||||||
|
|
||||||
namespace Encompass
|
namespace Encompass
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// EntitySetQuery is used to efficiently obtain a set of Entities that have all required Components and do not have any forbidden Components.
|
|
||||||
/// </summary>
|
|
||||||
public struct EntitySetQuery : IEnumerable<Entity>
|
public struct EntitySetQuery : IEnumerable<Entity>
|
||||||
{
|
{
|
||||||
private EntitySetQuery(EntityManager entityManager, ComponentUpdateManager componentUpdateManager, HashSet<Type> readTypes, HashSet<Type> readPendingTypes, ImmutableArray<Type> includes, ImmutableArray<Type> excludes)
|
|
||||||
{
|
|
||||||
EntityManager = entityManager;
|
|
||||||
ComponentUpdateManager = componentUpdateManager;
|
|
||||||
ReadTypes = readTypes;
|
|
||||||
ReadPendingTypes = readPendingTypes;
|
|
||||||
Includes = includes;
|
|
||||||
Excludes = excludes;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal EntitySetQuery(EntityManager entityManager, ComponentUpdateManager componentUpdateManager, HashSet<Type> readTypes, HashSet<Type> readPendingTypes)
|
|
||||||
{
|
|
||||||
EntityManager = entityManager;
|
|
||||||
ComponentUpdateManager = componentUpdateManager;
|
|
||||||
ReadTypes = readTypes;
|
|
||||||
ReadPendingTypes = readPendingTypes;
|
|
||||||
Includes = ImmutableArray.Create<Type>();
|
|
||||||
Excludes = ImmutableArray.Create<Type>();
|
|
||||||
}
|
|
||||||
|
|
||||||
private EntityManager EntityManager { get; }
|
private EntityManager EntityManager { get; }
|
||||||
private ComponentUpdateManager ComponentUpdateManager { get; }
|
private ComponentUpdateManager ComponentUpdateManager { get; }
|
||||||
private HashSet<Type> ReadTypes { get; }
|
private BitSet1024 WithPendingMask { get; }
|
||||||
private HashSet<Type> ReadPendingTypes { get; }
|
private BitSet1024 WithExistingMask { get; }
|
||||||
private ImmutableArray<Type> Includes { get; }
|
private BitSet1024 WithoutPendingMask { get; }
|
||||||
private ImmutableArray<Type> Excludes { get; }
|
private BitSet1024 WithoutExistingMask { get; }
|
||||||
|
private BitSet1024 NotWithMask { get; }
|
||||||
|
|
||||||
/// <summary>
|
internal EntitySetQuery(EntityManager entityManager, ComponentUpdateManager componentUpdateManager, BitSet1024 withPendingMask, BitSet1024 withExistingMask, BitSet1024 withoutPendingMask, BitSet1024 withoutExistingMask, BitSet1024 notWithMask)
|
||||||
/// Designates that the given component type is required.
|
|
||||||
/// </summary>
|
|
||||||
public EntitySetQuery With<TComponent>() where TComponent : struct, IComponent
|
|
||||||
{
|
{
|
||||||
return new EntitySetQuery(EntityManager, ComponentUpdateManager, ReadTypes, ReadPendingTypes, Includes.Add(typeof(TComponent)), Excludes);
|
EntityManager = entityManager;
|
||||||
}
|
ComponentUpdateManager = componentUpdateManager;
|
||||||
|
WithPendingMask = withPendingMask;
|
||||||
/// <summary>
|
WithExistingMask = withExistingMask;
|
||||||
/// Designates that the given component type is forbidden.
|
WithoutPendingMask = withoutPendingMask;
|
||||||
/// </summary>
|
WithoutExistingMask = withoutExistingMask;
|
||||||
public EntitySetQuery Without<TComponent>() where TComponent : struct, IComponent
|
NotWithMask = notWithMask;
|
||||||
{
|
|
||||||
return new EntitySetQuery(EntityManager, ComponentUpdateManager, ReadTypes, ReadPendingTypes, Includes, Excludes.Add(typeof(TComponent)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerator<Entity> GetEnumerator()
|
public IEnumerator<Entity> GetEnumerator()
|
||||||
{
|
{
|
||||||
return ComponentUpdateManager.QueryEntities(EntityManager.Entities, ReadTypes, ReadPendingTypes, Includes, Excludes).GetEnumerator();
|
foreach (var entity in EntityManager.Entities)
|
||||||
|
{
|
||||||
|
var pendingBits = ComponentUpdateManager.PendingBits(entity);
|
||||||
|
var existingBits = ComponentUpdateManager.ExistingBits(entity);
|
||||||
|
|
||||||
|
var pending = WithPendingMask.And(pendingBits);
|
||||||
|
var existing = WithExistingMask.And(existingBits);
|
||||||
|
var withCheck = pending.Or(existing).Or(NotWithMask);
|
||||||
|
|
||||||
|
var pendingForbidden = WithoutPendingMask.And(pendingBits);
|
||||||
|
var existingForbidden = WithoutExistingMask.And(existingBits);
|
||||||
|
var withoutCheck = pendingForbidden.And(existingForbidden);
|
||||||
|
|
||||||
|
if (withCheck.And(withoutCheck).AllTrue()) { yield return entity; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator()
|
IEnumerator IEnumerable.GetEnumerator()
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Encompass.Collections;
|
||||||
|
|
||||||
|
namespace Encompass
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// EntitySetQuery is used to efficiently obtain a set of Entities that have all required Components and do not have any forbidden Components.
|
||||||
|
/// </summary>
|
||||||
|
public class EntitySetQueryBuilder
|
||||||
|
{
|
||||||
|
internal EntitySetQueryBuilder(EntityManager entityManager, ComponentUpdateManager componentUpdateManager, IEnumerable<Type> pendingTypes, IEnumerable<Type> existingTypes)
|
||||||
|
{
|
||||||
|
EntityManager = entityManager;
|
||||||
|
ComponentUpdateManager = componentUpdateManager;
|
||||||
|
WithMask = BitSet1024Builder.Zeroes();
|
||||||
|
WithoutMask = BitSet1024Builder.Zeroes();
|
||||||
|
|
||||||
|
PendingMask = BitSet1024Builder.Zeroes();
|
||||||
|
foreach (var type in pendingTypes)
|
||||||
|
{
|
||||||
|
PendingMask = PendingMask.Set(componentUpdateManager.TypeToIndex[type]);
|
||||||
|
}
|
||||||
|
|
||||||
|
ExistingMask = BitSet1024Builder.Zeroes();
|
||||||
|
foreach (var type in existingTypes)
|
||||||
|
{
|
||||||
|
ExistingMask = ExistingMask.Set(componentUpdateManager.TypeToIndex[type]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private EntityManager EntityManager { get; }
|
||||||
|
private ComponentUpdateManager ComponentUpdateManager { get; }
|
||||||
|
private BitSet1024 WithMask { get; set; }
|
||||||
|
private BitSet1024 WithoutMask { get; set; }
|
||||||
|
private BitSet1024 PendingMask { get; set; }
|
||||||
|
private BitSet1024 ExistingMask { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Designates that the given component type is required.
|
||||||
|
/// </summary>
|
||||||
|
public EntitySetQueryBuilder With<TComponent>() where TComponent : struct, IComponent
|
||||||
|
{
|
||||||
|
WithMask = WithMask.Set(ComponentUpdateManager.TypeToIndex[typeof(TComponent)]);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Designates that the given component type is forbidden.
|
||||||
|
/// </summary>
|
||||||
|
public EntitySetQueryBuilder Without<TComponent>() where TComponent : struct, IComponent
|
||||||
|
{
|
||||||
|
WithoutMask = WithoutMask.Set(ComponentUpdateManager.TypeToIndex[typeof(TComponent)]);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EntitySetQuery Build()
|
||||||
|
{
|
||||||
|
return new EntitySetQuery(
|
||||||
|
EntityManager,
|
||||||
|
ComponentUpdateManager,
|
||||||
|
WithMask.And(PendingMask),
|
||||||
|
WithMask.And(ExistingMask),
|
||||||
|
WithoutMask.And(PendingMask),
|
||||||
|
WithoutMask.And(ExistingMask),
|
||||||
|
WithMask.Not()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue