From 14523e91d4dc48452a6832735ced19b307f1a219 Mon Sep 17 00:00:00 2001 From: slxdy Date: Tue, 19 Nov 2024 20:24:05 +0100 Subject: [PATCH] Added Linux launch instructions --- MelonLoader.Installer/App.axaml | 3 ++ MelonLoader.Installer/MLManager.cs | 37 +++++-------- MelonLoader.Installer/Program.cs | 25 +++------ .../ViewModels/DetailsViewModel.cs | 11 ++++ MelonLoader.Installer/ViewModels/GameModel.cs | 3 +- MelonLoader.Installer/Views/DetailsView.axaml | 31 +++++++++-- .../Views/DetailsView.axaml.cs | 53 ++++++++++++++----- MelonLoader.Installer/Views/MainView.axaml.cs | 2 + 8 files changed, 106 insertions(+), 59 deletions(-) diff --git a/MelonLoader.Installer/App.axaml b/MelonLoader.Installer/App.axaml index ed21c5e..61619ab 100644 --- a/MelonLoader.Installer/App.axaml +++ b/MelonLoader.Installer/App.axaml @@ -18,5 +18,8 @@ + \ No newline at end of file diff --git a/MelonLoader.Installer/MLManager.cs b/MelonLoader.Installer/MLManager.cs index d8c5499..2788b32 100644 --- a/MelonLoader.Installer/MLManager.cs +++ b/MelonLoader.Installer/MLManager.cs @@ -168,12 +168,11 @@ private static async Task GetVersionsAsync(List versions) return true; } - public static bool Uninstall(string gameDir, bool removeUserFiles, [NotNullWhen(false)] out string? errorMessage) + public static string? Uninstall(string gameDir, bool removeUserFiles) { if (!Directory.Exists(gameDir)) { - errorMessage = "The provided directory does not exist."; - return false; + return "The provided directory does not exist."; } foreach (var proxy in proxyNames) @@ -194,8 +193,7 @@ public static bool Uninstall(string gameDir, bool removeUserFiles, [NotNullWhen( } catch { - errorMessage = "Failed to uninstall MelonLoader. Ensure that the game is fully closed before trying again."; - return false; + return "Failed to uninstall MelonLoader. Ensure that the game is fully closed before trying again."; } } @@ -208,8 +206,7 @@ public static bool Uninstall(string gameDir, bool removeUserFiles, [NotNullWhen( } catch { - errorMessage = "Failed to uninstall MelonLoader. Ensure that the game is fully closed before trying again."; - return false; + return "Failed to uninstall MelonLoader. Ensure that the game is fully closed before trying again."; } } @@ -222,8 +219,7 @@ public static bool Uninstall(string gameDir, bool removeUserFiles, [NotNullWhen( } catch { - errorMessage = $"Failed to fully uninstall MelonLoader: Failed to remove dobby."; - return false; + return "Failed to fully uninstall MelonLoader: Failed to remove dobby."; } } @@ -236,8 +232,7 @@ public static bool Uninstall(string gameDir, bool removeUserFiles, [NotNullWhen( } catch { - errorMessage = $"Failed to fully uninstall MelonLoader: Failed to remove 'NOTICE.txt'."; - return false; + return "Failed to fully uninstall MelonLoader: Failed to remove 'NOTICE.txt'."; } } @@ -252,8 +247,7 @@ public static bool Uninstall(string gameDir, bool removeUserFiles, [NotNullWhen( } catch { - errorMessage = $"Failed to fully uninstall MelonLoader: Failed to remove the Mods folder."; - return false; + return "Failed to fully uninstall MelonLoader: Failed to remove the Mods folder."; } } @@ -266,8 +260,7 @@ public static bool Uninstall(string gameDir, bool removeUserFiles, [NotNullWhen( } catch { - errorMessage = $"Failed to fully uninstall MelonLoader: Failed to remove the Plugins folder."; - return false; + return "Failed to fully uninstall MelonLoader: Failed to remove the Plugins folder."; } } @@ -280,8 +273,7 @@ public static bool Uninstall(string gameDir, bool removeUserFiles, [NotNullWhen( } catch { - errorMessage = $"Failed to fully uninstall MelonLoader: Failed to remove the UserData folder."; - return false; + return "Failed to fully uninstall MelonLoader: Failed to remove the UserData folder."; } } @@ -294,14 +286,12 @@ public static bool Uninstall(string gameDir, bool removeUserFiles, [NotNullWhen( } catch { - errorMessage = $"Failed to fully uninstall MelonLoader: Failed to remove the UserLibs folder."; - return false; + return "Failed to fully uninstall MelonLoader: Failed to remove the UserLibs folder."; } } } - errorMessage = null; - return true; + return null; } public static void SetLocalZip(string zipPath, InstallProgressEventHandler? onProgress, InstallFinishedEventHandler? onFinished) @@ -372,9 +362,10 @@ public static async Task InstallAsync(string gameDir, bool removeUserFiles, MLVe onProgress?.Invoke(0, "Uninstalling previous versions"); - if (!Uninstall(gameDir, removeUserFiles, out var error)) + var unErr = Uninstall(gameDir, removeUserFiles); + if (unErr != null) { - onFinished?.Invoke(error); + onFinished?.Invoke(unErr); return; } diff --git a/MelonLoader.Installer/Program.cs b/MelonLoader.Installer/Program.cs index cdd2c98..6990b2f 100644 --- a/MelonLoader.Installer/Program.cs +++ b/MelonLoader.Installer/Program.cs @@ -21,8 +21,6 @@ internal static class Program [STAThread] private static void Main(string[] args) { - SetupCrashLogging(); - if (!Directory.Exists(Config.CacheDir)) Directory.CreateDirectory(Config.CacheDir); @@ -53,7 +51,14 @@ private static void Main(string[] args) Updater.UpdateIfPossible(); - BuildAvaloniaApp().StartWithClassicDesktopLifetime(args); + try + { + BuildAvaloniaApp().StartWithClassicDesktopLifetime(args); + } + catch (Exception ex) + { + LogCrashException(ex); + } Exiting?.Invoke(); @@ -61,20 +66,6 @@ private static void Main(string[] args) File.Delete(processLockPath); } - private static void SetupCrashLogging() - { - AppDomain.CurrentDomain.UnhandledException += OnUnhandledException; - } - - private static void OnUnhandledException(object sender, UnhandledExceptionEventArgs e) - { - if (!e.IsTerminating) - return; - - if (e.ExceptionObject is Exception ex and not TaskCanceledException) - LogCrashException(ex); - } - public static void LogCrashException(Exception ex) { try diff --git a/MelonLoader.Installer/ViewModels/DetailsViewModel.cs b/MelonLoader.Installer/ViewModels/DetailsViewModel.cs index 0520f4b..33a5a13 100644 --- a/MelonLoader.Installer/ViewModels/DetailsViewModel.cs +++ b/MelonLoader.Installer/ViewModels/DetailsViewModel.cs @@ -4,6 +4,7 @@ public class DetailsViewModel(GameModel game) : ViewModelBase { private bool _installing; private bool _offline; + private bool _linuxInstructions; public GameModel Game => game; @@ -29,5 +30,15 @@ public bool Offline } } + public bool LinuxInstructions + { + get => _linuxInstructions; + set + { + _linuxInstructions = value; + OnPropertyChanged(); + } + } + public bool EnableSettings => !Offline && !Installing; } diff --git a/MelonLoader.Installer/ViewModels/GameModel.cs b/MelonLoader.Installer/ViewModels/GameModel.cs index 7726b02..1bfd0b3 100644 --- a/MelonLoader.Installer/ViewModels/GameModel.cs +++ b/MelonLoader.Installer/ViewModels/GameModel.cs @@ -16,6 +16,7 @@ public class GameModel(string path, string name, bool is32Bit, bool isLinux, Gam public string MLStatusText => mlVersion == null ? "Not Installed" : "Installed " + MLVersionText; public bool MLInstalled => mlVersion != null; public bool IsProtected => isProtected; + public string Dir { get; } = System.IO.Path.GetDirectoryName(path)!; public SemVersion? MLVersion { @@ -46,7 +47,7 @@ public bool ValidateGame() return false; } - var newMlVersion = Installer.MLVersion.GetMelonLoaderVersion(System.IO.Path.GetDirectoryName(path)!, out var ml86, out var mlLinux); + var newMlVersion = Installer.MLVersion.GetMelonLoaderVersion(Dir, out var ml86, out var mlLinux); if (newMlVersion != null && (ml86 != Is32Bit || mlLinux != IsLinux)) newMlVersion = null; diff --git a/MelonLoader.Installer/Views/DetailsView.axaml b/MelonLoader.Installer/Views/DetailsView.axaml index 1d799e3..9ca50bb 100644 --- a/MelonLoader.Installer/Views/DetailsView.axaml +++ b/MelonLoader.Installer/Views/DetailsView.axaml @@ -6,17 +6,19 @@ mc:Ignorable="d" d:DesignWidth="450" d:DesignHeight="650" x:Class="MelonLoader.Installer.Views.DetailsView" x:DataType="vm:DetailsViewModel"> - + @@ -56,5 +58,26 @@ VerticalAlignment="Center" Opacity="0.7" FontSize="14" /> + + + How do I start MelonLoader? + + + + Linux Launch Instructions + + In order to start MelonLoader under Wine, you'll need to export the following variable: + WINEDLLOVERRIDES="version=n,b" + On Steam, you can set the launch options to: + WINEDLLOVERRIDES="version=n,b" %command%" + + + In order to start MelonLoader, you'll need to export the following variables: + + LD_PRELOAD="libversion.so" + On Steam, you can set the launch options to: + + + \ No newline at end of file diff --git a/MelonLoader.Installer/Views/DetailsView.axaml.cs b/MelonLoader.Installer/Views/DetailsView.axaml.cs index 52cd525..2112d3a 100644 --- a/MelonLoader.Installer/Views/DetailsView.axaml.cs +++ b/MelonLoader.Installer/Views/DetailsView.axaml.cs @@ -41,6 +41,16 @@ protected override void OnDataContextChanged(EventArgs e) if (Model == null) return; + +#if LINUX + if (Model.Game.IsLinux) + { + LdLibPathVar.Text = $"LD_LIBRARY_PATH=\"{Model.Game.Dir}:$LD_LIBRARY_PATH\""; + SteamLaunchOptions.Text = $"{LdLibPathVar.Text} {LdPreloadVar.Text} %command%"; + } + + ShowLinuxInstructions.IsVisible = Model.Game.MLInstalled; +#endif Model.Game.PropertyChanged += PropertyChangedHandler; @@ -73,7 +83,16 @@ public void UpdateVersionList() private void BackClickHandler(object sender, RoutedEventArgs args) { - if (Model is { Installing: true }) + if (Model == null) + return; + + if (Model.LinuxInstructions) + { + Model.LinuxInstructions = false; + return; + } + + if (Model.Installing) return; MainWindow.Instance.ShowMainView(); @@ -116,6 +135,7 @@ private void InstallHandler(object sender, RoutedEventArgs args) } Model.Installing = true; + ShowLinuxInstructions.IsVisible = false; _ = MLManager.InstallAsync(Path.GetDirectoryName(Model.Game.Path)!, Model.Game.MLInstalled && !KeepFilesCheck.IsChecked!.Value, (MLVersion)VersionCombobox.SelectedItem!, Model.Game.IsLinux, Model.Game.Is32Bit, @@ -139,10 +159,12 @@ private void OnInstallFinished(string? errorMessage) var wasReinstall = Model.Game.MLInstalled; Model.Game.ValidateGame(); + +#if LINUX + ShowLinuxInstructions.IsVisible = Model.Game.MLInstalled; +#endif Model.Installing = false; - NightlyCheck.IsEnabled = true; - VersionCombobox.IsEnabled = true; if (errorMessage != null) { @@ -150,7 +172,7 @@ private void OnInstallFinished(string? errorMessage) return; } - DialogBox.ShowNotice("Success!", $"{(wasReinstall ? "Reinstall" : "Install")} was Successful!"); + DialogBox.ShowNotice("Success!", $"Successfully {(Model.Game.MLInstalled ? (wasReinstall ? "reinstalled" : "installed") : "uninstalled")} MelonLoader!"); } private void OpenDirHandler(object sender, RoutedEventArgs args) @@ -158,7 +180,7 @@ private void OpenDirHandler(object sender, RoutedEventArgs args) if (Model == null) return; - TopLevel.GetTopLevel(this)!.Launcher.LaunchDirectoryInfoAsync(new(Path.GetDirectoryName(Model.Game.Path)!)); + TopLevel.GetTopLevel(this)!.Launcher.LaunchDirectoryInfoAsync(new(Model.Game.Dir)); } private void UninstallHandler(object sender, RoutedEventArgs args) @@ -172,15 +194,9 @@ private void UninstallHandler(object sender, RoutedEventArgs args) if (!Model.Game.MLInstalled) return; - if (!MLManager.Uninstall(Path.GetDirectoryName(Model.Game.Path)!, !KeepFilesCheck.IsChecked!.Value, out var error)) - { - DialogBox.ShowError(error); - Model.Game.ValidateGame(); - return; - } - - Model.Game.ValidateGame(); - DialogBox.ShowNotice("Success!", "Uninstall was Successful!"); + var error = MLManager.Uninstall(Model.Game.Dir, !KeepFilesCheck.IsChecked!.Value); + + OnInstallFinished(error); } private async void SelectZipHandler(object sender, TappedEventArgs args) @@ -208,6 +224,7 @@ private async void SelectZipHandler(object sender, TappedEventArgs args) var path = files[0].Path.LocalPath; Model.Installing = true; + ShowLinuxInstructions.IsVisible = false; _ = Task.Run(() => MLManager.SetLocalZip(path, (progress, newStatus) => Dispatcher.UIThread.Post(() => OnInstallProgress(progress, newStatus)), @@ -226,4 +243,12 @@ private async void SelectZipHandler(object sender, TappedEventArgs args) UpdateVersionList(); }))); } + + private void ShowLinuxInstructionsHandler(object sender, TappedEventArgs args) + { + if (Model == null) + return; + + Model.LinuxInstructions = true; + } } \ No newline at end of file diff --git a/MelonLoader.Installer/Views/MainView.axaml.cs b/MelonLoader.Installer/Views/MainView.axaml.cs index c33029e..bcd30af 100644 --- a/MelonLoader.Installer/Views/MainView.axaml.cs +++ b/MelonLoader.Installer/Views/MainView.axaml.cs @@ -22,6 +22,8 @@ protected override void OnDataContextChanged(EventArgs e) if (Model == null) return; + Model.Ready = false; + Task.Run(InitServicesAsync); }