Exemple #1
0
        private void RenderHelpBox(SerializedProperty prop)
        {
            var helpBoxAttr = UTUtils.GetPropertyAttribute <HelpBoxAttribute>(prop);

            if (helpBoxAttr != null)
            {
                UTStyles.RenderNote(helpBoxAttr.text);
            }
        }
Exemple #2
0
        private void RenderStackedArray(string name, SerializedProperty prop, SerializedProperty otherProp,
                                        string addMethod, string addText, string changedCallback)
        {
            prop.isExpanded = UTStyles.FoldoutHeader($"{name} [{prop.arraySize}]", prop.isExpanded);
            if (!prop.isExpanded)
            {
                return;
            }
            for (int i = 0; i < prop.arraySize; i++)
            {
                EditorGUILayout.BeginHorizontal();
                if (RenderPositionControls(i, new[] { prop, otherProp }))
                {
                    break;
                }

                EditorGUI.BeginChangeCheck();
                EditorGUILayout.PropertyField(prop.GetArrayElementAtIndex(i), new GUIContent());
                EditorGUILayout.PropertyField(otherProp.GetArrayElementAtIndex(i), new GUIContent());
                if (EditorGUI.EndChangeCheck())
                {
                    HandleChangeCallback(t, changedCallback, prop, otherProp, new object[] { prop.GetArrayElementAtIndex(i), otherProp.GetArrayElementAtIndex(i), i });
                }

                if (RenderRemoveControls(i, new[] { prop, otherProp }))
                {
                    HandleChangeCallback(t, changedCallback, prop, otherProp, new object[] { null, null, i });
                    break;
                }

                EditorGUILayout.EndHorizontal();
            }

            if (RenderAddControls(new[] { prop, otherProp }, addText, addMethod))
            {
                HandleChangeCallback(t, changedCallback, prop, otherProp, new object[] { prop.GetArrayElementAtIndex(prop.arraySize - 1), otherProp.GetArrayElementAtIndex(otherProp.arraySize - 1), prop.arraySize - 1 });
            }
        }
Exemple #3
0
        private void RenderArray(SerializedProperty prop, string changedCallback)
        {
            var formatted = Regex.Split(prop.name, @"(?<!^)(?=[A-Z])");

            formatted[0]    = formatted[0].Substring(0, 1).ToUpper() + formatted[0].Substring(1);
            prop.isExpanded = UTStyles.FoldoutHeader($"{String.Join(" ", formatted)} [{prop.arraySize}]", prop.isExpanded);
            if (!prop.isExpanded)
            {
                return;
            }
            for (int i = 0; i < prop.arraySize; i++)
            {
                EditorGUILayout.BeginHorizontal();
                if (RenderPositionControls(i, new[] { prop }))
                {
                    break;
                }
                EditorGUI.BeginChangeCheck();
                EditorGUILayout.PropertyField(prop.GetArrayElementAtIndex(i), new GUIContent());
                if (EditorGUI.EndChangeCheck())
                {
                    HandleChangeCallback(t, changedCallback, prop, null, new object[] { prop.GetArrayElementAtIndex(i), i });
                }

                if (RenderRemoveControls(i, new[] { prop }))
                {
                    HandleChangeCallback(t, changedCallback, prop, null, new object[] { null, i });
                    break;
                }
                EditorGUILayout.EndHorizontal();
            }

            if (RenderAddControls(new[] { prop }, "Add Element", null))
            {
                HandleChangeCallback(t, changedCallback, prop, null, new object[] { prop.GetArrayElementAtIndex(prop.arraySize - 1), prop.arraySize - 1 });
            }
        }
