From 0fd8de80295225043f75a82b2fa9a1b692841920 Mon Sep 17 00:00:00 2001 From: Nils Hausfeld Date: Sat, 15 Jun 2024 22:13:05 +0200 Subject: [PATCH] - Added custom func to fetch information for nodes that need special treatment like Array, Enum or Un/Pack nodes - More refactoring and cleanup --- Source/Editor/Surface/Archetypes/Constants.cs | 24 +++++++++ Source/Editor/Surface/Archetypes/Packing.cs | 32 ++++++++++++ .../Editor/Surface/ContextMenu/VisjectCM.cs | 50 ++++++++----------- Source/Editor/Surface/NodeArchetype.cs | 13 ++++- 4 files changed, 88 insertions(+), 31 deletions(-) diff --git a/Source/Editor/Surface/Archetypes/Constants.cs b/Source/Editor/Surface/Archetypes/Constants.cs index b94bc34cb..8cce34332 100644 --- a/Source/Editor/Surface/Archetypes/Constants.cs +++ b/Source/Editor/Surface/Archetypes/Constants.cs @@ -7,6 +7,8 @@ using Real = System.Single; #endif using System; +using System.Collections; +using System.Collections.Generic; using System.Linq; using FlaxEditor.CustomEditors.Editors; using FlaxEditor.GUI; @@ -182,6 +184,13 @@ namespace FlaxEditor.Surface.Archetypes base.OnDestroy(); } + + internal static void GetInputOutputDescription(NodeArchetype nodeArch, out (string, ScriptType)[] inputs, out (string, ScriptType)[] outputs) + { + var type = new ScriptType(nodeArch.DefaultValues[0].GetType()); + inputs = null; + outputs = [(type.Name, type)]; + } } private class ArrayNode : SurfaceNode @@ -321,6 +330,12 @@ namespace FlaxEditor.Surface.Archetypes array.SetValue(value, box.ID - 1); SetValue(0, array); } + + internal static void GetInputOutputDescription(NodeArchetype nodeArch, out (string, ScriptType)[] inputs, out (string, ScriptType)[] outputs) + { + inputs = null; + outputs = [("", new ScriptType(typeof(Array)))]; + } } private class DictionaryNode : SurfaceNode @@ -449,6 +464,12 @@ namespace FlaxEditor.Surface.Archetypes array.SetValue(value, box.ID - 1); SetValue(0, array); } + + internal static void GetInputOutputDescription(NodeArchetype nodeArch, out (string, ScriptType)[] inputs, out (string, ScriptType)[] outputs) + { + inputs = null; + outputs = [("", new ScriptType(typeof(Dictionary)))]; + } } /// @@ -743,6 +764,7 @@ namespace FlaxEditor.Surface.Archetypes Title = "Enum", Create = (id, context, arch, groupArch) => new EnumNode(id, context, arch, groupArch), Description = "Enum constant value.", + GetInputOutputDescription = EnumNode.GetInputOutputDescription, Flags = NodeFlags.VisualScriptGraph | NodeFlags.AnimGraph | NodeFlags.NoSpawnViaGUI, Size = new Float2(180, 20), DefaultValues = new object[] @@ -779,6 +801,7 @@ namespace FlaxEditor.Surface.Archetypes Title = "Array", Create = (id, context, arch, groupArch) => new ArrayNode(id, context, arch, groupArch), Description = "Constant array value.", + GetInputOutputDescription = ArrayNode.GetInputOutputDescription, Flags = NodeFlags.VisualScriptGraph | NodeFlags.AnimGraph, Size = new Float2(150, 20), DefaultValues = new object[] { new int[] { 0, 1, 2 } }, @@ -790,6 +813,7 @@ namespace FlaxEditor.Surface.Archetypes Title = "Dictionary", Create = (id, context, arch, groupArch) => new DictionaryNode(id, context, arch, groupArch), Description = "Creates an empty dictionary.", + GetInputOutputDescription = DictionaryNode.GetInputOutputDescription, Flags = NodeFlags.VisualScriptGraph | NodeFlags.AnimGraph, Size = new Float2(150, 40), DefaultValues = new object[] { typeof(int).FullName, typeof(string).FullName }, diff --git a/Source/Editor/Surface/Archetypes/Packing.cs b/Source/Editor/Surface/Archetypes/Packing.cs index 40244c2ca..5e84d615a 100644 --- a/Source/Editor/Surface/Archetypes/Packing.cs +++ b/Source/Editor/Surface/Archetypes/Packing.cs @@ -245,6 +245,21 @@ namespace FlaxEditor.Surface.Archetypes } return false; } + + internal static void GetInputOutputDescription(NodeArchetype nodeArch, out (string, ScriptType)[] inputs, out (string, ScriptType)[] outputs) + { + var type = TypeUtils.GetType((string)nodeArch.DefaultValues[0]); + outputs = [(type.Name, type)]; + + var fields = type.GetMembers(BindingFlags.Public | BindingFlags.Instance).Where(x => x.IsField).ToArray(); + var fieldsLength = fields.Length; + inputs = new (string, ScriptType)[fieldsLength]; + for (var i = 0; i < fieldsLength; i++) + { + var field = fields[i]; + inputs[i] = (field.Name, field.ValueType); + } + } } private sealed class UnpackStructureNode : StructureNode @@ -283,6 +298,21 @@ namespace FlaxEditor.Surface.Archetypes } return false; } + + internal static void GetInputOutputDescription(NodeArchetype nodeArch, out (string, ScriptType)[] inputs, out (string, ScriptType)[] outputs) + { + var type = TypeUtils.GetType((string)nodeArch.DefaultValues[0]); + inputs = [(type.Name, type)]; + + var fields = type.GetMembers(BindingFlags.Public | BindingFlags.Instance).Where(x => x.IsField).ToArray(); + var fieldsLength = fields.Length; + outputs = new (string, ScriptType)[fieldsLength]; + for (var i = 0; i < fieldsLength; i++) + { + var field = fields[i]; + outputs[i] = (field.Name, field.ValueType); + } + } } /// @@ -411,6 +441,7 @@ namespace FlaxEditor.Surface.Archetypes Create = (id, context, arch, groupArch) => new PackStructureNode(id, context, arch, groupArch), IsInputCompatible = PackStructureNode.IsInputCompatible, IsOutputCompatible = PackStructureNode.IsOutputCompatible, + GetInputOutputDescription = PackStructureNode.GetInputOutputDescription, Description = "Makes the structure data to from the components.", Flags = NodeFlags.VisualScriptGraph | NodeFlags.AnimGraph | NodeFlags.NoSpawnViaGUI, Size = new Float2(180, 20), @@ -523,6 +554,7 @@ namespace FlaxEditor.Surface.Archetypes Create = (id, context, arch, groupArch) => new UnpackStructureNode(id, context, arch, groupArch), IsInputCompatible = UnpackStructureNode.IsInputCompatible, IsOutputCompatible = UnpackStructureNode.IsOutputCompatible, + GetInputOutputDescription = UnpackStructureNode.GetInputOutputDescription, Description = "Breaks the structure data to allow extracting components from it.", Flags = NodeFlags.VisualScriptGraph | NodeFlags.AnimGraph | NodeFlags.NoSpawnViaGUI, Size = new Float2(180, 20), diff --git a/Source/Editor/Surface/ContextMenu/VisjectCM.cs b/Source/Editor/Surface/ContextMenu/VisjectCM.cs index a7737b4de..c2518519a 100644 --- a/Source/Editor/Surface/ContextMenu/VisjectCM.cs +++ b/Source/Editor/Surface/ContextMenu/VisjectCM.cs @@ -663,13 +663,10 @@ namespace FlaxEditor.Surface.ContextMenu Profiler.BeginEvent("VisjectCM.SetDescriptionPanelArchetype"); - ScriptType declaringType; - string elementName, elementTypeName; - _descriptionInputPanel.RemoveChildren(); _descriptionOutputPanel.RemoveChildren(); - + ScriptType declaringType; if (archetype.Tag is ScriptMemberInfo memberInfo) { var name = memberInfo.Name; @@ -710,24 +707,25 @@ namespace FlaxEditor.Surface.ContextMenu declaringType = archetype.DefaultType; // Special handling for Pack nodes - if (archetype == Packing.Nodes[6] || archetype == Packing.Nodes[13]) + if (archetype.GetInputOutputDescription != null) { - bool isOutput = archetype == Packing.Nodes[6]; - var type = TypeUtils.GetType((string)archetype.DefaultValues[0]); - AddInputOutputElement(archetype, type, isOutput, $"{type.Name}"); - - var fields = type.GetMembers(BindingFlags.Public | BindingFlags.Instance).Where(x => x.IsField).ToArray(); - var fieldsLength = fields.Length; - for (var i = 0; i < fieldsLength; i++) + archetype.GetInputOutputDescription.Invoke(archetype, out (string, ScriptType)[] inputs, out (string, ScriptType)[] outputs); + + if (inputs != null) { - var field = fields[i]; - AddInputOutputElement(archetype, field.ValueType, !isOutput, $"{field.Name} ({field.ValueType.Name})"); + for (int i = 0; i < inputs.Length; i++) + { + AddInputOutputElement(archetype, inputs[i].Item2, false, $"{inputs[i].Item1} ({inputs[i].Item2.Name})"); + } + } + + if (outputs != null) + { + for (int i = 0; i < outputs.Length; i++) + { + AddInputOutputElement(archetype, outputs[i].Item2, true, $"{outputs[i].Item1} ({outputs[i].Item2.Name})"); + } } - } - else if (archetype == Archetypes.Constants.Nodes[10]) - { - var t = new ScriptType(archetype.DefaultValues[0].GetType()); - AddInputOutputElement(archetype, t, true, $"ENUM {t.Name}"); } else { @@ -737,17 +735,9 @@ namespace FlaxEditor.Surface.ContextMenu { bool isOutput = element.Type == NodeElementType.Output; if (element.ConnectionsType == null) - { - if(archetype == Archetypes.Constants.Nodes[12]) - AddInputOutputElement(archetype, element.ConnectionsType, isOutput, $"-{element.Text} ({ConnectionsHint.Array.ToString()})"); - else if (archetype == Archetypes.Constants.Nodes[13]) - AddInputOutputElement(archetype, element.ConnectionsType, isOutput, $"-{element.Text} ({ConnectionsHint.Dictionary.ToString()})"); - else - AddInputOutputElement(archetype, element.ConnectionsType, isOutput, $"-{element.Text} ({archetype.ConnectionsHints.ToString()})"); - continue; - } - - AddInputOutputElement(archetype, element.ConnectionsType, isOutput, $"-{element.Text} ({element.ConnectionsType.Name})"); + AddInputOutputElement(archetype, element.ConnectionsType, isOutput, $"-{element.Text} ({archetype.ConnectionsHints.ToString()})"); + else + AddInputOutputElement(archetype, element.ConnectionsType, isOutput, $"-{element.Text} ({element.ConnectionsType.Name})"); } } } diff --git a/Source/Editor/Surface/NodeArchetype.cs b/Source/Editor/Surface/NodeArchetype.cs index efcec6b62..63d731b72 100644 --- a/Source/Editor/Surface/NodeArchetype.cs +++ b/Source/Editor/Surface/NodeArchetype.cs @@ -90,10 +90,15 @@ namespace FlaxEditor.Surface public delegate SurfaceNode CreateCustomNodeFunc(uint id, VisjectSurfaceContext context, NodeArchetype nodeArch, GroupArchetype groupArch); /// - /// Checks if the given type is compatible with the given node archetype. Used for custom nodes + /// Checks if the given type is compatible with the given node archetype. Used for custom nodes. /// public delegate bool IsCompatible(NodeArchetype nodeArch, ScriptType portType, ConnectionsHint hint, VisjectSurfaceContext context); + /// + /// Gets description of inputs and outputs of the archetype. Used for special cases for the description panel. + /// + public delegate void GetElementsDescriptionFunc(NodeArchetype nodeArch, out (string, ScriptType)[] inputs, out (string, ScriptType)[] outputs); + /// /// Unique node type ID within a single group. /// @@ -144,6 +149,11 @@ namespace FlaxEditor.Surface /// public string Description; + /// + /// Custom function to get descriptions of input and output elements. Used for description panel (optional). + /// + public GetElementsDescriptionFunc GetInputOutputDescription; + /// /// Alternative node titles. /// @@ -217,6 +227,7 @@ namespace FlaxEditor.Surface SubTitle = SubTitle, Signature = Signature, Description = Description, + GetInputOutputDescription = GetInputOutputDescription, AlternativeTitles = (string[])AlternativeTitles?.Clone(), Tag = Tag, SortScore = SortScore,