Beispiel #1
0
        /// <summary>
        /// Does the actual downloading of the mod. This is it's own function, to avoid double code
        /// </summary>
        /// <param name="update">The update info coming from the update server</param>
        /// <param name="mod">The mod metadata from Everest for the installed mod</param>
        /// <param name="button">The button for that mod shown on the interface</param>
        /// <returns>Bool wether the update failed or not</returns>
        private bool doDownloadModUpdate(ModUpdateInfo update, EverestModuleMetadata mod, TextMenu.Button button)
        {
            // we will download the mod to Celeste_Directory/[update.GetHashCode()].zip at first.
            string zipPath = Path.Combine(Everest.PathGame, $"modupdate-{update.GetHashCode()}.zip");

            try {
                // download it...
                button.Label = $"{ModUpdaterHelper.FormatModName(update.Name)} ({Dialog.Clean("MODUPDATECHECKER_DOWNLOADING")})";
                downloadMod(update, button, zipPath);

                // verify its checksum
                ModUpdaterHelper.VerifyChecksum(update, zipPath);

                // mark restarting as required, as we will do weird stuff like closing zips afterwards.
                shouldRestart = true;

                // install it
                button.Label = $"{ModUpdaterHelper.FormatModName(update.Name)} ({Dialog.Clean("MODUPDATECHECKER_INSTALLING")})";
                ModUpdaterHelper.InstallModUpdate(update, mod, zipPath);

                // done!
                button.Label = $"{ModUpdaterHelper.FormatModName(update.Name)} ({Dialog.Clean("MODUPDATECHECKER_UPDATED")})";

                return(true);
            } catch (Exception e) {
                // update failed
                button.Label = $"{ModUpdaterHelper.FormatModName(update.Name)} ({Dialog.Clean("MODUPDATECHECKER_FAILED")})";
                Logger.Log("OuiModUpdateList", $"Updating {update.Name} failed");
                Logger.LogDetailed(e);

                // try to delete mod-update.zip if it still exists.
                ModUpdaterHelper.TryDelete(zipPath);
                return(false);
            }
        }
Beispiel #2
0
        protected virtual void CreateModMenuSectionHeader(TextMenu menu, bool inGame, EventInstance snapshot)
        {
            Type type = SettingsType;
            EverestModuleSettings settings = _Settings;

            if (type == null || settings == null)
            {
                return;
            }

            string typeName = type.Name.ToLowerInvariant();

            if (typeName.EndsWith("settings"))
            {
                typeName = typeName.Substring(0, typeName.Length - 8);
            }
            string nameDefaultPrefix = $"modoptions_{typeName}_";

            string name; // We lazily reuse this field for the props later on.

            name = type.GetCustomAttribute <SettingNameAttribute>()?.Name ?? $"{nameDefaultPrefix}title";
            name = name.DialogCleanOrNull() ?? ModUpdaterHelper.FormatModName(Metadata.Name);

            menu.Add(new patch_TextMenu.patch_SubHeader(name + " | v." + Metadata.VersionString));
        }
Beispiel #3
0
        /// <summary>
        /// Downloads a mod update.
        /// </summary>
        /// <param name="update">The update info coming from the update server</param>
        /// <param name="button">The button for that mod shown on the interface</param>
        /// <param name="zipPath">The path to the zip the update will be downloaded to</param>
        private static void downloadMod(ModUpdateInfo update, TextMenu.Button button, string zipPath)
        {
            Logger.Log("OuiModUpdateList", $"Downloading {update.URL} to {zipPath}");

            Func <int, long, int, bool> progressCallback = (position, length, speed) => {
                if (ongoingUpdateCancelled)
                {
                    return(false);
                }

                if (length > 0)
                {
                    button.Label = $"{ModUpdaterHelper.FormatModName(update.Name)} ({((int) Math.Floor(100D * (position / (double) length)))}% @ {speed} KiB/s)";
                }
                else
                {
                    button.Label = $"{ModUpdaterHelper.FormatModName(update.Name)} ({((int) Math.Floor(position / 1000D))}KiB @ {speed} KiB/s)";
                }
                return(true);
            };

            try {
                Everest.Updater.DownloadFileWithProgress(update.URL, zipPath, progressCallback);
            } catch (WebException e) {
                Logger.Log(LogLevel.Warn, "OuiModUpdateList", $"Download failed, trying mirror {update.MirrorURL}");
                Logger.LogDetailed(e);
                Everest.Updater.DownloadFileWithProgress(update.MirrorURL, zipPath, progressCallback);
            }
        }
