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[] IgnoredDependencies;
|
|
public string[] DisabledDependencies;
|
|
|
|
public WarningEntry(string modName, string[] missingDependencies, string[] ignoredDependencies, string[] disabledDependencies)
|
|
{
|
|
ModName = modName;
|
|
MissingDependencies = missingDependencies;
|
|
IgnoredDependencies = ignoredDependencies;
|
|
DisabledDependencies = disabledDependencies;
|
|
}
|
|
}
|
|
|
|
internal class WarningUI : MonoBehaviour
|
|
{ // TODO: rework this to just use disable/ignore reason
|
|
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<WarningEntry> _warningsQueue = new Queue<WarningEntry>();
|
|
|
|
private static IEnumerator LookForUnmetDependencies()
|
|
{
|
|
Logger.log.Debug("Waiting for MainFlowCoordinator to appear...");
|
|
|
|
yield return new WaitWhile(() => FindObjectOfType<MainFlowCoordinator>() == null);
|
|
|
|
Logger.log.Debug("Looking for unmet dependencies...");
|
|
|
|
lock (Instance)
|
|
{
|
|
if (_mainFlow == null)
|
|
{
|
|
_mainFlow = FindObjectOfType<MainFlowCoordinator>();
|
|
_warningDialog = _mainFlow.GetPrivateField<SimpleDialogPromptViewController>("_simpleDialogPromptViewController");
|
|
}
|
|
|
|
_warningsQueue.Clear();
|
|
|
|
var enabledPlugins = PluginManager.AllPlugins.Select(p => p.Metadata).Where(x => x.Id != null).ToDictionary(x => x.Id, y => y.Version);
|
|
var ignoredPlugins = PluginLoader.ignoredPlugins.Where(x => x.Id != null).ToDictionary(x => x.Id, y => y.Version);
|
|
var disabledPlugins = PluginManager.DisabledPlugins.Where(x => x.Id != null).ToDictionary(x => x.Id, y => y.Version);
|
|
|
|
// iterate only disabled and ignored, as thats where missing deps can end up
|
|
foreach (var meta in PluginManager.DisabledPlugins.Concat(PluginLoader.ignoredPlugins))
|
|
{
|
|
List<string> disabledDependencies = new List<string>();
|
|
List<string> ignoredDependencies = new List<string>();
|
|
List<string> missingDependencies = new List<string>();
|
|
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 (disabledPlugins.TryGetValue(dep.Key, out var version) && dep.Value.IsSatisfied(version))
|
|
{
|
|
Logger.log.Debug($"Dependency {dep.Key} was found, but disabled.");
|
|
disabledDependencies.Add($"{dep.Key} {dep.Value.ToString()}");
|
|
}
|
|
else if (ignoredPlugins.TryGetValue(dep.Key, out version) && dep.Value.IsSatisfied(version))
|
|
{
|
|
Logger.log.Debug($"Dependency {dep.Key} was found, but was ignored, likely due to a missing dependency.");
|
|
ignoredDependencies.Add($"{dep.Key} {dep.Value.ToString()}");
|
|
}
|
|
else if (enabledPlugins.TryGetValue(dep.Key, out version) && dep.Value.IsSatisfied(version))
|
|
{
|
|
// do nothing, this was probably user disabled
|
|
}
|
|
else
|
|
{
|
|
Logger.log.Debug($"{meta.Name} is missing dependency {dep.Key} {dep.Value}");
|
|
missingDependencies.Add($"{dep.Key} {dep.Value.ToString()}");
|
|
}
|
|
|
|
}
|
|
|
|
if(disabledDependencies.Count > 0 || ignoredDependencies.Count > 0 || missingDependencies.Count > 0)
|
|
_warningsQueue.Enqueue(new WarningEntry(meta.Name, missingDependencies.ToArray(), ignoredDependencies.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 <b>{warning.ModName}</b> has unmet dependencies!" +
|
|
(warning.MissingDependencies.Length > 0 ? $"\nMissing:\n<color=red>{string.Join("\n", warning.MissingDependencies)}</color>" : "") +
|
|
(warning.IgnoredDependencies.Length > 0 ? $"\nIgnored:\n<color=#C2B2B2>{string.Join("\n", warning.IgnoredDependencies)}</color>" : "") +
|
|
(warning.DisabledDependencies.Length > 0 ? $"\nDisabled:\n<color=#C2C2C2>{string.Join("\n", warning.DisabledDependencies)}</color>" : "")
|
|
, "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();
|
|
}
|
|
}
|
|
}
|
|
}
|