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; }
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); }); }
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"); }
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)); } }
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")))); }
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); } } }
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) { }
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) { }
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); }
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) { }
// 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); } }
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); } }