Example #1
0
        public void CreateNode(UdonNodeDefinition udonNodeDefinition, Vector2?position = null)
        {
            UdonNodeData nodeData = null;

            if (!TrySetupNode(udonNodeDefinition, position, out UdonNode node, ref nodeData))
            {
                return;
            }
            PopulateDefaultValues();
            LayoutSlots(udonNodeDefinition, node, 0);
            ReSerializeData();
            AddNode(node);

            void PopulateDefaultValues()
            {
                if (udonNodeDefinition.defaultValues == null)
                {
                    return;
                }
                nodeData.nodeValues = new SerializableObjectContainer[udonNodeDefinition.defaultValues.Count];
                nodeData.nodeUIDs   = new string[udonNodeDefinition.defaultValues.Count];
                for (int i = 0; i < udonNodeDefinition.defaultValues.Count; i++)
                {
                    object defaultValue = udonNodeDefinition.defaultValues[i];
                    if (defaultValue != null)
                    {
                        nodeData.nodeValues[i] = SerializableObjectContainer.Serialize(defaultValue);
                    }
                }
            }
        }
        public UdonParameterField(UdonGraph udonGraph, UdonNodeData nodeData)
        {
            this.udonGraph = udonGraph;
            this.nodeData  = nodeData;

            // Get Definition or exit early
            UdonNodeDefinition definition = UdonEditorManager.Instance.GetNodeDefinition(nodeData.fullName);

            if (definition == null)
            {
                UnityEngine.Debug.LogWarning($"Couldn't create Parameter Field for {nodeData.fullName}");
                return;
            }

            this.text     = (string)nodeData.nodeValues[(int)UdonParameterProperty.ValueIndices.name].Deserialize();
            this.typeText = UdonGraphExtensions.PrettyString(definition.name).FriendlyNameify();

            this.AddManipulator(new ContextualMenuManipulator(BuildContextualMenu));

            this.Q("icon").AddToClassList("parameter-" + definition.type);
            this.Q("icon").visible = true;

            var textField = (TextField)this.Q("textField");

            textField.isDelayed = true;
        }
Example #3
0
        public UdonParameterField(UdonGraph udonGraph, UdonNodeData nodeData)
        {
            this.udonGraph = udonGraph;
            this.nodeData  = nodeData;

            // Get Definition or exit early
            UdonNodeDefinition definition = UdonEditorManager.Instance.GetNodeDefinition(nodeData.fullName);

            if (definition == null)
            {
                UnityEngine.Debug.LogWarning($"Couldn't create Parameter Field for {nodeData.fullName}");
                return;
            }

            this.text     = (string)nodeData.nodeValues[(int)UdonParameterProperty.ValueIndices.name].Deserialize();
            this.typeText = UdonGraphExtensions.PrettyString(definition.name).FriendlyNameify();

            this.AddManipulator(new ContextualMenuManipulator(BuildContextualMenu));

            this.Q("icon").AddToClassList("parameter-" + definition.type);
            this.Q("icon").visible = true;

            var textField = (TextField)this.Q("textField");

            textField.isDelayed = true;
            textField.OnValueChanged((e) => {
                UnityEditor.Undo.RecordObject(udonGraph.graphProgramAsset, "Rename Variable");
                // Sanitize value for variable name
                string newVariableName = e.newValue.SanitizeVariableName();
                text = newVariableName;
                nodeData.nodeValues[(int)UdonParameterProperty.ValueIndices.name] = SerializableObjectContainer.Serialize(newVariableName);
            });
        }
Example #4
0
 private static bool IsSpecialDefinition(UdonNodeDefinition definition)
 {
     return(definition.fullName == "Block" || definition.fullName == "Branch" || definition.fullName == "While" ||
            definition.fullName == "For" || definition.fullName == "Get_Variable" ||
            definition.fullName == "Set_Variable" ||
            definition.fullName == "SubGraph" || definition.fullName == "Comment");
 }
Example #5
0
        private void LayoutSlots(UdonNodeDefinition udonNodeDefinition, UdonNode node, int connectedFlowCount)
        {
            //Layout Flow Slots
            if (udonNodeDefinition.flow)
            {
                if (!udonNodeDefinition.fullName.StartsWith("Event_"))
                {
                    node.AddInputSlot("");
                }

                node.AddOutputSlot("");
                if (_specialFlows.Contains(udonNodeDefinition.fullName))
                {
                    node.AddOutputSlot("");
                }

                if (udonNodeDefinition.fullName == "Block")
                {
                    int connectedFlows = connectedFlowCount;
                    if (connectedFlows > 1)
                    {
                        for (int i = 0; i < connectedFlows - 1; i++)
                        {
                            node.AddOutputSlot("");
                        }
                    }
                }
            }

            //Layout InOut Slots
            for (int index = 0; index < udonNodeDefinition.Inputs.Count; index++)
            {
                UdonNodeParameter input = udonNodeDefinition.Inputs[index];
                string            label = "";
                if (udonNodeDefinition.Inputs.Count > index && index >= 0)
                {
                    label = udonNodeDefinition.Inputs[index].name;
                }

                if (label == "IUdonEventReceiver")
                {
                    label = "UdonBehaviour";
                }

                label = label.FriendlyNameify();

                Slot slot = node.AddInputSlot(FriendlyTypeName(input.type),
                                              SlotTypeConverter(input.type, udonNodeDefinition.fullName));
                slot.title = label;
            }

            foreach (UdonNodeParameter output in udonNodeDefinition.Outputs)
            {
                node.AddOutputSlot(FriendlyTypeName(output.type), SlotTypeConverter(output.type, udonNodeDefinition.fullName));
            }
        }
