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

            if (helpBoxAttr != null)
            {
                if (helpBoxAttr.methodName.Length > 0 && !UTUtils.GetVisibleThroughAttribute(prop, helpBoxAttr.methodName, false))
                {
                    return;
                }
                UTStyles.RenderNote(helpBoxAttr.text);
            }
        }
Exemple #2
0
        public override void AfterGUI(SerializedProperty property)
        {
            if (methodName != "")
            {
                isVisible = UTUtils.GetVisibleThroughAttribute(property, methodName, false);
            }

            if (!isVisible)
            {
                return;
            }
            UTStyles.RenderNote(text);
        }
Exemple #3
0
        private void OnGUI()
        {
            GUILayout.Box("", new GUIStyle(EditorStyles.helpBox)
            {
                normal = new GUIStyleState()
                {
                    background = UTStyles.Splash
                }
            }, GUILayout.Height(150));
            if (labelStyle == null)
            {
                labelStyle = new GUIStyle("BoldLabel")
                {
                    fontSize = 13
                };
            }

            EditorGUILayout.BeginVertical();
            EditorGUILayout.LabelField("Welcome to UdonToolkit!", labelStyle);
            GUILayout.Label(@"Udon Toolkit is a project aimed at simplifying usage of Udon by providing a set of easy to use purpose-built behaviours, from generic triggers and actions, to more complete systems like Key Items, Cabinet Drawers, etc.

This also includes a system of attributes that allow you to utilize the same UI elements when building your own behaviours!

If you find that something is broken or works not as you would expect - please ping me in the discord server, or better - create an issue on github.", "WordWrappedMiniLabel", GUILayout.ExpandWidth(true));
            GUILayout.Space(10);
            EditorGUILayout.BeginHorizontal();
            if (GUILayout.Button("Documentation", GUILayout.ExpandWidth(true)))
            {
                Application.OpenURL(WikiURL);
            }
            if (GUILayout.Button("Github Repo", GUILayout.ExpandWidth(true)))
            {
                Application.OpenURL(GithubURL);
            }
            if (GUILayout.Button("Discord Server", GUILayout.ExpandWidth(true)))
            {
                Application.OpenURL(DiscordURL);
            }
            if (GUILayout.Button("Support UdonToolkit", GUILayout.ExpandWidth(true)))
            {
                Application.OpenURL(PatreonURL);
            }
            EditorGUILayout.EndHorizontal();
            GUILayout.Space(2);
            UTStyles.RenderNote("This will only show once, you can open it again via Window / UdonToolkit / Show Startup Screen");
            EditorGUILayout.EndVertical();
        }
Exemple #4
0
        public override void AfterGUI(Rect position, SerializedProperty property, GUIContent label)
        {
            if (!isVisible)
            {
                return;
            }
            if (property.name == "data" && property.depth > 0)
            {
                return;
            }
            var rect = EditorGUI.IndentedRect(position);
            // check for section header
            var secHeader = UTUtils.GetPropertyAttribute <SectionHeaderAttribute>(property);

            rect.yMin  += secHeader != null ? fieldHeight / 2 + 2 : fieldHeight + 2;
            rect.height = boxHeight;
            UTStyles.RenderNote(ref rect, text);
        }
Exemple #5
0
        private void OnGUI()
        {
            if (labelStyle == null)
            {
                labelStyle = new GUIStyle("BoldLabel")
                {
                    fontSize = 13
                };
            }

            EditorGUILayout.BeginVertical();
            EditorGUILayout.LabelField("Welcome to UdonToolkit!", labelStyle);
            GUILayout.Label(@"Udon Toolkit is built to serve as a foundation for your next Udon-based world. It contains a lot of useful behaviours from Area Triggers, to Player Teleporters and Followers.

Also included are various fully-featured systems, like a Camera System that adds an enhanced camera functionality to your world. 

The last part of the Udon Toolkit is an expansive attributes system that allows you to create complex UI for your behaviours the same way Udon Toolkit does.

If you find that something is broken or works not as you would expect - please ping me in the discord server, or better - create an issue on github.", "WordWrappedMiniLabel", GUILayout.ExpandWidth(true));
            GUILayout.Space(10);
            if (GUILayout.Button("Documentation", GUILayout.ExpandWidth(true)))
            {
                Application.OpenURL(WikiURL);
            }
            if (GUILayout.Button("Github Repo", GUILayout.ExpandWidth(true)))
            {
                Application.OpenURL(GithubURL);
            }
            if (GUILayout.Button("Discord Server", GUILayout.ExpandWidth(true)))
            {
                Application.OpenURL(DiscordURL);
            }
            if (GUILayout.Button("Support UdonToolkit", GUILayout.ExpandWidth(true)))
            {
                Application.OpenURL(PatreonURL);
            }
            GUILayout.Space(2);
            UTStyles.RenderNote("This will only show once, you can open it again via Window / UdonToolkit / Show Startup Screen");
            EditorGUILayout.EndVertical();
        }
Exemple #6
0
        private void OnGUI()
        {
            emptyLayer = 0;
            UTUtils.GetLayerMasks();
            UTStyles.RenderHeader("Camera System Setup");
            UTStyles.RenderNote("This tool will set up a camera system in your scene, for more details on how to customize the camera - consult the documentation page.");
            if (GUILayout.Button("Documentation", GUILayout.ExpandWidth(true)))
            {
                Application.OpenURL(WikiURL);
            }

            UTStyles.RenderSectionHeader("Position and Style");

            var newCameraSpot = (Transform)EditorGUILayout.ObjectField("Camera Position", cameraSpot, typeof(Transform), true);

            if (newCameraSpot != cameraSpot)
            {
                setup = false;
            }

            cameraSpot = newCameraSpot;
            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("Watermark Overlay");
            watermark = (Texture)EditorGUILayout.ObjectField(watermark, typeof(Texture), true);
            EditorGUILayout.EndHorizontal();
            UTStyles.RenderNote("Overlay should be a 16:9 transparent texture");
            addGuide = EditorGUILayout.Toggle("Add Camera Guide", addGuide);
            if (addGuide)
            {
                var newGuideStyle = (GuideStyle)EditorGUILayout.EnumPopup("Guide Panel Style", guideStyle);
                if (newGuideStyle != guideStyle || standObj == null || standObjEditor == null)
                {
                    var standPath = newGuideStyle == GuideStyle.Futuristic ? SciFiStandPath : TikiStandPath;
                    standObj       = AssetDatabase.LoadAssetAtPath(GetAssetPath(standPath), typeof(object));
                    standObjEditor = UnityEditor.Editor.CreateEditor(standObj);
                }
                var r = GUILayoutUtility.GetRect(450, 150);
                standObjEditor.OnPreviewGUI(r, EditorStyles.helpBox);
                guideStyle = newGuideStyle;
            }

            UTStyles.RenderSectionHeader("PostProcessing and Collisions");
            UTStyles.RenderNote("Layers are very important to the overall setup. Make sure you follow the instructions below");

            layers.Clear();
            for (int i = 0; i < 32; i++)
            {
                var layerName = LayerMask.LayerToName(i);
                if (layerName.Length > 0)
                {
                    layers.Add($"[{i}] {layerName}");
                }
                else
                {
                    if (i > 22 && emptyLayer == 0)
                    {
                        emptyLayer = i;
                    }
                    layers.Add($"[{i}] -- not set --");
                }
            }

            var layersArr = layers.ToArray();

            if (emptyLayer != 0)
            {
                if (GUILayout.Button("Setup Layers"))
                {
                    SetupLayers();
                }
                UTStyles.RenderNote("It seems like you have empty layers available, UdonToolkit can set up everything for you if you click the button above");
                UTStyles.HorizontalLine();
            }

            cameraPPLayer = EditorGUILayout.Popup("Camera PP Layer", cameraPPLayer, layersArr);
            UTStyles.RenderNote("This layer will be used for detecting PP volumes for the Camera System");
            if (cameraPPLayer == 22)
            {
                EditorGUILayout.HelpBox("It is crucial to not put Camera PP volumes on the same layer as the main PostProcessing, or your own view will be affected by the camera effects", MessageType.Warning);
            }

            if (setup)
            {
                var oldColor = GUI.backgroundColor;
                GUI.backgroundColor = Color.green;
                UTStyles.RenderNote("Camera system has been set up in the scene!");
                GUI.backgroundColor = oldColor;
            }
            if (GUILayout.Button("Create Camera System", GUILayout.Height(30)))
            {
                RunCameraSetup();
            }

            if (GUILayout.Button("Add Guide Stand Only", GUILayout.Height(20)))
            {
                AddGuide();
            }
        }
Exemple #7
0
        public override void OnInspectorGUI()
        {
            droppedObjects = false;
            isPlaying      = !Application.isPlaying;
            t = (UdonSharpBehaviour)target;
            if (cT == null)
            {
                cT         = t.GetType();
                undoString = $"Update {cT.Name}";
            }

            if (drawDefaultInspector)
            {
                DrawDefaultGUI(t);
                return;
            }
            if (UdonSharpGUI.DrawDefaultUdonSharpBehaviourHeader(t, true))
            {
                return;
            }
            // Header
            var customNameAttr = cT.GetCustomAttributes(typeof(CustomNameAttribute))
                                 .Select(i => i as CustomNameAttribute).ToArray();
            var helpUrlAttribute = cT.GetCustomAttributes(typeof(HelpURLAttribute))
                                   .Select(i => i as HelpURLAttribute).ToArray();

            if (customNameAttr.Any() || helpUrlAttribute.Any())
            {
                EditorGUILayout.BeginHorizontal();
                UTStyles.RenderHeader(customNameAttr.Any() ? customNameAttr[0].name : cT.Name.Replace("Controller", ""));
                if (helpUrlAttribute.Any())
                {
                    if (GUILayout.Button("?", GUILayout.Height(26), GUILayout.Width(26)))
                    {
                        Application.OpenURL(helpUrlAttribute[0].URL);
                    }
                }
                EditorGUILayout.EndHorizontal();
            }

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

            // Help Box
            var helpBoxAttr = cT.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);
            }

            // Before Editor Callback
            var beforeEditorCallback = cT.GetCustomAttribute <OnBeforeEditorAttribute>();

            if (beforeEditorCallback != null)
            {
                var m = cT.GetMethod(beforeEditorCallback.methodName);
                m?.Invoke(t, new object[] { serializedObject });
            }

            // for direct editing of fields in case of jagged arrays - we need to record changes
            Undo.RecordObject(t, undoString);

            // Actual GUI
            try {
                DrawGUI(t);
            } catch (Exception ex) {
                // for some reason unity likes to throw ExitGUI exceptions when looking up scene objects
                // even tho it doesnt throw them when you don't try-catch
                if (ex.GetType() != typeof(ExitGUIException))
                {
                    Debug.LogException(ex);
                }
            }

            // After Editor Callback
            var afterEditorCallback = cT.GetCustomAttribute <OnAfterEditorAttribute>();

            if (afterEditorCallback != null)
            {
                var m = cT.GetMethod(afterEditorCallback.methodName);
                m?.Invoke(t, new object[] { serializedObject });
            }

            if (EditorGUI.EndChangeCheck() || droppedObjects)
            {
                // Global Values Callback
                var globalEditorCallback = cT.GetCustomAttribute <OnValuesChangedAttribute>();
                if (globalEditorCallback != null)
                {
                    var m = cT.GetMethod(globalEditorCallback.methodName);
                    m?.Invoke(t, new object[] { serializedObject });
                }
                serializedObject.ApplyModifiedProperties();
            }

            if (droppedObjects)
            {
                return;
            }

            // Extra Methods
            var methods = cT.GetMethods(methodFlags).Where(i => i.GetCustomAttribute <ButtonAttribute>() != null).ToArray();
            var buttons = methods
                          .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(isPlaying && !button.activeInEditMode);
                    if (GUILayout.Button(button.text))
                    {
                        if (button.activeInEditMode)
                        {
                            methods[i].Invoke(t, new object[] {});
                        }
                        else
                        {
                            UdonSharpEditorUtility.GetProxyBehaviour(t.GetComponent <UdonBehaviour>()).SendCustomEvent(methods[i].Name);
                        }
                    }
                    EditorGUI.EndDisabledGroup();
                    if (i == buttons.Length - 1 && rowEndI != -100)
                    {
                        EditorGUILayout.EndHorizontal();
                    }
                }
            }

            UTStyles.HorizontalLine();
            if (GUILayout.Button("Show Default Inspector", UTStyles.smallButton))
            {
                drawDefaultInspector = true;
            }
        }
