diff --git a/.github/labeler.yml b/.github/labeler.yml index ac3c77288..b80dbb1fb 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -18,6 +18,10 @@ gpu: - changed-files: - any-glob-to-any-file: ['src/Ryujinx.Graphics.Vulkan/**', 'src/Spv.Generator/**'] +'graphics-backend:metal': + - changed-files: + - any-glob-to-any-file: ['src/Ryujinx.Graphics.Metal/**', 'src/Ryujinx.Graphics.Metal.SharpMetalExtensions/**'] + gui: - changed-files: - any-glob-to-any-file: ['src/Ryujinx/**', 'src/Ryujinx.UI.Common/**', 'src/Ryujinx.UI.LocaleGenerator/**'] diff --git a/README.md b/README.md index 1532245f2..b8a788013 100644 --- a/README.md +++ b/README.md @@ -54,12 +54,13 @@ failing to meet this requirement may result in a poor gameplay experience or une ## Latest build -Stable builds are made every so often onto a separate "release" branch that then gets put into the releases you know and love. +Stable builds are made every so often, based on the `master` branch, that then gets put into the releases you know and love. These stable builds exist so that the end user can get a more **enjoyable and stable experience**. +They are released every month or so, to ensure consistent updates, while not being an annoying amount of individual updates to download over the course of that month. You can find the latest stable release [here](https://github.com/GreemDev/Ryujinx/releases/latest). -Canary builds are compiled automatically for each commit on the master branch. +Canary builds are compiled automatically for each commit on the `master` branch. While we strive to ensure optimal stability and performance prior to pushing an update, these builds **may be unstable or completely broken**. These canary builds are only recommended for experienced users. @@ -109,7 +110,7 @@ If you are planning to contribute or just want to learn more about this project - **Configuration** The emulator has settings for enabling or disabling some logging, remapping controllers, and more. - You can configure all of them through the graphical interface or manually through the config file, `Config.json`, found in the user folder which can be accessed by clicking `Open Ryujinx Folder` under the File menu in the GUI. + You can configure all of them through the graphical interface or manually through the config file, `Config.json`, found in the Ryujinx data folder which can be accessed by clicking `Open Ryujinx Folder` under the File menu in the GUI. ## License diff --git a/src/Ryujinx.Common/TitleIDs.cs b/src/Ryujinx.Common/TitleIDs.cs index e0cb12026..301dcdbf6 100644 --- a/src/Ryujinx.Common/TitleIDs.cs +++ b/src/Ryujinx.Common/TitleIDs.cs @@ -8,7 +8,7 @@ namespace Ryujinx.Common { public static class TitleIDs { - public static ReactiveObject> CurrentApplication { get; set; } = new(); + public static ReactiveObject> CurrentApplication { get; } = new(); public static GraphicsBackend SelectGraphicsBackend(string titleId, GraphicsBackend currentBackend) { 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)); } diff --git a/src/Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/ApplicationProxy/IApplicationFunctions.cs b/src/Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/ApplicationProxy/IApplicationFunctions.cs index 12c046f56..c782340e8 100644 --- a/src/Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/ApplicationProxy/IApplicationFunctions.cs +++ b/src/Ryujinx.HLE/HOS/Services/Am/AppletOE/ApplicationProxyService/ApplicationProxy/IApplicationFunctions.cs @@ -659,7 +659,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati if (string.IsNullOrWhiteSpace(filePath)) { - throw new InvalidSystemResourceException("JIT (010000000000003B) system title not found! The JIT will not work, provide the system archive to fix this error. (See https://github.com/GreemDev/Ryujinx#requirements for more information)"); + throw new InvalidSystemResourceException("JIT (010000000000003B) system title not found! The JIT will not work, provide the system archive to fix this error. (See https://github.com/Ryubing/Ryujinx#requirements for more information)"); } context.Device.LoadNca(filePath); diff --git a/src/Ryujinx.HLE/HOS/Services/Sdb/Pl/SharedFontManager.cs b/src/Ryujinx.HLE/HOS/Services/Sdb/Pl/SharedFontManager.cs index ea3bd84df..0e02220a0 100644 --- a/src/Ryujinx.HLE/HOS/Services/Sdb/Pl/SharedFontManager.cs +++ b/src/Ryujinx.HLE/HOS/Services/Sdb/Pl/SharedFontManager.cs @@ -105,7 +105,7 @@ namespace Ryujinx.HLE.HOS.Services.Sdb.Pl titleName = "Unknown"; } - throw new InvalidSystemResourceException($"{titleName} ({fontTitle:x8}) system title not found! This font will not work, provide the system archive to fix this error. (See https://github.com/GreemDev/Ryujinx#requirements for more information)"); + throw new InvalidSystemResourceException($"{titleName} ({fontTitle:x8}) system title not found! This font will not work, provide the system archive to fix this error. (See https://github.com/Ryubing/Ryujinx#requirements for more information)"); } } else diff --git a/src/Ryujinx.HLE/PerformanceStatistics.cs b/src/Ryujinx.HLE/PerformanceStatistics.cs index 890bce8bc..e80faa7d2 100644 --- a/src/Ryujinx.HLE/PerformanceStatistics.cs +++ b/src/Ryujinx.HLE/PerformanceStatistics.cs @@ -161,5 +161,20 @@ namespace Ryujinx.HLE { return 1000 / _frameRate[FrameTypeGame]; } + + public string FormatGameFrameRate() + { + double frameRate = GetGameFrameRate(); + double frameTime = GetGameFrameTime(); + + return $"{frameRate:00.00} FPS ({frameTime:00.00}ms)"; + } + + public string FormatFifoPercent() + { + double fifoPercent = GetFifoPercent(); + + return $"FIFO: {fifoPercent:00.00}%"; + } } } diff --git a/src/Ryujinx.HLE/Switch.cs b/src/Ryujinx.HLE/Switch.cs index e15fab03a..86b04061e 100644 --- a/src/Ryujinx.HLE/Switch.cs +++ b/src/Ryujinx.HLE/Switch.cs @@ -34,8 +34,8 @@ namespace Ryujinx.HLE public int CpuCoresCount = 4; //Switch 1 has 4 cores - public VSyncMode VSyncMode { get; set; } = VSyncMode.Switch; - public bool CustomVSyncIntervalEnabled { get; set; } = false; + public VSyncMode VSyncMode { get; set; } + public bool CustomVSyncIntervalEnabled { get; set; } public int CustomVSyncInterval { get; set; } public long TargetVSyncInterval { get; set; } = 60; diff --git a/src/Ryujinx/AppHost.cs b/src/Ryujinx/AppHost.cs index b2cae2348..4df3eab0d 100644 --- a/src/Ryujinx/AppHost.cs +++ b/src/Ryujinx/AppHost.cs @@ -1151,8 +1151,8 @@ namespace Ryujinx.Ava LocaleManager.Instance[LocaleKeys.VolumeShort] + $": {(int)(Device.GetVolume() * 100)}%", dockedMode, ConfigurationState.Instance.Graphics.AspectRatio.Value.ToText(), - $"{Device.Statistics.GetGameFrameRate():00.00} FPS ({Device.Statistics.GetGameFrameTime():00.00} ms)", - $"FIFO: {Device.Statistics.GetFifoPercent():00.00} %", + Device.Statistics.FormatGameFrameRate(), + Device.Statistics.FormatFifoPercent(), _displayCount)); } diff --git a/src/Ryujinx/Assets/locales.json b/src/Ryujinx/Assets/locales.json index 9117a553b..8ceef5f67 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": { 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/AmiiboWindowViewModel.cs b/src/Ryujinx/UI/ViewModels/AmiiboWindowViewModel.cs index 01a5dadd3..afbc7882f 100644 --- a/src/Ryujinx/UI/ViewModels/AmiiboWindowViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/AmiiboWindowViewModel.cs @@ -432,7 +432,7 @@ namespace Ryujinx.Ava.UI.ViewModels { try { - HttpResponseMessage response = await _httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Head, "https://raw.githubusercontent.com/GreemDev/Ryujinx/refs/heads/master/assets/amiibo/Amiibo.json")); + HttpResponseMessage response = await _httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Head, "https://raw.githubusercontent.com/Ryubing/Ryujinx/refs/heads/master/assets/amiibo/Amiibo.json")); if (response.IsSuccessStatusCode) { @@ -451,7 +451,7 @@ namespace Ryujinx.Ava.UI.ViewModels { try { - HttpResponseMessage response = await _httpClient.GetAsync($"https://raw.githubusercontent.com/GreemDev/Ryujinx/refs/heads/master/assets/amiibo/Amiibo.json"); + HttpResponseMessage response = await _httpClient.GetAsync($"https://raw.githubusercontent.com/Ryubing/Ryujinx/refs/heads/master/assets/amiibo/Amiibo.json"); if (response.IsSuccessStatusCode) { 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}"> - + diff --git a/src/Ryujinx/UI/Windows/AboutWindow.axaml b/src/Ryujinx/UI/Windows/AboutWindow.axaml index 1b00ad23c..df880160f 100644 --- a/src/Ryujinx/UI/Windows/AboutWindow.axaml +++ b/src/Ryujinx/UI/Windows/AboutWindow.axaml @@ -182,7 +182,7 @@ HorizontalAlignment="Left" Background="Transparent" Click="Button_OnClick" - Tag="https://github.com/GreemDev/Ryujinx/graphs/contributors?type=a"> + Tag="https://github.com/Ryubing/Ryujinx/graphs/contributors?type=a"> 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;