Bläddra i källkod

added vanilla files hash check

Veloe 3 år sedan
förälder
incheckning
e5dddf0560

+ 571 - 21
VeloeMinecraftLauncher/MinecraftLauncher/Downloader.cs

@@ -9,14 +9,556 @@ using System.Net.Http;
 using System.Text;
 using System.Text.Json;
 using System.Threading.Tasks;
+using System.IO.Compression;
+using VeloeMinecraftLauncher.Entity.Assets;
 using VeloeMinecraftLauncher.ViewModels;
 using VeloeMinecraftLauncher.Views;
+using VeloeMinecraftLauncher.Entity.VersionManifest;
+using System.Collections.ObjectModel;
 
 namespace VeloeMinecraftLauncher.MinecraftLauncher
 {
     internal static class Downloader
     {
-        public static T DownloadAndDeserializeJsonData<T>(string url) where T : new()
+        public static async Task<TaskStatus> StartDownload(
+            Action<string> DownloadingFileName,
+            Action<bool> IsControlsEnabled,
+            Action<WebClient> SetProgressBar,
+            Action<WebClient> RemoveProgressBar,
+            Entity.Version.Version versionJson,
+            bool DownloadJava = false,
+            bool InstallForge = false,
+            bool InstallOptifine = false,
+            bool InstallForgeOptifine = false,
+            bool InstallFabric = false
+            )
+        {
+            try
+            {
+                Settings.logger.Debug("Downloading minecraft {0}", versionJson.id);
+                var webClient = new WebClient();
+                
+                SetProgressBar(webClient);
+                //webClient.DownloadProgressChanged += WebClient_DownloadProgressChanged;
+                //download java
+                if (DownloadJava)
+                {
+                    Settings.logger.Debug("Getting required Java version.");
+                    if (versionJson.javaVersion.majorVersion != null)
+                    {
+                        string javaUrl = "";
+                        switch (versionJson.javaVersion.majorVersion)
+                        {
+                            case 8:
+                                if (Environment.Is64BitOperatingSystem && OperatingSystem.IsWindows())
+                                    javaUrl = "https://files.veloe.link/launcher/java/8/windows64/java.zip";
+                                if (!Environment.Is64BitOperatingSystem && OperatingSystem.IsWindows())
+                                    javaUrl = "https://files.veloe.link/launcher/java/8/windows32/java.zip";
+
+                                if (Environment.Is64BitOperatingSystem && OperatingSystem.IsLinux())
+                                    javaUrl = "https://files.veloe.link/launcher/java/8/linux64/java.zip";
+                                if (!Environment.Is64BitOperatingSystem && OperatingSystem.IsLinux())
+                                    javaUrl = "https://files.veloe.link/launcher/java/8/linux32/java.zip";
+                                break;
+                            case 16:
+                                if (Environment.Is64BitOperatingSystem && OperatingSystem.IsWindows())
+                                    javaUrl = "https://files.veloe.link/launcher/java/16/windows64/java.zip";
+                                if (Environment.Is64BitOperatingSystem && OperatingSystem.IsLinux())
+                                    javaUrl = "https://files.veloe.link/launcher/java/16/linux64/java.zip";
+                                break;
+                            case 17:
+                                if (Environment.Is64BitOperatingSystem && OperatingSystem.IsWindows())
+                                    javaUrl = "https://files.veloe.link/launcher/java/17/windows64/java.zip";
+                                if (Environment.Is64BitOperatingSystem && OperatingSystem.IsLinux())
+                                    javaUrl = "https://files.veloe.link/launcher/java/17/linux64/java.zip";
+
+                                break;
+                            case 18:
+                                if (Environment.Is64BitOperatingSystem && OperatingSystem.IsWindows())
+                                    javaUrl = "https://files.veloe.link/launcher/java/18/windows64/java.zip";
+                                if (Environment.Is64BitOperatingSystem && OperatingSystem.IsLinux())
+                                    javaUrl = "https://files.veloe.link/launcher/java/18/linux64/java.zip";
+
+                                break;
+                        }
+                        if (javaUrl != "")
+                        {
+                            Settings.logger.Debug("Downloading Java");
+                            DownloadingFileName("java.zip");
+                            webClient.DownloadFileAsync(new System.Uri(javaUrl), Settings.MinecraftForlderPath + "java.zip");
+                            waitWhileBisy(ref webClient);
+
+                            Settings.logger.Debug("Unpacking Java");
+                            DownloadingFileName("Unpacking java.zip");
+                            ZipFile.ExtractToDirectory($"{Settings.MinecraftForlderPath}java.zip", Settings.MinecraftForlderPath, true);
+                            File.Delete($"{Settings.MinecraftForlderPath}java.zip");
+                        }
+                        else
+                            Settings.logger.Debug("Required Java version don't found in json file."); //log that java was not downloaded;
+                    }
+                }
+
+                //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))
+                {
+                    Settings.logger.Debug("Creating path: {0}", path);
+                    Directory.CreateDirectory(path);
+                }
+
+                string chksum = String.Empty;
+                //here hash check
+                if (File.Exists(path + "/" + versionJson.id + ".jar"))
+                {
+                    DownloadingFileName($"Checking hash: {versionJson.id}.jar");
+                    FileStream fop = File.OpenRead(path + "/" + versionJson.id + ".jar");
+                    byte[] hash = System.Security.Cryptography.SHA1.Create().ComputeHash(fop);
+                    chksum = BitConverter.ToString(hash).Replace("-", String.Empty).ToLower();
+
+                    fop.Close();
+                    fop.Dispose();
+                }
+
+                if (chksum != versionJson.downloads.client.sha1)
+                {
+                    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);
+                }
+                //end download jar
+                //download libraries
+                Settings.logger.Debug("Downloading libraries.");
+                foreach (var library in versionJson.libraries)
+                {
+                    var libPath = Settings.MinecraftForlderPath + "libraries/";
+                    string[] libPathSplit = new[] { "" };
+                    string libUrl = "";
+                    string sha1 = String.Empty;
+                    // getting path and url if universal lib
+                    if (library.natives is null)
+                    {
+                        libPath = Settings.MinecraftForlderPath + "libraries/";
+                        libPathSplit = library.downloads.artifact.path.Split('/');
+                        libUrl = library.downloads.artifact.url;
+                        sha1 = library.downloads.artifact.sha1;
+                        for (int i = 0; i < libPathSplit.Length - 1; i++)
+                        {
+                            libPath += libPathSplit[i] + "/";
+                        }
+
+                    }
+                    else
+                    {   // getting path if native
+                        libPath = Settings.MinecraftForlderPath + "libraries/";
+                        libPathSplit = new[] { "" };
+                        libUrl = "";
+
+                        if (OperatingSystem.IsWindows() && library.natives.windows is not null)
+                        {
+                            if (library.downloads.classifiers.NativesWindows is not null)
+                            {
+                                libPathSplit = library.downloads.classifiers.NativesWindows.path.Split('/');
+                                libUrl = library.downloads.classifiers.NativesWindows.url;
+                                sha1 = library.downloads.classifiers.NativesWindows.sha1;
+                            }
+                            else
+                            {
+                                if (Environment.Is64BitOperatingSystem)
+                                {
+                                    libPathSplit = library.downloads.classifiers.NativesWindows64.path.Split('/');
+                                    libUrl = library.downloads.classifiers.NativesWindows64.url;
+                                    sha1 = library.downloads.classifiers.NativesWindows64.sha1;
+                                }
+                                else
+                                {
+                                    libPathSplit = library.downloads.classifiers.NativesWindows32.path.Split('/');
+                                    libUrl = library.downloads.classifiers.NativesWindows32.url;
+                                    sha1 = library.downloads.classifiers.NativesWindows32.sha1;
+                                }
+                            }
+                        }
+                        if (OperatingSystem.IsLinux() && library.natives.linux is not null)
+                        {
+                            libPathSplit = library.downloads.classifiers.NativesLinux.path.Split('/');
+                            libUrl = library.downloads.classifiers.NativesLinux.url;
+                            sha1 = library.downloads.classifiers.NativesLinux.url;
+                        }
+
+
+                        for (int i = 0; i < libPathSplit.Length - 1; i++)
+                        {
+                            libPath += libPathSplit[i] + "/";
+                        }
+                    }
+
+                    //if no lib url
+                    if (libUrl == String.Empty)
+                        continue;
+
+                    //checking rules
+                    if (library.rules == null)
+                    {
+                        if (!Directory.Exists(libPath))
+                        {
+                            Settings.logger.Debug("Creating path: {0}", path);
+                            Directory.CreateDirectory(libPath);
+                        }
+
+                        chksum = String.Empty;
+
+                        if (File.Exists(libPath + "/" + libPathSplit.Last()))
+                        {
+                            DownloadingFileName($"Checking hash: {libPathSplit.Last()}");
+                            FileStream fop = File.OpenRead(libPath + "/" + libPathSplit.Last());
+                            byte[] hash = System.Security.Cryptography.SHA1.Create().ComputeHash(fop);
+                            chksum = BitConverter.ToString(hash).Replace("-", String.Empty).ToLower();
+
+                            fop.Close();
+                            fop.Dispose();
+                        }
+
+                        if (chksum != sha1)
+                        {
+                            Settings.logger.Debug("Downloading: {0}", libPathSplit.Last());
+                            DownloadingFileName(libPathSplit.Last());
+                            webClient.DownloadFileAsync(new System.Uri(libUrl), libPath + "/" + libPathSplit.Last());
+                            waitWhileBisy(ref webClient);
+                        }
+                    }
+                    else
+                    {
+                        foreach (var rule in library.rules)
+                        {
+                            if (rule.action == "allow") // && rule.os is null
+                            {
+                                if (!Directory.Exists(libPath))
+                                {
+                                    Settings.logger.Debug("Creating path: {0}", path);
+                                    Directory.CreateDirectory(libPath);
+                                }
+
+                                chksum = String.Empty;
+
+                                if (File.Exists(libPath + "/" + libPathSplit.Last()) && sha1 != String.Empty)
+                                {
+                                    DownloadingFileName($"Checking hash: {libPathSplit.Last()}");
+                                    FileStream fop = File.OpenRead(libPath + "/" + libPathSplit.Last());
+                                    byte[] hash = System.Security.Cryptography.SHA1.Create().ComputeHash(fop);
+                                    chksum = BitConverter.ToString(hash).Replace("-", String.Empty).ToLower();
+
+                                    fop.Close();
+                                    fop.Dispose();
+                                }
+
+                                if (chksum != sha1)
+                                {
+                                    Settings.logger.Debug("Downloading: {0}", libPathSplit.Last());
+                                    DownloadingFileName(libPathSplit.Last());
+                                    webClient.DownloadFileAsync(new System.Uri(libUrl), libPath + "/" + libPathSplit.Last());
+                                    waitWhileBisy(ref webClient);
+                                }
+                                continue;
+                            }
+                            //fabic on start needs all libraries for all os, so os check removed
+                            /*
+                            if (rule.action == "allow" && (rule.os.name == "windows" || rule.os.name == "linux" || rule.os.name == "osx" ))
+                            {
+                                if (!Directory.Exists(libPath))
+                                {
+                                    Settings.logger.Debug("Creating path: {0}", path);
+                                    Directory.CreateDirectory(libPath);
+                                }
+                                Settings.logger.Debug("Downloading: {0}", libPathSplit.Last());
+                                DownloadingFileName = libPathSplit.Last();
+                                webClient.DownloadFileAsync(new System.Uri(libUrl), libPath + "/" + libPathSplit.Last());
+                                waitWhileBisy(ref webClient);
+                            }
+                            */
+                        }
+                    }
+                    //unpacking native libs
+                    if (((library.natives is not null || library.downloads.classifiers is not null) && File.Exists(libPath + "/" + libPathSplit.Last())) /*&& chksum != sha1*/)
+                    {
+                        try
+                        {
+                            if (!((
+                                library.downloads.classifiers.NativesWindows is not null ||
+                                    library.downloads.classifiers.NativesWindows64 is not null ||
+                                    library.downloads.classifiers.NativesWindows32 is not null) && OperatingSystem.IsWindows() ||
+                                library.downloads.classifiers.NativesLinux is not null && OperatingSystem.IsLinux()))
+                                continue;
+
+                            if (!Directory.Exists(Settings.MinecraftForlderPath + "versions/" + versionJson.id + "/natives/"))
+                            {
+                                Settings.logger.Debug("Creating path: {0}", Settings.MinecraftForlderPath + "versions/" + versionJson.id + "/natives/");
+                                Directory.CreateDirectory(Settings.MinecraftForlderPath + "versions/" + versionJson.id + "/natives/");
+                            }
+                            Settings.logger.Debug("Extracting {0} to {1}", libPathSplit.Last(), Settings.MinecraftForlderPath + "versions/" + versionJson.id + "/natives/");
+                            ZipFile.ExtractToDirectory(libPath + "/" + libPathSplit.Last(), Settings.MinecraftForlderPath + "versions/" + versionJson.id + "/natives/", true);
+                        }
+                        catch (IOException ex)
+                        {
+                            Settings.logger.Error("IOException in VersionsDownloaderViewModel on native lib extraction");
+                        }
+                        //TODO delete META-INF and sha1 files after
+                    }
+                }
+
+                var assetsJson = Downloader.DownloadAndDeserializeJsonData<AssetsManifest>(versionJson.assetIndex.url);
+                var assetsPath = Settings.MinecraftForlderPath + "assets/" + versionJson.assets + "/objects";
+                var assetsUrl = "https://resources.download.minecraft.net/";
+
+                //download assets json
+                Settings.logger.Debug("Downloading: {0}", versionJson.assets + ".json");
+
+                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");
+
+                //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);
+
+                    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();
+
+                        fop.Close();
+                        fop.Dispose();
+                    }
+
+                    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);
+                    }
+                }
+
+                if (InstallForge)
+                {
+                    var forgePath = $"Forge{versionJson.id}";
+                    var forgeUrl = $"https://files.veloe.link/launcher/forge/Forge{versionJson.id}/";
+
+                    if (!Directory.Exists($"{Settings.MinecraftForlderPath}versions/Forge{versionJson.id}"))
+                    {
+                        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);
+
+                    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);
+
+                    Settings.logger.Debug("Extracting: {0}", "libraries.zip");
+                    DownloadingFileName("Unpacking libraries.zip");
+                    ZipFile.ExtractToDirectory($"{Settings.MinecraftForlderPath}versions/Forge{versionJson.id}/libraries.zip", Settings.MinecraftForlderPath, true);
+                    File.Delete($"{Settings.MinecraftForlderPath}versions/Forge{versionJson.id}/libraries.zip");
+                }
+
+                if (InstallOptifine)
+                {
+                    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}"))
+                    {
+                        Settings.logger.Debug("Creating path: {0}", $"{Settings.MinecraftForlderPath}Optifine/" + optifinePath);
+                        Directory.CreateDirectory($"{Settings.MinecraftForlderPath}Optifine/" + 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);
+
+                    Settings.logger.Debug("Downloading: {0}", $"Optifine{versionJson.id}.json");
+                    DownloadingFileName($"Optifine{versionJson.id}.json");
+                    webClient.DownloadFileAsync(new System.Uri($"{optifineUrl}Optifine{versionJson.id}.jar"), Settings.MinecraftForlderPath + "versions/" + optifinePath + "/" + optifinePath + ".jar");
+                    waitWhileBisy(ref webClient);
+
+                    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);
+
+                    Settings.logger.Debug("Extracting: {0}", "libraries.zip");
+                    DownloadingFileName("Unpacking libraries.zip");
+                    ZipFile.ExtractToDirectory($"{Settings.MinecraftForlderPath}versions/Optifine{versionJson.id}/libraries.zip", Settings.MinecraftForlderPath, true);
+                    File.Delete($"{Settings.MinecraftForlderPath}versions/Optifine{versionJson.id}/libraries.zip");
+                }
+
+                if (InstallForgeOptifine)
+                {
+                    if (!Directory.Exists($"{Settings.MinecraftForlderPath}versions/Forge{versionJson.id}/mods"))
+                    {
+                        Settings.logger.Debug("Creating path: {0}", $"{Settings.MinecraftForlderPath}versions/Forge" + versionJson.id + "/mods");
+                        Directory.CreateDirectory($"{Settings.MinecraftForlderPath}versions/Forge" + versionJson.id + "/mods");
+                    }
+
+                    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);
+                }
+
+                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);
+                Settings.logger.Error(ex.StackTrace);
+                return TaskStatus.Faulted;
+            }
+            return TaskStatus.RanToCompletion;
+        }
+
+        public static async Task<TaskStatus> StartDownloadMcTfc(Action<string> DownloadingFileName,
+            Action<bool> IsControlsEnabled,
+            Action<WebClient> SetProgressBar,
+            Action<WebClient> RemoveProgressBar,
+            ObservableCollection<Entity.VersionManifest.Version> FilteredVersions,
+            bool DownloadJava = false,
+            bool InstallForge = false,
+            bool InstallOptifine = false,
+            bool InstallForgeOptifine = false,
+            bool InstallFabric = false)
+        {
+            try
+            {
+                var FilteredVersion = FilteredVersions.Where(x => x.id == "1.12.2").FirstOrDefault();
+
+                if (FilteredVersion is null)
+                    return TaskStatus.Faulted;
+
+                InstallForge = true;
+                InstallForgeOptifine = true;
+
+                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);
+                var mcTfcUrl = $"https://files.veloe.link/launcher/McTFC/McTFC.zip";
+
+                if (!Directory.Exists($"{Settings.MinecraftForlderPath}versions/McTFC"))
+                {
+                    Settings.logger.Debug("Creating path: {0}", $"{Settings.MinecraftForlderPath}versions/McTFC");
+                    Directory.CreateDirectory($"{Settings.MinecraftForlderPath}versions/McTFC");
+                }
+
+                WebClient webClient = new WebClient();
+
+                SetProgressBar(webClient);
+
+                Settings.logger.Debug("Downloading: {0}", "McTFC.zip");
+                DownloadingFileName("McTFC.zip");
+                webClient.DownloadFileAsync(new System.Uri(mcTfcUrl), Settings.MinecraftForlderPath + "versions/McTFC.zip");
+                waitWhileBisy(ref webClient);
+
+                Settings.logger.Debug("Extracting: {0}", "McTFC.zip");
+                DownloadingFileName("Unpacking McTFC.zip");
+                ZipFile.ExtractToDirectory($"{Settings.MinecraftForlderPath}versions/McTFC.zip", Settings.MinecraftForlderPath + "versions/McTFC", true);
+                File.Delete($"{Settings.MinecraftForlderPath}versions/McTFC.zip");
+
+                RemoveProgressBar(webClient);
+
+                //Progress = 100;
+                Settings.logger.Debug("Downloading McTFC finished.");
+                DownloadingFileName("Finished McTFC!");
+                IsControlsEnabled(true);
+                webClient.Dispose();
+
+            }
+            catch (Exception ex)
+            {
+                IsControlsEnabled(true);
+                DownloadingFileName("Error occured while downloading McTFC.");        
+                var message = ex.Message;
+                var stackTrace = ex.StackTrace;
+                Settings.logger.Error(ex.Message);
+                Settings.logger.Error(ex.StackTrace);
+                Exception innerException = ex.InnerException;
+                while (innerException is not null)
+                {
+                    message += "\n" + innerException.Message;
+                    stackTrace += "\n" + innerException.StackTrace;
+                    Settings.logger.Error(innerException.Message);
+                    Settings.logger.Error(innerException.StackTrace);
+                    innerException = innerException.InnerException;
+                }
+
+                Dispatcher.UIThread.InvokeAsync(() =>
+                {
+                    if (Avalonia.Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
+                    {
+                        Dispatcher.UIThread.InvokeAsync(() =>
+                        {
+                            var ErrorMessageViewModel = new ErrorWindowViewModel(message, stackTrace);
+                            var ErrorMessage = new ErrorWindow()
+                            {
+                                DataContext = ErrorMessageViewModel
+                            };
+                            ErrorMessage.ShowDialog(desktop.MainWindow);
+                        });
+                    }
+                });
+                return TaskStatus.Faulted;
+            }
+            return TaskStatus.RanToCompletion;
+        }
+
+        public static T DownloadAndDeserializeJsonData<T>(string url, string path = "", string filename = "") where T : new()
         {
             using (var webClient = new HttpClient())
             {
@@ -25,6 +567,31 @@ namespace VeloeMinecraftLauncher.MinecraftLauncher
                 {
                     Settings.logger.Debug($"Downloading: {url.Split('/').Last()}");
                     jsonData = webClient.GetStringAsync(url).Result;
+                
+
+                if (string.IsNullOrEmpty(jsonData))
+                {
+                    Settings.logger.Warning("Empty string!");
+                    return new T();
+                }
+                else
+                {
+                    if (filename != "")
+                    {
+                        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);
+                }
+                    /*
+                    return string.IsNullOrEmpty(jsonData)
+                                ? new T()
+                                : JsonSerializer.Deserialize<T>(jsonData);*/
                 }
                 catch (Exception ex)
                 {
@@ -57,33 +624,16 @@ namespace VeloeMinecraftLauncher.MinecraftLauncher
                             });
                         }
                     });
