the big ComponentMessage rework
parent
0b2ef55634
commit
a42123f58d
11
TODO
11
TODO
|
@ -1,11 +1,6 @@
|
||||||
- guard rail tests for nonexistent lookups in manager classes
|
- Change "Writes" To "Sends" and make it only take Messages
|
||||||
- custom exception for nonexistent Entity ID
|
- Add "Updates" for updating components
|
||||||
- custom exception for nonexistent Component ID
|
|
||||||
|
|
||||||
- special Engine kinds (detector, modifier, spawner)
|
- so we have four attributes: Activates, Reads, Updates, and Sends
|
||||||
|
|
||||||
- maybe AddEngine should take a constructed engine similarly to AddComponent?
|
|
||||||
|
|
||||||
- component getters should return ValueTuple instead of KeyValuePair so we can do destructuring assignments
|
|
||||||
|
|
||||||
- docs
|
- docs
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Encompass.Exceptions;
|
||||||
|
|
||||||
|
namespace Encompass
|
||||||
|
{
|
||||||
|
public class Activates : Attribute
|
||||||
|
{
|
||||||
|
public readonly HashSet<Type> activateTypes = new HashSet<Type>();
|
||||||
|
|
||||||
|
public Activates(params Type[] activateTypes)
|
||||||
|
{
|
||||||
|
foreach (var activateType in activateTypes)
|
||||||
|
{
|
||||||
|
var isComponent = activateType.GetInterfaces().Contains(typeof(IComponent));
|
||||||
|
if (!isComponent)
|
||||||
|
{
|
||||||
|
throw new IllegalActivateTypeException("{0} must be a Component", activateType.Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.activateTypes.Add(typeof(ComponentMessage<>).MakeGenericType(activateType));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,22 +5,32 @@ using Encompass.Exceptions;
|
||||||
|
|
||||||
namespace Encompass
|
namespace Encompass
|
||||||
{
|
{
|
||||||
[System.AttributeUsage(System.AttributeTargets.Class)]
|
[AttributeUsage(AttributeTargets.Class)]
|
||||||
public class Reads : System.Attribute
|
public class Reads : Attribute
|
||||||
{
|
{
|
||||||
public readonly HashSet<Type> readTypes;
|
public readonly HashSet<Type> readTypes = new HashSet<Type>();
|
||||||
|
|
||||||
public Reads(params Type[] readTypes)
|
public Reads(params Type[] readTypes)
|
||||||
{
|
{
|
||||||
foreach (var readType in readTypes)
|
foreach (var readType in readTypes)
|
||||||
{
|
{
|
||||||
if (!readType.GetInterfaces().Contains(typeof(IMessage)))
|
var isMessage = readType.GetInterfaces().Contains(typeof(IMessage));
|
||||||
|
var isComponent = readType.GetInterfaces().Contains(typeof(IComponent));
|
||||||
|
|
||||||
|
if (!isMessage && !isComponent)
|
||||||
{
|
{
|
||||||
throw new IllegalReadTypeException("{0} must be a Message", readType.Name);
|
throw new IllegalReadTypeException("{0} must be a Message or Component", readType.Name);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.readTypes = new HashSet<Type>(readTypes);
|
if (isComponent)
|
||||||
|
{
|
||||||
|
this.readTypes.Add(typeof(ComponentMessage<>).MakeGenericType(readType));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.readTypes.Add(readType);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,8 +62,7 @@ namespace Encompass
|
||||||
entityIDToComponentIDs[entityID].Add(componentID);
|
entityIDToComponentIDs[entityID].Add(componentID);
|
||||||
componentIDToEntityID[componentID] = entityID;
|
componentIDToEntityID[componentID] = entityID;
|
||||||
|
|
||||||
inactiveComponents.Add(componentID);
|
activeComponents.Add(componentID);
|
||||||
MarkForActivation(componentID);
|
|
||||||
|
|
||||||
entitiesWithAddedComponents.Add(entityID);
|
entitiesWithAddedComponents.Add(entityID);
|
||||||
|
|
||||||
|
@ -89,11 +88,11 @@ namespace Encompass
|
||||||
return GetComponentIDsByEntityID(entityID).Intersect(activeComponents).Select((id) => new ValueTuple<Guid, IComponent>(id, IDToComponent[id]));
|
return GetComponentIDsByEntityID(entityID).Intersect(activeComponents).Select((id) => new ValueTuple<Guid, IComponent>(id, IDToComponent[id]));
|
||||||
}
|
}
|
||||||
|
|
||||||
internal IEnumerable<ValueTuple<Guid, TComponent>> GetActiveComponentsByType<TComponent>() where TComponent : struct, IComponent
|
internal IEnumerable<ValueTuple<Guid, Guid, TComponent>> GetActiveComponentsByType<TComponent>() where TComponent : struct, IComponent
|
||||||
{
|
{
|
||||||
return typeToComponentIDs.ContainsKey(typeof(TComponent)) ?
|
return typeToComponentIDs.ContainsKey(typeof(TComponent)) ?
|
||||||
typeToComponentIDs[typeof(TComponent)].Intersect(activeComponents).Select((id) => new ValueTuple<Guid, TComponent>(id, (TComponent)IDToComponent[id])) :
|
typeToComponentIDs[typeof(TComponent)].Intersect(activeComponents).Select((id) => new ValueTuple<Guid, Guid, TComponent>(GetEntityIDByComponentID(id), id, (TComponent)IDToComponent[id])) :
|
||||||
Enumerable.Empty<ValueTuple<Guid, TComponent>>();
|
Enumerable.Empty<ValueTuple<Guid, Guid, TComponent>>();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal IEnumerable<ValueTuple<Guid, IComponent>> GetActiveComponentsByType(Type type)
|
internal IEnumerable<ValueTuple<Guid, IComponent>> GetActiveComponentsByType(Type type)
|
||||||
|
@ -103,16 +102,11 @@ namespace Encompass
|
||||||
Enumerable.Empty<ValueTuple<Guid, IComponent>>();
|
Enumerable.Empty<ValueTuple<Guid, IComponent>>();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal ValueTuple<Guid, TComponent> GetActiveComponentByType<TComponent>() where TComponent : struct, IComponent
|
|
||||||
{
|
|
||||||
return GetActiveComponentsByType<TComponent>().Single();
|
|
||||||
}
|
|
||||||
|
|
||||||
internal IEnumerable<ValueTuple<Guid, TComponent>> GetComponentsByEntityAndType<TComponent>(Guid entityID) where TComponent : struct, IComponent
|
internal IEnumerable<ValueTuple<Guid, TComponent>> GetComponentsByEntityAndType<TComponent>(Guid entityID) where TComponent : struct, IComponent
|
||||||
{
|
{
|
||||||
var entityComponentsByType = GetComponentsByEntity(entityID).Where((pair) => componentIDToType[pair.Item1] == typeof(TComponent)).Select((pair) => new ValueTuple<Guid, TComponent>(pair.Item1, (TComponent)pair.Item2));
|
var entityComponentsByType = GetComponentsByEntity(entityID).Where((pair) => componentIDToType[pair.Item1] == typeof(TComponent)).Select((pair) => new ValueTuple<Guid, TComponent>(pair.Item1, (TComponent)pair.Item2));
|
||||||
var activeComponentsByType = GetActiveComponentsByType<TComponent>();
|
var activeComponentsByType = GetActiveComponentsByType<TComponent>();
|
||||||
return activeComponentsByType.Intersect(entityComponentsByType);
|
return activeComponentsByType.Select((triple) => (triple.Item2, triple.Item3)).Intersect(entityComponentsByType);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal IEnumerable<ValueTuple<Guid, IComponent>> GetComponentsByEntityAndType(Guid entityID, Type type)
|
internal IEnumerable<ValueTuple<Guid, IComponent>> GetComponentsByEntityAndType(Guid entityID, Type type)
|
||||||
|
@ -180,22 +174,7 @@ namespace Encompass
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void MarkForActivation(Guid componentID)
|
internal void Activate(Guid componentID)
|
||||||
{
|
|
||||||
componentsMarkedForActivation.Add(componentID);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void ActivateMarkedComponents()
|
|
||||||
{
|
|
||||||
foreach (var componentID in componentsMarkedForActivation)
|
|
||||||
{
|
|
||||||
Activate(componentID);
|
|
||||||
}
|
|
||||||
|
|
||||||
componentsMarkedForActivation.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Activate(Guid componentID)
|
|
||||||
{
|
{
|
||||||
if (inactiveComponents.Remove(componentID))
|
if (inactiveComponents.Remove(componentID))
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Encompass
|
||||||
|
{
|
||||||
|
public struct ComponentMessage<TComponent> : IMessage where TComponent : struct, IComponent
|
||||||
|
{
|
||||||
|
public Entity entity;
|
||||||
|
public Guid componentID;
|
||||||
|
public TComponent component;
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,6 +10,7 @@ namespace Encompass
|
||||||
{
|
{
|
||||||
internal readonly HashSet<Type> writeTypes = new HashSet<Type>();
|
internal readonly HashSet<Type> writeTypes = new HashSet<Type>();
|
||||||
internal readonly HashSet<Type> readTypes = new HashSet<Type>();
|
internal readonly HashSet<Type> readTypes = new HashSet<Type>();
|
||||||
|
internal readonly HashSet<Type> activateTypes = new HashSet<Type>();
|
||||||
|
|
||||||
private EntityManager entityManager;
|
private EntityManager entityManager;
|
||||||
private ComponentManager componentManager;
|
private ComponentManager componentManager;
|
||||||
|
@ -28,6 +29,12 @@ namespace Encompass
|
||||||
{
|
{
|
||||||
readTypes = readsAttribute.readTypes;
|
readTypes = readsAttribute.readTypes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var activatesAttribute = GetType().GetCustomAttribute<Activates>(false);
|
||||||
|
if (activatesAttribute != null)
|
||||||
|
{
|
||||||
|
activateTypes = activatesAttribute.activateTypes;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void AssignEntityManager(EntityManager entityManager)
|
internal void AssignEntityManager(EntityManager entityManager)
|
||||||
|
@ -82,29 +89,64 @@ namespace Encompass
|
||||||
return (TComponent)componentManager.GetComponentByID(componentID);
|
return (TComponent)componentManager.GetComponentByID(componentID);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected IEnumerable<ValueTuple<Guid, TComponent>> ReadComponents<TComponent>() where TComponent : struct, IComponent
|
internal IEnumerable<ValueTuple<Entity, Guid, TComponent>> ReadComponentsFromWorld<TComponent>() where TComponent : struct, IComponent
|
||||||
{
|
{
|
||||||
return componentManager.GetActiveComponentsByType<TComponent>();
|
return componentManager.GetActiveComponentsByType<TComponent>().Select((triple) => (GetEntity(triple.Item1), triple.Item2, triple.Item3));
|
||||||
}
|
|
||||||
|
|
||||||
protected ValueTuple<Guid, TComponent> ReadComponent<TComponent>() where TComponent : struct, IComponent
|
|
||||||
{
|
|
||||||
return componentManager.GetActiveComponentByType<TComponent>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Guid AddComponent<TComponent>(Entity entity, TComponent component) where TComponent : struct, IComponent
|
protected Guid AddComponent<TComponent>(Entity entity, TComponent component) where TComponent : struct, IComponent
|
||||||
{
|
{
|
||||||
return componentManager.AddComponent(entity.ID, component);
|
if (!activateTypes.Contains(typeof(ComponentMessage<TComponent>)))
|
||||||
|
{
|
||||||
|
throw new IllegalActivateException("Engine {0} tried to activate undeclared Component {1}", GetType().Name, typeof(TComponent).Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
var componentID = componentManager.AddComponent(entity.ID, component);
|
||||||
|
|
||||||
|
ComponentMessage<TComponent> componentMessage;
|
||||||
|
componentMessage.entity = entity;
|
||||||
|
componentMessage.componentID = componentID;
|
||||||
|
componentMessage.component = component;
|
||||||
|
EmitMessage(componentMessage);
|
||||||
|
|
||||||
|
return componentID;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Guid AddDrawComponent<TComponent>(Entity entity, TComponent component, int layer = 0) where TComponent : struct, IComponent
|
protected Guid AddDrawComponent<TComponent>(Entity entity, TComponent component, int layer = 0) where TComponent : struct, IComponent
|
||||||
{
|
{
|
||||||
return componentManager.AddDrawComponent(entity.ID, component, layer);
|
if (!activateTypes.Contains(typeof(ComponentMessage<TComponent>)))
|
||||||
|
{
|
||||||
|
throw new IllegalActivateException("Engine {0} tried to activate undeclared Component {1}", GetType().Name, typeof(TComponent).Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void ActivateComponent(Guid componentID)
|
var componentID = componentManager.AddDrawComponent(entity.ID, component, layer);
|
||||||
|
|
||||||
|
ComponentMessage<TComponent> componentMessage;
|
||||||
|
componentMessage.entity = entity;
|
||||||
|
componentMessage.componentID = componentID;
|
||||||
|
componentMessage.component = component;
|
||||||
|
EmitMessage(componentMessage);
|
||||||
|
|
||||||
|
return componentID;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void ActivateComponent<TComponent>(Guid componentID) where TComponent : struct, IComponent
|
||||||
{
|
{
|
||||||
componentManager.MarkForActivation(componentID);
|
if (!activateTypes.Contains(typeof(ComponentMessage<TComponent>)))
|
||||||
|
{
|
||||||
|
throw new IllegalActivateException("Engine {0} tried to activate undeclared Component {1}", GetType().Name, typeof(TComponent).Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
var entity = GetEntity(componentManager.GetEntityIDByComponentID(componentID));
|
||||||
|
var component = GetComponentByID<TComponent>(componentID);
|
||||||
|
|
||||||
|
ComponentMessage<TComponent> componentMessage;
|
||||||
|
componentMessage.entity = entity;
|
||||||
|
componentMessage.componentID = componentID;
|
||||||
|
componentMessage.component = component;
|
||||||
|
EmitMessage(componentMessage);
|
||||||
|
|
||||||
|
componentManager.Activate(componentID);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void DeactivateComponent(Guid componentID)
|
protected void DeactivateComponent(Guid componentID)
|
||||||
|
@ -114,6 +156,11 @@ namespace Encompass
|
||||||
|
|
||||||
protected IEnumerable<ValueTuple<Guid, TComponent>> GetComponents<TComponent>(Entity entity) where TComponent : struct, IComponent
|
protected IEnumerable<ValueTuple<Guid, TComponent>> GetComponents<TComponent>(Entity entity) where TComponent : struct, IComponent
|
||||||
{
|
{
|
||||||
|
if (!readTypes.Contains(typeof(ComponentMessage<TComponent>)))
|
||||||
|
{
|
||||||
|
throw new IllegalReadException("Engine {0} tried to read undeclared Component {1}", GetType().Name, typeof(TComponent).Name);
|
||||||
|
}
|
||||||
|
|
||||||
return componentManager.GetComponentsByEntityAndType<TComponent>(entity.ID);
|
return componentManager.GetComponentsByEntityAndType<TComponent>(entity.ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -124,7 +171,12 @@ namespace Encompass
|
||||||
|
|
||||||
protected bool HasComponent<TComponent>(Entity entity) where TComponent : struct, IComponent
|
protected bool HasComponent<TComponent>(Entity entity) where TComponent : struct, IComponent
|
||||||
{
|
{
|
||||||
return componentManager.EntityHasComponentOfType<TComponent>(entity.ID);
|
if (!readTypes.Contains(typeof(ComponentMessage<TComponent>)))
|
||||||
|
{
|
||||||
|
throw new IllegalReadException("Engine {0} tried to read undeclared Component {1}", GetType().Name, typeof(TComponent).Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return messageManager.GetMessagesByType<ComponentMessage<TComponent>>().Where((message) => message.entity == entity).Any();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void UpdateComponentInWorld<TComponent>(Guid componentID, TComponent newComponent) where TComponent : struct, IComponent
|
internal void UpdateComponentInWorld<TComponent>(Guid componentID, TComponent newComponent) where TComponent : struct, IComponent
|
||||||
|
@ -162,11 +214,31 @@ namespace Encompass
|
||||||
return messageManager.GetMessagesByType<TMessage>();
|
return messageManager.GetMessagesByType<TMessage>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected TMessage ReadMessage<TMessage>() where TMessage : struct, IMessage
|
||||||
|
{
|
||||||
|
return ReadMessages<TMessage>().Single();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected IEnumerable<(Guid, TComponent)> ReadComponents<TComponent>() where TComponent : struct, IComponent
|
||||||
|
{
|
||||||
|
if (!readTypes.Contains(typeof(ComponentMessage<TComponent>)))
|
||||||
|
{
|
||||||
|
throw new IllegalReadException("Engine {0} tried to read undeclared Component {1}", this.GetType().Name, typeof(TComponent).Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ReadMessages<ComponentMessage<TComponent>>().Select((message) => (message.componentID, message.component));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected (Guid, TComponent) ReadComponent<TComponent>() where TComponent : struct, IComponent
|
||||||
|
{
|
||||||
|
return ReadComponents<TComponent>().Single();
|
||||||
|
}
|
||||||
|
|
||||||
protected bool SomeMessage<TMessage>() where TMessage : struct, IMessage
|
protected bool SomeMessage<TMessage>() where TMessage : struct, IMessage
|
||||||
{
|
{
|
||||||
if (!readTypes.Contains(typeof(TMessage)))
|
if (!readTypes.Contains(typeof(TMessage)))
|
||||||
{
|
{
|
||||||
throw new IllegalReadException("Engine {0} tried to read undeclared Message {1}", this.GetType().Name, typeof(TMessage).Name);
|
throw new IllegalReadException("Engine {0} tried to read undeclared Message {1}", GetType().Name, typeof(TMessage).Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
return messageManager.GetMessagesByType<TMessage>().Any();
|
return messageManager.GetMessagesByType<TMessage>().Any();
|
||||||
|
@ -174,6 +246,11 @@ namespace Encompass
|
||||||
|
|
||||||
protected bool SomeComponent<TComponent>() where TComponent : struct, IComponent
|
protected bool SomeComponent<TComponent>() where TComponent : struct, IComponent
|
||||||
{
|
{
|
||||||
|
if (!readTypes.Contains(typeof(ComponentMessage<TComponent>)))
|
||||||
|
{
|
||||||
|
throw new IllegalReadException("Engine {0} tried to read undeclared Component {1}", GetType().Name, typeof(TComponent).Name);
|
||||||
|
}
|
||||||
|
|
||||||
return componentManager.GetActiveComponentsByType<TComponent>().Any();
|
return componentManager.GetActiveComponentsByType<TComponent>().Any();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace Encompass.Engines
|
||||||
|
{
|
||||||
|
internal class ComponentMessageEmitter<TComponent> : Engine where TComponent : struct, IComponent
|
||||||
|
{
|
||||||
|
public ComponentMessageEmitter() : base()
|
||||||
|
{
|
||||||
|
var writesAttribute = GetType().GetCustomAttribute<Writes>(false);
|
||||||
|
if (writesAttribute != null)
|
||||||
|
{
|
||||||
|
writesAttribute.writeTypes.Add(typeof(ComponentMessage<TComponent>));
|
||||||
|
}
|
||||||
|
|
||||||
|
writeTypes.Add(typeof(ComponentMessage<TComponent>));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Update(double dt)
|
||||||
|
{
|
||||||
|
foreach (var (entity, componentID, component) in ReadComponentsFromWorld<TComponent>())
|
||||||
|
{
|
||||||
|
ComponentMessage<TComponent> componentMessage;
|
||||||
|
componentMessage.entity = entity;
|
||||||
|
componentMessage.componentID = componentID;
|
||||||
|
componentMessage.component = component;
|
||||||
|
EmitMessage(componentMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
namespace Encompass
|
namespace Encompass
|
||||||
{
|
{
|
||||||
public struct Entity
|
public struct Entity : IEquatable<Entity>
|
||||||
{
|
{
|
||||||
public readonly Guid ID;
|
public readonly Guid ID;
|
||||||
|
|
||||||
|
@ -10,5 +10,35 @@ namespace Encompass
|
||||||
{
|
{
|
||||||
this.ID = id;
|
this.ID = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
if (obj is Entity)
|
||||||
|
{
|
||||||
|
return this.Equals((Entity)obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Equals(Entity other)
|
||||||
|
{
|
||||||
|
return other.ID == ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator ==(Entity one, Entity two)
|
||||||
|
{
|
||||||
|
return one.Equals(two);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator !=(Entity one, Entity two)
|
||||||
|
{
|
||||||
|
return !one.Equals(two);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return ID.GetHashCode();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Encompass.Exceptions
|
||||||
|
{
|
||||||
|
public class IllegalActivateException : Exception
|
||||||
|
{
|
||||||
|
public IllegalActivateException(
|
||||||
|
string format,
|
||||||
|
params object[] args
|
||||||
|
) : base(string.Format(format, args)) { }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Encompass.Exceptions
|
||||||
|
{
|
||||||
|
public class IllegalActivateTypeException : Exception
|
||||||
|
{
|
||||||
|
public IllegalActivateTypeException(
|
||||||
|
string format,
|
||||||
|
params object[] args
|
||||||
|
) : base(string.Format(format, args)) { }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Encompass.Exceptions
|
||||||
|
{
|
||||||
|
public class UnregisteredComponentReadException : Exception
|
||||||
|
{
|
||||||
|
public UnregisteredComponentReadException(
|
||||||
|
string format,
|
||||||
|
params object[] args
|
||||||
|
) : base(string.Format(format, args)) { }
|
||||||
|
}
|
||||||
|
}
|
|
@ -41,12 +41,12 @@ namespace Encompass
|
||||||
|
|
||||||
protected IEnumerable<ValueTuple<Guid, TComponent>> ReadComponents<TComponent>() where TComponent : struct, IComponent
|
protected IEnumerable<ValueTuple<Guid, TComponent>> ReadComponents<TComponent>() where TComponent : struct, IComponent
|
||||||
{
|
{
|
||||||
return componentManager.GetActiveComponentsByType<TComponent>();
|
return componentManager.GetActiveComponentsByType<TComponent>().Select((triple) => (triple.Item2, triple.Item3));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected ValueTuple<Guid, TComponent> ReadComponent<TComponent>() where TComponent : struct, IComponent
|
protected ValueTuple<Guid, TComponent> ReadComponent<TComponent>() where TComponent : struct, IComponent
|
||||||
{
|
{
|
||||||
return componentManager.GetActiveComponentByType<TComponent>();
|
return ReadComponents<TComponent>().Single();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected IEnumerable<ValueTuple<Guid, TComponent>> GetComponents<TComponent>(Entity entity) where TComponent : struct, IComponent
|
protected IEnumerable<ValueTuple<Guid, TComponent>> GetComponents<TComponent>(Entity entity) where TComponent : struct, IComponent
|
||||||
|
|
|
@ -36,7 +36,6 @@ namespace Encompass
|
||||||
entityManager.DestroyMarkedEntities();
|
entityManager.DestroyMarkedEntities();
|
||||||
|
|
||||||
componentManager.PerformComponentUpdates();
|
componentManager.PerformComponentUpdates();
|
||||||
componentManager.ActivateMarkedComponents();
|
|
||||||
componentManager.DeactivateMarkedComponents();
|
componentManager.DeactivateMarkedComponents();
|
||||||
componentManager.RemoveMarkedComponents();
|
componentManager.RemoveMarkedComponents();
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Encompass.Exceptions;
|
using Encompass.Exceptions;
|
||||||
|
using Encompass.Engines;
|
||||||
|
|
||||||
namespace Encompass
|
namespace Encompass
|
||||||
{
|
{
|
||||||
|
@ -17,9 +18,12 @@ namespace Encompass
|
||||||
private readonly DrawLayerManager drawLayerManager;
|
private readonly DrawLayerManager drawLayerManager;
|
||||||
private readonly RenderManager renderManager;
|
private readonly RenderManager renderManager;
|
||||||
|
|
||||||
private readonly Dictionary<Type, HashSet<Engine>> typeToEmitters = new Dictionary<Type, HashSet<Engine>>();
|
|
||||||
private readonly Dictionary<Type, HashSet<Engine>> typeToReaders = new Dictionary<Type, HashSet<Engine>>();
|
private readonly Dictionary<Type, HashSet<Engine>> typeToReaders = new Dictionary<Type, HashSet<Engine>>();
|
||||||
|
|
||||||
|
private readonly HashSet<Engine> senders = new HashSet<Engine>();
|
||||||
|
|
||||||
|
private readonly HashSet<Type> registeredComponentTypes = new HashSet<Type>();
|
||||||
|
|
||||||
public WorldBuilder()
|
public WorldBuilder()
|
||||||
{
|
{
|
||||||
var entitiesWithAddedComponents = new HashSet<Guid>();
|
var entitiesWithAddedComponents = new HashSet<Guid>();
|
||||||
|
@ -56,6 +60,12 @@ namespace Encompass
|
||||||
componentManager.MarkForDeactivation(componentID);
|
componentManager.MarkForDeactivation(componentID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal void RegisterComponent(Type componentType)
|
||||||
|
{
|
||||||
|
registeredComponentTypes.Add(componentType);
|
||||||
|
AddEngine((Engine)Activator.CreateInstance(typeof(ComponentMessageEmitter<>).MakeGenericType(componentType)));
|
||||||
|
}
|
||||||
|
|
||||||
public Engine AddEngine<TEngine>(TEngine engine) where TEngine : Engine
|
public Engine AddEngine<TEngine>(TEngine engine) where TEngine : Engine
|
||||||
{
|
{
|
||||||
engine.AssignEntityManager(entityManager);
|
engine.AssignEntityManager(entityManager);
|
||||||
|
@ -65,60 +75,42 @@ namespace Encompass
|
||||||
engines.Add(engine);
|
engines.Add(engine);
|
||||||
engineGraph.AddVertex(engine);
|
engineGraph.AddVertex(engine);
|
||||||
|
|
||||||
foreach (var writeType in engine.writeTypes.Where((type) => type.GetInterfaces().Contains(typeof(IMessage))))
|
foreach (var activateType in engine.activateTypes)
|
||||||
{
|
{
|
||||||
if (!typeToEmitters.ContainsKey(writeType))
|
engine.writeTypes.Add(activateType);
|
||||||
{
|
|
||||||
typeToEmitters.Add(writeType, new HashSet<Engine>());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
typeToEmitters[writeType].Add(engine);
|
var messageReadTypes = engine.readTypes.Where((type) => type.GetInterfaces().Contains(typeof(IMessage)));
|
||||||
|
var messageSendTypes = engine.writeTypes.Where((type) => type.GetInterfaces().Contains(typeof(IMessage)));
|
||||||
|
|
||||||
if (typeToReaders.ContainsKey(writeType))
|
if (messageReadTypes.Intersect(messageSendTypes).Any())
|
||||||
{
|
{
|
||||||
foreach (var reader in typeToReaders[writeType])
|
var type = messageReadTypes.Intersect(messageSendTypes).First();
|
||||||
{
|
throw new EngineMessageSelfCycleException("Engine {0} both reads and writes Message {1}", engine.GetType().Name, type.Name);
|
||||||
if (engine == reader)
|
|
||||||
{
|
|
||||||
if (writeType.GetInterfaces().Contains(typeof(IMessage)))
|
|
||||||
{
|
|
||||||
throw new EngineMessageSelfCycleException("Engine both reads and writes Message {0}", writeType.Name);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
if (messageSendTypes.Any())
|
||||||
{
|
{
|
||||||
engineGraph.AddEdge(engine, reader);
|
senders.Add(engine);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (var readType in engine.readTypes)
|
||||||
|
{
|
||||||
|
if (readType.IsGenericType && readType.GetGenericTypeDefinition() == typeof(ComponentMessage<>))
|
||||||
|
{
|
||||||
|
var componentType = readType.GetGenericArguments().Single();
|
||||||
|
if (!registeredComponentTypes.Contains(componentType))
|
||||||
|
{
|
||||||
|
RegisterComponent(componentType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var readType in engine.readTypes.Where((type) => type.GetInterfaces().Contains(typeof(IMessage))))
|
|
||||||
{
|
|
||||||
if (!typeToReaders.ContainsKey(readType))
|
if (!typeToReaders.ContainsKey(readType))
|
||||||
{
|
{
|
||||||
typeToReaders.Add(readType, new HashSet<Engine>());
|
typeToReaders.Add(readType, new HashSet<Engine>());
|
||||||
}
|
}
|
||||||
|
|
||||||
typeToReaders[readType].Add(engine);
|
typeToReaders[readType].Add(engine);
|
||||||
|
|
||||||
if (typeToEmitters.ContainsKey(readType))
|
|
||||||
{
|
|
||||||
foreach (var emitter in typeToEmitters[readType])
|
|
||||||
{
|
|
||||||
if (emitter == engine)
|
|
||||||
{
|
|
||||||
if (readType.GetInterfaces().Contains(typeof(IMessage)))
|
|
||||||
{
|
|
||||||
throw new EngineMessageSelfCycleException("Engine both reads and writes Message {0}", readType.Name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
engineGraph.AddEdge(emitter, engine);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return engine;
|
return engine;
|
||||||
|
@ -148,8 +140,27 @@ namespace Encompass
|
||||||
return renderer;
|
return renderer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void BuildEngineGraph()
|
||||||
|
{
|
||||||
|
foreach (var senderEngine in senders)
|
||||||
|
{
|
||||||
|
foreach (var messageType in senderEngine.writeTypes.Where((type) => type.GetInterfaces().Contains(typeof(IMessage))))
|
||||||
|
{
|
||||||
|
if (typeToReaders.ContainsKey(messageType))
|
||||||
|
{
|
||||||
|
foreach (var readerEngine in typeToReaders[messageType])
|
||||||
|
{
|
||||||
|
engineGraph.AddEdge(senderEngine, readerEngine);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public World Build()
|
public World Build()
|
||||||
{
|
{
|
||||||
|
BuildEngineGraph();
|
||||||
|
|
||||||
if (engineGraph.Cyclic())
|
if (engineGraph.Cyclic())
|
||||||
{
|
{
|
||||||
var cycles = engineGraph.SimpleCycles();
|
var cycles = engineGraph.SimpleCycles();
|
||||||
|
@ -225,7 +236,6 @@ namespace Encompass
|
||||||
);
|
);
|
||||||
|
|
||||||
componentManager.PerformComponentUpdates();
|
componentManager.PerformComponentUpdates();
|
||||||
componentManager.ActivateMarkedComponents();
|
|
||||||
componentManager.DeactivateMarkedComponents();
|
componentManager.DeactivateMarkedComponents();
|
||||||
componentManager.RemoveMarkedComponents();
|
componentManager.RemoveMarkedComponents();
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ namespace Tests
|
||||||
static IEnumerable<(Guid, MockComponent)> gottenMockComponentIDPairs = Enumerable.Empty<(Guid, MockComponent)>();
|
static IEnumerable<(Guid, MockComponent)> gottenMockComponentIDPairs = Enumerable.Empty<(Guid, MockComponent)>();
|
||||||
static (Guid, MockComponent) gottenMockComponentIDPair;
|
static (Guid, MockComponent) gottenMockComponentIDPair;
|
||||||
|
|
||||||
[Reads(typeof(EntityMessage))]
|
[Reads(typeof(EntityMessage), typeof(MockComponent))]
|
||||||
class GetMockComponentsEngine : Engine
|
class GetMockComponentsEngine : Engine
|
||||||
{
|
{
|
||||||
public override void Update(double dt)
|
public override void Update(double dt)
|
||||||
|
@ -38,7 +38,7 @@ namespace Tests
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Reads(typeof(EntityMessage))]
|
[Reads(typeof(EntityMessage), typeof(MockComponent))]
|
||||||
class GetMockComponentEngine : Engine
|
class GetMockComponentEngine : Engine
|
||||||
{
|
{
|
||||||
public override void Update(double dt)
|
public override void Update(double dt)
|
||||||
|
@ -56,8 +56,8 @@ namespace Tests
|
||||||
public MockComponent mockComponent;
|
public MockComponent mockComponent;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Reads(typeof(AddComponentTestMessage))]
|
[Reads(typeof(AddComponentTestMessage), typeof(MockComponent))]
|
||||||
class AddComponentEngine : Engine
|
class AddComponentTestEngine : Engine
|
||||||
{
|
{
|
||||||
public override void Update(double dt)
|
public override void Update(double dt)
|
||||||
{
|
{
|
||||||
|
@ -73,8 +73,7 @@ namespace Tests
|
||||||
public void AddComponent()
|
public void AddComponent()
|
||||||
{
|
{
|
||||||
var worldBuilder = new WorldBuilder();
|
var worldBuilder = new WorldBuilder();
|
||||||
worldBuilder.AddEngine(new AddComponentEngine());
|
worldBuilder.AddEngine(new AddComponentTestEngine());
|
||||||
worldBuilder.AddEngine(new GetMockComponentEngine());
|
|
||||||
|
|
||||||
var entity = worldBuilder.CreateEntity();
|
var entity = worldBuilder.CreateEntity();
|
||||||
|
|
||||||
|
@ -94,6 +93,79 @@ namespace Tests
|
||||||
world.Update(0.01);
|
world.Update(0.01);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct AddMockComponentMessage : IMessage
|
||||||
|
{
|
||||||
|
public Entity entity;
|
||||||
|
public MockComponent mockComponent;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Writes(typeof(AddMockComponentMessage))]
|
||||||
|
class EmitMockComponentMessageEngine : Engine
|
||||||
|
{
|
||||||
|
private Entity entity;
|
||||||
|
|
||||||
|
public EmitMockComponentMessageEngine(Entity entity)
|
||||||
|
{
|
||||||
|
this.entity = entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Update(double dt)
|
||||||
|
{
|
||||||
|
MockComponent mockComponent;
|
||||||
|
mockComponent.myInt = 10;
|
||||||
|
mockComponent.myString = "four";
|
||||||
|
|
||||||
|
AddMockComponentMessage addMockComponentMessage;
|
||||||
|
addMockComponentMessage.entity = entity;
|
||||||
|
addMockComponentMessage.mockComponent = mockComponent;
|
||||||
|
EmitMessage(addMockComponentMessage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Activates(typeof(MockComponent))]
|
||||||
|
[Reads(typeof(AddMockComponentMessage))]
|
||||||
|
class AddMockComponentEngine : Engine
|
||||||
|
{
|
||||||
|
public override void Update(double dt)
|
||||||
|
{
|
||||||
|
foreach (var message in ReadMessages<AddMockComponentMessage>())
|
||||||
|
{
|
||||||
|
AddComponent(message.entity, message.mockComponent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Reads(typeof(MockComponent))]
|
||||||
|
class HasMockComponentEngine : Engine
|
||||||
|
{
|
||||||
|
private Entity entity;
|
||||||
|
|
||||||
|
public HasMockComponentEngine(Entity entity)
|
||||||
|
{
|
||||||
|
this.entity = entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Update(double dt)
|
||||||
|
{
|
||||||
|
Assert.IsTrue(HasComponent<MockComponent>(entity));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void AddComponentAndReadSameFrame()
|
||||||
|
{
|
||||||
|
var worldBuilder = new WorldBuilder();
|
||||||
|
var entity = worldBuilder.CreateEntity();
|
||||||
|
|
||||||
|
worldBuilder.AddEngine(new EmitMockComponentMessageEngine(entity));
|
||||||
|
worldBuilder.AddEngine(new AddMockComponentEngine());
|
||||||
|
worldBuilder.AddEngine(new HasMockComponentEngine(entity));
|
||||||
|
|
||||||
|
var world = worldBuilder.Build();
|
||||||
|
|
||||||
|
world.Update(0.01);
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void GetComponents()
|
public void GetComponents()
|
||||||
{
|
{
|
||||||
|
@ -161,7 +233,7 @@ namespace Tests
|
||||||
public Entity entity;
|
public Entity entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Reads(typeof(HasComponentTestMessage))]
|
[Reads(typeof(HasComponentTestMessage), typeof(MockComponent))]
|
||||||
class HasComponentTestEngine : Engine
|
class HasComponentTestEngine : Engine
|
||||||
{
|
{
|
||||||
public override void Update(double dt)
|
public override void Update(double dt)
|
||||||
|
@ -201,7 +273,7 @@ namespace Tests
|
||||||
public Entity entity;
|
public Entity entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
[Reads(typeof(HasComponentWhenInactiveTestMessage))]
|
[Reads(typeof(HasComponentWhenInactiveTestMessage), typeof(MockComponent))]
|
||||||
class HasComponentWhenInactiveTestEngine : Engine
|
class HasComponentWhenInactiveTestEngine : Engine
|
||||||
{
|
{
|
||||||
public override void Update(double dt)
|
public override void Update(double dt)
|
||||||
|
@ -244,7 +316,6 @@ namespace Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
[Reads(typeof(RemoveComponentTestMessage))]
|
[Reads(typeof(RemoveComponentTestMessage))]
|
||||||
[Writes(typeof(MockComponent))]
|
|
||||||
class RemoveComponentTestEngine : Engine
|
class RemoveComponentTestEngine : Engine
|
||||||
{
|
{
|
||||||
public override void Update(double dt)
|
public override void Update(double dt)
|
||||||
|
@ -318,15 +389,15 @@ namespace Tests
|
||||||
public Guid componentID;
|
public Guid componentID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Activates(typeof(MockComponent))]
|
||||||
[Reads(typeof(ActivateComponentMessage))]
|
[Reads(typeof(ActivateComponentMessage))]
|
||||||
[Writes(typeof(MockComponent))]
|
|
||||||
class ActivateComponentEngine : Engine
|
class ActivateComponentEngine : Engine
|
||||||
{
|
{
|
||||||
public override void Update(double dt)
|
public override void Update(double dt)
|
||||||
{
|
{
|
||||||
foreach (var activateComponentMessage in ReadMessages<ActivateComponentMessage>())
|
foreach (var activateComponentMessage in ReadMessages<ActivateComponentMessage>())
|
||||||
{
|
{
|
||||||
ActivateComponent(activateComponentMessage.componentID);
|
ActivateComponent<MockComponent>(activateComponentMessage.componentID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -367,7 +438,7 @@ namespace Tests
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Reads(typeof(CheckHasMockComponentMessage))]
|
[Reads(typeof(CheckHasMockComponentMessage), typeof(MockComponent))]
|
||||||
class CheckHasMockComponentEngine : Engine
|
class CheckHasMockComponentEngine : Engine
|
||||||
{
|
{
|
||||||
public override void Update(double dt)
|
public override void Update(double dt)
|
||||||
|
@ -386,6 +457,8 @@ namespace Tests
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: need to rethink this test because ActivateComponent is instant now
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void ActivateComponent()
|
public void ActivateComponent()
|
||||||
{
|
{
|
||||||
|
|
|
@ -23,6 +23,7 @@ namespace Tests
|
||||||
|
|
||||||
static List<MockMessage> resultMessages;
|
static List<MockMessage> resultMessages;
|
||||||
|
|
||||||
|
[Reads(typeof(MockComponent))]
|
||||||
public class ReadComponentsTestEngine : Engine
|
public class ReadComponentsTestEngine : Engine
|
||||||
{
|
{
|
||||||
public override void Update(double dt)
|
public override void Update(double dt)
|
||||||
|
@ -32,6 +33,7 @@ namespace Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[Reads(typeof(MockComponent))]
|
||||||
public class ReadComponentTestEngine : Engine
|
public class ReadComponentTestEngine : Engine
|
||||||
{
|
{
|
||||||
public override void Update(double dt)
|
public override void Update(double dt)
|
||||||
|
@ -117,6 +119,7 @@ namespace Tests
|
||||||
Assert.Throws<InvalidOperationException>(() => world.Update(0.01f));
|
Assert.Throws<InvalidOperationException>(() => world.Update(0.01f));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Reads(typeof(MockComponent))]
|
||||||
[Writes(typeof(MockComponent))]
|
[Writes(typeof(MockComponent))]
|
||||||
public class UpdateComponentTestEngine : Engine
|
public class UpdateComponentTestEngine : Engine
|
||||||
{
|
{
|
||||||
|
@ -136,6 +139,7 @@ namespace Tests
|
||||||
public void UpdateComponent()
|
public void UpdateComponent()
|
||||||
{
|
{
|
||||||
var worldBuilder = new WorldBuilder();
|
var worldBuilder = new WorldBuilder();
|
||||||
|
|
||||||
worldBuilder.AddEngine(new UpdateComponentTestEngine());
|
worldBuilder.AddEngine(new UpdateComponentTestEngine());
|
||||||
worldBuilder.AddEngine(new ReadComponentTestEngine());
|
worldBuilder.AddEngine(new ReadComponentTestEngine());
|
||||||
|
|
||||||
|
@ -156,11 +160,12 @@ namespace Tests
|
||||||
Assert.AreEqual("blaze it", resultComponent.myString);
|
Assert.AreEqual("blaze it", resultComponent.myString);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Reads(typeof(MockComponent))]
|
||||||
public class UndeclaredUpdateComponentTestEngine : Engine
|
public class UndeclaredUpdateComponentTestEngine : Engine
|
||||||
{
|
{
|
||||||
public override void Update(double dt)
|
public override void Update(double dt)
|
||||||
{
|
{
|
||||||
(var componentID, var component) = this.ReadComponent<MockComponent>();
|
(var componentID, var component) = ReadComponent<MockComponent>();
|
||||||
|
|
||||||
component.myInt = 420;
|
component.myInt = 420;
|
||||||
component.myString = "blaze it";
|
component.myString = "blaze it";
|
||||||
|
@ -358,6 +363,7 @@ namespace Tests
|
||||||
static ValueTuple<Guid, MockComponent> pairA;
|
static ValueTuple<Guid, MockComponent> pairA;
|
||||||
static ValueTuple<Guid, MockComponent> pairB;
|
static ValueTuple<Guid, MockComponent> pairB;
|
||||||
|
|
||||||
|
[Reads(typeof(MockComponent))]
|
||||||
class SameValueComponentReadEngine : Engine
|
class SameValueComponentReadEngine : Engine
|
||||||
{
|
{
|
||||||
public override void Update(double dt)
|
public override void Update(double dt)
|
||||||
|
@ -397,6 +403,7 @@ namespace Tests
|
||||||
|
|
||||||
static IEnumerable<ValueTuple<Guid, MockComponent>> emptyComponentReadResult;
|
static IEnumerable<ValueTuple<Guid, MockComponent>> emptyComponentReadResult;
|
||||||
|
|
||||||
|
[Reads(typeof(MockComponent))]
|
||||||
class ReadEmptyMockComponentsEngine : Engine
|
class ReadEmptyMockComponentsEngine : Engine
|
||||||
{
|
{
|
||||||
public override void Update(double dt)
|
public override void Update(double dt)
|
||||||
|
@ -419,6 +426,7 @@ namespace Tests
|
||||||
|
|
||||||
struct DestroyerComponent : IComponent { }
|
struct DestroyerComponent : IComponent { }
|
||||||
|
|
||||||
|
[Reads(typeof(DestroyerComponent))]
|
||||||
class DestroyerEngine : Engine
|
class DestroyerEngine : Engine
|
||||||
{
|
{
|
||||||
public override void Update(double dt)
|
public override void Update(double dt)
|
||||||
|
@ -434,6 +442,7 @@ namespace Tests
|
||||||
|
|
||||||
static IEnumerable<ValueTuple<Guid, MockComponent>> results;
|
static IEnumerable<ValueTuple<Guid, MockComponent>> results;
|
||||||
|
|
||||||
|
[Reads(typeof(MockComponent))]
|
||||||
class ReaderEngine : Engine
|
class ReaderEngine : Engine
|
||||||
{
|
{
|
||||||
public override void Update(double dt)
|
public override void Update(double dt)
|
||||||
|
@ -471,6 +480,7 @@ namespace Tests
|
||||||
Assert.That(results, Does.Not.Contain((componentBID, mockComponent)));
|
Assert.That(results, Does.Not.Contain((componentBID, mockComponent)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Reads(typeof(DestroyerComponent), typeof(MockComponent))]
|
||||||
[Writes(typeof(MockComponent))]
|
[Writes(typeof(MockComponent))]
|
||||||
class DestroyAndAddComponentEngine : Engine
|
class DestroyAndAddComponentEngine : Engine
|
||||||
{
|
{
|
||||||
|
@ -506,6 +516,7 @@ namespace Tests
|
||||||
|
|
||||||
static Entity entityFromComponentIDResult;
|
static Entity entityFromComponentIDResult;
|
||||||
|
|
||||||
|
[Reads(typeof(MockComponent))]
|
||||||
class GetEntityFromComponentIDEngine : Engine
|
class GetEntityFromComponentIDEngine : Engine
|
||||||
{
|
{
|
||||||
public override void Update(double dt)
|
public override void Update(double dt)
|
||||||
|
@ -536,6 +547,7 @@ namespace Tests
|
||||||
|
|
||||||
static MockComponent mockComponentByIDResult;
|
static MockComponent mockComponentByIDResult;
|
||||||
|
|
||||||
|
[Reads(typeof(MockComponent))]
|
||||||
class GetComponentByIDEngine : Engine
|
class GetComponentByIDEngine : Engine
|
||||||
{
|
{
|
||||||
public override void Update(double dt)
|
public override void Update(double dt)
|
||||||
|
@ -565,6 +577,7 @@ namespace Tests
|
||||||
|
|
||||||
struct OtherComponent : IComponent { }
|
struct OtherComponent : IComponent { }
|
||||||
|
|
||||||
|
[Reads(typeof(MockComponent))]
|
||||||
class GetComponentByIDWithTypeMismatchEngine : Engine
|
class GetComponentByIDWithTypeMismatchEngine : Engine
|
||||||
{
|
{
|
||||||
public override void Update(double dt)
|
public override void Update(double dt)
|
||||||
|
@ -595,6 +608,7 @@ namespace Tests
|
||||||
struct EntityIDComponent : IComponent { public Guid entityID; }
|
struct EntityIDComponent : IComponent { public Guid entityID; }
|
||||||
static bool hasEntity;
|
static bool hasEntity;
|
||||||
|
|
||||||
|
[Reads(typeof(EntityIDComponent))]
|
||||||
class HasEntityTestEngine : Engine
|
class HasEntityTestEngine : Engine
|
||||||
{
|
{
|
||||||
public override void Update(double dt)
|
public override void Update(double dt)
|
||||||
|
|
|
@ -23,7 +23,7 @@ namespace Tests
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Writes(typeof(TestComponent))]
|
[Activates(typeof(TestComponent))]
|
||||||
class TestSpawner : Spawner<SpawnMessageA>
|
class TestSpawner : Spawner<SpawnMessageA>
|
||||||
{
|
{
|
||||||
protected override void Spawn(SpawnMessageA message)
|
protected override void Spawn(SpawnMessageA message)
|
||||||
|
|
Loading…
Reference in New Issue