Browse Source

warning cleaning

Veloe 2 years ago
parent
commit
799c9e1dfb
23 changed files with 312 additions and 234 deletions
  1. 3 3
      VeloeLauncherUpdater/LatestLauncherVersion.cs
  2. 30 28
      VeloeLauncherUpdater/Program.cs
  3. 2 2
      VeloeLauncherUpdater/VeloeLauncherUpdater.csproj
  4. 20 8
      VeloeMinecraftLauncher/MinecraftLauncher/Downloader.cs
  5. 5 5
      VeloeMinecraftLauncher/MinecraftLauncher/Settings.cs
  6. 23 19
      VeloeMinecraftLauncher/MinecraftLauncher/StartCommandBuilder.cs
  7. 4 4
      VeloeMinecraftLauncher/Models/Entity/Assets/Asset.cs
  8. 8 0
      VeloeMinecraftLauncher/Models/Entity/Changelog.cs
  9. 6 0
      VeloeMinecraftLauncher/Models/Entity/DownloadedVersion.cs
  10. 5 5
      VeloeMinecraftLauncher/Models/Entity/LauncherProfiles.cs
  11. 11 11
      VeloeMinecraftLauncher/Models/Entity/McStatus/McStatus.cs
  12. 4 4
      VeloeMinecraftLauncher/Models/Entity/Modpack.cs
  13. 24 14
      VeloeMinecraftLauncher/Models/Entity/Version/Version.cs
  14. 4 0
      VeloeMinecraftLauncher/Models/Entity/VesrionManifest/Latest.cs
  15. 5 5
      VeloeMinecraftLauncher/Models/Entity/VesrionManifest/Version.cs
  16. 2 2
      VeloeMinecraftLauncher/Models/Entity/VesrionManifest/VersionManifest.cs
  17. 8 0
      VeloeMinecraftLauncher/Models/ServerPanelModel.cs
  18. 2 2
      VeloeMinecraftLauncher/VeloeMinecraftLauncher.csproj
  19. 5 5
      VeloeMinecraftLauncher/ViewModels/ErrorWindowViewModel.cs
  20. 108 90
      VeloeMinecraftLauncher/ViewModels/MainWindowViewModel.cs
  21. 5 4
      VeloeMinecraftLauncher/ViewModels/SettingsWindowViewModel.cs
  22. 5 5
      VeloeMinecraftLauncher/ViewModels/VersionsDownloaderViewModel.cs
  23. 23 18
      VeloeMinecraftLauncher/Views/TitleBar/TitleBarWindow.axaml.cs

+ 3 - 3
VeloeLauncherUpdater/LatestLauncherVersion.cs

@@ -8,8 +8,8 @@ namespace VeloeLauncherUpdater
 {
     public class LatestLauncherVersion
     {
-        public string Latest { get; set; }
-        public string Updater { get; set; }
-        public string Url { get; set; }
+        public string? Latest { get; set; }
+        public string? Updater { get; set; }
+        public string? Url { get; set; }
     }
 }

+ 30 - 28
VeloeLauncherUpdater/Program.cs

@@ -3,7 +3,6 @@ using Serilog;
 using Serilog.Events;
 using System.Diagnostics;
 using System.IO.Compression;
-using System.Net;
 using System.Text.Json;
 using VeloeLauncherUpdater;
 