-                 
-                }
-
-                if (string.IsNullOrEmpty(jsonData))
-                {
-                    Settings.logger.Warning("Empty string!");
                     return new T();
                 }
-                else
-                {
-                    //Settings.logger.Debug("Return serialized string.");
-                    return JsonSerializer.Deserialize<T>(jsonData);
-                }
-                /*
-                return string.IsNullOrEmpty(jsonData)
-                            ? new T()
-                            : JsonSerializer.Deserialize<T>(jsonData);*/
             }
         }
 
-        public static void DownloadFile(string url, string path, string filename)
+        private static void waitWhileBisy(ref WebClient webClient)
         {
-            using (var webClient = new WebClient())
+            while (webClient.IsBusy)
             {
-                if (!Directory.Exists(path))
-                    Directory.CreateDirectory(path);
-                webClient.DownloadFileAsync(new System.Uri(url), path + "/" + filename);
+                Task.Delay(100).Wait();
             }
         }
     }

+ 257 - 215
VeloeMinecraftLauncher/ViewModels/MainWindowViewModel.cs

@@ -34,150 +34,150 @@ namespace VeloeMinecraftLauncher.ViewModels
     {
         public MainWindowViewModel()
         {           
-                Task.Run(() =>
+            Task.Run(() =>
+            {
+                try
                 {
-                    try
-                    {
-                        //creating logger
-                        EventSink eventSink = new(null);
-                        eventSink.DataReceived += LogHandler;
-
-                        logger = new LoggerConfiguration()
-                           .MinimumLevel.Debug()
-                           .WriteTo.Sink(eventSink)
-                           .WriteTo.File("launcher.log", LogEventLevel.Debug, fileSizeLimitBytes: 100000000)// restricted... is Optional
-                           .CreateLogger();
-                        Settings.logger = logger;
-
-                        //loading settings
-                        logger.Debug("Loading settings.");
-                        Settings.LoadSettings();
-                        username = Settings.Username;
-
-                        //loading local verions
-                        logger.Debug("Loading local versions.");
-                        updateAvailable();
-                    }
-                    catch (Exception ex)
-                    {
-                        OpenErrorWindow(ex);
-                    }
+                    //creating logger
+                    EventSink eventSink = new(null);
+                    eventSink.DataReceived += LogHandler;
+
+                    logger = new LoggerConfiguration()
+                        .MinimumLevel.Debug()
+                        .WriteTo.Sink(eventSink)
+                        .WriteTo.File("launcher.log", LogEventLevel.Debug, fileSizeLimitBytes: 100000000)// restricted... is Optional
+                        .CreateLogger();
+                    Settings.logger = logger;
+
+                    //loading settings
+                    logger.Debug("Loading settings.");
+                    Settings.LoadSettings();
+                    username = Settings.Username;
+
+                    //loading local verions
+                    logger.Debug("Loading local versions.");
+                    updateAvailable();
+                }
+                catch (Exception ex)
+                {
+                    OpenErrorWindow(ex);
+                }
 
-                    UpdateUpdater();
+                UpdateUpdater();
 
-                    try
+                try
+                {
+                    //check launcher update
+                    logger.Information("Checking launcher versions updates.");
+                    latestLauncherInfo = Downloader.DownloadAndDeserializeJsonData<LatestLauncherVersion>("https://files.veloe.link/launcher/update/versions.json");
+                    if (latestLauncherInfo is not null)
                     {
-                        //check launcher update
-                        logger.Information("Checking launcher versions updates.");
-                        latestLauncherInfo = Downloader.DownloadAndDeserializeJsonData<LatestLauncherVersion>("https://files.veloe.link/launcher/update/versions.json");
-                        if (latestLauncherInfo is not null)
-                        {
-                            logger.Information("Launcher version on server: {0}", latestLauncherInfo.latest);
-                            logger.Information("Launcher version: {0}", Assembly.GetExecutingAssembly().GetName().Version);
-                            string[] version = latestLauncherInfo.latest.Split('.');
+                        logger.Information("Launcher version on server: {0}", latestLauncherInfo.latest);
+                        logger.Information("Launcher version: {0}", Assembly.GetExecutingAssembly().GetName().Version);
+                        string[] version = latestLauncherInfo.latest.Split('.');
 
-                            var vat = Assembly.GetExecutingAssembly().GetName().Version;
+                        var vat = Assembly.GetExecutingAssembly().GetName().Version;
 
-                            if (Int16.Parse(version[0]) > Assembly.GetExecutingAssembly().GetName().Version.Major ||
-                                Int16.Parse(version[1]) > Assembly.GetExecutingAssembly().GetName().Version.Minor ||
-                                Int16.Parse(version[2]) > Assembly.GetExecutingAssembly().GetName().Version.Build ||
-                                Int16.Parse(version[3]) > Assembly.GetExecutingAssembly().GetName().Version.Revision)
-                            {
-                                logger.Debug("Update available!");
-                                IsUpdateAvailable = true;
-                            }
+                        if (Int16.Parse(version[0]) > Assembly.GetExecutingAssembly().GetName().Version.Major ||
+                            Int16.Parse(version[1]) > Assembly.GetExecutingAssembly().GetName().Version.Minor ||
+                            Int16.Parse(version[2]) > Assembly.GetExecutingAssembly().GetName().Version.Build ||
+                            Int16.Parse(version[3]) > Assembly.GetExecutingAssembly().GetName().Version.Revision)
+                        {
+                            logger.Debug("Update available!");
+                            IsUpdateAvailable = true;
                         }
                     }
-                    catch (Exception ex)
-                    {
-                        OpenErrorWindow(ex);
-                    }
-                    try
-                    {
+                }
+                catch (Exception ex)
+                {
+                    OpenErrorWindow(ex);
+                }
+                try
+                {
                   
-                    logger.Debug("Connecting to WebSoket");
-                //conection to my servers 
-                connection = new HubConnectionBuilder()
-                        .WithUrl("https://monitor.veloe.link/hubs/data")
-                        .WithAutomaticReconnect()
-                        .Build();
-
-                    Func<Exception, Task> reconnecting = ex => Task.Run(() =>
-                    {
-                        logger.Warning("Reconnecting to WebCoket...");
-                    });
-                    Func<string, Task> reconnected = str => Task.Run(() =>
-                    {
-                        logger.Warning("Reconnected to WebCoket.");
-                        connection.InvokeAsync("ConnectToGroup", "McTFC");
-                        connection.InvokeAsync("ConnectToGroup", "McVanilla");
-                        connection.InvokeAsync("ConnectToGroup", "McTech");
-                    });
-
-                    connection.Reconnecting += reconnecting;
-                    connection.Reconnected += reconnected;
-
-                    connection.On<string>("UpdateMcTFC", (message) =>
-                    {
-                        McStatus status = JsonSerializer.Deserialize<McStatus>(message);
-                        McTfcBlock = $"McTFC: Online";
-                        McTfcPlayersBlock = $"{status.NumPlayers}/{status.MaxPlayers}";
-                        McTfcTip = String.Empty;
-                        if (UInt16.Parse(status.NumPlayers) > 0)
-                            foreach (var player in status.Players)
-                            {
-                                McTfcTip += player;
-                                McTfcTip += "\n";
-                            }
-                        else
-                            McTfcTip = "No players.";
-                        mcTfcTimer.Stop();
-                        mcTfcTimer.Start();
-
-                    //ConsoleText += message;
+                logger.Debug("Connecting to WebSoket");
+            //conection to my servers 
+            connection = new HubConnectionBuilder()
+                    .WithUrl("https://monitor.veloe.link/hubs/data")
+                    .WithAutomaticReconnect()
+                    .Build();
+
+                Func<Exception, Task> reconnecting = ex => Task.Run(() =>
+                {
+                    logger.Warning("Reconnecting to WebCoket...");
                 });
-
-                    connection.On<string>("UpdateMcVanilla", (message) =>
-                    {
-                        McStatus status = JsonSerializer.Deserialize<McStatus>(message);
-                        McVanillaBlock = $"McVanilla: Online";
-                        McVanillaPlayersBlock = $"{status.NumPlayers}/{status.MaxPlayers}";
-                        mcTechTimer.Stop();
-                        mcTechTimer.Start();
-                    //ConsoleText += message;
+                Func<string, Task> reconnected = str => Task.Run(() =>
+                {
+                    logger.Warning("Reconnected to WebCoket.");
+                    connection.InvokeAsync("ConnectToGroup", "McTFC");
+                    connection.InvokeAsync("ConnectToGroup", "McVanilla");
+                    connection.InvokeAsync("ConnectToGroup", "McTech");
                 });
 
-                    connection.On<string>("UpdateMcTech", (message) =>
-                    {
-                        McStatus status = JsonSerializer.Deserialize<McStatus>(message);
-                        McTechBlock = $"McTech: Online {status.NumPlayers}/{status.MaxPlayers}";
-                        McTechPlayersBlock = $"{status.NumPlayers}/{status.MaxPlayers}";
-                        mcVanillaTimer.Stop();
-                        mcVanillaTimer.Start();
-                    //ConsoleText += message;
-                });
+                connection.Reconnecting += reconnecting;
+                connection.Reconnected += reconnected;
 
-                    mcTfcTimer.Elapsed += OnTimedEventMcTfc;
+                connection.On<string>("UpdateMcTFC", (message) =>
+                {
+                    McStatus status = JsonSerializer.Deserialize<McStatus>(message);
+                    McTfcBlock = $"McTFC: Online";
+                    McTfcPlayersBlock = $"{status.NumPlayers}/{status.MaxPlayers}";
+                    McTfcTip = String.Empty;
+                    if (UInt16.Parse(status.NumPlayers) > 0)
+                        foreach (var player in status.Players)
+                        {
+                            McTfcTip += player;
+                            McTfcTip += "\n";
+                        }
+                    else
+                        McTfcTip = "No players.";
+                    mcTfcTimer.Stop();
                     mcTfcTimer.Start();
-                    mcTechTimer.Elapsed += OnTimedEventMcTech;
+
+                //ConsoleText += message;
+            });
+
+                connection.On<string>("UpdateMcVanilla", (message) =>
+                {
+                    McStatus status = JsonSerializer.Deserialize<McStatus>(message);
+                    McVanillaBlock = $"McVanilla: Online";
+                    McVanillaPlayersBlock = $"{status.NumPlayers}/{status.MaxPlayers}";
+                    mcTechTimer.Stop();
                     mcTechTimer.Start();
-                    mcVanillaTimer.Elapsed += OnTimedEventMcVanilla;
+                //ConsoleText += message;
+            });
+
+                connection.On<string>("UpdateMcTech", (message) =>
+                {
+                    McStatus status = JsonSerializer.Deserialize<McStatus>(message);
+                    McTechBlock = $"McTech: Online {status.NumPlayers}/{status.MaxPlayers}";
+                    McTechPlayersBlock = $"{status.NumPlayers}/{status.MaxPlayers}";
+                    mcVanillaTimer.Stop();
                     mcVanillaTimer.Start();
+                //ConsoleText += message;
+            });
 
-                    connection.StartAsync();
+                mcTfcTimer.Elapsed += OnTimedEventMcTfc;
+                mcTfcTimer.Start();
+                mcTechTimer.Elapsed += OnTimedEventMcTech;
+                mcTechTimer.Start();
+                mcVanillaTimer.Elapsed += OnTimedEventMcVanilla;
+                mcVanillaTimer.Start();
 
-                    connection.InvokeAsync("ConnectToGroup", "McTFC");
-                    connection.InvokeAsync("ConnectToGroup", "McVanilla");
-                    connection.InvokeAsync("ConnectToGroup", "McTech");
+                connection.StartAsync();
 
-                    consoleOutputTimer.Elapsed += UpdateConsoleOutput;
-                    consoleOutputTimer.AutoReset = false;
-                    }
-                    catch (Exception ex)
-                    {
-                        OpenErrorWindow(ex);
-                    }
-                });
+                connection.InvokeAsync("ConnectToGroup", "McTFC");
+                connection.InvokeAsync("ConnectToGroup", "McVanilla");
+                connection.InvokeAsync("ConnectToGroup", "McTech");
+
+                consoleOutputTimer.Elapsed += UpdateConsoleOutput;
+                consoleOutputTimer.AutoReset = false;
+                }
+                catch (Exception ex)
+                {
+                    OpenErrorWindow(ex);
+                }
+            });
             
         }
 
@@ -196,6 +196,7 @@ namespace VeloeMinecraftLauncher.ViewModels
         private bool isNoGameRunning = true;
         private bool isUpdateAvailable = false;
         private string settingsButton = "Settings";
+        private string startButtonOutput;
         private string mcTfcBlock = "Wait for update...";
         private string mcTechBlock = "Wait for update...";
         private string mcVanillaBlock = "Wait for update...";
@@ -285,6 +286,12 @@ namespace VeloeMinecraftLauncher.ViewModels
             }
         }
 
+        public string StartButtonOutput
+        {
+            get => startButtonOutput;
+            set => this.RaiseAndSetIfChanged(ref startButtonOutput, value);
+        }
+
         public string ArgumentsBox
         {
             get => argumentsBox;
@@ -429,129 +436,162 @@ namespace VeloeMinecraftLauncher.ViewModels
             }
         }
 
-        public void StartMinecraft()
+        public async void StartMinecraft()
         {
-            try
+            Task.Run(async() =>
             {
-                logger.Debug("Starting minecraft.");
-                if (DownloadedVerion is null)
-                    return;
-
-                int version = 0;
-
-                //var verionJsonFileStream = File.OpenRead(DownloadedVerion.path);
-                using (StreamReader reader = new StreamReader(DownloadedVerion.path))
+                try
                 {
-                    string json = reader.ReadToEnd();
+                    logger.Debug("Starting minecraft.");
+                    if (DownloadedVerion is null)
+                        return;
 
-                    var versionJson = JsonSerializer.Deserialize<Entity.Version.Version>(json);
 
-                    string arguments = StartCommandBuilder.Build(versionJson, Username);
+                    int version = 0;
 
-                    if (!Settings.useCustomJava)
+                    //var verionJsonFileStream = File.OpenRead(DownloadedVerion.path);
+                    using (StreamReader reader = new StreamReader(DownloadedVerion.path))
                     {
-                        if (versionJson.javaVersion != null)
-                        {
-                            logger.Debug("Java version required: {0}", versionJson.javaVersion.majorVersion);
-                            version = versionJson.javaVersion.majorVersion;
-                        }
-                        else
+                        string json = reader.ReadToEnd();
+
+                        var versionJson = JsonSerializer.Deserialize<Entity.Version.Version>(json);
+
+                        if (Settings.checkGameAssets)
                         {
-                            if (versionJson.inheritsFrom != null)
+                            TaskStatus result;
+
+                            if (versionJson.inheritsFrom is null)
+                                result = Downloader.StartDownload(value => StartButtonOutput = value, value => IsNoGameRunning = value, value => { }, value => { }, versionJson).Result;
+                            else
                             {
                                 using (StreamReader inheritsFromReader = new StreamReader(Settings.MinecraftForlderPath + "versions/" + versionJson.inheritsFrom + "/" + versionJson.inheritsFrom + ".json"))
                                 {
                                     string jsonInheritsFrom = inheritsFromReader.ReadToEnd();
                                     var inheritsFromJson = JsonSerializer.Deserialize<Entity.Version.Version>(jsonInheritsFrom);
-                                    if (inheritsFromJson.javaVersion != null)
+
+                                    result = Downloader.StartDownload(value => StartButtonOutput = value, value => IsNoGameRunning = value, value => { }, value => { }, inheritsFromJson).Result;
+                                }
+                            }
+
+                            if (result != TaskStatus.RanToCompletion)
+                            {
+                                IsNoGameRunning = true;
+                                return;
+                            }
+                        }
+
+                        string arguments = StartCommandBuilder.Build(versionJson, Username);
+
+                        if (!Settings.useCustomJava)
+                        {
+                            if (versionJson.javaVersion != null)
+                            {
+                                logger.Debug("Java version required: {0}", versionJson.javaVersion.majorVersion);
+                                version = versionJson.javaVersion.majorVersion;
+                            }
+                            else
+                            {
+                                if (versionJson.inheritsFrom != null)
+                                {
+                                    using (StreamReader inheritsFromReader = new StreamReader(Settings.MinecraftForlderPath + "versions/" + versionJson.inheritsFrom + "/" + versionJson.inheritsFrom + ".json"))
                                     {
-                                        logger.Debug("Java version required: {0}", inheritsFromJson.javaVersion.majorVersion);
-                                        version = inheritsFromJson.javaVersion.majorVersion;
+                                        string jsonInheritsFrom = inheritsFromReader.ReadToEnd();
+                                        var inheritsFromJson = JsonSerializer.Deserialize<Entity.Version.Version>(jsonInheritsFrom);
+                                        if (inheritsFromJson.javaVersion != null)
+                                        {
+                                            logger.Debug("Java version required: {0}", inheritsFromJson.javaVersion.majorVersion);
+                                            version = inheritsFromJson.javaVersion.majorVersion;
+                                        }
                                     }
                                 }
                             }
                         }
-                    }
 
-                    ConsoleText += arguments;
-                    ArgumentsBox = arguments;
-                }
+                        ConsoleText += arguments;
+                        ArgumentsBox = arguments;
+                    }
 
-                if (DownloadedVerion is null)
-                    return;
+                    if (DownloadedVerion is null)
+                        return;
 
-                string javaPath = Settings.JavaPath;
+                    string javaPath = Settings.JavaPath;
 
-                if (!Settings.useCustomJava)
-                {
-                    javaPath = Settings.MinecraftForlderPath + "javaruntime/" + version + "/bin/java";
-                    if (OperatingSystem.IsWindows())
-                        javaPath += ".exe";
-                }
+                    if (!Settings.useCustomJava)
+                    {
+                        javaPath = Settings.MinecraftForlderPath + "javaruntime/" + version + "/bin/java";
+                        if (OperatingSystem.IsWindows())
+                            javaPath += ".exe";
+                    }
 
-                logger.Debug("Java version path: {0}", javaPath);
-                logger.Debug("Minecraft arguments: {0}", ArgumentsBox);
+                    logger.Debug("Java version path: {0}", javaPath);
+                    logger.Debug("Minecraft arguments: {0}", ArgumentsBox);
 
-                ProcessStartInfo proc;
-                proc = new ProcessStartInfo
-                {
-                    UseShellExecute = false,
-                    RedirectStandardOutput = true,
-                    RedirectStandardError = true,
-                    WindowStyle = ProcessWindowStyle.Hidden,
-                    CreateNoWindow = true,
-                    FileName = System.IO.Path.Combine(Settings.MinecraftForlderPath, javaPath),
-                    StandardErrorEncoding = Encoding.UTF8,
-                    WorkingDirectory = Settings.MinecraftForlderPath,
-                    Arguments = ArgumentsBox
-                };
+                    ProcessStartInfo proc;
+                    proc = new ProcessStartInfo
+                    {
+                        UseShellExecute = false,
+                        RedirectStandardOutput = true,
+                        RedirectStandardError = true,
+                        WindowStyle = ProcessWindowStyle.Hidden,
+                        CreateNoWindow = true,
+                        FileName = System.IO.Path.Combine(Settings.MinecraftForlderPath, javaPath),
+                        StandardErrorEncoding = Encoding.UTF8,
+                        WorkingDirectory = Settings.MinecraftForlderPath,
+                        Arguments = ArgumentsBox
+                    };
 
 
-                Process minecraft = new Process();
+                    Process minecraft = new Process();
 
-                minecraft.StartInfo = proc;
+                    minecraft.StartInfo = proc;
 
-                Task.Run(() =>
-                {
-                    try
+                    Task.Run(() =>
                     {
-                        logger.Debug("Starting java process.");
+                        try
+                        {
+                            logger.Debug("Starting java process.");
+
+                            minecraft.OutputDataReceived += OutputHandler;
+                            minecraft.ErrorDataReceived += OutputHandler;
+
+                            //* Start process and handlers            
+                            //minecraft.WaitForExit();
 
-                        minecraft.OutputDataReceived += OutputHandler;
-                        minecraft.ErrorDataReceived += OutputHandler;
+                            minecraft.EnableRaisingEvents = true;
 
-                        //minecraft.Exited += ProcessExited; //dont work properly
-                        //* Start process and handlers            
-                        //minecraft.WaitForExit();
-                        minecraft.Start();
+                            IsNoGameRunning = false;
+                            minecraft.Start();
 
-                        minecraft.BeginOutputReadLine();
-                        minecraft.BeginErrorReadLine();
+                            minecraft.Exited += ProcessExited;
 
-                        if (!Settings.gameLogToLauncher)
+                            minecraft.BeginOutputReadLine();
+                            minecraft.BeginErrorReadLine();
+
+                            if (!Settings.gameLogToLauncher)
+                            {
+                                minecraft.OutputDataReceived -= OutputHandler;
+                                minecraft.CancelOutputRead();
+                            }
+
+                            return Task.CompletedTask;
+                        }
+                        catch (Exception ex)
                         {
-                            minecraft.OutputDataReceived -= OutputHandler;
-                            minecraft.CancelOutputRead();
+                            OpenErrorWindow(ex);
+                            return Task.CompletedTask;
                         }
+                    });
+                    logger.Debug("Updating Settings");
+                    Settings.Username = username;
+                    Settings.lastChosenVersion = DownloadedVerion.version;
+                    Settings.SaveSettings();
 
-                        return Task.CompletedTask;
-                    }
-                    catch (Exception ex)
-                    {
-                        OpenErrorWindow(ex);
-                        return Task.CompletedTask;
-                    }
-                });
-                logger.Debug("Updating Settings");
-                Settings.Username = username;
-                Settings.lastChosenVersion = DownloadedVerion.version;
-                Settings.SaveSettings();
-            
-            }
-            catch (Exception ex)
-            {
-                OpenErrorWindow(ex);
-            }
+                }
+                catch (Exception ex)
+                {
+                    OpenErrorWindow(ex);
+                }
+            });
             
         }
 
