123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457 |
- #if UNITY_EDITOR
- using UnityEngine;
- using UnityEditor;
- using System.Collections.Generic;
- using System.Linq;
- using UnityEditorInternal;
- using System.Reflection;
- using System;
-
- namespace VRCSDK2
- {
- public static class VRC_EditorTools
- {
- private static LayerMask LayerMaskPopupInternal(LayerMask selectedValue, System.Func<int, string[], int> showMask)
- {
- string[] layerNames = InternalEditorUtility.layers;
- List<int> layerNumbers = new List<int>();
-
- foreach (string layer in layerNames)
- layerNumbers.Add(LayerMask.NameToLayer(layer));
-
- int mask = 0;
- for (int idx = 0; idx < layerNumbers.Count; ++idx)
- if (((1 << layerNumbers[idx]) & selectedValue.value) > 0)
- mask |= (1 << idx);
-
- mask = showMask(mask, layerNames);
-
- selectedValue.value = 0;
- for (int idx = 0; idx < layerNumbers.Count; ++idx)
- if (((1 << idx) & mask) > 0)
- selectedValue.value |= (1 << layerNumbers[idx]);
-
- return selectedValue;
- }
-
- public static LayerMask LayerMaskPopup(LayerMask selectedValue, params GUILayoutOption[] options)
- {
- return LayerMaskPopupInternal(selectedValue, (mask, layerNames) => EditorGUILayout.MaskField(mask, layerNames, options));
- }
-
- public static LayerMask LayerMaskPopup(string label, LayerMask selectedValue, params GUILayoutOption[] options)
- {
- return LayerMaskPopupInternal(selectedValue, (mask, layerNames) => EditorGUILayout.MaskField(label, mask, layerNames, options));
- }
-
- public static LayerMask LayerMaskPopup(Rect rect, LayerMask selectedValue, GUIStyle style = null)
- {
- System.Func<int, string[], int> show = (mask, layerNames) =>
- {
- if (style == null)
- return EditorGUI.MaskField(rect, mask, layerNames);
- else
- return EditorGUI.MaskField(rect, mask, layerNames, style);
- };
- return LayerMaskPopupInternal(selectedValue, show);
- }
-
- public static LayerMask LayerMaskPopup(Rect rect, string label, LayerMask selectedValue, GUIStyle style = null)
- {
- System.Func<int, string[], int> show = (mask, layerNames) =>
- {
- if (style == null)
- return EditorGUI.MaskField(rect, label, mask, layerNames);
- else
- return EditorGUI.MaskField(rect, label, mask, layerNames, style);
- };
- return LayerMaskPopupInternal(selectedValue, show);
- }
-
- private static T FilteredEnumPopupInternal<T>(T selectedValue, System.Func<T, bool> predicate, System.Func<int, string[], int> showPopup, System.Func<string, string> rename) where T : struct, System.IConvertible
- {
- if (!typeof(T).IsEnum)
- throw new System.ArgumentException(typeof(T).Name + " is not an Enum", "T");
-
- T[] ary = System.Enum.GetValues(typeof(T)).Cast<T>().Where(v => predicate(v)).ToArray();
- string[] names = ary.Select(e => System.Enum.GetName(typeof(T), e)).ToArray();
-
- int selectedIdx = 0;
- for (; selectedIdx < ary.Length; ++selectedIdx)
- if (ary[selectedIdx].Equals(selectedValue))
- break;
- if (selectedIdx == ary.Length)
- selectedIdx = 0;
-
- if (ary.Length == 0)
- throw new System.ArgumentException("Predicate filtered out all options", "predicate");
-
- if (rename != null)
- return ary[showPopup(selectedIdx, names.Select(rename).ToArray())];
- else
- return ary[showPopup(selectedIdx, names)];
- }
-
- private static void FilteredEnumPopupInternal<T>(SerializedProperty enumProperty, System.Func<T, bool> predicate, System.Func<int, string[], int> showPopup, System.Func<string, string> rename) where T : struct, System.IConvertible
- {
- string selectedName = enumProperty.enumNames[enumProperty.enumValueIndex];
- T selectedValue = FilteredEnumPopupInternal<T>((T)System.Enum.Parse(typeof(T), selectedName), predicate, showPopup, rename);
- selectedName = selectedValue.ToString();
- for (int idx = 0; idx < enumProperty.enumNames.Length; ++idx)
- if (enumProperty.enumNames[idx] == selectedName)
- {
- enumProperty.enumValueIndex = idx;
- break;
- }
- }
-
- public static T FilteredEnumPopup<T>(string label, T selectedValue, System.Func<T, bool> predicate, System.Func<string, string> rename = null, params GUILayoutOption[] options) where T : struct, System.IConvertible
- {
- return FilteredEnumPopupInternal(selectedValue, predicate, (selectedIdx, names) => EditorGUILayout.Popup(label, selectedIdx, names, options), rename);
- }
-
- public static T FilteredEnumPopup<T>(T selectedValue, System.Func<T, bool> predicate, System.Func<string, string> rename = null, params GUILayoutOption[] options) where T : struct, System.IConvertible
- {
- return FilteredEnumPopupInternal(selectedValue, predicate, (selectedIdx, names) => EditorGUILayout.Popup(selectedIdx, names, options), rename);
- }
-
- public static T FilteredEnumPopup<T>(Rect rect, string label, T selectedValue, System.Func<T, bool> predicate, System.Func<string, string> rename = null, GUIStyle style = null) where T : struct, System.IConvertible
- {
- System.Func<int, string[], int> show = (selectedIdx, names) =>
- {
- if (style != null)
- return EditorGUI.Popup(rect, label, selectedIdx, names, style);
- else
- return EditorGUI.Popup(rect, label, selectedIdx, names);
- };
- return FilteredEnumPopupInternal(selectedValue, predicate, show, rename);
- }
-
- public static T FilteredEnumPopup<T>(Rect rect, T selectedValue, System.Func<T, bool> predicate, System.Func<string, string> rename = null, GUIStyle style = null) where T : struct, System.IConvertible
- {
- System.Func<int, string[], int> show = (selectedIdx, names) =>
- {
- if (style != null)
- return EditorGUI.Popup(rect, selectedIdx, names, style);
- else
- return EditorGUI.Popup(rect, selectedIdx, names);
- };
- return FilteredEnumPopupInternal(selectedValue, predicate, show, rename);
- }
-
- public static void FilteredEnumPopup<T>(string label, SerializedProperty selectedValue, System.Func<T, bool> predicate, System.Func<string, string> rename = null, params GUILayoutOption[] options) where T : struct, System.IConvertible
- {
- FilteredEnumPopupInternal(selectedValue, predicate, (selectedIdx, names) => EditorGUILayout.Popup(label, selectedIdx, names, options), rename);
- }
-
- public static void FilteredEnumPopup<T>(SerializedProperty selectedValue, System.Func<T, bool> predicate, System.Func<string, string> rename = null, params GUILayoutOption[] options) where T : struct, System.IConvertible
- {
- FilteredEnumPopupInternal(selectedValue, predicate, (selectedIdx, names) => EditorGUILayout.Popup(selectedIdx, names, options), rename);
- }
-
- public static void FilteredEnumPopup<T>(Rect rect, string label, SerializedProperty selectedValue, System.Func<T, bool> predicate, System.Func<string, string> rename = null, GUIStyle style = null) where T : struct, System.IConvertible
- {
- System.Func<int, string[], int> show = (selectedIdx, names) =>
- {
- if (style != null)
- return EditorGUI.Popup(rect, label, selectedIdx, names, style);
- else
- return EditorGUI.Popup(rect, label, selectedIdx, names);
- };
- FilteredEnumPopupInternal(selectedValue, predicate, show, rename);
- }
-
- public static void FilteredEnumPopup<T>(Rect rect, SerializedProperty selectedValue, System.Func<T, bool> predicate, System.Func<string, string> rename = null, GUIStyle style = null) where T : struct, System.IConvertible
- {
- System.Func<int, string[], int> show = (selectedIdx, names) =>
- {
- if (style != null)
- return EditorGUI.Popup(rect, selectedIdx, names, style);
- else
- return EditorGUI.Popup(rect, selectedIdx, names);
- };
- FilteredEnumPopupInternal(selectedValue, predicate, show, rename);
- }
-
- private static VRC_Trigger.TriggerEvent CustomTriggerPopupInternal(VRC_Trigger sourceTrigger, VRC_Trigger.TriggerEvent selectedValue, System.Func<int, string[], int> show)
- {
- if (sourceTrigger == null)
- return null;
-
- VRC_Trigger.TriggerEvent[] actionsAry = sourceTrigger.Triggers.Where(t => t.TriggerType == VRC_Trigger.TriggerType.Custom).ToArray();
- string[] names = actionsAry.Select(t => t.Name).ToArray();
-
- int selectedIdx = Math.Max(0, names.Length - 1);
- if (selectedValue != null)
- for (; selectedIdx > 0; --selectedIdx)
- if (names[selectedIdx] == selectedValue.Name)
- break;
- if (actionsAry.Length == 0)
- return null;
-
- return actionsAry[show(selectedIdx, names)];
- }
-
- public static VRC_Trigger.TriggerEvent CustomTriggerPopup(Rect rect, VRC_Trigger sourceTrigger, VRC_Trigger.TriggerEvent selectedValue, GUIStyle style = null)
- {
- System.Func<int, string[], int> show = (selectedIdx, names) =>
- {
- if (style != null)
- return EditorGUI.Popup(rect, selectedIdx, names, style);
- else
- return EditorGUI.Popup(rect, selectedIdx, names);
- };
-
- return CustomTriggerPopupInternal(sourceTrigger, selectedValue, show);
- }
-
- public static VRC_Trigger.TriggerEvent CustomTriggerPopup(Rect rect, string label, VRC_Trigger sourceTrigger, VRC_Trigger.TriggerEvent selectedValue, GUIStyle style = null)
- {
- System.Func<int, string[], int> show = (selectedIdx, names) =>
- {
- if (style != null)
- return EditorGUI.Popup(rect, label, selectedIdx, names, style);
- else
- return EditorGUI.Popup(rect, label, selectedIdx, names);
- };
-
- return CustomTriggerPopupInternal(sourceTrigger, selectedValue, show);
- }
-
- public static VRC_Trigger.TriggerEvent CustomTriggerPopup(VRC_Trigger sourceTrigger, VRC_Trigger.TriggerEvent selectedValue, params GUILayoutOption[] options)
- {
- return CustomTriggerPopupInternal(sourceTrigger, selectedValue, (selectedIdx, names) => EditorGUILayout.Popup(selectedIdx, names, options));
- }
-
- public static VRC_Trigger.TriggerEvent CustomTriggerPopup(string label, VRC_Trigger sourceTrigger, VRC_Trigger.TriggerEvent selectedValue, params GUILayoutOption[] options)
- {
- return CustomTriggerPopupInternal(sourceTrigger, selectedValue, (selectedIdx, names) => EditorGUILayout.Popup(label, selectedIdx, names, options));
- }
-
- public static VRC_Trigger.TriggerEvent CustomTriggerPopup(string label, VRC_Trigger sourceTrigger, string selectedValue, params GUILayoutOption[] options)
- {
- if (sourceTrigger == null)
- return null;
-
- return CustomTriggerPopup(label, sourceTrigger, sourceTrigger.Triggers.FirstOrDefault(t => t.TriggerType == VRC_Trigger.TriggerType.Custom && t.Name == selectedValue), options);
- }
-
- public static VRC_Trigger.TriggerEvent CustomTriggerPopup(VRC_Trigger sourceTrigger, string selectedValue, params GUILayoutOption[] options)
- {
- if (sourceTrigger == null)
- return null;
-
- return CustomTriggerPopup(sourceTrigger, sourceTrigger.Triggers.FirstOrDefault(t => t.TriggerType == VRC_Trigger.TriggerType.Custom && t.Name == selectedValue), options);
- }
-
- public static VRC_Trigger.TriggerEvent CustomTriggerPopup(Rect rect, VRC_Trigger sourceTrigger, string selectedValue, GUIStyle style = null)
- {
- if (sourceTrigger == null)
- return null;
-
- return CustomTriggerPopup(rect, sourceTrigger, sourceTrigger.Triggers.FirstOrDefault(t => t.TriggerType == VRC_Trigger.TriggerType.Custom && t.Name == selectedValue), style);
- }
-
- public static VRC_Trigger.TriggerEvent CustomTriggerPopup(Rect rect, string label, VRC_Trigger sourceTrigger, string selectedValue, GUIStyle style = null)
- {
- if (sourceTrigger == null)
- return null;
-
- return CustomTriggerPopup(rect, label, sourceTrigger, sourceTrigger.Triggers.FirstOrDefault(t => t.TriggerType == VRC_Trigger.TriggerType.Custom && t.Name == selectedValue), style);
- }
-
- private static void InternalSerializedCustomTriggerPopup(SerializedProperty triggersProperty, SerializedProperty customProperty, System.Func<int, string[], int> show, System.Action fail)
- {
- if (customProperty == null || (customProperty.propertyType != SerializedPropertyType.String))
- throw new ArgumentException("Expected a string for customProperty");
- if (triggersProperty == null || (!triggersProperty.isArray && triggersProperty.propertyType != SerializedPropertyType.ObjectReference))
- throw new ArgumentException("Expected an object or array for triggersProperty");
-
- List<String> customNames = new List<string>();
- bool allNull = true;
-
- if (triggersProperty.isArray)
- {
- int idx;
- for (idx = 0; idx < triggersProperty.arraySize; ++idx)
- {
- GameObject obj = triggersProperty.GetArrayElementAtIndex(idx).objectReferenceValue as GameObject;
- if (obj != null)
- {
- customNames = obj.GetComponent<VRC_Trigger>().Triggers.Where(t => t.TriggerType == VRC_Trigger.TriggerType.Custom).Select(t => t.Name).ToList();
- allNull = false;
- break;
- }
- }
- for (; idx < triggersProperty.arraySize; ++idx)
- {
- GameObject obj = triggersProperty.GetArrayElementAtIndex(idx).objectReferenceValue as GameObject;
- if (obj != null)
- {
- List<string> thisCustomNames = obj.GetComponent<VRC_Trigger>().Triggers.Where(t => t.TriggerType == VRC_Trigger.TriggerType.Custom).Select(t => t.Name).ToList();
- customNames.RemoveAll(s => thisCustomNames.Contains(s) == false);
- }
- }
- }
- else
- {
- GameObject obj = triggersProperty.objectReferenceValue as GameObject;
- if (obj != null)
- {
- allNull = false;
- customNames = obj.GetComponent<VRC_Trigger>().Triggers.Where(t => t.TriggerType == VRC_Trigger.TriggerType.Custom).Select(t => t.Name).ToList();
- }
- }
-
- if (customNames.Count == 0 && !allNull && triggersProperty.isArray)
- {
- fail();
- customProperty.stringValue = "";
- }
- else
- {
- if (customNames.Count == 0)
- customNames.Add("");
-
- int selectedIdx = Math.Max(0, customNames.Count - 1);
- if (!string.IsNullOrEmpty(customProperty.stringValue))
- for (; selectedIdx > 0; --selectedIdx)
- if (customNames[selectedIdx] == customProperty.stringValue)
- break;
-
- selectedIdx = show(selectedIdx, customNames.ToArray());
- customProperty.stringValue = customNames[selectedIdx];
- }
- }
-
- public static void CustomTriggerPopup(string label, SerializedProperty triggersProperty, SerializedProperty customProperty, params GUILayoutOption[] options)
- {
- InternalSerializedCustomTriggerPopup(triggersProperty, customProperty, (idx, names) => EditorGUILayout.Popup(label, idx, names, options), () => EditorGUILayout.HelpBox("Receivers do not have Custom Triggers which share names.", MessageType.Warning));
- }
-
- public static void CustomTriggerPopup(SerializedProperty triggersProperty, SerializedProperty customProperty, params GUILayoutOption[] options)
- {
- InternalSerializedCustomTriggerPopup(triggersProperty, customProperty, (idx, names) => EditorGUILayout.Popup(idx, names, options), () => EditorGUILayout.HelpBox("Receivers do not have Custom Triggers which share names.", MessageType.Warning));
- }
-
- public static void CustomTriggerPopup(Rect rect, SerializedProperty triggersProperty, SerializedProperty customProperty, GUIStyle style = null)
- {
- InternalSerializedCustomTriggerPopup(triggersProperty, customProperty, (idx, names) => style == null ? EditorGUI.Popup(rect, idx, names) : EditorGUI.Popup(rect, idx, names, style), () => EditorGUI.HelpBox(rect, "Receivers do not have Custom Triggers which share names.", MessageType.Warning));
- }
-
- public static void CustomTriggerPopup(Rect rect, string label, SerializedProperty triggersProperty, SerializedProperty customProperty, GUIStyle style = null)
- {
- InternalSerializedCustomTriggerPopup(triggersProperty, customProperty, (idx, names) => style == null ? EditorGUI.Popup(rect, label, idx, names) : EditorGUI.Popup(rect, label, idx, names, style), () => EditorGUI.HelpBox(rect, "Receivers do not have Custom Triggers which share names.", MessageType.Warning));
- }
-
- public static void DrawTriggerActionCallback(string actionLabel, VRC_Trigger trigger, VRC_EventHandler.VrcEvent e)
- {
- VRC_Trigger.TriggerEvent triggerEvent = VRC_EditorTools.CustomTriggerPopup(actionLabel, trigger, e.ParameterString);
- e.ParameterString = triggerEvent == null ? null : triggerEvent.Name;
- }
-
- public static Dictionary<string, List<MethodInfo>> GetSharedAccessibleMethodsOnGameObjects(SerializedProperty objectsProperty)
- {
- Dictionary<string, List<MethodInfo>> methods = new Dictionary<string, List<MethodInfo>>();
-
- int idx = 0;
- for (; idx < objectsProperty.arraySize; ++idx)
- {
- SerializedProperty prop = objectsProperty.GetArrayElementAtIndex(idx);
- GameObject obj = prop.objectReferenceValue != null ? prop.objectReferenceValue as GameObject : null;
- if (obj != null)
- {
- methods = VRC_EditorTools.GetAccessibleMethodsOnGameObject(obj);
- break;
- }
- }
- List<string> toRemove = new List<string>();
- for (; idx < objectsProperty.arraySize; ++idx)
- {
- SerializedProperty prop = objectsProperty.GetArrayElementAtIndex(idx);
- GameObject obj = prop.objectReferenceValue != null ? prop.objectReferenceValue as GameObject : null;
- if (obj != null)
- {
- Dictionary<string, List<MethodInfo>> thisObjMethods = VRC_EditorTools.GetAccessibleMethodsOnGameObject(obj);
- foreach (string className in methods.Keys.Where(s => thisObjMethods.Keys.Contains(s) == false))
- toRemove.Add(className);
- }
- }
-
- foreach (string className in toRemove)
- methods.Remove(className);
-
- return methods;
- }
-
- public static Dictionary<string, List<MethodInfo>> GetAccessibleMethodsOnGameObject(GameObject go)
- {
- Dictionary<string, List<MethodInfo>> methods = new Dictionary<string, List<MethodInfo>>();
- if (go == null)
- return methods;
-
- Component[] cs = go.GetComponents<Component>();
- if (cs == null)
- return methods;
-
- foreach (Component c in cs.Where(co => co != null))
- {
- Type t = c.GetType();
-
- if (methods.ContainsKey(t.Name))
- continue;
-
- // if component is the eventhandler
- if (t == typeof(VRC_EventHandler))
- continue;
-
- List<MethodInfo> l = GetAccessibleMethodsForClass(t);
- methods.Add(t.Name, l);
- }
-
- return methods;
- }
-
- public static List<MethodInfo> GetAccessibleMethodsForClass(Type t)
- {
- // Get the public methods.
- MethodInfo[] myArrayMethodInfo = t.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
- List<MethodInfo> methods = new List<MethodInfo>();
-
- // if component is in UnityEngine namespace, skip it
- if (!string.IsNullOrEmpty(t.Namespace) && (t.Namespace.Contains("UnityEngine") || t.Namespace.Contains("UnityEditor")))
- return methods;
-
- bool isVRCSDK2 = !string.IsNullOrEmpty(t.Namespace) && t.Namespace.Contains("VRCSDK2");
-
- // Display information for all methods.
- for (int i = 0; i < myArrayMethodInfo.Length; i++)
- {
- MethodInfo myMethodInfo = (MethodInfo)myArrayMethodInfo[i];
-
- // if it's VRCSDK2, require RPC
- if (isVRCSDK2 && myMethodInfo.GetCustomAttributes(typeof(VRCSDK2.RPC), true).Length == 0)
- continue;
-
- methods.Add(myMethodInfo);
- }
- return methods;
- }
-
- public static byte[] ReadBytesFromProperty(SerializedProperty property)
- {
- byte[] bytes = new byte[property.arraySize];
- for (int idx = 0; idx < property.arraySize; ++idx)
- bytes[idx] = (byte)property.GetArrayElementAtIndex(idx).intValue;
- return bytes;
- }
-
- public static void WriteBytesToProperty(SerializedProperty property, byte[] bytes)
- {
- property.arraySize = bytes != null ? bytes.Length : 0;
- for (int idx = 0; idx < property.arraySize; ++idx)
- property.GetArrayElementAtIndex(idx).intValue = (int)bytes[idx];
- }
- }
- }
- #endif
|