Exemple #4
0
        private void RenderStackedArray(string name, SerializedProperty prop, SerializedProperty otherProp, PopupAttribute leftPopup,
                                        PopupAttribute rightPopup,
                                        string addMethod, string addText, string changedCallback)
        {
            prop.isExpanded = UTStyles.FoldoutHeader($"{name} [{prop.arraySize}]", prop.isExpanded);
            if (!prop.isExpanded)
            {
                return;
            }
            for (int i = 0; i < prop.arraySize; i++)
            {
                EditorGUILayout.BeginHorizontal();
                if (RenderPositionControls(i, new[] { prop, otherProp }))
                {
                    break;
                }

                // this code is very similar to PopupAttribute itself
                // but we have to handle it here directly because we are connecting two different props together
                // should probably refactor at some point
                EditorGUI.BeginChangeCheck();
                // Left Field
                if (leftPopup == null)
                {
                    EditorGUILayout.PropertyField(prop.GetArrayElementAtIndex(i), new GUIContent());
                }
                else
                {
                    string[] options;
                    var      sourceType = leftPopup.sourceType;
                    var      source     = prop.GetArrayElementAtIndex(i);

                    // Right Field
                    if (sourceType == PopupAttribute.PopupSource.Animator)
                    {
                        options = UTUtils.GetAnimatorTriggers(source.objectReferenceValue as Animator);
                    }
                    else if (sourceType == PopupAttribute.PopupSource.UdonBehaviour)
                    {
                        options = UTUtils.GetUdonEvents(source.objectReferenceValue as UdonBehaviour);
                    }
                    else if (sourceType == PopupAttribute.PopupSource.Shader)
                    {
                        var propsSource = UTUtils.GetValueThroughAttribute(source, leftPopup.methodName, out _);
                        options = UTUtils.GetShaderPropertiesByType(propsSource as Shader, leftPopup.shaderPropType);
                    }
                    else
                    {
                        options = (string[])UTUtils.GetValueThroughAttribute(prop, leftPopup.methodName, out _);
                    }

                    var selectedIndex = options.ToList().IndexOf(prop.GetArrayElementAtIndex(i).stringValue);
                    if (selectedIndex >= options.Length || selectedIndex == -1)
                    {
                        selectedIndex = 0;
                    }

                    selectedIndex = EditorGUILayout.Popup(selectedIndex, options);
                    prop.GetArrayElementAtIndex(i).stringValue = options[selectedIndex];
                }

                if (rightPopup == null)
                {
                    EditorGUILayout.PropertyField(otherProp.GetArrayElementAtIndex(i), new GUIContent());
                }
                else
                {
                    string[] options;
                    var      sourceType = rightPopup.sourceType;
                    var      source     = prop.GetArrayElementAtIndex(i);

                    // Right Field
                    if (sourceType == PopupAttribute.PopupSource.Animator)
                    {
                        options = UTUtils.GetAnimatorTriggers(source.objectReferenceValue as Animator);
                    }
                    else if (sourceType == PopupAttribute.PopupSource.UdonBehaviour)
                    {
                        options = UTUtils.GetUdonEvents(source.objectReferenceValue as UdonBehaviour);
                    }
                    else if (sourceType == PopupAttribute.PopupSource.Shader)
                    {
                        var propsSource = UTUtils.GetValueThroughAttribute(source, rightPopup.methodName, out _);
                        options = UTUtils.GetShaderPropertiesByType(propsSource as Shader, rightPopup.shaderPropType);
                    }
                    else
                    {
                        options = (string[])UTUtils.GetValueThroughAttribute(otherProp, rightPopup.methodName, out _);
                    }

                    var selectedIndex = options.ToList().IndexOf(otherProp.GetArrayElementAtIndex(i).stringValue);
                    if (selectedIndex >= options.Length || selectedIndex == -1)
                    {
                        selectedIndex = 0;
                    }

                    selectedIndex = EditorGUILayout.Popup(selectedIndex, options);
                    otherProp.GetArrayElementAtIndex(i).stringValue = options[selectedIndex];
                }

                if (EditorGUI.EndChangeCheck())
                {
                    if (changedCallback != null)
                    {
                        var m = t.GetType().GetMethod(changedCallback);
                        if (m != null)
                        {
                            m.Invoke(t,
                                     m.GetParameters().Length > 2
                  ? new object[] { prop.GetArrayElementAtIndex(i), otherProp.GetArrayElementAtIndex(i), i }
                  : new object[] { prop, otherProp });
                        }
                    }
                }

                if (RenderRemoveControls(i, new[] { prop, otherProp }))
                {
                    if (changedCallback != null)
                    {
                        var m = t.GetType().GetMethod(changedCallback);
                        if (m != null)
                        {
                            m.Invoke(t,
                                     m.GetParameters().Length > 2
                  ? new object[] { null, null, i }
                  : new object[] { prop, otherProp });
                        }
                    }
                    break;
                }

                EditorGUILayout.EndHorizontal();
            }

            if (RenderAddControls(new[] { prop, otherProp }, addText, addMethod))
            {
                if (changedCallback != null)
                {
                    var m = t.GetType().GetMethod(changedCallback);
                    if (m != null)
                    {
                        m.Invoke(t,
                                 m.GetParameters().Length > 2
                ? new object[] { prop.GetArrayElementAtIndex(prop.arraySize), otherProp.GetArrayElementAtIndex(prop.arraySize), prop.arraySize }
                : new object[] { prop, otherProp });
                    }
                }
            }
        }