@@ -596,9 +636,13 @@ namespace VeloeMinecraftLauncher.ViewModels
             }
         }
 
-        //dont work properly
         void ProcessExited(object sendingProcess, EventArgs e)
         {
+            ((Process)sendingProcess).Exited -= ProcessExited;
+
+            logger.Debug("Exit code: {0}", ((Process)sendingProcess).ExitCode);
+
+            StartButtonOutput = "";
             IsNoGameRunning = true;
             ((Process)sendingProcess).Dispose();           
         }
@@ -837,8 +881,6 @@ namespace VeloeMinecraftLauncher.ViewModels
         }
     }
 
-    
-
     public class LatestLauncherVersion
     {
         public string latest { get; set; }

+ 34 - 449
VeloeMinecraftLauncher/ViewModels/VersionsDownloaderViewModel.cs

@@ -49,9 +49,9 @@ namespace VeloeMinecraftLauncher.ViewModels
                 Task.Run(() =>
                 {
                     logger = Settings.logger;
-                    if (FilteredVerions is null)
+                    if (FilteredVersions is null)
                     {
-                        FilteredVerions = new ObservableCollection<Entity.VersionManifest.Version>();
+                        FilteredVersions = new ObservableCollection<Entity.VersionManifest.Version>();
                     }
                     logger.Debug("Getting versionManifest.json");
                     versionManifest = Downloader.DownloadAndDeserializeJsonData<VersionManifest>("https://launchermeta.mojang.com/mc/game/version_manifest_v2.json");
@@ -168,7 +168,7 @@ namespace VeloeMinecraftLauncher.ViewModels
             }
         }
 
-        public ObservableCollection<Entity.VersionManifest.Version>FilteredVerions
+        public ObservableCollection<Entity.VersionManifest.Version>FilteredVersions
         {
             get => filteredVersions; set
             {
@@ -298,458 +298,43 @@ namespace VeloeMinecraftLauncher.ViewModels
 
         public async Task OnStartBunttonClick()
         {
-            Task.Run(()=>StartDownload());                     
-        }
+            Task.Run(() => {
 
-        public async Task<TaskStatus> StartDownload()
-        {
-            try
-            {
                 if (FilteredVersion is null)
                     return TaskStatus.Faulted;
-                IsControlsEnabled = false;
-                logger.Debug("Downloading minecraft {0}", FilteredVersion.id);
-                var webClient = new WebClient();
 
                 logger.Debug("Downloading {0}.json", FilteredVersion.id);
-                var versonJson = Downloader.DownloadAndDeserializeJsonData<Entity.Version.Version>(FilteredVersion.url);
-
-                if (versonJson != null)
-                {
-                    webClient.DownloadProgressChanged += WebClient_DownloadProgressChanged;
-                    //download java
-                    if (DownloadJava)
-                    {
-                        logger.Debug("Getting required Java version.");
-                        if (versonJson.javaVersion.majorVersion != null)
-                        {
-                            string javaUrl = "";
-                            switch (versonJson.javaVersion.majorVersion)
-                            {
-                                case 8:
-                                    if (Environment.Is64BitOperatingSystem && OperatingSystem.IsWindows())
-                                        javaUrl = "https://files.veloe.link/launcher/java/8/windows64/java.zip";
-                                    if (!Environment.Is64BitOperatingSystem && OperatingSystem.IsWindows())
-                                        javaUrl = "https://files.veloe.link/launcher/java/8/windows32/java.zip";
-
-                                    if (Environment.Is64BitOperatingSystem && OperatingSystem.IsLinux())
-                                        javaUrl = "https://files.veloe.link/launcher/java/8/linux64/java.zip";
-                                    if (!Environment.Is64BitOperatingSystem && OperatingSystem.IsLinux())
-                                        javaUrl = "https://files.veloe.link/launcher/java/8/linux32/java.zip";
-                                    break;
-                                case 16:
-                                    if (Environment.Is64BitOperatingSystem && OperatingSystem.IsWindows())
-                                        javaUrl = "https://files.veloe.link/launcher/java/16/windows64/java.zip";
-                                    if (Environment.Is64BitOperatingSystem && OperatingSystem.IsLinux())
-                                        javaUrl = "https://files.veloe.link/launcher/java/16/linux64/java.zip";
-                                    break;
-                                case 17:
-                                    if (Environment.Is64BitOperatingSystem && OperatingSystem.IsWindows())
-                                        javaUrl = "https://files.veloe.link/launcher/java/17/windows64/java.zip";
-                                    if (Environment.Is64BitOperatingSystem && OperatingSystem.IsLinux())
-                                        javaUrl = "https://files.veloe.link/launcher/java/17/linux64/java.zip";
-
-                                    break;
-                                case 18:
-                                    if (Environment.Is64BitOperatingSystem && OperatingSystem.IsWindows())
-                                        javaUrl = "https://files.veloe.link/launcher/java/18/windows64/java.zip";
-                                    if (Environment.Is64BitOperatingSystem && OperatingSystem.IsLinux())
-                                        javaUrl = "https://files.veloe.link/launcher/java/18/linux64/java.zip";
-
-                                    break;
-                            }
-                            if (javaUrl != "")
-                            {
-                                logger.Debug("Downloading Java");
-                                DownloadingFileName = "java.zip";
-                                webClient.DownloadFileAsync(new System.Uri(javaUrl), Settings.MinecraftForlderPath + "java.zip");
-                                waitWhileBisy(ref webClient);
-
-                                logger.Debug("Unpacking Java");
-                                DownloadingFileName = "Unpacking java.zip";
-                                ZipFile.ExtractToDirectory($"{Settings.MinecraftForlderPath}java.zip", Settings.MinecraftForlderPath, true);
-                                File.Delete($"{Settings.MinecraftForlderPath}java.zip");
-                            }
-                            else
-                                logger.Debug("Required Java version don't found in json file."); //log that java was not downloaded;
-                        }
-
-                    }
-
-                    //download json
-                    var path = Settings.MinecraftForlderPath + "/versions/" + FilteredVersion.id;
-                    if (!Directory.Exists(path))
-                    {
-                        logger.Debug("Creating path: {0}", path);
-                        Directory.CreateDirectory(path);
-                    }
-
-                    logger.Debug("Downloading {0}", $"{FilteredVersion.id}.json");
-                    DownloadingFileName = $"{FilteredVersion.id}.json";
-                    webClient.DownloadFileAsync(new System.Uri(FilteredVersion.url), path + "/" + FilteredVersion.id + ".json");
-                    waitWhileBisy(ref webClient);
-                    //download jar
-                    if (!Directory.Exists(path))
-                    {
-                        logger.Debug("Creating path: {0}", path);
-                        Directory.CreateDirectory(path);
-                    }
-
-                    logger.Debug("Downloading {0}", $"{FilteredVersion.id}.jar");
-                    DownloadingFileName = $"{FilteredVersion.id}.jar";
-                    webClient.DownloadFileAsync(new System.Uri(versonJson.downloads.client.url), path + "/" + FilteredVersion.id + ".jar");
-                    waitWhileBisy(ref webClient);
-
-                    //download libraries
-                    logger.Debug("Downloading libraries.");
-                    foreach (var library in versonJson.libraries)
-                    {
-                        var libPath = Settings.MinecraftForlderPath + "libraries/";
-                        string[] libPathSplit = new[] { "" };
-                        string libUrl = "";
-                        // getting path and url if universal lib
-                        if (library.natives is null)
-                        {
-                            libPath = Settings.MinecraftForlderPath + "libraries/";
-                            libPathSplit = library.downloads.artifact.path.Split('/');
-                            libUrl = library.downloads.artifact.url;
-                            for (int i = 0; i < libPathSplit.Length - 1; i++)
-                            {
-                                libPath += libPathSplit[i] + "/";
-                            }
-
-                        }
-                        else
-                        {   // getting path if native
-                            libPath = Settings.MinecraftForlderPath + "libraries/";
-                            libPathSplit = new[] { "" };
-                            libUrl = "";
-
-                            if (OperatingSystem.IsWindows() && library.natives.windows is not null)
-                            {
-                                if (library.downloads.classifiers.NativesWindows is not null)
-                                {
-                                    libPathSplit = library.downloads.classifiers.NativesWindows.path.Split('/');
-                                    libUrl = library.downloads.classifiers.NativesWindows.url;
-                                }
-                                else
-                                {
-                                    if (Environment.Is64BitOperatingSystem)
-                                    {
-                                        libPathSplit = library.downloads.classifiers.NativesWindows64.path.Split('/');
-                                        libUrl = library.downloads.classifiers.NativesWindows64.url;
-                                    }
-                                    else
-                                    {
-                                        libPathSplit = library.downloads.classifiers.NativesWindows32.path.Split('/');
-                                        libUrl = library.downloads.classifiers.NativesWindows32.url;
-                                    }
-                                }
-                            }
-                            if (OperatingSystem.IsLinux() && library.natives.linux is not null)
-                            {
-                                libPathSplit = library.downloads.classifiers.NativesLinux.path.Split('/');
-                                libUrl = library.downloads.classifiers.NativesLinux.url;
-                            }
-
-
-                            for (int i = 0; i < libPathSplit.Length - 1; i++)
-                            {
-                                libPath += libPathSplit[i] + "/";
-                            }
-                        }
-
-                        //if no lib url
-                        if (libUrl == String.Empty)
-                            continue;
-
-                        //checking rules
-                        if (library.rules == null)
-                        {
-                            if (!Directory.Exists(libPath))
-                            {
-                                logger.Debug("Creating path: {0}", path);
-                                Directory.CreateDirectory(libPath);
-                            }
-                            logger.Debug("Downloading: {0}", libPathSplit.Last());
-                            DownloadingFileName = libPathSplit.Last();
-                            webClient.DownloadFileAsync(new System.Uri(libUrl), libPath + "/" + libPathSplit.Last());
-                            waitWhileBisy(ref webClient);
-                        }
-                        else
-                        {
-                            foreach (var rule in library.rules)
-                            {
-                                if (rule.action == "allow" && rule.os is null)
-                                {
-                                    if (!Directory.Exists(libPath))
-                                    {
-                                        logger.Debug("Creating path: {0}", path);
-                                        Directory.CreateDirectory(libPath);
-                                    }
-                                    logger.Debug("Downloading: {0}", libPathSplit.Last());
-                                    DownloadingFileName = libPathSplit.Last();
-                                    webClient.DownloadFileAsync(new System.Uri(libUrl), libPath + "/" + libPathSplit.Last());
-                                    waitWhileBisy(ref webClient);
-                                    continue;
-                                }
-                                if (rule.action == "allow" && (rule.os.name == "windows" || rule.os.name == "linux" || rule.os.name == "osx" ))
-                                {
-                                    if (!Directory.Exists(libPath))
-                                    {
-                                        logger.Debug("Creating path: {0}", path);
-                                        Directory.CreateDirectory(libPath);
-                                    }
-                                    logger.Debug("Downloading: {0}", libPathSplit.Last());
-                                    DownloadingFileName = libPathSplit.Last();
-                                    webClient.DownloadFileAsync(new System.Uri(libUrl), libPath + "/" + libPathSplit.Last());
-                                    waitWhileBisy(ref webClient);
-                                }
-                            }
-                        }
-                        //unpacking native libs
-                        if (library.natives is not null || library.downloads.classifiers is not null)
-                        {
-                            try
-                            {
-                                if (!Directory.Exists(Settings.MinecraftForlderPath + "versions/" + versonJson.id + "/natives/"))
-                                {
-                                    logger.Debug("Creating path: {0}", Settings.MinecraftForlderPath + "versions/" + versonJson.id + "/natives/");
-                                    Directory.CreateDirectory(Settings.MinecraftForlderPath + "versions/" + versonJson.id + "/natives/");
-                                }
-                                logger.Debug("Extracting {0} to {1}", libPathSplit.Last(), Settings.MinecraftForlderPath + "versions/" + versonJson.id + "/natives/");
-                                ZipFile.ExtractToDirectory(libPath + "/" + libPathSplit.Last(), Settings.MinecraftForlderPath + "versions/" + versonJson.id + "/natives/", true);
-                            }
-                            catch (IOException ex)
-                            {
-                                logger.Error("IOException in VersionsDownloaderViewModel on native lib extraction");
-                            }
-                            //TODO delete META-INF and sha1 files after
-                        }
-                    }
-
-                    var assetsJson = Downloader.DownloadAndDeserializeJsonData<AssetsManifest>(versonJson.assetIndex.url);
-                    var assetsPath = Settings.MinecraftForlderPath + "assets/" + versonJson.assets + "/objects";
-                    var assetsUrl = "https://resources.download.minecraft.net/";
-
-                    //download assets json
-                    logger.Debug("Downloading: {0}", versonJson.assets + ".json");
-                    Downloader.DownloadFile(versonJson.assetIndex.url, Settings.MinecraftForlderPath + "/assets/" + versonJson.assets + "/indexes/", versonJson.assets + ".json");
-
-                    //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);
-
-                        string chksum = String.Empty;
-                        //here hash check
-                        if (File.Exists(assetsPath + "/" + folder + "/" + 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();
-
-                            fop.Close();
-                            fop.Dispose();
-                        }
-
-                        if (chksum != asset.Value.hash)
-                        {
-                            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);
-                        }
-                    }
-
-                    if (InstallForge)
-                    {
-                        var forgePath = $"Forge{versonJson.id}";
-                        var forgeUrl = $"https://files.veloe.link/launcher/forge/Forge{versonJson.id}/";
-
-                        if (!Directory.Exists($"{Settings.MinecraftForlderPath}versions/Forge{versonJson.id}"))
-                        {
-                            logger.Debug("Creating path: {0}", $"{Settings.MinecraftForlderPath}versions/" + forgePath);
-                            Directory.CreateDirectory($"{Settings.MinecraftForlderPath}versions/" + forgePath);
-                        }
-
-                        logger.Debug("Downloading: {0}", $"Forge{versonJson.id}.json");
-                        DownloadingFileName = $"Forge{versonJson.id}.json";
-                        webClient.DownloadFileAsync(new System.Uri($"{forgeUrl}Forge{versonJson.id}.json"), Settings.MinecraftForlderPath + "versions/" + forgePath + "/" + forgePath + ".json");
-                        waitWhileBisy(ref webClient);
-
-                        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);
-
-                        logger.Debug("Extracting: {0}", "libraries.zip");
-                        DownloadingFileName = "Unpacking libraries.zip";
-                        ZipFile.ExtractToDirectory($"{Settings.MinecraftForlderPath}versions/Forge{versonJson.id}/libraries.zip", Settings.MinecraftForlderPath, true);
-                        File.Delete($"{Settings.MinecraftForlderPath}versions/Forge{versonJson.id}/libraries.zip");
-                    }
-
-                    if (InstallOptifine)
-                    {
-                        var optifinePath = $"Optifine{versonJson.id}";
-                        var optifineUrl = $"https://files.veloe.link/launcher/optifine/Optifine{versonJson.id}/";
-
-                        if (!Directory.Exists($"{Settings.MinecraftForlderPath}versions/Optifine{versonJson.id}"))
-                        {
-                            logger.Debug("Creating path: {0}", $"{Settings.MinecraftForlderPath}Optifine/" + optifinePath);
-                            Directory.CreateDirectory($"{Settings.MinecraftForlderPath}Optifine/" + optifinePath);
-                        }
-
-                        logger.Debug("Downloading: {0}", $"Optifine{versonJson.id}.json");
-                        DownloadingFileName = $"Optifine{versonJson.id}.json";
-                        webClient.DownloadFileAsync(new System.Uri($"{optifineUrl}Optifine{versonJson.id}.json"), Settings.MinecraftForlderPath + "versions/" + optifinePath + "/" + optifinePath + ".json");
-                        waitWhileBisy(ref webClient);
-
-                        logger.Debug("Downloading: {0}", $"Optifine{versonJson.id}.json");
-                        DownloadingFileName = $"Optifine{versonJson.id}.json";
-                        webClient.DownloadFileAsync(new System.Uri($"{optifineUrl}Optifine{versonJson.id}.jar"), Settings.MinecraftForlderPath + "versions/" + optifinePath + "/" + optifinePath + ".jar");
-                        waitWhileBisy(ref webClient);
-
-                        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);
-
-                        logger.Debug("Extracting: {0}", "libraries.zip");
-                        DownloadingFileName = "Unpacking libraries.zip";
-                        ZipFile.ExtractToDirectory($"{Settings.MinecraftForlderPath}versions/Optifine{versonJson.id}/libraries.zip", Settings.MinecraftForlderPath, true);
-                        File.Delete($"{Settings.MinecraftForlderPath}versions/Optifine{versonJson.id}/libraries.zip");
-                    }
-
-                    if (InstallForgeOptifine)
-                    {
-                        if (!Directory.Exists($"{Settings.MinecraftForlderPath}versions/Forge{versonJson.id}/mods"))
-                        {
-                            logger.Debug("Creating path: {0}", $"{Settings.MinecraftForlderPath}versions/Forge" + versonJson.id + "/mods");
-                            Directory.CreateDirectory($"{Settings.MinecraftForlderPath}versions/Forge" + versonJson.id + "/mods");
-                        }
-
-                        logger.Debug("Downloading: {0}", $"Optifine{versonJson.id}.jar");
-                        DownloadingFileName = $"Optifine{versonJson.id}.jar";
-                        webClient.DownloadFileAsync(new System.Uri(@$"https://files.veloe.link/launcher/forge/Forge{versonJson.id}/Optifine{versonJson.id}.jar"),
-                        Settings.MinecraftForlderPath + "versions/Forge" + versonJson.id + "/mods/" + "Optifine" + versonJson.id + ".jar");
-                        waitWhileBisy(ref webClient);
-                    }
-
-                    webClient.DownloadProgressChanged -= WebClient_DownloadProgressChanged;
-                    Progress = 100;
-                    logger.Debug("Downloading finished.");
-                    DownloadingFileName = "Finished!";
-                    IsControlsEnabled = true;
-                }
-
-                webClient.Dispose();
-            }
-            catch (Exception ex)
-            {
-                IsControlsEnabled = true;
-                DownloadingFileName = $"Error occured while downloading {FilteredVersion.id}.";
-                logger.Error(ex.Message);
-                logger.Error(ex.StackTrace);
-                return TaskStatus.Faulted;
-            }
-            return TaskStatus.RanToCompletion;
+                DownloadingFileName = $"{FilteredVersion.id}.json";
+                var versionJson = Downloader.DownloadAndDeserializeJsonData<Entity.Version.Version>(FilteredVersion.url, Settings.MinecraftForlderPath + "versions/" + FilteredVersion.id + "/", FilteredVersion.id + ".json");
+
+                if (versionJson is not null)
+                    Downloader.StartDownload(
+                      value => DownloadingFileName = value,
+                      value => IsControlsEnabled = value,
+                      value => value.DownloadProgressChanged += WebClient_DownloadProgressChanged,
+                      value => value.DownloadProgressChanged -= WebClient_DownloadProgressChanged,
+                      versionJson,
+                      DownloadJava,
+                      InstallForge,
+                      InstallOptifine,
+                      InstallForgeOptifine,
+                      InstallFabric);
+            return TaskStatus.RanToCompletion; });
         }
-
+      
         public async void OnStartMcTfcBunttonClick()
         {
-            Task.Run(() => StartDownloadMcTfc());
-        }
-
-        private async Task<TaskStatus> StartDownloadMcTfc()
-        {
-            try
-            {
-                FilteredVersion = FilteredVerions.Where(x => x.id == "1.12.2").FirstOrDefault();
-
-                if (FilteredVersion is null)
-                    return TaskStatus.Faulted;
-
-
-                InstallForge = true;
-                InstallForgeOptifine = true;
-
-                await StartDownload();
-
-                IsControlsEnabled = false;
-                var mcTfcUrl = $"https://files.veloe.link/launcher/McTFC/McTFC.zip";
-
-                if (!Directory.Exists($"{Settings.MinecraftForlderPath}versions/McTFC"))
-                {
-                    logger.Debug("Creating path: {0}", $"{Settings.MinecraftForlderPath}versions/McTFC");
-                    Directory.CreateDirectory($"{Settings.MinecraftForlderPath}versions/McTFC");
-                }
-
-                WebClient webClient = new WebClient();
-
-                webClient.DownloadProgressChanged += WebClient_DownloadProgressChanged;
-
-                logger.Debug("Downloading: {0}", "McTFC.zip");
-                DownloadingFileName = "McTFC.zip";
-                webClient.DownloadFileAsync(new System.Uri(mcTfcUrl), Settings.MinecraftForlderPath + "versions/McTFC.zip");
-                waitWhileBisy(ref webClient);
-
-                logger.Debug("Extracting: {0}", "McTFC.zip");
-                DownloadingFileName = "Unpacking McTFC.zip";
-                ZipFile.ExtractToDirectory($"{Settings.MinecraftForlderPath}versions/McTFC.zip", Settings.MinecraftForlderPath + "versions/McTFC", true);
-                File.Delete($"{Settings.MinecraftForlderPath}versions/McTFC.zip");
-
-                webClient.DownloadProgressChanged -= WebClient_DownloadProgressChanged;
-                Progress = 100;
-                logger.Debug("Downloading McTFC finished.");
-                DownloadingFileName = "Finished McTFC!";
-                IsControlsEnabled = true;
-                webClient.Dispose();
-
-            }
-            catch (Exception ex)
-            {
-                IsControlsEnabled = true;
-                DownloadingFileName = "Error occured while downloading McTFC.";
-                var message = ex.Message;
-                var stackTrace = ex.StackTrace;
-                logger.Error(ex.Message);
-                logger.Error(ex.StackTrace);
-                Exception innerException = ex.InnerException;
-                while (innerException is not null)
-                {
-                    message += "\n" + innerException.Message;
-                    stackTrace += "\n" + innerException.StackTrace;
-                    logger.Error(innerException.Message);
-                    logger.Error(innerException.StackTrace);
-                    innerException = innerException.InnerException;
-                }
-
-
-                if (Avalonia.Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
-                {
-                    var ErrorMessageViewModel = new ErrorWindowViewModel(message, stackTrace);
-                    var ErrorMessage = new ErrorWindow()
-                    {
-                        DataContext = ErrorMessageViewModel
-                    };
-                    ErrorMessage.ShowDialog(desktop.MainWindow);           
-                }
-                return TaskStatus.Faulted;
-            }
-            return TaskStatus.RanToCompletion;
-        }
-
-
-        private void waitWhileBisy(ref WebClient webClient)
-        {
-            while(webClient.IsBusy)
-            {
-                //Progress = webClientProgress;
-                Task.Delay(100).Wait();
-            }
+            Task.Run(() => Downloader.StartDownloadMcTfc(
+                value => DownloadingFileName = value,
+                value => IsControlsEnabled = value,
+                value => value.DownloadProgressChanged += WebClient_DownloadProgressChanged,
+                value => value.DownloadProgressChanged -= WebClient_DownloadProgressChanged,
+                FilteredVersions,
+                DownloadJava,
+                InstallForge,
+                InstallOptifine,
+                InstallForgeOptifine,
+                InstallFabric));
         }
 
         private void WebClient_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
@@ -761,7 +346,7 @@ namespace VeloeMinecraftLauncher.ViewModels
         {
             try
             {
-                FilteredVerions.Clear();
+                FilteredVersions.Clear();
 
                 if (versionManifest.versions is null)
                     return;
@@ -769,7 +354,7 @@ namespace VeloeMinecraftLauncher.ViewModels
                 foreach (var version in versionManifest.versions)
                 {
                     if (ShowSnaps && version.type == "snapshot" || ShowOld && version.type is ("old_alpha" or "old_beta") || version.type == "release")
-                        FilteredVerions.Add(version);
+                        FilteredVersions.Add(version);
                 }
             }
             catch (Exception ex)

+ 8 - 1
VeloeMinecraftLauncher/Views/MainWindow.axaml

@@ -60,6 +60,14 @@
 					IsVisible="{Binding IsUpdateAvailable}">
 					Update Available
 				</Button>
+				<TextBlock
+					ZIndex="998"
+					Grid.Row="1"
+					HorizontalAlignment="Right"
+					VerticalAlignment="Bottom"
+					Text="{Binding StartButtonOutput}"
+					Margin="5">
+				</TextBlock>
 				<TabControl
 					Grid.Row="1"
 					HorizontalAlignment="Stretch">
@@ -258,7 +266,6 @@
 						</ScrollViewer>
 					</TabItem>
 				</TabControl>
-
 				<StackPanel
 					Grid.Row="2"
 					Orientation="Horizontal"

+ 1 - 1
VeloeMinecraftLauncher/Views/SettingsWindow.axaml

@@ -67,7 +67,7 @@
 				<CheckBox Grid.Row="3" Grid.Column="0" IsChecked="{Binding SetMaxRam}">Set max RAM</CheckBox>
 				<TextBox Grid.Row="3" Grid.Column="1" Margin="5" Name="MaxRam" Text="{Binding MaxRam}" IsEnabled="{Binding SetMaxRam}" HorizontalAlignment="Left" VerticalAlignment="Top"></TextBox>
 
-				<CheckBox Grid.Row="4" Grid.Column="0" IsChecked="{Binding CheckAssets}" IsEnabled="false">Check game assets before start</CheckBox>
+				<CheckBox Grid.Row="4" Grid.Column="0" IsChecked="{Binding CheckAssets}" IsEnabled="True">Check game assets before start</CheckBox>
 				<CheckBox Grid.Row="5" Grid.ColumnSpan="2" IsChecked="{Binding GameLogToLauncher}">Show game log in launcher (performace issues)</CheckBox>
 
 				<Button Grid.Row="6" Grid.Column="0" Command="{Binding SaveSettings}" IsEnabled="{Binding IsValid}" Content="Save" VerticalAlignment="Top"></Button>

+ 1 - 1
VeloeMinecraftLauncher/Views/VersionsDownloader.axaml

@@ -42,7 +42,7 @@
 			  DockPanel.Dock="Top">
 			</titlebars:TitleBarWindow>
 			<StackPanel Margin="10" Spacing="5">
-				<ComboBox Items="{Binding FilteredVerions}" PlaceholderText="Select version" SelectedItem="{Binding FilteredVersion}" IsEnabled="{Binding IsControlsEnabled}" HorizontalAlignment="Stretch"></ComboBox>
+				<ComboBox Items="{Binding FilteredVersions}" PlaceholderText="Select version" SelectedItem="{Binding FilteredVersion}" IsEnabled="{Binding IsControlsEnabled}" HorizontalAlignment="Stretch"></ComboBox>
 				<CheckBox IsChecked="{Binding ShowOld}" IsEnabled="{Binding IsControlsEnabled}">Show old</CheckBox>
 				<CheckBox IsChecked="{Binding ShowSnaps}" IsEnabled="{Binding IsControlsEnabled}">Show snapshots</CheckBox>
 				<CheckBox IsChecked="{Binding DownloadJava}" IsEnabled="{Binding IsControlsEnabled}">Download Java</CheckBox>