Exemple #8
0
        public override void OnInspectorGUI()
        {
            t = (UdonSharpBehaviour)target;

            showUdonSettings = (bool)(UTUtils.GetUTSetting("showUdonSettings", UTUtils.UTSettingType.Bool) ?? false);

            // we force-disable collision transfer for toolkit driven behaviours as it is not applicable
            if (!nonUBChecked)
            {
                nonUBMode    = t.gameObject.GetComponent <UdonBehaviour>() == null;
                nonUBChecked = true;
            }

            if (!nonUBMode)
            {
                if (UdonSharpEditorUtility.GetBackingUdonBehaviour(t).AllowCollisionOwnershipTransfer)
                {
                    UdonSharpEditorUtility.GetBackingUdonBehaviour(t).AllowCollisionOwnershipTransfer = false;
                }
            }

            var headerExited = false;

            EditorGUI.BeginChangeCheck();
            showUdonSettings = GUILayout.Toggle(showUdonSettings, "Udon Settings", UTStyles.smallButton);
            if (EditorGUI.EndChangeCheck())
            {
                UTUtils.SetUTSetting("showUdonSettings", UTUtils.UTSettingType.Bool, showUdonSettings);
            }

            if (showUdonSettings)
            {
                headerExited = UdonSharpGUI.DrawDefaultUdonSharpBehaviourHeader(t, true);
            }

            if (headerExited)
            {
                return;
            }

            #region Caching

            if (!cacheBuilt)
            {
                tT           = t.GetType();
                programAsset = UdonSharpEditorUtility.GetUdonSharpProgramAsset(t);
                behInfo      = new UTBehaviourInfo(t);

                var prop = serializedObject.GetIterator();
                var next = prop.NextVisible(true);

                if (next)
                {
                    do
                    {
                        if (prop.name == "m_Script")
                        {
                            continue;
                        }

                        if (!fieldCache.ContainsKey(prop.name))
                        {
                            var newField = new UTField(prop);
                            fieldCache.Add(prop.name, newField);
                            if (newField.isInTabGroup)
                            {
                                if (!tabs.ContainsKey(newField.tabGroupName))
                                {
                                    tabs.Add(newField.tabGroupName, new Dictionary <string, UTFieldType>());
                                    // we only support one tab group per behaviour right now
                                    if (!tabsExist)
                                    {
                                        fieldOrder.Add(newField.tabGroupName, UTFieldType.Tab);
                                        tabsExist = true;
                                    }
                                }

                                // since tabs can host foldouts - we need to explicitly retarget them
                                // this logic could be generalized if i ever want to make all of this recursive
                                if (newField.isInFoldout)
                                {
                                    if (!foldouts.ContainsKey(newField.foldoutName))
                                    {
                                        foldouts.Add(newField.foldoutName, new Dictionary <string, UTFieldType>());
                                        tabs[newField.tabGroupName].Add(newField.foldoutName, UTFieldType.Foldout);
                                    }

                                    AddToFieldOrder(newField, prop, true);
                                    continue;
                                }

                                AddToFieldOrder(newField, prop, addToTabGroup: true);
                                continue;
                            }

                            if (newField.isInFoldout)
                            {
                                if (!foldouts.ContainsKey(newField.foldoutName))
                                {
                                    foldouts.Add(newField.foldoutName, new Dictionary <string, UTFieldType>());
                                    fieldOrder.Add(newField.foldoutName, UTFieldType.Foldout);
                                }

                                AddToFieldOrder(newField, prop, true);
                                continue;
                            }

                            AddToFieldOrder(newField, prop);
                        }
                    } while (prop.NextVisible(false));
                }

                cacheBuilt = true;
                return;
            }

            var e = Event.current;
            if (e.type == EventType.Repaint)
            {
                if (firstRepaint)
                {
                    firstRepaint = false;
                    return;
                }
            }

            #endregion

            if (behInfo.customName != null || behInfo.helpUrl != null)
            {
                EditorGUILayout.BeginHorizontal();
                UTStyles.RenderHeader(behInfo.customName != null ? behInfo.customName : behInfo.name);
                if (behInfo.helpUrl != null)
                {
                    if (GUILayout.Button("?", GUILayout.Height(26), GUILayout.Width(26)))
                    {
                        Application.OpenURL(behInfo.helpUrl);
                    }
                }
                EditorGUILayout.EndHorizontal();
            }

            if (behInfo.helpMsg != null)
            {
                UTStyles.RenderNote(behInfo.helpMsg);
            }

            if (behInfo.onBeforeEditor != null)
            {
                behInfo.onBeforeEditor.Invoke(t, new object[] { serializedObject });
            }

            // handle jagged arrays
            Undo.RecordObject(t, "Change Properties");

            EditorGUI.BeginChangeCheck();
            droppedObjects = false;

            // this method is overrideable by custom code
            DrawGUI();

            if (EditorGUI.EndChangeCheck() || droppedObjects || shouldReserialize)
            {
                if (behInfo.onValuesChanged != null)
                {
                    behInfo.onValuesChanged.Invoke(t, new object[] { serializedObject });
                }
                serializedObject.ApplyModifiedProperties();
            }

            if (droppedObjects)
            {
                return;
            }

            if (behInfo.onAfterEditor != null)
            {
                behInfo.onAfterEditor.Invoke(t, new object[] { serializedObject });
            }

            #region Buttons
            if (behInfo.buttons != null && !Application.isPlaying && behInfo.buttons.Length > 0)
            {
                buttonsExpanded = UTStyles.FoldoutHeader("Editor Methods", buttonsExpanded);
                if (buttonsExpanded)
                {
                    EditorGUILayout.BeginVertical(new GUIStyle("helpBox"));
                    foreach (var button in behInfo.buttons)
                    {
                        if (GUILayout.Button(button.Name))
                        {
                            button.Invoke(t, new object[] {});
                        }
                    }
                    EditorGUILayout.EndVertical();
                }
            }
            if (Application.isPlaying && behInfo.udonCustomEvents.Length > 0 && !nonUBMode)
            {
                methodsExpanded = UTStyles.FoldoutHeader("Udon Events", methodsExpanded);
                if (methodsExpanded)
                {
                    EditorGUILayout.BeginVertical(new GUIStyle("helpBox"));
                    var rowBreak = Mathf.Max(1, Mathf.Min(3, behInfo.udonCustomEvents.Length - 1));
                    var rowEndI  = -100;
                    foreach (var(button, i) in behInfo.udonCustomEvents.WithIndex())
                    {
                        if (i == rowEndI && i != behInfo.udonCustomEvents.Length - 1)
                        {
                            EditorGUILayout.EndHorizontal();
                        }
                        if (i % rowBreak == 0 && i != behInfo.udonCustomEvents.Length - 1)
                        {
                            EditorGUILayout.BeginHorizontal();
                            rowEndI = Math.Min(i + rowBreak, behInfo.udonCustomEvents.Length - 1);
                        }
                        if (GUILayout.Button(button))
                        {
                            UdonSharpEditorUtility.GetBackingUdonBehaviour(t).SendCustomEvent(button);
                            UdonSharpEditorUtility.CopyUdonToProxy(t);
                        }
                        if (i == behInfo.udonCustomEvents.Length - 1 && rowEndI != -100)
                        {
                            EditorGUILayout.EndHorizontal();
                        }
                    }
                    EditorGUILayout.EndVertical();
                }
            }
            #endregion
        }