diff --git a/Saradomin.sln.DotSettings b/Saradomin.sln.DotSettings index ff21452..0044dd2 100644 --- a/Saradomin.sln.DotSettings +++ b/Saradomin.sln.DotSettings @@ -1,2 +1,3 @@  + True True \ No newline at end of file diff --git a/Saradomin.sln.DotSettings.user b/Saradomin.sln.DotSettings.user index d39f247..f99c7a4 100644 --- a/Saradomin.sln.DotSettings.user +++ b/Saradomin.sln.DotSettings.user @@ -2,7 +2,7 @@ /usr/share/dotnet/sdk/7.0.100/MSBuild.dll No - <SessionState ContinuousTestingMode="0" IsActive="True" Name="All tests from FindMostRecentBackupDirectory.cs" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"> - <Project Location="/home/xacket/Projects/Saradomin-Launcher/UnitTests" Presentation="&lt;UnitTests&gt;" /> + <SessionState ContinuousTestingMode="0" IsActive="True" Name="All tests from FindMostRecentBackupDirectory.cs" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"> + <Project Location="\home\xacket\Projects\Saradomin-Launcher\UnitTests" Presentation="&lt;UnitTests&gt;" /> </SessionState> \ No newline at end of file diff --git a/Saradomin/Infrastructure/Services/SettingsService.cs b/Saradomin/Infrastructure/Services/SettingsService.cs index 5bd999f..9e3f71e 100644 --- a/Saradomin/Infrastructure/Services/SettingsService.cs +++ b/Saradomin/Infrastructure/Services/SettingsService.cs @@ -1,3 +1,4 @@ +using System; using System.IO; using System.Text.Json; using Saradomin.Model.Settings.Client; diff --git a/Saradomin/Utilities/SingleplayerManagement.cs b/Saradomin/Utilities/Singleplayer/SingleplayerManagement.cs similarity index 96% rename from Saradomin/Utilities/SingleplayerManagement.cs rename to Saradomin/Utilities/Singleplayer/SingleplayerManagement.cs index d40c9d5..a4fe832 100644 --- a/Saradomin/Utilities/SingleplayerManagement.cs +++ b/Saradomin/Utilities/Singleplayer/SingleplayerManagement.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Net.NetworkInformation; namespace Saradomin.Utilities; @@ -22,15 +23,11 @@ public static class SingleplayerManagement public static void MakeBackup(Action log) { - if (!Directory.Exists(CrossPlatform.GetSingleplayerBackupsHome())) - Directory.CreateDirectory(CrossPlatform.GetSingleplayerBackupsHome()); - string timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmss"); string newBackupDir = Path.Combine( CrossPlatform.GetSingleplayerBackupsHome(), timestamp ); - Directory.CreateDirectory(newBackupDir); foreach (string dir in DirsToBackup) { diff --git a/Saradomin/Utilities/Singleplayer/Windows.cs b/Saradomin/Utilities/Singleplayer/Windows.cs new file mode 100644 index 0000000..ee4d0f0 --- /dev/null +++ b/Saradomin/Utilities/Singleplayer/Windows.cs @@ -0,0 +1,77 @@ +using System; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Net.NetworkInformation; +using System.Threading; + +namespace Saradomin.Utilities.Singleplayer; + +public static class Windows +{ + private static bool IsPortInUse(int port) + { + var ipGlobalProperties = IPGlobalProperties.GetIPGlobalProperties(); + var tcpConnInfoArray = ipGlobalProperties.GetActiveTcpListeners(); + + return tcpConnInfoArray.Any(endpoint => endpoint.Port == port); + } + + private static Process StartJavaProcess(string javaExecutable, string jarPath, string memoryAllocation, Action outputHandler, Action onExit) + { + Process process = new Process(); + process.StartInfo = new ProcessStartInfo + { + FileName = javaExecutable, + Arguments = $"-Xmx{memoryAllocation} -Xms{memoryAllocation} -jar \"{jarPath}\"", + UseShellExecute = false, + CreateNoWindow = true, + RedirectStandardOutput = true, + RedirectStandardError = true, + WorkingDirectory = Path.Combine(CrossPlatform.GetSingleplayerHome(), "game") + }; + + process.OutputDataReceived += (_, args) => + { + if (string.IsNullOrEmpty(args.Data)) return; + outputHandler?.Invoke(args.Data); + }; + + process.ErrorDataReceived += (_, args) => + { + if (string.IsNullOrEmpty(args.Data)) return; + outputHandler?.Invoke(args.Data); + }; + + process.EnableRaisingEvents = true; + process.Exited += (_, _) => onExit?.Invoke(); + + process.Start(); + + process.BeginOutputReadLine(); + process.BeginErrorReadLine(); + return process; + } + + public static void WindowsLaunchServerAndClient(string javaExecutableLocation, Action log) + { + string serverJar = CrossPlatform.GetSingleplayerHome() + @"\game\server.jar"; + string clientJar = CrossPlatform.GetSingleplayerHome() + @"\game\client.jar"; + + if (IsPortInUse(43595)) + { + log("Port 43595 is in use. Cannot start the server again."); + return; + } + + Process serverProcess = StartJavaProcess(javaExecutableLocation, serverJar, "2G", log, null); + + while (!IsPortInUse(43595)) Thread.Sleep(1000); + + StartJavaProcess(javaExecutableLocation, clientJar, "1G", null, () => + { + serverProcess.Kill(); + }); + } + +} \ No newline at end of file diff --git a/Saradomin/ViewModel/Controls/SingleplayerViewModel.cs b/Saradomin/ViewModel/Controls/SingleplayerViewModel.cs index aa07d1e..d783b3d 100644 --- a/Saradomin/ViewModel/Controls/SingleplayerViewModel.cs +++ b/Saradomin/ViewModel/Controls/SingleplayerViewModel.cs @@ -1,8 +1,13 @@ using System; +using System.Diagnostics; using System.Diagnostics.Contracts; using System.IO; +using System.Linq; using System.Net.Http; +using System.Net.NetworkInformation; +using System.Runtime.InteropServices; using System.Text.RegularExpressions; +using System.Threading; using System.Threading.Tasks; using Avalonia; using Avalonia.Controls; @@ -73,7 +78,7 @@ public class SingleplayerViewModel : ViewModelBase public void DownloadSingleplayer() { - if (!CanLaunch) return; // While the button could be disabled, this looks nicer visually (since we update the download progress in the button text) + if (File.Exists(CrossPlatform.LocateSingleplayerExecutable()) && !CanLaunch) return; // While the button could be disabled, this looks nicer visually (since we update the download progress in the button text) CanLaunch = false; MakeBackup(); PrintLog($"Starting singleplayer download..."); @@ -103,6 +108,8 @@ public class SingleplayerViewModel : ViewModelBase private void PrintLog(string message) { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) message = Regex.Replace(message, @"\e\[[0-9;]*m", string.Empty); + ShowLogPanel = true; Dispatcher.UIThread.Post(() => { SingleplayerLogsTextBox.Text += message + Environment.NewLine; }, DispatcherPriority.Background); @@ -113,12 +120,19 @@ public class SingleplayerViewModel : ViewModelBase public void LaunchSingleplayer() { CanLaunch = false; - new Task(() => - CrossPlatform.RunCommandAndGetOutput( - $"{CrossPlatform.LocateSingleplayerExecutable()} {Launcher.JavaExecutableLocation}", - PrintLog, - PrintLog) - ).Start(); + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + new Task(() => Utilities.Singleplayer.Windows.WindowsLaunchServerAndClient(Launcher.JavaExecutableLocation, PrintLog)).Start(); + } + else + { + new Task(() => + CrossPlatform.RunCommandAndGetOutput( + $"{CrossPlatform.LocateSingleplayerExecutable()} \"{Launcher.JavaExecutableLocation}\"", + PrintLog, + PrintLog) + ).Start(); + } } private void LaunchFaq() diff --git a/Saradomin/ViewModel/Windows/MainWindowViewModel.cs b/Saradomin/ViewModel/Windows/MainWindowViewModel.cs index b31c06f..a9247ae 100644 --- a/Saradomin/ViewModel/Windows/MainWindowViewModel.cs +++ b/Saradomin/ViewModel/Windows/MainWindowViewModel.cs @@ -25,9 +25,6 @@ namespace Saradomin.ViewModel.Windows private readonly IRemoteConfigService _remoteConfigService; private readonly ISettingsService _settingsService; - private bool JavaExecutableValid - => CrossPlatform.IsJavaExecutableValid(_settingsService.Launcher.JavaExecutableLocation); - private LauncherSettings Launcher { get; } public string Title { get; set; } = "2009scape launcher"; @@ -50,9 +47,7 @@ namespace Saradomin.ViewModel.Windows _remoteConfigService = remoteConfigService; _javaUpdateService = javaUpdateService; _javaUpdateService.JavaDownloadProgressChanged += OnJavaDownloadProgressUpdated; - - _settingsService = settingsService; Launcher = _settingsService.Launcher; @@ -62,13 +57,9 @@ namespace Saradomin.ViewModel.Windows }; Message.Subscribe(this, MainViewLoaded); - Message.Subscribe(this, SettingsModified); Message.Subscribe(this, NotificatationBoxStateChanged); - if (!JavaExecutableValid) - { - _settingsService.Launcher.JavaExecutableLocation = CrossPlatform.LocateJavaExecutable(); - } + _settingsService.Launcher.JavaExecutableLocation ??= CrossPlatform.LocateJavaExecutable(); } public void ExitApplication() @@ -102,23 +93,6 @@ namespace Saradomin.ViewModel.Windows } } - public void SettingsModified(SettingsModifiedMessage msg) - { - if (msg.SettingName == nameof(LauncherSettings.JavaExecutableLocation)) - { - if (!JavaExecutableValid) - { - CanLaunch = false; - LaunchText = "Unable to locate Java. Find Java executable using Settings page."; - } - else - { - CanLaunch = true; - LaunchText = "Play!"; - } - } - } - public void NotificatationBoxStateChanged(NotificationBoxStateChangedMessage msg) { DimContent = msg.WasOpened;