private DependencyGraph(IList <T> mods, Func <T, string> modNameGetter) { int size = mods.Count; vertices = new Vertex[size]; IDictionary <string, Vertex> nameLookup = new Dictionary <string, Vertex>(size); // Create a vertex in the dependency graph for each mod to load for (int i = 0; i < size; ++i) { Assembly modAssembly = mods[i].Assembly; string modName = modNameGetter(mods[i]); Vertex modVertex = new Vertex(i, mods[i], modName); vertices[i] = modVertex; nameLookup[modAssembly.GetName().Name] = modVertex; } // Add an edge for each dependency between mods IDictionary <string, IList <AssemblyName> > modsWithMissingDeps = new SortedDictionary <string, IList <AssemblyName> >(); List <AssemblyName> missingDependencies = new List <AssemblyName>(); HashSet <string> optionalDependencies = new HashSet <string>(); foreach (Vertex modVertex in vertices) { Assembly modAssembly = modVertex.mod.Assembly; missingDependencies.Clear(); optionalDependencies.Clear(); MelonOptionalDependenciesAttribute optionals = (MelonOptionalDependenciesAttribute)Attribute.GetCustomAttribute(modAssembly, typeof(MelonOptionalDependenciesAttribute)); if (optionals != null && optionals.AssemblyNames != null) { optionalDependencies.UnionWith(optionals.AssemblyNames); } foreach (AssemblyName dependency in modAssembly.GetReferencedAssemblies()) { if (nameLookup.TryGetValue(dependency.Name, out Vertex dependencyVertex)) { modVertex.dependencies.Add(dependencyVertex); dependencyVertex.dependents.Add(modVertex); } else if (!TryLoad(dependency) && !optionalDependencies.Contains(dependency.Name)) { missingDependencies.Add(dependency); } } if (missingDependencies.Count > 0) { // modVertex.skipLoading = true; modsWithMissingDeps.Add(modNameGetter(modVertex.mod), missingDependencies.ToArray()); } } if (modsWithMissingDeps.Count > 0) { // Some mods are missing dependencies. Don't load these mods and show an error message MelonLogger.LogWarning(BuildMissingDependencyMessage(modsWithMissingDeps)); } }
private DependencyGraph(IList <T> melons) { int size = melons.Count; vertices = new Vertex[size]; Dictionary <string, Vertex> nameLookup = new Dictionary <string, Vertex>(size); // Create a vertex in the dependency graph for each Melon to load for (int i = 0; i < size; ++i) { Assembly melonAssembly = melons[i].Assembly; string melonName = melons[i].Info.Name; Vertex melonVertex = new Vertex(i, melons[i], melonName); vertices[i] = melonVertex; nameLookup[melonAssembly.GetName().Name] = melonVertex; } // Add an edge for each dependency between Melons SortedDictionary <string, IList <AssemblyName> > melonsWithMissingDeps = new SortedDictionary <string, IList <AssemblyName> >(); SortedDictionary <string, IList <AssemblyName> > melonsWithIncompatibilities = new SortedDictionary <string, IList <AssemblyName> >(); List <AssemblyName> missingDependencies = new List <AssemblyName>(); List <AssemblyName> incompatibilities = new List <AssemblyName>(); HashSet <string> optionalDependencies = new HashSet <string>(); HashSet <string> additionalDependencies = new HashSet <string>(); foreach (Vertex melonVertex in vertices) { Assembly melonAssembly = melonVertex.melon.Assembly; missingDependencies.Clear(); optionalDependencies.Clear(); incompatibilities.Clear(); additionalDependencies.Clear(); MelonOptionalDependenciesAttribute optionals = (MelonOptionalDependenciesAttribute)Attribute.GetCustomAttribute(melonAssembly, typeof(MelonOptionalDependenciesAttribute)); if ((optionals != null) && (optionals.AssemblyNames != null)) { optionalDependencies.UnionWith(optionals.AssemblyNames); } MelonAdditionalDependenciesAttribute additionals = (MelonAdditionalDependenciesAttribute)Attribute.GetCustomAttribute(melonAssembly, typeof(MelonAdditionalDependenciesAttribute)); if ((additionals != null) && (additionals.AssemblyNames != null)) { additionalDependencies.UnionWith(additionals.AssemblyNames); } MelonIncompatibleAssembliesAttribute incompatibleAssemblies = (MelonIncompatibleAssembliesAttribute)Attribute.GetCustomAttribute(melonAssembly, typeof(MelonIncompatibleAssembliesAttribute)); if ((incompatibleAssemblies != null) && (incompatibleAssemblies.AssemblyNames != null)) { foreach (string name in incompatibleAssemblies.AssemblyNames) { foreach (Vertex v in vertices) { AssemblyName assemblyName = v.melon.Assembly.GetName(); if ((v != melonVertex) && (assemblyName.Name == name)) { incompatibilities.Add(assemblyName); v.skipLoading = true; } } } } foreach (AssemblyName dependency in melonAssembly.GetReferencedAssemblies()) { if (nameLookup.TryGetValue(dependency.Name, out Vertex dependencyVertex)) { melonVertex.dependencies.Add(dependencyVertex); dependencyVertex.dependents.Add(melonVertex); } else if (!TryLoad(dependency) && !optionalDependencies.Contains(dependency.Name)) { missingDependencies.Add(dependency); } } foreach (string dependencyName in additionalDependencies) { AssemblyName dependency = new AssemblyName(dependencyName); if (nameLookup.TryGetValue(dependencyName, out Vertex dependencyVertex)) { melonVertex.dependencies.Add(dependencyVertex); dependencyVertex.dependents.Add(melonVertex); } else if (!TryLoad(dependency)) { missingDependencies.Add(dependency); } } if (missingDependencies.Count > 0) { // melonVertex.skipLoading = true; melonsWithMissingDeps.Add(melonVertex.melon.Info.Name, missingDependencies.ToArray()); } if (incompatibilities.Count > 0) { melonsWithIncompatibilities.Add(melonVertex.melon.Info.Name, incompatibilities.ToArray()); } } // Some Melons are missing dependencies. Don't load these Melons and show an error message if (melonsWithMissingDeps.Count > 0) { MelonLogger.Warning(BuildMissingDependencyMessage(melonsWithMissingDeps)); } if (melonsWithIncompatibilities.Count > 0) { MelonLogger.Warning(BuildIncompatibleAssembliesMessage(melonsWithIncompatibilities)); } }