/// <summary> /// Creates the node. /// </summary> /// <param name="id">The node id.</param> /// <param name="context">The context.</param> /// <param name="groupArchetype">The group archetype.</param> /// <param name="nodeArchetype">The node archetype.</param> /// <returns>Created node or null if failed.</returns> public static SurfaceNode CreateNode(uint id, VisjectSurfaceContext context, GroupArchetype groupArchetype, NodeArchetype nodeArchetype) { Assert.IsTrue(groupArchetype.Archetypes.Contains(nodeArchetype)); SurfaceNode node; if (nodeArchetype.Create != null) { node = nodeArchetype.Create(id, context, nodeArchetype, groupArchetype); } else { node = new SurfaceNode(id, context, nodeArchetype, groupArchetype); } return(node); }
/// <summary> /// Spawns the node. /// </summary> /// <param name="groupArchetype">The group archetype.</param> /// <param name="nodeArchetype">The node archetype.</param> /// <param name="location">The location.</param> /// <param name="customValues">The custom values array. Must match node archetype <see cref="NodeArchetype.DefaultValues"/> size. Pass null to use default values.</param> /// <returns>Created node.</returns> public SurfaceNode SpawnNode(GroupArchetype groupArchetype, NodeArchetype nodeArchetype, Vector2 location, object[] customValues = null) { if (groupArchetype == null || nodeArchetype == null) { throw new ArgumentNullException(); } if (!_surface.CanSpawnNodeType(nodeArchetype)) { Editor.LogWarning("Cannot spawn given node type."); return(null); } var id = GetFreeNodeID(); // Create node var node = NodeFactory.CreateNode(id, this, groupArchetype, nodeArchetype); if (node == null) { Editor.LogWarning("Failed to create node."); return(null); } Nodes.Add(node); // Initialize if (customValues != null) { if (node.Values != null && node.Values.Length == customValues.Length) { Array.Copy(customValues, node.Values, customValues.Length); } else { throw new InvalidOperationException("Invalid node custom values."); } } OnControlLoaded(node); node.OnSurfaceLoaded(); node.Location = location; OnControlSpawned(node); MarkAsModified(); return(node); }
/// <summary> /// Initializes a new instance of the <see cref="SurfaceNode"/> class. /// </summary> /// <param name="id">The node id.</param> /// <param name="context">The surface context.</param> /// <param name="nodeArch">The node archetype.</param> /// <param name="groupArch">The group archetype.</param> public SurfaceNode(uint id, VisjectSurfaceContext context, NodeArchetype nodeArch, GroupArchetype groupArch) : base(context, nodeArch.Size.X + Constants.NodeMarginX * 2, nodeArch.Size.Y + Constants.NodeMarginY * 2 + Constants.NodeHeaderSize + Constants.NodeFooterSize) { Title = nodeArch.Title; ID = id; Archetype = nodeArch; GroupArchetype = groupArch; AutoFocus = false; TooltipText = nodeArch.Description; CullChildren = false; if (Archetype.DefaultValues != null) { Values = new object[Archetype.DefaultValues.Length]; Array.Copy(Archetype.DefaultValues, Values, Values.Length); } }
private static void OnActiveContextMenuShowAsync() { Profiler.BeginEvent("Setup Anim Graph Context Menu (async)"); foreach (var scriptType in Editor.Instance.CodeEditing.All.Get()) { if (!SurfaceUtils.IsValidVisualScriptType(scriptType)) { continue; } // Skip Newtonsoft.Json stuff var scriptTypeTypeName = scriptType.TypeName; if (scriptTypeTypeName.StartsWith("Newtonsoft.Json.")) { continue; } var scriptTypeName = scriptType.Name; // Enum if (scriptType.IsEnum) { // Create node archetype var node = (NodeArchetype)Archetypes.Constants.Nodes[10].Clone(); node.DefaultValues[0] = Activator.CreateInstance(scriptType.Type); node.Flags &= ~NodeFlags.NoSpawnViaGUI; node.Title = scriptTypeName; node.Description = Editor.Instance.CodeDocs.GetTooltip(scriptType); // Create group archetype var groupKey = new KeyValuePair <string, ushort>(scriptTypeName, 2); if (!_cache.TryGetValue(groupKey, out var group)) { group = new GroupArchetype { GroupID = groupKey.Value, Name = groupKey.Key, Color = new Color(243, 156, 18), Tag = _version, Archetypes = new List <NodeArchetype>(), }; _cache.Add(groupKey, group); } // Add node to the group ((IList <NodeArchetype>)group.Archetypes).Add(node); continue; } // Structure if (scriptType.IsValueType) { if (scriptType.IsVoid) { continue; } // Create group archetype var groupKey = new KeyValuePair <string, ushort>(scriptTypeName, 4); if (!_cache.TryGetValue(groupKey, out var group)) { group = new GroupArchetype { GroupID = groupKey.Value, Name = groupKey.Key, Color = new Color(155, 89, 182), Tag = _version, Archetypes = new List <NodeArchetype>(), }; _cache.Add(groupKey, group); } var tooltip = Editor.Instance.CodeDocs.GetTooltip(scriptType); // Create Pack node archetype var node = (NodeArchetype)Archetypes.Packing.Nodes[6].Clone(); node.DefaultValues[0] = scriptTypeTypeName; node.Flags &= ~NodeFlags.NoSpawnViaGUI; node.Title = "Pack " + scriptTypeName; node.Description = tooltip; ((IList <NodeArchetype>)group.Archetypes).Add(node); // Create Unpack node archetype node = (NodeArchetype)Archetypes.Packing.Nodes[13].Clone(); node.DefaultValues[0] = scriptTypeTypeName; node.Flags &= ~NodeFlags.NoSpawnViaGUI; node.Title = "Unpack " + scriptTypeName; node.Description = tooltip; ((IList <NodeArchetype>)group.Archetypes).Add(node); } } // Add group to context menu (on a main thread) FlaxEngine.Scripting.InvokeOnUpdate(() => { lock (_locker) { _taskContextMenu.AddGroups(_cache.Values); _taskContextMenu = null; } }); Profiler.EndEvent(); lock (_locker) { _task = null; } }
/// <summary> /// Gets the archetypes for the node. /// </summary> /// <param name="groups">The group archetypes.</param> /// <param name="groupID">The group identifier.</param> /// <param name="typeID">The type identifier.</param> /// <param name="gArch">The output group archetype.</param> /// <param name="arch">The output node archetype.</param> /// <returns>True if found it, otherwise false.</returns> public static bool GetArchetype(List <GroupArchetype> groups, ushort groupID, ushort typeID, out GroupArchetype gArch, out NodeArchetype arch) { gArch = null; arch = null; // Find archetype for that node foreach (var groupArchetype in groups) { if (groupArchetype.GroupID == groupID && groupArchetype.Archetypes != null) { foreach (var nodeArchetype in groupArchetype.Archetypes) { if (nodeArchetype.TypeID == typeID) { // Found gArch = groupArchetype; arch = nodeArchetype; return(true); } } } } // Error Editor.LogError($"Failed to create Visject Surface node with id: {groupID}:{typeID}"); return(false); }
private static void OnActiveContextMenuShowAsync() { Profiler.BeginEvent("Setup Visual Script Context Menu (async)"); #if DEBUG_INVOKE_METHODS_SEARCHING || DEBUG_FIELDS_SEARCHING var searchStartTime = DateTime.Now; var searchHitsCount = 0; #endif foreach (var scriptType in Editor.Instance.CodeEditing.All.Get()) { if (!SurfaceUtils.IsValidVisualScriptType(scriptType)) { continue; } // Skip Newtonsoft.Json stuff var scriptTypeTypeName = scriptType.TypeName; if (scriptTypeTypeName.StartsWith("Newtonsoft.Json.")) { continue; } var scriptTypeName = scriptType.Name; // Enum if (scriptType.IsEnum) { // Create node archetype var node = (NodeArchetype)Archetypes.Constants.Nodes[10].Clone(); node.DefaultValues[0] = Activator.CreateInstance(scriptType.Type); node.Flags &= ~NodeFlags.NoSpawnViaGUI; node.Title = scriptTypeName; node.Description = scriptTypeTypeName; var attributes = scriptType.GetAttributes(false); var tooltipAttribute = (TooltipAttribute)attributes.FirstOrDefault(x => x is TooltipAttribute); if (tooltipAttribute != null) { node.Description += "\n" + tooltipAttribute.Text; } // Create group archetype var groupKey = new KeyValuePair <string, ushort>(scriptTypeName, 2); if (!_cache.TryGetValue(groupKey, out var group)) { group = new GroupArchetype { GroupID = groupKey.Value, Name = groupKey.Key, Color = new Color(243, 156, 18), Tag = _version, Archetypes = new List <NodeArchetype>(), }; _cache.Add(groupKey, group); } // Add node to the group ((IList <NodeArchetype>)group.Archetypes).Add(node); continue; } // Structure if (scriptType.IsValueType) { if (scriptType.IsVoid) { continue; } // Create group archetype var groupKey = new KeyValuePair <string, ushort>(scriptTypeName, 4); if (!_cache.TryGetValue(groupKey, out var group)) { group = new GroupArchetype { GroupID = groupKey.Value, Name = groupKey.Key, Color = new Color(155, 89, 182), Tag = _version, Archetypes = new List <NodeArchetype>(), }; _cache.Add(groupKey, group); } var attributes = scriptType.GetAttributes(false); var tooltipAttribute = (TooltipAttribute)attributes.FirstOrDefault(x => x is TooltipAttribute); // Create Pack node archetype var node = (NodeArchetype)Archetypes.Packing.Nodes[6].Clone(); node.DefaultValues[0] = scriptTypeTypeName; node.Flags &= ~NodeFlags.NoSpawnViaGUI; node.Title = "Pack " + scriptTypeName; node.Description = scriptTypeTypeName; if (tooltipAttribute != null) { node.Description += "\n" + tooltipAttribute.Text; } ((IList <NodeArchetype>)group.Archetypes).Add(node); // Create Unpack node archetype node = (NodeArchetype)Archetypes.Packing.Nodes[13].Clone(); node.DefaultValues[0] = scriptTypeTypeName; node.Flags &= ~NodeFlags.NoSpawnViaGUI; node.Title = "Unpack " + scriptTypeName; node.Description = scriptTypeTypeName; if (tooltipAttribute != null) { node.Description += "\n" + tooltipAttribute.Text; } ((IList <NodeArchetype>)group.Archetypes).Add(node); } foreach (var member in scriptType.GetMembers(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly)) { if (member.IsGeneric) { continue; } if (member.IsMethod) { // Skip methods not declared in this type if (member.Type is MethodInfo m && m.GetBaseDefinition().DeclaringType != m.DeclaringType) { continue; } var name = member.Name; if (name == "ToString") { continue; } // Skip if searching by name doesn't return a match var members = scriptType.GetMembers(name, MemberTypes.Method, BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly); if (!members.Contains(member)) { continue; } // Check if method is valid for Visual Script usage if (SurfaceUtils.IsValidVisualScriptInvokeMethod(member, out var parameters)) { // Create node archetype var node = (NodeArchetype)Archetypes.Function.Nodes[3].Clone(); node.DefaultValues[0] = scriptTypeTypeName; node.DefaultValues[1] = name; node.DefaultValues[2] = parameters.Length; node.Flags &= ~NodeFlags.NoSpawnViaGUI; node.Title = SurfaceUtils.GetMethodDisplayName((string)node.DefaultValues[1]); node.Description = SurfaceUtils.GetVisualScriptMemberInfoDescription(member); node.SubTitle = string.Format(" (in {0})", scriptTypeName); node.Tag = member; // Create group archetype var groupKey = new KeyValuePair <string, ushort>(scriptTypeName, 16); if (!_cache.TryGetValue(groupKey, out var group)) { group = new GroupArchetype { GroupID = groupKey.Value, Name = groupKey.Key, Color = new Color(109, 160, 24), Tag = _version, Archetypes = new List <NodeArchetype>(), }; _cache.Add(groupKey, group); } // Add node to the group ((IList <NodeArchetype>)group.Archetypes).Add(node); #if DEBUG_INVOKE_METHODS_SEARCHING Editor.LogWarning(scriptTypeTypeName + " -> " + member.GetSignature()); searchHitsCount++; #endif } } else if (member.IsField) { var name = member.Name; // Skip if searching by name doesn't return a match var members = scriptType.GetMembers(name, MemberTypes.Field, BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly); if (!members.Contains(member)) { continue; } // Check if field is valid for Visual Script usage if (SurfaceUtils.IsValidVisualScriptField(member)) { if (member.HasGet) { // Create node archetype var node = (NodeArchetype)Archetypes.Function.Nodes[6].Clone(); node.DefaultValues[0] = scriptTypeTypeName; node.DefaultValues[1] = name; node.DefaultValues[2] = member.ValueType.TypeName; node.DefaultValues[3] = member.IsStatic; node.Flags &= ~NodeFlags.NoSpawnViaGUI; node.Title = "Get " + name; node.Description = SurfaceUtils.GetVisualScriptMemberInfoDescription(member); node.SubTitle = string.Format(" (in {0})", scriptTypeName); // Create group archetype var groupKey = new KeyValuePair <string, ushort>(scriptTypeName, 16); if (!_cache.TryGetValue(groupKey, out var group)) { group = new GroupArchetype { GroupID = groupKey.Value, Name = groupKey.Key, Color = new Color(109, 160, 24), Tag = _version, Archetypes = new List <NodeArchetype>(), }; _cache.Add(groupKey, group); } // Add node to the group ((IList <NodeArchetype>)group.Archetypes).Add(node); #if DEBUG_FIELDS_SEARCHING Editor.LogWarning(scriptTypeTypeName + " -> Get " + member.GetSignature()); searchHitsCount++; #endif } if (member.HasSet) { // Create node archetype var node = (NodeArchetype)Archetypes.Function.Nodes[7].Clone(); node.DefaultValues[0] = scriptTypeTypeName; node.DefaultValues[1] = name; node.DefaultValues[2] = member.ValueType.TypeName; node.DefaultValues[3] = member.IsStatic; node.Flags &= ~NodeFlags.NoSpawnViaGUI; node.Title = "Set " + name; node.Description = SurfaceUtils.GetVisualScriptMemberInfoDescription(member); node.SubTitle = string.Format(" (in {0})", scriptTypeName); // Create group archetype var groupKey = new KeyValuePair <string, ushort>(scriptTypeName, 16); if (!_cache.TryGetValue(groupKey, out var group)) { group = new GroupArchetype { GroupID = groupKey.Value, Name = groupKey.Key, Color = new Color(109, 160, 24), Tag = _version, Archetypes = new List <NodeArchetype>(), }; _cache.Add(groupKey, group); } // Add node to the group ((IList <NodeArchetype>)group.Archetypes).Add(node); #if DEBUG_FIELDS_SEARCHING Editor.LogWarning(scriptTypeTypeName + " -> Set " + member.GetSignature()); searchHitsCount++; #endif } } } } } // Add group to context menu (on a main thread) FlaxEngine.Scripting.InvokeOnUpdate(() => { #if DEBUG_INVOKE_METHODS_SEARCHING || DEBUG_FIELDS_SEARCHING var addStartTime = DateTime.Now; #endif lock (_locker) { _taskContextMenu.AddGroups(_cache.Values); _taskContextMenu = null; } #if DEBUG_INVOKE_METHODS_SEARCHING || DEBUG_FIELDS_SEARCHING Editor.LogError($"Added items to VisjectCM in: {(DateTime.Now - addStartTime).TotalMilliseconds} ms"); #endif }); #if DEBUG_INVOKE_METHODS_SEARCHING || DEBUG_FIELDS_SEARCHING Editor.LogError($"Collected {searchHitsCount} items in: {(DateTime.Now - searchStartTime).TotalMilliseconds} ms"); #endif Profiler.EndEvent(); lock (_locker) { _task = null; } }