Skip to content

Instantly share code, notes, and snippets.

@nbrosz
Created December 11, 2017 03:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nbrosz/a0544d3196765d739f5729bffe6e5b18 to your computer and use it in GitHub Desktop.
Save nbrosz/a0544d3196765d739f5729bffe6e5b18 to your computer and use it in GitHub Desktop.
A rough first draft attempt at a custom message passing system for Unity.
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