Merge pull request #3 from thatcosmonaut/component_write_priority
Component write prioritypull/5/head
commit
5872e916ac
|
@ -1,26 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using Encompass.Exceptions;
|
|
||||||
|
|
||||||
namespace Encompass
|
|
||||||
{
|
|
||||||
public class Activates : Attribute
|
|
||||||
{
|
|
||||||
public readonly HashSet<Type> activateTypes = new HashSet<Type>();
|
|
||||||
|
|
||||||
public Activates(params Type[] activateTypes)
|
|
||||||
{
|
|
||||||
foreach (var activateType in activateTypes)
|
|
||||||
{
|
|
||||||
var isComponent = activateType.GetInterfaces().Contains(typeof(IComponent));
|
|
||||||
if (!isComponent)
|
|
||||||
{
|
|
||||||
throw new IllegalActivateTypeException("{0} must be a Component", activateType.Name);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.activateTypes.Add(typeof(PendingComponentMessage<>).MakeGenericType(activateType));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
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 = new HashSet<Type>();
|
|
||||||
|
|
||||||
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.Add(typeof(ComponentUpdateMessage<>).MakeGenericType(updateType));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Encompass.Exceptions;
|
||||||
|
|
||||||
|
namespace Encompass
|
||||||
|
{
|
||||||
|
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
|
||||||
|
public class Writes : Attribute
|
||||||
|
{
|
||||||
|
public readonly HashSet<Type> writeTypes = new HashSet<Type>();
|
||||||
|
public Dictionary<Type, int> priorities = new Dictionary<Type, int>();
|
||||||
|
|
||||||
|
public Writes(params Type[] writeTypes)
|
||||||
|
{
|
||||||
|
foreach (var writeType in writeTypes)
|
||||||
|
{
|
||||||
|
var isComponent = writeType.GetInterfaces().Contains(typeof(IComponent));
|
||||||
|
if (!isComponent)
|
||||||
|
{
|
||||||
|
throw new IllegalWriteTypeException("{0} must be a Component", writeType.Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.writeTypes.Add(typeof(ComponentWriteMessage<>).MakeGenericType(writeType));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Writes(Type writeType, int priority)
|
||||||
|
{
|
||||||
|
var isComponent = writeType.GetInterfaces().Contains(typeof(IComponent));
|
||||||
|
if (!isComponent)
|
||||||
|
{
|
||||||
|
throw new IllegalWriteTypeException("{0} must be a Component", writeType.Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.writeTypes.Add(typeof(ComponentWriteMessage<>).MakeGenericType(writeType));
|
||||||
|
this.priorities.Add(writeType, priority);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Encompass.Exceptions;
|
||||||
|
|
||||||
|
namespace Encompass
|
||||||
|
{
|
||||||
|
public class WritesPending : Attribute
|
||||||
|
{
|
||||||
|
public readonly HashSet<Type> writePendingTypes = new HashSet<Type>();
|
||||||
|
|
||||||
|
public WritesPending(params Type[] writePendingTypes)
|
||||||
|
{
|
||||||
|
foreach (var writePendingType in writePendingTypes)
|
||||||
|
{
|
||||||
|
var isComponent = writePendingType.GetInterfaces().Contains(typeof(IComponent));
|
||||||
|
if (!isComponent)
|
||||||
|
{
|
||||||
|
throw new IllegalWritePendingTypeException("{0} must be a Component", writePendingType.Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.writePendingTypes.Add(typeof(PendingComponentMessage<>).MakeGenericType(writePendingType));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,10 +19,10 @@ namespace Encompass
|
||||||
|
|
||||||
private readonly Dictionary<Type, HashSet<Guid>> typeToComponentIDs = new Dictionary<Type, HashSet<Guid>>();
|
private readonly Dictionary<Type, HashSet<Guid>> typeToComponentIDs = new Dictionary<Type, HashSet<Guid>>();
|
||||||
|
|
||||||
private readonly List<(Entity, Type, Guid, IComponent)> componentAddData = new List<(Entity, Type, Guid, IComponent)>();
|
private readonly Dictionary<(Entity, Type), (Guid, IComponent)> componentWriteData = new Dictionary<(Entity, Type), (Guid, IComponent)>();
|
||||||
private readonly HashSet<Guid> componentIDsMarkedForAdd = new HashSet<Guid>();
|
private readonly Dictionary<(Entity, Type), int> componentWritePriorities = new Dictionary<(Entity, Type), int>();
|
||||||
|
private readonly HashSet<Guid> componentIDsMarkedForWrite = new HashSet<Guid>();
|
||||||
private readonly HashSet<Guid> componentsMarkedForRemoval = new HashSet<Guid>();
|
private readonly HashSet<Guid> componentsMarkedForRemoval = new HashSet<Guid>();
|
||||||
private readonly Dictionary<Guid, IComponent> pendingUpdates = new Dictionary<Guid, IComponent>();
|
|
||||||
|
|
||||||
public ComponentManager(DrawLayerManager drawLayerManager)
|
public ComponentManager(DrawLayerManager drawLayerManager)
|
||||||
{
|
{
|
||||||
|
@ -40,26 +40,46 @@ namespace Encompass
|
||||||
return Guid.NewGuid();
|
return Guid.NewGuid();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal Guid MarkComponentForAdd<TComponent>(Entity entity, TComponent component) where TComponent : struct, IComponent
|
internal Guid MarkComponentForWrite<TComponent>(Entity entity, TComponent component, int priority) where TComponent : struct, IComponent
|
||||||
{
|
{
|
||||||
var id = NextID();
|
Guid id;
|
||||||
componentAddData.Add((entity, typeof(TComponent), id, component));
|
if (EntityHasComponentOfType<TComponent>(entity))
|
||||||
componentIDsMarkedForAdd.Add(id);
|
{
|
||||||
|
id = GetComponentByEntityAndType<TComponent>(entity).Item1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
id = NextID();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (componentWriteData.ContainsKey((entity, typeof(TComponent))))
|
||||||
|
{
|
||||||
|
var currentPriority = componentWritePriorities[(entity, typeof(TComponent))];
|
||||||
|
if (priority < currentPriority)
|
||||||
|
{
|
||||||
|
componentWriteData[(entity, typeof(TComponent))] = (id, component);
|
||||||
|
componentWritePriorities[(entity, typeof(TComponent))] = priority;
|
||||||
|
componentIDsMarkedForWrite.Add(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
componentWriteData.Add((entity, typeof(TComponent)), (id, component));
|
||||||
|
componentWritePriorities[(entity, typeof(TComponent))] = priority;
|
||||||
|
componentIDsMarkedForWrite.Add(id);
|
||||||
|
}
|
||||||
|
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal Guid MarkDrawComponentForAdd<TComponent>(Entity entity, TComponent component, int layer = 0) where TComponent : struct, IComponent
|
internal Guid MarkDrawComponentForWrite<TComponent>(Entity entity, TComponent component, int priority, int layer = 0) where TComponent : struct, IComponent
|
||||||
{
|
{
|
||||||
var id = MarkComponentForAdd(entity, component);
|
var id = MarkComponentForWrite(entity, component, priority);
|
||||||
drawLayerManager.RegisterComponentWithLayer(id, layer);
|
drawLayerManager.RegisterComponentWithLayer(id, layer);
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void AddComponent(Entity entity, Type type, Guid componentID, IComponent component)
|
internal void AddComponent(Entity entity, Type type, Guid componentID, IComponent component)
|
||||||
{
|
|
||||||
if (!entityIDToComponentTypeToComponentID.ContainsKey(entity.ID)) { return; }
|
|
||||||
|
|
||||||
if (!entityIDToComponentTypeToComponentID[entity.ID].ContainsKey(type))
|
|
||||||
{
|
{
|
||||||
IDToComponent[componentID] = component;
|
IDToComponent[componentID] = component;
|
||||||
componentIDToEntityID[componentID] = entity.ID;
|
componentIDToEntityID[componentID] = entity.ID;
|
||||||
|
@ -72,21 +92,34 @@ namespace Encompass
|
||||||
typeToComponentIDs[type].Add(componentID);
|
typeToComponentIDs[type].Add(componentID);
|
||||||
entityIDToComponentIDs[entity.ID].Add(componentID);
|
entityIDToComponentIDs[entity.ID].Add(componentID);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
internal void UpdateComponent(Guid componentID, IComponent component)
|
||||||
{
|
{
|
||||||
throw new MultipleComponentOfSameTypeException("Entity {0} cannot have multiple components of type {1}", entity.ID, type.Name);
|
IDToComponent[componentID] = component;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void AddMarkedComponents()
|
internal void WriteComponents()
|
||||||
{
|
{
|
||||||
foreach (var (entity, type, componentID, component) in componentAddData)
|
foreach (var keyValuePair in componentWriteData)
|
||||||
|
{
|
||||||
|
var (entity, type) = keyValuePair.Key;
|
||||||
|
var (componentID, component) = keyValuePair.Value;
|
||||||
|
|
||||||
|
if (!componentIDsMarkedForWrite.Contains(componentID) || !entityIDToComponentTypeToComponentID.ContainsKey(entity.ID)) { continue; }
|
||||||
|
|
||||||
|
if (entityIDToComponentTypeToComponentID[entity.ID].ContainsKey(type))
|
||||||
|
{
|
||||||
|
UpdateComponent(componentID, component);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
AddComponent(entity, type, componentID, component);
|
AddComponent(entity, type, componentID, component);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
componentAddData.Clear();
|
componentWriteData.Clear();
|
||||||
componentIDsMarkedForAdd.Clear();
|
componentIDsMarkedForWrite.Clear();
|
||||||
|
componentWritePriorities.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal IEnumerable<Guid> GetComponentIDsByEntityID(Guid entityID)
|
internal IEnumerable<Guid> GetComponentIDsByEntityID(Guid entityID)
|
||||||
|
@ -133,38 +166,39 @@ namespace Encompass
|
||||||
}
|
}
|
||||||
|
|
||||||
internal IComponent GetComponentByID(Guid componentID)
|
internal IComponent GetComponentByID(Guid componentID)
|
||||||
|
{
|
||||||
|
if (IDToComponent.ContainsKey(componentID))
|
||||||
{
|
{
|
||||||
return IDToComponent[componentID];
|
return IDToComponent[componentID];
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new ComponentNotFoundException("Component with ID {0} does not exist.", componentID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal Type GetComponentTypeByID(Guid componentID)
|
internal Type GetComponentTypeByID(Guid componentID)
|
||||||
|
{
|
||||||
|
if (componentIDToType.ContainsKey(componentID))
|
||||||
{
|
{
|
||||||
return componentIDToType[componentID];
|
return componentIDToType[componentID];
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new ComponentNotFoundException("Component with ID {0} does not exist.", componentID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal Guid GetEntityIDByComponentID(Guid componentID)
|
internal Guid GetEntityIDByComponentID(Guid componentID)
|
||||||
|
{
|
||||||
|
if (componentIDToEntityID.ContainsKey(componentID))
|
||||||
{
|
{
|
||||||
return componentIDToEntityID[componentID];
|
return componentIDToEntityID[componentID];
|
||||||
}
|
}
|
||||||
|
else
|
||||||
internal void AddUpdateComponentOperation<TComponent>(Guid componentID, TComponent newComponentValue) where TComponent : struct, IComponent
|
|
||||||
{
|
{
|
||||||
if (pendingUpdates.ContainsKey(componentID))
|
throw new ComponentNotFoundException("Component with ID {0} does not exist.", componentID);
|
||||||
{
|
|
||||||
throw new RepeatUpdateComponentException("Component {0} with ID {1} was updated multiple times this frame", typeof(TComponent).Name, componentID);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pendingUpdates.Add(componentID, newComponentValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void PerformComponentUpdates()
|
|
||||||
{
|
|
||||||
foreach (var idPair in pendingUpdates)
|
|
||||||
{
|
|
||||||
IDToComponent[idPair.Key] = idPair.Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
pendingUpdates.Clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void MarkAllComponentsOnEntityForRemoval(Guid entityID)
|
internal void MarkAllComponentsOnEntityForRemoval(Guid entityID)
|
||||||
|
@ -184,11 +218,12 @@ namespace Encompass
|
||||||
{
|
{
|
||||||
foreach (var componentID in componentsMarkedForRemoval)
|
foreach (var componentID in componentsMarkedForRemoval)
|
||||||
{
|
{
|
||||||
if (componentIDsMarkedForAdd.Contains(componentID))
|
if (componentIDsMarkedForWrite.Contains(componentID))
|
||||||
{
|
{
|
||||||
componentIDsMarkedForAdd.Remove(componentID);
|
componentIDsMarkedForWrite.Remove(componentID);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
if (IDToComponent.ContainsKey(componentID))
|
||||||
{
|
{
|
||||||
Remove(componentID);
|
Remove(componentID);
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,10 +21,13 @@ namespace Encompass
|
||||||
private readonly Dictionary<Entity, PooledDictionary<Type, Guid>> entityToTypeToPendingComponentID = new Dictionary<Entity, PooledDictionary<Type, Guid>>();
|
private readonly Dictionary<Entity, PooledDictionary<Type, Guid>> entityToTypeToPendingComponentID = new Dictionary<Entity, PooledDictionary<Type, Guid>>();
|
||||||
private readonly Dictionary<Entity, PooledDictionary<Type, Guid>> entityToTypeToComponentID = new Dictionary<Entity, PooledDictionary<Type, Guid>>();
|
private readonly Dictionary<Entity, PooledDictionary<Type, Guid>> entityToTypeToComponentID = new Dictionary<Entity, PooledDictionary<Type, Guid>>();
|
||||||
|
|
||||||
|
private readonly Dictionary<Entity, PooledDictionary<Type, int>> entityToTypeToPendingComponentPriority = new Dictionary<Entity, PooledDictionary<Type, int>>();
|
||||||
|
|
||||||
internal void RegisterEntity(Entity entity)
|
internal void RegisterEntity(Entity entity)
|
||||||
{
|
{
|
||||||
entityToTypeToComponentID[entity] = new PooledDictionary<Type, Guid>();
|
entityToTypeToComponentID[entity] = new PooledDictionary<Type, Guid>();
|
||||||
entityToTypeToPendingComponentID[entity] = new PooledDictionary<Type, Guid>();
|
entityToTypeToPendingComponentID[entity] = new PooledDictionary<Type, Guid>();
|
||||||
|
entityToTypeToPendingComponentPriority[entity] = new PooledDictionary<Type, int>();
|
||||||
entityToTypeToExistingComponentID[entity] = new PooledDictionary<Type, Guid>();
|
entityToTypeToExistingComponentID[entity] = new PooledDictionary<Type, Guid>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,6 +39,9 @@ namespace Encompass
|
||||||
entityToTypeToPendingComponentID[entity].Dispose();
|
entityToTypeToPendingComponentID[entity].Dispose();
|
||||||
entityToTypeToPendingComponentID.Remove(entity);
|
entityToTypeToPendingComponentID.Remove(entity);
|
||||||
|
|
||||||
|
entityToTypeToPendingComponentPriority[entity].Dispose();
|
||||||
|
entityToTypeToPendingComponentPriority.Remove(entity);
|
||||||
|
|
||||||
entityToTypeToExistingComponentID[entity].Dispose();
|
entityToTypeToExistingComponentID[entity].Dispose();
|
||||||
entityToTypeToExistingComponentID.Remove(entity);
|
entityToTypeToExistingComponentID.Remove(entity);
|
||||||
}
|
}
|
||||||
|
@ -75,6 +81,11 @@ namespace Encompass
|
||||||
{
|
{
|
||||||
dictionary.Clear();
|
dictionary.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (var dictionary in entityToTypeToPendingComponentPriority.Values)
|
||||||
|
{
|
||||||
|
dictionary.Clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void AddExistingComponentMessage<TComponent>(ComponentMessage<TComponent> componentMessage) where TComponent : struct, IComponent
|
internal void AddExistingComponentMessage<TComponent>(ComponentMessage<TComponent> componentMessage) where TComponent : struct, IComponent
|
||||||
|
@ -107,15 +118,21 @@ namespace Encompass
|
||||||
componentMessageTypeToPendingComponentIDs.Add(typeof(TComponent), new HashSet<Guid>());
|
componentMessageTypeToPendingComponentIDs.Add(typeof(TComponent), new HashSet<Guid>());
|
||||||
}
|
}
|
||||||
|
|
||||||
componentMessageTypeToPendingComponentIDs[typeof(TComponent)].Add(pendingComponentMessage.componentID);
|
|
||||||
|
|
||||||
if (!entityToTypeToPendingComponentID[pendingComponentMessage.entity].ContainsKey(typeof(TComponent)))
|
if (!entityToTypeToPendingComponentID[pendingComponentMessage.entity].ContainsKey(typeof(TComponent)))
|
||||||
{
|
{
|
||||||
entityToTypeToPendingComponentID[pendingComponentMessage.entity].Add(typeof(TComponent), pendingComponentMessage.componentID);
|
entityToTypeToPendingComponentID[pendingComponentMessage.entity].Add(typeof(TComponent), pendingComponentMessage.componentID);
|
||||||
|
entityToTypeToPendingComponentPriority[pendingComponentMessage.entity].Add(typeof(TComponent), pendingComponentMessage.priority);
|
||||||
|
componentMessageTypeToPendingComponentIDs[typeof(TComponent)].Add(pendingComponentMessage.componentID);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
throw new MultipleComponentOfSameTypeException("Entity {0} cannot have multiple components of type {1}", pendingComponentMessage.entity.ID, typeof(TComponent).Name);
|
if (pendingComponentMessage.priority < entityToTypeToPendingComponentPriority[pendingComponentMessage.entity][typeof(TComponent)])
|
||||||
|
{
|
||||||
|
componentMessageTypeToPendingComponentIDs[typeof(TComponent)].Remove(entityToTypeToPendingComponentID[pendingComponentMessage.entity][typeof(TComponent)]);
|
||||||
|
entityToTypeToPendingComponentID[pendingComponentMessage.entity][typeof(TComponent)] = pendingComponentMessage.componentID;
|
||||||
|
entityToTypeToPendingComponentPriority[pendingComponentMessage.entity][typeof(TComponent)] = pendingComponentMessage.priority;
|
||||||
|
componentMessageTypeToPendingComponentIDs[typeof(TComponent)].Add(pendingComponentMessage.componentID);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -259,18 +276,39 @@ namespace Encompass
|
||||||
}
|
}
|
||||||
|
|
||||||
internal IComponent GetComponentByID(Guid componentID)
|
internal IComponent GetComponentByID(Guid componentID)
|
||||||
|
{
|
||||||
|
if (componentIDToComponent.ContainsKey(componentID))
|
||||||
{
|
{
|
||||||
return componentIDToComponent[componentID];
|
return componentIDToComponent[componentID];
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new ComponentNotFoundException("Component with ID {0} does not exist.", componentID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal Type GetComponentTypeByID(Guid componentID)
|
internal Type GetComponentTypeByID(Guid componentID)
|
||||||
|
{
|
||||||
|
if (componentIDToType.ContainsKey(componentID))
|
||||||
{
|
{
|
||||||
return componentIDToType[componentID];
|
return componentIDToType[componentID];
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new ComponentNotFoundException("Component with ID {0} does not exist.", componentID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal Guid GetEntityIDByComponentID(Guid componentID)
|
internal Guid GetEntityIDByComponentID(Guid componentID)
|
||||||
|
{
|
||||||
|
if (componentIDToEntityID.ContainsKey(componentID))
|
||||||
{
|
{
|
||||||
return componentIDToEntityID[componentID];
|
return componentIDToEntityID[componentID];
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new ComponentNotFoundException("Component with ID {0} does not exist.", componentID);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ namespace Encompass
|
||||||
{
|
{
|
||||||
internal readonly HashSet<Type> sendTypes = new HashSet<Type>();
|
internal readonly HashSet<Type> sendTypes = new HashSet<Type>();
|
||||||
internal readonly HashSet<Type> receiveTypes = new HashSet<Type>();
|
internal readonly HashSet<Type> receiveTypes = new HashSet<Type>();
|
||||||
|
internal readonly Dictionary<Type, int> writePriorities = new Dictionary<Type, int>();
|
||||||
|
|
||||||
private EntityManager entityManager;
|
private EntityManager entityManager;
|
||||||
private MessageManager messageManager;
|
private MessageManager messageManager;
|
||||||
|
@ -24,16 +25,17 @@ namespace Encompass
|
||||||
sendTypes = sendsAttribute.sendTypes;
|
sendTypes = sendsAttribute.sendTypes;
|
||||||
}
|
}
|
||||||
|
|
||||||
var activatesAttribute = GetType().GetCustomAttribute<Activates>(false);
|
var activatesAttribute = GetType().GetCustomAttribute<WritesPending>(false);
|
||||||
if (activatesAttribute != null)
|
if (activatesAttribute != null)
|
||||||
{
|
{
|
||||||
sendTypes.UnionWith(activatesAttribute.activateTypes);
|
sendTypes.UnionWith(activatesAttribute.writePendingTypes);
|
||||||
}
|
}
|
||||||
|
|
||||||
var updatesAttribute = GetType().GetCustomAttribute<Updates>(false);
|
var writesAttributes = GetType().GetCustomAttributes<Writes>(false);
|
||||||
if (updatesAttribute != null)
|
foreach (var writesAttribute in writesAttributes)
|
||||||
{
|
{
|
||||||
sendTypes.UnionWith(updatesAttribute.updateTypes);
|
sendTypes.UnionWith(writesAttribute.writeTypes);
|
||||||
|
writePriorities = new Dictionary<Type, int>[2] { writePriorities, writesAttribute.priorities }.SelectMany(dict => dict).ToDictionary(pair => pair.Key, pair => pair.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
var receivesAttribute = GetType().GetCustomAttribute<Receives>(false);
|
var receivesAttribute = GetType().GetCustomAttribute<Receives>(false);
|
||||||
|
@ -92,18 +94,34 @@ namespace Encompass
|
||||||
return entityManager.GetEntity(entityID);
|
return entityManager.GetEntity(entityID);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Guid GetEntityIDByComponentID(Guid componentID)
|
protected Guid GetEntityIDByComponentID<TComponent>(Guid componentID) where TComponent : struct, IComponent
|
||||||
{
|
{
|
||||||
|
var pendingRead = receiveTypes.Contains(typeof(PendingComponentMessage<TComponent>));
|
||||||
|
var existingRead = receiveTypes.Contains(typeof(ComponentMessage<TComponent>));
|
||||||
|
|
||||||
|
if (!pendingRead && !existingRead)
|
||||||
|
{
|
||||||
|
throw new IllegalReadException("Engine {0} tried to read undeclared Component {1}", GetType().Name, typeof(TComponent).Name);
|
||||||
|
}
|
||||||
|
|
||||||
return componentMessageManager.GetEntityIDByComponentID(componentID);
|
return componentMessageManager.GetEntityIDByComponentID(componentID);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Entity GetEntityByComponentID(Guid componentID)
|
protected Entity GetEntityByComponentID<TComponent>(Guid componentID) where TComponent : struct, IComponent
|
||||||
{
|
{
|
||||||
return GetEntity(GetEntityIDByComponentID(componentID));
|
return GetEntity(GetEntityIDByComponentID<TComponent>(componentID));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected TComponent GetComponentByID<TComponent>(Guid componentID) where TComponent : struct, IComponent
|
protected TComponent GetComponentByID<TComponent>(Guid componentID) where TComponent : struct, IComponent
|
||||||
{
|
{
|
||||||
|
var pendingRead = receiveTypes.Contains(typeof(PendingComponentMessage<TComponent>));
|
||||||
|
var existingRead = receiveTypes.Contains(typeof(ComponentMessage<TComponent>));
|
||||||
|
|
||||||
|
if (!pendingRead && !existingRead)
|
||||||
|
{
|
||||||
|
throw new IllegalReadException("Engine {0} tried to read undeclared Component {1}", GetType().Name, typeof(TComponent).Name);
|
||||||
|
}
|
||||||
|
|
||||||
if (componentMessageManager.GetComponentTypeByID(componentID) != typeof(TComponent))
|
if (componentMessageManager.GetComponentTypeByID(componentID) != typeof(TComponent))
|
||||||
{
|
{
|
||||||
throw new ComponentTypeMismatchException("Expected Component to be of type {0} but was actually of type {1}", typeof(TComponent).Name, componentMessageManager.GetComponentTypeByID(componentID).Name);
|
throw new ComponentTypeMismatchException("Expected Component to be of type {0} but was actually of type {1}", typeof(TComponent).Name, componentMessageManager.GetComponentTypeByID(componentID).Name);
|
||||||
|
@ -124,40 +142,6 @@ namespace Encompass
|
||||||
return GetEntity(componentManager.GetEntityIDByComponentID(componentID));
|
return GetEntity(componentManager.GetEntityIDByComponentID(componentID));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Guid AddComponent<TComponent>(Entity entity, TComponent component) where TComponent : struct, IComponent
|
|
||||||
{
|
|
||||||
var componentID = componentManager.MarkComponentForAdd(entity, component);
|
|
||||||
|
|
||||||
if (sendTypes.Contains(typeof(PendingComponentMessage<TComponent>)))
|
|
||||||
{
|
|
||||||
PendingComponentMessage<TComponent> newComponentMessage;
|
|
||||||
newComponentMessage.entity = entity;
|
|
||||||
newComponentMessage.componentID = componentID;
|
|
||||||
newComponentMessage.component = component;
|
|
||||||
SendMessage(newComponentMessage);
|
|
||||||
SendPendingComponentMessage(newComponentMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
return componentID;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Guid AddDrawComponent<TComponent>(Entity entity, TComponent component, int layer = 0) where TComponent : struct, IComponent
|
|
||||||
{
|
|
||||||
var componentID = componentManager.MarkDrawComponentForAdd(entity, component, layer);
|
|
||||||
|
|
||||||
if (sendTypes.Contains(typeof(PendingComponentMessage<TComponent>)))
|
|
||||||
{
|
|
||||||
PendingComponentMessage<TComponent> newComponentMessage;
|
|
||||||
newComponentMessage.entity = entity;
|
|
||||||
newComponentMessage.componentID = componentID;
|
|
||||||
newComponentMessage.component = component;
|
|
||||||
SendMessage(newComponentMessage);
|
|
||||||
SendPendingComponentMessage(newComponentMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
return componentID;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected IEnumerable<ValueTuple<Guid, TComponent>> ReadComponents<TComponent>() where TComponent : struct, IComponent
|
protected IEnumerable<ValueTuple<Guid, TComponent>> ReadComponents<TComponent>() where TComponent : struct, IComponent
|
||||||
{
|
{
|
||||||
var pendingRead = receiveTypes.Contains(typeof(PendingComponentMessage<TComponent>));
|
var pendingRead = receiveTypes.Contains(typeof(PendingComponentMessage<TComponent>));
|
||||||
|
@ -280,22 +264,57 @@ namespace Encompass
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void UpdateComponentInWorld<TComponent>(Guid componentID, TComponent newComponent) where TComponent : struct, IComponent
|
protected Guid SetComponent<TComponent>(Entity entity, TComponent component) where TComponent : struct, IComponent
|
||||||
{
|
{
|
||||||
componentManager.AddUpdateComponentOperation(componentID, newComponent);
|
var priority = writePriorities.ContainsKey(typeof(TComponent)) ? writePriorities[typeof(TComponent)] : 0;
|
||||||
|
|
||||||
|
var componentID = componentManager.MarkComponentForWrite(entity, component, priority);
|
||||||
|
|
||||||
|
if (!sendTypes.Contains(typeof(ComponentWriteMessage<TComponent>)))
|
||||||
|
{
|
||||||
|
throw new IllegalWriteException("Engine {0} tried to update undeclared Component {1}", GetType().Name, typeof(TComponent).Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void UpdateComponent<TComponent>(Guid componentID, TComponent newComponentValue) where TComponent : struct, IComponent
|
if (sendTypes.Contains(typeof(PendingComponentMessage<TComponent>)))
|
||||||
{
|
{
|
||||||
if (!sendTypes.Contains(typeof(ComponentUpdateMessage<TComponent>)))
|
PendingComponentMessage<TComponent> newComponentMessage;
|
||||||
{
|
newComponentMessage.entity = entity;
|
||||||
throw new IllegalUpdateException("Engine {0} tried to update undeclared Component {1}", GetType().Name, typeof(TComponent).Name);
|
newComponentMessage.componentID = componentID;
|
||||||
|
newComponentMessage.component = component;
|
||||||
|
newComponentMessage.priority = priority;
|
||||||
|
SendPendingComponentMessage(newComponentMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
ComponentUpdateMessage<TComponent> componentUpdateMessage;
|
return componentID;
|
||||||
componentUpdateMessage.componentID = componentID;
|
}
|
||||||
componentUpdateMessage.component = newComponentValue;
|
|
||||||
SendMessage(componentUpdateMessage);
|
protected Guid SetComponent<TComponent>(Guid componentID, TComponent component) where TComponent : struct, IComponent
|
||||||
|
{
|
||||||
|
return SetComponent(GetEntityByComponentID<TComponent>(componentID), component);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Guid SetDrawComponent<TComponent>(Entity entity, TComponent component, int layer = 0) where TComponent : struct, IComponent
|
||||||
|
{
|
||||||
|
var priority = writePriorities.ContainsKey(typeof(TComponent)) ? writePriorities[typeof(TComponent)] : 0;
|
||||||
|
|
||||||
|
var componentID = componentManager.MarkDrawComponentForWrite(entity, component, priority, layer);
|
||||||
|
|
||||||
|
if (!sendTypes.Contains(typeof(ComponentWriteMessage<TComponent>)))
|
||||||
|
{
|
||||||
|
throw new IllegalWriteException("Engine {0} tried to write undeclared Component {1}", GetType().Name, typeof(TComponent).Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sendTypes.Contains(typeof(PendingComponentMessage<TComponent>)))
|
||||||
|
{
|
||||||
|
PendingComponentMessage<TComponent> newComponentMessage;
|
||||||
|
newComponentMessage.entity = entity;
|
||||||
|
newComponentMessage.componentID = componentID;
|
||||||
|
newComponentMessage.component = component;
|
||||||
|
newComponentMessage.priority = priority;
|
||||||
|
SendPendingComponentMessage(newComponentMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
return componentID;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void SendMessage<TMessage>(TMessage message) where TMessage : struct, IMessage
|
protected void SendMessage<TMessage>(TMessage message) where TMessage : struct, IMessage
|
||||||
|
|
|
@ -1,18 +0,0 @@
|
||||||
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,5 +1,7 @@
|
||||||
|
using System.Linq;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Encompass.Exceptions;
|
||||||
|
|
||||||
namespace Encompass
|
namespace Encompass
|
||||||
{
|
{
|
||||||
|
@ -34,9 +36,16 @@ namespace Encompass
|
||||||
}
|
}
|
||||||
|
|
||||||
public Entity GetEntity(Guid id)
|
public Entity GetEntity(Guid id)
|
||||||
|
{
|
||||||
|
if (IDToEntity.ContainsKey(id))
|
||||||
{
|
{
|
||||||
return IDToEntity[id];
|
return IDToEntity[id];
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new EntityNotFoundException("Entity with ID {0} does not exist.", id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void MarkForDestroy(Guid entityID)
|
public void MarkForDestroy(Guid entityID)
|
||||||
{
|
{
|
||||||
|
|
|
@ -2,9 +2,9 @@ using System;
|
||||||
|
|
||||||
namespace Encompass.Exceptions
|
namespace Encompass.Exceptions
|
||||||
{
|
{
|
||||||
public class IllegalUpdateTypeException : Exception
|
public class ComponentNotFoundException : Exception
|
||||||
{
|
{
|
||||||
public IllegalUpdateTypeException(
|
public ComponentNotFoundException(
|
||||||
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 EngineUpdateConflictException : Exception
|
public class EngineWriteConflictException : Exception
|
||||||
{
|
{
|
||||||
public EngineUpdateConflictException(
|
public EngineWriteConflictException(
|
||||||
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 IllegalActivateException : Exception
|
public class EntityNotFoundException : Exception
|
||||||
{
|
{
|
||||||
public IllegalActivateException(
|
public EntityNotFoundException(
|
||||||
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 IllegalUpdateException : Exception
|
public class IllegalWriteException : Exception
|
||||||
{
|
{
|
||||||
public IllegalUpdateException(
|
public IllegalWriteException(
|
||||||
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 IllegalActivateTypeException : Exception
|
public class IllegalWritePendingException : Exception
|
||||||
{
|
{
|
||||||
public IllegalActivateTypeException(
|
public IllegalWritePendingException(
|
||||||
string format,
|
string format,
|
||||||
params object[] args
|
params object[] args
|
||||||
) : base(string.Format(format, args)) { }
|
) : base(string.Format(format, args)) { }
|
|
@ -0,0 +1,12 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Encompass.Exceptions
|
||||||
|
{
|
||||||
|
public class IllegalWritePendingTypeException : Exception
|
||||||
|
{
|
||||||
|
public IllegalWritePendingTypeException(
|
||||||
|
string format,
|
||||||
|
params object[] args
|
||||||
|
) : base(string.Format(format, args)) { }
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Encompass.Exceptions
|
||||||
|
{
|
||||||
|
public class IllegalWriteTypeException : Exception
|
||||||
|
{
|
||||||
|
public IllegalWriteTypeException(
|
||||||
|
string format,
|
||||||
|
params object[] args
|
||||||
|
) : base(string.Format(format, args)) { }
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,7 +2,7 @@ using System;
|
||||||
|
|
||||||
namespace Encompass
|
namespace Encompass
|
||||||
{
|
{
|
||||||
internal struct ComponentUpdateMessage<TComponent> : IMessage where TComponent : struct, IComponent
|
internal struct ComponentWriteMessage<TComponent> : IMessage where TComponent : struct, IComponent
|
||||||
{
|
{
|
||||||
public Guid componentID;
|
public Guid componentID;
|
||||||
public TComponent component;
|
public TComponent component;
|
|
@ -7,5 +7,6 @@ namespace Encompass
|
||||||
public Entity entity;
|
public Entity entity;
|
||||||
public Guid componentID;
|
public Guid componentID;
|
||||||
public TComponent component;
|
public TComponent component;
|
||||||
|
public int priority;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -41,9 +41,8 @@ namespace Encompass
|
||||||
componentMessageManager.ClearMessages();
|
componentMessageManager.ClearMessages();
|
||||||
entityManager.DestroyMarkedEntities();
|
entityManager.DestroyMarkedEntities();
|
||||||
|
|
||||||
componentManager.PerformComponentUpdates();
|
|
||||||
componentManager.RemoveMarkedComponents();
|
componentManager.RemoveMarkedComponents();
|
||||||
componentManager.AddMarkedComponents();
|
componentManager.WriteComponents();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Draw()
|
public void Draw()
|
||||||
|
|
|
@ -50,14 +50,14 @@ namespace Encompass
|
||||||
messageManager.AddMessageDelayed(message, time);
|
messageManager.AddMessageDelayed(message, time);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Guid AddComponent<TComponent>(Entity entity, TComponent component) where TComponent : struct, IComponent
|
public Guid SetComponent<TComponent>(Entity entity, TComponent component, int priority = 0) where TComponent : struct, IComponent
|
||||||
{
|
{
|
||||||
return componentManager.MarkComponentForAdd(entity, component);
|
return componentManager.MarkComponentForWrite(entity, component, priority);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Guid AddDrawComponent<TComponent>(Entity entity, TComponent component, int layer = 0) where TComponent : struct, IComponent
|
public Guid SetDrawComponent<TComponent>(Entity entity, TComponent component, int priority = 0, int layer = 0) where TComponent : struct, IComponent
|
||||||
{
|
{
|
||||||
return componentManager.MarkDrawComponentForAdd(entity, component, layer);
|
return componentManager.MarkDrawComponentForWrite(entity, component, priority, layer);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void RegisterComponent(Type componentType)
|
internal void RegisterComponent(Type componentType)
|
||||||
|
@ -66,11 +66,6 @@ namespace Encompass
|
||||||
AddEngine((Engine)Activator.CreateInstance(typeof(ComponentMessageEmitter<>).MakeGenericType(componentType)));
|
AddEngine((Engine)Activator.CreateInstance(typeof(ComponentMessageEmitter<>).MakeGenericType(componentType)));
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void RegisterNewComponentUpdater(Type componentType)
|
|
||||||
{
|
|
||||||
AddEngine((Engine)Activator.CreateInstance(typeof(ComponentUpdater<>).MakeGenericType(componentType)));
|
|
||||||
}
|
|
||||||
|
|
||||||
public Engine AddEngine<TEngine>(TEngine engine) where TEngine : Engine
|
public Engine AddEngine<TEngine>(TEngine engine) where TEngine : Engine
|
||||||
{
|
{
|
||||||
engine.AssignEntityManager(entityManager);
|
engine.AssignEntityManager(entityManager);
|
||||||
|
@ -128,19 +123,6 @@ namespace Encompass
|
||||||
typeToReaders[receiveType].Add(engine);
|
typeToReaders[receiveType].Add(engine);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var sendType in engine.sendTypes)
|
|
||||||
{
|
|
||||||
if (sendType.IsGenericType)
|
|
||||||
{
|
|
||||||
var genericTypeDefinition = sendType.GetGenericTypeDefinition();
|
|
||||||
if (genericTypeDefinition == typeof(ComponentUpdateMessage<>))
|
|
||||||
{
|
|
||||||
var componentType = sendType.GetGenericArguments().Single();
|
|
||||||
RegisterNewComponentUpdater(componentType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return engine;
|
return engine;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -201,45 +183,92 @@ namespace Encompass
|
||||||
throw new EngineCycleException(errorString);
|
throw new EngineCycleException(errorString);
|
||||||
}
|
}
|
||||||
|
|
||||||
var mutatedComponentTypes = new HashSet<Type>();
|
var writtenComponentTypesWithoutPriority = new HashSet<Type>();
|
||||||
var duplicateMutations = new List<Type>();
|
var writtenComponentTypesWithPriority = new HashSet<Type>();
|
||||||
var updateMessageToEngines = new Dictionary<Type, List<Engine>>();
|
var duplicateWritesWithoutPriority = new List<Type>();
|
||||||
|
var duplicateWritesWithSamePriority = new List<Type>();
|
||||||
|
var writePriorities = new Dictionary<Type, HashSet<int>>();
|
||||||
|
var writeMessageToEngines = new Dictionary<Type, List<Engine>>();
|
||||||
|
|
||||||
foreach (var engine in engines)
|
foreach (var engine in engines)
|
||||||
{
|
{
|
||||||
var updateTypes = engine.sendTypes.Where((type) => type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ComponentUpdateMessage<>));
|
var writeTypes = engine.sendTypes.Where((type) => type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ComponentWriteMessage<>));
|
||||||
|
|
||||||
foreach (var updateType in updateTypes)
|
foreach (var writeType in writeTypes)
|
||||||
{
|
{
|
||||||
if (mutatedComponentTypes.Contains(updateType))
|
var componentType = writeType.GetGenericArguments()[0];
|
||||||
|
|
||||||
|
if (engine.writePriorities.ContainsKey(componentType))
|
||||||
{
|
{
|
||||||
duplicateMutations.Add(updateType);
|
var priority = engine.writePriorities[componentType];
|
||||||
|
|
||||||
|
writtenComponentTypesWithPriority.Add(componentType);
|
||||||
|
|
||||||
|
if (!writePriorities.ContainsKey(componentType))
|
||||||
|
{
|
||||||
|
writePriorities[componentType] = new HashSet<int>();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (writePriorities[componentType].Contains(priority))
|
||||||
|
{
|
||||||
|
duplicateWritesWithSamePriority.Add(componentType);
|
||||||
|
}
|
||||||
|
else if (writtenComponentTypesWithoutPriority.Contains(componentType))
|
||||||
|
{
|
||||||
|
duplicateWritesWithoutPriority.Add(componentType);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
mutatedComponentTypes.Add(updateType);
|
writePriorities[componentType].Add(priority);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (!updateMessageToEngines.ContainsKey(updateType))
|
else
|
||||||
{
|
{
|
||||||
updateMessageToEngines[updateType] = new List<Engine>();
|
if (writtenComponentTypesWithoutPriority.Contains(componentType) || writtenComponentTypesWithPriority.Contains(componentType))
|
||||||
}
|
|
||||||
|
|
||||||
updateMessageToEngines[updateType].Add(engine);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (duplicateMutations.Count > 0)
|
|
||||||
{
|
{
|
||||||
var errorString = "Multiple Engines update the same Component: ";
|
duplicateWritesWithoutPriority.Add(componentType);
|
||||||
foreach (var componentType in duplicateMutations)
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
writtenComponentTypesWithoutPriority.Add(componentType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!writeMessageToEngines.ContainsKey(componentType))
|
||||||
|
{
|
||||||
|
writeMessageToEngines[componentType] = new List<Engine>();
|
||||||
|
}
|
||||||
|
|
||||||
|
writeMessageToEngines[componentType].Add(engine);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (duplicateWritesWithoutPriority.Count > 0)
|
||||||
|
{
|
||||||
|
var errorString = "Multiple Engines write the same Component without declaring priority: ";
|
||||||
|
foreach (var componentType in duplicateWritesWithoutPriority)
|
||||||
{
|
{
|
||||||
errorString += "\n" +
|
errorString += "\n" +
|
||||||
componentType.Name + " updated by: " +
|
componentType.Name + " written by: " +
|
||||||
string.Join(", ", updateMessageToEngines[componentType].Select((engine) => engine.GetType().Name));
|
string.Join(", ", writeMessageToEngines[componentType].Select((engine) => engine.GetType().Name));
|
||||||
|
}
|
||||||
|
errorString += "\nTo resolve the conflict, add priority arguments to the Writes declarations.";
|
||||||
|
|
||||||
|
throw new EngineWriteConflictException(errorString);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new EngineUpdateConflictException(errorString);
|
if (duplicateWritesWithSamePriority.Count > 0)
|
||||||
|
{
|
||||||
|
var errorString = "Multiple Engines write the same Component with the same priority: ";
|
||||||
|
foreach (var componentType in duplicateWritesWithSamePriority)
|
||||||
|
{
|
||||||
|
errorString += "\n" +
|
||||||
|
componentType.Name + " written by: " +
|
||||||
|
string.Join(", ", writeMessageToEngines[componentType].Select(engine => engine.GetType().Name));
|
||||||
|
}
|
||||||
|
errorString += "\nTo resolve the conflict, add priority arguments to the Writes declarations.";
|
||||||
|
|
||||||
|
throw new EngineWriteConflictException(errorString);
|
||||||
}
|
}
|
||||||
|
|
||||||
var engineOrder = new List<Engine>();
|
var engineOrder = new List<Engine>();
|
||||||
|
@ -257,9 +286,8 @@ namespace Encompass
|
||||||
renderManager
|
renderManager
|
||||||
);
|
);
|
||||||
|
|
||||||
componentManager.PerformComponentUpdates();
|
|
||||||
componentManager.RemoveMarkedComponents();
|
componentManager.RemoveMarkedComponents();
|
||||||
componentManager.AddMarkedComponents();
|
componentManager.WriteComponents();
|
||||||
|
|
||||||
return world;
|
return world;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
<TargetFramework>netstandard2.0</TargetFramework>
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
<RootNamespace>Encompass</RootNamespace>
|
<RootNamespace>Encompass</RootNamespace>
|
||||||
<PackageId>EncompassECS.Framework</PackageId>
|
<PackageId>EncompassECS.Framework</PackageId>
|
||||||
<Version>0.13.0-rc2</Version>
|
<Version>0.13.0-rc7</Version>
|
||||||
<Authors>Evan Hemsley</Authors>
|
<Authors>Evan Hemsley</Authors>
|
||||||
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
|
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
|
||||||
<Company>Moonside Games</Company>
|
<Company>Moonside Games</Company>
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
using System.ComponentModel;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using FluentAssertions;
|
using FluentAssertions;
|
||||||
|
|
||||||
|
@ -11,7 +12,7 @@ namespace Tests
|
||||||
{
|
{
|
||||||
public class ComponentTests
|
public class ComponentTests
|
||||||
{
|
{
|
||||||
struct MockComponent : IComponent
|
struct MockComponent : Encompass.IComponent
|
||||||
{
|
{
|
||||||
public string myString;
|
public string myString;
|
||||||
public int myInt;
|
public int myInt;
|
||||||
|
@ -22,7 +23,6 @@ namespace Tests
|
||||||
public Entity entity;
|
public Entity entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
static IEnumerable<(Guid, MockComponent)> gottenMockComponentIDPairs = Enumerable.Empty<(Guid, MockComponent)>();
|
|
||||||
static (Guid, MockComponent) gottenMockComponentIDPair;
|
static (Guid, MockComponent) gottenMockComponentIDPair;
|
||||||
|
|
||||||
[Receives(typeof(EntityMessage))]
|
[Receives(typeof(EntityMessage))]
|
||||||
|
@ -70,7 +70,7 @@ namespace Tests
|
||||||
mockComponent.myInt = 3;
|
mockComponent.myInt = 3;
|
||||||
mockComponent.myString = "hello";
|
mockComponent.myString = "hello";
|
||||||
|
|
||||||
worldBuilder.AddComponent(entity, mockComponent);
|
worldBuilder.SetComponent(entity, mockComponent);
|
||||||
|
|
||||||
AddComponentTestMessage addComponentTestMessage;
|
AddComponentTestMessage addComponentTestMessage;
|
||||||
addComponentTestMessage.entity = entity;
|
addComponentTestMessage.entity = entity;
|
||||||
|
@ -83,58 +83,76 @@ namespace Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void AddMultipleComponentOfSameTypeToEntity()
|
public void SetMultipleComponentOfSameTypeOnEntity()
|
||||||
{
|
{
|
||||||
var worldBuilder = new WorldBuilder();
|
var worldBuilder = new WorldBuilder();
|
||||||
|
worldBuilder.AddEngine(new ReadMockComponentEngine());
|
||||||
MockComponent mockComponent;
|
|
||||||
mockComponent.myInt = 3;
|
|
||||||
mockComponent.myString = "hello";
|
|
||||||
|
|
||||||
var entity = worldBuilder.CreateEntity();
|
var entity = worldBuilder.CreateEntity();
|
||||||
worldBuilder.AddComponent(entity, mockComponent);
|
worldBuilder.SetComponent(entity, new MockComponent { myInt = 20, myString = "what" }, 2);
|
||||||
worldBuilder.AddComponent(entity, mockComponent);
|
worldBuilder.SetComponent(entity, new MockComponent { myInt = 50, myString = "hi" }, 0);
|
||||||
|
worldBuilder.SetComponent(entity, new MockComponent { myInt = 40, myString = "wassup" }, 1);
|
||||||
|
|
||||||
Assert.Throws<MultipleComponentOfSameTypeException>(() => worldBuilder.Build());
|
var world = worldBuilder.Build();
|
||||||
|
|
||||||
|
world.Update(0.01);
|
||||||
|
|
||||||
|
Assert.That(gottenMockComponentIDPair.Item2.myInt, Is.EqualTo(50));
|
||||||
|
Assert.That(gottenMockComponentIDPair.Item2.myString, Is.EqualTo("hi"));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Reads(typeof(MockComponent))]
|
[Reads(typeof(MockComponent))]
|
||||||
class MultipleAddEngine : Engine
|
[WritesPending(typeof(MockComponent))]
|
||||||
|
[Writes(typeof(MockComponent))]
|
||||||
|
class OverwriteEngine : Engine
|
||||||
{
|
{
|
||||||
public override void Update(double dt)
|
public override void Update(double dt)
|
||||||
{
|
{
|
||||||
foreach (var (mockComponentID, mockComponent) in ReadComponents<MockComponent>())
|
foreach (var (mockComponentID, mockComponent) in ReadComponents<MockComponent>())
|
||||||
{
|
{
|
||||||
var entity = GetEntityByComponentID(mockComponentID);
|
var entity = GetEntityByComponentID<MockComponent>(mockComponentID);
|
||||||
|
|
||||||
AddComponent(entity, new MockComponent());
|
SetComponent(entity, new MockComponent { myInt = 420 });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[ReadsPending(typeof(MockComponent))]
|
||||||
|
[Reads(typeof(MockComponent))]
|
||||||
|
class ReadMockComponentEngine : Engine
|
||||||
|
{
|
||||||
|
public override void Update(double dt)
|
||||||
|
{
|
||||||
|
gottenMockComponentIDPair = ReadComponent<MockComponent>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void EngineAddMultipleComponentOfSameTypeToEntity()
|
public void EngineOverwriteComponent()
|
||||||
{
|
{
|
||||||
var worldBuilder = new WorldBuilder();
|
var worldBuilder = new WorldBuilder();
|
||||||
worldBuilder.AddEngine(new MultipleAddEngine());
|
worldBuilder.AddEngine(new OverwriteEngine());
|
||||||
|
worldBuilder.AddEngine(new ReadMockComponentEngine());
|
||||||
|
|
||||||
var entity = worldBuilder.CreateEntity();
|
var entity = worldBuilder.CreateEntity();
|
||||||
worldBuilder.AddComponent(entity, new MockComponent());
|
worldBuilder.SetComponent(entity, new MockComponent {});
|
||||||
|
|
||||||
var world = worldBuilder.Build();
|
var world = worldBuilder.Build();
|
||||||
|
world.Update(0.01);
|
||||||
|
|
||||||
Assert.Throws<MultipleComponentOfSameTypeException>(() => world.Update(0.01));
|
Assert.That(gottenMockComponentIDPair.Item2.myInt, Is.EqualTo(420));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Reads(typeof(MockComponent))]
|
[Reads(typeof(MockComponent))]
|
||||||
|
[Writes(typeof(MockComponent))]
|
||||||
class AddAndRemoveComponentEngine : Engine
|
class AddAndRemoveComponentEngine : Engine
|
||||||
{
|
{
|
||||||
public override void Update(double dt)
|
public override void Update(double dt)
|
||||||
{
|
{
|
||||||
foreach (var (mockComponentID, mockComponent) in ReadComponents<MockComponent>())
|
foreach (var (mockComponentID, mockComponent) in ReadComponents<MockComponent>())
|
||||||
{
|
{
|
||||||
var entity = GetEntityByComponentID(mockComponentID);
|
var entity = GetEntityByComponentID<MockComponent>(mockComponentID);
|
||||||
AddComponent(entity, mockComponent);
|
SetComponent(entity, mockComponent);
|
||||||
RemoveComponent(mockComponentID);
|
RemoveComponent(mockComponentID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -147,7 +165,7 @@ namespace Tests
|
||||||
worldBuilder.AddEngine(new AddAndRemoveComponentEngine());
|
worldBuilder.AddEngine(new AddAndRemoveComponentEngine());
|
||||||
|
|
||||||
var entity = worldBuilder.CreateEntity();
|
var entity = worldBuilder.CreateEntity();
|
||||||
worldBuilder.AddComponent(entity, new MockComponent());
|
worldBuilder.SetComponent(entity, new MockComponent());
|
||||||
|
|
||||||
var world = worldBuilder.Build();
|
var world = worldBuilder.Build();
|
||||||
|
|
||||||
|
@ -183,15 +201,16 @@ namespace Tests
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Activates(typeof(MockComponent))]
|
[WritesPending(typeof(MockComponent))]
|
||||||
[Receives(typeof(AddMockComponentMessage))]
|
[Receives(typeof(AddMockComponentMessage))]
|
||||||
|
[Writes(typeof(MockComponent))]
|
||||||
class AddMockComponentEngine : Engine
|
class AddMockComponentEngine : Engine
|
||||||
{
|
{
|
||||||
public override void Update(double dt)
|
public override void Update(double dt)
|
||||||
{
|
{
|
||||||
foreach (var message in ReadMessages<AddMockComponentMessage>())
|
foreach (var message in ReadMessages<AddMockComponentMessage>())
|
||||||
{
|
{
|
||||||
AddComponent(message.entity, message.mockComponent);
|
SetComponent(message.entity, message.mockComponent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -239,7 +258,7 @@ namespace Tests
|
||||||
mockComponent.myInt = 3;
|
mockComponent.myInt = 3;
|
||||||
mockComponent.myString = "hello";
|
mockComponent.myString = "hello";
|
||||||
|
|
||||||
var componentID = worldBuilder.AddComponent<MockComponent>(entity, mockComponent);
|
var componentID = worldBuilder.SetComponent<MockComponent>(entity, mockComponent);
|
||||||
|
|
||||||
EntityMessage entityMessage;
|
EntityMessage entityMessage;
|
||||||
entityMessage.entity = entity;
|
entityMessage.entity = entity;
|
||||||
|
@ -282,7 +301,7 @@ namespace Tests
|
||||||
mockComponent.myInt = 3;
|
mockComponent.myInt = 3;
|
||||||
mockComponent.myString = "hello";
|
mockComponent.myString = "hello";
|
||||||
|
|
||||||
worldBuilder.AddComponent(entity, mockComponent);
|
worldBuilder.SetComponent(entity, mockComponent);
|
||||||
|
|
||||||
HasComponentTestMessage hasComponentTestMessage;
|
HasComponentTestMessage hasComponentTestMessage;
|
||||||
hasComponentTestMessage.entity = entity;
|
hasComponentTestMessage.entity = entity;
|
||||||
|
@ -368,7 +387,7 @@ namespace Tests
|
||||||
mockComponent.myInt = 3;
|
mockComponent.myInt = 3;
|
||||||
mockComponent.myString = "hello";
|
mockComponent.myString = "hello";
|
||||||
|
|
||||||
var componentID = worldBuilder.AddComponent(entity, mockComponent);
|
var componentID = worldBuilder.SetComponent(entity, mockComponent);
|
||||||
|
|
||||||
RemoveComponentTestMessage removeComponentMessage;
|
RemoveComponentTestMessage removeComponentMessage;
|
||||||
removeComponentMessage.entity = entity;
|
removeComponentMessage.entity = entity;
|
||||||
|
|
|
@ -59,8 +59,8 @@ namespace Tests
|
||||||
mockComponentB.myInt = 1;
|
mockComponentB.myInt = 1;
|
||||||
mockComponentB.myString = "howdy";
|
mockComponentB.myString = "howdy";
|
||||||
|
|
||||||
var componentAID = worldBuilder.AddComponent(entity, mockComponent);
|
var componentAID = worldBuilder.SetComponent(entity, mockComponent);
|
||||||
var componentBID = worldBuilder.AddComponent(entityB, mockComponentB);
|
var componentBID = worldBuilder.SetComponent(entityB, mockComponentB);
|
||||||
|
|
||||||
var world = worldBuilder.Build();
|
var world = worldBuilder.Build();
|
||||||
|
|
||||||
|
@ -83,7 +83,7 @@ namespace Tests
|
||||||
mockComponent.myInt = 0;
|
mockComponent.myInt = 0;
|
||||||
mockComponent.myString = "hello";
|
mockComponent.myString = "hello";
|
||||||
|
|
||||||
worldBuilder.AddComponent(entity, mockComponent);
|
worldBuilder.SetComponent(entity, mockComponent);
|
||||||
|
|
||||||
var world = worldBuilder.Build();
|
var world = worldBuilder.Build();
|
||||||
|
|
||||||
|
@ -109,8 +109,8 @@ namespace Tests
|
||||||
mockComponentB.myInt = 1;
|
mockComponentB.myInt = 1;
|
||||||
mockComponentB.myString = "howdy";
|
mockComponentB.myString = "howdy";
|
||||||
|
|
||||||
worldBuilder.AddComponent(entity, mockComponent);
|
worldBuilder.SetComponent(entity, mockComponent);
|
||||||
worldBuilder.AddComponent(entityB, mockComponentB);
|
worldBuilder.SetComponent(entityB, mockComponentB);
|
||||||
|
|
||||||
var world = worldBuilder.Build();
|
var world = worldBuilder.Build();
|
||||||
|
|
||||||
|
@ -120,7 +120,7 @@ namespace Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
[Reads(typeof(MockComponent))]
|
[Reads(typeof(MockComponent))]
|
||||||
[Updates(typeof(MockComponent))]
|
[Writes(typeof(MockComponent))]
|
||||||
public class UpdateComponentTestEngine : Engine
|
public class UpdateComponentTestEngine : Engine
|
||||||
{
|
{
|
||||||
public override void Update(double dt)
|
public override void Update(double dt)
|
||||||
|
@ -129,7 +129,7 @@ namespace Tests
|
||||||
|
|
||||||
component.myInt = 420;
|
component.myInt = 420;
|
||||||
component.myString = "blaze it";
|
component.myString = "blaze it";
|
||||||
UpdateComponent(componentID, component);
|
SetComponent(GetEntityByComponentID<MockComponent>(componentID), component);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,7 +149,7 @@ namespace Tests
|
||||||
mockComponent.myInt = 0;
|
mockComponent.myInt = 0;
|
||||||
mockComponent.myString = "hello";
|
mockComponent.myString = "hello";
|
||||||
|
|
||||||
worldBuilder.AddComponent(entity, mockComponent);
|
worldBuilder.SetComponent(entity, mockComponent);
|
||||||
|
|
||||||
var world = worldBuilder.Build();
|
var world = worldBuilder.Build();
|
||||||
|
|
||||||
|
@ -169,7 +169,7 @@ namespace Tests
|
||||||
|
|
||||||
component.myInt = 420;
|
component.myInt = 420;
|
||||||
component.myString = "blaze it";
|
component.myString = "blaze it";
|
||||||
UpdateComponent(componentID, component);
|
SetComponent(componentID, component);
|
||||||
|
|
||||||
component = ReadComponent<MockComponent>().Item2;
|
component = ReadComponent<MockComponent>().Item2;
|
||||||
}
|
}
|
||||||
|
@ -187,11 +187,11 @@ namespace Tests
|
||||||
mockComponent.myInt = 0;
|
mockComponent.myInt = 0;
|
||||||
mockComponent.myString = "hello";
|
mockComponent.myString = "hello";
|
||||||
|
|
||||||
worldBuilder.AddComponent(entity, mockComponent);
|
worldBuilder.SetComponent(entity, mockComponent);
|
||||||
|
|
||||||
var world = worldBuilder.Build();
|
var world = worldBuilder.Build();
|
||||||
|
|
||||||
var ex = Assert.Throws<IllegalUpdateException>(() => world.Update(0.01f));
|
var ex = Assert.Throws<IllegalWriteException>(() => world.Update(0.01f));
|
||||||
Assert.That(ex.Message, Is.EqualTo("Engine UndeclaredUpdateComponentTestEngine tried to update undeclared Component MockComponent"));
|
Assert.That(ex.Message, Is.EqualTo("Engine UndeclaredUpdateComponentTestEngine tried to update undeclared Component MockComponent"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -353,7 +353,7 @@ namespace Tests
|
||||||
var worldBuilder = new WorldBuilder();
|
var worldBuilder = new WorldBuilder();
|
||||||
|
|
||||||
var entity = worldBuilder.CreateEntity();
|
var entity = worldBuilder.CreateEntity();
|
||||||
worldBuilder.AddComponent(entity, new MockComponent());
|
worldBuilder.SetComponent(entity, new MockComponent());
|
||||||
|
|
||||||
var world = worldBuilder.Build();
|
var world = worldBuilder.Build();
|
||||||
|
|
||||||
|
@ -391,10 +391,10 @@ namespace Tests
|
||||||
componentB.myString = "hello";
|
componentB.myString = "hello";
|
||||||
|
|
||||||
var entity = worldBuilder.CreateEntity();
|
var entity = worldBuilder.CreateEntity();
|
||||||
worldBuilder.AddComponent(entity, componentA);
|
worldBuilder.SetComponent(entity, componentA);
|
||||||
|
|
||||||
var entityB = worldBuilder.CreateEntity();
|
var entityB = worldBuilder.CreateEntity();
|
||||||
worldBuilder.AddComponent(entityB, componentB);
|
worldBuilder.SetComponent(entityB, componentB);
|
||||||
|
|
||||||
var world = worldBuilder.Build();
|
var world = worldBuilder.Build();
|
||||||
world.Update(0.01f);
|
world.Update(0.01f);
|
||||||
|
@ -436,7 +436,7 @@ namespace Tests
|
||||||
foreach (var componentPair in ReadComponents<DestroyerComponent>())
|
foreach (var componentPair in ReadComponents<DestroyerComponent>())
|
||||||
{
|
{
|
||||||
var componentID = componentPair.Item1;
|
var componentID = componentPair.Item1;
|
||||||
var entityID = GetEntityIDByComponentID(componentID);
|
var entityID = GetEntityIDByComponentID<DestroyerComponent>(componentID);
|
||||||
Destroy(entityID);
|
Destroy(entityID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -469,13 +469,13 @@ namespace Tests
|
||||||
mockComponent.myInt = 2;
|
mockComponent.myInt = 2;
|
||||||
mockComponent.myString = "blah";
|
mockComponent.myString = "blah";
|
||||||
|
|
||||||
worldBuilder.AddComponent(entity, destroyerComponent);
|
worldBuilder.SetComponent(entity, destroyerComponent);
|
||||||
var componentID = worldBuilder.AddComponent(entity, mockComponent);
|
var componentID = worldBuilder.SetComponent(entity, mockComponent);
|
||||||
|
|
||||||
worldBuilder.AddComponent(entityB, destroyerComponent);
|
worldBuilder.SetComponent(entityB, destroyerComponent);
|
||||||
var componentBID = worldBuilder.AddComponent(entityB, mockComponent);
|
var componentBID = worldBuilder.SetComponent(entityB, mockComponent);
|
||||||
|
|
||||||
var componentCID = worldBuilder.AddComponent(entityC, mockComponent);
|
var componentCID = worldBuilder.SetComponent(entityC, mockComponent);
|
||||||
|
|
||||||
var world = worldBuilder.Build();
|
var world = worldBuilder.Build();
|
||||||
|
|
||||||
|
@ -495,7 +495,7 @@ namespace Tests
|
||||||
foreach (var componentPair in ReadComponents<DestroyerComponent>())
|
foreach (var componentPair in ReadComponents<DestroyerComponent>())
|
||||||
{
|
{
|
||||||
var componentID = componentPair.Item1;
|
var componentID = componentPair.Item1;
|
||||||
var entity = GetEntityByComponentID(componentID);
|
var entity = GetEntityByComponentID<MockComponent>(componentID);
|
||||||
var (id, _) = GetComponent<MockComponent>(entity);
|
var (id, _) = GetComponent<MockComponent>(entity);
|
||||||
RemoveComponent(id);
|
RemoveComponent(id);
|
||||||
Destroy(entity.ID);
|
Destroy(entity.ID);
|
||||||
|
@ -512,8 +512,8 @@ namespace Tests
|
||||||
|
|
||||||
var entity = worldBuilder.CreateEntity();
|
var entity = worldBuilder.CreateEntity();
|
||||||
|
|
||||||
worldBuilder.AddComponent(entity, new DestroyerComponent());
|
worldBuilder.SetComponent(entity, new DestroyerComponent());
|
||||||
worldBuilder.AddComponent(entity, new MockComponent());
|
worldBuilder.SetComponent(entity, new MockComponent());
|
||||||
|
|
||||||
var world = worldBuilder.Build();
|
var world = worldBuilder.Build();
|
||||||
|
|
||||||
|
@ -528,7 +528,7 @@ namespace Tests
|
||||||
public override void Update(double dt)
|
public override void Update(double dt)
|
||||||
{
|
{
|
||||||
var componentID = ReadComponent<MockComponent>().Item1;
|
var componentID = ReadComponent<MockComponent>().Item1;
|
||||||
entityFromComponentIDResult = GetEntityByComponentID(componentID);
|
entityFromComponentIDResult = GetEntityByComponentID<MockComponent>(componentID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -543,7 +543,7 @@ namespace Tests
|
||||||
component.myString = "howdy";
|
component.myString = "howdy";
|
||||||
|
|
||||||
var entity = worldBuilder.CreateEntity();
|
var entity = worldBuilder.CreateEntity();
|
||||||
worldBuilder.AddComponent(entity, component);
|
worldBuilder.SetComponent(entity, component);
|
||||||
|
|
||||||
var world = worldBuilder.Build();
|
var world = worldBuilder.Build();
|
||||||
world.Update(0.01);
|
world.Update(0.01);
|
||||||
|
@ -551,17 +551,18 @@ namespace Tests
|
||||||
Assert.That(entity, Is.EqualTo(entityFromComponentIDResult));
|
Assert.That(entity, Is.EqualTo(entityFromComponentIDResult));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Activates(typeof(MockComponent))]
|
|
||||||
[Reads(typeof(MockComponent))]
|
[Reads(typeof(MockComponent))]
|
||||||
|
[WritesPending(typeof(MockComponent))]
|
||||||
|
[Writes(typeof(MockComponent))]
|
||||||
class AddAndRemoveMockComponentEngine : Engine
|
class AddAndRemoveMockComponentEngine : Engine
|
||||||
{
|
{
|
||||||
public override void Update(double dt)
|
public override void Update(double dt)
|
||||||
{
|
{
|
||||||
foreach (var (mockComponentID, mockComponent) in ReadComponents<MockComponent>())
|
foreach (var (mockComponentID, mockComponent) in ReadComponents<MockComponent>())
|
||||||
{
|
{
|
||||||
var entity = GetEntityByComponentID(mockComponentID);
|
var entity = GetEntityByComponentID<MockComponent>(mockComponentID);
|
||||||
RemoveComponent(mockComponentID);
|
RemoveComponent(mockComponentID);
|
||||||
AddComponent(entity, new MockComponent());
|
SetComponent(entity, new MockComponent());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -573,7 +574,7 @@ namespace Tests
|
||||||
{
|
{
|
||||||
foreach (var (mockComponentID, mockComponent) in ReadComponents<MockComponent>())
|
foreach (var (mockComponentID, mockComponent) in ReadComponents<MockComponent>())
|
||||||
{
|
{
|
||||||
entityFromComponentIDResult = GetEntityByComponentID(mockComponentID);
|
entityFromComponentIDResult = GetEntityByComponentID<MockComponent>(mockComponentID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -586,7 +587,7 @@ namespace Tests
|
||||||
worldBuilder.AddEngine(new GetEntityFromPendingComponentIDEngine());
|
worldBuilder.AddEngine(new GetEntityFromPendingComponentIDEngine());
|
||||||
|
|
||||||
var entity = worldBuilder.CreateEntity();
|
var entity = worldBuilder.CreateEntity();
|
||||||
worldBuilder.AddComponent(entity, new MockComponent());
|
worldBuilder.SetComponent(entity, new MockComponent());
|
||||||
|
|
||||||
var world = worldBuilder.Build();
|
var world = worldBuilder.Build();
|
||||||
|
|
||||||
|
@ -613,7 +614,7 @@ namespace Tests
|
||||||
worldBuilder.AddEngine(new GetPendingComponentFromIDEngine());
|
worldBuilder.AddEngine(new GetPendingComponentFromIDEngine());
|
||||||
|
|
||||||
var entity = worldBuilder.CreateEntity();
|
var entity = worldBuilder.CreateEntity();
|
||||||
worldBuilder.AddComponent(entity, new MockComponent());
|
worldBuilder.SetComponent(entity, new MockComponent());
|
||||||
|
|
||||||
var world = worldBuilder.Build();
|
var world = worldBuilder.Build();
|
||||||
|
|
||||||
|
@ -642,7 +643,7 @@ namespace Tests
|
||||||
component.myString = "howdy";
|
component.myString = "howdy";
|
||||||
|
|
||||||
var entity = worldBuilder.CreateEntity();
|
var entity = worldBuilder.CreateEntity();
|
||||||
worldBuilder.AddComponent(entity, component);
|
worldBuilder.SetComponent(entity, component);
|
||||||
|
|
||||||
var world = worldBuilder.Build();
|
var world = worldBuilder.Build();
|
||||||
world.Update(0.01f);
|
world.Update(0.01f);
|
||||||
|
@ -652,7 +653,7 @@ namespace Tests
|
||||||
|
|
||||||
struct OtherComponent : IComponent { }
|
struct OtherComponent : IComponent { }
|
||||||
|
|
||||||
[Reads(typeof(MockComponent))]
|
[Reads(typeof(MockComponent), typeof(OtherComponent))]
|
||||||
class GetComponentByIDWithTypeMismatchEngine : Engine
|
class GetComponentByIDWithTypeMismatchEngine : Engine
|
||||||
{
|
{
|
||||||
public override void Update(double dt)
|
public override void Update(double dt)
|
||||||
|
@ -673,7 +674,7 @@ namespace Tests
|
||||||
component.myString = "howdy";
|
component.myString = "howdy";
|
||||||
|
|
||||||
var entity = worldBuilder.CreateEntity();
|
var entity = worldBuilder.CreateEntity();
|
||||||
worldBuilder.AddComponent(entity, component);
|
worldBuilder.SetComponent(entity, component);
|
||||||
|
|
||||||
var world = worldBuilder.Build();
|
var world = worldBuilder.Build();
|
||||||
|
|
||||||
|
@ -708,7 +709,7 @@ namespace Tests
|
||||||
EntityIDComponent entityIDComponent;
|
EntityIDComponent entityIDComponent;
|
||||||
entityIDComponent.entityID = entityTwo.ID;
|
entityIDComponent.entityID = entityTwo.ID;
|
||||||
|
|
||||||
worldBuilder.AddComponent(entity, entityIDComponent);
|
worldBuilder.SetComponent(entity, entityIDComponent);
|
||||||
|
|
||||||
var world = worldBuilder.Build();
|
var world = worldBuilder.Build();
|
||||||
|
|
||||||
|
@ -727,25 +728,26 @@ namespace Tests
|
||||||
public MockComponent mockComponent;
|
public MockComponent mockComponent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Reads(typeof(MockComponent))]
|
||||||
[Receives(typeof(MockComponentUpdateMessage))]
|
[Receives(typeof(MockComponentUpdateMessage))]
|
||||||
[Updates(typeof(MockComponent))]
|
[Writes(typeof(MockComponent))]
|
||||||
class RepeatUpdateEngine : Engine
|
class UpdateByComponentIDEngine : Engine
|
||||||
{
|
{
|
||||||
public override void Update(double dt)
|
public override void Update(double dt)
|
||||||
{
|
{
|
||||||
foreach (var mockComponentUpdateMessage in ReadMessages<MockComponentUpdateMessage>())
|
foreach (var mockComponentUpdateMessage in ReadMessages<MockComponentUpdateMessage>())
|
||||||
{
|
{
|
||||||
UpdateComponent(mockComponentUpdateMessage.componentID, mockComponentUpdateMessage.mockComponent);
|
SetComponent(mockComponentUpdateMessage.componentID, mockComponentUpdateMessage.mockComponent);
|
||||||
UpdateComponent(mockComponentUpdateMessage.componentID, mockComponentUpdateMessage.mockComponent);
|
SetComponent(mockComponentUpdateMessage.componentID, mockComponentUpdateMessage.mockComponent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void EngineUpdatesComponentMultipleTimes()
|
public void EngineUpdateByComponentID()
|
||||||
{
|
{
|
||||||
var worldBuilder = new WorldBuilder();
|
var worldBuilder = new WorldBuilder();
|
||||||
worldBuilder.AddEngine(new RepeatUpdateEngine());
|
worldBuilder.AddEngine(new UpdateByComponentIDEngine());
|
||||||
|
|
||||||
var entity = worldBuilder.CreateEntity();
|
var entity = worldBuilder.CreateEntity();
|
||||||
|
|
||||||
|
@ -753,7 +755,7 @@ namespace Tests
|
||||||
mockComponent.myInt = 1;
|
mockComponent.myInt = 1;
|
||||||
mockComponent.myString = "5";
|
mockComponent.myString = "5";
|
||||||
|
|
||||||
var mockComponentID = worldBuilder.AddComponent(entity, mockComponent);
|
var mockComponentID = worldBuilder.SetComponent(entity, mockComponent);
|
||||||
|
|
||||||
MockComponentUpdateMessage mockComponentUpdateMessage;
|
MockComponentUpdateMessage mockComponentUpdateMessage;
|
||||||
mockComponentUpdateMessage.componentID = mockComponentID;
|
mockComponentUpdateMessage.componentID = mockComponentID;
|
||||||
|
@ -761,7 +763,7 @@ namespace Tests
|
||||||
worldBuilder.SendMessage(mockComponentUpdateMessage);
|
worldBuilder.SendMessage(mockComponentUpdateMessage);
|
||||||
|
|
||||||
var world = worldBuilder.Build();
|
var world = worldBuilder.Build();
|
||||||
Assert.Throws<RepeatUpdateComponentException>(() => world.Update(0.01));
|
Assert.DoesNotThrow(() => world.Update(0.01));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Reads(typeof(MockComponent))]
|
[Reads(typeof(MockComponent))]
|
||||||
|
@ -787,7 +789,7 @@ namespace Tests
|
||||||
worldBuilder.AddEngine(new MessageReadEngine());
|
worldBuilder.AddEngine(new MessageReadEngine());
|
||||||
|
|
||||||
var entity = worldBuilder.CreateEntity();
|
var entity = worldBuilder.CreateEntity();
|
||||||
worldBuilder.AddComponent(entity, new MockComponent {});
|
worldBuilder.SetComponent(entity, new MockComponent {});
|
||||||
|
|
||||||
var world = worldBuilder.Build();
|
var world = worldBuilder.Build();
|
||||||
|
|
||||||
|
@ -806,7 +808,8 @@ namespace Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
[Receives(typeof(MockMessage))]
|
[Receives(typeof(MockMessage))]
|
||||||
[Activates(typeof(MockComponent))]
|
[WritesPending(typeof(MockComponent))]
|
||||||
|
[Writes(typeof(MockComponent))]
|
||||||
class ActivateComponentEngine : Engine
|
class ActivateComponentEngine : Engine
|
||||||
{
|
{
|
||||||
public override void Update(double dt)
|
public override void Update(double dt)
|
||||||
|
@ -814,7 +817,7 @@ namespace Tests
|
||||||
foreach (var message in ReadMessages<MockMessage>())
|
foreach (var message in ReadMessages<MockMessage>())
|
||||||
{
|
{
|
||||||
var entity = CreateEntity();
|
var entity = CreateEntity();
|
||||||
AddComponent(entity, new MockComponent {});
|
SetComponent(entity, new MockComponent {});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -844,5 +847,49 @@ namespace Tests
|
||||||
|
|
||||||
Assert.DoesNotThrow(() => world.Update(0.01));
|
Assert.DoesNotThrow(() => world.Update(0.01));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct DestroyComponentMessage : IMessage { public Entity entity; }
|
||||||
|
|
||||||
|
[Reads(typeof(MockComponent))]
|
||||||
|
[Writes(typeof(MockComponent))]
|
||||||
|
class AddComponentEngine : Engine
|
||||||
|
{
|
||||||
|
public override void Update(double dt)
|
||||||
|
{
|
||||||
|
foreach (var (componentID, component) in ReadComponents<MockComponent>())
|
||||||
|
{
|
||||||
|
SetComponent(componentID, new MockComponent {});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Receives(typeof(DestroyComponentMessage))]
|
||||||
|
class DestroyEntityEngine : Engine
|
||||||
|
{
|
||||||
|
public override void Update(double dt)
|
||||||
|
{
|
||||||
|
foreach (var message in ReadMessages<DestroyComponentMessage>())
|
||||||
|
{
|
||||||
|
Destroy(message.entity.ID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void EngineSetComponentAndDestroyEntitySameFrame()
|
||||||
|
{
|
||||||
|
var worldBuilder = new WorldBuilder();
|
||||||
|
worldBuilder.AddEngine(new AddComponentEngine());
|
||||||
|
worldBuilder.AddEngine(new DestroyEntityEngine());
|
||||||
|
|
||||||
|
var entity = worldBuilder.CreateEntity();
|
||||||
|
worldBuilder.SetComponent(entity, new MockComponent {});
|
||||||
|
worldBuilder.SendMessage(new DestroyComponentMessage { entity = entity });
|
||||||
|
|
||||||
|
var world = worldBuilder.Build();
|
||||||
|
world.Update(0.01);
|
||||||
|
|
||||||
|
Assert.DoesNotThrow(() => world.Update(0.01));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,7 @@ namespace Tests
|
||||||
AComponent aComponent;
|
AComponent aComponent;
|
||||||
|
|
||||||
var entity = worldBuilder.CreateEntity();
|
var entity = worldBuilder.CreateEntity();
|
||||||
var componentID = worldBuilder.AddComponent(entity, aComponent);
|
var componentID = worldBuilder.SetComponent(entity, aComponent);
|
||||||
|
|
||||||
var world = worldBuilder.Build();
|
var world = worldBuilder.Build();
|
||||||
|
|
||||||
|
@ -52,10 +52,10 @@ namespace Tests
|
||||||
AComponent aComponentTwo;
|
AComponent aComponentTwo;
|
||||||
|
|
||||||
var entity = worldBuilder.CreateEntity();
|
var entity = worldBuilder.CreateEntity();
|
||||||
var componentID = worldBuilder.AddComponent(entity, aComponent);
|
var componentID = worldBuilder.SetComponent(entity, aComponent);
|
||||||
|
|
||||||
var entityB = worldBuilder.CreateEntity();
|
var entityB = worldBuilder.CreateEntity();
|
||||||
var componentTwoID = worldBuilder.AddComponent(entityB, aComponentTwo);
|
var componentTwoID = worldBuilder.SetComponent(entityB, aComponentTwo);
|
||||||
var world = worldBuilder.Build();
|
var world = worldBuilder.Build();
|
||||||
|
|
||||||
world.Update(0.01f);
|
world.Update(0.01f);
|
||||||
|
|
|
@ -52,9 +52,9 @@ namespace Tests
|
||||||
TestDrawComponent testDrawComponent;
|
TestDrawComponent testDrawComponent;
|
||||||
|
|
||||||
var entity = worldBuilder.CreateEntity();
|
var entity = worldBuilder.CreateEntity();
|
||||||
worldBuilder.AddComponent(entity, aComponent);
|
worldBuilder.SetComponent(entity, aComponent);
|
||||||
worldBuilder.AddComponent(entity, cComponent);
|
worldBuilder.SetComponent(entity, cComponent);
|
||||||
var testDrawComponentID = worldBuilder.AddDrawComponent(entity, testDrawComponent, 2);
|
var testDrawComponentID = worldBuilder.SetDrawComponent(entity, testDrawComponent, 2);
|
||||||
|
|
||||||
var world = worldBuilder.Build();
|
var world = worldBuilder.Build();
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@ namespace Tests
|
||||||
{
|
{
|
||||||
foreach (var (componentID, component) in ReadComponents<TestDrawComponent>())
|
foreach (var (componentID, component) in ReadComponents<TestDrawComponent>())
|
||||||
{
|
{
|
||||||
Destroy(GetEntityIDByComponentID(componentID));
|
Destroy(GetEntityIDByComponentID<TestDrawComponent>(componentID));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -88,7 +88,7 @@ namespace Tests
|
||||||
TestDrawComponent testDrawComponent;
|
TestDrawComponent testDrawComponent;
|
||||||
|
|
||||||
var entity = worldBuilder.CreateEntity();
|
var entity = worldBuilder.CreateEntity();
|
||||||
var testDrawComponentID = worldBuilder.AddDrawComponent(entity, testDrawComponent, 1);
|
var testDrawComponentID = worldBuilder.SetDrawComponent(entity, testDrawComponent, 1);
|
||||||
|
|
||||||
var world = worldBuilder.Build();
|
var world = worldBuilder.Build();
|
||||||
|
|
||||||
|
|
|
@ -23,13 +23,14 @@ namespace Tests
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[Activates(typeof(TestComponent))]
|
[WritesPending(typeof(TestComponent))]
|
||||||
|
[Writes(typeof(TestComponent))]
|
||||||
class TestSpawner : Spawner<SpawnMessageA>
|
class TestSpawner : Spawner<SpawnMessageA>
|
||||||
{
|
{
|
||||||
protected override void Spawn(SpawnMessageA message)
|
protected override void Spawn(SpawnMessageA message)
|
||||||
{
|
{
|
||||||
resultEntity = CreateEntity();
|
resultEntity = CreateEntity();
|
||||||
AddComponent(resultEntity, new TestComponent());
|
SetComponent(resultEntity, new TestComponent());
|
||||||
Assert.Pass();
|
Assert.Pass();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -112,30 +112,99 @@ namespace Tests
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class MutationConflict
|
public class MultipleEngineWriteConflict
|
||||||
{
|
{
|
||||||
struct AComponent : IComponent { }
|
struct AComponent : IComponent { }
|
||||||
|
|
||||||
[Updates(typeof(AComponent))]
|
[Writes(typeof(AComponent))]
|
||||||
class AEngine : Engine
|
class AEngine : Engine
|
||||||
{
|
{
|
||||||
public override void Update(double dt) { }
|
public override void Update(double dt) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Updates(typeof(AComponent))]
|
[Writes(typeof(AComponent))]
|
||||||
class BEngine : Engine
|
class BEngine : Engine
|
||||||
{
|
{
|
||||||
public override void Update(double dt) { }
|
public override void Update(double dt) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void MutationConflictException()
|
public void EngineWriteConflictException()
|
||||||
{
|
{
|
||||||
var worldBuilder = new WorldBuilder();
|
var worldBuilder = new WorldBuilder();
|
||||||
worldBuilder.AddEngine(new AEngine());
|
worldBuilder.AddEngine(new AEngine());
|
||||||
worldBuilder.AddEngine(new BEngine());
|
worldBuilder.AddEngine(new BEngine());
|
||||||
|
|
||||||
Assert.Throws<EngineUpdateConflictException>(() => worldBuilder.Build());
|
Assert.Throws<EngineWriteConflictException>(() => worldBuilder.Build());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MultipleEngineWriteWithPriority
|
||||||
|
{
|
||||||
|
struct SetMessage : IMessage
|
||||||
|
{
|
||||||
|
public Entity entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct AComponent : IComponent
|
||||||
|
{
|
||||||
|
public int myInt;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Receives(typeof(SetMessage))]
|
||||||
|
[Writes(typeof(AComponent), 0)]
|
||||||
|
[WritesPending(typeof(AComponent))]
|
||||||
|
class AEngine : Engine
|
||||||
|
{
|
||||||
|
public override void Update(double dt)
|
||||||
|
{
|
||||||
|
foreach (var setMessage in ReadMessages<SetMessage>())
|
||||||
|
{
|
||||||
|
SetComponent(setMessage.entity, new AComponent { myInt = 0 });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Receives(typeof(SetMessage))]
|
||||||
|
[Writes(typeof(AComponent), 1)]
|
||||||
|
[WritesPending(typeof(AComponent))]
|
||||||
|
class BEngine : Engine
|
||||||
|
{
|
||||||
|
public override void Update(double dt)
|
||||||
|
{
|
||||||
|
foreach (var setMessage in ReadMessages<SetMessage>())
|
||||||
|
{
|
||||||
|
SetComponent(setMessage.entity, new AComponent { myInt = 1 });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static AComponent resultComponent;
|
||||||
|
|
||||||
|
[ReadsPending(typeof(AComponent))]
|
||||||
|
class ReadComponentEngine : Engine
|
||||||
|
{
|
||||||
|
public override void Update(double dt)
|
||||||
|
{
|
||||||
|
resultComponent = ReadComponent<AComponent>().Item2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void LowerPriorityWrites()
|
||||||
|
{
|
||||||
|
var worldBuilder = new WorldBuilder();
|
||||||
|
worldBuilder.AddEngine(new AEngine());
|
||||||
|
worldBuilder.AddEngine(new BEngine());
|
||||||
|
|
||||||
|
var entity = worldBuilder.CreateEntity();
|
||||||
|
worldBuilder.SendMessage(new SetMessage { entity = entity });
|
||||||
|
|
||||||
|
var world = worldBuilder.Build();
|
||||||
|
|
||||||
|
world.Update(0.01);
|
||||||
|
|
||||||
|
Assert.That(resultComponent.myInt, Is.EqualTo(0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -206,6 +275,68 @@ namespace Tests
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class PriorityConflict
|
||||||
|
{
|
||||||
|
[Writes(typeof(MockComponent), 2)]
|
||||||
|
class AEngine : Engine
|
||||||
|
{
|
||||||
|
public override void Update(double dt)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Writes(typeof(MockComponent), 2)]
|
||||||
|
class BEngine : Engine
|
||||||
|
{
|
||||||
|
public override void Update(double dt)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void PriorityConflictTest()
|
||||||
|
{
|
||||||
|
var worldBuilder = new WorldBuilder();
|
||||||
|
worldBuilder.AddEngine(new AEngine());
|
||||||
|
worldBuilder.AddEngine(new BEngine());
|
||||||
|
|
||||||
|
Assert.Throws<EngineWriteConflictException>(() => worldBuilder.Build());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class EngineWriteConflict
|
||||||
|
{
|
||||||
|
[Writes(typeof(MockComponent))]
|
||||||
|
class AEngine : Engine
|
||||||
|
{
|
||||||
|
public override void Update(double dt)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Writes(typeof(MockComponent), 2)]
|
||||||
|
class BEngine : Engine
|
||||||
|
{
|
||||||
|
public override void Update(double dt)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void EngineWriteConflictPriorityAndNoPriorityTest()
|
||||||
|
{
|
||||||
|
var worldBuilder = new WorldBuilder();
|
||||||
|
worldBuilder.AddEngine(new AEngine());
|
||||||
|
worldBuilder.AddEngine(new BEngine());
|
||||||
|
|
||||||
|
Assert.Throws<EngineWriteConflictException>(() => worldBuilder.Build());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public class LegalEngines
|
public class LegalEngines
|
||||||
{
|
{
|
||||||
static List<Engine> order = new List<Engine>();
|
static List<Engine> order = new List<Engine>();
|
||||||
|
|
|
@ -43,26 +43,26 @@ namespace Tests
|
||||||
TestDrawComponent testDrawComponent = default(TestDrawComponent);
|
TestDrawComponent testDrawComponent = default(TestDrawComponent);
|
||||||
|
|
||||||
var entity = worldBuilder.CreateEntity();
|
var entity = worldBuilder.CreateEntity();
|
||||||
worldBuilder.AddComponent(entity, testComponent);
|
worldBuilder.SetComponent(entity, testComponent);
|
||||||
var testDrawComponentOneID = worldBuilder.AddDrawComponent(entity, testDrawComponent, 3);
|
var testDrawComponentOneID = worldBuilder.SetDrawComponent(entity, testDrawComponent, 3);
|
||||||
|
|
||||||
TestDrawComponent testDrawComponentTwo = default(TestDrawComponent);
|
TestDrawComponent testDrawComponentTwo = default(TestDrawComponent);
|
||||||
|
|
||||||
var entityTwo = worldBuilder.CreateEntity();
|
var entityTwo = worldBuilder.CreateEntity();
|
||||||
worldBuilder.AddComponent(entityTwo, testComponent);
|
worldBuilder.SetComponent(entityTwo, testComponent);
|
||||||
var testDrawComponentTwoID = worldBuilder.AddDrawComponent(entityTwo, testDrawComponentTwo, 1);
|
var testDrawComponentTwoID = worldBuilder.SetDrawComponent(entityTwo, testDrawComponentTwo, 1);
|
||||||
|
|
||||||
TestDrawComponent testDrawComponentThree = default(TestDrawComponent);
|
TestDrawComponent testDrawComponentThree = default(TestDrawComponent);
|
||||||
|
|
||||||
var entityThree = worldBuilder.CreateEntity();
|
var entityThree = worldBuilder.CreateEntity();
|
||||||
worldBuilder.AddComponent(entityThree, testComponent);
|
worldBuilder.SetComponent(entityThree, testComponent);
|
||||||
var testDrawComponentThreeID = worldBuilder.AddDrawComponent(entityThree, testDrawComponentThree, 5);
|
var testDrawComponentThreeID = worldBuilder.SetDrawComponent(entityThree, testDrawComponentThree, 5);
|
||||||
|
|
||||||
TestDrawComponent testDrawComponentFour = default(TestDrawComponent);
|
TestDrawComponent testDrawComponentFour = default(TestDrawComponent);
|
||||||
|
|
||||||
var entityFour = worldBuilder.CreateEntity();
|
var entityFour = worldBuilder.CreateEntity();
|
||||||
worldBuilder.AddComponent(entityFour, testComponent);
|
worldBuilder.SetComponent(entityFour, testComponent);
|
||||||
var testDrawComponentFourID = worldBuilder.AddDrawComponent(entityFour, testDrawComponentFour, -5);
|
var testDrawComponentFourID = worldBuilder.SetDrawComponent(entityFour, testDrawComponentFour, -5);
|
||||||
|
|
||||||
var world = worldBuilder.Build();
|
var world = worldBuilder.Build();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue