using System; using System.Collections.Generic; using System.Linq; using Collections.Pooled; using Encompass.Exceptions; namespace Encompass { class ComponentMessageManager { private readonly Dictionary componentIDToComponent = new Dictionary(); private readonly Dictionary componentIDToType = new Dictionary(); private readonly Dictionary componentIDToEntityID = new Dictionary(); private readonly Dictionary> componentMessageTypeToExistingComponentIDs = new Dictionary>(); private readonly Dictionary> componentMessageTypeToPendingComponentIDs = new Dictionary>(); private readonly Dictionary> componentMessageTypeToComponentIDs = new Dictionary>(); private readonly Dictionary> entityToTypeToExistingComponentID = new Dictionary>(); private readonly Dictionary> entityToTypeToPendingComponentID = new Dictionary>(); private readonly Dictionary> entityToTypeToComponentID = new Dictionary>(); internal void RegisterEntity(Entity entity) { entityToTypeToComponentID[entity] = new PooledDictionary(); entityToTypeToPendingComponentID[entity] = new PooledDictionary(); entityToTypeToExistingComponentID[entity] = new PooledDictionary(); } internal void RegisterDestroyedEntity(Entity entity) { entityToTypeToComponentID[entity].Dispose(); entityToTypeToComponentID.Remove(entity); entityToTypeToPendingComponentID[entity].Dispose(); entityToTypeToPendingComponentID.Remove(entity); entityToTypeToExistingComponentID[entity].Dispose(); entityToTypeToExistingComponentID.Remove(entity); } internal void ClearMessages() { componentIDToComponent.Clear(); componentIDToType.Clear(); componentIDToEntityID.Clear(); foreach (var set in componentMessageTypeToExistingComponentIDs.Values) { set.Clear(); } foreach (var set in componentMessageTypeToPendingComponentIDs.Values) { set.Clear(); } foreach (var set in componentMessageTypeToComponentIDs.Values) { set.Clear(); } foreach (var dictionary in entityToTypeToExistingComponentID.Values) { dictionary.Clear(); } foreach (var dictionary in entityToTypeToPendingComponentID.Values) { dictionary.Clear(); } foreach (var dictionary in entityToTypeToComponentID.Values) { dictionary.Clear(); } } internal void AddExistingComponentMessage(ComponentMessage componentMessage) where TComponent : struct, IComponent { RegisterExistingOrPendingComponentMessage(componentMessage.entity, componentMessage.componentID, componentMessage.component); if (!componentMessageTypeToExistingComponentIDs.ContainsKey(typeof(TComponent))) { componentMessageTypeToExistingComponentIDs.Add(typeof(TComponent), new HashSet()); } componentMessageTypeToExistingComponentIDs[typeof(TComponent)].Add(componentMessage.componentID); if (!entityToTypeToExistingComponentID[componentMessage.entity].ContainsKey(typeof(TComponent))) { entityToTypeToExistingComponentID[componentMessage.entity].Add(typeof(TComponent), componentMessage.componentID); } else { throw new MultipleComponentOfSameTypeException("Entity {0} cannot have multiple components of type {1}", componentMessage.entity.ID, typeof(TComponent).Name); } } internal void AddPendingComponentMessage(PendingComponentMessage pendingComponentMessage) where TComponent : struct, IComponent { RegisterExistingOrPendingComponentMessage(pendingComponentMessage.entity, pendingComponentMessage.componentID, pendingComponentMessage.component); if (!componentMessageTypeToPendingComponentIDs.ContainsKey(typeof(TComponent))) { componentMessageTypeToPendingComponentIDs.Add(typeof(TComponent), new HashSet()); } componentMessageTypeToPendingComponentIDs[typeof(TComponent)].Add(pendingComponentMessage.componentID); if (!entityToTypeToPendingComponentID[pendingComponentMessage.entity].ContainsKey(typeof(TComponent))) { entityToTypeToPendingComponentID[pendingComponentMessage.entity].Add(typeof(TComponent), pendingComponentMessage.componentID); } else { throw new MultipleComponentOfSameTypeException("Entity {0} cannot have multiple components of type {1}", pendingComponentMessage.entity.ID, typeof(TComponent).Name); } } private void RegisterExistingOrPendingComponentMessage(Entity entity, Guid componentID, TComponent component) where TComponent: struct, IComponent { componentIDToComponent[componentID] = component; componentIDToEntityID[componentID] = entity.ID; componentIDToType[componentID] = typeof(TComponent); if (!componentMessageTypeToComponentIDs.ContainsKey(typeof(TComponent))) { componentMessageTypeToComponentIDs.Add(typeof(TComponent), new HashSet()); } componentMessageTypeToComponentIDs[typeof(TComponent)].Add(componentID); entityToTypeToComponentID[entity][typeof(TComponent)] = componentID; } // general component reads by type internal IEnumerable<(Guid, TComponent)> ReadExistingAndPendingComponentsByType() where TComponent : struct, IComponent { if (componentMessageTypeToComponentIDs.TryGetValue(typeof(TComponent), out HashSet idSet)) { return idSet.Select(id => (id, (TComponent)componentIDToComponent[id])); } return Enumerable.Empty<(Guid, TComponent)>(); } internal IEnumerable<(Guid, TComponent)> ReadExistingComponentsByType() where TComponent: struct, IComponent { if (componentMessageTypeToExistingComponentIDs.TryGetValue(typeof(TComponent), out HashSet idSet)) { return idSet.Select(id => (id, (TComponent)componentIDToComponent[id])); } return Enumerable.Empty<(Guid, TComponent)>(); } internal IEnumerable<(Guid, TComponent)> ReadPendingComponentsByType() where TComponent : struct, IComponent { if (componentMessageTypeToPendingComponentIDs.TryGetValue(typeof(TComponent), out HashSet idSet)) { return idSet.Select(id => (id, (TComponent)componentIDToComponent[id])); } return Enumerable.Empty<(Guid, TComponent)>(); } // singular component reads by type internal (Guid, TComponent) ReadFirstExistingOrPendingComponentByType() where TComponent : struct, IComponent { return ReadExistingAndPendingComponentsByType().First(); } internal (Guid, TComponent) ReadFirstExistingComponentByType() where TComponent : struct, IComponent { return ReadExistingComponentsByType().First(); } internal (Guid, TComponent) ReadFirstPendingComponentByType() where TComponent : struct, IComponent { return ReadPendingComponentsByType().First(); } // check if some component of type exists in the world internal bool SomeExistingOrPendingComponent() where TComponent : struct, IComponent { if (componentMessageTypeToComponentIDs.TryGetValue(typeof(TComponent), out HashSet idSet)) { return idSet.Count > 0; } return false; } internal bool SomeExistingComponent() where TComponent : struct, IComponent { if (componentMessageTypeToExistingComponentIDs.TryGetValue(typeof(TComponent), out HashSet idSet)) { return idSet.Count > 0; } return false; } internal bool SomePendingComponent() where TComponent : struct, IComponent { if (componentMessageTypeToPendingComponentIDs.TryGetValue(typeof(TComponent), out HashSet idSet)) { return idSet.Count > 0; } return false; } // read components by entity and type internal (Guid, TComponent) ReadExistingComponentByEntityAndType(Entity entity) where TComponent : struct, IComponent { if (entityToTypeToExistingComponentID.ContainsKey(entity) && entityToTypeToExistingComponentID[entity].TryGetValue(typeof(TComponent), out Guid id)) { return (id, (TComponent)componentIDToComponent[id]); } else { throw new NoComponentOfTypeOnEntityException("No Component of type {0} exists on Entity {1}", typeof(TComponent).Name, entity.ID); } } internal (Guid, TComponent) ReadPendingComponentByEntityAndType(Entity entity) where TComponent : struct, IComponent { if (entityToTypeToPendingComponentID.ContainsKey(entity) && entityToTypeToPendingComponentID[entity].TryGetValue(typeof(TComponent), out Guid id)) { return (id, (TComponent)componentIDToComponent[id]); } else { throw new NoComponentOfTypeOnEntityException("No Component of type {0} exists on Entity {1}", typeof(TComponent).Name, entity.ID); } } // check if entity has component of type internal bool HasExistingOrPendingComponent(Entity entity) where TComponent : struct, IComponent { return entityToTypeToComponentID.ContainsKey(entity) && entityToTypeToComponentID[entity].ContainsKey(typeof(TComponent)); } internal bool HasExistingComponent(Entity entity) where TComponent : struct, IComponent { return entityToTypeToExistingComponentID.ContainsKey(entity) && entityToTypeToExistingComponentID[entity].ContainsKey(typeof(TComponent)); } internal bool HasPendingComponent(Entity entity) where TComponent : struct, IComponent { return entityToTypeToPendingComponentID.ContainsKey(entity) && entityToTypeToPendingComponentID[entity].ContainsKey(typeof(TComponent)); } internal IComponent GetComponentByID(Guid componentID) { return componentIDToComponent[componentID]; } internal Type GetComponentTypeByID(Guid componentID) { return componentIDToType[componentID]; } internal Guid GetEntityIDByComponentID(Guid componentID) { return componentIDToEntityID[componentID]; } } }