|
@@ -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();
|
|
|
});
|