encompass-cs/encompass-cs/Collections/TypedMessageStore.cs

131 lines
4.0 KiB
C#

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<TMessage> : 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<int, List<int>> _entityToIndices = new Dictionary<int, List<int>>();
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<int>()); }
_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<TMessage> All()
{
return new ReadOnlySpan<TMessage>(_store, 0, _nextIndex);
}
public IEnumerable<TMessage> 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();
}
}
}
}