Example #6
0
        public void AddFromData(UdonNodeData nodeData)
        {
            UdonNodeDefinition definition = UdonEditorManager.Instance.GetNodeDefinition(nodeData.fullName);

            if (definition != null)
            {
                contentContainer.Add(new BlackboardRow(new UdonParameterField(_graph, nodeData),
                                                       new UdonParameterProperty(_graph, definition, nodeData)));
            }
        }
        public static string PrettyFullName(UdonNodeDefinition nodeDefinition, bool keepLong = false)
        {
            string fullName = nodeDefinition.fullName;
            string result;

            if (keepLong)
            {
                result = fullName.Replace("UnityEngine", "UnityEngine.").Replace("System", "System.");
            }
            else
            {
                result = fullName.Replace("UnityEngine", "").Replace("System", "");
            }

            string[] resultSplit = result.Split(new[] { "__" }, StringSplitOptions.None);
            if (resultSplit.Length >= 3)
            {
                string outName = "";
                if (nodeDefinition.type != typeof(void))
                {
                    if (nodeDefinition.outputNames != null && nodeDefinition.outputNames.Length > 0)
                    {
                        outName = string.Join(", ", nodeDefinition.outputNames);
                    }
                }

                if (nodeDefinition.inputNames != null && nodeDefinition.inputNames.Length > 0)
                {
                    result = $"{resultSplit[0]}{resultSplit[1]}({string.Join(", ", nodeDefinition.inputNames)}{outName})";
                }
                else
                {
                    result = $"{resultSplit[0]}{resultSplit[1]}({resultSplit[2].Replace("_", ", ")}{outName})";
                }
            }
            else if (resultSplit.Length >= 2)
            {
                result = $"{resultSplit[0]}{resultSplit[1]}()";
            }

            if (!keepLong)
            {
                result = result.FriendlyNameify();
                result = result.Replace("op_", "");
                result = result.Replace("_", " ");
            }

            return(result);
        }
        public static bool ShouldShowDocumentationLink(UdonNodeDefinition definition)
        {
            List <string> specialNames = new List <string>
            {
                "Block",
                "Branch",
                "For",
                "While",
                "Foreach",
                "Get_Variable",
                "Set_Variable",
                "Set_ReturnValue",
                "Event_Custom",
                "Event_OnDataStorageAdded",
                "Event_OnDataStorageChanged",
                "Event_OnDataStorageRemoved",
                "Event_OnDrop",
                "Event_Interact",
                "Event_OnNetworkReady",
                "Event_OnOwnershipTransferred",
                "Event_OnPickup",
                "Event_OnPickupUseDown",
                "Event_OnPickupUseUp",
                "Event_OnPlayerJoined",
                "Event_OnPlayerLeft",
                "Event_OnSpawn",
                "Event_OnStationEntered",
                "Event_OnStationExited",
                "Event_OnVideoEnd",
                "Event_OnVideoPause",
                "Event_OnVideoPlay",
                "Event_OnVideoStart",
                "Event_MidiNoteOn",
                "Event_MidiNoteOff",
                "Event_MidiControlChange",
                "VRCUdonCommonInterfacesIUdonEventReceiver.__SendCustomEvent__SystemString__SystemVoid",
                "VRCUdonCommonInterfacesIUdonEventReceiver.__SetHeapVariable__SystemString_SystemObject__SystemVoid",
                "VRCUdonCommonInterfacesIUdonEventReceiver.__GetHeapVariable__SystemString__SystemObject",
                "Const_VRCUdonCommonInterfacesIUdonEventReceiver",
            };

            // Don't show for any of these
            return(!(definition.type == null ||
                     definition.type.Namespace == null ||
                     specialNames.Contains(definition.fullName) ||
                     (!definition.type.Namespace.Contains("UnityEngine") &&
                      !definition.type.Namespace.Contains("System"))));
        }
