change attributes

pull/5/head
Evan Hemsley 2019-07-18 18:20:38 -07:00
parent 3deff94dfe
commit c8c5a8c7c4
12 changed files with 120 additions and 91 deletions

View File

@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Encompass.Exceptions;
namespace Encompass
{
[AttributeUsage(AttributeTargets.Class)]
public class Sends : Attribute
{
public readonly HashSet<Type> sendTypes;
public Sends(params Type[] sendTypes)
{
foreach (var sendType in sendTypes)
{
var isMessage = sendType.GetInterfaces().Contains(typeof(IMessage));
if (!isMessage)
{
throw new IllegalWriteTypeException("{0} must be a Message", sendType.Name);
}
}
this.sendTypes = new HashSet<Type>(sendTypes);
}
}
}

View File

@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Encompass.Exceptions;
namespace Encompass
{
[AttributeUsage(AttributeTargets.Class)]
public class Updates : Attribute
{
public readonly HashSet<Type> updateTypes;
public Updates(params Type[] updateTypes)
{
foreach (var updateType in updateTypes)
{
var isComponent = updateType.GetInterfaces().Contains(typeof(IComponent));
if (!isComponent)
{
throw new IllegalUpdateTypeException("{0} must be a Component", updateType.Name);
}
}
this.updateTypes = new HashSet<Type>(updateTypes);
}
}
}

View File

@ -1,31 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Encompass.Exceptions;
namespace Encompass
{
[AttributeUsage(AttributeTargets.Class)]
public class Writes : Attribute
{
public readonly HashSet<Type> writeTypes;
public Writes(params Type[] writeTypes)
{
foreach (var writeType in writeTypes)
{
if (!writeType.GetInterfaces().Contains(typeof(IMessage)) && !writeType.GetInterfaces().Contains(typeof(IComponent)))
{
throw new IllegalWriteTypeException("{0} must be a Message or Component", writeType.Name);
}
}
if (writeTypes.Any((type) => type.GetInterfaces().Contains(typeof(IMessage))) && writeTypes.Any((type) => type.GetInterfaces().Contains(typeof(IComponent))))
{
throw new ComponentAndMessageWriteException("An Engine which writes Components cannot also write Messages");
}
this.writeTypes = new HashSet<Type>(writeTypes);
}
}
}

View File

