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 abstract class Engine
{ {
public readonly List<Type> mutateComponentTypes = new List<Type>(); 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 EntityManager entityManager;
private ComponentManager componentManager; private ComponentManager componentManager;
private MessageManager messageManager;
public Engine() public Engine()
{ {
@ -18,6 +21,18 @@ namespace Encompass
{ {
mutateComponentTypes = mutatesAttribute.mutateComponentTypes; 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) internal void AssignEntityManager(EntityManager entityManager)
@ -30,6 +45,11 @@ namespace Encompass
this.componentManager = componentManager; this.componentManager = componentManager;
} }
internal void AssignMessageManager(MessageManager messageManager)
{
this.messageManager = messageManager;
}
public abstract void Update(float dt); public abstract void Update(float dt);
protected Entity CreateEntity() protected Entity CreateEntity()
@ -72,5 +92,29 @@ namespace Encompass
this.UpdateComponent(component, updateFunction); 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 List<Engine> engines;
private EntityManager entityManager; private EntityManager entityManager;
private ComponentManager componentManager; private ComponentManager componentManager;
private MessageManager messageManager;
internal World( internal World(
List<Engine> engines, List<Engine> engines,
EntityManager entityManager, EntityManager entityManager,
ComponentManager componentManager ComponentManager componentManager,
MessageManager messageManager
) )
{ {
this.engines = engines; this.engines = engines;
this.entityManager = entityManager; this.entityManager = entityManager;
this.componentManager = componentManager; this.componentManager = componentManager;
this.messageManager = messageManager;
} }
public void Update(float dt) public void Update(float dt)
@ -26,6 +29,7 @@ namespace Encompass
engine.Update(dt); engine.Update(dt);
} }
messageManager.ClearMessages();
entityManager.DestroyMarkedEntities(); entityManager.DestroyMarkedEntities();
componentManager.ActivateComponents(); componentManager.ActivateComponents();
componentManager.RemoveComponents(); componentManager.RemoveComponents();

View File

@ -8,11 +8,13 @@ namespace Encompass
private ComponentManager componentManager; private ComponentManager componentManager;
private EntityManager entityManager; private EntityManager entityManager;
private MessageManager messageManager;
public WorldBuilder() public WorldBuilder()
{ {
componentManager = new ComponentManager(); componentManager = new ComponentManager();
entityManager = new EntityManager(componentManager); entityManager = new EntityManager(componentManager);
messageManager = new MessageManager();
} }
public Entity CreateEntity() public Entity CreateEntity()
@ -26,6 +28,7 @@ namespace Encompass
engine.AssignEntityManager(this.entityManager); engine.AssignEntityManager(this.entityManager);
engine.AssignComponentManager(this.componentManager); engine.AssignComponentManager(this.componentManager);
engine.AssignMessageManager(this.messageManager);
engines.Add(engine); engines.Add(engine);
@ -37,7 +40,8 @@ namespace Encompass
var world = new World( var world = new World(
this.engines, this.engines,
this.entityManager, this.entityManager,
this.componentManager this.componentManager,
this.messageManager
); );
this.componentManager.ActivateComponents(); 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="graph\DirectedGraph.cs" />
<Content Include="IComponent.cs" /> <Content Include="IComponent.cs" />
<Content Include="IMessage.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> </ItemGroup>
</Project> </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 IEnumerable<MockComponent> resultComponents;
static MockComponent resultComponent; static MockComponent resultComponent;
static IEnumerable<MockMessage> resultMessages;
public class ReadComponentsTestEngine : Engine public class ReadComponentsTestEngine : Engine
{ {
public override void Update(float dt) public override void Update(float dt)
@ -172,5 +174,68 @@ namespace Tests
var ex = Assert.Throws<IllegalComponentMutationException>(() => world.Update(0.01f)); var ex = Assert.Throws<IllegalComponentMutationException>(() => world.Update(0.01f));
Assert.That(ex.Message, Is.EqualTo("Engine UndeclaredUpdateComponentTestEngine tried to mutate undeclared Component MockComponent")); 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"));
}
} }
} }