A rough first draft attempt at a custom message passing system for Unity.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections; | |
using System.Collections.Generic; | |
using UnityEngine; | |
namespace Messaging { | |
public abstract class MessagingBehavior : MonoBehaviour { | |
public delegate void MessageHandler(MessagingBehavior source, object data); | |
private void SendMessage (MessagingBehavior source, GameObject target, string message, object data) { | |
MessageRouter.Inst.SendMessage(source, target, message, data); | |
} | |
protected void SendMessage (GameObject target, string message, object data) { | |
SendMessage(this, target, message, data); | |
} | |
public new void SendMessage(string message, object data) { | |
SendMessage(this, this.gameObject, message, data); | |
} | |
public new void SendMessageUpwards(string message, object data) { | |
SendMessageUpwards(message, data, -1); | |
} | |
public void SendMessageUpwards(string message, object data, int maxLevels) { | |
var currentGameObject = this.gameObject; | |
while (currentGameObject != null) { | |
SendMessage(currentGameObject, message, data); | |
var parentTransform = currentGameObject.transform.parent; | |
if (parentTransform != null) | |
currentGameObject = currentGameObject.transform.parent.gameObject; | |
else | |
currentGameObject = null; | |
} | |
} | |
private void SendMessageUpwards(GameObject currentGameObject, string message, object data, int maxLevels) { | |
if (currentGameObject != null) { | |
SendMessage(currentGameObject, message, data); | |
var parentTransform = currentGameObject.transform.parent; | |
if (parentTransform != null) | |
SendMessageUpwards(parentTransform.gameObject, message, data, maxLevels - 1); | |
} | |
} | |
public void SendMessageDownwards(string message, object data, int maxLevels = -1) { | |
SendMessageDownwards(this.gameObject, message, data, maxLevels); | |
} | |
private void SendMessageDownwards(GameObject currentGameObject, string message, object data, int maxLevels, bool includeCurrent = true) { | |
if (currentGameObject != null) { | |
if (includeCurrent) | |
SendMessage(currentGameObject, message, data); | |
if (maxLevels != 0) { | |
foreach( Transform child in currentGameObject.transform) { | |
SendMessageDownwards(child.gameObject, message, data, maxLevels-1); | |
} | |
} | |
} | |
} | |
public void SendMessageToSiblings(string message, object data) { | |
var parentTransform = transform.parent; | |
if (parentTransform != null) { | |
SendMessageDownwards(parentTransform.gameObject, message, data, 1, false); | |
} | |
} | |
protected void RegisterReceiver (string message, MessageHandler receiver) { | |
MessageRouter.Inst.RegisterReceiver(this.gameObject, message, receiver); | |
} | |
protected void DeregisterReceiver (string message, MessageHandler receiver) { | |
MessageRouter.Inst.DeregisterReceiver(this.gameObject, message, receiver); | |
} | |
protected void DeregisterAll() { | |
MessageRouter.Inst.DeregisterAllReceivers(this.gameObject); | |
} | |
protected void OnDestroy() { | |
OnDestroyCalled(); | |
DeregisterAll(); | |
} | |
public virtual void OnDestroyCalled() {} | |
private class MessageRouter : Singleton<MessageRouter> { | |
private Dictionary<GameObject, Dictionary<string, MessageLink>> routingMap = new Dictionary<GameObject, Dictionary<string, MessageLink>>(); | |
public void RegisterReceiver (GameObject gameObject, string message, MessageHandler receiver) { | |
var messageLink = GetMessageLink(gameObject, message, true); | |
messageLink.MessageEvent += receiver; | |
} | |
public void DeregisterReceiver (GameObject gameObject, string message, MessageHandler receiver) { | |
var messageLink = GetMessageLink(gameObject, message, false); | |
if (messageLink != null) { | |
messageLink.MessageEvent -= receiver; | |
} | |
} | |
public void DeregisterAllReceivers(GameObject gameObject) { | |
var messageMap = GetMessageMap(gameObject, false); | |
if (messageMap != null) { | |
foreach( var messagePair in messageMap ){ | |
messagePair.Value.Empty(); | |
} | |
} | |
routingMap.Remove(gameObject); | |
} | |
public void SendMessage (MessagingBehavior source, GameObject target, string message, object data) { | |
var messageLink = GetMessageLink(target, message, false); | |
if (messageLink != null && !messageLink.IsEmpty) { | |
messageLink.Call(source, data); | |
} | |
} | |
private Dictionary<string, MessageLink> GetMessageMap(GameObject gameObject, bool createIfNotExist) { | |
Dictionary<string, MessageLink> messageMap; | |
if (!routingMap.TryGetValue(gameObject, out messageMap)) { | |
if (!createIfNotExist) | |
return null; | |
routingMap.Add(gameObject, messageMap = new Dictionary<string, MessageLink>()); | |
} | |
return messageMap; | |
} | |
private MessageLink GetMessageLink(GameObject gameObject, string message, bool createIfNotExist) { | |
var messageMap = GetMessageMap(gameObject, createIfNotExist); | |
if (messageMap == null) | |
return null; | |
MessageLink returnLink; | |
if (!messageMap.TryGetValue(message, out returnLink)) { | |
if (!createIfNotExist) | |
return null; | |
messageMap.Add(message, returnLink = new MessageLink()); | |
} | |
return returnLink; | |
} | |
public class MessageLink { | |
public event MessageHandler MessageEvent; | |
public bool IsEmpty {get {return MessageEvent == null;}} | |
public void Call(MessagingBehavior source, object data) { | |
MessageEvent.Invoke(source, data); | |
} | |
public void Empty() { | |
MessageEvent = null; | |
} | |
} | |
} | |
private abstract class Singleton<T> where T : class, new() { | |
private static T instance; | |
private static object instanceLock = new object(); | |
public static T Inst { | |
get { | |
if (instance == null) { | |
lock (instanceLock) { | |
if (instance == null) { | |
instance = new T(); | |
} | |
} | |
} | |
return instance; | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment