Added RelayNodeView;
Chnaged GraphView to multiple files for better organization;
This commit is contained in:
@@ -1,11 +1,9 @@
|
|||||||
using System.Collections.Generic;
|
using UnityEditor.Experimental.GraphView;
|
||||||
using UnityEditor.Experimental.GraphView;
|
|
||||||
|
|
||||||
namespace Misaki.GraphView.Editor
|
namespace Misaki.GraphView.Editor
|
||||||
{
|
{
|
||||||
public interface IPortContainer
|
public interface IPortContainer
|
||||||
{
|
{
|
||||||
public List<Port> InputPorts { get; }
|
public Port GetPort(int index, Direction direction);
|
||||||
public List<Port> OutputPorts { get; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,441 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
|
||||||
using UnityEditor;
|
|
||||||
using UnityEditor.Experimental.GraphView;
|
|
||||||
using UnityEngine;
|
|
||||||
using UnityEngine.UIElements;
|
|
||||||
|
|
||||||
namespace Misaki.GraphView.Editor
|
|
||||||
{
|
|
||||||
public class GraphView : UnityEditor.Experimental.GraphView.GraphView
|
|
||||||
{
|
|
||||||
private readonly Dictionary<string, Node> _nodeViewsMap = new();
|
|
||||||
private readonly Dictionary<Edge, SlotConnection> _slotConnections = new();
|
|
||||||
|
|
||||||
private readonly GraphBlackboardView _blackboardView;
|
|
||||||
private readonly GraphInspectorView _graphInspectorView;
|
|
||||||
|
|
||||||
private readonly GraphViewConfig _graphViewConfig;
|
|
||||||
private GraphObject _graphObject => _graphViewConfig.graphObject;
|
|
||||||
|
|
||||||
public EditorWindow EditorWindow { get; }
|
|
||||||
public GraphViewConfig GraphViewConfig => _graphViewConfig;
|
|
||||||
|
|
||||||
public GraphView(EditorWindow editorWindow, GraphViewConfig graphViewConfig)
|
|
||||||
{
|
|
||||||
EditorWindow = editorWindow;
|
|
||||||
_graphViewConfig = graphViewConfig;
|
|
||||||
|
|
||||||
var gridBackground = new GridBackground { name = "gridBackground" };
|
|
||||||
Add(gridBackground);
|
|
||||||
gridBackground.SendToBack();
|
|
||||||
|
|
||||||
var minimapConfig = _graphViewConfig.miniMapConfig;
|
|
||||||
if (minimapConfig is { enable: true })
|
|
||||||
{
|
|
||||||
var minimap = new MiniMap()
|
|
||||||
{
|
|
||||||
anchored = true
|
|
||||||
};
|
|
||||||
minimap.SetPosition(minimapConfig.position);
|
|
||||||
Add(minimap);
|
|
||||||
}
|
|
||||||
|
|
||||||
_blackboardView = new GraphBlackboardView(_graphObject, this, _graphViewConfig.serializedObject, _graphViewConfig.exposedPropertyTypeManager);
|
|
||||||
_blackboardView.OnPropertySelected += ChangeInspectorView;
|
|
||||||
|
|
||||||
foreach (var property in _graphObject.ExposedProperties)
|
|
||||||
{
|
|
||||||
_blackboardView.AddProperty(property);
|
|
||||||
}
|
|
||||||
|
|
||||||
_graphInspectorView = new GraphInspectorView();
|
|
||||||
|
|
||||||
Add(_blackboardView);
|
|
||||||
Add(_graphInspectorView);
|
|
||||||
|
|
||||||
this.StretchToParentSize();
|
|
||||||
|
|
||||||
this.AddManipulator(new ContentDragger());
|
|
||||||
this.AddManipulator(new SelectionDragger());
|
|
||||||
this.AddManipulator(new RectangleSelector());
|
|
||||||
this.AddManipulator(new ClickSelector());
|
|
||||||
|
|
||||||
var zoomConfig = _graphViewConfig.zoomConfig;
|
|
||||||
var zoomer = new ContentZoomer();
|
|
||||||
if (zoomConfig !=null)
|
|
||||||
{
|
|
||||||
zoomer.minScale = zoomConfig.minScale;
|
|
||||||
zoomer.maxScale = zoomConfig.maxScale;
|
|
||||||
zoomer.scaleStep = zoomConfig.scaleStep;
|
|
||||||
}
|
|
||||||
this.AddManipulator(zoomer);
|
|
||||||
|
|
||||||
InitializeAssetElements();
|
|
||||||
|
|
||||||
graphViewChanged += OnGraphViewChanged;
|
|
||||||
|
|
||||||
RegisterCallback<DragPerformEvent>(OnDragPerform);
|
|
||||||
RegisterCallbackOnce<GeometryChangedEvent>(_ => _graphInspectorView?.DockToParent(layout, DockingPosition.Right, false));
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void BuildContextualMenu(ContextualMenuPopulateEvent evt)
|
|
||||||
{
|
|
||||||
base.BuildContextualMenu(evt);
|
|
||||||
var mousePosition = (evt.currentTarget as VisualElement).ChangeCoordinatesTo(contentViewContainer, evt.localMousePosition);
|
|
||||||
|
|
||||||
if (selection.Count == 0)
|
|
||||||
{
|
|
||||||
evt.menu.InsertAction(1, "Create Sticky Note", e =>
|
|
||||||
{
|
|
||||||
var stickyNote = new StickyNoteData
|
|
||||||
{
|
|
||||||
title = "Sticky Note",
|
|
||||||
contents = "Contents",
|
|
||||||
theme = StickyNoteTheme.Classic,
|
|
||||||
fontSize = StickyNoteFontSize.Medium,
|
|
||||||
position = new Rect(mousePosition, new Vector2(200, 200))
|
|
||||||
};
|
|
||||||
|
|
||||||
AddStickyNote(stickyNote);
|
|
||||||
}, DropdownMenuAction.AlwaysEnabled);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void InitializeAssetElements()
|
|
||||||
{
|
|
||||||
var searchProvider = ScriptableObject.CreateInstance<NodeSearchProvider>();
|
|
||||||
searchProvider.SetOwner(this);
|
|
||||||
|
|
||||||
nodeCreationRequest = context =>
|
|
||||||
{
|
|
||||||
SearchWindow.Open(new SearchWindowContext(context.screenMousePosition), searchProvider);
|
|
||||||
};
|
|
||||||
|
|
||||||
foreach (var node in _graphObject.Nodes)
|
|
||||||
{
|
|
||||||
AddNodeView(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var noteData in _graphObject.StickyNotes)
|
|
||||||
{
|
|
||||||
AddStickyNoteView(noteData);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var connection in _graphObject.Connections)
|
|
||||||
{
|
|
||||||
AddConnectionView(connection);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private GraphViewChange OnGraphViewChanged(GraphViewChange graphViewChange)
|
|
||||||
{
|
|
||||||
if (graphViewChange.elementsToRemove != null)
|
|
||||||
{
|
|
||||||
var removedElements = graphViewChange.elementsToRemove;
|
|
||||||
Undo.RecordObject(_graphObject, "Remove elements");
|
|
||||||
|
|
||||||
for (var i = removedElements.Count - 1; i >= 0; i--)
|
|
||||||
{
|
|
||||||
if (removedElements[i] is Node { userData: ExecutableNode node })
|
|
||||||
{
|
|
||||||
RemoveNode(node);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (removedElements[i] is StickyNote {userData : StickyNoteData stickyNote})
|
|
||||||
{
|
|
||||||
RemoveStickyNote(stickyNote);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (removedElements[i] is Edge edge)
|
|
||||||
{
|
|
||||||
if (_slotConnections.Remove(edge, out var connection))
|
|
||||||
{
|
|
||||||
var inputNode = _graphObject.GetNode(connection.InputSlotData.nodeID);
|
|
||||||
var outputNode = _graphObject.GetNode(connection.OutputSlotData.nodeID);
|
|
||||||
|
|
||||||
if (inputNode is ISlotContainer inputSlotContainer && outputNode is ISlotContainer outputSlotContainer)
|
|
||||||
{
|
|
||||||
var inputSlot = inputSlotContainer.GetSlot(connection.InputSlotData.slotIndex, connection.InputSlotData.direction);
|
|
||||||
var outputSlot = outputSlotContainer.GetSlot(connection.OutputSlotData.slotIndex, connection.OutputSlotData.direction);
|
|
||||||
|
|
||||||
inputSlot.Unlink(outputSlot);
|
|
||||||
}
|
|
||||||
|
|
||||||
RemoveConnection(connection);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if (graphViewChange.movedElements != null)
|
|
||||||
// {
|
|
||||||
// var movedElements = graphViewChange.movedElements;
|
|
||||||
// Undo.RecordObject(_graphObject, $"Move {movedElements.FirstOrDefault()?.GetType().Name}");
|
|
||||||
//
|
|
||||||
// foreach (var element in graphViewChange.movedElements)
|
|
||||||
// {
|
|
||||||
// element.SetPosition(element.GetPosition());
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
if (graphViewChange.edgesToCreate != null)
|
|
||||||
{
|
|
||||||
var createdEdges = graphViewChange.edgesToCreate;
|
|
||||||
Undo.RecordObject(_graphObject, $"Connect {createdEdges.FirstOrDefault()?.GetType().Name}");
|
|
||||||
|
|
||||||
foreach (var edge in createdEdges)
|
|
||||||
if (edge.input.userData is Slot inputSlot && edge.output.userData is Slot outputSlot)
|
|
||||||
{
|
|
||||||
var connection = new SlotConnection(inputSlot.slotData, outputSlot.slotData);
|
|
||||||
_slotConnections.Add(edge, connection);
|
|
||||||
|
|
||||||
outputSlot.Link(inputSlot);
|
|
||||||
AddConnection(connection);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_graphObject.SetGraphTransform(viewTransform);
|
|
||||||
|
|
||||||
_graphViewConfig.serializedObject.Update();
|
|
||||||
EditorUtility.SetDirty(_graphObject);
|
|
||||||
|
|
||||||
return graphViewChange;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override List<Port> GetCompatiblePorts(Port startPort, NodeAdapter nodeAdapter)
|
|
||||||
{
|
|
||||||
var compatiblePorts = new List<Port>();
|
|
||||||
|
|
||||||
foreach (var port in ports)
|
|
||||||
{
|
|
||||||
if (startPort == port || startPort.node == port.node || startPort.direction == port.direction)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (startPort.portType != port.portType &&
|
|
||||||
_graphObject.ValueConverterManager != null &&
|
|
||||||
!_graphObject.ValueConverterManager.CanConvert(startPort.portType, port.portType))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
compatiblePorts.Add(port);
|
|
||||||
}
|
|
||||||
|
|
||||||
return compatiblePorts;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnDragPerform(DragPerformEvent evt)
|
|
||||||
{
|
|
||||||
var data = DragAndDrop.GetGenericData("DragSelection");
|
|
||||||
if (data is List<ISelectable> selectables)
|
|
||||||
{
|
|
||||||
var propertyViews = selectables.OfType<BlackboardPropertyView>().ToArray();
|
|
||||||
if (propertyViews.Length <= 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var position = (evt.currentTarget as VisualElement).ChangeCoordinatesTo(contentViewContainer, evt.localMousePosition);
|
|
||||||
foreach (var view in propertyViews)
|
|
||||||
{
|
|
||||||
if (view.userData is not ExposedProperty property)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var baseNode = new PropertyInput(property)
|
|
||||||
{
|
|
||||||
position = new Rect(position, Vector2.zero)
|
|
||||||
};
|
|
||||||
AddNode(baseNode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddNode(ExecutableNode executableNode)
|
|
||||||
{
|
|
||||||
Undo.RecordObject(_graphObject, $"Add {executableNode.GetType().Name}");
|
|
||||||
|
|
||||||
_graphObject.AddNode(executableNode);
|
|
||||||
AddNodeView(executableNode);
|
|
||||||
|
|
||||||
EditorUtility.SetDirty(_graphObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AddNodeView(DataNode node)
|
|
||||||
{
|
|
||||||
var nodeView = CreateNodeView(node);
|
|
||||||
if (nodeView == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
nodeView.SetPosition(node.position);
|
|
||||||
|
|
||||||
if (nodeView is IInspectable inspectable)
|
|
||||||
{
|
|
||||||
inspectable.OnItemSelected += ChangeInspectorView;
|
|
||||||
}
|
|
||||||
|
|
||||||
AddElement(nodeView);
|
|
||||||
_nodeViewsMap.Add(node.Id, nodeView);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual Node CreateNodeView(DataNode node)
|
|
||||||
{
|
|
||||||
var types = TypeCache.GetTypesWithAttribute<CustomInspectorAttribute>();
|
|
||||||
var type = types.FirstOrDefault(t =>
|
|
||||||
t.GetCustomAttribute<CustomInspectorAttribute>().InspectorType == node.GetType());
|
|
||||||
|
|
||||||
if (node is PropertyInput propertyInputNode)
|
|
||||||
{
|
|
||||||
return PropertyInputNodeView.Create(propertyInputNode, _graphViewConfig.portColorManager);
|
|
||||||
}
|
|
||||||
else if (node is ExecutableNode executableNode)
|
|
||||||
{
|
|
||||||
type ??= typeof(ExecutableNodeView);
|
|
||||||
return Activator.CreateInstance(type, executableNode, _graphViewConfig.serializedObject, _graphViewConfig.portColorManager, _graphObject.Logger) as ExecutableNodeView;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RemoveNode(ExecutableNode executableNode)
|
|
||||||
{
|
|
||||||
Undo.RecordObject(_graphObject, $"Remove {executableNode.GetType().Name}");
|
|
||||||
|
|
||||||
_graphObject.RemoveNode(executableNode);
|
|
||||||
RemoveNodeView(executableNode);
|
|
||||||
|
|
||||||
EditorUtility.SetDirty(_graphObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RemoveNodeView(ExecutableNode executableNode)
|
|
||||||
{
|
|
||||||
if (_nodeViewsMap.Remove(executableNode.Id, out var nodeView))
|
|
||||||
{
|
|
||||||
RemoveElement(nodeView);
|
|
||||||
|
|
||||||
if (nodeView is IInspectable inspectable)
|
|
||||||
{
|
|
||||||
inspectable.OnItemSelected -= ChangeInspectorView;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddStickyNote(StickyNoteData stickyNote)
|
|
||||||
{
|
|
||||||
Undo.RecordObject(_graphObject, $"Add {stickyNote.title}");
|
|
||||||
|
|
||||||
_graphObject.AddStickyNote(stickyNote);
|
|
||||||
|
|
||||||
AddStickyNoteView(stickyNote);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AddStickyNoteView(StickyNoteData stickyNote)
|
|
||||||
{
|
|
||||||
var stickyNoteView = new StickyNoteView(stickyNote);
|
|
||||||
stickyNoteView.SetPosition(stickyNote.position);
|
|
||||||
AddElement(stickyNoteView);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RemoveStickyNote(StickyNoteData stickyNote)
|
|
||||||
{
|
|
||||||
Undo.RecordObject(_graphObject, $"Remove {stickyNote.title}");
|
|
||||||
|
|
||||||
_graphObject.RemoveStickyNote(stickyNote);
|
|
||||||
|
|
||||||
RemoveStickyNoteView(stickyNote);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RemoveStickyNoteView(StickyNoteData stickyNote)
|
|
||||||
{
|
|
||||||
// var stickyNoteView = GetStickyNoteView(stickyNote);
|
|
||||||
// if (stickyNoteView != null)
|
|
||||||
// {
|
|
||||||
// RemoveElement(stickyNoteView);
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddConnection(SlotConnection connection)
|
|
||||||
{
|
|
||||||
Undo.RecordObject(_graphObject, $"Add {connection.GetType().Name}");
|
|
||||||
|
|
||||||
_graphObject.AddConnection(connection);
|
|
||||||
|
|
||||||
EditorUtility.SetDirty(_graphObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void RemoveConnection(SlotConnection connection)
|
|
||||||
{
|
|
||||||
Undo.RecordObject(_graphObject, $"Remove {connection.GetType().Name}");
|
|
||||||
|
|
||||||
_graphObject.RemoveConnection(connection);
|
|
||||||
|
|
||||||
EditorUtility.SetDirty(_graphObject);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void AddConnectionView(SlotConnection connection)
|
|
||||||
{
|
|
||||||
var inputSlotData = connection.InputSlotData;
|
|
||||||
var outputSlotData = connection.OutputSlotData;
|
|
||||||
|
|
||||||
if (!_nodeViewsMap.TryGetValue(inputSlotData.nodeID, out var inputNodeView) ||
|
|
||||||
!_nodeViewsMap.TryGetValue(outputSlotData.nodeID, out var outputNodeView))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inputNodeView is not IPortContainer inputPortContainer || outputNodeView is not IPortContainer outputPortContainer)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var inputPort = inputPortContainer.InputPorts[inputSlotData.slotIndex];
|
|
||||||
var outputPort = outputPortContainer.OutputPorts[outputSlotData.slotIndex];
|
|
||||||
|
|
||||||
var edge = inputPort.ConnectTo(outputPort);
|
|
||||||
AddElement(edge);
|
|
||||||
_slotConnections.Add(edge, connection);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ToggleBlackboardViewVisibility()
|
|
||||||
{
|
|
||||||
if (_blackboardView == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_blackboardView.style.visibility = _blackboardView.style.visibility == Visibility.Hidden
|
|
||||||
? Visibility.Visible
|
|
||||||
: Visibility.Hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ChangeInspectorView(IInspectable inspectable)
|
|
||||||
{
|
|
||||||
if (_graphInspectorView == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_graphInspectorView.OnNodeSelectionChanged(inspectable);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ToggleInspectorViewVisibility()
|
|
||||||
{
|
|
||||||
if (_graphInspectorView == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_graphInspectorView.style.visibility = _graphInspectorView.style.visibility == Visibility.Hidden
|
|
||||||
? Visibility.Visible
|
|
||||||
: Visibility.Hidden;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 66c6b56270850cc458f01ab2bbd9429e
|
|
||||||
8
Editor/Views/GraphView.meta
Normal file
8
Editor/Views/GraphView.meta
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: e691d14381aaee54fb5214d0fcc9cfd4
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
197
Editor/Views/GraphView/GraphView.cs
Normal file
197
Editor/Views/GraphView/GraphView.cs
Normal file
@@ -0,0 +1,197 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEditor.Experimental.GraphView;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.UIElements;
|
||||||
|
|
||||||
|
namespace Misaki.GraphView.Editor
|
||||||
|
{
|
||||||
|
public partial class GraphView : UnityEditor.Experimental.GraphView.GraphView
|
||||||
|
{
|
||||||
|
private readonly Dictionary<string, Node> _nodeViewsMap = new();
|
||||||
|
private readonly Dictionary<Edge, SlotConnection> _slotConnections = new();
|
||||||
|
|
||||||
|
private readonly GraphBlackboardView _blackboardView;
|
||||||
|
private readonly GraphInspectorView _graphInspectorView;
|
||||||
|
|
||||||
|
private readonly GraphViewConfig _graphViewConfig;
|
||||||
|
private GraphObject _graphObject => _graphViewConfig.graphObject;
|
||||||
|
|
||||||
|
public EditorWindow EditorWindow
|
||||||
|
{
|
||||||
|
get;
|
||||||
|
}
|
||||||
|
public GraphViewConfig GraphViewConfig => _graphViewConfig;
|
||||||
|
|
||||||
|
public GraphView(EditorWindow editorWindow, GraphViewConfig graphViewConfig)
|
||||||
|
{
|
||||||
|
EditorWindow = editorWindow;
|
||||||
|
_graphViewConfig = graphViewConfig;
|
||||||
|
|
||||||
|
var gridBackground = new GridBackground { name = "gridBackground" };
|
||||||
|
Add(gridBackground);
|
||||||
|
gridBackground.SendToBack();
|
||||||
|
|
||||||
|
var minimapConfig = _graphViewConfig.miniMapConfig;
|
||||||
|
if (minimapConfig is { enable: true })
|
||||||
|
{
|
||||||
|
var minimap = new MiniMap()
|
||||||
|
{
|
||||||
|
anchored = true
|
||||||
|
};
|
||||||
|
minimap.SetPosition(minimapConfig.position);
|
||||||
|
Add(minimap);
|
||||||
|
}
|
||||||
|
|
||||||
|
_blackboardView = new GraphBlackboardView(_graphObject, this, _graphViewConfig.serializedObject, _graphViewConfig.exposedPropertyTypeManager);
|
||||||
|
_blackboardView.OnPropertySelected += ChangeInspectorView;
|
||||||
|
|
||||||
|
foreach (var property in _graphObject.ExposedProperties)
|
||||||
|
{
|
||||||
|
_blackboardView.AddProperty(property);
|
||||||
|
}
|
||||||
|
|
||||||
|
_graphInspectorView = new GraphInspectorView();
|
||||||
|
|
||||||
|
Add(_blackboardView);
|
||||||
|
Add(_graphInspectorView);
|
||||||
|
|
||||||
|
this.StretchToParentSize();
|
||||||
|
|
||||||
|
this.AddManipulator(new ContentDragger());
|
||||||
|
this.AddManipulator(new SelectionDragger());
|
||||||
|
this.AddManipulator(new RectangleSelector());
|
||||||
|
this.AddManipulator(new ClickSelector());
|
||||||
|
|
||||||
|
var zoomConfig = _graphViewConfig.zoomConfig;
|
||||||
|
var zoomer = new ContentZoomer();
|
||||||
|
if (zoomConfig != null)
|
||||||
|
{
|
||||||
|
zoomer.minScale = zoomConfig.minScale;
|
||||||
|
zoomer.maxScale = zoomConfig.maxScale;
|
||||||
|
zoomer.scaleStep = zoomConfig.scaleStep;
|
||||||
|
}
|
||||||
|
this.AddManipulator(zoomer);
|
||||||
|
|
||||||
|
InitializeAssetElements();
|
||||||
|
|
||||||
|
graphViewChanged += OnGraphViewChanged;
|
||||||
|
|
||||||
|
RegisterCallback<DragPerformEvent>(OnDragPerform);
|
||||||
|
RegisterCallbackOnce<GeometryChangedEvent>(_ => _graphInspectorView?.DockToParent(layout, DockingPosition.Right, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitializeAssetElements()
|
||||||
|
{
|
||||||
|
var searchProvider = ScriptableObject.CreateInstance<NodeSearchProvider>();
|
||||||
|
searchProvider.SetOwner(this);
|
||||||
|
|
||||||
|
nodeCreationRequest = context =>
|
||||||
|
{
|
||||||
|
SearchWindow.Open(new SearchWindowContext(context.screenMousePosition), searchProvider);
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (var node in _graphObject.Nodes)
|
||||||
|
{
|
||||||
|
AddNodeView(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var noteData in _graphObject.StickyNotes)
|
||||||
|
{
|
||||||
|
AddStickyNoteView(noteData);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var connection in _graphObject.Connections)
|
||||||
|
{
|
||||||
|
AddConnectionView(connection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override List<Port> GetCompatiblePorts(Port startPort, NodeAdapter nodeAdapter)
|
||||||
|
{
|
||||||
|
var compatiblePorts = new List<Port>();
|
||||||
|
|
||||||
|
foreach (var port in ports)
|
||||||
|
{
|
||||||
|
if (startPort == port || startPort.node == port.node || startPort.direction == port.direction)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (startPort.portType != port.portType &&
|
||||||
|
_graphObject.ValueConverterManager != null &&
|
||||||
|
!_graphObject.ValueConverterManager.CanConvert(startPort.portType, port.portType))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
compatiblePorts.Add(port);
|
||||||
|
}
|
||||||
|
|
||||||
|
return compatiblePorts;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnDragPerform(DragPerformEvent evt)
|
||||||
|
{
|
||||||
|
var data = DragAndDrop.GetGenericData("DragSelection");
|
||||||
|
if (data is List<ISelectable> selectables)
|
||||||
|
{
|
||||||
|
var propertyViews = selectables.OfType<BlackboardPropertyView>().ToArray();
|
||||||
|
if (propertyViews.Length <= 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var position = (evt.currentTarget as VisualElement).ChangeCoordinatesTo(contentViewContainer, evt.localMousePosition);
|
||||||
|
foreach (var view in propertyViews)
|
||||||
|
{
|
||||||
|
if (view.userData is not ExposedProperty property)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var baseNode = new PropertyInput(property)
|
||||||
|
{
|
||||||
|
position = new Rect(position, Vector2.zero)
|
||||||
|
};
|
||||||
|
AddNode(baseNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ToggleBlackboardViewVisibility()
|
||||||
|
{
|
||||||
|
if (_blackboardView == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_blackboardView.style.visibility = _blackboardView.style.visibility == Visibility.Hidden
|
||||||
|
? Visibility.Visible
|
||||||
|
: Visibility.Hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ChangeInspectorView(IInspectable inspectable)
|
||||||
|
{
|
||||||
|
if (_graphInspectorView == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_graphInspectorView.OnNodeSelectionChanged(inspectable);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ToggleInspectorViewVisibility()
|
||||||
|
{
|
||||||
|
if (_graphInspectorView == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_graphInspectorView.style.visibility = _graphInspectorView.style.visibility == Visibility.Hidden
|
||||||
|
? Visibility.Visible
|
||||||
|
: Visibility.Hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
2
Editor/Views/GraphView/GraphView.cs.meta
Normal file
2
Editor/Views/GraphView/GraphView.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 85dea80825e410d4093cc4d10f33931b
|
||||||
45
Editor/Views/GraphView/GraphView_ContextualMenu.cs
Normal file
45
Editor/Views/GraphView/GraphView_ContextualMenu.cs
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
using UnityEditor.Experimental.GraphView;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.UIElements;
|
||||||
|
|
||||||
|
namespace Misaki.GraphView.Editor
|
||||||
|
{
|
||||||
|
public partial class GraphView
|
||||||
|
{
|
||||||
|
public override void BuildContextualMenu(ContextualMenuPopulateEvent evt)
|
||||||
|
{
|
||||||
|
base.BuildContextualMenu(evt);
|
||||||
|
var mousePosition = (evt.currentTarget as VisualElement).ChangeCoordinatesTo(contentViewContainer, evt.localMousePosition);
|
||||||
|
|
||||||
|
if (evt.target is GraphView)
|
||||||
|
{
|
||||||
|
evt.menu.InsertAction(1, "Create Sticky Note", e =>
|
||||||
|
{
|
||||||
|
var stickyNote = new StickyNoteData
|
||||||
|
{
|
||||||
|
title = "Sticky Note",
|
||||||
|
contents = "Contents",
|
||||||
|
theme = StickyNoteTheme.Classic,
|
||||||
|
fontSize = StickyNoteFontSize.Medium,
|
||||||
|
position = new Rect(mousePosition, new Vector2(200, 200))
|
||||||
|
};
|
||||||
|
|
||||||
|
AddStickyNote(stickyNote);
|
||||||
|
}, DropdownMenuAction.AlwaysEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (evt.target is Edge)
|
||||||
|
{
|
||||||
|
evt.menu.AppendAction("Create Relay Node", e =>
|
||||||
|
{
|
||||||
|
var relayNode = new RelayNode
|
||||||
|
{
|
||||||
|
position = new Rect(mousePosition, Vector2.zero)
|
||||||
|
};
|
||||||
|
|
||||||
|
AddRelayNode(relayNode);
|
||||||
|
}, DropdownMenuAction.AlwaysEnabled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
2
Editor/Views/GraphView/GraphView_ContextualMenu.cs.meta
Normal file
2
Editor/Views/GraphView/GraphView_ContextualMenu.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: d8daa8d0ebadc4a40872f6613533e4bd
|
||||||
84
Editor/Views/GraphView/GraphView_GraphChanged.cs
Normal file
84
Editor/Views/GraphView/GraphView_GraphChanged.cs
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEditor.Experimental.GraphView;
|
||||||
|
|
||||||
|
namespace Misaki.GraphView.Editor
|
||||||
|
{
|
||||||
|
public partial class GraphView
|
||||||
|
{
|
||||||
|
private GraphViewChange OnGraphViewChanged(GraphViewChange graphViewChange)
|
||||||
|
{
|
||||||
|
if (graphViewChange.elementsToRemove != null)
|
||||||
|
{
|
||||||
|
var removedElements = graphViewChange.elementsToRemove;
|
||||||
|
Undo.RecordObject(_graphObject, "Remove elements");
|
||||||
|
|
||||||
|
for (var i = removedElements.Count - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
if (removedElements[i] is Node { userData: DataNode node })
|
||||||
|
{
|
||||||
|
RemoveNode(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (removedElements[i] is StickyNote { userData: StickyNoteData stickyNote })
|
||||||
|
{
|
||||||
|
RemoveStickyNote(stickyNote);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (removedElements[i] is Edge edge)
|
||||||
|
{
|
||||||
|
if (_slotConnections.Remove(edge, out var connection))
|
||||||
|
{
|
||||||
|
var inputNode = _graphObject.GetNode(connection.InputSlotData.nodeID);
|
||||||
|
var outputNode = _graphObject.GetNode(connection.OutputSlotData.nodeID);
|
||||||
|
|
||||||
|
if (inputNode is ISlotContainer inputSlotContainer && outputNode is ISlotContainer outputSlotContainer)
|
||||||
|
{
|
||||||
|
var inputSlot = inputSlotContainer.GetSlot(connection.InputSlotData.slotIndex, connection.InputSlotData.direction);
|
||||||
|
var outputSlot = outputSlotContainer.GetSlot(connection.OutputSlotData.slotIndex, connection.OutputSlotData.direction);
|
||||||
|
|
||||||
|
inputSlot.Unlink(outputSlot);
|
||||||
|
}
|
||||||
|
|
||||||
|
RemoveConnection(connection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (graphViewChange.movedElements != null)
|
||||||
|
// {
|
||||||
|
// var movedElements = graphViewChange.movedElements;
|
||||||
|
// Undo.RecordObject(_graphObject, $"Move {movedElements.FirstOrDefault()?.GetType().Name}");
|
||||||
|
//
|
||||||
|
// foreach (var element in graphViewChange.movedElements)
|
||||||
|
// {
|
||||||
|
// element.SetPosition(element.GetPosition());
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
if (graphViewChange.edgesToCreate != null)
|
||||||
|
{
|
||||||
|
var createdEdges = graphViewChange.edgesToCreate;
|
||||||
|
Undo.RecordObject(_graphObject, $"Connect {createdEdges.FirstOrDefault()?.GetType().Name}");
|
||||||
|
|
||||||
|
foreach (var edge in createdEdges)
|
||||||
|
if (edge.input.userData is Slot inputSlot && edge.output.userData is Slot outputSlot)
|
||||||
|
{
|
||||||
|
var connection = new SlotConnection(inputSlot.slotData, outputSlot.slotData);
|
||||||
|
_slotConnections.Add(edge, connection);
|
||||||
|
|
||||||
|
outputSlot.Link(inputSlot);
|
||||||
|
AddConnection(connection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_graphObject.SetGraphTransform(viewTransform);
|
||||||
|
|
||||||
|
_graphViewConfig.serializedObject.Update();
|
||||||
|
EditorUtility.SetDirty(_graphObject);
|
||||||
|
|
||||||
|
return graphViewChange;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
2
Editor/Views/GraphView/GraphView_GraphChanged.cs.meta
Normal file
2
Editor/Views/GraphView/GraphView_GraphChanged.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: c31e6279987ed0f449f1b23a385eb4be
|
||||||
176
Editor/Views/GraphView/GraphView_GraphElement.cs
Normal file
176
Editor/Views/GraphView/GraphView_GraphElement.cs
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEditor.Experimental.GraphView;
|
||||||
|
|
||||||
|
namespace Misaki.GraphView.Editor
|
||||||
|
{
|
||||||
|
public partial class GraphView
|
||||||
|
{
|
||||||
|
public void AddNode(ExecutableNode executableNode)
|
||||||
|
{
|
||||||
|
Undo.RecordObject(_graphObject, $"Add {executableNode.GetType().Name}");
|
||||||
|
|
||||||
|
_graphObject.AddNode(executableNode);
|
||||||
|
AddNodeView(executableNode);
|
||||||
|
|
||||||
|
EditorUtility.SetDirty(_graphObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddNodeView(DataNode node)
|
||||||
|
{
|
||||||
|
var nodeView = CreateNodeView(node);
|
||||||
|
if (nodeView == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
nodeView.SetPosition(node.position);
|
||||||
|
|
||||||
|
if (nodeView is IInspectable inspectable)
|
||||||
|
{
|
||||||
|
inspectable.OnItemSelected += ChangeInspectorView;
|
||||||
|
}
|
||||||
|
|
||||||
|
AddElement(nodeView);
|
||||||
|
_nodeViewsMap.Add(node.Id, nodeView);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual Node CreateNodeView(DataNode node)
|
||||||
|
{
|
||||||
|
var types = TypeCache.GetTypesWithAttribute<CustomInspectorAttribute>();
|
||||||
|
var type = types.FirstOrDefault(t =>
|
||||||
|
t.GetCustomAttribute<CustomInspectorAttribute>().InspectorType == node.GetType());
|
||||||
|
|
||||||
|
if (node is PropertyInput propertyInputNode)
|
||||||
|
{
|
||||||
|
return PropertyInputNodeView.Create(propertyInputNode, _graphViewConfig.portColorManager);
|
||||||
|
}
|
||||||
|
else if (node is ExecutableNode executableNode)
|
||||||
|
{
|
||||||
|
type ??= typeof(ExecutableNodeView);
|
||||||
|
return Activator.CreateInstance(type, executableNode, _graphViewConfig.serializedObject, _graphViewConfig.portColorManager, _graphObject.Logger) as ExecutableNodeView;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RemoveNode(DataNode dataNode)
|
||||||
|
{
|
||||||
|
Undo.RecordObject(_graphObject, $"Remove {dataNode.GetType().Name}");
|
||||||
|
|
||||||
|
_graphObject.RemoveNode(dataNode);
|
||||||
|
RemoveNodeView(dataNode);
|
||||||
|
|
||||||
|
EditorUtility.SetDirty(_graphObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RemoveNodeView(DataNode dataNode)
|
||||||
|
{
|
||||||
|
if (_nodeViewsMap.Remove(dataNode.Id, out var nodeView))
|
||||||
|
{
|
||||||
|
RemoveElement(nodeView);
|
||||||
|
|
||||||
|
if (nodeView is IInspectable inspectable)
|
||||||
|
{
|
||||||
|
inspectable.OnItemSelected -= ChangeInspectorView;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddStickyNote(StickyNoteData stickyNote)
|
||||||
|
{
|
||||||
|
Undo.RecordObject(_graphObject, $"Add {stickyNote.title}");
|
||||||
|
|
||||||
|
_graphObject.AddStickyNote(stickyNote);
|
||||||
|
AddStickyNoteView(stickyNote);
|
||||||
|
|
||||||
|
EditorUtility.SetDirty(_graphObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddStickyNoteView(StickyNoteData stickyNote)
|
||||||
|
{
|
||||||
|
var stickyNoteView = new StickyNoteView(stickyNote);
|
||||||
|
stickyNoteView.SetPosition(stickyNote.position);
|
||||||
|
AddElement(stickyNoteView);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveStickyNote(StickyNoteData stickyNote)
|
||||||
|
{
|
||||||
|
Undo.RecordObject(_graphObject, $"Remove {stickyNote.title}");
|
||||||
|
|
||||||
|
_graphObject.RemoveStickyNote(stickyNote);
|
||||||
|
|
||||||
|
RemoveStickyNoteView(stickyNote);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RemoveStickyNoteView(StickyNoteData stickyNote)
|
||||||
|
{
|
||||||
|
// var stickyNoteView = GetStickyNoteView(stickyNote);
|
||||||
|
// if (stickyNoteView != null)
|
||||||
|
// {
|
||||||
|
// RemoveElement(stickyNoteView);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddConnection(SlotConnection connection)
|
||||||
|
{
|
||||||
|
Undo.RecordObject(_graphObject, $"Add {connection.GetType().Name}");
|
||||||
|
|
||||||
|
_graphObject.AddConnection(connection);
|
||||||
|
|
||||||
|
EditorUtility.SetDirty(_graphObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RemoveConnection(SlotConnection connection)
|
||||||
|
{
|
||||||
|
Undo.RecordObject(_graphObject, $"Remove {connection.GetType().Name}");
|
||||||
|
|
||||||
|
_graphObject.RemoveConnection(connection);
|
||||||
|
|
||||||
|
EditorUtility.SetDirty(_graphObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddConnectionView(SlotConnection connection)
|
||||||
|
{
|
||||||
|
var inputSlotData = connection.InputSlotData;
|
||||||
|
var outputSlotData = connection.OutputSlotData;
|
||||||
|
|
||||||
|
if (!_nodeViewsMap.TryGetValue(inputSlotData.nodeID, out var inputNodeView) ||
|
||||||
|
!_nodeViewsMap.TryGetValue(outputSlotData.nodeID, out var outputNodeView))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inputNodeView is not IPortContainer inputPortContainer || outputNodeView is not IPortContainer outputPortContainer)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var inputPort = inputPortContainer.GetPort(inputSlotData.slotIndex, Direction.Input);
|
||||||
|
var outputPort = outputPortContainer.GetPort(outputSlotData.slotIndex, Direction.Output);
|
||||||
|
|
||||||
|
var edge = inputPort.ConnectTo(outputPort);
|
||||||
|
AddElement(edge);
|
||||||
|
_slotConnections.Add(edge, connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddRelayNode(RelayNode relayNode)
|
||||||
|
{
|
||||||
|
Undo.RecordObject(_graphObject, $"Add {relayNode.GetType().Name}");
|
||||||
|
|
||||||
|
_graphObject.AddNode(relayNode);
|
||||||
|
AddRelayNodeView(relayNode);
|
||||||
|
|
||||||
|
EditorUtility.SetDirty(_graphObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AddRelayNodeView(RelayNode relayNode)
|
||||||
|
{
|
||||||
|
var relayNodeView = new RelayNodeView(relayNode, _graphViewConfig.portColorManager);
|
||||||
|
relayNodeView.SetPosition(relayNode.position);
|
||||||
|
AddElement(relayNodeView);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
2
Editor/Views/GraphView/GraphView_GraphElement.cs.meta
Normal file
2
Editor/Views/GraphView/GraphView_GraphElement.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: d01a10830ebed08498c09668ee5d0c74
|
||||||
@@ -16,18 +16,18 @@ namespace Misaki.GraphView.Editor
|
|||||||
private readonly Type _nodeType;
|
private readonly Type _nodeType;
|
||||||
private readonly NodeInfoAttribute _nodeInfo;
|
private readonly NodeInfoAttribute _nodeInfo;
|
||||||
|
|
||||||
private readonly List<Port> _inputPorts = new ();
|
private readonly List<Port> _inputPorts = new();
|
||||||
private readonly List<Port> _outputPorts = new ();
|
private readonly List<Port> _outputPorts = new();
|
||||||
|
|
||||||
private readonly IPortColorManager _portColorManager;
|
private readonly IPortColorManager _portColorManager;
|
||||||
private readonly SerializedObject _serializedObject;
|
private readonly SerializedObject _serializedObject;
|
||||||
|
|
||||||
private readonly VisualElement _logContainer = new();
|
private readonly VisualElement _logContainer = new();
|
||||||
|
|
||||||
public List<Port> InputPorts => _inputPorts;
|
public Action<IInspectable> OnItemSelected
|
||||||
public List<Port> OutputPorts => _outputPorts;
|
{
|
||||||
|
get; set;
|
||||||
public Action<IInspectable> OnItemSelected { get; set; }
|
}
|
||||||
|
|
||||||
public string InspectorName => _nodeInfo.Name ?? _nodeType.Name;
|
public string InspectorName => _nodeInfo.Name ?? _nodeType.Name;
|
||||||
|
|
||||||
@@ -107,7 +107,7 @@ namespace Misaki.GraphView.Editor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CreateLogElement(ExecutableNode node, string message, LogType type)
|
private void CreateLogElement(DataNode node, string message, LogType type)
|
||||||
{
|
{
|
||||||
if (node.Id != _dataNode.Id)
|
if (node.Id != _dataNode.Id)
|
||||||
{
|
{
|
||||||
@@ -212,6 +212,16 @@ namespace Misaki.GraphView.Editor
|
|||||||
OnItemSelected?.Invoke(null);
|
OnItemSelected?.Invoke(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Port GetPort(int index, Direction direction)
|
||||||
|
{
|
||||||
|
return direction switch
|
||||||
|
{
|
||||||
|
Direction.Input => _inputPorts[index],
|
||||||
|
Direction.Output => _outputPorts[index],
|
||||||
|
_ => null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Displays the inspector for the node.
|
/// Displays the inspector for the node.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -1,7 +1,4 @@
|
|||||||
using System;
|
using UnityEditor.Experimental.GraphView;
|
||||||
using System.Collections.Generic;
|
|
||||||
using NUnit.Framework;
|
|
||||||
using UnityEditor.Experimental.GraphView;
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.UIElements;
|
using UnityEngine.UIElements;
|
||||||
|
|
||||||
@@ -9,28 +6,23 @@ namespace Misaki.GraphView.Editor
|
|||||||
{
|
{
|
||||||
public class PropertyInputNodeView : TokenNode, IPortContainer
|
public class PropertyInputNodeView : TokenNode, IPortContainer
|
||||||
{
|
{
|
||||||
private readonly List<Port> _outputPorts = new List<Port>();
|
private readonly Port _outputPort;
|
||||||
|
|
||||||
private readonly PropertyInput _data;
|
private readonly PropertyInput _data;
|
||||||
//private readonly ExposedPropertyEditor _editor;
|
//private readonly ExposedPropertyEditor _editor;
|
||||||
|
|
||||||
public PropertyInput Data => _data;
|
public PropertyInput Data => _data;
|
||||||
|
|
||||||
public List<Port> InputPorts => null;
|
|
||||||
public List<Port> OutputPorts => _outputPorts;
|
|
||||||
|
|
||||||
public PropertyInputNodeView(PropertyInput data, Port output) : base(null, output)
|
public PropertyInputNodeView(PropertyInput data, Port output) : base(null, output)
|
||||||
{
|
{
|
||||||
_data = data;
|
_data = data;
|
||||||
//_editor = editor;
|
_outputPort = output;
|
||||||
|
|
||||||
name = data.Property.propertyName;
|
name = data.Property.propertyName;
|
||||||
title = data.Property.propertyName;
|
title = data.Property.propertyName;
|
||||||
userData = data;
|
userData = data;
|
||||||
|
|
||||||
this.Q<VisualElement>("top").style.minHeight = 24;
|
this.Q<VisualElement>("top").style.minHeight = 24;
|
||||||
|
|
||||||
_outputPorts.Add(output);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PropertyInputNodeView Create(PropertyInput data, IPortColorManager portColorManager)
|
public static PropertyInputNodeView Create(PropertyInput data, IPortColorManager portColorManager)
|
||||||
@@ -75,5 +67,10 @@ namespace Misaki.GraphView.Editor
|
|||||||
base.SetPosition(newPos);
|
base.SetPosition(newPos);
|
||||||
_data.position = newPos;
|
_data.position = newPos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Port GetPort(int index, Direction direction)
|
||||||
|
{
|
||||||
|
return _outputPort;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
51
Editor/Views/Nodes/RelayNodeView.cs
Normal file
51
Editor/Views/Nodes/RelayNodeView.cs
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
using System;
|
||||||
|
using UnityEditor.Experimental.GraphView;
|
||||||
|
|
||||||
|
namespace Misaki.GraphView.Editor
|
||||||
|
{
|
||||||
|
public class RelayNodeView : Node, IPortContainer
|
||||||
|
{
|
||||||
|
private RelayNode _dataNode;
|
||||||
|
private IPortColorManager _portColorManager;
|
||||||
|
|
||||||
|
private readonly Port _inputPort;
|
||||||
|
private readonly Port _outputPort;
|
||||||
|
|
||||||
|
public RelayNodeView(RelayNode dataNode, IPortColorManager portColorManager)
|
||||||
|
{
|
||||||
|
_dataNode = dataNode;
|
||||||
|
_portColorManager = portColorManager;
|
||||||
|
|
||||||
|
_inputPort = Port.Create<Edge>(Orientation.Horizontal, Direction.Input, Port.Capacity.Single, typeof(object));
|
||||||
|
_outputPort = Port.Create<Edge>(Orientation.Horizontal, Direction.Output, Port.Capacity.Multi, typeof(object));
|
||||||
|
|
||||||
|
_inputPort.portName = string.Empty;
|
||||||
|
_outputPort.portName = string.Empty;
|
||||||
|
|
||||||
|
SetPortsTypeAndColor(typeof(object));
|
||||||
|
|
||||||
|
inputContainer.Add(_inputPort);
|
||||||
|
outputContainer.Add(_outputPort);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetPortsTypeAndColor(Type portType)
|
||||||
|
{
|
||||||
|
_inputPort.portType = portType;
|
||||||
|
_outputPort.portType = portType;
|
||||||
|
|
||||||
|
if (_portColorManager != null)
|
||||||
|
{
|
||||||
|
if (_portColorManager.TryGetColor(portType, out var portColor))
|
||||||
|
{
|
||||||
|
_inputPort.portColor = portColor;
|
||||||
|
_outputPort.portColor = portColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Port GetPort(int index, Direction direction)
|
||||||
|
{
|
||||||
|
return direction == Direction.Input ? _inputPort : _outputPort;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
2
Editor/Views/Nodes/RelayNodeView.cs.meta
Normal file
2
Editor/Views/Nodes/RelayNodeView.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: ba1646416a4d47148947945befe2b938
|
||||||
@@ -1,15 +1,17 @@
|
|||||||
using System;
|
using System;
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace Misaki.GraphView
|
namespace Misaki.GraphView
|
||||||
{
|
{
|
||||||
public interface ILogger
|
public interface ILogger
|
||||||
{
|
{
|
||||||
public Action<ExecutableNode, string, LogType> OnLog { get; set; }
|
public Action<DataNode, string, LogType> OnLog
|
||||||
|
{
|
||||||
|
get; set;
|
||||||
|
}
|
||||||
|
|
||||||
public void LogInfo(ExecutableNode node, string message);
|
public void LogInfo(DataNode node, string message);
|
||||||
public void LogWarning(ExecutableNode node, string message);
|
public void LogWarning(DataNode node, string message);
|
||||||
public void LogError(ExecutableNode node, string message);
|
public void LogError(DataNode node, string message);
|
||||||
|
|
||||||
public void ClearLogs();
|
public void ClearLogs();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Misaki.GraphView
|
namespace Misaki.GraphView
|
||||||
{
|
{
|
||||||
@@ -7,6 +8,7 @@ namespace Misaki.GraphView
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Unlink all slots from this slot.
|
/// Unlink all slots from this slot.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="slot">The slot to unlink all connections from.</param>
|
||||||
public static void UnlinkAll(this Slot slot)
|
public static void UnlinkAll(this Slot slot)
|
||||||
{
|
{
|
||||||
var slotCount = slot.LinkedSlotData.Count;
|
var slotCount = slot.LinkedSlotData.Count;
|
||||||
@@ -25,10 +27,108 @@ namespace Misaki.GraphView
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get the value type of the slot data.
|
/// Get the value type of the slot data.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns><see cref="Type"/> The type of the slot value </returns>
|
/// <param name="slotData">The slot data to get the value type from.</param>
|
||||||
|
/// <returns><see cref="Type"/> The type of the slot value.</returns>
|
||||||
public static Type GetValueType(this SlotData slotData)
|
public static Type GetValueType(this SlotData slotData)
|
||||||
{
|
{
|
||||||
return Type.GetType(slotData.valueType);
|
return Type.GetType(slotData.valueType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void ReceiveData(this Slot slot, object data)
|
||||||
|
{
|
||||||
|
slot.value = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Pull data from the slot and execute the provided action.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="slot">The slot to pull data from.</param>
|
||||||
|
/// <param name="OnPullData">The action to execute when pulling data.</param>
|
||||||
|
public static void PullData(this Slot slot, Action<Slot> OnPullData)
|
||||||
|
{
|
||||||
|
var property = slot.owner.GetType().GetField(slot.slotData.slotName, ConstResource.NODE_FIELD_BINDING_FLAGS);
|
||||||
|
if (property == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
OnPullData(slot);
|
||||||
|
|
||||||
|
if (slot.LinkedSlotData.Count == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
property.SetValue(slot.owner, slot.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Push data to the slot and execute the provided action.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="slot">The slot to push data to.</param>
|
||||||
|
/// <param name="OnPushData">The action to execute when pushing data.</param>
|
||||||
|
public static void PushData(this Slot slot, Action<Slot> OnPushData)
|
||||||
|
{
|
||||||
|
var property = slot.owner.GetType().GetField(slot.slotData.slotName, ConstResource.NODE_FIELD_BINDING_FLAGS);
|
||||||
|
if (property == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
OnPushData(slot);
|
||||||
|
|
||||||
|
slot.value = property.GetValue(slot.owner);
|
||||||
|
|
||||||
|
foreach (var slotData in slot.LinkedSlotData)
|
||||||
|
{
|
||||||
|
var node = slot.owner.GraphObject.GetNode(slotData.nodeID);
|
||||||
|
if (node is not ISlotContainer slotContainer)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var otherSlot = slotContainer.GetSlot(slotData.slotIndex, slotData.direction);
|
||||||
|
|
||||||
|
if (slotData.GetValueType() == slot.slotData.GetValueType() || slot.slotData.GetValueType() == typeof(object))
|
||||||
|
{
|
||||||
|
otherSlot.ReceiveData(slot.value);
|
||||||
|
}
|
||||||
|
else if (slot.owner.GraphObject.ValueConverterManager != null && slot.owner.GraphObject.ValueConverterManager.TryConvert(slot.slotData.GetValueType(),
|
||||||
|
slotData.GetValueType(), slot.value, out var data))
|
||||||
|
{
|
||||||
|
otherSlot.ReceiveData(data);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
slot.owner.GraphObject.Logger?.LogError(slot.owner, $"Failed to convert value from {otherSlot.slotData.valueType} to {slotData.valueType}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Pull data from a collection of slots and execute the provided action.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="slots">The collection of slots to pull data from.</param>
|
||||||
|
/// <param name="OnPullData">The action to execute when pulling data.</param>
|
||||||
|
public static void PullData(this IEnumerable<Slot> slots, Action<Slot> OnPullData)
|
||||||
|
{
|
||||||
|
foreach (var slot in slots)
|
||||||
|
{
|
||||||
|
slot.PullData(OnPullData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Push data to a collection of slots and execute the provided action.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="slots">The collection of slots to push data to.</param>
|
||||||
|
/// <param name="OnPushData">The action to execute when pushing data.</param>
|
||||||
|
public static void PushData(this IEnumerable<Slot> slots, Action<Slot> OnPushData)
|
||||||
|
{
|
||||||
|
foreach (var slot in slots)
|
||||||
|
{
|
||||||
|
slot.PushData(OnPushData);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -10,16 +10,16 @@ namespace Misaki.GraphView
|
|||||||
public abstract class ExecutableNode : DataNode, ISlotContainer, IExecutable
|
public abstract class ExecutableNode : DataNode, ISlotContainer, IExecutable
|
||||||
{
|
{
|
||||||
[SerializeField]
|
[SerializeField]
|
||||||
private List<Slot> _inputs = new ();
|
private List<Slot> _inputs = new();
|
||||||
[SerializeField]
|
[SerializeField]
|
||||||
private List<Slot> _outputs = new ();
|
private List<Slot> _outputs = new();
|
||||||
|
|
||||||
public ReadOnlyCollection<Slot> Inputs => _inputs.AsReadOnly();
|
public ReadOnlyCollection<Slot> Inputs => _inputs.AsReadOnly();
|
||||||
public ReadOnlyCollection<Slot> Outputs => _outputs.AsReadOnly();
|
public ReadOnlyCollection<Slot> Outputs => _outputs.AsReadOnly();
|
||||||
|
|
||||||
private bool _isExecuted;
|
private bool _isExecuted;
|
||||||
|
|
||||||
public Action OnExecutoinStarted;
|
public Action OnExecutionStarted;
|
||||||
public Action OnExecutionCompleted;
|
public Action OnExecutionCompleted;
|
||||||
public Action OnExecutionFailed;
|
public Action OnExecutionFailed;
|
||||||
public Action OnExecuteFlagCleared;
|
public Action OnExecuteFlagCleared;
|
||||||
@@ -135,9 +135,8 @@ namespace Misaki.GraphView
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
OnExecutoinStarted?.Invoke();
|
OnExecutionStarted?.Invoke();
|
||||||
|
Inputs.PullData(OnPullData);
|
||||||
PullData();
|
|
||||||
|
|
||||||
if (!graphObject.GraphProcessor.IsRunning)
|
if (!graphObject.GraphProcessor.IsRunning)
|
||||||
{
|
{
|
||||||
@@ -151,7 +150,7 @@ namespace Misaki.GraphView
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
PushData();
|
Outputs.PushData(OnPushData);
|
||||||
|
|
||||||
_isExecuted = true;
|
_isExecuted = true;
|
||||||
OnExecutionCompleted?.Invoke();
|
OnExecutionCompleted?.Invoke();
|
||||||
@@ -164,66 +163,10 @@ namespace Misaki.GraphView
|
|||||||
OnExecuteFlagCleared?.Invoke();
|
OnExecuteFlagCleared?.Invoke();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PullData()
|
|
||||||
{
|
|
||||||
foreach (var input in Inputs)
|
|
||||||
{
|
|
||||||
var property = GetType().GetField(input.slotData.slotName, ConstResource.NODE_FIELD_BINDING_FLAGS);
|
|
||||||
if (property == null)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
OnPullData(input);
|
|
||||||
|
|
||||||
if (input.LinkedSlotData.Count == 0)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
property.SetValue(this, input.value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual void OnPullData(Slot input)
|
protected virtual void OnPullData(Slot input)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PushData()
|
|
||||||
{
|
|
||||||
foreach (var output in Outputs)
|
|
||||||
{
|
|
||||||
var property = GetType().GetField(output.slotData.slotName, ConstResource.NODE_FIELD_BINDING_FLAGS);
|
|
||||||
if (property == null)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
OnPushData(output);
|
|
||||||
|
|
||||||
output.value = property.GetValue(this);
|
|
||||||
foreach (var slotData in output.LinkedSlotData)
|
|
||||||
{
|
|
||||||
var node = graphObject.GetNode(slotData.nodeID);
|
|
||||||
if (node is not ISlotContainer slotContainer)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var slot = slotContainer.GetSlot(slotData.slotIndex, SlotDirection.Input);
|
|
||||||
if (slotData.valueType == output.slotData.valueType || output.slotData.valueType == typeof(object).FullName)
|
|
||||||
{
|
|
||||||
slot.ReceiveData(output.value);
|
|
||||||
}
|
|
||||||
else if (graphObject.ValueConverterManager != null && graphObject.ValueConverterManager.TryConvert(output.slotData.GetValueType(),
|
|
||||||
slotData.GetValueType(), output.value, out var data))
|
|
||||||
{
|
|
||||||
slot.ReceiveData(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual void OnPushData(Slot output)
|
protected virtual void OnPushData(Slot output)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,78 @@
|
|||||||
using UnityEngine;
|
using System;
|
||||||
|
|
||||||
namespace Misaki.GraphView
|
namespace Misaki.GraphView
|
||||||
{
|
{
|
||||||
public class RelayNode
|
[Serializable]
|
||||||
|
public class RelayNode : DataNode, ISlotContainer, IExecutable
|
||||||
{
|
{
|
||||||
|
private Slot _inputSlot;
|
||||||
|
private Slot _outputSlot;
|
||||||
|
|
||||||
|
private bool _isExecuted;
|
||||||
|
|
||||||
|
public override void Initialize(GraphObject graph)
|
||||||
|
{
|
||||||
|
graphObject = graph;
|
||||||
|
|
||||||
|
_inputSlot = new(this, new()
|
||||||
|
{
|
||||||
|
slotName = "Input",
|
||||||
|
nodeID = Id,
|
||||||
|
slotIndex = 0,
|
||||||
|
direction = SlotDirection.Input,
|
||||||
|
valueType = typeof(object).FullName
|
||||||
|
});
|
||||||
|
|
||||||
|
_outputSlot = new(this, new()
|
||||||
|
{
|
||||||
|
slotName = "Output",
|
||||||
|
nodeID = Id,
|
||||||
|
slotIndex = 0,
|
||||||
|
direction = SlotDirection.Output,
|
||||||
|
valueType = typeof(object).FullName
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddSlot(Slot slot)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveSlot(Slot slot)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public Slot GetSlot(int index, SlotDirection direction)
|
||||||
|
{
|
||||||
|
return direction switch
|
||||||
|
{
|
||||||
|
SlotDirection.Input => _inputSlot,
|
||||||
|
SlotDirection.Output => _outputSlot,
|
||||||
|
_ => null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UnlinkAllSlots()
|
||||||
|
{
|
||||||
|
_inputSlot.UnlinkAll();
|
||||||
|
_outputSlot.UnlinkAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Execute()
|
||||||
|
{
|
||||||
|
if (_isExecuted)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_outputSlot.ReceiveData(_inputSlot.value);
|
||||||
|
_outputSlot.PushData(null);
|
||||||
|
|
||||||
|
_isExecuted = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClearExecutionFlag()
|
||||||
|
{
|
||||||
|
_isExecuted = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -89,12 +89,5 @@ namespace Misaki.GraphView
|
|||||||
_linkedSlotData.Remove(other.slotData);
|
_linkedSlotData.Remove(other.slotData);
|
||||||
other._linkedSlotData.Remove(slotData);
|
other._linkedSlotData.Remove(slotData);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ReceiveData(object data)
|
|
||||||
{
|
|
||||||
value = data;
|
|
||||||
// We move this to PullData method in BaseNode
|
|
||||||
//owner.GetType().GetField(slotData.slotName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.SetValue(owner, data);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -22,8 +22,8 @@ MonoBehaviour:
|
|||||||
contents: Test
|
contents: Test
|
||||||
position:
|
position:
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
x: 764.2733
|
x: 624.0001
|
||||||
y: 223.30664
|
y: 217.33333
|
||||||
width: 164
|
width: 164
|
||||||
height: 156.66666
|
height: 156.66666
|
||||||
theme: 0
|
theme: 0
|
||||||
@@ -55,7 +55,7 @@ MonoBehaviour:
|
|||||||
valueType: System.Object
|
valueType: System.Object
|
||||||
_exposedProperties:
|
_exposedProperties:
|
||||||
- rid: 299037523270959195
|
- rid: 299037523270959195
|
||||||
graphPosition: {x: 72, y: 28.666666, z: 0}
|
graphPosition: {x: 131.33333, y: -8, z: 0}
|
||||||
graphScale: {x: 1, y: 1, z: 1}
|
graphScale: {x: 1, y: 1, z: 1}
|
||||||
references:
|
references:
|
||||||
version: 2
|
version: 2
|
||||||
@@ -118,8 +118,8 @@ MonoBehaviour:
|
|||||||
slotIndex: 0
|
slotIndex: 0
|
||||||
direction: 1
|
direction: 1
|
||||||
valueType: System.Single
|
valueType: System.Single
|
||||||
a: 0
|
a: 1
|
||||||
b: 0
|
b: 1
|
||||||
- rid: 299037570321612881
|
- rid: 299037570321612881
|
||||||
type: {class: Output, ns: Misaki.GraphView.Sample, asm: GraphView.Sample}
|
type: {class: Output, ns: Misaki.GraphView.Sample, asm: GraphView.Sample}
|
||||||
data:
|
data:
|
||||||
@@ -154,8 +154,8 @@ MonoBehaviour:
|
|||||||
id: 5ee073fb-e411-4061-867a-9ce3afd9a188
|
id: 5ee073fb-e411-4061-867a-9ce3afd9a188
|
||||||
position:
|
position:
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
x: 335.3333
|
x: 357.66666
|
||||||
y: 484.6667
|
y: 484.6665
|
||||||
width: 98.66666
|
width: 98.66666
|
||||||
height: 36
|
height: 36
|
||||||
_inputs: []
|
_inputs: []
|
||||||
|
|||||||
@@ -5,23 +5,26 @@ namespace Misaki.GraphView.Sample
|
|||||||
{
|
{
|
||||||
public class Logger : ILogger
|
public class Logger : ILogger
|
||||||
{
|
{
|
||||||
private readonly List<string> _logs = new ();
|
private readonly List<string> _logs = new();
|
||||||
|
|
||||||
public Action<ExecutableNode, string, LogType> OnLog { get; set; }
|
public Action<DataNode, string, LogType> OnLog
|
||||||
|
{
|
||||||
|
get; set;
|
||||||
|
}
|
||||||
|
|
||||||
public void LogInfo(ExecutableNode node, string message)
|
public void LogInfo(DataNode node, string message)
|
||||||
{
|
{
|
||||||
_logs.Add($"Log Info from node {node.GetType().Name}: {message}");
|
_logs.Add($"Log Info from node {node.GetType().Name}: {message}");
|
||||||
OnLog?.Invoke(node, message, LogType.Info);
|
OnLog?.Invoke(node, message, LogType.Info);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void LogWarning(ExecutableNode node, string message)
|
public void LogWarning(DataNode node, string message)
|
||||||
{
|
{
|
||||||
_logs.Add($"Log Warning from node {node.GetType().Name}: {message}");
|
_logs.Add($"Log Warning from node {node.GetType().Name}: {message}");
|
||||||
OnLog?.Invoke(node, message, LogType.Warning);
|
OnLog?.Invoke(node, message, LogType.Warning);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void LogError(ExecutableNode node, string message)
|
public void LogError(DataNode node, string message)
|
||||||
{
|
{
|
||||||
_logs.Add($"Log Error from node {node.GetType().Name}: {message}");
|
_logs.Add($"Log Error from node {node.GetType().Name}: {message}");
|
||||||
OnLog?.Invoke(node, message, LogType.Error);
|
OnLog?.Invoke(node, message, LogType.Error);
|
||||||
|
|||||||
Reference in New Issue
Block a user