using System; using System.Collections.Generic; namespace MoonTools.ECS { internal class FilterStorage { private EntityStorage EntityStorage; private RelationDepot RelationDepot; private TypeIndices ComponentTypeIndices; private TypeIndices RelationTypeIndices; private Dictionary> filterSignatureToEntityIDs = new Dictionary>(); private Dictionary> componentTypeToFilterSignatures = new Dictionary>(); private Dictionary> relationTypeToFilterSignatures = new Dictionary>(); public FilterStorage( EntityStorage entityStorage, RelationDepot relationDepot, TypeIndices componentTypeIndices, TypeIndices relationTypeIndices ) { EntityStorage = entityStorage; RelationDepot = relationDepot; ComponentTypeIndices = componentTypeIndices; RelationTypeIndices = relationTypeIndices; } public Filter CreateFilter( HashSet included, HashSet excluded, HashSet inRelations, HashSet outRelations ) { var filterSignature = new FilterSignature(included, excluded, inRelations, outRelations); if (!filterSignatureToEntityIDs.ContainsKey(filterSignature)) { filterSignatureToEntityIDs.Add(filterSignature, new IndexableSet()); foreach (var type in included) { if (!componentTypeToFilterSignatures.ContainsKey(type)) { componentTypeToFilterSignatures.Add(type, new HashSet()); } componentTypeToFilterSignatures[type].Add(filterSignature); } foreach (var type in excluded) { if (!componentTypeToFilterSignatures.ContainsKey(type)) { componentTypeToFilterSignatures.Add(type, new HashSet()); } componentTypeToFilterSignatures[type].Add(filterSignature); } foreach (var type in inRelations) { if (!relationTypeToFilterSignatures.ContainsKey(type)) { relationTypeToFilterSignatures.Add(type, new HashSet()); } relationTypeToFilterSignatures[type].Add(filterSignature); } foreach (var type in outRelations) { if (!relationTypeToFilterSignatures.ContainsKey(type)) { relationTypeToFilterSignatures.Add(type, new HashSet()); } relationTypeToFilterSignatures[type].Add(filterSignature); } } return new Filter(this, included, excluded, inRelations, outRelations); } public ReverseSpanEnumerator FilterEntities(FilterSignature filterSignature) { return filterSignatureToEntityIDs[filterSignature].GetEnumerator(); } public LinearCongruentialEnumerator FilterEntitiesRandom(FilterSignature filterSignature) { return RandomGenerator.LinearCongruentialGenerator(FilterCount(filterSignature)); } public Entity FilterNthEntity(FilterSignature filterSignature, int index) { return new Entity(filterSignatureToEntityIDs[filterSignature][index]); } public Entity FilterRandomEntity(FilterSignature filterSignature) { var randomIndex = RandomGenerator.Next(FilterCount(filterSignature)); return new Entity(filterSignatureToEntityIDs[filterSignature][randomIndex]); } public int FilterCount(FilterSignature filterSignature) { return filterSignatureToEntityIDs[filterSignature].Count; } public void CheckComponentChange(int entityID, int componentTypeIndex) { if (componentTypeToFilterSignatures.TryGetValue(componentTypeIndex, out var filterSignatures)) { foreach (var filterSignature in filterSignatures) { CheckFilter(entityID, filterSignature); } } } public void CheckRelationChange(int entityID, int relationTypeIndex) { if (relationTypeToFilterSignatures.TryGetValue(relationTypeIndex, out var filterSignatures)) { foreach (var filterSignature in filterSignatures) { CheckFilter(entityID, filterSignature); } } } public void Check(int entityID) where TComponent : unmanaged { CheckComponentChange(entityID, ComponentTypeIndices.GetIndex()); } public bool CheckSatisfied(int entityID, FilterSignature filterSignature) { foreach (var type in filterSignature.Included) { if (!EntityStorage.HasComponent(entityID, type)) { return false; } } foreach (var type in filterSignature.Excluded) { if (EntityStorage.HasComponent(entityID, type)) { return false; } } foreach (var type in filterSignature.InRelations) { if (!RelationDepot.HasInRelation(entityID, type)) { return false; } } foreach (var type in filterSignature.OutRelations) { if (!RelationDepot.HasOutRelation(entityID, type)) { return false; } } return true; } private void CheckFilter(int entityID, FilterSignature filterSignature) { if (CheckSatisfied(entityID, filterSignature)) { filterSignatureToEntityIDs[filterSignature].Remove(entityID); } else { filterSignatureToEntityIDs[filterSignature].Remove(entityID); } } public void RemoveEntity(int entityID, int componentTypeIndex) { if (componentTypeToFilterSignatures.TryGetValue(componentTypeIndex, out var filterSignatures)) { foreach (var filterSignature in filterSignatures) { filterSignatureToEntityIDs[filterSignature].Remove(entityID); } } } } }