commit
447a668e1c
|
@ -21,7 +21,7 @@ namespace Encompass
|
||||||
throw new IllegalReadTypeException("{0} must be a Component", readType.Name);
|
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);
|
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);
|
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);
|
throw new IllegalWriteTypeException("{0} must be a Component", writeType.Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.writeTypes.Add(typeof(ComponentWriteMessage<>).MakeGenericType(writeType));
|
writeTypes.Add(writeType);
|
||||||
this.priorities.Add(writeType, priority);
|
priorities.Add(writeType, priority);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ namespace Encompass
|
||||||
throw new IllegalWritePendingTypeException("{0} must be a Component", writePendingType.Name);
|
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.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Encompass.Exceptions;
|
|
||||||
using Collections.Pooled;
|
|
||||||
|
|
||||||
namespace Encompass
|
namespace Encompass
|
||||||
{
|
{
|
||||||
internal class ComponentManager
|
internal class ComponentManager
|
||||||
{
|
{
|
||||||
private readonly DrawLayerManager drawLayerManager;
|
private readonly DrawLayerManager drawLayerManager;
|
||||||
|
private readonly ComponentUpdateManager componentUpdateManager;
|
||||||
|
|
||||||
private readonly Dictionary<Guid, Type> componentIDToType = new Dictionary<Guid, Type>();
|
private readonly ComponentStore componentStore = new ComponentStore();
|
||||||
private readonly Dictionary<Guid, IComponent> IDToComponent = new Dictionary<Guid, IComponent>();
|
private readonly HashSet<Entity> entitiesMarkedForRemoval = new HashSet<Entity>();
|
||||||
private readonly Dictionary<Guid, PooledSet<Guid>> entityIDToComponentIDs = new Dictionary<Guid, PooledSet<Guid>>();
|
|
||||||
private readonly Dictionary<Guid, Guid> componentIDToEntityID = new Dictionary<Guid, Guid>();
|
|
||||||
|
|
||||||
private readonly Dictionary<Guid, PooledDictionary<Type, Guid>> entityIDToComponentTypeToComponentID = new Dictionary<Guid, PooledDictionary<Type, Guid>>();
|
public ComponentManager(DrawLayerManager drawLayerManager, ComponentUpdateManager componentUpdateManager)
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
this.drawLayerManager = drawLayerManager;
|
this.drawLayerManager = drawLayerManager;
|
||||||
|
this.componentUpdateManager = componentUpdateManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void RegisterEntity(Guid entityID)
|
internal void SetComponentStore(ComponentStore componentStore)
|
||||||
{
|
{
|
||||||
entityIDToComponentIDs.Add(entityID, new PooledSet<Guid>());
|
this.componentStore.SwapWith(componentStore);
|
||||||
entityIDToComponentTypeToComponentID.Add(entityID, new PooledDictionary<Type, Guid>());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
componentStore.Set(entity, component);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void WriteComponents()
|
internal void WriteComponents()
|
||||||
{
|
{
|
||||||
foreach (var keyValuePair in componentWriteData)
|
componentStore.SwapWith(componentUpdateManager.UpToDateComponentStore);
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWriteData.Clear();
|
internal IEnumerable<(TComponent, Entity)> GetComponentsIncludingEntity<TComponent>() where TComponent : struct, IComponent
|
||||||
componentIDsMarkedForWrite.Clear();
|
{
|
||||||
componentWritePriorities.Clear();
|
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 componentStore.All<TComponent>().Select(pair => pair.Item2);
|
||||||
{
|
|
||||||
return idSet;
|
|
||||||
}
|
|
||||||
return Enumerable.Empty<Guid>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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 componentStore.Get<TComponent>(entity);
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal bool EntityHasComponentOfType<TComponent>(Entity entity) where TComponent : struct, IComponent
|
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
|
internal bool ComponentOfTypeExists<TComponent>() where TComponent : struct, IComponent
|
||||||
{
|
{
|
||||||
if (typeToComponentIDs.TryGetValue(typeof(TComponent), out HashSet<Guid> idSet))
|
return componentStore.Any<TComponent>();
|
||||||
{
|
|
||||||
return idSet.Count > 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
internal void MarkAllComponentsOnEntityForRemoval(Entity entity)
|
||||||
}
|
|
||||||
|
|
||||||
internal IComponent GetComponentByID(Guid componentID)
|
|
||||||
{
|
{
|
||||||
if (IDToComponent.ContainsKey(componentID))
|
entitiesMarkedForRemoval.Add(entity);
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void RemoveMarkedComponents()
|
internal void RemoveMarkedComponents()
|
||||||
{
|
{
|
||||||
foreach (var componentID in componentsMarkedForRemoval)
|
foreach (var entity in entitiesMarkedForRemoval)
|
||||||
{
|
{
|
||||||
if (componentIDsMarkedForWrite.Contains(componentID))
|
componentStore.Remove(entity);
|
||||||
|
drawLayerManager.UnRegisterEntityWithLayer(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
entitiesMarkedForRemoval.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Remove<TComponent>(Entity entity) where TComponent : struct, IComponent
|
||||||
{
|
{
|
||||||
componentIDsMarkedForWrite.Remove(componentID);
|
componentUpdateManager.Remove<TComponent>(entity);
|
||||||
}
|
drawLayerManager.UnRegisterComponentWithLayer<TComponent>(entity);
|
||||||
|
|
||||||
if (IDToComponent.ContainsKey(componentID))
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 SortedList<int, int> layerOrder = new SortedList<int, int>();
|
||||||
|
|
||||||
private readonly Dictionary<int, HashSet<Guid>> layerIndexToComponentIDs = new Dictionary<int, HashSet<Guid>>();
|
private readonly Dictionary<int, ComponentStore> layerIndexToComponentStore = new Dictionary<int, ComponentStore>(512);
|
||||||
private readonly Dictionary<int, HashSet<GeneralRenderer>> layerIndexToGeneralRenderers = new Dictionary<int, HashSet<GeneralRenderer>>();
|
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; } }
|
public IEnumerable<int> LayerOrder { get { return layerOrder.Values; } }
|
||||||
|
|
||||||
|
@ -49,23 +49,28 @@ namespace Encompass
|
||||||
RegisterGeneralRendererWithLayer(renderer, newLayer);
|
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];
|
var set = layerIndexToComponentStore[layer];
|
||||||
set.Add(id);
|
set.Set<TComponent>(entity, component);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var set = new HashSet<Guid>();
|
var set = new ComponentStore();
|
||||||
layerIndexToComponentIDs.Add(layer, set);
|
layerIndexToComponentStore.Add(layer, set);
|
||||||
set.Add(id);
|
set.Set<TComponent>(entity, component);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentIDToLayerIndex[id] = layer;
|
typeToEntityToLayer[typeof(TComponent)].Add(entity, layer);
|
||||||
|
|
||||||
if (!layerOrder.ContainsKey(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];
|
var layer = typeToEntityToLayer[typeof(TComponent)][entity];
|
||||||
layerIndexToComponentIDs[layer].Remove(id);
|
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) ?
|
foreach (var store in layerIndexToComponentStore.Values)
|
||||||
layerIndexToComponentIDs[layer] :
|
{
|
||||||
Enumerable.Empty<Guid>();
|
store.Remove(entity);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<GeneralRenderer> GeneralRenderersByLayer(int layer)
|
public IEnumerable<GeneralRenderer> GeneralRenderersByLayer(int layer)
|
||||||
|
@ -96,5 +104,12 @@ namespace Encompass
|
||||||
layerIndexToGeneralRenderers[layer] :
|
layerIndexToGeneralRenderers[layer] :
|
||||||
Enumerable.Empty<GeneralRenderer>();
|
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 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> sendTypes = new HashSet<Type>();
|
||||||
internal readonly HashSet<Type> receiveTypes = 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 Dictionary<Type, int> writePriorities = new Dictionary<Type, int>();
|
||||||
|
internal readonly int defaultWritePriority = 0;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// If false, the Engine will ignore time dilation.
|
/// If false, the Engine will ignore time dilation.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal bool usesTimeDilation = true;
|
internal bool usesTimeDilation = true;
|
||||||
public bool TimeDilationActive { get => usesTimeDilation && timeManager.TimeDilationActive; }
|
public bool TimeDilationActive { get => usesTimeDilation && timeManager.TimeDilationActive; }
|
||||||
/// <summary>
|
|
||||||
/// Used when activating time dilation. Lower priority overrides higher priority.
|
|
||||||
/// </summary>
|
|
||||||
|
|
||||||
private EntityManager entityManager;
|
private EntityManager entityManager;
|
||||||
private MessageManager messageManager;
|
private MessageManager messageManager;
|
||||||
private ComponentManager componentManager;
|
private ComponentManager componentManager;
|
||||||
private ComponentMessageManager componentMessageManager;
|
private ComponentUpdateManager componentUpdateManager;
|
||||||
private TimeManager timeManager;
|
private TimeManager timeManager;
|
||||||
|
|
||||||
protected Engine()
|
protected Engine()
|
||||||
|
@ -47,13 +49,19 @@ namespace Encompass
|
||||||
var activatesAttribute = GetType().GetCustomAttribute<WritesPending>(false);
|
var activatesAttribute = GetType().GetCustomAttribute<WritesPending>(false);
|
||||||
if (activatesAttribute != null)
|
if (activatesAttribute != null)
|
||||||
{
|
{
|
||||||
sendTypes.UnionWith(activatesAttribute.writePendingTypes);
|
writePendingTypes = activatesAttribute.writePendingTypes;
|
||||||
}
|
}
|
||||||
|
|
||||||
var writesAttributes = GetType().GetCustomAttributes<Writes>(false);
|
var defaultWritePriorityAttribute = GetType().GetCustomAttribute<DefaultWritePriority>(false);
|
||||||
foreach (var writesAttribute in writesAttributes)
|
|
||||||
|
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);
|
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);
|
var readsAttribute = GetType().GetCustomAttribute<Reads>(false);
|
||||||
if (readsAttribute != null)
|
if (readsAttribute != null)
|
||||||
{
|
{
|
||||||
receiveTypes.UnionWith(readsAttribute.readTypes);
|
readTypes = readsAttribute.readTypes;
|
||||||
}
|
}
|
||||||
|
|
||||||
var readsPendingAttribute = GetType().GetCustomAttribute<ReadsPending>(false);
|
var readsPendingAttribute = GetType().GetCustomAttribute<ReadsPending>(false);
|
||||||
if (readsPendingAttribute != null)
|
if (readsPendingAttribute != null)
|
||||||
{
|
{
|
||||||
receiveTypes.UnionWith(readsPendingAttribute.readPendingTypes);
|
readPendingTypes = readsPendingAttribute.readPendingTypes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool Equals(object obj)
|
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;
|
return false;
|
||||||
|
@ -111,9 +119,9 @@ namespace Encompass
|
||||||
this.messageManager = messageManager;
|
this.messageManager = messageManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void AssignComponentMessageManager(ComponentMessageManager componentMessageManager)
|
internal void AssignComponentUpdateManager(ComponentUpdateManager componentUpdateManager)
|
||||||
{
|
{
|
||||||
this.componentMessageManager = componentMessageManager;
|
this.componentUpdateManager = componentUpdateManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void AssignTimeManager(TimeManager timeManager)
|
internal void AssignTimeManager(TimeManager timeManager)
|
||||||
|
@ -154,37 +162,12 @@ namespace Encompass
|
||||||
return entityManager.GetEntity(entityID);
|
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>
|
/// <summary>
|
||||||
/// Returns an Entity containing the specified Component type.
|
/// Returns an Entity containing the specified Component type.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected Entity ReadEntity<TComponent>() where TComponent : struct, IComponent
|
protected Entity ReadEntity<TComponent>() where TComponent : struct, IComponent
|
||||||
{
|
{
|
||||||
var (id, component) = ReadComponentHelper<TComponent>();
|
return ReadComponentHelper<TComponent>().Item1;
|
||||||
return GetEntityByComponentID<TComponent>(id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -192,60 +175,31 @@ namespace Encompass
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected IEnumerable<Entity> ReadEntities<TComponent>() where TComponent : struct, IComponent
|
protected IEnumerable<Entity> ReadEntities<TComponent>() where TComponent : struct, IComponent
|
||||||
{
|
{
|
||||||
foreach (var (id, _) in ReadComponentsHelper<TComponent>())
|
return ReadComponentsHelper<TComponent>().Select(pair => pair.Item1);
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// these next two are for the ComponentMessageEmitter only
|
// 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>();
|
return componentManager.GetComponentsByType<TComponent>();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal Entity ReadEntityFromWorld(Guid componentID)
|
private IEnumerable<(Entity, TComponent)> ReadComponentsHelper<TComponent>() where TComponent : struct, IComponent
|
||||||
{
|
{
|
||||||
return GetEntity(componentManager.GetEntityIDByComponentID(componentID));
|
var pendingRead = readPendingTypes.Contains(typeof(TComponent));
|
||||||
}
|
var existingRead = readTypes.Contains(typeof(TComponent));
|
||||||
|
|
||||||
private IEnumerable<(Guid, TComponent)> ReadComponentsHelper<TComponent>() where TComponent : struct, IComponent
|
|
||||||
{
|
|
||||||
var pendingRead = receiveTypes.Contains(typeof(PendingComponentMessage<TComponent>));
|
|
||||||
var existingRead = receiveTypes.Contains(typeof(ComponentMessage<TComponent>));
|
|
||||||
if (existingRead && pendingRead)
|
if (existingRead && pendingRead)
|
||||||
{
|
{
|
||||||
return componentMessageManager.ReadExistingAndPendingComponentsByType<TComponent>();
|
return componentUpdateManager.ReadExistingAndPendingComponentsByType<TComponent>();
|
||||||
}
|
}
|
||||||
else if (existingRead)
|
else if (existingRead)
|
||||||
{
|
{
|
||||||
return componentMessageManager.ReadExistingComponentsByType<TComponent>();
|
return componentUpdateManager.ReadExistingComponentsByType<TComponent>();
|
||||||
}
|
}
|
||||||
else if (pendingRead)
|
else if (pendingRead)
|
||||||
{
|
{
|
||||||
return componentMessageManager.ReadPendingComponentsByType<TComponent>();
|
return componentUpdateManager.ReadPendingComponentsByType<TComponent>();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -266,24 +220,29 @@ namespace Encompass
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected IEnumerable<(TComponent, Entity)> ReadComponentsIncludingEntity<TComponent>() where TComponent : struct, IComponent
|
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>));
|
return componentManager.GetComponentsIncludingEntity<TComponent>();
|
||||||
var existingRead = receiveTypes.Contains(typeof(ComponentMessage<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)
|
if (existingRead && pendingRead)
|
||||||
{
|
{
|
||||||
return componentMessageManager.ReadFirstExistingOrPendingComponentByType<TComponent>();
|
return componentUpdateManager.ReadFirstExistingOrPendingComponentByType<TComponent>();
|
||||||
}
|
}
|
||||||
else if (existingRead)
|
else if (existingRead)
|
||||||
{
|
{
|
||||||
return componentMessageManager.ReadFirstExistingComponentByType<TComponent>();
|
return componentUpdateManager.ReadFirstExistingComponentByType<TComponent>();
|
||||||
}
|
}
|
||||||
else if (pendingRead)
|
else if (pendingRead)
|
||||||
{
|
{
|
||||||
return componentMessageManager.ReadFirstPendingComponentByType<TComponent>();
|
return componentUpdateManager.ReadFirstPendingComponentByType<TComponent>();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -304,8 +263,8 @@ namespace Encompass
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected (TComponent, Entity) ReadComponentIncludingEntity<TComponent>() where TComponent : struct, IComponent
|
protected (TComponent, Entity) ReadComponentIncludingEntity<TComponent>() where TComponent : struct, IComponent
|
||||||
{
|
{
|
||||||
var (id, component) = ReadComponentHelper<TComponent>();
|
var (entity, component) = ReadComponentHelper<TComponent>();
|
||||||
return (component, GetEntityByComponentID<TComponent>(id));
|
return (component, entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -313,19 +272,19 @@ namespace Encompass
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected bool SomeComponent<TComponent>() where TComponent : struct, IComponent
|
protected bool SomeComponent<TComponent>() where TComponent : struct, IComponent
|
||||||
{
|
{
|
||||||
var pendingRead = receiveTypes.Contains(typeof(PendingComponentMessage<TComponent>));
|
var pendingRead = readPendingTypes.Contains(typeof(TComponent));
|
||||||
var existingRead = receiveTypes.Contains(typeof(ComponentMessage<TComponent>));
|
var existingRead = readTypes.Contains(typeof(TComponent));
|
||||||
if (existingRead && pendingRead)
|
if (existingRead && pendingRead)
|
||||||
{
|
{
|
||||||
return componentMessageManager.SomeExistingOrPendingComponent<TComponent>();
|
return componentUpdateManager.SomeExistingOrPendingComponent<TComponent>();
|
||||||
}
|
}
|
||||||
else if (existingRead)
|
else if (existingRead)
|
||||||
{
|
{
|
||||||
return componentMessageManager.SomeExistingComponent<TComponent>();
|
return componentUpdateManager.SomeExistingComponent<TComponent>();
|
||||||
}
|
}
|
||||||
else if (pendingRead)
|
else if (pendingRead)
|
||||||
{
|
{
|
||||||
return componentMessageManager.SomePendingComponent<TComponent>();
|
return componentUpdateManager.SomePendingComponent<TComponent>();
|
||||||
}
|
}
|
||||||
else
|
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 pendingRead = readPendingTypes.Contains(typeof(TComponent));
|
||||||
var existingRead = receiveTypes.Contains(typeof(ComponentMessage<TComponent>));
|
var existingRead = readTypes.Contains(typeof(TComponent));
|
||||||
if (existingRead && pendingRead)
|
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
|
else
|
||||||
{
|
{
|
||||||
|
@ -354,11 +313,11 @@ namespace Encompass
|
||||||
}
|
}
|
||||||
else if (existingRead)
|
else if (existingRead)
|
||||||
{
|
{
|
||||||
return componentMessageManager.ReadExistingComponentByEntityAndType<TComponent>(entity);
|
return componentUpdateManager.ReadExistingComponentByEntityAndType<TComponent>(entity);
|
||||||
}
|
}
|
||||||
else if (pendingRead)
|
else if (pendingRead)
|
||||||
{
|
{
|
||||||
return componentMessageManager.ReadPendingComponentByEntityAndType<TComponent>(entity);
|
return componentUpdateManager.ReadPendingComponentByEntityAndType<TComponent>(entity);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -377,58 +336,7 @@ namespace Encompass
|
||||||
/// </exception>
|
/// </exception>
|
||||||
protected TComponent GetComponent<TComponent>(Entity entity) where TComponent : struct, IComponent
|
protected TComponent GetComponent<TComponent>(Entity entity) where TComponent : struct, IComponent
|
||||||
{
|
{
|
||||||
return GetComponentHelper<TComponent>(entity).Item2;
|
return GetComponentHelper<TComponent>(entity);
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -439,20 +347,20 @@ namespace Encompass
|
||||||
/// </exception>
|
/// </exception>
|
||||||
protected bool HasComponent<TComponent>(Entity entity) where TComponent : struct, IComponent
|
protected bool HasComponent<TComponent>(Entity entity) where TComponent : struct, IComponent
|
||||||
{
|
{
|
||||||
var pendingRead = receiveTypes.Contains(typeof(PendingComponentMessage<TComponent>));
|
var pendingRead = readPendingTypes.Contains(typeof(TComponent));
|
||||||
var existingRead = receiveTypes.Contains(typeof(ComponentMessage<TComponent>));
|
var existingRead = readTypes.Contains(typeof(TComponent));
|
||||||
|
|
||||||
if (pendingRead && existingRead)
|
if (pendingRead && existingRead)
|
||||||
{
|
{
|
||||||
return componentMessageManager.HasExistingOrPendingComponent<TComponent>(entity);
|
return componentUpdateManager.HasExistingOrPendingComponent<TComponent>(entity);
|
||||||
}
|
}
|
||||||
else if (existingRead)
|
else if (existingRead)
|
||||||
{
|
{
|
||||||
return componentMessageManager.HasExistingComponent<TComponent>(entity);
|
return componentUpdateManager.HasExistingComponent<TComponent>(entity);
|
||||||
}
|
}
|
||||||
else if (pendingRead)
|
else if (pendingRead)
|
||||||
{
|
{
|
||||||
return componentMessageManager.HasPendingComponent<TComponent>(entity);
|
return componentUpdateManager.HasPendingComponent<TComponent>(entity);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -468,23 +376,20 @@ namespace Encompass
|
||||||
/// </exception>
|
/// </exception>
|
||||||
protected bool HasComponent(Entity entity, Type type)
|
protected bool HasComponent(Entity entity, Type type)
|
||||||
{
|
{
|
||||||
var pending = typeof(PendingComponentMessage<>).MakeGenericType(type);
|
var pendingRead = readPendingTypes.Contains(type);
|
||||||
var existing = typeof(ComponentMessage<>).MakeGenericType(type);
|
var existingRead = readTypes.Contains(type);
|
||||||
|
|
||||||
var pendingRead = receiveTypes.Contains(pending);
|
|
||||||
var existingRead = receiveTypes.Contains(existing);
|
|
||||||
|
|
||||||
if (pendingRead && existingRead)
|
if (pendingRead && existingRead)
|
||||||
{
|
{
|
||||||
return componentMessageManager.HasExistingOrPendingComponent(entity, type);
|
return componentUpdateManager.HasExistingOrPendingComponent(entity, type);
|
||||||
}
|
}
|
||||||
else if (existingRead)
|
else if (existingRead)
|
||||||
{
|
{
|
||||||
return componentMessageManager.HasExistingComponent(entity, type);
|
return componentUpdateManager.HasExistingComponent(entity, type);
|
||||||
}
|
}
|
||||||
else if (pendingRead)
|
else if (pendingRead)
|
||||||
{
|
{
|
||||||
return componentMessageManager.HasPendingComponent(entity, type);
|
return componentUpdateManager.HasPendingComponent(entity, type);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -500,28 +405,26 @@ namespace Encompass
|
||||||
/// </exception>
|
/// </exception>
|
||||||
protected void SetComponent<TComponent>(Entity entity, TComponent component) where TComponent : struct, IComponent
|
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 (!writeTypes.Contains(typeof(TComponent)))
|
||||||
|
|
||||||
if (!sendTypes.Contains(typeof(ComponentWriteMessage<TComponent>)))
|
|
||||||
{
|
{
|
||||||
throw new IllegalWriteException("Engine {0} tried to update undeclared Component {1}", GetType().Name, typeof(TComponent).Name);
|
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;
|
written = AddPendingComponent(entity, component, priority);
|
||||||
newComponentMessage.entity = entity;
|
}
|
||||||
newComponentMessage.componentID = componentID;
|
else
|
||||||
newComponentMessage.component = component;
|
{
|
||||||
newComponentMessage.priority = priority;
|
written = componentUpdateManager.UpdateComponent(entity, component, priority);
|
||||||
SendPendingComponentMessage(newComponentMessage);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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>
|
/// <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
|
protected void SendMessage<TMessage>(TMessage message, double time) where TMessage : struct, IMessage
|
||||||
{
|
{
|
||||||
messageManager.AddMessageDelayed(message, time);
|
messageManager.AddMessage(message, time);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -556,30 +459,17 @@ namespace Encompass
|
||||||
/// <param name="time">The time in seconds that will elapse before the message is sent.</param>
|
/// <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
|
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
|
internal void AddExistingComponent<TComponent>(Entity entity, TComponent component) where TComponent : struct, IComponent
|
||||||
protected void SendMessage(IMessage message)
|
|
||||||
{
|
{
|
||||||
var type = message.GetType();
|
componentUpdateManager.AddExistingComponent(entity, component);
|
||||||
|
|
||||||
if (!sendTypes.Contains(type) || !type.IsValueType)
|
|
||||||
{
|
|
||||||
throw new IllegalSendException("Engine {0} tried to send undeclared Message {1}", GetType().Name, type.Name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
messageManager.AddMessage(message);
|
internal bool AddPendingComponent<TComponent>(Entity entity, TComponent component, int priority) where TComponent : struct, IComponent
|
||||||
}
|
|
||||||
|
|
||||||
internal void SendExistingComponentMessage<TComponent>(ComponentMessage<TComponent> message) where TComponent : struct, IComponent
|
|
||||||
{
|
{
|
||||||
componentMessageManager.AddExistingComponentMessage(message);
|
return componentUpdateManager.AddPendingComponent(entity, component, priority);
|
||||||
}
|
|
||||||
|
|
||||||
internal void SendPendingComponentMessage<TComponent>(PendingComponentMessage<TComponent> message) where TComponent : struct, IComponent
|
|
||||||
{
|
|
||||||
componentMessageManager.AddPendingComponentMessage(message);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -606,7 +496,7 @@ namespace Encompass
|
||||||
/// </exception>
|
/// </exception>
|
||||||
protected TMessage ReadMessage<TMessage>() where TMessage : struct, IMessage
|
protected TMessage ReadMessage<TMessage>() where TMessage : struct, IMessage
|
||||||
{
|
{
|
||||||
return ReadMessages<TMessage>().First();
|
return messageManager.First<TMessage>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -622,16 +512,7 @@ namespace Encompass
|
||||||
throw new IllegalReadException("Engine {0} tried to read undeclared Message {1}", GetType().Name, typeof(TMessage).Name);
|
throw new IllegalReadException("Engine {0} tried to read undeclared Message {1}", GetType().Name, typeof(TMessage).Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ReadMessages<TMessage>().Any();
|
return messageManager.Any<TMessage>();
|
||||||
}
|
|
||||||
|
|
||||||
/// <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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -640,7 +521,7 @@ namespace Encompass
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected void Destroy(Entity entity)
|
protected void Destroy(Entity entity)
|
||||||
{
|
{
|
||||||
entityManager.MarkForDestroy(entity.ID);
|
entityManager.MarkForDestroy(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -673,21 +554,10 @@ namespace Encompass
|
||||||
{
|
{
|
||||||
if (!HasComponent<TComponent>(entity)) { return false; }
|
if (!HasComponent<TComponent>(entity)) { return false; }
|
||||||
|
|
||||||
var (componentID, component) = GetComponentHelper<TComponent>(entity);
|
componentManager.Remove<TComponent>(entity);
|
||||||
|
|
||||||
RemoveComponent(componentID);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Removes the Component with the specified ID from its Entity.
|
|
||||||
/// </summary>
|
|
||||||
private void RemoveComponent(Guid componentID)
|
|
||||||
{
|
|
||||||
componentManager.MarkForRemoval(componentID);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Activates the Encompass time dilation system.
|
/// Activates the Encompass time dilation system.
|
||||||
/// Engines that have the IgnoresTimeDilation property will ignore all time dilation.
|
/// 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)
|
internal Entity(Guid id)
|
||||||
{
|
{
|
||||||
this.ID = id;
|
ID = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool Equals(object obj)
|
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;
|
return false;
|
||||||
|
|
|
@ -7,17 +7,15 @@ namespace Encompass
|
||||||
{
|
{
|
||||||
internal class EntityManager
|
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 ComponentManager componentManager;
|
||||||
private readonly ComponentMessageManager componentMessageManager;
|
|
||||||
|
|
||||||
public EntityManager(ComponentManager componentManager, ComponentMessageManager componentMessageManager)
|
public EntityManager(ComponentManager componentManager)
|
||||||
{
|
{
|
||||||
this.componentManager = componentManager;
|
this.componentManager = componentManager;
|
||||||
this.componentMessageManager = componentMessageManager;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Entity CreateEntity()
|
public Entity CreateEntity()
|
||||||
|
@ -25,8 +23,6 @@ namespace Encompass
|
||||||
var id = NextID();
|
var id = NextID();
|
||||||
var entity = new Entity(id);
|
var entity = new Entity(id);
|
||||||
IDToEntity[id] = entity;
|
IDToEntity[id] = entity;
|
||||||
componentManager.RegisterEntity(id);
|
|
||||||
componentMessageManager.RegisterEntity(entity);
|
|
||||||
return 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()
|
public void DestroyMarkedEntities()
|
||||||
{
|
{
|
||||||
foreach (var entityID in entitiesMarkedForDestroy)
|
foreach (var entity in entitiesMarkedForDestroy)
|
||||||
{
|
{
|
||||||
componentMessageManager.RegisterDestroyedEntity(GetEntity(entityID));
|
componentManager.MarkAllComponentsOnEntityForRemoval(entity);
|
||||||
componentManager.MarkAllComponentsOnEntityForRemoval(entityID);
|
IDToEntity.Remove(entity.ID);
|
||||||
IDToEntity.Remove(entityID);
|
|
||||||
componentManager.RegisterDestroyedEntity(entityID);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
entitiesMarkedForDestroy.Clear();
|
entitiesMarkedForDestroy.Clear();
|
||||||
|
|
|
@ -1,102 +1,55 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
|
|
||||||
namespace Encompass
|
namespace Encompass
|
||||||
{
|
{
|
||||||
internal class MessageManager
|
internal class MessageManager
|
||||||
{
|
{
|
||||||
private TimeManager timeManager;
|
private readonly TimeManager timeManager;
|
||||||
|
private readonly MessageStore messageStore = new MessageStore();
|
||||||
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)>();
|
|
||||||
|
|
||||||
public MessageManager(TimeManager timeManager)
|
public MessageManager(TimeManager timeManager)
|
||||||
{
|
{
|
||||||
this.timeManager = timeManager;
|
this.timeManager = timeManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void RegisterMessageType(Type messageType)
|
internal void AddMessage<TMessage>(TMessage message) where TMessage : struct, IMessage
|
||||||
{
|
{
|
||||||
if (!messageTypeToMessages.ContainsKey(messageType))
|
messageStore.AddMessage<TMessage>(message);
|
||||||
{
|
|
||||||
messageTypeToMessages.Add(messageType, new List<IMessage>());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void AddMessage(IMessage message)
|
internal void AddMessage<TMessage>(TMessage message, double time) where TMessage : struct, IMessage
|
||||||
{
|
{
|
||||||
var type = message.GetType();
|
messageStore.AddMessage(message, time);
|
||||||
|
|
||||||
messageTypeToMessages[type].Add(message);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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>()); }
|
messageStore.AddMessageIgnoringTimeDilation(message, time);
|
||||||
|
|
||||||
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));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void ClearMessages()
|
internal void ClearMessages()
|
||||||
{
|
{
|
||||||
foreach (var entry in messageTypeToMessages)
|
messageStore.ClearAll();
|
||||||
{
|
|
||||||
entry.Value.Clear();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void ProcessDelayedMessages(double dt)
|
internal void ProcessDelayedMessages(double dt)
|
||||||
{
|
{
|
||||||
for (int i = delayedMessages.Count - 1; i >= 0; i--)
|
messageStore.ProcessDelayedMessages(dt * timeManager.TimeDilationFactor, dt);
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal IEnumerable<TMessage> GetMessagesByType<TMessage>() where TMessage : struct, IMessage
|
internal IEnumerable<TMessage> GetMessagesByType<TMessage>() where TMessage : struct, IMessage
|
||||||
{
|
{
|
||||||
return messageTypeToMessages.ContainsKey(typeof(TMessage)) ?
|
return messageStore.All<TMessage>();
|
||||||
messageTypeToMessages[typeof(TMessage)].Cast<TMessage>() :
|
}
|
||||||
Enumerable.Empty<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;
|
||||||
using System.Reflection;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Encompass
|
namespace Encompass
|
||||||
{
|
{
|
||||||
internal class RenderManager
|
internal class RenderManager
|
||||||
{
|
{
|
||||||
private readonly ComponentManager componentManager;
|
|
||||||
private readonly DrawLayerManager drawLayerManager;
|
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(
|
public RenderManager(DrawLayerManager drawLayerManager)
|
||||||
ComponentManager componentManager,
|
|
||||||
DrawLayerManager drawLayerManager,
|
|
||||||
EntityManager entityManager
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
this.componentManager = componentManager;
|
|
||||||
this.drawLayerManager = drawLayerManager;
|
this.drawLayerManager = drawLayerManager;
|
||||||
this.entityManager = entityManager;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RegisterOrderedRenderer<TComponent>(Action<Entity, IComponent> renderAction) where TComponent : struct, IComponent
|
public void RegisterOrderedRenderer<TComponent>(Action<Entity, IComponent> renderAction) where TComponent : struct, IComponent
|
||||||
|
@ -37,16 +28,10 @@ namespace Encompass
|
||||||
{
|
{
|
||||||
foreach (var layer in drawLayerManager.LayerOrder)
|
foreach (var layer in drawLayerManager.LayerOrder)
|
||||||
{
|
{
|
||||||
var componentIDSet = drawLayerManager.ComponentIDsByLayer(layer);
|
|
||||||
var generalRendererSet = drawLayerManager.GeneralRenderersByLayer(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))
|
if (drawComponentTypeToOrderedRenderer.ContainsKey(componentType))
|
||||||
{
|
{
|
||||||
var internalRenderAction = drawComponentTypeToOrderedRenderer[componentType];
|
var internalRenderAction = drawComponentTypeToOrderedRenderer[componentType];
|
||||||
|
|
|
@ -19,11 +19,6 @@ namespace Encompass
|
||||||
this.componentManager = componentManager;
|
this.componentManager = componentManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal Guid GetEntityIDByComponentID(Guid componentID)
|
|
||||||
{
|
|
||||||
return componentManager.GetEntityIDByComponentID(componentID);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal Entity GetEntity(Guid entityID)
|
internal Entity GetEntity(Guid entityID)
|
||||||
{
|
{
|
||||||
return entityManager.GetEntity(entityID);
|
return entityManager.GetEntity(entityID);
|
||||||
|
@ -41,12 +36,12 @@ namespace Encompass
|
||||||
|
|
||||||
protected IEnumerable<TComponent> ReadComponents<TComponent>() where TComponent : struct, IComponent
|
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
|
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
|
protected TComponent ReadComponent<TComponent>() where TComponent : struct, IComponent
|
||||||
|
@ -61,7 +56,7 @@ namespace Encompass
|
||||||
|
|
||||||
protected TComponent GetComponent<TComponent>(Entity entity) where TComponent : struct, IComponent
|
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
|
protected bool HasComponent<TComponent>(Entity entity) where TComponent : struct, IComponent
|
||||||
|
|
|
@ -14,23 +14,21 @@ namespace Encompass
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
double calculatedFactor = 1;
|
|
||||||
|
|
||||||
if (elapsedTime < easeInTime)
|
if (elapsedTime < easeInTime)
|
||||||
{
|
{
|
||||||
calculatedFactor = easeInFunction(elapsedTime, 1, factor - 1, easeInTime);
|
return easeInFunction(elapsedTime, 1, factor - 1, easeInTime);
|
||||||
}
|
}
|
||||||
else if (elapsedTime < easeInTime + activeTime)
|
else if (elapsedTime < easeInTime + activeTime)
|
||||||
{
|
{
|
||||||
calculatedFactor = factor;
|
return factor;
|
||||||
}
|
}
|
||||||
else if (elapsedTime < easeInTime + activeTime + easeOutTime)
|
else if (elapsedTime < easeInTime + activeTime + easeOutTime)
|
||||||
{
|
{
|
||||||
var elapsedOutTime = elapsedTime - easeInTime - activeTime;
|
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
|
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)
|
private double Linear(double t, double b, double c, double d)
|
||||||
{
|
{
|
||||||
return c * t / d + b;
|
return (c * t / d) + b;
|
||||||
}
|
}
|
||||||
|
|
||||||
public double TimeDilationFactor
|
public double TimeDilationFactor
|
||||||
|
|
|
@ -11,7 +11,7 @@ namespace Encompass
|
||||||
private readonly EntityManager entityManager;
|
private readonly EntityManager entityManager;
|
||||||
private readonly ComponentManager componentManager;
|
private readonly ComponentManager componentManager;
|
||||||
private readonly MessageManager messageManager;
|
private readonly MessageManager messageManager;
|
||||||
private readonly ComponentMessageManager componentMessageManager;
|
private readonly ComponentUpdateManager componentUpdateManager;
|
||||||
private readonly TimeManager timeManager;
|
private readonly TimeManager timeManager;
|
||||||
private readonly RenderManager renderManager;
|
private readonly RenderManager renderManager;
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ namespace Encompass
|
||||||
EntityManager entityManager,
|
EntityManager entityManager,
|
||||||
ComponentManager componentManager,
|
ComponentManager componentManager,
|
||||||
MessageManager messageManager,
|
MessageManager messageManager,
|
||||||
ComponentMessageManager componentMessageManager,
|
ComponentUpdateManager componentUpdateManager,
|
||||||
TimeManager timeManager,
|
TimeManager timeManager,
|
||||||
RenderManager renderManager
|
RenderManager renderManager
|
||||||
)
|
)
|
||||||
|
@ -29,7 +29,7 @@ namespace Encompass
|
||||||
this.entityManager = entityManager;
|
this.entityManager = entityManager;
|
||||||
this.componentManager = componentManager;
|
this.componentManager = componentManager;
|
||||||
this.messageManager = messageManager;
|
this.messageManager = messageManager;
|
||||||
this.componentMessageManager = componentMessageManager;
|
this.componentUpdateManager = componentUpdateManager;
|
||||||
this.timeManager = timeManager;
|
this.timeManager = timeManager;
|
||||||
this.renderManager = renderManager;
|
this.renderManager = renderManager;
|
||||||
}
|
}
|
||||||
|
@ -56,11 +56,12 @@ namespace Encompass
|
||||||
}
|
}
|
||||||
|
|
||||||
messageManager.ClearMessages();
|
messageManager.ClearMessages();
|
||||||
componentMessageManager.ClearMessages();
|
|
||||||
entityManager.DestroyMarkedEntities();
|
entityManager.DestroyMarkedEntities();
|
||||||
|
|
||||||
componentManager.RemoveMarkedComponents();
|
|
||||||
componentManager.WriteComponents();
|
componentManager.WriteComponents();
|
||||||
|
componentManager.RemoveMarkedComponents();
|
||||||
|
|
||||||
|
componentUpdateManager.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -20,11 +20,13 @@ namespace Encompass
|
||||||
{
|
{
|
||||||
private readonly List<Engine> engines = new List<Engine>();
|
private readonly List<Engine> engines = new List<Engine>();
|
||||||
private readonly DirectedGraph<Engine, Unit> engineGraph = GraphBuilder.DirectedGraph<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 ComponentManager componentManager;
|
||||||
private readonly EntityManager entityManager;
|
private readonly EntityManager entityManager;
|
||||||
private readonly MessageManager messageManager;
|
private readonly MessageManager messageManager;
|
||||||
private readonly ComponentMessageManager componentMessageManager;
|
private readonly ComponentUpdateManager componentUpdateManager;
|
||||||
private readonly TimeManager timeManager;
|
private readonly TimeManager timeManager;
|
||||||
private readonly DrawLayerManager drawLayerManager;
|
private readonly DrawLayerManager drawLayerManager;
|
||||||
private readonly RenderManager renderManager;
|
private readonly RenderManager renderManager;
|
||||||
|
@ -39,11 +41,11 @@ namespace Encompass
|
||||||
{
|
{
|
||||||
drawLayerManager = new DrawLayerManager();
|
drawLayerManager = new DrawLayerManager();
|
||||||
timeManager = new TimeManager();
|
timeManager = new TimeManager();
|
||||||
componentManager = new ComponentManager(drawLayerManager);
|
componentUpdateManager = new ComponentUpdateManager();
|
||||||
|
componentManager = new ComponentManager(drawLayerManager, componentUpdateManager);
|
||||||
messageManager = new MessageManager(timeManager);
|
messageManager = new MessageManager(timeManager);
|
||||||
componentMessageManager = new ComponentMessageManager();
|
entityManager = new EntityManager(componentManager);
|
||||||
entityManager = new EntityManager(componentManager, componentMessageManager);
|
renderManager = new RenderManager(drawLayerManager);
|
||||||
renderManager = new RenderManager(componentManager, drawLayerManager, entityManager);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -67,25 +69,28 @@ namespace Encompass
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void SendMessage<TMessage>(TMessage message, double time) where TMessage : struct, IMessage
|
public void SendMessage<TMessage>(TMessage message, double time) where TMessage : struct, IMessage
|
||||||
{
|
{
|
||||||
messageManager.AddMessageDelayed(message, time);
|
messageManager.AddMessage<TMessage>(message, time);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets Component data for the specified Component Type on the specified Entity.
|
/// Sets Component data for the specified Component Type on the specified Entity.
|
||||||
/// </summary>
|
/// </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)
|
if (component is IDrawableComponent drawableComponent)
|
||||||
{
|
{
|
||||||
componentManager.RegisterDrawableComponent(componentID, drawableComponent);
|
componentManager.RegisterDrawableComponent(entity, component, drawableComponent.Layer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void RegisterComponent(Type componentType)
|
internal void RegisterComponent(Type componentType)
|
||||||
{
|
{
|
||||||
registeredComponentTypes.Add(componentType);
|
registeredComponentTypes.Add(componentType);
|
||||||
AddEngine((Engine)Activator.CreateInstance(typeof(ComponentMessageEmitter<>).MakeGenericType(componentType)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -97,7 +102,7 @@ namespace Encompass
|
||||||
engine.AssignEntityManager(entityManager);
|
engine.AssignEntityManager(entityManager);
|
||||||
engine.AssignComponentManager(componentManager);
|
engine.AssignComponentManager(componentManager);
|
||||||
engine.AssignMessageManager(messageManager);
|
engine.AssignMessageManager(messageManager);
|
||||||
engine.AssignComponentMessageManager(componentMessageManager);
|
engine.AssignComponentUpdateManager(componentUpdateManager);
|
||||||
engine.AssignTimeManager(timeManager);
|
engine.AssignTimeManager(timeManager);
|
||||||
|
|
||||||
engines.Add(engine);
|
engines.Add(engine);
|
||||||
|
@ -106,42 +111,28 @@ namespace Encompass
|
||||||
var messageReceiveTypes = engine.receiveTypes;
|
var messageReceiveTypes = engine.receiveTypes;
|
||||||
var messageSendTypes = engine.sendTypes;
|
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))
|
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);
|
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);
|
senders.Add(engine);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var receiveType in engine.receiveTypes)
|
foreach (var componentType in engine.readTypes.Union(engine.writeTypes).Union(engine.readPendingTypes))
|
||||||
{
|
|
||||||
if (receiveType.IsGenericType)
|
|
||||||
{
|
|
||||||
var genericTypeDefinition = receiveType.GetGenericTypeDefinition();
|
|
||||||
if (genericTypeDefinition == typeof(ComponentMessage<>) || genericTypeDefinition == typeof(PendingComponentMessage<>))
|
|
||||||
{
|
|
||||||
var componentType = receiveType.GetGenericArguments().Single();
|
|
||||||
if (!registeredComponentTypes.Contains(componentType))
|
|
||||||
{
|
{
|
||||||
RegisterComponent(componentType);
|
RegisterComponent(componentType);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
foreach (var receiveType in engine.receiveTypes.Union(engine.readPendingTypes))
|
||||||
|
{
|
||||||
if (!typeToReaders.ContainsKey(receiveType))
|
if (!typeToReaders.ContainsKey(receiveType))
|
||||||
{
|
{
|
||||||
typeToReaders.Add(receiveType, new HashSet<Engine>());
|
typeToReaders.Add(receiveType, new HashSet<Engine>());
|
||||||
|
@ -184,7 +175,7 @@ namespace Encompass
|
||||||
{
|
{
|
||||||
foreach (var senderEngine in senders)
|
foreach (var senderEngine in senders)
|
||||||
{
|
{
|
||||||
foreach (var messageType in senderEngine.sendTypes)
|
foreach (var messageType in senderEngine.sendTypes.Union(senderEngine.writePendingTypes))
|
||||||
{
|
{
|
||||||
if (typeToReaders.ContainsKey(messageType))
|
if (typeToReaders.ContainsKey(messageType))
|
||||||
{
|
{
|
||||||
|
@ -243,16 +234,12 @@ namespace Encompass
|
||||||
|
|
||||||
var defaultWritePriorityAttribute = engine.GetType().GetCustomAttribute<DefaultWritePriority>(false);
|
var defaultWritePriorityAttribute = engine.GetType().GetCustomAttribute<DefaultWritePriority>(false);
|
||||||
|
|
||||||
var writeTypes = engine.sendTypes.Where((type) => type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ComponentWriteMessage<>));
|
foreach (var writeType in engine.writeTypes)
|
||||||
|
|
||||||
foreach (var writeType in writeTypes)
|
|
||||||
{
|
{
|
||||||
var componentType = writeType.GetGenericArguments()[0];
|
|
||||||
|
|
||||||
int? priority = null;
|
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)
|
else if (defaultWritePriorityAttribute != null)
|
||||||
{
|
{
|
||||||
|
@ -261,44 +248,44 @@ namespace Encompass
|
||||||
|
|
||||||
if (priority.HasValue)
|
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
|
else
|
||||||
{
|
{
|
||||||
writePriorities[componentType].Add(priority.Value);
|
writePriorities[writeType].Add(priority.Value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (writtenComponentTypesWithoutPriority.Contains(componentType) || writtenComponentTypesWithPriority.Contains(componentType))
|
if (writtenComponentTypesWithoutPriority.Contains(writeType) || writtenComponentTypesWithPriority.Contains(writeType))
|
||||||
{
|
{
|
||||||
duplicateWritesWithoutPriority.Add(componentType);
|
duplicateWritesWithoutPriority.Add(writeType);
|
||||||
}
|
}
|
||||||
else
|
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>();
|
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())
|
foreach (var engine in engineGraph.TopologicalSort())
|
||||||
{
|
{
|
||||||
engineOrder.Add(engine);
|
engineOrder.Add(engine);
|
||||||
|
@ -341,13 +336,13 @@ namespace Encompass
|
||||||
entityManager,
|
entityManager,
|
||||||
componentManager,
|
componentManager,
|
||||||
messageManager,
|
messageManager,
|
||||||
componentMessageManager,
|
componentUpdateManager,
|
||||||
timeManager,
|
timeManager,
|
||||||
renderManager
|
renderManager
|
||||||
);
|
);
|
||||||
|
|
||||||
componentManager.RemoveMarkedComponents();
|
componentUpdateManager.SetStartingComponentStore(startingComponentStoreForComponentUpdateManager);
|
||||||
componentManager.WriteComponents();
|
componentManager.SetComponentStore(startingComponentStoreForComponentManager);
|
||||||
|
|
||||||
return world;
|
return world;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
<TargetFramework>netstandard2.0</TargetFramework>
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
<RootNamespace>Encompass</RootNamespace>
|
<RootNamespace>Encompass</RootNamespace>
|
||||||
<PackageId>EncompassECS.Framework</PackageId>
|
<PackageId>EncompassECS.Framework</PackageId>
|
||||||
<Version>0.17.0</Version>
|
<Version>0.18.0-preview8</Version>
|
||||||
<Authors>Evan Hemsley</Authors>
|
<Authors>Evan Hemsley</Authors>
|
||||||
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
|
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
|
||||||
<Company>Moonside Games</Company>
|
<Company>Moonside Games</Company>
|
||||||
|
@ -23,7 +23,6 @@
|
||||||
</None>
|
</None>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<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>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
@ -1,12 +1,7 @@
|
||||||
using System.ComponentModel;
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using FluentAssertions;
|
using FluentAssertions;
|
||||||
|
|
||||||
using Encompass;
|
using Encompass;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
using Encompass.Exceptions;
|
|
||||||
|
|
||||||
namespace Tests
|
namespace Tests
|
||||||
{
|
{
|
||||||
|
@ -89,16 +84,16 @@ namespace Tests
|
||||||
worldBuilder.AddEngine(new ReadMockComponentEngine());
|
worldBuilder.AddEngine(new ReadMockComponentEngine());
|
||||||
|
|
||||||
var entity = worldBuilder.CreateEntity();
|
var entity = worldBuilder.CreateEntity();
|
||||||
worldBuilder.SetComponent(entity, new MockComponent { myInt = 20, myString = "what" }, 2);
|
worldBuilder.SetComponent(entity, new MockComponent { myInt = 20, myString = "what" });
|
||||||
worldBuilder.SetComponent(entity, new MockComponent { myInt = 50, myString = "hi" }, 0);
|
worldBuilder.SetComponent(entity, new MockComponent { myInt = 50, myString = "hi" });
|
||||||
worldBuilder.SetComponent(entity, new MockComponent { myInt = 40, myString = "wassup" }, 1);
|
worldBuilder.SetComponent(entity, new MockComponent { myInt = 40, myString = "wassup" });
|
||||||
|
|
||||||
var world = worldBuilder.Build();
|
var world = worldBuilder.Build();
|
||||||
|
|
||||||
world.Update(0.01);
|
world.Update(0.01);
|
||||||
|
|
||||||
Assert.That(gottenMockComponent.myInt, Is.EqualTo(50));
|
Assert.That(gottenMockComponent.myInt, Is.EqualTo(40));
|
||||||
Assert.That(gottenMockComponent.myString, Is.EqualTo("hi"));
|
Assert.That(gottenMockComponent.myString, Is.EqualTo("wassup"));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Reads(typeof(MockComponent))]
|
[Reads(typeof(MockComponent))]
|
||||||
|
@ -267,45 +262,6 @@ namespace Tests
|
||||||
|
|
||||||
Assert.AreEqual(mockComponent, gottenMockComponent);
|
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
|
struct HasComponentTestMessage : IMessage
|
||||||
{
|
{
|
||||||
public Entity entity;
|
public Entity entity;
|
||||||
|
@ -347,6 +303,8 @@ namespace Tests
|
||||||
world.Update(0.01);
|
world.Update(0.01);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool hasComponentRuntimeTypeResult;
|
||||||
|
|
||||||
[Receives(typeof(HasComponentTestMessage))]
|
[Receives(typeof(HasComponentTestMessage))]
|
||||||
[Reads(typeof(MockComponent))]
|
[Reads(typeof(MockComponent))]
|
||||||
class HasComponentWithRuntimeTypeEngine : Engine
|
class HasComponentWithRuntimeTypeEngine : Engine
|
||||||
|
@ -355,7 +313,7 @@ namespace Tests
|
||||||
{
|
{
|
||||||
foreach (var hasComponentTestEngine in ReadMessages<HasComponentTestMessage>())
|
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();
|
var world = worldBuilder.Build();
|
||||||
|
|
||||||
world.Update(0.01);
|
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
|
struct RemoveComponentTestMessage : IMessage
|
||||||
|
@ -431,6 +410,8 @@ namespace Tests
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool hasComponentResult;
|
||||||
|
|
||||||
[Receives(typeof(CheckHasMockComponentMessage))]
|
[Receives(typeof(CheckHasMockComponentMessage))]
|
||||||
[Reads(typeof(MockComponent))]
|
[Reads(typeof(MockComponent))]
|
||||||
class CheckHasMockComponentEngine : Engine
|
class CheckHasMockComponentEngine : Engine
|
||||||
|
@ -439,13 +420,13 @@ namespace Tests
|
||||||
{
|
{
|
||||||
foreach (var checkHasMockComponentMessage in ReadMessages<CheckHasMockComponentMessage>())
|
foreach (var checkHasMockComponentMessage in ReadMessages<CheckHasMockComponentMessage>())
|
||||||
{
|
{
|
||||||
Assert.IsTrue(HasComponent<MockComponent>(checkHasMockComponentMessage.entity));
|
hasComponentResult = HasComponent<MockComponent>(checkHasMockComponentMessage.entity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void RemoveComponent()
|
public void RemovedComponentShouldStillExistOnSameFrame()
|
||||||
{
|
{
|
||||||
var worldBuilder = new WorldBuilder();
|
var worldBuilder = new WorldBuilder();
|
||||||
var entity = worldBuilder.CreateEntity();
|
var entity = worldBuilder.CreateEntity();
|
||||||
|
@ -467,6 +448,12 @@ namespace Tests
|
||||||
var world = worldBuilder.Build();
|
var world = worldBuilder.Build();
|
||||||
|
|
||||||
world.Update(0.01f);
|
world.Update(0.01f);
|
||||||
|
|
||||||
|
hasComponentResult.Should().BeTrue();
|
||||||
|
|
||||||
|
world.Update(0.01f);
|
||||||
|
|
||||||
|
hasComponentResult.Should().BeFalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
struct CheckHasMockComponentMessage : IMessage
|
struct CheckHasMockComponentMessage : IMessage
|
||||||
|
|
|
@ -557,7 +557,7 @@ namespace Tests
|
||||||
world.Update(0.01);
|
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, entity)));
|
Assert.That(results, Does.Not.Contain((mockComponent, entityB)));
|
||||||
Assert.That(results, Does.Contain((mockComponent, entityC)));
|
Assert.That(results, Does.Contain((mockComponent, entityC)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,6 +35,9 @@ namespace Tests
|
||||||
world.Update(0.01f);
|
world.Update(0.01f);
|
||||||
world.Draw();
|
world.Draw();
|
||||||
|
|
||||||
|
world.Update(0.01);
|
||||||
|
world.Draw();
|
||||||
|
|
||||||
Assert.That(result, Is.EqualTo((aComponent, entity)));
|
Assert.That(result, Is.EqualTo((aComponent, entity)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,7 +58,9 @@ namespace Tests
|
||||||
var world = worldBuilder.Build();
|
var world = worldBuilder.Build();
|
||||||
|
|
||||||
world.Update(0.01f);
|
world.Update(0.01f);
|
||||||
|
world.Draw();
|
||||||
|
|
||||||
|
world.Update(0.01f);
|
||||||
world.Draw();
|
world.Draw();
|
||||||
|
|
||||||
Assert.That(result, Is.EqualTo((aComponent, entity)).Or.EqualTo((aComponentTwo, entityB)));
|
Assert.That(result, Is.EqualTo((aComponent, entity)).Or.EqualTo((aComponentTwo, entityB)));
|
||||||
|
|
|
@ -223,14 +223,14 @@ namespace Tests
|
||||||
[Receives(typeof(SetMessage))]
|
[Receives(typeof(SetMessage))]
|
||||||
[Writes(typeof(AComponent))]
|
[Writes(typeof(AComponent))]
|
||||||
[WritesPending(typeof(AComponent))]
|
[WritesPending(typeof(AComponent))]
|
||||||
[Encompass.DefaultWritePriority(1)]
|
[Encompass.DefaultWritePriority(4)]
|
||||||
class AEngine : Engine
|
class AEngine : Engine
|
||||||
{
|
{
|
||||||
public override void Update(double dt)
|
public override void Update(double dt)
|
||||||
{
|
{
|
||||||
foreach (var setMessage in ReadMessages<SetMessage>())
|
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;
|
static AComponent resultComponent;
|
||||||
|
|
||||||
[ReadsPending(typeof(AComponent))]
|
[ReadsPending(typeof(AComponent))]
|
||||||
|
@ -267,6 +281,8 @@ namespace Tests
|
||||||
var worldBuilder = new WorldBuilder();
|
var worldBuilder = new WorldBuilder();
|
||||||
worldBuilder.AddEngine(new AEngine());
|
worldBuilder.AddEngine(new AEngine());
|
||||||
worldBuilder.AddEngine(new BEngine());
|
worldBuilder.AddEngine(new BEngine());
|
||||||
|
worldBuilder.AddEngine(new CEngine());
|
||||||
|
worldBuilder.AddEngine(new ReadComponentEngine());
|
||||||
|
|
||||||
var entity = worldBuilder.CreateEntity();
|
var entity = worldBuilder.CreateEntity();
|
||||||
worldBuilder.SendMessage(new SetMessage { entity = entity });
|
worldBuilder.SendMessage(new SetMessage { entity = entity });
|
||||||
|
@ -275,7 +291,7 @@ namespace Tests
|
||||||
|
|
||||||
world.Update(0.01);
|
world.Update(0.01);
|
||||||
|
|
||||||
Assert.That(resultComponent.myInt, Is.EqualTo(0));
|
Assert.That(resultComponent.myInt, Is.EqualTo(3));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue