2019-06-14 03:28:26 +00:00
|
|
|
using System;
|
|
|
|
using System.Collections.Generic;
|
|
|
|
using System.Linq;
|
2019-07-18 01:53:31 +00:00
|
|
|
using Encompass.Exceptions;
|
2019-08-02 01:56:52 +00:00
|
|
|
using Collections.Pooled;
|
2019-06-14 03:28:26 +00:00
|
|
|
|
2019-06-16 01:05:56 +00:00
|
|
|
namespace Encompass
|
|
|
|
{
|
|
|
|
internal class ComponentManager
|
|
|
|
{
|
2019-06-20 17:46:15 +00:00
|
|
|
private readonly DrawLayerManager drawLayerManager;
|
2019-06-20 00:40:01 +00:00
|
|
|
|
2019-06-20 17:46:15 +00:00
|
|
|
private readonly Dictionary<Guid, Type> componentIDToType = new Dictionary<Guid, Type>();
|
|
|
|
private readonly Dictionary<Guid, IComponent> IDToComponent = new Dictionary<Guid, IComponent>();
|
2019-08-10 02:29:08 +00:00
|
|
|
private readonly Dictionary<Guid, PooledSet<Guid>> entityIDToComponentIDs = new Dictionary<Guid, PooledSet<Guid>>();
|
2019-06-20 17:46:15 +00:00
|
|
|
private readonly Dictionary<Guid, Guid> componentIDToEntityID = new Dictionary<Guid, Guid>();
|
2019-06-14 03:28:26 +00:00
|
|
|
|
2019-08-10 03:04:11 +00:00
|
|
|
private readonly Dictionary<Guid, PooledDictionary<Type, HashSet<Guid>>> entityIDToComponentTypeToComponentIDs = new Dictionary<Guid, PooledDictionary<Type, HashSet<Guid>>>();
|
2019-07-31 19:07:13 +00:00
|
|
|
|
2019-07-18 01:56:02 +00:00
|
|
|
private readonly Dictionary<Type, HashSet<Guid>> typeToComponentIDs = new Dictionary<Type, HashSet<Guid>>();
|
2019-06-14 03:28:26 +00:00
|
|
|
|
2019-07-18 01:12:29 +00:00
|
|
|
private readonly HashSet<Guid> componentsMarkedForRemoval = new HashSet<Guid>();
|
|
|
|
|
2019-07-18 01:53:31 +00:00
|
|
|
private readonly Dictionary<Guid, IComponent> pendingUpdates = new Dictionary<Guid, IComponent>();
|
|
|
|
|
2019-08-01 22:06:19 +00:00
|
|
|
public ComponentManager(DrawLayerManager drawLayerManager)
|
2019-06-19 23:13:02 +00:00
|
|
|
{
|
2019-06-20 00:40:01 +00:00
|
|
|
this.drawLayerManager = drawLayerManager;
|
2019-06-19 23:13:02 +00:00
|
|
|
}
|
|
|
|
|
2019-07-13 00:37:31 +00:00
|
|
|
internal void RegisterEntity(Guid entityID)
|
|
|
|
{
|
2019-08-10 02:29:08 +00:00
|
|
|
entityIDToComponentIDs.Add(entityID, new PooledSet<Guid>());
|
2019-08-10 03:04:11 +00:00
|
|
|
entityIDToComponentTypeToComponentIDs.Add(entityID, new PooledDictionary<Type, HashSet<Guid>>(ClearMode.Never));
|
2019-07-13 00:37:31 +00:00
|
|
|
}
|
|
|
|
|
2019-07-23 05:52:51 +00:00
|
|
|
internal Guid NextID()
|
2019-06-16 01:05:56 +00:00
|
|
|
{
|
2019-07-23 05:52:51 +00:00
|
|
|
return Guid.NewGuid();
|
|
|
|
}
|
2019-06-17 18:33:38 +00:00
|
|
|
|
2019-07-23 05:52:51 +00:00
|
|
|
internal Guid AddComponent<TComponent>(Entity entity, Guid componentID, TComponent component) where TComponent : struct, IComponent
|
|
|
|
{
|
2019-06-17 18:33:38 +00:00
|
|
|
IDToComponent[componentID] = component;
|
2019-06-19 21:14:44 +00:00
|
|
|
componentIDToType[componentID] = typeof(TComponent);
|
2019-06-20 17:46:15 +00:00
|
|
|
|
2019-06-19 23:13:02 +00:00
|
|
|
if (!typeToComponentIDs.ContainsKey(typeof(TComponent)))
|
|
|
|
{
|
2019-07-18 01:56:02 +00:00
|
|
|
typeToComponentIDs.Add(typeof(TComponent), new HashSet<Guid>());
|
2019-06-19 23:13:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
typeToComponentIDs[typeof(TComponent)].Add(componentID);
|
2019-06-17 18:33:38 +00:00
|
|
|
|
2019-07-23 05:52:51 +00:00
|
|
|
entityIDToComponentIDs[entity.ID].Add(componentID);
|
2019-07-31 19:07:13 +00:00
|
|
|
if (!entityIDToComponentTypeToComponentIDs[entity.ID].ContainsKey(typeof(TComponent))) {
|
2019-08-10 03:04:11 +00:00
|
|
|
entityIDToComponentTypeToComponentIDs[entity.ID].Add(typeof(TComponent), new HashSet<Guid>());
|
2019-07-31 19:07:13 +00:00
|
|
|
}
|
|
|
|
entityIDToComponentTypeToComponentIDs[entity.ID][typeof(TComponent)].Add(componentID);
|
|
|
|
|
2019-07-23 05:52:51 +00:00
|
|
|
componentIDToEntityID[componentID] = entity.ID;
|
2019-06-14 03:28:26 +00:00
|
|
|
|
2019-06-20 05:38:56 +00:00
|
|
|
return componentID;
|
|
|
|
}
|
2019-06-20 00:40:01 +00:00
|
|
|
|
2019-07-23 05:52:51 +00:00
|
|
|
internal Guid AddDrawComponent<TComponent>(Entity entity, Guid componentID, TComponent component, int layer = 0) where TComponent : struct, IComponent
|
2019-06-20 05:38:56 +00:00
|
|
|
{
|
2019-07-23 05:52:51 +00:00
|
|
|
AddComponent(entity, componentID, component);
|
2019-06-20 05:38:56 +00:00
|
|
|
drawLayerManager.RegisterComponentWithLayer(componentID, layer);
|
2019-06-17 18:33:38 +00:00
|
|
|
return componentID;
|
2019-06-14 03:28:26 +00:00
|
|
|
}
|
|
|
|
|
2019-08-02 06:09:41 +00:00
|
|
|
|
2019-06-20 00:40:01 +00:00
|
|
|
internal IEnumerable<Guid> GetComponentIDsByEntityID(Guid entityID)
|
|
|
|
{
|
2019-08-10 02:29:08 +00:00
|
|
|
if (entityIDToComponentIDs.TryGetValue(entityID, out PooledSet<Guid> idSet))
|
2019-08-01 23:44:29 +00:00
|
|
|
{
|
|
|
|
return idSet;
|
|
|
|
}
|
|
|
|
return Enumerable.Empty<Guid>();
|
2019-06-14 03:28:26 +00:00
|
|
|
}
|
|
|
|
|
2019-08-01 23:44:29 +00:00
|
|
|
internal IEnumerable<(Guid, TComponent)> GetComponentsByType<TComponent>() where TComponent : struct, IComponent
|
2019-06-19 21:14:44 +00:00
|
|
|
{
|
2019-08-10 02:29:08 +00:00
|
|
|
if (typeToComponentIDs.TryGetValue(typeof(TComponent), out HashSet<Guid> idSet))
|
2019-08-01 23:44:29 +00:00
|
|
|
{
|
|
|
|
return idSet.Select(id => (id, (TComponent)IDToComponent[id]));
|
|
|
|
}
|
|
|
|
return Enumerable.Empty<(Guid, TComponent)>();
|
2019-06-19 21:14:44 +00:00
|
|
|
}
|
|
|
|
|
2019-06-27 23:55:12 +00:00
|
|
|
internal IEnumerable<ValueTuple<Guid, TComponent>> GetComponentsByEntityAndType<TComponent>(Guid entityID) where TComponent : struct, IComponent
|
2019-06-16 01:05:56 +00:00
|
|
|
{
|
2019-08-10 03:04:11 +00:00
|
|
|
if (entityIDToComponentTypeToComponentIDs.ContainsKey(entityID) && entityIDToComponentTypeToComponentIDs[entityID].TryGetValue(typeof(TComponent), out HashSet<Guid> idSet))
|
2019-08-01 23:44:29 +00:00
|
|
|
{
|
|
|
|
return idSet.Select(id => (id, (TComponent)IDToComponent[id]));
|
|
|
|
}
|
|
|
|
return Enumerable.Empty<(Guid, TComponent)>();
|
2019-06-14 03:28:26 +00:00
|
|
|
}
|
|
|
|
|
2019-08-01 23:44:29 +00:00
|
|
|
internal bool EntityHasComponentOfType<TComponent>(Guid entityID) where TComponent : struct, IComponent
|
2019-06-19 21:14:44 +00:00
|
|
|
{
|
2019-08-10 03:04:11 +00:00
|
|
|
if (entityIDToComponentTypeToComponentIDs.ContainsKey(entityID) && entityIDToComponentTypeToComponentIDs[entityID].TryGetValue(typeof(TComponent), out HashSet<Guid> idSet))
|
2019-08-01 23:44:29 +00:00
|
|
|
{
|
|
|
|
return idSet.Count > 0;
|
|
|
|
}
|
2019-06-19 21:14:44 +00:00
|
|
|
|
2019-08-01 23:44:29 +00:00
|
|
|
return false;
|
2019-06-19 23:13:02 +00:00
|
|
|
}
|
|
|
|
|
2019-08-01 23:44:29 +00:00
|
|
|
internal bool ComponentOfTypeExists<TComponent>() where TComponent : struct, IComponent
|
2019-06-16 01:05:56 +00:00
|
|
|
{
|
2019-08-10 02:29:08 +00:00
|
|
|
if (typeToComponentIDs.TryGetValue(typeof(TComponent), out HashSet<Guid> idSet))
|
2019-08-01 23:44:29 +00:00
|
|
|
{
|
|
|
|
return idSet.Count > 0;
|
|
|
|
}
|
2019-06-14 03:28:26 +00:00
|
|
|
|
2019-08-01 23:44:29 +00:00
|
|
|
return false;
|
2019-06-19 21:14:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
internal IComponent GetComponentByID(Guid componentID)
|
|
|
|
{
|
|
|
|
return IDToComponent[componentID];
|
|
|
|
}
|
|
|
|
|
|
|
|
internal Type GetComponentTypeByID(Guid componentID)
|
|
|
|
{
|
|
|
|
return componentIDToType[componentID];
|
|
|
|
}
|
|
|
|
|
2019-06-22 00:50:01 +00:00
|
|
|
internal Guid GetEntityIDByComponentID(Guid componentID)
|
2019-06-19 21:14:44 +00:00
|
|
|
{
|
|
|
|
return componentIDToEntityID[componentID];
|
|
|
|
}
|
|
|
|
|
2019-07-18 01:53:31 +00:00
|
|
|
internal void AddUpdateComponentOperation<TComponent>(Guid componentID, TComponent newComponentValue) where TComponent : struct, IComponent
|
|
|
|
{
|
|
|
|
if (pendingUpdates.ContainsKey(componentID))
|
|
|
|
{
|
2019-07-20 21:13:11 +00:00
|
|
|
throw new RepeatUpdateComponentException("Component {0} with ID {1} was updated multiple times this frame", typeof(TComponent).Name, componentID);
|
2019-07-18 01:53:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pendingUpdates.Add(componentID, newComponentValue);
|
|
|
|
}
|
|
|
|
|
|
|
|
internal void PerformComponentUpdates()
|
2019-06-16 01:05:56 +00:00
|
|
|
{
|
2019-07-18 01:53:31 +00:00
|
|
|
foreach (var idPair in pendingUpdates)
|
|
|
|
{
|
|
|
|
IDToComponent[idPair.Key] = idPair.Value;
|
|
|
|
}
|
|
|
|
|
|
|
|
pendingUpdates.Clear();
|
2019-06-15 07:39:08 +00:00
|
|
|
}
|
|
|
|
|
2019-07-18 01:12:29 +00:00
|
|
|
internal void MarkAllComponentsOnEntityForRemoval(Guid entityID)
|
2019-06-16 01:05:56 +00:00
|
|
|
{
|
2019-07-18 01:12:29 +00:00
|
|
|
foreach (var componentID in GetComponentIDsByEntityID(entityID))
|
|
|
|
{
|
|
|
|
MarkForRemoval(componentID);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
internal void MarkForRemoval(Guid componentID)
|
|
|
|
{
|
|
|
|
componentsMarkedForRemoval.Add(componentID);
|
|
|
|
}
|
|
|
|
|
|
|
|
internal void RemoveMarkedComponents()
|
|
|
|
{
|
|
|
|
foreach (var componentID in componentsMarkedForRemoval)
|
|
|
|
{
|
|
|
|
Remove(componentID);
|
|
|
|
}
|
|
|
|
|
|
|
|
componentsMarkedForRemoval.Clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
private void Remove(Guid componentID)
|
2019-06-16 01:05:56 +00:00
|
|
|
{
|
2019-07-17 18:24:21 +00:00
|
|
|
var type = componentIDToType[componentID];
|
2019-06-14 03:28:26 +00:00
|
|
|
|
2019-07-17 18:24:21 +00:00
|
|
|
var entityID = componentIDToEntityID[componentID];
|
|
|
|
if (entityIDToComponentIDs.ContainsKey(entityID))
|
2019-06-16 01:05:56 +00:00
|
|
|
{
|
2019-07-17 18:24:21 +00:00
|
|
|
entityIDToComponentIDs[entityID].Remove(componentID);
|
2019-06-15 07:39:08 +00:00
|
|
|
}
|
2019-06-17 18:33:38 +00:00
|
|
|
|
2019-07-17 18:24:21 +00:00
|
|
|
IDToComponent.Remove(componentID);
|
|
|
|
componentIDToType.Remove(componentID);
|
|
|
|
componentIDToEntityID.Remove(componentID);
|
|
|
|
typeToComponentIDs[type].Remove(componentID);
|
2019-06-20 00:40:01 +00:00
|
|
|
|
2019-07-17 18:24:21 +00:00
|
|
|
drawLayerManager.UnRegisterComponentWithLayer(componentID);
|
2019-06-14 03:28:26 +00:00
|
|
|
}
|
2019-06-20 03:37:46 +00:00
|
|
|
|
|
|
|
public void RegisterDestroyedEntity(Guid entityID)
|
|
|
|
{
|
2019-08-10 02:29:08 +00:00
|
|
|
entityIDToComponentIDs[entityID].Dispose();
|
2019-06-20 03:37:46 +00:00
|
|
|
entityIDToComponentIDs.Remove(entityID);
|
2019-08-02 01:56:52 +00:00
|
|
|
|
2019-08-09 05:38:48 +00:00
|
|
|
foreach (var set in entityIDToComponentTypeToComponentIDs[entityID].Values)
|
|
|
|
{
|
2019-08-10 03:04:11 +00:00
|
|
|
set.Clear();
|
2019-08-09 05:38:48 +00:00
|
|
|
}
|
2019-08-02 06:09:41 +00:00
|
|
|
entityIDToComponentTypeToComponentIDs[entityID].Dispose();
|
2019-07-31 19:07:13 +00:00
|
|
|
entityIDToComponentTypeToComponentIDs.Remove(entityID);
|
2019-06-20 03:37:46 +00:00
|
|
|
}
|
2019-06-14 03:28:26 +00:00
|
|
|
}
|
|
|
|
}
|