using System; using System.Collections.Generic; namespace Encompass { internal abstract class TypedMessageStore { public abstract void ProcessDelayedMessages(double dilatedDelta, double realtimeDelta); public abstract void Clear(); } internal class TypedMessageStore : TypedMessageStore where TMessage : struct, IMessage { // 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 (var i = _delayedStore.Count - 1; i >= 0; i--) { var (message, time) = _delayedStore[i]; var updatedTime = time - dilatedDelta; if (updatedTime <= 0) { Add(message); _delayedStore.RemoveAt(i); } else { _delayedStore[i] = (message, updatedTime); } } for (var i = _delayedStoreIgnoringTimeDilation.Count - 1; i >= 0; i--) { var (message, time) = _delayedStoreIgnoringTimeDilation[i]; var updatedTime = time - realtimeDelta; if (updatedTime <= 0) { Add(message); _delayedStoreIgnoringTimeDilation.RemoveAt(i); } else { _delayedStoreIgnoringTimeDilation[i] = (message, updatedTime); } } } public void Add(in TMessage 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 (!_entityToIndices.ContainsKey(entityID)) { _entityToIndices.Add(entityID, new List()); } _entityToIndices[entityID].Add(index); } } public void Add(in TMessage message, double time) { _delayedStore.Add((message, time)); } public void AddIgnoringTimeDilation(in TMessage message, double time) { _delayedStoreIgnoringTimeDilation.Add((message, time)); } public ref readonly TMessage First() { return ref _store[0]; } public bool Any() { return _nextIndex != 0; } public ReadOnlySpan All() { return new ReadOnlySpan(_store, 0, _nextIndex); } public IEnumerable WithEntity(int entityID) { 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 _entityToIndices.ContainsKey(entityID) && _entityToIndices[entityID].Count > 0; } public override void Clear() { _nextIndex = 0; foreach (var set in _entityToIndices.Values) { set.Clear(); } } } }