Beispiel #4
0
        /// <summary>
        /// Downloads a mod update.
        /// </summary>
        /// <param name="update">The update info coming from the update server</param>
        /// <param name="button">The button for that mod shown on the interface</param>
        /// <param name="zipPath">The path to the zip the update will be downloaded to</param>
        private static void downloadMod(ModUpdateInfo update, TextMenu.Button button, string zipPath)
        {
            Logger.Log("OuiModUpdateList", $"Downloading {update.URL} to {zipPath}");

            Everest.Updater.DownloadFileWithProgress(update.URL, zipPath, (position, length, speed) => {
                if (length > 0)
                {
                    button.Label = $"{ModUpdaterHelper.FormatModName(update.Name)} ({((int) Math.Floor(100D * (position / (double) length)))}% @ {speed} KiB/s)";
                }
                else
                {
                    button.Label = $"{ModUpdaterHelper.FormatModName(update.Name)} ({((int) Math.Floor(position / 1000D))}KiB @ {speed} KiB/s)";
                }
            });
        }
Beispiel #5
0
        private void autoUpdate(SortedDictionary <ModUpdateInfo, EverestModuleMetadata> updateList)
        {
            int currentlyUpdatedModIndex = 1;

            // this is common to all mods.
            string zipPath = Path.Combine(Everest.PathGame, "mod-update.zip");

            bool restartRequired = false;
            bool failuresOccured = false;

            // iterate through all mods to update now.
            foreach (ModUpdateInfo update in updateList.Keys)
            {
                // common beginning for all messages: f.e. [1/3] Auto-updating Polygon Dreams
                string progressString = $"[{currentlyUpdatedModIndex}/{updateList.Count}] {Dialog.Clean("AUTOUPDATECHECKER_UPDATING")} {ModUpdaterHelper.FormatModName(update.Name)}:";

                try {
                    // show the cancel button for downloading
                    showCancel = true;

                    // download it...
                    modUpdatingMessage = $"{progressString} {Dialog.Clean("AUTOUPDATECHECKER_DOWNLOADING")}";

                    Logger.Log("AutoModUpdater", $"Downloading {update.URL} to {zipPath}");
                    Func <int, long, int, bool> progressCallback = (position, length, speed) => {
                        if (skipUpdate)
                        {
                            return(false);
                        }

                        if (length > 0)
                        {
                            modUpdatingMessage = $"{progressString} {Dialog.Clean("AUTOUPDATECHECKER_DOWNLOADING")} " +
                                                 $"({((int) Math.Floor(100D * (position / (double) length)))}% @ {speed} KiB/s)";
                        }
                        else
                        {
                            modUpdatingMessage = $"{progressString} {Dialog.Clean("AUTOUPDATECHECKER_DOWNLOADING")} " +
                                                 $"({((int) Math.Floor(position / 1000D))}KiB @ {speed} KiB/s)";
                        }
                        return(true);
                    };

                    try {
                        Everest.Updater.DownloadFileWithProgress(update.URL, zipPath, progressCallback);
                    } catch (WebException e) {
                        Logger.Log(LogLevel.Warn, "AutoModUpdater", $"Download failed, trying mirror {update.MirrorURL}");
                        Logger.LogDetailed(e);
                        Everest.Updater.DownloadFileWithProgress(update.MirrorURL, zipPath, progressCallback);
                    }

                    // hide the cancel button for downloading, download is done
                    showCancel = false;

                    if (skipUpdate)
                    {
                        Logger.Log("AutoModUpdater", "Update was skipped");

                        // try to delete mod-update.zip if it still exists.
                        ModUpdaterHelper.TryDelete(zipPath);

                        if (restartRequired)
                        {
                            // stop trying to update mods; restart right away
                            break;
                        }
                        else
                        {
                            // proceed to the game right away
                            shouldContinue = true;
                            return;
                        }
                    }

                    // verify its checksum
                    modUpdatingMessage = $"{progressString} {Dialog.Clean("AUTOUPDATECHECKER_VERIFYING")}";
                    ModUpdaterHelper.VerifyChecksum(update, zipPath);

                    // install it
                    restartRequired    = true;
                    modUpdatingMessage = $"{progressString} {Dialog.Clean("AUTOUPDATECHECKER_INSTALLING")}";
                    ModUpdaterHelper.InstallModUpdate(update, updateList[update], zipPath);
                } catch (Exception e) {
                    // update failed
                    Logger.Log("AutoModUpdater", $"Updating {update.Name} failed");
                    Logger.LogDetailed(e);
                    failuresOccured = true;

                    // try to delete mod-update.zip if it still exists.
                    ModUpdaterHelper.TryDelete(zipPath);

                    // stop trying to update further mods.
                    break;
                }

                currentlyUpdatedModIndex++;
            }

            // don't show "cancel" anymore, install ended.
            showCancel = false;

            if (!failuresOccured)
            {
                // restart when everything is done
                modUpdatingMessage = Dialog.Clean("DEPENDENCYDOWNLOADER_RESTARTING");
                Thread.Sleep(1000);
                Everest.QuickFullRestart();
            }
            else
            {
                modUpdatingMessage = Dialog.Clean("AUTOUPDATECHECKER_FAILED");

                // stop the cogwheel
                cogwheelSpinning = false;
                cogwheelStopTime = RawTimeActive;

                if (restartRequired)
                {
                    // failures occured, restart is required
                    modUpdatingSubMessage = Dialog.Clean("AUTOUPDATECHECKER_REBOOT");
                    confirmToRestart      = true;
                }
                else
                {
                    // failures occured, restart is not required
                    modUpdatingSubMessage = Dialog.Clean("AUTOUPDATECHECKER_CONTINUE");
                    confirmToContinue     = true;
                }
            }
        }
