|
@@ -1,44 +1,135 @@
|
|
|
-using Avalonia.Controls.ApplicationLifetimes;
|
|
|
-using Avalonia.Threading;
|
|
|
-using System;
|
|
|
+using System;
|
|
|
+using System.Collections.Generic;
|
|
|
+using System.Collections.ObjectModel;
|
|
|
using System.IO;
|
|
|
+using System.IO.Compression;
|
|
|
using System.Linq;
|
|
|
using System.Net;
|
|
|
using System.Net.Http;
|
|
|
+using System.Net.Http.Handlers;
|
|
|
using System.Text.Json;
|
|
|
+using System.Threading;
|
|
|
using System.Threading.Tasks;
|
|
|
-using System.IO.Compression;
|
|
|
using VeloeMinecraftLauncher.Entity.Assets;
|
|
|
-using VeloeMinecraftLauncher.ViewModels;
|
|
|
-using VeloeMinecraftLauncher.Views;
|
|
|
-using System.Collections.ObjectModel;
|
|
|
using VeloeMinecraftLauncher.Models.Entity;
|
|
|
-using SkiaSharp;
|
|
|
|
|
|
namespace VeloeMinecraftLauncher.MinecraftLauncher;
|
|
|
|
|
|
internal static class Downloader
|
|
|
{
|
|
|
+ static HttpClient _httpClient = new HttpClient();
|
|
|
+
|
|
|
public static async Task<TaskStatus> StartDownload(
|
|
|
+ Action<string> DownloadingFileName, //status text showing on ui
|
|
|
+ Action<string> TaskStatus, //
|
|
|
+ Action<bool> IsControlsEnabled, //value locking ui buttons
|
|
|
+ Action<long> SetProgress, // progress bar
|
|
|
+ Entity.Version.Version versionJson,
|
|
|
+ CancellationToken cancellationToken,
|
|
|
+ bool DownloadJava = false,
|
|
|
+ bool InstallForge = false,
|
|
|
+ bool InstallOptifine = false,
|
|
|
+ bool InstallForgeOptifine = false,
|
|
|
+ bool InstallFabric = false)
|
|
|
+ {
|
|
|
+ return await DownloadClient(DownloadingFileName, TaskStatus, IsControlsEnabled, SetProgress, versionJson, cancellationToken,
|
|
|
+ DownloadJava, InstallForge, InstallOptifine, InstallForgeOptifine, InstallFabric);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static async Task<TaskStatus> StartDownloadModpack(
|
|
|
Action<string> DownloadingFileName,
|
|
|
+ Action<string> TaskStatus,
|
|
|
Action<bool> IsControlsEnabled,
|
|
|
- Action<WebClient> SetProgressBar,
|
|
|
- Action<WebClient> RemoveProgressBar,
|
|
|
- Entity.Version.Version versionJson,
|
|
|
+ Action<long> SetProgress,
|
|
|
+ ObservableCollection<Entity.VersionManifest.Version> FilteredVersions,
|
|
|
+ Modpack SelectedModpack,
|
|
|
+ CancellationToken cancellationToken,
|
|
|
+ bool DownloadJava = false,
|
|
|
+ bool InstallForge = false,
|
|
|
+ bool InstallOptifine = false,
|
|
|
+ bool InstallForgeOptifine = false,
|
|
|
+ bool InstallFabric = false)
|
|
|
+ {
|
|
|
+ return await DownloadClient(DownloadingFileName, TaskStatus, IsControlsEnabled, SetProgress, null, cancellationToken, DownloadJava,
|
|
|
+ InstallForge, InstallOptifine, InstallForgeOptifine, InstallFabric,FilteredVersions,SelectedModpack,true);
|
|
|
+ }
|
|
|
+
|
|
|
+ private static async Task<TaskStatus> DownloadClient(
|
|
|
+ Action<string> DownloadingFileName, //status text showing on ui
|
|
|
+ Action<string> TasksStatus,
|
|
|
+ Action<bool> IsControlsEnabled, //value locking ui buttons
|
|
|
+ Action<long> SetProgress, // progress bar
|
|
|
+ Entity.Version.Version? versionJson,
|
|
|
+ CancellationToken cancellationToken,
|
|
|
bool DownloadJava = false,
|
|
|
bool InstallForge = false,
|
|
|
bool InstallOptifine = false,
|
|
|
bool InstallForgeOptifine = false,
|
|
|
- bool InstallFabric = false
|
|
|
- )
|
|
|
+ bool InstallFabric = false,
|
|
|
+ ObservableCollection<Entity.VersionManifest.Version>? FilteredVersions = null,
|
|
|
+ Modpack? SelectedModpack = null,
|
|
|
+ bool downloadModpack = false)
|
|
|
{
|
|
|
try
|
|
|
{
|
|
|
+ //task 1 - download java
|
|
|
+ //task 2 - download jar
|
|
|
+ //task 3 - download libs
|
|
|
+ //task 4 - download assets
|
|
|
+ //task 5 - download addons
|
|
|
+ //task 6 - download modpacks
|
|
|
+ IsControlsEnabled(false);
|
|
|
+ SetProgress( 0 );
|
|
|
+ var tasksCount = 3;
|
|
|
+ var tasksIterator = 0;
|
|
|
+
|
|
|
+ if (DownloadJava) tasksCount++;
|
|
|
+ if (InstallForge || InstallOptifine || InstallForgeOptifine || InstallFabric) tasksCount++;
|
|
|
+ if (downloadModpack) tasksCount++;
|
|
|
+
|
|
|
+ TasksStatus($"Task {tasksIterator} of {tasksCount} complete.");
|
|
|
+
|
|
|
+ var handler = new HttpClientHandler() { AllowAutoRedirect = true };
|
|
|
+ var ph = new ProgressMessageHandler(handler);
|
|
|
+ ph.HttpSendProgress += (_, args) =>
|
|
|
+ {
|
|
|
+ SetProgress(args.ProgressPercentage);
|
|
|
+ };
|
|
|
+
|
|
|
+ ph.HttpReceiveProgress += (_, args) =>
|
|
|
+ {
|
|
|
+ SetProgress(args.ProgressPercentage);
|
|
|
+ };
|
|
|
+
|
|
|
+ using var httpClient = new HttpClient(ph);
|
|
|
+
|
|
|
+ Entity.VersionManifest.Version? filteredVersion;
|
|
|
+
|
|
|
+ if (downloadModpack)
|
|
|
+ {
|
|
|
+ if (FilteredVersions is null || SelectedModpack is null)
|
|
|
+ return TaskStatus.Faulted;
|
|
|
+
|
|
|
+ filteredVersion = FilteredVersions.Where(x => x.Id == SelectedModpack.Version).FirstOrDefault();
|
|
|
+
|
|
|
+ if (filteredVersion is null)
|
|
|
+ return TaskStatus.Faulted;
|
|
|
+
|
|
|
+ InstallForge = SelectedModpack.Forge;
|
|
|
+ InstallForgeOptifine = SelectedModpack.ForgeOptifine;
|
|
|
+ InstallOptifine = SelectedModpack.Optifine;
|
|
|
+ InstallFabric = SelectedModpack.Fabric;
|
|
|
+
|
|
|
+ Settings.logger.Debug("Downloading {0}.json", filteredVersion.Id);
|
|
|
+ DownloadingFileName($"{filteredVersion.Id}.json");
|
|
|
+ versionJson = await Downloader.DownloadAndDeserializeJsonData<Entity.Version.Version>(filteredVersion.Url, Settings.minecraftForlderPath + "versions/" + filteredVersion.Id + "/", filteredVersion.Id + ".json");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (versionJson is null)
|
|
|
+ return TaskStatus.Faulted;
|
|
|
+ //SetMaxProgressBarValue(size);
|
|
|
Settings.logger.Debug("Downloading minecraft {0}", versionJson.Id);
|
|
|
- var webClient = new WebClient();
|
|
|
-
|
|
|
- SetProgressBar(webClient);
|
|
|
- //webClient.DownloadProgressChanged += WebClient_DownloadProgressChanged;
|
|
|
+
|
|
|
//download java
|
|
|
if (DownloadJava)
|
|
|
{
|
|
@@ -79,7 +170,7 @@ internal static class Downloader
|
|
|
javaUrl = "https://files.veloe.link/launcher/java/18/linux64/java.zip";
|
|
|
|
|
|
break;
|
|
|
- }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
if (versionJson.Assets == "legacy")
|
|
@@ -99,9 +190,8 @@ internal static class Downloader
|
|
|
{
|
|
|
Settings.logger.Debug("Downloading Java");
|
|
|
DownloadingFileName("java.zip");
|
|
|
- webClient.DownloadFileAsync(new System.Uri(javaUrl), Settings.minecraftForlderPath + "java.zip");
|
|
|
- waitWhileBisy(ref webClient);
|
|
|
-
|
|
|
+ await DownloadFileAsync(javaUrl, Settings.minecraftForlderPath + "java.zip", cancellationToken, httpClient);
|
|
|
+
|
|
|
Settings.logger.Debug("Unpacking Java");
|
|
|
DownloadingFileName("Unpacking java.zip");
|
|
|
ZipFile.ExtractToDirectory($"{Settings.minecraftForlderPath}java.zip", Settings.minecraftForlderPath, true);
|
|
@@ -109,20 +199,17 @@ internal static class Downloader
|
|
|
}
|
|
|
else
|
|
|
Settings.logger.Debug("Required Java version don't found in json file."); //log that java was not downloaded;
|
|
|
- }
|
|
|
|
|
|
+ tasksIterator++;
|
|
|
+ TasksStatus($"Task {tasksIterator} of {tasksCount} complete.");
|
|
|
+ }
|
|
|
//download json
|
|
|
var path = Settings.minecraftForlderPath + "/versions/" + versionJson.Id;
|
|
|
if (!Directory.Exists(path))
|
|
|
{
|
|
|
Settings.logger.Debug("Creating path: {0}", path);
|
|
|
Directory.CreateDirectory(path);
|
|
|
- }
|
|
|
-
|
|
|
- //Settings.logger.Debug("Downloading {0}", $"{versionJson.id}.json");
|
|
|
- //DownloadingFileName($"{versionJson.id}.json");
|
|
|
- //webClient.DownloadFileAsync(new System.Uri(versionJson.url), path + "/" + versionJson.id + ".json");
|
|
|
- //waitWhileBisy(ref webClient);
|
|
|
+ }
|
|
|
|
|
|
//download jar
|
|
|
if (!Directory.Exists(path))
|
|
@@ -148,12 +235,15 @@ internal static class Downloader
|
|
|
{
|
|
|
Settings.logger.Debug("Downloading {0}", $"{versionJson.Id}.jar");
|
|
|
DownloadingFileName($"{versionJson.Id}.jar");
|
|
|
- webClient.DownloadFileAsync(new System.Uri(versionJson.Downloads.Client.Url), path + "/" + versionJson.Id + ".jar");
|
|
|
- waitWhileBisy(ref webClient);
|
|
|
+ await DownloadFileAsync(versionJson.Downloads.Client.Url, path + "/" + versionJson.Id + ".jar", cancellationToken, httpClient);
|
|
|
+
|
|
|
}
|
|
|
+ tasksIterator++;
|
|
|
+ TasksStatus($"Task {tasksIterator} of {tasksCount} complete.");
|
|
|
//end download jar
|
|
|
//download libraries
|
|
|
Settings.logger.Debug("Downloading libraries.");
|
|
|
+
|
|
|
foreach (var library in versionJson.Libraries)
|
|
|
{
|
|
|
var libPath = Settings.minecraftForlderPath + "libraries/";
|
|
@@ -214,7 +304,7 @@ internal static class Downloader
|
|
|
|
|
|
//checking rules
|
|
|
if (library.Rules == null)
|
|
|
- {
|
|
|
+ {
|
|
|
if (!Directory.Exists(libDir))
|
|
|
{
|
|
|
Settings.logger.Debug("Creating path: {0}", path);
|
|
@@ -238,8 +328,7 @@ internal static class Downloader
|
|
|
{
|
|
|
Settings.logger.Debug("Downloading: {0}", libName);
|
|
|
DownloadingFileName(libName);
|
|
|
- webClient.DownloadFileAsync(new System.Uri(libUrl), libDir + "/" + libName);
|
|
|
- waitWhileBisy(ref webClient);
|
|
|
+ await DownloadFileAsync(libUrl, libDir + "/" + libName, cancellationToken, httpClient);
|
|
|
}
|
|
|
}
|
|
|
else
|
|
@@ -271,8 +360,7 @@ internal static class Downloader
|
|
|
{
|
|
|
Settings.logger.Debug("Downloading: {0}", libName);
|
|
|
DownloadingFileName(libName);
|
|
|
- webClient.DownloadFileAsync(new System.Uri(libUrl), libDir + "/" + libName);
|
|
|
- waitWhileBisy(ref webClient);
|
|
|
+ await DownloadFileAsync(libUrl, libDir + "/" + libName, cancellationToken, httpClient);
|
|
|
}
|
|
|
continue;
|
|
|
}
|
|
@@ -288,7 +376,7 @@ internal static class Downloader
|
|
|
Settings.logger.Debug("Downloading: {0}", libName);
|
|
|
DownloadingFileName = libName;
|
|
|
webClient.DownloadFileAsync(new System.Uri(libUrl), libPath + "/" + libName);
|
|
|
- waitWhileBisy(ref webClient);
|
|
|
+
|
|
|
}
|
|
|
*/
|
|
|
}
|
|
@@ -313,15 +401,18 @@ internal static class Downloader
|
|
|
Settings.logger.Debug("Extracting {0} to {1}", libName, Settings.minecraftForlderPath + "versions/" + versionJson.Id + "/natives/");
|
|
|
ZipFile.ExtractToDirectory(libDir + "/" + libName, Settings.minecraftForlderPath + "versions/" + versionJson.Id + "/natives/", true);
|
|
|
}
|
|
|
- catch (IOException ex)
|
|
|
+ catch (IOException)
|
|
|
{
|
|
|
- Settings.logger.Error("IOException in VersionsDownloaderViewModel on native lib extraction");
|
|
|
+ Settings.logger.Error("IOException on native lib extraction");
|
|
|
}
|
|
|
//TODO delete META-INF and sha1 files after
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- var assetsJson = Downloader.DownloadAndDeserializeJsonData<AssetsManifest>(versionJson.AssetIndex.Url);
|
|
|
+ tasksIterator++;
|
|
|
+ TasksStatus($"Task {tasksIterator} of {tasksCount} complete.");
|
|
|
+
|
|
|
+ var assetsJson = await Downloader.DownloadAndDeserializeJsonData<AssetsManifest>(versionJson.AssetIndex.Url);
|
|
|
var assetsPath = Settings.minecraftForlderPath + "assets/" + versionJson.Assets + "/objects";
|
|
|
var assetsUrl = "https://resources.download.minecraft.net/";
|
|
|
|
|
@@ -330,37 +421,56 @@ internal static class Downloader
|
|
|
|
|
|
if (!Directory.Exists(Settings.minecraftForlderPath + "/assets/" + versionJson.Assets + "/indexes/"))
|
|
|
Directory.CreateDirectory(Settings.minecraftForlderPath + "/assets/" + versionJson.Assets + "/indexes/");
|
|
|
- webClient.DownloadFileAsync(new System.Uri(versionJson.AssetIndex.Url), Settings.minecraftForlderPath + "/assets/" + versionJson.Assets + "/indexes/" + versionJson.Assets + ".json");
|
|
|
- waitWhileBisy(ref webClient);
|
|
|
+ await DownloadFileAsync(versionJson.AssetIndex.Url, Settings.minecraftForlderPath + "/assets/" + versionJson.Assets + "/indexes/" + versionJson.Assets + ".json", cancellationToken);
|
|
|
|
|
|
- //download assets
|
|
|
- foreach (var asset in assetsJson.Objects)
|
|
|
- {
|
|
|
- var folder = asset.Value.Hash.Substring(0, 2);
|
|
|
- if (!Directory.Exists(assetsPath + "/" + folder))
|
|
|
- Directory.CreateDirectory(assetsPath + "/" + folder);
|
|
|
+ Settings.logger.Debug("Downloading assets.");
|
|
|
+ SetProgress(0);
|
|
|
+ var assetsCount = assetsJson.Objects.Count;
|
|
|
+ var assetsIterator = 1;
|
|
|
|
|
|
- chksum = String.Empty;
|
|
|
- //here hash check
|
|
|
- if (File.Exists(assetsPath + "/" + folder + "/" + asset.Value.Hash))
|
|
|
- {
|
|
|
- DownloadingFileName($"Checking hash: {asset.Value.Hash}");
|
|
|
- FileStream fop = File.OpenRead(assetsPath + "/" + folder + "/" + asset.Value.Hash);
|
|
|
- byte[] hash = System.Security.Cryptography.SHA1.Create().ComputeHash(fop);
|
|
|
- chksum = BitConverter.ToString(hash).Replace("-", String.Empty).ToLower();
|
|
|
+ List<Task> assetsDownloadTasks = new();
|
|
|
+ using SemaphoreSlim concurrencySemaphore = new SemaphoreSlim(0,40);
|
|
|
|
|
|
- fop.Close();
|
|
|
- fop.Dispose();
|
|
|
- }
|
|
|
+ foreach (var asset in assetsJson.Objects.DistinctBy(a => a.Value.Hash))
|
|
|
+ {
|
|
|
+ assetsDownloadTasks.Add(Task.Run(async () => {
|
|
|
+
|
|
|
+ var folder = asset.Value.Hash.Substring(0, 2);
|
|
|
|
|
|
- if (chksum != asset.Value.Hash)
|
|
|
- {
|
|
|
- Settings.logger.Debug("Downloading: {0}", asset.Value.Hash);
|
|
|
- DownloadingFileName($"Asset {asset.Value.Hash}");
|
|
|
- webClient.DownloadFileAsync(new System.Uri(assetsUrl + folder + "/" + asset.Value.Hash), assetsPath + "/" + folder + "/" + asset.Value.Hash);
|
|
|
- waitWhileBisy(ref webClient);
|
|
|
- }
|
|
|
+ var chksum = String.Empty;
|
|
|
+ //here hash check
|
|
|
+ if (File.Exists(assetsPath + "/" + folder + "/" + asset.Value.Hash))
|
|
|
+ {
|
|
|
+ DownloadingFileName($"Checking hash {assetsIterator} of {assetsCount}");
|
|
|
+ using FileStream fop = File.OpenRead(assetsPath + "/" + folder + "/" + asset.Value.Hash);
|
|
|
+ byte[] hash = System.Security.Cryptography.SHA1.Create().ComputeHash(fop);
|
|
|
+ chksum = BitConverter.ToString(hash).Replace("-", String.Empty).ToLower();
|
|
|
+ fop.Close();
|
|
|
+ }
|
|
|
+
|
|
|
+ if (chksum != asset.Value.Hash)
|
|
|
+ {
|
|
|
+ concurrencySemaphore.Wait(cancellationToken);
|
|
|
+ if (!Directory.Exists(assetsPath + "/" + folder))
|
|
|
+ Directory.CreateDirectory(assetsPath + "/" + folder);
|
|
|
+
|
|
|
+ Settings.logger.Debug("Downloading asset: {0} ", asset.Value.Hash);
|
|
|
+ //DownloadingFileName($"Asset {assetsIterator} of {assetsCount}");
|
|
|
+ DownloadingFileName($"Asset {assetsIterator} of {assetsCount}");
|
|
|
+ await DownloadFileAsync(assetsUrl + folder + "/" + asset.Value.Hash, assetsPath + "/" + folder + "/" + asset.Value.Hash, cancellationToken);
|
|
|
+ concurrencySemaphore.Release();
|
|
|
+ }
|
|
|
+ SetProgress(assetsIterator * 100 / assetsCount);
|
|
|
+ Interlocked.Increment(ref assetsIterator);
|
|
|
+
|
|
|
+ }));
|
|
|
}
|
|
|
+ concurrencySemaphore.Release(40);
|
|
|
+ Task.WaitAll(assetsDownloadTasks.ToArray());
|
|
|
+
|
|
|
+ SetProgress(100);
|
|
|
+ tasksIterator++;
|
|
|
+ TasksStatus($"Task {tasksIterator} of {tasksCount} complete.");
|
|
|
|
|
|
if (InstallForge)
|
|
|
{
|
|
@@ -372,17 +482,17 @@ internal static class Downloader
|
|
|
Settings.logger.Debug("Creating path: {0}", $"{Settings.minecraftForlderPath}versions/" + forgePath);
|
|
|
Directory.CreateDirectory($"{Settings.minecraftForlderPath}versions/" + forgePath);
|
|
|
}
|
|
|
- waitWhileBisy(ref webClient);
|
|
|
+
|
|
|
|
|
|
Settings.logger.Debug("Downloading: {0}", $"Forge{versionJson.Id}.json");
|
|
|
DownloadingFileName($"Forge{versionJson.Id}.json");
|
|
|
- webClient.DownloadFileAsync(new System.Uri($"{forgeUrl}Forge{versionJson.Id}.json"), Settings.minecraftForlderPath + "versions/" + forgePath + "/" + forgePath + ".json");
|
|
|
- waitWhileBisy(ref webClient);
|
|
|
+ await DownloadFileAsync($"{forgeUrl}Forge{versionJson.Id}.json", Settings.minecraftForlderPath + "versions/" + forgePath + "/" + forgePath + ".json", cancellationToken, httpClient);
|
|
|
+
|
|
|
|
|
|
Settings.logger.Debug("Downloading: {0}", "libraries.zip");
|
|
|
DownloadingFileName("libraries.zip");
|
|
|
- webClient.DownloadFileAsync(new System.Uri(forgeUrl + "libraries.zip"), Settings.minecraftForlderPath + "versions/" + forgePath + "/libraries.zip");
|
|
|
- waitWhileBisy(ref webClient);
|
|
|
+ await DownloadFileAsync(forgeUrl + "libraries.zip", Settings.minecraftForlderPath + "versions/" + forgePath + "/libraries.zip", cancellationToken, httpClient);
|
|
|
+
|
|
|
|
|
|
Settings.logger.Debug("Extracting: {0}", "libraries.zip");
|
|
|
DownloadingFileName("Unpacking libraries.zip");
|
|
@@ -395,26 +505,26 @@ internal static class Downloader
|
|
|
var optifinePath = $"Optifine{versionJson.Id}";
|
|
|
var optifineUrl = $"https://files.veloe.link/launcher/optifine/Optifine{versionJson.Id}/";
|
|
|
|
|
|
- if (!Directory.Exists($"{Settings.minecraftForlderPath}versions/Optifine{versionJson.Id}"))
|
|
|
+ if (!Directory.Exists($"{Settings.minecraftForlderPath}versions/{optifinePath}"))
|
|
|
{
|
|
|
- Settings.logger.Debug("Creating path: {0}", $"{Settings.minecraftForlderPath}Optifine/" + optifinePath);
|
|
|
- Directory.CreateDirectory($"{Settings.minecraftForlderPath}Optifine/" + optifinePath);
|
|
|
+ Settings.logger.Debug("Creating path: {0}", $"{Settings.minecraftForlderPath}versions/" + optifinePath);
|
|
|
+ Directory.CreateDirectory($"{Settings.minecraftForlderPath}versions/" + optifinePath);
|
|
|
}
|
|
|
|
|
|
Settings.logger.Debug("Downloading: {0}", $"Optifine{versionJson.Id}.json");
|
|
|
DownloadingFileName($"Optifine{versionJson.Id}.json");
|
|
|
- webClient.DownloadFileAsync(new System.Uri($"{optifineUrl}Optifine{versionJson.Id}.json"), Settings.minecraftForlderPath + "versions/" + optifinePath + "/" + optifinePath + ".json");
|
|
|
- waitWhileBisy(ref webClient);
|
|
|
+ await DownloadFileAsync($"{optifineUrl}Optifine{versionJson.Id}.json", Settings.minecraftForlderPath + "versions/" + optifinePath + "/" + optifinePath + ".json", cancellationToken, httpClient);
|
|
|
+
|
|
|
|
|
|
Settings.logger.Debug("Downloading: {0}", $"Optifine{versionJson.Id}.jar");
|
|
|
DownloadingFileName($"Optifine{versionJson.Id}.json");
|
|
|
- webClient.DownloadFileAsync(new System.Uri($"{optifineUrl}Optifine{versionJson.Id}.jar"), Settings.minecraftForlderPath + "versions/" + optifinePath + "/" + optifinePath + ".jar");
|
|
|
- waitWhileBisy(ref webClient);
|
|
|
+ await DownloadFileAsync($"{optifineUrl}Optifine{versionJson.Id}.jar", Settings.minecraftForlderPath + "versions/" + optifinePath + "/" + optifinePath + ".jar", cancellationToken, httpClient);
|
|
|
+
|
|
|
|
|
|
Settings.logger.Debug("Downloading: {0}", "libraries.zip");
|
|
|
DownloadingFileName("libraries.zip");
|
|
|
- webClient.DownloadFileAsync(new System.Uri(optifineUrl + "libraries.zip"), Settings.minecraftForlderPath + "versions/" + optifinePath + "/libraries.zip");
|
|
|
- waitWhileBisy(ref webClient);
|
|
|
+ await DownloadFileAsync(optifineUrl + "libraries.zip", Settings.minecraftForlderPath + "versions/" + optifinePath + "/libraries.zip", cancellationToken, httpClient);
|
|
|
+
|
|
|
|
|
|
Settings.logger.Debug("Extracting: {0}", "libraries.zip");
|
|
|
DownloadingFileName("Unpacking libraries.zip");
|
|
@@ -432,199 +542,152 @@ internal static class Downloader
|
|
|
|
|
|
Settings.logger.Debug("Downloading: {0}", $"Optifine{versionJson.Id}.jar");
|
|
|
DownloadingFileName($"Optifine{versionJson.Id}.jar");
|
|
|
- webClient.DownloadFileAsync(new System.Uri(@$"https://files.veloe.link/launcher/forge/Forge{versionJson.Id}/Optifine{versionJson.Id}.jar"),
|
|
|
- Settings.minecraftForlderPath + "versions/Forge" + versionJson.Id + "/mods/" + "Optifine" + versionJson.Id + ".jar");
|
|
|
- waitWhileBisy(ref webClient);
|
|
|
+ await DownloadFileAsync($@"https://files.veloe.link/launcher/forge/Forge{versionJson.Id}/Optifine{versionJson.Id}.jar", Settings.minecraftForlderPath + "versions/Forge" + versionJson.Id + "/mods/" + "Optifine" + versionJson.Id + ".jar", cancellationToken, httpClient);
|
|
|
}
|
|
|
|
|
|
- RemoveProgressBar(webClient);
|
|
|
- //Progress = 100;
|
|
|
- Settings.logger.Debug("Downloading finished.");
|
|
|
- DownloadingFileName("Finished!");
|
|
|
- IsControlsEnabled(true);
|
|
|
-
|
|
|
- webClient.Dispose();
|
|
|
- }
|
|
|
- catch (Exception ex)
|
|
|
- {
|
|
|
- IsControlsEnabled(true);
|
|
|
- DownloadingFileName($"Error occured while downloading {versionJson.Id}.");
|
|
|
- Settings.logger.Error(ex.Message);
|
|
|
- if (ex.StackTrace is not null)
|
|
|
- Settings.logger.Error(ex.StackTrace);
|
|
|
- return TaskStatus.Faulted;
|
|
|
- }
|
|
|
- return TaskStatus.RanToCompletion;
|
|
|
- }
|
|
|
-
|
|
|
- public static async Task<TaskStatus> StartDownloadModpack(Action<string> DownloadingFileName,
|
|
|
- Action<bool> IsControlsEnabled,
|
|
|
- Action<WebClient> SetProgressBar,
|
|
|
- Action<WebClient> RemoveProgressBar,
|
|
|
- ObservableCollection<Entity.VersionManifest.Version> FilteredVersions,
|
|
|
- Modpack SelectedModpack,
|
|
|
- bool DownloadJava = false,
|
|
|
- bool InstallForge = false,
|
|
|
- bool InstallOptifine = false,
|
|
|
- bool InstallForgeOptifine = false,
|
|
|
- bool InstallFabric = false)
|
|
|
- {
|
|
|
- try
|
|
|
- {
|
|
|
- var FilteredVersion = FilteredVersions.Where(x => x.Id == SelectedModpack.Version).FirstOrDefault();
|
|
|
-
|
|
|
- if (FilteredVersion is null)
|
|
|
- return TaskStatus.Faulted;
|
|
|
-
|
|
|
- IsControlsEnabled(false);
|
|
|
-
|
|
|
- InstallForge = SelectedModpack.Forge;
|
|
|
- InstallForgeOptifine = SelectedModpack.ForgeOptifine;
|
|
|
- InstallOptifine = SelectedModpack.Optifine;
|
|
|
- InstallFabric = SelectedModpack.Fabric;
|
|
|
-
|
|
|
- Settings.logger.Debug("Downloading {0}.json", FilteredVersion.Id);
|
|
|
- DownloadingFileName($"{FilteredVersion.Id}.json");
|
|
|
- var versionJson = Downloader.DownloadAndDeserializeJsonData<Entity.Version.Version>(FilteredVersion.Url, Settings.minecraftForlderPath + "versions/" + FilteredVersion.Id + "/", FilteredVersion.Id + ".json");
|
|
|
-
|
|
|
- await Downloader.StartDownload(
|
|
|
- DownloadingFileName,
|
|
|
- IsControlsEnabled,
|
|
|
- SetProgressBar,
|
|
|
- RemoveProgressBar,
|
|
|
- versionJson,
|
|
|
- DownloadJava,
|
|
|
- InstallForge,
|
|
|
- InstallOptifine,
|
|
|
- InstallForgeOptifine,
|
|
|
- InstallFabric);
|
|
|
-
|
|
|
- IsControlsEnabled(false);
|
|
|
-
|
|
|
- string modpackUrl = string.Empty;
|
|
|
-
|
|
|
- if (SelectedModpack.Url is not null)
|
|
|
- modpackUrl = SelectedModpack.Url;
|
|
|
- else
|
|
|
- modpackUrl = $"https://files.veloe.link/launcher/modpacks/{SelectedModpack.Name}.zip";
|
|
|
-
|
|
|
- if (!Directory.Exists($"{Settings.minecraftForlderPath}versions/{SelectedModpack.Name}"))
|
|
|
+ if (InstallForge || InstallOptifine || InstallForgeOptifine || InstallFabric)
|
|
|
{
|
|
|
- Settings.logger.Debug("Creating path: {0}", $"{Settings.minecraftForlderPath}versions/{SelectedModpack.Name}");
|
|
|
- Directory.CreateDirectory($"{Settings.minecraftForlderPath}versions/{SelectedModpack.Name}");
|
|
|
+ tasksIterator++;
|
|
|
+ TasksStatus($"Task {tasksIterator} of {tasksCount} complete.");
|
|
|
}
|
|
|
|
|
|
- WebClient webClient = new WebClient();
|
|
|
+ if (downloadModpack)
|
|
|
+ {
|
|
|
+ if (SelectedModpack is null)
|
|
|
+ return TaskStatus.Faulted;
|
|
|
|
|
|
- SetProgressBar(webClient);
|
|
|
+ string modpackUrl = string.Empty;
|
|
|
|
|
|
- Settings.logger.Debug("Downloading: {0}", $"{SelectedModpack.Name}.zip");
|
|
|
- DownloadingFileName($"{SelectedModpack.Name}.zip");
|
|
|
- webClient.DownloadFileAsync(new System.Uri(modpackUrl), Settings.minecraftForlderPath + $"versions/{SelectedModpack.Name}.zip");
|
|
|
- waitWhileBisy(ref webClient);
|
|
|
+ if (SelectedModpack.Url is not null)
|
|
|
+ modpackUrl = SelectedModpack.Url;
|
|
|
+ else
|
|
|
+ modpackUrl = $"https://files.veloe.link/launcher/modpacks/{SelectedModpack.Name}.zip";
|
|
|
|
|
|
- FileStream stream = null;
|
|
|
- if (Directory.Exists($"{Settings.minecraftForlderPath}versions/{SelectedModpack.Name}/mods"))
|
|
|
- {
|
|
|
- foreach (var file in Directory.GetFiles($"{Settings.minecraftForlderPath}versions/{SelectedModpack.Name}/mods"))
|
|
|
+ if (!Directory.Exists($"{Settings.minecraftForlderPath}versions/{SelectedModpack.Name}"))
|
|
|
{
|
|
|
- try { stream = File.Open(file,FileMode.Open, FileAccess.Read, FileShare.None);}
|
|
|
- catch (IOException) { throw; }
|
|
|
- finally { stream?.Close(); }
|
|
|
+ Settings.logger.Debug("Creating path: {0}", $"{Settings.minecraftForlderPath}versions/{SelectedModpack.Name}");
|
|
|
+ Directory.CreateDirectory($"{Settings.minecraftForlderPath}versions/{SelectedModpack.Name}");
|
|
|
}
|
|
|
- }
|
|
|
- if (Directory.Exists($"{Settings.minecraftForlderPath}versions/{SelectedModpack.Name}/config"))
|
|
|
- foreach (var file in Directory.GetFiles($"{Settings.minecraftForlderPath}versions/{SelectedModpack.Name}/mods"))
|
|
|
+
|
|
|
+ Settings.logger.Debug("Downloading: {0}", $"{SelectedModpack.Name}.zip");
|
|
|
+ DownloadingFileName($"{SelectedModpack.Name}.zip");
|
|
|
+ await DownloadFileAsync(modpackUrl, Settings.minecraftForlderPath + $"versions/{SelectedModpack.Name}.zip", cancellationToken, httpClient);
|
|
|
+
|
|
|
+ FileStream? stream = null;
|
|
|
+
|
|
|
+ if (Directory.Exists($"{Settings.minecraftForlderPath}versions/{SelectedModpack.Name}/mods"))
|
|
|
{
|
|
|
- try { stream = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.None); }
|
|
|
- catch (IOException) { throw; }
|
|
|
- finally { stream?.Close(); }
|
|
|
+ foreach (var file in Directory.GetFiles($"{Settings.minecraftForlderPath}versions/{SelectedModpack.Name}/mods"))
|
|
|
+ {
|
|
|
+ try { stream = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.None); }
|
|
|
+ finally { stream?.Close(); }
|
|
|
+ }
|
|
|
}
|
|
|
+ if (Directory.Exists($"{Settings.minecraftForlderPath}versions/{SelectedModpack.Name}/config"))
|
|
|
+ foreach (var file in Directory.GetFiles($"{Settings.minecraftForlderPath}versions/{SelectedModpack.Name}/mods"))
|
|
|
+ {
|
|
|
+ try { stream = File.Open(file, FileMode.Open, FileAccess.Read, FileShare.None); }
|
|
|
+ finally { stream?.Close(); }
|
|
|
+ }
|
|
|
|
|
|
- if (Directory.Exists($"{Settings.minecraftForlderPath}versions/{SelectedModpack.Name}/mods"))
|
|
|
- Directory.Delete($"{Settings.minecraftForlderPath}versions/{SelectedModpack.Name}/mods", true);
|
|
|
- if (Directory.Exists($"{Settings.minecraftForlderPath}versions/{SelectedModpack.Name}/config"))
|
|
|
- Directory.Delete($"{Settings.minecraftForlderPath}versions/{SelectedModpack.Name}/config", true);
|
|
|
+ stream?.Dispose();
|
|
|
|
|
|
- Settings.logger.Debug("Extracting: {0}", $"{SelectedModpack.Name}.zip");
|
|
|
- DownloadingFileName($"Unpacking {SelectedModpack.Name}.zip");
|
|
|
- ZipFile.ExtractToDirectory($"{Settings.minecraftForlderPath}versions/{SelectedModpack.Name}.zip", Settings.minecraftForlderPath + $"versions/{SelectedModpack.Name}", true);
|
|
|
- File.Delete($"{Settings.minecraftForlderPath}versions/{SelectedModpack.Name}.zip");
|
|
|
+ if (Directory.Exists($"{Settings.minecraftForlderPath}versions/{SelectedModpack.Name}/mods"))
|
|
|
+ Directory.Delete($"{Settings.minecraftForlderPath}versions/{SelectedModpack.Name}/mods", true);
|
|
|
+ if (Directory.Exists($"{Settings.minecraftForlderPath}versions/{SelectedModpack.Name}/config"))
|
|
|
+ Directory.Delete($"{Settings.minecraftForlderPath}versions/{SelectedModpack.Name}/config", true);
|
|
|
|
|
|
- File.WriteAllText($"{Settings.minecraftForlderPath}versions/{SelectedModpack.Name}/revision.json",JsonSerializer.Serialize(SelectedModpack.Revision));
|
|
|
+ Settings.logger.Debug("Extracting: {0}", $"{SelectedModpack.Name}.zip");
|
|
|
+ DownloadingFileName($"Unpacking {SelectedModpack.Name}.zip");
|
|
|
+ ZipFile.ExtractToDirectory($"{Settings.minecraftForlderPath}versions/{SelectedModpack.Name}.zip", Settings.minecraftForlderPath + $"versions/{SelectedModpack.Name}", true);
|
|
|
+ File.Delete($"{Settings.minecraftForlderPath}versions/{SelectedModpack.Name}.zip");
|
|
|
|
|
|
- RemoveProgressBar(webClient);
|
|
|
+ File.WriteAllText($"{Settings.minecraftForlderPath}versions/{SelectedModpack.Name}/revision.json", JsonSerializer.Serialize(SelectedModpack.Revision));
|
|
|
+ tasksIterator++;
|
|
|
+ TasksStatus($"Task {tasksIterator} of {tasksCount} complete.");
|
|
|
+ }
|
|
|
|
|
|
+ //RemoveProgressBar(webClient);
|
|
|
//Progress = 100;
|
|
|
- Settings.logger.Debug("Downloading {0} finished.", SelectedModpack.Name);
|
|
|
- DownloadingFileName($"Finished {SelectedModpack.Name}!");
|
|
|
+ Settings.logger.Debug("Downloading finished.");
|
|
|
+ DownloadingFileName("Finished!");
|
|
|
IsControlsEnabled(true);
|
|
|
- webClient.Dispose();
|
|
|
|
|
|
+ //webClient.Dispose();
|
|
|
+ }
|
|
|
+ catch (TaskCanceledException ex)
|
|
|
+ {
|
|
|
+ IsControlsEnabled(true);
|
|
|
+ if (downloadModpack && SelectedModpack is not null)
|
|
|
+ DownloadingFileName($"Downloading {SelectedModpack.Name} canceled.");
|
|
|
+ else
|
|
|
+ DownloadingFileName($"Downloading {versionJson.Id} canceled.");
|
|
|
+ Settings.logger.Warning(ex.Message);
|
|
|
+ return TaskStatus.Canceled;
|
|
|
}
|
|
|
catch (Exception ex)
|
|
|
{
|
|
|
IsControlsEnabled(true);
|
|
|
- DownloadingFileName($"Error occured while downloading {SelectedModpack.Name}.");
|
|
|
- ViewModelBase.OpenErrorWindow(ex);
|
|
|
+ if (downloadModpack && SelectedModpack is not null)
|
|
|
+ DownloadingFileName($"Error occured while downloading {SelectedModpack.Name}.");
|
|
|
+ else
|
|
|
+ DownloadingFileName($"Error occured while downloading {versionJson.Id}.");
|
|
|
+ Settings.logger.Error(ex.Message);
|
|
|
+ if (ex.StackTrace is not null)
|
|
|
+ Settings.logger.Error(ex.StackTrace);
|
|
|
return TaskStatus.Faulted;
|
|
|
}
|
|
|
return TaskStatus.RanToCompletion;
|
|
|
}
|
|
|
|
|
|
- public static T DownloadAndDeserializeJsonData<T>(string url, string path = "", string filename = "") where T : new()
|
|
|
+ public static async Task<T> DownloadAndDeserializeJsonData<T>(string url, string path = "", string filename = "") where T : new()
|
|
|
{
|
|
|
- using (var webClient = new HttpClient())
|
|
|
+ var jsonData = string.Empty;
|
|
|
+
|
|
|
+ try
|
|
|
{
|
|
|
- var jsonData = string.Empty;
|
|
|
- try
|
|
|
- {
|
|
|
- try
|
|
|
- {
|
|
|
- Settings.logger.Debug($"Downloading: {url.Split('/').Last()}");
|
|
|
- jsonData = webClient.GetStringAsync(url).Result;
|
|
|
- }
|
|
|
- catch (Exception ex)
|
|
|
- {
|
|
|
- throw new WebException($"An error occured while downloading {url}. Check your internet connection.",ex);
|
|
|
- }
|
|
|
+ Settings.logger.Debug($"Downloading: {url.Split('/').Last()}");
|
|
|
+ jsonData = await _httpClient.GetStringAsync(url);
|
|
|
+ }
|
|
|
+ catch (Exception ex)
|
|
|
+ {
|
|
|
+ throw new WebException($"An error occured while downloading {url}. Check your internet connection.",ex);
|
|
|
+ }
|
|
|
|
|
|
- if (string.IsNullOrEmpty(jsonData))
|
|
|
- {
|
|
|
- Settings.logger.Warning("Empty string!");
|
|
|
- return new T();
|
|
|
- }
|
|
|
- else
|
|
|
+ if (string.IsNullOrEmpty(jsonData))
|
|
|
+ {
|
|
|
+ Settings.logger.Warning("Empty string!");
|
|
|
+ return new T();
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ if (!string.IsNullOrEmpty(filename) && !string.IsNullOrEmpty(path))
|
|
|
+ {
|
|
|
+ if (!Directory.Exists(path))
|
|
|
{
|
|
|
- if (!string.IsNullOrEmpty(filename) && !string.IsNullOrEmpty(path))
|
|
|
- {
|
|
|
- if (!Directory.Exists(path))
|
|
|
- {
|
|
|
- Settings.logger.Debug("Creating path: {0}", path);
|
|
|
- Directory.CreateDirectory(path);
|
|
|
- }
|
|
|
- File.WriteAllText(path + filename, jsonData);
|
|
|
- }
|
|
|
- //Settings.logger.Debug("Return serialized string.");
|
|
|
- return JsonSerializer.Deserialize<T>(jsonData, new JsonSerializerOptions{PropertyNameCaseInsensitive = true});
|
|
|
+ Settings.logger.Debug("Creating path: {0}", path);
|
|
|
+ Directory.CreateDirectory(path);
|
|
|
}
|
|
|
- /*
|
|
|
- return string.IsNullOrEmpty(jsonData)
|
|
|
- ? new T()
|
|
|
- : JsonSerializer.Deserialize<T>(jsonData);*/
|
|
|
- }
|
|
|
- catch (Exception ex)
|
|
|
- {
|
|
|
- throw;
|
|
|
+ File.WriteAllText(path + filename, jsonData);
|
|
|
}
|
|
|
- }
|
|
|
+ //Settings.logger.Debug("Return serialized string.");
|
|
|
+ return JsonSerializer.Deserialize<T>(jsonData, new JsonSerializerOptions{PropertyNameCaseInsensitive = true});
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- private static void waitWhileBisy(ref WebClient webClient)
|
|
|
- {
|
|
|
- while (webClient.IsBusy)
|
|
|
- {
|
|
|
- Task.Delay(10).Wait();
|
|
|
- }
|
|
|
+ private static async Task DownloadFileAsync(string url, string path, CancellationToken ct, HttpClient? client = null)
|
|
|
+ {
|
|
|
+ if (client == null) client = _httpClient;
|
|
|
+ using HttpResponseMessage response = await client.GetAsync(new System.Uri(url),HttpCompletionOption.ResponseHeadersRead, ct);
|
|
|
+ response.EnsureSuccessStatusCode();
|
|
|
+ using Stream contentStream = await response.Content.ReadAsStreamAsync(ct);
|
|
|
+ using FileStream fileStream = File.OpenWrite(path);
|
|
|
+ await contentStream.CopyToAsync(fileStream,ct);
|
|
|
+ }
|
|
|
+
|
|
|
+ public static async Task<bool> IsFileAvaliable(string url, CancellationToken ct)
|
|
|
+ {
|
|
|
+ using HttpResponseMessage response = await _httpClient.GetAsync(new System.Uri(url), HttpCompletionOption.ResponseHeadersRead, ct);
|
|
|
+ return response.IsSuccessStatusCode;
|
|
|
}
|
|
|
}
|