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); }); }
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 void DeleteNode(string nodeID) { UdonNodeData node = data.FindNode(nodeID); if (node == null) { return; } data.RemoveNode(node); ReSerializeData(); }
public override void RemoveEdge(Edge e) { int index = 0; if (e.fromSlot.isFlowSlot) { foreach (Slot outputSlot in e.fromSlot.node.outputFlowSlots) { if (outputSlot == e.fromSlot) { break; } index++; } } else { foreach (Slot inputSlot in e.toSlot.node.inputDataSlots) { if (inputSlot == e.toSlot) { break; } index++; } } UdonNodeData toNode = data.FindNode(((UdonNode)e.toSlot.node).uid); UdonNodeData fromNode = data.FindNode(((UdonNode)e.fromSlot.node).uid); if (e.fromSlot.isFlowSlot) { fromNode.RemoveFlowNode(index); } else { toNode.RemoveNode(index); } ReSerializeData(); base.RemoveEdge(e); }
public void Reload() { if (this == null) { DestroyImmediate(this); return; } Reloading = true; // ReSharper disable once DelegateSubtraction Undo.undoRedoPerformed -= OnUndoRedo; //Remove old handler if present to prevent duplicates, doesn't cause errors if not present Undo.undoRedoPerformed += OnUndoRedo; nodes.Clear(); edges.Clear(); IEnumerable <UdonNodeDefinition> definitions = UdonEditorManager.Instance.GetNodeDefinitions(); if (definitions == null || definitions.Count() < 100) { throw new NullReferenceException("Udon NodeDefinitions have failed to load, aborting graph load."); } for (int i = data.nodes.Count - 1; i >= 0; i--) { UdonNodeData node = data.nodes[i]; UdonNode udonNode = CreateNode(node); if (udonNode != null) { continue; } Debug.Log($"Removing null node '{node.fullName}'"); data.nodes.RemoveAt(i); } foreach (Node node in nodes) { UdonNode udonNode = (UdonNode)node; udonNode.PopulateEdges(); } Reloading = false; ReSerializeData(); }
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); } }
public static Port Create(string portName, Direction portDirection, IEdgeConnectorListener connectorListener, Type type, UdonNodeData data, int index, Orientation orientation = Orientation.Horizontal) { Capacity capacity = Capacity.Single; if (portDirection == Direction.Input && type == null || portDirection == Direction.Output && type != null) { capacity = Capacity.Multi; } var port = new UdonPort(orientation, portDirection, capacity, type) { m_EdgeConnector = new EdgeConnector <Edge>(connectorListener), }; port.portName = portName; port._udonNodeData = data; port._nodeValueIndex = index; port.SetupPort(); return(port); }
public override Edge Connect(Slot fromSlot, Slot toSlot) { int index = 0; int indexOther = 0; if (fromSlot.isFlowSlot) { foreach (Slot outputSlot in fromSlot.node.outputFlowSlots) { if (outputSlot == fromSlot) { break; } index++; } } else { foreach (Slot inputSlot in toSlot.node.inputDataSlots) { if (inputSlot == toSlot) { break; } index++; } foreach (Slot outputSlot in fromSlot.node.outputDataSlots) { if (outputSlot == fromSlot) { break; } indexOther++; } } UdonNodeData fromNode = data.FindNode(((UdonNode)fromSlot.node).uid); UdonNodeData toNode = data.FindNode(((UdonNode)toSlot.node).uid); if (fromSlot.isFlowSlot) { fromNode.AddFlowNode(toNode, index); } else { toNode.AddNode(fromNode, index, indexOther); } if (fromNode.fullName == "Block") { int connectedFlows = fromNode.flowUIDs.Count(f => !string.IsNullOrEmpty(f)); if (connectedFlows >= fromSlot.node.outputFlowSlots.Count()) { fromSlot.node.AddOutputSlot(""); } } ReSerializeData(); return(base.Connect(fromSlot, toSlot)); }
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 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); }
// 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 GetOrSetProgramVariableNode(UdonNodeDefinition nodeDefinition, UdonGraph view, UdonNodeData nodeData = null) : base(nodeDefinition, view, nodeData) { }
public SetVariableNode(UdonNodeDefinition nodeDefinition, UdonGraph view, UdonNodeData nodeData = null) : base(nodeDefinition, view, nodeData) { }
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 UdonNode CreateNode(UdonNodeData nodeData) { UdonNodeDefinition udonNodeDefinition; try { udonNodeDefinition = UdonEditorManager.Instance.GetNodeDefinition(nodeData.fullName); } catch { Debug.LogError($"Skipping missing node: {nodeData.fullName}"); return(null); } if (!TrySetupNode(udonNodeDefinition, nodeData.position, out UdonNode node, ref nodeData)) { return(null); } int connectedFlowCount = nodeData.flowUIDs.Count(f => !string.IsNullOrEmpty(f)); ValidateNodeData(); LayoutSlots(udonNodeDefinition, node, connectedFlowCount); AddNode(node); return(node); void ValidateNodeData() { bool modifiedData = false; for (int i = 0; i < nodeData.nodeValues.Length; i++) { if (udonNodeDefinition.Inputs.Count <= i) { continue; } Type expectedType = udonNodeDefinition.Inputs[i].type; 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(); } } }
public SetReturnValueNode(UdonNodeDefinition nodeDefinition, UdonGraph view, UdonNodeData nodeData = null) : base(nodeDefinition, view, nodeData) { }
public SendCustomEventNode(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 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); } }
internal void PopulateEdges() { UdonNodeData data = ((UdonGraph)graph).data.FindNode(uid); //UdonNodeDefinition nodeDefinition = ((UdonGraph)graph).data. UdonNodeDefinition udonNodeDefinition; if (NodeDefinitionCache.ContainsKey(data.fullName)) { udonNodeDefinition = NodeDefinitionCache[data.fullName]; } else { udonNodeDefinition = UdonEditorManager.Instance.GetNodeDefinition(data.fullName); NodeDefinitionCache.Add(data.fullName, udonNodeDefinition); } for (int i = 0; i < inputDataSlots.Count(); i++) // udonNodeDefinition.Inputs.Count { if (data.nodeUIDs.Length <= i) { continue; } if (string.IsNullOrEmpty(data.nodeUIDs[i])) { continue; } string[] splitUID = data.nodeUIDs[i].Split('|'); string nodeUID = splitUID[0]; int otherIndex = 0; if (splitUID.Length > 1) { otherIndex = int.Parse(splitUID[1]); } if (string.IsNullOrEmpty(nodeUID)) { continue; } Node connectedNode = graph.nodes.FirstOrDefault(n => ((UdonNode)n).uid == nodeUID); if (connectedNode == null) { Debug.LogError("Failed to connect node " + nodeUID); data.nodeUIDs[i] = ""; ((UdonGraph)graph).ReSerializeData(); continue; } List <Slot> slots = inputDataSlots.ToList(); if (slots.Count <= i) { Debug.LogError($"Failed to find input data slot (index {i}) for node {uid} {data.fullName}"); continue; } Slot destSlot = slots[i]; if (destSlot == null) { Debug.LogError("Failed to find input data slot for node " + uid); continue; } if (otherIndex < 0) { otherIndex = 0; } if (connectedNode.outputDataSlots.Count() <= otherIndex) { otherIndex = 0; } Slot sourceSlot = connectedNode.outputDataSlots.ToList()[otherIndex]; //.FirstOrDefault(); // // catch // { // Debug.LogError($"failed to connect node {uid} {data.fullName} to node {((UdonNode)connectedNode).uid} | otherindex is {otherIndex}"); // } if (sourceSlot == null) { Debug.LogError("Failed to find output data slot for node " + nodeUID); continue; } graph.Connect(sourceSlot, destSlot); } for (int i = 0; i < data.flowUIDs.Length; i++) { string nodeUID = data.flowUIDs[i]; if (string.IsNullOrEmpty(nodeUID)) { continue; } Node connectedNode = graph.nodes.FirstOrDefault(n => ((UdonNode)n).uid == nodeUID); if (connectedNode == null) { Debug.LogError("Failed to connect flow node " + nodeUID); continue; } if (uid == "4e2c7cdc-8134-4616-bc83-783dc495759f") { int count = 0; foreach (Slot slot in outputFlowSlots) { count++; } Debug.Log(count); } Slot sourceSlot = outputFlowSlots.Count() > 1 ? outputFlowSlots.ToArray()[i] : outputFlowSlots.FirstOrDefault(); if (sourceSlot == null) { Debug.LogError("Failed to find output flow slot for node " + uid); continue; } Slot destSlot = connectedNode.inputFlowSlots.FirstOrDefault(); if (destSlot == null) { Debug.LogError("Failed to find input flow slot for node " + nodeUID); continue; } graph.Connect(sourceSlot, destSlot); } }
// 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); } }