Exemple #5
0
        public override void OnInspectorGUI()
        {
            t = (UTController)target;
            // Copy current values
            if (!copiedValues)
            {
                t.SyncBack();
                copiedValues = true;
            }

            // Header
            var customNameAttr = t.GetType().GetCustomAttributes(typeof(CustomNameAttribute))
                                 .Select(i => i as CustomNameAttribute).ToArray();
            var customName = customNameAttr.Length != 0 ? customNameAttr[0].name : t.GetType().Name.Replace("Controller", "");

            UTStyles.RenderHeader(customName);

            EditorGUI.BeginChangeCheck();
            serializedObject.Update();

            EditorGUILayout.HelpBox("Controllers are Deprecated since UdonToolkit v0.4.0 in favor of a more streamlined system", MessageType.Warning);
            if (GUILayout.Button("Learn more"))
            {
                Application.OpenURL("https://l.vrchat.sh/utV4Migrate");
            }

            // Extra pre-gui actions
            t.SetupController();

            // Auto UB Addition
            if (t.GetComponent <UdonBehaviour>() == null)
            {
                if (uB)
                {
                    var comp = t.gameObject.AddComponent <UdonBehaviour>();
                    comp.programSource = uB;
                }
                else
                {
                    var controlledBehAttr = t.GetType().GetCustomAttributes(typeof(ControlledBehaviourAttribute))
                                            .Select(i => i as ControlledBehaviourAttribute).ToArray();
                    if (controlledBehAttr.Any())
                    {
                        var comp = t.gameObject.AddComponent <UdonBehaviour>();
                        uB = controlledBehAttr[0].uB;
                        comp.programSource = uB;
                    }
                }
            }

            // Help Box
            var helpBoxAttr = t.GetType().GetCustomAttributes(typeof(HelpMessageAttribute))
                              .Select(i => i as HelpMessageAttribute).ToArray();

            if (helpBoxAttr.Any())
            {
                UTStyles.RenderNote(helpBoxAttr[0]?.helpMessage);
            }

            // Check prefabs
            if (PrefabUtility.IsPartOfAnyPrefab(t.gameObject))
            {
                EditorGUILayout.HelpBox(
                    "Udon doesn't play well with Prefabs. " +
                    "It is recommended to unpack your prefabs when modifying any values.\n" +
                    "Right click the prefab and choose \"Unpack Prefab\"", MessageType.Warning);
            }

            // Actual GUI
            DrawGUI(t);
            if (EditorGUI.EndChangeCheck())
            {
                Undo.RecordObject(t, undoString);
                serializedObject.ApplyModifiedProperties();
                t.SyncValues();
            }

            // Sync Toggles
            UTStyles.RenderSectionHeader("Udon Sync");
            if (t.uB != null)
            {
                var uBo = new SerializedObject(t.uB);
                uBo.Update();
                EditorGUI.BeginChangeCheck();
                EditorGUILayout.PropertyField(uBo.FindProperty("SynchronizePosition"));
                var col = t.gameObject.GetComponent <Collider>();
                if (col != null)
                {
                    EditorGUILayout.PropertyField(uBo.FindProperty("AllowCollisionOwnershipTransfer"), new GUIContent("Collision Owner Transfer"));
                }
                if (EditorGUI.EndChangeCheck())
                {
                    uBo.ApplyModifiedProperties();
                }
            }

            // Extra Methods
            var methods = t.GetType().GetMethods().Where(i => i.GetCustomAttribute <ButtonAttribute>() != null)
                          .ToArray();
            var buttons = t.GetType().GetMethods().Select(i => i.GetCustomAttribute <ButtonAttribute>()).Where(i => i != null)
                          .ToArray();

            if (buttons.Any())
            {
                UTStyles.RenderSectionHeader("Methods");
                var rowBreak = Mathf.Max(1, Mathf.Min(3, buttons.Length - 1));
                var rowEndI  = -100;
                foreach (var(button, i) in buttons.WithIndex())
                {
                    if (i == rowEndI && i != buttons.Length - 1)
                    {
                        EditorGUILayout.EndHorizontal();
                    }
                    if (i % rowBreak == 0 && i != buttons.Length - 1)
                    {
                        EditorGUILayout.BeginHorizontal();
                        rowEndI = Math.Min(i + rowBreak, buttons.Length - 1);
                    }
                    EditorGUI.BeginDisabledGroup(!Application.isPlaying && !button.activeInEditMode);
                    if (GUILayout.Button(button.text))
                    {
                        t.Invoke(methods[i].Name, 0);
                    }
                    EditorGUI.EndDisabledGroup();
                    if (i == buttons.Length - 1 && rowEndI != -100)
                    {
                        EditorGUILayout.EndHorizontal();
                    }
                }
            }
            UTStyles.RenderSectionHeader("Manual Value Sync");
            EditorGUILayout.BeginHorizontal();
            if (GUILayout.Button("Copy to Udon"))
            {
                t.SyncValues();
            }

            if (GUILayout.Button("Copy from Udon"))
            {
                t.SyncBack();
            }
            EditorGUILayout.EndHorizontal();
        }
