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));
            }
        }