Example #9
0
        public void AddFromData(UdonNodeData nodeData)
        {
            // don't add internal variables, which start with __
            // Todo: handle all "__" variables instead, need to tell community first and let the word spread
            string newVariableName = (string)nodeData.nodeValues[(int)UdonParameterProperty.ValueIndices.name].Deserialize();

            if (newVariableName.StartsWithCached("__returnValue"))
            {
                return;
            }

            UdonNodeDefinition definition = UdonEditorManager.Instance.GetNodeDefinition(nodeData.fullName);

            if (definition != null)
            {
                BlackboardRow row = new BlackboardRow(new UdonParameterField(_graph, nodeData),
                                                      new UdonParameterProperty(_graph, definition, nodeData));
                contentContainer.Add(row);
                _idToRow.Add(nodeData.uid, row);
            }
        }
        private GUIContent NodeContentWithIcon(UdonNodeDefinition nodeDefinition, string menuName, string tooltip)
        {
            GUIContent content;

            if (nodeDefinition != null)
            {
                Type thumbType = nodeDefinition.type;

                if (thumbType != null)
                {
                    if (thumbType.IsArray)
                    {
                        thumbType = thumbType.GetElementType();
                    }
                }

                Texture2D thumb = GetCachedTypeThumbnail(thumbType);

                //TODO: This is real gross and hacky, figure out how to just let the name clip naturally without clipping the icon in the process
                int maxLength = (int)(_dropDownWidth / 7);
                menuName = menuName.Substring(0, menuName.Length <= maxLength ? menuName.Length : maxLength);
                while (GUI.skin.label.CalcSize(new GUIContent(menuName)).x > _dropDownWidth - 35)
                {
                    menuName = menuName.Substring(0, menuName.Length - 1);
                }

                content = thumb != null
                    ? new GUIContent($"{menuName}", thumb, tooltip)
                    : new GUIContent($"     {menuName}", tooltip);
            }
            else
            {
                content = new GUIContent($"     {menuName}", tooltip);
            }
            return(content);
        }
        private void DrawListGUI(bool isNext = false, float anim = 0)
        {
            Rect rect = position;

            rect.x       = +1f;
            rect.x      -= 230 * anim;
            rect.y       = 30f;
            rect.height -= 30f;
            rect.width  -= 2f;
            GUILayout.BeginArea(rect);

            rect = GUILayoutUtility.GetRect(10f, 25f);

            if (string.IsNullOrEmpty(_currentActivePath) || _currentActivePath == "/")
            {
                GUI.Label(rect, _searchString == string.Empty ? "Nodes" : "Search", _styles.Header);
            }
            else
            {
                string nestedTitle = _currentActivePath.Substring(0, _currentActivePath.Length - 1);
                if (GUI.Button(rect, _searchString == string.Empty ? nestedTitle : "Search", _styles.Header))
                {
                    if (!isNext && !string.IsNullOrEmpty(_currentActivePath))
                    {
                        List <string> tmp = _currentActivePath.Split('/').ToList();
                        if (tmp.Count - 2 >= 0)
                        {
                            _nextActiveNode  = tmp[tmp.Count - 2];
                            _nextActiveIndex = 0;
                            tmp.RemoveAt(_currentActivePath.Split('/').Length - 2);
                        }
                        _nextActivePath = string.Join("/", tmp.ToArray());
                        _isAnimating    = true;
                        _animGoal       = 1;
                        _lastTime       = DateTime.Now.Millisecond;
                    }
                }
                if (string.IsNullOrEmpty(_searchString))
                {
                    GUI.Label(new Rect((float)(rect.x + 6.0), rect.y + 6f, 13f, 13f), "", _styles.LeftArrow);
                }
            }

            _headerRect = rect;
            //TODO: don't be lazy, figure out the math for this so you don't have to loop :P
            bool repaint = false;

            while (_currentActiveIndex * LIST_BUTTON_HEIGHT >=
                   _scrollPosition.y + DROPDOWN_HEIGHT - (LIST_BUTTON_HEIGHT * 3) - 5)
            {
                _scrollPosition.y += LIST_BUTTON_HEIGHT;
                repaint            = true;
            }

            while (_currentActiveIndex * LIST_BUTTON_HEIGHT < _scrollPosition.y)
            {
                _scrollPosition.y -= LIST_BUTTON_HEIGHT;
                repaint            = true;
            }

            if (repaint)
            {
                Repaint();
            }

            float oldScrollPosition = _scrollPosition.y;

            _scrollPosition = EditorGUILayout.BeginScrollView(_scrollPosition);

            if (string.IsNullOrEmpty(_searchString))
            {
                DrawNodeEntries(NodeMenu, isNext);
            }
            else
            {
                for (int i = 0; i < (_filteredNodeDefinitions.Count() > 100 ? 100 : _filteredNodeDefinitions.Count()); i++)
                {
                    UdonNodeDefinition udonNodeDefinition = _filteredNodeDefinitions.ElementAt(i);

                    string aB = _currentActiveNode;
                    if (_filteredNodeDefinitions.All(f => f.fullName != aB))
                    {
                        _currentActiveNode = udonNodeDefinition.fullName;
                    }

                    GUIStyle buttonStyle = _currentActiveNode == udonNodeDefinition.fullName
                        ? _styles.ActiveComponentButton
                        : _styles.ComponentButton;

                    rect = GUILayoutUtility.GetRect(10f, LIST_BUTTON_HEIGHT);
                    bool pressedButton = GUI.Button(rect, NodeContentWithIcon(udonNodeDefinition, PrettyFullName(udonNodeDefinition), PrettyFullName(udonNodeDefinition, true)), buttonStyle);
                    if (pressedButton ||
                        (_currentActiveNode == udonNodeDefinition.fullName && (KeyUpEvent(KeyCode.Return) || KeyUpEvent(KeyCode.RightArrow))))
                    {
                        Rect graphExtents = (Rect)GetInstanceField(typeof(UdonGraph), _graph, "graphExtents");
                        graphExtents = new Rect(new Vector2(_graphGUI.scrollPosition.x + (graphExtents.x + (_graphGUI.Host.position.width / 2)) - 125, _graphGUI.scrollPosition.y + (graphExtents.y + (_graphGUI.Host.position.height / 2)) - 24), new Vector2(10, 10));
                        _graph.CreateNode(udonNodeDefinition, graphExtents.position);
                        Close();
                    }

                    if (rect.Contains(Event.current.mousePosition) &&
                        Event.current.mousePosition.y <= _dropDownRect.yMin + DROPDOWN_HEIGHT + _scrollPosition.y &&
                        Event.current.mousePosition.y > _headerRect.yMax + _scrollPosition.y - LIST_BUTTON_HEIGHT)
                    {
                        _currentActiveNode  = udonNodeDefinition.fullName;
                        _currentActiveIndex = i;
                    }


                    if (Event.current.type != EventType.MouseMove)
                    {
                        continue;
                    }

                    if (mouseOverWindow != null)
                    {
                        mouseOverWindow.Repaint();
                    }
                }
            }

            GUILayout.EndScrollView();

            if ((int)_scrollPosition.y != (int)oldScrollPosition)
            {
                {
                    Repaint();
                }
            }

            GUILayout.EndArea();

            if (!string.IsNullOrEmpty(_searchString))
            {
                if (KeyUsedEvent(KeyCode.DownArrow))
                {
                    OffsetActiveButton(1);
                }
                else if (KeyUsedEvent(KeyCode.UpArrow))
                {
                    OffsetActiveButton(-1);
                }
            }
        }
