introduce concept of pending component
parent
1845d5f766
commit
89154f21d7
5
TODO
5
TODO
|
@ -1,6 +1 @@
|
||||||
- Change "Writes" To "Sends" and make it only take Messages
|
|
||||||
- Add "Updates" for updating components
|
|
||||||
|
|
||||||
- so we have four attributes: Activates, Reads, Updates, and Sends
|
|
||||||
|
|
||||||
- docs
|
- docs
|
||||||
|
|
|
@ -19,7 +19,7 @@ namespace Encompass
|
||||||
throw new IllegalActivateTypeException("{0} must be a Component", activateType.Name);
|
throw new IllegalActivateTypeException("{0} must be a Component", activateType.Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.activateTypes.Add(typeof(NewComponentMessage<>).MakeGenericType(activateType));
|
this.activateTypes.Add(typeof(PendingComponentMessage<>).MakeGenericType(activateType));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Encompass
|
|
||||||
{
|
|
||||||
[AttributeUsage(AttributeTargets.Class)]
|
|
||||||
public class Detects : Attribute
|
|
||||||
{
|
|
||||||
public readonly List<Type> componentTypes;
|
|
||||||
|
|
||||||
public Detects(params Type[] componentTypes)
|
|
||||||
{
|
|
||||||
this.componentTypes = new List<Type>(componentTypes);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,28 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using Encompass.Exceptions;
|
|
||||||
|
|
||||||
namespace Encompass
|
|
||||||
{
|
|
||||||
[AttributeUsage(AttributeTargets.Class)]
|
|
||||||
public class ReadsNew : Attribute
|
|
||||||
{
|
|
||||||
public readonly HashSet<Type> newComponentReadTypes = new HashSet<Type>();
|
|
||||||
|
|
||||||
public ReadsNew(params Type[] readTypes)
|
|
||||||
{
|
|
||||||
foreach (var readType in readTypes)
|
|
||||||
{
|
|
||||||
var isComponent = readType.GetInterfaces().Contains(typeof(IComponent));
|
|
||||||
|
|
||||||
if (!isComponent)
|
|
||||||
{
|
|
||||||
throw new IllegalReadTypeException("{0} must be a Component", readType.Name);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.newComponentReadTypes.Add(typeof(ComponentMessage<>).MakeGenericType(readType));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Encompass.Exceptions;
|
||||||
|
|
||||||
|
namespace Encompass
|
||||||
|
{
|
||||||
|
[AttributeUsage(AttributeTargets.Class)]
|
||||||
|
public class ReadsPending : Attribute
|
||||||
|
{
|
||||||
|
public readonly HashSet<Type> readPendingTypes = new HashSet<Type>();
|
||||||
|
|
||||||
|
public ReadsPending(params Type[] readPendingTypes)
|
||||||
|
{
|
||||||
|
foreach (var readPendingType in readPendingTypes)
|
||||||
|
{
|
||||||
|
var isComponent = readPendingType.GetInterfaces().Contains(typeof(IComponent));
|
||||||
|
|
||||||
|
if (!isComponent)
|
||||||
|
{
|
||||||
|
throw new IllegalReadTypeException("{0} must be a Component", readPendingType.Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.readPendingTypes.Add(typeof(PendingComponentMessage<>).MakeGenericType(readPendingType));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -42,10 +42,10 @@ namespace Encompass
|
||||||
receiveTypes.UnionWith(readsAttribute.readTypes);
|
receiveTypes.UnionWith(readsAttribute.readTypes);
|
||||||
}
|
}
|
||||||
|
|
||||||
var readsNewAttribute = GetType().GetCustomAttribute<ReadsNew>(false);
|
var readsPendingAttribute = GetType().GetCustomAttribute<ReadsPending>(false);
|
||||||
if (readsNewAttribute != null)
|
if (readsPendingAttribute != null)
|
||||||
{
|
{
|
||||||
receiveTypes.UnionWith(readsNewAttribute.newComponentReadTypes);
|
receiveTypes.UnionWith(readsPendingAttribute.readPendingTypes);
|
||||||
}
|
}
|
||||||
|
|
||||||
var updatesAttribute = GetType().GetCustomAttribute<Updates>(false);
|
var updatesAttribute = GetType().GetCustomAttribute<Updates>(false);
|
||||||
|
@ -118,14 +118,14 @@ namespace Encompass
|
||||||
|
|
||||||
protected Guid AddComponent<TComponent>(Entity entity, TComponent component) where TComponent : struct, IComponent
|
protected Guid AddComponent<TComponent>(Entity entity, TComponent component) where TComponent : struct, IComponent
|
||||||
{
|
{
|
||||||
if (!sendTypes.Contains(typeof(NewComponentMessage<TComponent>)))
|
if (!sendTypes.Contains(typeof(PendingComponentMessage<TComponent>)))
|
||||||
{
|
{
|
||||||
throw new IllegalActivateException("Engine {0} tried to activate undeclared Component {1}", GetType().Name, typeof(TComponent).Name);
|
throw new IllegalActivateException("Engine {0} tried to activate undeclared Component {1}", GetType().Name, typeof(TComponent).Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
var componentID = componentManager.AddComponent(entity.ID, component);
|
var componentID = componentManager.AddComponent(entity.ID, component);
|
||||||
|
|
||||||
NewComponentMessage<TComponent> componentMessage;
|
PendingComponentMessage<TComponent> componentMessage;
|
||||||
componentMessage.entity = entity;
|
componentMessage.entity = entity;
|
||||||
componentMessage.componentID = componentID;
|
componentMessage.componentID = componentID;
|
||||||
componentMessage.component = component;
|
componentMessage.component = component;
|
||||||
|
@ -136,14 +136,14 @@ namespace Encompass
|
||||||
|
|
||||||
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
|
||||||
{
|
{
|
||||||
if (!sendTypes.Contains(typeof(NewComponentMessage<TComponent>)))
|
if (!sendTypes.Contains(typeof(PendingComponentMessage<TComponent>)))
|
||||||
{
|
{
|
||||||
throw new IllegalActivateException("Engine {0} tried to activate undeclared Component {1}", GetType().Name, typeof(TComponent).Name);
|
throw new IllegalActivateException("Engine {0} tried to activate undeclared Component {1}", GetType().Name, typeof(TComponent).Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
var componentID = componentManager.AddDrawComponent(entity.ID, component, layer);
|
var componentID = componentManager.AddDrawComponent(entity.ID, component, layer);
|
||||||
|
|
||||||
NewComponentMessage<TComponent> newComponentMessage;
|
PendingComponentMessage<TComponent> newComponentMessage;
|
||||||
newComponentMessage.entity = entity;
|
newComponentMessage.entity = entity;
|
||||||
newComponentMessage.componentID = componentID;
|
newComponentMessage.componentID = componentID;
|
||||||
newComponentMessage.component = component;
|
newComponentMessage.component = component;
|
||||||
|
@ -154,7 +154,7 @@ namespace Encompass
|
||||||
|
|
||||||
protected void ActivateComponent<TComponent>(Guid componentID) where TComponent : struct, IComponent
|
protected void ActivateComponent<TComponent>(Guid componentID) where TComponent : struct, IComponent
|
||||||
{
|
{
|
||||||
if (!sendTypes.Contains(typeof(NewComponentMessage<TComponent>)))
|
if (!sendTypes.Contains(typeof(PendingComponentMessage<TComponent>)))
|
||||||
{
|
{
|
||||||
throw new IllegalActivateException("Engine {0} tried to activate undeclared Component {1}", GetType().Name, typeof(TComponent).Name);
|
throw new IllegalActivateException("Engine {0} tried to activate undeclared Component {1}", GetType().Name, typeof(TComponent).Name);
|
||||||
}
|
}
|
||||||
|
@ -162,7 +162,7 @@ namespace Encompass
|
||||||
var entity = GetEntity(componentManager.GetEntityIDByComponentID(componentID));
|
var entity = GetEntity(componentManager.GetEntityIDByComponentID(componentID));
|
||||||
var component = GetComponentByID<TComponent>(componentID);
|
var component = GetComponentByID<TComponent>(componentID);
|
||||||
|
|
||||||
NewComponentMessage<TComponent> newComponentMessage;
|
PendingComponentMessage<TComponent> newComponentMessage;
|
||||||
newComponentMessage.entity = entity;
|
newComponentMessage.entity = entity;
|
||||||
newComponentMessage.componentID = componentID;
|
newComponentMessage.componentID = componentID;
|
||||||
newComponentMessage.component = component;
|
newComponentMessage.component = component;
|
||||||
|
@ -186,19 +186,19 @@ namespace Encompass
|
||||||
return ReadMessages<ComponentMessage<TComponent>>().Where((message) => message.entity == entity).Select((message) => (message.componentID, message.component));
|
return ReadMessages<ComponentMessage<TComponent>>().Where((message) => message.entity == entity).Select((message) => (message.componentID, message.component));
|
||||||
}
|
}
|
||||||
|
|
||||||
private IEnumerable<ValueTuple<Guid, TComponent>> NewComponentsOnEntity<TComponent>(Entity entity) where TComponent : struct, IComponent
|
private IEnumerable<ValueTuple<Guid, TComponent>> PendingComponentsOnEntity<TComponent>(Entity entity) where TComponent : struct, IComponent
|
||||||
{
|
{
|
||||||
if (!receiveTypes.Contains(typeof(NewComponentMessage<TComponent>)))
|
if (!receiveTypes.Contains(typeof(PendingComponentMessage<TComponent>)))
|
||||||
{
|
{
|
||||||
throw new IllegalReadException("Engine {0} tried to read undeclared new Component {1}", GetType().Name, typeof(TComponent).Name);
|
throw new IllegalReadException("Engine {0} tried to read undeclared pending Component {1}", GetType().Name, typeof(TComponent).Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ReadMessages<NewComponentMessage<TComponent>>().Where((message) => message.entity == entity).Select((message) => (message.componentID, message.component));
|
return ReadMessages<PendingComponentMessage<TComponent>>().Where((message) => message.entity == entity).Select((message) => (message.componentID, message.component));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected IEnumerable<ValueTuple<Guid, TComponent>> GetComponentsIncludingNew<TComponent>(Entity entity) where TComponent : struct, IComponent
|
protected IEnumerable<ValueTuple<Guid, TComponent>> GetPendingComponents<TComponent>(Entity entity) where TComponent : struct, IComponent
|
||||||
{
|
{
|
||||||
return ExistingComponentsOnEntity<TComponent>(entity).Union(NewComponentsOnEntity<TComponent>(entity));
|
return PendingComponentsOnEntity<TComponent>(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
|
@ -206,11 +206,21 @@ namespace Encompass
|
||||||
return ExistingComponentsOnEntity<TComponent>(entity);
|
return ExistingComponentsOnEntity<TComponent>(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected ValueTuple<Guid, TComponent> GetPendingComponent<TComponent>(Entity entity) where TComponent : struct, IComponent
|
||||||
|
{
|
||||||
|
return PendingComponentsOnEntity<TComponent>(entity).First();
|
||||||
|
}
|
||||||
|
|
||||||
protected ValueTuple<Guid, TComponent> GetComponent<TComponent>(Entity entity) where TComponent : struct, IComponent
|
protected ValueTuple<Guid, TComponent> GetComponent<TComponent>(Entity entity) where TComponent : struct, IComponent
|
||||||
{
|
{
|
||||||
return GetComponents<TComponent>(entity).First();
|
return GetComponents<TComponent>(entity).First();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected bool HasPendingComponent<TComponent>(Entity entity) where TComponent : struct, IComponent
|
||||||
|
{
|
||||||
|
return GetPendingComponents<TComponent>(entity).Any();
|
||||||
|
}
|
||||||
|
|
||||||
protected bool HasComponent<TComponent>(Entity entity) where TComponent : struct, IComponent
|
protected bool HasComponent<TComponent>(Entity entity) where TComponent : struct, IComponent
|
||||||
{
|
{
|
||||||
return GetComponents<TComponent>(entity).Any();
|
return GetComponents<TComponent>(entity).Any();
|
||||||
|
@ -220,7 +230,7 @@ namespace Encompass
|
||||||
{
|
{
|
||||||
if (!updateTypes.Contains(typeof(TComponent)))
|
if (!updateTypes.Contains(typeof(TComponent)))
|
||||||
{
|
{
|
||||||
throw new IllegalSendException("Engine {0} tried to write undeclared Component {1}", this.GetType().Name, typeof(TComponent).Name);
|
throw new IllegalSendException("Engine {0} tried to update undeclared Component {1}", this.GetType().Name, typeof(TComponent).Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentManager.AddUpdateComponentOperation(componentID, newComponent);
|
componentManager.AddUpdateComponentOperation(componentID, newComponent);
|
||||||
|
@ -235,7 +245,7 @@ namespace Encompass
|
||||||
{
|
{
|
||||||
if (!sendTypes.Contains(typeof(TMessage)))
|
if (!sendTypes.Contains(typeof(TMessage)))
|
||||||
{
|
{
|
||||||
throw new IllegalSendException("Engine {0} tried to write undeclared Message {1}", this.GetType().Name, typeof(TMessage).Name);
|
throw new IllegalSendException("Engine {0} tried to send undeclared Message {1}", this.GetType().Name, typeof(TMessage).Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
messageManager.AddMessage(message);
|
messageManager.AddMessage(message);
|
||||||
|
@ -256,6 +266,16 @@ namespace Encompass
|
||||||
return ReadMessages<TMessage>().Single();
|
return ReadMessages<TMessage>().Single();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected IEnumerable<ValueTuple<Guid, TComponent>> ReadPendingComponents<TComponent>() where TComponent : struct, IComponent
|
||||||
|
{
|
||||||
|
if (!receiveTypes.Contains(typeof(PendingComponentMessage<TComponent>)))
|
||||||
|
{
|
||||||
|
throw new IllegalReadException("Engine {0} tried to read undeclared pending Component {1}", GetType().Name, typeof(TComponent).Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ReadMessages<PendingComponentMessage<TComponent>>().Select((message) => (message.componentID, message.component));
|
||||||
|
}
|
||||||
|
|
||||||
protected IEnumerable<ValueTuple<Guid, TComponent>> ReadComponents<TComponent>() where TComponent : struct, IComponent
|
protected IEnumerable<ValueTuple<Guid, TComponent>> ReadComponents<TComponent>() where TComponent : struct, IComponent
|
||||||
{
|
{
|
||||||
if (!receiveTypes.Contains(typeof(ComponentMessage<TComponent>)))
|
if (!receiveTypes.Contains(typeof(ComponentMessage<TComponent>)))
|
||||||
|
@ -266,6 +286,11 @@ namespace Encompass
|
||||||
return ReadMessages<ComponentMessage<TComponent>>().Select((message) => (message.componentID, message.component));
|
return ReadMessages<ComponentMessage<TComponent>>().Select((message) => (message.componentID, message.component));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected ValueTuple<Guid, TComponent> ReadPendingComponent<TComponent>() where TComponent : struct, IComponent
|
||||||
|
{
|
||||||
|
return ReadPendingComponents<TComponent>().Single();
|
||||||
|
}
|
||||||
|
|
||||||
protected ValueTuple<Guid, TComponent> ReadComponent<TComponent>() where TComponent : struct, IComponent
|
protected ValueTuple<Guid, TComponent> ReadComponent<TComponent>() where TComponent : struct, IComponent
|
||||||
{
|
{
|
||||||
return ReadComponents<TComponent>().Single();
|
return ReadComponents<TComponent>().Single();
|
||||||
|
@ -281,6 +306,16 @@ namespace Encompass
|
||||||
return ReadMessages<TMessage>().Any();
|
return ReadMessages<TMessage>().Any();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected bool SomePendingComponent<TComponent>() where TComponent : struct, IComponent
|
||||||
|
{
|
||||||
|
if (!receiveTypes.Contains(typeof(PendingComponentMessage<TComponent>)))
|
||||||
|
{
|
||||||
|
throw new IllegalReadException("Engine {0} tried to read undeclared pending Component {1}", GetType().Name, typeof(TComponent).Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ReadMessages<PendingComponentMessage<TComponent>>().Any();
|
||||||
|
}
|
||||||
|
|
||||||
protected bool SomeComponent<TComponent>() where TComponent : struct, IComponent
|
protected bool SomeComponent<TComponent>() where TComponent : struct, IComponent
|
||||||
{
|
{
|
||||||
if (!receiveTypes.Contains(typeof(ComponentMessage<TComponent>)))
|
if (!receiveTypes.Contains(typeof(ComponentMessage<TComponent>)))
|
||||||
|
|
|
@ -6,14 +6,14 @@ namespace Encompass.Engines
|
||||||
{
|
{
|
||||||
public NewComponentMessageEmitter() : base()
|
public NewComponentMessageEmitter() : base()
|
||||||
{
|
{
|
||||||
sendTypes.Add(typeof(NewComponentMessage<TComponent>));
|
sendTypes.Add(typeof(PendingComponentMessage<TComponent>));
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Update(double dt)
|
public override void Update(double dt)
|
||||||
{
|
{
|
||||||
foreach (var (entity, componentID, component) in ReadComponentsFromWorld<TComponent>())
|
foreach (var (entity, componentID, component) in ReadComponentsFromWorld<TComponent>())
|
||||||
{
|
{
|
||||||
NewComponentMessage<TComponent> newComponentMessage;
|
PendingComponentMessage<TComponent> newComponentMessage;
|
||||||
newComponentMessage.entity = entity;
|
newComponentMessage.entity = entity;
|
||||||
newComponentMessage.componentID = componentID;
|
newComponentMessage.componentID = componentID;
|
||||||
newComponentMessage.component = component;
|
newComponentMessage.component = component;
|
||||||
|
|
|
@ -2,9 +2,9 @@ using System;
|
||||||
|
|
||||||
namespace Encompass.Exceptions
|
namespace Encompass.Exceptions
|
||||||
{
|
{
|
||||||
public class EngineWriteConflictException : Exception
|
public class EngineSelfCycleException : Exception
|
||||||
{
|
{
|
||||||
public EngineWriteConflictException(
|
public EngineSelfCycleException(
|
||||||
string format,
|
string format,
|
||||||
params object[] args
|
params object[] args
|
||||||
) : base(string.Format(format, args)) { }
|
) : base(string.Format(format, args)) { }
|
|
@ -2,9 +2,9 @@ using System;
|
||||||
|
|
||||||
namespace Encompass.Exceptions
|
namespace Encompass.Exceptions
|
||||||
{
|
{
|
||||||
public class EngineMessageSelfCycleException : Exception
|
public class EngineUpdateConflictException : Exception
|
||||||
{
|
{
|
||||||
public EngineMessageSelfCycleException(
|
public EngineUpdateConflictException(
|
||||||
string format,
|
string format,
|
||||||
params object[] args
|
params object[] args
|
||||||
) : base(string.Format(format, args)) { }
|
) : base(string.Format(format, args)) { }
|
|
@ -2,7 +2,7 @@ using System;
|
||||||
|
|
||||||
namespace Encompass
|
namespace Encompass
|
||||||
{
|
{
|
||||||
public struct NewComponentMessage<TComponent> : IMessage where TComponent : struct, IComponent
|
public struct PendingComponentMessage<TComponent> : IMessage where TComponent : struct, IComponent
|
||||||
{
|
{
|
||||||
public Entity entity;
|
public Entity entity;
|
||||||
public Guid componentID;
|
public Guid componentID;
|
||||||
|
|
|
@ -87,13 +87,13 @@ namespace Encompass
|
||||||
|
|
||||||
foreach (var messageType in messageReceiveTypes.Intersect(messageSendTypes))
|
foreach (var messageType in messageReceiveTypes.Intersect(messageSendTypes))
|
||||||
{
|
{
|
||||||
// ComponentMessages can safely self-cycle
|
if ((messageType.IsGenericType && messageType.GetGenericTypeDefinition() == typeof(PendingComponentMessage<>)))
|
||||||
// this does introduce a gotcha though: if you AddComponent and then HasComponent or GetComponent you will receive a false negative
|
|
||||||
// there is no point to doing this but it is a gotcha i suppose
|
|
||||||
if (!(messageType.IsGenericType && messageType.GetGenericTypeDefinition() == typeof(ComponentMessage<>)))
|
|
||||||
{
|
{
|
||||||
throw new EngineMessageSelfCycleException("Engine {0} both reads and writes Message {1}", engine.GetType().Name, messageType.Name);
|
var componentType = messageType.GetGenericArguments().Single();
|
||||||
|
throw new EngineSelfCycleException("Engine {0} both activates and reads pending Component {1}", engine.GetType().Name, componentType.Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
throw new EngineSelfCycleException("Engine {0} both receives and sends Message {1}", engine.GetType().Name, messageType.Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (messageSendTypes.Any())
|
if (messageSendTypes.Any())
|
||||||
|
@ -106,7 +106,7 @@ namespace Encompass
|
||||||
if (receiveType.IsGenericType)
|
if (receiveType.IsGenericType)
|
||||||
{
|
{
|
||||||
var genericTypeDefinition = receiveType.GetGenericTypeDefinition();
|
var genericTypeDefinition = receiveType.GetGenericTypeDefinition();
|
||||||
if (genericTypeDefinition == typeof(ComponentMessage<>) || genericTypeDefinition == typeof(NewComponentMessage<>))
|
if (genericTypeDefinition == typeof(ComponentMessage<>) || genericTypeDefinition == typeof(PendingComponentMessage<>))
|
||||||
{
|
{
|
||||||
var componentType = receiveType.GetGenericArguments().Single();
|
var componentType = receiveType.GetGenericArguments().Single();
|
||||||
if (!registeredComponentTypes.Contains(componentType))
|
if (!registeredComponentTypes.Contains(componentType))
|
||||||
|
@ -129,7 +129,7 @@ namespace Encompass
|
||||||
if (sendType.IsGenericType)
|
if (sendType.IsGenericType)
|
||||||
{
|
{
|
||||||
var genericTypeDefinition = sendType.GetGenericTypeDefinition();
|
var genericTypeDefinition = sendType.GetGenericTypeDefinition();
|
||||||
if (genericTypeDefinition == typeof(ComponentMessage<>) || genericTypeDefinition == typeof(NewComponentMessage<>))
|
if (genericTypeDefinition == typeof(ComponentMessage<>) || genericTypeDefinition == typeof(PendingComponentMessage<>))
|
||||||
{
|
{
|
||||||
var componentType = sendType.GetGenericArguments().Single();
|
var componentType = sendType.GetGenericArguments().Single();
|
||||||
if (!registeredNewComponentTypes.Contains(componentType))
|
if (!registeredNewComponentTypes.Contains(componentType))
|
||||||
|
@ -195,12 +195,13 @@ namespace Encompass
|
||||||
{
|
{
|
||||||
var cycles = engineGraph.SimpleCycles();
|
var cycles = engineGraph.SimpleCycles();
|
||||||
var errorString = "Cycle(s) found in Engines: ";
|
var errorString = "Cycle(s) found in Engines: ";
|
||||||
foreach (var cycle in cycles.Reverse())
|
foreach (var cycle in cycles)
|
||||||
{
|
{
|
||||||
|
var reversed = cycle.Reverse();
|
||||||
errorString += "\n" +
|
errorString += "\n" +
|
||||||
string.Join(" -> ", cycle.Select((engine) => engine.GetType().Name)) +
|
string.Join(" -> ", reversed.Select((engine) => engine.GetType().Name)) +
|
||||||
" -> " +
|
" -> " +
|
||||||
cycle.First().GetType().Name;
|
reversed.First().GetType().Name;
|
||||||
}
|
}
|
||||||
throw new EngineCycleException(errorString);
|
throw new EngineCycleException(errorString);
|
||||||
}
|
}
|
||||||
|
@ -213,38 +214,35 @@ namespace Encompass
|
||||||
{
|
{
|
||||||
foreach (var updateType in engine.updateTypes)
|
foreach (var updateType in engine.updateTypes)
|
||||||
{
|
{
|
||||||
if (updateType.GetInterfaces().Contains(typeof(IComponent))) // if our write type is a component
|
if (mutatedComponentTypes.Contains(updateType))
|
||||||
{
|
{
|
||||||
if (mutatedComponentTypes.Contains(updateType))
|
duplicateMutations.Add(updateType);
|
||||||
{
|
|
||||||
duplicateMutations.Add(updateType);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
mutatedComponentTypes.Add(updateType);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!componentToEngines.ContainsKey(updateType))
|
|
||||||
{
|
|
||||||
componentToEngines[updateType] = new List<Engine>();
|
|
||||||
}
|
|
||||||
|
|
||||||
componentToEngines[updateType].Add(engine);
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mutatedComponentTypes.Add(updateType);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!componentToEngines.ContainsKey(updateType))
|
||||||
|
{
|
||||||
|
componentToEngines[updateType] = new List<Engine>();
|
||||||
|
}
|
||||||
|
|
||||||
|
componentToEngines[updateType].Add(engine);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (duplicateMutations.Count > 0)
|
if (duplicateMutations.Count > 0)
|
||||||
{
|
{
|
||||||
var errorString = "Multiple Engines write the same Component: ";
|
var errorString = "Multiple Engines update the same Component: ";
|
||||||
foreach (var componentType in duplicateMutations)
|
foreach (var componentType in duplicateMutations)
|
||||||
{
|
{
|
||||||
errorString += "\n" +
|
errorString += "\n" +
|
||||||
componentType.Name + " written by: " +
|
componentType.Name + " updated by: " +
|
||||||
string.Join(", ", componentToEngines[componentType].Select((engine) => engine.GetType().Name));
|
string.Join(", ", componentToEngines[componentType].Select((engine) => engine.GetType().Name));
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new EngineWriteConflictException(errorString);
|
throw new EngineUpdateConflictException(errorString);
|
||||||
}
|
}
|
||||||
|
|
||||||
var engineOrder = new List<Engine>();
|
var engineOrder = new List<Engine>();
|
||||||
|
|
|
@ -124,6 +124,7 @@ namespace Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
[Reads(typeof(MockComponent))]
|
[Reads(typeof(MockComponent))]
|
||||||
|
[ReadsPending(typeof(MockComponent))]
|
||||||
class HasMockComponentEngine : Engine
|
class HasMockComponentEngine : Engine
|
||||||
{
|
{
|
||||||
private Entity entity;
|
private Entity entity;
|
||||||
|
@ -135,7 +136,7 @@ namespace Tests
|
||||||
|
|
||||||
public override void Update(double dt)
|
public override void Update(double dt)
|
||||||
{
|
{
|
||||||
Assert.IsTrue(HasComponent<MockComponent>(entity));
|
Assert.IsTrue(HasPendingComponent<MockComponent>(entity));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -468,14 +469,14 @@ namespace Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
[Receives(typeof(CheckHasMockComponentMessage))]
|
[Receives(typeof(CheckHasMockComponentMessage))]
|
||||||
[Reads(typeof(MockComponent))]
|
[ReadsPending(typeof(MockComponent))]
|
||||||
class CheckHasMockComponentEngine : Engine
|
class CheckHasMockComponentEngine : Engine
|
||||||
{
|
{
|
||||||
public override void Update(double dt)
|
public override void Update(double dt)
|
||||||
{
|
{
|
||||||
foreach (var checkHasMockComponentMessage in ReadMessages<CheckHasMockComponentMessage>())
|
foreach (var checkHasMockComponentMessage in ReadMessages<CheckHasMockComponentMessage>())
|
||||||
{
|
{
|
||||||
Assert.IsTrue(HasComponent<MockComponent>(checkHasMockComponentMessage.entity));
|
Assert.IsTrue(HasPendingComponent<MockComponent>(checkHasMockComponentMessage.entity));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -192,7 +192,7 @@ namespace Tests
|
||||||
var world = worldBuilder.Build();
|
var world = worldBuilder.Build();
|
||||||
|
|
||||||
var ex = Assert.Throws<IllegalSendException>(() => world.Update(0.01f));
|
var ex = Assert.Throws<IllegalSendException>(() => world.Update(0.01f));
|
||||||
Assert.That(ex.Message, Is.EqualTo("Engine UndeclaredUpdateComponentTestEngine tried to write undeclared Component MockComponent"));
|
Assert.That(ex.Message, Is.EqualTo("Engine UndeclaredUpdateComponentTestEngine tried to update undeclared Component MockComponent"));
|
||||||
}
|
}
|
||||||
|
|
||||||
struct MockMessage : IMessage
|
struct MockMessage : IMessage
|
||||||
|
@ -279,7 +279,7 @@ namespace Tests
|
||||||
var world = worldBuilder.Build();
|
var world = worldBuilder.Build();
|
||||||
|
|
||||||
var ex = Assert.Throws<IllegalSendException>(() => world.Update(0.01f));
|
var ex = Assert.Throws<IllegalSendException>(() => world.Update(0.01f));
|
||||||
Assert.That(ex.Message, Is.EqualTo("Engine UndeclaredMessageEmitEngine tried to write undeclared Message MockMessage"));
|
Assert.That(ex.Message, Is.EqualTo("Engine UndeclaredMessageEmitEngine tried to send undeclared Message MockMessage"));
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool someTest;
|
static bool someTest;
|
||||||
|
|
|
@ -48,8 +48,6 @@ namespace Tests
|
||||||
|
|
||||||
world.Update(0.01f);
|
world.Update(0.01f);
|
||||||
|
|
||||||
Console.WriteLine(renderer.IsTracking(entityNotToTrack.ID));
|
|
||||||
|
|
||||||
Assert.IsTrue(renderer.IsTracking(entityToTrack.ID));
|
Assert.IsTrue(renderer.IsTracking(entityToTrack.ID));
|
||||||
Assert.IsFalse(renderer.IsTracking(entityNotToTrack.ID));
|
Assert.IsFalse(renderer.IsTracking(entityNotToTrack.ID));
|
||||||
Assert.IsFalse(renderer.IsTracking(entityWithoutDrawComponent.ID));
|
Assert.IsFalse(renderer.IsTracking(entityWithoutDrawComponent.ID));
|
||||||
|
|
|
@ -133,7 +133,7 @@ namespace Tests
|
||||||
worldBuilder.AddEngine(new AEngine());
|
worldBuilder.AddEngine(new AEngine());
|
||||||
worldBuilder.AddEngine(new BEngine());
|
worldBuilder.AddEngine(new BEngine());
|
||||||
|
|
||||||
Assert.Throws<EngineWriteConflictException>(() => worldBuilder.Build());
|
Assert.Throws<EngineUpdateConflictException>(() => worldBuilder.Build());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,7 +156,7 @@ namespace Tests
|
||||||
{
|
{
|
||||||
var worldBuilder = new WorldBuilder();
|
var worldBuilder = new WorldBuilder();
|
||||||
|
|
||||||
Assert.Throws<EngineMessageSelfCycleException>(() => worldBuilder.AddEngine(new AEngine()), "Engine both reads and writes Message AMessage");
|
Assert.Throws<EngineSelfCycleException>(() => worldBuilder.AddEngine(new AEngine()), "Engine both sends and receives Message AMessage");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue