diff --git a/encompass-cs/Attributes/DefaultWritePriority.cs b/encompass-cs/Attributes/DefaultWritePriority.cs index cf0c065..65500c7 100644 --- a/encompass-cs/Attributes/DefaultWritePriority.cs +++ b/encompass-cs/Attributes/DefaultWritePriority.cs @@ -5,11 +5,11 @@ namespace Encompass [AttributeUsage(AttributeTargets.Class)] public class DefaultWritePriority : Attribute { - public int writePriority; + public int WritePriority { get; } public DefaultWritePriority(int writePriority) { - this.writePriority = writePriority; + WritePriority = writePriority; } } } diff --git a/encompass-cs/Attributes/QueryWith.cs b/encompass-cs/Attributes/QueryWith.cs index 3ae11a6..ac8797d 100644 --- a/encompass-cs/Attributes/QueryWith.cs +++ b/encompass-cs/Attributes/QueryWith.cs @@ -8,20 +8,13 @@ namespace Encompass [AttributeUsage(AttributeTargets.Class)] public class QueryWith : Attribute { - public readonly HashSet queryWithTypes = new HashSet(); + public readonly HashSet QueryWithTypes = new HashSet(); 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); + QueryWithTypes.Add(queryWithType); } } } diff --git a/encompass-cs/Attributes/QueryWithout.cs b/encompass-cs/Attributes/QueryWithout.cs index 77f1e9f..3332b45 100644 --- a/encompass-cs/Attributes/QueryWithout.cs +++ b/encompass-cs/Attributes/QueryWithout.cs @@ -8,20 +8,13 @@ namespace Encompass [AttributeUsage(AttributeTargets.Class)] public class QueryWithout : Attribute { - public readonly HashSet queryWithoutTypes = new HashSet(); + public readonly HashSet QueryWithoutTypes = new HashSet(); 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); + QueryWithoutTypes.Add(type); } } } diff --git a/encompass-cs/Attributes/Reads.cs b/encompass-cs/Attributes/Reads.cs index b35e81f..e508775 100644 --- a/encompass-cs/Attributes/Reads.cs +++ b/encompass-cs/Attributes/Reads.cs @@ -8,20 +8,13 @@ namespace Encompass [AttributeUsage(AttributeTargets.Class)] public class Reads : Attribute { - public readonly HashSet readTypes = new HashSet(); + public readonly HashSet ReadTypes = new HashSet(); public Reads(params Type[] readTypes) { foreach (var readType in readTypes) { - var isComponent = readType.GetInterfaces().Contains(typeof(IComponent)); - - if (!isComponent) - { - throw new IllegalReadTypeException("{0} must be a Component", readType.Name); - } - - this.readTypes.Add(readType); + ReadTypes.Add(readType); } } } diff --git a/encompass-cs/Attributes/ReadsImmediate.cs b/encompass-cs/Attributes/ReadsImmediate.cs index e47d4ba..d399ae4 100644 --- a/encompass-cs/Attributes/ReadsImmediate.cs +++ b/encompass-cs/Attributes/ReadsImmediate.cs @@ -1,27 +1,18 @@ using System; using System.Collections.Generic; -using System.Linq; -using Encompass.Exceptions; namespace Encompass { [AttributeUsage(AttributeTargets.Class)] public class ReadsImmediate : Attribute { - public readonly HashSet readImmediateTypes = new HashSet(); + public readonly HashSet ReadImmediateTypes = new HashSet(); 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); + ReadImmediateTypes.Add(readImmediateType); } } } diff --git a/encompass-cs/Attributes/Receives.cs b/encompass-cs/Attributes/Receives.cs index e8d0542..79d4b66 100644 --- a/encompass-cs/Attributes/Receives.cs +++ b/encompass-cs/Attributes/Receives.cs @@ -8,7 +8,7 @@ namespace Encompass [AttributeUsage(AttributeTargets.Class)] public class Receives : Attribute { - public readonly HashSet receiveTypes; + public readonly HashSet ReceiveTypes; public Receives(params Type[] receiveTypes) { @@ -21,7 +21,7 @@ namespace Encompass } } - this.receiveTypes = new HashSet(receiveTypes); + ReceiveTypes = new HashSet(receiveTypes); } } } diff --git a/encompass-cs/Attributes/Sends.cs b/encompass-cs/Attributes/Sends.cs index 7bb1a0e..8fbacd3 100644 --- a/encompass-cs/Attributes/Sends.cs +++ b/encompass-cs/Attributes/Sends.cs @@ -8,7 +8,7 @@ namespace Encompass [AttributeUsage(AttributeTargets.Class)] public class Sends : Attribute { - public readonly HashSet sendTypes; + public readonly HashSet SendTypes; public Sends(params Type[] sendTypes) { @@ -21,7 +21,7 @@ namespace Encompass } } - this.sendTypes = new HashSet(sendTypes); + this.SendTypes = new HashSet(sendTypes); } } } diff --git a/encompass-cs/Attributes/Writes.cs b/encompass-cs/Attributes/Writes.cs index ee73ded..0cc1250 100644 --- a/encompass-cs/Attributes/Writes.cs +++ b/encompass-cs/Attributes/Writes.cs @@ -8,33 +8,21 @@ namespace Encompass [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] public class Writes : Attribute { - public readonly HashSet writeTypes = new HashSet(); - public Dictionary priorities = new Dictionary(); + public readonly HashSet WriteTypes = new HashSet(); + public readonly Dictionary Priorities = new Dictionary(); public Writes(params Type[] writeTypes) { foreach (var writeType in writeTypes) { - var isComponent = writeType.GetInterfaces().Contains(typeof(IComponent)); - if (!isComponent) - { - throw new IllegalWriteTypeException("{0} must be a Component", writeType.Name); - } - - this.writeTypes.Add(writeType); + WriteTypes.Add(writeType); } } public Writes(Type writeType, int priority) { - var isComponent = writeType.GetInterfaces().Contains(typeof(IComponent)); - if (!isComponent) - { - throw new IllegalWriteTypeException("{0} must be a Component", writeType.Name); - } - - writeTypes.Add(writeType); - priorities.Add(writeType, priority); + WriteTypes.Add(writeType); + Priorities.Add(writeType, priority); } } } diff --git a/encompass-cs/Attributes/WritesImmediate.cs b/encompass-cs/Attributes/WritesImmediate.cs index 66a46a6..1011b55 100644 --- a/encompass-cs/Attributes/WritesImmediate.cs +++ b/encompass-cs/Attributes/WritesImmediate.cs @@ -1,26 +1,18 @@ using System; using System.Collections.Generic; -using System.Linq; -using Encompass.Exceptions; namespace Encompass { [AttributeUsage(AttributeTargets.Class)] public class WritesImmediate : Attribute { - public readonly HashSet writeImmediateTypes = new HashSet(); + public readonly HashSet WriteImmediateTypes = new HashSet(); 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); + WriteImmediateTypes.Add(writeImmediateType); } } } diff --git a/encompass-cs/Collections/ComponentBitSet.cs b/encompass-cs/Collections/ComponentBitSet.cs index 1d0c39d..2867686 100644 --- a/encompass-cs/Collections/ComponentBitSet.cs +++ b/encompass-cs/Collections/ComponentBitSet.cs @@ -6,49 +6,49 @@ namespace Encompass { internal class ComponentBitSet { - Dictionary entities = new Dictionary(); - Dictionary TypeToIndex { get; } + private readonly Dictionary _entities = new Dictionary(); + private readonly Dictionary _typeToIndex; public ComponentBitSet(Dictionary typeToIndex) { - TypeToIndex = typeToIndex; + _typeToIndex = typeToIndex; } public void Clear() { - entities.Clear(); + _entities.Clear(); } public void AddEntity(int entityID) { - entities.Add(entityID, BitSet512.Zero); + _entities.Add(entityID, BitSet512.Zero); } - public void Set(int entityID) where TComponent : struct, IComponent + public void Set(int entityID) where TComponent : struct { - if (!entities.ContainsKey(entityID)) { AddEntity(entityID); } - entities[entityID] = entities[entityID].Set(TypeToIndex[typeof(TComponent)]); + if (!_entities.ContainsKey(entityID)) { AddEntity(entityID); } + _entities[entityID] = _entities[entityID].Set(_typeToIndex[typeof(TComponent)]); } - public void RemoveComponent(int entityID) where TComponent : struct, IComponent + public void RemoveComponent(int entityID) where TComponent : struct { - if (entities.ContainsKey(entityID)) + if (_entities.ContainsKey(entityID)) { - entities[entityID] = entities[entityID].UnSet(TypeToIndex[typeof(TComponent)]); + _entities[entityID] = _entities[entityID].UnSet(_typeToIndex[typeof(TComponent)]); } } public void RemoveEntity(int entityID) { - if (entities.ContainsKey(entityID)) + if (_entities.ContainsKey(entityID)) { - entities.Remove(entityID); + _entities.Remove(entityID); } } public BitSet512 EntityBitArray(int entityID) { - return entities.ContainsKey(entityID) ? entities[entityID] : BitSet512.Zero; + return _entities.ContainsKey(entityID) ? _entities[entityID] : BitSet512.Zero; } } } diff --git a/encompass-cs/Collections/ComponentDeltaStore.cs b/encompass-cs/Collections/ComponentDeltaStore.cs index 9b212d0..48d44c4 100644 --- a/encompass-cs/Collections/ComponentDeltaStore.cs +++ b/encompass-cs/Collections/ComponentDeltaStore.cs @@ -3,39 +3,48 @@ using System.Collections.Generic; namespace Encompass { - internal class ComponentDeltaStore : ComponentStore + internal class ComponentDeltaStore { + private readonly ComponentStore _store; private readonly Dictionary _replayers = new Dictionary(); private readonly HashSet _currentReplayers = new HashSet(); public IEnumerable CurrentReplayers { get { return _currentReplayers; } } - public ComponentDeltaStore(Dictionary typeToIndex) : base(typeToIndex) + public ComponentDeltaStore(Dictionary typeToIndex) { + _store = new ComponentStore(typeToIndex); } - public override void RegisterComponentType() + public void RegisterComponentType() where TComponent : struct { - base.RegisterComponentType(); + _store.RegisterComponentType(); if (!_replayers.ContainsKey(typeof(TComponent))) { _replayers.Add(typeof(TComponent), new Replayer(this)); } } - public override void Set(int entityID, TComponent component) + public ref readonly TComponent GetComponent(int entityID) where TComponent : struct { - base.Set(entityID, component); + return ref _store.Get(entityID); + } + + public void Set(int entityID, in TComponent component) where TComponent : struct + { + _store.Set(entityID, component); + RegisterComponentType(); var replayer = _replayers[typeof(TComponent)]; _currentReplayers.Add(replayer); replayer.UnMarkRemoval(entityID); } - public override bool Set(int entityID, TComponent component, int priority) + public bool Set(int entityID, TComponent component, int priority) where TComponent : struct { - var result = base.Set(entityID, component, priority); + var result = _store.Set(entityID, component, priority); if (result) { + RegisterComponentType(); var replayer = _replayers[typeof(TComponent)]; _currentReplayers.Add(replayer); replayer.UnMarkRemoval(entityID); @@ -43,11 +52,12 @@ namespace Encompass return result; } - public override bool Remove(int entityID, int priority) + public bool Remove(int entityID, int priority) where TComponent : struct { - var result = base.Remove(entityID, priority); + var result = _store.Remove(entityID, priority); if (result) { + RegisterComponentType(); var replayer = _replayers[typeof(TComponent)]; _currentReplayers.Add(replayer); replayer.MarkRemoval(entityID); @@ -55,18 +65,23 @@ namespace Encompass return result; } - public override void Remove(int entityID) + public void Remove(int entityID) { - base.Remove(entityID); + _store.Remove(entityID); foreach (var replayer in CurrentReplayers) { replayer.MarkRemoval(entityID); } } - public override void ClearAll() + public Span AllEntities() where TComponent : struct { - base.ClearAll(); + return _store.AllEntities(); + } + + public void ClearAll() + { + _store.ClearAll(); foreach (var replayer in _currentReplayers) { replayer.Clear(); diff --git a/encompass-cs/Collections/ComponentStore.cs b/encompass-cs/Collections/ComponentStore.cs index aee17e8..3f35b4b 100644 --- a/encompass-cs/Collections/ComponentStore.cs +++ b/encompass-cs/Collections/ComponentStore.cs @@ -4,46 +4,42 @@ using System.Collections.Generic; namespace Encompass { - internal class ComponentStore + internal sealed class ComponentStore { - private Dictionary Stores = new Dictionary(512); + private Dictionary _stores = new Dictionary(512); public ComponentBitSet ComponentBitSet { get; private set; } + private readonly Dictionary _typeToIndex; public ComponentStore(Dictionary typeToIndex) { + _typeToIndex = typeToIndex; ComponentBitSet = new ComponentBitSet(typeToIndex); } - public IEnumerable<(Type, TypedComponentStore)> StoresEnumerable() + public void RegisterComponentType() where TComponent : struct { - foreach (var entry in Stores) - { - yield return (entry.Key, entry.Value); - } - } - - public virtual void RegisterComponentType() where TComponent : struct, IComponent - { - if (!Stores.ContainsKey(typeof(TComponent))) + if (!_stores.ContainsKey(typeof(TComponent))) { var store = new TypedComponentStore(); - Stores.Add(typeof(TComponent), store); + _stores.Add(typeof(TComponent), store); } + + if (!_typeToIndex.ContainsKey(typeof(TComponent))) { _typeToIndex.Add(typeof(TComponent), _typeToIndex.Count); } } - private TypedComponentStore Lookup() where TComponent : struct, IComponent + private TypedComponentStore Lookup() where TComponent : struct { - return Stores[typeof(TComponent)] as TypedComponentStore; + return _stores[typeof(TComponent)] as TypedComponentStore; } - public bool Has(int entityID) where TComponent : struct, IComponent + public bool Has(int entityID) where TComponent : struct { return Lookup().Has(entityID); } public bool Has(Type type, int entityID) { - return Stores.ContainsKey(type) && Stores[type].Has(entityID); + return _stores[type].Has(entityID); } public BitSet512 EntityBitArray(int entityID) @@ -51,18 +47,28 @@ namespace Encompass return ComponentBitSet.EntityBitArray(entityID); } - public TComponent Get(int entityID) where TComponent : struct, IComponent + public ref TComponent Get(int entityID) where TComponent : struct { - return Lookup().Get(entityID); + return ref Lookup().Get(entityID); } - public virtual void Set(int entityID, TComponent component) where TComponent : struct, IComponent + public ref readonly TComponent Singular() where TComponent : struct + { + return ref Lookup().Singular(); + } + + public ref readonly Entity SingularEntity() where TComponent : struct + { + return ref Lookup().SingularEntity(); + } + + public void Set(int entityID, in TComponent component) where TComponent : struct { Lookup().Set(entityID, component); ComponentBitSet.Set(entityID); } - public virtual bool Set(int entityID, TComponent component, int priority) where TComponent : struct, IComponent + public bool Set(int entityID, in TComponent component, int priority) where TComponent : struct { if (Lookup().Set(entityID, component, priority)) { @@ -72,7 +78,7 @@ namespace Encompass return false; } - public virtual bool Remove(int entityID, int priority) where TComponent : struct, IComponent + public bool Remove(int entityID, int priority) where TComponent : struct { if (Lookup().Remove(entityID, priority)) { @@ -82,59 +88,53 @@ namespace Encompass return false; } - public void ForceRemove(int entityID) where TComponent : struct, IComponent + public void ForceRemove(int entityID) where TComponent : struct { Lookup().ForceRemove(entityID); ComponentBitSet.RemoveComponent(entityID); } - public virtual void Remove(int entityID) + public void Remove(int entityID) { - foreach (var entry in Stores.Values) + foreach (var entry in _stores.Values) { entry.ForceRemove(entityID); } ComponentBitSet.RemoveEntity(entityID); } - public bool Any() where TComponent : struct, IComponent + public bool Any() where TComponent : struct { return Lookup().Count > 0; } - public IEnumerable<(int, Type, IComponent)> AllInterfaceTyped() + public Span All() where TComponent : struct { - foreach (var store in Stores.Values) - { - foreach (var thing in store.AllInterfaceTyped()) - { - yield return thing; - } - } + return Lookup().AllComponents(); } - public IEnumerable<(TComponent, int)> All() where TComponent : struct, IComponent + public Span AllEntities() where TComponent : struct { - return Lookup().All(); + return Lookup().AllEntities(); } - public void Clear() where TComponent : struct, IComponent + public void Clear() where TComponent : struct { Lookup().Clear(); } - public virtual void ClearAllPriorities() + public void ClearAllPriorities() { - foreach (var store in Stores.Values) + foreach (var store in _stores.Values) { store.ClearPriorities(); } } - public virtual void ClearAll() + public void ClearAll() { ComponentBitSet.Clear(); - foreach (var store in Stores.Values) + foreach (var store in _stores.Values) { store.Clear(); } @@ -142,7 +142,7 @@ namespace Encompass public void SwapWith(ComponentStore other) { - (Stores, other.Stores) = (other.Stores, Stores); + (_stores, other._stores) = (other._stores, _stores); (ComponentBitSet, other.ComponentBitSet) = (other.ComponentBitSet, ComponentBitSet); } diff --git a/encompass-cs/Collections/MessageStore.cs b/encompass-cs/Collections/MessageStore.cs index 5e7186f..8495966 100644 --- a/encompass-cs/Collections/MessageStore.cs +++ b/encompass-cs/Collections/MessageStore.cs @@ -5,40 +5,40 @@ namespace Encompass { internal class MessageStore { - private Dictionary Stores = new Dictionary(512); + private readonly Dictionary _stores = new Dictionary(512); private void RegisterMessageType() where TMessage : struct, IMessage { - Stores.Add(typeof(TMessage), new TypedMessageStore()); + _stores.Add(typeof(TMessage), new TypedMessageStore()); } private TypedMessageStore Lookup() where TMessage : struct, IMessage { - if (!Stores.ContainsKey(typeof(TMessage))) { RegisterMessageType(); } - return Stores[typeof(TMessage)] as TypedMessageStore; + if (!_stores.ContainsKey(typeof(TMessage))) { RegisterMessageType(); } + return _stores[typeof(TMessage)] as TypedMessageStore; } - public void AddMessage(TMessage message) where TMessage : struct, IMessage + public void AddMessage(in TMessage message) where TMessage : struct, IMessage { Lookup().Add(message); } - public void AddMessage(TMessage message, double time) where TMessage : struct, IMessage + public void AddMessage(in TMessage message, double time) where TMessage : struct, IMessage { Lookup().Add(message, time); } - public void AddMessageIgnoringTimeDilation(TMessage message, double time) where TMessage : struct, IMessage + public void AddMessageIgnoringTimeDilation(in TMessage message, double time) where TMessage : struct, IMessage { Lookup().AddIgnoringTimeDilation(message, time); } - public TMessage First() where TMessage : struct, IMessage + public ref readonly TMessage First() where TMessage : struct, IMessage { - return Lookup().First(); + return ref Lookup().First(); } - public IEnumerable All() where TMessage : struct, IMessage + public Span All() where TMessage : struct, IMessage { return Lookup().All(); } @@ -53,6 +53,11 @@ namespace Encompass return Lookup().WithEntity(entityID); } + public ref readonly TMessage FirstWithEntity(int entityID) where TMessage : struct, IMessage + { + return ref Lookup().FirstWithEntity(entityID); + } + public bool SomeWithEntity(int entityID) where TMessage : struct, IMessage, IHasEntity { return Lookup().SomeWithEntity(entityID); @@ -60,7 +65,7 @@ namespace Encompass public void ProcessDelayedMessages(double dilatedDelta, double realtimeDelta) { - foreach (var store in Stores.Values) + foreach (var store in _stores.Values) { store.ProcessDelayedMessages(dilatedDelta, realtimeDelta); } @@ -68,7 +73,7 @@ namespace Encompass public void ClearAll() { - foreach (var store in Stores.Values) + foreach (var store in _stores.Values) { store.Clear(); } diff --git a/encompass-cs/Collections/Replayer.cs b/encompass-cs/Collections/Replayer.cs index b5cd3f7..f90018a 100644 --- a/encompass-cs/Collections/Replayer.cs +++ b/encompass-cs/Collections/Replayer.cs @@ -2,7 +2,7 @@ namespace Encompass { - internal abstract class Replayer + internal abstract class Replayer { public abstract void Replay(ComponentStore store); public abstract void MarkRemoval(int entityID); @@ -10,7 +10,7 @@ namespace Encompass public abstract void Clear(); } - internal class Replayer : Replayer where TComponent : struct, IComponent + internal class Replayer : Replayer where TComponent : struct { private readonly ComponentDeltaStore _deltaStore; private readonly HashSet _removals = new HashSet(); @@ -22,9 +22,10 @@ namespace Encompass public override void Replay(ComponentStore store) { - foreach (var (component, entityID) in _deltaStore.All()) + foreach (ref readonly var entity in _deltaStore.AllEntities()) { - store.Set(entityID, component); + ref readonly var component = ref _deltaStore.GetComponent(entity.ID); + store.Set(entity.ID, component); } foreach (var entityID in _removals) diff --git a/encompass-cs/Collections/TypedComponentStore.cs b/encompass-cs/Collections/TypedComponentStore.cs index 78a8f20..232fa2b 100644 --- a/encompass-cs/Collections/TypedComponentStore.cs +++ b/encompass-cs/Collections/TypedComponentStore.cs @@ -1,12 +1,12 @@ using System; using System.Collections.Generic; +using System.Runtime.CompilerServices; namespace Encompass { internal abstract class TypedComponentStore { public abstract int Count { get; } - public abstract IEnumerable<(int, Type, IComponent)> AllInterfaceTyped(); public abstract bool Has(int entity); public abstract bool Remove(int entity, int priority); public abstract void ForceRemove(int entity); @@ -14,43 +14,72 @@ namespace Encompass public abstract void ClearPriorities(); } - internal class TypedComponentStore : TypedComponentStore where TComponent : struct, IComponent + internal class TypedComponentStore : TypedComponentStore where TComponent : struct { - private readonly Dictionary store = new Dictionary(128); - private readonly Dictionary priorities = new Dictionary(128); + private int _nextID = 0; + private readonly Dictionary _entityIDToStorageIndex = new Dictionary(128); + private readonly Dictionary _priorities = new Dictionary(128); + private Entity[] _storageIndexToEntities = new Entity[128]; + private TComponent[] _components = new TComponent[128]; - public override int Count { get => store.Count; } + public override int Count { get => _entityIDToStorageIndex.Count; } - public TComponent Get(int entityID) + public ref TComponent Get(int entityID) { - 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]; + if (!_entityIDToStorageIndex.ContainsKey(entityID)) { throw new Exceptions.NoComponentOfTypeOnEntityException("No component of type {0} exists on Entity with ID {1}", typeof(TComponent), entityID); } + return ref _components[_entityIDToStorageIndex[entityID]]; } - public void Set(int entityID, TComponent component) + public ref TComponent Singular() { - store[entityID] = component; + return ref _components[0]; } - public bool Set(int entityID, TComponent component, int priority) + public ref Entity SingularEntity() { - if (!priorities.ContainsKey(entityID) || priority < priorities[entityID]) + return ref _storageIndexToEntities[0]; + } + + public void Set(int entityID, in TComponent component) + { + InternalSet(entityID, component); + } + + public bool Set(int entityID, in TComponent component, int priority) + { + if (!_priorities.ContainsKey(entityID) || priority <= _priorities[entityID]) // if priorities are equal that means it's the same engine { - store[entityID] = component; - priorities[entityID] = priority; + InternalSet(entityID, component); + _priorities[entityID] = priority; return true; } return false; } + private void InternalSet(int entityID, in TComponent component) + { + if (!_entityIDToStorageIndex.ContainsKey(entityID)) + { + var index = _nextID++; + if (index >= _components.Length) + { + System.Array.Resize(ref _components, _components.Length * 2); + System.Array.Resize(ref _storageIndexToEntities, _storageIndexToEntities.Length * 2); + } + _entityIDToStorageIndex[entityID] = index; + _storageIndexToEntities[index] = new Entity(entityID); + } + + _components[_entityIDToStorageIndex[entityID]] = component; + } + public override bool Remove(int entityID, int priority) { - if (!priorities.ContainsKey(entityID) || priority < priorities[entityID]) + if (!_priorities.ContainsKey(entityID) || priority <= _priorities[entityID]) // if priorities are equal that means it's the same engine { - priorities[entityID] = priority; - store.Remove(entityID); - priorities.Remove(entityID); + _priorities[entityID] = priority; + ForceRemove(entityID); return true; } @@ -59,40 +88,53 @@ namespace Encompass public override void ForceRemove(int entityID) { - store.Remove(entityID); - priorities.Remove(entityID); + if (_entityIDToStorageIndex.ContainsKey(entityID)) + { + var storageIndex = _entityIDToStorageIndex[entityID]; + _entityIDToStorageIndex.Remove(entityID); + _priorities.Remove(entityID); + + // move a component into the hole to maintain contiguous memory + if (_nextID > 1 && storageIndex != _nextID - 1) + { + var lastStorageIndex = _nextID - 1; + ref readonly var lastEntity = ref _storageIndexToEntities[lastStorageIndex]; + + _entityIDToStorageIndex[lastEntity.ID] = storageIndex; + _storageIndexToEntities[storageIndex] = lastEntity; + _components[storageIndex] = _components[lastStorageIndex]; + + } + + _nextID--; + } } public override bool Has(int entityID) { - return store.ContainsKey(entityID); + return _entityIDToStorageIndex.ContainsKey(entityID); } public override void Clear() { - store.Clear(); - priorities.Clear(); + _nextID = 0; + _entityIDToStorageIndex.Clear(); + _priorities.Clear(); } public override void ClearPriorities() { - priorities.Clear(); + _priorities.Clear(); } - public IEnumerable<(TComponent, int)> All() + public Span AllEntities() { - foreach (var kvp in store) - { - yield return (kvp.Value, kvp.Key); - } + return new Span(_storageIndexToEntities, 0, _nextID); } - public override IEnumerable<(int, Type, IComponent)> AllInterfaceTyped() + public Span AllComponents() { - foreach (var kvp in store) - { - yield return (kvp.Key, typeof(TComponent), (IComponent)kvp.Value); - } + return new Span(_components, 0, _nextID); } } } diff --git a/encompass-cs/Collections/TypedMessageStore.cs b/encompass-cs/Collections/TypedMessageStore.cs index bfa7a8b..c8a263e 100644 --- a/encompass-cs/Collections/TypedMessageStore.cs +++ b/encompass-cs/Collections/TypedMessageStore.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; namespace Encompass @@ -10,98 +11,117 @@ namespace Encompass internal class TypedMessageStore : TypedMessageStore where TMessage : struct, IMessage { - private readonly List store = new List(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 Dictionary> entityToMessage = new Dictionary>(); + // messages are placed in a contiguous region + // so we can return the collection as a Span + private int _nextIndex = 0; + private TMessage[] _store = new TMessage[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 Dictionary> _entityToIndices = new Dictionary>(); public override void ProcessDelayedMessages(double dilatedDelta, double realtimeDelta) { - for (int i = delayedStore.Count - 1; i >= 0; i--) + for (var i = _delayedStore.Count - 1; i >= 0; i--) { - var (message, time) = delayedStore[i]; + var (message, time) = _delayedStore[i]; var updatedTime = time - dilatedDelta; if (updatedTime <= 0) { Add(message); - delayedStore.RemoveAt(i); + _delayedStore.RemoveAt(i); } else { - delayedStore[i] = (message, updatedTime); + _delayedStore[i] = (message, updatedTime); } } - for (int i = delayedStoreIgnoringTimeDilation.Count - 1; i >= 0; i--) + for (var i = _delayedStoreIgnoringTimeDilation.Count - 1; i >= 0; i--) { - var (message, time) = delayedStoreIgnoringTimeDilation[i]; + var (message, time) = _delayedStoreIgnoringTimeDilation[i]; var updatedTime = time - realtimeDelta; if (updatedTime <= 0) { Add(message); - delayedStoreIgnoringTimeDilation.RemoveAt(i); + _delayedStoreIgnoringTimeDilation.RemoveAt(i); } else { - delayedStoreIgnoringTimeDilation[i] = (message, updatedTime); + _delayedStoreIgnoringTimeDilation[i] = (message, updatedTime); } } } - public void Add(TMessage message) + public void Add(in TMessage message) { - store.Add(message); + var index = _nextIndex++; + if (index >= _store.Length) + { + Array.Resize(ref _store, _store.Length * 2); + } + _store[index] = message; if (message is IHasEntity entityMessage) { var entityID = entityMessage.Entity.ID; - if (!entityToMessage.ContainsKey(entityID)) { entityToMessage.Add(entityID, new List()); } - entityToMessage[entityID].Add(message); + if (!_entityToIndices.ContainsKey(entityID)) { _entityToIndices.Add(entityID, new List()); } + _entityToIndices[entityID].Add(index); } } - public void Add(TMessage message, double time) + public void Add(in TMessage message, double time) { - delayedStore.Add((message, time)); + _delayedStore.Add((message, time)); } - public void AddIgnoringTimeDilation(TMessage message, double time) + public void AddIgnoringTimeDilation(in TMessage message, double time) { - delayedStoreIgnoringTimeDilation.Add((message, time)); + _delayedStoreIgnoringTimeDilation.Add((message, time)); } - public TMessage First() + public ref readonly TMessage First() { - return store[0]; + return ref _store[0]; } public bool Any() { - return store.Count > 0; + return _nextIndex != 0; } - public IEnumerable All() + public Span All() { - return store; + return new Span(_store, 0, _nextIndex); } public IEnumerable WithEntity(int entityID) { - return entityToMessage.ContainsKey(entityID) ? entityToMessage[entityID] : System.Linq.Enumerable.Empty(); + if (_entityToIndices.ContainsKey(entityID)) + { + foreach (var index in _entityToIndices[entityID]) + { + yield return _store[index]; + } + } + } + + public ref readonly TMessage FirstWithEntity(int entityID) + { + return ref _store[_entityToIndices[entityID][0]]; } public bool SomeWithEntity(int entityID) { - return entityToMessage.ContainsKey(entityID) && entityToMessage[entityID].Count > 0; + return _entityToIndices.ContainsKey(entityID) && _entityToIndices[entityID].Count > 0; } public override void Clear() { - store.Clear(); - foreach (var set in entityToMessage.Values) + _nextIndex = 0; + foreach (var set in _entityToIndices.Values) { set.Clear(); } diff --git a/encompass-cs/ComponentManager.cs b/encompass-cs/ComponentManager.cs index 046704e..49fe78d 100644 --- a/encompass-cs/ComponentManager.cs +++ b/encompass-cs/ComponentManager.cs @@ -1,272 +1,289 @@ using System; using System.Collections.Generic; -using MoonTools.FastCollections; namespace Encompass { internal class ComponentManager { - private readonly DrawLayerManager drawLayerManager; + private readonly DrawLayerManager _drawLayerManager; - private readonly ComponentStore existingComponentStore; - private readonly ComponentStore immediateComponentStore; - private readonly ComponentDeltaStore replayStore; - private ComponentStore upToDateComponentStore; + private readonly ComponentStore _existingComponentStore; + private readonly ComponentStore _immediateComponentStore; + private readonly ComponentDeltaStore _replayStore; + private readonly ComponentStore _upToDateComponentStore; public Dictionary TypeToIndex { get; } - private readonly HashSet entitiesMarkedForRemoval = new HashSet(); + private readonly HashSet _entitiesMarkedForRemoval = new HashSet(); - internal ComponentBitSet ImmediateBits { get { return immediateComponentStore.ComponentBitSet; } } - internal ComponentBitSet ExistingBits { get { return existingComponentStore.ComponentBitSet; } } + internal ComponentBitSet ImmediateBits { get { return _immediateComponentStore.ComponentBitSet; } } + internal ComponentBitSet ExistingBits { get { return _existingComponentStore.ComponentBitSet; } } public ComponentManager(DrawLayerManager drawLayerManager, Dictionary typeToIndex) { - this.drawLayerManager = drawLayerManager; - existingComponentStore = new ComponentStore(typeToIndex); - immediateComponentStore = new ComponentStore(typeToIndex); - replayStore = new ComponentDeltaStore(typeToIndex); - upToDateComponentStore = new ComponentStore(typeToIndex); + this._drawLayerManager = drawLayerManager; + _existingComponentStore = new ComponentStore(typeToIndex); + _immediateComponentStore = new ComponentStore(typeToIndex); + _replayStore = new ComponentDeltaStore(typeToIndex); + _upToDateComponentStore = new ComponentStore(typeToIndex); TypeToIndex = typeToIndex; } - public void RegisterComponentType() where TComponent : struct, IComponent + public void RegisterComponentType() where TComponent : struct { - existingComponentStore.RegisterComponentType(); - immediateComponentStore.RegisterComponentType(); - replayStore.RegisterComponentType(); - upToDateComponentStore.RegisterComponentType(); + _existingComponentStore.RegisterComponentType(); + _immediateComponentStore.RegisterComponentType(); + _replayStore.RegisterComponentType(); + _upToDateComponentStore.RegisterComponentType(); } internal void SetExistingComponentStore(ComponentStore componentStore) { - existingComponentStore.SwapWith(componentStore); + _existingComponentStore.SwapWith(componentStore); } internal void SetUpToDateComponentStore(ComponentStore componentStore) { - upToDateComponentStore.SwapWith(componentStore); + _upToDateComponentStore.SwapWith(componentStore); } - internal void RegisterDrawableComponent(int entityID, TComponent component, int layer) where TComponent : struct, IComponent + internal void RegisterDrawableComponent(int entityID, int layer) where TComponent : struct { - drawLayerManager.RegisterComponentWithLayer(entityID, component, layer); + _drawLayerManager.RegisterComponentWithLayer(entityID, layer); } internal void WriteComponents() { - existingComponentStore.UpdateUsing(replayStore); - existingComponentStore.ClearAllPriorities(); - upToDateComponentStore.ClearAllPriorities(); - immediateComponentStore.ClearAll(); - replayStore.ClearAll(); + _existingComponentStore.UpdateUsing(_replayStore); + _existingComponentStore.ClearAllPriorities(); + _upToDateComponentStore.ClearAllPriorities(); + _immediateComponentStore.ClearAll(); + _replayStore.ClearAll(); } - internal bool AddImmediateComponent(int entityID, TComponent component, int priority) where TComponent : struct, IComponent + internal bool AddImmediateComponent(int entityID, in TComponent component, int priority) where TComponent : struct { - if (immediateComponentStore.Set(entityID, component, priority)) + if (_immediateComponentStore.Set(entityID, component, priority)) { - replayStore.Set(entityID, component); - upToDateComponentStore.Set(entityID, component); + _replayStore.Set(entityID, component); + _upToDateComponentStore.Set(entityID, component); return true; } return false; } - internal void AddImmediateComponent(int entityID, TComponent component) where TComponent : struct, IComponent + internal void AddImmediateComponent(int entityID, in TComponent component) where TComponent : struct { - immediateComponentStore.Set(entityID, component); - replayStore.Set(entityID, component); - upToDateComponentStore.Set(entityID, component); + _immediateComponentStore.Set(entityID, component); + _replayStore.Set(entityID, component); + _upToDateComponentStore.Set(entityID, component); } - internal bool UpdateComponent(int entityID, TComponent component, int priority) where TComponent : struct, IComponent + internal bool UpdateComponent(int entityID, in TComponent component, int priority) where TComponent : struct { - var result = upToDateComponentStore.Set(entityID, component, priority); + var result = _upToDateComponentStore.Set(entityID, component, priority); if (result) { - replayStore.Set(entityID, component); + _replayStore.Set(entityID, component); } return result; } - internal void AddComponent(int entityID, TComponent component) where TComponent : struct, IComponent + internal void AddComponent(int entityID, in TComponent component) where TComponent : struct { - upToDateComponentStore.Set(entityID, component); - replayStore.Set(entityID, component); + _upToDateComponentStore.Set(entityID, component); + _replayStore.Set(entityID, component); } // existing or immediate reads - internal IEnumerable<(TComponent, int)> ReadExistingAndImmediateComponentsByType() where TComponent : struct, IComponent + internal Span ReadExistingAndImmediateComponentsByType() where TComponent : struct { - return upToDateComponentStore.All(); + return _upToDateComponentStore.All(); } - internal (TComponent, int) ReadFirstExistingOrImmediateComponentByType() where TComponent : struct, IComponent + internal ref readonly TComponent ExistingOrImmediateSingular() where TComponent : struct { - if (!SomeExistingOrImmediateComponent()) { throw new Exceptions.NoComponentOfTypeException($"No Component with type {typeof(TComponent)} exists"); } - var enumerator = ReadExistingAndImmediateComponentsByType().GetEnumerator(); - enumerator.MoveNext(); - return enumerator.Current; + return ref _upToDateComponentStore.Singular(); } - internal bool SomeExistingOrImmediateComponent() where TComponent : struct, IComponent + internal Span GetExistingAndImmediateEntities() where TComponent : struct { - return upToDateComponentStore.Any(); + return _upToDateComponentStore.AllEntities(); + } + + internal ref readonly Entity ExistingOrImmediateSingularEntity() where TComponent : struct + { + return ref _upToDateComponentStore.SingularEntity(); + } + + internal bool SomeExistingOrImmediateComponent() where TComponent : struct + { + return _upToDateComponentStore.Any(); } // existing reads - internal (TComponent, int) ReadFirstExistingComponentByType() where TComponent : struct, IComponent + internal Span GetExistingComponents() where TComponent : struct { - if (!SomeExistingComponent()) { throw new Exceptions.NoComponentOfTypeException($"No Component with type {typeof(TComponent)} exists"); } - var enumerator = GetComponentsIncludingEntity().GetEnumerator(); - enumerator.MoveNext(); - return enumerator.Current; + return _existingComponentStore.All(); } - internal bool SomeExistingComponent() where TComponent : struct, IComponent + internal ref readonly TComponent ExistingSingular() where TComponent : struct { - return existingComponentStore.Any(); + return ref _existingComponentStore.Singular(); + } + + internal Span GetExistingEntities() where TComponent : struct + { + return _existingComponentStore.AllEntities(); + } + + internal ref readonly Entity ExistingSingularEntity() where TComponent : struct + { + return ref _existingComponentStore.SingularEntity(); + } + + internal bool SomeExistingComponent() where TComponent : struct + { + return _existingComponentStore.Any(); } // immediate reads - internal IEnumerable<(TComponent, int)> ReadImmediateComponentsByType() where TComponent : struct, IComponent + internal Span ReadImmediateComponentsByType() where TComponent : struct { - return immediateComponentStore.All(); + return _immediateComponentStore.All(); } - internal (TComponent, int) ReadFirstImmediateComponentByType() where TComponent : struct, IComponent + internal ref readonly TComponent ImmediateSingular() where TComponent : struct { - if (!SomeImmediateComponent()) { throw new Exceptions.NoComponentOfTypeException($"No Component with type {typeof(TComponent)} exists"); } - var enumerator = ReadImmediateComponentsByType().GetEnumerator(); - enumerator.MoveNext(); - return enumerator.Current; + return ref _immediateComponentStore.Singular(); } - internal bool SomeImmediateComponent() where TComponent : struct, IComponent + internal Span GetImmediateEntities() where TComponent : struct { - return immediateComponentStore.Any(); + return _immediateComponentStore.AllEntities(); + } + + internal ref readonly Entity ImmediateSingularEntity() where TComponent : struct + { + return ref _immediateComponentStore.SingularEntity(); + } + + internal bool SomeImmediateComponent() where TComponent : struct + { + return _immediateComponentStore.Any(); } // component getters - internal TComponent ReadImmediateOrExistingComponentByEntityAndType(int entityID) where TComponent : struct, IComponent + internal ref TComponent ReadImmediateOrExistingComponentByEntityAndType(int entityID) where TComponent : struct { - return upToDateComponentStore.Get(entityID); + return ref _upToDateComponentStore.Get(entityID); } - internal TComponent ReadExistingComponentByEntityAndType(int entityID) where TComponent : struct, IComponent + internal ref TComponent ReadExistingComponentByEntityAndType(int entityID) where TComponent : struct { - return existingComponentStore.Get(entityID); + return ref _existingComponentStore.Get(entityID); } - internal TComponent ReadImmediateComponentByEntityAndType(int entityID) where TComponent : struct, IComponent + internal ref TComponent ReadImmediateComponentByEntityAndType(int entityID) where TComponent : struct { - return immediateComponentStore.Get(entityID); + return ref _immediateComponentStore.Get(entityID); } // has checkers - internal bool HasExistingOrImmediateComponent(int entityID) where TComponent : struct, IComponent + internal bool HasExistingOrImmediateComponent(int entityID) where TComponent : struct { - return upToDateComponentStore.Has(entityID); + return _upToDateComponentStore.Has(entityID); } internal bool HasExistingOrImmediateComponent(int entityID, Type type) { - return upToDateComponentStore.Has(type, entityID); + return _upToDateComponentStore.Has(type, entityID); } - internal bool HasExistingComponent(int entityID) where TComponent : struct, IComponent + internal bool HasExistingComponent(int entityID) where TComponent : struct { - return existingComponentStore.Has(entityID); + return _existingComponentStore.Has(entityID); } internal bool HasExistingComponent(int entityID, Type type) { - return existingComponentStore.Has(type, entityID); + return _existingComponentStore.Has(type, entityID); } - internal bool HasImmediateComponent(int entityID) where TComponent : struct, IComponent + internal bool HasImmediateComponent(int entityID) where TComponent : struct { - return immediateComponentStore.Has(entityID); + return _immediateComponentStore.Has(entityID); } internal bool HasImmediateComponent(int entityID, Type type) { - return immediateComponentStore.Has(type, entityID); + return _immediateComponentStore.Has(type, entityID); } - internal IEnumerable<(TComponent, int)> GetComponentsIncludingEntity() where TComponent : struct, IComponent + internal Span GetComponentsByType() where TComponent : struct { - return existingComponentStore.All(); + return _existingComponentStore.All(); } - internal IEnumerable GetComponentsByType() where TComponent : struct, IComponent + internal ref readonly TComponent GetComponentByEntityAndType(int entityID) where TComponent : struct { - foreach (var pair in existingComponentStore.All()) - { - yield return pair.Item1; - } + return ref _existingComponentStore.Get(entityID); } - internal TComponent GetComponentByEntityAndType(int entityID) where TComponent : struct, IComponent + internal bool EntityHasComponentOfType(int entityID) where TComponent : struct { - return existingComponentStore.Get(entityID); - } - - internal bool EntityHasComponentOfType(int entityID) where TComponent : struct, IComponent - { - return existingComponentStore.Has(entityID); + return _existingComponentStore.Has(entityID); } internal void MarkAllComponentsOnEntityForRemoval(int entityID) { - entitiesMarkedForRemoval.Add(entityID); + _entitiesMarkedForRemoval.Add(entityID); } internal void RemoveMarkedComponents() { - foreach (var entityID in entitiesMarkedForRemoval) + foreach (var entityID in _entitiesMarkedForRemoval) { - existingComponentStore.Remove(entityID); - immediateComponentStore.Remove(entityID); - replayStore.Remove(entityID); - upToDateComponentStore.Remove(entityID); - drawLayerManager.UnRegisterEntityWithLayer(entityID); + _existingComponentStore.Remove(entityID); + _immediateComponentStore.Remove(entityID); + _replayStore.Remove(entityID); + _upToDateComponentStore.Remove(entityID); + _drawLayerManager.UnRegisterEntityWithLayer(entityID); } - entitiesMarkedForRemoval.Clear(); + _entitiesMarkedForRemoval.Clear(); } - public bool RemoveImmediate(int entityID, int priority) where TComponent : struct, IComponent + public bool RemoveImmediate(int entityID, int priority) where TComponent : struct { - if (immediateComponentStore.Remove(entityID, priority)) + if (_immediateComponentStore.Remove(entityID, priority)) { - replayStore.Remove(entityID, priority); - upToDateComponentStore.Remove(entityID, priority); - drawLayerManager.UnRegisterComponentWithLayer(entityID); + _replayStore.Remove(entityID, priority); + _upToDateComponentStore.Remove(entityID, priority); + _drawLayerManager.UnRegisterComponentWithLayer(entityID); return true; } return false; } - public void Remove(int entityID, int priority) where TComponent : struct, IComponent + public void Remove(int entityID, int priority) where TComponent : struct { - if (upToDateComponentStore.Remove(entityID, priority)) + if (_upToDateComponentStore.Remove(entityID, priority)) { - replayStore.Remove(entityID, priority); - drawLayerManager.UnRegisterComponentWithLayer(entityID); + _replayStore.Remove(entityID, priority); + _drawLayerManager.UnRegisterComponentWithLayer(entityID); } } public bool UpToDateEntityIsEmpty(int entityID) { - return upToDateComponentStore.EntityBitArray(entityID).AllFalse(); + return _upToDateComponentStore.EntityBitArray(entityID).AllFalse(); } } } diff --git a/encompass-cs/DrawLayerManager.cs b/encompass-cs/DrawLayerManager.cs index b738fce..e500371 100644 --- a/encompass-cs/DrawLayerManager.cs +++ b/encompass-cs/DrawLayerManager.cs @@ -7,112 +7,126 @@ namespace Encompass { internal class DrawLayerManager { - private readonly SortedList layerOrder = new SortedList(); + private readonly SortedList _layerOrder = new SortedList(); - private readonly Dictionary layerIndexToComponentStore = new Dictionary(512); - private readonly Dictionary> layerIndexToGeneralRenderers = new Dictionary>(512); + private readonly Dictionary>> _layerIndexToTypeToID = new Dictionary>>(); + private readonly Dictionary> _layerIndexToGeneralRenderers = new Dictionary>(512); - private readonly Dictionary> typeToEntityToLayer = new Dictionary>(512); - private Dictionary typeToIndex; - public IEnumerable LayerOrder { get { return layerOrder.Values; } } + private readonly Dictionary> _typeToEntityToLayer = new Dictionary>(512); + public IEnumerable LayerOrder { get { return _layerOrder.Values; } } - public DrawLayerManager(Dictionary typeToIndex) + public DrawLayerManager() { - this.typeToIndex = typeToIndex; RegisterDrawLayer(0); } public void RegisterDrawLayer(int layer) { - if (!layerIndexToComponentStore.ContainsKey(layer)) + if (!_layerIndexToTypeToID.ContainsKey(layer)) { - layerOrder.Add(layer, layer); - layerIndexToGeneralRenderers.Add(layer, new HashSet()); - layerIndexToComponentStore.Add(layer, new ComponentStore(typeToIndex)); + _layerOrder.Add(layer, layer); + _layerIndexToGeneralRenderers.Add(layer, new HashSet()); + _layerIndexToTypeToID.Add(layer, new Dictionary>()); } } - public void RegisterOrderedDrawable() where TComponent : struct, IComponent + public void RegisterOrderedDrawable() where TComponent : struct { - if (!typeToEntityToLayer.ContainsKey(typeof(TComponent))) + if (!_typeToEntityToLayer.ContainsKey(typeof(TComponent))) { - typeToEntityToLayer.Add(typeof(TComponent), new Dictionary(128)); + _typeToEntityToLayer.Add(typeof(TComponent), new Dictionary(128)); } - foreach (var pair in layerIndexToComponentStore) + foreach (var pair in _layerIndexToTypeToID) { - pair.Value.RegisterComponentType(); + if (!pair.Value.ContainsKey(typeof(TComponent))) + { + pair.Value.Add(typeof(TComponent), new HashSet()); + } } } public void RegisterGeneralRendererWithLayer(GeneralRenderer renderer, int layer) { RegisterDrawLayer(layer); - var set = layerIndexToGeneralRenderers[layer]; + var set = _layerIndexToGeneralRenderers[layer]; set.Add(renderer); } - public void UnregisterGeneralRendererWithLayer(GeneralRenderer renderer, int layer) + public void RegisterComponentWithLayer(int entityID, int layer) where TComponent : struct { - if (layerIndexToGeneralRenderers.ContainsKey(layer)) - { - layerIndexToGeneralRenderers[layer].Remove(renderer); - } - } - - public void AdjustRendererLayer(GeneralRenderer renderer, int oldLayer, int newLayer) - { - UnregisterGeneralRendererWithLayer(renderer, oldLayer); - RegisterGeneralRendererWithLayer(renderer, newLayer); - } - - public void RegisterComponentWithLayer(int entityID, TComponent component, int layer) where TComponent : struct, IComponent - { - if (!layerIndexToComponentStore.ContainsKey(layer)) + if (!_layerIndexToTypeToID.ContainsKey(layer)) { throw new UndefinedLayerException("Layer {0} is not defined. Use WorldBuilder.RegisterDrawLayer to register the layer.", layer); } - if (typeToEntityToLayer[typeof(TComponent)].ContainsKey(entityID)) { UnRegisterComponentWithLayer(entityID); } + if (_typeToEntityToLayer[typeof(TComponent)].ContainsKey(entityID)) + { + if (_typeToEntityToLayer[typeof(TComponent)][entityID] != layer) + { + UnRegisterComponentWithLayer(entityID); - var set = layerIndexToComponentStore[layer]; - set.Set(entityID, component); + var set = _layerIndexToTypeToID[layer][typeof(TComponent)]; + set.Add(entityID); - typeToEntityToLayer[typeof(TComponent)].Add(entityID, layer); + _typeToEntityToLayer[typeof(TComponent)].Add(entityID, layer); + } + } + else + { + var set = _layerIndexToTypeToID[layer][typeof(TComponent)]; + set.Add(entityID); + + _typeToEntityToLayer[typeof(TComponent)].Add(entityID, layer); + } } - public void UnRegisterComponentWithLayer(int entityID) where TComponent : struct, IComponent + public void UnRegisterComponentWithLayer(int entityID) where TComponent : struct { - if (!typeToEntityToLayer.ContainsKey(typeof(TComponent))) { return; } + if (!_typeToEntityToLayer.ContainsKey(typeof(TComponent))) { return; } - if (typeToEntityToLayer[typeof(TComponent)].ContainsKey(entityID)) + if (_typeToEntityToLayer[typeof(TComponent)].ContainsKey(entityID)) { - var layer = typeToEntityToLayer[typeof(TComponent)][entityID]; - layerIndexToComponentStore[layer].ForceRemove(entityID); + var layer = _typeToEntityToLayer[typeof(TComponent)][entityID]; + _layerIndexToTypeToID[layer][typeof(TComponent)].Remove(entityID); } - typeToEntityToLayer[typeof(TComponent)].Remove(entityID); + _typeToEntityToLayer[typeof(TComponent)].Remove(entityID); } public void UnRegisterEntityWithLayer(int entityID) { - foreach (var store in layerIndexToComponentStore.Values) + foreach (var store in _layerIndexToTypeToID.Values) { - store.Remove(entityID); + foreach (var typeToSet in store) + { + var type = typeToSet.Key; + var set = typeToSet.Value; + + if (set.Contains(entityID)) + { + _typeToEntityToLayer[type].Remove(entityID); + set.Remove(entityID); + } + } } } public IEnumerable GeneralRenderersByLayer(int layer) { - return layerIndexToGeneralRenderers.ContainsKey(layer) ? - layerIndexToGeneralRenderers[layer] : + return _layerIndexToGeneralRenderers.ContainsKey(layer) ? + _layerIndexToGeneralRenderers[layer] : Enumerable.Empty(); } - public IEnumerable<(int, Type, IComponent)> AllInLayer(int layer) + public IEnumerable<(int, Type)> AllInLayer(int layer) { - return layerIndexToComponentStore.ContainsKey(layer) ? - layerIndexToComponentStore[layer].AllInterfaceTyped() : - Enumerable.Empty<(int, Type, IComponent)>(); + foreach (var kvp in _layerIndexToTypeToID[layer]) + { + foreach (var id in kvp.Value) + { + yield return (id, kvp.Key); + } + } } } } diff --git a/encompass-cs/Engine.cs b/encompass-cs/Engine.cs index 8a3cdf6..36d0ccd 100644 --- a/encompass-cs/Engine.cs +++ b/encompass-cs/Engine.cs @@ -14,104 +14,104 @@ namespace Encompass /// public abstract class Engine : IEquatable { - internal Guid ID; + internal Guid _id; - internal readonly HashSet readTypes = new HashSet(); - internal readonly HashSet readImmediateTypes = new HashSet(); - internal readonly HashSet sendTypes = new HashSet(); - internal readonly HashSet receiveTypes = new HashSet(); - internal readonly HashSet writeTypes = new HashSet(); - internal readonly HashSet writeImmediateTypes = new HashSet(); - internal readonly HashSet queryWithTypes = new HashSet(); - internal readonly HashSet queryWithoutTypes = new HashSet(); - internal readonly Dictionary writePriorities = new Dictionary(); - internal readonly int defaultWritePriority = 0; + internal readonly HashSet ReadTypes = new HashSet(); + internal readonly HashSet ReadImmediateTypes = new HashSet(); + internal readonly HashSet SendTypes = new HashSet(); + internal readonly HashSet ReceiveTypes = new HashSet(); + internal readonly HashSet WriteTypes = new HashSet(); + internal readonly HashSet WriteImmediateTypes = new HashSet(); + internal readonly HashSet QueryWithTypes = new HashSet(); + internal readonly HashSet QueryWithoutTypes = new HashSet(); + internal readonly Dictionary WritePriorities = new Dictionary(); + internal readonly int DefaultWritePriority = 0; /// /// If false, the Engine will ignore time dilation. /// - internal bool usesTimeDilation = true; - public bool TimeDilationActive { get => usesTimeDilation && timeManager.TimeDilationActive; } + internal bool _usesTimeDilation = true; + public bool TimeDilationActive { get => _usesTimeDilation && _timeManager.TimeDilationActive; } - private EntityManager entityManager; - private MessageManager messageManager; - private ComponentManager componentManager; - private TimeManager timeManager; - private TrackingManager trackingManager; + private EntityManager _entityManager; + private MessageManager _messageManager; + private ComponentManager _componentManager; + private TimeManager _timeManager; + private TrackingManager _trackingManager; - private EntitySetQuery entityQuery; + private EntitySetQuery _entityQuery; - private HashSet _trackedEntities = new HashSet(); + private readonly HashSet _trackedEntities = new HashSet(); protected IEnumerable TrackedEntities { get { foreach (var entityID in _trackedEntities) { - yield return entityManager.GetEntity(entityID); + yield return _entityManager.GetEntity(entityID); } } } - private HashSet _newlyCreatedEntities = new HashSet(); + private readonly HashSet _newlyCreatedEntities = new HashSet(); protected Engine() { - ID = Guid.NewGuid(); + _id = Guid.NewGuid(); var sendsAttribute = GetType().GetCustomAttribute(false); if (sendsAttribute != null) { - sendTypes = sendsAttribute.sendTypes; + SendTypes = sendsAttribute.SendTypes; } var activatesAttribute = GetType().GetCustomAttribute(false); if (activatesAttribute != null) { - writeImmediateTypes = activatesAttribute.writeImmediateTypes; + WriteImmediateTypes = activatesAttribute.WriteImmediateTypes; } var defaultWritePriorityAttribute = GetType().GetCustomAttribute(false); if (defaultWritePriorityAttribute != null) { - defaultWritePriority = defaultWritePriorityAttribute.writePriority; + DefaultWritePriority = defaultWritePriorityAttribute.WritePriority; } foreach (var writesAttribute in GetType().GetCustomAttributes(false)) { - writeTypes.UnionWith(writesAttribute.writeTypes); - writePriorities = new Dictionary[2] { writePriorities, writesAttribute.priorities }.SelectMany(dict => dict).ToDictionary(pair => pair.Key, pair => pair.Value); + WriteTypes.UnionWith(writesAttribute.WriteTypes); + WritePriorities = new Dictionary[2] { WritePriorities, writesAttribute.Priorities }.SelectMany(dict => dict).ToDictionary(pair => pair.Key, pair => pair.Value); } var receivesAttribute = GetType().GetCustomAttribute(false); if (receivesAttribute != null) { - receiveTypes = receivesAttribute.receiveTypes; + ReceiveTypes = receivesAttribute.ReceiveTypes; } var readsAttribute = GetType().GetCustomAttribute(false); if (readsAttribute != null) { - readTypes = readsAttribute.readTypes; + ReadTypes = readsAttribute.ReadTypes; } var readsImmediateAttribute = GetType().GetCustomAttribute(false); if (readsImmediateAttribute != null) { - readImmediateTypes = readsImmediateAttribute.readImmediateTypes; + ReadImmediateTypes = readsImmediateAttribute.ReadImmediateTypes; } var queryWithAttribute = GetType().GetCustomAttribute(false); if (queryWithAttribute != null) { - queryWithTypes = queryWithAttribute.queryWithTypes; + QueryWithTypes = queryWithAttribute.QueryWithTypes; } var queryWithoutAttribute = GetType().GetCustomAttribute(false); if (queryWithoutAttribute != null) { - queryWithoutTypes = queryWithoutAttribute.queryWithoutTypes; + QueryWithoutTypes = queryWithoutAttribute.QueryWithoutTypes; } } @@ -127,42 +127,42 @@ namespace Encompass public bool Equals(Engine other) { - return other.ID == ID; + return other._id == _id; } public override int GetHashCode() { - return ID.GetHashCode(); + return HashCode.Combine(_id); } internal void AssignEntityManager(EntityManager entityManager) { - this.entityManager = entityManager; + _entityManager = entityManager; } internal void AssignComponentManager(ComponentManager componentManager) { - this.componentManager = componentManager; + _componentManager = componentManager; } internal void AssignMessageManager(MessageManager messageManager) { - this.messageManager = messageManager; + _messageManager = messageManager; } internal void AssignTimeManager(TimeManager timeManager) { - this.timeManager = timeManager; + _timeManager = timeManager; } internal void AssignTrackingManager(TrackingManager trackingManager) { - this.trackingManager = trackingManager; + _trackingManager = trackingManager; } internal void CheckMessageRead() where TMessage : struct, IMessage { - if (!receiveTypes.Contains(typeof(TMessage))) + if (!ReceiveTypes.Contains(typeof(TMessage))) { throw new IllegalReadException("Engine {0} tried to read undeclared Message {1}", this.GetType().Name, typeof(TMessage).Name); } @@ -189,7 +189,7 @@ namespace Encompass /// protected Entity CreateEntity() { - var entity = entityManager.CreateEntity(); + var entity = _entityManager.CreateEntity(); _newlyCreatedEntities.Add(entity.ID); return entity; } @@ -197,9 +197,9 @@ namespace Encompass /// /// Returns true if an Entity with the specified ID exists. /// - protected bool EntityExists(Entity entity) + protected bool EntityExists(in Entity entity) { - return entityManager.EntityExists(entity.ID); + return _entityManager.EntityExists(entity.ID); } /// @@ -207,50 +207,52 @@ namespace Encompass /// protected bool EntityExists(int entityID) { - return entityManager.EntityExists(entityID); - } - - /// - /// Returns an Entity containing the specified Component type. - /// - protected Entity ReadEntity() where TComponent : struct, IComponent - { - return entityManager.GetEntity(ReadComponentHelper().Item2); + return _entityManager.EntityExists(entityID); } /// /// Returns all Entities containing the specified Component type. /// - protected IEnumerable ReadEntities() where TComponent : struct, IComponent + protected Span ReadEntities() where TComponent : struct, IComponent { - foreach (var pair in ReadComponentsHelper()) - { - yield return entityManager.GetEntity(pair.Item2); - } - } - - // these next two are for the ComponentMessageEmitter only - - internal IEnumerable ReadComponentsFromWorld() where TComponent : struct, IComponent - { - return componentManager.GetComponentsByType(); - } - - private IEnumerable<(TComponent, int)> ReadComponentsHelper() where TComponent : struct, IComponent - { - var immediateRead = readImmediateTypes.Contains(typeof(TComponent)); - var existingRead = readTypes.Contains(typeof(TComponent)); + var immediateRead = ReadImmediateTypes.Contains(typeof(TComponent)); + var existingRead = ReadTypes.Contains(typeof(TComponent)); if (existingRead && immediateRead) { - return componentManager.ReadExistingAndImmediateComponentsByType(); + return _componentManager.GetExistingAndImmediateEntities(); } else if (existingRead) { - return componentManager.GetComponentsIncludingEntity(); + return _componentManager.GetExistingEntities(); } else if (immediateRead) { - return componentManager.ReadImmediateComponentsByType(); + return _componentManager.GetImmediateEntities(); + } + else + { + throw new IllegalReadException("Engine {0} tried to read undeclared Component {1}", GetType().Name, typeof(TComponent).Name); + } + } + + /// + /// Returns an Entity containing the specified Component type. + /// + protected ref readonly Entity ReadEntity() where TComponent : struct, IComponent + { + var immediateRead = ReadImmediateTypes.Contains(typeof(TComponent)); + var existingRead = ReadTypes.Contains(typeof(TComponent)); + if (existingRead && immediateRead) + { + return ref _componentManager.ExistingOrImmediateSingularEntity(); + } + else if (existingRead) + { + return ref _componentManager.ExistingSingularEntity(); + } + else if (immediateRead) + { + return ref _componentManager.ImmediateSingularEntity(); } else { @@ -261,40 +263,21 @@ namespace Encompass /// /// Returns all of the Components with the specified Component Type. /// - protected IEnumerable ReadComponents() where TComponent : struct, IComponent + protected Span ReadComponents() where TComponent : struct, IComponent { - foreach (var pair in ReadComponentsHelper()) - { - yield return pair.Item1; - } - } - - /// - /// Returns all of the components of the specified type including an Entity reference for each Component. - /// - protected IEnumerable<(TComponent, Entity)> ReadComponentsIncludingEntity() where TComponent : struct, IComponent - { - foreach (var (component, id) in ReadComponentsHelper()) - { - yield return (component, entityManager.GetEntity(id)); - } - } - - private (TComponent, int) ReadComponentHelper() where TComponent : struct, IComponent - { - var immediateRead = readImmediateTypes.Contains(typeof(TComponent)); - var existingRead = readTypes.Contains(typeof(TComponent)); + var immediateRead = ReadImmediateTypes.Contains(typeof(TComponent)); + var existingRead = ReadTypes.Contains(typeof(TComponent)); if (existingRead && immediateRead) { - return componentManager.ReadFirstExistingOrImmediateComponentByType(); + return _componentManager.ReadExistingAndImmediateComponentsByType(); } else if (existingRead) { - return componentManager.ReadFirstExistingComponentByType(); + return _componentManager.GetExistingComponents(); } else if (immediateRead) { - return componentManager.ReadFirstImmediateComponentByType(); + return _componentManager.ReadImmediateComponentsByType(); } else { @@ -305,38 +288,21 @@ namespace Encompass /// /// Returns a Component with the specified Component Type. If multiples exist, an arbitrary Component is returned. /// - protected TComponent ReadComponent() where TComponent : struct, IComponent + protected ref readonly TComponent ReadComponent() where TComponent : struct, IComponent { - return ReadComponentHelper().Item1; - } - - /// - /// Returns a component of the specified type including its Entity reference. If multiples exist, an arbitrary Component is returned. - /// - protected (TComponent, Entity) ReadComponentIncludingEntity() where TComponent : struct, IComponent - { - var (component, id) = ReadComponentHelper(); - return (component, entityManager.GetEntity(id)); - } - - /// - /// Returns true if any Component with the specified Component Type exists. - /// - protected bool SomeComponent() where TComponent : struct, IComponent - { - var immediateRead = readImmediateTypes.Contains(typeof(TComponent)); - var existingRead = readTypes.Contains(typeof(TComponent)); + var immediateRead = ReadImmediateTypes.Contains(typeof(TComponent)); + var existingRead = ReadTypes.Contains(typeof(TComponent)); if (existingRead && immediateRead) { - return componentManager.SomeExistingOrImmediateComponent(); + return ref _componentManager.ExistingOrImmediateSingular(); } else if (existingRead) { - return componentManager.SomeExistingComponent(); + return ref _componentManager.ExistingSingular(); } else if (immediateRead) { - return componentManager.SomeImmediateComponent(); + return ref _componentManager.ImmediateSingular(); } else { @@ -344,21 +310,46 @@ namespace Encompass } } - private TComponent GetComponentHelper(int entityID) where TComponent : struct, IComponent + /// + /// Returns true if any Component with the specified Component Type exists. + /// + protected bool SomeComponent() where TComponent : struct, IComponent { - var immediateRead = readImmediateTypes.Contains(typeof(TComponent)); - var existingRead = readTypes.Contains(typeof(TComponent)); + var immediateRead = ReadImmediateTypes.Contains(typeof(TComponent)); + var existingRead = ReadTypes.Contains(typeof(TComponent)); if (existingRead && immediateRead) { - return componentManager.ReadImmediateOrExistingComponentByEntityAndType(entityID); + return _componentManager.SomeExistingOrImmediateComponent(); } else if (existingRead) { - return componentManager.ReadExistingComponentByEntityAndType(entityID); + return _componentManager.SomeExistingComponent(); } else if (immediateRead) { - return componentManager.ReadImmediateComponentByEntityAndType(entityID); + return _componentManager.SomeImmediateComponent(); + } + else + { + throw new IllegalReadException("Engine {0} tried to read undeclared Component {1}", GetType().Name, typeof(TComponent).Name); + } + } + + private ref TComponent GetComponentHelper(int entityID) where TComponent : struct, IComponent + { + var immediateRead = ReadImmediateTypes.Contains(typeof(TComponent)); + var existingRead = ReadTypes.Contains(typeof(TComponent)); + if (existingRead && immediateRead) + { + return ref _componentManager.ReadImmediateOrExistingComponentByEntityAndType(entityID); + } + else if (existingRead) + { + return ref _componentManager.ReadExistingComponentByEntityAndType(entityID); + } + else if (immediateRead) + { + return ref _componentManager.ReadImmediateComponentByEntityAndType(entityID); } else { @@ -375,9 +366,9 @@ namespace Encompass /// /// Thrown when the Engine does not declare that it reads the given Component Type. /// - protected TComponent GetComponent(Entity entity) where TComponent : struct, IComponent + protected ref readonly TComponent GetComponent(in Entity entity) where TComponent : struct, IComponent { - return GetComponentHelper(entity.ID); + return ref GetComponentHelper(entity.ID); } /// @@ -386,22 +377,22 @@ namespace Encompass /// /// Thrown when the Engine does not declare that is Reads the given Component Type. /// - protected bool HasComponent(Entity entity) where TComponent : struct, IComponent + protected bool HasComponent(in Entity entity) where TComponent : struct, IComponent { - var immediateRead = readImmediateTypes.Contains(typeof(TComponent)); - var existingRead = readTypes.Contains(typeof(TComponent)); + var immediateRead = ReadImmediateTypes.Contains(typeof(TComponent)); + var existingRead = ReadTypes.Contains(typeof(TComponent)); if (immediateRead && existingRead) { - return componentManager.HasExistingOrImmediateComponent(entity.ID); + return _componentManager.HasExistingOrImmediateComponent(entity.ID); } else if (existingRead) { - return componentManager.HasExistingComponent(entity.ID); + return _componentManager.HasExistingComponent(entity.ID); } else if (immediateRead) { - return componentManager.HasImmediateComponent(entity.ID); + return _componentManager.HasImmediateComponent(entity.ID); } else { @@ -415,22 +406,22 @@ namespace Encompass /// /// Thrown when the Engine does not declare that is Reads the given Component Type. /// - protected bool HasComponent(Entity entity, Type type) + protected bool HasComponent(in Entity entity, Type type) { - var immediateRead = readImmediateTypes.Contains(type); - var existingRead = readTypes.Contains(type); + var immediateRead = ReadImmediateTypes.Contains(type); + var existingRead = ReadTypes.Contains(type); if (immediateRead && existingRead) { - return componentManager.HasExistingOrImmediateComponent(entity.ID, type); + return _componentManager.HasExistingOrImmediateComponent(entity.ID, type); } else if (existingRead) { - return componentManager.HasExistingComponent(entity.ID, type); + return _componentManager.HasExistingComponent(entity.ID, type); } else if (immediateRead) { - return componentManager.HasImmediateComponent(entity.ID, type); + return _componentManager.HasImmediateComponent(entity.ID, type); } else { @@ -444,37 +435,37 @@ namespace Encompass /// /// Thrown when the Engine does not declare that it Writes the given Component Type. /// - protected void SetComponent(Entity entity, TComponent component) where TComponent : struct, IComponent + protected void SetComponent(in Entity entity, in TComponent component) where TComponent : struct, IComponent { - var priority = writePriorities.ContainsKey(typeof(TComponent)) ? writePriorities[typeof(TComponent)] : defaultWritePriority; + var priority = WritePriorities.ContainsKey(typeof(TComponent)) ? WritePriorities[typeof(TComponent)] : DefaultWritePriority; - if (!writeTypes.Contains(typeof(TComponent))) + if (!WriteTypes.Contains(typeof(TComponent))) { throw new IllegalWriteException("Engine {0} tried to update undeclared Component {1}", GetType().Name, typeof(TComponent).Name); } bool written; - if (writeImmediateTypes.Contains(typeof(TComponent))) + if (WriteImmediateTypes.Contains(typeof(TComponent))) { - written = componentManager.AddImmediateComponent(entity.ID, component, priority); + written = _componentManager.AddImmediateComponent(entity.ID, component, priority); if (written) { - trackingManager.ImmediateUpdateTracking(entity.ID, typeof(TComponent)); + _trackingManager.ImmediateUpdateTracking(entity.ID, typeof(TComponent)); } } else { - written = componentManager.UpdateComponent(entity.ID, component, priority); + written = _componentManager.UpdateComponent(entity.ID, component, priority); } - if (!componentManager.HasExistingComponent(entity.ID)) + if (!_componentManager.HasExistingComponent(entity.ID)) { - trackingManager.RegisterAddition(entity.ID, typeof(TComponent)); + _trackingManager.RegisterAddition(entity.ID, typeof(TComponent)); } if (written && component is IDrawableComponent drawableComponent) { - componentManager.RegisterDrawableComponent(entity.ID, component, drawableComponent.Layer); + _componentManager.RegisterDrawableComponent(entity.ID, drawableComponent.Layer); } } @@ -484,28 +475,28 @@ namespace Encompass /// /// Thrown when the Engine does not declare that it Writes the given Component Type. /// - protected void AddComponent(Entity entity, TComponent component) where TComponent : struct, IComponent + protected void AddComponent(in Entity entity, in TComponent component) where TComponent : struct, IComponent { if (!EntityCreatedThisFrame(entity.ID)) { throw new IllegalWriteException("AddComponent used on Entity that was not created in this context. Use SetComponent instead."); } - if (writeImmediateTypes.Contains(typeof(TComponent))) + if (WriteImmediateTypes.Contains(typeof(TComponent))) { - componentManager.AddImmediateComponent(entity.ID, component); - trackingManager.ImmediateUpdateTracking(entity.ID, typeof(TComponent)); + _componentManager.AddImmediateComponent(entity.ID, component); + _trackingManager.ImmediateUpdateTracking(entity.ID, typeof(TComponent)); } else { - componentManager.AddComponent(entity.ID, component); + _componentManager.AddComponent(entity.ID, component); } - trackingManager.RegisterAddition(entity.ID, typeof(TComponent)); + _trackingManager.RegisterAddition(entity.ID, typeof(TComponent)); if (component is IDrawableComponent drawableComponent) { - componentManager.RegisterDrawableComponent(entity.ID, component, drawableComponent.Layer); + _componentManager.RegisterDrawableComponent(entity.ID, drawableComponent.Layer); } } @@ -515,32 +506,32 @@ namespace Encompass /// /// Thrown when the Engine does not declare that it Sends the Message Type. /// - protected void SendMessage(TMessage message) where TMessage : struct, IMessage + protected void SendMessage(in TMessage message) where TMessage : struct, IMessage { - if (!sendTypes.Contains(typeof(TMessage))) + if (!SendTypes.Contains(typeof(TMessage))) { throw new IllegalSendException("Engine {0} tried to send undeclared Message {1}", GetType().Name, typeof(TMessage).Name); } - messageManager.AddMessage(message); + _messageManager.AddMessage(message); } /// /// Sends a message after the specified number of seconds, respecting time dilation. /// /// The time in seconds that will elapse before the message is sent. - protected void SendMessage(TMessage message, double time) where TMessage : struct, IMessage + protected void SendMessage(in TMessage message, double time) where TMessage : struct, IMessage { - messageManager.AddMessage(message, time); + _messageManager.AddMessage(message, time); } /// /// Sends a message after the specified number of seconds, ignoring time dilation. /// /// The time in seconds that will elapse before the message is sent. - protected void SendMessageIgnoringTimeDilation(TMessage message, double time) where TMessage : struct, IMessage + protected void SendMessageIgnoringTimeDilation(in TMessage message, double time) where TMessage : struct, IMessage { - messageManager.AddMessageIgnoringTimeDilation(message, time); + _messageManager.AddMessageIgnoringTimeDilation(message, time); } /// @@ -549,10 +540,10 @@ namespace Encompass /// /// Thrown when the Engine does not declare that it Receives the specified Message Type. /// - protected IEnumerable ReadMessages() where TMessage : struct, IMessage + protected Span ReadMessages() where TMessage : struct, IMessage { CheckMessageRead(); - return messageManager.GetMessagesByType(); + return _messageManager.GetMessagesByType(); } /// @@ -561,10 +552,10 @@ namespace Encompass /// /// Thrown when the Engine does not declare that it Receives the specified Message Type. /// - protected TMessage ReadMessage() where TMessage : struct, IMessage + protected ref readonly TMessage ReadMessage() where TMessage : struct, IMessage { CheckMessageRead(); - return messageManager.First(); + return ref _messageManager.First(); } /// @@ -576,16 +567,16 @@ namespace Encompass protected bool SomeMessage() where TMessage : struct, IMessage { CheckMessageRead(); - return messageManager.Any(); + return _messageManager.Any(); } /// /// Destroys the specified Entity. This also removes all of the Components associated with the Entity. /// Entity destruction takes place after all the Engines have been processed by World Update. /// - protected void Destroy(Entity entity) + protected void Destroy(in Entity entity) { - entityManager.MarkForDestroy(entity.ID); + _entityManager.MarkForDestroy(entity.ID); } /// @@ -614,30 +605,30 @@ namespace Encompass /// 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. /// - protected void RemoveComponent(Entity entity) where TComponent : struct, IComponent + protected void RemoveComponent(in Entity entity) where TComponent : struct, IComponent { - var priority = writePriorities.ContainsKey(typeof(TComponent)) ? writePriorities[typeof(TComponent)] : defaultWritePriority; + var priority = WritePriorities.ContainsKey(typeof(TComponent)) ? WritePriorities[typeof(TComponent)] : DefaultWritePriority; - if (!writeTypes.Contains(typeof(TComponent))) + if (!WriteTypes.Contains(typeof(TComponent))) { 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 (WriteImmediateTypes.Contains(typeof(TComponent))) { - if (componentManager.RemoveImmediate(entity.ID, priority)) + if (_componentManager.RemoveImmediate(entity.ID, priority)) { - trackingManager.ImmediateUpdateTracking(entity.ID, typeof(TComponent)); + _trackingManager.ImmediateUpdateTracking(entity.ID, typeof(TComponent)); } } else { - componentManager.Remove(entity.ID, priority); + _componentManager.Remove(entity.ID, priority); } - if (componentManager.HasExistingComponent(entity.ID)) + if (_componentManager.HasExistingComponent(entity.ID)) { - trackingManager.RegisterRemoval(entity.ID, typeof(TComponent)); + _trackingManager.RegisterRemoval(entity.ID, typeof(TComponent)); } } @@ -652,7 +643,7 @@ namespace Encompass /// The time that will elapse before time is fully undilated. protected void ActivateTimeDilation(double factor, double easeInTime, double activeTime, double easeOutTime) { - timeManager.ActivateTimeDilation(factor, easeInTime, activeTime, easeOutTime); + _timeManager.ActivateTimeDilation(factor, easeInTime, activeTime, easeOutTime); } /// @@ -667,7 +658,7 @@ namespace Encompass /// The time that will elapse before time is fully undilated. protected void ActivateTimeDilation(double factor, double easeInTime, System.Func easeInFunction, double activeTime, double easeOutTime) { - timeManager.ActivateTimeDilation(factor, easeInTime, easeInFunction, activeTime, easeOutTime); + _timeManager.ActivateTimeDilation(factor, easeInTime, easeInFunction, activeTime, easeOutTime); } /// @@ -682,7 +673,7 @@ namespace Encompass /// An easing function for the easing out of time dilation. protected void ActivateTimeDilation(double factor, double easeInTime, double activeTime, double easeOutTime, System.Func easeOutFunction) { - timeManager.ActivateTimeDilation(factor, easeInTime, activeTime, easeOutTime, easeOutFunction); + _timeManager.ActivateTimeDilation(factor, easeInTime, activeTime, easeOutTime, easeOutFunction); } /// @@ -698,7 +689,7 @@ namespace Encompass /// An easing function for the easing out of time dilation. protected void ActivateTimeDilation(double factor, double easeInTime, System.Func easeInFunction, double activeTime, double easeOutTime, System.Func easeOutFunction) { - timeManager.ActivateTimeDilation(factor, easeInTime, easeInFunction, activeTime, easeOutTime, easeOutFunction); + _timeManager.ActivateTimeDilation(factor, easeInTime, easeInFunction, activeTime, easeOutTime, easeOutFunction); } /// @@ -707,38 +698,38 @@ namespace Encompass /// The Message subtype. /// The entity that all messages in the IEnumerable refer to. /// - protected IEnumerable ReadMessagesWithEntity(Entity entity) where TMessage : struct, IMessage, IHasEntity + protected IEnumerable ReadMessagesWithEntity(in Entity entity) where TMessage : struct, IMessage, IHasEntity { CheckMessageRead(); - return messageManager.WithEntity(entity.ID); + return _messageManager.WithEntity(entity.ID); } /// /// Efficiently reads a single Message of a given type that references a given Entity. /// It is recommended to use this method in conjunction with SomeMessageWithEntity to prevent errors. /// - protected TMessage ReadMessageWithEntity(Entity entity) where TMessage : struct, IMessage, IHasEntity + protected ref readonly TMessage ReadMessageWithEntity(in Entity entity) where TMessage : struct, IMessage, IHasEntity { CheckMessageRead(); - return messageManager.WithEntitySingular(entity.ID); + return ref _messageManager.WithEntitySingular(entity.ID); } /// /// Efficiently checks if any Message of a given type referencing a given Entity exists. /// - protected bool SomeMessageWithEntity(Entity entity) where TMessage : struct, IMessage, IHasEntity + protected bool SomeMessageWithEntity(in Entity entity) where TMessage : struct, IMessage, IHasEntity { CheckMessageRead(); - return messageManager.SomeWithEntity(entity.ID); + return _messageManager.SomeWithEntity(entity.ID); } internal void CheckAndUpdateTracking(int entityID) { - if (_trackedEntities.Contains(entityID) && !entityQuery.CheckEntity(entityID, componentManager.ExistingBits)) + if (_trackedEntities.Contains(entityID) && !_entityQuery.CheckEntity(entityID, _componentManager.ExistingBits)) { _trackedEntities.Remove(entityID); } - else if (!_trackedEntities.Contains(entityID) && entityQuery.CheckEntity(entityID, componentManager.ExistingBits)) + else if (!_trackedEntities.Contains(entityID) && _entityQuery.CheckEntity(entityID, _componentManager.ExistingBits)) { _trackedEntities.Add(entityID); } @@ -746,11 +737,11 @@ namespace Encompass internal void ImmediateCheckAndUpdateTracking(int entityID) { - if (_trackedEntities.Contains(entityID) && !entityQuery.ImmediateCheckEntity(entityID, componentManager.ImmediateBits, componentManager.ExistingBits)) + 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)) + else if (!_trackedEntities.Contains(entityID) && _entityQuery.ImmediateCheckEntity(entityID, _componentManager.ImmediateBits, _componentManager.ExistingBits)) { _trackedEntities.Add(entityID); } @@ -762,30 +753,34 @@ namespace Encompass internal void BuildEntityQuery() { var withMask = BitSet512.Zero; - foreach (var type in queryWithTypes) + foreach (var type in QueryWithTypes) { - withMask = withMask.Set(componentManager.TypeToIndex[type]); + if (!_componentManager.TypeToIndex.ContainsKey(type)) { _componentManager.TypeToIndex.Add(type, _componentManager.TypeToIndex.Count); } + withMask = withMask.Set(_componentManager.TypeToIndex[type]); } var withoutMask = BitSet512.Zero; - foreach (var type in queryWithoutTypes) + foreach (var type in QueryWithoutTypes) { - withoutMask = withoutMask.Set(componentManager.TypeToIndex[type]); + if (!_componentManager.TypeToIndex.ContainsKey(type)) { _componentManager.TypeToIndex.Add(type, _componentManager.TypeToIndex.Count); } + withoutMask = withoutMask.Set(_componentManager.TypeToIndex[type]); } var immediateMask = BitSet512.Zero; - foreach (var type in readImmediateTypes) + foreach (var type in ReadImmediateTypes) { - immediateMask = immediateMask.Set(componentManager.TypeToIndex[type]); + if (!_componentManager.TypeToIndex.ContainsKey(type)) { _componentManager.TypeToIndex.Add(type, _componentManager.TypeToIndex.Count); } + immediateMask = immediateMask.Set(_componentManager.TypeToIndex[type]); } var existingMask = BitSet512.Zero; - foreach (var type in readTypes) + foreach (var type in ReadTypes) { - existingMask = existingMask.Set(componentManager.TypeToIndex[type]); + if (!_componentManager.TypeToIndex.ContainsKey(type)) { _componentManager.TypeToIndex.Add(type, _componentManager.TypeToIndex.Count); } + existingMask = existingMask.Set(_componentManager.TypeToIndex[type]); } - entityQuery = new EntitySetQuery( + _entityQuery = new EntitySetQuery( withMask & immediateMask, withMask & existingMask, withoutMask & immediateMask, diff --git a/encompass-cs/Engines/Spawner.cs b/encompass-cs/Engines/Spawner.cs index 3ad21bf..a1f6e4e 100644 --- a/encompass-cs/Engines/Spawner.cs +++ b/encompass-cs/Engines/Spawner.cs @@ -13,10 +13,10 @@ namespace Encompass var readsAttribute = GetType().GetCustomAttribute(false); if (readsAttribute != null) { - readsAttribute.readTypes.Add(typeof(TMessage)); + readsAttribute.ReadTypes.Add(typeof(TMessage)); } - receiveTypes.Add(typeof(TMessage)); + ReceiveTypes.Add(typeof(TMessage)); } public override void Update(double dt) diff --git a/encompass-cs/Entity.cs b/encompass-cs/Entity.cs index 7287499..d7913ea 100644 --- a/encompass-cs/Entity.cs +++ b/encompass-cs/Entity.cs @@ -37,7 +37,7 @@ namespace Encompass public override int GetHashCode() { - return ID.GetHashCode(); + return HashCode.Combine(ID); } } } diff --git a/encompass-cs/EntityManager.cs b/encompass-cs/EntityManager.cs index c800281..a45f0a4 100644 --- a/encompass-cs/EntityManager.cs +++ b/encompass-cs/EntityManager.cs @@ -5,48 +5,48 @@ namespace Encompass { internal class EntityManager { - private readonly int entityCapacity; - private readonly IDManager idManager = new IDManager(); - private readonly HashSet IDs = new HashSet(); + private readonly int _entityCapacity; + private readonly IDManager _idManager = new IDManager(); + private readonly HashSet _ids = new HashSet(); - private readonly HashSet entitiesMarkedForDestroy = new HashSet(); + private readonly HashSet _entitiesMarkedForDestroy = new HashSet(); - private readonly ComponentManager componentManager; + private readonly ComponentManager _componentManager; public IEnumerable EntityIDs { - get { return IDs; } + get { return _ids; } } public EntityManager(ComponentManager componentManager, int entityCapacity) { - this.componentManager = componentManager; - this.entityCapacity = entityCapacity; + _componentManager = componentManager; + _entityCapacity = entityCapacity; } private int NextID() { - return idManager.NextID(); + return _idManager.NextID(); } public Entity CreateEntity() { - if (IDs.Count < entityCapacity) + if (_ids.Count < _entityCapacity) { var id = NextID(); var entity = new Entity(id); - IDs.Add(id); + _ids.Add(id); return entity; } else { - throw new EntityOverflowException("The number of entities has exceeded the entity capacity of {0}", entityCapacity); + throw new EntityOverflowException("The number of entities has exceeded the entity capacity of {0}", _entityCapacity); } } public bool EntityExists(int id) { - return IDs.Contains(id); + return _ids.Contains(id); } public Entity GetEntity(int id) @@ -61,20 +61,20 @@ namespace Encompass public void MarkForDestroy(int entityID) { - entitiesMarkedForDestroy.Add(entityID); + _entitiesMarkedForDestroy.Add(entityID); } public void DestroyMarkedEntities(IEnumerable engines) { - foreach (var entityID in entitiesMarkedForDestroy) + foreach (var entityID in _entitiesMarkedForDestroy) { foreach (var engine in engines) { engine.RegisterDestroyedEntity(entityID); } - componentManager.MarkAllComponentsOnEntityForRemoval(entityID); - IDs.Remove(entityID); - idManager.Free(entityID); + _componentManager.MarkAllComponentsOnEntityForRemoval(entityID); + _ids.Remove(entityID); + _idManager.Free(entityID); } - entitiesMarkedForDestroy.Clear(); + _entitiesMarkedForDestroy.Clear(); } // NOTE: this is very suboptimal @@ -82,7 +82,7 @@ namespace Encompass { foreach (var id in EntityIDs) { - if (componentManager.UpToDateEntityIsEmpty(id)) + if (_componentManager.UpToDateEntityIsEmpty(id)) { MarkForDestroy(id); } diff --git a/encompass-cs/Exceptions/IllegalReadTypeException.cs b/encompass-cs/Exceptions/IllegalReadTypeException.cs deleted file mode 100644 index 3bc2512..0000000 --- a/encompass-cs/Exceptions/IllegalReadTypeException.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; - -namespace Encompass.Exceptions -{ - public class IllegalReadTypeException : Exception - { - public IllegalReadTypeException( - string format, - params object[] args - ) : base(string.Format(format, args)) { } - } -} diff --git a/encompass-cs/IComponent.cs b/encompass-cs/IComponent.cs deleted file mode 100644 index 4fcce29..0000000 --- a/encompass-cs/IComponent.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Encompass -{ - /// - /// Structs that implement IComponent are considered to be Components. - /// - public interface IComponent { } -} diff --git a/encompass-cs/IDManager.cs b/encompass-cs/IDManager.cs index 01bb529..360f580 100644 --- a/encompass-cs/IDManager.cs +++ b/encompass-cs/IDManager.cs @@ -4,25 +4,25 @@ namespace Encompass { internal class IDManager { - int nextID = 0; + int _nextID = 0; - private Stack availableIDs = new Stack(); + private readonly Stack _availableIDs = new Stack(); public int NextID() { - if (availableIDs.Count > 0) + if (_availableIDs.Count > 0) { - return availableIDs.Pop(); + return _availableIDs.Pop(); } else { - return nextID++; + return _nextID++; } } - public void Free(int ID) + public void Free(int id) { - availableIDs.Push(ID); + _availableIDs.Push(id); } } } diff --git a/encompass-cs/Interfaces/IComponent.cs b/encompass-cs/Interfaces/IComponent.cs new file mode 100644 index 0000000..d51b93c --- /dev/null +++ b/encompass-cs/Interfaces/IComponent.cs @@ -0,0 +1,4 @@ +namespace Encompass +{ + public interface IComponent { } +} diff --git a/encompass-cs/Interfaces/IDrawableComponent.cs b/encompass-cs/Interfaces/IDrawableComponent.cs index e292d90..d150624 100644 --- a/encompass-cs/Interfaces/IDrawableComponent.cs +++ b/encompass-cs/Interfaces/IDrawableComponent.cs @@ -2,6 +2,6 @@ namespace Encompass { public interface IDrawableComponent { - int Layer { get; set; } + int Layer { get; } } -} \ No newline at end of file +} diff --git a/encompass-cs/MessageManager.cs b/encompass-cs/MessageManager.cs index c9e53ae..234f46f 100644 --- a/encompass-cs/MessageManager.cs +++ b/encompass-cs/MessageManager.cs @@ -1,72 +1,71 @@ +using System; using System.Collections.Generic; namespace Encompass { internal class MessageManager { - private readonly TimeManager timeManager; - private readonly MessageStore messageStore = new MessageStore(); + private readonly TimeManager _timeManager; + private readonly MessageStore _messageStore = new MessageStore(); public MessageManager(TimeManager timeManager) { - this.timeManager = timeManager; + _timeManager = timeManager; } - internal void AddMessage(TMessage message) where TMessage : struct, IMessage + internal void AddMessage(in TMessage message) where TMessage : struct, IMessage { - messageStore.AddMessage(message); + _messageStore.AddMessage(message); } - internal void AddMessage(TMessage message, double time) where TMessage : struct, IMessage + internal void AddMessage(in TMessage message, double time) where TMessage : struct, IMessage { - messageStore.AddMessage(message, time); + _messageStore.AddMessage(message, time); } - internal void AddMessageIgnoringTimeDilation(TMessage message, double time) where TMessage : struct, IMessage + internal void AddMessageIgnoringTimeDilation(in TMessage message, double time) where TMessage : struct, IMessage { - messageStore.AddMessageIgnoringTimeDilation(message, time); + _messageStore.AddMessageIgnoringTimeDilation(message, time); } internal void ClearMessages() { - messageStore.ClearAll(); + _messageStore.ClearAll(); } internal void ProcessDelayedMessages(double dt) { - messageStore.ProcessDelayedMessages(dt * timeManager.TimeDilationFactor, dt); + _messageStore.ProcessDelayedMessages(dt * _timeManager.TimeDilationFactor, dt); } - internal IEnumerable GetMessagesByType() where TMessage : struct, IMessage + internal Span GetMessagesByType() where TMessage : struct, IMessage { - return messageStore.All(); + return _messageStore.All(); } internal bool Any() where TMessage : struct, IMessage { - return messageStore.Any(); + return _messageStore.Any(); } - internal TMessage First() where TMessage : struct, IMessage + internal ref readonly TMessage First() where TMessage : struct, IMessage { - return messageStore.First(); + return ref _messageStore.First(); } internal IEnumerable WithEntity(int entityID) where TMessage : struct, IMessage, IHasEntity { - return messageStore.WithEntity(entityID); + return _messageStore.WithEntity(entityID); } - internal TMessage WithEntitySingular(int entityID) where TMessage : struct, IMessage, IHasEntity + internal ref readonly TMessage WithEntitySingular(int entityID) where TMessage : struct, IMessage, IHasEntity { - var enumerator = messageStore.WithEntity(entityID).GetEnumerator(); - enumerator.MoveNext(); - return enumerator.Current; + return ref _messageStore.FirstWithEntity(entityID); } internal bool SomeWithEntity(int entityID) where TMessage : struct, IMessage, IHasEntity { - return messageStore.SomeWithEntity(entityID); + return _messageStore.SomeWithEntity(entityID); } } } diff --git a/encompass-cs/RenderManager.cs b/encompass-cs/RenderManager.cs index 529a431..f2031ae 100644 --- a/encompass-cs/RenderManager.cs +++ b/encompass-cs/RenderManager.cs @@ -5,40 +5,40 @@ namespace Encompass { internal class RenderManager { - private readonly EntityManager entityManager; - private readonly DrawLayerManager drawLayerManager; + private readonly EntityManager _entityManager; + private readonly DrawLayerManager _drawLayerManager; - private readonly Dictionary> drawComponentTypeToOrderedRenderer = new Dictionary>(256); + private readonly Dictionary> _drawComponentTypeToOrderedRenderer = new Dictionary>(256); public RenderManager(EntityManager entityManager, DrawLayerManager drawLayerManager) { - this.entityManager = entityManager; - this.drawLayerManager = drawLayerManager; + _entityManager = entityManager; + _drawLayerManager = drawLayerManager; } - public void RegisterOrderedRenderer(Action renderAction) where TComponent : struct, IComponent + public void RegisterOrderedRenderer(Action renderAction) where TComponent : struct { - drawComponentTypeToOrderedRenderer.Add(typeof(TComponent), renderAction); - drawLayerManager.RegisterOrderedDrawable(); + _drawComponentTypeToOrderedRenderer.Add(typeof(TComponent), renderAction); + _drawLayerManager.RegisterOrderedDrawable(); } public void RegisterGeneralRendererWithLayer(GeneralRenderer renderer, int layer) { - drawLayerManager.RegisterGeneralRendererWithLayer(renderer, layer); + _drawLayerManager.RegisterGeneralRendererWithLayer(renderer, layer); } public void Draw() { - foreach (var layer in drawLayerManager.LayerOrder) + foreach (var layer in _drawLayerManager.LayerOrder) { - var generalRendererSet = drawLayerManager.GeneralRenderersByLayer(layer); + var generalRendererSet = _drawLayerManager.GeneralRenderersByLayer(layer); - foreach (var (entityID, componentType, component) in drawLayerManager.AllInLayer(layer)) + foreach (var (entityID, componentType) in _drawLayerManager.AllInLayer(layer)) { - if (drawComponentTypeToOrderedRenderer.ContainsKey(componentType)) + if (_drawComponentTypeToOrderedRenderer.ContainsKey(componentType)) { - var internalRenderAction = drawComponentTypeToOrderedRenderer[componentType]; - internalRenderAction(entityManager.GetEntity(entityID), component); + var internalRenderAction = _drawComponentTypeToOrderedRenderer[componentType]; + internalRenderAction(_entityManager.GetEntity(entityID)); } } diff --git a/encompass-cs/Renderer.cs b/encompass-cs/Renderer.cs index 3dba03c..85b5489 100644 --- a/encompass-cs/Renderer.cs +++ b/encompass-cs/Renderer.cs @@ -1,75 +1,56 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; namespace Encompass { public abstract class Renderer { - internal EntityManager entityManager; - internal ComponentManager componentManager; + internal EntityManager _entityManager; + internal ComponentManager _componentManager; internal void AssignEntityManager(EntityManager entityManager) { - this.entityManager = entityManager; + _entityManager = entityManager; } internal void AssignComponentManager(ComponentManager componentManager) { - this.componentManager = componentManager; + _componentManager = componentManager; } - protected IEnumerable ReadEntities() where TComponent : struct, IComponent + protected Span ReadEntities() where TComponent : struct, IComponent { - foreach (var pair in ReadComponentsIncludingEntity()) - { - yield return pair.Item2; - } + return _componentManager.GetExistingEntities(); } - protected Entity ReadEntity() where TComponent : struct, IComponent + protected ref readonly Entity ReadEntity() where TComponent : struct, IComponent { - return ReadComponentIncludingEntity().Item2; + return ref _componentManager.ExistingSingularEntity(); } - protected IEnumerable ReadComponents() where TComponent : struct, IComponent + protected Span ReadComponents() where TComponent : struct, IComponent { - return componentManager.GetComponentsByType(); + return _componentManager.GetComponentsByType(); } - protected IEnumerable<(TComponent, Entity)> ReadComponentsIncludingEntity() where TComponent : struct, IComponent + protected ref readonly TComponent ReadComponent() where TComponent : struct, IComponent { - foreach (var (component, id) in componentManager.GetComponentsIncludingEntity()) - { - yield return (component, entityManager.GetEntity(id)); - } + return ref _componentManager.ExistingSingular(); } - protected TComponent ReadComponent() where TComponent : struct, IComponent + protected ref readonly TComponent GetComponent(Entity entity) where TComponent : struct, IComponent { - var enumerator = ReadComponents().GetEnumerator(); - enumerator.MoveNext(); - return enumerator.Current; - } - - protected (TComponent, Entity) ReadComponentIncludingEntity() where TComponent : struct, IComponent - { - var enumerator = ReadComponentsIncludingEntity().GetEnumerator(); - enumerator.MoveNext(); - return enumerator.Current; - } - - protected TComponent GetComponent(Entity entity) where TComponent : struct, IComponent - { - return componentManager.GetComponentByEntityAndType(entity.ID); + return ref _componentManager.GetComponentByEntityAndType(entity.ID); } protected bool HasComponent(Entity entity) where TComponent : struct, IComponent { - return componentManager.EntityHasComponentOfType(entity.ID); + return _componentManager.EntityHasComponentOfType(entity.ID); } protected bool SomeComponent() where TComponent : struct, IComponent { - return componentManager.SomeExistingComponent(); + return _componentManager.SomeExistingComponent(); } } } diff --git a/encompass-cs/Renderers/OrderedRenderer.cs b/encompass-cs/Renderers/OrderedRenderer.cs index 20ca636..5b462b3 100644 --- a/encompass-cs/Renderers/OrderedRenderer.cs +++ b/encompass-cs/Renderers/OrderedRenderer.cs @@ -7,11 +7,12 @@ namespace Encompass /// public abstract class OrderedRenderer : Renderer where TComponent : struct, IComponent, IDrawableComponent { - public abstract void Render(Entity entity, TComponent drawComponent); + public abstract void Render(Entity entity, in TComponent drawComponent); - internal void InternalRender(Entity entity, IComponent component) + internal void InternalRender(Entity entity) { - Render(entity, (TComponent)component); + ref readonly var component = ref GetComponent(entity); + Render(entity, component); } } } diff --git a/encompass-cs/TimeDilationData.cs b/encompass-cs/TimeDilationData.cs index b344589..e57901f 100644 --- a/encompass-cs/TimeDilationData.cs +++ b/encompass-cs/TimeDilationData.cs @@ -1,35 +1,56 @@ +using System; + namespace Encompass { internal struct TimeDilationData { - public double elapsedTime; - public double easeInTime; - public System.Func easeInFunction; - public double activeTime; - public double easeOutTime; - public System.Func easeOutFunction; - public double factor; + private readonly double _factor; public double Factor { get { - if (elapsedTime < easeInTime) + if (ElapsedTime < EaseInTime) { - return easeInFunction(elapsedTime, 1, factor - 1, easeInTime); + return EaseInFunction(ElapsedTime, 1, _factor - 1, EaseInTime); } - else if (elapsedTime < easeInTime + activeTime) + else if (ElapsedTime < EaseInTime + ActiveTime) { - return factor; + return _factor; } - else if (elapsedTime < easeInTime + activeTime + easeOutTime) + else if (ElapsedTime < EaseInTime + ActiveTime + EaseOutTime) { - var elapsedOutTime = elapsedTime - easeInTime - activeTime; - return easeOutFunction(elapsedOutTime, factor, 1 - factor, easeOutTime); + var elapsedOutTime = ElapsedTime - EaseInTime - ActiveTime; + return EaseOutFunction(elapsedOutTime, _factor, 1 - _factor, EaseOutTime); } return 1; } } + + public double ElapsedTime { get; set; } + public double EaseInTime { get; } + public Func EaseInFunction { get; } + public double ActiveTime { get; } + public double EaseOutTime { get; } + public Func EaseOutFunction { get; } + + public TimeDilationData( + double factor, + double easeInTime, + Func easeInfunction, + double activeTime, + double easeOutTime, + Func easeOutFunction + ) + { + _factor = factor; + EaseInTime = easeInTime; + EaseInFunction = easeInfunction; + ActiveTime = activeTime; + EaseOutTime = easeOutTime; + EaseOutFunction = easeOutFunction; + ElapsedTime = 0; + } } -} \ No newline at end of file +} diff --git a/encompass-cs/TimeManager.cs b/encompass-cs/TimeManager.cs index ee05939..19363d2 100644 --- a/encompass-cs/TimeManager.cs +++ b/encompass-cs/TimeManager.cs @@ -4,7 +4,7 @@ namespace Encompass { internal class TimeManager { - private readonly List timeDilationDatas = new List(32); + private readonly List _timeDilationDatas = new List(32); private double Linear(double t, double b, double c, double d) { @@ -15,36 +15,36 @@ namespace Encompass { get { - if (timeDilationDatas.Count == 0) { return 1; } + if (_timeDilationDatas.Count == 0) { return 1; } var average = 0.0; - foreach (var data in timeDilationDatas) + foreach (var data in _timeDilationDatas) { average += data.Factor; } - return average / timeDilationDatas.Count; + return average / _timeDilationDatas.Count; } } public bool TimeDilationActive { - get => timeDilationDatas.Count != 0; + get => _timeDilationDatas.Count != 0; } public void Update(double dt) { - for (var i = timeDilationDatas.Count - 1; i >= 0; i--) + for (var i = _timeDilationDatas.Count - 1; i >= 0; i--) { - var data = timeDilationDatas[i]; + var data = _timeDilationDatas[i]; - data.elapsedTime += dt; + data.ElapsedTime += dt; - if (data.elapsedTime > data.easeInTime + data.activeTime + data.easeOutTime) + if (data.ElapsedTime > data.EaseInTime + data.ActiveTime + data.EaseOutTime) { - timeDilationDatas.RemoveAt(i); + _timeDilationDatas.RemoveAt(i); } else { - timeDilationDatas[i] = data; + _timeDilationDatas[i] = data; } } } @@ -66,16 +66,15 @@ namespace Encompass public void ActivateTimeDilation(double factor, double easeInTime, System.Func easeInFunction, double activeTime, double easeOutTime, System.Func easeOutFunction) { - timeDilationDatas.Add(new TimeDilationData - { - elapsedTime = 0, - easeInTime = easeInTime, - easeInFunction = easeInFunction, - activeTime = activeTime, - easeOutTime = easeOutTime, - easeOutFunction = easeOutFunction, - factor = factor - }); + _timeDilationDatas.Add(new TimeDilationData + ( + factor, + easeInTime, + easeInFunction, + activeTime, + easeOutTime, + easeOutFunction + )); } } } diff --git a/encompass-cs/TrackingManager.cs b/encompass-cs/TrackingManager.cs index c9e7830..3acf34d 100644 --- a/encompass-cs/TrackingManager.cs +++ b/encompass-cs/TrackingManager.cs @@ -5,13 +5,13 @@ namespace Encompass { internal class TrackingManager { - private Dictionary> _immediateComponentTypesToEngines = new Dictionary>(); - private Dictionary> _componentTypesToEngines = new Dictionary>(); + private readonly Dictionary> _immediateComponentTypesToEngines = new Dictionary>(); + private readonly Dictionary> _componentTypesToEngines = new Dictionary>(); - private HashSet<(int, Type)> _additions = new HashSet<(int, Type)>(); - private HashSet<(int, Type)> _removals = new HashSet<(int, Type)>(); + private readonly HashSet<(int, Type)> _additions = new HashSet<(int, Type)>(); + private readonly HashSet<(int, Type)> _removals = new HashSet<(int, Type)>(); - private HashSet<(int, Engine)> _pairsToCheck = new HashSet<(int, Engine)>(); + private readonly HashSet<(int, Engine)> _pairsToCheck = new HashSet<(int, Engine)>(); public void RegisterComponentTypeToEngine(Type type, Engine engine) { diff --git a/encompass-cs/UberEngine.cs b/encompass-cs/UberEngine.cs index 7abfc7d..5d5378e 100644 --- a/encompass-cs/UberEngine.cs +++ b/encompass-cs/UberEngine.cs @@ -2,23 +2,24 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; +using System.Runtime.CompilerServices; namespace Encompass { internal class UberEngine : Engine { - private IEnumerable _componentTypes; - private IEnumerable _messageTypes; + private readonly IEnumerable _componentTypes; + private readonly IEnumerable _messageTypes; public Entity Entity { get; private set; } public UberEngine(IEnumerable componentTypes, IEnumerable messageTypes) { _componentTypes = componentTypes; _messageTypes = messageTypes; - readTypes.UnionWith(componentTypes); - writeTypes.UnionWith(componentTypes); - sendTypes.UnionWith(messageTypes); - receiveTypes.UnionWith(messageTypes); + ReadTypes.UnionWith(componentTypes); + WriteTypes.UnionWith(componentTypes); + SendTypes.UnionWith(messageTypes); + ReceiveTypes.UnionWith(messageTypes); } public void Write() @@ -39,17 +40,15 @@ namespace Encompass foreach (var type in _componentTypes) { CallGenericMethod(type, "ReadComponent", null); - CallGenericMethod(type, "ReadComponentIncludingEntity", null); - CallGenericMethod(type, "ReadComponents", null); - CallGenericMethod(type, "ReadComponentsIncludingEntity", null); + CallGenericWrappedMethod(type, "ReadComponentsWrapper", null); CallGenericMethod(type, "ReadEntity", null); - CallGenericMethod(type, "ReadEntities", null); - CallGenericMethod(type, "GetComponent", new Type[] { typeof(Entity) }, new object[] { Entity }); - CallGenericMethod(type, "HasComponent", new Type[] { typeof(Entity) }, new object[] { Entity }); + CallGenericWrappedMethod(type, "ReadEntitiesWrapper", null); + CallGenericMethod(type, "GetComponent", new object[] { Entity }); + CallGenericMethod(type, "HasComponent", 1, new object[] { Entity }); CallGenericMethod(type, "SomeComponent", null); CallGenericMethod(type, "DestroyWith", null); CallGenericMethod(type, "DestroyAllWith", null); - CallGenericMethod(type, "RemoveComponent", new Type[] { typeof(Entity) }, new object[] { Entity }); + CallGenericMethod(type, "RemoveComponent", new object[] { Entity }); } foreach (var type in _messageTypes) @@ -58,20 +57,49 @@ namespace Encompass CallGenericMethod(type, "SendMessage", 1, new object[] { Activator.CreateInstance(type) }); CallGenericMethod(type, "SendMessage", 2, new object[] { Activator.CreateInstance(type), 1 }); CallGenericMethod(type, "ReadMessage", null); - CallGenericMethod(type, "ReadMessages", null); + + CallGenericWrappedMethod(type, "ReadMessagesWrapper", null); CallGenericMethod(type, "SomeMessage", null); if (typeof(IHasEntity).IsAssignableFrom(type)) { - CallGenericMethod(type, "ReadMessagesWithEntity", new Type[] { typeof(Entity) }, new object[] { Entity }); + CallGenericMethod(type, "ReadMessagesWithEntity", new object[] { Entity }); + CallGenericMethod(type, "ReadMessageWithEntity", new object[] { Entity }); + CallGenericMethod(type, "SomeMessageWithEntity", new object[] { Entity }); } } } + // we can't reflect invoke on Span returns right now... so we have non-return wrapper methods + + protected void ReadComponentsWrapper() where TComponent : struct, IComponent + { + ReadComponents(); + } + + protected void ReadMessagesWrapper() where TMessage : struct, IMessage + { + ReadMessages(); + } + + protected void ReadEntitiesWrapper() where TComponent : struct, IComponent + { + ReadEntities(); + } + + // trying to use PrepareMethod because we can't reflect invoke methods that return a span... private void CallGenericMethod(Type type, string methodName, object[] parameters) { var readComponentMethod = typeof(Engine).GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance); var genericReadComponentMethod = readComponentMethod.MakeGenericMethod(type); genericReadComponentMethod.Invoke(this, parameters); + // RuntimeHelpers.PrepareMethod(genericReadComponentMethod.MethodHandle); + } + + private void CallGenericWrappedMethod(Type type, string methodName, object[] parameters) + { + var readComponentMethod = typeof(UberEngine).GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance); + var genericReadComponentMethod = readComponentMethod.MakeGenericMethod(type); + genericReadComponentMethod.Invoke(this, parameters); } private void CallGenericMethod(Type type, string methodName, Type[] types, object[] parameters) @@ -79,6 +107,7 @@ namespace Encompass var readComponentMethod = typeof(Engine).GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance, null, types, null); var genericReadComponentMethod = readComponentMethod.MakeGenericMethod(type); genericReadComponentMethod.Invoke(this, parameters); + // RuntimeHelpers.PrepareMethod(genericReadComponentMethod.MethodHandle); } private void CallGenericMethod(Type type, string methodName, int argumentNum, object[] parameters) @@ -86,6 +115,7 @@ namespace Encompass var method = typeof(Engine).GetRuntimeMethods().Where(m => m.Name == methodName && m.GetParameters().Length == argumentNum).First(); var genericMethod = method.MakeGenericMethod(type); genericMethod.Invoke(this, parameters); + // RuntimeHelpers.PrepareMethod(genericMethod.MethodHandle); } } } diff --git a/encompass-cs/UberRenderer.cs b/encompass-cs/UberRenderer.cs index be4bde4..9d96e2c 100644 --- a/encompass-cs/UberRenderer.cs +++ b/encompass-cs/UberRenderer.cs @@ -6,7 +6,7 @@ namespace Encompass { class UberRenderer : Renderer { - private IEnumerable _componentTypes; + private readonly IEnumerable _componentTypes; private Entity _entity; public UberRenderer(IEnumerable componentTypes) @@ -19,27 +19,43 @@ namespace Encompass _entity = entity; } + // can't reflect invoke on Span returns... public void Render() { foreach (var type in _componentTypes) { - CallGenericMethod(type, "ReadEntities", null); + CallGenericWrappedMethod(type, "ReadEntitiesWrapper", null); CallGenericMethod(type, "ReadEntity", null); + CallGenericWrappedMethod(type, "ReadComponentsWrapper", null); CallGenericMethod(type, "ReadComponent", null); - CallGenericMethod(type, "ReadComponentIncludingEntity", null); - CallGenericMethod(type, "ReadComponents", null); - CallGenericMethod(type, "ReadComponentsIncludingEntity", null); CallGenericMethod(type, "GetComponent", new object[] { _entity }); CallGenericMethod(type, "HasComponent", new object[] { _entity }); CallGenericMethod(type, "SomeComponent", null); } } + protected void ReadEntitiesWrapper() where TComponent : struct, IComponent + { + ReadEntities(); + } + + protected void ReadComponentsWrapper() where TComponent : struct, IComponent + { + ReadComponents(); + } + private void CallGenericMethod(Type type, string methodName, object[] parameters) { var readComponentMethod = typeof(Renderer).GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance); var genericReadComponentMethod = readComponentMethod.MakeGenericMethod(type); genericReadComponentMethod.Invoke(this, parameters); } + + private void CallGenericWrappedMethod(Type type, string methodName, object[] parameters) + { + var readComponentMethod = typeof(UberRenderer).GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance); + var genericReadComponentMethod = readComponentMethod.MakeGenericMethod(type); + genericReadComponentMethod.Invoke(this, parameters); + } } } diff --git a/encompass-cs/World.cs b/encompass-cs/World.cs index b611d96..b0b181b 100644 --- a/encompass-cs/World.cs +++ b/encompass-cs/World.cs @@ -7,13 +7,13 @@ namespace Encompass /// public class World { - private readonly List enginesInOrder; - private readonly EntityManager entityManager; - private readonly ComponentManager componentManager; - private readonly TrackingManager trackingManager; - private readonly MessageManager messageManager; - private readonly TimeManager timeManager; - private readonly RenderManager renderManager; + private readonly List _enginesInOrder; + private readonly EntityManager _entityManager; + private readonly ComponentManager _componentManager; + private readonly TrackingManager _trackingManager; + private readonly MessageManager _messageManager; + private readonly TimeManager _timeManager; + private readonly RenderManager _renderManager; internal World( List enginesInOrder, @@ -25,13 +25,13 @@ namespace Encompass RenderManager renderManager ) { - this.enginesInOrder = enginesInOrder; - this.entityManager = entityManager; - this.componentManager = componentManager; - this.trackingManager = trackingManager; - this.messageManager = messageManager; - this.timeManager = timeManager; - this.renderManager = renderManager; + _enginesInOrder = enginesInOrder; + _entityManager = entityManager; + _componentManager = componentManager; + _trackingManager = trackingManager; + _messageManager = messageManager; + _timeManager = timeManager; + _renderManager = renderManager; } /// @@ -40,15 +40,15 @@ namespace Encompass /// The time in seconds that has passed since the previous frame. public void Update(double dt) { - trackingManager.UpdateTracking(); - messageManager.ProcessDelayedMessages(dt); - timeManager.Update(dt); + _trackingManager.UpdateTracking(); + _messageManager.ProcessDelayedMessages(dt); + _timeManager.Update(dt); - foreach (var engine in enginesInOrder) + foreach (var engine in _enginesInOrder) { - if (engine.usesTimeDilation) + if (engine._usesTimeDilation) { - engine.Update(dt * timeManager.TimeDilationFactor); + engine.Update(dt * _timeManager.TimeDilationFactor); } else { @@ -58,12 +58,12 @@ namespace Encompass engine.ClearNewlyCreatedEntities(); } - messageManager.ClearMessages(); - entityManager.PruneEmptyEntities(); - entityManager.DestroyMarkedEntities(enginesInOrder); + _messageManager.ClearMessages(); + _entityManager.PruneEmptyEntities(); + _entityManager.DestroyMarkedEntities(_enginesInOrder); - componentManager.RemoveMarkedComponents(); - componentManager.WriteComponents(); + _componentManager.RemoveMarkedComponents(); + _componentManager.WriteComponents(); } /// @@ -71,7 +71,7 @@ namespace Encompass /// public void Draw() { - renderManager.Draw(); + _renderManager.Draw(); } } } diff --git a/encompass-cs/WorldBuilder.cs b/encompass-cs/WorldBuilder.cs index 3145626..dbcebcd 100644 --- a/encompass-cs/WorldBuilder.cs +++ b/encompass-cs/WorldBuilder.cs @@ -18,43 +18,43 @@ namespace Encompass /// public class WorldBuilder { - private readonly int entityCapacity; - private readonly List engines = new List(); - private readonly DirectedGraph engineGraph = GraphBuilder.DirectedGraph(); - private readonly ComponentStore startingExistingComponentStore; - private readonly ComponentStore startingUpToDateComponentStore; + private readonly int _entityCapacity; + private readonly List _engines = new List(); + private readonly DirectedGraph _engineGraph = GraphBuilder.DirectedGraph(); + private readonly ComponentStore _startingExistingComponentStore; + private readonly ComponentStore _startingUpToDateComponentStore; - private readonly ComponentManager componentManager; - private readonly EntityManager entityManager; - private readonly MessageManager messageManager; - private readonly TimeManager timeManager; - private readonly DrawLayerManager drawLayerManager; - private readonly RenderManager renderManager; - private readonly TrackingManager trackingManager; + private readonly ComponentManager _componentManager; + private readonly EntityManager _entityManager; + private readonly MessageManager _messageManager; + private readonly TimeManager _timeManager; + private readonly DrawLayerManager _drawLayerManager; + private readonly RenderManager _renderManager; + private readonly TrackingManager _trackingManager; - private readonly Dictionary> typeToReaders = new Dictionary>(); + private readonly Dictionary> _typeToReaders = new Dictionary>(); - private readonly HashSet senders = new HashSet(); + private readonly HashSet _senders = new HashSet(); - private readonly HashSet componentTypesToPreload = new HashSet(); + private readonly HashSet _componentTypesToPreload = new HashSet(); - private readonly HashSet messageTypes = new HashSet(); + private readonly HashSet _messageTypes = new HashSet(); - private readonly Dictionary typeToIndex = new Dictionary(); + private readonly Dictionary _typeToIndex = new Dictionary(); public WorldBuilder(int entityCapacity = 32768) { - this.entityCapacity = entityCapacity; - drawLayerManager = new DrawLayerManager(typeToIndex); - timeManager = new TimeManager(); - trackingManager = new TrackingManager(); - componentManager = new ComponentManager(drawLayerManager, typeToIndex); - messageManager = new MessageManager(timeManager); - entityManager = new EntityManager(componentManager, entityCapacity); - renderManager = new RenderManager(entityManager, drawLayerManager); + _entityCapacity = entityCapacity; + _drawLayerManager = new DrawLayerManager(); + _timeManager = new TimeManager(); + _trackingManager = new TrackingManager(); + _componentManager = new ComponentManager(_drawLayerManager, _typeToIndex); + _messageManager = new MessageManager(_timeManager); + _entityManager = new EntityManager(_componentManager, entityCapacity); + _renderManager = new RenderManager(_entityManager, _drawLayerManager); - startingExistingComponentStore = new ComponentStore(typeToIndex); - startingUpToDateComponentStore = new ComponentStore(typeToIndex); + _startingExistingComponentStore = new ComponentStore(_typeToIndex); + _startingUpToDateComponentStore = new ComponentStore(_typeToIndex); } /// @@ -62,56 +62,56 @@ namespace Encompass /// public Entity CreateEntity() { - return entityManager.CreateEntity(); + return _entityManager.CreateEntity(); } /// /// Specifies that the given Message should be sent immediately on the first World Update. /// - public void SendMessage(TMessage message) where TMessage : struct, IMessage + public void SendMessage(in TMessage message) where TMessage : struct, IMessage { - messageManager.AddMessage(message); + _messageManager.AddMessage(message); } /// /// Specifies that the given Message should be sent after the specified number of seconds after the first World Update. /// - public void SendMessage(TMessage message, double time) where TMessage : struct, IMessage + public void SendMessage(in TMessage message, double time) where TMessage : struct, IMessage { - messageManager.AddMessage(message, time); + _messageManager.AddMessage(message, time); } /// /// Sets Component data for the specified Component Type on the specified Entity. /// - public void SetComponent(Entity entity, TComponent component) where TComponent : struct, IComponent + public void SetComponent(Entity entity, in TComponent component) where TComponent : struct { RegisterComponentType(); - startingExistingComponentStore.Set(entity.ID, component); - startingUpToDateComponentStore.Set(entity.ID, component); + _startingExistingComponentStore.Set(entity.ID, component); + _startingUpToDateComponentStore.Set(entity.ID, component); if (component is IDrawableComponent drawableComponent) { - componentManager.RegisterDrawableComponent(entity.ID, component, drawableComponent.Layer); - drawLayerManager.RegisterOrderedDrawable(); + _componentManager.RegisterDrawableComponent(entity.ID, drawableComponent.Layer); + _drawLayerManager.RegisterOrderedDrawable(); } } - internal void RegisterComponentType() where TComponent : struct, IComponent + internal void RegisterComponentType() where TComponent : struct { - if (!typeToIndex.ContainsKey(typeof(TComponent))) + if (!_typeToIndex.ContainsKey(typeof(TComponent))) { - typeToIndex.Add(typeof(TComponent), typeToIndex.Count); - componentTypesToPreload.Add(typeof(TComponent)); - componentManager.RegisterComponentType(); - startingExistingComponentStore.RegisterComponentType(); - startingUpToDateComponentStore.RegisterComponentType(); + _typeToIndex.Add(typeof(TComponent), _typeToIndex.Count); + _componentTypesToPreload.Add(typeof(TComponent)); + _componentManager.RegisterComponentType(); + _startingExistingComponentStore.RegisterComponentType(); + _startingUpToDateComponentStore.RegisterComponentType(); } } internal void RegisterMessageTypes(IEnumerable types) { - messageTypes.UnionWith(types); + _messageTypes.UnionWith(types); } /// @@ -120,21 +120,21 @@ namespace Encompass /// An instance of an Engine. public Engine AddEngine(TEngine engine) where TEngine : Engine { - engine.AssignEntityManager(entityManager); - engine.AssignComponentManager(componentManager); - engine.AssignMessageManager(messageManager); - engine.AssignTimeManager(timeManager); - engine.AssignTrackingManager(trackingManager); + engine.AssignEntityManager(_entityManager); + engine.AssignComponentManager(_componentManager); + engine.AssignMessageManager(_messageManager); + engine.AssignTimeManager(_timeManager); + engine.AssignTrackingManager(_trackingManager); - engines.Add(engine); - engineGraph.AddNode(engine); + _engines.Add(engine); + _engineGraph.AddNode(engine); - var messageReceiveTypes = engine.receiveTypes; - var messageSendTypes = engine.sendTypes; + var messageReceiveTypes = engine.ReceiveTypes; + var messageSendTypes = engine.SendTypes; - RegisterMessageTypes(engine.receiveTypes.Union(engine.sendTypes)); + RegisterMessageTypes(engine.ReceiveTypes.Union(engine.SendTypes)); - foreach (var writeImmediateType in engine.writeImmediateTypes.Intersect(engine.readImmediateTypes)) + foreach (var writeImmediateType in engine.WriteImmediateTypes.Intersect(engine.ReadImmediateTypes)) { throw new EngineSelfCycleException("Engine {0} both writes and reads immediate Component {1}", engine.GetType().Name, writeImmediateType.Name); } @@ -144,28 +144,28 @@ namespace Encompass throw new EngineSelfCycleException("Engine {0} both receives and sends Message {1}", engine.GetType().Name, messageType.Name); } - if (messageSendTypes.Count > 0 || engine.writeImmediateTypes.Count > 0) + if (messageSendTypes.Count > 0 || engine.WriteImmediateTypes.Count > 0) { - senders.Add(engine); + _senders.Add(engine); } - foreach (var componentType in engine.queryWithTypes.Union(engine.queryWithoutTypes)) + foreach (var componentType in engine.QueryWithTypes.Union(engine.QueryWithoutTypes)) { - trackingManager.RegisterComponentTypeToEngine(componentType, engine); - if (engine.readImmediateTypes.Contains(componentType)) + _trackingManager.RegisterComponentTypeToEngine(componentType, engine); + if (engine.ReadImmediateTypes.Contains(componentType)) { - trackingManager.RegisterImmediateComponentTypeToEngine(componentType, engine); + _trackingManager.RegisterImmediateComponentTypeToEngine(componentType, engine); } } - foreach (var receiveType in engine.receiveTypes.Union(engine.readImmediateTypes)) + foreach (var receiveType in engine.ReceiveTypes.Union(engine.ReadImmediateTypes)) { - if (!typeToReaders.ContainsKey(receiveType)) + if (!_typeToReaders.ContainsKey(receiveType)) { - typeToReaders.Add(receiveType, new HashSet()); + _typeToReaders.Add(receiveType, new HashSet()); } - typeToReaders[receiveType].Add(engine); + _typeToReaders[receiveType].Add(engine); } return engine; @@ -177,7 +177,7 @@ namespace Encompass /// The draw layer to register. public void RegisterDrawLayer(int layer) { - drawLayerManager.RegisterDrawLayer(layer); + _drawLayerManager.RegisterDrawLayer(layer); } /// @@ -186,9 +186,9 @@ namespace Encompass public OrderedRenderer AddOrderedRenderer(OrderedRenderer renderer) where TComponent : struct, IComponent, IDrawableComponent { RegisterComponentType(); - renderer.AssignEntityManager(entityManager); - renderer.AssignComponentManager(componentManager); - renderManager.RegisterOrderedRenderer(renderer.InternalRender); + renderer.AssignEntityManager(_entityManager); + renderer.AssignComponentManager(_componentManager); + _renderManager.RegisterOrderedRenderer(renderer.InternalRender); return renderer; } @@ -200,29 +200,29 @@ namespace Encompass /// The layer at which the GeneralRenderer should render. Higher numbers draw over lower numbers. public TRenderer AddGeneralRenderer(TRenderer renderer, int layer) where TRenderer : GeneralRenderer { - renderer.AssignEntityManager(entityManager); - renderer.AssignComponentManager(componentManager); + renderer.AssignEntityManager(_entityManager); + renderer.AssignComponentManager(_componentManager); - renderManager.RegisterGeneralRendererWithLayer(renderer, layer); + _renderManager.RegisterGeneralRendererWithLayer(renderer, layer); return renderer; } private void BuildEngineGraph() { - foreach (var senderEngine in senders) + foreach (var senderEngine in _senders) { - foreach (var messageType in senderEngine.sendTypes.Union(senderEngine.writeImmediateTypes)) + foreach (var messageType in senderEngine.SendTypes.Union(senderEngine.WriteImmediateTypes)) { - if (typeToReaders.ContainsKey(messageType)) + if (_typeToReaders.ContainsKey(messageType)) { - foreach (var readerEngine in typeToReaders[messageType]) + foreach (var readerEngine in _typeToReaders[messageType]) { if (senderEngine != readerEngine) { - if (!engineGraph.Exists(senderEngine, readerEngine)) + if (!_engineGraph.Exists(senderEngine, readerEngine)) { - engineGraph.AddEdge(senderEngine, readerEngine); + _engineGraph.AddEdge(senderEngine, readerEngine); } } } @@ -240,9 +240,9 @@ namespace Encompass { BuildEngineGraph(); - if (engineGraph.Cyclic()) + if (_engineGraph.Cyclic()) { - var cycles = engineGraph.SimpleCycles(); + var cycles = _engineGraph.SimpleCycles(); var errorString = "Cycle(s) found in Engines: "; foreach (var cycle in cycles) { @@ -262,25 +262,25 @@ namespace Encompass var writePriorities = new Dictionary>(); var writeMessageToEngines = new Dictionary>(); - foreach (var engine in engines) + foreach (var engine in _engines) { if (engine.GetType().GetCustomAttribute() != null) { - engine.usesTimeDilation = false; + engine._usesTimeDilation = false; } var defaultWritePriorityAttribute = engine.GetType().GetCustomAttribute(false); - foreach (var writeType in engine.writeTypes) + foreach (var writeType in engine.WriteTypes) { int? priority = null; - if (engine.writePriorities.ContainsKey(writeType)) + if (engine.WritePriorities.ContainsKey(writeType)) { - priority = engine.writePriorities[writeType]; + priority = engine.WritePriorities[writeType]; } else if (defaultWritePriorityAttribute != null) { - priority = defaultWritePriorityAttribute.writePriority; + priority = defaultWritePriorityAttribute.WritePriority; } if (priority.HasValue) @@ -354,25 +354,11 @@ namespace Encompass throw new EngineWriteConflictException(errorString); } - // doing reflection to grab all component types, because not all writes need to be declared - foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) - { - foreach (var componentType in assembly.GetTypes()) - { - if (typeof(IComponent).IsAssignableFrom(componentType) && componentType.IsValueType && !componentType.IsEnum && !componentType.IsPrimitive) - { - var method = typeof(WorldBuilder).GetMethod("RegisterComponentType", BindingFlags.NonPublic | BindingFlags.Instance); - var generic = method.MakeGenericMethod(componentType); - generic.Invoke(this, null); - } - } - } - - PreloadJIT(componentTypesToPreload, messageTypes); + PreloadJIT(_messageTypes); var engineOrder = new List(); - foreach (var engine in engineGraph.TopologicalSort()) + foreach (var engine in _engineGraph.TopologicalSort()) { engineOrder.Add(engine); engine.BuildEntityQuery(); @@ -380,18 +366,18 @@ namespace Encompass var world = new World( engineOrder, - entityManager, - componentManager, - trackingManager, - messageManager, - timeManager, - renderManager + _entityManager, + _componentManager, + _trackingManager, + _messageManager, + _timeManager, + _renderManager ); - componentManager.SetExistingComponentStore(startingExistingComponentStore); - componentManager.SetUpToDateComponentStore(startingUpToDateComponentStore); + _componentManager.SetExistingComponentStore(_startingExistingComponentStore); + _componentManager.SetUpToDateComponentStore(_startingUpToDateComponentStore); - trackingManager.InitializeTracking(entityManager.EntityIDs); + _trackingManager.InitializeTracking(_entityManager.EntityIDs); return world; } @@ -402,19 +388,44 @@ namespace Encompass /// It does so by grabbing all component and message types known to the WorldBuilder and /// executing every possible generic method that could be executed with those types. /// - private void PreloadJIT(IEnumerable componentTypes, IEnumerable messageTypes) + private void PreloadJIT(IEnumerable messageTypes) { var dummyTimeManager = new TimeManager(); var dummyMessageManager = new MessageManager(dummyTimeManager); - var dummyDrawLayerManager = new DrawLayerManager(typeToIndex); + var dummyDrawLayerManager = new DrawLayerManager(); var dummyTrackingManager = new TrackingManager(); - var dummyComponentManager = new ComponentManager(dummyDrawLayerManager, typeToIndex); - var dummyEntityManager = new EntityManager(dummyComponentManager, entityCapacity); + var dummyComponentManager = new ComponentManager(dummyDrawLayerManager, _typeToIndex); + var dummyEntityManager = new EntityManager(dummyComponentManager, _entityCapacity); var dummyRenderManager = new RenderManager(dummyEntityManager, dummyDrawLayerManager); + // doing reflection to grab all component types, because not all writes need to be declared + foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) + { + foreach (var componentType in assembly.GetTypes()) + { + if (typeof(IComponent).IsAssignableFrom(componentType) && componentType.IsValueType && !componentType.IsEnum && !componentType.IsPrimitive) + { + var method = typeof(WorldBuilder).GetMethod("RegisterComponentType", BindingFlags.NonPublic | BindingFlags.Instance); + var generic = method.MakeGenericMethod(componentType); + generic.Invoke(this, null); + + var dummyRegisterMethod = typeof(ComponentManager).GetMethod("RegisterComponentType", BindingFlags.Public | BindingFlags.Instance); + var dummyGeneric = dummyRegisterMethod.MakeGenericMethod(componentType); + dummyGeneric.Invoke(dummyComponentManager, null); + } + + if (componentType.GetInterface("IDrawableComponent") != null) + { + var drawLayerManagerRegisterMethod = typeof(DrawLayerManager).GetMethod("RegisterOrderedDrawable"); + var drawLayerManagerRegisterGenericMethod = drawLayerManagerRegisterMethod.MakeGenericMethod(componentType); + drawLayerManagerRegisterGenericMethod.Invoke(dummyDrawLayerManager, null); + } + } + } + var prepEngineOrder = new List(); - var uberEngine = new UberEngine(componentTypes, messageTypes); + var uberEngine = new UberEngine(_componentTypesToPreload, messageTypes); uberEngine.AssignEntityManager(dummyEntityManager); uberEngine.AssignComponentManager(dummyComponentManager); @@ -422,24 +433,10 @@ namespace Encompass uberEngine.AssignTimeManager(dummyTimeManager); uberEngine.AssignTrackingManager(dummyTrackingManager); - var uberRenderer = new UberRenderer(componentTypes); + var uberRenderer = new UberRenderer(_componentTypesToPreload); uberRenderer.AssignComponentManager(dummyComponentManager); uberRenderer.AssignEntityManager(dummyEntityManager); - foreach (var type in componentTypes) - { - var componentManagerRegisterMethod = typeof(ComponentManager).GetMethod("RegisterComponentType"); - var componentManagerRegisterGenericMethod = componentManagerRegisterMethod.MakeGenericMethod(type); - componentManagerRegisterGenericMethod.Invoke(dummyComponentManager, null); - - if (type.GetInterface("IDrawableComponent") != null) - { - var drawLayerManagerRegisterMethod = typeof(DrawLayerManager).GetMethod("RegisterOrderedDrawable"); - var drawLayerManagerRegisterGenericMethod = drawLayerManagerRegisterMethod.MakeGenericMethod(type); - drawLayerManagerRegisterGenericMethod.Invoke(dummyDrawLayerManager, null); - } - } - prepEngineOrder.Add(uberEngine); var dummyWorld = new World( diff --git a/encompass-cs/encompass-cs.csproj b/encompass-cs/encompass-cs.csproj index 9fda87b..67ada2d 100644 --- a/encompass-cs/encompass-cs.csproj +++ b/encompass-cs/encompass-cs.csproj @@ -1,6 +1,8 @@ netstandard2.0 + 8.0 + true Encompass EncompassECS.Framework 0.20.0 @@ -26,5 +28,6 @@ + diff --git a/test/ComponentTest.cs b/test/ComponentTest.cs index 1b94e51..9c6e2e7 100644 --- a/test/ComponentTest.cs +++ b/test/ComponentTest.cs @@ -2,14 +2,14 @@ using NUnit.Framework; using FluentAssertions; using Encompass; +using System.Runtime.CompilerServices; namespace Tests { public class ComponentTests { - struct MockComponent : Encompass.IComponent + struct MockComponent : IComponent { - public string myString; public int myInt; } @@ -26,7 +26,7 @@ namespace Tests { public override void Update(double dt) { - foreach (var entityMessage in ReadMessages()) + foreach (ref readonly var entityMessage in ReadMessages()) { gottenMockComponent = GetComponent(entityMessage.entity); } @@ -45,25 +45,27 @@ namespace Tests { public override void Update(double dt) { - foreach (var addComponentTestMessage in ReadMessages()) + foreach (ref readonly var addComponentTestMessage in ReadMessages()) { Assert.IsTrue(HasComponent(addComponentTestMessage.entity)); - Assert.That(GetComponent(addComponentTestMessage.entity), Is.EqualTo(addComponentTestMessage.mockComponent)); + ref readonly var gottenComponent = ref GetComponent(addComponentTestMessage.entity); + gottenComponent.Should().BeEquivalentTo(addComponentTestMessage.mockComponent); } } } [Test] - public void AddComponent() + public unsafe void AddComponent() { var worldBuilder = new WorldBuilder(); worldBuilder.AddEngine(new AddComponentTestEngine()); var entity = worldBuilder.CreateEntity(); + const string MyString = "hello"; + MockComponent mockComponent; mockComponent.myInt = 3; - mockComponent.myString = "hello"; worldBuilder.SetComponent(entity, mockComponent); @@ -85,16 +87,15 @@ namespace Tests worldBuilder.AddEngine(new ReadMockComponentEngine()); var entity = worldBuilder.CreateEntity(); - worldBuilder.SetComponent(entity, new MockComponent { myInt = 20, myString = "what" }); - worldBuilder.SetComponent(entity, new MockComponent { myInt = 50, myString = "hi" }); - worldBuilder.SetComponent(entity, new MockComponent { myInt = 40, myString = "wassup" }); + worldBuilder.SetComponent(entity, new MockComponent { myInt = 20 }); + worldBuilder.SetComponent(entity, new MockComponent { myInt = 50 }); + worldBuilder.SetComponent(entity, new MockComponent { myInt = 40 }); var world = worldBuilder.Build(); world.Update(0.01); Assert.That(gottenMockComponent.myInt, Is.EqualTo(40)); - Assert.That(gottenMockComponent.myString, Is.EqualTo("wassup")); } [Reads(typeof(MockComponent))] @@ -103,8 +104,9 @@ namespace Tests { public override void Update(double dt) { - foreach (var (mockComponent, entity) in ReadComponentsIncludingEntity()) + foreach (ref readonly var entity in ReadEntities()) { + ref readonly var mockComponent = ref GetComponent(entity); SetComponent(entity, new MockComponent { myInt = mockComponent.myInt + 1 }); } } @@ -149,8 +151,9 @@ namespace Tests { public override void Update(double dt) { - foreach (var (mockComponent, entity) in ReadComponentsIncludingEntity()) + foreach (ref readonly var entity in ReadEntities()) { + ref readonly var mockComponent = ref GetComponent(entity); SetComponent(entity, mockComponent); RemoveComponent(entity); } @@ -191,7 +194,6 @@ namespace Tests { MockComponent mockComponent; mockComponent.myInt = 10; - mockComponent.myString = "four"; AddMockComponentMessage addMockComponentMessage; addMockComponentMessage.entity = entity; @@ -207,7 +209,7 @@ namespace Tests { public override void Update(double dt) { - foreach (var message in ReadMessages()) + foreach (ref readonly var message in ReadMessages()) { SetComponent(message.entity, message.mockComponent); } @@ -255,9 +257,8 @@ namespace Tests MockComponent mockComponent; mockComponent.myInt = 3; - mockComponent.myString = "hello"; - worldBuilder.SetComponent(entity, mockComponent); + worldBuilder.SetComponent(entity, mockComponent); EntityMessage entityMessage; entityMessage.entity = entity; @@ -281,7 +282,7 @@ namespace Tests { public override void Update(double dt) { - foreach (var hasComponentTestEngine in ReadMessages()) + foreach (ref readonly var hasComponentTestEngine in ReadMessages()) { Assert.IsTrue(HasComponent(hasComponentTestEngine.entity)); } @@ -298,7 +299,6 @@ namespace Tests MockComponent mockComponent; mockComponent.myInt = 3; - mockComponent.myString = "hello"; worldBuilder.SetComponent(entity, mockComponent); @@ -319,7 +319,7 @@ namespace Tests { public override void Update(double dt) { - foreach (var hasComponentTestEngine in ReadMessages()) + foreach (ref readonly var hasComponentTestEngine in ReadMessages()) { hasComponentRuntimeTypeResult = HasComponent(hasComponentTestEngine.entity, typeof(MockComponent)); } @@ -336,7 +336,6 @@ namespace Tests MockComponent mockComponent; mockComponent.myInt = 3; - mockComponent.myString = "hello"; worldBuilder.SetComponent(entity, mockComponent); @@ -382,7 +381,7 @@ namespace Tests { public override void Update(double dt) { - foreach (var removeComponentMessage in ReadMessages()) + foreach (ref readonly var removeComponentMessage in ReadMessages()) { RemoveComponent(removeComponentMessage.entity); } @@ -427,7 +426,7 @@ namespace Tests { public override void Update(double dt) { - foreach (var checkHasMockComponentMessage in ReadMessages()) + foreach (ref readonly var checkHasMockComponentMessage in ReadMessages()) { hasComponentResult = HasComponent(checkHasMockComponentMessage.entity); } @@ -446,7 +445,6 @@ namespace Tests MockComponent mockComponent; mockComponent.myInt = 3; - mockComponent.myString = "hello"; worldBuilder.SetComponent(entity, mockComponent); @@ -477,7 +475,7 @@ namespace Tests { public override void Update(double dt) { - foreach (var checkHasMockComponentMessage in ReadMessages()) + foreach (ref readonly var checkHasMockComponentMessage in ReadMessages()) { Assert.IsTrue(HasComponent(checkHasMockComponentMessage.entity)); } diff --git a/test/EngineTest.cs b/test/EngineTest.cs index 77ceeb1..c5621fe 100644 --- a/test/EngineTest.cs +++ b/test/EngineTest.cs @@ -13,26 +13,25 @@ namespace Tests struct MockComponent : IComponent { public int myInt; - public string myString; } public class EngineTest { - static List resultComponents; + static MockComponent[] resultComponents; static MockComponent resultComponent; - static List resultMessages = new List(); + static MockMessage[] resultMessages; [Reads(typeof(MockComponent))] public class ReadComponentsTestEngine : Engine { public override void Update(double dt) { - resultComponents = ReadComponents().ToList(); + resultComponents = ReadComponents().ToArray(); } } - static List<(MockComponent, Entity)> resultComponentsIncludingEntity; + static List<(MockComponent, Entity)> resultComponentsIncludingEntity = new List<(MockComponent, Entity)>(); static (MockComponent, Entity) resultComponentIncludingEntity; [Reads(typeof(MockComponent))] @@ -40,7 +39,11 @@ namespace Tests { public override void Update(double dt) { - resultComponentsIncludingEntity = ReadComponentsIncludingEntity().ToList(); + foreach (ref readonly var entity in ReadEntities()) + { + ref readonly var mockComponent = ref GetComponent(entity); + resultComponentsIncludingEntity.Add((mockComponent, entity)); + } } } @@ -58,7 +61,9 @@ namespace Tests { public override void Update(double dt) { - resultComponentIncludingEntity = ReadComponentIncludingEntity(); + ref readonly var entity = ref ReadEntity(); + ref readonly var mockComponent = ref GetComponent(entity); + resultComponentIncludingEntity = (mockComponent, entity); } } @@ -72,12 +77,10 @@ namespace Tests var entityB = worldBuilder.CreateEntity(); MockComponent mockComponent; - mockComponent.myInt = 0; - mockComponent.myString = "hello"; + mockComponent.myInt = 2; MockComponent mockComponentB; mockComponentB.myInt = 1; - mockComponentB.myString = "howdy"; worldBuilder.SetComponent(entity, mockComponent); worldBuilder.SetComponent(entityB, mockComponentB); @@ -93,6 +96,8 @@ namespace Tests [Test] public void ReadComponentsIncludingEntity() { + resultComponentsIncludingEntity.Clear(); + var worldBuilder = new WorldBuilder(); worldBuilder.AddEngine(new ReadComponentsIncludingEntityEngine()); @@ -100,12 +105,10 @@ namespace Tests var entityB = worldBuilder.CreateEntity(); MockComponent mockComponent; - mockComponent.myInt = 0; - mockComponent.myString = "hello"; + mockComponent.myInt = 2; MockComponent mockComponentB; mockComponentB.myInt = 1; - mockComponentB.myString = "howdy"; worldBuilder.SetComponent(entity, mockComponent); worldBuilder.SetComponent(entityB, mockComponentB); @@ -135,8 +138,7 @@ namespace Tests var entity = worldBuilder.CreateEntity(); MockComponent mockComponent; - mockComponent.myInt = 0; - mockComponent.myString = "hello"; + mockComponent.myInt = 3; worldBuilder.SetComponent(entity, mockComponent); @@ -157,12 +159,10 @@ namespace Tests var entityB = worldBuilder.CreateEntity(); MockComponent mockComponent; - mockComponent.myInt = 0; - mockComponent.myString = "hello"; + mockComponent.myInt = 2; MockComponent mockComponentB; mockComponentB.myInt = 1; - mockComponentB.myString = "howdy"; worldBuilder.SetComponent(entity, mockComponent); worldBuilder.SetComponent(entityB, mockComponentB); @@ -183,8 +183,7 @@ namespace Tests var entity = worldBuilder.CreateEntity(); MockComponent mockComponent; - mockComponent.myInt = 0; - mockComponent.myString = "hello"; + mockComponent.myInt = 2; worldBuilder.SetComponent(entity, mockComponent); @@ -201,11 +200,8 @@ namespace Tests { public override void Update(double dt) { - var (component, entity) = ReadComponentIncludingEntity(); - - component.myInt = 420; - component.myString = "blaze it"; - SetComponent(entity, component); + ref readonly var entity = ref ReadEntity(); + SetComponent(entity, new MockComponent { myInt = 420 }); } } @@ -222,8 +218,7 @@ namespace Tests var entity = worldBuilder.CreateEntity(); MockComponent mockComponent; - mockComponent.myInt = 0; - mockComponent.myString = "hello"; + mockComponent.myInt = 3; worldBuilder.SetComponent(entity, mockComponent); @@ -233,7 +228,6 @@ namespace Tests world.Update(0.01); Assert.AreEqual(420, resultComponent.myInt); - Assert.AreEqual("blaze it", resultComponent.myString); } [Reads(typeof(MockComponent))] @@ -241,13 +235,8 @@ namespace Tests { public override void Update(double dt) { - var (component, entity) = ReadComponentIncludingEntity(); - - component.myInt = 420; - component.myString = "blaze it"; - SetComponent(entity, component); - - component = ReadComponent(); + ref readonly var entity = ref ReadEntity(); + SetComponent(entity, new MockComponent { myInt = 420 }); } } @@ -260,8 +249,7 @@ namespace Tests var entity = worldBuilder.CreateEntity(); MockComponent mockComponent; - mockComponent.myInt = 0; - mockComponent.myString = "hello"; + mockComponent.myInt = 3; worldBuilder.SetComponent(entity, mockComponent); @@ -293,7 +281,7 @@ namespace Tests { public override void Update(double dt) { - resultMessages = this.ReadMessages().ToList(); + resultMessages = ReadMessages().ToArray(); } } @@ -322,14 +310,14 @@ namespace Tests } } - static IEnumerable emptyReadMessagesResult; + static MockMessage[] emptyReadMessagesResult; [Receives(typeof(MockMessage))] class ReadMessagesWhenNoneExistEngine : Engine { public override void Update(double dt) { - emptyReadMessagesResult = ReadMessages(); + emptyReadMessagesResult = ReadMessages().ToArray(); } } @@ -578,10 +566,10 @@ namespace Tests { public override void Update(double dt) { - var components = ReadComponentsIncludingEntity(); + var entities = ReadEntities(); - pairA = components.First(); - pairB = components.Last(); + pairA = (GetComponent(entities[0]), entities[0]); + pairB = (GetComponent(entities[1]), entities[1]); } } @@ -594,11 +582,9 @@ namespace Tests MockComponent componentA; componentA.myInt = 20; - componentA.myString = "hello"; MockComponent componentB; componentB.myInt = 20; - componentB.myString = "hello"; var entity = worldBuilder.CreateEntity(); worldBuilder.SetComponent(entity, componentA); @@ -613,14 +599,12 @@ namespace Tests Assert.That(EngineTest.pairA.Item1, Is.EqualTo(EngineTest.pairB.Item1)); } - static IEnumerable<(MockComponent, Entity)> emptyComponentReadResult; - [Reads(typeof(MockComponent))] class ReadEmptyMockComponentsEngine : Engine { public override void Update(double dt) { - emptyComponentReadResult = ReadComponentsIncludingEntity(); + ReadEntities().ToArray().Should().BeEmpty(); } } @@ -632,8 +616,6 @@ namespace Tests var world = worldBuilder.Build(); world.Update(0.01f); - - Assert.That(emptyComponentReadResult, Is.Empty); } struct DestroyerComponent : IComponent { } @@ -643,21 +625,27 @@ namespace Tests { public override void Update(double dt) { - foreach (var (component, entity) in ReadComponentsIncludingEntity()) + foreach (ref readonly var entity in ReadEntities()) { Destroy(entity); } } } - static List<(MockComponent, Entity)> results; + static List<(MockComponent, Entity)> results = new List<(MockComponent, Entity)>(); [Reads(typeof(MockComponent))] class ReaderEngine : Engine { public override void Update(double dt) { - results = ReadComponentsIncludingEntity().ToList(); + results.Clear(); + + foreach (ref readonly var entity in ReadEntities()) + { + ref readonly var mockComponent = ref GetComponent(entity); + results.Add((mockComponent, entity)); + } } } @@ -675,7 +663,6 @@ namespace Tests DestroyerComponent destroyerComponent; MockComponent mockComponent; mockComponent.myInt = 2; - mockComponent.myString = "blah"; worldBuilder.SetComponent(entity, destroyerComponent); worldBuilder.SetComponent(entity, mockComponent); @@ -700,7 +687,7 @@ namespace Tests { public override void Update(double dt) { - foreach (var message in ReadMessages()) + foreach (ref readonly var message in ReadMessages()) { Destroy(message.entity); } @@ -710,6 +697,8 @@ namespace Tests [Test] public void DestroyEntityWithoutID() { + results.Clear(); + var worldBuilder = new WorldBuilder(); worldBuilder.AddEngine(new AddComponentEngine()); worldBuilder.AddEngine(new DestroyEntityEngine()); @@ -733,7 +722,7 @@ namespace Tests { public override void Update(double dt) { - foreach (var (componentPair, entity) in ReadComponentsIncludingEntity()) + foreach (ref readonly var entity in ReadEntities()) { RemoveComponent(entity); Destroy(entity); @@ -765,7 +754,7 @@ namespace Tests { public override void Update(double dt) { - foreach (var (mockComponent, entity) in ReadComponentsIncludingEntity()) + foreach (ref readonly var entity in ReadEntities()) { RemoveComponent(entity); SetComponent(entity, new MockComponent()); @@ -780,7 +769,7 @@ namespace Tests { public override void Update(double dt) { - var (_, entity) = ReadComponentIncludingEntity(); + ref readonly var entity = ref ReadEntity(); } } @@ -805,7 +794,7 @@ namespace Tests { public override void Update(double dt) { - foreach (var (component, entity) in ReadComponentsIncludingEntity()) + foreach (ref readonly var entity in ReadEntities()) { RemoveComponent(entity); SendMessage(new MockMessage { }, 1); @@ -816,7 +805,7 @@ namespace Tests [Test] public void EngineSendMessageDelayed() { - resultMessages.Clear(); + Array.Clear(resultMessages, 0, resultMessages.Length); var worldBuilder = new WorldBuilder(); worldBuilder.AddEngine(new ActivateTimeDilationEngine()); @@ -852,7 +841,7 @@ namespace Tests { public override void Update(double dt) { - foreach (var (component, entity) in ReadComponentsIncludingEntity()) + foreach (ref readonly var entity in ReadEntities()) { RemoveComponent(entity); SendMessageIgnoringTimeDilation(new MockMessage { }, 1); @@ -863,7 +852,7 @@ namespace Tests [Test] public void EngineSendMessageDelayedIgnoringTimeDilation() { - resultMessages.Clear(); + Array.Clear(resultMessages, 0, resultMessages.Length); var worldBuilder = new WorldBuilder(); worldBuilder.AddEngine(new ActivateTimeDilationEngine()); @@ -896,7 +885,7 @@ namespace Tests { public override void Update(double dt) { - foreach (var message in ReadMessages()) + foreach (ref readonly var message in ReadMessages()) { var entity = CreateEntity(); SetComponent(entity, new MockComponent { }); @@ -977,12 +966,12 @@ namespace Tests struct MockComponentB : IComponent { + private int value; + public MockComponentB(int value) { this.value = value; } - - int value; } static MockComponentB getComponentResult; @@ -1134,7 +1123,7 @@ namespace Tests { public override void Update(double dt) { - foreach (var (_, entity) in ReadComponentsIncludingEntity()) + foreach (ref readonly var entity in ReadEntities()) { RemoveComponent(entity); } @@ -1329,8 +1318,7 @@ namespace Tests { public override void Update(double dt) { - var (component, entity) = ReadComponentIncludingEntity(); - + ref readonly var entity = ref ReadEntity(); AddComponent(entity, new MockComponent()); } } @@ -1364,8 +1352,7 @@ namespace Tests { public override void Update(double dt) { - var (component, entity) = ReadComponentIncludingEntity(); - + ref readonly var component = ref ReadComponent(); getComponentResult = component; } } @@ -1811,7 +1798,7 @@ namespace Tests } public override void Update(double dt) { - _components.AddRange(ReadComponents()); + _components.AddRange(ReadComponents().ToArray()); } } @@ -1847,12 +1834,11 @@ namespace Tests public override void Update(double dt) { - foreach (var (component, entity) in ReadComponentsIncludingEntity()) + foreach (ref readonly var entity in ReadEntities()) { if (HasComponent(entity)) { _components.Add(GetComponent(entity)); - } } } @@ -1879,12 +1865,12 @@ namespace Tests struct MockTimerComponent : IComponent { + public double Timer { get; } + public MockTimerComponent(double time) { Timer = time; } - - public double Timer { get; set; } } [Reads(typeof(MockTimerComponent))] @@ -1893,19 +1879,18 @@ namespace Tests { public override void Update(double dt) { - foreach (var (component, entity) in ReadComponentsIncludingEntity()) + foreach (ref readonly var entity in ReadEntities()) { - var updatedComponent = component; - updatedComponent.Timer -= dt; + ref readonly var component = ref GetComponent(entity); - if (updatedComponent.Timer <= 0) + if (component.Timer - dt <= 0) { RemoveComponent(entity); } else { - SetComponent(entity, updatedComponent); + SetComponent(entity, new MockTimerComponent(component.Timer - dt)); } } } diff --git a/test/GeneralRendererTest.cs b/test/GeneralRendererTest.cs index bc1aedc..32659c0 100644 --- a/test/GeneralRendererTest.cs +++ b/test/GeneralRendererTest.cs @@ -15,7 +15,8 @@ namespace Tests { public override void Render() { - result = ReadComponentIncludingEntity(); + ref readonly var entity = ref ReadEntity(); + result = (GetComponent(entity), entity); } } diff --git a/test/OrderedRendererTest.cs b/test/OrderedRendererTest.cs index 6f7dc8a..92cb3b8 100644 --- a/test/OrderedRendererTest.cs +++ b/test/OrderedRendererTest.cs @@ -20,13 +20,13 @@ namespace Tests class TestRenderer : OrderedRenderer { - public override void Render(Entity entity, TestDrawComponent testDrawComponent) { } + public override void Render(Entity entity, in TestDrawComponent testDrawComponent) { } } static bool called = false; class DeactivatedRenderer : TestRenderer { - public override void Render(Entity entity, TestDrawComponent testDrawComponent) + public override void Render(Entity entity, in TestDrawComponent testDrawComponent) { called = true; } @@ -37,7 +37,7 @@ namespace Tests class CalledRenderer : OrderedRenderer { - public override void Render(Entity entity, TestDrawComponent testDrawComponent) + public override void Render(Entity entity, in TestDrawComponent testDrawComponent) { resultComponent = (testDrawComponent, entity); calledOnDraw = true; diff --git a/test/WorldBuilderTest.cs b/test/WorldBuilderTest.cs index 2fd62fd..2f3e7d2 100644 --- a/test/WorldBuilderTest.cs +++ b/test/WorldBuilderTest.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using Encompass.Exceptions; using System.Linq; using FluentAssertions; +using System; namespace Tests { @@ -114,7 +115,7 @@ namespace Tests public class MultipleEngineWriteConflict { - struct AComponent : IComponent { } + struct AComponent { } [Writes(typeof(AComponent))] class AEngine : Engine @@ -158,7 +159,7 @@ namespace Tests { public override void Update(double dt) { - foreach (var setMessage in ReadMessages()) + foreach (ref readonly var setMessage in ReadMessages()) { SetComponent(setMessage.entity, new AComponent { myInt = 0 }); } @@ -172,7 +173,7 @@ namespace Tests { public override void Update(double dt) { - foreach (var setMessage in ReadMessages()) + foreach (ref readonly var setMessage in ReadMessages()) { SetComponent(setMessage.entity, new AComponent { myInt = 1 }); } @@ -228,7 +229,7 @@ namespace Tests { public override void Update(double dt) { - foreach (var setMessage in ReadMessages()) + foreach (ref readonly var setMessage in ReadMessages()) { SetComponent(setMessage.entity, new AComponent { myInt = 5 }); } @@ -243,7 +244,7 @@ namespace Tests { public override void Update(double dt) { - foreach (var setMessage in ReadMessages()) + foreach (ref readonly var setMessage in ReadMessages()) { SetComponent(setMessage.entity, new AComponent { myInt = 1 }); } @@ -257,7 +258,7 @@ namespace Tests { public override void Update(double dt) { - foreach (var setMessage in ReadMessages()) + foreach (ref readonly var setMessage in ReadMessages()) { SetComponent(setMessage.entity, new AComponent { myInt = 3 }); } @@ -318,28 +319,6 @@ namespace Tests } } - public class IllegalReadType - { - struct ANonMessage { } - - [Reads(typeof(ANonMessage))] - class MyEngine : Engine - { - public override void Update(double dt) - { - - } - } - - [Test] - public void ThrowsError() - { - var worldBuilder = new WorldBuilder(); - - Assert.Throws(() => worldBuilder.AddEngine(new MyEngine()), "ANonMessage must be a Message or Component"); - } - } - public class IllegalWriteType { struct ANonMessage { } @@ -501,20 +480,22 @@ namespace Tests Assert.That(order.IndexOf(engineC), Is.LessThan(order.IndexOf(engineD))); } - static List resultMessages = new List(); + static AMessage[] resultMessages; [Receives(typeof(AMessage))] class ReadMessageEngine : Engine { public override void Update(double dt) { - resultMessages = ReadMessages().ToList(); + resultMessages = ReadMessages().ToArray(); } } [Test] public void SendMessageDelayed() { + resultMessages = Array.Empty(); + var worldBuilder = new WorldBuilder(); worldBuilder.AddEngine(new ReadMessageEngine()); diff --git a/test/WorldTest.cs b/test/WorldTest.cs index def4165..6ce089b 100644 --- a/test/WorldTest.cs +++ b/test/WorldTest.cs @@ -21,7 +21,7 @@ namespace Tests class TestEntityRenderer : OrderedRenderer { - public override void Render(Entity entity, TestDrawComponent testDrawComponent) + public override void Render(Entity entity, in TestDrawComponent testDrawComponent) { drawOrder.Add(entity); } diff --git a/test/test.csproj b/test/test.csproj index 8f6a401..9479dc3 100644 --- a/test/test.csproj +++ b/test/test.csproj @@ -5,6 +5,7 @@ false Tests EncompassECS.Framework.Tests + true