commit
447a668e1c
|
@ -21,7 +21,7 @@ namespace Encompass
|
|||
throw new IllegalReadTypeException("{0} must be a Component", readType.Name);
|
||||
}
|
||||
|
||||
this.readTypes.Add(typeof(ComponentMessage<>).MakeGenericType(readType));
|
||||
this.readTypes.Add(readType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ namespace Encompass
|
|||
throw new IllegalReadTypeException("{0} must be a Component", readPendingType.Name);
|
||||
}
|
||||
|
||||
this.readPendingTypes.Add(typeof(PendingComponentMessage<>).MakeGenericType(readPendingType));
|
||||
this.readPendingTypes.Add(readPendingType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ namespace Encompass
|
|||
throw new IllegalWriteTypeException("{0} must be a Component", writeType.Name);
|
||||
}
|
||||
|
||||
this.writeTypes.Add(typeof(ComponentWriteMessage<>).MakeGenericType(writeType));
|
||||
this.writeTypes.Add(writeType);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -33,8 +33,8 @@ namespace Encompass
|
|||
throw new IllegalWriteTypeException("{0} must be a Component", writeType.Name);
|
||||
}
|
||||
|
||||
this.writeTypes.Add(typeof(ComponentWriteMessage<>).MakeGenericType(writeType));
|
||||
this.priorities.Add(writeType, priority);
|
||||
writeTypes.Add(writeType);
|
||||
priorities.Add(writeType, priority);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ namespace Encompass
|
|||
throw new IllegalWritePendingTypeException("{0} must be a Component", writePendingType.Name);
|
||||
}
|
||||
|
||||
this.writePendingTypes.Add(typeof(PendingComponentMessage<>).MakeGenericType(writePendingType));
|
||||
this.writePendingTypes.Add(writePendingType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Encompass
|
||||
{
|
||||
internal class ComponentStore
|
||||
{
|
||||
private Dictionary<Type, TypedComponentStore> Stores = new Dictionary<Type, TypedComponentStore>(512);
|
||||
|
||||
public IEnumerable<(Type, TypedComponentStore)> StoresEnumerable()
|
||||
{
|
||||
foreach (var entry in Stores)
|
||||
{
|
||||
yield return (entry.Key, entry.Value);
|
||||
}
|
||||
}
|
||||
|
||||
private TypedComponentStore<TComponent> Lookup<TComponent>() where TComponent : struct, IComponent
|
||||
{
|
||||
if (!Stores.ContainsKey(typeof(TComponent)))
|
||||
{
|
||||
var store = new TypedComponentStore<TComponent>();
|
||||
Stores.Add(typeof(TComponent), store);
|
||||
}
|
||||
return Stores[typeof(TComponent)] as TypedComponentStore<TComponent>;
|
||||
}
|
||||
|
||||
public bool Has<TComponent>(Entity entity) where TComponent : struct, IComponent
|
||||
{
|
||||
return Lookup<TComponent>().Has(entity);
|
||||
}
|
||||
|
||||
public bool Has(Type type, Entity entity)
|
||||
{
|
||||
return Stores.ContainsKey(type) && Stores[type].Has(entity);
|
||||
}
|
||||
|
||||
public TComponent Get<TComponent>(Entity entity) where TComponent : struct, IComponent
|
||||
{
|
||||
return Lookup<TComponent>().Get(entity);
|
||||
}
|
||||
|
||||
public void Set<TComponent>(Entity entity, TComponent component) where TComponent : struct, IComponent
|
||||
{
|
||||
Lookup<TComponent>().Set(entity, component);
|
||||
}
|
||||
|
||||
public bool Set<TComponent>(Entity entity, TComponent component, int priority) where TComponent : struct, IComponent
|
||||
{
|
||||
return Lookup<TComponent>().Set(entity, component, priority);
|
||||
}
|
||||
|
||||
public void Remove<TComponent>(Entity entity) where TComponent : struct, IComponent
|
||||
{
|
||||
Lookup<TComponent>().Remove(entity);
|
||||
}
|
||||
|
||||
public void Remove(Entity entity)
|
||||
{
|
||||
foreach (var entry in Stores.Values)
|
||||
{
|
||||
entry.Remove(entity);
|
||||
}
|
||||
}
|
||||
|
||||
public bool Any<TComponent>() where TComponent : struct, IComponent
|
||||
{
|
||||
return Lookup<TComponent>().Count > 0;
|
||||
}
|
||||
|
||||
public IEnumerable<(Entity, Type, IComponent)> AllInterfaceTyped()
|
||||
{
|
||||
foreach (var store in Stores.Values)
|
||||
{
|
||||
foreach (var thing in store.AllInterfaceTyped())
|
||||
{
|
||||
yield return thing;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<(Entity, TComponent)> All<TComponent>() where TComponent : struct, IComponent
|
||||
{
|
||||
return Lookup<TComponent>().All();
|
||||
}
|
||||
|
||||
public void Clear<TComponent>() where TComponent : struct, IComponent
|
||||
{
|
||||
Lookup<TComponent>().Clear();
|
||||
}
|
||||
|
||||
public void ClearAll()
|
||||
{
|
||||
foreach (var store in Stores.Values)
|
||||
{
|
||||
store.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
public void SwapWith(ComponentStore other)
|
||||
{
|
||||
(Stores, other.Stores) = (other.Stores, Stores);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Encompass
|
||||
{
|
||||
internal class MessageStore
|
||||
{
|
||||
private Dictionary<Type, TypedMessageStore> Stores = new Dictionary<Type, TypedMessageStore>(512);
|
||||
|
||||
private void RegisterMessageType<TMessage>() where TMessage : struct, IMessage
|
||||
{
|
||||
Stores.Add(typeof(TMessage), new TypedMessageStore<TMessage>());
|
||||
}
|
||||
|
||||
private TypedMessageStore<TMessage> Lookup<TMessage>() where TMessage : struct, IMessage
|
||||
{
|
||||
if (!Stores.ContainsKey(typeof(TMessage))) { RegisterMessageType<TMessage>(); }
|
||||
return Stores[typeof(TMessage)] as TypedMessageStore<TMessage>;
|
||||
}
|
||||
|
||||
public void AddMessage<TMessage>(TMessage message) where TMessage : struct, IMessage
|
||||
{
|
||||
Lookup<TMessage>().Add(message);
|
||||
}
|
||||
|
||||
public void AddMessage<TMessage>(TMessage message, double time) where TMessage : struct, IMessage
|
||||
{
|
||||
Lookup<TMessage>().Add(message, time);
|
||||
}
|
||||
|
||||
public void AddMessageIgnoringTimeDilation<TMessage>(TMessage message, double time) where TMessage : struct, IMessage
|
||||
{
|
||||
Lookup<TMessage>().AddIgnoringTimeDilation(message, time);
|
||||
}
|
||||
|
||||
public TMessage First<TMessage>() where TMessage : struct, IMessage
|
||||
{
|
||||
return Lookup<TMessage>().First();
|
||||
}
|
||||
|
||||
public IEnumerable<TMessage> All<TMessage>() where TMessage : struct, IMessage
|
||||
{
|
||||
return Lookup<TMessage>().All();
|
||||
}
|
||||
|
||||
public bool Any<TMessage>() where TMessage : struct, IMessage
|
||||
{
|
||||
return Lookup<TMessage>().Any();
|
||||
}
|
||||
|
||||
public void ProcessDelayedMessages(double dilatedDelta, double realtimeDelta)
|
||||
{
|
||||
foreach (var store in Stores.Values)
|
||||
{
|
||||
store.ProcessDelayedMessages(dilatedDelta, realtimeDelta);
|
||||
}
|
||||
}
|
||||
|
||||
public void ClearAll()
|
||||
{
|
||||
foreach (var store in Stores.Values)
|
||||
{
|
||||
store.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Encompass
|
||||
{
|
||||
internal abstract class TypedComponentStore
|
||||
{
|
||||
public abstract int Count { get; }
|
||||
public abstract IEnumerable<(Entity, Type, IComponent)> AllInterfaceTyped();
|
||||
public abstract bool Has(Entity entity);
|
||||
public abstract void Remove(Entity entity);
|
||||
public abstract void Clear();
|
||||
}
|
||||
|
||||
internal class TypedComponentStore<TComponent> : TypedComponentStore where TComponent : struct, IComponent
|
||||
{
|
||||
private readonly Dictionary<Entity, TComponent> store = new Dictionary<Entity, TComponent>(128);
|
||||
private readonly Dictionary<Entity, int> priorities = new Dictionary<Entity, int>(128);
|
||||
|
||||
public override int Count { get => store.Count; }
|
||||
|
||||
public TComponent Get(Entity entity)
|
||||
{
|
||||
return store[entity];
|
||||
}
|
||||
|
||||
public void Set(Entity entity, TComponent component)
|
||||
{
|
||||
store[entity] = component;
|
||||
}
|
||||
|
||||
public bool Set(Entity entity, TComponent component, int priority)
|
||||
{
|
||||
if (!priorities.ContainsKey(entity) || priority < priorities[entity]) {
|
||||
store[entity] = component;
|
||||
priorities[entity] = priority;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool Has(Entity entity)
|
||||
{
|
||||
return store.ContainsKey(entity);
|
||||
}
|
||||
|
||||
public override void Clear()
|
||||
{
|
||||
store.Clear();
|
||||
priorities.Clear();
|
||||
}
|
||||
|
||||
public IEnumerable<(Entity, TComponent)> All()
|
||||
{
|
||||
return store.Select(kvp => (kvp.Key, kvp.Value));
|
||||
}
|
||||
|
||||
public override IEnumerable<(Entity, Type, IComponent)> AllInterfaceTyped()
|
||||
{
|
||||
return store.Select(kvp => (kvp.Key, typeof(TComponent), (IComponent)kvp.Value));
|
||||
}
|
||||
|
||||
// public override IEnumerable<T> All<T>()
|
||||
// {
|
||||
// return store.Values.Cast<T>();
|
||||
// }
|
||||
|
||||
public override void Remove(Entity entity)
|
||||
{
|
||||
store.Remove(entity);
|
||||
priorities.Remove(entity);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace Encompass
|
||||
{
|
||||
internal abstract class TypedMessageStore
|
||||
{
|
||||
public abstract void ProcessDelayedMessages(double dilatedDelta, double realtimeDelta);
|
||||
public abstract void Clear();
|
||||
}
|
||||
|
||||
internal class TypedMessageStore<TMessage> : TypedMessageStore where TMessage : struct, IMessage
|
||||
{
|
||||
private readonly List<TMessage> store = new List<TMessage>(128);
|
||||
private readonly List<(TMessage, double)> delayedStore = new List<(TMessage, double)>(128);
|
||||
private readonly List<(TMessage, double)> delayedStoreIgnoringTimeDilation = new List<(TMessage, double)>(128);
|
||||
|
||||
public override void ProcessDelayedMessages(double dilatedDelta, double realtimeDelta)
|
||||
{
|
||||
for (int i = delayedStore.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var (message, time) = delayedStore[i];
|
||||
|
||||
var updatedTime = time - dilatedDelta;
|
||||
|
||||
if (updatedTime <= 0)
|
||||
{
|
||||
Add(message);
|
||||
delayedStore.RemoveAt(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
delayedStore[i] = (message, updatedTime);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = delayedStoreIgnoringTimeDilation.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var (message, time) = delayedStoreIgnoringTimeDilation[i];
|
||||
|
||||
var updatedTime = time - realtimeDelta;
|
||||
|
||||
if (updatedTime <= 0)
|
||||
{
|
||||
Add(message);
|
||||
delayedStoreIgnoringTimeDilation.RemoveAt(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
delayedStoreIgnoringTimeDilation[i] = (message, updatedTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Add(TMessage message)
|
||||
{
|
||||
store.Add(message);
|
||||
}
|
||||
|
||||
public void Add(TMessage message, double time)
|
||||
{
|
||||
delayedStore.Add((message, time));
|
||||
}
|
||||
|
||||
public void AddIgnoringTimeDilation(TMessage message, double time)
|
||||
{
|
||||
delayedStoreIgnoringTimeDilation.Add((message, time));
|
||||
}
|
||||
|
||||
public TMessage First()
|
||||
{
|
||||
return store[0];
|
||||
}
|
||||
|
||||
public bool Any()
|
||||
{
|
||||
return store.Count > 0;
|
||||
}
|
||||
|
||||
public IEnumerable<TMessage> All()
|
||||
{
|
||||
return store;
|
||||
}
|
||||
|
||||
public override void Clear()
|
||||
{
|
||||
store.Clear();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,265 +1,87 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Encompass.Exceptions;
|
||||
using Collections.Pooled;
|
||||
|
||||
namespace Encompass
|
||||
{
|
||||
internal class ComponentManager
|
||||
{
|
||||
private readonly DrawLayerManager drawLayerManager;
|
||||
private readonly ComponentUpdateManager componentUpdateManager;
|
||||
|
||||
private readonly Dictionary<Guid, Type> componentIDToType = new Dictionary<Guid, Type>();
|
||||
private readonly Dictionary<Guid, IComponent> IDToComponent = new Dictionary<Guid, IComponent>();
|
||||
private readonly Dictionary<Guid, PooledSet<Guid>> entityIDToComponentIDs = new Dictionary<Guid, PooledSet<Guid>>();
|
||||
private readonly Dictionary<Guid, Guid> componentIDToEntityID = new Dictionary<Guid, Guid>();
|
||||
private readonly ComponentStore componentStore = new ComponentStore();
|
||||
private readonly HashSet<Entity> entitiesMarkedForRemoval = new HashSet<Entity>();
|
||||
|
||||
private readonly Dictionary<Guid, PooledDictionary<Type, Guid>> entityIDToComponentTypeToComponentID = new Dictionary<Guid, PooledDictionary<Type, Guid>>();
|
||||
|
||||
private readonly Dictionary<Type, HashSet<Guid>> typeToComponentIDs = new Dictionary<Type, HashSet<Guid>>();
|
||||
|
||||
private readonly Dictionary<(Entity, Type), (Guid, IComponent)> componentWriteData = new Dictionary<(Entity, Type), (Guid, IComponent)>();
|
||||
private readonly Dictionary<(Entity, Type), int> componentWritePriorities = new Dictionary<(Entity, Type), int>();
|
||||
private readonly HashSet<Guid> componentIDsMarkedForWrite = new HashSet<Guid>();
|
||||
private readonly HashSet<Guid> componentsMarkedForRemoval = new HashSet<Guid>();
|
||||
|
||||
public ComponentManager(DrawLayerManager drawLayerManager)
|
||||
public ComponentManager(DrawLayerManager drawLayerManager, ComponentUpdateManager componentUpdateManager)
|
||||
{
|
||||
this.drawLayerManager = drawLayerManager;
|
||||
this.componentUpdateManager = componentUpdateManager;
|
||||
}
|
||||
|
||||
internal void RegisterEntity(Guid entityID)
|
||||
internal void SetComponentStore(ComponentStore componentStore)
|
||||
{
|
||||
entityIDToComponentIDs.Add(entityID, new PooledSet<Guid>());
|
||||
entityIDToComponentTypeToComponentID.Add(entityID, new PooledDictionary<Type, Guid>());
|
||||
this.componentStore.SwapWith(componentStore);
|
||||
}
|
||||
|
||||
private Guid NextID()
|
||||
internal void RegisterDrawableComponent<TComponent>(Entity entity, TComponent component, int layer) where TComponent : struct, IComponent
|
||||
{
|
||||
return Guid.NewGuid();
|
||||
drawLayerManager.RegisterComponentWithLayer(entity, component, layer);
|
||||
}
|
||||
|
||||
internal Guid MarkComponentForWrite<TComponent>(Entity entity, TComponent component, int priority) where TComponent : struct, IComponent
|
||||
internal void AddComponent<TComponent>(Entity entity, TComponent component) where TComponent : struct, IComponent
|
||||
{
|
||||
Guid id;
|
||||
if (EntityHasComponentOfType<TComponent>(entity))
|
||||
{
|
||||
id = GetComponentByEntityAndType<TComponent>(entity).Item1;
|
||||
}
|
||||
else
|
||||
{
|
||||
id = NextID();
|
||||
}
|
||||
|
||||
if (componentWriteData.ContainsKey((entity, typeof(TComponent))))
|
||||
{
|
||||
var currentPriority = componentWritePriorities[(entity, typeof(TComponent))];
|
||||
if (priority < currentPriority)
|
||||
{
|
||||
componentWriteData[(entity, typeof(TComponent))] = (id, component);
|
||||
componentWritePriorities[(entity, typeof(TComponent))] = priority;
|
||||
componentIDsMarkedForWrite.Add(id);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
componentWriteData.Add((entity, typeof(TComponent)), (id, component));
|
||||
componentWritePriorities[(entity, typeof(TComponent))] = priority;
|
||||
componentIDsMarkedForWrite.Add(id);
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
internal void RegisterDrawableComponent<TComponent>(Guid componentID, TComponent component) where TComponent : IDrawableComponent
|
||||
{
|
||||
drawLayerManager.RegisterComponentWithLayer(componentID, component.Layer);
|
||||
}
|
||||
|
||||
internal void AddComponent(Entity entity, Type type, Guid componentID, IComponent component)
|
||||
{
|
||||
IDToComponent[componentID] = component;
|
||||
componentIDToEntityID[componentID] = entity.ID;
|
||||
componentIDToType[componentID] = type;
|
||||
entityIDToComponentTypeToComponentID[entity.ID][type] = componentID;
|
||||
if (!typeToComponentIDs.ContainsKey(type))
|
||||
{
|
||||
typeToComponentIDs.Add(type, new HashSet<Guid>());
|
||||
}
|
||||
typeToComponentIDs[type].Add(componentID);
|
||||
entityIDToComponentIDs[entity.ID].Add(componentID);
|
||||
}
|
||||
|
||||
internal void UpdateComponent(Guid componentID, IComponent component)
|
||||
{
|
||||
IDToComponent[componentID] = component;
|
||||
componentStore.Set(entity, component);
|
||||
}
|
||||
|
||||
internal void WriteComponents()
|
||||
{
|
||||
foreach (var keyValuePair in componentWriteData)
|
||||
{
|
||||
var (entity, type) = keyValuePair.Key;
|
||||
var (componentID, component) = keyValuePair.Value;
|
||||
|
||||
if (!componentIDsMarkedForWrite.Contains(componentID) || !entityIDToComponentTypeToComponentID.ContainsKey(entity.ID)) { continue; }
|
||||
|
||||
if (entityIDToComponentTypeToComponentID[entity.ID].ContainsKey(type))
|
||||
{
|
||||
UpdateComponent(componentID, component);
|
||||
}
|
||||
else
|
||||
{
|
||||
AddComponent(entity, type, componentID, component);
|
||||
}
|
||||
componentStore.SwapWith(componentUpdateManager.UpToDateComponentStore);
|
||||
}
|
||||
|
||||
componentWriteData.Clear();
|
||||
componentIDsMarkedForWrite.Clear();
|
||||
componentWritePriorities.Clear();
|
||||
internal IEnumerable<(TComponent, Entity)> GetComponentsIncludingEntity<TComponent>() where TComponent : struct, IComponent
|
||||
{
|
||||
return componentStore.All<TComponent>().Select(pair => (pair.Item2, pair.Item1));
|
||||
}
|
||||
|
||||
internal IEnumerable<Guid> GetComponentIDsByEntityID(Guid entityID)
|
||||
internal IEnumerable<TComponent> GetComponentsByType<TComponent>() where TComponent : struct, IComponent
|
||||
{
|
||||
if (entityIDToComponentIDs.TryGetValue(entityID, out PooledSet<Guid> idSet))
|
||||
{
|
||||
return idSet;
|
||||
}
|
||||
return Enumerable.Empty<Guid>();
|
||||
return componentStore.All<TComponent>().Select(pair => pair.Item2);
|
||||
}
|
||||
|
||||
internal IEnumerable<(Guid, TComponent)> GetComponentsByType<TComponent>() where TComponent : struct, IComponent
|
||||
internal TComponent GetComponentByEntityAndType<TComponent>(Entity entity) where TComponent : struct, IComponent
|
||||
{
|
||||
if (typeToComponentIDs.TryGetValue(typeof(TComponent), out HashSet<Guid> idSet))
|
||||
{
|
||||
return idSet.Select(id => (id, (TComponent)IDToComponent[id]));
|
||||
}
|
||||
return Enumerable.Empty<(Guid, TComponent)>();
|
||||
}
|
||||
|
||||
internal (Guid, TComponent) GetComponentByEntityAndType<TComponent>(Entity entity) where TComponent : struct, IComponent
|
||||
{
|
||||
if (entityIDToComponentTypeToComponentID.ContainsKey(entity.ID) && entityIDToComponentTypeToComponentID[entity.ID].TryGetValue(typeof(TComponent), out Guid id))
|
||||
{
|
||||
return (id, (TComponent)IDToComponent[id]);
|
||||
}
|
||||
|
||||
throw new NoComponentOfTypeOnEntityException("No Component of type {0} exists on Entity {1}", typeof(TComponent).Name, entity.ID);
|
||||
return componentStore.Get<TComponent>(entity);
|
||||
}
|
||||
|
||||
internal bool EntityHasComponentOfType<TComponent>(Entity entity) where TComponent : struct, IComponent
|
||||
{
|
||||
return (entityIDToComponentTypeToComponentID.ContainsKey(entity.ID) && entityIDToComponentTypeToComponentID[entity.ID].ContainsKey(typeof(TComponent)));
|
||||
return componentStore.Has<TComponent>(entity);
|
||||
}
|
||||
|
||||
internal bool ComponentOfTypeExists<TComponent>() where TComponent : struct, IComponent
|
||||
{
|
||||
if (typeToComponentIDs.TryGetValue(typeof(TComponent), out HashSet<Guid> idSet))
|
||||
{
|
||||
return idSet.Count > 0;
|
||||
return componentStore.Any<TComponent>();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
internal IComponent GetComponentByID(Guid componentID)
|
||||
internal void MarkAllComponentsOnEntityForRemoval(Entity entity)
|
||||
{
|
||||
if (IDToComponent.ContainsKey(componentID))
|
||||
{
|
||||
return IDToComponent[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);
|
||||
}
|
||||
}
|
||||
|
||||
internal void MarkAllComponentsOnEntityForRemoval(Guid entityID)
|
||||
{
|
||||
foreach (var componentID in GetComponentIDsByEntityID(entityID))
|
||||
{
|
||||
MarkForRemoval(componentID);
|
||||
}
|
||||
}
|
||||
|
||||
internal void MarkForRemoval(Guid componentID)
|
||||
{
|
||||
componentsMarkedForRemoval.Add(componentID);
|
||||
entitiesMarkedForRemoval.Add(entity);
|
||||
}
|
||||
|
||||
internal void RemoveMarkedComponents()
|
||||
{
|
||||
foreach (var componentID in componentsMarkedForRemoval)
|
||||
foreach (var entity in entitiesMarkedForRemoval)
|
||||
{
|
||||
if (componentIDsMarkedForWrite.Contains(componentID))
|
||||
{
|
||||
componentIDsMarkedForWrite.Remove(componentID);
|
||||
componentStore.Remove(entity);
|
||||
drawLayerManager.UnRegisterEntityWithLayer(entity);
|
||||
}
|
||||
|
||||
if (IDToComponent.ContainsKey(componentID))
|
||||
entitiesMarkedForRemoval.Clear();
|
||||
}
|
||||
|
||||
public void Remove<TComponent>(Entity entity) where TComponent : struct, IComponent
|
||||
{
|
||||
Remove(componentID);
|
||||
}
|
||||
}
|
||||
|
||||
componentsMarkedForRemoval.Clear();
|
||||
}
|
||||
|
||||
private void Remove(Guid componentID)
|
||||
{
|
||||
var type = componentIDToType[componentID];
|
||||
|
||||
var entityID = componentIDToEntityID[componentID];
|
||||
if (entityIDToComponentIDs.ContainsKey(entityID))
|
||||
{
|
||||
entityIDToComponentIDs[entityID].Remove(componentID);
|
||||
}
|
||||
|
||||
if (entityIDToComponentTypeToComponentID.ContainsKey(entityID))
|
||||
{
|
||||
entityIDToComponentTypeToComponentID[entityID].Remove(type);
|
||||
}
|
||||
|
||||
IDToComponent.Remove(componentID);
|
||||
componentIDToType.Remove(componentID);
|
||||
componentIDToEntityID.Remove(componentID);
|
||||
typeToComponentIDs[type].Remove(componentID);
|
||||
|
||||
drawLayerManager.UnRegisterComponentWithLayer(componentID);
|
||||
}
|
||||
|
||||
public void RegisterDestroyedEntity(Guid entityID)
|
||||
{
|
||||
entityIDToComponentIDs[entityID].Dispose();
|
||||
entityIDToComponentIDs.Remove(entityID);
|
||||
|
||||
entityIDToComponentTypeToComponentID[entityID].Dispose();
|
||||
entityIDToComponentTypeToComponentID.Remove(entityID);
|
||||
componentUpdateManager.Remove<TComponent>(entity);
|
||||
drawLayerManager.UnRegisterComponentWithLayer<TComponent>(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,356 +0,0 @@
|
|||
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
|
||||
{
|
||||
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 (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, IComponent) ReadExistingComponentByEntityAndType(Entity entity, Type type)
|
||||
{
|
||||
if (entityToTypeToExistingComponentID.ContainsKey(entity) && entityToTypeToExistingComponentID[entity].TryGetValue(type, out Guid id))
|
||||
{
|
||||
return (id, componentIDToComponent[id]);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NoComponentOfTypeOnEntityException("No Component of type {0} exists on Entity {1}", type.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);
|
||||
}
|
||||
}
|
||||
|
||||
internal (Guid, IComponent) ReadPendingComponentByEntityAndType(Entity entity, Type type)
|
||||
{
|
||||
if (entityToTypeToPendingComponentID.ContainsKey(entity) && entityToTypeToPendingComponentID[entity].TryGetValue(type, out Guid id))
|
||||
{
|
||||
return (id, componentIDToComponent[id]);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NoComponentOfTypeOnEntityException("No Component of type {0} exists on Entity {1}", type.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 HasExistingOrPendingComponent(Entity entity, Type type)
|
||||
{
|
||||
return entityToTypeToComponentID.ContainsKey(entity) && entityToTypeToComponentID[entity].ContainsKey(type);
|
||||
}
|
||||
|
||||
internal bool HasExistingComponent<TComponent>(Entity entity) where TComponent : struct, IComponent
|
||||
{
|
||||
return entityToTypeToExistingComponentID.ContainsKey(entity) && entityToTypeToExistingComponentID[entity].ContainsKey(typeof(TComponent));
|
||||
}
|
||||
|
||||
internal bool HasExistingComponent(Entity entity, Type type)
|
||||
{
|
||||
return entityToTypeToExistingComponentID.ContainsKey(entity) && entityToTypeToExistingComponentID[entity].ContainsKey(type);
|
||||
}
|
||||
|
||||
internal bool HasPendingComponent<TComponent>(Entity entity) where TComponent : struct, IComponent
|
||||
{
|
||||
return entityToTypeToPendingComponentID.ContainsKey(entity) && entityToTypeToPendingComponentID[entity].ContainsKey(typeof(TComponent));
|
||||
}
|
||||
|
||||
internal bool HasPendingComponent(Entity entity, Type type)
|
||||
{
|
||||
return entityToTypeToPendingComponentID.ContainsKey(entity) && entityToTypeToPendingComponentID[entity].ContainsKey(type);
|
||||
}
|
||||
|
||||
internal IComponent GetComponentByID(Guid componentID)
|
||||
{
|
||||
if (componentIDToComponent.ContainsKey(componentID))
|
||||
{
|
||||
return componentIDToComponent[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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,166 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Encompass
|
||||
{
|
||||
internal class ComponentUpdateManager
|
||||
{
|
||||
private readonly ComponentStore existingAndPendingComponentStore = new ComponentStore();
|
||||
private readonly ComponentStore existingComponentStore = new ComponentStore();
|
||||
private readonly ComponentStore pendingComponentStore = new ComponentStore();
|
||||
private readonly Dictionary<Type, Dictionary<Entity, int>> typeToEntityToPendingComponentPriority = new Dictionary<Type, Dictionary<Entity, int>>(128);
|
||||
|
||||
public ComponentStore UpToDateComponentStore { get; private set; } = new ComponentStore();
|
||||
|
||||
internal void Clear()
|
||||
{
|
||||
existingAndPendingComponentStore.ClearAll();
|
||||
existingComponentStore.ClearAll();
|
||||
pendingComponentStore.ClearAll();
|
||||
UpToDateComponentStore.ClearAll();
|
||||
|
||||
foreach (var dictionary in typeToEntityToPendingComponentPriority.Values)
|
||||
{
|
||||
dictionary.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
internal void SetStartingComponentStore(ComponentStore componentStore)
|
||||
{
|
||||
UpToDateComponentStore = componentStore;
|
||||
}
|
||||
|
||||
internal void AddExistingComponent<TComponent>(Entity entity, TComponent component) where TComponent : struct, IComponent
|
||||
{
|
||||
RegisterExistingOrPendingComponentMessage(entity, component);
|
||||
|
||||
existingComponentStore.Set(entity, component);
|
||||
}
|
||||
|
||||
internal bool AddPendingComponent<TComponent>(Entity entity, TComponent component, int priority) where TComponent : struct, IComponent
|
||||
{
|
||||
if (pendingComponentStore.Set(entity, component, priority))
|
||||
{
|
||||
RegisterExistingOrPendingComponentMessage(entity, component);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void RegisterExistingOrPendingComponentMessage<TComponent>(Entity entity, TComponent component) where TComponent : struct, IComponent
|
||||
{
|
||||
existingAndPendingComponentStore.Set(entity, component);
|
||||
UpToDateComponentStore.Set(entity, component);
|
||||
}
|
||||
|
||||
public bool UpdateComponent<TComponent>(Entity entity, TComponent component, int priority) where TComponent : struct, IComponent
|
||||
{
|
||||
return UpToDateComponentStore.Set<TComponent>(entity, component, priority);
|
||||
}
|
||||
|
||||
// general component reads by type
|
||||
|
||||
internal IEnumerable<(Entity, TComponent)> ReadExistingAndPendingComponentsByType<TComponent>() where TComponent : struct, IComponent
|
||||
{
|
||||
return existingAndPendingComponentStore.All<TComponent>();
|
||||
}
|
||||
|
||||
internal IEnumerable<(Entity, TComponent)> ReadExistingComponentsByType<TComponent>() where TComponent : struct, IComponent
|
||||
{
|
||||
return existingComponentStore.All<TComponent>();
|
||||
}
|
||||
|
||||
internal IEnumerable<(Entity, TComponent)> ReadPendingComponentsByType<TComponent>() where TComponent : struct, IComponent
|
||||
{
|
||||
return pendingComponentStore.All<TComponent>();
|
||||
}
|
||||
|
||||
// singular component reads by type
|
||||
|
||||
internal (Entity, 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 (Entity, 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 (Entity, TComponent) ReadFirstPendingComponentByType<TComponent>() where TComponent : struct, IComponent
|
||||
{
|
||||
if (!SomePendingComponent<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
|
||||
{
|
||||
return existingAndPendingComponentStore.Any<TComponent>();
|
||||
}
|
||||
|
||||
internal bool SomeExistingComponent<TComponent>() where TComponent : struct, IComponent
|
||||
{
|
||||
return existingComponentStore.Any<TComponent>();
|
||||
}
|
||||
|
||||
internal bool SomePendingComponent<TComponent>() where TComponent : struct, IComponent
|
||||
{
|
||||
return pendingComponentStore.Any<TComponent>();
|
||||
}
|
||||
|
||||
// read components by entity and type
|
||||
|
||||
internal TComponent ReadExistingComponentByEntityAndType<TComponent>(Entity entity) where TComponent : struct, IComponent
|
||||
{
|
||||
return existingComponentStore.Get<TComponent>(entity);
|
||||
}
|
||||
|
||||
internal TComponent ReadPendingComponentByEntityAndType<TComponent>(Entity entity) where TComponent : struct, IComponent
|
||||
{
|
||||
return pendingComponentStore.Get<TComponent>(entity);
|
||||
}
|
||||
|
||||
// check if entity has component of type
|
||||
|
||||
internal bool HasExistingOrPendingComponent<TComponent>(Entity entity) where TComponent : struct, IComponent
|
||||
{
|
||||
return existingAndPendingComponentStore.Has<TComponent>(entity);
|
||||
}
|
||||
|
||||
internal bool HasExistingOrPendingComponent(Entity entity, Type type)
|
||||
{
|
||||
return existingAndPendingComponentStore.Has(type, entity);
|
||||
}
|
||||
|
||||
internal bool HasExistingComponent<TComponent>(Entity entity) where TComponent : struct, IComponent
|
||||
{
|
||||
return existingComponentStore.Has<TComponent>(entity);
|
||||
}
|
||||
|
||||
internal bool HasExistingComponent(Entity entity, Type type)
|
||||
{
|
||||
return existingComponentStore.Has(type, entity);
|
||||
}
|
||||
|
||||
internal bool HasPendingComponent<TComponent>(Entity entity) where TComponent : struct, IComponent
|
||||
{
|
||||
return pendingComponentStore.Has<TComponent>(entity);
|
||||
}
|
||||
|
||||
internal bool HasPendingComponent(Entity entity, Type type)
|
||||
{
|
||||
return pendingComponentStore.Has(type, entity);
|
||||
}
|
||||
|
||||
internal void Remove<TComponent>(Entity entity) where TComponent : struct, IComponent
|
||||
{
|
||||
UpToDateComponentStore.Remove<TComponent>(entity);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,10 +8,10 @@ namespace Encompass
|
|||
{
|
||||
private readonly SortedList<int, int> layerOrder = new SortedList<int, int>();
|
||||
|
||||
private readonly Dictionary<int, HashSet<Guid>> layerIndexToComponentIDs = new Dictionary<int, HashSet<Guid>>();
|
||||
private readonly Dictionary<int, HashSet<GeneralRenderer>> layerIndexToGeneralRenderers = new Dictionary<int, HashSet<GeneralRenderer>>();
|
||||
private readonly Dictionary<int, ComponentStore> layerIndexToComponentStore = new Dictionary<int, ComponentStore>(512);
|
||||
private readonly Dictionary<int, HashSet<GeneralRenderer>> layerIndexToGeneralRenderers = new Dictionary<int, HashSet<GeneralRenderer>>(512);
|
||||
|
||||
private readonly Dictionary<Guid, int> componentIDToLayerIndex = new Dictionary<Guid, int>();
|
||||
private readonly Dictionary<Type, Dictionary<Entity, int>> typeToEntityToLayer = new Dictionary<Type, Dictionary<Entity, int>>(512);
|
||||
|
||||
public IEnumerable<int> LayerOrder { get { return layerOrder.Values; } }
|
||||
|
||||
|
@ -49,23 +49,28 @@ namespace Encompass
|
|||
RegisterGeneralRendererWithLayer(renderer, newLayer);
|
||||
}
|
||||
|
||||
public void RegisterComponentWithLayer(Guid id, int layer)
|
||||
public void RegisterComponentWithLayer<TComponent>(Entity entity, TComponent component, int layer) where TComponent : struct, IComponent
|
||||
{
|
||||
if (componentIDToLayerIndex.ContainsKey(id)) { UnRegisterComponentWithLayer(id); }
|
||||
if (!typeToEntityToLayer.ContainsKey(typeof(TComponent)))
|
||||
{
|
||||
typeToEntityToLayer.Add(typeof(TComponent), new Dictionary<Entity, int>());
|
||||
}
|
||||
|
||||
if (layerIndexToComponentIDs.ContainsKey(layer))
|
||||
if (typeToEntityToLayer[typeof(TComponent)].ContainsKey(entity)) { UnRegisterComponentWithLayer<TComponent>(entity); }
|
||||
|
||||
if (layerIndexToComponentStore.ContainsKey(layer))
|
||||
{
|
||||
var set = layerIndexToComponentIDs[layer];
|
||||
set.Add(id);
|
||||
var set = layerIndexToComponentStore[layer];
|
||||
set.Set<TComponent>(entity, component);
|
||||
}
|
||||
else
|
||||
{
|
||||
var set = new HashSet<Guid>();
|
||||
layerIndexToComponentIDs.Add(layer, set);
|
||||
set.Add(id);
|
||||
var set = new ComponentStore();
|
||||
layerIndexToComponentStore.Add(layer, set);
|
||||
set.Set<TComponent>(entity, component);
|
||||
}
|
||||
|
||||
componentIDToLayerIndex[id] = layer;
|
||||
typeToEntityToLayer[typeof(TComponent)].Add(entity, layer);
|
||||
|
||||
if (!layerOrder.ContainsKey(layer))
|
||||
{
|
||||
|
@ -73,21 +78,24 @@ namespace Encompass
|
|||
}
|
||||
}
|
||||
|
||||
public void UnRegisterComponentWithLayer(Guid id)
|
||||
public void UnRegisterComponentWithLayer<TComponent>(Entity entity) where TComponent : struct, IComponent
|
||||
{
|
||||
if (componentIDToLayerIndex.ContainsKey(id))
|
||||
if (!typeToEntityToLayer.ContainsKey(typeof(TComponent))) { return; }
|
||||
|
||||
if (typeToEntityToLayer[typeof(TComponent)].ContainsKey(entity))
|
||||
{
|
||||
var layer = componentIDToLayerIndex[id];
|
||||
layerIndexToComponentIDs[layer].Remove(id);
|
||||
var layer = typeToEntityToLayer[typeof(TComponent)][entity];
|
||||
layerIndexToComponentStore[layer].Remove<TComponent>(entity);
|
||||
}
|
||||
componentIDToLayerIndex.Remove(id);
|
||||
typeToEntityToLayer[typeof(TComponent)].Remove(entity);
|
||||
}
|
||||
|
||||
public IEnumerable<Guid> ComponentIDsByLayer(int layer)
|
||||
public void UnRegisterEntityWithLayer(Entity entity)
|
||||
{
|
||||
return layerIndexToComponentIDs.ContainsKey(layer) ?
|
||||
layerIndexToComponentIDs[layer] :
|
||||
Enumerable.Empty<Guid>();
|
||||
foreach (var store in layerIndexToComponentStore.Values)
|
||||
{
|
||||
store.Remove(entity);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<GeneralRenderer> GeneralRenderersByLayer(int layer)
|
||||
|
@ -96,5 +104,12 @@ namespace Encompass
|
|||
layerIndexToGeneralRenderers[layer] :
|
||||
Enumerable.Empty<GeneralRenderer>();
|
||||
}
|
||||
|
||||
public IEnumerable<(Entity, Type, IComponent)> AllInLayer(int layer)
|
||||
{
|
||||
return layerIndexToComponentStore.ContainsKey(layer) ?
|
||||
layerIndexToComponentStore[layer].AllInterfaceTyped() :
|
||||
Enumerable.Empty<(Entity, Type, IComponent)>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,23 +15,25 @@ namespace Encompass
|
|||
{
|
||||
internal Guid ID;
|
||||
|
||||
internal readonly HashSet<Type> readTypes = new HashSet<Type>();
|
||||
internal readonly HashSet<Type> readPendingTypes = new HashSet<Type>();
|
||||
internal readonly HashSet<Type> sendTypes = new HashSet<Type>();
|
||||
internal readonly HashSet<Type> receiveTypes = new HashSet<Type>();
|
||||
internal readonly HashSet<Type> writeTypes = new HashSet<Type>();
|
||||
internal readonly HashSet<Type> writePendingTypes = new HashSet<Type>();
|
||||
internal readonly Dictionary<Type, int> writePriorities = new Dictionary<Type, int>();
|
||||
internal readonly int defaultWritePriority = 0;
|
||||
|
||||
/// <summary>
|
||||
/// If false, the Engine will ignore time dilation.
|
||||
/// </summary>
|
||||
internal bool usesTimeDilation = true;
|
||||
public bool TimeDilationActive { get => usesTimeDilation && timeManager.TimeDilationActive; }
|
||||
/// <summary>
|
||||
/// Used when activating time dilation. Lower priority overrides higher priority.
|
||||
/// </summary>
|
||||
|
||||
private EntityManager entityManager;
|
||||
private MessageManager messageManager;
|
||||
private ComponentManager componentManager;
|
||||
private ComponentMessageManager componentMessageManager;
|
||||
private ComponentUpdateManager componentUpdateManager;
|
||||
private TimeManager timeManager;
|
||||
|
||||
protected Engine()
|
||||
|
@ -47,13 +49,19 @@ namespace Encompass
|
|||
var activatesAttribute = GetType().GetCustomAttribute<WritesPending>(false);
|
||||
if (activatesAttribute != null)
|
||||
{
|
||||
sendTypes.UnionWith(activatesAttribute.writePendingTypes);
|
||||
writePendingTypes = activatesAttribute.writePendingTypes;
|
||||
}
|
||||
|
||||
var writesAttributes = GetType().GetCustomAttributes<Writes>(false);
|
||||
foreach (var writesAttribute in writesAttributes)
|
||||
var defaultWritePriorityAttribute = GetType().GetCustomAttribute<DefaultWritePriority>(false);
|
||||
|
||||
if (defaultWritePriorityAttribute != null)
|
||||
{
|
||||
sendTypes.UnionWith(writesAttribute.writeTypes);
|
||||
defaultWritePriority = defaultWritePriorityAttribute.writePriority;
|
||||
}
|
||||
|
||||
foreach (var writesAttribute in GetType().GetCustomAttributes<Writes>(false))
|
||||
{
|
||||
writeTypes.UnionWith(writesAttribute.writeTypes);
|
||||
writePriorities = new Dictionary<Type, int>[2] { writePriorities, writesAttribute.priorities }.SelectMany(dict => dict).ToDictionary(pair => pair.Key, pair => pair.Value);
|
||||
}
|
||||
|
||||
|
@ -66,21 +74,21 @@ namespace Encompass
|
|||
var readsAttribute = GetType().GetCustomAttribute<Reads>(false);
|
||||
if (readsAttribute != null)
|
||||
{
|
||||
receiveTypes.UnionWith(readsAttribute.readTypes);
|
||||
readTypes = readsAttribute.readTypes;
|
||||
}
|
||||
|
||||
var readsPendingAttribute = GetType().GetCustomAttribute<ReadsPending>(false);
|
||||
if (readsPendingAttribute != null)
|
||||
{
|
||||
receiveTypes.UnionWith(readsPendingAttribute.readPendingTypes);
|
||||
readPendingTypes = readsPendingAttribute.readPendingTypes;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj is Engine)
|
||||
if (obj is Engine engine)
|
||||
{
|
||||
return this.Equals((Engine)obj);
|
||||
return Equals(engine);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -111,9 +119,9 @@ namespace Encompass
|
|||
this.messageManager = messageManager;
|
||||
}
|
||||
|
||||
internal void AssignComponentMessageManager(ComponentMessageManager componentMessageManager)
|
||||
internal void AssignComponentUpdateManager(ComponentUpdateManager componentUpdateManager)
|
||||
{
|
||||
this.componentMessageManager = componentMessageManager;
|
||||
this.componentUpdateManager = componentUpdateManager;
|
||||
}
|
||||
|
||||
internal void AssignTimeManager(TimeManager timeManager)
|
||||
|
@ -154,37 +162,12 @@ namespace Encompass
|
|||
return entityManager.GetEntity(entityID);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the Entity ID associated with the specified Component Type and ID.
|
||||
/// </summary>
|
||||
private Guid GetEntityIDByComponentID<TComponent>(Guid componentID) where TComponent : struct, IComponent
|
||||
{
|
||||
var pendingRead = receiveTypes.Contains(typeof(PendingComponentMessage<TComponent>));
|
||||
var existingRead = receiveTypes.Contains(typeof(ComponentMessage<TComponent>));
|
||||
|
||||
if (!pendingRead && !existingRead)
|
||||
{
|
||||
throw new IllegalReadException("Engine {0} tried to read undeclared Component {1}", GetType().Name, typeof(TComponent).Name);
|
||||
}
|
||||
|
||||
return componentMessageManager.GetEntityIDByComponentID(componentID);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the Entity associated with the specified Component Type and ID.
|
||||
/// </summary>
|
||||
private Entity GetEntityByComponentID<TComponent>(Guid componentID) where TComponent : struct, IComponent
|
||||
{
|
||||
return GetEntity(GetEntityIDByComponentID<TComponent>(componentID));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an Entity containing the specified Component type.
|
||||
/// </summary>
|
||||
protected Entity ReadEntity<TComponent>() where TComponent : struct, IComponent
|
||||
{
|
||||
var (id, component) = ReadComponentHelper<TComponent>();
|
||||
return GetEntityByComponentID<TComponent>(id);
|
||||
return ReadComponentHelper<TComponent>().Item1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -192,60 +175,31 @@ namespace Encompass
|
|||
/// </summary>
|
||||
protected IEnumerable<Entity> ReadEntities<TComponent>() where TComponent : struct, IComponent
|
||||
{
|
||||
foreach (var (id, _) in ReadComponentsHelper<TComponent>())
|
||||
{
|
||||
yield return GetEntityByComponentID<TComponent>(id);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the Component struct with the specified Component Type and ID.
|
||||
/// </summary>
|
||||
internal TComponent GetComponentByID<TComponent>(Guid componentID) where TComponent : struct, IComponent
|
||||
{
|
||||
var pendingRead = receiveTypes.Contains(typeof(PendingComponentMessage<TComponent>));
|
||||
var existingRead = receiveTypes.Contains(typeof(ComponentMessage<TComponent>));
|
||||
|
||||
if (!pendingRead && !existingRead)
|
||||
{
|
||||
throw new IllegalReadException("Engine {0} tried to read undeclared Component {1}", GetType().Name, typeof(TComponent).Name);
|
||||
}
|
||||
|
||||
if (componentMessageManager.GetComponentTypeByID(componentID) != typeof(TComponent))
|
||||
{
|
||||
throw new ComponentTypeMismatchException("Expected Component to be of type {0} but was actually of type {1}", typeof(TComponent).Name, componentMessageManager.GetComponentTypeByID(componentID).Name);
|
||||
}
|
||||
|
||||
return (TComponent)componentMessageManager.GetComponentByID(componentID);
|
||||
return ReadComponentsHelper<TComponent>().Select(pair => pair.Item1);
|
||||
}
|
||||
|
||||
// these next two are for the ComponentMessageEmitter only
|
||||
|
||||
internal IEnumerable<(Guid, TComponent)> ReadComponentsFromWorld<TComponent>() where TComponent : struct, IComponent
|
||||
internal IEnumerable<TComponent> ReadComponentsFromWorld<TComponent>() where TComponent : struct, IComponent
|
||||
{
|
||||
return componentManager.GetComponentsByType<TComponent>();
|
||||
}
|
||||
|
||||
internal Entity ReadEntityFromWorld(Guid componentID)
|
||||
private IEnumerable<(Entity, TComponent)> ReadComponentsHelper<TComponent>() where TComponent : struct, IComponent
|
||||
{
|
||||
return GetEntity(componentManager.GetEntityIDByComponentID(componentID));
|
||||
}
|
||||
|
||||
private IEnumerable<(Guid, TComponent)> ReadComponentsHelper<TComponent>() where TComponent : struct, IComponent
|
||||
{
|
||||
var pendingRead = receiveTypes.Contains(typeof(PendingComponentMessage<TComponent>));
|
||||
var existingRead = receiveTypes.Contains(typeof(ComponentMessage<TComponent>));
|
||||
var pendingRead = readPendingTypes.Contains(typeof(TComponent));
|
||||
var existingRead = readTypes.Contains(typeof(TComponent));
|
||||
if (existingRead && pendingRead)
|
||||
{
|
||||
return componentMessageManager.ReadExistingAndPendingComponentsByType<TComponent>();
|
||||
return componentUpdateManager.ReadExistingAndPendingComponentsByType<TComponent>();
|
||||
}
|
||||
else if (existingRead)
|
||||
{
|
||||
return componentMessageManager.ReadExistingComponentsByType<TComponent>();
|
||||
return componentUpdateManager.ReadExistingComponentsByType<TComponent>();
|
||||
}
|
||||
else if (pendingRead)
|
||||
{
|
||||
return componentMessageManager.ReadPendingComponentsByType<TComponent>();
|
||||
return componentUpdateManager.ReadPendingComponentsByType<TComponent>();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -266,24 +220,29 @@ namespace Encompass
|
|||
/// </summary>
|
||||
protected IEnumerable<(TComponent, Entity)> ReadComponentsIncludingEntity<TComponent>() where TComponent : struct, IComponent
|
||||
{
|
||||
return ReadComponentsHelper<TComponent>().Select((tuple) => (tuple.Item2, GetEntityByComponentID<TComponent>(tuple.Item1)));
|
||||
return ReadComponentsHelper<TComponent>().Select((tuple) => (tuple.Item2, tuple.Item1));
|
||||
}
|
||||
|
||||
private (Guid, TComponent) ReadComponentHelper<TComponent>() where TComponent : struct, IComponent
|
||||
internal IEnumerable<(TComponent, Entity)> InternalRead<TComponent>() where TComponent : struct, IComponent
|
||||
{
|
||||
var pendingRead = receiveTypes.Contains(typeof(PendingComponentMessage<TComponent>));
|
||||
var existingRead = receiveTypes.Contains(typeof(ComponentMessage<TComponent>));
|
||||
return componentManager.GetComponentsIncludingEntity<TComponent>();
|
||||
}
|
||||
|
||||
private (Entity, TComponent) ReadComponentHelper<TComponent>() where TComponent : struct, IComponent
|
||||
{
|
||||
var pendingRead = readPendingTypes.Contains(typeof(TComponent));
|
||||
var existingRead = readTypes.Contains(typeof(TComponent));
|
||||
if (existingRead && pendingRead)
|
||||
{
|
||||
return componentMessageManager.ReadFirstExistingOrPendingComponentByType<TComponent>();
|
||||
return componentUpdateManager.ReadFirstExistingOrPendingComponentByType<TComponent>();
|
||||
}
|
||||
else if (existingRead)
|
||||
{
|
||||
return componentMessageManager.ReadFirstExistingComponentByType<TComponent>();
|
||||
return componentUpdateManager.ReadFirstExistingComponentByType<TComponent>();
|
||||
}
|
||||
else if (pendingRead)
|
||||
{
|
||||
return componentMessageManager.ReadFirstPendingComponentByType<TComponent>();
|
||||
return componentUpdateManager.ReadFirstPendingComponentByType<TComponent>();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -304,8 +263,8 @@ namespace Encompass
|
|||
/// </summary>
|
||||
protected (TComponent, Entity) ReadComponentIncludingEntity<TComponent>() where TComponent : struct, IComponent
|
||||
{
|
||||
var (id, component) = ReadComponentHelper<TComponent>();
|
||||
return (component, GetEntityByComponentID<TComponent>(id));
|
||||
var (entity, component) = ReadComponentHelper<TComponent>();
|
||||
return (component, entity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -313,19 +272,19 @@ namespace Encompass
|
|||
/// </summary>
|
||||
protected bool SomeComponent<TComponent>() where TComponent : struct, IComponent
|
||||
{
|
||||
var pendingRead = receiveTypes.Contains(typeof(PendingComponentMessage<TComponent>));
|
||||
var existingRead = receiveTypes.Contains(typeof(ComponentMessage<TComponent>));
|
||||
var pendingRead = readPendingTypes.Contains(typeof(TComponent));
|
||||
var existingRead = readTypes.Contains(typeof(TComponent));
|
||||
if (existingRead && pendingRead)
|
||||
{
|
||||
return componentMessageManager.SomeExistingOrPendingComponent<TComponent>();
|
||||
return componentUpdateManager.SomeExistingOrPendingComponent<TComponent>();
|
||||
}
|
||||
else if (existingRead)
|
||||
{
|
||||
return componentMessageManager.SomeExistingComponent<TComponent>();
|
||||
return componentUpdateManager.SomeExistingComponent<TComponent>();
|
||||
}
|
||||
else if (pendingRead)
|
||||
{
|
||||
return componentMessageManager.SomePendingComponent<TComponent>();
|
||||
return componentUpdateManager.SomePendingComponent<TComponent>();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -333,19 +292,19 @@ namespace Encompass
|
|||
}
|
||||
}
|
||||
|
||||
private (Guid, TComponent) GetComponentHelper<TComponent>(Entity entity) where TComponent : struct, IComponent
|
||||
private TComponent GetComponentHelper<TComponent>(Entity entity) where TComponent : struct, IComponent
|
||||
{
|
||||
var pendingRead = receiveTypes.Contains(typeof(PendingComponentMessage<TComponent>));
|
||||
var existingRead = receiveTypes.Contains(typeof(ComponentMessage<TComponent>));
|
||||
var pendingRead = readPendingTypes.Contains(typeof(TComponent));
|
||||
var existingRead = readTypes.Contains(typeof(TComponent));
|
||||
if (existingRead && pendingRead)
|
||||
{
|
||||
if (componentMessageManager.HasPendingComponent<TComponent>(entity))
|
||||
if (componentUpdateManager.HasPendingComponent<TComponent>(entity))
|
||||
{
|
||||
return componentMessageManager.ReadPendingComponentByEntityAndType<TComponent>(entity);
|
||||
return componentUpdateManager.ReadPendingComponentByEntityAndType<TComponent>(entity);
|
||||
}
|
||||
else if (componentMessageManager.HasExistingComponent<TComponent>(entity))
|
||||
else if (componentUpdateManager.HasExistingComponent<TComponent>(entity))
|
||||
{
|
||||
return componentMessageManager.ReadExistingComponentByEntityAndType<TComponent>(entity);
|
||||
return componentUpdateManager.ReadExistingComponentByEntityAndType<TComponent>(entity);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -354,11 +313,11 @@ namespace Encompass
|
|||
}
|
||||
else if (existingRead)
|
||||
{
|
||||
return componentMessageManager.ReadExistingComponentByEntityAndType<TComponent>(entity);
|
||||
return componentUpdateManager.ReadExistingComponentByEntityAndType<TComponent>(entity);
|
||||
}
|
||||
else if (pendingRead)
|
||||
{
|
||||
return componentMessageManager.ReadPendingComponentByEntityAndType<TComponent>(entity);
|
||||
return componentUpdateManager.ReadPendingComponentByEntityAndType<TComponent>(entity);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -377,58 +336,7 @@ namespace Encompass
|
|||
/// </exception>
|
||||
protected TComponent GetComponent<TComponent>(Entity entity) where TComponent : struct, IComponent
|
||||
{
|
||||
return GetComponentHelper<TComponent>(entity).Item2;
|
||||
}
|
||||
|
||||
private (Guid, IComponent) GetComponentHelper(Entity entity, Type type)
|
||||
{
|
||||
var pending = typeof(PendingComponentMessage<>).MakeGenericType(type);
|
||||
var existing = typeof(ComponentMessage<>).MakeGenericType(type);
|
||||
|
||||
var pendingRead = receiveTypes.Contains(pending);
|
||||
var existingRead = receiveTypes.Contains(existing);
|
||||
|
||||
if (existingRead && pendingRead)
|
||||
{
|
||||
if (componentMessageManager.HasPendingComponent(entity, pending))
|
||||
{
|
||||
return componentMessageManager.ReadPendingComponentByEntityAndType(entity, pending);
|
||||
}
|
||||
else if (componentMessageManager.HasExistingComponent(entity, existing))
|
||||
{
|
||||
return componentMessageManager.ReadExistingComponentByEntityAndType(entity, existing);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NoComponentOfTypeOnEntityException("No Component of type {0} exists on Entity {1}", type.Name, entity.ID);
|
||||
}
|
||||
}
|
||||
else if (existingRead)
|
||||
{
|
||||
return componentMessageManager.ReadExistingComponentByEntityAndType(entity, existing);
|
||||
}
|
||||
else if (pendingRead)
|
||||
{
|
||||
return componentMessageManager.ReadPendingComponentByEntityAndType(entity, pending);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IllegalReadException("Engine {0} tried to read undeclared Component {1}", GetType().Name, type.Name);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a Component with the specified Type that exists on the Entity.
|
||||
/// </summary>
|
||||
/// <exception cref="Encompass.Exceptions.NoComponentOfTypeOnEntityException">
|
||||
/// Thrown when the Entity does not have a Component of the specified Type
|
||||
/// </exception>
|
||||
/// <exception cref="Encompass.Exceptions.IllegalReadException">
|
||||
/// Thrown when the Engine does not declare that it reads the given Component Type.
|
||||
/// </exception>
|
||||
protected IComponent GetComponent(Entity entity, Type type)
|
||||
{
|
||||
return GetComponentHelper(entity, type).Item2;
|
||||
return GetComponentHelper<TComponent>(entity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -439,20 +347,20 @@ namespace Encompass
|
|||
/// </exception>
|
||||
protected bool HasComponent<TComponent>(Entity entity) where TComponent : struct, IComponent
|
||||
{
|
||||
var pendingRead = receiveTypes.Contains(typeof(PendingComponentMessage<TComponent>));
|
||||
var existingRead = receiveTypes.Contains(typeof(ComponentMessage<TComponent>));
|
||||
var pendingRead = readPendingTypes.Contains(typeof(TComponent));
|
||||
var existingRead = readTypes.Contains(typeof(TComponent));
|
||||
|
||||
if (pendingRead && existingRead)
|
||||
{
|
||||
return componentMessageManager.HasExistingOrPendingComponent<TComponent>(entity);
|
||||
return componentUpdateManager.HasExistingOrPendingComponent<TComponent>(entity);
|
||||
}
|
||||
else if (existingRead)
|
||||
{
|
||||
return componentMessageManager.HasExistingComponent<TComponent>(entity);
|
||||
return componentUpdateManager.HasExistingComponent<TComponent>(entity);
|
||||
}
|
||||
else if (pendingRead)
|
||||
{
|
||||
return componentMessageManager.HasPendingComponent<TComponent>(entity);
|
||||
return componentUpdateManager.HasPendingComponent<TComponent>(entity);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -468,23 +376,20 @@ namespace Encompass
|
|||
/// </exception>
|
||||
protected bool HasComponent(Entity entity, Type type)
|
||||
{
|
||||
var pending = typeof(PendingComponentMessage<>).MakeGenericType(type);
|
||||
var existing = typeof(ComponentMessage<>).MakeGenericType(type);
|
||||
|
||||
var pendingRead = receiveTypes.Contains(pending);
|
||||
var existingRead = receiveTypes.Contains(existing);
|
||||
var pendingRead = readPendingTypes.Contains(type);
|
||||
var existingRead = readTypes.Contains(type);
|
||||
|
||||
if (pendingRead && existingRead)
|
||||
{
|
||||
return componentMessageManager.HasExistingOrPendingComponent(entity, type);
|
||||
return componentUpdateManager.HasExistingOrPendingComponent(entity, type);
|
||||
}
|
||||
else if (existingRead)
|
||||
{
|
||||
return componentMessageManager.HasExistingComponent(entity, type);
|
||||
return componentUpdateManager.HasExistingComponent(entity, type);
|
||||
}
|
||||
else if (pendingRead)
|
||||
{
|
||||
return componentMessageManager.HasPendingComponent(entity, type);
|
||||
return componentUpdateManager.HasPendingComponent(entity, type);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -500,28 +405,26 @@ namespace Encompass
|
|||
/// </exception>
|
||||
protected void SetComponent<TComponent>(Entity entity, TComponent component) where TComponent : struct, IComponent
|
||||
{
|
||||
var priority = writePriorities.ContainsKey(typeof(TComponent)) ? writePriorities[typeof(TComponent)] : 0;
|
||||
var priority = writePriorities.ContainsKey(typeof(TComponent)) ? writePriorities[typeof(TComponent)] : defaultWritePriority;
|
||||
|
||||
var componentID = componentManager.MarkComponentForWrite(entity, component, priority);
|
||||
|
||||
if (!sendTypes.Contains(typeof(ComponentWriteMessage<TComponent>)))
|
||||
if (!writeTypes.Contains(typeof(TComponent)))
|
||||
{
|
||||
throw new IllegalWriteException("Engine {0} tried to update undeclared Component {1}", GetType().Name, typeof(TComponent).Name);
|
||||
}
|
||||
|
||||
if (sendTypes.Contains(typeof(PendingComponentMessage<TComponent>)))
|
||||
bool written;
|
||||
if (writePendingTypes.Contains(typeof(TComponent)))
|
||||
{
|
||||
PendingComponentMessage<TComponent> newComponentMessage;
|
||||
newComponentMessage.entity = entity;
|
||||
newComponentMessage.componentID = componentID;
|
||||
newComponentMessage.component = component;
|
||||
newComponentMessage.priority = priority;
|
||||
SendPendingComponentMessage(newComponentMessage);
|
||||
written = AddPendingComponent(entity, component, priority);
|
||||
}
|
||||
else
|
||||
{
|
||||
written = componentUpdateManager.UpdateComponent(entity, component, priority);
|
||||
}
|
||||
|
||||
if (component is IDrawableComponent drawableComponent)
|
||||
if (written && component is IDrawableComponent drawableComponent)
|
||||
{
|
||||
componentManager.RegisterDrawableComponent(componentID, drawableComponent);
|
||||
componentManager.RegisterDrawableComponent(entity, component, drawableComponent.Layer);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -547,7 +450,7 @@ namespace Encompass
|
|||
/// <param name="time">The time in seconds that will elapse before the message is sent.</param>
|
||||
protected void SendMessage<TMessage>(TMessage message, double time) where TMessage : struct, IMessage
|
||||
{
|
||||
messageManager.AddMessageDelayed(message, time);
|
||||
messageManager.AddMessage(message, time);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -556,30 +459,17 @@ namespace Encompass
|
|||
/// <param name="time">The time in seconds that will elapse before the message is sent.</param>
|
||||
protected void SendMessageIgnoringTimeDilation<TMessage>(TMessage message, double time) where TMessage : struct, IMessage
|
||||
{
|
||||
messageManager.AddMessageDelayedIgnoringTimeDilation(message, time);
|
||||
messageManager.AddMessageIgnoringTimeDilation(message, time);
|
||||
}
|
||||
|
||||
// unparameterized version to enable dynamic dispatch
|
||||
protected void SendMessage(IMessage message)
|
||||
internal void AddExistingComponent<TComponent>(Entity entity, TComponent component) where TComponent : struct, IComponent
|
||||
{
|
||||
var type = message.GetType();
|
||||
|
||||
if (!sendTypes.Contains(type) || !type.IsValueType)
|
||||
{
|
||||
throw new IllegalSendException("Engine {0} tried to send undeclared Message {1}", GetType().Name, type.Name);
|
||||
componentUpdateManager.AddExistingComponent(entity, component);
|
||||
}
|
||||
|
||||
messageManager.AddMessage(message);
|
||||
}
|
||||
|
||||
internal void SendExistingComponentMessage<TComponent>(ComponentMessage<TComponent> message) where TComponent : struct, IComponent
|
||||
internal bool AddPendingComponent<TComponent>(Entity entity, TComponent component, int priority) where TComponent : struct, IComponent
|
||||
{
|
||||
componentMessageManager.AddExistingComponentMessage(message);
|
||||
}
|
||||
|
||||
internal void SendPendingComponentMessage<TComponent>(PendingComponentMessage<TComponent> message) where TComponent : struct, IComponent
|
||||
{
|
||||
componentMessageManager.AddPendingComponentMessage(message);
|
||||
return componentUpdateManager.AddPendingComponent(entity, component, priority);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -606,7 +496,7 @@ namespace Encompass
|
|||
/// </exception>
|
||||
protected TMessage ReadMessage<TMessage>() where TMessage : struct, IMessage
|
||||
{
|
||||
return ReadMessages<TMessage>().First();
|
||||
return messageManager.First<TMessage>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -622,16 +512,7 @@ namespace Encompass
|
|||
throw new IllegalReadException("Engine {0} tried to read undeclared Message {1}", GetType().Name, typeof(TMessage).Name);
|
||||
}
|
||||
|
||||
return ReadMessages<TMessage>().Any();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Destroys the Entity with the specified ID. This also removes all of the Components associated with the Entity.
|
||||
/// Entity destruction takes place after all the Engines have been processed by World Update.
|
||||
/// </summary>
|
||||
internal void Destroy(Guid entityID)
|
||||
{
|
||||
entityManager.MarkForDestroy(entityID);
|
||||
return messageManager.Any<TMessage>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -640,7 +521,7 @@ namespace Encompass
|
|||
/// </summary>
|
||||
protected void Destroy(Entity entity)
|
||||
{
|
||||
entityManager.MarkForDestroy(entity.ID);
|
||||
entityManager.MarkForDestroy(entity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -673,21 +554,10 @@ namespace Encompass
|
|||
{
|
||||
if (!HasComponent<TComponent>(entity)) { return false; }
|
||||
|
||||
var (componentID, component) = GetComponentHelper<TComponent>(entity);
|
||||
|
||||
RemoveComponent(componentID);
|
||||
|
||||
componentManager.Remove<TComponent>(entity);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the Component with the specified ID from its Entity.
|
||||
/// </summary>
|
||||
private void RemoveComponent(Guid componentID)
|
||||
{
|
||||
componentManager.MarkForRemoval(componentID);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Activates the Encompass time dilation system.
|
||||
/// Engines that have the IgnoresTimeDilation property will ignore all time dilation.
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
namespace Encompass
|
||||
{
|
||||
internal class ComponentEmitter<TComponent> : Engine where TComponent : struct, IComponent
|
||||
{
|
||||
public ComponentEmitter()
|
||||
{
|
||||
sendTypes.Add(typeof(TComponent));
|
||||
}
|
||||
|
||||
public override void Update(double dt)
|
||||
{
|
||||
foreach (var (component, entity) in InternalRead<TComponent>())
|
||||
{
|
||||
AddExistingComponent(entity, component);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
namespace Encompass
|
||||
{
|
||||
internal class ComponentMessageEmitter<TComponent> : Engine where TComponent : struct, IComponent
|
||||
{
|
||||
public ComponentMessageEmitter() : base()
|
||||
{
|
||||
sendTypes.Add(typeof(ComponentMessage<TComponent>));
|
||||
}
|
||||
|
||||
public override void Update(double dt)
|
||||
{
|
||||
foreach (var (componentID, component) in ReadComponentsFromWorld<TComponent>())
|
||||
{
|
||||
ComponentMessage<TComponent> componentMessage;
|
||||
componentMessage.entity = ReadEntityFromWorld(componentID);
|
||||
componentMessage.componentID = componentID;
|
||||
componentMessage.component = component;
|
||||
SendMessage(componentMessage);
|
||||
SendExistingComponentMessage(componentMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,14 +12,14 @@ namespace Encompass
|
|||
|
||||
internal Entity(Guid id)
|
||||
{
|
||||
this.ID = id;
|
||||
ID = id;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj is Entity)
|
||||
if (obj is Entity entity)
|
||||
{
|
||||
return this.Equals((Entity)obj);
|
||||
return Equals(entity);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
|
@ -7,17 +7,15 @@ namespace Encompass
|
|||
{
|
||||
internal class EntityManager
|
||||
{
|
||||
private readonly Dictionary<Guid, Entity> IDToEntity = new Dictionary<Guid, Entity>();
|
||||
private readonly Dictionary<Guid, Entity> IDToEntity = new Dictionary<Guid, Entity>(1024);
|
||||
|
||||
private readonly HashSet<Guid> entitiesMarkedForDestroy = new HashSet<Guid>();
|
||||
private readonly HashSet<Entity> entitiesMarkedForDestroy = new HashSet<Entity>();
|
||||
|
||||
private readonly ComponentManager componentManager;
|
||||
private readonly ComponentMessageManager componentMessageManager;
|
||||
|
||||
public EntityManager(ComponentManager componentManager, ComponentMessageManager componentMessageManager)
|
||||
public EntityManager(ComponentManager componentManager)
|
||||
{
|
||||
this.componentManager = componentManager;
|
||||
this.componentMessageManager = componentMessageManager;
|
||||
}
|
||||
|
||||
public Entity CreateEntity()
|
||||
|
@ -25,8 +23,6 @@ namespace Encompass
|
|||
var id = NextID();
|
||||
var entity = new Entity(id);
|
||||
IDToEntity[id] = entity;
|
||||
componentManager.RegisterEntity(id);
|
||||
componentMessageManager.RegisterEntity(entity);
|
||||
return entity;
|
||||
}
|
||||
|
||||
|
@ -47,19 +43,17 @@ namespace Encompass
|
|||
}
|
||||
}
|
||||
|
||||
public void MarkForDestroy(Guid entityID)
|
||||
public void MarkForDestroy(Entity entity)
|
||||
{
|
||||
entitiesMarkedForDestroy.Add(entityID);
|
||||
entitiesMarkedForDestroy.Add(entity);
|
||||
}
|
||||
|
||||
public void DestroyMarkedEntities()
|
||||
{
|
||||
foreach (var entityID in entitiesMarkedForDestroy)
|
||||
foreach (var entity in entitiesMarkedForDestroy)
|
||||
{
|
||||
componentMessageManager.RegisterDestroyedEntity(GetEntity(entityID));
|
||||
componentManager.MarkAllComponentsOnEntityForRemoval(entityID);
|
||||
IDToEntity.Remove(entityID);
|
||||
componentManager.RegisterDestroyedEntity(entityID);
|
||||
componentManager.MarkAllComponentsOnEntityForRemoval(entity);
|
||||
IDToEntity.Remove(entity.ID);
|
||||
}
|
||||
|
||||
entitiesMarkedForDestroy.Clear();
|
||||
|
|
|
@ -1,102 +1,55 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Encompass
|
||||
{
|
||||
internal class MessageManager
|
||||
{
|
||||
private TimeManager timeManager;
|
||||
|
||||
private readonly Dictionary<Type, List<IMessage>> messageTypeToMessages = new Dictionary<Type, List<IMessage>>();
|
||||
|
||||
private readonly List<(IMessage, double)> delayedMessages = new List<(IMessage, double)>();
|
||||
private readonly List<(IMessage, double)> delayedMessagesIgnoringTimeDilation = new List<(IMessage, double)>();
|
||||
private readonly TimeManager timeManager;
|
||||
private readonly MessageStore messageStore = new MessageStore();
|
||||
|
||||
public MessageManager(TimeManager timeManager)
|
||||
{
|
||||
this.timeManager = timeManager;
|
||||
}
|
||||
|
||||
internal void RegisterMessageType(Type messageType)
|
||||
internal void AddMessage<TMessage>(TMessage message) where TMessage : struct, IMessage
|
||||
{
|
||||
if (!messageTypeToMessages.ContainsKey(messageType))
|
||||
{
|
||||
messageTypeToMessages.Add(messageType, new List<IMessage>());
|
||||
}
|
||||
messageStore.AddMessage<TMessage>(message);
|
||||
}
|
||||
|
||||
internal void AddMessage(IMessage message)
|
||||
internal void AddMessage<TMessage>(TMessage message, double time) where TMessage : struct, IMessage
|
||||
{
|
||||
var type = message.GetType();
|
||||
|
||||
messageTypeToMessages[type].Add(message);
|
||||
messageStore.AddMessage(message, time);
|
||||
}
|
||||
|
||||
internal void AddMessageDelayed(IMessage message, double time)
|
||||
internal void AddMessageIgnoringTimeDilation<TMessage>(TMessage message, double time) where TMessage : struct, IMessage
|
||||
{
|
||||
if (!messageTypeToMessages.ContainsKey(message.GetType())) { messageTypeToMessages.Add(message.GetType(), new List<IMessage>()); }
|
||||
|
||||
delayedMessages.Add((message, time));
|
||||
}
|
||||
|
||||
internal void AddMessageDelayedIgnoringTimeDilation(IMessage message, double time)
|
||||
{
|
||||
if (!messageTypeToMessages.ContainsKey(message.GetType())) { messageTypeToMessages.Add(message.GetType(), new List<IMessage>()); }
|
||||
|
||||
delayedMessagesIgnoringTimeDilation.Add((message, time));
|
||||
messageStore.AddMessageIgnoringTimeDilation(message, time);
|
||||
}
|
||||
|
||||
internal void ClearMessages()
|
||||
{
|
||||
foreach (var entry in messageTypeToMessages)
|
||||
{
|
||||
entry.Value.Clear();
|
||||
}
|
||||
messageStore.ClearAll();
|
||||
}
|
||||
|
||||
internal void ProcessDelayedMessages(double dt)
|
||||
{
|
||||
for (int i = delayedMessages.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var (message, time) = delayedMessages[i];
|
||||
|
||||
var updatedTime = time - (dt * timeManager.TimeDilationFactor);
|
||||
|
||||
if (updatedTime <= 0)
|
||||
{
|
||||
AddMessage(message);
|
||||
delayedMessages.RemoveAt(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
delayedMessages[i] = (message, updatedTime);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = delayedMessagesIgnoringTimeDilation.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var (message, time) = delayedMessagesIgnoringTimeDilation[i];
|
||||
|
||||
var updatedTime = time - dt;
|
||||
|
||||
if (updatedTime <= 0)
|
||||
{
|
||||
AddMessage(message);
|
||||
delayedMessagesIgnoringTimeDilation.RemoveAt(i);
|
||||
}
|
||||
else
|
||||
{
|
||||
delayedMessagesIgnoringTimeDilation[i] = (message, updatedTime);
|
||||
}
|
||||
}
|
||||
messageStore.ProcessDelayedMessages(dt * timeManager.TimeDilationFactor, dt);
|
||||
}
|
||||
|
||||
internal IEnumerable<TMessage> GetMessagesByType<TMessage>() where TMessage : struct, IMessage
|
||||
{
|
||||
return messageTypeToMessages.ContainsKey(typeof(TMessage)) ?
|
||||
messageTypeToMessages[typeof(TMessage)].Cast<TMessage>() :
|
||||
Enumerable.Empty<TMessage>();
|
||||
return messageStore.All<TMessage>();
|
||||
}
|
||||
|
||||
internal bool Any<TMessage>() where TMessage : struct, IMessage
|
||||
{
|
||||
return messageStore.Any<TMessage>();
|
||||
}
|
||||
|
||||
internal TMessage First<TMessage>() where TMessage : struct, IMessage
|
||||
{
|
||||
return messageStore.First<TMessage>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace Encompass
|
||||
{
|
||||
internal struct ComponentMessage<TComponent> : IMessage where TComponent : struct, IComponent
|
||||
{
|
||||
public Entity entity;
|
||||
public Guid componentID;
|
||||
public TComponent component;
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace Encompass
|
||||
{
|
||||
internal struct ComponentWriteMessage<TComponent> : IMessage where TComponent : struct, IComponent
|
||||
{
|
||||
public Guid componentID;
|
||||
public TComponent component;
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace Encompass
|
||||
{
|
||||
internal struct PendingComponentMessage<TComponent> : IMessage where TComponent : struct, IComponent
|
||||
{
|
||||
public Entity entity;
|
||||
public Guid componentID;
|
||||
public TComponent component;
|
||||
public int priority;
|
||||
}
|
||||
}
|
|
@ -1,26 +1,17 @@
|
|||
using System;
|
||||
using System.Reflection;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Encompass
|
||||
{
|
||||
internal class RenderManager
|
||||
{
|
||||
private readonly ComponentManager componentManager;
|
||||
private readonly DrawLayerManager drawLayerManager;
|
||||
private readonly EntityManager entityManager;
|
||||
|
||||
private readonly Dictionary<Type, Action<Entity, IComponent>> drawComponentTypeToOrderedRenderer = new Dictionary<Type, Action<Entity, IComponent>>();
|
||||
private readonly Dictionary<Type, Action<Entity, IComponent>> drawComponentTypeToOrderedRenderer = new Dictionary<Type, Action<Entity, IComponent>>(256);
|
||||
|
||||
public RenderManager(
|
||||
ComponentManager componentManager,
|
||||
DrawLayerManager drawLayerManager,
|
||||
EntityManager entityManager
|
||||
)
|
||||
public RenderManager(DrawLayerManager drawLayerManager)
|
||||
{
|
||||
this.componentManager = componentManager;
|
||||
this.drawLayerManager = drawLayerManager;
|
||||
this.entityManager = entityManager;
|
||||
}
|
||||
|
||||
public void RegisterOrderedRenderer<TComponent>(Action<Entity, IComponent> renderAction) where TComponent : struct, IComponent
|
||||
|
@ -37,16 +28,10 @@ namespace Encompass
|
|||
{
|
||||
foreach (var layer in drawLayerManager.LayerOrder)
|
||||
{
|
||||
var componentIDSet = drawLayerManager.ComponentIDsByLayer(layer);
|
||||
var generalRendererSet = drawLayerManager.GeneralRenderersByLayer(layer);
|
||||
|
||||
foreach (var componentID in componentIDSet)
|
||||
foreach (var (entity, componentType, component) in drawLayerManager.AllInLayer(layer))
|
||||
{
|
||||
var component = componentManager.GetComponentByID(componentID);
|
||||
var componentType = componentManager.GetComponentTypeByID(componentID);
|
||||
var entityID = componentManager.GetEntityIDByComponentID(componentID);
|
||||
var entity = entityManager.GetEntity(entityID);
|
||||
|
||||
if (drawComponentTypeToOrderedRenderer.ContainsKey(componentType))
|
||||
{
|
||||
var internalRenderAction = drawComponentTypeToOrderedRenderer[componentType];
|
||||
|
|
|
@ -19,11 +19,6 @@ namespace Encompass
|
|||
this.componentManager = componentManager;
|
||||
}
|
||||
|
||||
internal Guid GetEntityIDByComponentID(Guid componentID)
|
||||
{
|
||||
return componentManager.GetEntityIDByComponentID(componentID);
|
||||
}
|
||||
|
||||
internal Entity GetEntity(Guid entityID)
|
||||
{
|
||||
return entityManager.GetEntity(entityID);
|
||||
|
@ -41,12 +36,12 @@ namespace Encompass
|
|||
|
||||
protected IEnumerable<TComponent> ReadComponents<TComponent>() where TComponent : struct, IComponent
|
||||
{
|
||||
return componentManager.GetComponentsByType<TComponent>().Select(tuple => tuple.Item2);
|
||||
return componentManager.GetComponentsByType<TComponent>();
|
||||
}
|
||||
|
||||
protected IEnumerable<(TComponent, Entity)> ReadComponentsIncludingEntity<TComponent>() where TComponent : struct, IComponent
|
||||
{
|
||||
return componentManager.GetComponentsByType<TComponent>().Select(tuple => (tuple.Item2, GetEntity(GetEntityIDByComponentID(tuple.Item1))));
|
||||
return componentManager.GetComponentsIncludingEntity<TComponent>();
|
||||
}
|
||||
|
||||
protected TComponent ReadComponent<TComponent>() where TComponent : struct, IComponent
|
||||
|
@ -61,7 +56,7 @@ namespace Encompass
|
|||
|
||||
protected TComponent GetComponent<TComponent>(Entity entity) where TComponent : struct, IComponent
|
||||
{
|
||||
return componentManager.GetComponentByEntityAndType<TComponent>(entity).Item2;
|
||||
return componentManager.GetComponentByEntityAndType<TComponent>(entity);
|
||||
}
|
||||
|
||||
protected bool HasComponent<TComponent>(Entity entity) where TComponent : struct, IComponent
|
||||
|
|
|
@ -14,23 +14,21 @@ namespace Encompass
|
|||
{
|
||||
get
|
||||
{
|
||||
double calculatedFactor = 1;
|
||||
|
||||
if (elapsedTime < easeInTime)
|
||||
{
|
||||
calculatedFactor = easeInFunction(elapsedTime, 1, factor - 1, easeInTime);
|
||||
return easeInFunction(elapsedTime, 1, factor - 1, easeInTime);
|
||||
}
|
||||
else if (elapsedTime < easeInTime + activeTime)
|
||||
{
|
||||
calculatedFactor = factor;
|
||||
return factor;
|
||||
}
|
||||
else if (elapsedTime < easeInTime + activeTime + easeOutTime)
|
||||
{
|
||||
var elapsedOutTime = elapsedTime - easeInTime - activeTime;
|
||||
calculatedFactor = easeOutFunction(elapsedOutTime, factor, 1 - factor, easeOutTime);
|
||||
return easeOutFunction(elapsedOutTime, factor, 1 - factor, easeOutTime);
|
||||
}
|
||||
|
||||
return calculatedFactor;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,11 +5,11 @@ namespace Encompass
|
|||
{
|
||||
internal class TimeManager
|
||||
{
|
||||
private List<TimeDilationData> timeDilationDatas = new List<TimeDilationData>();
|
||||
private readonly List<TimeDilationData> timeDilationDatas = new List<TimeDilationData>(32);
|
||||
|
||||
private double Linear(double t, double b, double c, double d)
|
||||
{
|
||||
return c * t / d + b;
|
||||
return (c * t / d) + b;
|
||||
}
|
||||
|
||||
public double TimeDilationFactor
|
||||
|
|
|
@ -11,7 +11,7 @@ namespace Encompass
|
|||
private readonly EntityManager entityManager;
|
||||
private readonly ComponentManager componentManager;
|
||||
private readonly MessageManager messageManager;
|
||||
private readonly ComponentMessageManager componentMessageManager;
|
||||
private readonly ComponentUpdateManager componentUpdateManager;
|
||||
private readonly TimeManager timeManager;
|
||||
private readonly RenderManager renderManager;
|
||||
|
||||
|
@ -20,7 +20,7 @@ namespace Encompass
|
|||
EntityManager entityManager,
|
||||
ComponentManager componentManager,
|
||||
MessageManager messageManager,
|
||||
ComponentMessageManager componentMessageManager,
|
||||
ComponentUpdateManager componentUpdateManager,
|
||||
TimeManager timeManager,
|
||||
RenderManager renderManager
|
||||
)
|
||||
|
@ -29,7 +29,7 @@ namespace Encompass
|
|||
this.entityManager = entityManager;
|
||||
this.componentManager = componentManager;
|
||||
this.messageManager = messageManager;
|
||||
this.componentMessageManager = componentMessageManager;
|
||||
this.componentUpdateManager = componentUpdateManager;
|
||||
this.timeManager = timeManager;
|
||||
this.renderManager = renderManager;
|
||||
}
|
||||
|
@ -56,11 +56,12 @@ namespace Encompass
|
|||
}
|
||||
|
||||
messageManager.ClearMessages();
|
||||
componentMessageManager.ClearMessages();
|
||||
entityManager.DestroyMarkedEntities();
|
||||
|
||||
componentManager.RemoveMarkedComponents();
|
||||
componentManager.WriteComponents();
|
||||
componentManager.RemoveMarkedComponents();
|
||||
|
||||
componentUpdateManager.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -20,11 +20,13 @@ namespace Encompass
|
|||
{
|
||||
private readonly List<Engine> engines = new List<Engine>();
|
||||
private readonly DirectedGraph<Engine, Unit> engineGraph = GraphBuilder.DirectedGraph<Engine>();
|
||||
private readonly ComponentStore startingComponentStoreForComponentManager = new ComponentStore();
|
||||
private readonly ComponentStore startingComponentStoreForComponentUpdateManager = new ComponentStore();
|
||||
|
||||
private readonly ComponentManager componentManager;
|
||||
private readonly EntityManager entityManager;
|
||||
private readonly MessageManager messageManager;
|
||||
private readonly ComponentMessageManager componentMessageManager;
|
||||
private readonly ComponentUpdateManager componentUpdateManager;
|
||||
private readonly TimeManager timeManager;
|
||||
private readonly DrawLayerManager drawLayerManager;
|
||||
private readonly RenderManager renderManager;
|
||||
|
@ -39,11 +41,11 @@ namespace Encompass
|
|||
{
|
||||
drawLayerManager = new DrawLayerManager();
|
||||
timeManager = new TimeManager();
|
||||
componentManager = new ComponentManager(drawLayerManager);
|
||||
componentUpdateManager = new ComponentUpdateManager();
|
||||
componentManager = new ComponentManager(drawLayerManager, componentUpdateManager);
|
||||
messageManager = new MessageManager(timeManager);
|
||||
componentMessageManager = new ComponentMessageManager();
|
||||
entityManager = new EntityManager(componentManager, componentMessageManager);
|
||||
renderManager = new RenderManager(componentManager, drawLayerManager, entityManager);
|
||||
entityManager = new EntityManager(componentManager);
|
||||
renderManager = new RenderManager(drawLayerManager);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -67,25 +69,28 @@ namespace Encompass
|
|||
/// </summary>
|
||||
public void SendMessage<TMessage>(TMessage message, double time) where TMessage : struct, IMessage
|
||||
{
|
||||
messageManager.AddMessageDelayed(message, time);
|
||||
messageManager.AddMessage<TMessage>(message, time);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets Component data for the specified Component Type on the specified Entity.
|
||||
/// </summary>
|
||||
public void SetComponent<TComponent>(Entity entity, TComponent component, int priority = 0) where TComponent : struct, IComponent
|
||||
public void SetComponent<TComponent>(Entity entity, TComponent component) where TComponent : struct, IComponent
|
||||
{
|
||||
var componentID = componentManager.MarkComponentForWrite(entity, component, priority);
|
||||
startingComponentStoreForComponentManager.Set(entity, component);
|
||||
startingComponentStoreForComponentUpdateManager.Set(entity, component);
|
||||
|
||||
RegisterComponent(typeof(TComponent));
|
||||
|
||||
if (component is IDrawableComponent drawableComponent)
|
||||
{
|
||||
componentManager.RegisterDrawableComponent(componentID, drawableComponent);
|
||||
componentManager.RegisterDrawableComponent(entity, component, drawableComponent.Layer);
|
||||
}
|
||||
}
|
||||
|
||||
internal void RegisterComponent(Type componentType)
|
||||
{
|
||||
registeredComponentTypes.Add(componentType);
|
||||
AddEngine((Engine)Activator.CreateInstance(typeof(ComponentMessageEmitter<>).MakeGenericType(componentType)));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -97,7 +102,7 @@ namespace Encompass
|
|||
engine.AssignEntityManager(entityManager);
|
||||
engine.AssignComponentManager(componentManager);
|
||||
engine.AssignMessageManager(messageManager);
|
||||
engine.AssignComponentMessageManager(componentMessageManager);
|
||||
engine.AssignComponentUpdateManager(componentUpdateManager);
|
||||
engine.AssignTimeManager(timeManager);
|
||||
|
||||
engines.Add(engine);
|
||||
|
@ -106,42 +111,28 @@ namespace Encompass
|
|||
var messageReceiveTypes = engine.receiveTypes;
|
||||
var messageSendTypes = engine.sendTypes;
|
||||
|
||||
foreach (var messageType in messageReceiveTypes.Union(messageSendTypes))
|
||||
foreach (var writePendingType in engine.writePendingTypes.Intersect(engine.readPendingTypes))
|
||||
{
|
||||
messageManager.RegisterMessageType(messageType);
|
||||
throw new EngineSelfCycleException("Engine {0} both writes and reads pending Component {1}", engine.GetType().Name, writePendingType.Name);
|
||||
}
|
||||
|
||||
foreach (var messageType in messageReceiveTypes.Intersect(messageSendTypes))
|
||||
{
|
||||
if ((messageType.IsGenericType && messageType.GetGenericTypeDefinition() == typeof(PendingComponentMessage<>)))
|
||||
{
|
||||
var componentType = messageType.GetGenericArguments().Single();
|
||||
throw new EngineSelfCycleException("Engine {0} both activates and reads pending Component {1}", engine.GetType().Name, componentType.Name);
|
||||
}
|
||||
|
||||
throw new EngineSelfCycleException("Engine {0} both receives and sends Message {1}", engine.GetType().Name, messageType.Name);
|
||||
}
|
||||
|
||||
if (messageSendTypes.Any())
|
||||
if (messageSendTypes.Count > 0 || engine.writePendingTypes.Count > 0)
|
||||
{
|
||||
senders.Add(engine);
|
||||
}
|
||||
|
||||
foreach (var receiveType in engine.receiveTypes)
|
||||
{
|
||||
if (receiveType.IsGenericType)
|
||||
{
|
||||
var genericTypeDefinition = receiveType.GetGenericTypeDefinition();
|
||||
if (genericTypeDefinition == typeof(ComponentMessage<>) || genericTypeDefinition == typeof(PendingComponentMessage<>))
|
||||
{
|
||||
var componentType = receiveType.GetGenericArguments().Single();
|
||||
if (!registeredComponentTypes.Contains(componentType))
|
||||
foreach (var componentType in engine.readTypes.Union(engine.writeTypes).Union(engine.readPendingTypes))
|
||||
{
|
||||
RegisterComponent(componentType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var receiveType in engine.receiveTypes.Union(engine.readPendingTypes))
|
||||
{
|
||||
if (!typeToReaders.ContainsKey(receiveType))
|
||||
{
|
||||
typeToReaders.Add(receiveType, new HashSet<Engine>());
|
||||
|
@ -184,7 +175,7 @@ namespace Encompass
|
|||
{
|
||||
foreach (var senderEngine in senders)
|
||||
{
|
||||
foreach (var messageType in senderEngine.sendTypes)
|
||||
foreach (var messageType in senderEngine.sendTypes.Union(senderEngine.writePendingTypes))
|
||||
{
|
||||
if (typeToReaders.ContainsKey(messageType))
|
||||
{
|
||||
|
@ -243,16 +234,12 @@ namespace Encompass
|
|||
|
||||
var defaultWritePriorityAttribute = engine.GetType().GetCustomAttribute<DefaultWritePriority>(false);
|
||||
|
||||
var writeTypes = engine.sendTypes.Where((type) => type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ComponentWriteMessage<>));
|
||||
|
||||
foreach (var writeType in writeTypes)
|
||||
foreach (var writeType in engine.writeTypes)
|
||||
{
|
||||
var componentType = writeType.GetGenericArguments()[0];
|
||||
|
||||
int? priority = null;
|
||||
if (engine.writePriorities.ContainsKey(componentType))
|
||||
if (engine.writePriorities.ContainsKey(writeType))
|
||||
{
|
||||
priority = engine.writePriorities[componentType];
|
||||
priority = engine.writePriorities[writeType];
|
||||
}
|
||||
else if (defaultWritePriorityAttribute != null)
|
||||
{
|
||||
|
@ -261,44 +248,44 @@ namespace Encompass
|
|||
|
||||
if (priority.HasValue)
|
||||
{
|
||||
writtenComponentTypesWithPriority.Add(componentType);
|
||||
writtenComponentTypesWithPriority.Add(writeType);
|
||||
|
||||
if (!writePriorities.ContainsKey(componentType))
|
||||
if (!writePriorities.ContainsKey(writeType))
|
||||
{
|
||||
writePriorities[componentType] = new HashSet<int>();
|
||||
writePriorities[writeType] = new HashSet<int>();
|
||||
}
|
||||
|
||||
if (writePriorities[componentType].Contains(priority.Value))
|
||||
if (writePriorities[writeType].Contains(priority.Value))
|
||||
{
|
||||
duplicateWritesWithSamePriority.Add(componentType);
|
||||
duplicateWritesWithSamePriority.Add(writeType);
|
||||
}
|
||||
else if (writtenComponentTypesWithoutPriority.Contains(componentType))
|
||||
else if (writtenComponentTypesWithoutPriority.Contains(writeType))
|
||||
{
|
||||
duplicateWritesWithoutPriority.Add(componentType);
|
||||
duplicateWritesWithoutPriority.Add(writeType);
|
||||
}
|
||||
else
|
||||
{
|
||||
writePriorities[componentType].Add(priority.Value);
|
||||
writePriorities[writeType].Add(priority.Value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (writtenComponentTypesWithoutPriority.Contains(componentType) || writtenComponentTypesWithPriority.Contains(componentType))
|
||||
if (writtenComponentTypesWithoutPriority.Contains(writeType) || writtenComponentTypesWithPriority.Contains(writeType))
|
||||
{
|
||||
duplicateWritesWithoutPriority.Add(componentType);
|
||||
duplicateWritesWithoutPriority.Add(writeType);
|
||||
}
|
||||
else
|
||||
{
|
||||
writtenComponentTypesWithoutPriority.Add(componentType);
|
||||
writtenComponentTypesWithoutPriority.Add(writeType);
|
||||
}
|
||||
}
|
||||
|
||||
if (!writeMessageToEngines.ContainsKey(componentType))
|
||||
if (!writeMessageToEngines.ContainsKey(writeType))
|
||||
{
|
||||
writeMessageToEngines[componentType] = new List<Engine>();
|
||||
writeMessageToEngines[writeType] = new List<Engine>();
|
||||
}
|
||||
|
||||
writeMessageToEngines[componentType].Add(engine);
|
||||
writeMessageToEngines[writeType].Add(engine);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -331,6 +318,14 @@ namespace Encompass
|
|||
}
|
||||
|
||||
var engineOrder = new List<Engine>();
|
||||
|
||||
foreach (var registeredComponentType in registeredComponentTypes)
|
||||
{
|
||||
var emitterEngine = (Engine)Activator.CreateInstance(typeof(ComponentEmitter<>).MakeGenericType(registeredComponentType));
|
||||
AddEngine(emitterEngine);
|
||||
engineOrder.Add(emitterEngine);
|
||||
}
|
||||
|
||||
foreach (var engine in engineGraph.TopologicalSort())
|
||||
{
|
||||
engineOrder.Add(engine);
|
||||
|
@ -341,13 +336,13 @@ namespace Encompass
|
|||
entityManager,
|
||||
componentManager,
|
||||
messageManager,
|
||||
componentMessageManager,
|
||||
componentUpdateManager,
|
||||
timeManager,
|
||||
renderManager
|
||||
);
|
||||
|
||||
componentManager.RemoveMarkedComponents();
|
||||
componentManager.WriteComponents();
|
||||
componentUpdateManager.SetStartingComponentStore(startingComponentStoreForComponentUpdateManager);
|
||||
componentManager.SetComponentStore(startingComponentStoreForComponentManager);
|
||||
|
||||
return world;
|
||||
}
|
||||
|
|
|
@ -3,13 +3,13 @@
|
|||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
<RootNamespace>Encompass</RootNamespace>
|
||||
<PackageId>EncompassECS.Framework</PackageId>
|
||||
<Version>0.17.0</Version>
|
||||
<Version>0.18.0-preview8</Version>
|
||||
<Authors>Evan Hemsley</Authors>
|
||||
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
|
||||
<Company>Moonside Games</Company>
|
||||
<Product>Encompass ECS</Product>
|
||||
<PackageProjectUrl>https://github.com/encompass-ecs</PackageProjectUrl>
|
||||
<PackageLicenseUrl/>
|
||||
<PackageLicenseUrl />
|
||||
<Copyright>Evan Hemsley 2019</Copyright>
|
||||
<Description>Encompass is an engine-agnostic Hyper ECS framework to help you code games, or other kinds of simulations.</Description>
|
||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
||||
|
@ -19,11 +19,10 @@
|
|||
<ItemGroup>
|
||||
<None Include="..\LICENSE">
|
||||
<Pack>True</Pack>
|
||||
<PackagePath/>
|
||||
<PackagePath />
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Collections.Pooled" Version="1.0.82"/>
|
||||
<PackageReference Include="MoonTools.Core.Graph" Version="1.0.0"/>
|
||||
<PackageReference Include="MoonTools.Core.Graph" Version="1.0.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
|
@ -1,12 +1,7 @@
|
|||
using System.ComponentModel;
|
||||
using NUnit.Framework;
|
||||
using FluentAssertions;
|
||||
|
||||
using Encompass;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Encompass.Exceptions;
|
||||
|
||||
namespace Tests
|
||||
{
|
||||
|
@ -89,16 +84,16 @@ namespace Tests
|
|||
worldBuilder.AddEngine(new ReadMockComponentEngine());
|
||||
|
||||
var entity = worldBuilder.CreateEntity();
|
||||
worldBuilder.SetComponent(entity, new MockComponent { myInt = 20, myString = "what" }, 2);
|
||||
worldBuilder.SetComponent(entity, new MockComponent { myInt = 50, myString = "hi" }, 0);
|
||||
worldBuilder.SetComponent(entity, new MockComponent { myInt = 40, myString = "wassup" }, 1);
|
||||
worldBuilder.SetComponent(entity, new MockComponent { myInt = 20, myString = "what" });
|
||||
worldBuilder.SetComponent(entity, new MockComponent { myInt = 50, myString = "hi" });
|
||||
worldBuilder.SetComponent(entity, new MockComponent { myInt = 40, myString = "wassup" });
|
||||
|
||||
var world = worldBuilder.Build();
|
||||
|
||||
world.Update(0.01);
|
||||
|
||||
Assert.That(gottenMockComponent.myInt, Is.EqualTo(50));
|
||||
Assert.That(gottenMockComponent.myString, Is.EqualTo("hi"));
|
||||
Assert.That(gottenMockComponent.myInt, Is.EqualTo(40));
|
||||
Assert.That(gottenMockComponent.myString, Is.EqualTo("wassup"));
|
||||
}
|
||||
|
||||
[Reads(typeof(MockComponent))]
|
||||
|
@ -267,45 +262,6 @@ namespace Tests
|
|||
|
||||
Assert.AreEqual(mockComponent, gottenMockComponent);
|
||||
}
|
||||
|
||||
[Receives(typeof(EntityMessage))]
|
||||
[Reads(typeof(MockComponent))]
|
||||
class GetMockComponentByRuntimeType : Engine
|
||||
{
|
||||
public override void Update(double dt)
|
||||
{
|
||||
foreach (var entityMessage in ReadMessages<EntityMessage>())
|
||||
{
|
||||
gottenMockComponent = (MockComponent)GetComponent(entityMessage.entity, typeof(MockComponent));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetComponentByRuntimeType()
|
||||
{
|
||||
var worldBuilder = new WorldBuilder();
|
||||
worldBuilder.AddEngine(new GetMockComponentEngine());
|
||||
|
||||
var entity = worldBuilder.CreateEntity();
|
||||
|
||||
MockComponent mockComponent;
|
||||
mockComponent.myInt = 3;
|
||||
mockComponent.myString = "hello";
|
||||
|
||||
worldBuilder.SetComponent<MockComponent>(entity, mockComponent);
|
||||
|
||||
EntityMessage entityMessage;
|
||||
entityMessage.entity = entity;
|
||||
worldBuilder.SendMessage(entityMessage);
|
||||
|
||||
var world = worldBuilder.Build();
|
||||
|
||||
world.Update(0.01);
|
||||
|
||||
Assert.AreEqual(mockComponent, gottenMockComponent);
|
||||
}
|
||||
|
||||
struct HasComponentTestMessage : IMessage
|
||||
{
|
||||
public Entity entity;
|
||||
|
@ -347,6 +303,8 @@ namespace Tests
|
|||
world.Update(0.01);
|
||||
}
|
||||
|
||||
static bool hasComponentRuntimeTypeResult;
|
||||
|
||||
[Receives(typeof(HasComponentTestMessage))]
|
||||
[Reads(typeof(MockComponent))]
|
||||
class HasComponentWithRuntimeTypeEngine : Engine
|
||||
|
@ -355,7 +313,7 @@ namespace Tests
|
|||
{
|
||||
foreach (var hasComponentTestEngine in ReadMessages<HasComponentTestMessage>())
|
||||
{
|
||||
Assert.IsTrue(HasComponent(hasComponentTestEngine.entity, typeof(MockComponent)));
|
||||
hasComponentRuntimeTypeResult = HasComponent(hasComponentTestEngine.entity, typeof(MockComponent));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -381,6 +339,27 @@ namespace Tests
|
|||
var world = worldBuilder.Build();
|
||||
|
||||
world.Update(0.01);
|
||||
|
||||
Assert.IsTrue(hasComponentRuntimeTypeResult);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void HasComponentWithRuntimeTypeFalseWhenNoneHaveBeenCreated()
|
||||
{
|
||||
var worldBuilder = new WorldBuilder();
|
||||
worldBuilder.AddEngine(new HasComponentWithRuntimeTypeEngine());
|
||||
|
||||
var entity = worldBuilder.CreateEntity();
|
||||
|
||||
HasComponentTestMessage hasComponentTestMessage;
|
||||
hasComponentTestMessage.entity = entity;
|
||||
worldBuilder.SendMessage(hasComponentTestMessage);
|
||||
|
||||
var world = worldBuilder.Build();
|
||||
|
||||
world.Update(0.01);
|
||||
|
||||
Assert.IsFalse(hasComponentRuntimeTypeResult);
|
||||
}
|
||||
|
||||
struct RemoveComponentTestMessage : IMessage
|
||||
|
@ -431,6 +410,8 @@ namespace Tests
|
|||
}
|
||||
}
|
||||
|
||||
static bool hasComponentResult;
|
||||
|
||||
[Receives(typeof(CheckHasMockComponentMessage))]
|
||||
[Reads(typeof(MockComponent))]
|
||||
class CheckHasMockComponentEngine : Engine
|
||||
|
@ -439,13 +420,13 @@ namespace Tests
|
|||
{
|
||||
foreach (var checkHasMockComponentMessage in ReadMessages<CheckHasMockComponentMessage>())
|
||||
{
|
||||
Assert.IsTrue(HasComponent<MockComponent>(checkHasMockComponentMessage.entity));
|
||||
hasComponentResult = HasComponent<MockComponent>(checkHasMockComponentMessage.entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RemoveComponent()
|
||||
public void RemovedComponentShouldStillExistOnSameFrame()
|
||||
{
|
||||
var worldBuilder = new WorldBuilder();
|
||||
var entity = worldBuilder.CreateEntity();
|
||||
|
@ -467,6 +448,12 @@ namespace Tests
|
|||
var world = worldBuilder.Build();
|
||||
|
||||
world.Update(0.01f);
|
||||
|
||||
hasComponentResult.Should().BeTrue();
|
||||
|
||||
world.Update(0.01f);
|
||||
|
||||
hasComponentResult.Should().BeFalse();
|
||||
}
|
||||
|
||||
struct CheckHasMockComponentMessage : IMessage
|
||||
|
|
|
@ -557,7 +557,7 @@ namespace Tests
|
|||
world.Update(0.01);
|
||||
|
||||
Assert.That(results, Does.Not.Contain((mockComponent, entity)));
|
||||
Assert.That(results, Does.Not.Contain((mockComponent, entity)));
|
||||
Assert.That(results, Does.Not.Contain((mockComponent, entityB)));
|
||||
Assert.That(results, Does.Contain((mockComponent, entityC)));
|
||||
}
|
||||
|
||||
|
|
|
@ -35,6 +35,9 @@ namespace Tests
|
|||
world.Update(0.01f);
|
||||
world.Draw();
|
||||
|
||||
world.Update(0.01);
|
||||
world.Draw();
|
||||
|
||||
Assert.That(result, Is.EqualTo((aComponent, entity)));
|
||||
}
|
||||
|
||||
|
@ -55,7 +58,9 @@ namespace Tests
|
|||
var world = worldBuilder.Build();
|
||||
|
||||
world.Update(0.01f);
|
||||
world.Draw();
|
||||
|
||||
world.Update(0.01f);
|
||||
world.Draw();
|
||||
|
||||
Assert.That(result, Is.EqualTo((aComponent, entity)).Or.EqualTo((aComponentTwo, entityB)));
|
||||
|
|
|
@ -223,14 +223,14 @@ namespace Tests
|
|||
[Receives(typeof(SetMessage))]
|
||||
[Writes(typeof(AComponent))]
|
||||
[WritesPending(typeof(AComponent))]
|
||||
[Encompass.DefaultWritePriority(1)]
|
||||
[Encompass.DefaultWritePriority(4)]
|
||||
class AEngine : Engine
|
||||
{
|
||||
public override void Update(double dt)
|
||||
{
|
||||
foreach (var setMessage in ReadMessages<SetMessage>())
|
||||
{
|
||||
SetComponent(setMessage.entity, new AComponent { myInt = 0 });
|
||||
SetComponent(setMessage.entity, new AComponent { myInt = 5 });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -250,6 +250,20 @@ namespace Tests
|
|||
}
|
||||
}
|
||||
|
||||
[Receives(typeof(SetMessage))]
|
||||
[Writes(typeof(AComponent), 2)]
|
||||
[WritesPending(typeof(AComponent))]
|
||||
class CEngine : Engine
|
||||
{
|
||||
public override void Update(double dt)
|
||||
{
|
||||
foreach (var setMessage in ReadMessages<SetMessage>())
|
||||
{
|
||||
SetComponent(setMessage.entity, new AComponent { myInt = 3 });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static AComponent resultComponent;
|
||||
|
||||
[ReadsPending(typeof(AComponent))]
|
||||
|
@ -267,6 +281,8 @@ namespace Tests
|
|||
var worldBuilder = new WorldBuilder();
|
||||
worldBuilder.AddEngine(new AEngine());
|
||||
worldBuilder.AddEngine(new BEngine());
|
||||
worldBuilder.AddEngine(new CEngine());
|
||||
worldBuilder.AddEngine(new ReadComponentEngine());
|
||||
|
||||
var entity = worldBuilder.CreateEntity();
|
||||
worldBuilder.SendMessage(new SetMessage { entity = entity });
|
||||
|
@ -275,7 +291,7 @@ namespace Tests
|
|||
|
||||
world.Update(0.01);
|
||||
|
||||
Assert.That(resultComponent.myInt, Is.EqualTo(0));
|
||||
Assert.That(resultComponent.myInt, Is.EqualTo(3));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue