Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions Celeste.Mod.mm/Content/Dialog/English.txt
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@
MODOPTIONS_COREMODULE_MIRRORPREFERENCES_WEGFAN= China
MODOPTIONS_COREMODULE_MIRRORPREFERENCES_OTOBOT= North America
MODOPTIONS_COREMODULE_MIRRORPREFERENCES_RISINGSUNLIGHT= France
MODOPTIONS_COREMODULE_MIRRORTESTING= Determine the best mirror

MODOPTIONS_COREMODULE_USEAPIMIRROR= Use Database Mirror
MODOPTIONS_COREMODULE_USEAPIMIRROR_DESC= This option can help if you get "Downloading the database failed" errors
Expand Down Expand Up @@ -337,6 +338,15 @@
MODOPTIONS_MODTOGGLE_BINS= Map Bin Files
MODOPTIONS_MODTOGGLE_SEARCHBOX_PLACEHOLDER= Press 'Tab' or 'Enter' to scroll to the next match

# Mirror Testing Menu
MODOPTIONS_MIRRORTESTING= TEST MIRRORS
MODOPTIONS_MIRRORTESTING_EXPLANATION= All mirrors will be used to download{n}a same mod and Everest will choose the mirror with the best download speed.
MODOPTIONS_MIRRORTESTING_DOWNLOADING= Downloading mod from ((mirror))
MODOPTIONS_MIRRORTESTING_DOWNLOADED= Downloaded mod from ((mirror)) in
MODOPTIONS_MIRRORTESTING_TIMEDOUT= Downloaded mod from ((mirror)) timed out
MODOPTIONS_MIRRORTESTING_CANCELED= Canceled
MODOPTIONS_MIRRORTESTING_ERROR= An error occured

# Asset Reload Helper
ASSETRELOADHELPER_RELOADINGMAP= Reloading map
ASSETRELOADHELPER_RELOADINGLEVEL= Reloading level
Expand Down
6 changes: 6 additions & 0 deletions Celeste.Mod.mm/Content/Dialog/French.txt
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,12 @@
MODOPTIONS_MODTOGGLE_BINS= Fichiers .bin de maps
MODOPTIONS_MODTOGGLE_SEARCHBOX_PLACEHOLDER= Appuie sur Tab ou Entrée pour lancer la recherche

# Mirror Testing Menu
MODOPTIONS_MIRRORTESTING= TEST DES MIROIRS
MODOPTIONS_MIRRORTESTING_EXPLANATION= Tout les miroirs vont être utilisés pour télécharger{n}un même mod puis Everest va choisir le miroir avec la meilleur vitesse de téléchargement.
MODOPTIONS_MIRRORTESTING_DOWNLOADING= Téléchargement du mod via le miroir ((mirror))
MODOPTIONS_MIRRORTESTING_DOWNLOADED= Téléchargement du mod via le miroir ((mirror)) fini en

# Asset Reload Helper
ASSETRELOADHELPER_RELOADINGMAP= Rechargement de la map...
ASSETRELOADHELPER_RELOADINGLEVEL= Rechargement du niveau...
Expand Down
8 changes: 8 additions & 0 deletions Celeste.Mod.mm/Mod/Core/CoreModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,14 @@ public override void CreateModMenuSection(patch_TextMenu menu, bool inGame, Even
menu.Insert(items.Count - 2, new TextMenu.Button(Dialog.Clean("modoptions_coremodule_togglemods")).Pressed(() => {
OuiModOptions.Instance.Overworld.Goto<OuiModToggler>();
}));

// insert mirror test under "Use Mirror to Download Mods"
int MirrorPreferenceEntryIndex = items.FindIndex(item => (item is TextMenu.Slider) && (item as TextMenu.Slider).Label == Dialog.Clean("MODOPTIONS_COREMODULE_MIRRORPREFERENCES"));
if (MirrorPreferenceEntryIndex != -1) {
menu.Insert(MirrorPreferenceEntryIndex + 1, new TextMenu.Button(Dialog.Clean("MODOPTIONS_COREMODULE_MIRRORTESTING")).Pressed(() => {
OuiModOptions.Instance.Overworld.Goto<OuiMirrorTester>();
}));
}
}
}

Expand Down
135 changes: 135 additions & 0 deletions Celeste.Mod.mm/Mod/UI/OuiMirrorTester.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
using Celeste.Mod.Core;
using Celeste.Mod.Helpers;
using Microsoft.Xna.Framework;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading.Tasks;

namespace Celeste.Mod.UI {
public class OuiMirrorTester : OuiGenericMenu, OuiModOptions.ISubmenu {
public override string MenuName => Dialog.Clean("MODOPTIONS_MIRRORTESTING");
private Task mirrorLoadingTask;
private bool ongoingUpdateCancelled = false;
public OuiMirrorTester() {
backToParentMenu = onBackPressed;
}

protected override void addOptionsToMenu(patch_TextMenu menu) {
TextMenuExt.SubHeaderExt loading = new TextMenuExt.SubHeaderExt(Dialog.Clean("MODOPTIONS_MIRRORTESTING_EXPLANATION"));
menu.Add(loading);

mirrorLoadingTask = new Task(() => {
int mirrorIndex = 0;
List<string> mirrorNames = CoreModule.Settings.MirrorPreferences.Split(',').ToList();
string downloadDestination = Path.Combine(Everest.PathTmp, $"mirror-tester.zip");
Dictionary<string, long> speedForMirror = new();

foreach (string mirrorUrl in ModUpdaterHelper.GetAllMirrorUrls("https://gamebanana.com/dl/1778093")) {
if (ongoingUpdateCancelled)
continue;
string mirrorName = Dialog.Clean("MODOPTIONS_COREMODULE_MIRRORPREFERENCES_" + mirrorNames[mirrorIndex]);
if (mirrorNames[mirrorIndex] == "gb") {
mirrorName = "GameBanana";
}
TextMenu.Button loadingMirror = new TextMenuExt.ButtonExt(Dialog.Clean("MODOPTIONS_MIRRORTESTING_DOWNLOADING").Replace("((mirror))", mirrorName)) { Disabled = true, TextColorDisabled = Color.LightGray };
menu.Add(loadingMirror);
Func<int, long, int, bool> progressCallback = (position, length, speed) => {
string speedString;
if (ongoingUpdateCancelled)
return false;
if (length > 0) {
speedString = $"{(int) Math.Floor(100D * (position / (double) length))}% @ {speed} KiB/s";
} else {
speedString = $"{(int) Math.Floor(position / 1000D)}KiB @ {speed} KiB/s";
}

loadingMirror.Label = Dialog.Clean("MODOPTIONS_MIRRORTESTING_DOWNLOADING").Replace("((mirror))", mirrorName) + $": {speedString}";
return true;
};


Logger.Verbose("OuiMirrorTester", $"Downloading from {mirrorUrl}");
bool finishedSuccessfully = false;
Stopwatch testerStopwatch = Stopwatch.StartNew();
try {
Everest.Updater.DownloadFileWithProgress(mirrorUrl, downloadDestination, progressCallback);
finishedSuccessfully = true;
} catch (TimeoutException) {
}
testerStopwatch.Stop();

if (finishedSuccessfully) {
loadingMirror.Label = Dialog.Clean("MODOPTIONS_MIRRORTESTING_DOWNLOADED").Replace("((mirror))", mirrorName) + $" {Math.Round((double) (testerStopwatch.ElapsedMilliseconds / 10)) / 100}s";
speedForMirror[mirrorNames[mirrorIndex]] = testerStopwatch.ElapsedMilliseconds;
} else {
loadingMirror.Label = Dialog.Clean("MODOPTIONS_MIRRORTESTING_TIMEDOUT").Replace("((mirror))", mirrorName);
speedForMirror[mirrorNames[mirrorIndex]] = long.MaxValue;
}
ModUpdaterHelper.TryDelete(downloadDestination);
mirrorIndex++;
};
if (!ongoingUpdateCancelled) {
mirrorNames.Sort((p1, p2) => speedForMirror[p1].CompareTo(speedForMirror[p2]));

List<string> mirrorPreferences = new List<string> {
"gb,jade,risingsunlight,otobot,wegfan",
"jade,risingsunlight,otobot,wegfan,gb",
"wegfan,otobot,jade,risingsunlight,gb",
"otobot,jade,risingsunlight,wegfan,gb",
"risingsunlight,jade,otobot,wegfan,gb"
};

CoreModule.Settings.MirrorPreferences = mirrorPreferences.Find(mirrors => mirrors.StartsWith(mirrorNames[0]));
}
Overworld.Goto<OuiModOptions>();
});

mirrorLoadingTask.Start();
}

private bool MessageDisplayed = false;
public override void Update() {
base.Update();

if (mirrorLoadingTask != null && mirrorLoadingTask.IsCompleted && !mirrorLoadingTask.IsCompletedSuccessfully && !MessageDisplayed) {
if (ongoingUpdateCancelled) {
menu.Add(new TextMenuExt.SubHeaderExt(Dialog.Clean("MODOPTIONS_MIRRORTESTING_CANCELED")));
} else {
menu.Add(new TextMenuExt.SubHeaderExt(Dialog.Clean("MODOPTIONS_MIRRORTESTING_ERROR")));

throw mirrorLoadingTask.Exception;
}
MessageDisplayed = true;
}
}


private void onBackPressed(Overworld overworld) {
if (mirrorLoadingTask.IsCompleted) {
overworld.Goto<OuiModOptions>();
} else {
ongoingUpdateCancelled = true;
}
}

public override void Render() {
base.Render();
}

public override IEnumerator Leave(Oui next) {
IEnumerator orig = base.Leave(next);
while (orig.MoveNext()) {
yield return orig.Current;
}

// we left the screen: clean up all variables.
mirrorLoadingTask = null;
ongoingUpdateCancelled = false;
MessageDisplayed = false;
}
}
}