commit
						569ee0ace8
					
				|  | @ -0,0 +1,28 @@ | ||||||
|  | using Encompass.Exceptions; | ||||||
|  | using System; | ||||||
|  | using System.Collections.Generic; | ||||||
|  | using System.Linq; | ||||||
|  | 
 | ||||||
|  | namespace Encompass | ||||||
|  | { | ||||||
|  |     [AttributeUsage(AttributeTargets.Class)] | ||||||
|  |     public class QueryWith : Attribute | ||||||
|  |     { | ||||||
|  |         public readonly HashSet<Type> queryWithTypes = new HashSet<Type>(); | ||||||
|  | 
 | ||||||
|  |         public QueryWith(params Type[] queryWithTypes) | ||||||
|  |         { | ||||||
|  |             foreach (var queryWithType in queryWithTypes) | ||||||
|  |             { | ||||||
|  |                 var isComponent = queryWithType.GetInterfaces().Contains(typeof(IComponent)); | ||||||
|  | 
 | ||||||
|  |                 if (!isComponent) | ||||||
|  |                 { | ||||||
|  |                     throw new IllegalReadTypeException("{0} must be a Component", queryWithType.Name); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 this.queryWithTypes.Add(queryWithType); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,28 @@ | ||||||
|  | using Encompass.Exceptions; | ||||||
|  | using System; | ||||||
|  | using System.Collections.Generic; | ||||||
|  | using System.Linq; | ||||||
|  | 
 | ||||||
|  | namespace Encompass | ||||||
|  | { | ||||||
|  |     [AttributeUsage(AttributeTargets.Class)] | ||||||
|  |     public class QueryWithout : Attribute | ||||||
|  |     { | ||||||
|  |         public readonly HashSet<Type> queryWithoutTypes = new HashSet<Type>(); | ||||||
|  | 
 | ||||||
|  |         public QueryWithout(params Type[] queryWithoutTypes) | ||||||
|  |         { | ||||||
|  |             foreach (var type in queryWithoutTypes) | ||||||
|  |             { | ||||||
|  |                 var isComponent = type.GetInterfaces().Contains(typeof(IComponent)); | ||||||
|  | 
 | ||||||
|  |                 if (!isComponent) | ||||||
|  |                 { | ||||||
|  |                     throw new IllegalReadTypeException("{0} must be a Component", type.Name); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 this.queryWithoutTypes.Add(type); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,28 @@ | ||||||
|  | using System; | ||||||
|  | using System.Collections.Generic; | ||||||
|  | using System.Linq; | ||||||
|  | using Encompass.Exceptions; | ||||||
|  | 
 | ||||||
|  | namespace Encompass | ||||||
|  | { | ||||||
|  |     [AttributeUsage(AttributeTargets.Class)] | ||||||
|  |     public class ReadsImmediate : Attribute | ||||||
|  |     { | ||||||
|  |         public readonly HashSet<Type> readImmediateTypes = new HashSet<Type>(); | ||||||
|  | 
 | ||||||
|  |         public ReadsImmediate(params Type[] readImmediateTypes) | ||||||
|  |         { | ||||||
|  |             foreach (var readImmediateType in readImmediateTypes) | ||||||
|  |             { | ||||||
|  |                 var isComponent = readImmediateType.GetInterfaces().Contains(typeof(IComponent)); | ||||||
|  | 
 | ||||||
|  |                 if (!isComponent) | ||||||
|  |                 { | ||||||
|  |                     throw new IllegalReadTypeException("{0} must be a Component", readImmediateType.Name); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 this.readImmediateTypes.Add(readImmediateType); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -1,28 +0,0 @@ | ||||||
| using System; |  | ||||||
| using System.Collections.Generic; |  | ||||||
| using System.Linq; |  | ||||||
| using Encompass.Exceptions; |  | ||||||
| 
 |  | ||||||
| namespace Encompass |  | ||||||
| { |  | ||||||
|     [AttributeUsage(AttributeTargets.Class)] |  | ||||||
|     public class ReadsPending : Attribute |  | ||||||
|     { |  | ||||||
|         public readonly HashSet<Type> readPendingTypes = new HashSet<Type>(); |  | ||||||
| 
 |  | ||||||
|         public ReadsPending(params Type[] readPendingTypes) |  | ||||||
|         { |  | ||||||
|             foreach (var readPendingType in readPendingTypes) |  | ||||||
|             { |  | ||||||
|                 var isComponent = readPendingType.GetInterfaces().Contains(typeof(IComponent)); |  | ||||||
| 
 |  | ||||||
|                 if (!isComponent) |  | ||||||
|                 { |  | ||||||
|                     throw new IllegalReadTypeException("{0} must be a Component", readPendingType.Name); |  | ||||||
|                 } |  | ||||||
| 
 |  | ||||||
|                 this.readPendingTypes.Add(readPendingType); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | @ -0,0 +1,27 @@ | ||||||
|  | using System; | ||||||
|  | using System.Collections.Generic; | ||||||
|  | using System.Linq; | ||||||
|  | using Encompass.Exceptions; | ||||||
|  | 
 | ||||||
|  | namespace Encompass | ||||||
|  | { | ||||||
|  |     [AttributeUsage(AttributeTargets.Class)] | ||||||
|  |     public class WritesImmediate : Attribute | ||||||
|  |     { | ||||||
|  |         public readonly HashSet<Type> writeImmediateTypes = new HashSet<Type>(); | ||||||
|  | 
 | ||||||
|  |         public WritesImmediate(params Type[] writeImmediateTypes) | ||||||
|  |         { | ||||||
|  |             foreach (var writeImmediateType in writeImmediateTypes) | ||||||
|  |             { | ||||||
|  |                 var isComponent = writeImmediateType.GetInterfaces().Contains(typeof(IComponent)); | ||||||
|  |                 if (!isComponent) | ||||||
|  |                 { | ||||||
|  |                     throw new IllegalWriteImmediateTypeException("{0} must be a Component", writeImmediateType.Name); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 this.writeImmediateTypes.Add(writeImmediateType); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -1,26 +0,0 @@ | ||||||
| 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(writePendingType); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | @ -0,0 +1,54 @@ | ||||||
|  | using MoonTools.FastCollections; | ||||||
|  | using System; | ||||||
|  | using System.Collections.Generic; | ||||||
|  | 
 | ||||||
|  | namespace Encompass | ||||||
|  | { | ||||||
|  |     internal class ComponentBitSet | ||||||
|  |     { | ||||||
|  |         Dictionary<int, BitSet512> entities = new Dictionary<int, BitSet512>(); | ||||||
|  |         Dictionary<Type, int> TypeToIndex { get; } | ||||||
|  | 
 | ||||||
|  |         public ComponentBitSet(Dictionary<Type, int> typeToIndex) | ||||||
|  |         { | ||||||
|  |             TypeToIndex = typeToIndex; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public void Clear() | ||||||
|  |         { | ||||||
|  |             entities.Clear(); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public void AddEntity(int entityID) | ||||||
|  |         { | ||||||
|  |             entities.Add(entityID, BitSet512.Zero); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public void Set<TComponent>(int entityID) where TComponent : struct, IComponent | ||||||
|  |         { | ||||||
|  |             if (!entities.ContainsKey(entityID)) { AddEntity(entityID); } | ||||||
|  |             entities[entityID] = entities[entityID].Set(TypeToIndex[typeof(TComponent)]); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public void RemoveComponent<TComponent>(int entityID) where TComponent : struct, IComponent | ||||||
|  |         { | ||||||
|  |             if (entities.ContainsKey(entityID)) | ||||||
|  |             { | ||||||
|  |                 entities[entityID] = entities[entityID].UnSet(TypeToIndex[typeof(TComponent)]); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public void RemoveEntity(int entityID) | ||||||
|  |         { | ||||||
|  |             if (entities.ContainsKey(entityID)) | ||||||
|  |             { | ||||||
|  |                 entities.Remove(entityID); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public BitSet512 EntityBitArray(int entityID) | ||||||
|  |         { | ||||||
|  |             return entities.ContainsKey(entityID) ? entities[entityID] : BitSet512.Zero; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,77 @@ | ||||||
|  | using System; | ||||||
|  | using System.Collections.Generic; | ||||||
|  | 
 | ||||||
|  | namespace Encompass | ||||||
|  | { | ||||||
|  |     internal class ComponentDeltaStore : ComponentStore | ||||||
|  |     { | ||||||
|  |         private readonly Dictionary<Type, Replayer> _replayers = new Dictionary<Type, Replayer>(); | ||||||
|  |         private readonly HashSet<Replayer> _currentReplayers = new HashSet<Replayer>(); | ||||||
|  | 
 | ||||||
|  |         public IEnumerable<Replayer> CurrentReplayers { get { return _currentReplayers; } } | ||||||
|  | 
 | ||||||
|  |         public ComponentDeltaStore(Dictionary<Type, int> typeToIndex) : base(typeToIndex) | ||||||
|  |         { | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public override void RegisterComponentType<TComponent>() | ||||||
|  |         { | ||||||
|  |             base.RegisterComponentType<TComponent>(); | ||||||
|  |             if (!_replayers.ContainsKey(typeof(TComponent))) | ||||||
|  |             { | ||||||
|  |                 _replayers.Add(typeof(TComponent), new Replayer<TComponent>(this)); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public override void Set<TComponent>(int entityID, TComponent component) | ||||||
|  |         { | ||||||
|  |             base.Set(entityID, component); | ||||||
|  |             var replayer = _replayers[typeof(TComponent)]; | ||||||
|  |             _currentReplayers.Add(replayer); | ||||||
|  |             replayer.UnMarkRemoval(entityID); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public override bool Set<TComponent>(int entityID, TComponent component, int priority) | ||||||
|  |         { | ||||||
|  |             var result = base.Set(entityID, component, priority); | ||||||
|  |             if (result) | ||||||
|  |             { | ||||||
|  |                 var replayer = _replayers[typeof(TComponent)]; | ||||||
|  |                 _currentReplayers.Add(replayer); | ||||||
|  |                 replayer.UnMarkRemoval(entityID); | ||||||
|  |             } | ||||||
|  |             return result; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public override bool Remove<TComponent>(int entityID, int priority) | ||||||
|  |         { | ||||||
|  |             var result = base.Remove<TComponent>(entityID, priority); | ||||||
|  |             if (result) | ||||||
|  |             { | ||||||
|  |                 var replayer = _replayers[typeof(TComponent)]; | ||||||
|  |                 _currentReplayers.Add(replayer); | ||||||
|  |                 replayer.MarkRemoval(entityID); | ||||||
|  |             } | ||||||
|  |             return result; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public override void Remove(int entityID) | ||||||
|  |         { | ||||||
|  |             base.Remove(entityID); | ||||||
|  |             foreach (var replayer in CurrentReplayers) | ||||||
|  |             { | ||||||
|  |                 replayer.MarkRemoval(entityID); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public override void ClearAll() | ||||||
|  |         { | ||||||
|  |             base.ClearAll(); | ||||||
|  |             foreach (var replayer in _currentReplayers) | ||||||
|  |             { | ||||||
|  |                 replayer.Clear(); | ||||||
|  |             } | ||||||
|  |             _currentReplayers.Clear(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -1,4 +1,5 @@ | ||||||
| using System; | using MoonTools.FastCollections; | ||||||
|  | using System; | ||||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||||
| 
 | 
 | ||||||
| namespace Encompass | namespace Encompass | ||||||
|  | @ -6,6 +7,12 @@ namespace Encompass | ||||||
|     internal class ComponentStore |     internal class ComponentStore | ||||||
|     { |     { | ||||||
|         private Dictionary<Type, TypedComponentStore> Stores = new Dictionary<Type, TypedComponentStore>(512); |         private Dictionary<Type, TypedComponentStore> Stores = new Dictionary<Type, TypedComponentStore>(512); | ||||||
|  |         public ComponentBitSet ComponentBitSet { get; private set; } | ||||||
|  | 
 | ||||||
|  |         public ComponentStore(Dictionary<Type, int> typeToIndex) | ||||||
|  |         { | ||||||
|  |             ComponentBitSet = new ComponentBitSet(typeToIndex); | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         public IEnumerable<(Type, TypedComponentStore)> StoresEnumerable() |         public IEnumerable<(Type, TypedComponentStore)> StoresEnumerable() | ||||||
|         { |         { | ||||||
|  | @ -15,11 +22,10 @@ namespace Encompass | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public void RegisterComponentType<TComponent>() where TComponent : struct, IComponent |         public virtual void RegisterComponentType<TComponent>() where TComponent : struct, IComponent | ||||||
|         { |         { | ||||||
|             if (!Stores.ContainsKey(typeof(TComponent))) |             if (!Stores.ContainsKey(typeof(TComponent))) | ||||||
|             { |             { | ||||||
|                 System.Console.WriteLine("register component type in component store"); |  | ||||||
|                 var store = new TypedComponentStore<TComponent>(); |                 var store = new TypedComponentStore<TComponent>(); | ||||||
|                 Stores.Add(typeof(TComponent), store); |                 Stores.Add(typeof(TComponent), store); | ||||||
|             } |             } | ||||||
|  | @ -31,42 +37,65 @@ namespace Encompass | ||||||
|             return Stores[typeof(TComponent)] as TypedComponentStore<TComponent>; |             return Stores[typeof(TComponent)] as TypedComponentStore<TComponent>; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public bool Has<TComponent>(Entity entity) where TComponent : struct, IComponent |         public bool Has<TComponent>(int entityID) where TComponent : struct, IComponent | ||||||
|         { |         { | ||||||
|             return Lookup<TComponent>().Has(entity); |             return Lookup<TComponent>().Has(entityID); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public bool Has(Type type, Entity entity) |         public bool Has(Type type, int entityID) | ||||||
|         { |         { | ||||||
|             return Stores.ContainsKey(type) && Stores[type].Has(entity); |             return Stores.ContainsKey(type) && Stores[type].Has(entityID); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public TComponent Get<TComponent>(Entity entity) where TComponent : struct, IComponent |         public BitSet512 EntityBitArray(int entityID) | ||||||
|         { |         { | ||||||
|             return Lookup<TComponent>().Get(entity); |             return ComponentBitSet.EntityBitArray(entityID); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public void Set<TComponent>(Entity entity, TComponent component) where TComponent : struct, IComponent |         public TComponent Get<TComponent>(int entityID) where TComponent : struct, IComponent | ||||||
|         { |         { | ||||||
|             Lookup<TComponent>().Set(entity, component); |             return Lookup<TComponent>().Get(entityID); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public bool Set<TComponent>(Entity entity, TComponent component, int priority) where TComponent : struct, IComponent |         public virtual void Set<TComponent>(int entityID, TComponent component) where TComponent : struct, IComponent | ||||||
|         { |         { | ||||||
|             return Lookup<TComponent>().Set(entity, component, priority); |             Lookup<TComponent>().Set(entityID, component); | ||||||
|  |             ComponentBitSet.Set<TComponent>(entityID); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public void Remove<TComponent>(Entity entity) where TComponent : struct, IComponent |         public virtual bool Set<TComponent>(int entityID, TComponent component, int priority) where TComponent : struct, IComponent | ||||||
|         { |         { | ||||||
|             Lookup<TComponent>().Remove(entity); |             if (Lookup<TComponent>().Set(entityID, component, priority)) | ||||||
|  |             { | ||||||
|  |                 ComponentBitSet.Set<TComponent>(entityID); | ||||||
|  |                 return true; | ||||||
|  |             } | ||||||
|  |             return false; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public void Remove(Entity entity) |         public virtual bool Remove<TComponent>(int entityID, int priority) where TComponent : struct, IComponent | ||||||
|  |         { | ||||||
|  |             if (Lookup<TComponent>().Remove(entityID, priority)) | ||||||
|  |             { | ||||||
|  |                 ComponentBitSet.RemoveComponent<TComponent>(entityID); | ||||||
|  |                 return true; | ||||||
|  |             } | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public void ForceRemove<TComponent>(int entityID) where TComponent : struct, IComponent | ||||||
|  |         { | ||||||
|  |             Lookup<TComponent>().ForceRemove(entityID); | ||||||
|  |             ComponentBitSet.RemoveComponent<TComponent>(entityID); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public virtual void Remove(int entityID) | ||||||
|         { |         { | ||||||
|             foreach (var entry in Stores.Values) |             foreach (var entry in Stores.Values) | ||||||
|             { |             { | ||||||
|                 entry.Remove(entity); |                 entry.ForceRemove(entityID); | ||||||
|             } |             } | ||||||
|  |             ComponentBitSet.RemoveEntity(entityID); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public bool Any<TComponent>() where TComponent : struct, IComponent |         public bool Any<TComponent>() where TComponent : struct, IComponent | ||||||
|  | @ -74,7 +103,7 @@ namespace Encompass | ||||||
|             return Lookup<TComponent>().Count > 0; |             return Lookup<TComponent>().Count > 0; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public IEnumerable<(Entity, Type, IComponent)> AllInterfaceTyped() |         public IEnumerable<(int, Type, IComponent)> AllInterfaceTyped() | ||||||
|         { |         { | ||||||
|             foreach (var store in Stores.Values) |             foreach (var store in Stores.Values) | ||||||
|             { |             { | ||||||
|  | @ -85,7 +114,7 @@ namespace Encompass | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public IEnumerable<(TComponent, Entity)> All<TComponent>() where TComponent : struct, IComponent |         public IEnumerable<(TComponent, int)> All<TComponent>() where TComponent : struct, IComponent | ||||||
|         { |         { | ||||||
|             return Lookup<TComponent>().All(); |             return Lookup<TComponent>().All(); | ||||||
|         } |         } | ||||||
|  | @ -95,8 +124,17 @@ namespace Encompass | ||||||
|             Lookup<TComponent>().Clear(); |             Lookup<TComponent>().Clear(); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public void ClearAll() |         public virtual void ClearAllPriorities() | ||||||
|         { |         { | ||||||
|  |             foreach (var store in Stores.Values) | ||||||
|  |             { | ||||||
|  |                 store.ClearPriorities(); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public virtual void ClearAll() | ||||||
|  |         { | ||||||
|  |             ComponentBitSet.Clear(); | ||||||
|             foreach (var store in Stores.Values) |             foreach (var store in Stores.Values) | ||||||
|             { |             { | ||||||
|                 store.Clear(); |                 store.Clear(); | ||||||
|  | @ -106,6 +144,15 @@ namespace Encompass | ||||||
|         public void SwapWith(ComponentStore other) |         public void SwapWith(ComponentStore other) | ||||||
|         { |         { | ||||||
|             (Stores, other.Stores) = (other.Stores, Stores); |             (Stores, other.Stores) = (other.Stores, Stores); | ||||||
|  |             (ComponentBitSet, other.ComponentBitSet) = (other.ComponentBitSet, ComponentBitSet); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public void UpdateUsing(ComponentDeltaStore delta) | ||||||
|  |         { | ||||||
|  |             foreach (var replayer in delta.CurrentReplayers) | ||||||
|  |             { | ||||||
|  |                 replayer.Replay(this); | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -48,6 +48,11 @@ namespace Encompass | ||||||
|             return Lookup<TMessage>().Any(); |             return Lookup<TMessage>().Any(); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         public IEnumerable<TMessage> WithEntity<TMessage>(int entityID) where TMessage : struct, IMessage, IHasEntity | ||||||
|  |         { | ||||||
|  |             return Lookup<TMessage>().WithEntity(entityID); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         public void ProcessDelayedMessages(double dilatedDelta, double realtimeDelta) |         public void ProcessDelayedMessages(double dilatedDelta, double realtimeDelta) | ||||||
|         { |         { | ||||||
|             foreach (var store in Stores.Values) |             foreach (var store in Stores.Values) | ||||||
|  |  | ||||||
|  | @ -0,0 +1,51 @@ | ||||||
|  | using System.Collections.Generic; | ||||||
|  | 
 | ||||||
|  | namespace Encompass | ||||||
|  | { | ||||||
|  |     internal abstract class Replayer  | ||||||
|  |     { | ||||||
|  |         public abstract void Replay(ComponentStore store); | ||||||
|  |         public abstract void MarkRemoval(int entityID); | ||||||
|  |         public abstract void UnMarkRemoval(int entityID); | ||||||
|  |         public abstract void Clear(); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     internal class Replayer<TComponent> : Replayer where TComponent : struct, IComponent | ||||||
|  |     { | ||||||
|  |         private readonly ComponentDeltaStore _deltaStore; | ||||||
|  |         private readonly HashSet<int> _removals = new HashSet<int>(); | ||||||
|  | 
 | ||||||
|  |         public Replayer(ComponentDeltaStore componentStore) | ||||||
|  |         { | ||||||
|  |             _deltaStore = componentStore; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public override void Replay(ComponentStore store) | ||||||
|  |         { | ||||||
|  |             foreach (var (component, entityID) in _deltaStore.All<TComponent>()) | ||||||
|  |             { | ||||||
|  |                 store.Set(entityID, component); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             foreach (var entityID in _removals) | ||||||
|  |             { | ||||||
|  |                 store.ForceRemove<TComponent>(entityID); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public override void Clear() | ||||||
|  |         { | ||||||
|  |             _removals.Clear(); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public override void MarkRemoval(int entityID) | ||||||
|  |         { | ||||||
|  |             _removals.Add(entityID); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public override void UnMarkRemoval(int entityID) | ||||||
|  |         { | ||||||
|  |             _removals.Remove(entityID); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -6,43 +6,66 @@ namespace Encompass | ||||||
|     internal abstract class TypedComponentStore |     internal abstract class TypedComponentStore | ||||||
|     { |     { | ||||||
|         public abstract int Count { get; } |         public abstract int Count { get; } | ||||||
|         public abstract IEnumerable<(Entity, Type, IComponent)> AllInterfaceTyped(); |         public abstract IEnumerable<(int, Type, IComponent)> AllInterfaceTyped(); | ||||||
|         public abstract bool Has(Entity entity); |         public abstract bool Has(int entity); | ||||||
|         public abstract void Remove(Entity entity); |         public abstract bool Remove(int entity, int priority); | ||||||
|  |         public abstract void ForceRemove(int entity); | ||||||
|         public abstract void Clear(); |         public abstract void Clear(); | ||||||
|  |         public abstract void ClearPriorities(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     internal class TypedComponentStore<TComponent> : TypedComponentStore where TComponent : struct, IComponent |     internal class TypedComponentStore<TComponent> : TypedComponentStore where TComponent : struct, IComponent | ||||||
|     { |     { | ||||||
|         private readonly Dictionary<Entity, TComponent> store = new Dictionary<Entity, TComponent>(128); |         private readonly Dictionary<int, TComponent> store = new Dictionary<int, TComponent>(128); | ||||||
|         private readonly Dictionary<Entity, int> priorities = new Dictionary<Entity, int>(128); |         private readonly Dictionary<int, int> priorities = new Dictionary<int, int>(128); | ||||||
| 
 | 
 | ||||||
|         public override int Count { get => store.Count; } |         public override int Count { get => store.Count; } | ||||||
| 
 | 
 | ||||||
|         public TComponent Get(Entity entity) |         public TComponent Get(int entityID) | ||||||
|         { |         { | ||||||
|             return store[entity]; |             if (!store.ContainsKey(entityID)) { throw new Exceptions.NoComponentOfTypeOnEntityException("No component of type {0} exists on Entity with ID {1}", typeof(TComponent), entityID); } | ||||||
|  |             return store[entityID]; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public void Set(Entity entity, TComponent component) |         public void Set(int entityID, TComponent component) | ||||||
|         { |         { | ||||||
|             store[entity] = component; |             store[entityID] = component; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public bool Set(Entity entity, TComponent component, int priority) |         public bool Set(int entityID, TComponent component, int priority) | ||||||
|         { |         { | ||||||
|             if (!priorities.ContainsKey(entity) || priority < priorities[entity]) { |             if (!priorities.ContainsKey(entityID) || priority < priorities[entityID]) | ||||||
|                 store[entity] = component; |             { | ||||||
|                 priorities[entity] = priority; |                 store[entityID] = component; | ||||||
|  |                 priorities[entityID] = priority; | ||||||
|                 return true; |                 return true; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             return false; |             return false; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public override bool Has(Entity entity) |         public override bool Remove(int entityID, int priority) | ||||||
|         { |         { | ||||||
|             return store.ContainsKey(entity); |             if (!priorities.ContainsKey(entityID) || priority < priorities[entityID]) | ||||||
|  |             { | ||||||
|  |                 priorities[entityID] = priority; | ||||||
|  |                 store.Remove(entityID); | ||||||
|  |                 priorities.Remove(entityID); | ||||||
|  |                 return true; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public override void ForceRemove(int entityID) | ||||||
|  |         { | ||||||
|  |             store.Remove(entityID); | ||||||
|  |             priorities.Remove(entityID); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public override bool Has(int entityID) | ||||||
|  |         { | ||||||
|  |             return store.ContainsKey(entityID); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public override void Clear() |         public override void Clear() | ||||||
|  | @ -51,7 +74,12 @@ namespace Encompass | ||||||
|             priorities.Clear(); |             priorities.Clear(); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public IEnumerable<(TComponent, Entity)> All() |         public override void ClearPriorities() | ||||||
|  |         { | ||||||
|  |             priorities.Clear(); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public IEnumerable<(TComponent, int)> All() | ||||||
|         { |         { | ||||||
|             foreach (var kvp in store) |             foreach (var kvp in store) | ||||||
|             { |             { | ||||||
|  | @ -59,18 +87,12 @@ namespace Encompass | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public override IEnumerable<(Entity, Type, IComponent)> AllInterfaceTyped() |         public override IEnumerable<(int, Type, IComponent)> AllInterfaceTyped() | ||||||
|         { |         { | ||||||
|             foreach (var kvp in store) |             foreach (var kvp in store) | ||||||
|             { |             { | ||||||
|                 yield return (kvp.Key, typeof(TComponent), (IComponent)kvp.Value); |                 yield return (kvp.Key, typeof(TComponent), (IComponent)kvp.Value); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 |  | ||||||
|         public override void Remove(Entity entity) |  | ||||||
|         { |  | ||||||
|             store.Remove(entity); |  | ||||||
|             priorities.Remove(entity); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -13,6 +13,7 @@ namespace Encompass | ||||||
|         private readonly List<TMessage> store = new List<TMessage>(128); |         private readonly List<TMessage> store = new List<TMessage>(128); | ||||||
|         private readonly List<(TMessage, double)> delayedStore = new List<(TMessage, double)>(128); |         private readonly List<(TMessage, double)> delayedStore = new List<(TMessage, double)>(128); | ||||||
|         private readonly List<(TMessage, double)> delayedStoreIgnoringTimeDilation = new List<(TMessage, double)>(128); |         private readonly List<(TMessage, double)> delayedStoreIgnoringTimeDilation = new List<(TMessage, double)>(128); | ||||||
|  |         private readonly Dictionary<int, List<TMessage>> entityToMessage = new Dictionary<int, List<TMessage>>(); | ||||||
| 
 | 
 | ||||||
|         public override void ProcessDelayedMessages(double dilatedDelta, double realtimeDelta) |         public override void ProcessDelayedMessages(double dilatedDelta, double realtimeDelta) | ||||||
|         { |         { | ||||||
|  | @ -54,6 +55,12 @@ namespace Encompass | ||||||
|         public void Add(TMessage message) |         public void Add(TMessage message) | ||||||
|         { |         { | ||||||
|             store.Add(message); |             store.Add(message); | ||||||
|  |             if (message is IHasEntity entityMessage) | ||||||
|  |             { | ||||||
|  |                 var entityID = entityMessage.Entity.ID; | ||||||
|  |                 if (!entityToMessage.ContainsKey(entityID)) { entityToMessage.Add(entityID, new List<TMessage>()); } | ||||||
|  |                 entityToMessage[entityID].Add(message); | ||||||
|  |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public void Add(TMessage message, double time) |         public void Add(TMessage message, double time) | ||||||
|  | @ -81,9 +88,18 @@ namespace Encompass | ||||||
|             return store; |             return store; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         public IEnumerable<TMessage> WithEntity(int entityID) | ||||||
|  |         { | ||||||
|  |             return entityToMessage.ContainsKey(entityID) ? entityToMessage[entityID] : System.Linq.Enumerable.Empty<TMessage>(); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         public override void Clear() |         public override void Clear() | ||||||
|         { |         { | ||||||
|             store.Clear(); |             store.Clear(); | ||||||
|  |             foreach (var set in entityToMessage.Values) | ||||||
|  |             { | ||||||
|  |                 set.Clear(); | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,3 +1,4 @@ | ||||||
|  | using System; | ||||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||||
| 
 | 
 | ||||||
| namespace Encompass | namespace Encompass | ||||||
|  | @ -5,90 +6,248 @@ namespace Encompass | ||||||
|     internal class ComponentManager |     internal class ComponentManager | ||||||
|     { |     { | ||||||
|         private readonly DrawLayerManager drawLayerManager; |         private readonly DrawLayerManager drawLayerManager; | ||||||
|         private readonly ComponentUpdateManager componentUpdateManager; |  | ||||||
| 
 | 
 | ||||||
|         private readonly ComponentStore componentStore = new ComponentStore(); |         private readonly ComponentStore existingComponentStore; | ||||||
|         private readonly HashSet<Entity> entitiesMarkedForRemoval = new HashSet<Entity>(); |         private readonly ComponentStore immediateComponentStore; | ||||||
|  |         private readonly ComponentDeltaStore replayStore; | ||||||
|  |         private ComponentStore upToDateComponentStore; | ||||||
| 
 | 
 | ||||||
|         public ComponentManager(DrawLayerManager drawLayerManager, ComponentUpdateManager componentUpdateManager) |         public Dictionary<Type, int> TypeToIndex { get; } | ||||||
|  | 
 | ||||||
|  |         private readonly HashSet<int> entitiesMarkedForRemoval = new HashSet<int>(); | ||||||
|  | 
 | ||||||
|  |         internal ComponentBitSet ImmediateBits { get { return immediateComponentStore.ComponentBitSet; } } | ||||||
|  |         internal ComponentBitSet ExistingBits { get { return existingComponentStore.ComponentBitSet; } } | ||||||
|  | 
 | ||||||
|  |         public ComponentManager(DrawLayerManager drawLayerManager, Dictionary<Type, int> typeToIndex) | ||||||
|         { |         { | ||||||
|             this.drawLayerManager = drawLayerManager; |             this.drawLayerManager = drawLayerManager; | ||||||
|             this.componentUpdateManager = componentUpdateManager; |             existingComponentStore = new ComponentStore(typeToIndex); | ||||||
|  |             immediateComponentStore = new ComponentStore(typeToIndex); | ||||||
|  |             replayStore = new ComponentDeltaStore(typeToIndex); | ||||||
|  |             upToDateComponentStore = new ComponentStore(typeToIndex); | ||||||
|  |             TypeToIndex = typeToIndex; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public void RegisterComponentType<TComponent>() where TComponent : struct, IComponent |         public void RegisterComponentType<TComponent>() where TComponent : struct, IComponent | ||||||
|         { |         { | ||||||
|             componentStore.RegisterComponentType<TComponent>(); |             existingComponentStore.RegisterComponentType<TComponent>(); | ||||||
|  |             immediateComponentStore.RegisterComponentType<TComponent>(); | ||||||
|  |             replayStore.RegisterComponentType<TComponent>(); | ||||||
|  |             upToDateComponentStore.RegisterComponentType<TComponent>(); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         internal void SetComponentStore(ComponentStore componentStore) |         internal void SetExistingComponentStore(ComponentStore componentStore) | ||||||
|         { |         { | ||||||
|             this.componentStore.SwapWith(componentStore); |             existingComponentStore.SwapWith(componentStore); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         internal void RegisterDrawableComponent<TComponent>(Entity entity, TComponent component, int layer) where TComponent : struct, IComponent |         internal void SetUpToDateComponentStore(ComponentStore componentStore) | ||||||
|         { |         { | ||||||
|             drawLayerManager.RegisterComponentWithLayer(entity, component, layer); |             upToDateComponentStore.SwapWith(componentStore); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         internal void AddComponent<TComponent>(Entity entity, TComponent component) where TComponent : struct, IComponent |         internal void RegisterDrawableComponent<TComponent>(int entityID, TComponent component, int layer) where TComponent : struct, IComponent | ||||||
|         { |         { | ||||||
|             componentStore.Set(entity, component); |             drawLayerManager.RegisterComponentWithLayer(entityID, component, layer); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         internal void WriteComponents() |         internal void WriteComponents() | ||||||
|         { |         { | ||||||
|             componentStore.SwapWith(componentUpdateManager.UpToDateComponentStore); |             existingComponentStore.UpdateUsing(replayStore); | ||||||
|  |             existingComponentStore.ClearAllPriorities(); | ||||||
|  |             upToDateComponentStore.ClearAllPriorities(); | ||||||
|  |             immediateComponentStore.ClearAll(); | ||||||
|  |             replayStore.ClearAll(); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         internal IEnumerable<(TComponent, Entity)> GetComponentsIncludingEntity<TComponent>() where TComponent : struct, IComponent |         internal bool AddImmediateComponent<TComponent>(int entityID, TComponent component, int priority) where TComponent : struct, IComponent | ||||||
|         { |         { | ||||||
|             return componentStore.All<TComponent>(); |             if (immediateComponentStore.Set(entityID, component, priority)) | ||||||
|  |             { | ||||||
|  |                 replayStore.Set(entityID, component); | ||||||
|  |                 upToDateComponentStore.Set(entityID, component); | ||||||
|  |                 return true; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public bool UpdateComponent<TComponent>(int entityID, TComponent component, int priority) where TComponent : struct, IComponent | ||||||
|  |         { | ||||||
|  |             var result = upToDateComponentStore.Set(entityID, component, priority); | ||||||
|  |             if (result) | ||||||
|  |             { | ||||||
|  |                 replayStore.Set(entityID, component); | ||||||
|  |             } | ||||||
|  |             return result; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // existing or immediate reads | ||||||
|  | 
 | ||||||
|  |         internal IEnumerable<(TComponent, int)> ReadExistingAndImmediateComponentsByType<TComponent>() where TComponent : struct, IComponent | ||||||
|  |         { | ||||||
|  |             return upToDateComponentStore.All<TComponent>(); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         internal (TComponent, int) ReadFirstExistingOrImmediateComponentByType<TComponent>() where TComponent : struct, IComponent | ||||||
|  |         { | ||||||
|  |             if (!SomeExistingOrImmediateComponent<TComponent>()) { throw new Exceptions.NoComponentOfTypeException($"No Component with type {typeof(TComponent)} exists"); } | ||||||
|  |             var enumerator = ReadExistingAndImmediateComponentsByType<TComponent>().GetEnumerator(); | ||||||
|  |             enumerator.MoveNext(); | ||||||
|  |             return enumerator.Current; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         internal bool SomeExistingOrImmediateComponent<TComponent>() where TComponent : struct, IComponent | ||||||
|  |         { | ||||||
|  |             return upToDateComponentStore.Any<TComponent>(); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // existing reads | ||||||
|  | 
 | ||||||
|  |         internal (TComponent, int) ReadFirstExistingComponentByType<TComponent>() where TComponent : struct, IComponent | ||||||
|  |         { | ||||||
|  |             if (!SomeExistingComponent<TComponent>()) { throw new Exceptions.NoComponentOfTypeException($"No Component with type {typeof(TComponent)} exists"); } | ||||||
|  |             var enumerator = GetComponentsIncludingEntity<TComponent>().GetEnumerator(); | ||||||
|  |             enumerator.MoveNext(); | ||||||
|  |             return enumerator.Current; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         internal bool SomeExistingComponent<TComponent>() where TComponent : struct, IComponent | ||||||
|  |         { | ||||||
|  |             return existingComponentStore.Any<TComponent>(); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // immediate reads | ||||||
|  | 
 | ||||||
|  |         internal IEnumerable<(TComponent, int)> ReadImmediateComponentsByType<TComponent>() where TComponent : struct, IComponent | ||||||
|  |         { | ||||||
|  |             return immediateComponentStore.All<TComponent>(); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         internal (TComponent, int) ReadFirstImmediateComponentByType<TComponent>() where TComponent : struct, IComponent | ||||||
|  |         { | ||||||
|  |             if (!SomeImmediateComponent<TComponent>()) { throw new Exceptions.NoComponentOfTypeException($"No Component with type {typeof(TComponent)} exists"); } | ||||||
|  |             var enumerator = ReadImmediateComponentsByType<TComponent>().GetEnumerator(); | ||||||
|  |             enumerator.MoveNext(); | ||||||
|  |             return enumerator.Current; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         internal bool SomeImmediateComponent<TComponent>() where TComponent : struct, IComponent | ||||||
|  |         { | ||||||
|  |             return immediateComponentStore.Any<TComponent>(); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // component getters | ||||||
|  | 
 | ||||||
|  |         internal TComponent ReadImmediateOrExistingComponentByEntityAndType<TComponent>(int entityID) where TComponent : struct, IComponent | ||||||
|  |         { | ||||||
|  |             return upToDateComponentStore.Get<TComponent>(entityID); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         internal TComponent ReadExistingComponentByEntityAndType<TComponent>(int entityID) where TComponent : struct, IComponent | ||||||
|  |         { | ||||||
|  |             return existingComponentStore.Get<TComponent>(entityID); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         internal TComponent ReadImmediateComponentByEntityAndType<TComponent>(int entityID) where TComponent : struct, IComponent | ||||||
|  |         { | ||||||
|  |             return immediateComponentStore.Get<TComponent>(entityID); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // has checkers | ||||||
|  | 
 | ||||||
|  |         internal bool HasExistingOrImmediateComponent<TComponent>(int entityID) where TComponent : struct, IComponent | ||||||
|  |         { | ||||||
|  |             return upToDateComponentStore.Has<TComponent>(entityID); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         internal bool HasExistingOrImmediateComponent(int entityID, Type type) | ||||||
|  |         { | ||||||
|  |             return upToDateComponentStore.Has(type, entityID); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         internal bool HasExistingComponent<TComponent>(int entityID) where TComponent : struct, IComponent | ||||||
|  |         { | ||||||
|  |             return existingComponentStore.Has<TComponent>(entityID); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         internal bool HasExistingComponent(int entityID, Type type) | ||||||
|  |         { | ||||||
|  |             return existingComponentStore.Has(type, entityID); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         internal bool HasImmediateComponent<TComponent>(int entityID) where TComponent : struct, IComponent | ||||||
|  |         { | ||||||
|  |             return immediateComponentStore.Has<TComponent>(entityID); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         internal bool HasImmediateComponent(int entityID, Type type) | ||||||
|  |         { | ||||||
|  |             return immediateComponentStore.Has(type, entityID); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         internal IEnumerable<(TComponent, int)> GetComponentsIncludingEntity<TComponent>() where TComponent : struct, IComponent | ||||||
|  |         { | ||||||
|  |             return existingComponentStore.All<TComponent>(); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         internal IEnumerable<TComponent> GetComponentsByType<TComponent>() where TComponent : struct, IComponent |         internal IEnumerable<TComponent> GetComponentsByType<TComponent>() where TComponent : struct, IComponent | ||||||
|         { |         { | ||||||
|             foreach (var pair in componentStore.All<TComponent>()) |             foreach (var pair in existingComponentStore.All<TComponent>()) | ||||||
|             { |             { | ||||||
|                 yield return pair.Item1; |                 yield return pair.Item1; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         internal TComponent GetComponentByEntityAndType<TComponent>(Entity entity) where TComponent : struct, IComponent |         internal TComponent GetComponentByEntityAndType<TComponent>(int entityID) where TComponent : struct, IComponent | ||||||
|         { |         { | ||||||
|             return componentStore.Get<TComponent>(entity); |             return existingComponentStore.Get<TComponent>(entityID); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         internal bool EntityHasComponentOfType<TComponent>(Entity entity) where TComponent : struct, IComponent |         internal bool EntityHasComponentOfType<TComponent>(int entityID) where TComponent : struct, IComponent | ||||||
|         { |         { | ||||||
|             return componentStore.Has<TComponent>(entity); |             return existingComponentStore.Has<TComponent>(entityID); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         internal bool ComponentOfTypeExists<TComponent>() where TComponent : struct, IComponent |         internal void MarkAllComponentsOnEntityForRemoval(int entityID) | ||||||
|         { |         { | ||||||
|             return componentStore.Any<TComponent>(); |             entitiesMarkedForRemoval.Add(entityID); | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         internal void MarkAllComponentsOnEntityForRemoval(Entity entity) |  | ||||||
|         { |  | ||||||
|             entitiesMarkedForRemoval.Add(entity); |  | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         internal void RemoveMarkedComponents() |         internal void RemoveMarkedComponents() | ||||||
|         { |         { | ||||||
|             foreach (var entity in entitiesMarkedForRemoval) |             foreach (var entityID in entitiesMarkedForRemoval) | ||||||
|             { |             { | ||||||
|                 componentStore.Remove(entity); |                 existingComponentStore.Remove(entityID); | ||||||
|                 drawLayerManager.UnRegisterEntityWithLayer(entity); |                 immediateComponentStore.Remove(entityID); | ||||||
|  |                 replayStore.Remove(entityID); | ||||||
|  |                 upToDateComponentStore.Remove(entityID); | ||||||
|  |                 drawLayerManager.UnRegisterEntityWithLayer(entityID); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             entitiesMarkedForRemoval.Clear(); |             entitiesMarkedForRemoval.Clear(); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public void Remove<TComponent>(Entity entity) where TComponent : struct, IComponent |         public bool RemoveImmediate<TComponent>(int entityID, int priority) where TComponent : struct, IComponent | ||||||
|         { |         { | ||||||
|             componentUpdateManager.Remove<TComponent>(entity); |             if (immediateComponentStore.Remove<TComponent>(entityID, priority)) | ||||||
|             drawLayerManager.UnRegisterComponentWithLayer<TComponent>(entity); |             { | ||||||
|  |                 replayStore.Remove<TComponent>(entityID, priority); | ||||||
|  |                 upToDateComponentStore.Remove<TComponent>(entityID, priority); | ||||||
|  |                 drawLayerManager.UnRegisterComponentWithLayer<TComponent>(entityID); | ||||||
|  |                 return true; | ||||||
|  |             } | ||||||
|  |             return false; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public void Remove<TComponent>(int entityID, int priority) where TComponent : struct, IComponent | ||||||
|  |         { | ||||||
|  |             if (upToDateComponentStore.Remove<TComponent>(entityID, priority)) | ||||||
|  |             { | ||||||
|  |                 replayStore.Remove<TComponent>(entityID, priority); | ||||||
|  |                 drawLayerManager.UnRegisterComponentWithLayer<TComponent>(entityID); | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,179 +0,0 @@ | ||||||
| using System; |  | ||||||
| using System.Collections.Generic; |  | ||||||
| 
 |  | ||||||
| namespace Encompass |  | ||||||
| { |  | ||||||
|     internal class ComponentUpdateManager |  | ||||||
|     { |  | ||||||
|         private readonly ComponentStore existingAndPendingComponentStore = new ComponentStore(); |  | ||||||
|         private readonly ComponentStore existingComponentStore = new ComponentStore(); |  | ||||||
|         private readonly ComponentStore pendingComponentStore = new ComponentStore(); |  | ||||||
|         private readonly Dictionary<Type, Dictionary<Entity, int>> typeToEntityToPendingComponentPriority = new Dictionary<Type, Dictionary<Entity, int>>(128); |  | ||||||
| 
 |  | ||||||
|         public ComponentStore UpToDateComponentStore { get; private set; } = new ComponentStore(); |  | ||||||
| 
 |  | ||||||
|         public void RegisterComponentType<TComponent>() where TComponent : struct, IComponent |  | ||||||
|         { |  | ||||||
|             existingAndPendingComponentStore.RegisterComponentType<TComponent>(); |  | ||||||
|             existingComponentStore.RegisterComponentType<TComponent>(); |  | ||||||
|             pendingComponentStore.RegisterComponentType<TComponent>(); |  | ||||||
|             UpToDateComponentStore.RegisterComponentType<TComponent>(); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         internal void Clear() |  | ||||||
|         { |  | ||||||
|             existingAndPendingComponentStore.ClearAll(); |  | ||||||
|             existingComponentStore.ClearAll(); |  | ||||||
|             pendingComponentStore.ClearAll(); |  | ||||||
|             UpToDateComponentStore.ClearAll(); |  | ||||||
| 
 |  | ||||||
|             foreach (var dictionary in typeToEntityToPendingComponentPriority.Values) |  | ||||||
|             { |  | ||||||
|                 dictionary.Clear(); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         internal void SetStartingComponentStore(ComponentStore componentStore) |  | ||||||
|         { |  | ||||||
|             UpToDateComponentStore = componentStore; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         internal void AddExistingComponent<TComponent>(Entity entity, TComponent component) where TComponent : struct, IComponent |  | ||||||
|         { |  | ||||||
|             RegisterExistingOrPendingComponentMessage(entity, component); |  | ||||||
| 
 |  | ||||||
|             existingComponentStore.Set(entity, component); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         internal bool AddPendingComponent<TComponent>(Entity entity, TComponent component, int priority) where TComponent : struct, IComponent |  | ||||||
|         { |  | ||||||
|             if (pendingComponentStore.Set(entity, component, priority)) |  | ||||||
|             { |  | ||||||
|                 RegisterExistingOrPendingComponentMessage(entity, component); |  | ||||||
|                 return true; |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             return false; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         private void RegisterExistingOrPendingComponentMessage<TComponent>(Entity entity, TComponent component) where TComponent : struct, IComponent |  | ||||||
|         { |  | ||||||
|             existingAndPendingComponentStore.Set(entity, component); |  | ||||||
|             UpToDateComponentStore.Set(entity, component); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         public bool UpdateComponent<TComponent>(Entity entity, TComponent component, int priority) where TComponent : struct, IComponent |  | ||||||
|         { |  | ||||||
|             return UpToDateComponentStore.Set<TComponent>(entity, component, priority); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         // general component reads by type |  | ||||||
| 
 |  | ||||||
|         internal IEnumerable<(TComponent, Entity)> ReadExistingAndPendingComponentsByType<TComponent>() where TComponent : struct, IComponent |  | ||||||
|         { |  | ||||||
|             return existingAndPendingComponentStore.All<TComponent>(); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         internal IEnumerable<(TComponent, Entity)> ReadExistingComponentsByType<TComponent>() where TComponent : struct, IComponent |  | ||||||
|         { |  | ||||||
|             return existingComponentStore.All<TComponent>(); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         internal IEnumerable<(TComponent, Entity)> ReadPendingComponentsByType<TComponent>() where TComponent : struct, IComponent |  | ||||||
|         { |  | ||||||
|             return pendingComponentStore.All<TComponent>(); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         // singular component reads by type |  | ||||||
| 
 |  | ||||||
|         internal (TComponent, Entity) ReadFirstExistingOrPendingComponentByType<TComponent>() where TComponent : struct, IComponent |  | ||||||
|         { |  | ||||||
|             if (!SomeExistingOrPendingComponent<TComponent>()) { throw new Exceptions.NoComponentOfTypeException($"No Component with type {typeof(TComponent)} exists"); } |  | ||||||
|             var enumerator = ReadExistingAndPendingComponentsByType<TComponent>().GetEnumerator(); |  | ||||||
|             enumerator.MoveNext(); |  | ||||||
|             return enumerator.Current; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         internal (TComponent, Entity) ReadFirstExistingComponentByType<TComponent>() where TComponent : struct, IComponent |  | ||||||
|         { |  | ||||||
|             if (!SomeExistingComponent<TComponent>()) { throw new Exceptions.NoComponentOfTypeException($"No Component with type {typeof(TComponent)} exists"); } |  | ||||||
|             var enumerator = ReadExistingComponentsByType<TComponent>().GetEnumerator(); |  | ||||||
|             enumerator.MoveNext(); |  | ||||||
|             return enumerator.Current; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         internal (TComponent, Entity) ReadFirstPendingComponentByType<TComponent>() where TComponent : struct, IComponent |  | ||||||
|         { |  | ||||||
|             if (!SomePendingComponent<TComponent>()) { throw new Exceptions.NoComponentOfTypeException($"No Component with type {typeof(TComponent)} exists"); } |  | ||||||
|             var enumerator = ReadPendingComponentsByType<TComponent>().GetEnumerator(); |  | ||||||
|             enumerator.MoveNext(); |  | ||||||
|             return enumerator.Current; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         // check if some component of type exists in the world |  | ||||||
| 
 |  | ||||||
|         internal bool SomeExistingOrPendingComponent<TComponent>() where TComponent : struct, IComponent |  | ||||||
|         { |  | ||||||
|             return existingAndPendingComponentStore.Any<TComponent>(); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         internal bool SomeExistingComponent<TComponent>() where TComponent : struct, IComponent |  | ||||||
|         { |  | ||||||
|             return existingComponentStore.Any<TComponent>(); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         internal bool SomePendingComponent<TComponent>() where TComponent : struct, IComponent |  | ||||||
|         { |  | ||||||
|             return pendingComponentStore.Any<TComponent>(); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         // read components by entity and type |  | ||||||
| 
 |  | ||||||
|         internal TComponent ReadExistingComponentByEntityAndType<TComponent>(Entity entity) where TComponent : struct, IComponent |  | ||||||
|         { |  | ||||||
|             return existingComponentStore.Get<TComponent>(entity); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         internal TComponent ReadPendingComponentByEntityAndType<TComponent>(Entity entity) where TComponent : struct, IComponent |  | ||||||
|         { |  | ||||||
|             return pendingComponentStore.Get<TComponent>(entity); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         // check if entity has component of type |  | ||||||
| 
 |  | ||||||
|         internal bool HasExistingOrPendingComponent<TComponent>(Entity entity) where TComponent : struct, IComponent |  | ||||||
|         { |  | ||||||
|             return existingAndPendingComponentStore.Has<TComponent>(entity); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         internal bool HasExistingOrPendingComponent(Entity entity, Type type) |  | ||||||
|         { |  | ||||||
|             return existingAndPendingComponentStore.Has(type, entity); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         internal bool HasExistingComponent<TComponent>(Entity entity) where TComponent : struct, IComponent |  | ||||||
|         { |  | ||||||
|             return existingComponentStore.Has<TComponent>(entity); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         internal bool HasExistingComponent(Entity entity, Type type) |  | ||||||
|         { |  | ||||||
|             return existingComponentStore.Has(type, entity); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         internal bool HasPendingComponent<TComponent>(Entity entity) where TComponent : struct, IComponent |  | ||||||
|         { |  | ||||||
|             return pendingComponentStore.Has<TComponent>(entity); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         internal bool HasPendingComponent(Entity entity, Type type) |  | ||||||
|         { |  | ||||||
|             return pendingComponentStore.Has(type, entity); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         internal void Remove<TComponent>(Entity entity) where TComponent : struct, IComponent |  | ||||||
|         { |  | ||||||
|             UpToDateComponentStore.Remove<TComponent>(entity); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | @ -12,12 +12,13 @@ namespace Encompass | ||||||
|         private readonly Dictionary<int, ComponentStore> layerIndexToComponentStore = new Dictionary<int, ComponentStore>(512); |         private readonly Dictionary<int, ComponentStore> layerIndexToComponentStore = new Dictionary<int, ComponentStore>(512); | ||||||
|         private readonly Dictionary<int, HashSet<GeneralRenderer>> layerIndexToGeneralRenderers = new Dictionary<int, HashSet<GeneralRenderer>>(512); |         private readonly Dictionary<int, HashSet<GeneralRenderer>> layerIndexToGeneralRenderers = new Dictionary<int, HashSet<GeneralRenderer>>(512); | ||||||
| 
 | 
 | ||||||
|         private readonly Dictionary<Type, Dictionary<Entity, int>> typeToEntityToLayer = new Dictionary<Type, Dictionary<Entity, int>>(512); |         private readonly Dictionary<Type, Dictionary<int, int>> typeToEntityToLayer = new Dictionary<Type, Dictionary<int, int>>(512); | ||||||
| 
 |         private Dictionary<Type, int> typeToIndex; | ||||||
|         public IEnumerable<int> LayerOrder { get { return layerOrder.Values; } } |         public IEnumerable<int> LayerOrder { get { return layerOrder.Values; } } | ||||||
| 
 | 
 | ||||||
|         public DrawLayerManager() |         public DrawLayerManager(Dictionary<Type, int> typeToIndex) | ||||||
|         { |         { | ||||||
|  |             this.typeToIndex = typeToIndex; | ||||||
|             RegisterDrawLayer(0); |             RegisterDrawLayer(0); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | @ -27,7 +28,7 @@ namespace Encompass | ||||||
|             { |             { | ||||||
|                 layerOrder.Add(layer, layer); |                 layerOrder.Add(layer, layer); | ||||||
|                 layerIndexToGeneralRenderers.Add(layer, new HashSet<GeneralRenderer>()); |                 layerIndexToGeneralRenderers.Add(layer, new HashSet<GeneralRenderer>()); | ||||||
|                 layerIndexToComponentStore.Add(layer, new ComponentStore()); |                 layerIndexToComponentStore.Add(layer, new ComponentStore(typeToIndex)); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | @ -35,7 +36,7 @@ namespace Encompass | ||||||
|         { |         { | ||||||
|             if (!typeToEntityToLayer.ContainsKey(typeof(TComponent))) |             if (!typeToEntityToLayer.ContainsKey(typeof(TComponent))) | ||||||
|             { |             { | ||||||
|                 typeToEntityToLayer.Add(typeof(TComponent), new Dictionary<Entity, int>(128)); |                 typeToEntityToLayer.Add(typeof(TComponent), new Dictionary<int, int>(128)); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             foreach (var pair in layerIndexToComponentStore) |             foreach (var pair in layerIndexToComponentStore) | ||||||
|  | @ -65,38 +66,38 @@ namespace Encompass | ||||||
|             RegisterGeneralRendererWithLayer(renderer, newLayer); |             RegisterGeneralRendererWithLayer(renderer, newLayer); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public void RegisterComponentWithLayer<TComponent>(Entity entity, TComponent component, int layer) where TComponent : struct, IComponent |         public void RegisterComponentWithLayer<TComponent>(int entityID, TComponent component, int layer) where TComponent : struct, IComponent | ||||||
|         { |         { | ||||||
|             if (!layerIndexToComponentStore.ContainsKey(layer)) |             if (!layerIndexToComponentStore.ContainsKey(layer)) | ||||||
|             { |             { | ||||||
|                 throw new UndefinedLayerException("Layer {0} is not defined. Use WorldBuilder.RegisterDrawLayer to register the layer.", layer); |                 throw new UndefinedLayerException("Layer {0} is not defined. Use WorldBuilder.RegisterDrawLayer to register the layer.", layer); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             if (typeToEntityToLayer[typeof(TComponent)].ContainsKey(entity)) { UnRegisterComponentWithLayer<TComponent>(entity); } |             if (typeToEntityToLayer[typeof(TComponent)].ContainsKey(entityID)) { UnRegisterComponentWithLayer<TComponent>(entityID); } | ||||||
| 
 | 
 | ||||||
|             var set = layerIndexToComponentStore[layer]; |             var set = layerIndexToComponentStore[layer]; | ||||||
|             set.Set<TComponent>(entity, component); |             set.Set<TComponent>(entityID, component); | ||||||
| 
 | 
 | ||||||
|             typeToEntityToLayer[typeof(TComponent)].Add(entity, layer); |             typeToEntityToLayer[typeof(TComponent)].Add(entityID, layer); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public void UnRegisterComponentWithLayer<TComponent>(Entity entity) where TComponent : struct, IComponent |         public void UnRegisterComponentWithLayer<TComponent>(int entityID) where TComponent : struct, IComponent | ||||||
|         { |         { | ||||||
|             if (!typeToEntityToLayer.ContainsKey(typeof(TComponent))) { return; } |             if (!typeToEntityToLayer.ContainsKey(typeof(TComponent))) { return; } | ||||||
| 
 | 
 | ||||||
|             if (typeToEntityToLayer[typeof(TComponent)].ContainsKey(entity)) |             if (typeToEntityToLayer[typeof(TComponent)].ContainsKey(entityID)) | ||||||
|             { |             { | ||||||
|                 var layer = typeToEntityToLayer[typeof(TComponent)][entity]; |                 var layer = typeToEntityToLayer[typeof(TComponent)][entityID]; | ||||||
|                 layerIndexToComponentStore[layer].Remove<TComponent>(entity); |                 layerIndexToComponentStore[layer].ForceRemove<TComponent>(entityID); | ||||||
|             } |             } | ||||||
|             typeToEntityToLayer[typeof(TComponent)].Remove(entity); |             typeToEntityToLayer[typeof(TComponent)].Remove(entityID); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public void UnRegisterEntityWithLayer(Entity entity) |         public void UnRegisterEntityWithLayer(int entityID) | ||||||
|         { |         { | ||||||
|             foreach (var store in layerIndexToComponentStore.Values) |             foreach (var store in layerIndexToComponentStore.Values) | ||||||
|             { |             { | ||||||
|                 store.Remove(entity); |                 store.Remove(entityID); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | @ -107,11 +108,11 @@ namespace Encompass | ||||||
|                 Enumerable.Empty<GeneralRenderer>(); |                 Enumerable.Empty<GeneralRenderer>(); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public IEnumerable<(Entity, Type, IComponent)> AllInLayer(int layer) |         public IEnumerable<(int, Type, IComponent)> AllInLayer(int layer) | ||||||
|         { |         { | ||||||
|             return layerIndexToComponentStore.ContainsKey(layer) ? |             return layerIndexToComponentStore.ContainsKey(layer) ? | ||||||
|                 layerIndexToComponentStore[layer].AllInterfaceTyped() : |                 layerIndexToComponentStore[layer].AllInterfaceTyped() : | ||||||
|                 Enumerable.Empty<(Entity, Type, IComponent)>(); |                 Enumerable.Empty<(int, Type, IComponent)>(); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -3,6 +3,7 @@ using System.Reflection; | ||||||
| using System.Collections.Generic; | using System.Collections.Generic; | ||||||
| using System.Linq; | using System.Linq; | ||||||
| using Encompass.Exceptions; | using Encompass.Exceptions; | ||||||
|  | using MoonTools.FastCollections; | ||||||
| 
 | 
 | ||||||
| namespace Encompass | namespace Encompass | ||||||
| { | { | ||||||
|  | @ -16,11 +17,13 @@ namespace Encompass | ||||||
|         internal Guid ID; |         internal Guid ID; | ||||||
| 
 | 
 | ||||||
|         internal readonly HashSet<Type> readTypes = new HashSet<Type>(); |         internal readonly HashSet<Type> readTypes = new HashSet<Type>(); | ||||||
|         internal readonly HashSet<Type> readPendingTypes = new HashSet<Type>(); |         internal readonly HashSet<Type> readImmediateTypes = new HashSet<Type>(); | ||||||
|         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 HashSet<Type> writeTypes = new HashSet<Type>(); |         internal readonly HashSet<Type> writeTypes = new HashSet<Type>(); | ||||||
|         internal readonly HashSet<Type> writePendingTypes = new HashSet<Type>(); |         internal readonly HashSet<Type> writeImmediateTypes = new HashSet<Type>(); | ||||||
|  |         internal readonly HashSet<Type> queryWithTypes = new HashSet<Type>(); | ||||||
|  |         internal readonly HashSet<Type> queryWithoutTypes = new HashSet<Type>(); | ||||||
|         internal readonly Dictionary<Type, int> writePriorities = new Dictionary<Type, int>(); |         internal readonly Dictionary<Type, int> writePriorities = new Dictionary<Type, int>(); | ||||||
|         internal readonly int defaultWritePriority = 0; |         internal readonly int defaultWritePriority = 0; | ||||||
| 
 | 
 | ||||||
|  | @ -33,8 +36,22 @@ namespace Encompass | ||||||
|         private EntityManager entityManager; |         private EntityManager entityManager; | ||||||
|         private MessageManager messageManager; |         private MessageManager messageManager; | ||||||
|         private ComponentManager componentManager; |         private ComponentManager componentManager; | ||||||
|         private ComponentUpdateManager componentUpdateManager; |  | ||||||
|         private TimeManager timeManager; |         private TimeManager timeManager; | ||||||
|  |         private TrackingManager trackingManager; | ||||||
|  | 
 | ||||||
|  |         private EntitySetQuery entityQuery; | ||||||
|  | 
 | ||||||
|  |         private HashSet<int> _trackedEntities = new HashSet<int>(); | ||||||
|  |         protected IEnumerable<Entity> TrackedEntities | ||||||
|  |         { | ||||||
|  |             get | ||||||
|  |             { | ||||||
|  |                 foreach (var entityID in _trackedEntities) | ||||||
|  |                 { | ||||||
|  |                     yield return entityManager.GetEntity(entityID); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         protected Engine() |         protected Engine() | ||||||
|         { |         { | ||||||
|  | @ -46,10 +63,10 @@ namespace Encompass | ||||||
|                 sendTypes = sendsAttribute.sendTypes; |                 sendTypes = sendsAttribute.sendTypes; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             var activatesAttribute = GetType().GetCustomAttribute<WritesPending>(false); |             var activatesAttribute = GetType().GetCustomAttribute<WritesImmediate>(false); | ||||||
|             if (activatesAttribute != null) |             if (activatesAttribute != null) | ||||||
|             { |             { | ||||||
|                 writePendingTypes = activatesAttribute.writePendingTypes; |                 writeImmediateTypes = activatesAttribute.writeImmediateTypes; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             var defaultWritePriorityAttribute = GetType().GetCustomAttribute<DefaultWritePriority>(false); |             var defaultWritePriorityAttribute = GetType().GetCustomAttribute<DefaultWritePriority>(false); | ||||||
|  | @ -77,10 +94,22 @@ namespace Encompass | ||||||
|                 readTypes = readsAttribute.readTypes; |                 readTypes = readsAttribute.readTypes; | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             var readsPendingAttribute = GetType().GetCustomAttribute<ReadsPending>(false); |             var readsImmediateAttribute = GetType().GetCustomAttribute<ReadsImmediate>(false); | ||||||
|             if (readsPendingAttribute != null) |             if (readsImmediateAttribute != null) | ||||||
|             { |             { | ||||||
|                 readPendingTypes = readsPendingAttribute.readPendingTypes; |                 readImmediateTypes = readsImmediateAttribute.readImmediateTypes; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             var queryWithAttribute = GetType().GetCustomAttribute<QueryWith>(false); | ||||||
|  |             if (queryWithAttribute != null) | ||||||
|  |             { | ||||||
|  |                 queryWithTypes = queryWithAttribute.queryWithTypes; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             var queryWithoutAttribute = GetType().GetCustomAttribute<QueryWithout>(false); | ||||||
|  |             if (queryWithoutAttribute != null) | ||||||
|  |             { | ||||||
|  |                 queryWithoutTypes = queryWithoutAttribute.queryWithoutTypes; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | @ -119,16 +148,16 @@ namespace Encompass | ||||||
|             this.messageManager = messageManager; |             this.messageManager = messageManager; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         internal void AssignComponentUpdateManager(ComponentUpdateManager componentUpdateManager) |  | ||||||
|         { |  | ||||||
|             this.componentUpdateManager = componentUpdateManager; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         internal void AssignTimeManager(TimeManager timeManager) |         internal void AssignTimeManager(TimeManager timeManager) | ||||||
|         { |         { | ||||||
|             this.timeManager = timeManager; |             this.timeManager = timeManager; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         internal void AssignTrackingManager(TrackingManager trackingManager) | ||||||
|  |         { | ||||||
|  |             this.trackingManager = trackingManager; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         /// <summary> |         /// <summary> | ||||||
|         /// Runs once per World update with the calculated delta-time. |         /// Runs once per World update with the calculated delta-time. | ||||||
|         /// </summary> |         /// </summary> | ||||||
|  | @ -156,7 +185,7 @@ namespace Encompass | ||||||
|         /// </summary> |         /// </summary> | ||||||
|         protected Entity ReadEntity<TComponent>() where TComponent : struct, IComponent |         protected Entity ReadEntity<TComponent>() where TComponent : struct, IComponent | ||||||
|         { |         { | ||||||
|             return ReadComponentHelper<TComponent>().Item2; |             return entityManager.GetEntity(ReadComponentHelper<TComponent>().Item2); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         /// <summary> |         /// <summary> | ||||||
|  | @ -166,7 +195,7 @@ namespace Encompass | ||||||
|         { |         { | ||||||
|             foreach (var pair in ReadComponentsHelper<TComponent>()) |             foreach (var pair in ReadComponentsHelper<TComponent>()) | ||||||
|             { |             { | ||||||
|                 yield return pair.Item2; |                 yield return entityManager.GetEntity(pair.Item2); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | @ -177,21 +206,21 @@ namespace Encompass | ||||||
|             return componentManager.GetComponentsByType<TComponent>(); |             return componentManager.GetComponentsByType<TComponent>(); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         private IEnumerable<(TComponent, Entity)> ReadComponentsHelper<TComponent>() where TComponent : struct, IComponent |         private IEnumerable<(TComponent, int)> ReadComponentsHelper<TComponent>() where TComponent : struct, IComponent | ||||||
|         { |         { | ||||||
|             var pendingRead = readPendingTypes.Contains(typeof(TComponent)); |             var immediateRead = readImmediateTypes.Contains(typeof(TComponent)); | ||||||
|             var existingRead = readTypes.Contains(typeof(TComponent)); |             var existingRead = readTypes.Contains(typeof(TComponent)); | ||||||
|             if (existingRead && pendingRead) |             if (existingRead && immediateRead) | ||||||
|             { |             { | ||||||
|                 return componentUpdateManager.ReadExistingAndPendingComponentsByType<TComponent>(); |                 return componentManager.ReadExistingAndImmediateComponentsByType<TComponent>(); | ||||||
|             } |             } | ||||||
|             else if (existingRead) |             else if (existingRead) | ||||||
|             { |             { | ||||||
|                 return componentUpdateManager.ReadExistingComponentsByType<TComponent>(); |                 return componentManager.GetComponentsIncludingEntity<TComponent>(); | ||||||
|             } |             } | ||||||
|             else if (pendingRead) |             else if (immediateRead) | ||||||
|             { |             { | ||||||
|                 return componentUpdateManager.ReadPendingComponentsByType<TComponent>(); |                 return componentManager.ReadImmediateComponentsByType<TComponent>(); | ||||||
|             } |             } | ||||||
|             else |             else | ||||||
|             { |             { | ||||||
|  | @ -215,29 +244,27 @@ namespace Encompass | ||||||
|         /// </summary> |         /// </summary> | ||||||
|         protected IEnumerable<(TComponent, Entity)> ReadComponentsIncludingEntity<TComponent>() where TComponent : struct, IComponent |         protected IEnumerable<(TComponent, Entity)> ReadComponentsIncludingEntity<TComponent>() where TComponent : struct, IComponent | ||||||
|         { |         { | ||||||
|             return ReadComponentsHelper<TComponent>(); |             foreach (var (component, id) in ReadComponentsHelper<TComponent>()) | ||||||
|  |             { | ||||||
|  |                 yield return (component, entityManager.GetEntity(id)); | ||||||
|  |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         internal IEnumerable<(TComponent, Entity)> InternalRead<TComponent>() where TComponent : struct, IComponent |         private (TComponent, int) ReadComponentHelper<TComponent>() where TComponent : struct, IComponent | ||||||
|         { |         { | ||||||
|             return componentManager.GetComponentsIncludingEntity<TComponent>(); |             var immediateRead = readImmediateTypes.Contains(typeof(TComponent)); | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         private (TComponent, Entity) ReadComponentHelper<TComponent>() where TComponent : struct, IComponent |  | ||||||
|         { |  | ||||||
|             var pendingRead = readPendingTypes.Contains(typeof(TComponent)); |  | ||||||
|             var existingRead = readTypes.Contains(typeof(TComponent)); |             var existingRead = readTypes.Contains(typeof(TComponent)); | ||||||
|             if (existingRead && pendingRead) |             if (existingRead && immediateRead) | ||||||
|             { |             { | ||||||
|                 return componentUpdateManager.ReadFirstExistingOrPendingComponentByType<TComponent>(); |                 return componentManager.ReadFirstExistingOrImmediateComponentByType<TComponent>(); | ||||||
|             } |             } | ||||||
|             else if (existingRead) |             else if (existingRead) | ||||||
|             { |             { | ||||||
|                 return componentUpdateManager.ReadFirstExistingComponentByType<TComponent>(); |                 return componentManager.ReadFirstExistingComponentByType<TComponent>(); | ||||||
|             } |             } | ||||||
|             else if (pendingRead) |             else if (immediateRead) | ||||||
|             { |             { | ||||||
|                 return componentUpdateManager.ReadFirstPendingComponentByType<TComponent>(); |                 return componentManager.ReadFirstImmediateComponentByType<TComponent>(); | ||||||
|             } |             } | ||||||
|             else |             else | ||||||
|             { |             { | ||||||
|  | @ -258,7 +285,8 @@ namespace Encompass | ||||||
|         /// </summary> |         /// </summary> | ||||||
|         protected (TComponent, Entity) ReadComponentIncludingEntity<TComponent>() where TComponent : struct, IComponent |         protected (TComponent, Entity) ReadComponentIncludingEntity<TComponent>() where TComponent : struct, IComponent | ||||||
|         { |         { | ||||||
|             return ReadComponentHelper<TComponent>(); |             var (component, id) = ReadComponentHelper<TComponent>(); | ||||||
|  |             return (component, entityManager.GetEntity(id)); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         /// <summary> |         /// <summary> | ||||||
|  | @ -266,19 +294,19 @@ namespace Encompass | ||||||
|         /// </summary> |         /// </summary> | ||||||
|         protected bool SomeComponent<TComponent>() where TComponent : struct, IComponent |         protected bool SomeComponent<TComponent>() where TComponent : struct, IComponent | ||||||
|         { |         { | ||||||
|             var pendingRead = readPendingTypes.Contains(typeof(TComponent)); |             var immediateRead = readImmediateTypes.Contains(typeof(TComponent)); | ||||||
|             var existingRead = readTypes.Contains(typeof(TComponent)); |             var existingRead = readTypes.Contains(typeof(TComponent)); | ||||||
|             if (existingRead && pendingRead) |             if (existingRead && immediateRead) | ||||||
|             { |             { | ||||||
|                 return componentUpdateManager.SomeExistingOrPendingComponent<TComponent>(); |                 return componentManager.SomeExistingOrImmediateComponent<TComponent>(); | ||||||
|             } |             } | ||||||
|             else if (existingRead) |             else if (existingRead) | ||||||
|             { |             { | ||||||
|                 return componentUpdateManager.SomeExistingComponent<TComponent>(); |                 return componentManager.SomeExistingComponent<TComponent>(); | ||||||
|             } |             } | ||||||
|             else if (pendingRead) |             else if (immediateRead) | ||||||
|             { |             { | ||||||
|                 return componentUpdateManager.SomePendingComponent<TComponent>(); |                 return componentManager.SomeImmediateComponent<TComponent>(); | ||||||
|             } |             } | ||||||
|             else |             else | ||||||
|             { |             { | ||||||
|  | @ -286,32 +314,21 @@ namespace Encompass | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         private TComponent GetComponentHelper<TComponent>(Entity entity) where TComponent : struct, IComponent |         private TComponent GetComponentHelper<TComponent>(int entityID) where TComponent : struct, IComponent | ||||||
|         { |         { | ||||||
|             var pendingRead = readPendingTypes.Contains(typeof(TComponent)); |             var immediateRead = readImmediateTypes.Contains(typeof(TComponent)); | ||||||
|             var existingRead = readTypes.Contains(typeof(TComponent)); |             var existingRead = readTypes.Contains(typeof(TComponent)); | ||||||
|             if (existingRead && pendingRead) |             if (existingRead && immediateRead) | ||||||
|             { |             { | ||||||
|                 if (componentUpdateManager.HasPendingComponent<TComponent>(entity)) |                 return componentManager.ReadImmediateOrExistingComponentByEntityAndType<TComponent>(entityID); | ||||||
|                 { |  | ||||||
|                     return componentUpdateManager.ReadPendingComponentByEntityAndType<TComponent>(entity); |  | ||||||
|                 } |  | ||||||
|                 else if (componentUpdateManager.HasExistingComponent<TComponent>(entity)) |  | ||||||
|                 { |  | ||||||
|                     return componentUpdateManager.ReadExistingComponentByEntityAndType<TComponent>(entity); |  | ||||||
|                 } |  | ||||||
|                 else |  | ||||||
|                 { |  | ||||||
|                     throw new NoComponentOfTypeOnEntityException("No Component of type {0} exists on Entity {1}", typeof(TComponent).Name, entity.ID); |  | ||||||
|                 } |  | ||||||
|             } |             } | ||||||
|             else if (existingRead) |             else if (existingRead) | ||||||
|             { |             { | ||||||
|                 return componentUpdateManager.ReadExistingComponentByEntityAndType<TComponent>(entity); |                 return componentManager.ReadExistingComponentByEntityAndType<TComponent>(entityID); | ||||||
|             } |             } | ||||||
|             else if (pendingRead) |             else if (immediateRead) | ||||||
|             { |             { | ||||||
|                 return componentUpdateManager.ReadPendingComponentByEntityAndType<TComponent>(entity); |                 return componentManager.ReadImmediateComponentByEntityAndType<TComponent>(entityID); | ||||||
|             } |             } | ||||||
|             else |             else | ||||||
|             { |             { | ||||||
|  | @ -330,7 +347,7 @@ namespace Encompass | ||||||
|         /// </exception> |         /// </exception> | ||||||
|         protected TComponent GetComponent<TComponent>(Entity entity) where TComponent : struct, IComponent |         protected TComponent GetComponent<TComponent>(Entity entity) where TComponent : struct, IComponent | ||||||
|         { |         { | ||||||
|             return GetComponentHelper<TComponent>(entity); |             return GetComponentHelper<TComponent>(entity.ID); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         /// <summary> |         /// <summary> | ||||||
|  | @ -341,20 +358,20 @@ namespace Encompass | ||||||
|         /// </exception> |         /// </exception> | ||||||
|         protected bool HasComponent<TComponent>(Entity entity) where TComponent : struct, IComponent |         protected bool HasComponent<TComponent>(Entity entity) where TComponent : struct, IComponent | ||||||
|         { |         { | ||||||
|             var pendingRead = readPendingTypes.Contains(typeof(TComponent)); |             var immediateRead = readImmediateTypes.Contains(typeof(TComponent)); | ||||||
|             var existingRead = readTypes.Contains(typeof(TComponent)); |             var existingRead = readTypes.Contains(typeof(TComponent)); | ||||||
| 
 | 
 | ||||||
|             if (pendingRead && existingRead) |             if (immediateRead && existingRead) | ||||||
|             { |             { | ||||||
|                 return componentUpdateManager.HasExistingOrPendingComponent<TComponent>(entity); |                 return componentManager.HasExistingOrImmediateComponent<TComponent>(entity.ID); | ||||||
|             } |             } | ||||||
|             else if (existingRead) |             else if (existingRead) | ||||||
|             { |             { | ||||||
|                 return componentUpdateManager.HasExistingComponent<TComponent>(entity); |                 return componentManager.HasExistingComponent<TComponent>(entity.ID); | ||||||
|             } |             } | ||||||
|             else if (pendingRead) |             else if (immediateRead) | ||||||
|             { |             { | ||||||
|                 return componentUpdateManager.HasPendingComponent<TComponent>(entity); |                 return componentManager.HasImmediateComponent<TComponent>(entity.ID); | ||||||
|             } |             } | ||||||
|             else |             else | ||||||
|             { |             { | ||||||
|  | @ -370,20 +387,20 @@ namespace Encompass | ||||||
|         /// </exception> |         /// </exception> | ||||||
|         protected bool HasComponent(Entity entity, Type type) |         protected bool HasComponent(Entity entity, Type type) | ||||||
|         { |         { | ||||||
|             var pendingRead = readPendingTypes.Contains(type); |             var immediateRead = readImmediateTypes.Contains(type); | ||||||
|             var existingRead = readTypes.Contains(type); |             var existingRead = readTypes.Contains(type); | ||||||
| 
 | 
 | ||||||
|             if (pendingRead && existingRead) |             if (immediateRead && existingRead) | ||||||
|             { |             { | ||||||
|                 return componentUpdateManager.HasExistingOrPendingComponent(entity, type); |                 return componentManager.HasExistingOrImmediateComponent(entity.ID, type); | ||||||
|             } |             } | ||||||
|             else if (existingRead) |             else if (existingRead) | ||||||
|             { |             { | ||||||
|                 return componentUpdateManager.HasExistingComponent(entity, type); |                 return componentManager.HasExistingComponent(entity.ID, type); | ||||||
|             } |             } | ||||||
|             else if (pendingRead) |             else if (immediateRead) | ||||||
|             { |             { | ||||||
|                 return componentUpdateManager.HasPendingComponent(entity, type); |                 return componentManager.HasImmediateComponent(entity.ID, type); | ||||||
|             } |             } | ||||||
|             else |             else | ||||||
|             { |             { | ||||||
|  | @ -407,18 +424,27 @@ namespace Encompass | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             bool written; |             bool written; | ||||||
|             if (writePendingTypes.Contains(typeof(TComponent))) |             if (writeImmediateTypes.Contains(typeof(TComponent))) | ||||||
|             { |             { | ||||||
|                 written = AddPendingComponent(entity, component, priority); |                 written = componentManager.AddImmediateComponent(entity.ID, component, priority); | ||||||
|  |                 if (written) | ||||||
|  |                 { | ||||||
|  |                     trackingManager.ImmediateUpdateTracking(entity.ID, typeof(TComponent)); | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
|             else |             else | ||||||
|             { |             { | ||||||
|                 written = componentUpdateManager.UpdateComponent(entity, component, priority); |                 written = componentManager.UpdateComponent(entity.ID, component, priority); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             if (!componentManager.HasExistingComponent<TComponent>(entity.ID)) | ||||||
|  |             { | ||||||
|  |                 trackingManager.RegisterAddition(entity.ID, typeof(TComponent)); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             if (written && component is IDrawableComponent drawableComponent) |             if (written && component is IDrawableComponent drawableComponent) | ||||||
|             { |             { | ||||||
|                 componentManager.RegisterDrawableComponent(entity, component, drawableComponent.Layer); |                 componentManager.RegisterDrawableComponent(entity.ID, component, drawableComponent.Layer); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | @ -456,16 +482,6 @@ namespace Encompass | ||||||
|             messageManager.AddMessageIgnoringTimeDilation(message, time); |             messageManager.AddMessageIgnoringTimeDilation(message, time); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         internal void AddExistingComponent<TComponent>(Entity entity, TComponent component) where TComponent : struct, IComponent |  | ||||||
|         { |  | ||||||
|             componentUpdateManager.AddExistingComponent(entity, component); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         internal bool AddPendingComponent<TComponent>(Entity entity, TComponent component, int priority) where TComponent : struct, IComponent |  | ||||||
|         { |  | ||||||
|             return componentUpdateManager.AddPendingComponent(entity, component, priority); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         /// <summary> |         /// <summary> | ||||||
|         /// Reads all messages of the specified Type. |         /// Reads all messages of the specified Type. | ||||||
|         /// </summary> |         /// </summary> | ||||||
|  | @ -515,7 +531,7 @@ namespace Encompass | ||||||
|         /// </summary> |         /// </summary> | ||||||
|         protected void Destroy(Entity entity) |         protected void Destroy(Entity entity) | ||||||
|         { |         { | ||||||
|             entityManager.MarkForDestroy(entity); |             entityManager.MarkForDestroy(entity.ID); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         /// <summary> |         /// <summary> | ||||||
|  | @ -544,12 +560,31 @@ namespace Encompass | ||||||
|         /// Note that the Engine must Read the Component type that is being removed. |         /// Note that the Engine must Read the Component type that is being removed. | ||||||
|         /// If a Component with the specified type does not exist on the Entity, returns false and does not mutate the Entity. |         /// If a Component with the specified type does not exist on the Entity, returns false and does not mutate the Entity. | ||||||
|         /// </summary> |         /// </summary> | ||||||
|         protected bool RemoveComponent<TComponent>(Entity entity) where TComponent : struct, IComponent |         protected void RemoveComponent<TComponent>(Entity entity) where TComponent : struct, IComponent | ||||||
|         { |         { | ||||||
|             if (!HasComponent<TComponent>(entity)) { return false; } |             var priority = writePriorities.ContainsKey(typeof(TComponent)) ? writePriorities[typeof(TComponent)] : defaultWritePriority; | ||||||
| 
 | 
 | ||||||
|             componentManager.Remove<TComponent>(entity); |             if (!writeTypes.Contains(typeof(TComponent))) | ||||||
|             return true; |             { | ||||||
|  |                 throw new IllegalWriteException("Engine {0} tried to remove undeclared Component {1}. Declare with Writes attribute.", GetType().Name, typeof(TComponent).Name); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             if (writeImmediateTypes.Contains(typeof(TComponent))) | ||||||
|  |             { | ||||||
|  |                 if (componentManager.RemoveImmediate<TComponent>(entity.ID, priority)) | ||||||
|  |                 { | ||||||
|  |                     trackingManager.ImmediateUpdateTracking(entity.ID, typeof(TComponent)); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             else | ||||||
|  |             { | ||||||
|  |                 componentManager.Remove<TComponent>(entity.ID, priority); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             if (componentManager.HasExistingComponent<TComponent>(entity.ID)) | ||||||
|  |             { | ||||||
|  |                 trackingManager.RegisterRemoval(entity.ID, typeof(TComponent)); | ||||||
|  |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         /// <summary> |         /// <summary> | ||||||
|  | @ -561,7 +596,7 @@ namespace Encompass | ||||||
|         /// <param name="easeInTime">The time that will elapse before time is fully dilated, in real time.</param> |         /// <param name="easeInTime">The time that will elapse before time is fully dilated, in real time.</param> | ||||||
|         /// <param name="activeTime">The length of real time that time will be fully dilated.</param> |         /// <param name="activeTime">The length of real time that time will be fully dilated.</param> | ||||||
|         /// <param name="easeOutTime">The time that will elapse before time is fully undilated.</param> |         /// <param name="easeOutTime">The time that will elapse before time is fully undilated.</param> | ||||||
|         public void ActivateTimeDilation(double factor, double easeInTime, double activeTime, double easeOutTime) |         protected void ActivateTimeDilation(double factor, double easeInTime, double activeTime, double easeOutTime) | ||||||
|         { |         { | ||||||
|             timeManager.ActivateTimeDilation(factor, easeInTime, activeTime, easeOutTime); |             timeManager.ActivateTimeDilation(factor, easeInTime, activeTime, easeOutTime); | ||||||
|         } |         } | ||||||
|  | @ -576,7 +611,7 @@ namespace Encompass | ||||||
|         /// <param name="easeInFunction">An easing function for the easing in of time dilation.</param> |         /// <param name="easeInFunction">An easing function for the easing in of time dilation.</param> | ||||||
|         /// <param name="activeTime">The length of real time that time will be fully dilated.</param> |         /// <param name="activeTime">The length of real time that time will be fully dilated.</param> | ||||||
|         /// <param name="easeOutTime">The time that will elapse before time is fully undilated.</param> |         /// <param name="easeOutTime">The time that will elapse before time is fully undilated.</param> | ||||||
|         public void ActivateTimeDilation(double factor, double easeInTime, System.Func<double, double, double, double, double> easeInFunction, double activeTime, double easeOutTime) |         protected void ActivateTimeDilation(double factor, double easeInTime, System.Func<double, double, double, double, double> easeInFunction, double activeTime, double easeOutTime) | ||||||
|         { |         { | ||||||
|             timeManager.ActivateTimeDilation(factor, easeInTime, easeInFunction, activeTime, easeOutTime); |             timeManager.ActivateTimeDilation(factor, easeInTime, easeInFunction, activeTime, easeOutTime); | ||||||
|         } |         } | ||||||
|  | @ -591,7 +626,7 @@ namespace Encompass | ||||||
|         /// <param name="activeTime">The length of real time that time will be fully dilated.</param> |         /// <param name="activeTime">The length of real time that time will be fully dilated.</param> | ||||||
|         /// <param name="easeOutTime">The time that will elapse before time is fully undilated.</param> |         /// <param name="easeOutTime">The time that will elapse before time is fully undilated.</param> | ||||||
|         /// <param name="easeOutFunction">An easing function for the easing out of time dilation.</param> |         /// <param name="easeOutFunction">An easing function for the easing out of time dilation.</param> | ||||||
|         public void ActivateTimeDilation(double factor, double easeInTime, double activeTime, double easeOutTime, System.Func<double, double, double, double, double> easeOutFunction) |         protected void ActivateTimeDilation(double factor, double easeInTime, double activeTime, double easeOutTime, System.Func<double, double, double, double, double> easeOutFunction) | ||||||
|         { |         { | ||||||
|             timeManager.ActivateTimeDilation(factor, easeInTime, activeTime, easeOutTime, easeOutFunction); |             timeManager.ActivateTimeDilation(factor, easeInTime, activeTime, easeOutTime, easeOutFunction); | ||||||
|         } |         } | ||||||
|  | @ -607,9 +642,87 @@ namespace Encompass | ||||||
|         /// <param name="activeTime">The length of real time that time will be fully dilated.</param> |         /// <param name="activeTime">The length of real time that time will be fully dilated.</param> | ||||||
|         /// <param name="easeOutTime">The time that will elapse before time is fully undilated.</param> |         /// <param name="easeOutTime">The time that will elapse before time is fully undilated.</param> | ||||||
|         /// <param name="easeOutFunction">An easing function for the easing out of time dilation.</param> |         /// <param name="easeOutFunction">An easing function for the easing out of time dilation.</param> | ||||||
|         public void ActivateTimeDilation(double factor, double easeInTime, System.Func<double, double, double, double, double> easeInFunction, double activeTime, double easeOutTime, System.Func<double, double, double, double, double> easeOutFunction) |         protected void ActivateTimeDilation(double factor, double easeInTime, System.Func<double, double, double, double, double> easeInFunction, double activeTime, double easeOutTime, System.Func<double, double, double, double, double> easeOutFunction) | ||||||
|         { |         { | ||||||
|             timeManager.ActivateTimeDilation(factor, easeInTime, easeInFunction, activeTime, easeOutTime, easeOutFunction); |             timeManager.ActivateTimeDilation(factor, easeInTime, easeInFunction, activeTime, easeOutTime, easeOutFunction); | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|  |         /// <summary> | ||||||
|  |         /// Efficiently reads Messages of a given type that all reference the same Entity. | ||||||
|  |         /// </summary> | ||||||
|  |         /// <typeparam name="TMessage">The Message subtype.</typeparam> | ||||||
|  |         /// <param name="entity">The entity that all messages in the IEnumerable refer to.</param> | ||||||
|  |         /// <returns></returns> | ||||||
|  |         protected IEnumerable<TMessage> ReadMessagesWithEntity<TMessage>(Entity entity) where TMessage : struct, IMessage, IHasEntity | ||||||
|  |         { | ||||||
|  |             return messageManager.WithEntity<TMessage>(entity.ID); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         internal void CheckAndUpdateTracking(int entityID) | ||||||
|  |         { | ||||||
|  |             if (_trackedEntities.Contains(entityID) && !entityQuery.CheckEntity(entityID, componentManager.ExistingBits)) | ||||||
|  |             { | ||||||
|  |                 _trackedEntities.Remove(entityID); | ||||||
|  |             } | ||||||
|  |             else if (!_trackedEntities.Contains(entityID) && entityQuery.CheckEntity(entityID, componentManager.ExistingBits)) | ||||||
|  |             { | ||||||
|  |                 _trackedEntities.Add(entityID); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         internal void ImmediateCheckAndUpdateTracking(int entityID) | ||||||
|  |         { | ||||||
|  |             if (_trackedEntities.Contains(entityID) && !entityQuery.ImmediateCheckEntity(entityID, componentManager.ImmediateBits, componentManager.ExistingBits)) | ||||||
|  |             { | ||||||
|  |                 _trackedEntities.Remove(entityID); | ||||||
|  |             } | ||||||
|  |             else if (!_trackedEntities.Contains(entityID) && entityQuery.ImmediateCheckEntity(entityID, componentManager.ImmediateBits, componentManager.ExistingBits)) | ||||||
|  |             { | ||||||
|  |                 _trackedEntities.Add(entityID); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         /// <summary> | ||||||
|  |         /// Returns an empty EntitySetQuery. Can be modified and iterated over to obtain Entities that fit the given criteria. | ||||||
|  |         /// </summary> | ||||||
|  |         internal void BuildEntityQuery() | ||||||
|  |         { | ||||||
|  |             var withMask = BitSet512.Zero; | ||||||
|  |             foreach (var type in queryWithTypes) | ||||||
|  |             { | ||||||
|  |                 withMask = withMask.Set(componentManager.TypeToIndex[type]); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             var withoutMask = BitSet512.Zero; | ||||||
|  |             foreach (var type in queryWithoutTypes) | ||||||
|  |             { | ||||||
|  |                 withoutMask = withoutMask.Set(componentManager.TypeToIndex[type]); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             var immediateMask = BitSet512.Zero; | ||||||
|  |             foreach (var type in readImmediateTypes) | ||||||
|  |             { | ||||||
|  |                 immediateMask = immediateMask.Set(componentManager.TypeToIndex[type]); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             var existingMask = BitSet512.Zero; | ||||||
|  |             foreach (var type in readTypes) | ||||||
|  |             { | ||||||
|  |                 existingMask = existingMask.Set(componentManager.TypeToIndex[type]); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             entityQuery = new EntitySetQuery( | ||||||
|  |                 withMask & immediateMask, | ||||||
|  |                 withMask & existingMask, | ||||||
|  |                 withoutMask & immediateMask, | ||||||
|  |                 withoutMask & existingMask, | ||||||
|  |                 ~withMask | ||||||
|  |             ); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         internal void RegisterDestroyedEntity(int entityID) | ||||||
|  |         { | ||||||
|  |             _trackedEntities.Remove(entityID); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -1,13 +0,0 @@ | ||||||
| namespace Encompass |  | ||||||
| { |  | ||||||
|     internal class ComponentEmitter<TComponent> : Engine where TComponent : struct, IComponent |  | ||||||
|     { |  | ||||||
|         public override void Update(double dt) |  | ||||||
|         { |  | ||||||
|             foreach (var (component, entity) in InternalRead<TComponent>()) |  | ||||||
|             { |  | ||||||
|                 AddExistingComponent(entity, component); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | @ -8,21 +8,16 @@ namespace Encompass | ||||||
|     /// </summary> |     /// </summary> | ||||||
|     public struct Entity : IEquatable<Entity> |     public struct Entity : IEquatable<Entity> | ||||||
|     { |     { | ||||||
|         public readonly Guid ID; |         public readonly int ID; | ||||||
| 
 | 
 | ||||||
|         internal Entity(Guid id) |         internal Entity(int id) | ||||||
|         { |         { | ||||||
|             ID = id; |             ID = id; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public override bool Equals(object obj) |         public override bool Equals(object obj) | ||||||
|         { |         { | ||||||
|             if (obj is Entity entity) |             return obj is Entity entity && Equals(entity); | ||||||
|             { |  | ||||||
|                 return Equals(entity); |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             return false; |  | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public bool Equals(Entity other) |         public bool Equals(Entity other) | ||||||
|  |  | ||||||
|  | @ -1,53 +1,80 @@ | ||||||
| using System; | using System.Collections.Generic; | ||||||
| using System.Collections.Generic; | using Encompass.Exceptions; | ||||||
| 
 | 
 | ||||||
| namespace Encompass | namespace Encompass | ||||||
| { | { | ||||||
|     internal class EntityManager |     internal class EntityManager | ||||||
|     { |     { | ||||||
|         private readonly HashSet<Guid> IDs = new HashSet<Guid>(); |         private readonly int entityCapacity; | ||||||
|  |         private readonly IDManager idManager = new IDManager(); | ||||||
|  |         private readonly HashSet<int> IDs = new HashSet<int>(); | ||||||
|    |    | ||||||
|         private readonly HashSet<Entity> entitiesMarkedForDestroy = new HashSet<Entity>(); |         private readonly HashSet<int> entitiesMarkedForDestroy = new HashSet<int>(); | ||||||
| 
 | 
 | ||||||
|         private readonly ComponentManager componentManager; |         private readonly ComponentManager componentManager; | ||||||
| 
 | 
 | ||||||
|         public EntityManager(ComponentManager componentManager) |         public IEnumerable<int> EntityIDs | ||||||
|  |         { | ||||||
|  |             get { return IDs; } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public EntityManager(ComponentManager componentManager, int entityCapacity) | ||||||
|         { |         { | ||||||
|             this.componentManager = componentManager; |             this.componentManager = componentManager; | ||||||
|  |             this.entityCapacity = entityCapacity; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         private int NextID() | ||||||
|  |         { | ||||||
|  |             return idManager.NextID(); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public Entity CreateEntity() |         public Entity CreateEntity() | ||||||
|  |         { | ||||||
|  |             if (IDs.Count < entityCapacity) | ||||||
|             { |             { | ||||||
|                 var id = NextID(); |                 var id = NextID(); | ||||||
|                 var entity = new Entity(id); |                 var entity = new Entity(id); | ||||||
|                 IDs.Add(id); |                 IDs.Add(id); | ||||||
|                 return entity; |                 return entity; | ||||||
|             } |             } | ||||||
|  |             else | ||||||
|  |             { | ||||||
|  |                 throw new EntityOverflowException("The number of entities has exceeded the entity capacity of {0}", entityCapacity); | ||||||
|  |             } | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         public bool EntityExists(Guid id) |         public bool EntityExists(int id) | ||||||
|         { |         { | ||||||
|             return IDs.Contains(id); |             return IDs.Contains(id); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public void MarkForDestroy(Entity entity) |         public Entity GetEntity(int id) | ||||||
|         { |         { | ||||||
|             entitiesMarkedForDestroy.Add(entity); |             if (!EntityExists(id)) | ||||||
|  |             { | ||||||
|  |                 throw new Encompass.Exceptions.EntityNotFoundException("Entity with id {0} does not exist.", id); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|         public void DestroyMarkedEntities() |             return new Entity(id); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public void MarkForDestroy(int entityID) | ||||||
|         { |         { | ||||||
|             foreach (var entity in entitiesMarkedForDestroy) |             entitiesMarkedForDestroy.Add(entityID); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public void DestroyMarkedEntities(IEnumerable<Engine> engines) | ||||||
|         { |         { | ||||||
|                 componentManager.MarkAllComponentsOnEntityForRemoval(entity); |             foreach (var entityID in entitiesMarkedForDestroy) | ||||||
|                 IDs.Remove(entity.ID); |             { | ||||||
|  |                 foreach (var engine in engines) { engine.RegisterDestroyedEntity(entityID); } | ||||||
|  |                 componentManager.MarkAllComponentsOnEntityForRemoval(entityID); | ||||||
|  |                 IDs.Remove(entityID); | ||||||
|  |                 idManager.Free(entityID); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             entitiesMarkedForDestroy.Clear(); |             entitiesMarkedForDestroy.Clear(); | ||||||
|         } |         } | ||||||
| 
 |  | ||||||
|         private Guid NextID() |  | ||||||
|         { |  | ||||||
|             return Guid.NewGuid(); |  | ||||||
|         } |  | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -0,0 +1,48 @@ | ||||||
|  | using MoonTools.FastCollections; | ||||||
|  | 
 | ||||||
|  | namespace Encompass | ||||||
|  | { | ||||||
|  |     internal struct EntitySetQuery | ||||||
|  |     { | ||||||
|  |         private BitSet512 WithImmediateMask { get; } | ||||||
|  |         private BitSet512 WithExistingMask { get; } | ||||||
|  |         private BitSet512 WithoutImmediateMask { get; } | ||||||
|  |         private BitSet512 WithoutExistingMask { get; } | ||||||
|  |         private BitSet512 NotWithMask { get; } | ||||||
|  | 
 | ||||||
|  |         internal EntitySetQuery(BitSet512 withImmediateMask, BitSet512 withExistingMask, BitSet512 withoutImmediateMask, BitSet512 withoutExistingMask, BitSet512 notWithMask) | ||||||
|  |         { | ||||||
|  |             WithImmediateMask = withImmediateMask; | ||||||
|  |             WithExistingMask = withExistingMask; | ||||||
|  |             WithoutImmediateMask = withoutImmediateMask; | ||||||
|  |             WithoutExistingMask = withoutExistingMask; | ||||||
|  |             NotWithMask = notWithMask; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public bool CheckEntity(int entityID, ComponentBitSet componentBitSet) | ||||||
|  |         { | ||||||
|  |             var existingBits = componentBitSet.EntityBitArray(entityID); | ||||||
|  |             var existing = (WithExistingMask & existingBits) | NotWithMask; | ||||||
|  | 
 | ||||||
|  |             var existingForbidden = ~(WithoutExistingMask & existingBits); | ||||||
|  | 
 | ||||||
|  |             return (existing & existingForbidden).AllTrue(); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public bool ImmediateCheckEntity(int entityID, ComponentBitSet immediateBitLookup, ComponentBitSet existingBitLookup) | ||||||
|  |         { | ||||||
|  |             var immediateBits = immediateBitLookup.EntityBitArray(entityID); | ||||||
|  |             var existingBits = existingBitLookup.EntityBitArray(entityID); | ||||||
|  | 
 | ||||||
|  |             var immediate = WithImmediateMask & immediateBits; | ||||||
|  |             var existing = WithExistingMask & existingBits; | ||||||
|  |             var withCheck = immediate | existing | NotWithMask; | ||||||
|  | 
 | ||||||
|  |             var immediateForbidden = ~(WithoutImmediateMask & immediateBits); | ||||||
|  |             var existingForbidden = ~(WithoutExistingMask & existingBits); | ||||||
|  |             var withoutCheck = immediateForbidden & existingForbidden; | ||||||
|  | 
 | ||||||
|  |             return (withCheck & withoutCheck).AllTrue(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -2,9 +2,9 @@ using System; | ||||||
| 
 | 
 | ||||||
| namespace Encompass.Exceptions | namespace Encompass.Exceptions | ||||||
| { | { | ||||||
|     public class ComponentNotFoundException : Exception |     public class EntityOverflowException : Exception | ||||||
|     { |     { | ||||||
|         public ComponentNotFoundException( |         public EntityOverflowException( | ||||||
|             string format, |             string format, | ||||||
|             params object[] args |             params object[] args | ||||||
|         ) : base(string.Format(format, args)) { } |         ) : base(string.Format(format, args)) { } | ||||||
|  | @ -2,9 +2,9 @@ | ||||||
| 
 | 
 | ||||||
| namespace Encompass.Exceptions | namespace Encompass.Exceptions | ||||||
| { | { | ||||||
|     public class ComponentTypeMismatchException : Exception |     public class IllegalWriteImmediateException : Exception | ||||||
|     { |     { | ||||||
|         public ComponentTypeMismatchException( |         public IllegalWriteImmediateException( | ||||||
|             string format, |             string format, | ||||||
|             params object[] args |             params object[] args | ||||||
|         ) : base(string.Format(format, args)) { } |         ) : base(string.Format(format, args)) { } | ||||||
|  | @ -1,12 +0,0 @@ | ||||||
| using System; |  | ||||||
| 
 |  | ||||||
| namespace Encompass.Exceptions |  | ||||||
| { |  | ||||||
|     public class IllegalWritePendingException : Exception |  | ||||||
|     { |  | ||||||
|         public IllegalWritePendingException( |  | ||||||
|             string format, |  | ||||||
|             params object[] args |  | ||||||
|         ) : base(string.Format(format, args)) { } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | @ -2,9 +2,9 @@ using System; | ||||||
| 
 | 
 | ||||||
| namespace Encompass.Exceptions | namespace Encompass.Exceptions | ||||||
| { | { | ||||||
|     public class IllegalWritePendingTypeException : Exception |     public class IllegalWriteImmediateTypeException : Exception | ||||||
|     { |     { | ||||||
|         public IllegalWritePendingTypeException( |         public IllegalWriteImmediateTypeException( | ||||||
|             string format, |             string format, | ||||||
|             params object[] args |             params object[] args | ||||||
|         ) : base(string.Format(format, args)) { } |         ) : base(string.Format(format, args)) { } | ||||||
|  |  | ||||||
|  | @ -1,12 +0,0 @@ | ||||||
| using System; |  | ||||||
| 
 |  | ||||||
| namespace Encompass.Exceptions |  | ||||||
| { |  | ||||||
|     public class RepeatUpdateComponentException : Exception |  | ||||||
|     { |  | ||||||
|         public RepeatUpdateComponentException( |  | ||||||
|             string format, |  | ||||||
|             params object[] args |  | ||||||
|         ) : base(string.Format(format, args)) { } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | @ -0,0 +1,28 @@ | ||||||
|  | using System.Collections.Generic; | ||||||
|  | 
 | ||||||
|  | namespace Encompass | ||||||
|  | { | ||||||
|  |     internal class IDManager | ||||||
|  |     { | ||||||
|  |         int nextID = 0; | ||||||
|  | 
 | ||||||
|  |         private Stack<int> availableIDs = new Stack<int>(); | ||||||
|  | 
 | ||||||
|  |         public int NextID() | ||||||
|  |         { | ||||||
|  |             if (availableIDs.Count > 0) | ||||||
|  |             { | ||||||
|  |                 return availableIDs.Pop(); | ||||||
|  |             } | ||||||
|  |             else | ||||||
|  |             { | ||||||
|  |                 return nextID++; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public void Free(int ID) | ||||||
|  |         { | ||||||
|  |             availableIDs.Push(ID); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -0,0 +1,7 @@ | ||||||
|  | namespace Encompass | ||||||
|  | { | ||||||
|  |     public interface IHasEntity | ||||||
|  |     { | ||||||
|  |         Entity Entity { get; } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -14,7 +14,7 @@ namespace Encompass | ||||||
| 
 | 
 | ||||||
|         internal void AddMessage<TMessage>(TMessage message) where TMessage : struct, IMessage |         internal void AddMessage<TMessage>(TMessage message) where TMessage : struct, IMessage | ||||||
|         { |         { | ||||||
|             messageStore.AddMessage<TMessage>(message); |             messageStore.AddMessage(message); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         internal void AddMessage<TMessage>(TMessage message, double time) where TMessage : struct, IMessage |         internal void AddMessage<TMessage>(TMessage message, double time) where TMessage : struct, IMessage | ||||||
|  | @ -51,5 +51,10 @@ namespace Encompass | ||||||
|         { |         { | ||||||
|             return messageStore.First<TMessage>(); |             return messageStore.First<TMessage>(); | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|  |         internal IEnumerable<TMessage> WithEntity<TMessage>(int entityID) where TMessage : struct, IMessage, IHasEntity | ||||||
|  |         { | ||||||
|  |             return messageStore.WithEntity<TMessage>(entityID); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -5,12 +5,14 @@ namespace Encompass | ||||||
| { | { | ||||||
|     internal class RenderManager |     internal class RenderManager | ||||||
|     { |     { | ||||||
|  |         private readonly EntityManager entityManager; | ||||||
|         private readonly DrawLayerManager drawLayerManager; |         private readonly DrawLayerManager drawLayerManager; | ||||||
| 
 | 
 | ||||||
|         private readonly Dictionary<Type, Action<Entity, IComponent>> drawComponentTypeToOrderedRenderer = new Dictionary<Type, Action<Entity, IComponent>>(256); |         private readonly Dictionary<Type, Action<Entity, IComponent>> drawComponentTypeToOrderedRenderer = new Dictionary<Type, Action<Entity, IComponent>>(256); | ||||||
| 
 | 
 | ||||||
|         public RenderManager(DrawLayerManager drawLayerManager) |         public RenderManager(EntityManager entityManager, DrawLayerManager drawLayerManager) | ||||||
|         { |         { | ||||||
|  |             this.entityManager = entityManager; | ||||||
|             this.drawLayerManager = drawLayerManager; |             this.drawLayerManager = drawLayerManager; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | @ -31,12 +33,12 @@ namespace Encompass | ||||||
|             { |             { | ||||||
|                 var generalRendererSet = drawLayerManager.GeneralRenderersByLayer(layer); |                 var generalRendererSet = drawLayerManager.GeneralRenderersByLayer(layer); | ||||||
| 
 | 
 | ||||||
|                 foreach (var (entity, componentType, component) in drawLayerManager.AllInLayer(layer)) |                 foreach (var (entityID, componentType, component) in drawLayerManager.AllInLayer(layer)) | ||||||
|                 { |                 { | ||||||
|                     if (drawComponentTypeToOrderedRenderer.ContainsKey(componentType)) |                     if (drawComponentTypeToOrderedRenderer.ContainsKey(componentType)) | ||||||
|                     { |                     { | ||||||
|                         var internalRenderAction = drawComponentTypeToOrderedRenderer[componentType]; |                         var internalRenderAction = drawComponentTypeToOrderedRenderer[componentType]; | ||||||
|                         internalRenderAction(entity, component); |                         internalRenderAction(entityManager.GetEntity(entityID), component); | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -37,7 +37,10 @@ namespace Encompass | ||||||
| 
 | 
 | ||||||
|         protected IEnumerable<(TComponent, Entity)> ReadComponentsIncludingEntity<TComponent>() where TComponent : struct, IComponent |         protected IEnumerable<(TComponent, Entity)> ReadComponentsIncludingEntity<TComponent>() where TComponent : struct, IComponent | ||||||
|         { |         { | ||||||
|             return componentManager.GetComponentsIncludingEntity<TComponent>(); |             foreach (var (component, id) in componentManager.GetComponentsIncludingEntity<TComponent>()) | ||||||
|  |             { | ||||||
|  |                 yield return (component, entityManager.GetEntity(id)); | ||||||
|  |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         protected TComponent ReadComponent<TComponent>() where TComponent : struct, IComponent |         protected TComponent ReadComponent<TComponent>() where TComponent : struct, IComponent | ||||||
|  | @ -56,17 +59,17 @@ namespace Encompass | ||||||
| 
 | 
 | ||||||
|         protected TComponent GetComponent<TComponent>(Entity entity) where TComponent : struct, IComponent |         protected TComponent GetComponent<TComponent>(Entity entity) where TComponent : struct, IComponent | ||||||
|         { |         { | ||||||
|             return componentManager.GetComponentByEntityAndType<TComponent>(entity); |             return componentManager.GetComponentByEntityAndType<TComponent>(entity.ID); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         protected bool HasComponent<TComponent>(Entity entity) where TComponent : struct, IComponent |         protected bool HasComponent<TComponent>(Entity entity) where TComponent : struct, IComponent | ||||||
|         { |         { | ||||||
|             return componentManager.EntityHasComponentOfType<TComponent>(entity); |             return componentManager.EntityHasComponentOfType<TComponent>(entity.ID); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         protected bool SomeComponent<TComponent>() where TComponent : struct, IComponent |         protected bool SomeComponent<TComponent>() where TComponent : struct, IComponent | ||||||
|         { |         { | ||||||
|             return componentManager.ComponentOfTypeExists<TComponent>(); |             return componentManager.SomeExistingComponent<TComponent>(); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -0,0 +1,97 @@ | ||||||
|  | using System; | ||||||
|  | using System.Collections.Generic; | ||||||
|  | 
 | ||||||
|  | namespace Encompass | ||||||
|  | { | ||||||
|  |     internal class TrackingManager | ||||||
|  |     { | ||||||
|  |         private Dictionary<Type, HashSet<Engine>> _immediateComponentTypesToEngines = new Dictionary<Type, HashSet<Engine>>(); | ||||||
|  |         private Dictionary<Type, HashSet<Engine>> _componentTypesToEngines = new Dictionary<Type, HashSet<Engine>>(); | ||||||
|  | 
 | ||||||
|  |         private HashSet<(int, Type)> _additions = new HashSet<(int, Type)>(); | ||||||
|  |         private HashSet<(int, Type)> _removals = new HashSet<(int, Type)>(); | ||||||
|  | 
 | ||||||
|  |         private HashSet<(int, Engine)> _pairsToCheck = new HashSet<(int, Engine)>(); | ||||||
|  | 
 | ||||||
|  |         public void RegisterComponentTypeToEngine(Type type, Engine engine) | ||||||
|  |         { | ||||||
|  |             if (!_componentTypesToEngines.ContainsKey(type)) { _componentTypesToEngines.Add(type, new HashSet<Engine>()); } | ||||||
|  |             _componentTypesToEngines[type].Add(engine); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public void RegisterImmediateComponentTypeToEngine(Type type, Engine engine) | ||||||
|  |         { | ||||||
|  |             if (!_immediateComponentTypesToEngines.ContainsKey(type)) { _immediateComponentTypesToEngines.Add(type, new HashSet<Engine>()); } | ||||||
|  |             _immediateComponentTypesToEngines[type].Add(engine); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public void RegisterAddition(int entityID, Type type) | ||||||
|  |         { | ||||||
|  |             _additions.Add((entityID, type)); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public void RegisterRemoval(int entityID, Type type) | ||||||
|  |         { | ||||||
|  |             _removals.Add((entityID, type)); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public void InitializeTracking(IEnumerable<int> entityIDs) | ||||||
|  |         { | ||||||
|  |             foreach (var entityID in entityIDs) | ||||||
|  |             { | ||||||
|  |                 foreach (var engineSet in _componentTypesToEngines.Values) | ||||||
|  |                 { | ||||||
|  |                     foreach (var engine in engineSet) | ||||||
|  |                     { | ||||||
|  |                         engine.CheckAndUpdateTracking(entityID); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public void ImmediateUpdateTracking(int entityID, Type componentType) | ||||||
|  |         { | ||||||
|  |             if (_immediateComponentTypesToEngines.ContainsKey(componentType)) | ||||||
|  |             { | ||||||
|  |                 foreach (var engine in _componentTypesToEngines[componentType]) | ||||||
|  |                 { | ||||||
|  |                     engine.ImmediateCheckAndUpdateTracking(entityID); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public void UpdateTracking() | ||||||
|  |         { | ||||||
|  |             // TODO: optimize so we only check each entity/engine pair once | ||||||
|  |             foreach (var (entity, componentType) in _additions) | ||||||
|  |             { | ||||||
|  |                 if (_componentTypesToEngines.ContainsKey(componentType)) | ||||||
|  |                 { | ||||||
|  |                     foreach (var engine in _componentTypesToEngines[componentType]) | ||||||
|  |                     { | ||||||
|  |                         _pairsToCheck.Add((entity, engine)); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             _additions.Clear(); | ||||||
|  | 
 | ||||||
|  |             foreach (var (entity, componentType) in _removals) | ||||||
|  |             { | ||||||
|  |                 if (_componentTypesToEngines.ContainsKey(componentType)) | ||||||
|  |                 { | ||||||
|  |                     foreach (var engine in _componentTypesToEngines[componentType]) | ||||||
|  |                     { | ||||||
|  |                         _pairsToCheck.Add((entity, engine)); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             _removals.Clear(); | ||||||
|  | 
 | ||||||
|  |             foreach (var (entity, engine) in _pairsToCheck) | ||||||
|  |             { | ||||||
|  |                 engine.CheckAndUpdateTracking(entity); | ||||||
|  |             } | ||||||
|  |             _pairsToCheck.Clear(); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | @ -9,9 +9,9 @@ namespace Encompass | ||||||
|     { |     { | ||||||
|         private IEnumerable<Type> _componentTypes; |         private IEnumerable<Type> _componentTypes; | ||||||
|         private IEnumerable<Type> _messageTypes; |         private IEnumerable<Type> _messageTypes; | ||||||
|         private Entity _entity; |         public Entity Entity { get; private set; } | ||||||
| 
 | 
 | ||||||
|         public UberEngine(Entity entity, IEnumerable<Type> componentTypes, IEnumerable<Type> messageTypes) |         public UberEngine(IEnumerable<Type> componentTypes, IEnumerable<Type> messageTypes) | ||||||
|         { |         { | ||||||
|             _componentTypes = componentTypes; |             _componentTypes = componentTypes; | ||||||
|             _messageTypes = messageTypes; |             _messageTypes = messageTypes; | ||||||
|  | @ -19,14 +19,15 @@ namespace Encompass | ||||||
|             writeTypes.UnionWith(componentTypes); |             writeTypes.UnionWith(componentTypes); | ||||||
|             sendTypes.UnionWith(messageTypes); |             sendTypes.UnionWith(messageTypes); | ||||||
|             receiveTypes.UnionWith(messageTypes); |             receiveTypes.UnionWith(messageTypes); | ||||||
|             _entity = entity; |  | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public void Write() |         public void Write() | ||||||
|         { |         { | ||||||
|  |             Entity = CreateEntity(); | ||||||
|  | 
 | ||||||
|             foreach (var type in _componentTypes) |             foreach (var type in _componentTypes) | ||||||
|             { |             { | ||||||
|                 var instanceParam = new object[] { _entity, Activator.CreateInstance(type) }; |                 var instanceParam = new object[] { Entity, Activator.CreateInstance(type) }; | ||||||
|                 var setComponentMethod = typeof(Engine).GetMethod("SetComponent", BindingFlags.NonPublic | BindingFlags.Instance); |                 var setComponentMethod = typeof(Engine).GetMethod("SetComponent", BindingFlags.NonPublic | BindingFlags.Instance); | ||||||
|                 var genericSetComponentMethod = setComponentMethod.MakeGenericMethod(type); |                 var genericSetComponentMethod = setComponentMethod.MakeGenericMethod(type); | ||||||
|                 genericSetComponentMethod.Invoke(this, instanceParam); |                 genericSetComponentMethod.Invoke(this, instanceParam); | ||||||
|  | @ -43,12 +44,12 @@ namespace Encompass | ||||||
|                 CallGenericMethod(type, "ReadComponentsIncludingEntity", null); |                 CallGenericMethod(type, "ReadComponentsIncludingEntity", null); | ||||||
|                 CallGenericMethod(type, "ReadEntity", null); |                 CallGenericMethod(type, "ReadEntity", null); | ||||||
|                 CallGenericMethod(type, "ReadEntities", null); |                 CallGenericMethod(type, "ReadEntities", null); | ||||||
|                 CallGenericMethod(type, "GetComponent", new Type[] { typeof(Entity) }, new object[] { _entity }); |                 CallGenericMethod(type, "GetComponent", new Type[] { typeof(Entity) }, new object[] { Entity }); | ||||||
|                 CallGenericMethod(type, "HasComponent", new Type[] { typeof(Entity) }, new object[] { _entity }); |                 CallGenericMethod(type, "HasComponent", new Type[] { typeof(Entity) }, new object[] { Entity }); | ||||||
|                 CallGenericMethod(type, "SomeComponent", null); |                 CallGenericMethod(type, "SomeComponent", null); | ||||||
|                 CallGenericMethod(type, "RemoveComponent", new Type[] { typeof(Entity) }, new object[] { _entity }); |  | ||||||
|                 CallGenericMethod(type, "DestroyWith", null); |                 CallGenericMethod(type, "DestroyWith", null); | ||||||
|                 CallGenericMethod(type, "DestroyAllWith", null); |                 CallGenericMethod(type, "DestroyAllWith", null); | ||||||
|  |                 CallGenericMethod(type, "RemoveComponent", new Type[] { typeof(Entity) }, new object[] { Entity }); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             foreach (var type in _messageTypes) |             foreach (var type in _messageTypes) | ||||||
|  | @ -59,6 +60,10 @@ namespace Encompass | ||||||
|                 CallGenericMethod(type, "ReadMessage", null); |                 CallGenericMethod(type, "ReadMessage", null); | ||||||
|                 CallGenericMethod(type, "ReadMessages", null); |                 CallGenericMethod(type, "ReadMessages", null); | ||||||
|                 CallGenericMethod(type, "SomeMessage", null); |                 CallGenericMethod(type, "SomeMessage", null); | ||||||
|  |                 if (typeof(IHasEntity).IsAssignableFrom(type)) | ||||||
|  |                 { | ||||||
|  |                     CallGenericMethod(type, "ReadMessagesWithEntity", new Type[] { typeof(Entity) }, new object[] { Entity }); | ||||||
|  |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -6,13 +6,17 @@ namespace Encompass | ||||||
| { | { | ||||||
|     class UberRenderer : Renderer |     class UberRenderer : Renderer | ||||||
|     { |     { | ||||||
|         private Entity _entity; |  | ||||||
|         private IEnumerable<Type> _componentTypes; |         private IEnumerable<Type> _componentTypes; | ||||||
|  |         private Entity _entity; | ||||||
| 
 | 
 | ||||||
|         public UberRenderer(Entity entity, IEnumerable<Type> componentTypes) |         public UberRenderer(IEnumerable<Type> componentTypes) | ||||||
|  |         { | ||||||
|  |             _componentTypes = componentTypes; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         public void SetEntity(Entity entity) | ||||||
|         { |         { | ||||||
|             _entity = entity; |             _entity = entity; | ||||||
|             _componentTypes = componentTypes; |  | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         public void Render() |         public void Render() | ||||||
|  |  | ||||||
|  | @ -10,8 +10,8 @@ namespace Encompass | ||||||
|         private readonly List<Engine> enginesInOrder; |         private readonly List<Engine> enginesInOrder; | ||||||
|         private readonly EntityManager entityManager; |         private readonly EntityManager entityManager; | ||||||
|         private readonly ComponentManager componentManager; |         private readonly ComponentManager componentManager; | ||||||
|  |         private readonly TrackingManager trackingManager; | ||||||
|         private readonly MessageManager messageManager; |         private readonly MessageManager messageManager; | ||||||
|         private readonly ComponentUpdateManager componentUpdateManager; |  | ||||||
|         private readonly TimeManager timeManager; |         private readonly TimeManager timeManager; | ||||||
|         private readonly RenderManager renderManager; |         private readonly RenderManager renderManager; | ||||||
| 
 | 
 | ||||||
|  | @ -19,8 +19,8 @@ namespace Encompass | ||||||
|             List<Engine> enginesInOrder, |             List<Engine> enginesInOrder, | ||||||
|             EntityManager entityManager, |             EntityManager entityManager, | ||||||
|             ComponentManager componentManager, |             ComponentManager componentManager, | ||||||
|  |             TrackingManager trackingManager, | ||||||
|             MessageManager messageManager, |             MessageManager messageManager, | ||||||
|             ComponentUpdateManager componentUpdateManager, |  | ||||||
|             TimeManager timeManager, |             TimeManager timeManager, | ||||||
|             RenderManager renderManager |             RenderManager renderManager | ||||||
|         ) |         ) | ||||||
|  | @ -28,8 +28,8 @@ namespace Encompass | ||||||
|             this.enginesInOrder = enginesInOrder; |             this.enginesInOrder = enginesInOrder; | ||||||
|             this.entityManager = entityManager; |             this.entityManager = entityManager; | ||||||
|             this.componentManager = componentManager; |             this.componentManager = componentManager; | ||||||
|  |             this.trackingManager = trackingManager; | ||||||
|             this.messageManager = messageManager; |             this.messageManager = messageManager; | ||||||
|             this.componentUpdateManager = componentUpdateManager; |  | ||||||
|             this.timeManager = timeManager; |             this.timeManager = timeManager; | ||||||
|             this.renderManager = renderManager; |             this.renderManager = renderManager; | ||||||
|         } |         } | ||||||
|  | @ -40,6 +40,7 @@ namespace Encompass | ||||||
|         /// <param name="dt">The time in seconds that has passed since the previous frame.</param> |         /// <param name="dt">The time in seconds that has passed since the previous frame.</param> | ||||||
|         public void Update(double dt) |         public void Update(double dt) | ||||||
|         { |         { | ||||||
|  |             trackingManager.UpdateTracking(); | ||||||
|             messageManager.ProcessDelayedMessages(dt); |             messageManager.ProcessDelayedMessages(dt); | ||||||
|             timeManager.Update(dt); |             timeManager.Update(dt); | ||||||
| 
 | 
 | ||||||
|  | @ -56,12 +57,10 @@ namespace Encompass | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             messageManager.ClearMessages(); |             messageManager.ClearMessages(); | ||||||
|             entityManager.DestroyMarkedEntities(); |             entityManager.DestroyMarkedEntities(enginesInOrder); | ||||||
| 
 | 
 | ||||||
|             componentManager.WriteComponents(); |  | ||||||
|             componentManager.RemoveMarkedComponents(); |             componentManager.RemoveMarkedComponents(); | ||||||
| 
 |             componentManager.WriteComponents(); | ||||||
|             componentUpdateManager.Clear(); |  | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         /// <summary> |         /// <summary> | ||||||
|  |  | ||||||
|  | @ -18,18 +18,19 @@ namespace Encompass | ||||||
|     /// </remarks> |     /// </remarks> | ||||||
|     public class WorldBuilder |     public class WorldBuilder | ||||||
|     { |     { | ||||||
|  |         private readonly int entityCapacity; | ||||||
|         private readonly List<Engine> engines = new List<Engine>(); |         private readonly List<Engine> engines = new List<Engine>(); | ||||||
|         private readonly DirectedGraph<Engine, Unit> engineGraph = GraphBuilder.DirectedGraph<Engine>(); |         private readonly DirectedGraph<Engine, Unit> engineGraph = GraphBuilder.DirectedGraph<Engine>(); | ||||||
|         private readonly ComponentStore startingComponentStoreForComponentManager = new ComponentStore(); |         private readonly ComponentStore startingExistingComponentStore; | ||||||
|         private readonly ComponentStore startingComponentStoreForComponentUpdateManager = new ComponentStore(); |         private readonly ComponentStore startingUpToDateComponentStore; | ||||||
| 
 | 
 | ||||||
|         private readonly ComponentManager componentManager; |         private readonly ComponentManager componentManager; | ||||||
|         private readonly EntityManager entityManager; |         private readonly EntityManager entityManager; | ||||||
|         private readonly MessageManager messageManager; |         private readonly MessageManager messageManager; | ||||||
|         private readonly ComponentUpdateManager componentUpdateManager; |  | ||||||
|         private readonly TimeManager timeManager; |         private readonly TimeManager timeManager; | ||||||
|         private readonly DrawLayerManager drawLayerManager; |         private readonly DrawLayerManager drawLayerManager; | ||||||
|         private readonly RenderManager renderManager; |         private readonly RenderManager renderManager; | ||||||
|  |         private readonly TrackingManager trackingManager; | ||||||
| 
 | 
 | ||||||
|         private readonly Dictionary<Type, HashSet<Engine>> typeToReaders = new Dictionary<Type, HashSet<Engine>>(); |         private readonly Dictionary<Type, HashSet<Engine>> typeToReaders = new Dictionary<Type, HashSet<Engine>>(); | ||||||
| 
 | 
 | ||||||
|  | @ -39,15 +40,21 @@ namespace Encompass | ||||||
| 
 | 
 | ||||||
|         private readonly HashSet<Type> messageTypes = new HashSet<Type>(); |         private readonly HashSet<Type> messageTypes = new HashSet<Type>(); | ||||||
| 
 | 
 | ||||||
|         public WorldBuilder() |         private readonly Dictionary<Type, int> typeToIndex = new Dictionary<Type, int>(); | ||||||
|  | 
 | ||||||
|  |         public WorldBuilder(int entityCapacity = 32768) | ||||||
|         { |         { | ||||||
|             drawLayerManager = new DrawLayerManager(); |             this.entityCapacity = entityCapacity; | ||||||
|  |             drawLayerManager = new DrawLayerManager(typeToIndex); | ||||||
|             timeManager = new TimeManager(); |             timeManager = new TimeManager(); | ||||||
|             componentUpdateManager = new ComponentUpdateManager(); |             trackingManager = new TrackingManager(); | ||||||
|             componentManager = new ComponentManager(drawLayerManager, componentUpdateManager); |             componentManager = new ComponentManager(drawLayerManager, typeToIndex); | ||||||
|             messageManager = new MessageManager(timeManager); |             messageManager = new MessageManager(timeManager); | ||||||
|             entityManager = new EntityManager(componentManager); |             entityManager = new EntityManager(componentManager, entityCapacity); | ||||||
|             renderManager = new RenderManager(drawLayerManager); |             renderManager = new RenderManager(entityManager, drawLayerManager); | ||||||
|  | 
 | ||||||
|  |             startingExistingComponentStore = new ComponentStore(typeToIndex); | ||||||
|  |             startingUpToDateComponentStore = new ComponentStore(typeToIndex); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         /// <summary> |         /// <summary> | ||||||
|  | @ -82,22 +89,25 @@ namespace Encompass | ||||||
|             RegisterComponentType<TComponent>(); |             RegisterComponentType<TComponent>(); | ||||||
|             componentTypesToRegister.Add(typeof(TComponent)); |             componentTypesToRegister.Add(typeof(TComponent)); | ||||||
| 
 | 
 | ||||||
|             startingComponentStoreForComponentManager.Set(entity, component); |             startingExistingComponentStore.Set(entity.ID, component); | ||||||
|             startingComponentStoreForComponentUpdateManager.Set(entity, component); |             startingUpToDateComponentStore.Set(entity.ID, component); | ||||||
| 
 | 
 | ||||||
|             if (component is IDrawableComponent drawableComponent) |             if (component is IDrawableComponent drawableComponent) | ||||||
|             { |             { | ||||||
|                 componentManager.RegisterDrawableComponent(entity, component, drawableComponent.Layer); |                 componentManager.RegisterDrawableComponent(entity.ID, component, drawableComponent.Layer); | ||||||
|                 drawLayerManager.RegisterOrderedDrawable<TComponent>(); |                 drawLayerManager.RegisterOrderedDrawable<TComponent>(); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         internal void RegisterComponentType<TComponent>() where TComponent : struct, IComponent |         internal void RegisterComponentType<TComponent>() where TComponent : struct, IComponent | ||||||
|         { |         { | ||||||
|  |             if (!typeToIndex.ContainsKey(typeof(TComponent))) | ||||||
|  |             { | ||||||
|  |                 typeToIndex.Add(typeof(TComponent), typeToIndex.Count); | ||||||
|                 componentManager.RegisterComponentType<TComponent>(); |                 componentManager.RegisterComponentType<TComponent>(); | ||||||
|             componentUpdateManager.RegisterComponentType<TComponent>(); |                 startingExistingComponentStore.RegisterComponentType<TComponent>(); | ||||||
|             startingComponentStoreForComponentManager.RegisterComponentType<TComponent>(); |                 startingUpToDateComponentStore.RegisterComponentType<TComponent>(); | ||||||
|             startingComponentStoreForComponentUpdateManager.RegisterComponentType<TComponent>(); |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         internal void RegisterMessageTypes(IEnumerable<Type> types) |         internal void RegisterMessageTypes(IEnumerable<Type> types) | ||||||
|  | @ -119,8 +129,8 @@ namespace Encompass | ||||||
|             engine.AssignEntityManager(entityManager); |             engine.AssignEntityManager(entityManager); | ||||||
|             engine.AssignComponentManager(componentManager); |             engine.AssignComponentManager(componentManager); | ||||||
|             engine.AssignMessageManager(messageManager); |             engine.AssignMessageManager(messageManager); | ||||||
|             engine.AssignComponentUpdateManager(componentUpdateManager); |  | ||||||
|             engine.AssignTimeManager(timeManager); |             engine.AssignTimeManager(timeManager); | ||||||
|  |             engine.AssignTrackingManager(trackingManager); | ||||||
| 
 | 
 | ||||||
|             engines.Add(engine); |             engines.Add(engine); | ||||||
|             engineGraph.AddNode(engine); |             engineGraph.AddNode(engine); | ||||||
|  | @ -130,9 +140,9 @@ namespace Encompass | ||||||
| 
 | 
 | ||||||
|             RegisterMessageTypes(engine.receiveTypes.Union(engine.sendTypes)); |             RegisterMessageTypes(engine.receiveTypes.Union(engine.sendTypes)); | ||||||
| 
 | 
 | ||||||
|             foreach (var writePendingType in engine.writePendingTypes.Intersect(engine.readPendingTypes)) |             foreach (var writeImmediateType in engine.writeImmediateTypes.Intersect(engine.readImmediateTypes)) | ||||||
|             { |             { | ||||||
|                 throw new EngineSelfCycleException("Engine {0} both writes and reads pending Component {1}", engine.GetType().Name, writePendingType.Name); |                 throw new EngineSelfCycleException("Engine {0} both writes and reads immediate Component {1}", engine.GetType().Name, writeImmediateType.Name); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             foreach (var messageType in messageReceiveTypes.Intersect(messageSendTypes)) |             foreach (var messageType in messageReceiveTypes.Intersect(messageSendTypes)) | ||||||
|  | @ -140,17 +150,26 @@ namespace Encompass | ||||||
|                 throw new EngineSelfCycleException("Engine {0} both receives and sends Message {1}", engine.GetType().Name, messageType.Name); |                 throw new EngineSelfCycleException("Engine {0} both receives and sends Message {1}", engine.GetType().Name, messageType.Name); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             if (messageSendTypes.Count > 0 || engine.writePendingTypes.Count > 0) |             if (messageSendTypes.Count > 0 || engine.writeImmediateTypes.Count > 0) | ||||||
|             { |             { | ||||||
|                 senders.Add(engine); |                 senders.Add(engine); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             foreach (var componentType in engine.readTypes.Union(engine.writeTypes).Union(engine.readPendingTypes)) |             foreach (var componentType in engine.queryWithTypes.Union(engine.queryWithoutTypes)) | ||||||
|  |             { | ||||||
|  |                 trackingManager.RegisterComponentTypeToEngine(componentType, engine); | ||||||
|  |                 if (engine.readImmediateTypes.Contains(componentType)) | ||||||
|  |                 { | ||||||
|  |                     trackingManager.RegisterImmediateComponentTypeToEngine(componentType, engine); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             foreach (var componentType in engine.readTypes.Union(engine.writeTypes).Union(engine.readImmediateTypes)) | ||||||
|             { |             { | ||||||
|                 AddComponentTypeToRegister(componentType); |                 AddComponentTypeToRegister(componentType); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             foreach (var receiveType in engine.receiveTypes.Union(engine.readPendingTypes)) |             foreach (var receiveType in engine.receiveTypes.Union(engine.readImmediateTypes)) | ||||||
|             { |             { | ||||||
|                 if (!typeToReaders.ContainsKey(receiveType)) |                 if (!typeToReaders.ContainsKey(receiveType)) | ||||||
|                 { |                 { | ||||||
|  | @ -160,9 +179,6 @@ namespace Encompass | ||||||
|                 typeToReaders[receiveType].Add(engine); |                 typeToReaders[receiveType].Add(engine); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             // System.Runtime.CompilerServices.RuntimeHelpers.PrepareMethod(typeof(TEngine).GetRuntimeMethod("Update", new Type[] { typeof(double) }).MethodHandle); |  | ||||||
|             // typeof(TEngine).GetMethod("Update", new Type[] { typeof(double) }).MethodHandle.GetFunctionPointer(); |  | ||||||
| 
 |  | ||||||
|             return engine; |             return engine; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | @ -206,7 +222,7 @@ namespace Encompass | ||||||
|         { |         { | ||||||
|             foreach (var senderEngine in senders) |             foreach (var senderEngine in senders) | ||||||
|             { |             { | ||||||
|                 foreach (var messageType in senderEngine.sendTypes.Union(senderEngine.writePendingTypes)) |                 foreach (var messageType in senderEngine.sendTypes.Union(senderEngine.writeImmediateTypes)) | ||||||
|                 { |                 { | ||||||
|                     if (typeToReaders.ContainsKey(messageType)) |                     if (typeToReaders.ContainsKey(messageType)) | ||||||
|                     { |                     { | ||||||
|  | @ -355,10 +371,6 @@ namespace Encompass | ||||||
|                 var method = typeof(WorldBuilder).GetMethod("RegisterComponentType", BindingFlags.NonPublic | BindingFlags.Instance); |                 var method = typeof(WorldBuilder).GetMethod("RegisterComponentType", BindingFlags.NonPublic | BindingFlags.Instance); | ||||||
|                 var generic = method.MakeGenericMethod(registeredComponentType); |                 var generic = method.MakeGenericMethod(registeredComponentType); | ||||||
|                 generic.Invoke(this, null); |                 generic.Invoke(this, null); | ||||||
| 
 |  | ||||||
|                 var emitterEngine = (Engine)Activator.CreateInstance(typeof(ComponentEmitter<>).MakeGenericType(registeredComponentType)); |  | ||||||
|                 AddEngine(emitterEngine); |  | ||||||
|                 engineOrder.Add(emitterEngine); |  | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             PreloadJIT(componentTypesToRegister, messageTypes); |             PreloadJIT(componentTypesToRegister, messageTypes); | ||||||
|  | @ -366,20 +378,23 @@ namespace Encompass | ||||||
|             foreach (var engine in engineGraph.TopologicalSort()) |             foreach (var engine in engineGraph.TopologicalSort()) | ||||||
|             { |             { | ||||||
|                 engineOrder.Add(engine); |                 engineOrder.Add(engine); | ||||||
|  |                 engine.BuildEntityQuery(); | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             var world = new World( |             var world = new World( | ||||||
|                 engineOrder, |                 engineOrder, | ||||||
|                 entityManager, |                 entityManager, | ||||||
|                 componentManager, |                 componentManager, | ||||||
|  |                 trackingManager, | ||||||
|                 messageManager, |                 messageManager, | ||||||
|                 componentUpdateManager, |  | ||||||
|                 timeManager, |                 timeManager, | ||||||
|                 renderManager |                 renderManager | ||||||
|             ); |             ); | ||||||
| 
 | 
 | ||||||
|             componentUpdateManager.SetStartingComponentStore(startingComponentStoreForComponentUpdateManager); |             componentManager.SetExistingComponentStore(startingExistingComponentStore); | ||||||
|             componentManager.SetComponentStore(startingComponentStoreForComponentManager); |             componentManager.SetUpToDateComponentStore(startingUpToDateComponentStore); | ||||||
|  | 
 | ||||||
|  |             trackingManager.InitializeTracking(entityManager.EntityIDs); | ||||||
| 
 | 
 | ||||||
|             return world; |             return world; | ||||||
|         } |         } | ||||||
|  | @ -394,24 +409,23 @@ namespace Encompass | ||||||
|         { |         { | ||||||
|             var dummyTimeManager = new TimeManager(); |             var dummyTimeManager = new TimeManager(); | ||||||
|             var dummyMessageManager = new MessageManager(dummyTimeManager); |             var dummyMessageManager = new MessageManager(dummyTimeManager); | ||||||
|             var dummyDrawLayerManager = new DrawLayerManager(); |             var dummyDrawLayerManager = new DrawLayerManager(typeToIndex); | ||||||
|             var dummyComponentUpdateManager = new ComponentUpdateManager(); |             var dummyTrackingManager = new TrackingManager(); | ||||||
|             var dummyComponentManager = new ComponentManager(dummyDrawLayerManager, dummyComponentUpdateManager); |             var dummyComponentManager = new ComponentManager(dummyDrawLayerManager, typeToIndex); | ||||||
|             var dummyEntityManager = new EntityManager(dummyComponentManager); |             var dummyEntityManager = new EntityManager(dummyComponentManager, entityCapacity); | ||||||
|             var dummyRenderManager = new RenderManager(dummyDrawLayerManager); |             var dummyRenderManager = new RenderManager(dummyEntityManager, dummyDrawLayerManager); | ||||||
| 
 | 
 | ||||||
|             var prepEngineOrder = new List<Engine>(); |             var prepEngineOrder = new List<Engine>(); | ||||||
| 
 | 
 | ||||||
|             var entity = dummyEntityManager.CreateEntity(); |             var uberEngine = new UberEngine(componentTypes, messageTypes); | ||||||
|             var uberEngine = new UberEngine(entity, componentTypes, messageTypes); |  | ||||||
| 
 | 
 | ||||||
|             uberEngine.AssignEntityManager(dummyEntityManager); |             uberEngine.AssignEntityManager(dummyEntityManager); | ||||||
|             uberEngine.AssignComponentManager(dummyComponentManager); |             uberEngine.AssignComponentManager(dummyComponentManager); | ||||||
|             uberEngine.AssignMessageManager(dummyMessageManager); |             uberEngine.AssignMessageManager(dummyMessageManager); | ||||||
|             uberEngine.AssignComponentUpdateManager(dummyComponentUpdateManager); |  | ||||||
|             uberEngine.AssignTimeManager(dummyTimeManager); |             uberEngine.AssignTimeManager(dummyTimeManager); | ||||||
|  |             uberEngine.AssignTrackingManager(dummyTrackingManager); | ||||||
| 
 | 
 | ||||||
|             var uberRenderer = new UberRenderer(entity, componentTypes); |             var uberRenderer = new UberRenderer(componentTypes); | ||||||
|             uberRenderer.AssignComponentManager(dummyComponentManager); |             uberRenderer.AssignComponentManager(dummyComponentManager); | ||||||
|             uberRenderer.AssignEntityManager(dummyEntityManager); |             uberRenderer.AssignEntityManager(dummyEntityManager); | ||||||
| 
 | 
 | ||||||
|  | @ -421,25 +435,12 @@ namespace Encompass | ||||||
|                 var componentManagerRegisterGenericMethod = componentManagerRegisterMethod.MakeGenericMethod(type); |                 var componentManagerRegisterGenericMethod = componentManagerRegisterMethod.MakeGenericMethod(type); | ||||||
|                 componentManagerRegisterGenericMethod.Invoke(dummyComponentManager, null); |                 componentManagerRegisterGenericMethod.Invoke(dummyComponentManager, null); | ||||||
| 
 | 
 | ||||||
|                 var componentUpdateManagerRegisterMethod = typeof(ComponentUpdateManager).GetMethod("RegisterComponentType"); |  | ||||||
|                 var componentUpdateManagerRegisterGenericMethod = componentUpdateManagerRegisterMethod.MakeGenericMethod(type); |  | ||||||
|                 componentUpdateManagerRegisterGenericMethod.Invoke(dummyComponentUpdateManager, null); |  | ||||||
| 
 |  | ||||||
|                 if (type.GetInterface("IDrawableComponent") != null) |                 if (type.GetInterface("IDrawableComponent") != null) | ||||||
|                 { |                 { | ||||||
|                     var drawLayerManagerRegisterMethod = typeof(DrawLayerManager).GetMethod("RegisterOrderedDrawable"); |                     var drawLayerManagerRegisterMethod = typeof(DrawLayerManager).GetMethod("RegisterOrderedDrawable"); | ||||||
|                     var drawLayerManagerRegisterGenericMethod = drawLayerManagerRegisterMethod.MakeGenericMethod(type); |                     var drawLayerManagerRegisterGenericMethod = drawLayerManagerRegisterMethod.MakeGenericMethod(type); | ||||||
|                     drawLayerManagerRegisterGenericMethod.Invoke(dummyDrawLayerManager, null); |                     drawLayerManagerRegisterGenericMethod.Invoke(dummyDrawLayerManager, null); | ||||||
|                 } |                 } | ||||||
| 
 |  | ||||||
|                 var emitterEngine = (Engine)Activator.CreateInstance(typeof(ComponentEmitter<>).MakeGenericType(type)); |  | ||||||
|                 emitterEngine.AssignEntityManager(dummyEntityManager); |  | ||||||
|                 emitterEngine.AssignComponentManager(dummyComponentManager); |  | ||||||
|                 emitterEngine.AssignMessageManager(dummyMessageManager); |  | ||||||
|                 emitterEngine.AssignComponentUpdateManager(dummyComponentUpdateManager); |  | ||||||
|                 emitterEngine.AssignTimeManager(dummyTimeManager); |  | ||||||
| 
 |  | ||||||
|                 prepEngineOrder.Add(emitterEngine); |  | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             prepEngineOrder.Add(uberEngine); |             prepEngineOrder.Add(uberEngine); | ||||||
|  | @ -448,22 +449,21 @@ namespace Encompass | ||||||
|                 prepEngineOrder, |                 prepEngineOrder, | ||||||
|                 dummyEntityManager, |                 dummyEntityManager, | ||||||
|                 dummyComponentManager, |                 dummyComponentManager, | ||||||
|  |                 dummyTrackingManager, | ||||||
|                 dummyMessageManager, |                 dummyMessageManager, | ||||||
|                 dummyComponentUpdateManager, |  | ||||||
|                 dummyTimeManager, |                 dummyTimeManager, | ||||||
|                 dummyRenderManager |                 dummyRenderManager | ||||||
|              ); |              ); | ||||||
| 
 | 
 | ||||||
|             uberEngine.Write(); |             uberEngine.Write(); | ||||||
|             dummyComponentManager.WriteComponents(); |             dummyComponentManager.WriteComponents(); | ||||||
|             dummyComponentUpdateManager.Clear(); |  | ||||||
| 
 | 
 | ||||||
|             dummyWorld.Update(1); |             dummyWorld.Update(1); | ||||||
| 
 | 
 | ||||||
|             uberEngine.Write(); |             uberEngine.Write(); | ||||||
|             dummyComponentManager.WriteComponents(); |             dummyComponentManager.WriteComponents(); | ||||||
|             dummyComponentUpdateManager.Clear(); |  | ||||||
| 
 | 
 | ||||||
|  |             uberRenderer.SetEntity(uberEngine.Entity); | ||||||
|             uberRenderer.Render(); |             uberRenderer.Render(); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -1,4 +1,4 @@ | ||||||
| <Project Sdk="Microsoft.NET.Sdk"> | <Project Sdk="Microsoft.NET.Sdk"> | ||||||
|   <PropertyGroup> |   <PropertyGroup> | ||||||
|     <TargetFramework>netstandard2.0</TargetFramework> |     <TargetFramework>netstandard2.0</TargetFramework> | ||||||
|     <RootNamespace>Encompass</RootNamespace> |     <RootNamespace>Encompass</RootNamespace> | ||||||
|  | @ -24,5 +24,7 @@ | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
|   <ItemGroup> |   <ItemGroup> | ||||||
|     <PackageReference Include="MoonTools.Core.Graph" Version="1.0.0" /> |     <PackageReference Include="MoonTools.Core.Graph" Version="1.0.0" /> | ||||||
|  |     <PackageReference Include="MoonTools.FastCollections" Version="1.0.0" /> | ||||||
|  |     <PackageReference Include="System.Collections.Immutable" Version="1.7.0" /> | ||||||
|   </ItemGroup> |   </ItemGroup> | ||||||
| </Project> | </Project> | ||||||
|  | @ -75,6 +75,7 @@ namespace Tests | ||||||
|             var world = worldBuilder.Build(); |             var world = worldBuilder.Build(); | ||||||
| 
 | 
 | ||||||
|             world.Update(0.01); |             world.Update(0.01); | ||||||
|  |             world.Update(0.01); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         [Test] |         [Test] | ||||||
|  | @ -97,7 +98,6 @@ namespace Tests | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         [Reads(typeof(MockComponent))] |         [Reads(typeof(MockComponent))] | ||||||
|         [WritesPending(typeof(MockComponent))] |  | ||||||
|         [Writes(typeof(MockComponent))] |         [Writes(typeof(MockComponent))] | ||||||
|         class OverwriteEngine : Engine |         class OverwriteEngine : Engine | ||||||
|         { |         { | ||||||
|  | @ -105,12 +105,11 @@ namespace Tests | ||||||
|             { |             { | ||||||
|                 foreach (var (mockComponent, entity) in ReadComponentsIncludingEntity<MockComponent>()) |                 foreach (var (mockComponent, entity) in ReadComponentsIncludingEntity<MockComponent>()) | ||||||
|                 { |                 { | ||||||
|                     SetComponent(entity, new MockComponent { myInt = 420 }); |                     SetComponent(entity, new MockComponent { myInt = mockComponent.myInt + 1 }); | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         [ReadsPending(typeof(MockComponent))] |  | ||||||
|         [Reads(typeof(MockComponent))] |         [Reads(typeof(MockComponent))] | ||||||
|         class ReadMockComponentEngine : Engine |         class ReadMockComponentEngine : Engine | ||||||
|         { |         { | ||||||
|  | @ -128,12 +127,20 @@ namespace Tests | ||||||
|             worldBuilder.AddEngine(new ReadMockComponentEngine()); |             worldBuilder.AddEngine(new ReadMockComponentEngine()); | ||||||
| 
 | 
 | ||||||
|             var entity = worldBuilder.CreateEntity(); |             var entity = worldBuilder.CreateEntity(); | ||||||
|             worldBuilder.SetComponent(entity, new MockComponent { }); |             worldBuilder.SetComponent(entity, new MockComponent { myInt = 420 }); | ||||||
| 
 | 
 | ||||||
|             var world = worldBuilder.Build(); |             var world = worldBuilder.Build(); | ||||||
|             world.Update(0.01); |             world.Update(0.01); | ||||||
| 
 | 
 | ||||||
|             Assert.That(gottenMockComponent.myInt, Is.EqualTo(420)); |             Assert.That(gottenMockComponent.myInt, Is.EqualTo(420)); | ||||||
|  | 
 | ||||||
|  |             world.Update(0.01); | ||||||
|  | 
 | ||||||
|  |             Assert.That(gottenMockComponent.myInt, Is.EqualTo(421)); | ||||||
|  | 
 | ||||||
|  |             world.Update(0.01); | ||||||
|  | 
 | ||||||
|  |             Assert.That(gottenMockComponent.myInt, Is.EqualTo(422)); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         [Reads(typeof(MockComponent))] |         [Reads(typeof(MockComponent))] | ||||||
|  | @ -193,7 +200,7 @@ namespace Tests | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         [WritesPending(typeof(MockComponent))] |         [WritesImmediate(typeof(MockComponent))] | ||||||
|         [Receives(typeof(AddMockComponentMessage))] |         [Receives(typeof(AddMockComponentMessage))] | ||||||
|         [Writes(typeof(MockComponent))] |         [Writes(typeof(MockComponent))] | ||||||
|         class AddMockComponentEngine : Engine |         class AddMockComponentEngine : Engine | ||||||
|  | @ -207,7 +214,7 @@ namespace Tests | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         [ReadsPending(typeof(MockComponent))] |         [ReadsImmediate(typeof(MockComponent))] | ||||||
|         class HasMockComponentEngine : Engine |         class HasMockComponentEngine : Engine | ||||||
|         { |         { | ||||||
|             private Entity entity; |             private Entity entity; | ||||||
|  | @ -258,6 +265,7 @@ namespace Tests | ||||||
| 
 | 
 | ||||||
|             var world = worldBuilder.Build(); |             var world = worldBuilder.Build(); | ||||||
| 
 | 
 | ||||||
|  |             world.Update(0.01); | ||||||
|             world.Update(0.01); |             world.Update(0.01); | ||||||
| 
 | 
 | ||||||
|             Assert.AreEqual(mockComponent, gottenMockComponent); |             Assert.AreEqual(mockComponent, gottenMockComponent); | ||||||
|  | @ -369,6 +377,7 @@ namespace Tests | ||||||
| 
 | 
 | ||||||
|         [Reads(typeof(MockComponent))] |         [Reads(typeof(MockComponent))] | ||||||
|         [Receives(typeof(RemoveComponentTestMessage))] |         [Receives(typeof(RemoveComponentTestMessage))] | ||||||
|  |         [Writes(typeof(MockComponent))] | ||||||
|         class RemoveComponentTestEngine : Engine |         class RemoveComponentTestEngine : Engine | ||||||
|         { |         { | ||||||
|             public override void Update(double dt) |             public override void Update(double dt) | ||||||
|  | @ -463,8 +472,8 @@ namespace Tests | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         [Receives(typeof(CheckHasMockComponentMessage))] |         [Receives(typeof(CheckHasMockComponentMessage))] | ||||||
|         [ReadsPending(typeof(MockComponent))] |         [ReadsImmediate(typeof(MockComponent))] | ||||||
|         class CheckHasPendingMockComponentEngine : Engine |         class CheckHasImmediateMockComponentEngine : Engine | ||||||
|         { |         { | ||||||
|             public override void Update(double dt) |             public override void Update(double dt) | ||||||
|             { |             { | ||||||
|  |  | ||||||
|  | @ -415,6 +415,88 @@ namespace Tests | ||||||
|             Assert.Throws<IllegalReadException>(() => world.Update(0.01f)); |             Assert.Throws<IllegalReadException>(() => world.Update(0.01f)); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         struct EntityMessage : IMessage, IHasEntity  | ||||||
|  |         {  | ||||||
|  |             public EntityMessage(Entity entity, int myInt) | ||||||
|  |             { | ||||||
|  |                 Entity = entity; | ||||||
|  |                 MyInt = myInt; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             public Entity Entity { get; } | ||||||
|  |             public int MyInt { get; } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         [Sends(typeof(EntityMessage), typeof(MockMessage))] | ||||||
|  |         class EntityMessageEmitterEngine : Engine | ||||||
|  |         { | ||||||
|  |             private Entity _entity; | ||||||
|  | 
 | ||||||
|  |             public EntityMessageEmitterEngine(Entity entity) | ||||||
|  |             { | ||||||
|  |                 _entity = entity; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             public override void Update(double dt) | ||||||
|  |             { | ||||||
|  |                 SendMessage(new EntityMessage(_entity, 2)); | ||||||
|  |                 SendMessage(new EntityMessage(_entity, 4)); | ||||||
|  |                 SendMessage(new EntityMessage(_entity, 5)); | ||||||
|  |                 SendMessage(new MockMessage()); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         static List<EntityMessage> entityMessageResults; | ||||||
|  | 
 | ||||||
|  |         [Receives(typeof(EntityMessage))] | ||||||
|  |         class EntityMessageReceiverEngine : Engine | ||||||
|  |         { | ||||||
|  |             private Entity _entity; | ||||||
|  | 
 | ||||||
|  |             public EntityMessageReceiverEngine(Entity entity) | ||||||
|  |             { | ||||||
|  |                 _entity = entity; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             public override void Update(double dt) | ||||||
|  |             { | ||||||
|  |                 entityMessageResults = ReadMessagesWithEntity<EntityMessage>(_entity).ToList(); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         [Test] | ||||||
|  |         public void MessagesWithEntity() | ||||||
|  |         { | ||||||
|  |             var worldBuilder = new WorldBuilder(); | ||||||
|  | 
 | ||||||
|  |             var entity = worldBuilder.CreateEntity(); | ||||||
|  |             worldBuilder.AddEngine(new EntityMessageEmitterEngine(entity)); | ||||||
|  |             worldBuilder.AddEngine(new EntityMessageReceiverEngine(entity)); | ||||||
|  | 
 | ||||||
|  |             var world = worldBuilder.Build(); | ||||||
|  | 
 | ||||||
|  |             world.Update(0.01); | ||||||
|  | 
 | ||||||
|  |             entityMessageResults.Should().HaveCount(3); | ||||||
|  |             entityMessageResults.Should().ContainEquivalentOf(new EntityMessage(entity, 2)); | ||||||
|  |             entityMessageResults.Should().ContainEquivalentOf(new EntityMessage(entity, 4)); | ||||||
|  |             entityMessageResults.Should().ContainEquivalentOf(new EntityMessage(entity, 5)); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         [Test] | ||||||
|  |         public void NoMessagesWithEntity() | ||||||
|  |         { | ||||||
|  |             var worldBuilder = new WorldBuilder(); | ||||||
|  | 
 | ||||||
|  |             var entity = worldBuilder.CreateEntity(); | ||||||
|  |             worldBuilder.AddEngine(new EntityMessageReceiverEngine(entity)); | ||||||
|  | 
 | ||||||
|  |             var world = worldBuilder.Build(); | ||||||
|  |             world.Update(0.01); | ||||||
|  | 
 | ||||||
|  |             entityMessageResults.Should().BeEmpty(); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|         class SomeComponentTestEngine : Engine |         class SomeComponentTestEngine : Engine | ||||||
|         { |         { | ||||||
|             public override void Update(double dt) |             public override void Update(double dt) | ||||||
|  | @ -593,7 +675,8 @@ namespace Tests | ||||||
|             Assert.That(results, Does.Not.Contain((mockComponent, entity))); |             Assert.That(results, Does.Not.Contain((mockComponent, entity))); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         [Reads(typeof(DestroyerComponent), typeof(MockComponent))] |         [Reads(typeof(DestroyerComponent))] | ||||||
|  |         [Writes(typeof(MockComponent))] | ||||||
|         class DestroyAndAddComponentEngine : Engine |         class DestroyAndAddComponentEngine : Engine | ||||||
|         { |         { | ||||||
|             public override void Update(double dt) |             public override void Update(double dt) | ||||||
|  | @ -624,7 +707,7 @@ namespace Tests | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         [Reads(typeof(MockComponent))] |         [Reads(typeof(MockComponent))] | ||||||
|         [WritesPending(typeof(MockComponent))] |         [WritesImmediate(typeof(MockComponent))] | ||||||
|         [Writes(typeof(MockComponent))] |         [Writes(typeof(MockComponent))] | ||||||
|         class AddAndRemoveMockComponentEngine : Engine |         class AddAndRemoveMockComponentEngine : Engine | ||||||
|         { |         { | ||||||
|  | @ -640,8 +723,8 @@ namespace Tests | ||||||
| 
 | 
 | ||||||
|         static Entity entityResult; |         static Entity entityResult; | ||||||
| 
 | 
 | ||||||
|         [ReadsPending(typeof(MockComponent))] |         [ReadsImmediate(typeof(MockComponent))] | ||||||
|         class GetEntityFromPendingReadComponents : Engine |         class GetEntityFromImmediateReadComponents : Engine | ||||||
|         { |         { | ||||||
|             public override void Update(double dt) |             public override void Update(double dt) | ||||||
|             { |             { | ||||||
|  | @ -650,11 +733,11 @@ namespace Tests | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         [Test] |         [Test] | ||||||
|         public void GetEntityFromPendingComponentID() |         public void GetEntityFromImmediateComponentID() | ||||||
|         { |         { | ||||||
|             var worldBuilder = new WorldBuilder(); |             var worldBuilder = new WorldBuilder(); | ||||||
|             worldBuilder.AddEngine(new AddAndRemoveMockComponentEngine()); |             worldBuilder.AddEngine(new AddAndRemoveMockComponentEngine()); | ||||||
|             worldBuilder.AddEngine(new GetEntityFromPendingReadComponents()); |             worldBuilder.AddEngine(new GetEntityFromImmediateReadComponents()); | ||||||
| 
 | 
 | ||||||
|             var entity = worldBuilder.CreateEntity(); |             var entity = worldBuilder.CreateEntity(); | ||||||
|             worldBuilder.SetComponent(entity, new MockComponent()); |             worldBuilder.SetComponent(entity, new MockComponent()); | ||||||
|  | @ -665,6 +748,7 @@ namespace Tests | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         [Reads(typeof(MockComponent))] |         [Reads(typeof(MockComponent))] | ||||||
|  |         [Writes(typeof(MockComponent))] | ||||||
|         class DelayedMessageEngine : Engine |         class DelayedMessageEngine : Engine | ||||||
|         { |         { | ||||||
|             public override void Update(double dt) |             public override void Update(double dt) | ||||||
|  | @ -711,6 +795,7 @@ namespace Tests | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         [Reads(typeof(MockComponent))] |         [Reads(typeof(MockComponent))] | ||||||
|  |         [Writes(typeof(MockComponent))] | ||||||
|         class DelayedMessageIgnoringTimeDilationEngine : Engine |         class DelayedMessageIgnoringTimeDilationEngine : Engine | ||||||
|         { |         { | ||||||
|             public override void Update(double dt) |             public override void Update(double dt) | ||||||
|  | @ -753,8 +838,8 @@ namespace Tests | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         [Receives(typeof(MockMessage))] |         [Receives(typeof(MockMessage))] | ||||||
|         [WritesPending(typeof(MockComponent))] |         [WritesImmediate(typeof(MockComponent))] | ||||||
|         [Writes(typeof(MockComponent))] |         [Writes(typeof(MockComponent), 1)] | ||||||
|         class ActivateComponentEngine : Engine |         class ActivateComponentEngine : Engine | ||||||
|         { |         { | ||||||
|             public override void Update(double dt) |             public override void Update(double dt) | ||||||
|  | @ -767,7 +852,8 @@ namespace Tests | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         [ReadsPending(typeof(MockComponent))] |         [ReadsImmediate(typeof(MockComponent))] | ||||||
|  |         [Writes(typeof(MockComponent), 0)] | ||||||
|         class RemoveComponentEngine : Engine |         class RemoveComponentEngine : Engine | ||||||
|         { |         { | ||||||
|             public override void Update(double dt) |             public override void Update(double dt) | ||||||
|  | @ -780,17 +866,20 @@ namespace Tests | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         [Test] |         [Test] | ||||||
|         public void EngineAddAndRemoveComponentSameFrame() |         public void EngineAddAndRemoveComponentSameFrameWithRemovePriority() | ||||||
|         { |         { | ||||||
|             var worldBuilder = new WorldBuilder(); |             var worldBuilder = new WorldBuilder(); | ||||||
|             worldBuilder.AddEngine(new ActivateComponentEngine()); |             worldBuilder.AddEngine(new ActivateComponentEngine()); | ||||||
|             worldBuilder.AddEngine(new RemoveComponentEngine()); |             worldBuilder.AddEngine(new RemoveComponentEngine()); | ||||||
|  |             worldBuilder.AddEngine(new ReadComponentsTestEngine()); | ||||||
| 
 | 
 | ||||||
|             worldBuilder.SendMessage(new MockMessage { }); |             worldBuilder.SendMessage(new MockMessage { }); | ||||||
| 
 | 
 | ||||||
|             var world = worldBuilder.Build(); |             var world = worldBuilder.Build(); | ||||||
| 
 | 
 | ||||||
|             Assert.DoesNotThrow(() => world.Update(0.01)); |             Assert.DoesNotThrow(() => world.Update(0.01)); | ||||||
|  |             world.Update(0.01); // update again for the read | ||||||
|  |             resultComponents.Should().BeEmpty(); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         struct DestroyComponentMessage : IMessage { public Entity entity; } |         struct DestroyComponentMessage : IMessage { public Entity entity; } | ||||||
|  | @ -826,7 +915,7 @@ namespace Tests | ||||||
|             worldBuilder.AddEngine(new ReadEntityByComponentTypeEngine()); |             worldBuilder.AddEngine(new ReadEntityByComponentTypeEngine()); | ||||||
| 
 | 
 | ||||||
|             var entity = worldBuilder.CreateEntity(); |             var entity = worldBuilder.CreateEntity(); | ||||||
|             worldBuilder.SetComponent(entity, new MockComponent { }); |             worldBuilder.SetComponent(entity, new MockComponent()); | ||||||
| 
 | 
 | ||||||
|             var world = worldBuilder.Build(); |             var world = worldBuilder.Build(); | ||||||
|             world.Update(0.01); |             world.Update(0.01); | ||||||
|  | @ -834,7 +923,69 @@ namespace Tests | ||||||
|             entity.Should().BeEquivalentTo(readEntity); |             entity.Should().BeEquivalentTo(readEntity); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         struct MockComponentB : IComponent | ||||||
|  |         { | ||||||
|  |             public MockComponentB(int value) | ||||||
|  |             { | ||||||
|  |                 this.value = value; | ||||||
|  |             } | ||||||
| 
 | 
 | ||||||
|  |             int value; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         static MockComponentB getComponentResult; | ||||||
|  | 
 | ||||||
|  |         [Reads(typeof(MockComponent), typeof(MockComponentB))] | ||||||
|  |         class GetComponentEngine : Engine | ||||||
|  |         { | ||||||
|  |             public override void Update(double dt) | ||||||
|  |             { | ||||||
|  |                 getComponentResult = GetComponent<MockComponentB>(ReadEntity<MockComponent>()); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         [Test] | ||||||
|  |         public void GetComponent() | ||||||
|  |         { | ||||||
|  |             var worldBuilder = new WorldBuilder(); | ||||||
|  | 
 | ||||||
|  |             var entity = worldBuilder.CreateEntity(); | ||||||
|  | 
 | ||||||
|  |             worldBuilder.SetComponent(entity, new MockComponent()); | ||||||
|  |             worldBuilder.SetComponent(entity, new MockComponentB(3)); | ||||||
|  |             worldBuilder.AddEngine(new GetComponentEngine()); | ||||||
|  | 
 | ||||||
|  |             var world = worldBuilder.Build(); | ||||||
|  | 
 | ||||||
|  |             world.Update(0.01); | ||||||
|  | 
 | ||||||
|  |             getComponentResult.Should().BeEquivalentTo(new MockComponentB(3)); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         [Reads(typeof(MockComponent), typeof(MockComponentB))] | ||||||
|  |         class GetComponentExceptionEngine : Engine | ||||||
|  |         { | ||||||
|  |             public override void Update(double dt) | ||||||
|  |             { | ||||||
|  |                 foreach (var entity in ReadEntities<MockComponent>()) | ||||||
|  |                 { | ||||||
|  |                     GetComponent<MockComponentB>(entity); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         [Test] | ||||||
|  |         public void GetComponentWhenComponentIsNotOnEntity() | ||||||
|  |         { | ||||||
|  |             var worldBuilder = new WorldBuilder(); | ||||||
|  |             worldBuilder.AddEngine(new GetComponentExceptionEngine()); | ||||||
|  | 
 | ||||||
|  |             var entity = worldBuilder.CreateEntity(); | ||||||
|  |             worldBuilder.SetComponent(entity, new MockComponent()); | ||||||
|  | 
 | ||||||
|  |             var world = worldBuilder.Build(); | ||||||
|  |             Assert.Throws<Encompass.Exceptions.NoComponentOfTypeOnEntityException>(() => world.Update(0.01)); | ||||||
|  |         } | ||||||
| 
 | 
 | ||||||
|         static Entity[] readEntities; |         static Entity[] readEntities; | ||||||
| 
 | 
 | ||||||
|  | @ -926,6 +1077,7 @@ namespace Tests | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         [Reads(typeof(MockComponent))] |         [Reads(typeof(MockComponent))] | ||||||
|  |         [Writes(typeof(MockComponent))] | ||||||
|         class RemoveComponentByTypeEngine : Engine |         class RemoveComponentByTypeEngine : Engine | ||||||
|         { |         { | ||||||
|             public override void Update(double dt) |             public override void Update(double dt) | ||||||
|  | @ -1087,5 +1239,536 @@ namespace Tests | ||||||
| 
 | 
 | ||||||
|             undilatedDeltaTime.Should().Be(0.5); |             undilatedDeltaTime.Should().Be(0.5); | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|  |         public class QueryTests | ||||||
|  |         { | ||||||
|  |             struct MockComponentB : IComponent { } | ||||||
|  |             struct MockComponentC : IComponent { } | ||||||
|  |             struct MockComponentD : IComponent { } | ||||||
|  | 
 | ||||||
|  |             [Reads(typeof(MockComponent), typeof(MockComponentB))] | ||||||
|  |             [Writes(typeof(MockComponentB))] | ||||||
|  |             [QueryWith(typeof(MockComponent), typeof(MockComponentB))] | ||||||
|  |             class EntityQueryWithComponentsEngine : Engine | ||||||
|  |             { | ||||||
|  |                 private List<Entity> entities; | ||||||
|  | 
 | ||||||
|  |                 public EntityQueryWithComponentsEngine(List<Entity> entities) | ||||||
|  |                 { | ||||||
|  |                     this.entities = entities; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 public override void Update(double dt) | ||||||
|  |                 { | ||||||
|  |                     entities.Clear(); | ||||||
|  |                     foreach (var entity in TrackedEntities) | ||||||
|  |                     { | ||||||
|  |                         entities.Add(entity); | ||||||
|  |                         RemoveComponent<MockComponentB>(entity); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             [Test] | ||||||
|  |             public void EntitiesWithComponents() | ||||||
|  |             { | ||||||
|  |                 var worldBuilder = new WorldBuilder(); | ||||||
|  | 
 | ||||||
|  |                 var entity = worldBuilder.CreateEntity(); | ||||||
|  |                 var entityB = worldBuilder.CreateEntity(); | ||||||
|  |                 var entityC = worldBuilder.CreateEntity(); | ||||||
|  | 
 | ||||||
|  |                 worldBuilder.SetComponent(entity, new MockComponent()); | ||||||
|  |                 worldBuilder.SetComponent(entity, new MockComponentB()); | ||||||
|  | 
 | ||||||
|  |                 worldBuilder.SetComponent(entityB, new MockComponent()); | ||||||
|  |                 worldBuilder.SetComponent(entityB, new MockComponentB()); | ||||||
|  | 
 | ||||||
|  |                 worldBuilder.SetComponent(entityC, new MockComponentB()); | ||||||
|  | 
 | ||||||
|  |                 var queriedEntities = new List<Entity>(); | ||||||
|  |                 worldBuilder.AddEngine(new EntityQueryWithComponentsEngine(queriedEntities)); | ||||||
|  | 
 | ||||||
|  |                 var world = worldBuilder.Build(); | ||||||
|  | 
 | ||||||
|  |                 world.Update(0.01); | ||||||
|  | 
 | ||||||
|  |                 queriedEntities.Should().BeEquivalentTo(new Entity[] { entity, entityB }); | ||||||
|  | 
 | ||||||
|  |                 world.Update(0.01); | ||||||
|  | 
 | ||||||
|  |                 queriedEntities.Should().BeEmpty(); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             [Reads(typeof(MockComponent))] | ||||||
|  |             [Writes(typeof(MockComponent))] | ||||||
|  |             [QueryWithout(typeof(MockComponent))] | ||||||
|  |             class EntityQueryWithoutComponentsEngine : Engine | ||||||
|  |             { | ||||||
|  |                 private List<Entity> entities; | ||||||
|  | 
 | ||||||
|  |                 public EntityQueryWithoutComponentsEngine(List<Entity> entities) | ||||||
|  |                 { | ||||||
|  |                     this.entities = entities; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 public override void Update(double dt) | ||||||
|  |                 { | ||||||
|  |                     entities.Clear(); | ||||||
|  |                     foreach (var entity in TrackedEntities) | ||||||
|  |                     { | ||||||
|  |                         entities.Add(entity); | ||||||
|  |                         SetComponent(entity, new MockComponent()); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             [Test] | ||||||
|  |             public void EntitiesWithoutComponents() | ||||||
|  |             { | ||||||
|  |                 var worldBuilder = new WorldBuilder(); | ||||||
|  | 
 | ||||||
|  |                 var entity = worldBuilder.CreateEntity(); | ||||||
|  |                 var entityB = worldBuilder.CreateEntity(); | ||||||
|  |                 var entityC = worldBuilder.CreateEntity(); | ||||||
|  | 
 | ||||||
|  |                 worldBuilder.SetComponent(entity, new MockComponent()); | ||||||
|  |                 worldBuilder.SetComponent(entity, new MockComponentB()); | ||||||
|  | 
 | ||||||
|  |                 worldBuilder.SetComponent(entityB, new MockComponent()); | ||||||
|  |                 worldBuilder.SetComponent(entityB, new MockComponentB()); | ||||||
|  | 
 | ||||||
|  |                 worldBuilder.SetComponent(entityC, new MockComponentB()); | ||||||
|  | 
 | ||||||
|  |                 var queriedEntities = new List<Entity>(); | ||||||
|  |                 worldBuilder.AddEngine(new EntityQueryWithoutComponentsEngine(queriedEntities)); | ||||||
|  | 
 | ||||||
|  |                 var world = worldBuilder.Build(); | ||||||
|  | 
 | ||||||
|  |                 world.Update(0.01); | ||||||
|  | 
 | ||||||
|  |                 queriedEntities.ToArray().Should().BeEquivalentTo(new Entity[] { entityC }); | ||||||
|  | 
 | ||||||
|  |                 world.Update(0.01); | ||||||
|  | 
 | ||||||
|  |                 queriedEntities.Should().BeEmpty(); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             [Reads(typeof(MockComponent), typeof(MockComponentB), typeof(MockComponentD))] | ||||||
|  |             [QueryWith(typeof(MockComponent), typeof(MockComponentB))] | ||||||
|  |             [QueryWithout(typeof(MockComponentD))] | ||||||
|  |             class EntityQueryWithandWithoutComponentsEngine : Engine | ||||||
|  |             { | ||||||
|  |                 private List<Entity> entities; | ||||||
|  | 
 | ||||||
|  |                 public EntityQueryWithandWithoutComponentsEngine(List<Entity> entities) | ||||||
|  |                 { | ||||||
|  |                     this.entities = entities; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 public override void Update(double dt) | ||||||
|  |                 { | ||||||
|  |                     entities.Clear(); | ||||||
|  | 
 | ||||||
|  |                     entities.AddRange(TrackedEntities); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             [Test] | ||||||
|  |             public void EntitiesWithAndWithoutComponents() | ||||||
|  |             { | ||||||
|  |                 var worldBuilder = new WorldBuilder(); | ||||||
|  | 
 | ||||||
|  |                 var entity = worldBuilder.CreateEntity(); | ||||||
|  |                 var entityB = worldBuilder.CreateEntity(); | ||||||
|  |                 var entityC = worldBuilder.CreateEntity(); | ||||||
|  |                 var entityD = worldBuilder.CreateEntity(); | ||||||
|  | 
 | ||||||
|  |                 worldBuilder.SetComponent(entity, new MockComponent()); | ||||||
|  |                 worldBuilder.SetComponent(entity, new MockComponentB()); | ||||||
|  |                 worldBuilder.SetComponent(entity, new MockComponentD()); | ||||||
|  | 
 | ||||||
|  |                 worldBuilder.SetComponent(entityB, new MockComponent()); | ||||||
|  | 
 | ||||||
|  |                 worldBuilder.SetComponent(entityC, new MockComponent()); | ||||||
|  |                 worldBuilder.SetComponent(entityC, new MockComponentB()); | ||||||
|  |                 worldBuilder.SetComponent(entityC, new MockComponentC()); | ||||||
|  |                 worldBuilder.SetComponent(entityC, new MockComponentD()); | ||||||
|  | 
 | ||||||
|  |                 worldBuilder.SetComponent(entityD, new MockComponent()); | ||||||
|  |                 worldBuilder.SetComponent(entityD, new MockComponentB()); | ||||||
|  |                 worldBuilder.SetComponent(entityD, new MockComponentC()); | ||||||
|  | 
 | ||||||
|  |                 var queriedEntities = new List<Entity>(); | ||||||
|  |                 worldBuilder.AddEngine(new EntityQueryWithandWithoutComponentsEngine(queriedEntities)); | ||||||
|  | 
 | ||||||
|  |                 var world = worldBuilder.Build(); | ||||||
|  | 
 | ||||||
|  |                 world.Update(0.01); | ||||||
|  | 
 | ||||||
|  |                 queriedEntities.ToArray().Should().BeEquivalentTo(new Entity[] { entityD }); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             [Reads(typeof(MockComponent))] | ||||||
|  |             [WritesImmediate(typeof(MockComponentB))] | ||||||
|  |             [Writes(typeof(MockComponentB), 0)] | ||||||
|  |             class AddImmediateComponentEngine : Engine | ||||||
|  |             { | ||||||
|  |                 public override void Update(double dt) | ||||||
|  |                 { | ||||||
|  |                     foreach (var entity in ReadEntities<MockComponent>()) | ||||||
|  |                     { | ||||||
|  |                         SetComponent(entity, new MockComponentB()); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             [ReadsImmediate(typeof(MockComponentB))] | ||||||
|  |             [QueryWith(typeof(MockComponentB))] | ||||||
|  |             class EntityQueryWithImmediateComponentsEngine : Engine | ||||||
|  |             { | ||||||
|  |                 private List<Entity> entities; | ||||||
|  | 
 | ||||||
|  |                 public EntityQueryWithImmediateComponentsEngine(List<Entity> entities) | ||||||
|  |                 { | ||||||
|  |                     this.entities = entities; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 public override void Update(double dt) | ||||||
|  |                 { | ||||||
|  |                     entities.Clear(); | ||||||
|  |                     entities.AddRange(TrackedEntities); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             [Test] | ||||||
|  |             public void EntitiesWithImmediateComponents() | ||||||
|  |             { | ||||||
|  |                 var worldBuilder = new WorldBuilder(); | ||||||
|  | 
 | ||||||
|  |                 var entity = worldBuilder.CreateEntity(); | ||||||
|  |                 var entityB = worldBuilder.CreateEntity(); | ||||||
|  | 
 | ||||||
|  |                 worldBuilder.SetComponent(entity, new MockComponent()); | ||||||
|  | 
 | ||||||
|  |                 var queriedEntities = new List<Entity>(); | ||||||
|  |                 worldBuilder.AddEngine(new AddImmediateComponentEngine()); | ||||||
|  |                 worldBuilder.AddEngine(new EntityQueryWithImmediateComponentsEngine(queriedEntities)); | ||||||
|  | 
 | ||||||
|  |                 var world = worldBuilder.Build(); | ||||||
|  | 
 | ||||||
|  |                 world.Update(0.01); | ||||||
|  | 
 | ||||||
|  |                 queriedEntities.ToArray().Should().BeEquivalentTo(new Entity[] { entity }); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             [ReadsImmediate(typeof(MockComponentB))] | ||||||
|  |             [QueryWithout(typeof(MockComponentB))] | ||||||
|  |             class EntityQueryWithoutImmediateComponentsEngine : Engine | ||||||
|  |             { | ||||||
|  |                 private List<Entity> entities; | ||||||
|  | 
 | ||||||
|  |                 public EntityQueryWithoutImmediateComponentsEngine(List<Entity> entities) | ||||||
|  |                 { | ||||||
|  |                     this.entities = entities; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 public override void Update(double dt) | ||||||
|  |                 { | ||||||
|  |                     entities.Clear(); | ||||||
|  |                     entities.AddRange(TrackedEntities); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             [Test] | ||||||
|  |             public void EntitiesWithoutImmediateComponents() | ||||||
|  |             { | ||||||
|  |                 var worldBuilder = new WorldBuilder(); | ||||||
|  | 
 | ||||||
|  |                 var entity = worldBuilder.CreateEntity(); | ||||||
|  |                 var entityB = worldBuilder.CreateEntity(); | ||||||
|  | 
 | ||||||
|  |                 worldBuilder.SetComponent(entity, new MockComponent()); | ||||||
|  | 
 | ||||||
|  |                 var queriedEntities = new List<Entity>(); | ||||||
|  |                 worldBuilder.AddEngine(new AddImmediateComponentEngine()); | ||||||
|  |                 worldBuilder.AddEngine(new EntityQueryWithoutImmediateComponentsEngine(queriedEntities)); | ||||||
|  | 
 | ||||||
|  |                 var world = worldBuilder.Build(); | ||||||
|  | 
 | ||||||
|  |                 world.Update(0.01); | ||||||
|  | 
 | ||||||
|  |                 queriedEntities.ToArray().Should().BeEquivalentTo(new Entity[] { entityB }); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             [Reads(typeof(MockComponentC), typeof(MockComponentD))] | ||||||
|  |             [WritesImmediate(typeof(MockComponent), typeof(MockComponentB))] | ||||||
|  |             [Writes(typeof(MockComponent), 0)] | ||||||
|  |             [Writes(typeof(MockComponentB), 0)] | ||||||
|  |             class ConditionallyAddImmediateComponentsEngine : Engine | ||||||
|  |             { | ||||||
|  |                 public override void Update(double dt) | ||||||
|  |                 { | ||||||
|  |                     foreach (var entity in ReadEntities<MockComponentC>()) | ||||||
|  |                     { | ||||||
|  |                         SetComponent(entity, new MockComponent()); | ||||||
|  |                     } | ||||||
|  | 
 | ||||||
|  |                     foreach (var entity in ReadEntities<MockComponentD>()) | ||||||
|  |                     { | ||||||
|  |                         SetComponent(entity, new MockComponent()); | ||||||
|  |                         SetComponent(entity, new MockComponentB()); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             [ReadsImmediate(typeof(MockComponent), typeof(MockComponentB))] | ||||||
|  |             [QueryWith(typeof(MockComponent))] | ||||||
|  |             [QueryWithout(typeof(MockComponentB))] | ||||||
|  |             class EntityQueryWithAndWithoutImmediateComponentsEngine : Engine | ||||||
|  |             { | ||||||
|  |                 private List<Entity> entities; | ||||||
|  | 
 | ||||||
|  |                 public EntityQueryWithAndWithoutImmediateComponentsEngine(List<Entity> entities) | ||||||
|  |                 { | ||||||
|  |                     this.entities = entities; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 public override void Update(double dt) | ||||||
|  |                 { | ||||||
|  |                     entities.Clear(); | ||||||
|  | 
 | ||||||
|  |                     entities.AddRange(TrackedEntities); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             [Test] | ||||||
|  |             public void EntitiesWithAndWithoutImmediateComponents() | ||||||
|  |             { | ||||||
|  |                 var worldBuilder = new WorldBuilder(); | ||||||
|  | 
 | ||||||
|  |                 var entity = worldBuilder.CreateEntity(); | ||||||
|  |                 var entityB = worldBuilder.CreateEntity(); | ||||||
|  |                 var entityC = worldBuilder.CreateEntity(); | ||||||
|  | 
 | ||||||
|  |                 worldBuilder.SetComponent(entityB, new MockComponentC()); | ||||||
|  |                 worldBuilder.SetComponent(entityC, new MockComponentD()); | ||||||
|  | 
 | ||||||
|  |                 var queriedEntities = new List<Entity>(); | ||||||
|  |                 worldBuilder.AddEngine(new ConditionallyAddImmediateComponentsEngine()); | ||||||
|  |                 worldBuilder.AddEngine(new EntityQueryWithAndWithoutImmediateComponentsEngine(queriedEntities)); | ||||||
|  | 
 | ||||||
|  |                 var world = worldBuilder.Build(); | ||||||
|  | 
 | ||||||
|  |                 world.Update(0.01); | ||||||
|  | 
 | ||||||
|  |                 queriedEntities.ToArray().Should().BeEquivalentTo(new Entity[] { entityB }); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             [Reads(typeof(MockComponentC))] | ||||||
|  |             [WritesImmediate(typeof(MockComponentB))] | ||||||
|  |             [Writes(typeof(MockComponentB), 0)] | ||||||
|  |             class ConditionallyAddImmediateComponentEngine : Engine | ||||||
|  |             { | ||||||
|  |                 public override void Update(double dt) | ||||||
|  |                 { | ||||||
|  |                     foreach (var entity in ReadEntities<MockComponentC>()) | ||||||
|  |                     { | ||||||
|  |                         SetComponent(entity, new MockComponentB()); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             [ReadsImmediate(typeof(MockComponentB))] | ||||||
|  |             [Reads(typeof(MockComponent))] | ||||||
|  |             [QueryWith(typeof(MockComponent), typeof(MockComponentB))] | ||||||
|  |             class EntityQueryWithImmediateAndNonImmediateComponents : Engine | ||||||
|  |             { | ||||||
|  |                 private List<Entity> entities; | ||||||
|  | 
 | ||||||
|  |                 public EntityQueryWithImmediateAndNonImmediateComponents(List<Entity> entities) | ||||||
|  |                 { | ||||||
|  |                     this.entities = entities; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 public override void Update(double dt) | ||||||
|  |                 { | ||||||
|  |                     entities.Clear(); | ||||||
|  |                     entities.AddRange(TrackedEntities); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             [Test] | ||||||
|  |             public void EntitiesWithImmediateAndNonImmediateComponents() | ||||||
|  |             { | ||||||
|  |                 var worldBuilder = new WorldBuilder(); | ||||||
|  | 
 | ||||||
|  |                 var entity = worldBuilder.CreateEntity(); | ||||||
|  |                 var entityB = worldBuilder.CreateEntity(); | ||||||
|  |                 var entityC = worldBuilder.CreateEntity(); | ||||||
|  | 
 | ||||||
|  |                 worldBuilder.SetComponent(entityB, new MockComponent()); | ||||||
|  |                 worldBuilder.SetComponent(entityB, new MockComponentC()); | ||||||
|  |                 worldBuilder.SetComponent(entityC, new MockComponentD()); | ||||||
|  | 
 | ||||||
|  |                 var queriedEntities = new List<Entity>(); | ||||||
|  |                 worldBuilder.AddEngine(new ConditionallyAddImmediateComponentEngine()); | ||||||
|  |                 worldBuilder.AddEngine(new EntityQueryWithImmediateAndNonImmediateComponents(queriedEntities)); | ||||||
|  | 
 | ||||||
|  |                 var world = worldBuilder.Build(); | ||||||
|  | 
 | ||||||
|  |                 world.Update(0.01); | ||||||
|  | 
 | ||||||
|  |                 queriedEntities.ToArray().Should().BeEquivalentTo(new Entity[] { entityB }); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             [ReadsImmediate(typeof(MockComponentB))] | ||||||
|  |             class ReadImmediateComponentsEngine : Engine | ||||||
|  |             { | ||||||
|  |                 private List<MockComponentB> _components; | ||||||
|  | 
 | ||||||
|  |                 public ReadImmediateComponentsEngine(List<MockComponentB> components) | ||||||
|  |                 { | ||||||
|  |                     _components = components; | ||||||
|  |                 } | ||||||
|  |                 public override void Update(double dt) | ||||||
|  |                 { | ||||||
|  |                     _components.AddRange(ReadComponents<MockComponentB>()); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             [Test] | ||||||
|  |             public void ReadImmediateComponents() | ||||||
|  |             { | ||||||
|  |                 var worldBuilder = new WorldBuilder(); | ||||||
|  | 
 | ||||||
|  |                 var _components = new List<MockComponentB>(); | ||||||
|  | 
 | ||||||
|  |                 var entity = worldBuilder.CreateEntity(); | ||||||
|  |                 worldBuilder.SetComponent(entity, new MockComponent()); | ||||||
|  | 
 | ||||||
|  |                 worldBuilder.AddEngine(new AddImmediateComponentEngine()); | ||||||
|  |                 worldBuilder.AddEngine(new ReadImmediateComponentsEngine(_components)); | ||||||
|  | 
 | ||||||
|  |                 var world = worldBuilder.Build(); | ||||||
|  |                 world.Update(0.01); | ||||||
|  | 
 | ||||||
|  |                 _components.Should().NotBeEmpty(); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             [ReadsImmediate(typeof(MockComponentB))] | ||||||
|  |             [Reads(typeof(MockComponent))] | ||||||
|  |             class HasAndGetImmediateComponentEngine : Engine | ||||||
|  |             { | ||||||
|  |                 private List<MockComponentB> _components; | ||||||
|  | 
 | ||||||
|  |                 public HasAndGetImmediateComponentEngine(List<MockComponentB> components) | ||||||
|  |                 { | ||||||
|  |                     _components = components; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 public override void Update(double dt) | ||||||
|  |                 { | ||||||
|  |                     foreach (var (component, entity) in ReadComponentsIncludingEntity<MockComponent>()) | ||||||
|  |                     { | ||||||
|  |                         if (HasComponent<MockComponentB>(entity)) | ||||||
|  |                         { | ||||||
|  |                             _components.Add(GetComponent<MockComponentB>(entity)); | ||||||
|  | 
 | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             [Test] | ||||||
|  |             public void HasAndGetImmediateComponent() | ||||||
|  |             { | ||||||
|  |                 var worldBuilder = new WorldBuilder(); | ||||||
|  | 
 | ||||||
|  |                 var _components = new List<MockComponentB>(); | ||||||
|  | 
 | ||||||
|  |                 var entity = worldBuilder.CreateEntity(); | ||||||
|  |                 worldBuilder.SetComponent(entity, new MockComponent()); | ||||||
|  | 
 | ||||||
|  |                 worldBuilder.AddEngine(new AddImmediateComponentEngine()); | ||||||
|  |                 worldBuilder.AddEngine(new HasAndGetImmediateComponentEngine(_components)); | ||||||
|  | 
 | ||||||
|  |                 var world = worldBuilder.Build(); | ||||||
|  |                 world.Update(0.01); | ||||||
|  | 
 | ||||||
|  |                 _components.Should().NotBeEmpty(); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             struct MockTimerComponent : IComponent | ||||||
|  |             { | ||||||
|  |                 public MockTimerComponent(double time) | ||||||
|  |                 { | ||||||
|  |                     Timer = time; | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 public double Timer { get; set; } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             [Reads(typeof(MockTimerComponent))] | ||||||
|  |             [Writes(typeof(MockTimerComponent))] | ||||||
|  |             class ReadWhileRemovingComponentsEngine : Engine | ||||||
|  |             { | ||||||
|  |                 public override void Update(double dt) | ||||||
|  |                 { | ||||||
|  |                     foreach (var (component, entity) in ReadComponentsIncludingEntity<MockTimerComponent>()) | ||||||
|  |                     { | ||||||
|  |                         var updatedComponent = component; | ||||||
|  |                         updatedComponent.Timer -= dt; | ||||||
|  | 
 | ||||||
|  |                         if (updatedComponent.Timer <= 0) | ||||||
|  |                         { | ||||||
|  |                             RemoveComponent<MockTimerComponent>(entity); | ||||||
|  | 
 | ||||||
|  |                         } | ||||||
|  |                         else | ||||||
|  |                         { | ||||||
|  |                             SetComponent<MockTimerComponent>(entity, updatedComponent); | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             [Test] | ||||||
|  |             public void ReadWhileRemovingComponents() | ||||||
|  |             { | ||||||
|  |                 var worldBuilder = new WorldBuilder(); | ||||||
|  | 
 | ||||||
|  |                 var entity = worldBuilder.CreateEntity(); | ||||||
|  |                 worldBuilder.SetComponent(entity, new MockTimerComponent(0.5)); | ||||||
|  | 
 | ||||||
|  |                 var entityB = worldBuilder.CreateEntity(); | ||||||
|  |                 worldBuilder.SetComponent(entityB, new MockTimerComponent(0.4)); | ||||||
|  | 
 | ||||||
|  |                 worldBuilder.AddEngine(new ReadWhileRemovingComponentsEngine()); | ||||||
|  | 
 | ||||||
|  |                 var world = worldBuilder.Build(); | ||||||
|  |                 Assert.DoesNotThrow(() => world.Update(0.2)); | ||||||
|  |                 Assert.DoesNotThrow(() => world.Update(0.25)); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             [Test] | ||||||
|  |             public void DestroyedEntitiesAreRemovedFromTracking() | ||||||
|  |             { | ||||||
|  |                 var worldBuilder = new WorldBuilder(); | ||||||
|  | 
 | ||||||
|  |                 var entity = worldBuilder.CreateEntity(); | ||||||
|  |                 worldBuilder.SetComponent(entity, new MockComponent()); | ||||||
|  | 
 | ||||||
|  |                 worldBuilder.AddEngine(new DestroyWithEngine()); | ||||||
|  |                 worldBuilder.AddEngine(new ReadEntitiesWithComponentTypeEngine()); | ||||||
|  | 
 | ||||||
|  |                 var world = worldBuilder.Build(); | ||||||
|  | 
 | ||||||
|  |                 world.Update(0.01); | ||||||
|  |                 world.Update(0.01); | ||||||
|  | 
 | ||||||
|  |                 readEntities.Should().BeEmpty(); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -2,6 +2,7 @@ using NUnit.Framework; | ||||||
| using FluentAssertions; | using FluentAssertions; | ||||||
| 
 | 
 | ||||||
| using Encompass; | using Encompass; | ||||||
|  | using Encompass.Exceptions; | ||||||
| 
 | 
 | ||||||
| namespace Tests | namespace Tests | ||||||
| { | { | ||||||
|  | @ -20,5 +21,18 @@ namespace Tests | ||||||
|             Assert.AreEqual(entity, entity); |             Assert.AreEqual(entity, entity); | ||||||
|             Assert.IsTrue(entity == copyEntity); |             Assert.IsTrue(entity == copyEntity); | ||||||
|         } |         } | ||||||
|  | 
 | ||||||
|  |         [Test] | ||||||
|  |         public void EntityOverflowException() | ||||||
|  |         { | ||||||
|  |             var worldBuilder = new WorldBuilder(16); | ||||||
|  | 
 | ||||||
|  |             for (var i = 0; i < 16; i++) | ||||||
|  |             { | ||||||
|  |                 worldBuilder.CreateEntity(); | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             Assert.Throws<EntityOverflowException>(() => worldBuilder.CreateEntity()); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | @ -19,7 +19,7 @@ namespace Tests | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         [WritesPending(typeof(TestComponent))] |         [WritesImmediate(typeof(TestComponent))] | ||||||
|         [Writes(typeof(TestComponent))] |         [Writes(typeof(TestComponent))] | ||||||
|         class TestSpawner : Spawner<SpawnMessageA> |         class TestSpawner : Spawner<SpawnMessageA> | ||||||
|         { |         { | ||||||
|  |  | ||||||
|  | @ -153,7 +153,7 @@ namespace Tests | ||||||
| 
 | 
 | ||||||
|             [Receives(typeof(SetMessage))] |             [Receives(typeof(SetMessage))] | ||||||
|             [Writes(typeof(AComponent), 0)] |             [Writes(typeof(AComponent), 0)] | ||||||
|             [WritesPending(typeof(AComponent))] |             [WritesImmediate(typeof(AComponent))] | ||||||
|             class AEngine : Engine |             class AEngine : Engine | ||||||
|             { |             { | ||||||
|                 public override void Update(double dt) |                 public override void Update(double dt) | ||||||
|  | @ -167,7 +167,7 @@ namespace Tests | ||||||
| 
 | 
 | ||||||
|             [Receives(typeof(SetMessage))] |             [Receives(typeof(SetMessage))] | ||||||
|             [Writes(typeof(AComponent), 1)] |             [Writes(typeof(AComponent), 1)] | ||||||
|             [WritesPending(typeof(AComponent))] |             [WritesImmediate(typeof(AComponent))] | ||||||
|             class BEngine : Engine |             class BEngine : Engine | ||||||
|             { |             { | ||||||
|                 public override void Update(double dt) |                 public override void Update(double dt) | ||||||
|  | @ -181,7 +181,7 @@ namespace Tests | ||||||
| 
 | 
 | ||||||
|             static AComponent resultComponent; |             static AComponent resultComponent; | ||||||
| 
 | 
 | ||||||
|             [ReadsPending(typeof(AComponent))] |             [ReadsImmediate(typeof(AComponent))] | ||||||
|             class ReadComponentEngine : Engine |             class ReadComponentEngine : Engine | ||||||
|             { |             { | ||||||
|                 public override void Update(double dt) |                 public override void Update(double dt) | ||||||
|  | @ -222,7 +222,7 @@ namespace Tests | ||||||
| 
 | 
 | ||||||
|             [Receives(typeof(SetMessage))] |             [Receives(typeof(SetMessage))] | ||||||
|             [Writes(typeof(AComponent))] |             [Writes(typeof(AComponent))] | ||||||
|             [WritesPending(typeof(AComponent))] |             [WritesImmediate(typeof(AComponent))] | ||||||
|             [Encompass.DefaultWritePriority(4)] |             [Encompass.DefaultWritePriority(4)] | ||||||
|             class AEngine : Engine |             class AEngine : Engine | ||||||
|             { |             { | ||||||
|  | @ -238,7 +238,7 @@ namespace Tests | ||||||
| 
 | 
 | ||||||
|             [Receives(typeof(SetMessage))] |             [Receives(typeof(SetMessage))] | ||||||
|             [Writes(typeof(AComponent), 3)] |             [Writes(typeof(AComponent), 3)] | ||||||
|             [WritesPending(typeof(AComponent))] |             [WritesImmediate(typeof(AComponent))] | ||||||
|             class BEngine : Engine |             class BEngine : Engine | ||||||
|             { |             { | ||||||
|                 public override void Update(double dt) |                 public override void Update(double dt) | ||||||
|  | @ -252,7 +252,7 @@ namespace Tests | ||||||
| 
 | 
 | ||||||
|             [Receives(typeof(SetMessage))] |             [Receives(typeof(SetMessage))] | ||||||
|             [Writes(typeof(AComponent), 2)] |             [Writes(typeof(AComponent), 2)] | ||||||
|             [WritesPending(typeof(AComponent))] |             [WritesImmediate(typeof(AComponent))] | ||||||
|             class CEngine : Engine |             class CEngine : Engine | ||||||
|             { |             { | ||||||
|                 public override void Update(double dt) |                 public override void Update(double dt) | ||||||
|  | @ -266,7 +266,7 @@ namespace Tests | ||||||
| 
 | 
 | ||||||
|             static AComponent resultComponent; |             static AComponent resultComponent; | ||||||
| 
 | 
 | ||||||
|             [ReadsPending(typeof(AComponent))] |             [ReadsImmediate(typeof(AComponent))] | ||||||
|             class ReadComponentEngine : Engine |             class ReadComponentEngine : Engine | ||||||
|             { |             { | ||||||
|                 public override void Update(double dt) |                 public override void Update(double dt) | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue