using UnityEngine; using System.Collections; using MalbersAnimations.Scriptables; #if UNITY_EDITOR using UnityEditorInternal; using UnityEditor; #endif namespace MalbersAnimations.Utilities { [AddComponentMenu("Malbers/Events/Messages")] public class Messages : MonoBehaviour { public MesssageItem[] messages; //Store messages to send it when Enter the animation State public bool UseSendMessage = true; public bool SendToChildren = true; public bool debug = true; public bool nextFrame = false; public Component Pinned; /// Send all the messages to a gameobject public virtual void SendMessage(GameObject component) => SendMessage(component.transform); /// Store the Receiver of the messages public virtual void Pin_Receiver(GameObject component) => Pinned = component.transform; /// Store the Receiver of the messages public virtual void Pin_Receiver(Component component) => Pinned = component; /// Send a message by its index to the stored receiver public virtual void SendMessage(int index) { if (nextFrame) this.Delay_Action(() => Deliver(messages[index], Pinned)); else Deliver(messages[index], Pinned); } public virtual void SendMessageByIndex(int index) => SendMessage(index); public virtual void SendMessage(Component go) { Pinned = go; foreach (var m in messages) { if (nextFrame) this.Delay_Action(() => Deliver(m, Pinned)); else Deliver(m, Pinned); } } private void Deliver(MesssageItem m, Component go) { if (UseSendMessage) m.DeliverMessage(go, SendToChildren, debug); else { IAnimatorListener[] listeners; if (SendToChildren) listeners = go.GetComponentsInChildren(); else listeners = go.GetComponents(); if (listeners != null && listeners.Length > 0) { foreach (var animListeners in listeners) m.DeliverAnimListener(animListeners,debug); } } } //#if UNITY_EDITOR // private void OnDrawGizmosSelected() // { // DrawInteration(true); // } // private void OnDrawGizmos() // { // DrawInteration(false); // } // private void DrawInteration(bool Selected) // { // foreach (var msg in messages) // { // Transform t = null; // if (msg.typeM == TypeMessage.Transform && !msg.transformValue.gameObject.IsPrefab()) t = msg.transformValue; // else if (msg.typeM == TypeMessage.Component && !msg.ComponentValue.gameObject.IsPrefab()) t = msg.ComponentValue.transform; // else if (msg.typeM == TypeMessage.GameObject && !msg.GoValue.IsPrefab()) t = msg.GoValue.transform; // if (t) MalbersEditor.DrawInteraction(transform.position, t.position, Selected, Color.white); // } // } //#endif } [System.Serializable] public class MesssageItem { public string message; public TypeMessage typeM; public bool boolValue; public int intValue; public float floatValue; public string stringValue; public IntVar intVarValue; public Transform transformValue; public GameObject GoValue; public Component ComponentValue; public float time; public bool sent; public bool Active = true; public MesssageItem() { message = string.Empty; Active = true; } public bool IsActive => Active && !string.IsNullOrEmpty(message); public void DeliverAnimListener(IAnimatorListener listener, bool debug = false) { if (!IsActive) return; //Mean the Message cannot be sent string val = ""; bool succesful = false; switch (typeM) { case TypeMessage.Bool: succesful = listener.OnAnimatorBehaviourMessage(message, boolValue); val = boolValue.ToString(); break; case TypeMessage.Int: succesful = listener.OnAnimatorBehaviourMessage(message, intValue); val = intValue.ToString(); break; case TypeMessage.Float: succesful = listener.OnAnimatorBehaviourMessage(message, floatValue); val = floatValue.ToString(); break; case TypeMessage.String: succesful = listener.OnAnimatorBehaviourMessage(message, stringValue); val = stringValue.ToString(); break; case TypeMessage.Void: succesful = listener.OnAnimatorBehaviourMessage(message, null); val = "Void"; break; case TypeMessage.IntVar: succesful = listener.OnAnimatorBehaviourMessage(message, (int)intVarValue); val = intVarValue.name.ToString(); break; case TypeMessage.Transform: succesful = listener.OnAnimatorBehaviourMessage(message, transformValue); val = transformValue.name.ToString(); break; case TypeMessage.GameObject: succesful = listener.OnAnimatorBehaviourMessage(message, GoValue); val = GoValue.name.ToString(); break; case TypeMessage.Component: succesful = listener.OnAnimatorBehaviourMessage(message, ComponentValue); val = GoValue.name.ToString(); break; default: break; } if (debug && succesful) Debug.Log($"[AnimMsg: {message}->{val}] [{typeM}] T:{Time.time:F3}"); //Debug } /// Using Message to the Monovehaviours asociated to this animator delivery with Send Message public void DeliverMessage(Component anim, bool SendToChildren, bool debug = false) { if (!IsActive) return; //Mean the Message cannot be sent switch (typeM) { case TypeMessage.Bool: SendMessage(anim, message, boolValue, SendToChildren); break; case TypeMessage.Int: SendMessage(anim, message, intValue, SendToChildren); break; case TypeMessage.Float: SendMessage(anim, message, floatValue, SendToChildren); break; case TypeMessage.String: SendMessage(anim, message, stringValue, SendToChildren); break; case TypeMessage.Void: SendMessageVoid(anim, message, SendToChildren); break; case TypeMessage.IntVar: SendMessage(anim, message, (int)intVarValue, SendToChildren); break; case TypeMessage.Transform: SendMessage(anim, message, transformValue, SendToChildren); break; case TypeMessage.GameObject: SendMessage(anim, message, GoValue, SendToChildren); break; case TypeMessage.Component: SendMessage(anim, message, ComponentValue, SendToChildren); break; default: break; } if (debug) Debug.Log($"[Send Msg: {message}->] [{typeM}] T:{Time.time:F3}", anim); //Debug } private void SendMessage(Component anim, string message, object value, bool SendToChildren) { if (SendToChildren) anim.BroadcastMessage(message, value, SendMessageOptions.DontRequireReceiver); else anim.SendMessage(message, value, SendMessageOptions.DontRequireReceiver); } private void SendMessageVoid(Component anim, string message, bool SendToChildren) { if (SendToChildren) anim.BroadcastMessage(message, SendMessageOptions.DontRequireReceiver); else anim.SendMessage(message, SendMessageOptions.DontRequireReceiver); } } #if UNITY_EDITOR [CustomPropertyDrawer(typeof(MesssageItem))] public class MessageDrawer : PropertyDrawer { public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { // position.y += 2; EditorGUI.BeginProperty(position, label, property); //GUI.Box(position, GUIContent.none, EditorStyles.helpBox); var indent = EditorGUI.indentLevel; EditorGUI.indentLevel = 0; //var height = EditorGUIUtility.singleLineHeight; //PROPERTIES var Active = property.FindPropertyRelative("Active"); var message = property.FindPropertyRelative("message"); var typeM = property.FindPropertyRelative("typeM"); var rect = new Rect(position); rect.y += 2; Rect R_0 = new Rect(rect.x, rect.y, 15, EditorGUIUtility.singleLineHeight); EditorGUI.PropertyField(R_0, Active, GUIContent.none); Rect R_1 = new Rect(rect.x + 15, rect.y, (rect.width / 3) + 15, EditorGUIUtility.singleLineHeight); EditorGUI.PropertyField(R_1, message, GUIContent.none); Rect R_3 = new Rect(rect.x + ((rect.width) / 3) + 5 + 30, rect.y, ((rect.width) / 3) - 5 - 15, EditorGUIUtility.singleLineHeight); EditorGUI.PropertyField(R_3, typeM, GUIContent.none); Rect R_5 = new Rect(rect.x + ((rect.width) / 3) * 2 + 5 + 15, rect.y, ((rect.width) / 3) - 5 - 15, EditorGUIUtility.singleLineHeight); var TypeM = (TypeMessage)typeM.intValue; SerializedProperty messageValue = property.FindPropertyRelative("boolValue"); switch (TypeM) { case TypeMessage.Bool: messageValue.boolValue = EditorGUI.ToggleLeft(R_5, messageValue.boolValue ? " True" : " False", messageValue.boolValue); break; case TypeMessage.Int: messageValue = property.FindPropertyRelative("intValue"); break; case TypeMessage.Float: messageValue = property.FindPropertyRelative("floatValue"); break; case TypeMessage.String: messageValue = property.FindPropertyRelative("stringValue"); break; case TypeMessage.IntVar: messageValue = property.FindPropertyRelative("intVarValue"); break; case TypeMessage.Transform: messageValue = property.FindPropertyRelative("transformValue"); break; case TypeMessage.Void: break; case TypeMessage.GameObject: messageValue = property.FindPropertyRelative("GoValue"); break; case TypeMessage.Component: messageValue = property.FindPropertyRelative("ComponentValue"); break; default: break; } if (TypeM != TypeMessage.Void && TypeM != TypeMessage.Bool) { EditorGUI.PropertyField(R_5, messageValue, GUIContent.none); } EditorGUI.indentLevel = indent; EditorGUI.EndProperty(); } } //INSPECTOR [CustomEditor(typeof(Messages))] public class MessagesEd : Editor { private ReorderableList list; // private Messages MMessage; private SerializedProperty sp_messages, debug, nextFrame, SendToChildren, UseSendMessage; private void OnEnable() { sp_messages = serializedObject.FindProperty("messages"); debug = serializedObject.FindProperty("debug"); SendToChildren = serializedObject.FindProperty("SendToChildren"); UseSendMessage = serializedObject.FindProperty("UseSendMessage"); nextFrame = serializedObject.FindProperty("nextFrame"); list = new ReorderableList(serializedObject, sp_messages, true, true, true, true) { drawHeaderCallback = HeaderCallbackDelegate1, drawElementCallback = ( rect, index, isActive, isFocused) => { EditorGUI.PropertyField(rect, sp_messages.GetArrayElementAtIndex(index), GUIContent.none); } }; } public override void OnInspectorGUI() { serializedObject.Update(); MalbersEditor.DrawDescription("Send messages to scripts with the [IAnimatorListener] interface. " + "Enable [SendMessage] to use Component.SendMessage() instead."); EditorGUILayout.BeginVertical(MTools.StyleGray); { list.DoLayoutList(); EditorGUILayout.BeginHorizontal(); var currentGUIColor = GUI.color; GUI.color = SendToChildren.boolValue ? (Color.green) : currentGUIColor; SendToChildren.boolValue = GUILayout.Toggle(SendToChildren.boolValue, new GUIContent("Children", "The Messages will be sent also to the gameobject children"), EditorStyles.miniButton); GUI.color = UseSendMessage.boolValue ? (Color.green) : currentGUIColor; UseSendMessage.boolValue = GUILayout.Toggle(UseSendMessage.boolValue, new GUIContent("SendMessage()", "Uses the SendMessage() method, instead of checking for IAnimator Listener Interfaces"), EditorStyles.miniButton); GUI.color = currentGUIColor; if (nextFrame != null) { GUI.color = nextFrame.boolValue ? (Color.green) : currentGUIColor; nextFrame.boolValue = GUILayout.Toggle(nextFrame.boolValue, new GUIContent("Next Frame", "Waits for the next frame to send the messages"), EditorStyles.miniButton); GUI.color = currentGUIColor; } MalbersEditor.DrawDebugIcon(debug); EditorGUILayout.EndHorizontal(); } EditorGUILayout.EndVertical(); serializedObject.ApplyModifiedProperties(); } static void HeaderCallbackDelegate1(Rect rect) { var width = (rect.width / 3); var height = EditorGUIUtility.singleLineHeight; Rect R_1 = new Rect(rect.x + 10, rect.y, width + 30, height); EditorGUI.LabelField(R_1, "Message"); Rect R_3 = new Rect(rect.x + 10 + width + 5 + 30, rect.y, width - 20, height); EditorGUI.LabelField(R_3, "Type"); Rect R_5 = new Rect(rect.x + 10 + width * 2 + 20, rect.y, width - 20, height); EditorGUI.LabelField(R_5, "Value"); } } #endif }