How does unity send its messages all over the place?

For example, if you use network. All the gameobjects components will have the functions OnPlayerConnected, OnPlayerDisconnected, etc called on them.

I would like to know how, because I would like to send messages myself all over the place.

Atm I am using a root gameobject called “Game” and I do broadcastmessage on that one. Many people say that using broadcastmessage/sendmessage is really slow. ( I understand why it is slow ). So I was wondering what unity does internally to have this effect?

@Lucas says they used reflection. See his answer’s here. and comments at the end of this blog.

If you’re not using SendMessage rapidly in performance-sensitive areas, it’s OK.

I don’t use it not because it’s slow, but because it makes my codes and designs ugly (string literals are a no-no for me…)

If you want a better approach sending messages, consider using delegates. If you want to globally send events, consider using some sort of an event manager, here’s what I used in my uFAction

using System;
using System.Linq;
using System.Reflection;
//using Fasterflect;

namespace uFAction
{
	/// <summary>
	/// A generic event system based on C#'s delegates
	/// Subscribe (add), unsubscribe (remove) and raise (fire) GameEvents
	/// Derive from GameEvent to create your own events
	/// (There's no target differentiation here nor any other constraint, you could target anything)
	/// </summary>
	public static class EventManager
	{
		/// <summary>
		/// Subscribe (add) a handler to the GameEvent specified by the generic argument `T`
		/// </summary>
		/// <typeparam name="T">The type of GameEvent to unsubscribe from</typeparam>
		/// <param name="handler">The handler that wants to unsubscribe (the handler to be removed)</param>
		public static void Subscribe<T>(Action<T> handler) where T : GameEvent
		{
			EventManagerInternal<T>.Subscribe(handler);
		}

		/// <summary>
		/// Unubscribe (remove) a handler to the GameEvent specified by the generic argument `T`
		/// </summary>
		/// <typeparam name="T">The type of GameEvent to subscribe to</typeparam>
		/// <param name="handler">The handler to subscribe (the handler to be added)</param>
		public static void Unsubscribe<T>(Action<T> handler) where T : GameEvent
		{
			EventManagerInternal<T>.Unsubscribe(handler);
		}

		/// <summary>
		/// Raises the specified event - Resolves the event type at runtime (uses faster flect cached reflection)
		/// </summary>
		public static void DynamicRaise(GameEvent e)
		{
			var type = typeof(EventManagerInternal<>);
			var eventType = e.GetType();
			var genType = type.MakeGenericType(eventType);
			var raise = genType.GetMethod("Raise", BindingFlags.Public | BindingFlags.Static);
			raise.Invoke(null, new object[] { e });

			// if you have Fasterflect, you could call the method like this for better performance
			//var raise = genType.DelegateForCallMethod("Raise", Flags.StaticPublic, eventType);
			//raise(null, e);
		}

		/// <summary>
		/// Raise (fire) the GameEvent specified by the generic argument `T`
		/// </summary>
		/// <typeparam name="T">The type of GameEvent to be raised</typeparam>
		public static void Raise<T>(T e) where T : GameEvent
		{
			EventManagerInternal<T>.Raise(e);
		}

		/// <summary>
		/// Clears the GameEvent delegate
		/// </summary>
		public static void Clear<T>() where T : GameEvent
		{
			EventManagerInternal<T>.Clear();
		}

		/// <summary>
		/// Returns true if the specified handler is contained in the GameEvent's delegate invocation list
		/// </summary>
		public static bool Contains<T>(Action<T> handler) where T : GameEvent
		{
			return EventManagerInternal<T>.Contains(handler);
		}

		/// <summary>
		/// Rasies the game event 'e' to all handlers except the ones specified
		/// </summary>
		public static void RaiseToAllExcept<T>(T e, params Action<T>[] handlers) where T : GameEvent
		{
			EventManagerInternal<T>.RaiseToAllExcept(e, handlers);
		}

		/// <summary>
		/// Raises the game event 'e' only to the specified handlers
		/// </summary>
		public static void RaiseToOnly<T>(T e, params Action<T>[] handlers) where T : GameEvent
		{
			EventManagerInternal<T>.RaiseToOnly(e, handlers);
		}

		/// <summary>
		/// The internal event manager class - do not be afraid, doing a:
		/// EventManagerInternal`Event1`.Sub(...); and EventManagerInternal`Event2`.Sub(...);
		/// the compiler will _not_ create two seperate classes - they will use the same place in memory!
		/// If you don't know what I'm talking about, see Jamie King's: https://www.youtube.com/watch?v=9eZnUk0Gu7M 
		/// </summary>
		private static class EventManagerInternal<T> where T : GameEvent
		{
			private static Action<T> action;

			public static void Subscribe(Action<T> handler)
			{
				action += handler;
			}

			public static void Unsubscribe(Action<T> handler)
			{
				action -= handler;
			}

			public static void Raise(T e)
			{
				if (action != null)
					action(e);
			}

			public static void RaiseToAllExcept(T e, params Action<T>[] handlers)
			{
				var toInvoke = from d in action.GetInvocationList()
							   where !handlers.Contains(d)
							   select (Action<T>)d;

				foreach (var handler in toInvoke)
					handler(e);
			}

			public static void RaiseToOnly(T e, params Action<T>[] handlers)
			{
				foreach (var h in handlers)
					h(e);
			}

			public static void Clear()
			{
				action = null;
			}

			public static bool Contains(Action<T> handler)
			{
				if (action == null)
					return false;

				return action.GetInvocationList().Any(d => d.Equals(handler));
			}
		}
	}
}

namespace uFAction
{
	/// <summary>
	/// An abstract base class for creating events - derive from it to create your own game events to use
	/// in the generic event system, EventManager.
	/// </summary>
	public abstract class GameEvent
	{
	}
}

See the doc in the link ^ for usage examples.

You basically create an event:

public class OnPlayerDied : GameEvent
{
   public GameObject Player { get; set; }
   public MoreInfo info { get; set; }
}

Listen to that event:

public class GameManager : MonoBehaviour
{
   void OnEnable() { EventManager.Subscribe<OnPlayerDied>(DeathHandler); }
   void OnEnable() { EventManager.Unsubscribe<OnPlayerDied>(DeathHandler); }
   void DeathHandler(OnPlayerDied arg)
   {
      print("Player + " arg.Player.name + " has died");
   }
}

And raise the event somewhere:

public class Player : MonoBehaviour
{
   private int health;
   public int Health
   {
      get { return health; }
      set { 
          health = value; 
          if (health <= 0) 
             EventManager.Raise(new OnPlayerDied { Player = gameObject, MoreInfo = new MoreInfo(...) });
       }
}