diff --git a/encompass-cs/ComponentUpdateManager.cs b/encompass-cs/ComponentUpdateManager.cs index 95dae3c..8b371ee 100644 --- a/encompass-cs/ComponentUpdateManager.cs +++ b/encompass-cs/ComponentUpdateManager.cs @@ -12,7 +12,8 @@ namespace Encompass private readonly ComponentStore existingComponentStore; private readonly ComponentStore pendingComponentStore; private readonly Dictionary> typeToEntityToPendingComponentPriority = new Dictionary>(128); - private Dictionary typeToIndex; + public Dictionary TypeToIndex { get; } + public ComponentStore UpToDateComponentStore { get; private set; } public ComponentUpdateManager(Dictionary 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() where TComponent : struct, IComponent @@ -196,54 +197,14 @@ namespace Encompass UpToDateComponentStore.Remove(entity); } - internal IEnumerable QueryEntities(IEnumerable entities, HashSet readTypes, HashSet readPendingTypes, IEnumerable withTypes, IEnumerable withoutTypes) + internal BitSet1024 PendingBits(Entity entity) { - var pendingMask = BitSet1024Builder.Zeroes(); - 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; } - } + return pendingComponentStore.EntityBitArray(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); - 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); } } } diff --git a/encompass-cs/Engine.cs b/encompass-cs/Engine.cs index 457c6f2..dfb3f35 100644 --- a/encompass-cs/Engine.cs +++ b/encompass-cs/Engine.cs @@ -615,9 +615,14 @@ namespace Encompass /// /// Returns an empty EntitySetQuery. Can be modified and iterated over to obtain Entities that fit the given criteria. /// - protected EntitySetQuery QueryEntities() + protected EntitySetQueryBuilder EntityQueryBuilder() { - return new EntitySetQuery(entityManager, componentUpdateManager, readTypes, readPendingTypes); + return new EntitySetQueryBuilder( + entityManager, + componentUpdateManager, + readPendingTypes, + readTypes + ); } } } diff --git a/encompass-cs/EntitySetQuery.cs b/encompass-cs/EntitySetQuery.cs index 3fd2e59..60bd110 100644 --- a/encompass-cs/EntitySetQuery.cs +++ b/encompass-cs/EntitySetQuery.cs @@ -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 { - /// - /// EntitySetQuery is used to efficiently obtain a set of Entities that have all required Components and do not have any forbidden Components. - /// public struct EntitySetQuery : IEnumerable { - private EntitySetQuery(EntityManager entityManager, ComponentUpdateManager componentUpdateManager, HashSet readTypes, HashSet readPendingTypes, ImmutableArray includes, ImmutableArray excludes) - { - EntityManager = entityManager; - ComponentUpdateManager = componentUpdateManager; - ReadTypes = readTypes; - ReadPendingTypes = readPendingTypes; - Includes = includes; - Excludes = excludes; - } - - internal EntitySetQuery(EntityManager entityManager, ComponentUpdateManager componentUpdateManager, HashSet readTypes, HashSet readPendingTypes) - { - EntityManager = entityManager; - ComponentUpdateManager = componentUpdateManager; - ReadTypes = readTypes; - ReadPendingTypes = readPendingTypes; - Includes = ImmutableArray.Create(); - Excludes = ImmutableArray.Create(); - } - private EntityManager EntityManager { get; } private ComponentUpdateManager ComponentUpdateManager { get; } - private HashSet ReadTypes { get; } - private HashSet ReadPendingTypes { get; } - private ImmutableArray Includes { get; } - private ImmutableArray Excludes { get; } + private BitSet1024 WithPendingMask { get; } + private BitSet1024 WithExistingMask { get; } + private BitSet1024 WithoutPendingMask { get; } + private BitSet1024 WithoutExistingMask { get; } + private BitSet1024 NotWithMask { get; } - /// - /// Designates that the given component type is required. - /// - public EntitySetQuery With() 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); - } - - /// - /// Designates that the given component type is forbidden. - /// - public EntitySetQuery Without() 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 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() diff --git a/encompass-cs/EntitySetQueryBuilder.cs b/encompass-cs/EntitySetQueryBuilder.cs new file mode 100644 index 0000000..00452c5 --- /dev/null +++ b/encompass-cs/EntitySetQueryBuilder.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; +using Encompass.Collections; + +namespace Encompass +{ + /// + /// EntitySetQuery is used to efficiently obtain a set of Entities that have all required Components and do not have any forbidden Components. + /// + public class EntitySetQueryBuilder + { + internal EntitySetQueryBuilder(EntityManager entityManager, ComponentUpdateManager componentUpdateManager, IEnumerable pendingTypes, IEnumerable 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; } + + /// + /// Designates that the given component type is required. + /// + public EntitySetQueryBuilder With() where TComponent : struct, IComponent + { + WithMask = WithMask.Set(ComponentUpdateManager.TypeToIndex[typeof(TComponent)]); + return this; + } + + /// + /// Designates that the given component type is forbidden. + /// + public EntitySetQueryBuilder Without() 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() + ); + } + } +}