@ -8,9 +8,10 @@ namespace Encompass
{ {
public abstract class Engine public abstract class Engine
{ {
internal readonly HashSet<Type> writeTypes = new HashSet<Type>(); internal readonly HashSet<Type> sendTypes = 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>(); internal readonly HashSet<Type> activateTypes = new HashSet<Type>();
internal readonly HashSet<Type> updateTypes = new HashSet<Type>();
private EntityManager entityManager; private EntityManager entityManager;
private ComponentManager componentManager; private ComponentManager componentManager;
@ -18,10 +19,10 @@ namespace Encompass
protected Engine() protected Engine()
{ {
var writesAttribute = GetType().GetCustomAttribute<Writes>(false); var writesAttribute = GetType().GetCustomAttribute<Sends>(false);
if (writesAttribute != null) if (writesAttribute != null)
{ {
writeTypes = writesAttribute.writeTypes; sendTypes = writesAttribute.sendTypes;
} }
var readsAttribute = GetType().GetCustomAttribute<Reads>(false); var readsAttribute = GetType().GetCustomAttribute<Reads>(false);
@ -35,6 +36,16 @@ namespace Encompass
{ {
activateTypes = activatesAttribute.activateTypes; activateTypes = activatesAttribute.activateTypes;
} }
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) internal void AssignEntityManager(EntityManager entityManager)
@ -181,7 +192,7 @@ namespace Encompass
internal void UpdateComponentInWorld<TComponent>(Guid componentID, TComponent newComponent) where TComponent : struct, IComponent internal void UpdateComponentInWorld<TComponent>(Guid componentID, TComponent newComponent) where TComponent : struct, IComponent
{ {
if (!writeTypes.Contains(typeof(TComponent))) if (!updateTypes.Contains(typeof(TComponent)))
{ {
throw new IllegalWriteException("Engine {0} tried to write undeclared Component {1}", this.GetType().Name, typeof(TComponent).Name); throw new IllegalWriteException("Engine {0} tried to write undeclared Component {1}", this.GetType().Name, typeof(TComponent).Name);
} }
@ -196,7 +207,7 @@ namespace Encompass
protected void EmitMessage<TMessage>(TMessage message) where TMessage : struct, IMessage protected void EmitMessage<TMessage>(TMessage message) where TMessage : struct, IMessage
{ {
if (!writeTypes.Contains(typeof(TMessage))) if (!sendTypes.Contains(typeof(TMessage)))
{ {
throw new IllegalWriteException("Engine {0} tried to write undeclared Message {1}", this.GetType().Name, typeof(TMessage).Name); throw new IllegalWriteException("Engine {0} tried to write undeclared Message {1}", this.GetType().Name, typeof(TMessage).Name);
} }

View File

@ -6,13 +6,13 @@ namespace Encompass.Engines
{ {
public ComponentMessageEmitter() : base() public ComponentMessageEmitter() : base()
{ {
var writesAttribute = GetType().GetCustomAttribute<Writes>(false); var writesAttribute = GetType().GetCustomAttribute<Sends>(false);
if (writesAttribute != null) if (writesAttribute != null)
{ {
writesAttribute.writeTypes.Add(typeof(ComponentMessage<TComponent>)); writesAttribute.sendTypes.Add(typeof(ComponentMessage<TComponent>));
} }
writeTypes.Add(typeof(ComponentMessage<TComponent>)); sendTypes.Add(typeof(ComponentMessage<TComponent>));
} }
public override void Update(double dt) public override void Update(double dt)

View File

@ -3,9 +3,9 @@ using System;
namespace Encompass.Exceptions namespace Encompass.Exceptions
{ {
public class ComponentAndMessageWriteException : Exception public class IllegalEngineAttributesException : Exception
{ {
public ComponentAndMessageWriteException( public IllegalEngineAttributesException(
string format, string format,
params object[] args params object[] args
) : base(string.Format(format, args)) { } ) : base(string.Format(format, args)) { }

View File

@ -2,9 +2,9 @@ using System;
namespace Encompass.Exceptions namespace Encompass.Exceptions
{ {
public class UnregisteredComponentReadException : Exception public class IllegalUpdateTypeException : Exception
{ {
public UnregisteredComponentReadException( public IllegalUpdateTypeException(
string format, string format,
params object[] args params object[] args
) : base(string.Format(format, args)) { } ) : base(string.Format(format, args)) { }

View File

@ -77,11 +77,11 @@ namespace Encompass
foreach (var activateType in engine.activateTypes) foreach (var activateType in engine.activateTypes)
{ {
engine.writeTypes.Add(activateType); engine.sendTypes.Add(activateType);
} }
var messageReadTypes = engine.readTypes.Where((type) => type.GetInterfaces().Contains(typeof(IMessage))); var messageReadTypes = engine.readTypes.Where((type) => type.GetInterfaces().Contains(typeof(IMessage)));
var messageSendTypes = engine.writeTypes.Where((type) => type.GetInterfaces().Contains(typeof(IMessage))); var messageSendTypes = engine.sendTypes;
if (messageReadTypes.Intersect(messageSendTypes).Any()) if (messageReadTypes.Intersect(messageSendTypes).Any())
{ {
@ -144,7 +144,7 @@ namespace Encompass
{ {
foreach (var senderEngine in senders) foreach (var senderEngine in senders)
{ {
foreach (var messageType in senderEngine.writeTypes.Where((type) => type.GetInterfaces().Contains(typeof(IMessage)))) foreach (var messageType in senderEngine.sendTypes.Where((type) => type.GetInterfaces().Contains(typeof(IMessage))))
{ {
if (typeToReaders.ContainsKey(messageType)) if (typeToReaders.ContainsKey(messageType))
{ {
@ -181,29 +181,25 @@ namespace Encompass
foreach (var engine in engines) foreach (var engine in engines)
{ {
var writeAttribute = engine.GetType().GetCustomAttribute<Writes>(false); foreach (var updateType in engine.updateTypes)
if (writeAttribute != null)
{ {
foreach (var writeType in writeAttribute.writeTypes) if (updateType.GetInterfaces().Contains(typeof(IComponent))) // if our write type is a component
{ {
if (writeType.GetInterfaces().Contains(typeof(IComponent))) // if our write type is a component if (mutatedComponentTypes.Contains(updateType))
{ {
if (mutatedComponentTypes.Contains(writeType)) duplicateMutations.Add(updateType);
{
duplicateMutations.Add(writeType);
}
else
{
mutatedComponentTypes.Add(writeType);
}
if (!componentToEngines.ContainsKey(writeType))
{
componentToEngines[writeType] = new List<Engine>();
}
componentToEngines[writeType].Add(engine);
} }
else
{
mutatedComponentTypes.Add(updateType);
}
if (!componentToEngines.ContainsKey(updateType))
{
componentToEngines[updateType] = new List<Engine>();
}
componentToEngines[updateType].Add(engine);
} }
} }
} }

View File

@ -85,7 +85,7 @@ namespace Tests
public MockComponent mockComponent; public MockComponent mockComponent;
} }
[Writes(typeof(AddMockComponentMessage))] [Sends(typeof(AddMockComponentMessage))]
class EmitMockComponentMessageEngine : Engine class EmitMockComponentMessageEngine : Engine
{ {
private Entity entity; private Entity entity;
@ -359,7 +359,7 @@ namespace Tests
} }
[Reads(typeof(RemoveComponentTestMessage))] [Reads(typeof(RemoveComponentTestMessage))]
[Writes(typeof(CheckHasMockComponentMessage))] [Sends(typeof(CheckHasMockComponentMessage))]
class DoRemoveCheckEngine : Engine class DoRemoveCheckEngine : Engine
{ {
private Entity entity; private Entity entity;
@ -440,7 +440,7 @@ namespace Tests
} }
[Reads(typeof(ActivateComponentMessage))] [Reads(typeof(ActivateComponentMessage))]
[Writes(typeof(CheckHasMockComponentMessage))] [Sends(typeof(CheckHasMockComponentMessage))]
class DoActivateCheckEngine : Engine class DoActivateCheckEngine : Engine
{ {
private Entity entity; private Entity entity;
@ -509,7 +509,6 @@ namespace Tests
} }
[Reads(typeof(DeactivateComponentMessage))] [Reads(typeof(DeactivateComponentMessage))]
[Writes(typeof(MockComponent))]
class DeactivateComponentEngine : Engine class DeactivateComponentEngine : Engine
{ {
public override void Update(double dt) public override void Update(double dt)
@ -522,7 +521,7 @@ namespace Tests
} }
[Reads(typeof(DeactivateComponentMessage))] [Reads(typeof(DeactivateComponentMessage))]
[Writes(typeof(CheckHasMockComponentMessage))] [Sends(typeof(CheckHasMockComponentMessage))]
class DoDeactivateCheckEngine : Engine class DoDeactivateCheckEngine : Engine
{ {
private Entity entity; private Entity entity;

View File

@ -120,7 +120,7 @@ namespace Tests
} }
[Reads(typeof(MockComponent))] [Reads(typeof(MockComponent))]
[Writes(typeof(MockComponent))] [Updates(typeof(MockComponent))]
public class UpdateComponentTestEngine : Engine public class UpdateComponentTestEngine : Engine
{ {
public override void Update(double dt) public override void Update(double dt)
@ -200,7 +200,7 @@ namespace Tests
public string myString; public string myString;
} }
[Writes(typeof(MockMessage))] [Sends(typeof(MockMessage))]
public class MessageEmitEngine : Engine public class MessageEmitEngine : Engine
{ {
public override void Update(double dt) public override void Update(double dt)
@ -284,7 +284,7 @@ namespace Tests
static bool someTest; static bool someTest;
[Writes(typeof(MockMessage))] [Sends(typeof(MockMessage))]
class EmitMockMessageEngine : Engine class EmitMockMessageEngine : Engine
{ {
public override void Update(double dt) public override void Update(double dt)
@ -481,7 +481,6 @@ namespace Tests
} }
[Reads(typeof(DestroyerComponent), typeof(MockComponent))] [Reads(typeof(DestroyerComponent), typeof(MockComponent))]
[Writes(typeof(MockComponent))]
class DestroyAndAddComponentEngine : Engine class DestroyAndAddComponentEngine : Engine
{ {
public override void Update(double dt) public override void Update(double dt)
@ -646,7 +645,8 @@ namespace Tests
Assert.IsFalse(hasEntity); Assert.IsFalse(hasEntity);
} }
[Writes(typeof(MockComponent), typeof(MockMessage))] [Sends(typeof(MockMessage))]
[Updates(typeof(MockComponent))]
class EngineThatWritesComponentAndMessage : Engine class EngineThatWritesComponentAndMessage : Engine
{ {
public override void Update(double dt) { } public override void Update(double dt) { }
@ -657,7 +657,7 @@ namespace Tests
{ {
var worldBuilder = new WorldBuilder(); var worldBuilder = new WorldBuilder();
Assert.Throws<ComponentAndMessageWriteException>(() => worldBuilder.AddEngine(new EngineThatWritesComponentAndMessage())); Assert.Throws<IllegalEngineAttributesException>(() => worldBuilder.AddEngine(new EngineThatWritesComponentAndMessage()));
} }
struct MockComponentUpdateMessage : IMessage struct MockComponentUpdateMessage : IMessage
@ -667,7 +667,7 @@ namespace Tests
} }
[Reads(typeof(MockComponentUpdateMessage))] [Reads(typeof(MockComponentUpdateMessage))]
[Writes(typeof(MockComponent))] [Updates(typeof(MockComponent))]
class RepeatUpdateEngine : Engine class RepeatUpdateEngine : Engine
{ {
public override void Update(double dt) public override void Update(double dt)

View File

@ -14,7 +14,7 @@ namespace Tests
static Entity resultEntity; static Entity resultEntity;
[Writes(typeof(SpawnMessageA))] [Sends(typeof(SpawnMessageA))]
class MessageEmitter : Engine class MessageEmitter : Engine
{ {
public override void Update(double dt) public override void Update(double dt)

View File

@ -14,7 +14,7 @@ namespace Tests
struct BMessage : IMessage { } struct BMessage : IMessage { }
[Reads(typeof(AMessage))] [Reads(typeof(AMessage))]
[Writes(typeof(BMessage))] [Sends(typeof(BMessage))]
class AEngine : Engine class AEngine : Engine
{ {
public override void Update(double dt) public override void Update(double dt)
@ -25,7 +25,7 @@ namespace Tests
} }
[Reads(typeof(BMessage))] [Reads(typeof(BMessage))]
[Writes(typeof(AMessage))] [Sends(typeof(AMessage))]
class BEngine : Engine class BEngine : Engine
{ {
public override void Update(double dt) public override void Update(double dt)
@ -54,7 +54,7 @@ namespace Tests
struct DMessage : IMessage { } struct DMessage : IMessage { }
[Reads(typeof(AMessage))] [Reads(typeof(AMessage))]
[Writes(typeof(BMessage))] [Sends(typeof(BMessage))]
class AEngine : Engine class AEngine : Engine
{ {
public override void Update(double dt) public override void Update(double dt)
@ -65,7 +65,7 @@ namespace Tests
} }
[Reads(typeof(BMessage))] [Reads(typeof(BMessage))]
[Writes(typeof(CMessage))] [Sends(typeof(CMessage))]
class BEngine : Engine class BEngine : Engine
{ {
public override void Update(double dt) public override void Update(double dt)
@ -76,7 +76,7 @@ namespace Tests
} }
[Reads(typeof(CMessage))] [Reads(typeof(CMessage))]
[Writes(typeof(DMessage))] [Sends(typeof(DMessage))]
class CEngine : Engine class CEngine : Engine
{ {
public override void Update(double dt) public override void Update(double dt)
@ -87,7 +87,7 @@ namespace Tests
} }
[Reads(typeof(DMessage))] [Reads(typeof(DMessage))]
[Writes(typeof(AMessage))] [Sends(typeof(AMessage))]
class DEngine : Engine class DEngine : Engine
{ {
public override void Update(double dt) public override void Update(double dt)
@ -114,13 +114,13 @@ namespace Tests
{ {
struct AComponent : IComponent { } struct AComponent : IComponent { }
[Writes(typeof(AComponent))] [Updates(typeof(AComponent))]
class AEngine : Engine class AEngine : Engine
{ {
public override void Update(double dt) { } public override void Update(double dt) { }
} }
[Writes(typeof(AComponent))] [Updates(typeof(AComponent))]
class BEngine : Engine class BEngine : Engine
{ {
public override void Update(double dt) { } public override void Update(double dt) { }
@ -142,7 +142,7 @@ namespace Tests
struct AMessage : IMessage { } struct AMessage : IMessage { }
[Reads(typeof(AMessage))] [Reads(typeof(AMessage))]
[Writes(typeof(AMessage))] [Sends(typeof(AMessage))]
class AEngine : Engine class AEngine : Engine
{ {
public override void Update(double dt) public override void Update(double dt)
@ -186,7 +186,7 @@ namespace Tests
{ {
struct ANonMessage { } struct ANonMessage { }
[Writes(typeof(ANonMessage))] [Sends(typeof(ANonMessage))]
class MyEngine : Engine class MyEngine : Engine
{ {
public override void Update(double dt) public override void Update(double dt)
@ -216,7 +216,7 @@ namespace Tests
struct CMessage : IMessage { } struct CMessage : IMessage { }
struct DMessage : IMessage { } struct DMessage : IMessage { }
[Writes(typeof(AMessage))] [Sends(typeof(AMessage))]
class AEngine : Engine class AEngine : Engine
{ {
public override void Update(double dt) public override void Update(double dt)
@ -225,7 +225,7 @@ namespace Tests
} }
} }
[Writes(typeof(BMessage))] [Sends(typeof(BMessage))]
class BEngine : Engine class BEngine : Engine
{ {
public override void Update(double dt) public override void Update(double dt)
@ -235,7 +235,7 @@ namespace Tests
} }
[Reads(typeof(AMessage), typeof(BMessage))] [Reads(typeof(AMessage), typeof(BMessage))]
[Writes(typeof(DMessage))] [Sends(typeof(DMessage))]
class CEngine : Engine class CEngine : Engine
{ {
public override void Update(double dt) public override void Update(double dt)