From 221524d879bc82077db182a49da027606c944c6c Mon Sep 17 00:00:00 2001 From: Jacobwasbeast <38381609+Jacobwasbeast@users.noreply.github.com> Date: Fri, 20 Dec 2024 13:54:27 -0600 Subject: [PATCH 01/27] Added Support for 532-Byte Amiibo BIN Files (#412) Added functionality to load 532-byte Amiibo BIN files, commonly used in Tagmo and similar tools. These files were missing the following pages. * 133 (85h) PWD * 134 (86h) PACK RFUI These pages can be added as null bytes if not present. The system seems to function correctly without them. --- .../Nfc/AmiiboDecryption/AmiiboBinReader.cs | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/Ryujinx.HLE/HOS/Services/Nfc/AmiiboDecryption/AmiiboBinReader.cs b/src/Ryujinx.HLE/HOS/Services/Nfc/AmiiboDecryption/AmiiboBinReader.cs index 13a5ef998..d0225da8d 100644 --- a/src/Ryujinx.HLE/HOS/Services/Nfc/AmiiboDecryption/AmiiboBinReader.cs +++ b/src/Ryujinx.HLE/HOS/Services/Nfc/AmiiboDecryption/AmiiboBinReader.cs @@ -33,9 +33,12 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.AmiiboDecryption const int pageSize = 4; const int totalBytes = totalPages * pageSize; - if (fileBytes.Length < totalBytes) + if (fileBytes.Length == 532) { - return new VirtualAmiiboFile(); + // add 8 bytes to the end of the file + byte[] newFileBytes = new byte[totalBytes]; + Array.Copy(fileBytes, newFileBytes, fileBytes.Length); + fileBytes = newFileBytes; } AmiiboDecrypter amiiboDecryptor = new AmiiboDecrypter(keyRetailBinPath); @@ -171,6 +174,14 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.AmiiboDecryption return false; } + if (readBytes.Length == 532) + { + // add 8 bytes to the end of the file + byte[] newFileBytes = new byte[540]; + Array.Copy(readBytes, newFileBytes, readBytes.Length); + readBytes = newFileBytes; + } + AmiiboDecrypter amiiboDecryptor = new AmiiboDecrypter(keyRetailBinPath); AmiiboDump amiiboDump = amiiboDecryptor.DecryptAmiiboDump(readBytes); @@ -231,6 +242,14 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.AmiiboDecryption return false; } + if (readBytes.Length == 532) + { + // add 8 bytes to the end of the file + byte[] newFileBytes = new byte[540]; + Array.Copy(readBytes, newFileBytes, readBytes.Length); + readBytes = newFileBytes; + } + AmiiboDecrypter amiiboDecryptor = new AmiiboDecrypter(keyRetailBinPath); AmiiboDump amiiboDump = amiiboDecryptor.DecryptAmiiboDump(readBytes); amiiboDump.AmiiboNickname = newNickName; From 381921390af49697cb8ee10d1bf80a1a8bacc603 Mon Sep 17 00:00:00 2001 From: Evan Husted Date: Fri, 20 Dec 2024 15:41:18 -0600 Subject: [PATCH 02/27] UI: Only show Amiibo bin scan menu item if the key file exists --- distribution/misc/macOS.svg | 61 ------------------- .../Nfc/AmiiboDecryption/AmiiboBinReader.cs | 7 +-- .../UI/ViewModels/MainWindowViewModel.cs | 6 ++ .../UI/Views/Main/MainMenuBarView.axaml | 1 + .../UI/Views/Main/MainMenuBarView.axaml.cs | 2 +- 5 files changed, 11 insertions(+), 66 deletions(-) delete mode 100644 distribution/misc/macOS.svg diff --git a/distribution/misc/macOS.svg b/distribution/misc/macOS.svg deleted file mode 100644 index 4bdd453a8..000000000 --- a/distribution/misc/macOS.svg +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/Ryujinx.HLE/HOS/Services/Nfc/AmiiboDecryption/AmiiboBinReader.cs b/src/Ryujinx.HLE/HOS/Services/Nfc/AmiiboDecryption/AmiiboBinReader.cs index d0225da8d..a0b8b5414 100644 --- a/src/Ryujinx.HLE/HOS/Services/Nfc/AmiiboDecryption/AmiiboBinReader.cs +++ b/src/Ryujinx.HLE/HOS/Services/Nfc/AmiiboDecryption/AmiiboBinReader.cs @@ -333,10 +333,9 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.AmiiboDecryption return Path.Combine(AppDataManager.KeysDirPath, "key_retail.bin"); } - public static bool HasKeyRetailBinPath() - { - return File.Exists(GetKeyRetailBinPath()); - } + public static bool HasKeyRetailBinPath => File.Exists(GetKeyRetailBinPath()); + + public static DateTime DateTimeFromTag(ushort value) { try diff --git a/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs b/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs index 283f9b9da..f607b71f6 100644 --- a/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs @@ -127,6 +127,9 @@ namespace Ryujinx.Ava.UI.ViewModels public IEnumerable LastLdnGameData; + // The UI specifically uses a thicker bordered variant of the icon to avoid crunching out the border at lower resolutions. + // For an example of this, download canary 1.2.95, then open the settings menu, and look at the icon in the top-left. + // The border gets reduced to colored pixels in the 4 corners. public static readonly Bitmap IconBitmap = new(Assembly.GetAssembly(typeof(ConfigurationState))!.GetManifestResourceStream("Ryujinx.UI.Common.Resources.Logo_Thiccjinx.png")!); @@ -330,6 +333,9 @@ namespace Ryujinx.Ava.UI.ViewModels OnPropertyChanged(); } } + + public bool CanScanAmiiboBinaries => AmiiboBinReader.HasKeyRetailBinPath; + public bool ShowLoadProgress { get => _showLoadProgress; diff --git a/src/Ryujinx/UI/Views/Main/MainMenuBarView.axaml b/src/Ryujinx/UI/Views/Main/MainMenuBarView.axaml index d9690e8ce..be805566e 100644 --- a/src/Ryujinx/UI/Views/Main/MainMenuBarView.axaml +++ b/src/Ryujinx/UI/Views/Main/MainMenuBarView.axaml @@ -247,6 +247,7 @@ Click="OpenBinFile" Header="{ext:Locale MenuBarActionsScanAmiiboBin}" Icon="{ext:Icon mdi-cube-scan}" + IsVisible="{Binding CanScanAmiiboBinaries}" IsEnabled="{Binding IsAmiiboBinRequested}" /> Date: Fri, 20 Dec 2024 15:44:01 -0600 Subject: [PATCH 03/27] HLE: rename AmiiboDecrypter to AmiiboDecryptor --- .../HOS/Services/Nfc/AmiiboDecryption/AmiiboBinReader.cs | 6 +++--- .../{AmiiboDecrypter.cs => AmiiboDecryptor.cs} | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) rename src/Ryujinx.HLE/HOS/Services/Nfc/AmiiboDecryption/{AmiiboDecrypter.cs => AmiiboDecryptor.cs} (77%) diff --git a/src/Ryujinx.HLE/HOS/Services/Nfc/AmiiboDecryption/AmiiboBinReader.cs b/src/Ryujinx.HLE/HOS/Services/Nfc/AmiiboDecryption/AmiiboBinReader.cs index a0b8b5414..65638b04e 100644 --- a/src/Ryujinx.HLE/HOS/Services/Nfc/AmiiboDecryption/AmiiboBinReader.cs +++ b/src/Ryujinx.HLE/HOS/Services/Nfc/AmiiboDecryption/AmiiboBinReader.cs @@ -41,7 +41,7 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.AmiiboDecryption fileBytes = newFileBytes; } - AmiiboDecrypter amiiboDecryptor = new AmiiboDecrypter(keyRetailBinPath); + AmiiboDecryptor amiiboDecryptor = new(keyRetailBinPath); AmiiboDump amiiboDump = amiiboDecryptor.DecryptAmiiboDump(fileBytes); byte[] titleId = new byte[8]; @@ -182,7 +182,7 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.AmiiboDecryption readBytes = newFileBytes; } - AmiiboDecrypter amiiboDecryptor = new AmiiboDecrypter(keyRetailBinPath); + AmiiboDecryptor amiiboDecryptor = new AmiiboDecryptor(keyRetailBinPath); AmiiboDump amiiboDump = amiiboDecryptor.DecryptAmiiboDump(readBytes); byte[] oldData = amiiboDump.GetData(); @@ -250,7 +250,7 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.AmiiboDecryption readBytes = newFileBytes; } - AmiiboDecrypter amiiboDecryptor = new AmiiboDecrypter(keyRetailBinPath); + AmiiboDecryptor amiiboDecryptor = new AmiiboDecryptor(keyRetailBinPath); AmiiboDump amiiboDump = amiiboDecryptor.DecryptAmiiboDump(readBytes); amiiboDump.AmiiboNickname = newNickName; byte[] oldData = amiiboDump.GetData(); diff --git a/src/Ryujinx.HLE/HOS/Services/Nfc/AmiiboDecryption/AmiiboDecrypter.cs b/src/Ryujinx.HLE/HOS/Services/Nfc/AmiiboDecryption/AmiiboDecryptor.cs similarity index 77% rename from src/Ryujinx.HLE/HOS/Services/Nfc/AmiiboDecryption/AmiiboDecrypter.cs rename to src/Ryujinx.HLE/HOS/Services/Nfc/AmiiboDecryption/AmiiboDecryptor.cs index 71758c947..cc6d02ea2 100644 --- a/src/Ryujinx.HLE/HOS/Services/Nfc/AmiiboDecryption/AmiiboDecrypter.cs +++ b/src/Ryujinx.HLE/HOS/Services/Nfc/AmiiboDecryption/AmiiboDecryptor.cs @@ -2,12 +2,12 @@ using System.IO; namespace Ryujinx.HLE.HOS.Services.Nfc.AmiiboDecryption { - public class AmiiboDecrypter + public class AmiiboDecryptor { public AmiiboMasterKey DataKey { get; private set; } public AmiiboMasterKey TagKey { get; private set; } - public AmiiboDecrypter(string keyRetailBinPath) + public AmiiboDecryptor(string keyRetailBinPath) { var combinedKeys = File.ReadAllBytes(keyRetailBinPath); var keys = AmiiboMasterKey.FromCombinedBin(combinedKeys); @@ -18,7 +18,7 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.AmiiboDecryption public AmiiboDump DecryptAmiiboDump(byte[] encryptedDumpData) { // Initialize AmiiboDump with encrypted data - AmiiboDump amiiboDump = new AmiiboDump(encryptedDumpData, DataKey, TagKey, isLocked: true); + AmiiboDump amiiboDump = new(encryptedDumpData, DataKey, TagKey, isLocked: true); // Unlock (decrypt) the dump amiiboDump.Unlock(); @@ -32,7 +32,7 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.AmiiboDecryption public AmiiboDump EncryptAmiiboDump(byte[] decryptedDumpData) { // Initialize AmiiboDump with decrypted data - AmiiboDump amiiboDump = new AmiiboDump(decryptedDumpData, DataKey, TagKey, isLocked: false); + AmiiboDump amiiboDump = new(decryptedDumpData, DataKey, TagKey, isLocked: false); // Lock (encrypt) the dump amiiboDump.Lock(); From bb3d95722ed5383c7157b3be610eca34c1384605 Mon Sep 17 00:00:00 2001 From: Evan Husted Date: Fri, 20 Dec 2024 15:51:24 -0600 Subject: [PATCH 04/27] infra: fix casing in release artifact tables --- .github/workflows/canary.yml | 14 +++++++------- .github/workflows/release.yml | 14 +++++++------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/.github/workflows/canary.yml b/.github/workflows/canary.yml index b352e82d7..09cd124ce 100644 --- a/.github/workflows/canary.yml +++ b/.github/workflows/canary.yml @@ -61,9 +61,9 @@ jobs: | Platform | Artifact | |--|--| - | Windows 64 bit | [Canary Windows Artifact](https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-win_x64.zip) | - | Linux 64 bit | [Canary Linux Artifact](https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz) | - | Linux arm 64 bit | [Canary Linux arm Artifact](https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-linux_arm64.tar.gz) | + | Windows 64-bit | [Canary Windows Artifact](https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-win_x64.zip) | + | Linux 64-bit | [Canary Linux Artifact](https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz) | + | Linux ARM 64-bit | [Canary Linux ARM Artifact](https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-linux_arm64.tar.gz) | | macOS | [Canary macOS artifact](https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-macos_universal.app.tar.gz) | **Full Changelog**: https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_SOURCE_REPO }}/compare/Canary-${{ steps.version_info.outputs.prev_build_version }}...Canary-${{ steps.version_info.outputs.build_version }} @@ -200,10 +200,10 @@ jobs: | Platform | Artifact | |--|--| - | Windows 64 bit | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-win_x64.zip | - | Linux 64 bit | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz | - | Linux arm 64 bit | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-linux_arm64.tar.gz | - | Macos | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-macos_universal.app.tar.gz | + | Windows 64-bit | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-win_x64.zip | + | Linux 64-bit | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz | + | Linux ARM 64-bit | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-linux_arm64.tar.gz | + | macOS | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-macos_universal.app.tar.gz | "**Full Changelog**: https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_SOURCE_REPO }}/compare/Canary-${{ steps.version_info.outputs.prev_build_version }}...Canary-${{ steps.version_info.outputs.build_version }}" omitBodyDuringUpdate: true diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 815321dfe..b81ab70f4 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -57,9 +57,9 @@ jobs: # Regular builds: | Platform | Artifact | |--|--| - | Windows 64 bit | [Release Windows Artifact](https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-win_x64.zip) | - | Linux 64 bit | [Release Linux Artifact](https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz) | - | Linux arm 64 bit | [Release Linux arm Artifact](https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_arm64.tar.gz) | + | Windows 64-bit | [Release Windows Artifact](https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-win_x64.zip) | + | Linux 64-bit | [Release Linux Artifact](https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz) | + | Linux ARM 64-bit | [Release Linux ARM Artifact](https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_arm64.tar.gz) | | macOS | [Release macOS Artifact](https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-macos_universal.app.tar.gz) | **Full Changelog**: https://github.com/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/compare/${{ steps.version_info.outputs.prev_build_version }}...${{ steps.version_info.outputs.build_version }} @@ -189,10 +189,10 @@ jobs: # Regular builds: | Platform | Artifact | |--|--| - | Windows 64 bit | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-win_x64.zip | - | Linux 64 bit | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz | - | Linux arm 64 bit | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_arm64.tar.gz | - | Macos | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-macos_universal.app.tar.gz | + | Windows 64-bit | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-win_x64.zip | + | Linux 64-bit | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz | + | Linux ARM 64-bit | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_arm64.tar.gz | + | macOS | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-macos_universal.app.tar.gz | "**Full Changelog**: https://github.com/${{ github.repository }}/compare/${{ steps.version_info.outputs.prev_build_version }}...${{ steps.version_info.outputs.build_version }}" omitBodyDuringUpdate: true From d68295e57de36f9156674fd28786f4f0eda0d265 Mon Sep 17 00:00:00 2001 From: Evan Husted Date: Fri, 20 Dec 2024 16:03:03 -0600 Subject: [PATCH 05/27] infra: remove duplicate tables, I think this is ignored entirely anyways due to omitBodyDuringUpdate. --- .github/workflows/canary.yml | 14 +------------- .github/workflows/release.yml | 11 +---------- 2 files changed, 2 insertions(+), 23 deletions(-) diff --git a/.github/workflows/canary.yml b/.github/workflows/canary.yml index 09cd124ce..3100671e9 100644 --- a/.github/workflows/canary.yml +++ b/.github/workflows/canary.yml @@ -272,19 +272,7 @@ jobs: name: "Canary ${{ steps.version_info.outputs.build_version }}" artifacts: "publish_ava/*.tar.gz, publish_headless/*.tar.gz" tag: ${{ steps.version_info.outputs.build_version }} - body: | - # Canary builds: - - These builds are experimental and may sometimes not work, use [regular builds](https://github.com/GreemDev/Ryujinx/releases/latest) instead if that sounds like something you don't want to deal with. - - | Platform | Artifact | - |--|--| - | Windows 64 bit | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-win_x64.zip | - | Linux 64 bit | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz | - | Linux arm 64 bit | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-linux_arm64.tar.gz | - | Macos | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-macos_universal.app.tar.gz | - - "**Full Changelog**: https://github.com/${{ github.repository }}/compare/Canary-${{ steps.version_info.outputs.prev_build_version }}...Canary-${{ steps.version_info.outputs.build_version }}" + body: "" omitBodyDuringUpdate: true allowUpdates: true replacesArtifacts: true diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b81ab70f4..59c31c71b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -261,16 +261,7 @@ jobs: name: ${{ steps.version_info.outputs.build_version }} artifacts: "publish/*.tar.gz, publish_headless/*.tar.gz" tag: ${{ steps.version_info.outputs.build_version }} - body: | - # Regular builds: - | Platform | Artifact | - |--|--| - | Windows 64 bit | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-win_x64.zip | - | Linux 64 bit | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_x64.tar.gz | - | Linux arm 64 bit | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-linux_arm64.tar.gz | - | Macos | https://github.com/${{ github.repository }}/releases/download/${{ steps.version_info.outputs.build_version }}/ryujinx-${{ steps.version_info.outputs.build_version }}-macos_universal.app.tar.gz | - - "**Full Changelog**: https://github.com/${{ github.repository }}/compare/${{ steps.version_info.outputs.prev_build_version }}...${{ steps.version_info.outputs.build_version }}" + body: "" omitBodyDuringUpdate: true allowUpdates: true replacesArtifacts: true From c77c1acd08ccf68835d216342810a640c5b36c80 Mon Sep 17 00:00:00 2001 From: sunshineinabox Date: Fri, 20 Dec 2024 14:31:05 -0800 Subject: [PATCH 06/27] Resolve Image Usage Validation Error (#296) This was a missed change that would resolve Image Usage validation error that is created fairly frequently. ``VUID-VkImageViewCreateInfo-pNext-02662(ERROR / SPEC): msgNum: -55646969 - Validation Error: [ VUID-VkImageViewCreateInfo-pNext-02662 ] Object 0: handle = 0x260b9d1f6b8, type = VK_OBJECT_TYPE_IMAGE; | MessageID = 0xfcaee507 | vkCreateImageView(): pCreateInfo->pNext.usage (VK_IMAGE_USAGE_SAMPLED_BIT|VK_IMAGE_USAGE_STORAGE_BIT) must not include any bits that were not set in VkImageCreateInfo::usage (VK_IMAGE_USAGE_TRANSFER_SRC_BIT|VK_IMAGE_USAGE_TRANSFER_DST_BIT|VK_IMAGE_USAGE_SAMPLED_BIT|VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) of the image. The Vulkan spec states: If the pNext chain includes a VkImageViewUsageCreateInfo structure, and image was not created with a VkImageStencilUsageCreateInfo structure included in the pNext chain of VkImageCreateInfo, its usage member must not include any bits that were not set in the usage member of the VkImageCreateInfo structure used to create image (https://vulkan.lunarg.com/doc/view/1.3.290.0/windows/1.3-extensions/vkspec.html#VUID-VkImageViewCreateInfo-pNext-02662) Objects: 1 [0] 0x260b9d1f6b8, type: 10, name: NULL `` --- .../FormatCapabilities.cs | 4 ++-- .../PipelineConverter.cs | 20 +++++++++++++++---- src/Ryujinx.Graphics.Vulkan/TextureStorage.cs | 12 +++++------ src/Ryujinx.Graphics.Vulkan/TextureView.cs | 7 +++++-- 4 files changed, 29 insertions(+), 14 deletions(-) diff --git a/src/Ryujinx.Graphics.Vulkan/FormatCapabilities.cs b/src/Ryujinx.Graphics.Vulkan/FormatCapabilities.cs index 5a3bd61bd..4971a63b6 100644 --- a/src/Ryujinx.Graphics.Vulkan/FormatCapabilities.cs +++ b/src/Ryujinx.Graphics.Vulkan/FormatCapabilities.cs @@ -148,7 +148,7 @@ namespace Ryujinx.Graphics.Vulkan return (formatFeatureFlags & flags) == flags; } - public VkFormat ConvertToVkFormat(Format srcFormat) + public VkFormat ConvertToVkFormat(Format srcFormat, bool storageFeatureFlagRequired) { var format = FormatTable.GetFormat(srcFormat); @@ -165,7 +165,7 @@ namespace Ryujinx.Graphics.Vulkan requiredFeatures |= FormatFeatureFlags.ColorAttachmentBit; } - if (srcFormat.IsImageCompatible()) + if (srcFormat.IsImageCompatible() && storageFeatureFlagRequired) { requiredFeatures |= FormatFeatureFlags.StorageImageBit; } diff --git a/src/Ryujinx.Graphics.Vulkan/PipelineConverter.cs b/src/Ryujinx.Graphics.Vulkan/PipelineConverter.cs index 85069c6b2..8a895f927 100644 --- a/src/Ryujinx.Graphics.Vulkan/PipelineConverter.cs +++ b/src/Ryujinx.Graphics.Vulkan/PipelineConverter.cs @@ -29,11 +29,17 @@ namespace Ryujinx.Graphics.Vulkan int colorCount = 0; int maxColorAttachmentIndex = -1; + bool isNotMsOrSupportsStorage = gd.Capabilities.SupportsShaderStorageImageMultisample || + !state.DepthStencilFormat.IsImageCompatible(); + for (int i = 0; i < state.AttachmentEnable.Length; i++) { if (state.AttachmentEnable[i]) { - attachmentFormats[attachmentCount] = gd.FormatCapabilities.ConvertToVkFormat(state.AttachmentFormats[i]); + bool isNotMsOrSupportsStorageAttachments = gd.Capabilities.SupportsShaderStorageImageMultisample || + !state.AttachmentFormats[i].IsImageCompatible(); + + attachmentFormats[attachmentCount] = gd.FormatCapabilities.ConvertToVkFormat(state.AttachmentFormats[i], isNotMsOrSupportsStorageAttachments); attachmentIndices[attachmentCount++] = i; colorCount++; @@ -43,7 +49,7 @@ namespace Ryujinx.Graphics.Vulkan if (state.DepthStencilEnable) { - attachmentFormats[attachmentCount++] = gd.FormatCapabilities.ConvertToVkFormat(state.DepthStencilFormat); + attachmentFormats[attachmentCount++] = gd.FormatCapabilities.ConvertToVkFormat(state.DepthStencilFormat, isNotMsOrSupportsStorage); } if (attachmentCount != 0) @@ -296,7 +302,10 @@ namespace Ryujinx.Graphics.Vulkan { if (state.AttachmentEnable[i]) { - pipeline.Internal.AttachmentFormats[attachmentCount++] = gd.FormatCapabilities.ConvertToVkFormat(state.AttachmentFormats[i]); + bool isNotMsOrSupportsStorage = gd.Capabilities.SupportsShaderStorageImageMultisample || + !state.AttachmentFormats[i].IsImageCompatible(); + + pipeline.Internal.AttachmentFormats[attachmentCount++] = gd.FormatCapabilities.ConvertToVkFormat(state.AttachmentFormats[i], isNotMsOrSupportsStorage); maxColorAttachmentIndex = i; if (state.AttachmentFormats[i].IsInteger()) @@ -310,7 +319,10 @@ namespace Ryujinx.Graphics.Vulkan if (state.DepthStencilEnable) { - pipeline.Internal.AttachmentFormats[attachmentCount++] = gd.FormatCapabilities.ConvertToVkFormat(state.DepthStencilFormat); + bool isNotMsOrSupportsStorage = !state.DepthStencilFormat.IsImageCompatible() || + gd.Capabilities.SupportsShaderStorageImageMultisample; + + pipeline.Internal.AttachmentFormats[attachmentCount++] = gd.FormatCapabilities.ConvertToVkFormat(state.DepthStencilFormat, isNotMsOrSupportsStorage); } pipeline.ColorBlendAttachmentStateCount = (uint)(maxColorAttachmentIndex + 1); diff --git a/src/Ryujinx.Graphics.Vulkan/TextureStorage.cs b/src/Ryujinx.Graphics.Vulkan/TextureStorage.cs index 10b36a3f9..51ef528d4 100644 --- a/src/Ryujinx.Graphics.Vulkan/TextureStorage.cs +++ b/src/Ryujinx.Graphics.Vulkan/TextureStorage.cs @@ -77,7 +77,9 @@ namespace Ryujinx.Graphics.Vulkan _device = device; _info = info; - var format = _gd.FormatCapabilities.ConvertToVkFormat(info.Format); + bool isMsImageStorageSupported = gd.Capabilities.SupportsShaderStorageImageMultisample || !info.Target.IsMultisample(); + + var format = _gd.FormatCapabilities.ConvertToVkFormat(info.Format, isMsImageStorageSupported); var levels = (uint)info.Levels; var layers = (uint)info.GetLayers(); var depth = (uint)(info.Target == Target.Texture3D ? info.Depth : 1); @@ -91,7 +93,7 @@ namespace Ryujinx.Graphics.Vulkan var sampleCountFlags = ConvertToSampleCountFlags(gd.Capabilities.SupportedSampleCounts, (uint)info.Samples); - var usage = GetImageUsage(info.Format, info.Target, gd.Capabilities); + var usage = GetImageUsage(info.Format, gd.Capabilities, isMsImageStorageSupported, true); var flags = ImageCreateFlags.CreateMutableFormatBit | ImageCreateFlags.CreateExtendedUsageBit; @@ -305,7 +307,7 @@ namespace Ryujinx.Graphics.Vulkan } } - public static ImageUsageFlags GetImageUsage(Format format, Target target, in HardwareCapabilities capabilities) + public static ImageUsageFlags GetImageUsage(Format format, in HardwareCapabilities capabilities, bool isMsImageStorageSupported, bool extendedUsage) { var usage = DefaultUsageFlags; @@ -318,9 +320,7 @@ namespace Ryujinx.Graphics.Vulkan usage |= ImageUsageFlags.ColorAttachmentBit; } - bool supportsMsStorage = capabilities.SupportsShaderStorageImageMultisample; - - if (format.IsImageCompatible() && (supportsMsStorage || !target.IsMultisample())) + if ((format.IsImageCompatible() && isMsImageStorageSupported) || extendedUsage) { usage |= ImageUsageFlags.StorageBit; } diff --git a/src/Ryujinx.Graphics.Vulkan/TextureView.cs b/src/Ryujinx.Graphics.Vulkan/TextureView.cs index b7b936809..64d976a45 100644 --- a/src/Ryujinx.Graphics.Vulkan/TextureView.cs +++ b/src/Ryujinx.Graphics.Vulkan/TextureView.cs @@ -61,8 +61,11 @@ namespace Ryujinx.Graphics.Vulkan gd.Textures.Add(this); - var format = _gd.FormatCapabilities.ConvertToVkFormat(info.Format); - var usage = TextureStorage.GetImageUsage(info.Format, info.Target, gd.Capabilities); + bool isMsImageStorageSupported = gd.Capabilities.SupportsShaderStorageImageMultisample || !info.Target.IsMultisample(); + + var format = _gd.FormatCapabilities.ConvertToVkFormat(info.Format, isMsImageStorageSupported); + var usage = TextureStorage.GetImageUsage(info.Format, gd.Capabilities, isMsImageStorageSupported, false); + var levels = (uint)info.Levels; var layers = (uint)info.GetLayers(); From a460eda1952173483f0e33c42fb05125e53a7fb9 Mon Sep 17 00:00:00 2001 From: GabCoolGuy Date: Sat, 21 Dec 2024 18:19:29 +0100 Subject: [PATCH 07/27] UI: Fixed some light theme colors (#420) Closes #419 --- src/Ryujinx/Assets/Styles/Themes.xaml | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/src/Ryujinx/Assets/Styles/Themes.xaml b/src/Ryujinx/Assets/Styles/Themes.xaml index 46e298035..3a0bd4217 100644 --- a/src/Ryujinx/Assets/Styles/Themes.xaml +++ b/src/Ryujinx/Assets/Styles/Themes.xaml @@ -4,11 +4,10 @@ + #008AA8 #FF00FABB #FFF0F0F0 #FFd6d6d6 - #FFFFFFFF - #FFFFFFFF #FF000000 #C1C1C1 #b3ffffff @@ -22,16 +21,19 @@ + #3ddcff #FF00FABB - #FFF0F0F0 - #FFd6d6d6 - #FFFFFFFF - #FFFFFFFF + #dedede + #c2c2c2 #FF000000 #C1C1C1 #b3ffffff #80cccccc #A0000000 + #fffcd12a + #13c3a4 + #FFFF4554 + #6483F5 #FF00FABB #FF2D2D2D #FF505050 - #FFFFFFFF - #FFFFFFFF #FFFFFFFF #3D3D3D #0FFFFFFF #1EFFFFFF #A0FFFFFF + #fffcd12a + #FF2EEAC9 + #FFFF4554 + #6483F5 From 5b36a9cf9fc1d098468171e57d9671cc3ee9a9f7 Mon Sep 17 00:00:00 2001 From: Evan Husted Date: Sat, 21 Dec 2024 16:59:13 -0600 Subject: [PATCH 08/27] chore: small cleanups --- .../HOS/Services/Nfc/AmiiboDecryption/AmiiboBinReader.cs | 2 +- .../HOS/Services/Nfc/AmiiboDecryption/AmiiboDump.cs | 2 +- .../HOS/Services/Nfc/AmiiboDecryption/AmiiboMasterKey.cs | 5 +---- src/Ryujinx.UI.Common/Helper/OpenHelper.cs | 3 +++ src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs | 2 +- src/Ryujinx/UI/Views/Main/MainMenuBarView.axaml.cs | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Ryujinx.HLE/HOS/Services/Nfc/AmiiboDecryption/AmiiboBinReader.cs b/src/Ryujinx.HLE/HOS/Services/Nfc/AmiiboDecryption/AmiiboBinReader.cs index 65638b04e..03063cb53 100644 --- a/src/Ryujinx.HLE/HOS/Services/Nfc/AmiiboDecryption/AmiiboBinReader.cs +++ b/src/Ryujinx.HLE/HOS/Services/Nfc/AmiiboDecryption/AmiiboBinReader.cs @@ -333,7 +333,7 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.AmiiboDecryption return Path.Combine(AppDataManager.KeysDirPath, "key_retail.bin"); } - public static bool HasKeyRetailBinPath => File.Exists(GetKeyRetailBinPath()); + public static bool HasAmiiboKeyFile => File.Exists(GetKeyRetailBinPath()); public static DateTime DateTimeFromTag(ushort value) diff --git a/src/Ryujinx.HLE/HOS/Services/Nfc/AmiiboDecryption/AmiiboDump.cs b/src/Ryujinx.HLE/HOS/Services/Nfc/AmiiboDecryption/AmiiboDump.cs index 7343a40ca..37d587dac 100644 --- a/src/Ryujinx.HLE/HOS/Services/Nfc/AmiiboDecryption/AmiiboDump.cs +++ b/src/Ryujinx.HLE/HOS/Services/Nfc/AmiiboDecryption/AmiiboDump.cs @@ -36,7 +36,7 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.AmiiboDecryption private byte[] DeriveKey(AmiiboMasterKey key, bool deriveAes, out byte[] derivedAesKey, out byte[] derivedAesIv) { - List seed = new List(); + List seed = []; // Start with the type string (14 bytes) seed.AddRange(key.TypeString); diff --git a/src/Ryujinx.HLE/HOS/Services/Nfc/AmiiboDecryption/AmiiboMasterKey.cs b/src/Ryujinx.HLE/HOS/Services/Nfc/AmiiboDecryption/AmiiboMasterKey.cs index f61f8c84d..940dc4c85 100644 --- a/src/Ryujinx.HLE/HOS/Services/Nfc/AmiiboDecryption/AmiiboMasterKey.cs +++ b/src/Ryujinx.HLE/HOS/Services/Nfc/AmiiboDecryption/AmiiboMasterKey.cs @@ -33,10 +33,7 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.AmiiboDecryption byte[] dataBin = combinedBin.Take(80).ToArray(); byte[] tagBin = combinedBin.Skip(80).Take(80).ToArray(); - AmiiboMasterKey dataKey = new AmiiboMasterKey(dataBin); - AmiiboMasterKey tagKey = new AmiiboMasterKey(tagBin); - - return (dataKey, tagKey); + return (new AmiiboMasterKey(dataBin), new AmiiboMasterKey(tagBin)); } } } diff --git a/src/Ryujinx.UI.Common/Helper/OpenHelper.cs b/src/Ryujinx.UI.Common/Helper/OpenHelper.cs index 8b0e1f1fd..bf398a355 100644 --- a/src/Ryujinx.UI.Common/Helper/OpenHelper.cs +++ b/src/Ryujinx.UI.Common/Helper/OpenHelper.cs @@ -1,3 +1,4 @@ +using Gommon; using Ryujinx.Common.Logging; using System; using System.Diagnostics; @@ -34,6 +35,8 @@ namespace Ryujinx.UI.Common.Helper } } + public static void OpenFolder(FilePath path) => OpenFolder(path.Path); + public static void LocateFile(string path) { if (File.Exists(path)) diff --git a/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs b/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs index f607b71f6..35a1c4a4d 100644 --- a/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs @@ -334,7 +334,7 @@ namespace Ryujinx.Ava.UI.ViewModels } } - public bool CanScanAmiiboBinaries => AmiiboBinReader.HasKeyRetailBinPath; + public bool CanScanAmiiboBinaries => AmiiboBinReader.HasAmiiboKeyFile; public bool ShowLoadProgress { diff --git a/src/Ryujinx/UI/Views/Main/MainMenuBarView.axaml.cs b/src/Ryujinx/UI/Views/Main/MainMenuBarView.axaml.cs index 04c303cd3..fa900be81 100644 --- a/src/Ryujinx/UI/Views/Main/MainMenuBarView.axaml.cs +++ b/src/Ryujinx/UI/Views/Main/MainMenuBarView.axaml.cs @@ -178,7 +178,7 @@ namespace Ryujinx.Ava.UI.Views.Main private void ScanBinAmiiboMenuItem_AttachedToVisualTree(object sender, VisualTreeAttachmentEventArgs e) { if (sender is MenuItem) - ViewModel.IsAmiiboBinRequested = ViewModel.IsAmiiboRequested && AmiiboBinReader.HasKeyRetailBinPath; + ViewModel.IsAmiiboBinRequested = ViewModel.IsAmiiboRequested && AmiiboBinReader.HasAmiiboKeyFile; } private async void InstallFileTypes_Click(object sender, RoutedEventArgs e) From 4171913bafa782913f059cd3a62becc2e6194bb2 Mon Sep 17 00:00:00 2001 From: Evan Husted Date: Sat, 21 Dec 2024 17:05:46 -0600 Subject: [PATCH 09/27] misc: One additional usage of Lock & comment why it's not used on the others. --- .../HostTracked/AddressSpacePartitionAllocator.cs | 6 ++++++ src/Ryujinx.HLE/HOS/Kernel/Common/KResourceLimit.cs | 2 +- .../HOS/Kernel/Threading/KCriticalSection.cs | 12 ++++++------ .../Services/Sockets/Bsd/Impl/EventFileDescriptor.cs | 1 + 4 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/Ryujinx.Cpu/Jit/HostTracked/AddressSpacePartitionAllocator.cs b/src/Ryujinx.Cpu/Jit/HostTracked/AddressSpacePartitionAllocator.cs index a49e0179d..f39b295cd 100644 --- a/src/Ryujinx.Cpu/Jit/HostTracked/AddressSpacePartitionAllocator.cs +++ b/src/Ryujinx.Cpu/Jit/HostTracked/AddressSpacePartitionAllocator.cs @@ -115,6 +115,9 @@ namespace Ryujinx.Cpu.Jit.HostTracked } private readonly AddressIntrusiveRedBlackTree _mappingTree; + + // type is not Lock due to the unique usage of this mechanism, + // an arbitrary object is used as the lock passed in by constructor. private readonly object _lock; public Block(MemoryTracking tracking, Func readPtCallback, MemoryBlock memory, ulong size, object locker) : base(memory, size) @@ -174,6 +177,9 @@ namespace Ryujinx.Cpu.Jit.HostTracked private readonly MemoryTracking _tracking; private readonly Func _readPtCallback; + + // type is not Lock due to the unique usage of this mechanism, + // an arbitrary object is used as the lock passed in by constructor. private readonly object _lock; public AddressSpacePartitionAllocator( diff --git a/src/Ryujinx.HLE/HOS/Kernel/Common/KResourceLimit.cs b/src/Ryujinx.HLE/HOS/Kernel/Common/KResourceLimit.cs index 90231b460..ce2b7185a 100644 --- a/src/Ryujinx.HLE/HOS/Kernel/Common/KResourceLimit.cs +++ b/src/Ryujinx.HLE/HOS/Kernel/Common/KResourceLimit.cs @@ -15,7 +15,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Common private readonly long[] _current2; private readonly long[] _peak; - private readonly object _lock = new(); + private readonly Lock _lock = new(); private readonly LinkedList _waitingThreads; diff --git a/src/Ryujinx.HLE/HOS/Kernel/Threading/KCriticalSection.cs b/src/Ryujinx.HLE/HOS/Kernel/Threading/KCriticalSection.cs index bfa6b68f6..b3fe5f1b6 100644 --- a/src/Ryujinx.HLE/HOS/Kernel/Threading/KCriticalSection.cs +++ b/src/Ryujinx.HLE/HOS/Kernel/Threading/KCriticalSection.cs @@ -5,10 +5,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading class KCriticalSection { private readonly KernelContext _context; - private readonly object _lock = new(); private int _recursionCount; - - public object Lock => _lock; + + // type is not Lock due to Monitor class usage + public object Lock { get; } = new(); public KCriticalSection(KernelContext context) { @@ -17,7 +17,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading public void Enter() { - Monitor.Enter(_lock); + Monitor.Enter(Lock); _recursionCount++; } @@ -33,7 +33,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading { ulong scheduledCoresMask = KScheduler.SelectThreads(_context); - Monitor.Exit(_lock); + Monitor.Exit(Lock); KThread currentThread = KernelStatic.GetCurrentThread(); bool isCurrentThreadSchedulable = currentThread != null && currentThread.IsSchedulable; @@ -56,7 +56,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading } else { - Monitor.Exit(_lock); + Monitor.Exit(Lock); } } } diff --git a/src/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Impl/EventFileDescriptor.cs b/src/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Impl/EventFileDescriptor.cs index 5b9e6811d..05fc91d32 100644 --- a/src/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Impl/EventFileDescriptor.cs +++ b/src/Ryujinx.HLE/HOS/Services/Sockets/Bsd/Impl/EventFileDescriptor.cs @@ -10,6 +10,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Bsd.Impl private ulong _value; private readonly EventFdFlags _flags; + // type is not Lock due to Monitor class usage private readonly object _lock = new(); public bool Blocking { get => !_flags.HasFlag(EventFdFlags.NonBlocking); set => throw new NotSupportedException(); } From ba199f432531ec784075c35ffb67b334e7c98db6 Mon Sep 17 00:00:00 2001 From: Evan Husted Date: Sat, 21 Dec 2024 18:34:07 -0600 Subject: [PATCH 10/27] UI: Change "System Version" to "Firmware Version" and change 0.0 when firmware is not installed to NaN --- src/Ryujinx/Assets/locales.json | 40 +++++++++---------- .../UI/ViewModels/MainWindowViewModel.cs | 2 +- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/Ryujinx/Assets/locales.json b/src/Ryujinx/Assets/locales.json index 276c9d983..e4ffb2f77 100644 --- a/src/Ryujinx/Assets/locales.json +++ b/src/Ryujinx/Assets/locales.json @@ -2424,25 +2424,25 @@ { "ID": "StatusBarSystemVersion", "Translations": { - "ar_SA": "إصدار النظام: {0}", - "de_DE": "Systemversion: {0}", - "el_GR": "Έκδοση Συστήματος: {0}", - "en_US": "System Version: {0}", - "es_ES": "Versión del sistema: {0}", - "fr_FR": "Version du Firmware: {0}", - "he_IL": "גרסת מערכת: {0}", - "it_IT": "Versione di sistema: {0}", - "ja_JP": "システムバージョン: {0}", - "ko_KR": "시스템 버전 : {0}", - "no_NO": "System versjon: {0}", - "pl_PL": "Wersja systemu: {0}", - "pt_BR": "Versão do firmware: {0}", - "ru_RU": "Версия прошивки: {0}", - "th_TH": "เวอร์ชั่นของระบบ: {0}", - "tr_TR": "Sistem Sürümü: {0}", - "uk_UA": "Версія системи: {0}", - "zh_CN": "系统固件版本:{0}", - "zh_TW": "系統版本: {0}" + "ar_SA": "", + "de_DE": "", + "el_GR": "", + "en_US": "Firmware Version: {0}", + "es_ES": "", + "fr_FR": "", + "he_IL": "", + "it_IT": "", + "ja_JP": "", + "ko_KR": "", + "no_NO": "", + "pl_PL": "", + "pt_BR": "", + "ru_RU": "", + "th_TH": "", + "tr_TR": "", + "uk_UA": "", + "zh_CN": "", + "zh_TW": "" } }, { @@ -21550,4 +21550,4 @@ } } ] -} \ No newline at end of file +} diff --git a/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs b/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs index 35a1c4a4d..cebd65701 100644 --- a/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs @@ -2015,7 +2015,7 @@ namespace Ryujinx.Ava.UI.ViewModels } else { - LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.StatusBarSystemVersion, "0.0"); + LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.StatusBarSystemVersion, "NaN"); } IsAppletMenuActive = hasApplet; From 77ef82d92a235fac8e2c25fe038591fdd2bfa9d8 Mon Sep 17 00:00:00 2001 From: Evan Husted Date: Sat, 21 Dec 2024 18:57:05 -0600 Subject: [PATCH 11/27] misc: Cache LocalesJson when loading locale --- src/Ryujinx.Common/Utilities/JsonHelper.cs | 10 ++++- src/Ryujinx/Common/LocaleManager.cs | 49 +++++++++------------- 2 files changed, 28 insertions(+), 31 deletions(-) diff --git a/src/Ryujinx.Common/Utilities/JsonHelper.cs b/src/Ryujinx.Common/Utilities/JsonHelper.cs index 276dd5f8c..82eeaddc1 100644 --- a/src/Ryujinx.Common/Utilities/JsonHelper.cs +++ b/src/Ryujinx.Common/Utilities/JsonHelper.cs @@ -1,3 +1,4 @@ +using System; using System.IO; using System.Text; using System.Text.Json; @@ -27,9 +28,14 @@ namespace Ryujinx.Common.Utilities ReadCommentHandling = JsonCommentHandling.Skip }; - public static string Serialize(T value, JsonTypeInfo typeInfo) => JsonSerializer.Serialize(value, typeInfo); + public static string Serialize(T value, JsonTypeInfo typeInfo) + => JsonSerializer.Serialize(value, typeInfo); - public static T Deserialize(string value, JsonTypeInfo typeInfo) => JsonSerializer.Deserialize(value, typeInfo); + public static T Deserialize(string value, JsonTypeInfo typeInfo) + => JsonSerializer.Deserialize(value, typeInfo); + + public static T Deserialize(ReadOnlySpan utf8Value, JsonTypeInfo typeInfo) + => JsonSerializer.Deserialize(utf8Value, typeInfo); public static void SerializeToFile(string filePath, T value, JsonTypeInfo typeInfo) { diff --git a/src/Ryujinx/Common/LocaleManager.cs b/src/Ryujinx/Common/LocaleManager.cs index 2ea5c83ee..613d92e0d 100644 --- a/src/Ryujinx/Common/LocaleManager.cs +++ b/src/Ryujinx/Common/LocaleManager.cs @@ -1,3 +1,4 @@ +using Gommon; using Ryujinx.Ava.UI.ViewModels; using Ryujinx.Common; using Ryujinx.Common.Logging; @@ -7,12 +8,7 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Globalization; -using System.IO; -using System.Linq; -using System.Text.Encodings.Web; -using System.Text.Json; using System.Text.Json.Serialization; -using System.Text.Unicode; namespace Ryujinx.Ava.Common.Locale { @@ -147,39 +143,34 @@ namespace Ryujinx.Ava.Common.Locale LocaleChanged?.Invoke(); } + #nullable enable + + private static LocalesJson? _localeData; + + #nullable disable + private static Dictionary LoadJsonLanguage(string languageCode) { var localeStrings = new Dictionary(); - string fileData = EmbeddedResources.ReadAllText($"Ryujinx/Assets/locales.json"); - if (fileData == null) + _localeData ??= EmbeddedResources.ReadAllText("Ryujinx/Assets/locales.json") + .Into(it => JsonHelper.Deserialize(it, LocalesJsonContext.Default.LocalesJson)); + + foreach (LocalesEntry locale in _localeData.Value.Locales) { - // We were unable to find file for that language code. - return null; - } - - LocalesJson json = JsonHelper.Deserialize(fileData, LocalesJsonContext.Default.LocalesJson); - - foreach (LocalesEntry locale in json.Locales) - { - if (locale.Translations.Count != json.Languages.Count) + if (locale.Translations.Count != _localeData.Value.Languages.Count) { Logger.Error?.Print(LogClass.UI, $"Locale key {{{locale.ID}}} is missing languages!"); throw new Exception("Missing locale data!"); } - if (Enum.TryParse(locale.ID, out var localeKey)) - { - if (locale.Translations.TryGetValue(languageCode, out string val) && val != "") - { - localeStrings[localeKey] = val; - } - else - { - locale.Translations.TryGetValue("en_US", out val); - localeStrings[localeKey] = val; - } - } + if (!Enum.TryParse(locale.ID, out var localeKey)) + continue; + + localeStrings[localeKey] = + locale.Translations.TryGetValue(languageCode, out string val) && val != string.Empty + ? val + : locale.Translations[DefaultLanguageCode]; } return localeStrings; @@ -200,5 +191,5 @@ namespace Ryujinx.Ava.Common.Locale [JsonSourceGenerationOptions(WriteIndented = true)] [JsonSerializable(typeof(LocalesJson))] - internal partial class LocalesJsonContext : JsonSerializerContext { } + internal partial class LocalesJsonContext : JsonSerializerContext; } From e15a207656b16b122a4f0f836ac10de412a66a26 Mon Sep 17 00:00:00 2001 From: Evan Husted Date: Sat, 21 Dec 2024 18:58:53 -0600 Subject: [PATCH 12/27] misc: Improve broken locale.json crash message --- src/Ryujinx/Common/LocaleManager.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Ryujinx/Common/LocaleManager.cs b/src/Ryujinx/Common/LocaleManager.cs index 613d92e0d..f29efb15a 100644 --- a/src/Ryujinx/Common/LocaleManager.cs +++ b/src/Ryujinx/Common/LocaleManager.cs @@ -160,8 +160,7 @@ namespace Ryujinx.Ava.Common.Locale { if (locale.Translations.Count != _localeData.Value.Languages.Count) { - Logger.Error?.Print(LogClass.UI, $"Locale key {{{locale.ID}}} is missing languages!"); - throw new Exception("Missing locale data!"); + throw new Exception($"Locale key {{{locale.ID}}} is missing languages! Has {locale.Translations.Count} translations, expected {_localeData.Value.Languages.Count}!"); } if (!Enum.TryParse(locale.ID, out var localeKey)) From 1f0fa525a371aad54c54e6ef6db058d310760ae3 Mon Sep 17 00:00:00 2001 From: Evan Husted Date: Sat, 21 Dec 2024 19:03:08 -0600 Subject: [PATCH 13/27] UI: some languages did already say Firmware version oddly enough --- src/Ryujinx/Assets/locales.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Ryujinx/Assets/locales.json b/src/Ryujinx/Assets/locales.json index e4ffb2f77..9fa113593 100644 --- a/src/Ryujinx/Assets/locales.json +++ b/src/Ryujinx/Assets/locales.json @@ -2429,19 +2429,19 @@ "el_GR": "", "en_US": "Firmware Version: {0}", "es_ES": "", - "fr_FR": "", + "fr_FR": "Version du Firmware: {0}", "he_IL": "", "it_IT": "", "ja_JP": "", "ko_KR": "", "no_NO": "", "pl_PL": "", - "pt_BR": "", - "ru_RU": "", + "pt_BR": "Versão do firmware: {0}", + "ru_RU": "Версия прошивки: {0}", "th_TH": "", "tr_TR": "", "uk_UA": "", - "zh_CN": "", + "zh_CN": "系统固件版本:{0}", "zh_TW": "" } }, From d9fe0da3459c7d7dea9b693281328f27a21e23bc Mon Sep 17 00:00:00 2001 From: Evan Husted Date: Sat, 21 Dec 2024 19:43:40 -0600 Subject: [PATCH 14/27] UI: Button to set emulator time based on system time in settings, under the time settings. Partially resolves #355. I think that wanted automatic. If automatic functionality is still desired even with this change then that will be considered. --- src/Ryujinx/UI/ViewModels/SettingsViewModel.cs | 16 ++++++++++++++++ .../UI/Views/Settings/SettingsSystemView.axaml | 15 ++++++++++++++- .../Views/Settings/SettingsSystemView.axaml.cs | 4 ++++ 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs b/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs index a5abeb36b..8edf71a39 100644 --- a/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs @@ -329,7 +329,11 @@ namespace Ryujinx.Ava.UI.ViewModels } } + //private DateTimeOffset _currentDate; + //private TimeSpan _currentTime; + public DateTimeOffset CurrentDate { get; set; } + public TimeSpan CurrentTime { get; set; } internal AvaloniaList TimeZones { get; set; } @@ -453,6 +457,18 @@ namespace Ryujinx.Ava.UI.ViewModels Dispatcher.UIThread.Post(() => OnPropertyChanged(nameof(PreferredGpuIndex))); } + public void MatchSystemTime() + { + var dto = DateTimeOffset.Now; + + CurrentDate = new DateTimeOffset(dto.Year, dto.Month, dto.Day, 0, 0, 0, dto.Offset); + + CurrentTime = dto.TimeOfDay; + + OnPropertyChanged(nameof(CurrentDate)); + OnPropertyChanged(nameof(CurrentTime)); + } + public async Task LoadTimeZones() { _timeZoneContentManager = new TimeZoneContentManager(); diff --git a/src/Ryujinx/UI/Views/Settings/SettingsSystemView.axaml b/src/Ryujinx/UI/Views/Settings/SettingsSystemView.axaml index e04e541c3..abb1a2e49 100644 --- a/src/Ryujinx/UI/Views/Settings/SettingsSystemView.axaml +++ b/src/Ryujinx/UI/Views/Settings/SettingsSystemView.axaml @@ -182,7 +182,20 @@ Width="350" ToolTip.Tip="{ext:Locale TimeTooltip}" /> - + + + + ViewModel.MatchSystemTime(); } } From 0f18df982f44d8edec9b9f55400c6ca95b691fae Mon Sep 17 00:00:00 2001 From: Evan Husted Date: Sat, 21 Dec 2024 19:59:16 -0600 Subject: [PATCH 15/27] UI: localize the button & make it smaller --- src/Ryujinx/Assets/locales.json | 48 +++++++++++++++++++ .../UI/ViewModels/SettingsViewModel.cs | 3 -- .../Views/Settings/SettingsSystemView.axaml | 8 ++-- 3 files changed, 52 insertions(+), 7 deletions(-) diff --git a/src/Ryujinx/Assets/locales.json b/src/Ryujinx/Assets/locales.json index 9fa113593..1b4624c95 100644 --- a/src/Ryujinx/Assets/locales.json +++ b/src/Ryujinx/Assets/locales.json @@ -3765,6 +3765,30 @@ "zh_TW": "系統時鐘:" } }, + { + "ID": "SettingsTabSystemSystemTimeMatch", + "Translations": { + "ar_SA": "", + "de_DE": "", + "el_GR": "", + "en_US": "Match PC Time", + "es_ES": "", + "fr_FR": "", + "he_IL": "", + "it_IT": "", + "ja_JP": "", + "ko_KR": "", + "no_NO": "", + "pl_PL": "", + "pt_BR": "", + "ru_RU": "", + "th_TH": "", + "tr_TR": "", + "uk_UA": "", + "zh_CN": "", + "zh_TW": "" + } + }, { "ID": "SettingsTabSystemEnablePptc", "Translations": { @@ -14541,6 +14565,30 @@ "zh_TW": "變更系統時鐘" } }, + { + "ID": "MatchTimeTooltip", + "Translations": { + "ar_SA": "", + "de_DE": "", + "el_GR": "", + "en_US": "Change System Time to match your PC's time.", + "es_ES": "", + "fr_FR": "", + "he_IL": "", + "it_IT": "", + "ja_JP": "", + "ko_KR": "", + "no_NO": "", + "pl_PL": "", + "pt_BR": "", + "ru_RU": "", + "th_TH": "", + "tr_TR": "", + "uk_UA": "", + "zh_CN": "", + "zh_TW": "" + } + }, { "ID": "VSyncToggleTooltip", "Translations": { diff --git a/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs b/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs index 8edf71a39..0824e3f86 100644 --- a/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs @@ -329,9 +329,6 @@ namespace Ryujinx.Ava.UI.ViewModels } } - //private DateTimeOffset _currentDate; - //private TimeSpan _currentTime; - public DateTimeOffset CurrentDate { get; set; } public TimeSpan CurrentTime { get; set; } diff --git a/src/Ryujinx/UI/Views/Settings/SettingsSystemView.axaml b/src/Ryujinx/UI/Views/Settings/SettingsSystemView.axaml index abb1a2e49..73cc70a23 100644 --- a/src/Ryujinx/UI/Views/Settings/SettingsSystemView.axaml +++ b/src/Ryujinx/UI/Views/Settings/SettingsSystemView.axaml @@ -183,15 +183,15 @@ ToolTip.Tip="{ext:Locale TimeTooltip}" /> From 2fac0f4db11b934320dfc26edb984ca5972ca3dc Mon Sep 17 00:00:00 2001 From: Evan Husted Date: Sat, 21 Dec 2024 20:00:16 -0600 Subject: [PATCH 16/27] Specify it's date & time --- src/Ryujinx/Assets/locales.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Ryujinx/Assets/locales.json b/src/Ryujinx/Assets/locales.json index 1b4624c95..4c426f062 100644 --- a/src/Ryujinx/Assets/locales.json +++ b/src/Ryujinx/Assets/locales.json @@ -14571,7 +14571,7 @@ "ar_SA": "", "de_DE": "", "el_GR": "", - "en_US": "Change System Time to match your PC's time.", + "en_US": "Change System Time to match your PC's date & time.", "es_ES": "", "fr_FR": "", "he_IL": "", From f898a5ecf4370c1d286e6187c8f00981f44244de Mon Sep 17 00:00:00 2001 From: Evan Husted Date: Sat, 21 Dec 2024 20:06:59 -0600 Subject: [PATCH 17/27] Remove code references to having a flatpak version --- src/Ryujinx.Common/ReleaseInformation.cs | 3 --- .../Helper/FileAssociationHelper.cs | 2 +- src/Ryujinx/Assets/locales.json | 24 ------------------- .../UI/Controls/ApplicationContextMenu.axaml | 1 - .../UI/ViewModels/MainWindowViewModel.cs | 2 -- src/Ryujinx/Updater.cs | 19 ++++----------- 6 files changed, 5 insertions(+), 46 deletions(-) diff --git a/src/Ryujinx.Common/ReleaseInformation.cs b/src/Ryujinx.Common/ReleaseInformation.cs index 011d9848a..cbf93013f 100644 --- a/src/Ryujinx.Common/ReleaseInformation.cs +++ b/src/Ryujinx.Common/ReleaseInformation.cs @@ -6,7 +6,6 @@ namespace Ryujinx.Common // DO NOT EDIT, filled by CI public static class ReleaseInformation { - private const string FlatHubChannel = "flathub"; private const string CanaryChannel = "canary"; private const string ReleaseChannel = "release"; @@ -29,8 +28,6 @@ namespace Ryujinx.Common !ReleaseChannelRepo.StartsWith("%%") && !ConfigFileName.StartsWith("%%"); - public static bool IsFlatHubBuild => IsValid && ReleaseChannelOwner.Equals(FlatHubChannel); - public static bool IsCanaryBuild => IsValid && ReleaseChannelName.Equals(CanaryChannel); public static bool IsReleaseBuild => IsValid && ReleaseChannelName.Equals(ReleaseChannel); diff --git a/src/Ryujinx.UI.Common/Helper/FileAssociationHelper.cs b/src/Ryujinx.UI.Common/Helper/FileAssociationHelper.cs index 9333a1b76..44860d080 100644 --- a/src/Ryujinx.UI.Common/Helper/FileAssociationHelper.cs +++ b/src/Ryujinx.UI.Common/Helper/FileAssociationHelper.cs @@ -23,7 +23,7 @@ namespace Ryujinx.UI.Common.Helper [LibraryImport("shell32.dll", SetLastError = true)] public static partial void SHChangeNotify(uint wEventId, uint uFlags, nint dwItem1, nint dwItem2); - public static bool IsTypeAssociationSupported => (OperatingSystem.IsLinux() || OperatingSystem.IsWindows()) && !ReleaseInformation.IsFlatHubBuild; + public static bool IsTypeAssociationSupported => (OperatingSystem.IsLinux() || OperatingSystem.IsWindows()); public static bool AreMimeTypesRegistered { diff --git a/src/Ryujinx/Assets/locales.json b/src/Ryujinx/Assets/locales.json index 4c426f062..007f1d1e6 100644 --- a/src/Ryujinx/Assets/locales.json +++ b/src/Ryujinx/Assets/locales.json @@ -16173,30 +16173,6 @@ "zh_TW": "CPU 模式" } }, - { - "ID": "DialogUpdaterFlatpakNotSupportedMessage", - "Translations": { - "ar_SA": "الرجاء تحديث ريوجينكس عبر فلات هاب.", - "de_DE": "Bitte aktualisiere Ryujinx über FlatHub", - "el_GR": "Παρακαλούμε ενημερώστε το Ryujinx μέσω FlatHub.", - "en_US": "Please update Ryujinx via FlatHub.", - "es_ES": "Por favor, actualiza Ryujinx a través de FlatHub.", - "fr_FR": "Merci de mettre à jour Ryujinx via FlatHub.", - "he_IL": "בבקשה עדכן את ריוג'ינקס דרך פלאטהב.", - "it_IT": "Aggiorna Ryujinx tramite FlatHub.", - "ja_JP": "FlatHub を使用して Ryujinx をアップデートしてください.", - "ko_KR": "FlatHub를 통해 Ryujinx를 업데이트하세요.", - "no_NO": "Vennligst oppdater Ryujinx via FlatHub.", - "pl_PL": "Zaktualizuj Ryujinx przez FlatHub.", - "pt_BR": "Por favor, atualize o Ryujinx pelo FlatHub.", - "ru_RU": "Пожалуйста, обновите Ryujinx через FlatHub.", - "th_TH": "โปรดอัปเดต Ryujinx ผ่านช่องทาง FlatHub", - "tr_TR": "Lütfen Ryujinx'i FlatHub aracılığıyla güncelleyin.", - "uk_UA": "", - "zh_CN": "请通过 FlatHub 更新 Ryujinx 模拟器。", - "zh_TW": "請透過 Flathub 更新 Ryujinx。" - } - }, { "ID": "UpdaterDisabledWarningTitle", "Translations": { diff --git a/src/Ryujinx/UI/Controls/ApplicationContextMenu.axaml b/src/Ryujinx/UI/Controls/ApplicationContextMenu.axaml index 951f7f616..7708936ca 100644 --- a/src/Ryujinx/UI/Controls/ApplicationContextMenu.axaml +++ b/src/Ryujinx/UI/Controls/ApplicationContextMenu.axaml @@ -17,7 +17,6 @@ diff --git a/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs b/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs index cebd65701..ae373c267 100644 --- a/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs @@ -424,8 +424,6 @@ namespace Ryujinx.Ava.UI.ViewModels public bool OpenBcatSaveDirectoryEnabled => !SelectedApplication.ControlHolder.ByteSpan.IsZeros() && SelectedApplication.ControlHolder.Value.BcatDeliveryCacheStorageSize > 0; - public bool CreateShortcutEnabled => !ReleaseInformation.IsFlatHubBuild; - public string LoadHeading { get => _loadHeading; diff --git a/src/Ryujinx/Updater.cs b/src/Ryujinx/Updater.cs index e240ad141..21d991d97 100644 --- a/src/Ryujinx/Updater.cs +++ b/src/Ryujinx/Updater.cs @@ -686,22 +686,11 @@ namespace Ryujinx.Ava #else if (showWarnings) { - if (ReleaseInformation.IsFlatHubBuild) - { - Dispatcher.UIThread.InvokeAsync(() => - ContentDialogHelper.CreateWarningDialog( - LocaleManager.Instance[LocaleKeys.UpdaterDisabledWarningTitle], - LocaleManager.Instance[LocaleKeys.DialogUpdaterFlatpakNotSupportedMessage]) + Dispatcher.UIThread.InvokeAsync(() => + ContentDialogHelper.CreateWarningDialog( + LocaleManager.Instance[LocaleKeys.UpdaterDisabledWarningTitle], + LocaleManager.Instance[LocaleKeys.DialogUpdaterDirtyBuildSubMessage]) ); - } - else - { - Dispatcher.UIThread.InvokeAsync(() => - ContentDialogHelper.CreateWarningDialog( - LocaleManager.Instance[LocaleKeys.UpdaterDisabledWarningTitle], - LocaleManager.Instance[LocaleKeys.DialogUpdaterDirtyBuildSubMessage]) - ); - } } return false; From 4c7cb54ec63f907523a9c56b4cbcf899a6b893ef Mon Sep 17 00:00:00 2001 From: Evan Husted Date: Sat, 21 Dec 2024 21:52:04 -0600 Subject: [PATCH 18/27] misc: I may be stupid --- src/Ryujinx.HLE/HOS/Kernel/Common/KResourceLimit.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Ryujinx.HLE/HOS/Kernel/Common/KResourceLimit.cs b/src/Ryujinx.HLE/HOS/Kernel/Common/KResourceLimit.cs index ce2b7185a..1763edce2 100644 --- a/src/Ryujinx.HLE/HOS/Kernel/Common/KResourceLimit.cs +++ b/src/Ryujinx.HLE/HOS/Kernel/Common/KResourceLimit.cs @@ -15,7 +15,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Common private readonly long[] _current2; private readonly long[] _peak; - private readonly Lock _lock = new(); + // type is not Lock due to Monitor class usage + private readonly object _lock = new(); private readonly LinkedList _waitingThreads; From 67ec10feea0db14a9647db4deebb11523c6f05da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hack=E8=8C=B6=E3=82=93?= <120134269+Hackjjang@users.noreply.github.com> Date: Sun, 22 Dec 2024 13:46:57 +0900 Subject: [PATCH 19/27] Korean translation update (#422) --- src/Ryujinx/Assets/locales.json | 54 ++++++++++++++++----------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/src/Ryujinx/Assets/locales.json b/src/Ryujinx/Assets/locales.json index 007f1d1e6..5df389381 100644 --- a/src/Ryujinx/Assets/locales.json +++ b/src/Ryujinx/Assets/locales.json @@ -705,7 +705,7 @@ "he_IL": "", "it_IT": "", "ja_JP": "", - "ko_KR": "", + "ko_KR": "Amiibo 스캔(빈에서)", "no_NO": "", "pl_PL": "", "pt_BR": "", @@ -1137,7 +1137,7 @@ "he_IL": "", "it_IT": "", "ja_JP": "", - "ko_KR": "", + "ko_KR": "자주 묻는 질문(FAQ) 및 문제해결 페이지", "no_NO": "", "pl_PL": "", "pt_BR": "", @@ -1161,7 +1161,7 @@ "he_IL": "", "it_IT": "", "ja_JP": "", - "ko_KR": "", + "ko_KR": "공식 Ryujinx 위키에서 자주 묻는 질문(FAQ) 및 문제 해결 페이지 열기", "no_NO": "", "pl_PL": "", "pt_BR": "", @@ -1185,7 +1185,7 @@ "he_IL": "", "it_IT": "", "ja_JP": "", - "ko_KR": "", + "ko_KR": "설치 및 구성 안내", "no_NO": "", "pl_PL": "", "pt_BR": "", @@ -1209,7 +1209,7 @@ "he_IL": "", "it_IT": "", "ja_JP": "", - "ko_KR": "", + "ko_KR": "공식 Ryujinx 위키에서 설정 및 구성 안내 열기", "no_NO": "", "pl_PL": "", "pt_BR": "", @@ -1233,7 +1233,7 @@ "he_IL": "", "it_IT": "", "ja_JP": "", - "ko_KR": "", + "ko_KR": "멀티플레이어(LDN/LAN) 안내", "no_NO": "", "pl_PL": "", "pt_BR": "", @@ -1257,7 +1257,7 @@ "he_IL": "", "it_IT": "", "ja_JP": "", - "ko_KR": "", + "ko_KR": "공식 Ryujinx 위키에서 멀티플레이어 안내 열기", "no_NO": "", "pl_PL": "", "pt_BR": "", @@ -8073,7 +8073,7 @@ "he_IL": "", "it_IT": "", "ja_JP": "", - "ko_KR": "지우기", + "ko_KR": "", "no_NO": "Tøm", "pl_PL": "", "pt_BR": "", @@ -11865,7 +11865,7 @@ "he_IL": "", "it_IT": "", "ja_JP": "", - "ko_KR": "", + "ko_KR": "{0} : {1}", "no_NO": "", "pl_PL": "", "pt_BR": "", @@ -18777,7 +18777,7 @@ "he_IL": "", "it_IT": "", "ja_JP": "", - "ko_KR": "", + "ko_KR": "{0:n0}MB", "no_NO": "", "pl_PL": "", "pt_BR": "", @@ -19065,7 +19065,7 @@ "he_IL": "{0} הרחבות משחק", "it_IT": "", "ja_JP": "", - "ko_KR": "", + "ko_KR": "{0} DLC 사용 가능", "no_NO": "{0} Nedlastbare innhold(er)", "pl_PL": "", "pt_BR": "", @@ -21201,7 +21201,7 @@ "he_IL": "", "it_IT": "", "ja_JP": "", - "ko_KR": "", + "ko_KR": "수직 동기화 :", "no_NO": "", "pl_PL": "", "pt_BR": "", @@ -21225,7 +21225,7 @@ "he_IL": "", "it_IT": "", "ja_JP": "", - "ko_KR": "", + "ko_KR": "사용자 정의 주사율 활성화(실험적)", "no_NO": "", "pl_PL": "", "pt_BR": "", @@ -21249,7 +21249,7 @@ "he_IL": "", "it_IT": "", "ja_JP": "", - "ko_KR": "", + "ko_KR": "스위치", "no_NO": "", "pl_PL": "", "pt_BR": "", @@ -21273,7 +21273,7 @@ "he_IL": "", "it_IT": "", "ja_JP": "", - "ko_KR": "", + "ko_KR": "무제한", "no_NO": "", "pl_PL": "", "pt_BR": "", @@ -21297,7 +21297,7 @@ "he_IL": "", "it_IT": "", "ja_JP": "", - "ko_KR": "", + "ko_KR": "사용자 정의 주사율", "no_NO": "", "pl_PL": "", "pt_BR": "", @@ -21321,7 +21321,7 @@ "he_IL": "", "it_IT": "", "ja_JP": "", - "ko_KR": "", + "ko_KR": "에뮬레이트된 수직 동기화. '스위치'는 스위치의 60Hz 주사율을 에뮬레이트합니다. '무한'은 무제한 주사율입니다.", "no_NO": "", "pl_PL": "", "pt_BR": "", @@ -21345,7 +21345,7 @@ "he_IL": "", "it_IT": "", "ja_JP": "", - "ko_KR": "", + "ko_KR": "에뮬레이트된 수직 동기화. '스위치'는 스위치의 60Hz 주사율을 에뮬레이트합니다. '무한'은 무제한 주사율입니다. '사용자 지정'은 지정된 사용자 지정 주사율을 에뮬레이트합니다.", "no_NO": "", "pl_PL": "", "pt_BR": "", @@ -21369,7 +21369,7 @@ "he_IL": "", "it_IT": "", "ja_JP": "", - "ko_KR": "", + "ko_KR": "사용자가 에뮬레이트된 화면 주사율을 지정할 수 있습니다. 일부 타이틀에서는 게임플레이 로직 속도가 빨라지거나 느려질 수 있습니다. 다른 타이틀에서는 주사율의 배수로 FPS를 제한하거나 예측할 수 없는 동작으로 이어질 수 있습니다. 이는 실험적 기능으로 게임 플레이에 어떤 영향을 미칠지 보장할 수 없습니다. \n\n모르면 끔으로 두세요.", "no_NO": "", "pl_PL": "", "pt_BR": "", @@ -21393,7 +21393,7 @@ "he_IL": "", "it_IT": "", "ja_JP": "", - "ko_KR": "", + "ko_KR": "사용자 정의 주사율 목표 값입니다.", "no_NO": "", "pl_PL": "", "pt_BR": "", @@ -21417,7 +21417,7 @@ "he_IL": "", "it_IT": "", "ja_JP": "", - "ko_KR": "", + "ko_KR": "일반 스위치 주사율의 백분율로 나타낸 사용자 지정 주사율입니다.", "no_NO": "", "pl_PL": "", "pt_BR": "", @@ -21441,7 +21441,7 @@ "he_IL": "", "it_IT": "", "ja_JP": "", - "ko_KR": "", + "ko_KR": "사용자 정의 주사율 % :", "no_NO": "", "pl_PL": "", "pt_BR": "", @@ -21465,7 +21465,7 @@ "he_IL": "", "it_IT": "", "ja_JP": "", - "ko_KR": "", + "ko_KR": "사용자 정의 주사율 값 :", "no_NO": "", "pl_PL": "", "pt_BR": "", @@ -21489,7 +21489,7 @@ "he_IL": "", "it_IT": "", "ja_JP": "", - "ko_KR": "", + "ko_KR": "간격", "no_NO": "", "pl_PL": "", "pt_BR": "", @@ -21513,7 +21513,7 @@ "he_IL": "", "it_IT": "", "ja_JP": "", - "ko_KR": "", + "ko_KR": "수직 동기화 모드 전환 :", "no_NO": "", "pl_PL": "", "pt_BR": "", @@ -21537,7 +21537,7 @@ "he_IL": "", "it_IT": "", "ja_JP": "", - "ko_KR": "", + "ko_KR": "사용자 정의 주사율 증가", "no_NO": "", "pl_PL": "", "pt_BR": "", @@ -21561,7 +21561,7 @@ "he_IL": "", "it_IT": "", "ja_JP": "", - "ko_KR": "", + "ko_KR": "사용자 정의 주사율 감소", "no_NO": "", "pl_PL": "", "pt_BR": "", From decd37ce6d670d6a1136409292d253dabd69475d Mon Sep 17 00:00:00 2001 From: Marco Carvalho Date: Sun, 22 Dec 2024 02:28:31 -0300 Subject: [PATCH 20/27] Add missing "yield return" (#424) --- src/Ryujinx.Cpu/AppleHv/HvMemoryManager.cs | 34 +++++++-------- src/Ryujinx.Cpu/Jit/MemoryManager.cs | 34 +++++++-------- .../Jit/MemoryManagerHostTracked.cs | 14 +++---- .../LightningJit/CodeGen/Arm64/StackWalker.cs | 6 +-- .../BufferMirrorRangeList.cs | 10 ++--- src/Ryujinx.HLE/HOS/ModLoader.cs | 9 ++-- src/Ryujinx.Memory/AddressSpaceManager.cs | 42 +++++++------------ 7 files changed, 54 insertions(+), 95 deletions(-) diff --git a/src/Ryujinx.Cpu/AppleHv/HvMemoryManager.cs b/src/Ryujinx.Cpu/AppleHv/HvMemoryManager.cs index bb56a4344..74c39d6a8 100644 --- a/src/Ryujinx.Cpu/AppleHv/HvMemoryManager.cs +++ b/src/Ryujinx.Cpu/AppleHv/HvMemoryManager.cs @@ -230,25 +230,20 @@ namespace Ryujinx.Cpu.AppleHv { if (size == 0) { - return Enumerable.Empty(); + yield break; } var guestRegions = GetPhysicalRegionsImpl(va, size); if (guestRegions == null) { - return null; + yield break; } - var regions = new HostMemoryRange[guestRegions.Count]; - - for (int i = 0; i < regions.Length; i++) + foreach (var guestRegion in guestRegions) { - var guestRegion = guestRegions[i]; nint pointer = _backingMemory.GetPointer(guestRegion.Address, guestRegion.Size); - regions[i] = new HostMemoryRange((nuint)(ulong)pointer, guestRegion.Size); + yield return new HostMemoryRange((nuint)(ulong)pointer, guestRegion.Size); } - - return regions; } /// @@ -256,23 +251,24 @@ namespace Ryujinx.Cpu.AppleHv { if (size == 0) { - return Enumerable.Empty(); + yield break; } - return GetPhysicalRegionsImpl(va, size); + foreach (var physicalRegion in GetPhysicalRegionsImpl(va, size)) + { + yield return physicalRegion; + } } - private List GetPhysicalRegionsImpl(ulong va, ulong size) + private IEnumerable GetPhysicalRegionsImpl(ulong va, ulong size) { if (!ValidateAddress(va) || !ValidateAddressAndSize(va, size)) { - return null; + yield break; } int pages = GetPagesCount(va, (uint)size, out va); - var regions = new List(); - ulong regionStart = GetPhysicalAddressInternal(va); ulong regionSize = PageSize; @@ -280,14 +276,14 @@ namespace Ryujinx.Cpu.AppleHv { if (!ValidateAddress(va + PageSize)) { - return null; + yield break; } ulong newPa = GetPhysicalAddressInternal(va + PageSize); if (GetPhysicalAddressInternal(va) + PageSize != newPa) { - regions.Add(new MemoryRange(regionStart, regionSize)); + yield return new MemoryRange(regionStart, regionSize); regionStart = newPa; regionSize = 0; } @@ -296,9 +292,7 @@ namespace Ryujinx.Cpu.AppleHv regionSize += PageSize; } - regions.Add(new MemoryRange(regionStart, regionSize)); - - return regions; + yield return new MemoryRange(regionStart, regionSize); } /// diff --git a/src/Ryujinx.Cpu/Jit/MemoryManager.cs b/src/Ryujinx.Cpu/Jit/MemoryManager.cs index 049e508d0..076fb6ad8 100644 --- a/src/Ryujinx.Cpu/Jit/MemoryManager.cs +++ b/src/Ryujinx.Cpu/Jit/MemoryManager.cs @@ -250,25 +250,20 @@ namespace Ryujinx.Cpu.Jit { if (size == 0) { - return Enumerable.Empty(); + yield break; } var guestRegions = GetPhysicalRegionsImpl(va, size); if (guestRegions == null) { - return null; + yield break; } - var regions = new HostMemoryRange[guestRegions.Count]; - - for (int i = 0; i < regions.Length; i++) + foreach (var guestRegion in guestRegions) { - var guestRegion = guestRegions[i]; nint pointer = _backingMemory.GetPointer(guestRegion.Address, guestRegion.Size); - regions[i] = new HostMemoryRange((nuint)(ulong)pointer, guestRegion.Size); + yield return new HostMemoryRange((nuint)(ulong)pointer, guestRegion.Size); } - - return regions; } /// @@ -276,23 +271,24 @@ namespace Ryujinx.Cpu.Jit { if (size == 0) { - return Enumerable.Empty(); + yield break; } - return GetPhysicalRegionsImpl(va, size); + foreach (var physicalRegion in GetPhysicalRegionsImpl(va, size)) + { + yield return physicalRegion; + } } - private List GetPhysicalRegionsImpl(ulong va, ulong size) + private IEnumerable GetPhysicalRegionsImpl(ulong va, ulong size) { if (!ValidateAddress(va) || !ValidateAddressAndSize(va, size)) { - return null; + yield break; } int pages = GetPagesCount(va, (uint)size, out va); - var regions = new List(); - ulong regionStart = GetPhysicalAddressInternal(va); ulong regionSize = PageSize; @@ -300,14 +296,14 @@ namespace Ryujinx.Cpu.Jit { if (!ValidateAddress(va + PageSize)) { - return null; + yield break; } ulong newPa = GetPhysicalAddressInternal(va + PageSize); if (GetPhysicalAddressInternal(va) + PageSize != newPa) { - regions.Add(new MemoryRange(regionStart, regionSize)); + yield return new MemoryRange(regionStart, regionSize); regionStart = newPa; regionSize = 0; } @@ -316,9 +312,7 @@ namespace Ryujinx.Cpu.Jit regionSize += PageSize; } - regions.Add(new MemoryRange(regionStart, regionSize)); - - return regions; + yield return new MemoryRange(regionStart, regionSize); } /// diff --git a/src/Ryujinx.Cpu/Jit/MemoryManagerHostTracked.cs b/src/Ryujinx.Cpu/Jit/MemoryManagerHostTracked.cs index 4dab212a7..499f991f2 100644 --- a/src/Ryujinx.Cpu/Jit/MemoryManagerHostTracked.cs +++ b/src/Ryujinx.Cpu/Jit/MemoryManagerHostTracked.cs @@ -475,17 +475,15 @@ namespace Ryujinx.Cpu.Jit return GetPhysicalRegionsImpl(va, size); } - private List GetPhysicalRegionsImpl(ulong va, ulong size) + private IEnumerable GetPhysicalRegionsImpl(ulong va, ulong size) { if (!ValidateAddress(va) || !ValidateAddressAndSize(va, size)) { - return null; + yield break; } int pages = GetPagesCount(va, (uint)size, out va); - var regions = new List(); - ulong regionStart = GetPhysicalAddressInternal(va); ulong regionSize = PageSize; @@ -493,14 +491,14 @@ namespace Ryujinx.Cpu.Jit { if (!ValidateAddress(va + PageSize)) { - return null; + yield break; } ulong newPa = GetPhysicalAddressInternal(va + PageSize); if (GetPhysicalAddressInternal(va) + PageSize != newPa) { - regions.Add(new MemoryRange(regionStart, regionSize)); + yield return new MemoryRange(regionStart, regionSize); regionStart = newPa; regionSize = 0; } @@ -509,9 +507,7 @@ namespace Ryujinx.Cpu.Jit regionSize += PageSize; } - regions.Add(new MemoryRange(regionStart, regionSize)); - - return regions; + yield return new MemoryRange(regionStart, regionSize); } /// diff --git a/src/Ryujinx.Cpu/LightningJit/CodeGen/Arm64/StackWalker.cs b/src/Ryujinx.Cpu/LightningJit/CodeGen/Arm64/StackWalker.cs index 3ce7c4f9c..1432c4598 100644 --- a/src/Ryujinx.Cpu/LightningJit/CodeGen/Arm64/StackWalker.cs +++ b/src/Ryujinx.Cpu/LightningJit/CodeGen/Arm64/StackWalker.cs @@ -8,8 +8,6 @@ namespace Ryujinx.Cpu.LightningJit.CodeGen.Arm64 { public IEnumerable GetCallStack(nint framePointer, nint codeRegionStart, int codeRegionSize, nint codeRegion2Start, int codeRegion2Size) { - List functionPointers = new(); - while (true) { nint functionPointer = Marshal.ReadIntPtr(framePointer, nint.Size); @@ -20,11 +18,9 @@ namespace Ryujinx.Cpu.LightningJit.CodeGen.Arm64 break; } - functionPointers.Add((ulong)functionPointer - 4); + yield return (ulong)functionPointer - 4; framePointer = Marshal.ReadIntPtr(framePointer); } - - return functionPointers; } } } diff --git a/src/Ryujinx.Graphics.Vulkan/BufferMirrorRangeList.cs b/src/Ryujinx.Graphics.Vulkan/BufferMirrorRangeList.cs index 5722ca1ac..e79248a47 100644 --- a/src/Ryujinx.Graphics.Vulkan/BufferMirrorRangeList.cs +++ b/src/Ryujinx.Graphics.Vulkan/BufferMirrorRangeList.cs @@ -168,16 +168,14 @@ namespace Ryujinx.Graphics.Vulkan return BinarySearch(list, offset, size) >= 0; } - public readonly List FindOverlaps(int offset, int size) + public readonly IEnumerable FindOverlaps(int offset, int size) { var list = _ranges; if (list == null) { - return null; + yield break; } - List result = null; - int index = BinarySearch(list, offset, size); if (index >= 0) @@ -189,12 +187,10 @@ namespace Ryujinx.Graphics.Vulkan do { - (result ??= new List()).Add(list[index++]); + yield return list[index++]; } while (index < list.Count && list[index].OverlapsWith(offset, size)); } - - return result; } private static int BinarySearch(List list, int offset, int size) diff --git a/src/Ryujinx.HLE/HOS/ModLoader.cs b/src/Ryujinx.HLE/HOS/ModLoader.cs index d8c62fc66..4bd695ae5 100644 --- a/src/Ryujinx.HLE/HOS/ModLoader.cs +++ b/src/Ryujinx.HLE/HOS/ModLoader.cs @@ -357,7 +357,6 @@ namespace Ryujinx.HLE.HOS { string cheatName = DefaultCheatName; List instructions = new(); - List cheats = new(); using StreamReader cheatData = cheatFile.OpenText(); while (cheatData.ReadLine() is { } line) @@ -373,13 +372,13 @@ namespace Ryujinx.HLE.HOS Logger.Warning?.Print(LogClass.ModLoader, $"Ignoring cheat '{cheatFile.FullName}' because it is malformed"); - return Array.Empty(); + yield break; } // Add the previous section to the list. if (instructions.Count > 0) { - cheats.Add(new Cheat($"<{cheatName} Cheat>", cheatFile, instructions)); + yield return new Cheat($"<{cheatName} Cheat>", cheatFile, instructions); } // Start a new cheat section. @@ -396,10 +395,8 @@ namespace Ryujinx.HLE.HOS // Add the last section being processed. if (instructions.Count > 0) { - cheats.Add(new Cheat($"<{cheatName} Cheat>", cheatFile, instructions)); + yield return new Cheat($"<{cheatName} Cheat>", cheatFile, instructions); } - - return cheats; } // Assumes searchDirPaths don't overlap diff --git a/src/Ryujinx.Memory/AddressSpaceManager.cs b/src/Ryujinx.Memory/AddressSpaceManager.cs index 807c5c0f4..7bd572d7a 100644 --- a/src/Ryujinx.Memory/AddressSpaceManager.cs +++ b/src/Ryujinx.Memory/AddressSpaceManager.cs @@ -106,10 +106,13 @@ namespace Ryujinx.Memory { if (size == 0) { - return Enumerable.Empty(); + yield break; } - return GetHostRegionsImpl(va, size); + foreach (var hostRegion in GetHostRegionsImpl(va, size)) + { + yield return hostRegion; + } } /// @@ -117,51 +120,36 @@ namespace Ryujinx.Memory { if (size == 0) { - return Enumerable.Empty(); + yield break; } var hostRegions = GetHostRegionsImpl(va, size); if (hostRegions == null) { - return null; + yield break; } - var regions = new MemoryRange[hostRegions.Count]; - ulong backingStart = (ulong)_backingMemory.Pointer; ulong backingEnd = backingStart + _backingMemory.Size; - int count = 0; - - for (int i = 0; i < regions.Length; i++) + foreach (var hostRegion in hostRegions) { - var hostRegion = hostRegions[i]; - if (hostRegion.Address >= backingStart && hostRegion.Address < backingEnd) { - regions[count++] = new MemoryRange(hostRegion.Address - backingStart, hostRegion.Size); + yield return new MemoryRange(hostRegion.Address - backingStart, hostRegion.Size); } } - - if (count != regions.Length) - { - return new ArraySegment(regions, 0, count); - } - - return regions; } - private List GetHostRegionsImpl(ulong va, ulong size) + private IEnumerable GetHostRegionsImpl(ulong va, ulong size) { if (!ValidateAddress(va) || !ValidateAddressAndSize(va, size)) { - return null; + yield break; } int pages = GetPagesCount(va, size, out va); - var regions = new List(); - nuint regionStart = GetHostAddress(va); ulong regionSize = PageSize; @@ -169,14 +157,14 @@ namespace Ryujinx.Memory { if (!ValidateAddress(va + PageSize)) { - return null; + yield break; } nuint newHostAddress = GetHostAddress(va + PageSize); if (GetHostAddress(va) + PageSize != newHostAddress) { - regions.Add(new HostMemoryRange(regionStart, regionSize)); + yield return new HostMemoryRange(regionStart, regionSize); regionStart = newHostAddress; regionSize = 0; } @@ -185,9 +173,7 @@ namespace Ryujinx.Memory regionSize += PageSize; } - regions.Add(new HostMemoryRange(regionStart, regionSize)); - - return regions; + yield return new HostMemoryRange(regionStart, regionSize); } [MethodImpl(MethodImplOptions.AggressiveInlining)] From 5913ceda4061028327521ed14b1c521ce6e87cf2 Mon Sep 17 00:00:00 2001 From: Marco Carvalho Date: Sun, 22 Dec 2024 14:36:05 -0300 Subject: [PATCH 21/27] Avoid zero-length array allocations (#427) --- src/Ryujinx.HLE/HOS/Horizon.cs | 4 ++-- src/Ryujinx.HLE/HOS/Services/Nfc/Nfp/VirtualAmiibo.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Ryujinx.HLE/HOS/Horizon.cs b/src/Ryujinx.HLE/HOS/Horizon.cs index c585aed54..f9c5ddecf 100644 --- a/src/Ryujinx.HLE/HOS/Horizon.cs +++ b/src/Ryujinx.HLE/HOS/Horizon.cs @@ -341,7 +341,7 @@ namespace Ryujinx.HLE.HOS { if (VirtualAmiibo.ApplicationBytes.Length > 0) { - VirtualAmiibo.ApplicationBytes = new byte[0]; + VirtualAmiibo.ApplicationBytes = Array.Empty(); VirtualAmiibo.InputBin = string.Empty; } if (NfpDevices[nfpDeviceId].State == NfpDeviceState.SearchingForTag) @@ -356,7 +356,7 @@ namespace Ryujinx.HLE.HOS VirtualAmiibo.InputBin = path; if (VirtualAmiibo.ApplicationBytes.Length > 0) { - VirtualAmiibo.ApplicationBytes = new byte[0]; + VirtualAmiibo.ApplicationBytes = Array.Empty(); } byte[] encryptedData = File.ReadAllBytes(path); VirtualAmiiboFile newFile = AmiiboBinReader.ReadBinFile(encryptedData); diff --git a/src/Ryujinx.HLE/HOS/Services/Nfc/Nfp/VirtualAmiibo.cs b/src/Ryujinx.HLE/HOS/Services/Nfc/Nfp/VirtualAmiibo.cs index ee43fc307..2cb35472f 100644 --- a/src/Ryujinx.HLE/HOS/Services/Nfc/Nfp/VirtualAmiibo.cs +++ b/src/Ryujinx.HLE/HOS/Services/Nfc/Nfp/VirtualAmiibo.cs @@ -16,7 +16,7 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp static class VirtualAmiibo { public static uint OpenedApplicationAreaId; - public static byte[] ApplicationBytes = new byte[0]; + public static byte[] ApplicationBytes = Array.Empty(); public static string InputBin = string.Empty; public static string NickName = string.Empty; private static readonly AmiiboJsonSerializerContext _serializerContext = AmiiboJsonSerializerContext.Default; @@ -137,7 +137,7 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp if (ApplicationBytes.Length > 0) { byte[] bytes = ApplicationBytes; - ApplicationBytes = new byte[0]; + ApplicationBytes = Array.Empty(); return bytes; } VirtualAmiiboFile virtualAmiiboFile = LoadAmiiboFile(amiiboId); From 1ea345faa7a908125ecdb278873451b5920cfed1 Mon Sep 17 00:00:00 2001 From: Evan Husted Date: Sun, 22 Dec 2024 12:53:48 -0600 Subject: [PATCH 22/27] UI: Move Match PC Time to next to the time selector & change label & tooltip to clarify behavior further. --- src/Ryujinx/Assets/locales.json | 4 ++-- src/Ryujinx/UI/Views/Settings/SettingsSystemView.axaml | 6 +----- src/Ryujinx/UI/Views/Settings/SettingsSystemView.axaml.cs | 2 +- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/Ryujinx/Assets/locales.json b/src/Ryujinx/Assets/locales.json index 5df389381..167accd34 100644 --- a/src/Ryujinx/Assets/locales.json +++ b/src/Ryujinx/Assets/locales.json @@ -3771,7 +3771,7 @@ "ar_SA": "", "de_DE": "", "el_GR": "", - "en_US": "Match PC Time", + "en_US": "Resync to PC Date & Time", "es_ES": "", "fr_FR": "", "he_IL": "", @@ -14571,7 +14571,7 @@ "ar_SA": "", "de_DE": "", "el_GR": "", - "en_US": "Change System Time to match your PC's date & time.", + "en_US": "Resync System Time to match your PC's current date & time.\n\nThis is not an active setting, it can still fall out of sync; in which case just click this button again.", "es_ES": "", "fr_FR": "", "he_IL": "", diff --git a/src/Ryujinx/UI/Views/Settings/SettingsSystemView.axaml b/src/Ryujinx/UI/Views/Settings/SettingsSystemView.axaml index 73cc70a23..9295413ba 100644 --- a/src/Ryujinx/UI/Views/Settings/SettingsSystemView.axaml +++ b/src/Ryujinx/UI/Views/Settings/SettingsSystemView.axaml @@ -181,15 +181,11 @@ SelectedTime="{Binding CurrentTime}" Width="350" ToolTip.Tip="{ext:Locale TimeTooltip}" /> - - diff --git a/src/Ryujinx/UI/Views/Settings/SettingsSystemView.axaml.cs b/src/Ryujinx/UI/Views/Settings/SettingsSystemView.axaml.cs index 5cecd7221..5103ce383 100644 --- a/src/Ryujinx/UI/Views/Settings/SettingsSystemView.axaml.cs +++ b/src/Ryujinx/UI/Views/Settings/SettingsSystemView.axaml.cs @@ -1,7 +1,7 @@ +using Avalonia; using Avalonia.Controls; using Avalonia.Interactivity; using Ryujinx.Ava.UI.ViewModels; -using System; using TimeZone = Ryujinx.Ava.UI.Models.TimeZone; namespace Ryujinx.Ava.UI.Views.Settings From 8259f790d75ca5c18ef8e3d56824b8f86dde1eff Mon Sep 17 00:00:00 2001 From: Evan Husted Date: Sun, 22 Dec 2024 13:19:10 -0600 Subject: [PATCH 23/27] misc: Cleanup locale validator --- .../LocaleValidationTask.cs | 21 ++++++++----------- src/Ryujinx/Assets/locales.json | 2 +- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/src/Ryujinx.BuildValidationTasks/LocaleValidationTask.cs b/src/Ryujinx.BuildValidationTasks/LocaleValidationTask.cs index 183228fdd..6dc3d8aa8 100644 --- a/src/Ryujinx.BuildValidationTasks/LocaleValidationTask.cs +++ b/src/Ryujinx.BuildValidationTasks/LocaleValidationTask.cs @@ -14,20 +14,20 @@ namespace Ryujinx.BuildValidationTasks { string path = System.Reflection.Assembly.GetExecutingAssembly().Location; - if (path.Split(new string[] { "src" }, StringSplitOptions.None).Length == 1 ) + if (path.Split(["src"], StringSplitOptions.None).Length == 1) { //i assume that we are in a build directory in the solution dir - path = new FileInfo(path).Directory.Parent.GetDirectories("src")[0].GetDirectories("Ryujinx")[0].GetDirectories("Assets")[0].GetFiles("locales.json")[0].FullName; + path = new FileInfo(path).Directory!.Parent!.GetDirectories("src")[0].GetDirectories("Ryujinx")[0].GetDirectories("Assets")[0].GetFiles("locales.json")[0].FullName; } else { - path = path.Split(new string[] { "src" }, StringSplitOptions.None)[0]; - path = new FileInfo(path).Directory.GetDirectories("src")[0].GetDirectories("Ryujinx")[0].GetDirectories("Assets")[0].GetFiles("locales.json")[0].FullName; + path = path.Split(["src"], StringSplitOptions.None)[0]; + path = new FileInfo(path).Directory!.GetDirectories("src")[0].GetDirectories("Ryujinx")[0].GetDirectories("Assets")[0].GetFiles("locales.json")[0].FullName; } string data; - using (StreamReader sr = new StreamReader(path)) + using (StreamReader sr = new(path)) { data = sr.ReadToEnd(); } @@ -38,13 +38,10 @@ namespace Ryujinx.BuildValidationTasks { LocalesEntry locale = json.Locales[i]; - foreach (string language in json.Languages) + foreach (string langCode in json.Languages.Where(it => !locale.Translations.ContainsKey(it))) { - if (!locale.Translations.ContainsKey(language)) - { - locale.Translations.Add(language, ""); - Log.LogMessage(MessageImportance.High, $"Added {{{language}}} to Locale {{{locale.ID}}}"); - } + locale.Translations.Add(langCode, string.Empty); + Log.LogMessage(MessageImportance.High, $"Added '{langCode}' to Locale '{locale.ID}'"); } locale.Translations = locale.Translations.OrderBy(pair => pair.Key).ToDictionary(pair => pair.Key, pair => pair.Value); @@ -53,7 +50,7 @@ namespace Ryujinx.BuildValidationTasks string jsonString = JsonConvert.SerializeObject(json, Formatting.Indented); - using (StreamWriter sw = new StreamWriter(path)) + using (StreamWriter sw = new(path)) { sw.Write(jsonString); } diff --git a/src/Ryujinx/Assets/locales.json b/src/Ryujinx/Assets/locales.json index 167accd34..33dd61d42 100644 --- a/src/Ryujinx/Assets/locales.json +++ b/src/Ryujinx/Assets/locales.json @@ -21574,4 +21574,4 @@ } } ] -} +} \ No newline at end of file From b5483d8fe028e18fe0ac4a69e40eb3780eaf76e1 Mon Sep 17 00:00:00 2001 From: Marco Carvalho Date: Sun, 22 Dec 2024 16:23:35 -0300 Subject: [PATCH 24/27] Prefer generic overload when type is known (#430) --- src/Ryujinx.Graphics.Vulkan/FormatCapabilities.cs | 2 +- src/Ryujinx.Graphics.Vulkan/FormatTable.cs | 2 +- src/Ryujinx.Graphics.Vulkan/Queries/Counters.cs | 2 +- src/Ryujinx.HLE/HOS/Services/IpcService.cs | 12 ++++++------ .../IUserLocalCommunicationService.cs | 2 +- src/Ryujinx.HLE/HOS/Services/Sm/IUserInterface.cs | 2 +- src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs | 4 ++-- src/Ryujinx/UI/Views/Main/MainStatusBarView.axaml.cs | 2 +- 8 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/Ryujinx.Graphics.Vulkan/FormatCapabilities.cs b/src/Ryujinx.Graphics.Vulkan/FormatCapabilities.cs index 4971a63b6..09f22889c 100644 --- a/src/Ryujinx.Graphics.Vulkan/FormatCapabilities.cs +++ b/src/Ryujinx.Graphics.Vulkan/FormatCapabilities.cs @@ -62,7 +62,7 @@ namespace Ryujinx.Graphics.Vulkan _api = api; _physicalDevice = physicalDevice; - int totalFormats = Enum.GetNames(typeof(Format)).Length; + int totalFormats = Enum.GetNames().Length; _bufferTable = new FormatFeatureFlags[totalFormats]; _optimalTable = new FormatFeatureFlags[totalFormats]; diff --git a/src/Ryujinx.Graphics.Vulkan/FormatTable.cs b/src/Ryujinx.Graphics.Vulkan/FormatTable.cs index 98796d9bf..305224cad 100644 --- a/src/Ryujinx.Graphics.Vulkan/FormatTable.cs +++ b/src/Ryujinx.Graphics.Vulkan/FormatTable.cs @@ -12,7 +12,7 @@ namespace Ryujinx.Graphics.Vulkan static FormatTable() { - _table = new VkFormat[Enum.GetNames(typeof(Format)).Length]; + _table = new VkFormat[Enum.GetNames().Length]; _reverseMap = new Dictionary(); #pragma warning disable IDE0055 // Disable formatting diff --git a/src/Ryujinx.Graphics.Vulkan/Queries/Counters.cs b/src/Ryujinx.Graphics.Vulkan/Queries/Counters.cs index 518ede5f3..c07e1c09c 100644 --- a/src/Ryujinx.Graphics.Vulkan/Queries/Counters.cs +++ b/src/Ryujinx.Graphics.Vulkan/Queries/Counters.cs @@ -13,7 +13,7 @@ namespace Ryujinx.Graphics.Vulkan.Queries { _pipeline = pipeline; - int count = Enum.GetNames(typeof(CounterType)).Length; + int count = Enum.GetNames().Length; _counterQueues = new CounterQueue[count]; diff --git a/src/Ryujinx.HLE/HOS/Services/IpcService.cs b/src/Ryujinx.HLE/HOS/Services/IpcService.cs index 808f21c0e..cd3df4edf 100644 --- a/src/Ryujinx.HLE/HOS/Services/IpcService.cs +++ b/src/Ryujinx.HLE/HOS/Services/IpcService.cs @@ -23,18 +23,18 @@ namespace Ryujinx.HLE.HOS.Services public IpcService(ServerBase server = null) { - CmifCommands = typeof(IpcService).Assembly.GetTypes() + CmifCommands = GetType().Assembly.GetTypes() .Where(type => type == GetType()) .SelectMany(type => type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public)) - .SelectMany(methodInfo => methodInfo.GetCustomAttributes(typeof(CommandCmifAttribute)) - .Select(command => (((CommandCmifAttribute)command).Id, methodInfo))) + .SelectMany(methodInfo => methodInfo.GetCustomAttributes() + .Select(command => (command.Id, methodInfo))) .ToDictionary(command => command.Id, command => command.methodInfo); - TipcCommands = typeof(IpcService).Assembly.GetTypes() + TipcCommands = GetType().Assembly.GetTypes() .Where(type => type == GetType()) .SelectMany(type => type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public)) - .SelectMany(methodInfo => methodInfo.GetCustomAttributes(typeof(CommandTipcAttribute)) - .Select(command => (((CommandTipcAttribute)command).Id, methodInfo))) + .SelectMany(methodInfo => methodInfo.GetCustomAttributes() + .Select(command => (command.Id, methodInfo))) .ToDictionary(command => command.Id, command => command.methodInfo); Server = server; diff --git a/src/Ryujinx.HLE/HOS/Services/Ldn/UserServiceCreator/IUserLocalCommunicationService.cs b/src/Ryujinx.HLE/HOS/Services/Ldn/UserServiceCreator/IUserLocalCommunicationService.cs index 9f65aed4b..b8b3014f1 100644 --- a/src/Ryujinx.HLE/HOS/Services/Ldn/UserServiceCreator/IUserLocalCommunicationService.cs +++ b/src/Ryujinx.HLE/HOS/Services/Ldn/UserServiceCreator/IUserLocalCommunicationService.cs @@ -444,7 +444,7 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator private ResultCode ScanInternal(IVirtualMemoryManager memory, ushort channel, ScanFilter scanFilter, ulong bufferPosition, ulong bufferSize, out ulong counter) { - ulong networkInfoSize = (ulong)Marshal.SizeOf(typeof(NetworkInfo)); + ulong networkInfoSize = (ulong)Marshal.SizeOf(); ulong maxGames = bufferSize / networkInfoSize; MemoryHelper.FillWithZeros(memory, bufferPosition, (int)bufferSize); diff --git a/src/Ryujinx.HLE/HOS/Services/Sm/IUserInterface.cs b/src/Ryujinx.HLE/HOS/Services/Sm/IUserInterface.cs index 7a90c664e..271b8fc84 100644 --- a/src/Ryujinx.HLE/HOS/Services/Sm/IUserInterface.cs +++ b/src/Ryujinx.HLE/HOS/Services/Sm/IUserInterface.cs @@ -94,7 +94,7 @@ namespace Ryujinx.HLE.HOS.Services.Sm { if (_services.TryGetValue(name, out Type type)) { - ServiceAttribute serviceAttribute = (ServiceAttribute)type.GetCustomAttributes(typeof(ServiceAttribute)).First(service => ((ServiceAttribute)service).Name == name); + ServiceAttribute serviceAttribute = type.GetCustomAttributes().First(service => service.Name == name); IpcService service = GetServiceInstance(type, context, serviceAttribute.Parameter); diff --git a/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs b/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs index f11d6e404..493e6659d 100644 --- a/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs @@ -97,7 +97,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input { if (IsModified) { - + _playerIdChoose = value; return; } @@ -105,7 +105,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input IsModified = false; _playerId = value; - if (!Enum.IsDefined(typeof(PlayerIndex), _playerId)) + if (!Enum.IsDefined(_playerId)) { _playerId = PlayerIndex.Player1; diff --git a/src/Ryujinx/UI/Views/Main/MainStatusBarView.axaml.cs b/src/Ryujinx/UI/Views/Main/MainStatusBarView.axaml.cs index dd4ed8297..1b017dbeb 100644 --- a/src/Ryujinx/UI/Views/Main/MainStatusBarView.axaml.cs +++ b/src/Ryujinx/UI/Views/Main/MainStatusBarView.axaml.cs @@ -52,7 +52,7 @@ namespace Ryujinx.Ava.UI.Views.Main private void AspectRatioStatus_OnClick(object sender, RoutedEventArgs e) { AspectRatio aspectRatio = ConfigurationState.Instance.Graphics.AspectRatio.Value; - ConfigurationState.Instance.Graphics.AspectRatio.Value = (int)aspectRatio + 1 > Enum.GetNames(typeof(AspectRatio)).Length - 1 ? AspectRatio.Fixed4x3 : aspectRatio + 1; + ConfigurationState.Instance.Graphics.AspectRatio.Value = (int)aspectRatio + 1 > Enum.GetNames().Length - 1 ? AspectRatio.Fixed4x3 : aspectRatio + 1; } private void Refresh_OnClick(object sender, RoutedEventArgs e) => Window.LoadApplications(); From cb355f504d8875defa5f9047dd63b7548e225212 Mon Sep 17 00:00:00 2001 From: Evan Husted Date: Sun, 22 Dec 2024 16:01:09 -0600 Subject: [PATCH 25/27] UI: Rearrange help menu item & merge wiki page link buttons into a "category" button. --- .../SyscallGenerator.cs | 6 +-- src/Ryujinx/Assets/locales.json | 26 +++++++++- .../UI/Views/Main/MainMenuBarView.axaml | 49 ++++++++++--------- 3 files changed, 53 insertions(+), 28 deletions(-) diff --git a/src/Ryujinx.Horizon.Kernel.Generators/SyscallGenerator.cs b/src/Ryujinx.Horizon.Kernel.Generators/SyscallGenerator.cs index 7419a839a..06b98e09d 100644 --- a/src/Ryujinx.Horizon.Kernel.Generators/SyscallGenerator.cs +++ b/src/Ryujinx.Horizon.Kernel.Generators/SyscallGenerator.cs @@ -34,14 +34,14 @@ namespace Ryujinx.Horizon.Kernel.Generators private const string TypeResult = NamespaceHorizonCommon + "." + TypeResultName; private const string TypeExecutionContext = "IExecutionContext"; - private static readonly string[] _expectedResults = new string[] - { + private static readonly string[] _expectedResults = + [ $"{TypeResultName}.Success", $"{TypeKernelResultName}.TimedOut", $"{TypeKernelResultName}.Cancelled", $"{TypeKernelResultName}.PortRemoteClosed", $"{TypeKernelResultName}.InvalidState", - }; + ]; private readonly struct OutParameter { diff --git a/src/Ryujinx/Assets/locales.json b/src/Ryujinx/Assets/locales.json index 33dd61d42..ee6bf3792 100644 --- a/src/Ryujinx/Assets/locales.json +++ b/src/Ryujinx/Assets/locales.json @@ -1125,6 +1125,30 @@ "zh_TW": "檢查更新" } }, + { + "ID": "MenuBarHelpFaqAndGuides", + "Translations": { + "ar_SA": "", + "de_DE": "", + "el_GR": "", + "en_US": "FAQ & Guides", + "es_ES": "", + "fr_FR": "", + "he_IL": "", + "it_IT": "", + "ja_JP": "", + "ko_KR": "", + "no_NO": "", + "pl_PL": "", + "pt_BR": "", + "ru_RU": "", + "th_TH": "", + "tr_TR": "", + "uk_UA": "", + "zh_CN": "", + "zh_TW": "" + } + }, { "ID": "MenuBarHelpFaq", "Translations": { @@ -21574,4 +21598,4 @@ } } ] -} \ No newline at end of file +} diff --git a/src/Ryujinx/UI/Views/Main/MainMenuBarView.axaml b/src/Ryujinx/UI/Views/Main/MainMenuBarView.axaml index be805566e..65f048bee 100644 --- a/src/Ryujinx/UI/Views/Main/MainMenuBarView.axaml +++ b/src/Ryujinx/UI/Views/Main/MainMenuBarView.axaml @@ -290,6 +290,11 @@ + - - - - - + + + + + From 23b0b2240069b3a9b683d6270f39e30ba729cf0c Mon Sep 17 00:00:00 2001 From: Evan Husted Date: Sun, 22 Dec 2024 16:08:12 -0600 Subject: [PATCH 26/27] UI: Ensure last played date & time are always on 2 separate lines, for consistency. --- src/Ryujinx.UI.Common/App/ApplicationData.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Ryujinx.UI.Common/App/ApplicationData.cs b/src/Ryujinx.UI.Common/App/ApplicationData.cs index 151220f39..657b9a022 100644 --- a/src/Ryujinx.UI.Common/App/ApplicationData.cs +++ b/src/Ryujinx.UI.Common/App/ApplicationData.cs @@ -38,7 +38,7 @@ namespace Ryujinx.UI.App.Common public string TimePlayedString => ValueFormatUtils.FormatTimeSpan(TimePlayed); - public string LastPlayedString => ValueFormatUtils.FormatDateTime(LastPlayed) ?? LocalizedNever(); + public string LastPlayedString => ValueFormatUtils.FormatDateTime(LastPlayed)?.Replace(" ", "\n") ?? LocalizedNever(); public string FileSizeString => ValueFormatUtils.FormatFileSize(FileSize); From a270dc721ccd12873c36d8b766cf8f3483c08a78 Mon Sep 17 00:00:00 2001 From: asfasagag Date: Sun, 22 Dec 2024 20:49:40 -0800 Subject: [PATCH 27/27] UI: Option to resize window to 1440p, 2160p (#432) Minor but useful quality of life addition --- src/Ryujinx/Assets/locales.json | 48 +++++++++++++++++++ .../UI/Views/Main/MainMenuBarView.axaml | 2 + 2 files changed, 50 insertions(+) diff --git a/src/Ryujinx/Assets/locales.json b/src/Ryujinx/Assets/locales.json index ee6bf3792..a6d0ece6a 100644 --- a/src/Ryujinx/Assets/locales.json +++ b/src/Ryujinx/Assets/locales.json @@ -1077,6 +1077,54 @@ "zh_TW": "" } }, + { + "ID": "MenuBarViewWindow1440", + "Translations": { + "ar_SA": "", + "de_DE": "", + "el_GR": "", + "en_US": "1440p", + "es_ES": "", + "fr_FR": "", + "he_IL": "", + "it_IT": "", + "ja_JP": "", + "ko_KR": "", + "no_NO": "", + "pl_PL": "", + "pt_BR": "", + "ru_RU": "", + "th_TH": "", + "tr_TR": "", + "uk_UA": "", + "zh_CN": "", + "zh_TW": "" + } + }, + { + "ID": "MenuBarViewWindow2160", + "Translations": { + "ar_SA": "", + "de_DE": "", + "el_GR": "", + "en_US": "2160p", + "es_ES": "", + "fr_FR": "", + "he_IL": "", + "it_IT": "", + "ja_JP": "", + "ko_KR": "", + "no_NO": "", + "pl_PL": "", + "pt_BR": "", + "ru_RU": "", + "th_TH": "", + "tr_TR": "", + "uk_UA": "", + "zh_CN": "", + "zh_TW": "" + } + }, { "ID": "MenuBarHelp", "Translations": { diff --git a/src/Ryujinx/UI/Views/Main/MainMenuBarView.axaml b/src/Ryujinx/UI/Views/Main/MainMenuBarView.axaml index 65f048bee..7d8135dcf 100644 --- a/src/Ryujinx/UI/Views/Main/MainMenuBarView.axaml +++ b/src/Ryujinx/UI/Views/Main/MainMenuBarView.axaml @@ -287,6 +287,8 @@ + +