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