324 lines
15 KiB
C#
324 lines
15 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using Encompass.Exceptions;
|
|
|
|
namespace Encompass
|
|
{
|
|
class ComponentMessageManager
|
|
{
|
|
private readonly ComponentStore componentIDToComponent = new ComponentStore();
|
|
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<Type, Dictionary<Entity, Guid>> typeToEntityToExistingComponentID = new Dictionary<Type, Dictionary<Entity, Guid>>();
|
|
private readonly Dictionary<Type, Dictionary<Entity, Guid>> typeToEntityToPendingComponentID = new Dictionary<Type, Dictionary<Entity, Guid>>();
|
|
private readonly Dictionary<Type, Dictionary<Entity, Guid>> typeToEntityToComponentID = new Dictionary<Type, Dictionary<Entity, Guid>>();
|
|
|
|
private readonly Dictionary<Type, Dictionary<Entity, int>> typeToEntityToPendingComponentPriority = new Dictionary<Type, Dictionary<Entity, int>>();
|
|
|
|
internal void ClearMessages()
|
|
{
|
|
componentIDToComponent.ClearAll();
|
|
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 typeToEntityToExistingComponentID.Values)
|
|
{
|
|
dictionary.Clear();
|
|
}
|
|
|
|
foreach (var dictionary in typeToEntityToPendingComponentID.Values)
|
|
{
|
|
dictionary.Clear();
|
|
}
|
|
|
|
foreach (var dictionary in typeToEntityToComponentID.Values)
|
|
{
|
|
dictionary.Clear();
|
|
}
|
|
|
|
foreach (var dictionary in typeToEntityToPendingComponentPriority.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 (!typeToEntityToExistingComponentID.ContainsKey(typeof(TComponent)))
|
|
{
|
|
typeToEntityToExistingComponentID.Add(typeof(TComponent), new Dictionary<Entity, Guid>());
|
|
}
|
|
|
|
if (!typeToEntityToExistingComponentID[typeof(TComponent)].ContainsKey(componentMessage.entity))
|
|
{
|
|
typeToEntityToExistingComponentID[typeof(TComponent)].Add(componentMessage.entity, 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 (!typeToEntityToPendingComponentID.ContainsKey(typeof(TComponent)))
|
|
{
|
|
typeToEntityToPendingComponentID.Add(typeof(TComponent), new Dictionary<Entity, Guid>());
|
|
typeToEntityToPendingComponentPriority.Add(typeof(TComponent), new Dictionary<Entity, int>());
|
|
}
|
|
|
|
if (!typeToEntityToPendingComponentID[typeof(TComponent)].ContainsKey(pendingComponentMessage.entity))
|
|
{
|
|
typeToEntityToPendingComponentID[typeof(TComponent)].Add(pendingComponentMessage.entity, pendingComponentMessage.componentID);
|
|
typeToEntityToPendingComponentPriority[typeof(TComponent)].Add(pendingComponentMessage.entity, pendingComponentMessage.priority);
|
|
componentMessageTypeToPendingComponentIDs[typeof(TComponent)].Add(pendingComponentMessage.componentID);
|
|
}
|
|
else
|
|
{
|
|
if (pendingComponentMessage.priority < typeToEntityToPendingComponentPriority[typeof(TComponent)][pendingComponentMessage.entity])
|
|
{
|
|
componentMessageTypeToPendingComponentIDs[typeof(TComponent)].Remove(typeToEntityToPendingComponentID[typeof(TComponent)][pendingComponentMessage.entity]);
|
|
typeToEntityToPendingComponentID[typeof(TComponent)][pendingComponentMessage.entity] = pendingComponentMessage.componentID;
|
|
typeToEntityToPendingComponentPriority[typeof(TComponent)][pendingComponentMessage.entity] = pendingComponentMessage.priority;
|
|
componentMessageTypeToPendingComponentIDs[typeof(TComponent)].Add(pendingComponentMessage.componentID);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void RegisterExistingOrPendingComponentMessage<TComponent>(Entity entity, Guid componentID, TComponent component) where TComponent : struct, IComponent
|
|
{
|
|
componentIDToComponent.Set(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);
|
|
|
|
if (!typeToEntityToComponentID.ContainsKey(typeof(TComponent)))
|
|
{
|
|
typeToEntityToComponentID.Add(typeof(TComponent), new Dictionary<Entity, Guid>());
|
|
}
|
|
typeToEntityToComponentID[typeof(TComponent)][entity] = 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, componentIDToComponent.Get<TComponent>(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, componentIDToComponent.Get<TComponent>(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, componentIDToComponent.Get<TComponent>(id)));
|
|
}
|
|
|
|
return Enumerable.Empty<(Guid, TComponent)>();
|
|
}
|
|
|
|
// singular component reads by type
|
|
|
|
internal (Guid, TComponent) ReadFirstExistingOrPendingComponentByType<TComponent>() where TComponent : struct, IComponent
|
|
{
|
|
if (!SomeExistingOrPendingComponent<TComponent>()) { throw new Exceptions.NoComponentOfTypeException($"No Component with type {typeof(TComponent)} exists"); }
|
|
return ReadExistingAndPendingComponentsByType<TComponent>().First();
|
|
}
|
|
|
|
internal (Guid, TComponent) ReadFirstExistingComponentByType<TComponent>() where TComponent : struct, IComponent
|
|
{
|
|
if (!SomeExistingComponent<TComponent>()) { throw new Exceptions.NoComponentOfTypeException($"No Component with type {typeof(TComponent)} exists"); }
|
|
return ReadExistingComponentsByType<TComponent>().First();
|
|
}
|
|
|
|
internal (Guid, TComponent) ReadFirstPendingComponentByType<TComponent>() where TComponent : struct, IComponent
|
|
{
|
|
if (!SomeExistingComponent<TComponent>()) { throw new Exceptions.NoComponentOfTypeException($"No Component with type {typeof(TComponent)} exists"); }
|
|
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 (typeToEntityToExistingComponentID.ContainsKey(typeof(TComponent)) && typeToEntityToExistingComponentID[typeof(TComponent)].TryGetValue(entity, out Guid id))
|
|
{
|
|
return (id, componentIDToComponent.Get<TComponent>(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 (typeToEntityToPendingComponentID.ContainsKey(typeof(TComponent)) && typeToEntityToPendingComponentID[typeof(TComponent)].TryGetValue(entity, out Guid id))
|
|
{
|
|
return (id, componentIDToComponent.Get<TComponent>(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 typeToEntityToComponentID.ContainsKey(typeof(TComponent)) && typeToEntityToComponentID[typeof(TComponent)].ContainsKey(entity);
|
|
}
|
|
|
|
internal bool HasExistingOrPendingComponent(Entity entity, Type type)
|
|
{
|
|
return typeToEntityToComponentID.ContainsKey(type) && typeToEntityToComponentID[type].ContainsKey(entity);
|
|
}
|
|
|
|
internal bool HasExistingComponent<TComponent>(Entity entity) where TComponent : struct, IComponent
|
|
{
|
|
return typeToEntityToExistingComponentID.ContainsKey(typeof(TComponent)) && typeToEntityToExistingComponentID[typeof(TComponent)].ContainsKey(entity);
|
|
}
|
|
|
|
internal bool HasExistingComponent(Entity entity, Type type)
|
|
{
|
|
return typeToEntityToExistingComponentID.ContainsKey(type) && typeToEntityToExistingComponentID[type].ContainsKey(entity);
|
|
}
|
|
|
|
internal bool HasPendingComponent<TComponent>(Entity entity) where TComponent : struct, IComponent
|
|
{
|
|
return typeToEntityToPendingComponentID.ContainsKey(typeof(TComponent)) && typeToEntityToPendingComponentID[typeof(TComponent)].ContainsKey(entity);
|
|
}
|
|
|
|
internal bool HasPendingComponent(Entity entity, Type type)
|
|
{
|
|
return typeToEntityToPendingComponentID.ContainsKey(type) && typeToEntityToPendingComponentID[type].ContainsKey(entity);
|
|
}
|
|
|
|
internal TComponent GetComponentByID<TComponent>(Guid componentID) where TComponent : struct, IComponent
|
|
{
|
|
if (componentIDToComponent.Has<TComponent>(componentID))
|
|
{
|
|
return componentIDToComponent.Get<TComponent>(componentID);
|
|
}
|
|
else
|
|
{
|
|
throw new ComponentNotFoundException("Component with ID {0} does not exist.", componentID);
|
|
}
|
|
}
|
|
|
|
internal Type GetComponentTypeByID(Guid componentID)
|
|
{
|
|
if (componentIDToType.ContainsKey(componentID))
|
|
{
|
|
return componentIDToType[componentID];
|
|
}
|
|
else
|
|
{
|
|
throw new ComponentNotFoundException("Component with ID {0} does not exist.", componentID);
|
|
}
|
|
}
|
|
|
|
internal Guid GetEntityIDByComponentID(Guid componentID)
|
|
{
|
|
if (componentIDToEntityID.ContainsKey(componentID))
|
|
{
|
|
return componentIDToEntityID[componentID];
|
|
}
|
|
else
|
|
{
|
|
throw new ComponentNotFoundException("Component with ID {0} does not exist.", componentID);
|
|
}
|
|
}
|
|
}
|
|
}
|