Exemple #6
0
        private void HandleArray(SerializedProperty prop)
        {
            var attrs                   = UTUtils.GetPropertyAttributes(prop);
            var modifierAttrs           = UTUtils.GetPropertyAttributes <Attribute>(prop);
            var isGroup                 = attrs.Where(a => a is ListViewAttribute).ToArray().Length > 0;
            var groupAttribute          = attrs.Select(a => a as ListViewAttribute).ToArray();
            var onValueChangedAttribute = UTUtils.GetPropertyAttribute <OnValueChangedAttribute>(prop);

            // hideIf attribute
            var hideIfAttribute = modifierAttrs.OfType <HideIfAttribute>().ToArray();
            var isHidden        = hideIfAttribute.Length > 0 && UTUtils.GetVisibleThroughAttribute(prop, hideIfAttribute[0].methodName, false);

            // handling for regular arrays, make nicer down the line
            if (!isGroup)
            {
                if (isHidden)
                {
                    return;
                }
                RenderArray(prop, onValueChangedAttribute?.methodName);
                RenderHelpBox(prop);
                return;
            }

            var groupName = groupAttribute[0].name;
            var items     = t.GetType().GetFields().Where(f =>
                                                          f.GetAttribute <ListViewAttribute>() != null && f.GetAttribute <ListViewAttribute>().name == groupName)
                            .ToList();

            // fast exit on 1 element with list view
            if (items.Count < 2)
            {
                if (isHidden)
                {
                    return;
                }
                RenderArray(prop, onValueChangedAttribute?.methodName);
                RenderHelpBox(prop);
                return;
            }

            var index = items.FindIndex(a => a.Name == prop.name);

            if (index > 0)
            {
                return;
            }

            var sectionHeaderAttribute = UTUtils.GetPropertyAttribute <SectionHeaderAttribute>(prop);

            if (sectionHeaderAttribute != null)
            {
                UTStyles.RenderSectionHeader(sectionHeaderAttribute.text);
            }

            if (isHidden)
            {
                return;
            }

            var otherProp           = serializedObject.FindProperty(items[1].Name);
            var leftPopupAttribute  = UTUtils.GetPropertyAttribute <PopupAttribute>(prop);
            var rightPopupAttribute = UTUtils.GetPropertyAttribute <PopupAttribute>(otherProp);

            if (rightPopupAttribute != null || leftPopupAttribute != null)
            {
                RenderStackedArray(groupAttribute[0].name, prop, otherProp, leftPopupAttribute, rightPopupAttribute, groupAttribute[0].addMethodName,
                                   groupAttribute[0].addButtonText, onValueChangedAttribute?.methodName);
                RenderHelpBox(prop);
                return;
            }

            RenderStackedArray(groupAttribute[0].name, prop, otherProp, groupAttribute[0].addMethodName,
                               groupAttribute[0].addButtonText, onValueChangedAttribute?.methodName);
            RenderHelpBox(prop);
        }