diff --git a/IPA.Loader/Loader/PluginLoader.cs b/IPA.Loader/Loader/PluginLoader.cs index f3f08807..a66ee4af 100644 --- a/IPA.Loader/Loader/PluginLoader.cs +++ b/IPA.Loader/Loader/PluginLoader.cs @@ -73,6 +73,8 @@ namespace IPA.Loader private PluginManifest manifest; + internal HashSet Dependencies { get; } = new HashSet(); + internal PluginManifest Manifest { get => manifest; @@ -281,30 +283,76 @@ namespace IPA.Loader internal static void ComputeLoadOrder() { - PluginsMetadata.Sort((a, b) => - { - if (a.Id == b.Id) return 0; - if (a.Id != null) +#if DEBUG + Logger.loader.Debug(string.Join(", ", PluginsMetadata.Select(p => p.ToString()))); +#endif + + bool InsertInto(HashSet root, PluginMetadata meta, bool isRoot = false) + { // this is slow, and hella recursive + bool inserted = false; + foreach (var sr in root) { - if (b.Manifest.Dependencies.ContainsKey(a.Id) || b.Manifest.LoadAfter.Contains(a.Id)) return -1; - if (b.Manifest.LoadBefore.Contains(a.Id)) return 1; + inserted = inserted || InsertInto(sr.Dependencies, meta); + + if (meta.Id != null) + if (sr.Manifest.Dependencies.ContainsKey(meta.Id) || sr.Manifest.LoadAfter.Contains(meta.Id)) + inserted = inserted || sr.Dependencies.Add(meta); + if (sr.Id != null) + if (meta.Manifest.LoadBefore.Contains(sr.Id)) + inserted = inserted || sr.Dependencies.Add(meta); } - if (b.Id != null) + + if (isRoot) { - if (a.Manifest.Dependencies.ContainsKey(b.Id) || a.Manifest.LoadAfter.Contains(b.Id)) return 1; - if (a.Manifest.LoadBefore.Contains(b.Id)) return -1; + foreach (var sr in root) + { + InsertInto(meta.Dependencies, sr); + + if (sr.Id != null) + if (meta.Manifest.Dependencies.ContainsKey(sr.Id) || meta.Manifest.LoadAfter.Contains(sr.Id)) + meta.Dependencies.Add(sr); + if (meta.Id != null) + if (sr.Manifest.LoadBefore.Contains(meta.Id)) + meta.Dependencies.Add(sr); + } + + root.Add(meta); } - return 0; - }); + return inserted; + } + + var pluginTree = new HashSet(); + foreach (var meta in PluginsMetadata) + InsertInto(pluginTree, meta, true); + + void DeTree(List into, HashSet tree) + { + foreach (var st in tree) + if (!into.Contains(st)) + { + DeTree(into, st.Dependencies); + into.Add(st); + } + } + + var deTreed = new List(); + DeTree(deTreed, pluginTree); + +#if DEBUG + Logger.loader.Debug(string.Join(", ", deTreed.Select(p => p.ToString()))); +#endif var metadata = new List(); var pluginsToLoad = new Dictionary(); - foreach (var meta in PluginsMetadata) + foreach (var meta in deTreed) { bool load = true; foreach (var dep in meta.Manifest.Dependencies) { +#if DEBUG + Logger.loader.Debug($"Looking for dependency {dep.Key} with version range {dep.Value.Intersect(new SemVer.Range("*.*.*"))}"); +#endif if (pluginsToLoad.ContainsKey(dep.Key) && dep.Value.IsSatisfied(pluginsToLoad[dep.Key])) continue; diff --git a/Refs/UnityEngine.CoreModule.dll b/Refs/UnityEngine.CoreModule.dll index bd347d7e..f6478af7 100644 Binary files a/Refs/UnityEngine.CoreModule.dll and b/Refs/UnityEngine.CoreModule.dll differ