From a620cbcc9050d7d3b0932d97db87628dd4e97b0a Mon Sep 17 00:00:00 2001 From: Isaac Marovitz <42140194+IsaacMarovitz@users.noreply.github.com> Date: Fri, 26 Jan 2024 14:25:48 +0000 Subject: [PATCH] Ava UI: Mod Manager Fixes (#6179) * Fix string format + Crash * Better Logging * Properly Delete Mods Rename * Catch when trying to access bad directory --- src/Ryujinx.Ava/Assets/Locales/en_US.json | 2 + .../UI/ViewModels/ModManagerViewModel.cs | 70 +++++++++++++++++-- src/Ryujinx.HLE/HOS/ModLoader.cs | 2 +- 3 files changed, 69 insertions(+), 5 deletions(-) diff --git a/src/Ryujinx.Ava/Assets/Locales/en_US.json b/src/Ryujinx.Ava/Assets/Locales/en_US.json index 79692a08c..8b38490f7 100644 --- a/src/Ryujinx.Ava/Assets/Locales/en_US.json +++ b/src/Ryujinx.Ava/Assets/Locales/en_US.json @@ -383,6 +383,8 @@ "DialogControllerSettingsModifiedConfirmSubMessage": "Do you want to save?", "DialogLoadFileErrorMessage": "{0}. Errored File: {1}", "DialogModAlreadyExistsMessage": "Mod already exists", + "DialogModInvalidMessage": "The specified directory does not contain a mod!", + "DialogModDeleteNoParentMessage": "Failed to Delete: Could not find the parent directory for mod \"{0}\"!", "DialogDlcNoDlcErrorMessage": "The specified file does not contain a DLC for the selected title!", "DialogPerformanceCheckLoggingEnabledMessage": "You have trace logging enabled, which is designed to be used by developers only.", "DialogPerformanceCheckLoggingEnabledConfirmMessage": "For optimal performance, it's recommended to disable trace logging. Would you like to disable trace logging now?", diff --git a/src/Ryujinx.Ava/UI/ViewModels/ModManagerViewModel.cs b/src/Ryujinx.Ava/UI/ViewModels/ModManagerViewModel.cs index 7340873ae..2c29660bf 100644 --- a/src/Ryujinx.Ava/UI/ViewModels/ModManagerViewModel.cs +++ b/src/Ryujinx.Ava/UI/ViewModels/ModManagerViewModel.cs @@ -8,8 +8,10 @@ using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.Models; using Ryujinx.Common.Configuration; +using Ryujinx.Common.Logging; using Ryujinx.Common.Utilities; using Ryujinx.HLE.HOS; +using System; using System.IO; using System.Linq; @@ -181,7 +183,30 @@ namespace Ryujinx.Ava.UI.ViewModels public void Delete(ModModel model) { - Directory.Delete(model.Path, true); + var modsDir = ModLoader.GetApplicationDir(ModLoader.GetSdModsBasePath(), _applicationId.ToString("x16")); + var parentDir = String.Empty; + + foreach (var dir in Directory.GetDirectories(modsDir, "*", SearchOption.TopDirectoryOnly)) + { + if (Directory.GetDirectories(dir, "*", SearchOption.AllDirectories).Contains(model.Path)) + { + parentDir = dir; + } + } + + if (parentDir == String.Empty) + { + Dispatcher.UIThread.Post(async () => + { + await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue( + LocaleKeys.DialogModDeleteNoParentMessage, + parentDir)); + }); + return; + } + + Logger.Info?.Print(LogClass.Application, $"Deleting mod at \"{model.Path}\""); + Directory.Delete(parentDir, true); Mods.Remove(model); OnPropertyChanged(nameof(ModCount)); @@ -190,9 +215,43 @@ namespace Ryujinx.Ava.UI.ViewModels private void AddMod(DirectoryInfo directory) { - var directories = Directory.GetDirectories(directory.ToString(), "*", SearchOption.AllDirectories); + string[] directories; + + try + { + directories = Directory.GetDirectories(directory.ToString(), "*", SearchOption.AllDirectories); + } + catch (Exception exception) + { + Dispatcher.UIThread.Post(async () => + { + await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue( + LocaleKeys.DialogLoadFileErrorMessage, + exception.ToString(), + directory)); + }); + return; + } + var destinationDir = ModLoader.GetApplicationDir(ModLoader.GetSdModsBasePath(), _applicationId.ToString("x16")); + // TODO: More robust checking for valid mod folders + var isDirectoryValid = true; + + if (directories.Length == 0) + { + isDirectoryValid = false; + } + + if (!isDirectoryValid) + { + Dispatcher.UIThread.Post(async () => + { + await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogModInvalidMessage]); + }); + return; + } + foreach (var dir in directories) { string dirToCreate = dir.Replace(directory.Parent.ToString(), destinationDir); @@ -202,7 +261,10 @@ namespace Ryujinx.Ava.UI.ViewModels { Dispatcher.UIThread.Post(async () => { - await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogLoadFileErrorMessage, LocaleKeys.DialogModAlreadyExistsMessage, dirToCreate)); + await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance.UpdateAndGetDynamicValue( + LocaleKeys.DialogLoadFileErrorMessage, + LocaleManager.Instance[LocaleKeys.DialogModAlreadyExistsMessage], + dirToCreate)); }); return; @@ -239,7 +301,7 @@ namespace Ryujinx.Ava.UI.ViewModels { foreach (var mod in Mods) { - Directory.Delete(mod.Path, true); + Delete(mod); } Mods.Clear(); diff --git a/src/Ryujinx.HLE/HOS/ModLoader.cs b/src/Ryujinx.HLE/HOS/ModLoader.cs index 669c775b7..322c8afdc 100644 --- a/src/Ryujinx.HLE/HOS/ModLoader.cs +++ b/src/Ryujinx.HLE/HOS/ModLoader.cs @@ -324,7 +324,7 @@ namespace Ryujinx.HLE.HOS return; } - Logger.Info?.Print(LogClass.ModLoader, $"Searching mods for {((applicationId & 0x1000) != 0 ? "DLC" : "Application")} {applicationId:X16}"); + Logger.Info?.Print(LogClass.ModLoader, $"Searching mods for {((applicationId & 0x1000) != 0 ? "DLC" : "Application")} {applicationId:X16} in \"{contentsDir.FullName}\""); var applicationDir = FindApplicationDir(contentsDir, $"{applicationId:x16}");