@@ -15,51 +14,49 @@ var logger = new LoggerConfiguration()
 try
 {
     string fileName = "VeloeMinecraftLauncher";
+    using var httpClient = new HttpClient();
+
     if (OperatingSystem.IsWindows())
         fileName += ".exe";
     if (File.Exists(fileName))
     {
+        if (OperatingSystem.IsLinux())
+        {
+            logger.Information("Manual updates only.");
+            return;
+        }
+
         FileVersionInfo fileVersionInfo = FileVersionInfo.GetVersionInfo(fileName);
-        LatestLauncherVersion latestLauncherVersion;
+        LatestLauncherVersion? latestLauncherVersion;
 
-        using (var httpClient = new HttpClient())
+        var jsonData = string.Empty;
+        try
         {
-            var jsonData = string.Empty;
-            try
-            {
-                jsonData = httpClient.GetStringAsync("https://files.veloe.link/launcher/update/versions.json").Result;
-            }
-            catch (Exception)
-            {
-                logger.Error("Error occured on getting versions.json from the server.");
-                throw;
-            }
-
-            latestLauncherVersion = string.IsNullOrEmpty(jsonData)
-                        ? new LatestLauncherVersion()
-                        : JsonSerializer.Deserialize<LatestLauncherVersion>(jsonData, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
+            jsonData = httpClient.GetStringAsync("https://files.veloe.link/launcher/update/versions.json").Result;
         }
-
-        if (OperatingSystem.IsLinux())
+        catch (Exception)
         {
-            logger.Information("Manual updates only.");
-            return;
+            logger.Error("Error occured on getting versions.json from the server.");
+            throw;
         }
 
-        if (latestLauncherVersion != null)
+        latestLauncherVersion = string.IsNullOrEmpty(jsonData)
+                    ? new LatestLauncherVersion()
+                    : JsonSerializer.Deserialize<LatestLauncherVersion>(jsonData, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
+
+        if (latestLauncherVersion?.Latest is not null && fileVersionInfo?.FileVersion is not null)
         {
             logger.Information("Latest launcher version on server: {0}", latestLauncherVersion.Latest);
             logger.Information("Launcher version: {0}", fileVersionInfo.FileVersion);
 
-            if (!(new Version(latestLauncherVersion.Latest) > new Version(fileVersionInfo.FileVersion)))
+            if (fileVersionInfo?.FileVersion is not null && !(new Version(latestLauncherVersion.Latest) > new Version(fileVersionInfo.FileVersion)))
             {
                 logger.Information("No update required.");
                 return;
             }
         }
     }
-
-    WebClient webClient = new WebClient();
+    
     try
     {
         logger.Information("Downloading latest.zip");
@@ -74,9 +71,13 @@ try
         if (url == String.Empty)
             return;
 
-        webClient.DownloadFile(new System.Uri(url), "latest.zip"); ;
+        using HttpResponseMessage response = await httpClient.GetAsync(new System.Uri(url), HttpCompletionOption.ResponseHeadersRead);
+        response.EnsureSuccessStatusCode();
+        using Stream contentStream = await response.Content.ReadAsStreamAsync();
+        using FileStream fileStream = File.OpenWrite("latest.zip");
+        await contentStream.CopyToAsync(fileStream);
     }
-    catch (Exception ex)
+    catch (Exception)
     {
         logger.Error("Error occured on getting latest.zip from the server.");
         throw;
@@ -92,7 +93,8 @@ catch (Exception ex)
 {
     logger.Error(ex.Message);
     logger.Error("Path exe: {0}", Directory.GetCurrentDirectory());
-    logger.Error(ex.StackTrace);
+    if (ex.StackTrace is not null)
+        logger.Error(ex.StackTrace);
 }
 
 

+ 2 - 2
VeloeLauncherUpdater/VeloeLauncherUpdater.csproj

@@ -6,8 +6,8 @@
     <ImplicitUsings>enable</ImplicitUsings>
     <Nullable>enable</Nullable>
     <DebugType>embedded</DebugType>
-    <AssemblyVersion>1.0.1.0</AssemblyVersion>
-    <FileVersion>1.0.1.0</FileVersion>
+    <AssemblyVersion>1.0.1.1</AssemblyVersion>
+    <FileVersion>1.0.1.1</FileVersion>
   </PropertyGroup>
 
   <ItemGroup>

+ 20 - 8
VeloeMinecraftLauncher/MinecraftLauncher/Downloader.cs

@@ -236,7 +236,6 @@ internal static class Downloader
                 Settings.logger.Debug("Downloading {0}", $"{versionJson.Id}.jar");
                 DownloadingFileName($"{versionJson.Id}.jar");
                 await DownloadFileAsync(versionJson.Downloads.Client.Url, path + "/" + versionJson.Id + ".jar", cancellationToken, httpClient);
-                 
             }
             tasksIterator++;
             TasksStatus($"Task {tasksIterator} of {tasksCount} complete.");
@@ -302,12 +301,21 @@ internal static class Downloader
                 var libName = Path.GetFileName(libPath);
                 var libDir = Path.GetDirectoryName(libPath);
 
+                if (libName is null || libDir is null)
+                {
+                    if (libPath == string.Empty)
+                        Settings.logger.Warning("Library dir, name are null, because libraryPath is empty! Skipping...");
+                    else
+                        Settings.logger.Warning("Library dir or name are null! Skipping...");
+                    continue;
+                }
+
                 //checking rules
                 if (library.Rules == null)
                 {
                     if (!Directory.Exists(libDir))
                     {
-                        Settings.logger.Debug("Creating path: {0}", path);
+                        Settings.logger.Debug("Creating path: {0}", libDir);
                         Directory.CreateDirectory(libDir);
                     }
 
@@ -339,7 +347,7 @@ internal static class Downloader
                         {
                             if (!Directory.Exists(libDir))
                             {
-                                Settings.logger.Debug("Creating path: {0}", path);
+                                Settings.logger.Debug("Creating path: {0}", libDir);
                                 Directory.CreateDirectory(libDir);
                             }
 
@@ -425,13 +433,13 @@ internal static class Downloader
 
             Settings.logger.Debug("Downloading assets.");
             SetProgress(0);
-            var assetsCount = assetsJson.Objects.Count;
+            var assetsCount = assetsJson?.Objects?.Count ?? 1;
             var assetsIterator = 1;
 
             List<Task> assetsDownloadTasks = new();
             using SemaphoreSlim concurrencySemaphore = new SemaphoreSlim(0,40);
 
-            foreach (var asset in assetsJson.Objects.DistinctBy(a => a.Value.Hash))
+            foreach (var asset in assetsJson?.Objects?.DistinctBy(a => a.Value.Hash) ?? new Dictionary<string,Asset>())
             {
                 assetsDownloadTasks.Add(Task.Run(async () => {
                     
@@ -620,8 +628,10 @@ internal static class Downloader
             IsControlsEnabled(true);
             if (downloadModpack && SelectedModpack is not null)
                 DownloadingFileName($"Downloading {SelectedModpack.Name} canceled.");
-            else
+            else if (versionJson is not null)
                 DownloadingFileName($"Downloading {versionJson.Id} canceled.");
+            else
+                DownloadingFileName("Downloading canceled: version config is null!");
             Settings.logger.Warning(ex.Message);
             return TaskStatus.Canceled;
         }
@@ -630,8 +640,10 @@ internal static class Downloader
             IsControlsEnabled(true);
             if (downloadModpack && SelectedModpack is not null)
                 DownloadingFileName($"Error occured while downloading {SelectedModpack.Name}.");
-            else
+            else if (versionJson is not null)
                 DownloadingFileName($"Error occured while downloading {versionJson.Id}.");
+            else
+                DownloadingFileName($"Error occured while downloading: version config is null!");
             Settings.logger.Error(ex.Message);
             if (ex.StackTrace is not null)
                 Settings.logger.Error(ex.StackTrace);
@@ -640,7 +652,7 @@ internal static class Downloader
         return TaskStatus.RanToCompletion;
     }
 
-    public static async Task<T> DownloadAndDeserializeJsonData<T>(string url, string path = "", string filename = "") where T : new()
+    public static async Task<T?> DownloadAndDeserializeJsonData<T>(string url, string path = "", string filename = "") where T : new()
     {
         var jsonData = string.Empty;
 

+ 5 - 5
VeloeMinecraftLauncher/MinecraftLauncher/Settings.cs

@@ -10,7 +10,7 @@ namespace VeloeMinecraftLauncher.MinecraftLauncher;
 internal static class Settings
 {
     //public static readonly string JavaPath = "C:\\Program Files\\Microsoft\\jdk-11.0.12.7-hotspot\\bin\\java.exe";
-    public static string javaPath = "";
+    public static string javaPath = string.Empty;
     public static string minecraftForlderPath = Directory.GetCurrentDirectory() + '/';
     public static UInt32 maxRam = 2048;
     public static bool useCustomJava = false;
@@ -18,8 +18,8 @@ internal static class Settings
     public static bool setPath = true;
     public static bool checkGameAssets = false;
     public static bool gameLogToLauncher = false;
-    public static string username;
-    public static string lastChosenVersion;
+    public static string username = string.Empty;
+    public static string lastChosenVersion = string.Empty;
     public static Serilog.ILogger logger;
     public static CaptureFilePathHook logFilePath;
     public static Serilog.ILogger avaloniaLogger;
@@ -65,8 +65,8 @@ internal static class Settings
             try
             {
                 var settingsSerializable = JsonSerializer.Deserialize<SettingsSerializable>(settings, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
-
-                Settings.UpdateSettings(settingsSerializable);
+                if (settingsSerializable is not null)
+                    Settings.UpdateSettings(settingsSerializable);
             }
             catch (JsonException ex)
             {

+ 23 - 19
VeloeMinecraftLauncher/MinecraftLauncher/StartCommandBuilder.cs

@@ -87,7 +87,7 @@ internal static class StartCommandBuilder
 
         }
         
-        Entity.Version.Version inheritsFrom = new();
+        Entity.Version.Version? inheritsFrom = null;
         if (version.InheritsFrom is null)
             returnString.Append(Path.GetFullPath(Settings.minecraftForlderPath + "versions/" + version.Id + "/" + version.Id + ".jar")); //main jar file
         else
@@ -98,7 +98,7 @@ internal static class StartCommandBuilder
             
             inheritsFrom = JsonSerializer.Deserialize<Entity.Version.Version>(inheritsJsonString, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
 
-            foreach (var library in inheritsFrom.Libraries)
+            foreach (var library in inheritsFrom?.Libraries ?? new())
             {
                 bool rulesVaild = true;
                 if (library.Natives is not null)
@@ -167,7 +167,9 @@ internal static class StartCommandBuilder
                         continue;
 
                     var value = ((JsonElement)argument).Deserialize(typeof(string)) as string;
-  
+
+                    if (value is null) continue;
+
                     //for new forge versions (1.18, 1.19)
                     if (value.Contains("${version_name}"))
                     {
@@ -183,7 +185,7 @@ internal static class StartCommandBuilder
                     }
 
                     bool containsArgWithValue = value.Contains('=');
-                    bool containsPathValueOnly = value.StartsWith(Path.GetDirectoryName(Settings.minecraftForlderPath + "libraries/"));
+                    bool containsPathValueOnly = value.StartsWith(Path.GetDirectoryName(Settings.minecraftForlderPath + "libraries/")!);
                     //value = value.Replace(" ", "");
                     if (containsArgWithValue)
                         value = value.Replace("=", "=\"");
@@ -221,17 +223,17 @@ internal static class StartCommandBuilder
                 if (!(((JsonElement)argument).ValueKind == JsonValueKind.String))
                     continue;
 
-                var value = ((JsonElement)argument).Deserialize(typeof(string));
+                var value = ((JsonElement)argument).Deserialize(typeof(string)) as string;
 
-                //if ()
+                if (value is null) continue;
 
-                if (!(value as string).Contains("--"))
+                if (!(value).Contains("--"))
                 {
-                    argsValues.Add(value as string);
+                    argsValues.Add(value);
                     continue;
                 }
 
-                args.Add(value as string);
+                args.Add(value);
             }
         }
         if (version.MinecraftArguments is not null)
@@ -273,7 +275,7 @@ internal static class StartCommandBuilder
 
         if (argsProvided.ContainsValue(false))
         {
-            if (inheritsFrom.Arguments is not null)
+            if (inheritsFrom?.Arguments is not null)
             {
                 foreach (var argument in inheritsFrom.Arguments.Game)
                 {
@@ -288,21 +290,23 @@ internal static class StartCommandBuilder
                     if (!(((JsonElement)argument).ValueKind == JsonValueKind.String))
                         continue;
 
-                    var value = ((JsonElement)argument).Deserialize(typeof(string));
+                    var value = ((JsonElement)argument).Deserialize(typeof(string)) as string;
 
-                    if (!(value as string).Contains("--"))
+                    if (value is null) continue;
+                         
+                    if (!(value).Contains("--"))
                     {
-                        argsValues.Add(value as string);
+                        argsValues.Add(value);
                         continue;
                     }
-                    if (!argsProvided.GetValueOrDefault(value as string, false))
+                    if (!argsProvided.GetValueOrDefault(value, false))
                     {
-                        args.Add(value as string);
-                        argsProvided[value as string] = true;
+                        args.Add(value);
+                        argsProvided[value] = true;
                     }
                 }
             }
-            if (inheritsFrom.MinecraftArguments is not null)
+            if (inheritsFrom?.MinecraftArguments is not null)
             {
                 var minecraftArguments = inheritsFrom.MinecraftArguments.Split(' ');
                 //args = version.minecraftArguments.Split(' ').Where(x=> x.Contains("--")).ToList();
@@ -340,14 +344,14 @@ internal static class StartCommandBuilder
                     //for forge
                     if (version.InheritsFrom is null)
                         returnString.Append(" --assetsDir " + "\"" + Path.GetDirectoryName(Settings.minecraftForlderPath + "assets/" + version.Assets + "/") + "\"");
-                    else
+                    else if (inheritsFrom is not null)
                         returnString.Append(" --assetsDir " + "\"" + Path.GetDirectoryName(Settings.minecraftForlderPath + "assets/" + inheritsFrom.Assets + "/") + "\"");
                     break;
                 case "--assetIndex":
                     //for forge
                     if (version.InheritsFrom is null)
                         returnString.Append(" --assetIndex " + version.Assets);
-                    else
+                    else if (inheritsFrom is not null)
                         returnString.Append(" --assetIndex " + inheritsFrom.Assets);
                     break;
                 case "--uuid":

+ 4 - 4
VeloeMinecraftLauncher/Models/Entity/Assets/Asset.cs

@@ -5,15 +5,15 @@ namespace VeloeMinecraftLauncher.Entity.Assets;
 
 internal class Asset
 {
-    public string Hash { get; set; }
-    public int Size { get; set; }
+    public string Hash { get; set; } = string.Empty;
+    public int Size { get; set; } = 0;
 }
 
 internal class AssetsManifest
 {
     [JsonPropertyName("virtual")]
-    public bool IsVirtual { get; set; }
+    public bool? IsVirtual { get; set; }
 
     [JsonPropertyName("objects")]
-    public Dictionary<string, Asset> Objects { get; set; }
+    public Dictionary<string, Asset>? Objects { get; set; }
 }

+ 8 - 0
VeloeMinecraftLauncher/Models/Entity/Changelog.cs

@@ -5,5 +5,13 @@ public class Changelog
     public string Text { get; set; }
     public string Version { get; set; }
     public string Date { get; set; }
+
+    public Changelog(string title, string text, string version, string date) 
+    {
+        Title = title;
+        Text = text;
+        Version = version;
+        Date = date;
+    }
 }
 

+ 6 - 0
VeloeMinecraftLauncher/Models/Entity/DownloadedVersion.cs

@@ -4,6 +4,12 @@ public class DownloadedVersion
     public string path;
     public string version;
 
+    public DownloadedVersion(string path, string version)
+    {
+        this.path = path;
+        this.version = version;
+    }
+
     public override string ToString()
     {
         return version;

+ 5 - 5
VeloeMinecraftLauncher/Models/Entity/LauncherProfiles.cs

@@ -6,7 +6,7 @@ namespace VeloeMinecraftLauncher.Entity.LauncherProfiles;
 [Serializable]
 public class LauncherProfiles
 {
-    public string SelectedProfile { get; set; }
+    public string SelectedProfile { get; set; } = string.Empty;
     public Dictionary<string, Profile> Profiles { get; set; }
 
     public LauncherProfiles()
@@ -18,8 +18,8 @@ public class LauncherProfiles
 [Serializable]
 public class Profile
 {
-    public string Name { get; set; }
-    public string LastVersionId { get; set; }
-    public string[] AllowedReleaseTypes { get; set; }
-    public string LauncherVisibilityOnGameClose { get; set; }
+    public string Name { get; set; } = string.Empty;
+    public string LastVersionId { get; set; } = string.Empty;
+    public string[] AllowedReleaseTypes { get; set; } =  Array.Empty<string>();  
+    public string LauncherVisibilityOnGameClose { get; set; } = string.Empty;
 }

+ 11 - 11
VeloeMinecraftLauncher/Models/Entity/McStatus/McStatus.cs

@@ -4,15 +4,15 @@ namespace VeloeMinecraftLauncher.Entity.McStatus;
 
 public class McStatus
 {
-    public string MessageOfTheDay { get; set; }
-    public string Gametype { get; set; }
-    public string GameId { get; set; }
-    public string Version { get; set; }
-    public string Plugins { get; set; }
-    public string Map { get; set; }
-    public string NumPlayers { get; set; }
-    public string MaxPlayers { get; set; }
-    public string HostPort { get; set; }
-    public string HostIp { get; set; }
-    public List<string> Players { get; set; }
+    public string? MessageOfTheDay { get; set; }
+    public string? Gametype { get; set; }
+    public string? GameId { get; set; }
+    public string? Version { get; set; }
+    public string? Plugins { get; set; }
+    public string? Map { get; set; }
+    public string? NumPlayers { get; set; }
+    public string? MaxPlayers { get; set; }
+    public string? HostPort { get; set; }
+    public string? HostIp { get; set; }
+    public List<string>? Players { get; set; }
 }

+ 4 - 4
VeloeMinecraftLauncher/Models/Entity/Modpack.cs

@@ -1,14 +1,14 @@
 namespace VeloeMinecraftLauncher.Models.Entity;
 public class Modpack
 {
-    public string Name { get; set; }
-    public string Version { get; set; }
+    public string Name { get; set; } = string.Empty;
+    public string Version { get; set; } = string.Empty;
     public bool Forge { get; set; } = false;
     public bool ForgeOptifine { get; set; } = false;
     public bool Optifine { get; set; } = false;
     public bool Fabric { get; set; } = false;
-    public string Url { get; set; }
-    public int Revision { get; set; }
+    public string Url { get; set; } = string.Empty;
+    public int Revision { get; set; } = -1;
 
     public override string ToString()
     {

+ 24 - 14
VeloeMinecraftLauncher/Models/Entity/Version/Version.cs

@@ -3,6 +3,8 @@ using System.Text.Json.Serialization;
 
 namespace VeloeMinecraftLauncher.Entity.Version;
 
+#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
+
 public class Arguments
 {      
     public List<object> Game { get; set; }
@@ -42,8 +44,8 @@ public class Classifiers
     [JsonPropertyName("natives-windows-64")]
     public NativesWindows NativesWindows64 { get; set; }
 
-    public Sources Sources { get; set; }
-    public Javadoc Javadoc { get; set; }
+    //public Sources Sources { get; set; }
+    //public Javadoc Javadoc { get; set; }
 }
 
 public class Client
@@ -52,23 +54,24 @@ public class Client
     public int Size { get; set; }
     public string Url { get; set; }
     public string Argument { get; set; }
-    public File File { get; set; }
+    //public File File { get; set; }
     public string Type { get; set; }
 }
 
 public class Downloads
 {
     public Client Client { get; set; }
-    public Server Server { get; set; }
+    //public Server Server { get; set; }
     public Artifact Artifact { get; set; }
     public Classifiers Classifiers { get; set; }
 }
-
+/*
 public class Extract
 {
     public List<string> Exclude { get; set; }
 }
-
+*/
+/*
 public class File
 {
     public string Id { get; set; }
@@ -76,7 +79,8 @@ public class File
     public int Size { get; set; }
     public string Url { get; set; }
 }
-
+*/
+/*
 public class Javadoc
 {
     public string Path { get; set; }
@@ -84,11 +88,11 @@ public class Javadoc
     public int Size { get; set; }
     public string Url { get; set; }
 }
-
+*/
 public class JavaVersion
 {
     public string Component { get; set; }
-    public int MajorVersion { get; set; }
+    public int? MajorVersion { get; set; }
 }
 
 public class Library
@@ -96,15 +100,15 @@ public class Library
     public Downloads Downloads { get; set; }
     public string Name { get; set; }
     public List<Rule> Rules { get; set; }
-    public Extract Extract { get; set; }
+    //public Extract Extract { get; set; }
     public Natives Natives { get; set; }
 }
-
+/*
 public class Logging
 {
     public Client Client { get; set; }
 }
-
+*/
 public class Natives
 {
     public string Linux { get; set; }
@@ -151,7 +155,7 @@ public class Version
     public string Id { get; set; }
     public JavaVersion JavaVersion { get; set; }
     public List<Library> Libraries { get; set; }
-    public Logging Logging { get; set; }
+    //public Logging Logging { get; set; }
     public string MainClass { get; set; }
     public string MinecraftArguments { get; set; }
     public int MinimumLauncherVersion { get; set; }
@@ -168,13 +172,17 @@ public class Rule
     public Os Os { get; set; }
 }
 
+//not used for now
+
+/*
 public class Server
 {
     public string Sha1 { get; set; }
     public int Size { get; set; }
     public string Url { get; set; }
 }
-
+*/
+/*
 public class Sources
 {
     public string Path { get; set; }
@@ -182,3 +190,5 @@ public class Sources
     public int Size { get; set; }
     public string Url { get; set; }
 }
+*/
+#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.

+ 4 - 0
VeloeMinecraftLauncher/Models/Entity/VesrionManifest/Latest.cs

@@ -1,7 +1,11 @@
 namespace VeloeMinecraftLauncher.Entity.VersionManifest;
 
+//not used for now
+
+/*
 public class Latest
 {
     public string Release { get; set; }
     public string Snapshot { get; set; }
 }
+*/

+ 5 - 5
VeloeMinecraftLauncher/Models/Entity/VesrionManifest/Version.cs

@@ -3,13 +3,13 @@
 namespace VeloeMinecraftLauncher.Entity.VersionManifest;
 
 public class Version
-{ 
-    public string Id { get; set; }
-    public string Type { get; set; }
-    public string Url { get; set; }
+{
+    public string Id { get; set; } = string.Empty;
+    public string Type { get; set; } = string.Empty;
+    public string Url { get; set; } = string.Empty;
     public DateTime Time { get; set; }
     public DateTime ReleaseTime { get; set; }
-    public string Sha1 { get; set; }
+    public string Sha1 { get; set; } = string.Empty;
     public int ComplianceLevel { get; set; }
 
     public override string ToString()

+ 2 - 2
VeloeMinecraftLauncher/Models/Entity/VesrionManifest/VersionManifest.cs

@@ -4,6 +4,6 @@ namespace VeloeMinecraftLauncher.Entity.VersionManifest;
 
 public class VersionManifest
 {
-    public Latest Latest { get; set; }
-    public List<Version> Versions { get; set; }
+    //public Latest Latest { get; set; }
+    public List<Version>? Versions { get; set; }
 }

+ 8 - 0
VeloeMinecraftLauncher/Models/ServerPanelModel.cs

@@ -9,6 +9,14 @@ public class ServerPanelModel : ReactiveValidationObject
     private string _tip;
     private string _players;
 
+    public ServerPanelModel(string name, string status, string tip, string players)
+    {
+        _name= name;
+        _status= status;
+        _tip= tip;
+        _players= players;
+    }
+
     public string Name
     {
         get => _name;

+ 2 - 2
VeloeMinecraftLauncher/VeloeMinecraftLauncher.csproj

@@ -10,8 +10,8 @@
     <DebugType>embedded</DebugType>
     <StartupObject>VeloeMinecraftLauncher.Program</StartupObject>
     <PlatformTarget>x64</PlatformTarget>
-    <AssemblyVersion>1.2.2.138</AssemblyVersion>
-    <FileVersion>1.2.2.138</FileVersion>
+    <AssemblyVersion>1.2.2.164</AssemblyVersion>
+    <FileVersion>1.2.2.164</FileVersion>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
     <NoWarn>NU1605</NoWarn>

+ 5 - 5
VeloeMinecraftLauncher/ViewModels/ErrorWindowViewModel.cs

@@ -45,11 +45,11 @@ public class ErrorWindowViewModel : ViewModelBase
 
     }
 
-    private string _errorMessage;
-    private string _errorTrace;
-    private bool _isErrorTraceVisible;
-    private bool _centerMessage;
-    private string _logfile;
+    private string _errorMessage = string.Empty;
+    private string _errorTrace = string.Empty;
+    private bool _isErrorTraceVisible = false;
+    private bool _centerMessage = false;
+    private string _logfile = string.Empty;
 
     public string ErrorTrace
     {

+ 108 - 90
VeloeMinecraftLauncher/ViewModels/MainWindowViewModel.cs

@@ -17,7 +17,6 @@ using System.Reflection;
 using Serilog;
 using Avalonia.Controls;
 using Avalonia.Threading;
-using System.Net;
 using System.IO.Compression;
 using ReactiveUI.Validation.Extensions;
 using Avalonia.Media;
@@ -62,6 +61,10 @@ public class MainWindowViewModel : ViewModelBase
             catch (Exception ex)
             {
                 OpenErrorWindow(ex);
+                if (_logger is null)
+                {
+                    _logger = new LoggerConfiguration().MinimumLevel.Debug().CreateLogger();
+                }
             }
 
             this.ValidationRule(
@@ -98,8 +101,9 @@ public class MainWindowViewModel : ViewModelBase
             {
                 var changelog = await Downloader.DownloadAndDeserializeJsonData<List<Changelog>>("https://files.veloe.link/launcher/changelog.json");
 
-                if (Avalonia.Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
+                if (changelog is not null &&  Avalonia.Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
                 {
+#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
                     Dispatcher.UIThread.InvokeAsync(() =>
                     {
                         var stackpanel = desktop.MainWindow.GetControl<StackPanel>("ChangeLogStackPanel");
@@ -123,7 +127,7 @@ public class MainWindowViewModel : ViewModelBase
                             });
                         }
                     });
-
+#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
                 }
             }
             catch (Exception ex)
@@ -138,45 +142,50 @@ public class MainWindowViewModel : ViewModelBase
 
                 var serverNames = await Downloader.DownloadAndDeserializeJsonData<List<string>>("https://files.veloe.link/launcher/servers.json");
 
-                _connection = new HubConnectionBuilder()
+                if (serverNames is not null)
+                {
+                    _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.");
-                    foreach (var server in serverNames)
+                    Func<Exception, Task> reconnecting = ex => Task.Run(() =>
                     {
-                        _connection.InvokeAsync("ConnectToGroup", server);
-                    }
-                });
-
-                _connection.Reconnecting += reconnecting;
-                _connection.Reconnected += reconnected;
-
-                if (Avalonia.Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
-                {
-                    Dispatcher.UIThread.InvokeAsync(() =>
+                        _logger.Warning("Reconnecting to WebCoket...");
+                    });
+                    Func<string, Task> reconnected = str => Task.Run(() =>
                     {
-                        var stackpanel = desktop.MainWindow.GetControl<StackPanel>("ServersStackPanel");
+                        _logger.Warning("Reconnected to WebCoket.");
                         foreach (var server in serverNames)
-                            stackpanel.Children.Add(CreateServerPanel(server));
+                        {
+                            _connection.InvokeAsync("ConnectToGroup", server);
+                        }
                     });
 
-                }
+                    _connection.Reconnecting += reconnecting;
+                    _connection.Reconnected += reconnected;
 
-                _connection.StartAsync();
+                    if (Avalonia.Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
+                    {
+#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
+                        Dispatcher.UIThread.InvokeAsync(() =>
+                        {
+                            var stackpanel = desktop.MainWindow.GetControl<StackPanel>("ServersStackPanel");
+                            foreach (var server in serverNames)
+                                stackpanel.Children.Add(CreateServerPanel(server));
+                        });
+#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
 
-                foreach (var server in serverNames)
-                {
-                    _connection.InvokeAsync("ConnectToGroup", server);
+                    }
+
+                    await _connection.StartAsync();
+
+                    foreach (var server in serverNames)
+                    {
+                        await _connection.InvokeAsync("ConnectToGroup", server);
+                    }
+                    _logger.Debug("Connected to WebSoket");
                 }
-                _logger.Debug("Connected to WebSoket");
 
                 _consoleOutputTimer.Elapsed += UpdateConsoleOutput;
                 _consoleOutputTimer.AutoReset = false;
@@ -188,7 +197,7 @@ public class MainWindowViewModel : ViewModelBase
             try
             {
                 _logger.Debug("Checking modpacks updates...");
-                var modpacksInfo = await Downloader.DownloadAndDeserializeJsonData<List<Modpack>>("https://files.veloe.link/launcher/modpacks.json");
+                var modpacksInfo = await Downloader.DownloadAndDeserializeJsonData<List<Modpack>>("https://files.veloe.link/launcher/modpacks.json") ?? new List<Modpack>();
                 var installedModpacks = //DownloadedVersions.Where(v => modpacksInfo.Select(m => m.Name).Contains(v.version)).Join(modpacksInfo, (v, m) => v.version == m.);
                     from downloadedVersion in DownloadedVersions
                     join modpack in modpacksInfo on downloadedVersion.version equals modpack.Name
@@ -244,22 +253,22 @@ public class MainWindowViewModel : ViewModelBase
 
     System.Timers.Timer _consoleOutputTimer = new(250);
 
-    private HubConnection _connection;
+    private HubConnection? _connection;
     private string _downloadButton = "Download versions";
     private string _startButton = "Start Minecraft";
-    private string _username = "";
+    private string _username = string.Empty;
     private StringBuilder _consoleText = new();
     private int _downloadedIndex;
-    private string _argumentsBox;
+    private string _argumentsBox = string.Empty;
     private bool _isNoGameRunning = true;
     private bool _isUpdateAvailable = false;
     private string _settingsButton = "Settings";
-    private string _startButtonOutput;
+    private string _startButtonOutput = string.Empty;
     private CancellationTokenSource _tokenSource = new();
 
     ILogger _logger;
 
-    LatestLauncherVersion _latestLauncherInfo;
+    LatestLauncherVersion? _latestLauncherInfo;
     DownloadedVersion _downloadedVersion;
     DownloadedVersion _startedVersion;
 
@@ -387,7 +396,7 @@ public class MainWindowViewModel : ViewModelBase
             DataContext = new VersionsDownloaderViewModel() 
         };
        
-        if (Avalonia.Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
+        if (Avalonia.Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
         {
             versionsDownloader.Closed += updateAvailable;
             versionsDownloader.ShowDialog(desktop.MainWindow);            
@@ -396,7 +405,6 @@ public class MainWindowViewModel : ViewModelBase
 
     public async void StartMinecraft()
     {
-#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
         await Task.Run(async() =>
         {
             try
@@ -423,7 +431,7 @@ public class MainWindowViewModel : ViewModelBase
                     {
                         TaskStatus result;
 
-                        if (versionJson.InheritsFrom is null)
+                        if (string.IsNullOrEmpty(versionJson.InheritsFrom))
                             result = await Downloader.StartDownload(value => StartButtonOutput = value, value => { } ,value => IsNoGameRunning = value, value => { }, versionJson, _tokenSource.Token);
                         else
                         {
@@ -432,7 +440,10 @@ public class MainWindowViewModel : ViewModelBase
                                 string jsonInheritsFrom = inheritsFromReader.ReadToEnd();
                                 var inheritsFromJson = JsonSerializer.Deserialize<Entity.Version.Version>(jsonInheritsFrom, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
 
-                                result = await Downloader.StartDownload(value => StartButtonOutput = value, value => { } ,value => IsNoGameRunning = value, value => { }, inheritsFromJson, _tokenSource.Token);
+                                if (inheritsFromJson is not null)
+                                    result = await Downloader.StartDownload(value => StartButtonOutput = value, value => { }, value => IsNoGameRunning = value, value => { }, inheritsFromJson, _tokenSource.Token);
+                                else
+                                    result = TaskStatus.Faulted;
                             }
                         }
 
@@ -448,23 +459,23 @@ public class MainWindowViewModel : ViewModelBase
 
                     if (!Settings.useCustomJava)
                     {
-                        if (versionJson.JavaVersion is not null)
+                        if (versionJson?.JavaVersion?.MajorVersion is not null)
                         {
                             _logger.Debug("Java version required: {0}", versionJson.JavaVersion.MajorVersion);
-                            version = versionJson.JavaVersion.MajorVersion;
+                            version = versionJson.JavaVersion.MajorVersion.Value;
                         }
                         else
                         {
-                            if (versionJson.InheritsFrom is not null)
+                            if (!string.IsNullOrEmpty(versionJson?.InheritsFrom))
                             {
                                 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, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
-                                    if (inheritsFromJson?.JavaVersion != null)
+                                    if (inheritsFromJson?.JavaVersion?.MajorVersion is not null)
                                     {
                                         _logger.Debug("Java version required: {0}", inheritsFromJson.JavaVersion.MajorVersion);
-                                        version = inheritsFromJson.JavaVersion.MajorVersion;
+                                        version = inheritsFromJson.JavaVersion.MajorVersion.Value;
                                     }
                                 }
                             }
@@ -521,9 +532,9 @@ public class MainWindowViewModel : ViewModelBase
                 if (!Settings.useCustomJava)
                     minecraft.StartInfo.EnvironmentVariables["JAVA_HOME"] = $"{Settings.minecraftForlderPath}javaruntime/{version}";
                 else
-                    minecraft.StartInfo.EnvironmentVariables["JAVA_HOME"] = Directory.GetParent(Path.GetDirectoryName(Settings.javaPath)).ToString();
+                    minecraft.StartInfo.EnvironmentVariables["JAVA_HOME"] = Settings.javaPath;
                 minecraft.StartInfo.EnvironmentVariables["PATH"] = "%JAVA_HOME%\bin;%PATH%";
-
+#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
                 Task.Run(() =>
                 {
                     try
@@ -562,6 +573,7 @@ public class MainWindowViewModel : ViewModelBase
                         return Task.CompletedTask;
                     }
                 });
+#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
                 _logger.Debug("Updating Settings");
                 Settings.username = _username;
                 Settings.lastChosenVersion = DownloadedVersion.version;
@@ -573,7 +585,6 @@ public class MainWindowViewModel : ViewModelBase
                 OpenErrorWindow(ex);
             }
         });
-#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
     }
 
     void OutputHandler(object sendingProcess, DataReceivedEventArgs outLine)
@@ -604,14 +615,14 @@ public class MainWindowViewModel : ViewModelBase
         ScrollToEnd("ConsoleScroll");
     }
 
-    void ScrollToEnd(string ScrollName)
+    void ScrollToEnd(string scrollName)
     {
-        if (Avalonia.Application.Current is not null && Avalonia.Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
+        if (Avalonia.Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
         {
             Dispatcher.UIThread.InvokeAsync(() =>
             {
-                var scroll = desktop.MainWindow.GetControl<ScrollViewer>("ConsoleScroll");
-                scroll.ScrollToEnd();
+                var scroll = desktop.MainWindow.GetControl<ScrollViewer>(scrollName);
+                scroll?.ScrollToEnd();
             });
 
         }
@@ -619,25 +630,26 @@ public class MainWindowViewModel : ViewModelBase
 
     void ProcessExited(object? sendingProcess, EventArgs e)
     {
-        ((Process)sendingProcess).Exited -= ProcessExited;
-        ((Process)sendingProcess).OutputDataReceived -= OutputHandler;
-        ((Process)sendingProcess).ErrorDataReceived -= OutputHandler;
-        ((Process)sendingProcess).CancelOutputRead();
-        ((Process)sendingProcess).CancelErrorRead();
-
-        _logger.Debug("Exit code: {0}", ((Process)sendingProcess).ExitCode);
-       
-        StartButtonOutput = "";
-        IsNoGameRunning = true;
-        if (((Process)sendingProcess).ExitCode is not (0 or 2))
-            OpenErrorWindow(new JavaProcessException($"Minecraft process exited with an error code {((Process)sendingProcess).ExitCode}.\nCheck log in game folder or launcher console.", $"{Settings.minecraftForlderPath}versions/{_startedVersion.version}/crash-reports"));
-        else if (((Process)sendingProcess).ExitCode is 2)
+        if(sendingProcess is Process minecraftProcess)
         {
-            OpenErrorWindow(new Exception("JVM exited on the startup (Exit code 2). Check your Java installation. Get more info in the laucher console."));
+            minecraftProcess.Exited -= ProcessExited;
+            minecraftProcess.OutputDataReceived -= OutputHandler;
+            minecraftProcess.ErrorDataReceived -= OutputHandler;
+            minecraftProcess.CancelOutputRead();
+            minecraftProcess.CancelErrorRead();
+
+            _logger.Debug("Exit code: {0}", minecraftProcess.ExitCode);
+
+            StartButtonOutput = "";
+            IsNoGameRunning = true;
+            if (minecraftProcess.ExitCode is not (0 or 2))
+                OpenErrorWindow(new JavaProcessException($"Minecraft process exited with an error code {minecraftProcess.ExitCode}.\nCheck log in game folder or launcher console.", $"{Settings.minecraftForlderPath}versions/{_startedVersion.version}/crash-reports"));
+            else if (minecraftProcess.ExitCode is 2)
+            {
+                OpenErrorWindow(new Exception("JVM exited on the startup (Exit code 2). Check your Java installation. Get more info in the laucher console."));
+            }
+            minecraftProcess.Dispose();
         }
-            
-
-        ((Process)sendingProcess).Dispose();         
     }
 
 
@@ -662,7 +674,7 @@ public class MainWindowViewModel : ViewModelBase
                 if (File.Exists(checkedPath = dir.FullName + "/" + dir.Name + ".json"))
                 {
                     _logger.Debug("Found version {0}",dir.Name);
-                    DownloadedVersions.Add(new DownloadedVersion() { path = checkedPath, version = dir.Name });
+                    DownloadedVersions.Add(new DownloadedVersion(checkedPath,dir.Name));
                     profiles.Profiles.Add($"Version {dir.Name}", new Profile() { Name = dir.Name, LastVersionId = dir.Name, LauncherVisibilityOnGameClose = "keep the launcher open" });
                 }
 
@@ -690,7 +702,7 @@ public class MainWindowViewModel : ViewModelBase
             var lpString = JsonSerializer.Serialize(profiles, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
             File.WriteAllText(Settings.minecraftForlderPath + "launcher_profiles.json", lpString);
         }
-        catch (DirectoryNotFoundException ex)
+        catch (DirectoryNotFoundException)
         {
             Directory.CreateDirectory(Settings.minecraftForlderPath + "versions");
             return;
@@ -726,7 +738,7 @@ public class MainWindowViewModel : ViewModelBase
     {
         var settingsWindow = new SettingsWindow { DataContext = new SettingsWindowViewModel() };
 
-        if (Avalonia.Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
+        if (Avalonia.Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
         {
             settingsWindow.Closed += updateAvailable;
             settingsWindow.ShowDialog(desktop.MainWindow);
@@ -748,7 +760,7 @@ public class MainWindowViewModel : ViewModelBase
         {
             updater.Start();
 
-            if (Avalonia.Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
+            if (Avalonia.Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
             {
                 desktop.MainWindow.Close();
             }
@@ -767,7 +779,7 @@ public class MainWindowViewModel : ViewModelBase
             if (File.Exists(fileName))
             {
                 FileVersionInfo fileVersionInfo = FileVersionInfo.GetVersionInfo(fileName);
-                LatestLauncherVersion latestLauncherVersion = await Downloader.DownloadAndDeserializeJsonData<LatestLauncherVersion>("https://files.veloe.link/launcher/update/versions.json");
+                var latestLauncherVersion = await Downloader.DownloadAndDeserializeJsonData<LatestLauncherVersion>("https://files.veloe.link/launcher/update/versions.json");
 
                 if (OperatingSystem.IsLinux())
                 {
@@ -775,7 +787,7 @@ public class MainWindowViewModel : ViewModelBase
                     return;
                 }
 
-                if (latestLauncherVersion is not null)
+                if (latestLauncherVersion?.Updater is not null && fileVersionInfo?.FileVersion is not null)
                 {
                     _logger.Information("Latest updater version on server: {0}", latestLauncherVersion.Updater);
                     _logger.Information("Updater version: {0}", fileVersionInfo.FileVersion);
@@ -786,6 +798,8 @@ public class MainWindowViewModel : ViewModelBase
                         return;
                     }
                 }
+                else
+                    _logger.Warning("Version verification for {0} failed: latestLauncherVersion or fileVersionInfo does not contain version info or null!", fileName);
             }
                            
             try
@@ -825,7 +839,7 @@ public class MainWindowViewModel : ViewModelBase
 
     private Panel CreateServerPanel(string name)
     {
-        ServerPanelModel serverPanelModel = new() { Name = name , Status = "Wait for update...", Tip = "No players.", Players = string.Empty};
+        ServerPanelModel serverPanelModel = new(name, "Wait for update...", "No players.",string.Empty);
 
         Panel panel = new Panel() 
         { 
@@ -859,27 +873,31 @@ public class MainWindowViewModel : ViewModelBase
 
         System.Timers.Timer timeoutTimer = new System.Timers.Timer(30000);
 
-        timeoutTimer.Elapsed += (Object source, ElapsedEventArgs e) => 
+        timeoutTimer.Elapsed += (object? source, ElapsedEventArgs e) => 
         { 
             serverPanelModel.Status = $"{serverPanelModel.Name}: Offline"; 
             serverPanelModel.Players = string.Empty; 
         };
         timeoutTimer.Start();
 
-        _connection.On<string>($"Update{serverPanelModel.Name}", (message) =>
+        _connection?.On<string>($"Update{serverPanelModel.Name}", (message) =>
         {
-            McStatus status = JsonSerializer.Deserialize<McStatus>(message, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
-            serverPanelModel.Status = $"{serverPanelModel.Name}: Online";
-            serverPanelModel.Players = $"{status.NumPlayers}/{status.MaxPlayers}";
-            serverPanelModel.Tip = String.Empty;
-            if (UInt16.Parse(status.NumPlayers) > 0)
-                foreach (var player in status.Players)
-                {
-                    serverPanelModel.Tip += player;
-                    serverPanelModel.Tip += "\n";
-                }
-            else
-                serverPanelModel.Tip = "No players.";
+            McStatus? status = JsonSerializer.Deserialize<McStatus>(message, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
+
+            if(status is not null)
+            {
+                serverPanelModel.Status = $"{serverPanelModel.Name}: Online";
+                serverPanelModel.Players = $"{status.NumPlayers}/{status.MaxPlayers}";
+                serverPanelModel.Tip = String.Empty;
+                if (UInt16.Parse(status.NumPlayers ?? "0") > 0)
+                    foreach (var player in status.Players ?? new())
+                    {
+                        serverPanelModel.Tip += player;
+                        serverPanelModel.Tip += "\n";
+                    }
+                else
+                    serverPanelModel.Tip = "No players.";
+            }      
             timeoutTimer.Stop();
             timeoutTimer.Start();
         });

+ 5 - 4
VeloeMinecraftLauncher/ViewModels/SettingsWindowViewModel.cs

@@ -10,6 +10,7 @@ using System.Collections.ObjectModel;
 using Serilog.Events;
 using System.Linq;
 using ReactiveUI.Validation.Components;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
 
 namespace VeloeMinecraftLauncher.ViewModels;
 
@@ -17,7 +18,7 @@ public class SettingsWindowViewModel : ViewModelBase
 {
     public SettingsWindowViewModel()
     {
-        LauncherVersion = Assembly.GetExecutingAssembly().GetName().Version.ToString();
+        LauncherVersion = Assembly.GetExecutingAssembly().GetName().Version?.ToString() ?? "unknown";
 
         var _logger = Settings.logger;
 
@@ -28,7 +29,7 @@ public class SettingsWindowViewModel : ViewModelBase
 
         var helper = this.ValidationRule(
             viewModel => viewModel.JavaPath,
-            value => { string path = Path.Combine(value, "bin/java"); if (OperatingSystem.IsWindows()) path += ".exe"; bool resultb = File.Exists(path); return resultb; },
+            value => { if (value is null) return false; string path = Path.Combine(value , "bin/java"); if (OperatingSystem.IsWindows()) path += ".exe"; bool resultb = File.Exists(path); return resultb; },
             "Can't find java executable.");
 
         this.ValidationRule(
@@ -37,7 +38,7 @@ public class SettingsWindowViewModel : ViewModelBase
             "Not a number.");   
 }
 
-    private string _launcherVersion;
+    private string _launcherVersion = string.Empty;
     private string _minecraftFolderPath = Settings.minecraftForlderPath;
     private string _javaPath = Settings.javaPath;
     private string _maxRam = Settings.maxRam.ToString();
@@ -107,7 +108,7 @@ public class SettingsWindowViewModel : ViewModelBase
             _isValid = true;
             if (!UseCustomJava)
             {
-                var rules = ValidationContext.Validations.Where(r => !(r as BasePropertyValidation<SettingsWindowViewModel>).Properties.Contains(nameof(JavaPath)));
+                var rules = ValidationContext.Validations.Where(r => !((BasePropertyValidation<SettingsWindowViewModel>)r).Properties.Contains(nameof(JavaPath)));
                 foreach (var rule in rules)
                     _isValid &= rule.IsValid;  
             }

+ 5 - 5
VeloeMinecraftLauncher/ViewModels/VersionsDownloaderViewModel.cs

@@ -42,7 +42,7 @@ public class VersionsDownloaderViewModel : ViewModelBase
     ObservableCollection<Modpack> _modpackVersions;
     List<Entity.VersionManifest.Version> _modpackVersionsAsVersion;
     Entity.VersionManifest.Version _filteredVersion;
-    Modpack _selectedModpack;
+    Modpack? _selectedModpack;
     VersionManifest _versionManifest;
 
     public VersionsDownloaderViewModel()
@@ -50,9 +50,9 @@ public class VersionsDownloaderViewModel : ViewModelBase
         IsControlsEnabled = false;
         try
         {
+            _logger = Settings.logger;
             Task.Run(async () =>
-            {
-                _logger = Settings.logger;
+            {              
                 if (FilteredVersions is null)
                 {
                     FilteredVersions = new();
@@ -62,8 +62,8 @@ public class VersionsDownloaderViewModel : ViewModelBase
                     _modpackVersions = new();
                 }
                 _logger.Debug("Getting versionManifest.json");
-                _versionManifest = await Downloader.DownloadAndDeserializeJsonData<VersionManifest>("https://launchermeta.mojang.com/mc/game/version_manifest_v2.json");
-                _modpackVersions.AddRange(await Downloader.DownloadAndDeserializeJsonData<List<Modpack>>("https://files.veloe.link/launcher/modpacks.json"));
+                _versionManifest = await Downloader.DownloadAndDeserializeJsonData<VersionManifest>("https://launchermeta.mojang.com/mc/game/version_manifest_v2.json") ?? new();
+                _modpackVersions.AddRange(await Downloader.DownloadAndDeserializeJsonData<List<Modpack>>("https://files.veloe.link/launcher/modpacks.json") ?? new());
                 _modpackVersionsAsVersion = _modpackVersions.Select(v=> new Entity.VersionManifest.Version() { Id = v.Name, Type = "modpack", ComplianceLevel = v.Revision}).ToList();
                 _logger.Debug("Updating available versions to download.");
                 UpdateList();

+ 23 - 18
VeloeMinecraftLauncher/Views/TitleBar/TitleBarWindow.axaml.cs

@@ -1,14 +1,11 @@
 using Avalonia;
 using Avalonia.Controls;
 using Avalonia.Controls.Shapes;
-using Avalonia.LogicalTree;
 using Avalonia.Markup.Xaml;
 using Avalonia.Media;
-using Avalonia.Media.Imaging;
-using Avalonia.Platform;
+using Avalonia.VisualTree;
 using System;
 using System.Runtime.InteropServices;
-using System.Threading;
 using System.Threading.Tasks;
 
 /*
@@ -36,6 +33,8 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 
 */
+
+#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
 namespace VeloeMinecraftLauncher.Views.TitleBar
 {
     public partial class TitleBarWindow : UserControl
@@ -124,19 +123,20 @@ namespace VeloeMinecraftLauncher.Views.TitleBar
         public string TitleText
         {
             get
-            { 
+            {
                 if (systemChromeTitle != null)
                     return systemChromeTitle.Text;
                 return "";
             }
-            set 
+            set
             {
                 if (systemChromeTitle != null)
-                systemChromeTitle.Text = value;
+                    systemChromeTitle.Text = value;
             }
         }
 
         public TitleBarWindow()
+
         {
             this.InitializeComponent();
 
@@ -168,15 +168,16 @@ namespace VeloeMinecraftLauncher.Views.TitleBar
             }
         }
 
-        private void CloseWindow(object sender, Avalonia.Interactivity.RoutedEventArgs e)
+        private void CloseWindow(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
         {
-            Window hostWindow = (Window)this.VisualRoot;
-            hostWindow.Close();
+            (this.GetVisualRoot() as Window)?.Close();
         }
 
-        private void MaximizeWindow(object sender, Avalonia.Interactivity.RoutedEventArgs e)
+        private void MaximizeWindow(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
         {
-            Window hostWindow = (Window)this.VisualRoot;
+            Window? hostWindow = this.GetVisualRoot() as Window;
+
+            if (hostWindow is null) return;
 
             if (hostWindow.WindowState == WindowState.Normal)
             {
@@ -188,22 +189,25 @@ namespace VeloeMinecraftLauncher.Views.TitleBar
             }
         }
 
-        private void MinimizeWindow(object sender, Avalonia.Interactivity.RoutedEventArgs e)
+        private void MinimizeWindow(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
         {
-            Window hostWindow = (Window)this.VisualRoot;
+            Window? hostWindow = this.GetVisualRoot() as Window;
+
+            if (hostWindow is null) return;
+
             hostWindow.WindowState = WindowState.Minimized;
         }
 
         private async void SubscribeToWindowState()
         {
-            Window hostWindow = (Window)this.VisualRoot;
+            Window? hostWindow = this.GetVisualRoot() as Window;
 
             while (hostWindow == null)
             {
-                hostWindow = (Window)this.VisualRoot;
+                hostWindow = this.GetVisualRoot() as Window;
                 await Task.Delay(50);
             }
-            
+
             hostWindow.GetObservable(Window.WindowStateProperty).Subscribe(s =>
             {
                 if (s != WindowState.Maximized)
@@ -233,5 +237,6 @@ namespace VeloeMinecraftLauncher.Views.TitleBar
             AvaloniaXamlLoader.Load(this);
         }
     }
-  
+
 }
+#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.