// Create a connection between two slots. public static bool ConnectSlots(Graphs.Slot fromSlot, Graphs.Slot toSlot) { var nodeTo = ((Node)toSlot.node).runtimeInstance; var triggerEvent = GetEventOfOutputSlot(fromSlot); var targetMethod = GetMethodOfInputSlot(toSlot); // Determine the type of the target action. var actionType = GetUnityActionToInvokeMethod(targetMethod); if (actionType == null) return false; // invalid target method type // Create an action that is bound to the target method. var targetAction = Delegate.CreateDelegate( actionType, nodeTo, targetMethod ); if (triggerEvent is UnityEvent) { // The trigger event has no parameter. // Add the action to the event with a default parameter. if (actionType == typeof(UnityAction)) { UnityEventTools.AddVoidPersistentListener( triggerEvent, (UnityAction)targetAction ); return true; } if (actionType == typeof(UnityAction<float>)) { UnityEventTools.AddFloatPersistentListener( triggerEvent, (UnityAction<float>)targetAction, 1.0f ); return true; } } else if (triggerEvent is UnityEvent<float>) { // The trigger event has a float parameter. // Then the target method should have a float parameter too. if (actionType == typeof(UnityAction<float>)) { // Add the action to the event. UnityEventTools.AddPersistentListener( (UnityEvent<float>)triggerEvent, (UnityAction<float>)targetAction ); return true; } } else if (triggerEvent is UnityEvent<Vector3>) { // The trigger event has a Vector3 parameter. // Then the target method should have a Vector3 parameter too. if (actionType == typeof(UnityAction<Vector3>)) { // Add the action to the event. UnityEventTools.AddPersistentListener( (UnityEvent<Vector3>)triggerEvent, (UnityAction<Vector3>)targetAction ); return true; } } else if (triggerEvent is UnityEvent<Quaternion>) { // The trigger event has a Quaternion parameter. // Then the target method should have a Quaternion parameter too. if (actionType == typeof(UnityAction<Quaternion>)) { // Add the action to the event. UnityEventTools.AddPersistentListener( (UnityEvent<Quaternion>)triggerEvent, (UnityAction<Quaternion>)targetAction ); return true; } } else if (triggerEvent is UnityEvent<Color>) { // The trigger event has a color parameter. // Then the target method should have a color parameter too. if (actionType == typeof(UnityAction<Color>)) { // Add the action to the event. UnityEventTools.AddPersistentListener( (UnityEvent<Color>)triggerEvent, (UnityAction<Color>)targetAction ); return true; } } return false; // trigger-target mismatch }
// Returns an event instance that is bound to a given output slot. static UnityEventBase GetEventOfOutputSlot(Graphs.Slot slot) { var node = ((Node)slot.node).runtimeInstance; var flags = BindingFlags.Instance | BindingFlags.NonPublic; var field = node.GetType().GetField(slot.name, flags); return (UnityEventBase)field.GetValue(node); }
// Returns a method that is bound to a given input slot. static MethodInfo GetMethodOfInputSlot(Graphs.Slot slot) { var node = ((Node)slot.node).runtimeInstance; return node.GetType().GetMethod(slot.name); }
public override void NodeGUI(Graphs.Node node) { SelectNode(node); foreach (var slot in node.inputSlots) LayoutSlot(slot, slot.title, false, true, true, Styles.pinIn); node.NodeUI(this); foreach (var slot in node.outputSlots) { EditorGUILayout.BeginHorizontal(); GUILayout.FlexibleSpace(); LayoutSlot(slot, slot.title, true, false, true, Styles.pinOut); EditorGUILayout.EndHorizontal(); } DragNodes(); }
// Disconnect given two slots. public static void DisconnectSlots(Graphs.Slot fromSlot, Graphs.Slot toSlot) { var nodeTo = ((Node)toSlot.node).runtimeInstance; var triggerEvent = GetEventOfOutputSlot(fromSlot); var targetMethod = GetMethodOfInputSlot(toSlot); var methodName = targetMethod.Name; var eventCount = triggerEvent.GetPersistentEventCount(); for (var i = 0; i < eventCount; i++) { if (nodeTo == triggerEvent.GetPersistentTarget(i) && methodName == triggerEvent.GetPersistentMethodName(i)) { UnityEventTools.RemovePersistentListener(triggerEvent, i); break; } } }
// Establish a connection between slots. public override Graphs.Edge Connect(Graphs.Slot fromSlot, Graphs.Slot toSlot) { var edge = base.Connect(fromSlot, toSlot); if (_isEditing) { // Make this operation undoable. var fromNodeRuntime = ((Node)fromSlot.node).runtimeInstance; Undo.RecordObject(fromNodeRuntime, "Create Connection"); // Add a serialized event. ConnectionTools.ConnectSlots(fromSlot, toSlot); // Send a repaint request to the inspector window because // the inspector is shown at this point in most cases. GUIUtility.RepaintAllInspectors(); } return edge; }
// Remove a connection between slots. public override void RemoveEdge(Graphs.Edge edge) { if (_isEditing) { var fromSlot = edge.fromSlot; var toSlot = edge.toSlot; // Make this operation undoable. var fromNodeRuntime = ((Node)fromSlot.node).runtimeInstance; Undo.RecordObject(fromNodeRuntime, "Disconnect"); // Remove the serialized event. ConnectionTools.DisconnectSlots(fromSlot, toSlot); } base.RemoveEdge(edge); }
static Vector2 GetPositionAsToSlot(Graphs.Slot slot) { var rect = GetSlotPosition(slot); return GUIClip(new Vector2(rect.x, rect.y + kEdgeSlotYOffset)); }
// Check if slots can be connected. public override bool CanConnect(Graphs.Slot fromSlot, Graphs.Slot toSlot) { // If the outlet is bang, any inlet can be connected. if (fromSlot.dataType == null) return true; // Apply simple type matching. return fromSlot.dataType == toSlot.dataType; }
// Accessors for Slot.m_Position static Rect GetSlotPosition(Graphs.Slot slot) { var flags = BindingFlags.NonPublic | BindingFlags.Instance; var func = typeof(Graphs.Slot).GetField("m_Position", flags); return (Rect)func.GetValue(slot); }
static void DrawEdge(Graphs.Edge edge, Color color) { var p1 = GetPositionAsFromSlot(edge.fromSlot); var p2 = GetPositionAsToSlot(edge.toSlot); DrawEdge(p1, p2, color * edge.color); }
public void EndSlotDragging(Graphs.Slot slot, bool allowMultiple) { Debug.Assert(allowMultiple); // Do nothing if no target was specified. if (_dropTarget != slot) return; // If we're going to modify an existing edge, remove it. if (_moveEdge != null) slot.node.graph.RemoveEdge(_moveEdge); // Try to connect the edge to the target. try { slot.node.graph.Connect(_dragSourceSlot, slot); } finally { EndDragging(); slot.node.graph.Dirty(); Event.current.Use(); } UnityEngine.GUIUtility.ExitGUI(); }
public void SlotDragging(Graphs.Slot slot, bool allowEndDrag, bool allowMultiple) { Debug.Assert(allowMultiple); if (!allowEndDrag) return; if (_dragSourceSlot == null || _dragSourceSlot == slot) return; // Is this slot can be a drop target? if (_dropTarget != slot && slot.node.graph.CanConnect(_dragSourceSlot, slot) && !slot.node.graph.Connected(_dragSourceSlot, slot)) { _dropTarget = slot; } Event.current.Use(); }
public void BeginSlotDragging(Graphs.Slot slot, bool allowStartDrag, bool allowEndDrag) { if (allowStartDrag) { // Start dragging with a new connection. _dragSourceSlot = slot; Event.current.Use(); } if (allowEndDrag && slot.edges.Count > 0) { // Start dragging to modify an existing connection. _moveEdge = slot.edges[slot.edges.Count - 1]; _dragSourceSlot = _moveEdge.fromSlot; _dropTarget = slot; Event.current.Use(); } }