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 pendingComponentStore;
|
||||
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 ComponentUpdateManager(Dictionary<Type, int> typeToIndex)
|
||||
|
@ -21,7 +22,7 @@ namespace Encompass
|
|||
existingComponentStore = new ComponentStore(typeToIndex);
|
||||
pendingComponentStore = new ComponentStore(typeToIndex);
|
||||
UpToDateComponentStore = new ComponentStore(typeToIndex);
|
||||
this.typeToIndex = typeToIndex;
|
||||
TypeToIndex = typeToIndex;
|
||||
}
|
||||
|
||||
public void RegisterComponentType<TComponent>() where TComponent : struct, IComponent
|
||||
|
@ -196,54 +197,14 @@ namespace Encompass
|
|||
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();
|
||||
foreach (var type in readPendingTypes)
|
||||
{
|
||||
pendingMask = pendingMask.Set(typeToIndex[type]);
|
||||
return pendingComponentStore.EntityBitArray(entity);
|
||||
}
|
||||
|
||||
var readMask = BitSet1024Builder.Zeroes();
|
||||
foreach (var type in readTypes)
|
||||
internal BitSet1024 ExistingBits(Entity entity)
|
||||
{
|
||||
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)
|
||||
{
|
||||
var pending = pendingMask.And(withMask).And(pendingEntity);
|
||||
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();
|
||||
return existingComponentStore.EntityBitArray(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -615,9 +615,14 @@ namespace Encompass
|
|||
/// <summary>
|
||||
/// Returns an empty EntitySetQuery. Can be modified and iterated over to obtain Entities that fit the given criteria.
|
||||
/// </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.Immutable;
|
||||
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 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 ComponentUpdateManager ComponentUpdateManager { get; }
|
||||
private HashSet<Type> ReadTypes { get; }
|
||||
private HashSet<Type> ReadPendingTypes { get; }
|
||||
private ImmutableArray<Type> Includes { get; }
|
||||
private ImmutableArray<Type> Excludes { get; }
|
||||
private BitSet1024 WithPendingMask { get; }
|
||||
private BitSet1024 WithExistingMask { get; }
|
||||
private BitSet1024 WithoutPendingMask { get; }
|
||||
private BitSet1024 WithoutExistingMask { get; }
|
||||
private BitSet1024 NotWithMask { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Designates that the given component type is required.
|
||||
/// </summary>
|
||||
public EntitySetQuery With<TComponent>() where TComponent : struct, IComponent
|
||||
internal EntitySetQuery(EntityManager entityManager, ComponentUpdateManager componentUpdateManager, BitSet1024 withPendingMask, BitSet1024 withExistingMask, BitSet1024 withoutPendingMask, BitSet1024 withoutExistingMask, BitSet1024 notWithMask)
|
||||
{
|
||||
return new EntitySetQuery(EntityManager, ComponentUpdateManager, ReadTypes, ReadPendingTypes, Includes.Add(typeof(TComponent)), Excludes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Designates that the given component type is forbidden.
|
||||
/// </summary>
|
||||
public EntitySetQuery Without<TComponent>() where TComponent : struct, IComponent
|
||||
{
|
||||
return new EntitySetQuery(EntityManager, ComponentUpdateManager, ReadTypes, ReadPendingTypes, Includes, Excludes.Add(typeof(TComponent)));
|
||||
EntityManager = entityManager;
|
||||
ComponentUpdateManager = componentUpdateManager;
|
||||
WithPendingMask = withPendingMask;
|
||||
WithExistingMask = withExistingMask;
|
||||
WithoutPendingMask = withoutPendingMask;
|
||||
WithoutExistingMask = withoutExistingMask;
|
||||
NotWithMask = notWithMask;
|
||||
}
|
||||
|
||||
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()
|
||||
|
|
|
@ -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