public void RegisterNode(Node node, NodeLibrary dependency) { _loadedAssemblies.Add(node.GetType().Assembly); var fullName = node.GetType().FullName ?? ""; if (_availableNodeViewModels.Contains(node)) { return; } if (_nodeNameToViewModelMap.ContainsKey(fullName)) { return; } if (_dependencyMap.ContainsKey(fullName)) { throw new ProviderException("Node registered twice"); } _nodeNameToViewModelMap.Add(fullName, node.GetType()); _availableNodeViewModels.Add(node); _dependencyMap.Add(fullName, dependency); PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("AddNodes")); }
/// <inheritdoc/> public void RegisterNode(Node node, NodeLibrary dependency) { _loadedAssemblies.Add(node.GetType().Assembly); var fullName = node.GetType().FullName ?? string.Empty; if (_availableNodeViewModels.Contains(node)) { return; } if (_nodeNameToViewModelMap.ContainsKey(fullName)) { return; } if (_dependencyMap.ContainsKey(fullName)) { throw new InvalidOperationException($"Node registered twice with {GetType().AssemblyQualifiedName}"); } _nodeNameToViewModelMap.Add(fullName, node.GetType()); _availableNodeViewModels.Add(node); _dependencyMap.Add(fullName, dependency); NodeRegistered?.Invoke(node); }
protected override void ConstructFieldTemplates(NodeProvider nodeProvider, Dictionary <Type, NodeFieldTemplate> templates) { NodeLibrary library = nodeProvider.GetNodeLibrary(); foreach (var nodeTemplate in library.nodeTemplates) { Type type = nodeTemplate.RuntimeNodeType; var template = new NodeFieldTemplate(); var fields = type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); foreach (var field in fields) { bool isPrivate = field.IsPrivate; if (IsOutput(field)) { template.OutputPorts.Add(new Ports.PortDescription(field.Name, field.FieldType, PortDirection.Output, false, false)); } else if (IsInput(field)) { template.OutputPorts.Add(new Ports.PortDescription(field.Name, field.FieldType, PortDirection.Input, false, false)); } else { template.Properties.Add(new PropertyDescription { FieldType = field }); } } templates.Add(type, template); } }
protected override NodeLibrary ConstructNodeLibrary(NodeLibrary library) { var assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (var assembly in assemblies) { Type[] types = assembly.GetTypes(); foreach (var type in types) { if (!type.IsAbstract && type.IsSubclassOf(typeof(NodeSketch.Nodes.Node))) { TitleAttribute titleAttrib = type.GetCustomAttribute <TitleAttribute>(false); string[] title; if (titleAttrib != null) { title = titleAttrib.Title.Split('/'); } else { title = type.FullName.Split('.'); } library.Add(new NodeTemplate(title, "UXML/Nodes/GraphNode", "Styles/Nodes/GraphNode", type)); } } } return(library); }
protected override void ConstructFieldTemplates(NodeProvider nodeProvider, Dictionary <Type, NodeFieldTemplate> templates) { NodeLibrary library = nodeProvider.GetNodeLibrary(); foreach (var nodeTemplate in library.nodeTemplates) { Type type = nodeTemplate.RuntimeNodeType; var fields = type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); var template = new NodeFieldTemplate(); var supressInput = type.GetCustomAttribute <SupressInputAttribute>(); // All tasks (nodes in this case) need to have an input, that isnt in the code of the behaviours // so we just add it in the first thing we do. if (supressInput == null) { template.InputPorts.Add(new PortDescription("Input", typeof(Task), PortDirection.Input, false, false)); } foreach (var field in fields) { OutputAttribute output = field.GetCustomAttribute <OutputAttribute>(); InputAttribute input = field.GetCustomAttribute <InputAttribute>(); SerializeField property = field.GetCustomAttribute <SerializeField>(); bool autoAdd = false; bool isInput = input == null ? false : true; bool isOutput = output == null ? false : true; if (output != null) { autoAdd = output.AutoAddPortOnConnect; } if (input != null) { autoAdd = input.AutoAddPortOnConnect; } bool isList = IsListType(field); if (output != null || input != null) { if (IsListType(field)) { AddGenericPort(template, field, isInput, isOutput, autoAdd); } else { AddNonGenericPort(template, field.FieldType, field.Name, field.Name, isInput, isOutput, autoAdd); } } else if (property != null) { AddNonGenericProperty(template, field, field.Name, field.Name); } } templates.Add(type, template); } }
private void RegisterPluginNodesFromAssembly(Assembly assembly, NodeLibrary libraryDependency) { foreach (var exportedType in assembly.ExportedTypes) { if (typeof(Node).IsAssignableFrom(exportedType) && !exportedType.IsAbstract) { TryRegisterNode(libraryDependency, exportedType); } } }
/// <inheritdoc/> public bool AddPluginFromDirectory(string dirPath, NodeLibrary libraryDependency) { try { foreach (var pluginAssembly in GetPluginAssemblies(dirPath)) { LoadAssembly(pluginAssembly, libraryDependency); } return(true); } catch (TypeLoadException) { return(false); } }
protected override NodeLibrary ConstructNodeLibrary(NodeLibrary library) { var assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (var assembly in assemblies) { Type[] types = assembly.GetTypes(); foreach (var type in types) { TitleAttribute titleAttrib = type.GetCustomAttribute <TitleAttribute>(false); string[] title; if (titleAttrib != null) { title = titleAttrib.Title.Split('/'); } else { title = type.FullName.Split('.'); } // Ignore abstract types if (type.IsAbstract) { continue; } if (type.IsSubclassOf(typeof(Composite))) { library.nodeTemplates.Add(new NodeTemplate(title, "UXML/Nodes/GraphNode", "Styles/Nodes/GraphNode", type)); } else if (type.IsSubclassOf(typeof(Decorator))) { library.nodeTemplates.Add(new NodeTemplate(title, "UXML/Nodes/ValueNode", "Styles/Nodes/GraphNode", type)); } else if (type.IsSubclassOf(typeof(Task))) { library.nodeTemplates.Add(new NodeTemplate(title, "UXML/Nodes/ValueNode", "Styles/Nodes/GraphNode", type)); } } } return(library); }
private void TryRegisterNode(NodeLibrary libraryDependency, Type exportedType) { try { var node = (Node)Activator.CreateInstance(exportedType); foreach (var terminal in node.Terminals) { ModelBase.SerializeableTypes.Add(terminal.Model.Type); } _nodeProvider.RegisterNode(node, libraryDependency); } catch (TypeLoadException) { Console.Error.WriteLine($"Unable to register node with type {exportedType}."); } catch (MissingMethodException) { Console.Error.WriteLine($"Unable to register node with type {exportedType}. This might be because it doesn't have a public parameterless constructor."); } }
private bool TryGetLibraryWithNameAndVersion(NodeLibrary library, out NodeLibrary otherLibrary) { otherLibrary = null; if (library.Name == null) { return(false); } bool SameName(NodeLibrary l) => l.Name == library.Name.ToLower(); bool SameMajorVersion(NodeLibrary l) => l.MajorVersion == library.MajorVersion; bool SameMinorVersion(NodeLibrary l) => l.MinorVersion == library.MinorVersion; bool SamePatch(NodeLibrary l) => l.Patch == library.Patch; otherLibrary = AvailableLibraries.FirstOrDefault(l => SameName(l) && SameMajorVersion(l) && SameMinorVersion(l) && SamePatch(l)); return(otherLibrary != null); }
private void AddLibraryToAvailableIfNewest(NodeLibrary library) { if (TryGetLibraryWithNameAndVersion(library, out var otherLibrary)) { if (!library.IsNewerVersionThan(otherLibrary)) { return; } AvailableLibraries.Remove(otherLibrary); AvailableLibraryItems.Remove(AvailableLibraryItems.FirstOrDefault(x => x.Library == otherLibrary)); AvailableLibraries.Add(library); AvailableLibraryItems.Add(new LibraryListItem(library, library.Name)); } else { AvailableLibraries.Add(library); AvailableLibraryItems.Add(new LibraryListItem(library, library.Name)); } }
public void TestNodeLibraryToString_ReturnsProperlyFormattedLibraryName() { var libraryNameToPath = new NodeLibrary("test", "", 1, 0, 0); Assert.AreEqual("test - 1.0.0", libraryNameToPath.ToString()); }
// TODO: Just pass in the library and get the name from that. public LibraryListItem(NodeLibrary library, string libraryDisplayName) { Library = library; LibraryDisplayName = libraryDisplayName; }
private bool IsLibraryInstalled(NodeLibrary libraryDescription) { return(InstalledLibraryItems.Any(i => i.LibraryDisplayName == libraryDescription.ToString())); }
private void LoadAssembly(Assembly assembly, NodeLibrary nodeLibrary) { RegisterPluginNodesFromAssembly(assembly, nodeLibrary); LoadSerializeableTypesFromAssembly(assembly); LoadColorsFromAssembly(assembly); }
private void OnTransportConnectedCb(NodeLibrary.Transport Transport, string msg) { DebugEx.TraceLog("OnConnected transport=" + Transport.ToString() + " msg=" + msg); }
private void OnTransportErrorCb(NodeLibrary.Transport Transport, TransportErrors Error, string msg) { DebugEx.TraceLog("OnTransportError transport=" + Transport.ToString() + " msg=" + msg); }
public List <SearchTreeEntry> CreateSearchTree(SearchWindowContext context) { // First build up temporary data structure containing group & title as an array of strings (the last one is the actual title) and associated node type. if (m_nodeProvider == null) { Debug.LogError("NodeProvider in Node Search Window is null cant construct search tree!"); return(new List <SearchTreeEntry>()); } NodeLibrary nodeLibrary = m_nodeProvider.GetNodeLibrary(); // Sort the entries lexicographically by group then title with the requirement that items always comes before sub-groups in the same group. // Example result: // - Art/BlendMode // - Art/Adjustments/ColorBalance // - Art/Adjustments/Contrast nodeLibrary.nodeTemplates.Sort((entry1, entry2) => { for (var i = 0; i < entry1.Title.Length; i++) { if (i >= entry2.Title.Length) { return(1); } var value = entry1.Title[i].CompareTo(entry2.Title[i]); if (value != 0) { // Make sure that leaves go before nodes if (entry1.Title.Length != entry2.Title.Length && (i == entry1.Title.Length - 1 || i == entry2.Title.Length - 1)) { return(entry1.Title.Length < entry2.Title.Length ? -1 : 1); } return(value); } } return(0); }); //* Build up the data structure needed by SearchWindow. // `groups` contains the current group path we're in. var groups = new List <string>(); // First item in the tree is the title of the window. var tree = new List <SearchTreeEntry> { new SearchTreeGroupEntry(new GUIContent("Add Node"), 0), }; foreach (var nodeEntry in nodeLibrary.nodeTemplates) { // `createIndex` represents from where we should add new group entries from the current entry's group path. var createIndex = int.MaxValue; // Compare the group path of the current entry to the current group path. for (var i = 0; i < nodeEntry.Title.Length - 1; i++) { var group = nodeEntry.Title[i]; if (i >= groups.Count) { // The current group path matches a prefix of the current entry's group path, so we add the // rest of the group path from the currrent entry. createIndex = i; break; } if (groups[i] != group) { // A prefix of the current group path matches a prefix of the current entry's group path, // so we remove everyfrom from the point where it doesn't match anymore, and then add the rest // of the group path from the current entry. groups.RemoveRange(i, groups.Count - i); createIndex = i; break; } } // Create new group entries as needed. // If we don't need to modify the group path, `createIndex` will be `int.MaxValue` and thus the loop won't run. for (var i = createIndex; i < nodeEntry.Title.Length - 1; i++) { var group = nodeEntry.Title[i]; groups.Add(group); tree.Add(new SearchTreeGroupEntry(new GUIContent(group)) { level = i + 1 }); } // Finally, add the actual entry. tree.Add(new SearchTreeEntry(new GUIContent(nodeEntry.Title.Last(), m_icon)) { level = nodeEntry.Title.Length, userData = nodeEntry }); } return(tree); }
/// <summary> /// Creates a new instance of <see cref="LibraryListItem"/> /// </summary> /// <param name="library">The <see cref="NodeLibrary"/> that this list item represents.</param> public LibraryListItem(NodeLibrary library) { Library = library; }