예제 #1
0
        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
            {
                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 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");
                        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;
                            }
                        }

                        // 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);
                        shouldAutoExit = false;
                    }
                    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]);
                }

                // 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 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 (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"));
            }
        }
        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"));
            }
        }