Example #12
0
        public void CreateNode(UdonNodeDefinition udonNodeDefinition, Vector2?position = null)
        {
            //Awful hack to fix regression in unity graph property type conversion
            {
                var prop = typeof(TypeConverter).GetField(
                    "useCompatibleTypeConversion",
                    System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static
                    );
                prop.SetValue(this, true);
            }

            UdonNode node = CreateInstance <UdonNode>();

            node.name     = udonNodeDefinition.fullName;
            node.title    = PrettyString(udonNodeDefinition.name).FriendlyNameify();
            node.position = position == null ? new Rect(Vector2.zero, Vector2.zero) : new Rect(position.Value, Vector2.zero);

            if (node.name.StartsWith("Event_") && node.name != "Event_Custom")
            {
                if (nodes.Any(n => n.name == node.name))
                {
                    Debug.LogWarning($"Can't create more than one {node.name} node, try managing your flow with a Block node instead!");
                    return;
                }
            }

            if (node.title == "Const_VRCUdonCommonInterfacesIUdonEventReceiver")
            {
                node.title = "UdonBehaviour";
            }

            UdonNodeData nodeData = data.AddNode(udonNodeDefinition.fullName);

            if (udonNodeDefinition.flow)
            {
                if (!udonNodeDefinition.fullName.StartsWith("Event_"))
                {
                    node.AddInputSlot("");
                }

                node.AddOutputSlot("");
                if (_specialFlows.Contains(udonNodeDefinition.fullName))
                {
                    node.AddOutputSlot("");
                }
            }

            foreach (Type input in udonNodeDefinition.inputs)
            {
                node.AddInputSlot(FriendlyTypeName(input), SlotTypeConverter(input, udonNodeDefinition.fullName));
            }

            foreach (Type output in udonNodeDefinition.outputs)
            {
                node.AddOutputSlot(FriendlyTypeName(output), SlotTypeConverter(output, udonNodeDefinition.fullName));
            }


            if (udonNodeDefinition.defaultValues != null)
            {
                nodeData.nodeValues = new SerializableObjectContainer[udonNodeDefinition.defaultValues.Length];
                nodeData.nodeUIDs   = new string[udonNodeDefinition.defaultValues.Length];
                for (int i = 0; i < udonNodeDefinition.defaultValues.Length; i++)
                {
                    object defaultValue = udonNodeDefinition.defaultValues[i];
                    if (defaultValue != null)
                    {
                        nodeData.nodeValues[i] = SerializableObjectContainer.Serialize(defaultValue);
                    }
                }
            }

            node.uid = nodeData.uid;

            ReSerializeData();

            AddNode(node);
        }
 public SendCustomEventNode(UdonNodeDefinition nodeDefinition, UdonGraph view, UdonNodeData nodeData = null) : base(nodeDefinition, view, nodeData)
 {
 }
 public SetVariableNode(UdonNodeDefinition nodeDefinition, UdonGraph view, UdonNodeData nodeData = null) : base(nodeDefinition, view, nodeData)
 {
 }
