UI: Scanning for mods on DLC content

This commit is contained in:
Evan Husted 2025-01-29 13:33:26 -06:00
parent e02ef52069
commit a624fe64b9
5 changed files with 35 additions and 13 deletions

View File

@ -296,7 +296,7 @@ namespace Ryujinx.HLE.HOS
AddModsFromDirectory(mods, applicationDir, modMetadata); AddModsFromDirectory(mods, applicationDir, modMetadata);
} }
public static void QueryContentsDir(ModCache mods, DirectoryInfo contentsDir, ulong applicationId) public static void QueryContentsDir(ModCache mods, DirectoryInfo contentsDir, ulong applicationId, ulong[] installedDlcs)
{ {
if (!contentsDir.Exists) if (!contentsDir.Exists)
{ {
@ -311,6 +311,16 @@ namespace Ryujinx.HLE.HOS
{ {
QueryApplicationDir(mods, applicationDir, applicationId); QueryApplicationDir(mods, applicationDir, applicationId);
} }
foreach (ulong installedDlcId in installedDlcs)
{
DirectoryInfo dlcModDir = FindApplicationDir(contentsDir, $"{installedDlcId:x16}");
if (dlcModDir != null)
{
QueryApplicationDir(mods, dlcModDir, applicationId);
}
}
} }
private static int QueryCheatsDir(ModCache mods, DirectoryInfo cheatsDir) private static int QueryCheatsDir(ModCache mods, DirectoryInfo cheatsDir)
@ -417,7 +427,7 @@ namespace Ryujinx.HLE.HOS
{ {
foreach ((ulong applicationId, ModCache cache) in modCaches) foreach ((ulong applicationId, ModCache cache) in modCaches)
{ {
QueryContentsDir(cache, searchDir, applicationId); QueryContentsDir(cache, searchDir, applicationId, Array.Empty<ulong>());
} }
return true; return true;

View File

@ -128,7 +128,11 @@ namespace Ryujinx.Ava.UI.Controls
public async void OpenModManager_Click(object sender, RoutedEventArgs args) public async void OpenModManager_Click(object sender, RoutedEventArgs args)
{ {
if (sender is MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel }) if (sender is MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel })
await ModManagerWindow.Show(viewModel.SelectedApplication.Id, viewModel.SelectedApplication.Name); await ModManagerWindow.Show(
viewModel.SelectedApplication.Id,
viewModel.SelectedApplication.IdBase,
viewModel.ApplicationLibrary,
viewModel.SelectedApplication.Name);
} }
public async void PurgePtcCache_Click(object sender, RoutedEventArgs args) public async void PurgePtcCache_Click(object sender, RoutedEventArgs args)

View File

@ -7,6 +7,7 @@ using Gommon;
using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.UI.Models; using Ryujinx.Ava.UI.Models;
using Ryujinx.Ava.Utilities.AppLibrary;
using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.Common.Utilities; using Ryujinx.Common.Utilities;
@ -29,6 +30,7 @@ namespace Ryujinx.Ava.UI.ViewModels
private string _search; private string _search;
private readonly ulong _applicationId; private readonly ulong _applicationId;
private readonly ulong[] _installedDlcIds;
private readonly IStorageProvider _storageProvider; private readonly IStorageProvider _storageProvider;
private static readonly ModMetadataJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions()); private static readonly ModMetadataJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions());
@ -61,18 +63,23 @@ namespace Ryujinx.Ava.UI.ViewModels
get => string.Format(LocaleManager.Instance[LocaleKeys.ModWindowHeading], Mods.Count); get => string.Format(LocaleManager.Instance[LocaleKeys.ModWindowHeading], Mods.Count);
} }
public ModManagerViewModel(ulong applicationId) public ModManagerViewModel(ulong applicationId, ulong applicationIdBase, ApplicationLibrary appLibrary)
{ {
_applicationId = applicationId; _applicationId = applicationId;
_installedDlcIds = appLibrary.DownloadableContents.Keys
.Where(x => x.TitleIdBase == applicationIdBase)
.Select(x => x.TitleId)
.ToArray();
_modJsonPath = Path.Combine(AppDataManager.GamesDirPath, applicationId.ToString("x16"), "mods.json"); _modJsonPath = Path.Combine(AppDataManager.GamesDirPath, applicationId.ToString("x16"), "mods.json");
_storageProvider = RyujinxApp.MainWindow.StorageProvider; _storageProvider = RyujinxApp.MainWindow.StorageProvider;
LoadMods(applicationId); LoadMods(applicationId, _installedDlcIds);
} }
private void LoadMods(ulong applicationId) private void LoadMods(ulong applicationId, ulong[] installedDlcIds)
{ {
Mods.Clear(); Mods.Clear();
SelectedMods.Clear(); SelectedMods.Clear();
@ -84,7 +91,7 @@ namespace Ryujinx.Ava.UI.ViewModels
bool inSd = path == ModLoader.GetSdModsBasePath(); bool inSd = path == ModLoader.GetSdModsBasePath();
ModLoader.ModCache modCache = new(); ModLoader.ModCache modCache = new();
ModLoader.QueryContentsDir(modCache, new DirectoryInfo(Path.Combine(path, "contents")), applicationId); ModLoader.QueryContentsDir(modCache, new DirectoryInfo(Path.Combine(path, "contents")), applicationId, _installedDlcIds);
foreach (ModLoader.Mod<DirectoryInfo> mod in modCache.RomfsDirs) foreach (ModLoader.Mod<DirectoryInfo> mod in modCache.RomfsDirs)
{ {
@ -278,7 +285,7 @@ namespace Ryujinx.Ava.UI.ViewModels
File.Copy(file, file.Replace(directory.Parent.ToString(), destinationDir), true); File.Copy(file, file.Replace(directory.Parent.ToString(), destinationDir), true);
} }
LoadMods(_applicationId); LoadMods(_applicationId, _installedDlcIds);
} }
public async void Add() public async void Add()

