encompass-cs/encompass-cs/ComponentMessageManager.cs

294 lines
13 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using Collections.Pooled;
using Encompass.Exceptions;
namespace Encompass
{
class ComponentMessageManager
{
private readonly Dictionary<Guid, IComponent> componentIDToComponent = new Dictionary<Guid, IComponent>();
private readonly Dictionary<Guid, Type> componentIDToType = new Dictionary<Guid, Type>();
private readonly Dictionary<Guid, Guid> componentIDToEntityID = new Dictionary<Guid, Guid>();
private readonly Dictionary<Type, HashSet<Guid>> componentMessageTypeToExistingComponentIDs = new Dictionary<Type, HashSet<Guid>>();
private readonly Dictionary<Type, HashSet<Guid>> componentMessageTypeToPendingComponentIDs = new Dictionary<Type, HashSet<Guid>>();
private readonly Dictionary<Type, HashSet<Guid>> componentMessageTypeToComponentIDs = new Dictionary<Type, HashSet<Guid>>();
private readonly Dictionary<Entity, PooledDictionary<Type, Guid>> entityToTypeToExistingComponentID = new Dictionary<Entity, PooledDictionary<Type, Guid>>();
private readonly Dictionary<Entity, PooledDictionary<Type, Guid>> entityToTypeToPendingComponentID = new Dictionary<Entity, PooledDictionary<Type, Guid>>();
private readonly Dictionary<Entity, PooledDictionary<Type, Guid>> entityToTypeToComponentID = new Dictionary<Entity, PooledDictionary<Type, Guid>>();
private readonly Dictionary<Entity, PooledDictionary<Type, int>> entityToTypeToPendingComponentPriority = new Dictionary<Entity, PooledDictionary<Type, int>>();
internal void RegisterEntity(Entity entity)
{
entityToTypeToComponentID[entity] = new PooledDictionary<Type, Guid>();
entityToTypeToPendingComponentID[entity] = new PooledDictionary<Type, Guid>();
entityToTypeToPendingComponentPriority[entity] = new PooledDictionary<Type, int>();
entityToTypeToExistingComponentID[entity] = new PooledDictionary<Type, Guid>();
}
internal void RegisterDestroyedEntity(Entity entity)
{
entityToTypeToComponentID[entity].Dispose();
entityToTypeToComponentID.Remove(entity);
entityToTypeToPendingComponentID[entity].Dispose();
entityToTypeToPendingComponentID.Remove(entity);
entityToTypeToPendingComponentPriority[entity].Dispose();
entityToTypeToPendingComponentPriority.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();
}
foreach (var dictionary in entityToTypeToPendingComponentPriority.Values)
{
dictionary.Clear();
}
}
internal void AddExistingComponentMessage<TComponent>(ComponentMessage<TComponent> componentMessage) where TComponent : struct, IComponent
{
RegisterExistingOrPendingComponentMessage(componentMessage.entity, componentMessage.componentID, componentMessage.component);
if (!componentMessageTypeToExistingComponentIDs.ContainsKey(typeof(TComponent)))
{
componentMessageTypeToExistingComponentIDs.Add(typeof(TComponent), new HashSet<Guid>());
}
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<TComponent>(PendingComponentMessage<TComponent> pendingComponentMessage) where TComponent : struct, IComponent
{
RegisterExistingOrPendingComponentMessage(pendingComponentMessage.entity, pendingComponentMessage.componentID, pendingComponentMessage.component);
if (!componentMessageTypeToPendingComponentIDs.ContainsKey(typeof(TComponent)))
{
componentMessageTypeToPendingComponentIDs.Add(typeof(TComponent), new HashSet<Guid>());
}
if (!entityToTypeToPendingComponentID[pendingComponentMessage.entity].ContainsKey(typeof(TComponent)))
{
entityToTypeToPendingComponentID[pendingComponentMessage.entity].Add(typeof(TComponent), pendingComponentMessage.componentID);
entityToTypeToPendingComponentPriority[pendingComponentMessage.entity].Add(typeof(TComponent), pendingComponentMessage.priority);
componentMessageTypeToPendingComponentIDs[typeof(TComponent)].Add(pendingComponentMessage.componentID);
}
else
{
if (pendingComponentMessage.priority < entityToTypeToPendingComponentPriority[pendingComponentMessage.entity][typeof(TComponent)])
{
componentMessageTypeToPendingComponentIDs[typeof(TComponent)].Remove(entityToTypeToPendingComponentID[pendingComponentMessage.entity][typeof(TComponent)]);
entityToTypeToPendingComponentID[pendingComponentMessage.entity][typeof(TComponent)] = pendingComponentMessage.componentID;
entityToTypeToPendingComponentPriority[pendingComponentMessage.entity][typeof(TComponent)] = pendingComponentMessage.priority;
componentMessageTypeToPendingComponentIDs[typeof(TComponent)].Add(pendingComponentMessage.componentID);
}
}
}
private void RegisterExistingOrPendingComponentMessage<TComponent>(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<Guid>());
}
componentMessageTypeToComponentIDs[typeof(TComponent)].Add(componentID);
entityToTypeToComponentID[entity][typeof(TComponent)] = componentID;
}
// general component reads by type
internal IEnumerable<(Guid, TComponent)> ReadExistingAndPendingComponentsByType<TComponent>() where TComponent : struct, IComponent
{
if (componentMessageTypeToComponentIDs.TryGetValue(typeof(TComponent), out HashSet<Guid> idSet))
{
return idSet.Select(id => (id, (TComponent)componentIDToComponent[id]));
}
return Enumerable.Empty<(Guid, TComponent)>();
}
internal IEnumerable<(Guid, TComponent)> ReadExistingComponentsByType<TComponent>() where TComponent: struct, IComponent
{
if (componentMessageTypeToExistingComponentIDs.TryGetValue(typeof(TComponent), out HashSet<Guid> idSet))
{
return idSet.Select(id => (id, (TComponent)componentIDToComponent[id]));
}
return Enumerable.Empty<(Guid, TComponent)>();
}
internal IEnumerable<(Guid, TComponent)> ReadPendingComponentsByType<TComponent>() where TComponent : struct, IComponent
{
if (componentMessageTypeToPendingComponentIDs.TryGetValue(typeof(TComponent), out HashSet<Guid> idSet))
{
return idSet.Select(id => (id, (TComponent)componentIDToComponent[id]));
}
return Enumerable.Empty<(Guid, TComponent)>();
}
// singular component reads by type
internal (Guid, TComponent) ReadFirstExistingOrPendingComponentByType<TComponent>() where TComponent : struct, IComponent
{
return ReadExistingAndPendingComponentsByType<TComponent>().First();
}
internal (Guid, TComponent) ReadFirstExistingComponentByType<TComponent>() where TComponent : struct, IComponent
{
return ReadExistingComponentsByType<TComponent>().First();
}
internal (Guid, TComponent) ReadFirstPendingComponentByType<TComponent>() where TComponent : struct, IComponent
{
return ReadPendingComponentsByType<TComponent>().First();
}
// check if some component of type exists in the world
internal bool SomeExistingOrPendingComponent<TComponent>() where TComponent : struct, IComponent
{
if (componentMessageTypeToComponentIDs.TryGetValue(typeof(TComponent), out HashSet<Guid> idSet))
{
return idSet.Count > 0;
}
return false;
}
internal bool SomeExistingComponent<TComponent>() where TComponent : struct, IComponent
{
if (componentMessageTypeToExistingComponentIDs.TryGetValue(typeof(TComponent), out HashSet<Guid> idSet))
{
return idSet.Count > 0;
}
return false;
}
internal bool SomePendingComponent<TComponent>() where TComponent : struct, IComponent
{
if (componentMessageTypeToPendingComponentIDs.TryGetValue(typeof(TComponent), out HashSet<Guid> idSet))
{
return idSet.Count > 0;
}
return false;
}
// read components by entity and type
internal (Guid, TComponent) ReadExistingComponentByEntityAndType<TComponent>(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<TComponent>(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<TComponent>(Entity entity) where TComponent : struct, IComponent
{
return entityToTypeToComponentID.ContainsKey(entity) && entityToTypeToComponentID[entity].ContainsKey(typeof(TComponent));
}
internal bool HasExistingComponent<TComponent>(Entity entity) where TComponent : struct, IComponent
{
return entityToTypeToExistingComponentID.ContainsKey(entity) && entityToTypeToExistingComponentID[entity].ContainsKey(typeof(TComponent));
}
internal bool HasPendingComponent<TComponent>(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];
}
}
}