namespace MoonTools.ECS; internal class ComponentDepot { private Dictionary storages = new Dictionary(); private Dictionary> filterSignatureToEntityIDs = new Dictionary>(); private Dictionary> typeToFilterSignatures = new Dictionary>(); private Dictionary> entityComponentMap = new Dictionary>(); internal void Register() where TComponent : struct { if (!storages.ContainsKey(typeof(TComponent))) { storages.Add(typeof(TComponent), new ComponentStorage()); } } private ComponentStorage Lookup(Type type) { return storages[type]; } private ComponentStorage Lookup() where TComponent : struct { // TODO: is it possible to optimize this? Register(); return storages[typeof(TComponent)] as ComponentStorage; } public bool Some() where TComponent : struct { return Lookup().Any(); } public bool Has(int entityID) where TComponent : struct { return Lookup().Has(entityID); } private bool Has(Type type, int entityID) { return Lookup(type).Has(entityID); } public ref readonly TComponent Get(int entityID) where TComponent : struct { return ref Lookup().Get(entityID); } public void Set(int entityID, in TComponent component) where TComponent : struct { Lookup().Set(entityID, component); if (!entityComponentMap.ContainsKey(entityID)) { entityComponentMap.Add(entityID, new HashSet()); } var notFound = entityComponentMap[entityID].Add(typeof(TComponent)); // update filters if (notFound) { if (typeToFilterSignatures.TryGetValue(typeof(TComponent), out var filterSignatures)) { foreach (var filterSignature in filterSignatures) { CheckFilter(filterSignature, entityID); } } } } public ReadOnlySpan ReadEntities() where TComponent : struct { return Lookup().AllEntities(); } public ReadOnlySpan ReadComponents() where TComponent : struct { return Lookup().AllComponents(); } private void Remove(Type type, int entityID) { Lookup(type).Remove(entityID); var found = entityComponentMap[entityID].Remove(type); // update filters if (found) { if (typeToFilterSignatures.TryGetValue(type, out var filterSignatures)) { foreach (var filterSignature in filterSignatures) { CheckFilter(filterSignature, entityID); } } } } public void Remove(int entityID) where TComponent : struct { Lookup().Remove(entityID); var found = entityComponentMap[entityID].Remove(typeof(TComponent)); // update filters if (found) { if (typeToFilterSignatures.TryGetValue(typeof(TComponent), out var filterSignatures)) { foreach (var filterSignature in filterSignatures) { CheckFilter(filterSignature, entityID); } } } } public void OnEntityDestroy(int entityID) { if (entityComponentMap.ContainsKey(entityID)) { foreach (var type in entityComponentMap[entityID]) { Remove(type, entityID); } entityComponentMap.Remove(entityID); } } public Filter CreateFilter(HashSet included, HashSet excluded) { var filterSignature = new FilterSignature(included, excluded); if (!filterSignatureToEntityIDs.ContainsKey(filterSignature)) { filterSignatureToEntityIDs.Add(filterSignature, new HashSet()); foreach (var type in included) { if (!typeToFilterSignatures.ContainsKey(type)) { typeToFilterSignatures.Add(type, new HashSet()); } typeToFilterSignatures[type].Add(filterSignature); } foreach (var type in excluded) { if (!typeToFilterSignatures.ContainsKey(type)) { typeToFilterSignatures.Add(type, new HashSet()); } typeToFilterSignatures[type].Add(filterSignature); } } return new Filter(this, included, excluded); } public IEnumerable FilterEntities(Filter filter) { foreach (var id in filterSignatureToEntityIDs[filter.Signature]) { yield return new Entity(id); } } private void CheckFilter(FilterSignature filterSignature, int entityID) { foreach (var type in filterSignature.Included) { if (!Has(type, entityID)) { filterSignatureToEntityIDs[filterSignature].Remove(entityID); return; } } foreach (var type in filterSignature.Excluded) { if (Has(type, entityID)) { filterSignatureToEntityIDs[filterSignature].Remove(entityID); return; } } filterSignatureToEntityIDs[filterSignature].Add(entityID); } }