diff --git a/BSIPA-ModList/BSIPA-ModList.csproj b/BSIPA-ModList/BSIPA-ModList.csproj
index cd96fcd9..9e4eb4a8 100644
--- a/BSIPA-ModList/BSIPA-ModList.csproj
+++ b/BSIPA-ModList/BSIPA-ModList.csproj
@@ -88,6 +88,7 @@
+
diff --git a/BSIPA-ModList/Plugin.cs b/BSIPA-ModList/Plugin.cs
index ac141662..b60c24a2 100644
--- a/BSIPA-ModList/Plugin.cs
+++ b/BSIPA-ModList/Plugin.cs
@@ -97,6 +97,9 @@ namespace BSIPA_ModList
if (ButtonUI.Instance == null)
new GameObject("BSIPA Mod List Object").AddComponent().Init();
+
+ if (WarningUI.Instance == null)
+ new GameObject("BSIPA Mod List Warning UI").AddComponent().Init();
}
}
diff --git a/BSIPA-ModList/UI/WarningUI.cs b/BSIPA-ModList/UI/WarningUI.cs
new file mode 100644
index 00000000..ecbfa2d0
--- /dev/null
+++ b/BSIPA-ModList/UI/WarningUI.cs
@@ -0,0 +1,149 @@
+using IPA.Loader;
+using IPA.Utilities;
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using UnityEngine;
+using UnityEngine.SceneManagement;
+
+namespace BSIPA_ModList.UI
+{
+ internal struct WarningEntry
+ {
+ public string ModName;
+ public string[] MissingDependencies;
+ public string[] DisabledDependencies;
+
+ public WarningEntry(string modName, string[] missingDependencies, string[] disabledDependencies)
+ {
+ ModName = modName;
+ MissingDependencies = missingDependencies;
+ DisabledDependencies = disabledDependencies;
+ }
+ }
+
+ internal class WarningUI : MonoBehaviour
+ {
+ internal static WarningUI Instance;
+ internal static bool firstShow = true;
+
+ public void Awake()
+ {
+ DontDestroyOnLoad(gameObject);
+ SceneManager.activeSceneChanged += this.SceneManager_activeSceneChanged;
+ }
+
+ private void SceneManager_activeSceneChanged(Scene from, Scene to)
+ {
+ if (to.name == "EmptyTransition")
+ {
+ if (Instance != null)
+ {
+ Instance.StopAllCoroutines();
+ Destroy(Instance.gameObject);
+ _mainFlow = null;
+ }
+ Instance = null;
+ }
+ }
+
+ public void Init()
+ {
+ Instance = this;
+
+ Logger.log.Debug("Warning UI Awake");
+ if (firstShow)
+ {
+ firstShow = false;
+ StartCoroutine(LookForUnmetDependencies());
+ }
+ }
+
+ private static MainFlowCoordinator _mainFlow;
+ private static SimpleDialogPromptViewController _warningDialog;
+ private static Queue _warningsQueue = new Queue();
+
+ private static IEnumerator LookForUnmetDependencies()
+ {
+ Logger.log.Debug("Waiting for MainFlowCoordinator to appear...");
+
+ yield return new WaitWhile(() => FindObjectOfType() == null);
+
+ Logger.log.Debug("Looking for unmet dependencies...");
+
+ lock (Instance)
+ {
+ if (_mainFlow == null)
+ {
+ _mainFlow = FindObjectOfType();
+ _warningDialog = _mainFlow.GetPrivateField("_simpleDialogPromptViewController");
+ }
+
+ _warningsQueue.Clear();
+ Dictionary loadedPlugins = PluginManager.AllPlugins.Select(x => x.Metadata).Concat(PluginManager.DisabledPlugins).Concat(PluginLoader.ignoredPlugins).ToDictionary(x => x.Id, y => y.Version);
+
+ foreach (var meta in PluginManager.AllPlugins.Select(x => x.Metadata).Concat(PluginManager.DisabledPlugins).Concat(PluginLoader.ignoredPlugins))
+ {
+ List disabledDependencies = new List();
+ List missingDependencies = new List();
+ foreach (var dep in meta.Manifest.Dependencies)
+ {
+#if DEBUG
+ Logger.log.Debug($"Looking for dependency {dep.Key} with version range {dep.Value.Intersect(new SemVer.Range("*.*.*"))}");
+#endif
+ if (loadedPlugins.ContainsKey(dep.Key) && dep.Value.IsSatisfied(loadedPlugins[dep.Key]))
+ continue;
+
+ if (loadedPlugins.ContainsKey(dep.Key) && dep.Value.IsSatisfied(loadedPlugins[dep.Key]))
+ {
+ Logger.log.Debug($"Dependency {dep.Key} was found, but disabled.");
+ disabledDependencies.Add($"{dep.Key}@{dep.Value.ToString()}");
+ }
+ else
+ {
+ Logger.log.Debug($"{meta.Name} is missing dependency {dep.Key}@{dep.Value}");
+ missingDependencies.Add($"{dep.Key}@{dep.Value.ToString()}");
+ }
+ }
+
+ if(disabledDependencies.Count > 0 || missingDependencies.Count > 0)
+ {
+ _warningsQueue.Enqueue(new WarningEntry(meta.Name, missingDependencies.ToArray(), disabledDependencies.ToArray()));
+ }
+ }
+
+ if (_warningsQueue.Count > 0)
+ {
+ yield return new WaitWhile(() => !_mainFlow.isActivated);
+
+ ShowWarningDialog();
+ }
+
+ yield break;
+ }
+ }
+
+ private static void ShowWarningDialog()
+ {
+ WarningEntry warning = _warningsQueue.Dequeue();
+ _warningDialog.Init("Unmet Dependencies", $"Mod {warning.ModName} has unmet dependencies!" +
+ (warning.MissingDependencies.Length > 0 ? $"\nMissing:\n{string.Join("\n", warning.MissingDependencies)}" : "") +
+ (warning.DisabledDependencies.Length > 0 ? $"\nDisabled:\n{string.Join("\n", warning.DisabledDependencies)}" : "")
+ , "Okay", WarningDialogDidFinish);
+ _mainFlow.InvokePrivateMethod("PresentViewController", _warningDialog, null, true);
+ }
+
+ private static void WarningDialogDidFinish(int button)
+ {
+ _mainFlow.InvokePrivateMethod("DismissViewController", _warningDialog, null, (_warningsQueue.Count > 0));
+
+ if (_warningsQueue.Count > 0)
+ {
+ ShowWarningDialog();
+ }
+ }
+ }
+}