From f42b2ed59d4a64e2c975dab92580dd18df5f5f7d Mon Sep 17 00:00:00 2001 From: Evan Husted Date: Mon, 20 Jan 2025 13:33:59 -0600 Subject: [PATCH 01/27] misc: chore: more correct last used user checking --- .../HOS/Services/Account/Acc/AccountSaveDataManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Ryujinx.HLE/HOS/Services/Account/Acc/AccountSaveDataManager.cs b/src/Ryujinx.HLE/HOS/Services/Account/Acc/AccountSaveDataManager.cs index aa57a0310..6fdfe1398 100644 --- a/src/Ryujinx.HLE/HOS/Services/Account/Acc/AccountSaveDataManager.cs +++ b/src/Ryujinx.HLE/HOS/Services/Account/Acc/AccountSaveDataManager.cs @@ -56,7 +56,7 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc ProfilesJson profilesJson = JsonHelper.DeserializeFromFile(_profilesJsonPath, _serializerContext.ProfilesJson); return profilesJson.Profiles - .FindFirst(profile => profile.AccountState == AccountState.Open) + .FindFirst(profile => profile.UserId == profilesJson.LastOpened) .Convert(profileJson => new UserProfile(new UserId(profileJson.UserId), profileJson.Name, profileJson.Image, profileJson.LastModifiedTimestamp)); } From 04ba7627103700a9edd4435f2b6e316c43d4d157 Mon Sep 17 00:00:00 2001 From: Evan Husted Date: Mon, 20 Jan 2025 14:30:28 -0600 Subject: [PATCH 02/27] UI: Move DLC RomFS dumping under normal RomFS dumping. Also removed it from DLC manager. --- src/Ryujinx/Assets/locales.json | 77 ++++++++++++++++++- src/Ryujinx/Common/ApplicationHelper.cs | 13 ++-- .../Common/Models/DownloadableContentModel.cs | 2 +- src/Ryujinx/Ryujinx.csproj | 7 +- .../UI/Controls/ApplicationContextMenu.axaml | 4 + .../Controls/ApplicationContextMenu.axaml.cs | 20 +++++ .../UI/Controls/ApplicationListView.axaml | 3 +- src/Ryujinx/UI/Controls/DlcSelectView.axaml | 67 ++++++++++++++++ .../UI/Controls/DlcSelectView.axaml.cs | 55 +++++++++++++ .../UI/Controls/NavigationDialogHost.axaml.cs | 2 +- .../UI/ViewModels/DlcSelectViewModel.cs | 25 ++++++ .../DownloadableContentManagerWindow.axaml | 17 +--- .../DownloadableContentManagerWindow.axaml.cs | 13 ---- 13 files changed, 259 insertions(+), 46 deletions(-) create mode 100644 src/Ryujinx/UI/Controls/DlcSelectView.axaml create mode 100644 src/Ryujinx/UI/Controls/DlcSelectView.axaml.cs create mode 100644 src/Ryujinx/UI/ViewModels/DlcSelectViewModel.cs diff --git a/src/Ryujinx/Assets/locales.json b/src/Ryujinx/Assets/locales.json index 49ee5a01d..d165bd742 100644 --- a/src/Ryujinx/Assets/locales.json +++ b/src/Ryujinx/Assets/locales.json @@ -2297,6 +2297,56 @@ "zh_TW": "從應用程式的目前配置中提取 RomFS 分區 (包含更新)" } }, + { + "ID": "GameListContextMenuExtractDataAocRomFS", + "Translations": { + "ar_SA": "", + "de_DE": "", + "el_GR": "", + "en_US": "DLC RomFS", + "es_ES": "", + "fr_FR": "RomFS de DLC", + "he_IL": "", + "it_IT": "", + "ja_JP": "", + "ko_KR": "", + "no_NO": "", + "pl_PL": "", + "pt_BR": "", + "ru_RU": "", + "sv_SE": "", + "th_TH": "", + "tr_TR": "", + "uk_UA": "", + "zh_CN": "", + "zh_TW": "" + } + }, + { + "ID": "GameListContextMenuExtractDataAocRomFSToolTip", + "Translations": { + "ar_SA": "", + "de_DE": "", + "el_GR": "", + "en_US": "Extract the RomFS from a selected DLC file", + "es_ES": "", + "fr_FR": "Extraire les RomFS d'un fichier DLC choisi", + "he_IL": "", + "it_IT": "", + "ja_JP": "", + "ko_KR": "", + "no_NO": "", + "pl_PL": "", + "pt_BR": "", + "ru_RU": "", + "sv_SE": "", + "th_TH": "", + "tr_TR": "", + "uk_UA": "", + "zh_CN": "", + "zh_TW": "" + } + }, { "ID": "GameListContextMenuExtractDataLogo", "Translations": { @@ -22896,6 +22946,31 @@ "zh_CN": "什么都没有", "zh_TW": "無法啟動 (Nothing)" } + }, + { + "ID": "ExtractAocListHeader", + "Translations": { + "ar_SA": "", + "de_DE": "", + "el_GR": "", + "en_US": "Select a DLC to Extract", + "es_ES": "", + "fr_FR": "Choisissez un DLC à extraire", + "he_IL": "", + "it_IT": "", + "ja_JP": "", + "ko_KR": "", + "no_NO": "", + "pl_PL": "", + "pt_BR": "", + "ru_RU": "", + "sv_SE": "", + "th_TH": "", + "tr_TR": "", + "uk_UA": "", + "zh_CN": "", + "zh_TW": "" + } } ] -} +} \ No newline at end of file diff --git a/src/Ryujinx/Common/ApplicationHelper.cs b/src/Ryujinx/Common/ApplicationHelper.cs index 88a991a3d..61c5cfe00 100644 --- a/src/Ryujinx/Common/ApplicationHelper.cs +++ b/src/Ryujinx/Common/ApplicationHelper.cs @@ -296,13 +296,13 @@ namespace Ryujinx.Ava.Common extractorThread.Start(); } - public static void ExtractAoc(string destination, NcaSectionType ncaSectionType, string updateFilePath, string updateName) + public static void ExtractAoc(string destination, string updateFilePath, string updateName) { var cancellationToken = new CancellationTokenSource(); UpdateWaitWindow waitingDialog = new( RyujinxApp.FormatTitle(LocaleKeys.DialogNcaExtractionTitle), - LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogNcaExtractionMessage, ncaSectionType, Path.GetFileName(updateFilePath)), + LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogNcaExtractionMessage, NcaSectionType.Data, Path.GetFileName(updateFilePath)), cancellationToken); Thread extractorThread = new(() => @@ -352,7 +352,7 @@ namespace Ryujinx.Ava.Common ? IntegrityCheckLevel.ErrorOnInvalid : IntegrityCheckLevel.None; - int index = Nca.GetSectionIndexFromType(ncaSectionType, publicDataNca.Header.ContentType); + int index = Nca.GetSectionIndexFromType(NcaSectionType.Data, publicDataNca.Header.ContentType); try { @@ -410,14 +410,13 @@ namespace Ryujinx.Ava.Common } }) { - Name = "GUI.NcaSectionExtractorThread", + Name = "GUI.AocExtractorThread", IsBackground = true, }; extractorThread.Start(); } - public static async Task ExtractAoc(IStorageProvider storageProvider, NcaSectionType ncaSectionType, - string updateFilePath, string updateName) + public static async Task ExtractAoc(IStorageProvider storageProvider, string updateFilePath, string updateName) { var result = await storageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions { @@ -430,7 +429,7 @@ namespace Ryujinx.Ava.Common return; } - ExtractAoc(result[0].Path.LocalPath, ncaSectionType, updateFilePath, updateName); + ExtractAoc(result[0].Path.LocalPath, updateFilePath, updateName); } diff --git a/src/Ryujinx/Common/Models/DownloadableContentModel.cs b/src/Ryujinx/Common/Models/DownloadableContentModel.cs index ad9934bd2..de7a334ee 100644 --- a/src/Ryujinx/Common/Models/DownloadableContentModel.cs +++ b/src/Ryujinx/Common/Models/DownloadableContentModel.cs @@ -6,7 +6,7 @@ namespace Ryujinx.Ava.Common.Models public bool IsBundled { get; } = System.IO.Path.GetExtension(ContainerPath)?.ToLower() == ".xci"; public string FileName => System.IO.Path.GetFileName(ContainerPath); - public string TitleIdStr => TitleId.ToString("x16"); + public string TitleIdStr => TitleId.ToString("x16").ToUpper(); public ulong TitleIdBase => TitleId & ~0x1FFFUL; } } diff --git a/src/Ryujinx/Ryujinx.csproj b/src/Ryujinx/Ryujinx.csproj index 8c72d5a3c..7d342812f 100644 --- a/src/Ryujinx/Ryujinx.csproj +++ b/src/Ryujinx/Ryujinx.csproj @@ -173,10 +173,5 @@ - - - UserSelectorDialog.axaml - Code - - + diff --git a/src/Ryujinx/UI/Controls/ApplicationContextMenu.axaml b/src/Ryujinx/UI/Controls/ApplicationContextMenu.axaml index 7708936ca..9fed95aa7 100644 --- a/src/Ryujinx/UI/Controls/ApplicationContextMenu.axaml +++ b/src/Ryujinx/UI/Controls/ApplicationContextMenu.axaml @@ -106,6 +106,10 @@ Click="ExtractApplicationRomFs_Click" Header="{ext:Locale GameListContextMenuExtractDataRomFS}" ToolTip.Tip="{ext:Locale GameListContextMenuExtractDataRomFSToolTip}" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Ryujinx/UI/Controls/DlcSelectView.axaml.cs b/src/Ryujinx/UI/Controls/DlcSelectView.axaml.cs new file mode 100644 index 000000000..c2144da2d --- /dev/null +++ b/src/Ryujinx/UI/Controls/DlcSelectView.axaml.cs @@ -0,0 +1,55 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; +using Avalonia.Styling; +using FluentAvalonia.UI.Controls; +using LibHac.Tools.FsSystem.NcaUtils; +using Ryujinx.Ava.Common; +using Ryujinx.Ava.Common.Locale; +using Ryujinx.Ava.Common.Models; +using Ryujinx.Ava.UI.Helpers; +using Ryujinx.Ava.UI.ViewModels; +using Ryujinx.Ava.Utilities.AppLibrary; +using Ryujinx.Ava.Utilities.Compat; +using System.Threading.Tasks; + +namespace Ryujinx.Ava.UI.Controls +{ + public partial class DlcSelectView : UserControl + { + public DlcSelectView() + { + InitializeComponent(); + } + + #nullable enable + public static async Task Show(ulong selectedTitleId, ApplicationLibrary appLibrary) + #nullable disable + { + DlcSelectViewModel viewModel = new(selectedTitleId, appLibrary); + + ContentDialog contentDialog = new() + { + PrimaryButtonText = LocaleManager.Instance[LocaleKeys.Continue], + SecondaryButtonText = string.Empty, + CloseButtonText = string.Empty, + Content = new DlcSelectView { DataContext = viewModel } + }; + + Style closeButton = new(x => x.Name("CloseButton")); + closeButton.Setters.Add(new Setter(WidthProperty, 80d)); + + Style closeButtonParent = new(x => x.Name("CommandSpace")); + closeButtonParent.Setters.Add(new Setter(HorizontalAlignmentProperty, + Avalonia.Layout.HorizontalAlignment.Right)); + + contentDialog.Styles.Add(closeButton); + contentDialog.Styles.Add(closeButtonParent); + + await ContentDialogHelper.ShowAsync(contentDialog); + + return viewModel.SelectedDlc; + } + } +} + diff --git a/src/Ryujinx/UI/Controls/NavigationDialogHost.axaml.cs b/src/Ryujinx/UI/Controls/NavigationDialogHost.axaml.cs index c27a3ac9b..4d021655e 100644 --- a/src/Ryujinx/UI/Controls/NavigationDialogHost.axaml.cs +++ b/src/Ryujinx/UI/Controls/NavigationDialogHost.axaml.cs @@ -69,7 +69,7 @@ namespace Ryujinx.Ava.UI.Controls VirtualFileSystem ownerVirtualFileSystem, HorizonClient ownerHorizonClient) { - var content = new NavigationDialogHost(ownerAccountManager, ownerContentManager, ownerVirtualFileSystem, ownerHorizonClient); + NavigationDialogHost content = new(ownerAccountManager, ownerContentManager, ownerVirtualFileSystem, ownerHorizonClient); ContentDialog contentDialog = new() { Title = LocaleManager.Instance[LocaleKeys.UserProfileWindowTitle], diff --git a/src/Ryujinx/UI/ViewModels/DlcSelectViewModel.cs b/src/Ryujinx/UI/ViewModels/DlcSelectViewModel.cs new file mode 100644 index 000000000..d50d8249a --- /dev/null +++ b/src/Ryujinx/UI/ViewModels/DlcSelectViewModel.cs @@ -0,0 +1,25 @@ +using CommunityToolkit.Mvvm.ComponentModel; +using Ryujinx.Ava.Common.Models; +using Ryujinx.Ava.Utilities.AppLibrary; +using System.Linq; + +namespace Ryujinx.Ava.UI.ViewModels +{ + public partial class DlcSelectViewModel : BaseModel + { + [ObservableProperty] private DownloadableContentModel[] _dlcs; + #nullable enable + [ObservableProperty] private DownloadableContentModel? _selectedDlc; + #nullable disable + + public DlcSelectViewModel(ulong titleId, ApplicationLibrary appLibrary) + { + _dlcs = appLibrary.DownloadableContents.Items + .Where(x => x.Dlc.TitleIdBase == titleId) + .Select(x => x.Dlc) + .OrderBy(it => it.IsBundled ? 0 : 1) + .ThenBy(it => it.TitleId) + .ToArray(); + } + } +} diff --git a/src/Ryujinx/UI/Windows/DownloadableContentManagerWindow.axaml b/src/Ryujinx/UI/Windows/DownloadableContentManagerWindow.axaml index 8270e070a..e2c4fe16e 100644 --- a/src/Ryujinx/UI/Windows/DownloadableContentManagerWindow.axaml +++ b/src/Ryujinx/UI/Windows/DownloadableContentManagerWindow.axaml @@ -7,7 +7,6 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels" xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia" - xmlns:pi="using:Projektanker.Icons.Avalonia" xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers" xmlns:models="clr-namespace:Ryujinx.Ava.Common.Models" Width="500" @@ -15,9 +14,6 @@ mc:Ignorable="d" x:DataType="viewModels:DownloadableContentManagerViewModel" Focusable="True"> - - - - + @@ -113,22 +109,13 @@ Margin="10 0" HorizontalAlignment="Left" VerticalAlignment="Center" - Text="{Binding TitleId}" /> + Text="{Binding TitleIdStr}" /> - @@ -168,8 +167,7 @@ Grid.Column="1" MinWidth="90" Margin="10,0,0,0" - ToolTip.Tip="{ext:Locale AddAutoloadDirTooltip}" - Click="AddAutoloadDirButton_OnClick"> + ToolTip.Tip="{ext:Locale AddAutoloadDirTooltip}"> diff --git a/src/Ryujinx/UI/Views/Settings/SettingsUIView.axaml.cs b/src/Ryujinx/UI/Views/Settings/SettingsUIView.axaml.cs index 3532e1855..9707b3193 100644 --- a/src/Ryujinx/UI/Views/Settings/SettingsUIView.axaml.cs +++ b/src/Ryujinx/UI/Views/Settings/SettingsUIView.axaml.cs @@ -1,12 +1,17 @@ +using Avalonia.Collections; using Avalonia.Controls; using Avalonia.Interactivity; using Avalonia.Platform.Storage; using Avalonia.VisualTree; +using Gommon; +using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.ViewModels; +using Ryujinx.Ava.Utilities; using System; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Threading.Tasks; namespace Ryujinx.Ava.UI.Views.Settings { @@ -18,31 +23,39 @@ namespace Ryujinx.Ava.UI.Views.Settings { InitializeComponent(); ShowTitleBarBox.IsVisible = OperatingSystem.IsWindows(); + AddGameDirButton.Command = + Commands.Create(() => AddDirButton(GameDirPathBox, ViewModel.GameDirectories, true)); + AddAutoloadDirButton.Command = + Commands.Create(() => AddDirButton(AutoloadDirPathBox, ViewModel.AutoloadDirectories, false)); } - private async void AddGameDirButton_OnClick(object sender, RoutedEventArgs e) + private async Task AddDirButton(TextBox addDirBox, AvaloniaList directories, bool isGameList) { - string path = GameDirPathBox.Text; + string path = addDirBox.Text; - if (!string.IsNullOrWhiteSpace(path) && Directory.Exists(path) && !ViewModel.GameDirectories.Contains(path)) + if (!string.IsNullOrWhiteSpace(path) && Directory.Exists(path) && !directories.Contains(path)) { - ViewModel.GameDirectories.Add(path); - ViewModel.GameDirectoryChanged = true; + directories.Add(path); + + addDirBox.Clear(); + + if (isGameList) + ViewModel.GameDirectoryChanged = true; + else + ViewModel.AutoloadDirectoryChanged = true; } else { - if (this.GetVisualRoot() is Window window) - { - var result = await window.StorageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions - { - AllowMultiple = false, - }); + Optional folder = await RyujinxApp.MainWindow.ViewModel.StorageProvider.OpenSingleFolderPickerAsync(); - if (result.Count > 0) - { - ViewModel.GameDirectories.Add(result[0].Path.LocalPath); + if (folder.HasValue) + { + directories.Add(folder.Value.Path.LocalPath); + + if (isGameList) ViewModel.GameDirectoryChanged = true; - } + else + ViewModel.AutoloadDirectoryChanged = true; } } } @@ -63,33 +76,6 @@ namespace Ryujinx.Ava.UI.Views.Settings } } - private async void AddAutoloadDirButton_OnClick(object sender, RoutedEventArgs e) - { - string path = AutoloadDirPathBox.Text; - - if (!string.IsNullOrWhiteSpace(path) && Directory.Exists(path) && !ViewModel.AutoloadDirectories.Contains(path)) - { - ViewModel.AutoloadDirectories.Add(path); - ViewModel.AutoloadDirectoryChanged = true; - } - else - { - if (this.GetVisualRoot() is Window window) - { - var result = await window.StorageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions - { - AllowMultiple = false, - }); - - if (result.Count > 0) - { - ViewModel.AutoloadDirectories.Add(result[0].Path.LocalPath); - ViewModel.AutoloadDirectoryChanged = true; - } - } - } - } - private void RemoveAutoloadDirButton_OnClick(object sender, RoutedEventArgs e) { int oldIndex = AutoloadDirsList.SelectedIndex; From 9f53b0749160ffdb93837f8a501416faf440ac49 Mon Sep 17 00:00:00 2001 From: Evan Husted Date: Wed, 22 Jan 2025 08:52:21 -0600 Subject: [PATCH 22/27] misc: chore: Fix shader cache & CPU cache being in different folders on non-Windows fixes #565 --- src/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs b/src/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs index 3a02eb615..b50ea174d 100644 --- a/src/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs +++ b/src/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs @@ -118,7 +118,7 @@ namespace Ryujinx.Graphics.Gpu.Shader private static string GetDiskCachePath() { return GraphicsConfig.EnableShaderCache && GraphicsConfig.TitleId != null - ? Path.Combine(AppDataManager.GamesDirPath, GraphicsConfig.TitleId, "cache", "shader") + ? Path.Combine(AppDataManager.GamesDirPath, GraphicsConfig.TitleId.ToLower(), "cache", "shader") : null; } From 13d411e4deae65c8ab3e155643037ddb86767594 Mon Sep 17 00:00:00 2001 From: Evan Husted Date: Wed, 22 Jan 2025 08:54:39 -0600 Subject: [PATCH 23/27] misc: chore: also ToLower the titleID for the OpenShaderDirectory button --- src/Ryujinx/UI/Controls/ApplicationContextMenu.axaml.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Ryujinx/UI/Controls/ApplicationContextMenu.axaml.cs b/src/Ryujinx/UI/Controls/ApplicationContextMenu.axaml.cs index 0d4b4133d..de95be387 100644 --- a/src/Ryujinx/UI/Controls/ApplicationContextMenu.axaml.cs +++ b/src/Ryujinx/UI/Controls/ApplicationContextMenu.axaml.cs @@ -251,7 +251,7 @@ namespace Ryujinx.Ava.UI.Controls { if (sender is MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel }) { - string shaderCacheDir = Path.Combine(AppDataManager.GamesDirPath, viewModel.SelectedApplication.IdString, "cache", "shader"); + string shaderCacheDir = Path.Combine(AppDataManager.GamesDirPath, viewModel.SelectedApplication.IdString.ToLower(), "cache", "shader"); if (!Directory.Exists(shaderCacheDir)) { From 069f630776ca5c3a6bd1023eba42035a33dd7ba9 Mon Sep 17 00:00:00 2001 From: Evan Husted Date: Wed, 22 Jan 2025 18:00:14 -0600 Subject: [PATCH 24/27] docs: compat: boots: ENDER MAGNOLIA: Bloom in the Mist --- docs/compatibility.csv | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/compatibility.csv b/docs/compatibility.csv index e26d36ecc..570c93618 100644 --- a/docs/compatibility.csv +++ b/docs/compatibility.csv @@ -1070,6 +1070,7 @@ 010017B0102A8000,"Emma: Lost in Memories",nvdec,playable,2021-01-28 16:19:10 010068300E08E000,"Enchanted in the Moonlight - Kiryu, Chikage & Yukinojo -",gpu;nvdec,ingame,2022-11-20 16:18:45 01007A4008486000,"Enchanting Mahjong Match",gpu,ingame,2020-04-17 22:01:31 +0100EF901E552000,"ENDER MAGNOLIA: Bloom in the Mist",deadlock,boots,2025-01-22 17:59:00 01004F3011F92000,"Endless Fables: Dark Moor",gpu;nvdec,ingame,2021-03-07 15:31:03 010067B017588000,"Endless Ocean™ Luminous",services-horizon;crash,ingame,2024-05-30 02:05:57 0100B8700BD14000,"Energy Cycle Edge",services,ingame,2021-11-30 05:02:31 From c03cd50fa3823daf4188627d0172918244ffe107 Mon Sep 17 00:00:00 2001 From: Evan Husted Date: Wed, 22 Jan 2025 19:53:39 -0600 Subject: [PATCH 25/27] UI: Add the ability to change a DualSense/DualShock 4's LED color. Not functional yet. This is the UI & persistence side of #572. --- .../GenericControllerInputConfig.cs | 5 +++ .../Hid/Controller/LedConfigController.cs | 15 +++++++ src/Ryujinx.Input.SDL2/SDL2Gamepad.cs | 6 +++ src/Ryujinx.Input/GamepadFeaturesFlag.cs | 5 +++ .../UI/Models/Input/GamepadInputConfig.cs | 43 ++++++++++++++++++- .../Input/ControllerInputViewModel.cs | 2 +- .../UI/ViewModels/Input/InputViewModel.cs | 2 + .../UI/Views/Input/ControllerInputView.axaml | 32 ++++++++++++++ .../Views/Input/ControllerInputView.axaml.cs | 3 -- .../Configuration/ConfigurationFileFormat.cs | 2 +- .../ConfigurationState.Migration.cs | 24 +++++++---- 11 files changed, 125 insertions(+), 14 deletions(-) create mode 100644 src/Ryujinx.Common/Configuration/Hid/Controller/LedConfigController.cs diff --git a/src/Ryujinx.Common/Configuration/Hid/Controller/GenericControllerInputConfig.cs b/src/Ryujinx.Common/Configuration/Hid/Controller/GenericControllerInputConfig.cs index e6fe74d53..fbb19767c 100644 --- a/src/Ryujinx.Common/Configuration/Hid/Controller/GenericControllerInputConfig.cs +++ b/src/Ryujinx.Common/Configuration/Hid/Controller/GenericControllerInputConfig.cs @@ -78,5 +78,10 @@ namespace Ryujinx.Common.Configuration.Hid.Controller /// Controller Rumble Settings /// public RumbleConfigController Rumble { get; set; } + + /// + /// Controller LED Settings + /// + public LedConfigController Led { get; set; } } } diff --git a/src/Ryujinx.Common/Configuration/Hid/Controller/LedConfigController.cs b/src/Ryujinx.Common/Configuration/Hid/Controller/LedConfigController.cs new file mode 100644 index 000000000..21727d62e --- /dev/null +++ b/src/Ryujinx.Common/Configuration/Hid/Controller/LedConfigController.cs @@ -0,0 +1,15 @@ +namespace Ryujinx.Common.Configuration.Hid.Controller +{ + public class LedConfigController + { + /// + /// Packed RGB int of the color + /// + public uint LedColor { get; set; } + + /// + /// Enable LED color changing by the emulator + /// + public bool EnableLed { get; set; } + } +} diff --git a/src/Ryujinx.Input.SDL2/SDL2Gamepad.cs b/src/Ryujinx.Input.SDL2/SDL2Gamepad.cs index 12bfab4bb..ed22c3661 100644 --- a/src/Ryujinx.Input.SDL2/SDL2Gamepad.cs +++ b/src/Ryujinx.Input.SDL2/SDL2Gamepad.cs @@ -1,6 +1,7 @@ using Ryujinx.Common.Configuration.Hid; using Ryujinx.Common.Configuration.Hid.Controller; using Ryujinx.Common.Logging; +using SDL2; using System; using System.Collections.Generic; using System.Numerics; @@ -118,6 +119,11 @@ namespace Ryujinx.Input.SDL2 result |= GamepadFeaturesFlag.Rumble; } + if (SDL_GameControllerHasLED(_gamepadHandle) == SDL_bool.SDL_TRUE) + { + result |= GamepadFeaturesFlag.Led; + } + return result; } diff --git a/src/Ryujinx.Input/GamepadFeaturesFlag.cs b/src/Ryujinx.Input/GamepadFeaturesFlag.cs index 69ec23686..52e8519d1 100644 --- a/src/Ryujinx.Input/GamepadFeaturesFlag.cs +++ b/src/Ryujinx.Input/GamepadFeaturesFlag.cs @@ -24,5 +24,10 @@ namespace Ryujinx.Input /// Also named sixaxis /// Motion, + + /// + /// The LED on the back of modern PlayStation controllers (DualSense & DualShock 4). + /// + Led, } } diff --git a/src/Ryujinx/UI/Models/Input/GamepadInputConfig.cs b/src/Ryujinx/UI/Models/Input/GamepadInputConfig.cs index 833670bdc..ea7dd34c3 100644 --- a/src/Ryujinx/UI/Models/Input/GamepadInputConfig.cs +++ b/src/Ryujinx/UI/Models/Input/GamepadInputConfig.cs @@ -1,3 +1,4 @@ +using Avalonia.Media; using Ryujinx.Ava.UI.ViewModels; using Ryujinx.Common.Configuration.Hid; using Ryujinx.Common.Configuration.Hid.Controller; @@ -387,6 +388,30 @@ namespace Ryujinx.Ava.UI.Models.Input } } + private bool _enableLedChanging; + + public bool EnableLedChanging + { + get => _enableLedChanging; + set + { + _enableLedChanging = value; + OnPropertyChanged(); + } + } + + private Color _ledColor; + + public Color LedColor + { + get => _ledColor; + set + { + _ledColor = value; + OnPropertyChanged(); + } + } + private bool _enableMotion; public bool EnableMotion { @@ -483,12 +508,23 @@ namespace Ryujinx.Ava.UI.Models.Input WeakRumble = controllerInput.Rumble.WeakRumble; StrongRumble = controllerInput.Rumble.StrongRumble; } + + if (controllerInput.Led != null) + { + EnableLedChanging = controllerInput.Led.EnableLed; + uint rawColor = controllerInput.Led.LedColor; + byte alpha = (byte)(rawColor >> 24); + byte red = (byte)(rawColor >> 16); + byte green = (byte)(rawColor >> 8); + byte blue = (byte)(rawColor % 256); + LedColor = new Color(alpha, red, green, blue); + } } } public InputConfig GetConfig() { - var config = new StandardControllerInputConfig + StandardControllerInputConfig config = new() { Id = Id, Backend = InputBackendType.GamepadSDL2, @@ -540,6 +576,11 @@ namespace Ryujinx.Ava.UI.Models.Input WeakRumble = WeakRumble, StrongRumble = StrongRumble, }, + Led = new LedConfigController + { + EnableLed = EnableLedChanging, + LedColor = LedColor.ToUInt32() + }, Version = InputConfig.CurrentVersion, DeadzoneLeft = DeadzoneLeft, DeadzoneRight = DeadzoneRight, diff --git a/src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs b/src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs index 482fe2981..0380ef598 100644 --- a/src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/Input/ControllerInputViewModel.cs @@ -37,7 +37,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input [ObservableProperty] private SvgImage _image; - public readonly InputViewModel ParentModel; + public InputViewModel ParentModel { get; } public ControllerInputViewModel(InputViewModel model, GamepadInputConfig config) { diff --git a/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs b/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs index 05f479d9f..7fda4e2d0 100644 --- a/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs @@ -68,6 +68,8 @@ namespace Ryujinx.Ava.UI.ViewModels.Input public bool IsKeyboard => !IsController; public bool IsRight { get; set; } public bool IsLeft { get; set; } + + public bool HasLed => SelectedGamepad.Features.HasFlag(GamepadFeaturesFlag.Led); public bool IsModified { get; set; } public event Action NotifyChangesEvent; diff --git a/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml b/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml index 7daf23eb6..73f74e36f 100644 --- a/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml +++ b/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml @@ -4,6 +4,7 @@ xmlns:ext="clr-namespace:Ryujinx.Ava.Common.Markup" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia" xmlns:controls="clr-namespace:Ryujinx.Ava.UI.Controls" xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels.Input" xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers" @@ -486,6 +487,37 @@ + + + + + + + + + + + + + diff --git a/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml.cs b/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml.cs index ee84fbc37..52a6d51b9 100644 --- a/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml.cs +++ b/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml.cs @@ -4,14 +4,11 @@ using Avalonia.Controls.Primitives; using Avalonia.Input; using Avalonia.Interactivity; using Avalonia.LogicalTree; -using DiscordRPC; using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.ViewModels.Input; using Ryujinx.Common.Configuration.Hid.Controller; -using Ryujinx.Common.Logging; using Ryujinx.Input; using Ryujinx.Input.Assigner; -using System; using StickInputId = Ryujinx.Common.Configuration.Hid.Controller.StickInputId; namespace Ryujinx.Ava.UI.Views.Input diff --git a/src/Ryujinx/Utilities/Configuration/ConfigurationFileFormat.cs b/src/Ryujinx/Utilities/Configuration/ConfigurationFileFormat.cs index 6d3570850..4bbc5e622 100644 --- a/src/Ryujinx/Utilities/Configuration/ConfigurationFileFormat.cs +++ b/src/Ryujinx/Utilities/Configuration/ConfigurationFileFormat.cs @@ -17,7 +17,7 @@ namespace Ryujinx.Ava.Utilities.Configuration /// /// The current version of the file format /// - public const int CurrentVersion = 60; + public const int CurrentVersion = 61; /// /// Version of the configuration file format diff --git a/src/Ryujinx/Utilities/Configuration/ConfigurationState.Migration.cs b/src/Ryujinx/Utilities/Configuration/ConfigurationState.Migration.cs index 943aab513..521780e94 100644 --- a/src/Ryujinx/Utilities/Configuration/ConfigurationState.Migration.cs +++ b/src/Ryujinx/Utilities/Configuration/ConfigurationState.Migration.cs @@ -263,15 +263,12 @@ namespace Ryujinx.Ava.Utilities.Configuration }), (30, static cff => { - foreach (InputConfig config in cff.InputConfig) + foreach (StandardControllerInputConfig config in cff.InputConfig.OfType()) { - if (config is StandardControllerInputConfig controllerConfig) + config.Rumble = new RumbleConfigController { - controllerConfig.Rumble = new RumbleConfigController - { - EnableRumble = false, StrongRumble = 1f, WeakRumble = 1f, - }; - } + EnableRumble = false, StrongRumble = 1f, WeakRumble = 1f, + }; } }), (31, static cff => cff.BackendThreading = BackendThreading.Auto), @@ -416,7 +413,18 @@ namespace Ryujinx.Ava.Utilities.Configuration // so as a compromise users who want to use it will simply need to re-enable it once after updating. cff.IgnoreApplet = false; }), - (60, static cff => cff.StartNoUI = false) + (60, static cff => cff.StartNoUI = false), + (61, static cff => + { + foreach (StandardControllerInputConfig config in cff.InputConfig.OfType()) + { + config.Led = new LedConfigController + { + EnableLed = false, + LedColor = 328189 + }; + } + }) ); } } From 9c8055440e1f4eeaa6eeb6b3bfb107e1389f29ac Mon Sep 17 00:00:00 2001 From: Evan Husted Date: Wed, 22 Jan 2025 23:58:11 -0600 Subject: [PATCH 26/27] HLE: TryAdd firmware NCAs --- src/Ryujinx.HLE/FileSystem/ContentManager.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/Ryujinx.HLE/FileSystem/ContentManager.cs b/src/Ryujinx.HLE/FileSystem/ContentManager.cs index ec0f58b01..a87453d00 100644 --- a/src/Ryujinx.HLE/FileSystem/ContentManager.cs +++ b/src/Ryujinx.HLE/FileSystem/ContentManager.cs @@ -710,9 +710,8 @@ namespace Ryujinx.HLE.FileSystem { updateNcasItem.Add((nca.Header.ContentType, entry.FullName)); } - else + else if (updateNcas.TryAdd(nca.Header.TitleId, new List<(NcaContentType, string)>())) { - updateNcas.Add(nca.Header.TitleId, new List<(NcaContentType, string)>()); updateNcas[nca.Header.TitleId].Add((nca.Header.ContentType, entry.FullName)); } } @@ -898,9 +897,8 @@ namespace Ryujinx.HLE.FileSystem { updateNcasItem.Add((nca.Header.ContentType, entry.FullPath)); } - else + else if (updateNcas.TryAdd(nca.Header.TitleId, new List<(NcaContentType, string)>())) { - updateNcas.Add(nca.Header.TitleId, new List<(NcaContentType, string)>()); updateNcas[nca.Header.TitleId].Add((nca.Header.ContentType, entry.FullPath)); } From c140e9b23cbd16b583a9c1bf2b1531a63d065367 Mon Sep 17 00:00:00 2001 From: Evan Husted Date: Thu, 23 Jan 2025 00:48:42 -0600 Subject: [PATCH 27/27] UI: Localize LED color & hide it until it's functional Also moved IgnoreApplet to the System config section object. --- src/Ryujinx/Assets/locales.json | 27 ++++++++++++++++++- src/Ryujinx/Headless/Options.cs | 2 +- src/Ryujinx/UI/Applet/AvaHostUIHandler.cs | 3 +-- .../UI/ViewModels/Input/InputViewModel.cs | 5 ++-- .../UI/ViewModels/SettingsViewModel.cs | 10 +++---- .../UI/Views/Input/ControllerInputView.axaml | 2 +- .../ConfigurationState.Migration.cs | 2 +- .../Configuration/ConfigurationState.Model.cs | 14 +++++----- .../Configuration/ConfigurationState.cs | 4 +-- 9 files changed, 47 insertions(+), 22 deletions(-) diff --git a/src/Ryujinx/Assets/locales.json b/src/Ryujinx/Assets/locales.json index 9117a553b..8a101d733 100644 --- a/src/Ryujinx/Assets/locales.json +++ b/src/Ryujinx/Assets/locales.json @@ -7622,6 +7622,31 @@ "zh_TW": "陀螺儀無感帶:" } }, + { + "ID": "ControllerSettingsLedColor", + "Translations": { + "ar_SA": "", + "de_DE": "", + "el_GR": "", + "en_US": "Custom LED", + "es_ES": "", + "fr_FR": "", + "he_IL": "", + "it_IT": "", + "ja_JP": "", + "ko_KR": "", + "no_NO": "", + "pl_PL": "", + "pt_BR": "", + "ru_RU": "", + "sv_SE": "", + "th_TH": "", + "tr_TR": "", + "uk_UA": "", + "zh_CN": "", + "zh_TW": "" + } + }, { "ID": "ControllerSettingsSave", "Translations": { @@ -22973,4 +22998,4 @@ } } ] -} \ No newline at end of file +} diff --git a/src/Ryujinx/Headless/Options.cs b/src/Ryujinx/Headless/Options.cs index 0d7e46285..f527e9811 100644 --- a/src/Ryujinx/Headless/Options.cs +++ b/src/Ryujinx/Headless/Options.cs @@ -149,7 +149,7 @@ namespace Ryujinx.Headless IgnoreMissingServices = configurationState.System.IgnoreMissingServices; if (NeedsOverride(nameof(IgnoreControllerApplet))) - IgnoreControllerApplet = configurationState.IgnoreApplet; + IgnoreControllerApplet = configurationState.System.IgnoreApplet; return; diff --git a/src/Ryujinx/UI/Applet/AvaHostUIHandler.cs b/src/Ryujinx/UI/Applet/AvaHostUIHandler.cs index a2cac35c7..d2fad58ac 100644 --- a/src/Ryujinx/UI/Applet/AvaHostUIHandler.cs +++ b/src/Ryujinx/UI/Applet/AvaHostUIHandler.cs @@ -6,7 +6,6 @@ using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.UI.Controls; using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.ViewModels; -using Ryujinx.Ava.UI.ViewModels.Input; using Ryujinx.Ava.UI.Windows; using Ryujinx.Ava.Utilities.Configuration; using Ryujinx.Common; @@ -42,7 +41,7 @@ namespace Ryujinx.Ava.UI.Applet bool okPressed = false; - if (ConfigurationState.Instance.IgnoreApplet) + if (ConfigurationState.Instance.System.IgnoreApplet) return false; Dispatcher.UIThread.InvokeAsync(async () => diff --git a/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs b/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs index 7fda4e2d0..3d1bd5f4a 100644 --- a/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs @@ -68,8 +68,9 @@ namespace Ryujinx.Ava.UI.ViewModels.Input public bool IsKeyboard => !IsController; public bool IsRight { get; set; } public bool IsLeft { get; set; } - - public bool HasLed => SelectedGamepad.Features.HasFlag(GamepadFeaturesFlag.Led); + + public bool HasLed => false; //temporary + //SelectedGamepad.Features.HasFlag(GamepadFeaturesFlag.Led); public bool IsModified { get; set; } public event Action NotifyChangesEvent; diff --git a/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs b/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs index 2678bbf98..b2311cfc7 100644 --- a/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs @@ -488,7 +488,6 @@ namespace Ryujinx.Ava.UI.ViewModels EnableDiscordIntegration = config.EnableDiscordIntegration; CheckUpdatesOnStart = config.CheckUpdatesOnStart; ShowConfirmExit = config.ShowConfirmExit; - IgnoreApplet = config.IgnoreApplet; RememberWindowState = config.RememberWindowState; ShowTitleBar = config.ShowTitleBar; HideCursor = (int)config.HideCursor.Value; @@ -532,6 +531,7 @@ namespace Ryujinx.Ava.UI.ViewModels EnableFsIntegrityChecks = config.System.EnableFsIntegrityChecks; DramSize = config.System.DramSize; IgnoreMissingServices = config.System.IgnoreMissingServices; + IgnoreApplet = config.System.IgnoreApplet; // CPU EnablePptc = config.System.EnablePtc; @@ -591,7 +591,6 @@ namespace Ryujinx.Ava.UI.ViewModels config.EnableDiscordIntegration.Value = EnableDiscordIntegration; config.CheckUpdatesOnStart.Value = CheckUpdatesOnStart; config.ShowConfirmExit.Value = ShowConfirmExit; - config.IgnoreApplet.Value = IgnoreApplet; config.RememberWindowState.Value = RememberWindowState; config.ShowTitleBar.Value = ShowTitleBar; config.HideCursor.Value = (HideCursorMode)HideCursor; @@ -632,12 +631,10 @@ namespace Ryujinx.Ava.UI.ViewModels } config.System.SystemTimeOffset.Value = Convert.ToInt64((CurrentDate.ToUnixTimeSeconds() + CurrentTime.TotalSeconds) - DateTimeOffset.Now.ToUnixTimeSeconds()); - config.Graphics.VSyncMode.Value = VSyncMode; - config.Graphics.EnableCustomVSyncInterval.Value = EnableCustomVSyncInterval; - config.Graphics.CustomVSyncInterval.Value = CustomVSyncInterval; config.System.EnableFsIntegrityChecks.Value = EnableFsIntegrityChecks; config.System.DramSize.Value = DramSize; config.System.IgnoreMissingServices.Value = IgnoreMissingServices; + config.System.IgnoreApplet.Value = IgnoreApplet; // CPU config.System.EnablePtc.Value = EnablePptc; @@ -646,6 +643,9 @@ namespace Ryujinx.Ava.UI.ViewModels config.System.UseHypervisor.Value = UseHypervisor; // Graphics + config.Graphics.VSyncMode.Value = VSyncMode; + config.Graphics.EnableCustomVSyncInterval.Value = EnableCustomVSyncInterval; + config.Graphics.CustomVSyncInterval.Value = CustomVSyncInterval; config.Graphics.GraphicsBackend.Value = (GraphicsBackend)GraphicsBackendIndex; config.Graphics.PreferredGpu.Value = _gpuIds.ElementAtOrDefault(PreferredGpuIndex); config.Graphics.EnableShaderCache.Value = EnableShaderCache; diff --git a/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml b/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml index 73f74e36f..db7040f4b 100644 --- a/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml +++ b/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml @@ -503,7 +503,7 @@ MinWidth="0" Grid.Column="0" IsChecked="{Binding Config.EnableLedChanging, Mode=TwoWay}"> - + public ReactiveObject IgnoreMissingServices { get; private set; } + + /// + /// Ignore Controller Applet + /// + public ReactiveObject IgnoreApplet { get; private set; } /// /// Uses Hypervisor over JIT if available @@ -404,6 +409,8 @@ namespace Ryujinx.Ava.Utilities.Configuration DramSize.LogChangesToValue(nameof(DramSize)); IgnoreMissingServices = new ReactiveObject(); IgnoreMissingServices.LogChangesToValue(nameof(IgnoreMissingServices)); + IgnoreApplet = new ReactiveObject(); + IgnoreApplet.LogChangesToValue(nameof(IgnoreApplet)); AudioVolume = new ReactiveObject(); AudioVolume.LogChangesToValue(nameof(AudioVolume)); UseHypervisor = new ReactiveObject(); @@ -745,11 +752,6 @@ namespace Ryujinx.Ava.Utilities.Configuration /// public ReactiveObject ShowConfirmExit { get; private set; } - /// - /// Ignore Applet - /// - public ReactiveObject IgnoreApplet { get; private set; } - /// /// Enables or disables save window size, position and state on close. /// @@ -782,8 +784,6 @@ namespace Ryujinx.Ava.Utilities.Configuration EnableDiscordIntegration = new ReactiveObject(); CheckUpdatesOnStart = new ReactiveObject(); ShowConfirmExit = new ReactiveObject(); - IgnoreApplet = new ReactiveObject(); - IgnoreApplet.LogChangesToValue(nameof(IgnoreApplet)); RememberWindowState = new ReactiveObject(); ShowTitleBar = new ReactiveObject(); EnableHardwareAcceleration = new ReactiveObject(); diff --git a/src/Ryujinx/Utilities/Configuration/ConfigurationState.cs b/src/Ryujinx/Utilities/Configuration/ConfigurationState.cs index 21210bb0e..80b3e5c03 100644 --- a/src/Ryujinx/Utilities/Configuration/ConfigurationState.cs +++ b/src/Ryujinx/Utilities/Configuration/ConfigurationState.cs @@ -56,7 +56,6 @@ namespace Ryujinx.Ava.Utilities.Configuration EnableDiscordIntegration = EnableDiscordIntegration, CheckUpdatesOnStart = CheckUpdatesOnStart, ShowConfirmExit = ShowConfirmExit, - IgnoreApplet = IgnoreApplet, RememberWindowState = RememberWindowState, ShowTitleBar = ShowTitleBar, EnableHardwareAcceleration = EnableHardwareAcceleration, @@ -78,6 +77,7 @@ namespace Ryujinx.Ava.Utilities.Configuration MemoryManagerMode = System.MemoryManagerMode, DramSize = System.DramSize, IgnoreMissingServices = System.IgnoreMissingServices, + IgnoreApplet = System.IgnoreApplet, UseHypervisor = System.UseHypervisor, GuiColumns = new GuiColumns { @@ -176,7 +176,6 @@ namespace Ryujinx.Ava.Utilities.Configuration EnableDiscordIntegration.Value = true; CheckUpdatesOnStart.Value = true; ShowConfirmExit.Value = true; - IgnoreApplet.Value = false; RememberWindowState.Value = true; ShowTitleBar.Value = !OperatingSystem.IsWindows(); EnableHardwareAcceleration.Value = true; @@ -200,6 +199,7 @@ namespace Ryujinx.Ava.Utilities.Configuration System.MemoryManagerMode.Value = MemoryManagerMode.HostMappedUnsafe; System.DramSize.Value = MemoryConfiguration.MemoryConfiguration4GiB; System.IgnoreMissingServices.Value = false; + System.IgnoreApplet.Value = false; System.UseHypervisor.Value = true; Multiplayer.LanInterfaceId.Value = "0"; Multiplayer.Mode.Value = MultiplayerMode.Disabled;