update engine generator
parent
573657fd39
commit
fea5c57860
|
@ -8,7 +8,7 @@ namespace Encompass
|
|||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class Updates : Attribute
|
||||
{
|
||||
public readonly HashSet<Type> updateTypes;
|
||||
public readonly HashSet<Type> updateTypes = new HashSet<Type>();
|
||||
|
||||
public Updates(params Type[] updateTypes)
|
||||
{
|
||||
|
@ -19,9 +19,9 @@ namespace Encompass
|
|||
{
|
||||
throw new IllegalUpdateTypeException("{0} must be a Component", updateType.Name);
|
||||
}
|
||||
}
|
||||
|
||||
this.updateTypes = new HashSet<Type>(updateTypes);
|
||||
this.updateTypes.Add(typeof(ComponentUpdateMessage<>).MakeGenericType(updateType));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,7 +10,6 @@ namespace Encompass
|
|||
{
|
||||
internal readonly HashSet<Type> sendTypes = new HashSet<Type>();
|
||||
internal readonly HashSet<Type> receiveTypes = new HashSet<Type>();
|
||||
internal readonly HashSet<Type> updateTypes = new HashSet<Type>();
|
||||
|
||||
private EntityManager entityManager;
|
||||
private ComponentManager componentManager;
|
||||
|
@ -30,6 +29,12 @@ namespace Encompass
|
|||
sendTypes.UnionWith(activatesAttribute.activateTypes);
|
||||
}
|
||||
|
||||
var updatesAttribute = GetType().GetCustomAttribute<Updates>(false);
|
||||
if (updatesAttribute != null)
|
||||
{
|
||||
sendTypes.UnionWith(updatesAttribute.updateTypes);
|
||||
}
|
||||
|
||||
var receivesAttribute = GetType().GetCustomAttribute<Receives>(false);
|
||||
if (receivesAttribute != null)
|
||||
{
|
||||
|
@ -47,16 +52,6 @@ namespace Encompass
|
|||
{
|
||||
receiveTypes.UnionWith(readsPendingAttribute.readPendingTypes);
|
||||
}
|
||||
|
||||
var updatesAttribute = GetType().GetCustomAttribute<Updates>(false);
|
||||
if (updatesAttribute != null)
|
||||
{
|
||||
updateTypes = updatesAttribute.updateTypes;
|
||||
if (sendTypes.Any())
|
||||
{
|
||||
throw new IllegalEngineAttributesException("Engine {0} sends Message(s) and updates Component(s)", GetType().Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal void AssignEntityManager(EntityManager entityManager)
|
||||
|
@ -228,24 +223,27 @@ namespace Encompass
|
|||
|
||||
internal void UpdateComponentInWorld<TComponent>(Guid componentID, TComponent newComponent) where TComponent : struct, IComponent
|
||||
{
|
||||
if (!updateTypes.Contains(typeof(TComponent)))
|
||||
{
|
||||
throw new IllegalSendException("Engine {0} tried to update undeclared Component {1}", this.GetType().Name, typeof(TComponent).Name);
|
||||
}
|
||||
|
||||
componentManager.AddUpdateComponentOperation(componentID, newComponent);
|
||||
}
|
||||
|
||||
protected void UpdateComponent<TComponent>(Guid componentID, TComponent newComponentValue) where TComponent : struct, IComponent
|
||||
{
|
||||
UpdateComponentInWorld(componentID, newComponentValue);
|
||||
if (!sendTypes.Contains(typeof(ComponentUpdateMessage<TComponent>)))
|
||||
{
|
||||
throw new IllegalUpdateException("Engine {0} tried to update undeclared Component {1}", GetType().Name, typeof(TComponent).Name);
|
||||
}
|
||||
|
||||
ComponentUpdateMessage<TComponent> componentUpdateMessage;
|
||||
componentUpdateMessage.componentID = componentID;
|
||||
componentUpdateMessage.component = newComponentValue;
|
||||
SendMessage(componentUpdateMessage);
|
||||
}
|
||||
|
||||
protected void SendMessage<TMessage>(TMessage message) where TMessage : struct, IMessage
|
||||
{
|
||||
if (!sendTypes.Contains(typeof(TMessage)))
|
||||
{
|
||||
throw new IllegalSendException("Engine {0} tried to send undeclared Message {1}", this.GetType().Name, typeof(TMessage).Name);
|
||||
throw new IllegalSendException("Engine {0} tried to send undeclared Message {1}", GetType().Name, typeof(TMessage).Name);
|
||||
}
|
||||
|
||||
messageManager.AddMessage(message);
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
namespace Encompass.Engines
|
||||
{
|
||||
internal class ComponentUpdater<TComponent> : Engine where TComponent : struct, IComponent
|
||||
{
|
||||
public ComponentUpdater() : base()
|
||||
{
|
||||
receiveTypes.Add(typeof(ComponentUpdateMessage<TComponent>));
|
||||
}
|
||||
|
||||
public override void Update(double dt)
|
||||
{
|
||||
foreach (var componentUpdateMessage in ReadMessages<ComponentUpdateMessage<TComponent>>())
|
||||
{
|
||||
UpdateComponentInWorld(componentUpdateMessage.componentID, componentUpdateMessage.component);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
using System.Reflection;
|
||||
|
||||
namespace Encompass.Engines
|
||||
{
|
||||
internal class NewComponentMessageEmitter<TComponent> : Engine where TComponent : struct, IComponent
|
||||
{
|
||||
public NewComponentMessageEmitter() : base()
|
||||
{
|
||||
sendTypes.Add(typeof(PendingComponentMessage<TComponent>));
|
||||
}
|
||||
|
||||
public override void Update(double dt)
|
||||
{
|
||||
foreach (var (entity, componentID, component) in ReadComponentsFromWorld<TComponent>())
|
||||
{
|
||||
PendingComponentMessage<TComponent> newComponentMessage;
|
||||
newComponentMessage.entity = entity;
|
||||
newComponentMessage.componentID = componentID;
|
||||
newComponentMessage.component = component;
|
||||
SendMessage(newComponentMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
using System;
|
||||
|
||||
namespace Encompass.Exceptions
|
||||
{
|
||||
public class IllegalUpdateException : Exception
|
||||
{
|
||||
public IllegalUpdateException(
|
||||
string format,
|
||||
params object[] args
|
||||
) : base(string.Format(format, args)) { }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
using System;
|
||||
|
||||
namespace Encompass
|
||||
{
|
||||
public struct ComponentUpdateMessage<TComponent> : IMessage where TComponent : struct, IComponent
|
||||
{
|
||||
public Guid componentID;
|
||||
public TComponent component;
|
||||
}
|
||||
}
|
|
@ -67,10 +67,9 @@ namespace Encompass
|
|||
AddEngine((Engine)Activator.CreateInstance(typeof(ComponentMessageEmitter<>).MakeGenericType(componentType)));
|
||||
}
|
||||
|
||||
internal void RegisterNewComponentEmitter(Type componentType)
|
||||
internal void RegisterNewComponentUpdater(Type componentType)
|
||||
{
|
||||
registeredNewComponentTypes.Add(componentType);
|
||||
AddEngine((Engine)Activator.CreateInstance(typeof(NewComponentMessageEmitter<>).MakeGenericType(componentType)));
|
||||
AddEngine((Engine)Activator.CreateInstance(typeof(ComponentUpdater<>).MakeGenericType(componentType)));
|
||||
}
|
||||
|
||||
public Engine AddEngine<TEngine>(TEngine engine) where TEngine : Engine
|
||||
|
@ -129,13 +128,10 @@ namespace Encompass
|
|||
if (sendType.IsGenericType)
|
||||
{
|
||||
var genericTypeDefinition = sendType.GetGenericTypeDefinition();
|
||||
if (genericTypeDefinition == typeof(ComponentMessage<>) || genericTypeDefinition == typeof(PendingComponentMessage<>))
|
||||
if (genericTypeDefinition == typeof(ComponentUpdateMessage<>))
|
||||
{
|
||||
var componentType = sendType.GetGenericArguments().Single();
|
||||
if (!registeredNewComponentTypes.Contains(componentType))
|
||||
{
|
||||
RegisterNewComponentEmitter(componentType);
|
||||
}
|
||||
RegisterNewComponentUpdater(componentType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -208,11 +204,13 @@ namespace Encompass
|
|||
|
||||
var mutatedComponentTypes = new HashSet<Type>();
|
||||
var duplicateMutations = new List<Type>();
|
||||
var componentToEngines = new Dictionary<Type, List<Engine>>();
|
||||
var updateMessageToEngines = new Dictionary<Type, List<Engine>>();
|
||||
|
||||
foreach (var engine in engines)
|
||||
{
|
||||
foreach (var updateType in engine.updateTypes)
|
||||
var updateTypes = engine.sendTypes.Where((type) => type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ComponentUpdateMessage<>));
|
||||
|
||||
foreach (var updateType in updateTypes)
|
||||
{
|
||||
if (mutatedComponentTypes.Contains(updateType))
|
||||
{
|
||||
|
@ -223,12 +221,12 @@ namespace Encompass
|
|||
mutatedComponentTypes.Add(updateType);
|
||||
}
|
||||
|
||||
if (!componentToEngines.ContainsKey(updateType))
|
||||
if (!updateMessageToEngines.ContainsKey(updateType))
|
||||
{
|
||||
componentToEngines[updateType] = new List<Engine>();
|
||||
updateMessageToEngines[updateType] = new List<Engine>();
|
||||
}
|
||||
|
||||
componentToEngines[updateType].Add(engine);
|
||||
updateMessageToEngines[updateType].Add(engine);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -239,7 +237,7 @@ namespace Encompass
|
|||
{
|
||||
errorString += "\n" +
|
||||
componentType.Name + " updated by: " +
|
||||
string.Join(", ", componentToEngines[componentType].Select((engine) => engine.GetType().Name));
|
||||
string.Join(", ", updateMessageToEngines[componentType].Select((engine) => engine.GetType().Name));
|
||||
}
|
||||
|
||||
throw new EngineUpdateConflictException(errorString);
|
||||
|
|
|
@ -394,6 +394,19 @@ namespace Tests
|
|||
}
|
||||
}
|
||||
|
||||
[Receives(typeof(CheckHasMockComponentMessage))]
|
||||
[Reads(typeof(MockComponent))]
|
||||
class CheckHasMockComponentEngine : Engine
|
||||
{
|
||||
public override void Update(double dt)
|
||||
{
|
||||
foreach (var checkHasMockComponentMessage in ReadMessages<CheckHasMockComponentMessage>())
|
||||
{
|
||||
Assert.IsTrue(HasComponent<MockComponent>(checkHasMockComponentMessage.entity));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void RemoveComponent()
|
||||
{
|
||||
|
@ -470,7 +483,7 @@ namespace Tests
|
|||
|
||||
[Receives(typeof(CheckHasMockComponentMessage))]
|
||||
[ReadsPending(typeof(MockComponent))]
|
||||
class CheckHasMockComponentEngine : Engine
|
||||
class CheckHasPendingMockComponentEngine : Engine
|
||||
{
|
||||
public override void Update(double dt)
|
||||
{
|
||||
|
@ -488,7 +501,7 @@ namespace Tests
|
|||
var entity = worldBuilder.CreateEntity();
|
||||
|
||||
worldBuilder.AddEngine(new ActivateComponentEngine());
|
||||
worldBuilder.AddEngine(new CheckHasMockComponentEngine());
|
||||
worldBuilder.AddEngine(new CheckHasPendingMockComponentEngine());
|
||||
worldBuilder.AddEngine(new DoActivateCheckEngine(entity));
|
||||
|
||||
MockComponent mockComponent;
|
||||
|
|
|
@ -191,7 +191,7 @@ namespace Tests
|
|||
|
||||
var world = worldBuilder.Build();
|
||||
|
||||
var ex = Assert.Throws<IllegalSendException>(() => world.Update(0.01f));
|
||||
var ex = Assert.Throws<IllegalUpdateException>(() => world.Update(0.01f));
|
||||
Assert.That(ex.Message, Is.EqualTo("Engine UndeclaredUpdateComponentTestEngine tried to update undeclared Component MockComponent"));
|
||||
}
|
||||
|
||||
|
@ -645,21 +645,6 @@ namespace Tests
|
|||
Assert.IsFalse(hasEntity);
|
||||
}
|
||||
|
||||
[Sends(typeof(MockMessage))]
|
||||
[Updates(typeof(MockComponent))]
|
||||
class EngineThatWritesComponentAndMessage : Engine
|
||||
{
|
||||
public override void Update(double dt) { }
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void EngineWritesComponentAndMessage()
|
||||
{
|
||||
var worldBuilder = new WorldBuilder();
|
||||
|
||||
Assert.Throws<IllegalEngineAttributesException>(() => worldBuilder.AddEngine(new EngineThatWritesComponentAndMessage()));
|
||||
}
|
||||
|
||||
struct MockComponentUpdateMessage : IMessage
|
||||
{
|
||||
public Guid componentID;
|
||||
|
|
Loading…
Reference in New Issue