using System;
using System.Collections.Generic;
using UnityEngine;
namespace AX.MessageSystem
{
///
/// 消息分发中心。
///
public static class MessageDispatcher
{
internal class Pair
{
public string MessageType;
public Action Handler;
public Pair() { }
public Pair(string messageType, Action handler)
{
MessageType = messageType;
Handler = handler;
}
}
internal const float Immediate = 0.0f;
internal const float NextFrame = -1.0f;
private static Dictionary> filteredHandlers = new Dictionary>();
private static Dictionary> messageHandlers = new Dictionary>();
private static List messages = new List();
public static void Clear()
{
foreach (var pair in filteredHandlers)
pair.Value.Clear();
filteredHandlers.Clear();
messageHandlers.Clear();
messages.Clear();
}
public static void AddListener(string messageType, Action handler)
{
AddListener(messageType, handler, default(string));
}
public static void AddListener(string messageType, Action handler, string filter)
{
if (string.IsNullOrEmpty(messageType) || handler == null)
throw new ArgumentNullException("messageType or handler is not be null.");
if (string.IsNullOrEmpty(filter))
{
if (messageHandlers.ContainsKey(messageType))
messageHandlers[messageType] += handler;
else
messageHandlers[messageType] = handler;
}
else
{
List handlers = null;
if (filteredHandlers.TryGetValue(filter, out handlers))
{
var index = handlers.FindIndex((pair) => pair.MessageType == messageType);
if (index >= 0)
handlers[index].Handler += handler;
else
handlers.Add(new Pair(messageType, handler));
}
else
{
var list = new List();
list.Add(new Pair(messageType, handler));
filteredHandlers.Add(filter, list);
}
}
}
public static void AddListener(string messageType, Action handler, params string[] filters)
{
if (string.IsNullOrEmpty(messageType) || handler == null)
throw new ArgumentNullException("messageType or handler is not be null.");
for (var i = 0; i < filters.Length; ++i)
{
var filter = filters[i];
if (string.IsNullOrEmpty(filter))
{
if (messageHandlers.ContainsKey(messageType))
messageHandlers[messageType] += handler;
else
messageHandlers[messageType] = handler;
}
else
{
List handlers = null;
if (filteredHandlers.TryGetValue(filter, out handlers))
{
var index = handlers.FindIndex((pair) => pair.MessageType == messageType);
if (index >= 0)
handlers[index].Handler += handler;
else
handlers.Add(new Pair(messageType, handler));
}
else
{
var list = new List();
list.Add(new Pair(messageType, handler));
filteredHandlers.Add(filter, list);
}
}
}
}
public static void RemoveListener(string messageType, Action handler)
{
RemoveListener(messageType, handler, default(string));
}
public static void RemoveListener(string messageType, Action handler, string filter)
{
if (string.IsNullOrEmpty(messageType) || handler == null)
throw new ArgumentNullException("messageType or handler is not be null.");
if (string.IsNullOrEmpty(filter))
{
if (messageHandlers.ContainsKey(messageType))
{
messageHandlers[messageType] -= handler;
if (messageHandlers[messageType] == null)
messageHandlers.Remove(messageType);
}
}
else
{
List handlers = null;
if (filteredHandlers.TryGetValue(filter, out handlers))
{
var index = handlers.FindIndex((pair) => pair.MessageType == messageType);
if (index >= 0)
{
handlers[index].Handler -= handler;
if (handlers[index].Handler == null)
handlers.RemoveAt(index);
}
}
}
}
public static void RemoveListener(string messageType, Action handler, params string[] filters)
{
if (string.IsNullOrEmpty(messageType) || handler == null)
throw new ArgumentNullException("messageType or handler is not be null.");
for (var i = 0; i < filters.Length; ++i)
{
var filter = filters[i];
if (string.IsNullOrEmpty(filter))
{
if (messageHandlers.ContainsKey(messageType))
{
messageHandlers[messageType] -= handler;
if (messageHandlers[messageType] == null)
messageHandlers.Remove(messageType);
}
}
else
{
List handlers = null;
if (filteredHandlers.TryGetValue(filter, out handlers))
{
var index = handlers.FindIndex((pair) => pair.MessageType == messageType);
if (index >= 0)
{
handlers[index].Handler -= handler;
if (handlers[index].Handler == null)
handlers.RemoveAt(index);
}
}
}
}
}
public static void Update()
{
//处理延迟消息并决定何时发送它
for (int i = 0; i < messages.Count; i++)
{
var message = messages[i];
message.Delay -= Time.deltaTime;
if (message.Delay < 0)
message.Delay = Immediate;
//是时候发送消息了
if (!message.IsSent && message.Delay == Immediate)
SendMessage(message);
}
//回收发送的消息
for (int i = messages.Count - 1; i >= 0; i--)
{
var message = messages[i];
if (message.IsSent || message.IsHandled)
{
messages.RemoveAt(i);
Message.Release((Message)message);
}
}
}
public static void SendMessage(IMessage message)
{
if (message == null || string.IsNullOrEmpty(message.Type))
throw new ArgumentNullException("message");
bool missing = true;
// 处理延迟消息
if (message.Delay > 0 || message.Delay < 0)
{
messages.Add(message);
missing = false;
}
else if (message.Filters == null)
{
Action action = null;
if (messageHandlers.TryGetValue(message.Type, out action))
{
//触发消息回调
message.IsSent = true;
action(message);
message.IsHandled = true;
missing = false;
}
}
else
{
for (var i = 0; i < message.Filters.Length; ++i)
{
var filter = message.Filters[i];
if (string.IsNullOrEmpty(filter))
{
Action action = null;
if (messageHandlers.TryGetValue(message.Type, out action))
{
message.IsSent = true;
action(message);
message.IsHandled = true;
missing = false;
}
}
else
{
List handlers = null;
if (filteredHandlers.TryGetValue(filter, out handlers))
{
var index = handlers.FindIndex((pair) => pair.MessageType == message.Type);
if (index >= 0)
{
message.IsSent = true;
handlers[index].Handler(message);
message.IsHandled = true;
missing = false;
}
}
}
}
}
//如果没有对应的接收方
if (missing)
{
if (Application.isEditor)
Debug.LogError("[MessageSystem] 该消息类型 { " + message.Type + " } 没有对应的接收方处理。");
message.IsSent = true;
message.IsHandled = true;
}
}
public static void SendMessage(string type)
{
SendMessage(null, type, default(object), Immediate, default(string));
}
// 注释掉下面方法的原因是开发人员经常使用发送数据的方法
// 但编译器会定位方法重载到这里
// 这导致了非必要的排错
// 如果想要延迟发送,请使用下面更精确的重载方法
//public static void SendMessage(string type, string filter)
//{
// SendMessage(null, type, default(object), Immediate, filter);
//}
// public static void SendMessage(string type, float delay)
// {
// SendMessage(null, type, default(object), delay, default(string));
// }
// public static void SendMessage(string type, float delay, string filter)
// {
// SendMessage(null, type, default(object), delay, filter);
// }
public static void SendMessage(string type, object data)
{
SendMessage(null, type, data, Immediate, default(string));
}
public static void SendMessage(string type, object data, string filter)
{
SendMessage(null, type, data, Immediate, filter);
}
public static void SendMessage(string type, object data, float delay)
{
SendMessage(null, type, data, delay, default(string));
}
public static void SendMessage(string type, object data, float delay, string filter)
{
SendMessage(null, type, data, delay, filter);
}
public static void SendMessage(object sender, string type)
{
SendMessage(sender, type, default(object), Immediate, default(string));
}
//public static void SendMessage(object sender, string type, float delay)
//{
// SendMessage(sender, type, default(object), delay, default(string));
//}
public static void SendMessage(object sender, string type, string filter)
{
SendMessage(sender, type, default(object), Immediate, filter);
}
public static void SendMessage(object sender, string type, float delay, string filter)
{
SendMessage(sender, type, default(object), delay, filter);
}
public static void SendMessage(object sender, string type, object data)
{
SendMessage(sender, type, data, Immediate, default(string));
}
public static void SendMessage(object sender, string type, object data, float delay)
{
SendMessage(sender, type, data, delay, default(string));
}
public static void SendMessage(object sender, string type, object data, string filter)
{
SendMessage(sender, type, data, Immediate, filter);
}
public static void SendMessage(object sender, string type, object data, float delay, string filter)
{
var message = Message.Acquire();
message.Sender = sender;
message.Type = type;
message.Data = data;
message.Delay = delay;
if (!string.IsNullOrEmpty(filter))
message.Filters = new string[] { filter };
SendMessage(message);
if (delay == Immediate)
Message.Release(message);
}
public static void SendMessage(object sender, string type, object data, float delay, params string[] filters)
{
var message = Message.Acquire();
message.Sender = sender;
message.Type = type;
message.Data = data;
message.Delay = delay;
if (filters != null)
message.Filters = filters;
SendMessage(message);
if (delay == Immediate)
Message.Release(message);
}
}
}