start on message stuff

pull/5/head
Evan Hemsley 2019-06-15 18:55:35 -07:00
parent e2ecd37556
commit c1aa6a07c9
10 changed files with 211 additions and 2 deletions

View File

@ -7,9 +7,12 @@ namespace Encompass
public abstract class Engine
{
public readonly List<Type> mutateComponentTypes = new List<Type>();
public readonly List<Type> emitMessageTypes = new List<Type>();
public readonly List<Type> readMessageTypes = new List<Type>();
private EntityManager entityManager;
private ComponentManager componentManager;
private MessageManager messageManager;
public Engine()
{
@ -18,6 +21,18 @@ namespace Encompass
{
mutateComponentTypes = mutatesAttribute.mutateComponentTypes;
}
var emitsAttribute = this.GetType().GetCustomAttribute<Emits>(false);
if (emitsAttribute != null)
{
emitMessageTypes = emitsAttribute.emitMessageTypes;
}
var readsAttribute = this.GetType().GetCustomAttribute<Reads>(false);
if (readsAttribute != null)
{
readMessageTypes = readsAttribute.readMessageTypes;
}
}
internal void AssignEntityManager(EntityManager entityManager)
@ -30,6 +45,11 @@ namespace Encompass
this.componentManager = componentManager;
}
internal void AssignMessageManager(MessageManager messageManager)
{
this.messageManager = messageManager;
}
public abstract void Update(float dt);
protected Entity CreateEntity()
@ -72,5 +92,29 @@ namespace Encompass
this.UpdateComponent(component, updateFunction);
}
}
protected void EmitMessage<TMessage>(TMessage message) where TMessage : struct, IMessage
{
if (emitMessageTypes.Contains(typeof(TMessage)))
{
this.messageManager.AddMessage(message);
}
else
{
throw new IllegalMessageEmitException("Engine {0} tried to emit undeclared Message {1}", this.GetType().Name, typeof(TMessage).Name);
}
}
protected IEnumerable<TMessage> ReadMessages<TMessage>() where TMessage : struct, IMessage
{
if (readMessageTypes.Contains(typeof(TMessage)))
{
return this.messageManager.GetMessagesByType<TMessage>();
}
else
{
throw new IllegalMessageReadException("Engine {0} tried to read undeclared Message {1}", this.GetType().Name, typeof(TMessage).Name);
}
}
}
}

32
src/MessageManager.cs Normal file
View File

@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace Encompass
{
internal class MessageManager
{
private Dictionary<Type, List<IMessage>> messageTypeToMessages = new Dictionary<Type, List<IMessage>>();
internal void AddMessage<TMessage>(TMessage message) where TMessage : struct, IMessage
{
if (!messageTypeToMessages.ContainsKey(typeof(TMessage)))
{
messageTypeToMessages.Add(typeof(TMessage), new List<IMessage>());
}
}
internal void ClearMessages()
{
foreach (var entry in messageTypeToMessages)
{
entry.Value.Clear();
}
}
internal IEnumerable<TMessage> GetMessagesByType<TMessage>() where TMessage : struct, IMessage
{
return messageTypeToMessages[typeof(TMessage)].Cast<TMessage>();
}
}
}

View File

@ -7,16 +7,19 @@ namespace Encompass
private List<Engine> engines;
private EntityManager entityManager;
private ComponentManager componentManager;
private MessageManager messageManager;
internal World(
List<Engine> engines,
EntityManager entityManager,
ComponentManager componentManager
ComponentManager componentManager,
MessageManager messageManager
)
{
this.engines = engines;
this.entityManager = entityManager;
this.componentManager = componentManager;
this.messageManager = messageManager;
}
public void Update(float dt)
@ -26,6 +29,7 @@ namespace Encompass
engine.Update(dt);
}
messageManager.ClearMessages();
entityManager.DestroyMarkedEntities();
componentManager.ActivateComponents();
componentManager.RemoveComponents();

View File