Example #15
0
        private bool TrySetupNode(UdonNodeDefinition udonNodeDefinition, Vector2?position, out UdonNode node,
                                  ref UdonNodeData nodeData)
        {
            DoPropHack();
            if (!TryCreateNodeInstance(out node))
            {
                return(false);
            }
            if (nodeData == null)
            {
                nodeData = data.AddNode(udonNodeDefinition.fullName);
            }
            node.uid = nodeData.uid;
            return(true);

            void DoPropHack()
            {
                //Awful hack to fix regression in unity graph property type conversion
                {
                    FieldInfo prop = typeof(TypeConverter).GetField(
                        "useCompatibleTypeConversion",
                        BindingFlags.NonPublic | BindingFlags.Static
                        );
                    if (prop != null)
                    {
                        prop.SetValue(this, true);
                    }
                }
            }

            bool TryCreateNodeInstance(out UdonNode outNode)
            {
                outNode = CreateInstance <UdonNode>();

                outNode.name     = udonNodeDefinition.fullName;
                outNode.title    = PrettyString(udonNodeDefinition.name).FriendlyNameify();
                outNode.position = position == null ? new Rect(Vector2.zero, Vector2.zero) : new Rect(position.Value, Vector2.zero);
                string nodeName = outNode.name;

                if (nodeName.StartsWith("Event_") &&
                    (nodeName != "Event_Custom" || graphProgramAsset.GetType() == typeof(UdonSubGraphAsset)))
                {
                    if (nodes.Any(n => n.name == nodeName))
                    {
                        Debug.LogWarning(
                            $"Can't create more than one {nodeName} node, try managing your flow with a Block node instead!");
                        return(false);
                    }
                }

                if (nodeName.StartsWith("Event_") &&
                    (nodeName != "Event_Custom" && graphProgramAsset.GetType() == typeof(UdonSubGraphAsset)))
                {
                    Debug.LogWarning($"SubGraphs can't use built-in events, pipe in your event from the parent graph instead!");
                    return(false);
                }

                if (outNode.title == "Const_VRCUdonCommonInterfacesIUdonEventReceiver")
                {
                    outNode.title = "UdonBehaviour";
                }

                return(true);
            }
        }
 public GetOrSetProgramVariableNode(UdonNodeDefinition nodeDefinition, UdonGraph view, UdonNodeData nodeData = null) :
     base(nodeDefinition, view, nodeData)
 {
 }
