Created unity project
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7d96ebd30e90841de9452b819ccb135e
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,14 @@
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Plugin(BoltProduct.ID)]
|
||||
internal class Acknowledgement_NCalc : PluginAcknowledgement
|
||||
{
|
||||
public Acknowledgement_NCalc(Plugin plugin) : base(plugin) { }
|
||||
|
||||
public override string title => "NCalc";
|
||||
public override string author => "Sébastien Ros";
|
||||
public override string url => "https://ncalc.codeplex.com/";
|
||||
public override string licenseName => "MIT";
|
||||
public override string licenseText => CommonLicenses.MIT;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a3d454da223e041ea89eaac8fb3e53fb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 628c7c9331b644b4eb1901bca13710be
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,21 @@
|
||||
using UnityEditor;
|
||||
|
||||
namespace Unity.VisualScripting.Analytics
|
||||
{
|
||||
class FlowMacroSavedEvent : UnityEditor.AssetModificationProcessor
|
||||
{
|
||||
static string[] OnWillSaveAssets(string[] paths)
|
||||
{
|
||||
foreach (string path in paths)
|
||||
{
|
||||
var assetType = AssetDatabase.GetMainAssetTypeAtPath(path);
|
||||
if (assetType == typeof(ScriptGraphAsset))
|
||||
{
|
||||
UsageAnalytics.CollectAndSend();
|
||||
break;
|
||||
}
|
||||
}
|
||||
return paths;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 444c595f4f0d649eba2094c40baf48cf
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,58 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
public static class BoltFlowNameUtility
|
||||
{
|
||||
[Obsolete("This method is obsolete. Please use the new UnitTitle(unitType, short, includeStatus) instead.")]
|
||||
public static string UnitTitle(Type unitType, bool @short)
|
||||
{
|
||||
if (@short)
|
||||
{
|
||||
var shortTitle = unitType.GetAttribute<UnitShortTitleAttribute>()?.title;
|
||||
|
||||
if (shortTitle != null)
|
||||
{
|
||||
return shortTitle;
|
||||
}
|
||||
}
|
||||
|
||||
var title = unitType.GetAttribute<UnitTitleAttribute>()?.title;
|
||||
|
||||
if (title != null)
|
||||
{
|
||||
return title;
|
||||
}
|
||||
|
||||
return unitType.HumanName();
|
||||
}
|
||||
|
||||
public static string UnitTitle(Type unitType, bool @short, bool includeStatus)
|
||||
{
|
||||
var suffix = string.Empty;
|
||||
if (includeStatus && Attribute.IsDefined(unitType, typeof(ObsoleteAttribute)))
|
||||
suffix = " (Deprecated)";
|
||||
|
||||
if (@short)
|
||||
{
|
||||
var shortTitle = unitType.GetAttribute<UnitShortTitleAttribute>()?.title;
|
||||
|
||||
if (shortTitle != null)
|
||||
{
|
||||
return $"{shortTitle} {suffix}";
|
||||
}
|
||||
}
|
||||
|
||||
var title = unitType.GetAttribute<UnitTitleAttribute>()?.title;
|
||||
|
||||
return title != null ? $"{title} {suffix}" : $"{unitType.HumanName()} {suffix}";
|
||||
}
|
||||
|
||||
public static string UnitPreviousTitle(Type unitType)
|
||||
{
|
||||
var title = unitType.GetAttribute<RenamedFromAttribute>()?.previousName.Split('.').Last();
|
||||
return title ?? string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 566f4983416e04cfda0b4592b86f1848
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 84fc151c3c97446ff9c9993706319db4
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,39 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Widget(typeof(ControlConnection))]
|
||||
public sealed class ControlConnectionWidget : UnitConnectionWidget<ControlConnection>
|
||||
{
|
||||
public ControlConnectionWidget(FlowCanvas canvas, ControlConnection connection) : base(canvas, connection) { }
|
||||
|
||||
|
||||
#region Drawing
|
||||
|
||||
public override Color color => Color.white;
|
||||
|
||||
protected override bool colorIfActive => !BoltFlow.Configuration.animateControlConnections || !BoltFlow.Configuration.animateValueConnections;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Droplets
|
||||
|
||||
protected override bool showDroplets => BoltFlow.Configuration.animateControlConnections;
|
||||
|
||||
protected override Vector2 GetDropletSize()
|
||||
{
|
||||
return BoltFlow.Icons.valuePortConnected?[12].Size() ?? 12 * Vector2.one;
|
||||
}
|
||||
|
||||
protected override void DrawDroplet(Rect position)
|
||||
{
|
||||
if (BoltFlow.Icons.valuePortConnected != null)
|
||||
{
|
||||
GUI.DrawTexture(position, BoltFlow.Icons.valuePortConnected[12]);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d88c7deff78ad4226b20ab4dfc84f89c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,9 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
public interface IUnitConnectionWidget : IGraphElementWidget
|
||||
{
|
||||
Color color { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9ed635d3114774915b9f96a96a330dca
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,28 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Widget(typeof(InvalidConnection))]
|
||||
public sealed class InvalidConnectionWidget : UnitConnectionWidget<InvalidConnection>
|
||||
{
|
||||
public InvalidConnectionWidget(FlowCanvas canvas, InvalidConnection connection) : base(canvas, connection) { }
|
||||
|
||||
|
||||
#region Drawing
|
||||
|
||||
public override Color color => UnitConnectionStyles.invalidColor;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Droplets
|
||||
|
||||
protected override bool showDroplets => false;
|
||||
|
||||
protected override Vector2 GetDropletSize() => Vector2.zero;
|
||||
|
||||
protected override void DrawDroplet(Rect position) { }
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 54bd5c4a9de7845ab9aaea996b90656d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,19 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
public static class UnitConnectionStyles
|
||||
{
|
||||
public static readonly Color activeColor = new Color(0.37f, 0.66f, 0.95f);
|
||||
|
||||
public static readonly Color highlightColor = new Color(1, 0.95f, 0f);
|
||||
|
||||
public static readonly Color invalidColor = new Color(1, 0, 0);
|
||||
|
||||
public static readonly Color disconnectColor = new Color(0.95f, 0.1f, 0.1f);
|
||||
|
||||
public static readonly float minBend = 15;
|
||||
|
||||
public static readonly float relativeBend = 1 / 4f;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f7fbf7894024a473ab12d0bec2b9b5e9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,247 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
public abstract class UnitConnectionWidget<TConnection> : GraphElementWidget<FlowCanvas, TConnection>, IUnitConnectionWidget
|
||||
where TConnection : class, IUnitConnection
|
||||
{
|
||||
protected UnitConnectionWidget(FlowCanvas canvas, TConnection connection) : base(canvas, connection) { }
|
||||
|
||||
|
||||
#region Model
|
||||
|
||||
protected TConnection connection => element;
|
||||
|
||||
protected IUnitConnectionDebugData ConnectionDebugData => GetDebugData<IUnitConnectionDebugData>();
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Lifecycle
|
||||
|
||||
public override void BeforeFrame()
|
||||
{
|
||||
base.BeforeFrame();
|
||||
|
||||
if (showDroplets)
|
||||
{
|
||||
GraphGUI.UpdateDroplets(canvas, droplets, ConnectionDebugData.lastInvokeFrame, ref lastInvokeTime, ref dropTime);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Positioning
|
||||
|
||||
public override IEnumerable<IWidget> positionDependencies
|
||||
{
|
||||
get
|
||||
{
|
||||
yield return canvas.Widget(connection.source);
|
||||
yield return canvas.Widget(connection.destination);
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool snapToGrid => false;
|
||||
|
||||
public Rect sourceHandlePosition { get; private set; }
|
||||
|
||||
public Rect destinationHandlePosition { get; private set; }
|
||||
|
||||
public Vector2 sourceHandleEdgeCenter { get; private set; }
|
||||
|
||||
public Vector2 destinationHandleEdgeCenter { get; private set; }
|
||||
|
||||
public Vector2 middlePosition;
|
||||
|
||||
private Rect _position;
|
||||
|
||||
private Rect _clippingPosition;
|
||||
|
||||
public override Rect position
|
||||
{
|
||||
get { return _position; }
|
||||
set { }
|
||||
}
|
||||
|
||||
public override Rect clippingPosition => _clippingPosition;
|
||||
|
||||
public override void CachePosition()
|
||||
{
|
||||
base.CachePosition();
|
||||
|
||||
sourceHandlePosition = canvas.Widget<IUnitPortWidget>(connection.source).handlePosition;
|
||||
destinationHandlePosition = canvas.Widget<IUnitPortWidget>(connection.destination).handlePosition;
|
||||
|
||||
sourceHandleEdgeCenter = sourceHandlePosition.GetEdgeCenter(Edge.Right);
|
||||
destinationHandleEdgeCenter = destinationHandlePosition.GetEdgeCenter(Edge.Left);
|
||||
|
||||
middlePosition = (sourceHandlePosition.center + destinationHandlePosition.center) / 2;
|
||||
|
||||
_position = new Rect
|
||||
(
|
||||
middlePosition.x,
|
||||
middlePosition.y,
|
||||
0,
|
||||
0
|
||||
);
|
||||
|
||||
_clippingPosition = _position.Encompass(sourceHandleEdgeCenter).Encompass(destinationHandleEdgeCenter);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Drawing
|
||||
|
||||
protected virtual bool colorIfActive => true;
|
||||
|
||||
public abstract Color color { get; }
|
||||
|
||||
protected override bool dim
|
||||
{
|
||||
get
|
||||
{
|
||||
var dim = BoltCore.Configuration.dimInactiveNodes && !connection.destination.unit.Analysis<UnitAnalysis>(context).isEntered;
|
||||
|
||||
if (BoltCore.Configuration.dimIncompatibleNodes && canvas.isCreatingConnection)
|
||||
{
|
||||
dim = true;
|
||||
}
|
||||
|
||||
return dim;
|
||||
}
|
||||
}
|
||||
|
||||
public override void DrawBackground()
|
||||
{
|
||||
base.DrawBackground();
|
||||
|
||||
BeginDim();
|
||||
|
||||
DrawConnection();
|
||||
|
||||
if (showDroplets)
|
||||
{
|
||||
DrawDroplets();
|
||||
}
|
||||
|
||||
EndDim();
|
||||
}
|
||||
|
||||
protected virtual void DrawConnection()
|
||||
{
|
||||
var color = this.color;
|
||||
|
||||
var sourceWidget = canvas.Widget<IUnitPortWidget>(connection.source);
|
||||
var destinationWidget = canvas.Widget<IUnitPortWidget>(connection.destination);
|
||||
|
||||
var highlight = !canvas.isCreatingConnection && (sourceWidget.isMouseOver || destinationWidget.isMouseOver);
|
||||
|
||||
var willDisconnect = sourceWidget.willDisconnect || destinationWidget.willDisconnect;
|
||||
|
||||
if (willDisconnect)
|
||||
{
|
||||
color = UnitConnectionStyles.disconnectColor;
|
||||
}
|
||||
else if (highlight)
|
||||
{
|
||||
color = UnitConnectionStyles.highlightColor;
|
||||
}
|
||||
else if (colorIfActive)
|
||||
{
|
||||
if (EditorApplication.isPaused)
|
||||
{
|
||||
if (EditorTimeBinding.frame == ConnectionDebugData.lastInvokeFrame)
|
||||
{
|
||||
color = UnitConnectionStyles.activeColor;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
color = Color.Lerp(UnitConnectionStyles.activeColor, color, (EditorTimeBinding.time - ConnectionDebugData.lastInvokeTime) / UnitWidget<IUnit>.Styles.invokeFadeDuration);
|
||||
}
|
||||
}
|
||||
|
||||
var thickness = 3;
|
||||
|
||||
GraphGUI.DrawConnection(color, sourceHandleEdgeCenter, destinationHandleEdgeCenter, Edge.Right, Edge.Left, null, Vector2.zero, UnitConnectionStyles.relativeBend, UnitConnectionStyles.minBend, thickness);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Selecting
|
||||
|
||||
public override bool canSelect => false;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Dragging
|
||||
|
||||
public override bool canDrag => false;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Deleting
|
||||
|
||||
public override bool canDelete => true;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Droplets
|
||||
|
||||
private readonly List<float> droplets = new List<float>();
|
||||
|
||||
private float dropTime;
|
||||
|
||||
private float lastInvokeTime;
|
||||
|
||||
private const float handleAlignmentMargin = 0.1f;
|
||||
|
||||
protected virtual bool showDroplets => true;
|
||||
|
||||
protected abstract Vector2 GetDropletSize();
|
||||
|
||||
protected abstract void DrawDroplet(Rect position);
|
||||
|
||||
protected virtual void DrawDroplets()
|
||||
{
|
||||
foreach (var droplet in droplets)
|
||||
{
|
||||
Vector2 position;
|
||||
|
||||
if (droplet < handleAlignmentMargin)
|
||||
{
|
||||
var t = droplet / handleAlignmentMargin;
|
||||
position = Vector2.Lerp(sourceHandlePosition.center, sourceHandleEdgeCenter, t);
|
||||
}
|
||||
else if (droplet > 1 - handleAlignmentMargin)
|
||||
{
|
||||
var t = (droplet - (1 - handleAlignmentMargin)) / handleAlignmentMargin;
|
||||
position = Vector2.Lerp(destinationHandleEdgeCenter, destinationHandlePosition.center, t);
|
||||
}
|
||||
else
|
||||
{
|
||||
var t = (droplet - handleAlignmentMargin) / (1 - 2 * handleAlignmentMargin);
|
||||
position = GraphGUI.GetPointOnConnection(t, sourceHandleEdgeCenter, destinationHandleEdgeCenter, Edge.Right, Edge.Left, UnitConnectionStyles.relativeBend, UnitConnectionStyles.minBend);
|
||||
}
|
||||
|
||||
var size = GetDropletSize();
|
||||
|
||||
using (LudiqGUI.color.Override(GUI.color * color))
|
||||
{
|
||||
DrawDroplet(new Rect(position.x - size.x / 2, position.y - size.y / 2, size.x, size.y));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e9d80f8d221a84498906e6f54205e6d3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,150 @@
|
||||
using System;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Widget(typeof(ValueConnection))]
|
||||
public sealed class ValueConnectionWidget : UnitConnectionWidget<ValueConnection>
|
||||
{
|
||||
public ValueConnectionWidget(FlowCanvas canvas, ValueConnection connection) : base(canvas, connection) { }
|
||||
|
||||
private new ValueConnection.DebugData ConnectionDebugData => GetDebugData<ValueConnection.DebugData>();
|
||||
|
||||
|
||||
#region Drawing
|
||||
|
||||
public override Color color => DetermineColor(connection.source.type, connection.destination.type);
|
||||
|
||||
protected override bool colorIfActive => !BoltFlow.Configuration.animateControlConnections || !BoltFlow.Configuration.animateValueConnections;
|
||||
|
||||
public override void DrawForeground()
|
||||
{
|
||||
base.DrawForeground();
|
||||
|
||||
if (BoltFlow.Configuration.showConnectionValues)
|
||||
{
|
||||
var showLastValue = EditorApplication.isPlaying && ConnectionDebugData.assignedLastValue;
|
||||
var showPredictedvalue = BoltFlow.Configuration.predictConnectionValues && !EditorApplication.isPlaying && Flow.CanPredict(connection.source, reference);
|
||||
|
||||
if (showLastValue || showPredictedvalue)
|
||||
{
|
||||
var previousIconSize = EditorGUIUtility.GetIconSize();
|
||||
EditorGUIUtility.SetIconSize(new Vector2(IconSize.Small, IconSize.Small));
|
||||
|
||||
object value;
|
||||
|
||||
if (showLastValue)
|
||||
{
|
||||
value = ConnectionDebugData.lastValue;
|
||||
}
|
||||
else // if (showPredictedvalue)
|
||||
{
|
||||
value = Flow.Predict(connection.source, reference);
|
||||
}
|
||||
|
||||
var label = new GUIContent(value.ToShortString(), Icons.Type(value?.GetType())?[IconSize.Small]);
|
||||
var labelSize = Styles.prediction.CalcSize(label);
|
||||
var labelPosition = new Rect(position.position - labelSize / 2, labelSize);
|
||||
|
||||
BeginDim();
|
||||
|
||||
GUI.Label(labelPosition, label, Styles.prediction);
|
||||
|
||||
EndDim();
|
||||
|
||||
EditorGUIUtility.SetIconSize(previousIconSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Color DetermineColor(Type source, Type destination)
|
||||
{
|
||||
if (destination == typeof(object))
|
||||
{
|
||||
return DetermineColor(source);
|
||||
}
|
||||
|
||||
return DetermineColor(destination);
|
||||
}
|
||||
|
||||
public static Color DetermineColor(Type type)
|
||||
{
|
||||
if (type == null)
|
||||
{
|
||||
return new Color(0.8f, 0.8f, 0.8f);
|
||||
}
|
||||
|
||||
if (type == typeof(string))
|
||||
{
|
||||
return new Color(1.0f, 0.62f, 0.35f);
|
||||
}
|
||||
|
||||
if (type == typeof(bool))
|
||||
{
|
||||
return new Color(0.86f, 0.55f, 0.92f);
|
||||
}
|
||||
|
||||
if (type == typeof(char))
|
||||
{
|
||||
return new Color(1.0f, 0.90f, 0.40f);
|
||||
}
|
||||
|
||||
if (type.IsEnum)
|
||||
{
|
||||
return new Color(1.0f, 0.63f, 0.66f);
|
||||
}
|
||||
|
||||
if (type.IsNumeric())
|
||||
{
|
||||
return new Color(0.45f, 0.78f, 1f);
|
||||
}
|
||||
|
||||
if (type.IsNumericConstruct())
|
||||
{
|
||||
return new Color(0.45f, 1.00f, 0.82f);
|
||||
}
|
||||
|
||||
return new Color(0.60f, 0.88f, 0.00f);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Droplets
|
||||
|
||||
protected override bool showDroplets => BoltFlow.Configuration.animateValueConnections;
|
||||
|
||||
protected override Vector2 GetDropletSize()
|
||||
{
|
||||
return BoltFlow.Icons.valuePortConnected?[12].Size() ?? 12 * Vector3.one;
|
||||
}
|
||||
|
||||
protected override void DrawDroplet(Rect position)
|
||||
{
|
||||
if (BoltFlow.Icons.valuePortConnected != null)
|
||||
{
|
||||
GUI.DrawTexture(position, BoltFlow.Icons.valuePortConnected?[12]);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
private static class Styles
|
||||
{
|
||||
static Styles()
|
||||
{
|
||||
prediction = new GUIStyle(EditorStyles.label);
|
||||
prediction.normal.textColor = Color.white;
|
||||
prediction.fontSize = 9;
|
||||
prediction.normal.background = new Color(0, 0, 0, 0.25f).GetPixel();
|
||||
prediction.padding = new RectOffset(4, 6, 3, 3);
|
||||
prediction.margin = new RectOffset(0, 0, 0, 0);
|
||||
prediction.alignment = TextAnchor.MiddleCenter;
|
||||
}
|
||||
|
||||
public static readonly GUIStyle prediction;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b1568bb10360a435d9c58e96f304fa98
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b5d939ea76bfb4e299827176cffe686c
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Descriptor(typeof(FlowGraph))]
|
||||
public sealed class FlowGraphDescriptor : GraphDescriptor<FlowGraph, GraphDescription>
|
||||
{
|
||||
public FlowGraphDescriptor(FlowGraph target) : base(target) { }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2945371b70d5248c29fba485e0f535f3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Descriptor(typeof(ScriptMachine))]
|
||||
public sealed class FlowMachineDescriptor : MachineDescriptor<ScriptMachine, MachineDescription>
|
||||
{
|
||||
public FlowMachineDescriptor(ScriptMachine target) : base(target) { }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bf11352faae8e4195bed44acfb96c522
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Descriptor(typeof(ScriptGraphAsset))]
|
||||
public sealed class FlowMacroDescriptor : MacroDescriptor<ScriptGraphAsset, MacroDescription>
|
||||
{
|
||||
public FlowMacroDescriptor(ScriptGraphAsset target) : base(target) { }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 23070ced5c01f495eb6b3dcc75ab6fc1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,23 @@
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
public interface IUnitDescriptor : IDescriptor
|
||||
{
|
||||
IUnit unit { get; }
|
||||
|
||||
new UnitDescription description { get; }
|
||||
|
||||
string Title();
|
||||
|
||||
string ShortTitle();
|
||||
|
||||
string Surtitle();
|
||||
|
||||
string Subtitle();
|
||||
|
||||
string Summary();
|
||||
|
||||
EditorTexture Icon();
|
||||
|
||||
void DescribePort(IUnitPort port, UnitPortDescription description);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 56af1e1695c6a47bb826414e1888797f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,324 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Analyser(typeof(IUnit))]
|
||||
public class UnitAnalyser<TUnit> : Analyser<TUnit, UnitAnalysis>
|
||||
where TUnit : class, IUnit
|
||||
{
|
||||
public UnitAnalyser(GraphReference reference, TUnit target) : base(reference, target) { }
|
||||
|
||||
public TUnit unit => target;
|
||||
|
||||
[Assigns]
|
||||
protected bool IsEntered()
|
||||
{
|
||||
using (var recursion = Recursion.New(1))
|
||||
{
|
||||
return IsEntered(unit, recursion);
|
||||
}
|
||||
}
|
||||
|
||||
private static bool IsEntered(IUnit unit, Recursion recursion)
|
||||
{
|
||||
if (unit.isControlRoot)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
foreach (var controlInput in unit.controlInputs)
|
||||
{
|
||||
if (!controlInput.isPredictable || controlInput.couldBeEntered)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var valueOutput in unit.valueOutputs)
|
||||
{
|
||||
if (!recursion?.TryEnter(valueOutput) ?? false)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var valueOutputEntered = valueOutput.validConnections.Any(c => IsEntered(c.destination.unit, recursion));
|
||||
|
||||
recursion?.Exit(valueOutput);
|
||||
|
||||
if (valueOutputEntered)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private string PortLabel(IUnitPort port)
|
||||
{
|
||||
return port.Description<UnitPortDescription>().label;
|
||||
}
|
||||
|
||||
[Assigns]
|
||||
protected virtual IEnumerable<Warning> Warnings()
|
||||
{
|
||||
var isEntered = IsEntered();
|
||||
|
||||
if (!unit.isDefined)
|
||||
{
|
||||
if (unit.definitionException != null)
|
||||
{
|
||||
yield return Warning.Exception(unit.definitionException);
|
||||
}
|
||||
else if (!unit.canDefine)
|
||||
{
|
||||
yield return Warning.Caution("Node is not properly configured.");
|
||||
}
|
||||
}
|
||||
else if (unit is MissingType)
|
||||
{
|
||||
var formerType = $"{(unit as MissingType)?.formerType}";
|
||||
formerType = string.IsNullOrEmpty(formerType) ? string.Empty : $"'{formerType}'";
|
||||
yield return new ActionButtonWarning(
|
||||
WarningLevel.Error,
|
||||
$"The source script for this node type can't be found. Did you remove its script?\n" +
|
||||
$"Replace the node or add the {formerType} script file back to your project files.",
|
||||
"Replace Node",
|
||||
() =>
|
||||
{ UnitWidgetHelper.ReplaceUnit(unit, reference, context, context.selection, new EventWrapper(unit)); }
|
||||
);
|
||||
yield break;
|
||||
}
|
||||
|
||||
if (!isEntered)
|
||||
{
|
||||
yield return Warning.Info("Node is never entered.");
|
||||
}
|
||||
|
||||
// Obsolete attribute is not inherited, so traverse the chain manually
|
||||
var obsoleteAttribute = unit.GetType().AndHierarchy().FirstOrDefault(t => t.HasAttribute<ObsoleteAttribute>())?.GetAttribute<ObsoleteAttribute>();
|
||||
|
||||
if (obsoleteAttribute != null)
|
||||
{
|
||||
var unitName = BoltFlowNameUtility.UnitTitle(unit.GetType(), true, false);
|
||||
|
||||
if (obsoleteAttribute.Message != null)
|
||||
{
|
||||
Debug.LogWarning($"\"{unitName}\" node is deprecated: {obsoleteAttribute.Message}");
|
||||
yield return Warning.Caution($"Deprecated: {obsoleteAttribute.Message}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning($"\"{unitName}\" node is deprecated.");
|
||||
yield return Warning.Caution("This node is deprecated.");
|
||||
}
|
||||
}
|
||||
|
||||
if (unit.isDefined)
|
||||
{
|
||||
foreach (var invalidInput in unit.invalidInputs)
|
||||
{
|
||||
yield return Warning.Caution($"{PortLabel(invalidInput)} is not used by this unit.");
|
||||
}
|
||||
|
||||
foreach (var invalidOutput in unit.invalidOutputs)
|
||||
{
|
||||
yield return Warning.Caution($"{PortLabel(invalidOutput)} is not provided by this unit.");
|
||||
}
|
||||
|
||||
foreach (var validPort in unit.validPorts)
|
||||
{
|
||||
if (validPort.hasInvalidConnection)
|
||||
{
|
||||
yield return Warning.Caution($"{PortLabel(validPort)} has an invalid connection.");
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_IOS || UNITY_ANDROID || UNITY_TVOS
|
||||
if (unit is IMouseEventUnit)
|
||||
{
|
||||
var graphName = string.IsNullOrEmpty(unit.graph.title) ? "A ScriptGraph" : $"The ScriptGraph {unit.graph.title}";
|
||||
var unitName = BoltFlowNameUtility.UnitTitle(unit.GetType(), true, false);
|
||||
Debug.LogWarning($"{graphName} contains a {unitName} node. Presence of MouseEvent nodes might impact performance on handheld devices.");
|
||||
yield return Warning.Caution("Presence of MouseEvent nodes might impact performance on handheld devices.");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
foreach (var controlInput in unit.controlInputs)
|
||||
{
|
||||
if (!controlInput.hasValidConnection)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (var relation in controlInput.relations)
|
||||
{
|
||||
if (relation.source is ValueInput)
|
||||
{
|
||||
var valueInput = (ValueInput)relation.source;
|
||||
|
||||
foreach (var warning in ValueInputWarnings(valueInput))
|
||||
{
|
||||
yield return warning;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var controlOutput in unit.controlOutputs)
|
||||
{
|
||||
if (!controlOutput.hasValidConnection)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var controlInputs = controlOutput.relations.Select(r => r.source).OfType<ControlInput>();
|
||||
|
||||
var isTriggered = !controlInputs.Any() || controlInputs.Any(ci => !ci.isPredictable || ci.couldBeEntered);
|
||||
|
||||
foreach (var relation in controlOutput.relations)
|
||||
{
|
||||
if (relation.source is ValueInput)
|
||||
{
|
||||
var valueInput = (ValueInput)relation.source;
|
||||
|
||||
foreach (var warning in ValueInputWarnings(valueInput))
|
||||
{
|
||||
yield return warning;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isEntered && !isTriggered)
|
||||
{
|
||||
yield return Warning.Caution($"{PortLabel(controlOutput)} is connected, but it is never triggered.");
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var valueOutput in unit.valueOutputs)
|
||||
{
|
||||
if (!valueOutput.hasValidConnection)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach (var relation in valueOutput.relations)
|
||||
{
|
||||
if (relation.source is ControlInput)
|
||||
{
|
||||
var controlInput = (ControlInput)relation.source;
|
||||
|
||||
if (isEntered && controlInput.isPredictable && !controlInput.couldBeEntered)
|
||||
{
|
||||
yield return Warning.Severe($"{PortLabel(controlInput)} is required, but it is never entered.");
|
||||
}
|
||||
}
|
||||
else if (relation.source is ValueInput)
|
||||
{
|
||||
var valueInput = (ValueInput)relation.source;
|
||||
|
||||
foreach (var warning in ValueInputWarnings(valueInput))
|
||||
{
|
||||
yield return warning;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerable<Warning> ValueInputWarnings(ValueInput valueInput)
|
||||
{
|
||||
// We can disable null reference check if no self is available
|
||||
// and the port requires an owner, for example in macros.
|
||||
var trustFutureOwner = valueInput.nullMeansSelf && reference.self == null;
|
||||
|
||||
var checkForNullReference = BoltFlow.Configuration.predictPotentialNullReferences && !valueInput.allowsNull && !trustFutureOwner;
|
||||
|
||||
var checkForMissingComponent = BoltFlow.Configuration.predictPotentialMissingComponents && typeof(Component).IsAssignableFrom(valueInput.type);
|
||||
|
||||
// Note that we cannot directly check the input's predicted value, because it
|
||||
// will return false for safeguard specifically because it might be missing requirements.
|
||||
// Therefore, we first check the connected value, then the default value.
|
||||
|
||||
// If the port is connected to a predictable output, use the connected value to perform checks.
|
||||
if (valueInput.hasValidConnection)
|
||||
{
|
||||
var valueOutput = valueInput.validConnectedPorts.Single();
|
||||
|
||||
if (Flow.CanPredict(valueOutput, reference))
|
||||
{
|
||||
if (checkForNullReference)
|
||||
{
|
||||
if (Flow.Predict(valueOutput, reference) == null)
|
||||
{
|
||||
yield return Warning.Severe($"{PortLabel(valueInput)} cannot be null.");
|
||||
}
|
||||
}
|
||||
|
||||
if (checkForMissingComponent)
|
||||
{
|
||||
var connectedPredictedValue = Flow.Predict(valueOutput, reference);
|
||||
|
||||
// This check is necessary, because the predicted value could be
|
||||
// incompatible as connections with non-guaranteed conversions are allowed.
|
||||
if (ConversionUtility.CanConvert(connectedPredictedValue, typeof(GameObject), true))
|
||||
{
|
||||
var gameObject = ConversionUtility.Convert<GameObject>(connectedPredictedValue);
|
||||
|
||||
if (gameObject != null)
|
||||
{
|
||||
var component = (Component)ConversionUtility.Convert(gameObject, valueInput.type);
|
||||
|
||||
if (component == null)
|
||||
{
|
||||
yield return Warning.Caution($"{PortLabel(valueInput)} is missing a {valueInput.type.DisplayName()} component.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// If the port isn't connected but has a default value, use the default value to perform checks.
|
||||
else if (valueInput.hasDefaultValue)
|
||||
{
|
||||
if (checkForNullReference)
|
||||
{
|
||||
if (Flow.Predict(valueInput, reference) == null)
|
||||
{
|
||||
yield return Warning.Severe($"{PortLabel(valueInput)} cannot be null.");
|
||||
}
|
||||
}
|
||||
|
||||
if (checkForMissingComponent)
|
||||
{
|
||||
var unconnectedPredictedValue = Flow.Predict(valueInput, reference);
|
||||
|
||||
if (ConversionUtility.CanConvert(unconnectedPredictedValue, typeof(GameObject), true))
|
||||
{
|
||||
var gameObject = ConversionUtility.Convert<GameObject>(unconnectedPredictedValue);
|
||||
|
||||
if (gameObject != null)
|
||||
{
|
||||
var component = (Component)ConversionUtility.Convert(gameObject, valueInput.type);
|
||||
|
||||
if (component == null)
|
||||
{
|
||||
yield return Warning.Caution($"{PortLabel(valueInput)} is missing a {valueInput.type.DisplayName()} component.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// The value isn't connected and has no default value,
|
||||
// therefore it is certain to be missing at runtime.
|
||||
else
|
||||
{
|
||||
yield return Warning.Severe($"{PortLabel(valueInput)} is missing.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 59cd7f950ffc142d997761f2547b6bfb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,7 @@
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
public sealed class UnitAnalysis : GraphElementAnalysis
|
||||
{
|
||||
public bool isEntered { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2c1bdc9069f004a5f96a18d68a450d49
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
public sealed class UnitDescription : GraphElementDescription
|
||||
{
|
||||
public string shortTitle { get; set; }
|
||||
public string surtitle { get; set; }
|
||||
public string subtitle { get; set; }
|
||||
public EditorTexture[] icons { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 046d84976aadf4fa58001515d8167521
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,391 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
using UnityObject = UnityEngine.Object;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Descriptor(typeof(IUnit))]
|
||||
public class UnitDescriptor<TUnit> : Descriptor<TUnit, UnitDescription>, IUnitDescriptor
|
||||
where TUnit : class, IUnit
|
||||
{
|
||||
public UnitDescriptor(TUnit target) : base(target)
|
||||
{
|
||||
unitType = unit.GetType();
|
||||
}
|
||||
|
||||
protected Type unitType { get; }
|
||||
|
||||
public TUnit unit => target;
|
||||
|
||||
IUnit IUnitDescriptor.unit => unit;
|
||||
|
||||
private enum State
|
||||
{
|
||||
Defined,
|
||||
|
||||
NotDefined,
|
||||
|
||||
FailedToDefine
|
||||
}
|
||||
|
||||
private State state
|
||||
{
|
||||
get
|
||||
{
|
||||
if (unit.isDefined)
|
||||
{
|
||||
return State.Defined;
|
||||
}
|
||||
else if (unit.failedToDefine)
|
||||
{
|
||||
return State.FailedToDefine;
|
||||
}
|
||||
else
|
||||
{
|
||||
return State.NotDefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#region Reflected Description
|
||||
|
||||
static UnitDescriptor()
|
||||
{
|
||||
XmlDocumentation.loadComplete += FreeReflectedDescriptions;
|
||||
}
|
||||
|
||||
public static void FreeReflectedDescriptions()
|
||||
{
|
||||
reflectedDescriptions.Clear();
|
||||
reflectedInputDescriptions.Clear();
|
||||
reflectedOutputDescriptions.Clear();
|
||||
}
|
||||
|
||||
protected UnitDescription reflectedDescription
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!reflectedDescriptions.TryGetValue(unitType, out var reflectedDescription))
|
||||
{
|
||||
reflectedDescription = FetchReflectedDescription(unitType);
|
||||
reflectedDescriptions.Add(unitType, reflectedDescription);
|
||||
}
|
||||
|
||||
return reflectedDescription;
|
||||
}
|
||||
}
|
||||
|
||||
protected UnitPortDescription ReflectedPortDescription(IUnitPort port)
|
||||
{
|
||||
if (port is IUnitInvalidPort)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (port is IUnitInputPort)
|
||||
{
|
||||
if (!reflectedInputDescriptions.TryGetValue(unitType, out var _reflectedInputDescriptions))
|
||||
{
|
||||
_reflectedInputDescriptions = FetchReflectedPortDescriptions<IUnitInputPort>(unitType);
|
||||
reflectedInputDescriptions.Add(unitType, _reflectedInputDescriptions);
|
||||
}
|
||||
|
||||
if (_reflectedInputDescriptions.TryGetValue(port.key, out var portDescription))
|
||||
{
|
||||
return portDescription;
|
||||
}
|
||||
}
|
||||
else if (port is IUnitOutputPort)
|
||||
{
|
||||
if (!reflectedOutputDescriptions.TryGetValue(unitType, out var _reflectedOutputDescriptions))
|
||||
{
|
||||
_reflectedOutputDescriptions = FetchReflectedPortDescriptions<IUnitOutputPort>(unitType);
|
||||
reflectedOutputDescriptions.Add(unitType, _reflectedOutputDescriptions);
|
||||
}
|
||||
|
||||
if (_reflectedOutputDescriptions.TryGetValue(port.key, out var portDescription))
|
||||
{
|
||||
return portDescription;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static readonly Dictionary<Type, UnitDescription> reflectedDescriptions = new Dictionary<Type, UnitDescription>();
|
||||
|
||||
private static readonly Dictionary<Type, Dictionary<string, UnitPortDescription>> reflectedInputDescriptions = new Dictionary<Type, Dictionary<string, UnitPortDescription>>();
|
||||
|
||||
private static readonly Dictionary<Type, Dictionary<string, UnitPortDescription>> reflectedOutputDescriptions = new Dictionary<Type, Dictionary<string, UnitPortDescription>>();
|
||||
|
||||
private static UnitDescription FetchReflectedDescription(Type unitType)
|
||||
{
|
||||
var oldName = BoltFlowNameUtility.UnitPreviousTitle(unitType);
|
||||
var prefix = string.IsNullOrEmpty(oldName) ? string.Empty : $"(Previously named {oldName}) ";
|
||||
|
||||
return new UnitDescription()
|
||||
{
|
||||
title = BoltFlowNameUtility.UnitTitle(unitType, false, true),
|
||||
shortTitle = BoltFlowNameUtility.UnitTitle(unitType, true, true),
|
||||
surtitle = unitType.GetAttribute<UnitSurtitleAttribute>()?.surtitle,
|
||||
subtitle = unitType.GetAttribute<UnitSubtitleAttribute>()?.subtitle,
|
||||
summary = prefix + unitType.Summary()
|
||||
};
|
||||
}
|
||||
|
||||
private static Dictionary<string, UnitPortDescription> FetchReflectedPortDescriptions<T>(Type unitType) where T : IUnitPort
|
||||
{
|
||||
var descriptions = new Dictionary<string, UnitPortDescription>();
|
||||
|
||||
foreach (var portMember in unitType.GetMembers().Where(member => typeof(T).IsAssignableFrom(member.GetAccessorType())))
|
||||
{
|
||||
var key = portMember.GetAttribute<PortKeyAttribute>()?.key ?? portMember.Name;
|
||||
|
||||
if (descriptions.ContainsKey(key))
|
||||
{
|
||||
Debug.LogWarning("Duplicate reflected port description for: " + key);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
descriptions.Add(key, FetchReflectedPortDescription(portMember));
|
||||
}
|
||||
|
||||
return descriptions;
|
||||
}
|
||||
|
||||
private static UnitPortDescription FetchReflectedPortDescription(MemberInfo portMember)
|
||||
{
|
||||
return new UnitPortDescription()
|
||||
{
|
||||
label = portMember.GetAttribute<PortLabelAttribute>()?.label ?? portMember.HumanName(),
|
||||
showLabel = !(portMember.HasAttribute<PortLabelHiddenAttribute>() || (portMember.GetAttribute<PortLabelAttribute>()?.hidden ?? false)),
|
||||
summary = portMember.Summary(),
|
||||
getMetadata = (unitMetadata) => unitMetadata[portMember.Name]
|
||||
};
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Description
|
||||
|
||||
[Assigns]
|
||||
public sealed override string Title()
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case State.Defined: return DefinedTitle();
|
||||
case State.NotDefined: return DefaultTitle();
|
||||
case State.FailedToDefine: return ErrorTitle(unit.definitionException);
|
||||
default: throw new UnexpectedEnumValueException<State>(state);
|
||||
}
|
||||
}
|
||||
|
||||
[Assigns]
|
||||
public string ShortTitle()
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case State.Defined: return DefinedShortTitle();
|
||||
case State.NotDefined: return DefaultShortTitle();
|
||||
case State.FailedToDefine: return ErrorShortTitle(unit.definitionException);
|
||||
default: throw new UnexpectedEnumValueException<State>(state);
|
||||
}
|
||||
}
|
||||
|
||||
[Assigns]
|
||||
public string Surtitle()
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case State.Defined: return DefinedSurtitle();
|
||||
case State.NotDefined: return DefaultSurtitle();
|
||||
case State.FailedToDefine: return ErrorSurtitle(unit.definitionException);
|
||||
default: throw new UnexpectedEnumValueException<State>(state);
|
||||
}
|
||||
}
|
||||
|
||||
[Assigns]
|
||||
public string Subtitle()
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case State.Defined: return DefinedSubtitle();
|
||||
case State.NotDefined: return DefaultSubtitle();
|
||||
case State.FailedToDefine: return ErrorSubtitle(unit.definitionException);
|
||||
default: throw new UnexpectedEnumValueException<State>(state);
|
||||
}
|
||||
}
|
||||
|
||||
[Assigns]
|
||||
public sealed override string Summary()
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case State.Defined: return DefinedSummary();
|
||||
case State.NotDefined: return DefaultSummary();
|
||||
case State.FailedToDefine: return ErrorSummary(unit.definitionException);
|
||||
default: throw new UnexpectedEnumValueException<State>(state);
|
||||
}
|
||||
}
|
||||
|
||||
[Assigns]
|
||||
[RequiresUnityAPI]
|
||||
public sealed override EditorTexture Icon()
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case State.Defined: return DefinedIcon();
|
||||
case State.NotDefined: return DefaultIcon();
|
||||
case State.FailedToDefine: return ErrorIcon(unit.definitionException);
|
||||
default: throw new UnexpectedEnumValueException<State>(state);
|
||||
}
|
||||
}
|
||||
|
||||
[Assigns]
|
||||
[RequiresUnityAPI]
|
||||
public IEnumerable<EditorTexture> Icons()
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case State.Defined: return DefinedIcons();
|
||||
case State.NotDefined: return DefaultIcons();
|
||||
case State.FailedToDefine: return ErrorIcons(unit.definitionException);
|
||||
default: throw new UnexpectedEnumValueException<State>(state);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual string DefinedTitle()
|
||||
{
|
||||
return reflectedDescription.title;
|
||||
}
|
||||
|
||||
protected virtual string DefaultTitle()
|
||||
{
|
||||
return reflectedDescription.title;
|
||||
}
|
||||
|
||||
protected virtual string ErrorTitle(Exception exception)
|
||||
{
|
||||
return reflectedDescription.title;
|
||||
}
|
||||
|
||||
protected virtual string DefinedShortTitle()
|
||||
{
|
||||
return reflectedDescription.shortTitle;
|
||||
}
|
||||
|
||||
protected virtual string DefaultShortTitle()
|
||||
{
|
||||
return reflectedDescription.shortTitle;
|
||||
}
|
||||
|
||||
protected virtual string ErrorShortTitle(Exception exception)
|
||||
{
|
||||
return ErrorTitle(exception);
|
||||
}
|
||||
|
||||
protected virtual string DefinedSurtitle()
|
||||
{
|
||||
return reflectedDescription.surtitle;
|
||||
}
|
||||
|
||||
protected virtual string DefaultSurtitle()
|
||||
{
|
||||
return reflectedDescription.surtitle;
|
||||
}
|
||||
|
||||
protected virtual string ErrorSurtitle(Exception exception)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
protected virtual string DefinedSubtitle()
|
||||
{
|
||||
return reflectedDescription.subtitle;
|
||||
}
|
||||
|
||||
protected virtual string DefaultSubtitle()
|
||||
{
|
||||
return reflectedDescription.subtitle;
|
||||
}
|
||||
|
||||
protected virtual string ErrorSubtitle(Exception exception)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
protected virtual string DefinedSummary()
|
||||
{
|
||||
return reflectedDescription.summary;
|
||||
}
|
||||
|
||||
protected virtual string DefaultSummary()
|
||||
{
|
||||
return reflectedDescription.summary;
|
||||
}
|
||||
|
||||
protected virtual string ErrorSummary(Exception exception)
|
||||
{
|
||||
return $"This node failed to define.\n\n{exception.DisplayName()}: {exception.Message}";
|
||||
}
|
||||
|
||||
protected virtual EditorTexture DefinedIcon()
|
||||
{
|
||||
return unit.GetType().Icon();
|
||||
}
|
||||
|
||||
protected virtual EditorTexture DefaultIcon()
|
||||
{
|
||||
return unit.GetType().Icon();
|
||||
}
|
||||
|
||||
protected virtual EditorTexture ErrorIcon(Exception exception)
|
||||
{
|
||||
return BoltCore.Icons.errorState;
|
||||
}
|
||||
|
||||
protected virtual IEnumerable<EditorTexture> DefinedIcons()
|
||||
{
|
||||
return Enumerable.Empty<EditorTexture>();
|
||||
}
|
||||
|
||||
protected virtual IEnumerable<EditorTexture> DefaultIcons()
|
||||
{
|
||||
return Enumerable.Empty<EditorTexture>();
|
||||
}
|
||||
|
||||
protected virtual IEnumerable<EditorTexture> ErrorIcons(Exception exception)
|
||||
{
|
||||
return Enumerable.Empty<EditorTexture>();
|
||||
}
|
||||
|
||||
public void DescribePort(IUnitPort port, UnitPortDescription description)
|
||||
{
|
||||
description.getMetadata = (unitMetadata) => unitMetadata.StaticObject(port);
|
||||
|
||||
// Only defined nodes can have specific ports
|
||||
if (state == State.Defined)
|
||||
{
|
||||
DefinedPort(port, description);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void DefinedPort(IUnitPort port, UnitPortDescription description)
|
||||
{
|
||||
var reflectedPortDescription = ReflectedPortDescription(port);
|
||||
|
||||
if (reflectedPortDescription != null)
|
||||
{
|
||||
description.CopyFrom(reflectedPortDescription);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 66a77230ee8e44f3f917beab188d7ba2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,79 @@
|
||||
using System;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
public sealed class UnitPortDescription : IDescription
|
||||
{
|
||||
private string _label;
|
||||
|
||||
private bool _isLabelVisible = true;
|
||||
|
||||
internal IUnitPort portType;
|
||||
|
||||
public EditorTexture icon
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_icon == null || !_icon.IsValid())
|
||||
{
|
||||
_icon = GetIcon(portType);
|
||||
}
|
||||
|
||||
return _icon;
|
||||
}
|
||||
set => _icon = value;
|
||||
}
|
||||
|
||||
private EditorTexture _icon;
|
||||
|
||||
public string fallbackLabel { get; set; }
|
||||
|
||||
public string label
|
||||
{
|
||||
get => _label ?? fallbackLabel;
|
||||
set => _label = value;
|
||||
}
|
||||
|
||||
public bool showLabel
|
||||
{
|
||||
get => !BoltFlow.Configuration.hidePortLabels || _isLabelVisible;
|
||||
set => _isLabelVisible = value;
|
||||
}
|
||||
|
||||
string IDescription.title => label;
|
||||
|
||||
public string summary { get; set; }
|
||||
|
||||
public Func<Metadata, Metadata> getMetadata { get; set; }
|
||||
|
||||
public void CopyFrom(UnitPortDescription other)
|
||||
{
|
||||
_label = other._label;
|
||||
_isLabelVisible = other._isLabelVisible;
|
||||
summary = other.summary;
|
||||
portType = other.portType ?? portType;
|
||||
getMetadata = other.getMetadata ?? getMetadata;
|
||||
}
|
||||
|
||||
private static EditorTexture GetIcon(IUnitPort portType)
|
||||
{
|
||||
if (portType is IUnitControlPort)
|
||||
{
|
||||
return typeof(Flow).Icon();
|
||||
}
|
||||
else if (portType is IUnitValuePort)
|
||||
{
|
||||
return Icons.Type(((IUnitValuePort)portType).type);
|
||||
}
|
||||
else if (portType is IUnitInvalidPort)
|
||||
{
|
||||
return BoltCore.Resources.icons.errorState;
|
||||
}
|
||||
else
|
||||
{
|
||||
// throw new NotSupportedException();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 51835fa842102474c83eeea00b0602aa
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,44 @@
|
||||
using System;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Descriptor(typeof(IUnitPort))]
|
||||
public sealed class UnitPortDescriptor : IDescriptor
|
||||
{
|
||||
public UnitPortDescriptor(IUnitPort target)
|
||||
{
|
||||
Ensure.That(nameof(target)).IsNotNull(target);
|
||||
|
||||
this.target = target;
|
||||
|
||||
description.portType = target;
|
||||
}
|
||||
|
||||
public IUnitPort target { get; }
|
||||
|
||||
object IDescriptor.target => target;
|
||||
|
||||
public UnitPortDescription description { get; private set; } = new UnitPortDescription();
|
||||
|
||||
IDescription IDescriptor.description => description;
|
||||
|
||||
public bool isDirty { get; set; } = true;
|
||||
|
||||
public void Validate()
|
||||
{
|
||||
if (isDirty)
|
||||
{
|
||||
isDirty = false;
|
||||
|
||||
description.fallbackLabel = target.key.Filter(symbols: false, punctuation: false).Prettify();
|
||||
|
||||
description.portType = target;
|
||||
|
||||
target.unit?.Descriptor<IUnitDescriptor>().DescribePort(target, description);
|
||||
|
||||
// No DescriptionAssignment is run, so we'll just always assume that the description changes.
|
||||
DescriptorProvider.instance.TriggerDescriptionChange(target);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0a272fe91f6be43dfb94b0c752db3a9c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bc884dcacf46c4fd28fe9c7e605b46b4
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,25 @@
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Descriptor(typeof(CustomEvent))]
|
||||
public class CustomEventDescriptor : EventUnitDescriptor<CustomEvent>
|
||||
{
|
||||
public CustomEventDescriptor(CustomEvent @event) : base(@event) { }
|
||||
|
||||
protected override string DefinedSubtitle()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
protected override void DefinedPort(IUnitPort port, UnitPortDescription description)
|
||||
{
|
||||
base.DefinedPort(port, description);
|
||||
|
||||
var index = unit.argumentPorts.IndexOf(port as ValueOutput);
|
||||
|
||||
if (index >= 0)
|
||||
{
|
||||
description.label = "Arg. " + index;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d86368fa2dad24d53acbed4e9df50329
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,24 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Descriptor(typeof(IEventUnit))]
|
||||
public class EventUnitDescriptor<TEvent> : UnitDescriptor<TEvent>
|
||||
where TEvent : class, IEventUnit
|
||||
{
|
||||
public EventUnitDescriptor(TEvent @event) : base(@event) { }
|
||||
|
||||
protected override string DefinedSubtitle()
|
||||
{
|
||||
return "Event";
|
||||
}
|
||||
|
||||
protected override IEnumerable<EditorTexture> DefinedIcons()
|
||||
{
|
||||
if (unit.coroutine)
|
||||
{
|
||||
yield return BoltFlow.Icons.coroutine;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 19496281535914fd8a7a96092a40fa01
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Widget(typeof(IEventUnit))]
|
||||
public sealed class EventUnitWidget : UnitWidget<IEventUnit>
|
||||
{
|
||||
public EventUnitWidget(FlowCanvas canvas, IEventUnit unit) : base(canvas, unit) { }
|
||||
|
||||
protected override NodeColorMix baseColor => NodeColor.Green;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 59a20dbcb66df4db5ae49b183017d4ec
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,13 @@
|
||||
using UnityEditor;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[CustomEditor(typeof(GlobalMessageListener), true)]
|
||||
public class GlobalMessageListenerEditor : Editor
|
||||
{
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
EditorGUILayout.HelpBox("This component is automatically added to relay Unity messages to Visual Scripting.", MessageType.Info);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 55b2c0b7bf4f34c8d957d908911e5f4f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,13 @@
|
||||
using UnityEditor;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[CustomEditor(typeof(MessageListener), true)]
|
||||
public class MessageListenerEditor : Editor
|
||||
{
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
EditorGUILayout.HelpBox("This component is automatically added to relay Unity messages to Visual Scripting.", MessageType.Info);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 80dec885f050a4915a36ab2aeba5754f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,20 @@
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Descriptor(typeof(TriggerCustomEvent))]
|
||||
public class TriggerCustomEventDescriptor : UnitDescriptor<TriggerCustomEvent>
|
||||
{
|
||||
public TriggerCustomEventDescriptor(TriggerCustomEvent trigger) : base(trigger) { }
|
||||
|
||||
protected override void DefinedPort(IUnitPort port, UnitPortDescription description)
|
||||
{
|
||||
base.DefinedPort(port, description);
|
||||
|
||||
var index = unit.arguments.IndexOf(port as ValueInput);
|
||||
|
||||
if (index >= 0)
|
||||
{
|
||||
description.label = "Arg. " + index;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 60210ddff070d4317a631c12b354cd23
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,495 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityObject = UnityEngine.Object;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Canvas(typeof(FlowGraph))]
|
||||
public sealed class FlowCanvas : VisualScriptingCanvas<FlowGraph>
|
||||
{
|
||||
public FlowCanvas(FlowGraph graph) : base(graph) { }
|
||||
|
||||
|
||||
#region Clipboard
|
||||
|
||||
public override void ShrinkCopyGroup(HashSet<IGraphElement> copyGroup)
|
||||
{
|
||||
copyGroup.RemoveWhere(element =>
|
||||
{
|
||||
if (element is IUnitConnection)
|
||||
{
|
||||
var connection = (IUnitConnection)element;
|
||||
|
||||
if (!copyGroup.Contains(connection.source.unit) ||
|
||||
!copyGroup.Contains(connection.destination.unit))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Window
|
||||
|
||||
public override void OnToolbarGUI()
|
||||
{
|
||||
showRelations = GUILayout.Toggle(showRelations, "Relations", LudiqStyles.toolbarButton);
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
|
||||
BoltFlow.Configuration.showConnectionValues = GUILayout.Toggle(BoltFlow.Configuration.showConnectionValues, "Values", LudiqStyles.toolbarButton);
|
||||
|
||||
BoltCore.Configuration.dimInactiveNodes = GUILayout.Toggle(BoltCore.Configuration.dimInactiveNodes, "Dim", LudiqStyles.toolbarButton);
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
BoltFlow.Configuration.Save();
|
||||
|
||||
BoltCore.Configuration.Save();
|
||||
}
|
||||
|
||||
base.OnToolbarGUI();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region View
|
||||
|
||||
protected override bool shouldEdgePan => base.shouldEdgePan || isCreatingConnection;
|
||||
|
||||
public const float inspectorZoomThreshold = 0.7f;
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Lifecycle
|
||||
|
||||
public override void Close()
|
||||
{
|
||||
base.Close();
|
||||
|
||||
CancelConnection();
|
||||
}
|
||||
|
||||
protected override void HandleHighPriorityInput()
|
||||
{
|
||||
if (isCreatingConnection)
|
||||
{
|
||||
if (e.IsMouseDown(MouseButton.Left))
|
||||
{
|
||||
connectionEnd = mousePosition;
|
||||
NewUnitContextual();
|
||||
e.Use();
|
||||
}
|
||||
else if (e.IsFree(EventType.KeyDown) && e.keyCode == KeyCode.Escape)
|
||||
{
|
||||
CancelConnection();
|
||||
e.Use();
|
||||
}
|
||||
}
|
||||
|
||||
base.HandleHighPriorityInput();
|
||||
}
|
||||
|
||||
private void CompleteContextualConnection(IUnitPort source, IUnitPort destination)
|
||||
{
|
||||
source.ValidlyConnectTo(destination);
|
||||
Cache();
|
||||
var unitPosition = this.Widget<IUnitWidget>(destination.unit).position.position;
|
||||
var portPosition = this.Widget<IUnitPortWidget>(destination).handlePosition.center.PixelPerfect();
|
||||
var offset = portPosition - unitPosition;
|
||||
destination.unit.position -= offset;
|
||||
this.Widget(destination.unit).Reposition();
|
||||
connectionSource = null;
|
||||
GUI.changed = true;
|
||||
}
|
||||
|
||||
public void NewUnitContextual()
|
||||
{
|
||||
var filter = UnitOptionFilter.Any;
|
||||
filter.GraphHashCode = graph.GetHashCode();
|
||||
|
||||
if (connectionSource is ValueInput)
|
||||
{
|
||||
var valueInput = (ValueInput)connectionSource;
|
||||
filter.CompatibleOutputType = valueInput.type;
|
||||
filter.Expose = false;
|
||||
filter.NoConnection = false;
|
||||
NewUnit(mousePosition, GetNewUnitOptions(filter), (unit) => CompleteContextualConnection(valueInput, unit.CompatibleValueOutput(valueInput.type)));
|
||||
}
|
||||
else if (connectionSource is ValueOutput)
|
||||
{
|
||||
var valueOutput = (ValueOutput)connectionSource;
|
||||
filter.CompatibleInputType = valueOutput.type;
|
||||
filter.NoConnection = false;
|
||||
NewUnit(mousePosition, GetNewUnitOptions(filter), (unit) => CompleteContextualConnection(valueOutput, unit.CompatibleValueInput(valueOutput.type)));
|
||||
}
|
||||
else if (connectionSource is ControlInput)
|
||||
{
|
||||
var controlInput = (ControlInput)connectionSource;
|
||||
filter.NoControlOutput = false;
|
||||
filter.NoConnection = false;
|
||||
NewUnit(mousePosition, GetNewUnitOptions(filter), (unit) => CompleteContextualConnection(controlInput, unit.controlOutputs.First()));
|
||||
}
|
||||
else if (connectionSource is ControlOutput)
|
||||
{
|
||||
var controlOutput = (ControlOutput)connectionSource;
|
||||
filter.NoControlInput = false;
|
||||
filter.NoConnection = false;
|
||||
NewUnit(mousePosition, GetNewUnitOptions(filter), (unit) => CompleteContextualConnection(controlOutput, unit.controlInputs.First()));
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Context
|
||||
|
||||
protected override void OnContext()
|
||||
{
|
||||
if (isCreatingConnection)
|
||||
{
|
||||
CancelConnection();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Checking for Alt seems to lose focus, for some reason maybe
|
||||
// unrelated to Bolt. Shift or other modifiers seem to work though.
|
||||
if (base.GetContextOptions().Any() && (!BoltFlow.Configuration.skipContextMenu || e.shift))
|
||||
{
|
||||
base.OnContext();
|
||||
}
|
||||
else
|
||||
{
|
||||
NewUnit(mousePosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override IEnumerable<DropdownOption> GetContextOptions()
|
||||
{
|
||||
yield return new DropdownOption((Action<Vector2>)(NewUnit), "Add Node...");
|
||||
yield return new DropdownOption((Action<Vector2>)(NewSticky), "Create Sticky Note");
|
||||
foreach (var baseOption in base.GetContextOptions())
|
||||
{
|
||||
yield return baseOption;
|
||||
}
|
||||
}
|
||||
|
||||
public void AddUnit(IUnit unit, Vector2 position)
|
||||
{
|
||||
UndoUtility.RecordEditedObject("Create Node");
|
||||
unit.guid = Guid.NewGuid();
|
||||
unit.position = position.PixelPerfect();
|
||||
graph.units.Add(unit);
|
||||
selection.Select(unit);
|
||||
GUI.changed = true;
|
||||
}
|
||||
|
||||
private UnitOptionTree GetNewUnitOptions(UnitOptionFilter filter)
|
||||
{
|
||||
var options = new UnitOptionTree(new GUIContent("Node"));
|
||||
|
||||
options.filter = filter;
|
||||
options.reference = reference;
|
||||
|
||||
if (filter.CompatibleOutputType == typeof(object))
|
||||
{
|
||||
options.surfaceCommonTypeLiterals = true;
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
private void NewSticky(Vector2 position)
|
||||
{
|
||||
UndoUtility.RecordEditedObject("Create Sticky Note");
|
||||
var stickyNote = new StickyNote() { position = new Rect(position, new Vector2(100, 100)) };
|
||||
graph.elements.Add(stickyNote);
|
||||
selection.Select(stickyNote);
|
||||
GUI.changed = true;
|
||||
}
|
||||
|
||||
private void NewUnit(Vector2 position)
|
||||
{
|
||||
var filter = UnitOptionFilter.Any;
|
||||
filter.GraphHashCode = graph.GetHashCode();
|
||||
NewUnit(position, GetNewUnitOptions(filter));
|
||||
}
|
||||
|
||||
private void NewUnit(Vector2 unitPosition, UnitOptionTree options, Action<IUnit> then = null)
|
||||
{
|
||||
delayCall += () =>
|
||||
{
|
||||
var activatorPosition = new Rect(e.mousePosition, new Vector2(200, 1));
|
||||
|
||||
var context = this.context;
|
||||
|
||||
LudiqGUI.FuzzyDropdown
|
||||
(
|
||||
activatorPosition,
|
||||
options,
|
||||
null,
|
||||
delegate (object _option)
|
||||
{
|
||||
context.BeginEdit();
|
||||
if (_option is IUnitOption)
|
||||
{
|
||||
var option = (IUnitOption)_option;
|
||||
var unit = option.InstantiateUnit();
|
||||
AddUnit(unit, unitPosition);
|
||||
option.PreconfigureUnit(unit);
|
||||
then?.Invoke(unit);
|
||||
GUI.changed = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((Type)_option == typeof(StickyNote))
|
||||
{
|
||||
NewSticky(unitPosition);
|
||||
}
|
||||
}
|
||||
|
||||
context.EndEdit();
|
||||
}
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Drag & Drop
|
||||
|
||||
private bool CanDetermineDraggedInput(UnityObject uo)
|
||||
{
|
||||
if (uo.IsSceneBound())
|
||||
{
|
||||
if (reference.self == uo.GameObject())
|
||||
{
|
||||
// Because we'll be able to assign it to Self
|
||||
return true;
|
||||
}
|
||||
|
||||
if (reference.serializedObject.IsSceneBound())
|
||||
{
|
||||
// Because we'll be able to use a direct scene reference
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool AcceptsDragAndDrop()
|
||||
{
|
||||
if (DragAndDropUtility.Is<ScriptGraphAsset>())
|
||||
{
|
||||
return FlowDragAndDropUtility.AcceptsScript(graph);
|
||||
}
|
||||
|
||||
return DragAndDropUtility.Is<UnityObject>() && !DragAndDropUtility.Is<IMacro>() && CanDetermineDraggedInput(DragAndDropUtility.Get<UnityObject>())
|
||||
|| EditorVariablesUtility.isDraggingVariable;
|
||||
}
|
||||
|
||||
public override void PerformDragAndDrop()
|
||||
{
|
||||
if (DragAndDropUtility.Is<ScriptGraphAsset>())
|
||||
{
|
||||
var flowMacro = DragAndDropUtility.Get<ScriptGraphAsset>();
|
||||
var superUnit = new SubgraphUnit(flowMacro);
|
||||
AddUnit(superUnit, DragAndDropUtility.position);
|
||||
}
|
||||
else if (DragAndDropUtility.Is<UnityObject>())
|
||||
{
|
||||
var uo = DragAndDropUtility.Get<UnityObject>();
|
||||
var type = uo.GetType();
|
||||
var filter = UnitOptionFilter.Any;
|
||||
filter.Literals = false;
|
||||
filter.Expose = false;
|
||||
var options = GetNewUnitOptions(filter);
|
||||
|
||||
var root = new List<object>();
|
||||
|
||||
if (!uo.IsSceneBound() || reference.serializedObject.IsSceneBound())
|
||||
{
|
||||
if (uo == reference.self)
|
||||
{
|
||||
root.Add(new UnitOption<This>(new This()));
|
||||
}
|
||||
|
||||
root.Add(new LiteralOption(new Literal(type, uo)));
|
||||
}
|
||||
|
||||
if (uo is MonoScript script)
|
||||
{
|
||||
var scriptType = script.GetClass();
|
||||
|
||||
if (scriptType != null)
|
||||
{
|
||||
root.Add(scriptType);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
root.Add(type);
|
||||
}
|
||||
|
||||
if (uo is GameObject)
|
||||
{
|
||||
root.AddRange(uo.GetComponents<Component>().Select(c => c.GetType()));
|
||||
}
|
||||
|
||||
options.rootOverride = root.ToArray();
|
||||
|
||||
NewUnit(DragAndDropUtility.position, options, (unit) =>
|
||||
{
|
||||
// Try to assign a correct input
|
||||
var compatibleInput = unit.CompatibleValueInput(type);
|
||||
|
||||
if (compatibleInput == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (uo.IsSceneBound())
|
||||
{
|
||||
if (reference.self == uo.GameObject())
|
||||
{
|
||||
// The component is owned by the same game object as the graph.
|
||||
|
||||
if (compatibleInput.nullMeansSelf)
|
||||
{
|
||||
compatibleInput.SetDefaultValue(null);
|
||||
}
|
||||
else
|
||||
{
|
||||
var self = new This();
|
||||
self.position = unit.position + new Vector2(-150, 19);
|
||||
graph.units.Add(self);
|
||||
self.self.ConnectToValid(compatibleInput);
|
||||
}
|
||||
}
|
||||
else if (reference.serializedObject.IsSceneBound())
|
||||
{
|
||||
// The component is from another object from the same scene
|
||||
compatibleInput.SetDefaultValue(uo.ConvertTo(compatibleInput.type));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotSupportedException("Cannot determine compatible input from dragged Unity object.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
compatibleInput.SetDefaultValue(uo.ConvertTo(compatibleInput.type));
|
||||
}
|
||||
});
|
||||
}
|
||||
else if (EditorVariablesUtility.isDraggingVariable)
|
||||
{
|
||||
var kind = EditorVariablesUtility.kind;
|
||||
var declaration = EditorVariablesUtility.declaration;
|
||||
|
||||
UnifiedVariableUnit unit;
|
||||
|
||||
if (e.alt)
|
||||
{
|
||||
unit = new SetVariable();
|
||||
}
|
||||
else if (e.shift)
|
||||
{
|
||||
unit = new IsVariableDefined();
|
||||
}
|
||||
else
|
||||
{
|
||||
unit = new GetVariable();
|
||||
}
|
||||
|
||||
unit.kind = kind;
|
||||
AddUnit(unit, DragAndDropUtility.position);
|
||||
unit.name.SetDefaultValue(declaration.name);
|
||||
}
|
||||
}
|
||||
|
||||
public override void DrawDragAndDropPreview()
|
||||
{
|
||||
if (DragAndDropUtility.Is<ScriptGraphAsset>())
|
||||
{
|
||||
GraphGUI.DrawDragAndDropPreviewLabel(DragAndDropUtility.offsetedPosition, DragAndDropUtility.Get<ScriptGraphAsset>().name, typeof(ScriptGraphAsset).Icon());
|
||||
}
|
||||
else if (DragAndDropUtility.Is<GameObject>())
|
||||
{
|
||||
var gameObject = DragAndDropUtility.Get<GameObject>();
|
||||
GraphGUI.DrawDragAndDropPreviewLabel(DragAndDropUtility.offsetedPosition, gameObject.name + "...", gameObject.Icon());
|
||||
}
|
||||
else if (DragAndDropUtility.Is<UnityObject>())
|
||||
{
|
||||
var obj = DragAndDropUtility.Get<UnityObject>();
|
||||
var type = obj.GetType();
|
||||
GraphGUI.DrawDragAndDropPreviewLabel(DragAndDropUtility.offsetedPosition, type.HumanName() + "...", type.Icon());
|
||||
}
|
||||
else if (EditorVariablesUtility.isDraggingVariable)
|
||||
{
|
||||
var kind = EditorVariablesUtility.kind;
|
||||
var name = EditorVariablesUtility.declaration.name;
|
||||
|
||||
string label;
|
||||
|
||||
if (e.alt)
|
||||
{
|
||||
label = $"Set {name}";
|
||||
}
|
||||
else if (e.shift)
|
||||
{
|
||||
label = $"Check if {name} is defined";
|
||||
}
|
||||
else
|
||||
{
|
||||
label = $"Get {name}";
|
||||
}
|
||||
|
||||
GraphGUI.DrawDragAndDropPreviewLabel(DragAndDropUtility.offsetedPosition, label, BoltCore.Icons.VariableKind(kind));
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Drawing
|
||||
|
||||
public bool showRelations { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
#region Connection Creation
|
||||
|
||||
public IUnitPort connectionSource { get; set; }
|
||||
|
||||
public Vector2 connectionEnd { get; set; }
|
||||
|
||||
public bool isCreatingConnection => connectionSource != null &&
|
||||
connectionSource.unit != null; // Make sure the port didn't get destroyed: https://support.ludiq.io/communities/5/topics/4034-x
|
||||
|
||||
public void CancelConnection()
|
||||
{
|
||||
connectionSource = null;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8a0959959a3a749c2aceb5082a6cf1c7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,13 @@
|
||||
using UnityEditor;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
public static class FlowDragAndDropUtility
|
||||
{
|
||||
public static bool AcceptsScript(IGraph graph)
|
||||
{
|
||||
// Can't drag a graph into itself
|
||||
return DragAndDrop.objectReferences[0] is ScriptGraphAsset graphAsset && graph != graphAsset.graph;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7ef5652404544c8cab2b662e003e8766
|
||||
timeCreated: 1612898755
|
||||
@@ -0,0 +1,26 @@
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[InitializeAfterPlugins]
|
||||
public static class FlowEditorBindings
|
||||
{
|
||||
static FlowEditorBindings()
|
||||
{
|
||||
Flow.isInspectedBinding = IsInspected;
|
||||
}
|
||||
|
||||
private static bool IsInspected(GraphPointer pointer)
|
||||
{
|
||||
Ensure.That(nameof(pointer)).IsNotNull(pointer);
|
||||
|
||||
foreach (var graphWindow in GraphWindow.tabsNoAlloc)
|
||||
{
|
||||
if (graphWindow.reference?.InstanceEquals(pointer) ?? false)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2f474ced62820425d9936932e5e28161
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,18 @@
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[GraphContext(typeof(FlowGraph))]
|
||||
public class FlowGraphContext : GraphContext<FlowGraph, FlowCanvas>
|
||||
{
|
||||
public FlowGraphContext(GraphReference reference) : base(reference) { }
|
||||
|
||||
public override string windowTitle => "Script Graph";
|
||||
|
||||
protected override IEnumerable<ISidebarPanelContent> SidebarPanels()
|
||||
{
|
||||
yield return new GraphInspectorPanel(this);
|
||||
yield return new VariablesPanel(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b73918c69dc7a46a7889cf2a9e4232a8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,116 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Editor(typeof(FlowGraph))]
|
||||
public class FlowGraphEditor : GraphEditor
|
||||
{
|
||||
public FlowGraphEditor(Metadata metadata) : base(metadata) { }
|
||||
|
||||
private new FlowGraph graph => (FlowGraph)base.graph;
|
||||
|
||||
private Metadata controlInputDefinitionsMetadata => metadata[nameof(FlowGraph.controlInputDefinitions)];
|
||||
private Metadata controlOutputDefinitionsMetadata => metadata[nameof(FlowGraph.controlOutputDefinitions)];
|
||||
private Metadata valueInputDefinitionsMetadata => metadata[nameof(FlowGraph.valueInputDefinitions)];
|
||||
private Metadata valueOutputDefinitionsMetadata => metadata[nameof(FlowGraph.valueOutputDefinitions)];
|
||||
|
||||
private IEnumerable<Warning> warnings => UnitPortDefinitionUtility.Warnings((FlowGraph)metadata.value);
|
||||
|
||||
protected override float GetHeight(float width, GUIContent label)
|
||||
{
|
||||
var height = 0f;
|
||||
|
||||
height += GetHeaderHeight(width);
|
||||
|
||||
height += GetControlInputDefinitionsHeight(width);
|
||||
|
||||
height += EditorGUIUtility.standardVerticalSpacing;
|
||||
|
||||
height += GetControlOutputDefinitionsHeight(width);
|
||||
|
||||
height += EditorGUIUtility.standardVerticalSpacing;
|
||||
|
||||
height += GetValueInputDefinitionsHeight(width);
|
||||
|
||||
height += EditorGUIUtility.standardVerticalSpacing;
|
||||
|
||||
height += GetValueOutputDefinitionsHeight(width);
|
||||
|
||||
if (warnings.Any())
|
||||
{
|
||||
height += EditorGUIUtility.standardVerticalSpacing;
|
||||
|
||||
foreach (var warning in warnings)
|
||||
{
|
||||
height += warning.GetHeight(width);
|
||||
}
|
||||
}
|
||||
|
||||
return height;
|
||||
}
|
||||
|
||||
protected override void OnGUI(Rect position, GUIContent label)
|
||||
{
|
||||
BeginLabeledBlock(metadata, position, label);
|
||||
|
||||
OnHeaderGUI(position);
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
|
||||
LudiqGUI.Inspector(controlInputDefinitionsMetadata, position.VerticalSection(ref y, GetControlInputDefinitionsHeight(position.width)));
|
||||
|
||||
y += EditorGUIUtility.standardVerticalSpacing;
|
||||
|
||||
LudiqGUI.Inspector(controlOutputDefinitionsMetadata, position.VerticalSection(ref y, GetControlOutputDefinitionsHeight(position.width)));
|
||||
|
||||
y += EditorGUIUtility.standardVerticalSpacing;
|
||||
|
||||
LudiqGUI.Inspector(valueInputDefinitionsMetadata, position.VerticalSection(ref y, GetValueInputDefinitionsHeight(position.width)));
|
||||
|
||||
y += EditorGUIUtility.standardVerticalSpacing;
|
||||
|
||||
LudiqGUI.Inspector(valueOutputDefinitionsMetadata, position.VerticalSection(ref y, GetValueOutputDefinitionsHeight(position.width)));
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
graph.PortDefinitionsChanged();
|
||||
}
|
||||
|
||||
if (warnings.Any())
|
||||
{
|
||||
y += EditorGUIUtility.standardVerticalSpacing;
|
||||
|
||||
foreach (var warning in warnings)
|
||||
{
|
||||
y--;
|
||||
warning.OnGUI(position.VerticalSection(ref y, warning.GetHeight(position.width) + 1));
|
||||
}
|
||||
}
|
||||
|
||||
EndBlock(metadata);
|
||||
}
|
||||
|
||||
private float GetControlInputDefinitionsHeight(float width)
|
||||
{
|
||||
return LudiqGUI.GetInspectorHeight(this, controlInputDefinitionsMetadata, width);
|
||||
}
|
||||
|
||||
private float GetControlOutputDefinitionsHeight(float width)
|
||||
{
|
||||
return LudiqGUI.GetInspectorHeight(this, controlOutputDefinitionsMetadata, width);
|
||||
}
|
||||
|
||||
private float GetValueInputDefinitionsHeight(float width)
|
||||
{
|
||||
return LudiqGUI.GetInspectorHeight(this, valueInputDefinitionsMetadata, width);
|
||||
}
|
||||
|
||||
private float GetValueOutputDefinitionsHeight(float width)
|
||||
{
|
||||
return LudiqGUI.GetInspectorHeight(this, valueOutputDefinitionsMetadata, width);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 88d0a1ad859d8469b94fecac8c36866d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,61 @@
|
||||
#if VISUAL_SCRIPT_INTERNAL
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Unity.VisualScripting;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
public class FlowGraphUnitUISample : RuntimeFlowGraph
|
||||
{
|
||||
[MenuItem("Tools/Visual Scripting/Internal/Create Node UI Samples", priority = LudiqProduct.DeveloperToolsMenuPriority + 403)]
|
||||
|
||||
public static void CreateUnitUISamples()
|
||||
{
|
||||
(new FlowGraphUnitUISample()).CreateGraphUISample();
|
||||
}
|
||||
|
||||
private void CreateGraphUISample()
|
||||
{
|
||||
CreateGraph();
|
||||
|
||||
IEnumerable<Type> GetEventUnitTypes() => AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes().Where(t => typeof(IUnit).IsAssignableFrom(t))).Where(t => t.IsClass && !t.IsAbstract);
|
||||
|
||||
Vector2 position = Vector2.zero;
|
||||
|
||||
int index = 0;
|
||||
|
||||
foreach (var unitType in GetEventUnitTypes())
|
||||
{
|
||||
try
|
||||
{
|
||||
string name = unitType.Assembly.GetName().Name;
|
||||
string space = unitType.FullName;
|
||||
|
||||
var unit = Activator.CreateInstance(name, space);
|
||||
|
||||
IUnit b = (IUnit)unit.Unwrap();
|
||||
|
||||
b.position = position;
|
||||
|
||||
if (index % 10 == 0)
|
||||
{
|
||||
position.x = 0;
|
||||
position.y += 180;
|
||||
}
|
||||
|
||||
position.x += 180;
|
||||
|
||||
AddUnit(b, position);
|
||||
|
||||
index++;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b1b39c71b073f4269acc255452659ff3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Editor(typeof(ScriptMachine))]
|
||||
public class FlowMachineEditor : MachineEditor
|
||||
{
|
||||
public FlowMachineEditor(Metadata metadata) : base(metadata) { }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e5469618019ff476db0e9a02c0c3f432
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 263ad70d08f1443a98e957c081b172a5
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8bacd8e244a98460fb44204788e98cf4
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,40 @@
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Descriptor(typeof(CreateStruct))]
|
||||
public class CreateStructDescriptor : UnitDescriptor<CreateStruct>
|
||||
{
|
||||
public CreateStructDescriptor(CreateStruct unit) : base(unit) { }
|
||||
|
||||
protected override string DefinedTitle()
|
||||
{
|
||||
if (BoltCore.Configuration.humanNaming)
|
||||
{
|
||||
return $"Create {unit.type.HumanName()}";
|
||||
}
|
||||
else
|
||||
{
|
||||
return $"new {unit.type.CSharpName()}";
|
||||
}
|
||||
}
|
||||
|
||||
protected override string DefinedShortTitle()
|
||||
{
|
||||
return BoltCore.Configuration.humanNaming ? "Create" : "new";
|
||||
}
|
||||
|
||||
protected override string DefinedSurtitle()
|
||||
{
|
||||
return unit.type.DisplayName();
|
||||
}
|
||||
|
||||
protected override string DefinedSummary()
|
||||
{
|
||||
return unit.type.Summary();
|
||||
}
|
||||
|
||||
protected override EditorTexture DefinedIcon()
|
||||
{
|
||||
return unit.type.Icon();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4eda0cc90c769438e8a22e872e15bf9a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,75 @@
|
||||
using System;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[FuzzyOption(typeof(CreateStruct))]
|
||||
public class CreateStructOption : UnitOption<CreateStruct>
|
||||
{
|
||||
public CreateStructOption() : base() { }
|
||||
|
||||
public CreateStructOption(CreateStruct unit) : base(unit) { }
|
||||
|
||||
public Type structType { get; private set; }
|
||||
|
||||
protected override void FillFromUnit()
|
||||
{
|
||||
structType = unit.type;
|
||||
base.FillFromUnit();
|
||||
}
|
||||
|
||||
protected override string Label(bool human)
|
||||
{
|
||||
if (human)
|
||||
{
|
||||
return $"Create {structType.HumanName()} ()";
|
||||
}
|
||||
else
|
||||
{
|
||||
return $"new {structType.CSharpName()} ()";
|
||||
}
|
||||
}
|
||||
|
||||
protected override string Haystack(bool human)
|
||||
{
|
||||
if (human)
|
||||
{
|
||||
return $"{structType.HumanName()}: Create {structType.HumanName()}";
|
||||
}
|
||||
else
|
||||
{
|
||||
return $"new {structType.CSharpName()}";
|
||||
}
|
||||
}
|
||||
|
||||
public override string SearchResultLabel(string query)
|
||||
{
|
||||
return base.SearchResultLabel(query) + " ()";
|
||||
}
|
||||
|
||||
protected override int Order()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected override string FavoriteKey()
|
||||
{
|
||||
return $"{structType.FullName}@create";
|
||||
}
|
||||
|
||||
public override void Deserialize(UnitOptionRow row)
|
||||
{
|
||||
base.Deserialize(row);
|
||||
|
||||
structType = Codebase.DeserializeType(row.tag1);
|
||||
}
|
||||
|
||||
public override UnitOptionRow Serialize()
|
||||
{
|
||||
var row = base.Serialize();
|
||||
|
||||
row.tag1 = Codebase.SerializeType(structType);
|
||||
|
||||
return row;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5f25afcb4762e4dad98e5b628f5f7730
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,39 @@
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Descriptor(typeof(Expose))]
|
||||
public class ExposeDescriptor : UnitDescriptor<Expose>
|
||||
{
|
||||
public ExposeDescriptor(Expose unit) : base(unit) { }
|
||||
|
||||
protected override string DefinedTitle()
|
||||
{
|
||||
return $"Expose {unit.type.DisplayName()}";
|
||||
}
|
||||
|
||||
protected override string DefinedSurtitle()
|
||||
{
|
||||
return "Expose";
|
||||
}
|
||||
|
||||
protected override string DefinedShortTitle()
|
||||
{
|
||||
return unit.type.DisplayName();
|
||||
}
|
||||
|
||||
protected override EditorTexture DefinedIcon()
|
||||
{
|
||||
return unit.type.Icon();
|
||||
}
|
||||
|
||||
protected override void DefinedPort(IUnitPort port, UnitPortDescription description)
|
||||
{
|
||||
base.DefinedPort(port, description);
|
||||
|
||||
if (port is ValueOutput && unit.members.TryGetValue((ValueOutput)port, out Member member))
|
||||
{
|
||||
description.label = member.info.HumanName();
|
||||
description.summary = member.info.Summary();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 61b4830f444214043a3097b099a3bfaf
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,55 @@
|
||||
using System;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[FuzzyOption(typeof(Expose))]
|
||||
public class ExposeOption : UnitOption<Expose>
|
||||
{
|
||||
public ExposeOption() : base() { }
|
||||
|
||||
public ExposeOption(Expose unit) : base(unit)
|
||||
{
|
||||
sourceScriptGuids = UnitBase.GetScriptGuids(unit.type).ToHashSet();
|
||||
}
|
||||
|
||||
public Type exposedType { get; private set; }
|
||||
|
||||
protected override string FavoriteKey()
|
||||
{
|
||||
return $"{exposedType.FullName}@expose";
|
||||
}
|
||||
|
||||
protected override string Label(bool human)
|
||||
{
|
||||
return $"Expose {unit.type.SelectedName(human)}";
|
||||
}
|
||||
|
||||
protected override bool ShowValueOutputsInFooter()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
protected override void FillFromUnit()
|
||||
{
|
||||
exposedType = unit.type;
|
||||
|
||||
base.FillFromUnit();
|
||||
}
|
||||
|
||||
public override void Deserialize(UnitOptionRow row)
|
||||
{
|
||||
base.Deserialize(row);
|
||||
|
||||
exposedType = Codebase.DeserializeType(row.tag1);
|
||||
}
|
||||
|
||||
public override UnitOptionRow Serialize()
|
||||
{
|
||||
var row = base.Serialize();
|
||||
|
||||
row.tag1 = Codebase.SerializeType(exposedType);
|
||||
|
||||
return row;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e5deae2e654bb4bc086635b77b883b36
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,20 @@
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Descriptor(typeof(GetMember))]
|
||||
public class GetMemberDescriptor : MemberUnitDescriptor<GetMember>
|
||||
{
|
||||
public GetMemberDescriptor(GetMember unit) : base(unit) { }
|
||||
|
||||
protected override ActionDirection direction => ActionDirection.Get;
|
||||
|
||||
protected override void DefinedPort(IUnitPort port, UnitPortDescription description)
|
||||
{
|
||||
base.DefinedPort(port, description);
|
||||
|
||||
if (port == unit.value)
|
||||
{
|
||||
description.summary = unit.member.info.Summary();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c029e370a4c824cee82a576fb7ea9ce3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,12 @@
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[FuzzyOption(typeof(GetMember))]
|
||||
public class GetMemberOption : MemberUnitOption<GetMember>
|
||||
{
|
||||
public GetMemberOption() : base() { }
|
||||
|
||||
public GetMemberOption(GetMember unit) : base(unit) { }
|
||||
|
||||
protected override ActionDirection direction => ActionDirection.Get;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 34c129757dd604677b0cf9b116a6a788
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,77 @@
|
||||
using System.Linq;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Descriptor(typeof(InvokeMember))]
|
||||
public class InvokeMemberDescriptor : MemberUnitDescriptor<InvokeMember>
|
||||
{
|
||||
public InvokeMemberDescriptor(InvokeMember unit) : base(unit) { }
|
||||
|
||||
protected override ActionDirection direction => ActionDirection.Any;
|
||||
|
||||
protected override string DefinedShortTitle()
|
||||
{
|
||||
if (member.isConstructor)
|
||||
{
|
||||
return BoltCore.Configuration.humanNaming ? "Create" : "new";
|
||||
}
|
||||
|
||||
return base.DefinedShortTitle();
|
||||
}
|
||||
|
||||
protected override void DefinedPort(IUnitPort port, UnitPortDescription description)
|
||||
{
|
||||
base.DefinedPort(port, description);
|
||||
|
||||
var documentation = member.info.Documentation();
|
||||
|
||||
if (port == unit.enter)
|
||||
{
|
||||
description.label = "Invoke";
|
||||
description.summary = "The entry point to invoke the method.";
|
||||
|
||||
if (member.isGettable)
|
||||
{
|
||||
description.summary += " You can still get the return value without connecting this port.";
|
||||
}
|
||||
}
|
||||
else if (port == unit.exit)
|
||||
{
|
||||
description.summary = "The action to call once the method has been invoked.";
|
||||
}
|
||||
else if (port == unit.result)
|
||||
{
|
||||
if (member.isGettable)
|
||||
{
|
||||
description.summary = documentation?.returns;
|
||||
}
|
||||
|
||||
if (unit.supportsChaining && unit.chainable)
|
||||
{
|
||||
description.showLabel = true;
|
||||
}
|
||||
}
|
||||
else if (port == unit.targetOutput)
|
||||
{
|
||||
if (member.isGettable)
|
||||
{
|
||||
description.showLabel = true;
|
||||
}
|
||||
}
|
||||
else if (port is ValueInput && unit.inputParameters.ContainsValue((ValueInput)port))
|
||||
{
|
||||
var parameter = member.GetParameterInfos().Single(p => "%" + p.Name == port.key);
|
||||
|
||||
description.label = parameter.DisplayName();
|
||||
description.summary = documentation?.ParameterSummary(parameter);
|
||||
}
|
||||
else if (port is ValueOutput && unit.outputParameters.ContainsValue((ValueOutput)port))
|
||||
{
|
||||
var parameter = member.GetParameterInfos().Single(p => "&" + p.Name == port.key);
|
||||
|
||||
description.label = parameter.DisplayName();
|
||||
description.summary = documentation?.ParameterSummary(parameter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: efe957c61ae624ee2bfbcccad6c40b02
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,34 @@
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[FuzzyOption(typeof(InvokeMember))]
|
||||
public class InvokeMemberOption : MemberUnitOption<InvokeMember>
|
||||
{
|
||||
public InvokeMemberOption() : base() { }
|
||||
|
||||
public InvokeMemberOption(InvokeMember unit) : base(unit) { }
|
||||
|
||||
protected override ActionDirection direction => ActionDirection.Any;
|
||||
|
||||
public override string SearchResultLabel(string query)
|
||||
{
|
||||
return base.SearchResultLabel(query) + $" ({unit.member.methodBase.DisplayParameterString(unit.member.targetType)})";
|
||||
}
|
||||
|
||||
protected override string Label(bool human)
|
||||
{
|
||||
return base.Label(human) + $" ({unit.member.methodBase.SelectedParameterString(unit.member.targetType, human)})";
|
||||
}
|
||||
|
||||
protected override string Haystack(bool human)
|
||||
{
|
||||
if (!human && member.isConstructor)
|
||||
{
|
||||
return base.Label(human);
|
||||
}
|
||||
else
|
||||
{
|
||||
return $"{targetType.SelectedName(human)}{(human ? ": " : ".")}{base.Label(human)}";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: be41f1ddb0e95454fa0e4bb3e51018d5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,28 @@
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Descriptor(typeof(Literal))]
|
||||
public class LiteralDescriptor : UnitDescriptor<Literal>
|
||||
{
|
||||
public LiteralDescriptor(Literal unit) : base(unit) { }
|
||||
|
||||
protected override string DefinedTitle()
|
||||
{
|
||||
return unit.type.DisplayName() + " Literal";
|
||||
}
|
||||
|
||||
protected override string DefinedShortTitle()
|
||||
{
|
||||
return unit.type.DisplayName();
|
||||
}
|
||||
|
||||
protected override string DefinedSummary()
|
||||
{
|
||||
return unit.type.Summary();
|
||||
}
|
||||
|
||||
protected override EditorTexture DefinedIcon()
|
||||
{
|
||||
return unit.type.Icon();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8860fae1979174c008fe0d7a3e525089
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,55 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Inspector(typeof(Literal))]
|
||||
public sealed class LiteralInspector : Inspector
|
||||
{
|
||||
public LiteralInspector(Metadata metadata) : base(metadata) { }
|
||||
|
||||
private Metadata typeMetadata => metadata[nameof(Literal.type)];
|
||||
private Metadata valueMetadata => metadata[nameof(Literal.value)];
|
||||
private Metadata typedValueMetadata => valueMetadata.Cast((Type)typeMetadata.value);
|
||||
|
||||
private bool hasType => typeMetadata.value != null;
|
||||
|
||||
protected override float GetHeight(float width, GUIContent label)
|
||||
{
|
||||
if (hasType)
|
||||
{
|
||||
return LudiqGUI.GetInspectorHeight(this, typedValueMetadata, width, label);
|
||||
}
|
||||
else
|
||||
{
|
||||
return LudiqGUI.GetInspectorHeight(this, typeMetadata, width, label);
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool cacheHeight => false;
|
||||
|
||||
protected override void OnGUI(Rect position, GUIContent label)
|
||||
{
|
||||
if (hasType)
|
||||
{
|
||||
LudiqGUI.Inspector(typedValueMetadata, position, label);
|
||||
}
|
||||
else
|
||||
{
|
||||
LudiqGUI.Inspector(typeMetadata, position, label);
|
||||
}
|
||||
}
|
||||
|
||||
public override float GetAdaptiveWidth()
|
||||
{
|
||||
if (hasType)
|
||||
{
|
||||
return typedValueMetadata.Inspector().GetAdaptiveWidth();
|
||||
}
|
||||
else
|
||||
{
|
||||
return typeMetadata.Inspector().GetAdaptiveWidth();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0de8b1e3472c14ae99456cce529e933c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,65 @@
|
||||
using System;
|
||||
using UnityObject = UnityEngine.Object;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[FuzzyOption(typeof(Literal))]
|
||||
public class LiteralOption : UnitOption<Literal>
|
||||
{
|
||||
public LiteralOption() : base() { }
|
||||
|
||||
public LiteralOption(Literal unit) : base(unit)
|
||||
{
|
||||
sourceScriptGuids = UnitBase.GetScriptGuids(unit.type).ToHashSet();
|
||||
}
|
||||
|
||||
public Type literalType { get; private set; }
|
||||
|
||||
protected override void FillFromUnit()
|
||||
{
|
||||
literalType = unit.type;
|
||||
base.FillFromUnit();
|
||||
}
|
||||
|
||||
protected override string Label(bool human)
|
||||
{
|
||||
if (unit.value is UnityObject uo && !uo.IsUnityNull())
|
||||
{
|
||||
return UnityAPI.Await(() => uo.name);
|
||||
}
|
||||
|
||||
return unit.type.SelectedName(human) + " Literal";
|
||||
}
|
||||
|
||||
protected override EditorTexture Icon()
|
||||
{
|
||||
if (unit.value is UnityObject uo && !uo.IsUnityNull())
|
||||
{
|
||||
return uo.Icon();
|
||||
}
|
||||
|
||||
return base.Icon();
|
||||
}
|
||||
|
||||
protected override string FavoriteKey()
|
||||
{
|
||||
return $"{literalType.FullName}@literal";
|
||||
}
|
||||
|
||||
public override void Deserialize(UnitOptionRow row)
|
||||
{
|
||||
base.Deserialize(row);
|
||||
|
||||
literalType = Codebase.DeserializeType(row.tag1);
|
||||
}
|
||||
|
||||
public override UnitOptionRow Serialize()
|
||||
{
|
||||
var row = base.Serialize();
|
||||
|
||||
row.tag1 = Codebase.SerializeType(literalType);
|
||||
|
||||
return row;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1d936f8125cf8482d829541d222e3f17
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,56 @@
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Widget(typeof(Literal))]
|
||||
public sealed class LiteralWidget : UnitWidget<Literal>
|
||||
{
|
||||
public LiteralWidget(FlowCanvas canvas, Literal unit) : base(canvas, unit) { }
|
||||
|
||||
protected override bool showHeaderAddon => unit.isDefined;
|
||||
|
||||
public override bool foregroundRequiresInput => true;
|
||||
|
||||
protected override float GetHeaderAddonWidth()
|
||||
{
|
||||
var adaptiveWidthAttribute = unit.type.GetAttribute<InspectorAdaptiveWidthAttribute>();
|
||||
|
||||
return Mathf.Min(metadata.Inspector().GetAdaptiveWidth(), adaptiveWidthAttribute?.width ?? Styles.maxSettingsWidth);
|
||||
}
|
||||
|
||||
protected override float GetHeaderAddonHeight(float width)
|
||||
{
|
||||
return LudiqGUI.GetInspectorHeight(null, metadata, width, GUIContent.none);
|
||||
}
|
||||
|
||||
public override void BeforeFrame()
|
||||
{
|
||||
base.BeforeFrame();
|
||||
|
||||
if (showHeaderAddon &&
|
||||
GetHeaderAddonWidth() != headerAddonPosition.width ||
|
||||
GetHeaderAddonHeight(headerAddonPosition.width) != headerAddonPosition.height)
|
||||
{
|
||||
Reposition();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void DrawHeaderAddon()
|
||||
{
|
||||
using (LudiqGUIUtility.labelWidth.Override(75)) // For reflected inspectors / custom property drawers
|
||||
using (Inspector.adaptiveWidth.Override(true))
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
|
||||
LudiqGUI.Inspector(metadata, headerAddonPosition, GUIContent.none);
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
unit.EnsureDefined();
|
||||
Reposition();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 04c08655b26284f21b41bddeec3acd2c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,39 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
[Analyser(typeof(MemberUnit))]
|
||||
public class MemberUnitAnalyser : UnitAnalyser<MemberUnit>
|
||||
{
|
||||
public MemberUnitAnalyser(GraphReference reference, MemberUnit target) : base(reference, target) { }
|
||||
|
||||
protected override IEnumerable<Warning> Warnings()
|
||||
{
|
||||
foreach (var baseWarning in base.Warnings())
|
||||
{
|
||||
yield return baseWarning;
|
||||
}
|
||||
|
||||
if (target.member != null && target.member.isReflected)
|
||||
{
|
||||
var obsoleteAttribute = target.member.info.GetAttribute<ObsoleteAttribute>();
|
||||
|
||||
if (obsoleteAttribute != null)
|
||||
{
|
||||
if (obsoleteAttribute.Message != null)
|
||||
{
|
||||
Debug.LogWarning($"\"{target.member.name}\" node member is deprecated: {obsoleteAttribute.Message}");
|
||||
yield return Warning.Caution("Deprecated: " + obsoleteAttribute.Message);
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning($"\"{target.member.name}\" node member is deprecated.");
|
||||
yield return Warning.Caution($"Member {target.member.name} is deprecated.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: be8bdd9b815a74b98927b0f862dfd0b2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,106 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Unity.VisualScripting.AssemblyQualifiedNameParser;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
public abstract class MemberUnitDescriptor<TMemberUnit> : UnitDescriptor<TMemberUnit> where TMemberUnit : MemberUnit
|
||||
{
|
||||
protected MemberUnitDescriptor(TMemberUnit unit) : base(unit)
|
||||
{
|
||||
}
|
||||
|
||||
protected Member member => unit.member;
|
||||
|
||||
protected abstract ActionDirection direction { get; }
|
||||
|
||||
private string Name()
|
||||
{
|
||||
return unit.member.info.DisplayName(direction);
|
||||
}
|
||||
|
||||
protected override string DefinedTitle()
|
||||
{
|
||||
return Name();
|
||||
}
|
||||
|
||||
protected override string ErrorSurtitle(Exception exception)
|
||||
{
|
||||
if (member?.targetType != null)
|
||||
{
|
||||
return member.targetType.DisplayName();
|
||||
}
|
||||
else if (member?.targetTypeName != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var parsedName = new ParsedAssemblyQualifiedName(member.targetTypeName).TypeName.Split('.').Last();
|
||||
|
||||
if (BoltCore.Configuration.humanNaming)
|
||||
{
|
||||
return parsedName.Prettify();
|
||||
}
|
||||
else
|
||||
{
|
||||
return parsedName;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
return "Malformed Type Name";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return "Missing Type";
|
||||
}
|
||||
}
|
||||
|
||||
protected override string ErrorTitle(Exception exception)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(member?.name))
|
||||
{
|
||||
if (BoltCore.Configuration.humanNaming)
|
||||
{
|
||||
return member.name.Prettify();
|
||||
}
|
||||
else
|
||||
{
|
||||
return member.name;
|
||||
}
|
||||
}
|
||||
|
||||
return base.ErrorTitle(exception);
|
||||
}
|
||||
|
||||
protected override string DefinedShortTitle()
|
||||
{
|
||||
return Name();
|
||||
}
|
||||
|
||||
protected override EditorTexture DefinedIcon()
|
||||
{
|
||||
return member.targetType.Icon();
|
||||
}
|
||||
|
||||
protected override EditorTexture ErrorIcon(Exception exception)
|
||||
{
|
||||
if (member.targetType != null)
|
||||
{
|
||||
return member.targetType.Icon();
|
||||
}
|
||||
|
||||
return base.ErrorIcon(exception);
|
||||
}
|
||||
|
||||
protected override string DefinedSurtitle()
|
||||
{
|
||||
return member.targetType.DisplayName();
|
||||
}
|
||||
|
||||
protected override string DefinedSummary()
|
||||
{
|
||||
return member.info.Summary();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cbba72664e24a4752a7ca4a3352735a5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,130 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Unity.VisualScripting
|
||||
{
|
||||
public interface IMemberUnitOption : IUnitOption
|
||||
{
|
||||
Type targetType { get; }
|
||||
Member member { get; }
|
||||
Member pseudoDeclarer { get; }
|
||||
}
|
||||
|
||||
public abstract class MemberUnitOption<TMemberUnit> : UnitOption<TMemberUnit>, IMemberUnitOption where TMemberUnit : MemberUnit
|
||||
{
|
||||
protected MemberUnitOption() : base() { }
|
||||
|
||||
protected MemberUnitOption(TMemberUnit unit) : base(unit)
|
||||
{
|
||||
sourceScriptGuids = UnitBase.GetScriptGuids(unit.member.targetType).ToHashSet();
|
||||
}
|
||||
|
||||
private Member _member;
|
||||
|
||||
private Member _pseudoDeclarer;
|
||||
|
||||
public Member member
|
||||
{
|
||||
get => _member ?? unit.member;
|
||||
set => _member = value;
|
||||
}
|
||||
|
||||
public Member pseudoDeclarer
|
||||
{
|
||||
get => _pseudoDeclarer ?? member.ToPseudoDeclarer();
|
||||
set => _pseudoDeclarer = value;
|
||||
}
|
||||
|
||||
public bool isPseudoInherited => member == pseudoDeclarer;
|
||||
|
||||
protected abstract ActionDirection direction { get; }
|
||||
|
||||
public Type targetType { get; private set; }
|
||||
|
||||
protected override GUIStyle Style()
|
||||
{
|
||||
if (unit.member.isPseudoInherited)
|
||||
{
|
||||
return FuzzyWindow.Styles.optionWithIconDim;
|
||||
}
|
||||
|
||||
return base.Style();
|
||||
}
|
||||
|
||||
protected override string Label(bool human)
|
||||
{
|
||||
return unit.member.info.SelectedName(human, direction);
|
||||
}
|
||||
|
||||
protected override string FavoriteKey()
|
||||
{
|
||||
return $"{member.ToUniqueString()}@{direction.ToString().ToLower()}";
|
||||
}
|
||||
|
||||
protected override int Order()
|
||||
{
|
||||
if (member.isConstructor)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return base.Order();
|
||||
}
|
||||
|
||||
protected override string Haystack(bool human)
|
||||
{
|
||||
return $"{targetType.SelectedName(human)}{(human ? ": " : ".")}{Label(human)}";
|
||||
}
|
||||
|
||||
protected override void FillFromUnit()
|
||||
{
|
||||
targetType = unit.member.targetType;
|
||||
member = unit.member;
|
||||
pseudoDeclarer = member.ToPseudoDeclarer();
|
||||
|
||||
base.FillFromUnit();
|
||||
}
|
||||
|
||||
public override void Deserialize(UnitOptionRow row)
|
||||
{
|
||||
base.Deserialize(row);
|
||||
|
||||
targetType = Codebase.DeserializeType(row.tag1);
|
||||
|
||||
if (!string.IsNullOrEmpty(row.tag2))
|
||||
{
|
||||
member = Codebase.DeserializeMember(row.tag2);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(row.tag3))
|
||||
{
|
||||
pseudoDeclarer = Codebase.DeserializeMember(row.tag3);
|
||||
}
|
||||
}
|
||||
|
||||
public override UnitOptionRow Serialize()
|
||||
{
|
||||
var row = base.Serialize();
|
||||
|
||||
row.tag1 = Codebase.SerializeType(targetType);
|
||||
row.tag2 = Codebase.SerializeMember(member);
|
||||
row.tag3 = Codebase.SerializeMember(pseudoDeclarer);
|
||||
|
||||
return row;
|
||||
}
|
||||
|
||||
public override void OnPopulate()
|
||||
{
|
||||
// Members are late-reflected to speed up loading and search
|
||||
// We only reflect them when we're just about to populate their node
|
||||
// By doing it in OnPopulate instead of on-demand later, we ensure
|
||||
// any error will be gracefully catched and shown as a warning by
|
||||
// the fuzzy window
|
||||
|
||||
member.EnsureReflected();
|
||||
pseudoDeclarer.EnsureReflected();
|
||||
|
||||
base.OnPopulate();
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user