@ -8,11 +8,13 @@ namespace Encompass
private ComponentManager componentManager;
private EntityManager entityManager;
private MessageManager messageManager;
public WorldBuilder()
{
componentManager = new ComponentManager();
entityManager = new EntityManager(componentManager);
messageManager = new MessageManager();
}
public Entity CreateEntity()
@ -26,6 +28,7 @@ namespace Encompass
engine.AssignEntityManager(this.entityManager);
engine.AssignComponentManager(this.componentManager);
engine.AssignMessageManager(this.messageManager);
engines.Add(engine);
@ -37,7 +40,8 @@ namespace Encompass
var world = new World(
this.engines,
this.entityManager,
this.componentManager
this.componentManager,
this.messageManager
);
this.componentManager.ActivateComponents();

16
src/attributes/Emits.cs Normal file
View File

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
namespace Encompass
{
[System.AttributeUsage(System.AttributeTargets.Class)]
public class Emits : System.Attribute
{
public readonly List<Type> emitMessageTypes;
public Emits(params Type[] emitMessageTypes)
{
this.emitMessageTypes = new List<Type>(emitMessageTypes);
}
}
}

16
src/attributes/Reads.cs Normal file
View File

@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
namespace Encompass
{
[System.AttributeUsage(System.AttributeTargets.Class)]
public class Reads : System.Attribute
{
public readonly List<Type> readMessageTypes;
public Reads(params Type[] readMessageTypes)
{
this.readMessageTypes = new List<Type>(readMessageTypes);
}
}
}

View File

@ -17,5 +17,9 @@
<Content Include="graph\DirectedGraph.cs" />
<Content Include="IComponent.cs" />
<Content Include="IMessage.cs" />
<Content Include="MessageManager.cs" />
<Content Include="attributes\Emits.cs" />
<Content Include="exceptions\IllegalMessageEmitException.cs" />
<Content Include="exceptions\IllegalMessageReadException.cs" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,12 @@
using System;
namespace Encompass
{
public class IllegalMessageEmitException : Exception
{
public IllegalMessageEmitException(
string format,
params object[] args
) : base(string.Format(format, args)) { }
}
}

View File

@ -0,0 +1,12 @@
using System;
namespace Encompass
{
public class IllegalMessageReadException : Exception
{
public IllegalMessageReadException(
string format,
params object[] args
) : base(string.Format(format, args)) { }
}
}

View File

@ -12,6 +12,8 @@ namespace Tests
static IEnumerable<MockComponent> resultComponents;
static MockComponent resultComponent;
static IEnumerable<MockMessage> resultMessages;
public class ReadComponentsTestEngine : Engine
{
public override void Update(float dt)
@ -172,5 +174,68 @@ namespace Tests
var ex = Assert.Throws<IllegalComponentMutationException>(() => world.Update(0.01f));
Assert.That(ex.Message, Is.EqualTo("Engine UndeclaredUpdateComponentTestEngine tried to mutate undeclared Component MockComponent"));
}
struct MockMessage : IMessage
{
public string myString;
}
[Emits(typeof(MockMessage))]
public class MessageEmitEngine : Engine
{
public override void Update(float dt)
{
MockMessage message;
message.myString = "howdy";
this.EmitMessage(message);
}
}
[Reads(typeof(MockMessage))]
public class MessageReadEngine : Engine
{
public override void Update(float dt)
{
resultMessages = this.ReadMessages<MockMessage>();
}
}
[Test]
public void EmitAndReadMessage()
{
var worldBuilder = new WorldBuilder();
worldBuilder.AddEngine<MessageEmitEngine>();
worldBuilder.AddEngine<MessageReadEngine>();
var world = worldBuilder.Build();
world.Update(0.01f);
Assert.AreEqual(resultMessages.First().myString, "howdy");
}
public class UndeclaredMessageEmitEngine : Engine
{
public override void Update(float dt)
{
MockMessage message;
message.myString = "howdy";
this.EmitMessage(message);
}
}
[Test]
public void EmitUndeclaredMessage()
{
var worldBuilder = new WorldBuilder();
worldBuilder.AddEngine<UndeclaredMessageEmitEngine>();
var world = worldBuilder.Build();
var ex = Assert.Throws<IllegalMessageEmitException>(() => world.Update(0.01f));
Assert.That(ex.Message, Is.EqualTo("Engine UndeclaredMessageEmitEngine tried to emit undeclared Message MockMessage"));
}
}
}