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); } } }