This commit is contained in:
2025-01-17 13:10:42 +01:00
commit 4536213c91
15115 changed files with 1442174 additions and 0 deletions

View File

@@ -0,0 +1,8 @@
namespace Unity.VisualScripting
{
[Descriptor(typeof(FlowGraph))]
public sealed class FlowGraphDescriptor : GraphDescriptor<FlowGraph, GraphDescription>
{
public FlowGraphDescriptor(FlowGraph target) : base(target) { }
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2945371b70d5248c29fba485e0f535f3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
namespace Unity.VisualScripting
{
[Descriptor(typeof(ScriptMachine))]
public sealed class FlowMachineDescriptor : MachineDescriptor<ScriptMachine, MachineDescription>
{
public FlowMachineDescriptor(ScriptMachine target) : base(target) { }
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: bf11352faae8e4195bed44acfb96c522
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
namespace Unity.VisualScripting
{
[Descriptor(typeof(ScriptGraphAsset))]
public sealed class FlowMacroDescriptor : MacroDescriptor<ScriptGraphAsset, MacroDescription>
{
public FlowMacroDescriptor(ScriptGraphAsset target) : base(target) { }
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 23070ced5c01f495eb6b3dcc75ab6fc1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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);
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 56af1e1695c6a47bb826414e1888797f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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.");
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 59cd7f950ffc142d997761f2547b6bfb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,7 @@
namespace Unity.VisualScripting
{
public sealed class UnitAnalysis : GraphElementAnalysis
{
public bool isEntered { get; set; }
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2c1bdc9069f004a5f96a18d68a450d49
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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; }
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 046d84976aadf4fa58001515d8167521
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 66a77230ee8e44f3f917beab188d7ba2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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;
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 51835fa842102474c83eeea00b0602aa
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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);
}
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0a272fe91f6be43dfb94b0c752db3a9c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: