From 4c87269dee8b525bac8c1c96ea16168d8c35d965 Mon Sep 17 00:00:00 2001 From: TheBestAstroNOT <139786546+TheBestAstroNOT@users.noreply.github.com> Date: Thu, 11 Dec 2025 00:43:20 +0530 Subject: [PATCH 01/15] Prompt user to select supported applications for a mod in the case where no compatible applications are found --- .../Static/Resources.cs | 9 +++- .../Assets/Languages/en-GB.xaml | 7 ++++ .../Reloaded.Mod.Launcher/MainWindow.xaml.cs | 42 +++++++++++++++++++ 3 files changed, 57 insertions(+), 1 deletion(-) diff --git a/source/Reloaded.Mod.Launcher.Lib/Static/Resources.cs b/source/Reloaded.Mod.Launcher.Lib/Static/Resources.cs index 00014d0b..0da55e26 100644 --- a/source/Reloaded.Mod.Launcher.Lib/Static/Resources.cs +++ b/source/Reloaded.Mod.Launcher.Lib/Static/Resources.cs @@ -220,9 +220,16 @@ public static void Init(IDictionaryResourceProvider provider) public static IDictionaryResource ErrorStacktraceTitle { get; set; } public static IDictionaryResource ErrorStacktraceSubtitle { get; set; } - // Update 1.X.X: New Progress Window for Local Mod Installation (UPDATE LAUNCHER VER BEFORE RELEASE) + // Update 1.29.3: New Progress Window for Local Mod Installation public static IDictionaryResource InstallModArchiveTitle { get; set; } public static IDictionaryResource InstalledModName { get; set; } public static IDictionaryResource InstallingModWait { get; set; } public static IDictionaryResource ExtractingLocalModArchive { get; set; } + + // Update 1.XX.XX: Add warning during installation of mods with no apps in their supported apps list or when no compatible app is installed (UPDATE LAUNCHER VER BEFORE RELEASE) + public static IDictionaryResource NoAppsInConfigTitle { get; set; } + public static IDictionaryResource NoAppsInConfigDescription { get; set; } + public static IDictionaryResource NoCompatibleAppsInConfigTitle { get; set; } + public static IDictionaryResource NoCompatibleAppsInConfigDescription { get; set; } + public static IDictionaryResource AppSelectionQuestion { get; set; } } \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher/Assets/Languages/en-GB.xaml b/source/Reloaded.Mod.Launcher/Assets/Languages/en-GB.xaml index 7318188a..e367a88f 100644 --- a/source/Reloaded.Mod.Launcher/Assets/Languages/en-GB.xaml +++ b/source/Reloaded.Mod.Launcher/Assets/Languages/en-GB.xaml @@ -203,6 +203,13 @@ Mod Name Please wait while we install the mod! Extracting a local mod, please wait! + + + Unable to find any supported app + Reloaded-II was unable to find any supported apps in the mod's config. + Unable to find a compatible app + Reloaded-II was unable to find an installed app which is compatible with this mod. + Do you want to select a supported app manually? You need to run this application as administrator. Administrative privileges are needed to receive application launch/exit events from Windows Management Instrumentation (WMI). Developers: Run your favourite IDE e.g. Visual Studio as Admin. diff --git a/source/Reloaded.Mod.Launcher/MainWindow.xaml.cs b/source/Reloaded.Mod.Launcher/MainWindow.xaml.cs index 1bb80223..5563c654 100644 --- a/source/Reloaded.Mod.Launcher/MainWindow.xaml.cs +++ b/source/Reloaded.Mod.Launcher/MainWindow.xaml.cs @@ -1,4 +1,5 @@ using NuGet.Common; +using Reloaded.Mod.Launcher.Pages.BaseSubpages.Dialogs; using Reloaded.Mod.Loader.Update.Providers.Web; using Sewer56.DeltaPatchGenerator.Lib.Utility; using Sewer56.Update.Extractors.SevenZipSharp; @@ -132,7 +133,48 @@ private async void InstallMod_Drop(object sender, DragEventArgs e) foreach (var item in modConfigService.ItemsById.ToArray()) { if (!modsBefore.ContainsKey(item.Key)) + { newConfigs.Add(item.Value.Config); + if(item.Value.Config.IsUniversalMod || item.Value.Config.SupportedAppId.Length > 0) + { + var match = Lib.IoC.Get().Items.FirstOrDefault(app => item.Value.Config.SupportedAppId.Contains(app.Config.AppId)); + if(match == null) + { + bool loadAppPage = Actions.DisplayMessagebox!.Invoke( + NoCompatibleAppsInConfigTitle.Get(), + $"{NoCompatibleAppsInConfigDescription.Get()}\n{AppSelectionQuestion.Get()}", + new Actions.DisplayMessageBoxParams + { + Type = Actions.MessageBoxType.OkCancel + }); + if (loadAppPage) + { + var createModDialog = new EditModDialog(new EditModDialogViewModel(item.Value, Lib.IoC.Get(), modConfigService)); + createModDialog.Owner = System.Windows.Window.GetWindow(this); + createModDialog.RealViewModel.Page = EditModPage.Special; + createModDialog.ShowDialog(); + } + } + } + else + { + bool loadAppPage = Actions.DisplayMessagebox!.Invoke( + NoAppsInConfigTitle.Get(), $"{NoAppsInConfigDescription.Get()}\n{AppSelectionQuestion.Get()}" + , + new Actions.DisplayMessageBoxParams + { + Type = Actions.MessageBoxType.OkCancel + }); + if (loadAppPage) + { + var createModDialog = new EditModDialog(new EditModDialogViewModel(item.Value, Lib.IoC.Get(), modConfigService)); + createModDialog.Owner = System.Windows.Window.GetWindow(this); + createModDialog.RealViewModel.Page = EditModPage.Special; + createModDialog.ShowDialog(); + } + } + } + } if (newConfigs.Count <= 0) From 7f88eee9d0e8b3714f41088e7121889752dd73e7 Mon Sep 17 00:00:00 2001 From: TheBestAstroNOT <139786546+TheBestAstroNOT@users.noreply.github.com> Date: Thu, 11 Dec 2025 01:09:45 +0530 Subject: [PATCH 02/15] Web downloads most likely work now --- .../Commands/Mod/EditModCommand.cs | 2 +- .../Dialog/EditModDialogViewModel.cs | 8 +-- source/Reloaded.Mod.Launcher.Lib/Startup.cs | 60 +++++++++++++++++++ .../Reloaded.Mod.Launcher/MainWindow.xaml.cs | 4 +- .../Dialogs/CreateModDialog.xaml.cs | 2 +- 5 files changed, 67 insertions(+), 9 deletions(-) diff --git a/source/Reloaded.Mod.Launcher.Lib/Commands/Mod/EditModCommand.cs b/source/Reloaded.Mod.Launcher.Lib/Commands/Mod/EditModCommand.cs index 7098ca18..65189c27 100644 --- a/source/Reloaded.Mod.Launcher.Lib/Commands/Mod/EditModCommand.cs +++ b/source/Reloaded.Mod.Launcher.Lib/Commands/Mod/EditModCommand.cs @@ -23,5 +23,5 @@ public EditModCommand(PathTuple? modTuple, object? parent) public bool CanExecute(object? parameter) => _modTuple != null; /// - public void Execute(object? parameter) => Actions.EditModDialog(new EditModDialogViewModel(_modTuple!, IoC.Get(), IoC.Get()), _parent); + public void Execute(object? parameter) => Actions.EditModDialog(new EditModDialogViewModel(_modTuple!, IoC.Get().Items, IoC.Get().Items), _parent); } \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher.Lib/Models/ViewModel/Dialog/EditModDialogViewModel.cs b/source/Reloaded.Mod.Launcher.Lib/Models/ViewModel/Dialog/EditModDialogViewModel.cs index df7097a0..41cf46d2 100644 --- a/source/Reloaded.Mod.Launcher.Lib/Models/ViewModel/Dialog/EditModDialogViewModel.cs +++ b/source/Reloaded.Mod.Launcher.Lib/Models/ViewModel/Dialog/EditModDialogViewModel.cs @@ -67,14 +67,12 @@ public class EditModDialogViewModel : ObservableObject, IDisposable /// public ObservableCollection Updates { get; set; } = new ObservableCollection(); - private readonly ApplicationConfigService _applicationConfigService; private SetModImageCommand _setModImageCommand; private Action? _close; /// - public EditModDialogViewModel(PathTuple modTuple, ApplicationConfigService applicationConfigService, ModConfigService modConfigService) + public EditModDialogViewModel(PathTuple modTuple, ObservableCollection> appItems, ObservableCollection> modsItems) { - _applicationConfigService = applicationConfigService; ConfigTuple = modTuple; Config = modTuple.Config; @@ -82,7 +80,7 @@ public EditModDialogViewModel(PathTuple modTuple, ApplicationConfigSe Tags.AddRange(Config.Tags); // Add Known Apps - var apps = applicationConfigService.Items; + var apps = appItems; foreach (var app in apps) { bool isAppEnabled = modTuple.Config.SupportedAppId.Contains(app.Config.AppId, StringComparer.OrdinalIgnoreCase); @@ -90,7 +88,7 @@ public EditModDialogViewModel(PathTuple modTuple, ApplicationConfigSe } // Build Dependencies - var mods = modConfigService.Items; // In case collection changes during window open. + var mods = modsItems; // In case collection changes during window open. foreach (var mod in mods) { bool isModEnabled = modTuple.Config.ModDependencies.Contains(mod.Config.ModId, StringComparer.OrdinalIgnoreCase); diff --git a/source/Reloaded.Mod.Launcher.Lib/Startup.cs b/source/Reloaded.Mod.Launcher.Lib/Startup.cs index 091edd40..64feb6bc 100644 --- a/source/Reloaded.Mod.Launcher.Lib/Startup.cs +++ b/source/Reloaded.Mod.Launcher.Lib/Startup.cs @@ -110,6 +110,17 @@ private static void LaunchApplicationAndExit(string applicationToLaunch, bool fo [MethodImpl(MethodImplOptions.NoInlining)] private static void DownloadModAndExit(string downloadUrl) { + var loaderConfig = IoC.Get(); + var modConfigDir = loaderConfig.GetModConfigDirectory(); + var modConfig = ModConfig.GetAllMods(modConfigDir); + var allAppsList = ApplicationConfig.GetAllApplications(loaderConfig.GetApplicationConfigDirectory()); + var allApps = new ObservableCollection>(allAppsList); + var oldItemsById = modConfig.ToDictionary( + x => x.Config.ModId, + x => x, + StringComparer.OrdinalIgnoreCase + ); + if (downloadUrl.StartsWith($"{Constants.ReloadedProtocol}:", StringComparison.InvariantCultureIgnoreCase)) downloadUrl = downloadUrl.Substring(Constants.ReloadedProtocol.Length + 1); @@ -119,6 +130,55 @@ private static void DownloadModAndExit(string downloadUrl) Actions.ShowFetchPackageDialog(viewModel); Update.ResolveMissingPackages(); + + modConfig = ModConfig.GetAllMods(modConfigDir); + var itemsById = modConfig.ToDictionary(x => x.Config.ModId, x => x, StringComparer.OrdinalIgnoreCase); + var items = new ObservableCollection>(modConfig); + foreach (var item in itemsById.ToArray()) + { + if (!oldItemsById.ContainsKey(item.Key)) + { + if (item.Value.Config.IsUniversalMod || item.Value.Config.SupportedAppId.Length > 0) + { + var match = IoC.Get().Items.FirstOrDefault(app => item.Value.Config.SupportedAppId.Contains(app.Config.AppId)); + if (match == null) + { + bool loadAppPage = Actions.DisplayMessagebox( + Resources.NoCompatibleAppsInConfigTitle.Get(), + $"{Resources.NoCompatibleAppsInConfigDescription.Get()}\n{Resources.AppSelectionQuestion.Get()}", + new Actions.DisplayMessageBoxParams + { + Type = Actions.MessageBoxType.OkCancel, + StartupLocation = Actions.WindowStartupLocation.CenterScreen + }); + if (loadAppPage) + { + var viewmodel = new EditModDialogViewModel(item.Value, allApps, items); + viewmodel.Page = EditModPage.Special; + var createModDialog = Actions.EditModDialog(viewmodel, null); + } + } + } + else + { + bool loadAppPage = Actions.DisplayMessagebox( + Resources.NoAppsInConfigTitle.Get(), + $"{Resources.NoAppsInConfigDescription.Get()}\n{Resources.AppSelectionQuestion.Get()}", + new Actions.DisplayMessageBoxParams + { + Type = Actions.MessageBoxType.OkCancel + }); + if (loadAppPage) + { + var viewmodel = new EditModDialogViewModel(item.Value, allApps, items); + viewmodel.Page = EditModPage.Special; + var createModDialog = Actions.EditModDialog(viewmodel, null); + } + } + } + + } + Actions.DisplayMessagebox(Resources.PackageDownloaderDownloadCompleteTitle.Get(), Resources.PackageDownloaderDownloadCompleteDescription.Get(), new Actions.DisplayMessageBoxParams() { Type = Actions.MessageBoxType.Ok, diff --git a/source/Reloaded.Mod.Launcher/MainWindow.xaml.cs b/source/Reloaded.Mod.Launcher/MainWindow.xaml.cs index 5563c654..993aa1ce 100644 --- a/source/Reloaded.Mod.Launcher/MainWindow.xaml.cs +++ b/source/Reloaded.Mod.Launcher/MainWindow.xaml.cs @@ -149,7 +149,7 @@ private async void InstallMod_Drop(object sender, DragEventArgs e) }); if (loadAppPage) { - var createModDialog = new EditModDialog(new EditModDialogViewModel(item.Value, Lib.IoC.Get(), modConfigService)); + var createModDialog = new EditModDialog(new EditModDialogViewModel(item.Value, Lib.IoC.Get().Items, modConfigService.Items)); createModDialog.Owner = System.Windows.Window.GetWindow(this); createModDialog.RealViewModel.Page = EditModPage.Special; createModDialog.ShowDialog(); @@ -167,7 +167,7 @@ private async void InstallMod_Drop(object sender, DragEventArgs e) }); if (loadAppPage) { - var createModDialog = new EditModDialog(new EditModDialogViewModel(item.Value, Lib.IoC.Get(), modConfigService)); + var createModDialog = new EditModDialog(new EditModDialogViewModel(item.Value, Lib.IoC.Get().Items, modConfigService.Items)); createModDialog.Owner = System.Windows.Window.GetWindow(this); createModDialog.RealViewModel.Page = EditModPage.Special; createModDialog.ShowDialog(); diff --git a/source/Reloaded.Mod.Launcher/Pages/BaseSubpages/Dialogs/CreateModDialog.xaml.cs b/source/Reloaded.Mod.Launcher/Pages/BaseSubpages/Dialogs/CreateModDialog.xaml.cs index 526922fa..43c0cbd9 100644 --- a/source/Reloaded.Mod.Launcher/Pages/BaseSubpages/Dialogs/CreateModDialog.xaml.cs +++ b/source/Reloaded.Mod.Launcher/Pages/BaseSubpages/Dialogs/CreateModDialog.xaml.cs @@ -26,7 +26,7 @@ public async Task Save() var mod = await ActionWrappers.TryGetValueAsync(() => modConfigService.ItemsById[createdMod.Config.ModId], 5000, 32); if (mod != null) { - var createModDialog = new EditModDialog(new EditModDialogViewModel(mod, Lib.IoC.Get(), modConfigService)); + var createModDialog = new EditModDialog(new EditModDialogViewModel(mod, Lib.IoC.Get().Items, modConfigService.Items)); createModDialog.Owner = Window.GetWindow(this); createModDialog.ShowDialog(); } From 76864cce6232680a3c1ab1142f2596a285751d0f Mon Sep 17 00:00:00 2001 From: TheBestAstroNOT <139786546+TheBestAstroNOT@users.noreply.github.com> Date: Thu, 11 Dec 2025 07:57:56 +0530 Subject: [PATCH 03/15] Update Resources.cs --- source/Reloaded.Mod.Launcher.Lib/Static/Resources.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/Reloaded.Mod.Launcher.Lib/Static/Resources.cs b/source/Reloaded.Mod.Launcher.Lib/Static/Resources.cs index 0da55e26..7fa35418 100644 --- a/source/Reloaded.Mod.Launcher.Lib/Static/Resources.cs +++ b/source/Reloaded.Mod.Launcher.Lib/Static/Resources.cs @@ -226,10 +226,10 @@ public static void Init(IDictionaryResourceProvider provider) public static IDictionaryResource InstallingModWait { get; set; } public static IDictionaryResource ExtractingLocalModArchive { get; set; } - // Update 1.XX.XX: Add warning during installation of mods with no apps in their supported apps list or when no compatible app is installed (UPDATE LAUNCHER VER BEFORE RELEASE) + // Update 1.XX.XX: Add warning during installation of mods with no apps in their supported apps list or when no compatible app is installed (UPDATE LAUNCHER VER BEFORE RELEASE). public static IDictionaryResource NoAppsInConfigTitle { get; set; } public static IDictionaryResource NoAppsInConfigDescription { get; set; } public static IDictionaryResource NoCompatibleAppsInConfigTitle { get; set; } public static IDictionaryResource NoCompatibleAppsInConfigDescription { get; set; } public static IDictionaryResource AppSelectionQuestion { get; set; } -} \ No newline at end of file +} From 6930137b1b4b2a4a433afbd57569fb3bd4e5c5b2 Mon Sep 17 00:00:00 2001 From: TheBestAstroNOT <139786546+TheBestAstroNOT@users.noreply.github.com> Date: Fri, 12 Dec 2025 22:06:20 +0530 Subject: [PATCH 04/15] Mod manager downloads probably work now, also changed OK/CANCEL to YES/NO --- .../ViewModel/DownloadPackagesViewModel.cs | 36 +++++++++++++++++++ source/Reloaded.Mod.Launcher.Lib/Startup.cs | 17 ++------- .../Static/Resources.cs | 2 ++ .../Assets/Languages/en-GB.xaml | 5 +++ .../Reloaded.Mod.Launcher/MainWindow.xaml.cs | 16 ++------- .../XamlResourceMessageBoxOkCancel.xaml.cs | 6 ++-- 6 files changed, 50 insertions(+), 32 deletions(-) diff --git a/source/Reloaded.Mod.Launcher.Lib/Models/ViewModel/DownloadPackagesViewModel.cs b/source/Reloaded.Mod.Launcher.Lib/Models/ViewModel/DownloadPackagesViewModel.cs index 4d946b2e..16bf6357 100644 --- a/source/Reloaded.Mod.Launcher.Lib/Models/ViewModel/DownloadPackagesViewModel.cs +++ b/source/Reloaded.Mod.Launcher.Lib/Models/ViewModel/DownloadPackagesViewModel.cs @@ -294,6 +294,8 @@ public void Execute(object? parameter) _viewModel.DownloadPackageStatus = DownloadPackageStatus.Downloading; try { + var modConfigService = IoC.GetConstant(); + var modsBefore = new Dictionary>(modConfigService.ItemsById); _canExecute = false; RaiseCanExecute(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); @@ -307,6 +309,40 @@ public void Execute(object? parameter) await Update.ResolveMissingPackagesAsync(); }); + modConfigService.ForceRefresh(); + var newConfigs = new List(); + foreach (var item in modConfigService.ItemsById.ToArray()) + { + if (!modsBefore.ContainsKey(item.Key)) + { + newConfigs.Add(item.Value.Config); + if (item.Value.Config.IsUniversalMod || item.Value.Config.SupportedAppId.Length > 0) + { + var match = IoC.Get().Items.FirstOrDefault(app => item.Value.Config.SupportedAppId.Contains(app.Config.AppId)); + if (match == null) + { + bool loadAppPage = Actions.DisplayResourceMessageBoxOkCancel!.Invoke(Resources.NoCompatibleAppsInConfigTitle.Get(), $"{Resources.NoCompatibleAppsInConfigDescription.Get()}\n{Resources.AppSelectionQuestion.Get()}", Resources.Yes.Get(), Resources.No.Get()); + if (loadAppPage) + { + var viewmodel = new EditModDialogViewModel(item.Value, IoC.Get().Items, modConfigService.Items); + viewmodel.Page = EditModPage.Special; + var createModDialog = Actions.EditModDialog(viewmodel, null); + } + } + } + else + { + bool loadAppPage = Actions.DisplayResourceMessageBoxOkCancel!.Invoke(Resources.NoAppsInConfigTitle.Get(), $"{Resources.NoAppsInConfigDescription.Get()}\n{Resources.AppSelectionQuestion.Get()}", Resources.Yes.Get(), Resources.No.Get()); + if (loadAppPage) + { + var viewmodel = new EditModDialogViewModel(item.Value, IoC.Get().Items, modConfigService.Items); + viewmodel.Page = EditModPage.Special; + var createModDialog = Actions.EditModDialog(viewmodel, null); + } + } + } + } + _canExecute = true; RaiseCanExecute(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); } diff --git a/source/Reloaded.Mod.Launcher.Lib/Startup.cs b/source/Reloaded.Mod.Launcher.Lib/Startup.cs index 64feb6bc..bd1dd4a2 100644 --- a/source/Reloaded.Mod.Launcher.Lib/Startup.cs +++ b/source/Reloaded.Mod.Launcher.Lib/Startup.cs @@ -143,14 +143,7 @@ private static void DownloadModAndExit(string downloadUrl) var match = IoC.Get().Items.FirstOrDefault(app => item.Value.Config.SupportedAppId.Contains(app.Config.AppId)); if (match == null) { - bool loadAppPage = Actions.DisplayMessagebox( - Resources.NoCompatibleAppsInConfigTitle.Get(), - $"{Resources.NoCompatibleAppsInConfigDescription.Get()}\n{Resources.AppSelectionQuestion.Get()}", - new Actions.DisplayMessageBoxParams - { - Type = Actions.MessageBoxType.OkCancel, - StartupLocation = Actions.WindowStartupLocation.CenterScreen - }); + bool loadAppPage = Actions.DisplayResourceMessageBoxOkCancel(Resources.NoCompatibleAppsInConfigTitle.Get(), $"{Resources.NoCompatibleAppsInConfigDescription.Get()}\n{Resources.AppSelectionQuestion.Get()}", Resources.Yes.Get(), Resources.No.Get()); if (loadAppPage) { var viewmodel = new EditModDialogViewModel(item.Value, allApps, items); @@ -161,13 +154,7 @@ private static void DownloadModAndExit(string downloadUrl) } else { - bool loadAppPage = Actions.DisplayMessagebox( - Resources.NoAppsInConfigTitle.Get(), - $"{Resources.NoAppsInConfigDescription.Get()}\n{Resources.AppSelectionQuestion.Get()}", - new Actions.DisplayMessageBoxParams - { - Type = Actions.MessageBoxType.OkCancel - }); + bool loadAppPage = Actions.DisplayResourceMessageBoxOkCancel(Resources.NoAppsInConfigTitle.Get(), $"{Resources.NoAppsInConfigDescription.Get()}\n{Resources.AppSelectionQuestion.Get()}", Resources.Yes.Get(), Resources.No.Get()); if (loadAppPage) { var viewmodel = new EditModDialogViewModel(item.Value, allApps, items); diff --git a/source/Reloaded.Mod.Launcher.Lib/Static/Resources.cs b/source/Reloaded.Mod.Launcher.Lib/Static/Resources.cs index 0da55e26..6324c881 100644 --- a/source/Reloaded.Mod.Launcher.Lib/Static/Resources.cs +++ b/source/Reloaded.Mod.Launcher.Lib/Static/Resources.cs @@ -232,4 +232,6 @@ public static void Init(IDictionaryResourceProvider provider) public static IDictionaryResource NoCompatibleAppsInConfigTitle { get; set; } public static IDictionaryResource NoCompatibleAppsInConfigDescription { get; set; } public static IDictionaryResource AppSelectionQuestion { get; set; } + public static IDictionaryResource Yes { get; set; } + public static IDictionaryResource No { get; set; } } \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher/Assets/Languages/en-GB.xaml b/source/Reloaded.Mod.Launcher/Assets/Languages/en-GB.xaml index e367a88f..6d2d8852 100644 --- a/source/Reloaded.Mod.Launcher/Assets/Languages/en-GB.xaml +++ b/source/Reloaded.Mod.Launcher/Assets/Languages/en-GB.xaml @@ -746,4 +746,9 @@ For more info, refer to the tutorial. Don't forget to set correct Publish target Please download the requirements above by using the button below. You may need administrator permissions. + + + Yes + No + \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher/MainWindow.xaml.cs b/source/Reloaded.Mod.Launcher/MainWindow.xaml.cs index 993aa1ce..626f5318 100644 --- a/source/Reloaded.Mod.Launcher/MainWindow.xaml.cs +++ b/source/Reloaded.Mod.Launcher/MainWindow.xaml.cs @@ -140,13 +140,7 @@ private async void InstallMod_Drop(object sender, DragEventArgs e) var match = Lib.IoC.Get().Items.FirstOrDefault(app => item.Value.Config.SupportedAppId.Contains(app.Config.AppId)); if(match == null) { - bool loadAppPage = Actions.DisplayMessagebox!.Invoke( - NoCompatibleAppsInConfigTitle.Get(), - $"{NoCompatibleAppsInConfigDescription.Get()}\n{AppSelectionQuestion.Get()}", - new Actions.DisplayMessageBoxParams - { - Type = Actions.MessageBoxType.OkCancel - }); + bool loadAppPage = Actions.DisplayResourceMessageBoxOkCancel!.Invoke(NoCompatibleAppsInConfigTitle.Get(), $"{NoCompatibleAppsInConfigDescription.Get()}\n{AppSelectionQuestion.Get()}", Yes.Get(), No.Get()); if (loadAppPage) { var createModDialog = new EditModDialog(new EditModDialogViewModel(item.Value, Lib.IoC.Get().Items, modConfigService.Items)); @@ -158,13 +152,7 @@ private async void InstallMod_Drop(object sender, DragEventArgs e) } else { - bool loadAppPage = Actions.DisplayMessagebox!.Invoke( - NoAppsInConfigTitle.Get(), $"{NoAppsInConfigDescription.Get()}\n{AppSelectionQuestion.Get()}" - , - new Actions.DisplayMessageBoxParams - { - Type = Actions.MessageBoxType.OkCancel - }); + bool loadAppPage = Actions.DisplayResourceMessageBoxOkCancel!.Invoke(NoAppsInConfigTitle.Get(), $"{NoAppsInConfigDescription.Get()}\n{AppSelectionQuestion.Get()}" , Yes.Get(), No.Get()); if (loadAppPage) { var createModDialog = new EditModDialog(new EditModDialogViewModel(item.Value, Lib.IoC.Get().Items, modConfigService.Items)); diff --git a/source/Reloaded.Mod.Launcher/Pages/Dialogs/XamlResourceMessageBoxOkCancel.xaml.cs b/source/Reloaded.Mod.Launcher/Pages/Dialogs/XamlResourceMessageBoxOkCancel.xaml.cs index 3c87b4af..5565b341 100644 --- a/source/Reloaded.Mod.Launcher/Pages/Dialogs/XamlResourceMessageBoxOkCancel.xaml.cs +++ b/source/Reloaded.Mod.Launcher/Pages/Dialogs/XamlResourceMessageBoxOkCancel.xaml.cs @@ -10,9 +10,9 @@ public class XamlResourceMessageBoxOkCancel : MessageBoxOkCancel } - public XamlResourceMessageBoxOkCancel(string titleResourceName, string descriptionResourceName, string okButtonTextResourceName, string cancelButtonTextResourceName) : base(new XamlResource(titleResourceName).Get(), new XamlResource(descriptionResourceName).Get()) + public XamlResourceMessageBoxOkCancel(string title, string message, string okText, string cancelText) : base(title, message) { - this.CancelBtn.Content = Lib.Static.Resources.ResourceProvider.Get(cancelButtonTextResourceName); - this.OKBtn.Content = Lib.Static.Resources.ResourceProvider.Get(okButtonTextResourceName); + this.OKBtn.Content = okText; + this.CancelBtn.Content = cancelText; } } \ No newline at end of file From 5249e8fc4e9b9323b57d26c59c5b99fcdbec517f Mon Sep 17 00:00:00 2001 From: TheBestAstroNOT Date: Wed, 17 Dec 2025 18:05:24 +0530 Subject: [PATCH 05/15] Update Resources.cs --- source/Reloaded.Mod.Launcher.Lib/Static/Resources.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/Reloaded.Mod.Launcher.Lib/Static/Resources.cs b/source/Reloaded.Mod.Launcher.Lib/Static/Resources.cs index b85017a4..126c547f 100644 --- a/source/Reloaded.Mod.Launcher.Lib/Static/Resources.cs +++ b/source/Reloaded.Mod.Launcher.Lib/Static/Resources.cs @@ -226,7 +226,7 @@ public static void Init(IDictionaryResourceProvider provider) public static IDictionaryResource InstallingModWait { get; set; } public static IDictionaryResource ExtractingLocalModArchive { get; set; } - // Update 1.XX.XX: Add warning during installation of mods with no apps in their supported apps list or when no compatible app is installed (UPDATE LAUNCHER VER BEFORE RELEASE). + // Update 1.XX.XX: Add warning during installation of mods with no apps in their supported apps list or when no compatible app is installed (UPDATE LAUNCHER VER BEFORE RELEASE) public static IDictionaryResource NoAppsInConfigTitle { get; set; } public static IDictionaryResource NoAppsInConfigDescription { get; set; } public static IDictionaryResource NoCompatibleAppsInConfigTitle { get; set; } From 64947d63473745c45f3c15307ca56e60583c82cc Mon Sep 17 00:00:00 2001 From: TheBestAstroNOT <139786546+TheBestAstroNOT@users.noreply.github.com> Date: Sun, 18 Jan 2026 20:42:42 +0530 Subject: [PATCH 06/15] Refactor EditModDialogViewModel constructor usage --- .../Reloaded.Mod.Launcher.Lib/Commands/Mod/EditModCommand.cs | 2 +- .../Models/ViewModel/Dialog/EditModDialogViewModel.cs | 3 +++ .../Models/ViewModel/DownloadPackagesViewModel.cs | 4 ++-- source/Reloaded.Mod.Launcher/MainWindow.xaml.cs | 4 ++-- .../Pages/BaseSubpages/Dialogs/CreateModDialog.xaml.cs | 2 +- 5 files changed, 9 insertions(+), 6 deletions(-) diff --git a/source/Reloaded.Mod.Launcher.Lib/Commands/Mod/EditModCommand.cs b/source/Reloaded.Mod.Launcher.Lib/Commands/Mod/EditModCommand.cs index 65189c27..7098ca18 100644 --- a/source/Reloaded.Mod.Launcher.Lib/Commands/Mod/EditModCommand.cs +++ b/source/Reloaded.Mod.Launcher.Lib/Commands/Mod/EditModCommand.cs @@ -23,5 +23,5 @@ public EditModCommand(PathTuple? modTuple, object? parent) public bool CanExecute(object? parameter) => _modTuple != null; /// - public void Execute(object? parameter) => Actions.EditModDialog(new EditModDialogViewModel(_modTuple!, IoC.Get().Items, IoC.Get().Items), _parent); + public void Execute(object? parameter) => Actions.EditModDialog(new EditModDialogViewModel(_modTuple!, IoC.Get(), IoC.Get()), _parent); } \ No newline at end of file diff --git a/source/Reloaded.Mod.Launcher.Lib/Models/ViewModel/Dialog/EditModDialogViewModel.cs b/source/Reloaded.Mod.Launcher.Lib/Models/ViewModel/Dialog/EditModDialogViewModel.cs index 41cf46d2..b698142c 100644 --- a/source/Reloaded.Mod.Launcher.Lib/Models/ViewModel/Dialog/EditModDialogViewModel.cs +++ b/source/Reloaded.Mod.Launcher.Lib/Models/ViewModel/Dialog/EditModDialogViewModel.cs @@ -70,6 +70,9 @@ public class EditModDialogViewModel : ObservableObject, IDisposable private SetModImageCommand _setModImageCommand; private Action? _close; + /// + public EditModDialogViewModel(PathTuple modTuple, ApplicationConfigService applicationConfigService, ModConfigService modConfigService) : this(modTuple, applicationConfigService.Items, modConfigService.Items) { } + /// public EditModDialogViewModel(PathTuple modTuple, ObservableCollection> appItems, ObservableCollection> modsItems) { diff --git a/source/Reloaded.Mod.Launcher.Lib/Models/ViewModel/DownloadPackagesViewModel.cs b/source/Reloaded.Mod.Launcher.Lib/Models/ViewModel/DownloadPackagesViewModel.cs index 16bf6357..dbe57451 100644 --- a/source/Reloaded.Mod.Launcher.Lib/Models/ViewModel/DownloadPackagesViewModel.cs +++ b/source/Reloaded.Mod.Launcher.Lib/Models/ViewModel/DownloadPackagesViewModel.cs @@ -324,7 +324,7 @@ public void Execute(object? parameter) bool loadAppPage = Actions.DisplayResourceMessageBoxOkCancel!.Invoke(Resources.NoCompatibleAppsInConfigTitle.Get(), $"{Resources.NoCompatibleAppsInConfigDescription.Get()}\n{Resources.AppSelectionQuestion.Get()}", Resources.Yes.Get(), Resources.No.Get()); if (loadAppPage) { - var viewmodel = new EditModDialogViewModel(item.Value, IoC.Get().Items, modConfigService.Items); + var viewmodel = new EditModDialogViewModel(item.Value, IoC.Get(), modConfigService); viewmodel.Page = EditModPage.Special; var createModDialog = Actions.EditModDialog(viewmodel, null); } @@ -335,7 +335,7 @@ public void Execute(object? parameter) bool loadAppPage = Actions.DisplayResourceMessageBoxOkCancel!.Invoke(Resources.NoAppsInConfigTitle.Get(), $"{Resources.NoAppsInConfigDescription.Get()}\n{Resources.AppSelectionQuestion.Get()}", Resources.Yes.Get(), Resources.No.Get()); if (loadAppPage) { - var viewmodel = new EditModDialogViewModel(item.Value, IoC.Get().Items, modConfigService.Items); + var viewmodel = new EditModDialogViewModel(item.Value, IoC.Get(), modConfigService); viewmodel.Page = EditModPage.Special; var createModDialog = Actions.EditModDialog(viewmodel, null); } diff --git a/source/Reloaded.Mod.Launcher/MainWindow.xaml.cs b/source/Reloaded.Mod.Launcher/MainWindow.xaml.cs index 626f5318..22c42050 100644 --- a/source/Reloaded.Mod.Launcher/MainWindow.xaml.cs +++ b/source/Reloaded.Mod.Launcher/MainWindow.xaml.cs @@ -143,7 +143,7 @@ private async void InstallMod_Drop(object sender, DragEventArgs e) bool loadAppPage = Actions.DisplayResourceMessageBoxOkCancel!.Invoke(NoCompatibleAppsInConfigTitle.Get(), $"{NoCompatibleAppsInConfigDescription.Get()}\n{AppSelectionQuestion.Get()}", Yes.Get(), No.Get()); if (loadAppPage) { - var createModDialog = new EditModDialog(new EditModDialogViewModel(item.Value, Lib.IoC.Get().Items, modConfigService.Items)); + var createModDialog = new EditModDialog(new EditModDialogViewModel(item.Value, Lib.IoC.Get(), modConfigService)); createModDialog.Owner = System.Windows.Window.GetWindow(this); createModDialog.RealViewModel.Page = EditModPage.Special; createModDialog.ShowDialog(); @@ -155,7 +155,7 @@ private async void InstallMod_Drop(object sender, DragEventArgs e) bool loadAppPage = Actions.DisplayResourceMessageBoxOkCancel!.Invoke(NoAppsInConfigTitle.Get(), $"{NoAppsInConfigDescription.Get()}\n{AppSelectionQuestion.Get()}" , Yes.Get(), No.Get()); if (loadAppPage) { - var createModDialog = new EditModDialog(new EditModDialogViewModel(item.Value, Lib.IoC.Get().Items, modConfigService.Items)); + var createModDialog = new EditModDialog(new EditModDialogViewModel(item.Value, Lib.IoC.Get(), modConfigService)); createModDialog.Owner = System.Windows.Window.GetWindow(this); createModDialog.RealViewModel.Page = EditModPage.Special; createModDialog.ShowDialog(); diff --git a/source/Reloaded.Mod.Launcher/Pages/BaseSubpages/Dialogs/CreateModDialog.xaml.cs b/source/Reloaded.Mod.Launcher/Pages/BaseSubpages/Dialogs/CreateModDialog.xaml.cs index 43c0cbd9..526922fa 100644 --- a/source/Reloaded.Mod.Launcher/Pages/BaseSubpages/Dialogs/CreateModDialog.xaml.cs +++ b/source/Reloaded.Mod.Launcher/Pages/BaseSubpages/Dialogs/CreateModDialog.xaml.cs @@ -26,7 +26,7 @@ public async Task Save() var mod = await ActionWrappers.TryGetValueAsync(() => modConfigService.ItemsById[createdMod.Config.ModId], 5000, 32); if (mod != null) { - var createModDialog = new EditModDialog(new EditModDialogViewModel(mod, Lib.IoC.Get().Items, modConfigService.Items)); + var createModDialog = new EditModDialog(new EditModDialogViewModel(mod, Lib.IoC.Get(), modConfigService)); createModDialog.Owner = Window.GetWindow(this); createModDialog.ShowDialog(); } From de781efa485650b2d69b1aec628219de65a58368 Mon Sep 17 00:00:00 2001 From: TheBestAstroNOT <139786546+TheBestAstroNOT@users.noreply.github.com> Date: Sun, 18 Jan 2026 21:20:43 +0530 Subject: [PATCH 07/15] Fix incorrect universal config check --- .../Models/ViewModel/DownloadPackagesViewModel.cs | 6 +++++- source/Reloaded.Mod.Launcher.Lib/Startup.cs | 5 ++++- source/Reloaded.Mod.Launcher/MainWindow.xaml.cs | 6 +++++- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/source/Reloaded.Mod.Launcher.Lib/Models/ViewModel/DownloadPackagesViewModel.cs b/source/Reloaded.Mod.Launcher.Lib/Models/ViewModel/DownloadPackagesViewModel.cs index dbe57451..838aef6c 100644 --- a/source/Reloaded.Mod.Launcher.Lib/Models/ViewModel/DownloadPackagesViewModel.cs +++ b/source/Reloaded.Mod.Launcher.Lib/Models/ViewModel/DownloadPackagesViewModel.cs @@ -316,7 +316,11 @@ public void Execute(object? parameter) if (!modsBefore.ContainsKey(item.Key)) { newConfigs.Add(item.Value.Config); - if (item.Value.Config.IsUniversalMod || item.Value.Config.SupportedAppId.Length > 0) + + if (item.Value.Config.IsUniversalMod) + continue; + + if (item.Value.Config.SupportedAppId.Length > 0) { var match = IoC.Get().Items.FirstOrDefault(app => item.Value.Config.SupportedAppId.Contains(app.Config.AppId)); if (match == null) diff --git a/source/Reloaded.Mod.Launcher.Lib/Startup.cs b/source/Reloaded.Mod.Launcher.Lib/Startup.cs index bd1dd4a2..b6f3ef3b 100644 --- a/source/Reloaded.Mod.Launcher.Lib/Startup.cs +++ b/source/Reloaded.Mod.Launcher.Lib/Startup.cs @@ -138,7 +138,10 @@ private static void DownloadModAndExit(string downloadUrl) { if (!oldItemsById.ContainsKey(item.Key)) { - if (item.Value.Config.IsUniversalMod || item.Value.Config.SupportedAppId.Length > 0) + if (item.Value.Config.IsUniversalMod) + continue; + + if (item.Value.Config.SupportedAppId.Length > 0) { var match = IoC.Get().Items.FirstOrDefault(app => item.Value.Config.SupportedAppId.Contains(app.Config.AppId)); if (match == null) diff --git a/source/Reloaded.Mod.Launcher/MainWindow.xaml.cs b/source/Reloaded.Mod.Launcher/MainWindow.xaml.cs index 22c42050..0221395d 100644 --- a/source/Reloaded.Mod.Launcher/MainWindow.xaml.cs +++ b/source/Reloaded.Mod.Launcher/MainWindow.xaml.cs @@ -135,7 +135,11 @@ private async void InstallMod_Drop(object sender, DragEventArgs e) if (!modsBefore.ContainsKey(item.Key)) { newConfigs.Add(item.Value.Config); - if(item.Value.Config.IsUniversalMod || item.Value.Config.SupportedAppId.Length > 0) + + if (item.Value.Config.IsUniversalMod) + continue; + + if(item.Value.Config.SupportedAppId.Length > 0) { var match = Lib.IoC.Get().Items.FirstOrDefault(app => item.Value.Config.SupportedAppId.Contains(app.Config.AppId)); if(match == null) From 2a5d8da262caab886cb006e3031b3f03a424f373 Mon Sep 17 00:00:00 2001 From: Sewer56 Date: Sun, 25 Jan 2026 13:54:28 +0000 Subject: [PATCH 08/15] Update version placeholders to 1.30.0 for new resource properties --- source/Reloaded.Mod.Launcher.Lib/Static/Resources.cs | 2 +- source/Reloaded.Mod.Launcher/Assets/Languages/en-GB.xaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/source/Reloaded.Mod.Launcher.Lib/Static/Resources.cs b/source/Reloaded.Mod.Launcher.Lib/Static/Resources.cs index 126c547f..dbc71394 100644 --- a/source/Reloaded.Mod.Launcher.Lib/Static/Resources.cs +++ b/source/Reloaded.Mod.Launcher.Lib/Static/Resources.cs @@ -226,7 +226,7 @@ public static void Init(IDictionaryResourceProvider provider) public static IDictionaryResource InstallingModWait { get; set; } public static IDictionaryResource ExtractingLocalModArchive { get; set; } - // Update 1.XX.XX: Add warning during installation of mods with no apps in their supported apps list or when no compatible app is installed (UPDATE LAUNCHER VER BEFORE RELEASE) + // Update 1.30.0: Add warning during installation of mods with no apps in their supported apps list or when no compatible app is installed public static IDictionaryResource NoAppsInConfigTitle { get; set; } public static IDictionaryResource NoAppsInConfigDescription { get; set; } public static IDictionaryResource NoCompatibleAppsInConfigTitle { get; set; } diff --git a/source/Reloaded.Mod.Launcher/Assets/Languages/en-GB.xaml b/source/Reloaded.Mod.Launcher/Assets/Languages/en-GB.xaml index 6d2d8852..68002ddc 100644 --- a/source/Reloaded.Mod.Launcher/Assets/Languages/en-GB.xaml +++ b/source/Reloaded.Mod.Launcher/Assets/Languages/en-GB.xaml @@ -747,7 +747,7 @@ For more info, refer to the tutorial. Don't forget to set correct Publish target Please download the requirements above by using the button below. You may need administrator permissions. - + Yes No From 1fe7401f4b1d5e389b43005c1d1ca96d67fc6142 Mon Sep 17 00:00:00 2001 From: Sewer56 Date: Sun, 25 Jan 2026 14:18:07 +0000 Subject: [PATCH 09/15] Remove unused variable assignments for EditModDialog return value --- .../Models/ViewModel/DownloadPackagesViewModel.cs | 4 ++-- source/Reloaded.Mod.Launcher.Lib/Startup.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/source/Reloaded.Mod.Launcher.Lib/Models/ViewModel/DownloadPackagesViewModel.cs b/source/Reloaded.Mod.Launcher.Lib/Models/ViewModel/DownloadPackagesViewModel.cs index 838aef6c..16179ffc 100644 --- a/source/Reloaded.Mod.Launcher.Lib/Models/ViewModel/DownloadPackagesViewModel.cs +++ b/source/Reloaded.Mod.Launcher.Lib/Models/ViewModel/DownloadPackagesViewModel.cs @@ -330,7 +330,7 @@ public void Execute(object? parameter) { var viewmodel = new EditModDialogViewModel(item.Value, IoC.Get(), modConfigService); viewmodel.Page = EditModPage.Special; - var createModDialog = Actions.EditModDialog(viewmodel, null); + Actions.EditModDialog(viewmodel, null); } } } @@ -341,7 +341,7 @@ public void Execute(object? parameter) { var viewmodel = new EditModDialogViewModel(item.Value, IoC.Get(), modConfigService); viewmodel.Page = EditModPage.Special; - var createModDialog = Actions.EditModDialog(viewmodel, null); + Actions.EditModDialog(viewmodel, null); } } } diff --git a/source/Reloaded.Mod.Launcher.Lib/Startup.cs b/source/Reloaded.Mod.Launcher.Lib/Startup.cs index b6f3ef3b..c1752a7a 100644 --- a/source/Reloaded.Mod.Launcher.Lib/Startup.cs +++ b/source/Reloaded.Mod.Launcher.Lib/Startup.cs @@ -151,7 +151,7 @@ private static void DownloadModAndExit(string downloadUrl) { var viewmodel = new EditModDialogViewModel(item.Value, allApps, items); viewmodel.Page = EditModPage.Special; - var createModDialog = Actions.EditModDialog(viewmodel, null); + Actions.EditModDialog(viewmodel, null); } } } @@ -162,7 +162,7 @@ private static void DownloadModAndExit(string downloadUrl) { var viewmodel = new EditModDialogViewModel(item.Value, allApps, items); viewmodel.Page = EditModPage.Special; - var createModDialog = Actions.EditModDialog(viewmodel, null); + Actions.EditModDialog(viewmodel, null); } } } From 4ed58eb29c83f2b87c375bb387f3d83b70b06873 Mon Sep 17 00:00:00 2001 From: Sewer56 Date: Sun, 25 Jan 2026 14:20:23 +0000 Subject: [PATCH 10/15] =?UTF-8?q?Add=20comment=20explaining=20O(N=C2=B2)?= =?UTF-8?q?=20complexity=20is=20acceptable=20for=20small=20app=20counts?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Models/ViewModel/Dialog/EditModDialogViewModel.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/source/Reloaded.Mod.Launcher.Lib/Models/ViewModel/Dialog/EditModDialogViewModel.cs b/source/Reloaded.Mod.Launcher.Lib/Models/ViewModel/Dialog/EditModDialogViewModel.cs index b698142c..3307fc1c 100644 --- a/source/Reloaded.Mod.Launcher.Lib/Models/ViewModel/Dialog/EditModDialogViewModel.cs +++ b/source/Reloaded.Mod.Launcher.Lib/Models/ViewModel/Dialog/EditModDialogViewModel.cs @@ -99,6 +99,7 @@ public EditModDialogViewModel(PathTuple modTuple, ObservableCollectio Dependencies.Add(dep); // Add Unknown Apps from Mods + // Note: O(N²) via Applications.Any() is acceptable here; typical users have <3 apps. foreach (var appId in mod.Config.SupportedAppId) { if (!Applications.Any(x => x.Generic.AppId.Equals(appId, StringComparison.OrdinalIgnoreCase))) From 88f6bfed382c58b4e634c26941531d36c5a167bd Mon Sep 17 00:00:00 2001 From: Sewer56 Date: Sun, 25 Jan 2026 14:27:46 +0000 Subject: [PATCH 11/15] Refactor: extract mod app compatibility validation into shared helper Extract duplicated validation logic from MainWindow.xaml.cs, Startup.cs, and DownloadPackagesViewModel.cs into ModValidationHelper.ValidateModAppCompatibility(). This consolidates ~90 lines of repeated code into a single reusable method, improving maintainability and ensuring consistent behavior across all mod installation paths (drag-drop, download, and protocol handler). --- .../ViewModel/DownloadPackagesViewModel.cs | 32 ++------- source/Reloaded.Mod.Launcher.Lib/Startup.cs | 32 ++------- .../Utility/ModValidationHelper.cs | 66 +++++++++++++++++++ .../Reloaded.Mod.Launcher/MainWindow.xaml.cs | 36 ++-------- 4 files changed, 79 insertions(+), 87 deletions(-) create mode 100644 source/Reloaded.Mod.Launcher.Lib/Utility/ModValidationHelper.cs diff --git a/source/Reloaded.Mod.Launcher.Lib/Models/ViewModel/DownloadPackagesViewModel.cs b/source/Reloaded.Mod.Launcher.Lib/Models/ViewModel/DownloadPackagesViewModel.cs index 16179ffc..823e84e8 100644 --- a/source/Reloaded.Mod.Launcher.Lib/Models/ViewModel/DownloadPackagesViewModel.cs +++ b/source/Reloaded.Mod.Launcher.Lib/Models/ViewModel/DownloadPackagesViewModel.cs @@ -316,34 +316,10 @@ public void Execute(object? parameter) if (!modsBefore.ContainsKey(item.Key)) { newConfigs.Add(item.Value.Config); - - if (item.Value.Config.IsUniversalMod) - continue; - - if (item.Value.Config.SupportedAppId.Length > 0) - { - var match = IoC.Get().Items.FirstOrDefault(app => item.Value.Config.SupportedAppId.Contains(app.Config.AppId)); - if (match == null) - { - bool loadAppPage = Actions.DisplayResourceMessageBoxOkCancel!.Invoke(Resources.NoCompatibleAppsInConfigTitle.Get(), $"{Resources.NoCompatibleAppsInConfigDescription.Get()}\n{Resources.AppSelectionQuestion.Get()}", Resources.Yes.Get(), Resources.No.Get()); - if (loadAppPage) - { - var viewmodel = new EditModDialogViewModel(item.Value, IoC.Get(), modConfigService); - viewmodel.Page = EditModPage.Special; - Actions.EditModDialog(viewmodel, null); - } - } - } - else - { - bool loadAppPage = Actions.DisplayResourceMessageBoxOkCancel!.Invoke(Resources.NoAppsInConfigTitle.Get(), $"{Resources.NoAppsInConfigDescription.Get()}\n{Resources.AppSelectionQuestion.Get()}", Resources.Yes.Get(), Resources.No.Get()); - if (loadAppPage) - { - var viewmodel = new EditModDialogViewModel(item.Value, IoC.Get(), modConfigService); - viewmodel.Page = EditModPage.Special; - Actions.EditModDialog(viewmodel, null); - } - } + ModValidationHelper.ValidateModAppCompatibility( + item.Value, + IoC.Get(), + modConfigService); } } diff --git a/source/Reloaded.Mod.Launcher.Lib/Startup.cs b/source/Reloaded.Mod.Launcher.Lib/Startup.cs index c1752a7a..fee61329 100644 --- a/source/Reloaded.Mod.Launcher.Lib/Startup.cs +++ b/source/Reloaded.Mod.Launcher.Lib/Startup.cs @@ -138,35 +138,11 @@ private static void DownloadModAndExit(string downloadUrl) { if (!oldItemsById.ContainsKey(item.Key)) { - if (item.Value.Config.IsUniversalMod) - continue; - - if (item.Value.Config.SupportedAppId.Length > 0) - { - var match = IoC.Get().Items.FirstOrDefault(app => item.Value.Config.SupportedAppId.Contains(app.Config.AppId)); - if (match == null) - { - bool loadAppPage = Actions.DisplayResourceMessageBoxOkCancel(Resources.NoCompatibleAppsInConfigTitle.Get(), $"{Resources.NoCompatibleAppsInConfigDescription.Get()}\n{Resources.AppSelectionQuestion.Get()}", Resources.Yes.Get(), Resources.No.Get()); - if (loadAppPage) - { - var viewmodel = new EditModDialogViewModel(item.Value, allApps, items); - viewmodel.Page = EditModPage.Special; - Actions.EditModDialog(viewmodel, null); - } - } - } - else - { - bool loadAppPage = Actions.DisplayResourceMessageBoxOkCancel(Resources.NoAppsInConfigTitle.Get(), $"{Resources.NoAppsInConfigDescription.Get()}\n{Resources.AppSelectionQuestion.Get()}", Resources.Yes.Get(), Resources.No.Get()); - if (loadAppPage) - { - var viewmodel = new EditModDialogViewModel(item.Value, allApps, items); - viewmodel.Page = EditModPage.Special; - Actions.EditModDialog(viewmodel, null); - } - } + ModValidationHelper.ValidateModAppCompatibility( + item.Value, + IoC.Get(), + IoC.Get()); } - } Actions.DisplayMessagebox(Resources.PackageDownloaderDownloadCompleteTitle.Get(), Resources.PackageDownloaderDownloadCompleteDescription.Get(), new Actions.DisplayMessageBoxParams() diff --git a/source/Reloaded.Mod.Launcher.Lib/Utility/ModValidationHelper.cs b/source/Reloaded.Mod.Launcher.Lib/Utility/ModValidationHelper.cs new file mode 100644 index 00000000..15b7156d --- /dev/null +++ b/source/Reloaded.Mod.Launcher.Lib/Utility/ModValidationHelper.cs @@ -0,0 +1,66 @@ +namespace Reloaded.Mod.Launcher.Lib.Utility; + +/// +/// Helper class for validating mod configurations after installation. +/// +public static class ModValidationHelper +{ + /// + /// Validates that a newly installed mod has compatible applications configured. + /// If no compatible apps are found, prompts the user to manually select one. + /// + /// The mod configuration to validate. + /// Service providing application configurations. + /// Service providing mod configurations. + /// Optional owner window for the edit dialog. + public static void ValidateModAppCompatibility( + PathTuple mod, + ApplicationConfigService applicationConfigService, + ModConfigService modConfigService, + object? ownerWindow = null) + { + if (mod.Config.IsUniversalMod) + return; + + if (mod.Config.SupportedAppId.Length > 0) + { + var match = applicationConfigService.Items.FirstOrDefault( + app => mod.Config.SupportedAppId.Contains(app.Config.AppId)); + + if (match == null) + { + PromptAndShowEditDialog( + Resources.NoCompatibleAppsInConfigTitle.Get(), + Resources.NoCompatibleAppsInConfigDescription.Get(), + mod, applicationConfigService, modConfigService, ownerWindow); + } + } + else + { + PromptAndShowEditDialog( + Resources.NoAppsInConfigTitle.Get(), + Resources.NoAppsInConfigDescription.Get(), + mod, applicationConfigService, modConfigService, ownerWindow); + } + } + + private static void PromptAndShowEditDialog( + string title, + string description, + PathTuple mod, + ApplicationConfigService applicationConfigService, + ModConfigService modConfigService, + object? ownerWindow) + { + var message = $"{description}\n{Resources.AppSelectionQuestion.Get()}"; + bool loadAppPage = Actions.DisplayResourceMessageBoxOkCancel!( + title, message, Resources.Yes.Get(), Resources.No.Get()); + + if (loadAppPage) + { + var viewmodel = new EditModDialogViewModel(mod, applicationConfigService, modConfigService); + viewmodel.Page = EditModPage.Special; + Actions.EditModDialog(viewmodel, ownerWindow); + } + } +} diff --git a/source/Reloaded.Mod.Launcher/MainWindow.xaml.cs b/source/Reloaded.Mod.Launcher/MainWindow.xaml.cs index 0221395d..295aba86 100644 --- a/source/Reloaded.Mod.Launcher/MainWindow.xaml.cs +++ b/source/Reloaded.Mod.Launcher/MainWindow.xaml.cs @@ -135,38 +135,12 @@ private async void InstallMod_Drop(object sender, DragEventArgs e) if (!modsBefore.ContainsKey(item.Key)) { newConfigs.Add(item.Value.Config); - - if (item.Value.Config.IsUniversalMod) - continue; - - if(item.Value.Config.SupportedAppId.Length > 0) - { - var match = Lib.IoC.Get().Items.FirstOrDefault(app => item.Value.Config.SupportedAppId.Contains(app.Config.AppId)); - if(match == null) - { - bool loadAppPage = Actions.DisplayResourceMessageBoxOkCancel!.Invoke(NoCompatibleAppsInConfigTitle.Get(), $"{NoCompatibleAppsInConfigDescription.Get()}\n{AppSelectionQuestion.Get()}", Yes.Get(), No.Get()); - if (loadAppPage) - { - var createModDialog = new EditModDialog(new EditModDialogViewModel(item.Value, Lib.IoC.Get(), modConfigService)); - createModDialog.Owner = System.Windows.Window.GetWindow(this); - createModDialog.RealViewModel.Page = EditModPage.Special; - createModDialog.ShowDialog(); - } - } - } - else - { - bool loadAppPage = Actions.DisplayResourceMessageBoxOkCancel!.Invoke(NoAppsInConfigTitle.Get(), $"{NoAppsInConfigDescription.Get()}\n{AppSelectionQuestion.Get()}" , Yes.Get(), No.Get()); - if (loadAppPage) - { - var createModDialog = new EditModDialog(new EditModDialogViewModel(item.Value, Lib.IoC.Get(), modConfigService)); - createModDialog.Owner = System.Windows.Window.GetWindow(this); - createModDialog.RealViewModel.Page = EditModPage.Special; - createModDialog.ShowDialog(); - } - } + ModValidationHelper.ValidateModAppCompatibility( + item.Value, + Lib.IoC.Get(), + modConfigService, + System.Windows.Window.GetWindow(this)); } - } if (newConfigs.Count <= 0) From b0ee37fdb8b11b1f58e2843ca6ee774a6a579a0a Mon Sep 17 00:00:00 2001 From: Sewer56 Date: Sun, 25 Jan 2026 14:54:38 +0000 Subject: [PATCH 12/15] Added: Changelog entry for mod app compatibility warning (PR #769) --- changelog-template.hbs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/changelog-template.hbs b/changelog-template.hbs index 2043b76e..4319e389 100644 --- a/changelog-template.hbs +++ b/changelog-template.hbs @@ -22,8 +22,32 @@ Alongside the addition of `textFieldFormat` from @monkeyman192 which (somehow) image +A real example where this could be useful could look like this: + +image + +Making the HUD arbitrarily wide on widescreen displays. + The old `TickFrequency` property has been marked as `[Obsolete]` but remains functional for backwards compatibility. +## Warn When Installing Mods Without Supported Games + +When installing mods via drag-and-drop, download, or the `r2:` protocol, Reloaded-II now checks if the mod +has any supported applications configured. If none are found, a dialog will prompt you to select which +game(s) the mod should be enabled for. + +image + +- Selecting **Yes** opens the mod edit dialog to configure supported applications +- Selecting **No** keeps the mod installed without changes (you can configure it later) + +This helps prevent the occasional issue where a mod author forgot to mark a mod as compatible with any game. +Without an associated game, the mod wouldn't appear in any game's mod list, which could leave users confused. + +image + +Fixes [#751](https://github.com/Reloaded-Project/Reloaded-II/issues/751). + ------------------------------------ ## Complete Changes (Autogenerated) From bdce2e8ab7e8a0bd4b077afd64adb11544af4e24 Mon Sep 17 00:00:00 2001 From: Sewer56 Date: Sun, 25 Jan 2026 14:59:14 +0000 Subject: [PATCH 13/15] Removed: Unused 'items' field --- source/Reloaded.Mod.Launcher.Lib/Startup.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/source/Reloaded.Mod.Launcher.Lib/Startup.cs b/source/Reloaded.Mod.Launcher.Lib/Startup.cs index fee61329..83ad97a8 100644 --- a/source/Reloaded.Mod.Launcher.Lib/Startup.cs +++ b/source/Reloaded.Mod.Launcher.Lib/Startup.cs @@ -133,7 +133,6 @@ private static void DownloadModAndExit(string downloadUrl) modConfig = ModConfig.GetAllMods(modConfigDir); var itemsById = modConfig.ToDictionary(x => x.Config.ModId, x => x, StringComparer.OrdinalIgnoreCase); - var items = new ObservableCollection>(modConfig); foreach (var item in itemsById.ToArray()) { if (!oldItemsById.ContainsKey(item.Key)) From b4126f5952e68e9651f05516e8ea751f694685f7 Mon Sep 17 00:00:00 2001 From: Sewer56 Date: Sun, 25 Jan 2026 15:01:47 +0000 Subject: [PATCH 14/15] Cleanup: Lift the logic for verifying at least 1 compatible app --- source/Reloaded.Mod.Launcher.Lib/Startup.cs | 40 +++++++++++---------- 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/source/Reloaded.Mod.Launcher.Lib/Startup.cs b/source/Reloaded.Mod.Launcher.Lib/Startup.cs index 83ad97a8..36c05873 100644 --- a/source/Reloaded.Mod.Launcher.Lib/Startup.cs +++ b/source/Reloaded.Mod.Launcher.Lib/Startup.cs @@ -110,17 +110,6 @@ private static void LaunchApplicationAndExit(string applicationToLaunch, bool fo [MethodImpl(MethodImplOptions.NoInlining)] private static void DownloadModAndExit(string downloadUrl) { - var loaderConfig = IoC.Get(); - var modConfigDir = loaderConfig.GetModConfigDirectory(); - var modConfig = ModConfig.GetAllMods(modConfigDir); - var allAppsList = ApplicationConfig.GetAllApplications(loaderConfig.GetApplicationConfigDirectory()); - var allApps = new ObservableCollection>(allAppsList); - var oldItemsById = modConfig.ToDictionary( - x => x.Config.ModId, - x => x, - StringComparer.OrdinalIgnoreCase - ); - if (downloadUrl.StartsWith($"{Constants.ReloadedProtocol}:", StringComparison.InvariantCultureIgnoreCase)) downloadUrl = downloadUrl.Substring(Constants.ReloadedProtocol.Length + 1); @@ -131,6 +120,28 @@ private static void DownloadModAndExit(string downloadUrl) Actions.ShowFetchPackageDialog(viewModel); Update.ResolveMissingPackages(); + // Ensure downloaded mod(s) all at least advertise 1 compatible App (if not universal) + AssertAllModsHaveAtLeastOneCompatibleApp(); + + Actions.DisplayMessagebox(Resources.PackageDownloaderDownloadCompleteTitle.Get(), Resources.PackageDownloaderDownloadCompleteDescription.Get(), new Actions.DisplayMessageBoxParams() + { + Type = Actions.MessageBoxType.Ok, + StartupLocation = Actions.WindowStartupLocation.CenterScreen, + Timeout = TimeSpan.FromSeconds(8) + }); + } + + private static void AssertAllModsHaveAtLeastOneCompatibleApp() + { + var loaderConfig = IoC.Get(); + var modConfigDir = loaderConfig.GetModConfigDirectory(); + var modConfig = ModConfig.GetAllMods(modConfigDir); + var oldItemsById = modConfig.ToDictionary( + x => x.Config.ModId, + x => x, + StringComparer.OrdinalIgnoreCase + ); + modConfig = ModConfig.GetAllMods(modConfigDir); var itemsById = modConfig.ToDictionary(x => x.Config.ModId, x => x, StringComparer.OrdinalIgnoreCase); foreach (var item in itemsById.ToArray()) @@ -143,13 +154,6 @@ private static void DownloadModAndExit(string downloadUrl) IoC.Get()); } } - - Actions.DisplayMessagebox(Resources.PackageDownloaderDownloadCompleteTitle.Get(), Resources.PackageDownloaderDownloadCompleteDescription.Get(), new Actions.DisplayMessageBoxParams() - { - Type = Actions.MessageBoxType.Ok, - StartupLocation = Actions.WindowStartupLocation.CenterScreen, - Timeout = TimeSpan.FromSeconds(8) - }); } [MethodImpl(MethodImplOptions.NoInlining)] From 3d2699cea99c6a7b098bd4be89cfa400f704b799 Mon Sep 17 00:00:00 2001 From: Sewer56 Date: Sun, 25 Jan 2026 15:03:45 +0000 Subject: [PATCH 15/15] Added: Missing author contribution to changelog text --- changelog-template.hbs | 1 + 1 file changed, 1 insertion(+) diff --git a/changelog-template.hbs b/changelog-template.hbs index 4319e389..de984f09 100644 --- a/changelog-template.hbs +++ b/changelog-template.hbs @@ -47,6 +47,7 @@ Without an associated game, the mod wouldn't appear in any game's mod list, whic image Fixes [#751](https://github.com/Reloaded-Project/Reloaded-II/issues/751). +Contributed by @TheBestAstroNOT (thanks!) , with extra quick cleanup done before merging. ------------------------------------