Skip to content

Instantly share code, notes, and snippets.

@SradnickDev
Last active April 7, 2022 01:48
Show Gist options
  • Save SradnickDev/e051871b27282d190086a08140a271db to your computer and use it in GitHub Desktop.
Save SradnickDev/e051871b27282d190086a08140a271db to your computer and use it in GitHub Desktop.
Static generic message hub / message system.
using System;
using System.Collections.Generic;
using UnityEngine;
public interface IMessage { }
public static class MessageHub
{
public delegate void MessageSubscription<in T>(T message) where T : IMessage;
private const int MaxPublishDepth = 10;
private static int m_publishDepth = 0;
private static readonly HashSet<Type> m_subscribedTypes = new HashSet<Type>();
private static class TypedMessageHub<TMessage> where TMessage : IMessage
{
private const int DefaultBufferSize = 10;
private static readonly List<MessageSubscription<TMessage>> m_subscriptions = new List<MessageSubscription<TMessage>>(DefaultBufferSize);
private static readonly List<MessageSubscription<TMessage>> m_buffer = new List<MessageSubscription<TMessage>>(DefaultBufferSize);
public static void Subscribe(MessageSubscription<TMessage> subscription)
{
m_subscriptions.Add(subscription);
}
public static void Unsubscribe(MessageSubscription<TMessage> subscription)
{
m_subscriptions.Remove(subscription);
}
public static void Publish(TMessage message)
{
if (m_subscriptions.Count > m_buffer.Count)
{
m_buffer.Capacity = m_subscriptions.Count * 2;
}
var iSubscriptionCount = m_subscriptions.Count;
for (var i = 0; i < iSubscriptionCount; i++)
{
m_buffer.Add(m_subscriptions[i]);
}
for (var i = 0; i < iSubscriptionCount; i++)
{
m_buffer[i]?.Invoke(message);
}
m_buffer.Clear();
}
public static void Clear()
{
m_subscriptions.Clear();
}
}
public static void Subscribe<T>(MessageSubscription<T> subscription) where T : IMessage
{
m_subscribedTypes.Add(typeof(T));
TypedMessageHub<T>.Subscribe(subscription);
}
public static void Unsubscribe<T>(MessageSubscription<T> subscription) where T : IMessage
{
TypedMessageHub<T>.Unsubscribe(subscription);
}
public static void Publish<T>(T message) where T : IMessage
{
m_publishDepth++;
if (m_publishDepth < MaxPublishDepth)
{
TypedMessageHub<T>.Publish(message);
m_publishDepth--;
}
else
{
Debug.LogError("[MessageHub] Max publish depth reached, make sure you don't stuck in an infinity publishing loop, otherwise increase max depth.");
}
}
public static void Clear<T>() where T : IMessage
{
TypedMessageHub<T>.Clear();
}
public static void ClearAll()
{
foreach (var subscribedType in m_subscribedTypes)
{
var type = typeof(TypedMessageHub<>).MakeGenericType(subscribedType);
var methodInfo = type.GetMethod("Clear");
methodInfo?.Invoke(null, null);
}
}
}
//--------------- Example ---------------
public class GameEventMessage : IMessage
{
public int SomeValue;
public GameObject Fo;
}
public class Example : MonoBehaviour
{
private void OnEnable()
{
MessageHub.Subscribe<GameEventMessage>(OnGameEventMessageReceived);
MessageHub.Publish(new GameEventMessage()
{
Fo = this.gameObject,
SomeValue = 10
});
}
private void OnDisable()
{
MessageHub.Unsubscribe<GameEventMessage>(OnGameEventMessageReceived);
}
public void OnGameEventMessageReceived(GameEventMessage message)
{
var value = message.SomeValue;
var target = message.Fo;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment