88 lines
2.0 KiB
C#
88 lines
2.0 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
|
|
namespace Game.Shared.Events;
|
|
|
|
public sealed class InMemoryEventBus : IEventBus
|
|
{
|
|
private readonly Dictionary<Type, List<Delegate>> _handlers = [];
|
|
private readonly object _lock = new();
|
|
|
|
public IDisposable Subscribe<TEvent>(Action<TEvent> handler) where TEvent : IEvent
|
|
{
|
|
ArgumentNullException.ThrowIfNull(handler);
|
|
|
|
var eventType = typeof(TEvent);
|
|
|
|
lock (_lock)
|
|
{
|
|
if (!_handlers.TryGetValue(eventType, out var list))
|
|
{
|
|
list = [];
|
|
_handlers[eventType] = list;
|
|
}
|
|
|
|
list.Add(handler);
|
|
}
|
|
|
|
return new EventSubscription(() => Unsubscribe(eventType, handler));
|
|
}
|
|
|
|
public void Publish<TEvent>(TEvent gameEvent) where TEvent : IEvent
|
|
{
|
|
ArgumentNullException.ThrowIfNull(gameEvent);
|
|
|
|
List<Delegate> snapshot = null;
|
|
var eventType = typeof(TEvent);
|
|
|
|
lock (_lock)
|
|
{
|
|
if (_handlers.TryGetValue(eventType, out var list))
|
|
{
|
|
snapshot = new List<Delegate>(list);
|
|
}
|
|
}
|
|
|
|
if (snapshot == null) return;
|
|
|
|
foreach (var subscriber in snapshot)
|
|
{
|
|
((Action<TEvent>)subscriber)(gameEvent);
|
|
}
|
|
}
|
|
|
|
private void Unsubscribe(Type eventType, Delegate handler)
|
|
{
|
|
lock (_lock)
|
|
{
|
|
if (!_handlers.TryGetValue(eventType, out var list)) return;
|
|
|
|
list.Remove(handler);
|
|
|
|
if (list.Count == 0)
|
|
{
|
|
_handlers.Remove(eventType);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void Clear()
|
|
{
|
|
lock (_lock)
|
|
{
|
|
_handlers.Clear();
|
|
}
|
|
}
|
|
|
|
private sealed class EventSubscription(Action unsubscribeAction) : IDisposable
|
|
{
|
|
private Action _unsubscribeAction = unsubscribeAction;
|
|
|
|
public void Dispose()
|
|
{
|
|
_unsubscribeAction?.Invoke();
|
|
_unsubscribeAction = null;
|
|
}
|
|
}
|
|
}
|