You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

149 lines
5.8 KiB

  1. using IPA.Loader;
  2. using IPA.Utilities;
  3. using System;
  4. using System.Collections;
  5. using System.Collections.Generic;
  6. using System.Linq;
  7. using System.Text;
  8. using System.Threading.Tasks;
  9. using UnityEngine;
  10. using UnityEngine.SceneManagement;
  11. namespace BSIPA_ModList.UI
  12. {
  13. internal struct WarningEntry
  14. {
  15. public string ModName;
  16. public string[] MissingDependencies;
  17. public string[] DisabledDependencies;
  18. public WarningEntry(string modName, string[] missingDependencies, string[] disabledDependencies)
  19. {
  20. ModName = modName;
  21. MissingDependencies = missingDependencies;
  22. DisabledDependencies = disabledDependencies;
  23. }
  24. }
  25. internal class WarningUI : MonoBehaviour
  26. {
  27. internal static WarningUI Instance;
  28. internal static bool firstShow = true;
  29. public void Awake()
  30. {
  31. DontDestroyOnLoad(gameObject);
  32. SceneManager.activeSceneChanged += this.SceneManager_activeSceneChanged;
  33. }
  34. private void SceneManager_activeSceneChanged(Scene from, Scene to)
  35. {
  36. if (to.name == "EmptyTransition")
  37. {
  38. if (Instance != null)
  39. {
  40. Instance.StopAllCoroutines();
  41. Destroy(Instance.gameObject);
  42. _mainFlow = null;
  43. }
  44. Instance = null;
  45. }
  46. }
  47. public void Init()
  48. {
  49. Instance = this;
  50. Logger.log.Debug("Warning UI Awake");
  51. if (firstShow)
  52. {
  53. firstShow = false;
  54. StartCoroutine(LookForUnmetDependencies());
  55. }
  56. }
  57. private static MainFlowCoordinator _mainFlow;
  58. private static SimpleDialogPromptViewController _warningDialog;
  59. private static Queue<WarningEntry> _warningsQueue = new Queue<WarningEntry>();
  60. private static IEnumerator LookForUnmetDependencies()
  61. {
  62. Logger.log.Debug("Waiting for MainFlowCoordinator to appear...");
  63. yield return new WaitWhile(() => FindObjectOfType<MainFlowCoordinator>() == null);
  64. Logger.log.Debug("Looking for unmet dependencies...");
  65. lock (Instance)
  66. {
  67. if (_mainFlow == null)
  68. {
  69. _mainFlow = FindObjectOfType<MainFlowCoordinator>();
  70. _warningDialog = _mainFlow.GetPrivateField<SimpleDialogPromptViewController>("_simpleDialogPromptViewController");
  71. }
  72. _warningsQueue.Clear();
  73. Dictionary<string, SemVer.Version> loadedPlugins = PluginManager.AllPlugins.Select(x => x.Metadata).Concat(PluginManager.DisabledPlugins).Concat(PluginLoader.ignoredPlugins).ToDictionary(x => x.Id, y => y.Version);
  74. foreach (var meta in PluginManager.AllPlugins.Select(x => x.Metadata).Concat(PluginManager.DisabledPlugins).Concat(PluginLoader.ignoredPlugins))
  75. {
  76. List<string> disabledDependencies = new List<string>();
  77. List<string> missingDependencies = new List<string>();
  78. foreach (var dep in meta.Manifest.Dependencies)
  79. {
  80. #if DEBUG
  81. Logger.log.Debug($"Looking for dependency {dep.Key} with version range {dep.Value.Intersect(new SemVer.Range("*.*.*"))}");
  82. #endif
  83. if (loadedPlugins.ContainsKey(dep.Key) && dep.Value.IsSatisfied(loadedPlugins[dep.Key]))
  84. continue;
  85. if (loadedPlugins.ContainsKey(dep.Key) && dep.Value.IsSatisfied(loadedPlugins[dep.Key]))
  86. {
  87. Logger.log.Debug($"Dependency {dep.Key} was found, but disabled.");
  88. disabledDependencies.Add($"{dep.Key}@{dep.Value.ToString()}");
  89. }
  90. else
  91. {
  92. Logger.log.Debug($"{meta.Name} is missing dependency {dep.Key}@{dep.Value}");
  93. missingDependencies.Add($"{dep.Key}@{dep.Value.ToString()}");
  94. }
  95. }
  96. if(disabledDependencies.Count > 0 || missingDependencies.Count > 0)
  97. {
  98. _warningsQueue.Enqueue(new WarningEntry(meta.Name, missingDependencies.ToArray(), disabledDependencies.ToArray()));
  99. }
  100. }
  101. if (_warningsQueue.Count > 0)
  102. {
  103. yield return new WaitWhile(() => !_mainFlow.isActivated);
  104. ShowWarningDialog();
  105. }
  106. yield break;
  107. }
  108. }
  109. private static void ShowWarningDialog()
  110. {
  111. WarningEntry warning = _warningsQueue.Dequeue();
  112. _warningDialog.Init("Unmet Dependencies", $"Mod <b>{warning.ModName}</b> has unmet dependencies!" +
  113. (warning.MissingDependencies.Length > 0 ? $"\nMissing:\n<color=red>{string.Join("\n", warning.MissingDependencies)}</color>" : "") +
  114. (warning.DisabledDependencies.Length > 0 ? $"\nDisabled:\n<color=#C2C2C2>{string.Join("\n", warning.DisabledDependencies)}</color>" : "")
  115. , "Okay", WarningDialogDidFinish);
  116. _mainFlow.InvokePrivateMethod("PresentViewController", _warningDialog, null, true);
  117. }
  118. private static void WarningDialogDidFinish(int button)
  119. {
  120. _mainFlow.InvokePrivateMethod("DismissViewController", _warningDialog, null, (_warningsQueue.Count > 0));
  121. if (_warningsQueue.Count > 0)
  122. {
  123. ShowWarningDialog();
  124. }
  125. }
  126. }
  127. }