Example #17
0
        public UdonNode CreateNode(UdonNodeData nodeData)
        {
            //Awful hack to fix regression in unity graph property type conversion
            {
                var prop = typeof(TypeConverter).GetField(
                    "useCompatibleTypeConversion",
                    System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static
                    );
                prop.SetValue(this, true);
            }

            UdonNodeDefinition udonNodeDefinition = null;

            try
            {
                udonNodeDefinition = UdonEditorManager.Instance.GetNodeDefinition(nodeData.fullName);
            }
            catch
            {
                Debug.LogError($"Skipping missing node: {nodeData.fullName}");
                return(null);
            }

            UdonNode node = CreateInstance <UdonNode>();

            node.name  = udonNodeDefinition.fullName;
            node.title = PrettyString(udonNodeDefinition.name).FriendlyNameify();

            if (node.name.StartsWith("Event_") && node.name != "Event_Custom")
            {
                if (nodes.Any(n => n.name == node.name))
                {
                    Debug.LogWarning($"Can't create more than one {node.name} node, try managing your flow with a Block node instead!");
                    return(null);
                }
            }

            if (node.title == "Const_VRCUdonCommonInterfacesIUdonEventReceiver")
            {
                node.title = "UdonBehaviour";
            }
            node.uid      = nodeData.uid;
            node.position = new Rect(nodeData.position, Vector2.zero);

            if (udonNodeDefinition.flow)
            {
                if (!udonNodeDefinition.fullName.StartsWith("Event_"))
                {
                    node.AddInputSlot("");
                }

                node.AddOutputSlot("");
                if (_specialFlows.Contains(udonNodeDefinition.fullName))
                {
                    node.AddOutputSlot("");
                }

                if (udonNodeDefinition.fullName == "Block")
                {
                    int connectedFlows = nodeData.flowUIDs.Count(f => !string.IsNullOrEmpty(f));
                    if (connectedFlows > 1)
                    {
                        for (int i = 0; i < connectedFlows - 1; i++)
                        {
                            node.AddOutputSlot("");
                        }
                    }
                }
            }

            if (udonNodeDefinition.fullName == "SubGraph")
            {
                if (nodeData.nodeValues.Length > 0 && nodeData.nodeValues[0] != null)
                {
                    IUdonGraphDataProvider graphDataProvider = (IUdonGraphDataProvider)nodeData.nodeValues[0].Deserialize();
                    if (graphDataProvider != null)
                    {
                        UdonGraphData subGraphData = graphDataProvider.GetGraphData();
                        bool          doExit       = false;
                        foreach (UdonNodeData eventNode in subGraphData.EventNodes)
                        {
                            if (eventNode.fullName != "Event_Custom")
                            {
                                continue;
                            }

                            string customEventName = "customEvent";
                            if (eventNode.nodeValues.Length > 0 && eventNode.nodeValues[0] != null)
                            {
                                string eventName = (string)eventNode.nodeValues[0].Deserialize();
                                if (!string.IsNullOrEmpty(eventName))
                                {
                                    customEventName = eventName;
                                }
                            }
                            node.AddInputSlot(customEventName);
                            doExit = true;

                            break; //TODO: support more than one custom event in a subgraph
                        }
                        if (doExit)
                        {
                            node.AddOutputSlot("Exit");
                        }
                    }
                }
            }

            // Data Validation //
            bool modifiedData = false;

            for (int i = 0; i < nodeData.nodeValues.Length; i++)
            {
                if (udonNodeDefinition.inputs.Length <= i)
                {
                    continue;
                }
                Type expectedType = udonNodeDefinition.inputs[i];

                if (nodeData.nodeValues[i] == null)
                {
                    continue;
                }
                object value = nodeData.nodeValues[i].Deserialize();
                if (value == null)
                {
                    continue;
                }

                if (!expectedType.IsInstanceOfType(value))
                {
                    nodeData.nodeValues[i] = SerializableObjectContainer.Serialize(null, expectedType);
                    modifiedData           = true;
                }
            }
            if (modifiedData)
            {
                ReSerializeData();
            }
            ////////////////////

            foreach (Type input in udonNodeDefinition.inputs)
            {
                node.AddInputSlot(FriendlyTypeName(input), SlotTypeConverter(input, udonNodeDefinition.fullName));
            }

            foreach (Type output in udonNodeDefinition.outputs)
            {
                node.AddOutputSlot(FriendlyTypeName(output), SlotTypeConverter(output, udonNodeDefinition.fullName));
            }

            AddNode(node);
            return(node);
        }
Example #18
0
 private static bool StartsWithIgnoredKeyword(UdonNodeDefinition definition)
 {
     return(definition.fullName.StartsWith("Variable_") || definition.fullName.StartsWith("Event_") ||
            definition.fullName.StartsWith("Const_") || definition.fullName.StartsWith("Type_"));
 }
        // 0 = Value, 1 = name, 2 = public, 3 = synced, 4 = syncType
        public UdonParameterProperty(UdonGraph graphView, UdonNodeDefinition definition, UdonNodeData nodeData)
        {
            this.graph      = graphView;
            this.definition = definition;
            this.nodeData   = nodeData;

            // Make sure the incoming nodeData has the right number of nodeValues (super old graphs didn't have sync info)
            if (this.nodeData.nodeValues.Length != 5)
            {
                this.nodeData.nodeValues = GetDefaultNodeValues();
                for (int i = 0; i < nodeData.nodeValues.Length; i++)
                {
                    this.nodeData.nodeValues[i] = nodeData.nodeValues[i];
                }
            }

            // Public Toggle
            isPublic = new EngineUI.Toggle
            {
                text  = "public",
                value = (bool)GetValue(ValueIndices.isPublic)
            };
            isPublic.OnValueChanged(e =>
            {
                SetNewValue(e.newValue, ValueIndices.isPublic);
            });
            Add(isPublic);

            // Is Synced Field
            isSynced = new EngineUI.Toggle
            {
                text  = "synced",
                value = (bool)GetValue(ValueIndices.isSynced),
            };

            isSynced.OnValueChanged(e =>
            {
                SetNewValue(e.newValue, ValueIndices.isSynced);
                syncField.visible = e.newValue;
            });
            Add(isSynced);

            // Sync Field, add to isSynced
            List <string> choices = new List <string>()
            {
                "none", "linear", "smooth"
            };

            syncField = new EditorUI.PopupField <string>(choices, 0)
            {
                visible = isSynced.value
            };
            syncField.OnValueChanged(e =>
            {
                SetNewValue(e.newValue, ValueIndices.syncType);
            });
            isSynced.Add(syncField);

            // Container to show/edit Default Value
            var friendlyName = UdonGraphExtensions.FriendlyTypeName(definition.type).FriendlyNameify();

            defaultValueContainer = new VisualElement
            {
                new Label("default value")
                {
                    name = "default-value-label"
                }
            };
            var field = GetTheRightField(definition.type);

            if (field != null)
            {
                // TODO: need to handle cases where we can't generate the field above
                defaultValueContainer.Add(field);
                Add(defaultValueContainer);
            }
        }
 public SetReturnValueNode(UdonNodeDefinition nodeDefinition, UdonGraph view, UdonNodeData nodeData = null) : base(nodeDefinition, view, nodeData)
 {
 }
