public void Fetch() { // 1. Download the mod updates database updateCatalog = ModUpdaterHelper.DownloadModUpdateList(); // 2. Find out what actually has been updated if (updateCatalog != null) { availableUpdatesCatalog = ModUpdaterHelper.ListAvailableUpdates(updateCatalog, excludeBlacklist: false); } }
public override IEnumerator Enter(Oui from) { Everest.Loader.AutoLoadNewMods = false; menu = new TextMenu(); // display the title and a dummy "Fetching" button menu.Add(new TextMenu.Header(Dialog.Clean("MODUPDATECHECKER_MENU_TITLE"))); menu.Add(subHeader = new TextMenuExt.SubHeaderExt(Dialog.Clean("MODUPDATECHECKER_MENU_HEADER"))); fetchingButton = new TextMenu.Button(Dialog.Clean("MODUPDATECHECKER_FETCHING")); fetchingButton.Disabled = true; menu.Add(fetchingButton); Scene.Add(menu); menu.Visible = Visible = true; menu.Focused = false; for (float p = 0f; p < 1f; p += Engine.DeltaTime * 4f) { menu.X = offScreenX + -1920f * Ease.CubeOut(p); alpha = Ease.CubeOut(p); yield return(null); } menu.Focused = true; menuOnScreen = true; task = new Task(() => { // 1. Download the mod updates database updateCatalog = ModUpdaterHelper.DownloadModUpdateList(); // 2. Find out what actually has been updated if (updateCatalog != null) { availableUpdatesCatalog = ModUpdaterHelper.ListAvailableUpdates(updateCatalog); } }); task.Start(); }
private void downloadAllDependencies() { // 1. Compute the list of dependencies we must download. LogLine(Dialog.Clean("DEPENDENCYDOWNLOADER_DOWNLOADING_DATABASE")); Dictionary <string, ModUpdateInfo> availableDownloads = ModUpdaterHelper.DownloadModUpdateList(); if (availableDownloads == null) { shouldAutoRestart = false; shouldRestart = false; LogLine(Dialog.Clean("DEPENDENCYDOWNLOADER_DOWNLOAD_DATABASE_FAILED")); } else { Logger.Log("OuiDependencyDownloader", "Computing dependencies to download..."); // these mods are not installed currently, we will install them Dictionary <string, ModUpdateInfo> modsToInstall = new Dictionary <string, ModUpdateInfo>(); // these mods are already installed, but need an update to satisfy the dependency Dictionary <string, ModUpdateInfo> modsToUpdate = new Dictionary <string, ModUpdateInfo>(); Dictionary <string, EverestModuleMetadata> modsToUpdateCurrentVersions = new Dictionary <string, EverestModuleMetadata>(); // Everest should be updated to satisfy a dependency on Everest bool shouldUpdateEverest = false; // these mods are absent from the database HashSet <string> modsNotFound = new HashSet <string>(); // these mods have multiple downloads, and as such, should be installed manually HashSet <string> modsNotInstallableAutomatically = new HashSet <string>(); // these mods are blacklisted, and should be removed from the blacklist instead of being re-installed HashSet <string> modsBlacklisted = new HashSet <string>(); // these mods are in the database, but the version found in there won't satisfy the dependency Dictionary <string, HashSet <Version> > modsWithIncompatibleVersionInDatabase = new Dictionary <string, HashSet <Version> >(); Dictionary <string, string> modsDatabaseVersions = new Dictionary <string, string>(); foreach (EverestModuleMetadata dependency in MissingDependencies) { if (Everest.Loader.Delayed.Any(delayedMod => dependency.Name == delayedMod.Item1.Name)) { Logger.Log("OuiDependencyDownloader", $"{dependency.Name} is installed but failed to load, skipping"); } else if (dependency.Name == "Everest") { Logger.Log("OuiDependencyDownloader", $"Everest should be updated"); shouldUpdateEverest = true; shouldAutoRestart = false; // TODO: maybe check more precisely for blacklisted mods? We're only basing ourselves on the name here. } else if (Everest.Loader.Blacklist.Contains($"{dependency.Name}.zip")) { Logger.Log("OuiDependencyDownloader", $"{dependency.Name} is blacklisted, and should be unblacklisted instead"); modsBlacklisted.Add(dependency.Name); shouldAutoRestart = false; } else if (!availableDownloads.ContainsKey(dependency.Name)) { Logger.Log("OuiDependencyDownloader", $"{dependency.Name} was not found in the database"); modsNotFound.Add(dependency.Name); shouldAutoRestart = false; } else if (availableDownloads[dependency.Name].xxHash.Count > 1) { Logger.Log("OuiDependencyDownloader", $"{dependency.Name} has multiple versions and cannot be installed automatically"); modsNotInstallableAutomatically.Add(dependency.Name); shouldAutoRestart = false; } else if (!isVersionCompatible(dependency.Version, availableDownloads[dependency.Name].Version)) { Logger.Log("OuiDependencyDownloader", $"{dependency.Name} has a version in database ({availableDownloads[dependency.Name].Version}) that would not satisfy dependency ({dependency.Version})"); // add the required version to the list of versions for this mod HashSet <Version> requiredVersions = modsWithIncompatibleVersionInDatabase.TryGetValue(dependency.Name, out HashSet <Version> result) ? result : new HashSet <Version>(); requiredVersions.Add(dependency.Version); modsWithIncompatibleVersionInDatabase[dependency.Name] = requiredVersions; modsDatabaseVersions[dependency.Name] = availableDownloads[dependency.Name].Version; shouldAutoRestart = false; } else { EverestModuleMetadata installedVersion = null; foreach (EverestModule module in Everest.Modules) { // note: if the mod is installed, but not as a zip, this will be treated as a fresh install rather than an update. // this is fine since zips take the priority over directories, and we cannot update directory mods anyway. if (module.Metadata.PathArchive != null && module.Metadata.Name == dependency.Name) { installedVersion = module.Metadata; break; } } if (installedVersion != null) { Logger.Log("OuiDependencyDownloader", $"{dependency.Name} is already installed and will be updated"); modsToUpdate[dependency.Name] = availableDownloads[dependency.Name]; modsToUpdateCurrentVersions[dependency.Name] = installedVersion; } else { Logger.Log("OuiDependencyDownloader", $"{dependency.Name} will be installed"); modsToInstall[dependency.Name] = availableDownloads[dependency.Name]; } } } // actually install the mods now foreach (ModUpdateInfo modToInstall in modsToInstall.Values) { downloadDependency(modToInstall, null); } foreach (ModUpdateInfo modToUpdate in modsToUpdate.Values) { downloadDependency(modToUpdate, modsToUpdateCurrentVersions[modToUpdate.Name]); } // display all mods that couldn't be accounted for if (shouldUpdateEverest) { LogLine(Dialog.Clean("DEPENDENCYDOWNLOADER_MUST_UPDATE_EVEREST")); } foreach (string mod in modsNotFound) { LogLine(string.Format(Dialog.Get("DEPENDENCYDOWNLOADER_MOD_NOT_FOUND"), mod)); } foreach (string mod in modsNotInstallableAutomatically) { LogLine(string.Format(Dialog.Get("DEPENDENCYDOWNLOADER_MOD_NOT_AUTO_INSTALLABLE"), mod)); } foreach (string mod in modsBlacklisted) { LogLine(string.Format(Dialog.Get("DEPENDENCYDOWNLOADER_MOD_BLACKLISTED"), mod)); } foreach (string mod in modsWithIncompatibleVersionInDatabase.Keys) { LogLine(string.Format(Dialog.Get("DEPENDENCYDOWNLOADER_MOD_WRONG_VERSION"), mod, string.Join(", ", modsWithIncompatibleVersionInDatabase[mod]), modsDatabaseVersions[mod])); } } Progress = 1; ProgressMax = 1; if (shouldAutoRestart) { // there are no errors to display: restart automatically LogLine(Dialog.Clean("DEPENDENCYDOWNLOADER_RESTARTING")); for (int i = 3; i > 0; --i) { Lines[Lines.Count - 1] = string.Format(Dialog.Get("DEPENDENCYDOWNLOADER_RESTARTING_IN"), i); Thread.Sleep(1000); } Lines[Lines.Count - 1] = Dialog.Clean("DEPENDENCYDOWNLOADER_RESTARTING"); Everest.QuickFullRestart(); } else if (shouldRestart) { LogLine("\n" + Dialog.Clean("DEPENDENCYDOWNLOADER_PRESS_BACK_TO_RESTART")); } else { LogLine("\n" + Dialog.Clean("DEPENDENCYDOWNLOADER_PRESS_BACK_TO_GO_BACK")); } }
private void downloadAllDependencies() { // 1. Compute the list of dependencies we must download. LogLine(Dialog.Clean("DEPENDENCYDOWNLOADER_DOWNLOADING_DATABASE")); Everest.Updater.Entry everestVersionToInstall = null; Dictionary <string, ModUpdateInfo> availableDownloads = ModUpdaterHelper.DownloadModUpdateList(); if (availableDownloads == null) { shouldAutoExit = false; shouldRestart = false; LogLine(Dialog.Clean("DEPENDENCYDOWNLOADER_DOWNLOAD_DATABASE_FAILED")); } else { // load information on all installed mods, so that we can spot blacklisted ones easily. LogLine(Dialog.Clean("DEPENDENCYDOWNLOADER_LOADING_INSTALLED_MODS")); Progress = 0; ProgressMax = 100; Dictionary <string, EverestModuleMetadata[]> allModsInformationFlipped = OuiModToggler.LoadAllModYamls(progress => { Lines[Lines.Count - 1] = $"{Dialog.Clean("DEPENDENCYDOWNLOADER_LOADING_INSTALLED_MODS")} ({(int) (progress * 100)}%)"; Progress = (int)(progress * 100); }); ProgressMax = 0; // but flip around the mapping for convenience. Dictionary <EverestModuleMetadata, string> allModsInformation = new Dictionary <EverestModuleMetadata, string>(); foreach (KeyValuePair <string, EverestModuleMetadata[]> mods in allModsInformationFlipped) { foreach (EverestModuleMetadata mod in mods.Value) { allModsInformation[mod] = mods.Key; } } Lines[Lines.Count - 1] = $"{Dialog.Clean("DEPENDENCYDOWNLOADER_LOADING_INSTALLED_MODS")} {Dialog.Clean("DEPENDENCYDOWNLOADER_DONE")}"; Logger.Log("OuiDependencyDownloader", "Computing dependencies to download..."); // these mods are not installed currently, we will install them Dictionary <string, ModUpdateInfo> modsToInstall = new Dictionary <string, ModUpdateInfo>(); // these mods are already installed, but need an update to satisfy the dependency Dictionary <string, ModUpdateInfo> modsToUpdate = new Dictionary <string, ModUpdateInfo>(); Dictionary <string, EverestModuleMetadata> modsToUpdateCurrentVersions = new Dictionary <string, EverestModuleMetadata>(); // Everest should be updated to satisfy a dependency on Everest bool shouldUpdateEverestManually = false; // these mods are absent from the database HashSet <string> modsNotFound = new HashSet <string>(); // these mods have multiple downloads, and as such, should be installed manually HashSet <string> modsNotInstallableAutomatically = new HashSet <string>(); // these mods should be unblacklisted. HashSet <string> modFilenamesToUnblacklist = new HashSet <string>(); // these mods are in the database, but the version found in there won't satisfy the dependency Dictionary <string, HashSet <Version> > modsWithIncompatibleVersionInDatabase = new Dictionary <string, HashSet <Version> >(); Dictionary <string, string> modsDatabaseVersions = new Dictionary <string, string>(); foreach (EverestModuleMetadata dependency in MissingDependencies) { if (Everest.Loader.Delayed.Any(delayedMod => dependency.Name == delayedMod.Item1.Name)) { Logger.Log("OuiDependencyDownloader", $"{dependency.Name} is installed but failed to load, skipping"); } else if (dependency.Name == "Everest") { Logger.Log("OuiDependencyDownloader", $"Everest should be updated"); shouldAutoExit = false; if (dependency.Version.Major != 1 || dependency.Version.Build > 0 || dependency.Version.Revision > 0) { // the Everest version is not 1.XXX.0.0: Everest should be updated manually because this shouldn't happen. shouldUpdateEverestManually = true; } else if (!shouldUpdateEverestManually && (everestVersionToInstall == null || everestVersionToInstall.Build < dependency.Version.Minor)) { everestVersionToInstall = findEverestVersionToInstall(dependency.Version.Minor); if (everestVersionToInstall == null) { // a suitable version was not found! so, it should be installed manually. shouldUpdateEverestManually = true; } } } else if (tryUnblacklist(dependency, allModsInformation, modFilenamesToUnblacklist)) { Logger.Log("OuiDependencyDownloader", $"{dependency.Name} is blacklisted, and should be unblacklisted instead"); } else if (!availableDownloads.ContainsKey(dependency.Name)) { Logger.Log("OuiDependencyDownloader", $"{dependency.Name} was not found in the database"); modsNotFound.Add(dependency.Name); shouldAutoExit = false; } else if (availableDownloads[dependency.Name].xxHash.Count > 1) { Logger.Log("OuiDependencyDownloader", $"{dependency.Name} has multiple versions and cannot be installed automatically"); modsNotInstallableAutomatically.Add(dependency.Name); shouldAutoExit = false; } else if (!isVersionCompatible(dependency.Version, availableDownloads[dependency.Name].Version)) { Logger.Log("OuiDependencyDownloader", $"{dependency.Name} has a version in database ({availableDownloads[dependency.Name].Version}) that would not satisfy dependency ({dependency.Version})"); // add the required version to the list of versions for this mod HashSet <Version> requiredVersions = modsWithIncompatibleVersionInDatabase.TryGetValue(dependency.Name, out HashSet <Version> result) ? result : new HashSet <Version>(); requiredVersions.Add(dependency.Version); modsWithIncompatibleVersionInDatabase[dependency.Name] = requiredVersions; modsDatabaseVersions[dependency.Name] = availableDownloads[dependency.Name].Version; shouldAutoExit = false; } else { EverestModuleMetadata installedVersion = null; foreach (EverestModule module in Everest.Modules) { // note: if the mod is installed, but not as a zip, this will be treated as a fresh install rather than an update. // this is fine since zips take the priority over directories, and we cannot update directory mods anyway. if (module.Metadata.PathArchive != null && module.Metadata.Name == dependency.Name) { installedVersion = module.Metadata; break; } } if (installedVersion != null) { Logger.Log("OuiDependencyDownloader", $"{dependency.Name} is already installed and will be updated"); modsToUpdate[dependency.Name] = availableDownloads[dependency.Name]; modsToUpdateCurrentVersions[dependency.Name] = installedVersion; } else { Logger.Log("OuiDependencyDownloader", $"{dependency.Name} will be installed"); modsToInstall[dependency.Name] = availableDownloads[dependency.Name]; } } } // actually install the mods now foreach (ModUpdateInfo modToInstall in modsToInstall.Values) { downloadDependency(modToInstall, null); } foreach (ModUpdateInfo modToUpdate in modsToUpdate.Values) { downloadDependency(modToUpdate, modsToUpdateCurrentVersions[modToUpdate.Name]); } // unblacklist mods if this is needed if (modFilenamesToUnblacklist.Count > 0) { // remove the mods from blacklist.txt if (!unblacklistMods(modFilenamesToUnblacklist)) { // something bad happened shouldAutoExit = false; shouldRestart = true; } foreach (string modFilename in modFilenamesToUnblacklist) { try { LogLine(string.Format(Dialog.Get("DEPENDENCYDOWNLOADER_MOD_UNBLACKLIST"), modFilename)); // remove the mod from the loaded blacklist while (Everest.Loader._Blacklist.Contains(modFilename)) { Everest.Loader._Blacklist.Remove(modFilename); } // hot load the mod if (modFilename.EndsWith(".zip")) { Everest.Loader.LoadZip(Path.Combine(Everest.Loader.PathMods, modFilename)); } else { Everest.Loader.LoadDir(Path.Combine(Everest.Loader.PathMods, modFilename)); } } catch (Exception e) { // something bad happened during the mod hot loading, log it and prompt to restart the game to load the mod. LogLine(Dialog.Clean("DEPENDENCYDOWNLOADER_UNBLACKLIST_FAILED")); Logger.LogDetailed(e); shouldAutoExit = false; shouldRestart = true; break; } } } // display all mods that couldn't be accounted for if (shouldUpdateEverestManually) { LogLine(Dialog.Clean("DEPENDENCYDOWNLOADER_MUST_UPDATE_EVEREST")); } foreach (string mod in modsNotFound) { LogLine(string.Format(Dialog.Get("DEPENDENCYDOWNLOADER_MOD_NOT_FOUND"), mod)); } foreach (string mod in modsNotInstallableAutomatically) { LogLine(string.Format(Dialog.Get("DEPENDENCYDOWNLOADER_MOD_NOT_AUTO_INSTALLABLE"), mod)); } foreach (string mod in modsWithIncompatibleVersionInDatabase.Keys) { LogLine(string.Format(Dialog.Get("DEPENDENCYDOWNLOADER_MOD_WRONG_VERSION"), mod, string.Join(", ", modsWithIncompatibleVersionInDatabase[mod]), modsDatabaseVersions[mod])); } } Progress = 1; ProgressMax = 1; if (shouldAutoExit) { // there are no errors to display: restart automatically if (shouldRestart) { LogLine(Dialog.Clean("DEPENDENCYDOWNLOADER_RESTARTING")); for (int i = 3; i > 0; --i) { Lines[Lines.Count - 1] = string.Format(Dialog.Get("DEPENDENCYDOWNLOADER_RESTARTING_IN"), i); Thread.Sleep(1000); } Lines[Lines.Count - 1] = Dialog.Clean("DEPENDENCYDOWNLOADER_RESTARTING"); Everest.QuickFullRestart(); } else { Exit(); } } else if (everestVersionToInstall != null) { LogLine("\n" + string.Format(Dialog.Get("DEPENDENCYDOWNLOADER_EVEREST_UPDATE"), everestVersionToInstall.Build)); this.everestVersionToInstall = everestVersionToInstall; } else if (shouldRestart) { LogLine("\n" + Dialog.Clean("DEPENDENCYDOWNLOADER_PRESS_BACK_TO_RESTART")); } else { LogLine("\n" + Dialog.Clean("DEPENDENCYDOWNLOADER_PRESS_BACK_TO_GO_BACK")); } }