Beispiel #6
0
        public override void Update()
        {
            // check if the "press Back to restart" message has to be toggled
            if (menu != null && subHeader != null)
            {
                if (menu.Focused && shouldRestart)
                {
                    subHeader.TextColor = Color.OrangeRed;
                    subHeader.Title     = $"{Dialog.Clean("MODUPDATECHECKER_MENU_HEADER")} ({Dialog.Clean("MODUPDATECHECKER_WILLRESTART")})";
                }
                else if (!menu.Focused && ongoingUpdateCancelled && menuOnScreen)
                {
                    subHeader.TextColor = Color.Gray;
                    subHeader.Title     = $"{Dialog.Clean("MODUPDATECHECKER_MENU_HEADER")} ({Dialog.Clean("MODUPDATECHECKER_CANCELLING")})";
                }
                else
                {
                    subHeader.TextColor = Color.Gray;
                    subHeader.Title     = Dialog.Clean("MODUPDATECHECKER_MENU_HEADER");
                }
            }

            if (menu != null && task != null && task.IsCompleted)
            {
                // there is no download or install task in progress

                if (fetchingButton != null)
                {
                    // This means fetching the updates just finished. We have to remove the "Checking for updates" button
                    // and put the actual update list instead.

                    Logger.Log("OuiModUpdateList", "Rendering updates");

                    menu.Remove(fetchingButton);
                    fetchingButton = null;

                    if (updateCatalog == null)
                    {
                        // display an error message
                        TextMenu.Button button = new TextMenu.Button(Dialog.Clean("MODUPDATECHECKER_ERROR"));
                        button.Disabled = true;
                        menu.Add(button);
                    }
                    else if (availableUpdatesCatalog.Count == 0)
                    {
                        // display a dummy "no update available" button
                        TextMenu.Button button = new TextMenu.Button(Dialog.Clean("MODUPDATECHECKER_NOUPDATE"));
                        button.Disabled = true;
                        menu.Add(button);
                    }
                    else
                    {
                        // if there are multiple updates...
                        if (availableUpdatesCatalog.Count > 1)
                        {
                            // display an "update all" button at the top of the list
                            updateAllButton = new TextMenu.Button(Dialog.Clean("MODUPDATECHECKER_UPDATE_ALL"));
                            updateAllButton.Pressed(() => downloadAllMods());

                            menu.Add(updateAllButton);
                        }

                        // then, display one button per update
                        foreach (ModUpdateInfo update in availableUpdatesCatalog.Keys)
                        {
                            EverestModuleMetadata metadata = availableUpdatesCatalog[update];

                            string versionUpdate = metadata.VersionString;
                            if (metadata.VersionString != update.Version)
                            {
                                versionUpdate = $"{metadata.VersionString} > {update.Version}";
                            }

                            TextMenu.Button button = new TextMenu.Button($"{ModUpdaterHelper.FormatModName(metadata.Name)} | v. {versionUpdate} ({new DateTime(1970, 1, 1, 0, 0, 0, 0).AddSeconds(update.LastUpdate):yyyy-MM-dd})");
                            button.Pressed(() => {
                                // make the menu non-interactive
                                menu.Focused    = false;
                                button.Disabled = true;

                                // trigger the update download
                                downloadModUpdate(update, metadata, button);
                            });

                            // if there is more than one hash, it means there is multiple downloads for this mod. Thus, we can't update it manually.
                            // if there isn't, add it to the list of mods that can be updated via "update all"
                            if (update.xxHash.Count > 1)
                            {
                                button.Disabled = true;
                            }
                            else
                            {
                                updatableMods.Add(new ModUpdateHolder()
                                {
                                    update = update, metadata = metadata, button = button
                                });
                            }

                            menu.Add(button);
                        }
                    }
                }

                if (menu.Focused && Selected && Input.MenuCancel.Pressed)
                {
                    if (shouldRestart)
                    {
                        Everest.QuickFullRestart();
                    }
                    else
                    {
                        // go back to mod options instead
                        Audio.Play(SFX.ui_main_button_back);
                        Overworld.Goto <OuiModOptions>();
                    }
                }
            }

            if (Input.MenuCancel.Pressed)
            {
                // cancel any ongoing download (this has no effect if no download is ongoing anyway).
                ongoingUpdateCancelled = true;
            }

            base.Update();
        }