Example #21
0
        // 0 = Value, 1 = name, 2 = public, 3 = synced, 4 = syncType
        public UdonParameterProperty(UdonGraph graphView, UdonNodeDefinition definition, UdonNodeData nodeData)
        {
            this.graph      = graphView;
            this.definition = definition;
            this.nodeData   = nodeData;

            // Make sure the incoming nodeData has the right number of nodeValues (super old graphs didn't have sync info)
            if (this.nodeData.nodeValues.Length != 5)
            {
                this.nodeData.nodeValues = GetDefaultNodeValues();
                for (int i = 0; i < nodeData.nodeValues.Length; i++)
                {
                    this.nodeData.nodeValues[i] = nodeData.nodeValues[i];
                }
            }

            // Public Toggle
            isPublic = new Toggle
            {
                text  = "public",
                value = (bool)GetValue(ValueIndices.isPublic)
            };
#if UNITY_2019_3_OR_NEWER
            isPublic.RegisterValueChangedCallback(
#else
            isPublic.OnValueChanged(
#endif
                e => { SetNewValue(e.newValue, ValueIndices.isPublic); });
            Add(isPublic);

            // Is Synced Field
            isSynced = new Toggle
            {
                text  = "synced",
                value = (bool)GetValue(ValueIndices.isSynced),
            };

#if UNITY_2019_3_OR_NEWER
            isSynced.RegisterValueChangedCallback(
#else
            isSynced.OnValueChanged(
#endif
                e =>
            {
                SetNewValue(e.newValue, ValueIndices.isSynced);
                syncField.visible = e.newValue;
            });
            Add(isSynced);

            // Sync Field, add to isSynced
            List <string> choices = new List <string>()
            {
                "none", "linear", "smooth"
            };
            syncField = new EditorUI.PopupField <string>(choices, 0)
            {
                visible = isSynced.value
            };
#if UNITY_2019_3_OR_NEWER
            syncField.RegisterValueChangedCallback(
#else
            syncField.OnValueChanged(
#endif
                e => { SetNewValue(e.newValue, ValueIndices.syncType); });
            isSynced.Add(syncField);

            // Container to show/edit Default Value
            var friendlyName      = UdonGraphExtensions.FriendlyTypeName(definition.type).FriendlyNameify();
            defaultValueContainer = new VisualElement();
            defaultValueContainer.Add(
                new Label("default value")
            {
                name = "default-value-label"
            });

            // Generate Default Value Field
            var value   = TryGetValueObject(out object result);
            _inputField = UdonFieldFactory.CreateField(
                definition.type,
                result,
                newValue => SetNewValue(newValue, ValueIndices.value)
                );
            if (_inputField != null)
            {
                defaultValueContainer.Add(_inputField);
                Add(defaultValueContainer);
            }
        }
Example #22
0
        public static string GetDocumentationLink(UdonNodeDefinition definition)
        {
            if (definition.fullName.StartsWithCached("Event_"))
            {
                string url = "https://docs.unity3d.com/2018.4/Documentation/ScriptReference/MonoBehaviour.";
                url += definition.name;
                url += ".html";
                return(url);
            }

            if (definition.fullName.Contains("Array.__ctor"))
            {
                //I couldn't find the array constructor documentation
                return("https://docs.microsoft.com/en-us/dotnet/api/system.array?view=netframework-4.8");
            }

            if (definition.fullName.Contains("Array.__Get"))
            {
                return("https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/member-access-operators#indexer-operator-");
            }

            if (definition.fullName.Contains(".__Equals__SystemObject"))
            {
                return("https://docs.microsoft.com/en-us/dotnet/api/system.object.equals?view=netframework-4.8");
            }

            if (definition.name.Contains("[]"))
            {
                string url = "https://docs.microsoft.com/en-us/dotnet/api/system.array.";
                url += definition.name.Split(' ')[1];
                url += "?view=netframework-4.8";
                return(url);
            }

            if (definition.type.Namespace.Contains("UnityEngine"))
            {
                string url = "https://docs.unity3d.com/2018.4/Documentation/ScriptReference/";
                if (definition.type.Namespace != "UnityEngine")
                {
                    url += definition.type.Namespace.Replace("UnityEngine.", "");
                    url += ".";
                }
                url += definition.type.Name;

                if (definition.fullName.Contains("__get_") || definition.fullName.Contains("__set_"))
                {
                    if (definition.fullName.Contains("__get_"))
                    {
                        url += "-" + definition.name.Split(new[] { "get_" }, StringSplitOptions.None)[1];
                    }
                    else
                    {
                        url += "-" + definition.name.Split(new[] { "set_" }, StringSplitOptions.None)[1];
                    }

                    url += ".html";
                    return(url);
                }

                if (definition.fullName.Contains("Const_") || definition.fullName.Contains("Type_") || definition.fullName.Contains("Variable_"))
                {
                    url += ".html";
                    return(url);
                }

                {
                    // Methods
                    url += "." + definition.name.Split(' ')[1];
                    url += ".html";
                    return(url);
                }
            }

            if (definition.type.Namespace.Contains("System"))
            {
                string url = "https://docs.microsoft.com/en-us/dotnet/api/system.";
                url += definition.type.Name;
                if (definition.fullName.Contains("__get_") || definition.fullName.Contains("__set_"))
                {
                    url += "." + definition.name.Split(' ')[1].Replace("get_", "").Replace("set_", "");
                    url += "?view=netframework-4.8";
                    return(url);
                }

                if (definition.name == "ctor")
                {
                    url += ".-ctor";
                    url += "?view=netframework-4.8#System_";
                    url += definition.type.Name + "__ctor_";
                    foreach (var pType in definition.Inputs)
                    {
                        url += "System_" + pType.type.Name.Replace('[', '_').Replace(']', '_') + "_";
                    }

                    return(url);
                }

                if (definition.fullName.Contains("Const_") || definition.fullName.Contains("Type_"))
                {
                    url += "?view=netframework-4.8";
                    return(url);
                }

                {
                    // Methods
                    // not entirely sure what case this catches, but we were always doing the split before, and it was breaking if we didn't have . in the name.
                    if (definition.name.Contains('.'))
                    {
                        url += "." + definition.name.Split(' ')[1];
                    }
                    url += "?view=netframework-4.8";
                    return(url);
                }
            }

            return("");
        }
        // 0 = Value, 1 = name, 2 = public, 3 = synced, 4 = syncType
        public UdonParameterProperty(UdonGraph graphView, UdonNodeDefinition definition, UdonNodeData nodeData)
        {
            this.graph      = graphView;
            this.definition = definition;
            this.nodeData   = nodeData;

            string friendlyName = UdonGraphExtensions.FriendlyTypeName(definition.type).FriendlyNameify();

            // Public Toggle
            isPublic = new Toggle
            {
                text  = "public",
                value = (bool)GetValue(ValueIndices.isPublic)
            };
#if UNITY_2019_3_OR_NEWER
            isPublic.RegisterValueChangedCallback(
#else
            isPublic.OnValueChanged(
#endif
                e => { SetNewValue(e.newValue, ValueIndices.isPublic); });
            Add(isPublic);

            if (UdonNetworkTypes.CanSync(definition.type))
            {
                // Is Synced Field
                isSynced = new Toggle
                {
                    text  = "synced",
                    value = (bool)GetValue(ValueIndices.isSynced),
                    name  = "syncToggle",
                };

#if UNITY_2019_3_OR_NEWER
                isSynced.RegisterValueChangedCallback(
#else
                isSynced.OnValueChanged(
#endif
                    e =>
                {
                    SetNewValue(e.newValue, ValueIndices.isSynced);
                    syncField.visible = e.newValue;
                });

                // Sync Field, add to isSynced
                List <string> choices = new List <string>()
                {
                    "none"
                };

                if (UdonNetworkTypes.CanSyncLinear(definition.type))
                {
                    choices.Add("linear");
                }

                if (UdonNetworkTypes.CanSyncSmooth(definition.type))
                {
                    choices.Add("smooth");
                }

                syncField = new EditorUI.PopupField <string>(choices, 0)
                {
                    visible = isSynced.value,
                };
                syncField.Insert(0, new Label("smooth:"));

#if UNITY_2019_3_OR_NEWER
                syncField.RegisterValueChangedCallback(
#else
                syncField.OnValueChanged(
#endif
                    e =>
                {
                    SetNewValue(e.newValue, ValueIndices.syncType);
                });

                // Only show sync smoothing dropdown if there are choices to be made
                if (choices.Count > 1)
                {
                    isSynced.Add(syncField);
                }

                Add(isSynced);
            }
            else
            {
                // Cannot Sync
                SetNewValue(false, ValueIndices.isSynced);
                Add(new Label($"{friendlyName} cannot be synced."));
            }

            // Container to show/edit Default Value
            defaultValueContainer = new VisualElement();
            defaultValueContainer.Add(
                new Label("default value")
            {
                name = "default-value-label"
            });

            // Generate Default Value Field
            var value   = TryGetValueObject(out object result);
            _inputField = UdonFieldFactory.CreateField(
                definition.type,
                result,
                newValue => SetNewValue(newValue, ValueIndices.value)
                );
            if (_inputField != null)
            {
                defaultValueContainer.Add(_inputField);
                Add(defaultValueContainer);
            }
        }