View File

@ -64,7 +64,7 @@ namespace Ryujinx.Ava.UI.Windows
ModLoader.ModCache mods = new(); ModLoader.ModCache mods = new();
ModLoader.QueryContentsDir(mods, new DirectoryInfo(Path.Combine(modsBasePath, "contents")), titleIdValue); ModLoader.QueryContentsDir(mods, new DirectoryInfo(Path.Combine(modsBasePath, "contents")), titleIdValue, []);
string currentCheatFile = string.Empty; string currentCheatFile = string.Empty;
string buildId = string.Empty; string buildId = string.Empty;

View File

@ -6,6 +6,7 @@ using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.UI.Models; using Ryujinx.Ava.UI.Models;
using Ryujinx.Ava.UI.ViewModels; using Ryujinx.Ava.UI.ViewModels;
using Ryujinx.Ava.Utilities.AppLibrary;
using Ryujinx.Common.Helper; using Ryujinx.Common.Helper;
using System.Threading.Tasks; using System.Threading.Tasks;
using Button = Avalonia.Controls.Button; using Button = Avalonia.Controls.Button;
@ -23,21 +24,21 @@ namespace Ryujinx.Ava.UI.Windows
InitializeComponent(); InitializeComponent();
} }
public ModManagerWindow(ulong titleId) public ModManagerWindow(ulong titleId, ulong titleIdBase, ApplicationLibrary applicationLibrary)
{ {
DataContext = ViewModel = new ModManagerViewModel(titleId); DataContext = ViewModel = new ModManagerViewModel(titleId, titleIdBase, applicationLibrary);
InitializeComponent(); InitializeComponent();
} }
public static async Task Show(ulong titleId, string titleName) public static async Task Show(ulong titleId, ulong titleIdBase, ApplicationLibrary appLibrary, string titleName)
{ {
ContentDialog contentDialog = new() ContentDialog contentDialog = new()
{ {
PrimaryButtonText = string.Empty, PrimaryButtonText = string.Empty,
SecondaryButtonText = string.Empty, SecondaryButtonText = string.Empty,
CloseButtonText = string.Empty, CloseButtonText = string.Empty,
Content = new ModManagerWindow(titleId), Content = new ModManagerWindow(titleId, titleIdBase, appLibrary),
Title = string.Format(LocaleManager.Instance[LocaleKeys.ModWindowTitle], titleName, titleId.ToString("X16")), Title = string.Format(LocaleManager.Instance[LocaleKeys.ModWindowTitle], titleName, titleId.ToString("X16")),
}; };