Compare commits

...

98 Commits

Author SHA1 Message Date
IvonWei
3cbd7dc1a1 Merge branch 'Ryubing:master' into master 2024-12-31 19:21:10 +08:00
Evan Husted
61ae427a4d misc: Add CommunityToolkit.Mvvm for observable property generation; apply it to MainWindowViewModel for now. 2024-12-31 03:29:08 -06:00
Evan Husted
19d2883a35 UI: Store config migrations in a dictionary and loop through it to do migrations. 2024-12-31 02:51:14 -06:00
Evan Husted
617c03119f misc: clean vsync toggle log 2024-12-31 00:52:39 -06:00
Evan Husted
e43d899e1d misc: Use a few static helpers for Avalonia objects 2024-12-31 00:19:23 -06:00
Evan Husted
0cd09ea0c5 misc: Simplify ControlHolder checks in MainWindowViewModel 2024-12-31 00:04:23 -06:00
Evan Husted
4135d74e4d UI: Only allow right click to create a context menu if a game is selected. 2024-12-30 23:50:55 -06:00
Evan Husted
bd29f658b1 misc: Forgot about OfType [ci skip] 2024-12-30 23:28:32 -06:00
Evan Husted
df150f0788 misc: Significantly reduce duplicated code in ConfigurationState migration logic. 300 lines removed; functionally identical. 2024-12-30 23:14:05 -06:00
Evan Husted
e50198b37d Clarify DramSize XMLdoc 2024-12-30 23:11:59 -06:00
Evan Husted
f426945fec misc: Rename DirtyHacks to DirtyHack
Rename DirtyHack.ShaderCompilationThreadSleep to ShaderTranslationDelay
Changed EnabledDirtyHack to a struct
rename DirtyHackCollection to DirtyHacks
2024-12-30 22:18:35 -06:00
Evan Husted
172869bfba misc: cleanup applying the current dirty hacks to the config upon loading the json 2024-12-30 22:11:16 -06:00
Evan Husted
b6f88514f9 misc: Move BitTricks methods into BitUtils
Cleanup DirtyHackCollection
2024-12-30 22:11:16 -06:00
Hack茶ん
e92f52e56c Korean translations for new locale keys (#465) 2024-12-30 21:13:43 -06:00
Evan Husted
318498eab0 misc: prefix ValidationTask with I, it's an interface
Mention in PR comment script that you now need to be logged into GitHub to download artifacts.
2024-12-30 20:57:18 -06:00
Evan Husted
a5cde8e006 misc: Update Gommon, apply new extension 2024-12-30 20:37:02 -06:00
Evan Husted
d0a344d632 Validation Project v2 (#471)
Original PR had issues in the CI when building.

> Refactor of the Validation System for more ease of use in the future.
The project now builds a standalone executable and executes it before
the main project is built or published.
Since it is now a standalone executable we are also able to use .NET
Core features as we are no longer locked to netstandard.

> The project currently includes 1 task, LocalesValidationTask, that
will check if the locales.json file has any of the following issues:
>   - The json is invalid.
>   - The json has locales with missing languages.
> - The json has locales with langauges that are just duplicates of the
en_US field.

> If the project is built or published locally it will also fix any
missing languages or duplicate fields.

---------

Co-authored-by: LotP1 <68976644+LotP1@users.noreply.github.com>
2024-12-30 20:31:27 -06:00
Otozinclus
ca66298817 Update Metal Games list (#472)
I tested let's go in most locations and did some battles and it runs
perfectly

Legends Arceus will freeze occasionally on Metal, so it was removed.
2024-12-30 20:28:35 -06:00
IvonWei
536f792558 Merge branch 'Ryubing:master' into master 2024-12-30 22:04:08 +08:00
madwind
7a451ab160 fix GetMappedStateSnapshot 2024-12-30 22:01:21 +08:00
Evan Husted
9ae1c4380d UI: Fix crashing when opening an Applet or application with no existing icon 2024-12-30 02:32:44 -06:00
Evan Husted
c88518bce2 Revert "Validation Project v2" (#470)
Reverts Ryubing/Ryujinx#444
2024-12-30 02:06:24 -06:00
Evan Husted
a3888ed7cf Revert "misc: New Solution Format (.SLNX)"
This reverts commit 7cbbd02973.
2024-12-30 02:05:40 -06:00
Evan Husted
7cbbd02973 misc: New Solution Format (.SLNX) 2024-12-30 02:02:55 -06:00
LotP1
b2e1e553e4 Validation Project v2 (#444)
Refactor of the Validation System for more ease of use in the future.
The project now builds a standalone executable and executes it before
the main project is built or published.
Since it is now a standalone executable we are also able to use .NET
Core features as we are no longer locked to netstandard.

The project currently includes 1 task, LocalesValidationTask, that will
check if the locales.json file has any of the following issues:
The json is invalid.
The json has locales with missing languages.
The json has locales with langauges that are just duplicates of the
en_US field.

If the project is built or published locally it will also fix any
missing languages or duplicate fields.

---------

Co-authored-by: Evan Husted <gr33m11@gmail.com>
Co-authored-by: Evan Husted <greem@greemdev.net>
2024-12-30 01:54:25 -06:00
Marco Carvalho
699e1962b1 Prefer 'Convert.ToHexString' over call chains based on 'BitConverter.ToString' (#428) [ci-skip]
Co-authored-by: Evan Husted <greem@greemdev.net>
2024-12-30 01:53:43 -06:00
WilliamWsyHK
e486b902b1 Skip processing application for LDN if it does not have control holder (#460) [ci-skip] 2024-12-30 01:53:06 -06:00
Evan Husted
0ab5b41c4b misc: Move dirty hack related stuff into a separate viewmodel, only show slider when translation delay is enabled. 2024-12-30 01:33:07 -06:00
Otozinclus
d10a478cce Shader translation delay hack (#469)
A workaround to avoid a freeze when translating shaders with the Metal
backend, that would happen after changing version or going from Vulkan
to Metal. 

Adds a delay in milliseconds, configurable in the UI behind the Dirty Hacks mechanism.

---------

Co-authored-by: Evan Husted <greem@greemdev.net>
2024-12-30 01:12:51 -06:00
Evan Husted
ec1020b165 UI: Dirty hacks clarification [ci skip] 2024-12-30 01:10:40 -06:00
Evan Husted
4082ebad1a Fix PR builds 2024-12-30 00:35:43 -06:00
Evan Husted
da8ea06074 misc: Small cleanups 2024-12-30 00:14:55 -06:00
Evan Husted
7f9dccb293 misc: chore: Cleanup DummyHardwareDeviceDriver.cs 2024-12-30 00:09:31 -06:00
Evan Husted
8e4a77aba0 UI: Text in the shader translation slider tooltip 2024-12-30 00:09:19 -06:00
Evan Husted
8fd8a776c9 misc: prevent crashes 2024-12-29 23:39:40 -06:00
Evan Husted
eec92c242c misc: Remove shader translation delay dirty hack from UI
it doesn't do anything
2024-12-29 22:55:33 -06:00
Evan Husted
42a739d34c misc: Expose DirtyHacks on GpuContext 2024-12-29 22:21:09 -06:00
Evan Husted
f362bef43d misc: Overhaul DirtyHacks saving to support storing a value alongside an off/off flag. 2024-12-29 21:17:01 -06:00
Evan Husted
f5ce539de9 misc: Move the rest of Ryujinx.UI.Common into other parts of the project. 2024-12-29 19:28:27 -06:00
Evan Husted
4f699afe7a misc: Move shortcut files into Avalonia project 2024-12-29 19:13:06 -06:00
Evan Husted
6caab1aa37 misc: move Models & Helpers into Common & Avalonia projects 2024-12-29 19:09:28 -06:00
Evan Husted
9baaa2b8f8 misc: Move image assets to Avalonia project 2024-12-29 18:37:37 -06:00
Evan Husted
7f376b4f45 misc: Move SystemInfo into Avalonia project 2024-12-29 18:13:38 -06:00
Evan Husted
32cdccde12 misc: Move UserError to Common project 2024-12-29 18:06:18 -06:00
IvonWei
99c7c3fb14 Merge branch 'Ryubing:master' into master 2024-12-29 18:37:03 +08:00
Evan Husted
cbd851d00e misc: Forgot about ReactiveObject 2024-12-29 04:16:08 -06:00
Evan Husted
09e7b660f4 Merge branch 'master' into master 2024-12-29 03:42:20 -06:00
Evan Husted
f463ea1c5d misc: Refactor Discord integration to listen on TitleIDs.CurrentApplication changes instead of waiting to be directly told when to change states. 2024-12-29 03:27:05 -06:00
Evan Husted
1dd69912b1 Partial revert, decouple TitleIDs.CurrentApplication from shader cache stuff; as I want that to ALWAYS reflect the current app. 2024-12-29 03:02:56 -06:00
Evan Husted
1fbb0d8e7d metal: also disable vsync for custom refresh rates 2024-12-29 02:21:25 -06:00
Evan Husted
9ee3f1ff36 metal: add PKL Arceus to MetalGreatTitles 2024-12-29 00:28:18 -06:00
Evan Husted
d052d74ac4 misc: Remove duplicate prefix in GPU information line in log 2024-12-29 00:27:23 -06:00
Evan Husted
df91c4c57a UI: Fix Title updates being not formatted 2024-12-29 00:08:20 -06:00
Evan Husted
2aaaa7872f UI: Improve XC2 hack hover tooltip information 2024-12-28 22:28:40 -06:00
Evan Husted
b5999583d6 misc: this is C# XMLdocs not Javadocs 2024-12-28 22:08:37 -06:00
Evan Husted
8b3a945b5f misc: Dirty Hacks
Enable this settings screen via a boolean in Config.json
First one is the xb2 menu softlock fix
2024-12-28 22:04:21 -06:00
madwind
69dfd8c60e fix right Stick 2024-12-29 02:11:31 +08:00
madwind
8e50dd9fa6 fix right JoyCon stick 2024-12-29 01:49:25 +08:00
madwind
68c03051ad For the JoyCon controller, wrap SDL2Gamepad as SDL2JoyCon to use a suitable layout and correct the motion sensing and joystick orientation. 2024-12-29 00:56:03 +08:00
Evan Husted
a837294b11 Merge branch 'master' into master 2024-12-28 06:01:06 -06:00
Evan Husted
09107b67ff misc: Remove GAL/Configuration duplicate enums 2024-12-28 05:08:21 -06:00
Evan Husted
12b264af44 Headless in Avalonia v2 (#448)
Launch the Ryujinx.exe, first argument --no-gui or nogui, and the rest of the arguments should be your normal headless script. You can include the new option --use-main-config which will provide any arguments that you don't, filled in from your main config made by the UI.

Input config is not inherited at this time.
2024-12-28 03:49:06 -06:00
Evan Husted
0c21b07f19 Update nightly_pr_comment.yml 2024-12-28 03:01:59 -06:00
Evan Husted
18625cf775 Update nightly_pr_comment.yml 2024-12-28 02:45:33 -06:00
heihei123456780
77a9246825 Updated zh-CN translation (#440) 2024-12-28 02:42:25 -06:00
Evan Husted
709eeda94a (try) fix PR build comments 2024-12-28 02:00:46 -06:00
Evan Husted
7d54424048 misc: Use selector fields 2024-12-27 21:31:46 -06:00
Evan Husted
664c63c6a8 metal: Bump SharpMetal to preview 21 2024-12-27 20:47:43 -06:00
IvonWei
f1c0cc8076 Merge branch 'Ryubing:master' into master 2024-12-28 09:09:10 +08:00
madwind
6dec7ff8ba fix motionData 2024-12-28 09:07:22 +08:00
Elijah Fronzak
153d1ef06b ru_RU locale update (#450)
Co-authored-by: Evan Husted <greem@greemdev.net>
2024-12-27 18:45:42 -06:00
Daniel Nylander
e1e4e5d2d5 Swedish translation (#446)
Co-authored-by: LotP1 <68976644+LotP1@users.noreply.github.com>
2024-12-27 17:58:58 -06:00
Evan Husted
44ee4190e6 JAVASCRIPT LOL 2024-12-27 16:11:23 -06:00
Evan Husted
9408452f93 ok that one was my fault 2024-12-27 16:10:03 -06:00
Evan Husted
38833ff60a i dont know why this is failing this is stupid 2024-12-27 16:07:23 -06:00
Evan Husted
1faa72f22f infra: fix big tables in releases 2024-12-27 15:44:20 -06:00
Evan Husted
56e45ae648 misc: Collapse LdnGameDataArray into the main class as an inner class
- privated the constructor; only obtainable by the static helper on the main LdnGameData class.
- constructor logic now in the static helper; constructor just directly sets the data it's given.
2024-12-27 15:33:31 -06:00
Evan Husted
07074272ca Revert "UI: Directly proxy window properties on the view model back to the stored window"
This reverts commit 9754d247b5.
2024-12-27 15:24:57 -06:00
Evan Husted
9eb273a0f7 Org rename (they call me indecisive) 2024-12-27 02:05:37 -06:00
Evan Husted
ccddaa77d1 infra: Org 2024-12-27 01:59:29 -06:00
Evan Husted
01c2e67334 lol 2024-12-27 01:41:48 -06:00
Evan Husted
4c646721d6 infra: Testing moving canary to the future home of this fork 2024-12-27 01:38:51 -06:00
Evan Husted
d3bc3a1081 UI: Simplify LDN data logic 2024-12-27 01:32:23 -06:00
Evan Husted
c69881a0a2 UI: chore: remove direct static MainWindowViewModel reference 2024-12-27 00:47:57 -06:00
Evan Husted
1bc0159139 Once again, I am stupid 2024-12-27 00:41:50 -06:00
Evan Husted
0733b7d0a1 chore: Remove duplicate VSyncMode enum in GAL 2024-12-27 00:38:12 -06:00
madwind
20fdbff964 clean log 2024-12-26 14:47:40 +08:00
IvonWei
e426680cb0 Merge branch 'GreemDev:master' into master 2024-12-26 11:58:50 +08:00
madwind
7863e97cb0 invoke OnGamepadConnected and OnGamepadDisconnected 2024-12-26 11:58:00 +08:00
madwind
c4dea0ee28 add SQL_JOYBATTERYUPDATED , OnJoyBatteryUpdated 2024-12-26 11:54:52 +08:00
IvonWei
e0b6a01e9d Merge branch 'GreemDev:master' into master 2024-12-25 17:00:53 +08:00
madwind
e509ffa716 delay 2000ms before ShowPowerLevel 2024-12-25 16:57:36 +08:00
IvonWei
714c68b548 Merge branch 'GreemDev:master' into master 2024-12-25 10:41:20 +08:00
madwind
fec197d9ec log powerLevel 2024-12-25 10:39:07 +08:00
IvonWei
a4b2feef79 Merge branch 'GreemDev:master' into master 2024-12-23 22:13:47 +08:00
IvonWei
ad7d9d1ce0 Update NpadController.cs
add ?
2024-12-23 18:55:49 +08:00
IvonWei
86f9544910 Update NpadController.cs
back to Debug
2024-12-23 18:54:11 +08:00
madwind
e9ecbd44fc Add a virtual controller to merge Joy-Cons. 2024-12-23 17:57:55 +08:00
202 changed files with 4177 additions and 2880 deletions

View File

@@ -64,14 +64,9 @@ jobs:
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.platform.name }}" -o ./publish -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER src/Ryujinx --self-contained
if: github.event_name == 'pull_request' && matrix.platform.os != 'macos-13'
- name: Publish Ryujinx.Headless.SDL2
run: dotnet publish -c "${{ matrix.configuration }}" -r "${{ matrix.platform.name }}" -o ./publish_sdl2_headless -p:Version="${{ env.RYUJINX_BASE_VERSION }}" -p:DebugType=embedded -p:SourceRevisionId="${{ steps.git_short_hash.outputs.result }}" -p:ExtraDefineConstants=DISABLE_UPDATER src/Ryujinx.Headless.SDL2 --self-contained
if: github.event_name == 'pull_request' && matrix.platform.os != 'macos-13'
- name: Set executable bit
run: |
chmod +x ./publish/Ryujinx ./publish/Ryujinx.sh
chmod +x ./publish_sdl2_headless/Ryujinx.Headless.SDL2 ./publish_sdl2_headless/Ryujinx.sh
if: github.event_name == 'pull_request' && matrix.platform.os == 'ubuntu-latest'
- name: Build AppImage
@@ -119,13 +114,6 @@ jobs:
name: ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.platform.zip_os_name }}-AppImage
path: publish_appimage
- name: Upload Ryujinx.Headless.SDL2 artifact
uses: actions/upload-artifact@v4
with:
name: nogui-ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.platform.zip_os_name }}
path: publish_sdl2_headless
if: github.event_name == 'pull_request' && matrix.platform.os != 'macos-13'
build_macos:
name: macOS Universal (${{ matrix.configuration }})
runs-on: ubuntu-latest
@@ -171,20 +159,9 @@ jobs:
run: |
./distribution/macos/create_macos_build_ava.sh . publish_tmp publish ./distribution/macos/entitlements.xml "${{ env.RYUJINX_BASE_VERSION }}" "${{ steps.git_short_hash.outputs.result }}" "${{ matrix.configuration }}" "-p:ExtraDefineConstants=DISABLE_UPDATER"
- name: Publish macOS Ryujinx.Headless.SDL2
run: |
./distribution/macos/create_macos_build_headless.sh . publish_tmp_headless publish_headless ./distribution/macos/entitlements.xml "${{ env.RYUJINX_BASE_VERSION }}" "${{ steps.git_short_hash.outputs.result }}" "${{ matrix.configuration }}" "-p:ExtraDefineConstants=DISABLE_UPDATER"
- name: Upload Ryujinx artifact
uses: actions/upload-artifact@v4
with:
name: ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-macos_universal
path: "publish/*.tar.gz"
if: github.event_name == 'pull_request'
- name: Upload Ryujinx.Headless.SDL2 artifact
uses: actions/upload-artifact@v4
with:
name: nogui-ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-macos_universal
path: "publish_headless/*.tar.gz"
if: github.event_name == 'pull_request'

View File

@@ -21,9 +21,9 @@ env:
DOTNET_CLI_TELEMETRY_OPTOUT: 1
RYUJINX_BASE_VERSION: "1.2"
RYUJINX_TARGET_RELEASE_CHANNEL_NAME: "canary"
RYUJINX_TARGET_RELEASE_CHANNEL_OWNER: "GreemDev"
RYUJINX_TARGET_RELEASE_CHANNEL_OWNER: "Ryubing"
RYUJINX_TARGET_RELEASE_CHANNEL_SOURCE_REPO: "Ryujinx"
RYUJINX_TARGET_RELEASE_CHANNEL_REPO: "Ryujinx-Canary"
RYUJINX_TARGET_RELEASE_CHANNEL_REPO: "Canary-Releases"
RELEASE: 1
jobs:
@@ -43,8 +43,8 @@ jobs:
with:
script: |
github.rest.git.createRef({
owner: context.repo.owner,
repo: context.repo.repo,
owner: "${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}",
repo: "${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_SOURCE_REPO }}",
ref: 'refs/tags/Canary-${{ steps.version_info.outputs.build_version }}',
sha: context.sha
})
@@ -64,7 +64,7 @@ jobs:
| 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) |
| 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 }}
omitBodyDuringUpdate: true
@@ -116,7 +116,6 @@ jobs:
- name: Publish
run: |
dotnet publish -c Release -r "${{ matrix.platform.name }}" -o ./publish_ava/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx --self-contained
dotnet publish -c Release -r "${{ matrix.platform.name }}" -o ./publish_sdl2_headless/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx.Headless.SDL2 --self-contained
- name: Packing Windows builds
if: matrix.platform.os == 'windows-latest'
@@ -125,11 +124,6 @@ jobs:
rm publish/libarmeilleure-jitsupport.dylib
7z a ../release_output/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip publish
popd
pushd publish_sdl2_headless
rm publish/libarmeilleure-jitsupport.dylib
7z a ../release_output/nogui-ryujinx-canary-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip publish
popd
shell: bash
- name: Packing Linux builds
@@ -140,12 +134,6 @@ jobs:
chmod +x publish/Ryujinx.sh publish/Ryujinx
tar -czvf ../release_output/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz publish
popd
pushd publish_sdl2_headless
rm publish/libarmeilleure-jitsupport.dylib
chmod +x publish/Ryujinx.sh publish/Ryujinx.Headless.SDL2
tar -czvf ../release_output/nogui-ryujinx-canary-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz publish
popd
shell: bash
#- name: Build AppImage (Linux)
@@ -191,21 +179,21 @@ jobs:
with:
name: ${{ steps.version_info.outputs.build_version }}
artifacts: "release_output/*.tar.gz,release_output/*.zip"
#artifacts: "release_output/*.tar.gz,release_output/*.zip/*AppImage*"
#artifacts: "release_output/*.tar.gz,release_output/*.zip,release_output/*AppImage*"
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.
These builds are experimental and may sometimes not work, use [regular builds](https://github.com/${{ github.repository }}/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 |
| 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 }}"
**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
allowUpdates: true
replacesArtifacts: true
@@ -262,15 +250,11 @@ jobs:
run: |
./distribution/macos/create_macos_build_ava.sh . publish_tmp_ava publish_ava ./distribution/macos/entitlements.xml "${{ steps.version_info.outputs.build_version }}" "${{ steps.version_info.outputs.git_short_hash }}" Release 1
- name: Publish macOS Ryujinx.Headless.SDL2
run: |
./distribution/macos/create_macos_build_headless.sh . publish_tmp_headless publish_headless ./distribution/macos/entitlements.xml "${{ steps.version_info.outputs.build_version }}" "${{ steps.version_info.outputs.git_short_hash }}" Release 1
- name: Pushing new release
uses: ncipollo/release-action@v1
with:
name: "Canary ${{ steps.version_info.outputs.build_version }}"
artifacts: "publish_ava/*.tar.gz, publish_headless/*.tar.gz"
artifacts: "publish_ava/*.tar.gz"
tag: ${{ steps.version_info.outputs.build_version }}
body: ""
omitBodyDuringUpdate: true

View File

@@ -37,21 +37,17 @@ jobs:
if (!artifacts.length) {
return core.error(`No artifacts found`);
}
let body = `Download the artifacts for this pull request:\n`;
let hidden_headless_artifacts = `\n\n <details><summary>GUI-less</summary>\n`;
let body = `*You need to be logged into GitHub to download these files.*\n\nDownload the artifacts for this pull request:\n`;
let hidden_debug_artifacts = `\n\n <details><summary>Only for Developers</summary>\n`;
for (const art of artifacts) {
const url = `https://github.com/Ryubing/Ryujinx/actions/runs/${run_id}/artifacts/${art.id}`;
if(art.name.includes('Debug')) {
hidden_debug_artifacts += `\n* [${art.name}](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`;
} else if(art.name.includes('nogui-ryujinx')) {
hidden_headless_artifacts += `\n* [${art.name}](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`;
hidden_debug_artifacts += `\n* [${art.name}](${url})`;
} else {
body += `\n* [${art.name}](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`;
body += `\n* [${art.name}](${url})`;
}
}
hidden_headless_artifacts += `\n</details>`;
hidden_debug_artifacts += `\n</details>`;
body += hidden_headless_artifacts;
body += hidden_debug_artifacts;
const {data: comments} = await github.rest.issues.listComments({repo, owner, issue_number});

View File

@@ -21,7 +21,7 @@ env:
DOTNET_CLI_TELEMETRY_OPTOUT: 1
RYUJINX_BASE_VERSION: "1.2"
RYUJINX_TARGET_RELEASE_CHANNEL_NAME: "release"
RYUJINX_TARGET_RELEASE_CHANNEL_OWNER: "GreemDev"
RYUJINX_TARGET_RELEASE_CHANNEL_OWNER: "Ryubing"
RYUJINX_TARGET_RELEASE_CHANNEL_REPO: "Ryujinx"
RELEASE: 1
@@ -42,8 +42,8 @@ jobs:
with:
script: |
github.rest.git.createRef({
owner: context.repo.owner,
repo: context.repo.repo,
owner: "${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}",
repo: "${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}",
ref: 'refs/tags/${{ steps.version_info.outputs.build_version }}',
sha: context.sha
})
@@ -54,13 +54,13 @@ jobs:
name: ${{ steps.version_info.outputs.build_version }}
tag: ${{ steps.version_info.outputs.build_version }}
body: |
# Regular builds:
# Stable 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) |
| 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) |
| Windows 64-bit | [Stable 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 | [Stable 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 | [Stable 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 | [Stable 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 }}
omitBodyDuringUpdate: true
@@ -112,7 +112,6 @@ jobs:
- name: Publish
run: |
dotnet publish -c Release -r "${{ matrix.platform.name }}" -o ./publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx --self-contained
dotnet publish -c Release -r "${{ matrix.platform.name }}" -o ./publish_sdl2_headless -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx.Headless.SDL2 --self-contained
- name: Packing Windows builds
if: matrix.platform.os == 'windows-latest'
@@ -121,11 +120,6 @@ jobs:
rm libarmeilleure-jitsupport.dylib
7z a ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip ../publish
popd
pushd publish_sdl2_headless
rm libarmeilleure-jitsupport.dylib
7z a ../release_output/nogui-ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip ../publish
popd
shell: bash
- name: Build AppImage (Linux)
@@ -172,11 +166,6 @@ jobs:
chmod +x Ryujinx.sh Ryujinx
tar -czvf ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz ../publish
popd
pushd publish_sdl2_headless
chmod +x Ryujinx.sh Ryujinx.Headless.SDL2
tar -czvf ../release_output/nogui-ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz ../publish
popd
shell: bash
- name: Pushing new release
@@ -186,15 +175,15 @@ jobs:
artifacts: "release_output/*.tar.gz,release_output/*.zip,release_output/*AppImage*"
tag: ${{ steps.version_info.outputs.build_version }}
body: |
# Regular builds:
# Stable 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 }}"
| Windows 64-bit | [Stable 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 | [Stable 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 | [Stable 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 | [Stable 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 }}
omitBodyDuringUpdate: true
allowUpdates: true
replacesArtifacts: true
@@ -251,15 +240,11 @@ jobs:
run: |
./distribution/macos/create_macos_build_ava.sh . publish_tmp_ava publish ./distribution/macos/entitlements.xml "${{ steps.version_info.outputs.build_version }}" "${{ steps.version_info.outputs.git_short_hash }}" Release 0
- name: Publish macOS Ryujinx.Headless.SDL2
run: |
./distribution/macos/create_macos_build_headless.sh . publish_tmp_headless publish_headless ./distribution/macos/entitlements.xml "${{ steps.version_info.outputs.build_version }}" "${{ steps.version_info.outputs.git_short_hash }}" Release 0
- name: Pushing new release
uses: ncipollo/release-action@v1
with:
name: ${{ steps.version_info.outputs.build_version }}
artifacts: "publish/*.tar.gz, publish_headless/*.tar.gz"
artifacts: "publish/*.tar.gz"
tag: ${{ steps.version_info.outputs.build_version }}
body: ""
omitBodyDuringUpdate: true

View File

@@ -17,6 +17,7 @@
<PackageVersion Include="Projektanker.Icons.Avalonia.FontAwesome" Version="9.4.0"/>
<PackageVersion Include="Projektanker.Icons.Avalonia.MaterialDesign" Version="9.4.0"/>
<PackageVersion Include="CommandLineParser" Version="2.9.1" />
<PackageVersion Include="CommunityToolkit.Mvvm" Version="8.4.0"/>
<PackageVersion Include="Concentus" Version="2.2.0" />
<PackageVersion Include="DiscordRichPresence" Version="1.2.1.24" />
<PackageVersion Include="DynamicData" Version="9.0.4" />
@@ -41,10 +42,10 @@
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies" Version="5.0.3-build14" />
<PackageVersion Include="Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK" Version="1.2.0" />
<PackageVersion Include="Ryujinx.SDL2-CS" Version="2.30.0-build32" />
<PackageVersion Include="Gommon" Version="2.6.8" />
<PackageVersion Include="Gommon" Version="2.7.0" />
<PackageVersion Include="securifybv.ShellLink" Version="0.1.0" />
<PackageVersion Include="shaderc.net" Version="0.1.0" />
<PackageVersion Include="SharpMetal" Version="1.0.0-preview20" />
<PackageVersion Include="SharpMetal" Version="1.0.0-preview21" />
<PackageVersion Include="SharpZipLib" Version="1.4.2" />
<PackageVersion Include="Silk.NET.Vulkan" Version="2.21.0" />
<PackageVersion Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.21.0" />

View File

@@ -57,14 +57,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.SDL2.Common", "src\
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Audio.Backends.SDL2", "src\Ryujinx.Audio.Backends.SDL2\Ryujinx.Audio.Backends.SDL2.csproj", "{D99A395A-8569-4DB0-B336-900647890052}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Headless.SDL2", "src\Ryujinx.Headless.SDL2\Ryujinx.Headless.SDL2.csproj", "{390DC343-5CB4-4C79-A5DD-E3ED235E4C49}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Nvdec.FFmpeg", "src\Ryujinx.Graphics.Nvdec.FFmpeg\Ryujinx.Graphics.Nvdec.FFmpeg.csproj", "{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx", "src\Ryujinx\Ryujinx.csproj", "{7C1B2721-13DA-4B62-B046-C626605ECCE6}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.UI.Common", "src\Ryujinx.UI.Common\Ryujinx.UI.Common.csproj", "{BA161CA0-CD65-4E6E-B644-51C8D1E542DC}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Horizon.Generators", "src\Ryujinx.Horizon.Generators\Ryujinx.Horizon.Generators.csproj", "{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Vulkan", "src\Ryujinx.Graphics.Vulkan\Ryujinx.Graphics.Vulkan.csproj", "{D4D09B08-D580-4D69-B886-C35D2853F6C8}"
@@ -213,10 +209,6 @@ Global
{D99A395A-8569-4DB0-B336-900647890052}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D99A395A-8569-4DB0-B336-900647890052}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D99A395A-8569-4DB0-B336-900647890052}.Release|Any CPU.Build.0 = Release|Any CPU
{390DC343-5CB4-4C79-A5DD-E3ED235E4C49}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{390DC343-5CB4-4C79-A5DD-E3ED235E4C49}.Debug|Any CPU.Build.0 = Debug|Any CPU
{390DC343-5CB4-4C79-A5DD-E3ED235E4C49}.Release|Any CPU.ActiveCfg = Release|Any CPU
{390DC343-5CB4-4C79-A5DD-E3ED235E4C49}.Release|Any CPU.Build.0 = Release|Any CPU
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -225,10 +217,6 @@ Global
{7C1B2721-13DA-4B62-B046-C626605ECCE6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7C1B2721-13DA-4B62-B046-C626605ECCE6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7C1B2721-13DA-4B62-B046-C626605ECCE6}.Release|Any CPU.Build.0 = Release|Any CPU
{BA161CA0-CD65-4E6E-B644-51C8D1E542DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BA161CA0-CD65-4E6E-B644-51C8D1E542DC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BA161CA0-CD65-4E6E-B644-51C8D1E542DC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BA161CA0-CD65-4E6E-B644-51C8D1E542DC}.Release|Any CPU.Build.0 = Release|Any CPU
{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Release|Any CPU.ActiveCfg = Release|Any CPU
@@ -261,13 +249,12 @@ Global
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Release|Any CPU.Build.0 = Release|Any CPU
{4A89A234-4F19-497D-A576-DDE8CDFC5B22}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4A89A234-4F19-497D-A576-DDE8CDFC5B22}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4A89A234-4F19-497D-A576-DDE8CDFC5B22}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C08931FA-1191-417A-864F-3882D93E683B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C08931FA-1191-417A-864F-3882D93E683B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C08931FA-1191-417A-864F-3882D93E683B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C08931FA-1191-417A-864F-3882D93E683B}.Release|Any CPU.Build.0 = Release|Any CPU
{4A89A234-4F19-497D-A576-DDE8CDFC5B22}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4A89A234-4F19-497D-A576-DDE8CDFC5B22}.Release|Any CPU.ActiveCfg = Release|Any CPU
{81EA598C-DBA1-40B0-8DA4-4796B78F2037}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{81EA598C-DBA1-40B0-8DA4-4796B78F2037}.Debug|Any CPU.Build.0 = Debug|Any CPU
{81EA598C-DBA1-40B0-8DA4-4796B78F2037}.Release|Any CPU.ActiveCfg = Release|Any CPU

View File

@@ -13,7 +13,7 @@ mkdir -p AppDir/usr/bin
cp distribution/linux/Ryujinx.desktop AppDir/Ryujinx.desktop
cp distribution/linux/appimage/AppRun AppDir/AppRun
cp src/Ryujinx.UI.Common/Resources/Logo_Ryujinx.png AppDir/Ryujinx.svg
cp distribution/misc/Logo.svg AppDir/Ryujinx.svg
cp -r "$BUILDDIR"/* AppDir/usr/bin/

View File

@@ -9,20 +9,12 @@ namespace Ryujinx.Audio.Backends.Dummy
{
public class DummyHardwareDeviceDriver : IHardwareDeviceDriver
{
private readonly ManualResetEvent _updateRequiredEvent;
private readonly ManualResetEvent _pauseEvent;
private readonly ManualResetEvent _updateRequiredEvent = new(false);
private readonly ManualResetEvent _pauseEvent = new(true);
public static bool IsSupported => true;
public float Volume { get; set; }
public DummyHardwareDeviceDriver()
{
_updateRequiredEvent = new ManualResetEvent(false);
_pauseEvent = new ManualResetEvent(true);
Volume = 1f;
}
public float Volume { get; set; } = 1f;
public IHardwareDeviceSession OpenDeviceSession(Direction direction, IVirtualMemoryManager memoryManager, SampleFormat sampleFormat, uint sampleRate, uint channelCount)
{
@@ -60,7 +52,7 @@ namespace Ryujinx.Audio.Backends.Dummy
Dispose(true);
}
protected virtual void Dispose(bool disposing)
private void Dispose(bool disposing)
{
if (disposing)
{

View File

@@ -0,0 +1,7 @@
namespace Ryujinx.BuildValidationTasks
{
public interface IValidationTask
{
public bool Execute(string projectPath, bool isGitRunner);
}
}

View File

@@ -1,73 +0,0 @@
using System;
using Microsoft.Build.Utilities;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using Newtonsoft.Json;
using Microsoft.Build.Framework;
namespace Ryujinx.BuildValidationTasks
{
public class LocaleValidationTask : Task
{
public override bool Execute()
{
string path = System.Reflection.Assembly.GetExecutingAssembly().Location;
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;
}
else
{
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(path))
{
data = sr.ReadToEnd();
}
LocalesJson json = JsonConvert.DeserializeObject<LocalesJson>(data);
for (int i = 0; i < json.Locales.Count; i++)
{
LocalesEntry locale = json.Locales[i];
foreach (string langCode in json.Languages.Where(it => !locale.Translations.ContainsKey(it)))
{
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);
json.Locales[i] = locale;
}
string jsonString = JsonConvert.SerializeObject(json, Formatting.Indented);
using (StreamWriter sw = new(path))
{
sw.Write(jsonString);
}
return true;
}
struct LocalesJson
{
public List<string> Languages { get; set; }
public List<LocalesEntry> Locales { get; set; }
}
struct LocalesEntry
{
public string ID { get; set; }
public Dictionary<string, string> Translations { get; set; }
}
}
}

View File

@@ -0,0 +1,117 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.IO;
using System.Text.Json;
using System.Text.Encodings.Web;
namespace Ryujinx.BuildValidationTasks
{
public class LocalesValidationTask : IValidationTask
{
public LocalesValidationTask() { }
public bool Execute(string projectPath, bool isGitRunner)
{
Console.WriteLine("Running Locale Validation Task...");
string path = projectPath + "src/Ryujinx/Assets/locales.json";
string data;
using (StreamReader sr = new(path))
{
data = sr.ReadToEnd();
}
LocalesJson json;
if (isGitRunner && data.Contains("\r\n"))
throw new FormatException("locales.json is using CRLF line endings! It should be using LF line endings, build locally to fix...");
try
{
json = JsonSerializer.Deserialize<LocalesJson>(data);
}
catch (JsonException e)
{
throw new JsonException(e.Message); //shorter and easier stacktrace
}
bool encounteredIssue = false;
for (int i = 0; i < json.Locales.Count; i++)
{
LocalesEntry locale = json.Locales[i];
foreach (string langCode in json.Languages.Where(lang => !locale.Translations.ContainsKey(lang)))
{
encounteredIssue = true;
if (!isGitRunner)
{
locale.Translations.Add(langCode, string.Empty);
Console.WriteLine($"Added '{langCode}' to Locale '{locale.ID}'");
}
else
{
Console.WriteLine($"Missing '{langCode}' in Locale '{locale.ID}'!");
}
}
foreach (string langCode in json.Languages.Where(lang => locale.Translations.ContainsKey(lang) && lang != "en_US" && locale.Translations[lang] == locale.Translations["en_US"]))
{
encounteredIssue = true;
if (!isGitRunner)
{
locale.Translations[langCode] = string.Empty;
Console.WriteLine($"Lanugage '{langCode}' is a duplicate of en_US in Locale '{locale.ID}'! Resetting it...");
}
else
{
Console.WriteLine($"Lanugage '{langCode}' is a duplicate of en_US in Locale '{locale.ID}'!");
}
}
locale.Translations = locale.Translations.OrderBy(pair => pair.Key).ToDictionary(pair => pair.Key, pair => pair.Value);
json.Locales[i] = locale;
}
if (isGitRunner && encounteredIssue)
throw new JsonException("1 or more locales are invalid!");
JsonSerializerOptions jsonOptions = new JsonSerializerOptions()
{
WriteIndented = true,
NewLine = "\n",
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping
};
string jsonString = JsonSerializer.Serialize(json, jsonOptions);
using (StreamWriter sw = new(path))
{
sw.Write(jsonString);
}
Console.WriteLine("Finished Locale Validation Task!");
return true;
}
struct LocalesJson
{
public List<string> Languages { get; set; }
public List<LocalesEntry> Locales { get; set; }
}
struct LocalesEntry
{
public string ID { get; set; }
public Dictionary<string, string> Translations { get; set; }
}
}
}

View File

@@ -0,0 +1,37 @@
using System;
using System.IO;
using System.Linq;
namespace Ryujinx.BuildValidationTasks
{
public class Program
{
static void Main(string[] args)
{
// Display the number of command line arguments.
if (args.Length == 0)
throw new ArgumentException("Error: too few arguments!");
string path = args[0];
if (string.IsNullOrEmpty(path))
throw new ArgumentException("Error: path is null or empty!");
if (!Path.Exists(path))
throw new FileLoadException($"path {{{path}}} does not exist!");
path = Path.GetFullPath(path);
if (!Directory.GetDirectories(path).Contains($"{path}src"))
throw new FileLoadException($"path {{{path}}} is not a valid ryujinx project!");
bool isGitRunner = path.Contains("runner") || path.Contains("D:\\a\\Ryujinx\\Ryujinx");
if (isGitRunner)
Console.WriteLine("Is Git Runner!");
// Run tasks
// Pass extra info needed in the task constructors
new LocalesValidationTask().Execute(path, isGitRunner);
}
}
}

View File

@@ -1,19 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
<OutputType>Exe</OutputType>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Build.Utilities.Core" />
<PackageReference Include="Newtonsoft.Json" />
</ItemGroup>
<Target Name="PostBuildTarget" AfterTargets="AfterBuild">
<Message Text="Running Validation Project" Importance="high" />
<UsingTask TaskName="Ryujinx.BuildValidationTasks.LocaleValidationTask" TaskFactory="TaskHostFactory" AssemblyFile="$(OutDir)Ryujinx.BuildValidationTasks.dll" />
<Target Name="LocalesJsonValidation" AfterTargets="AfterRebuild">
<LocaleValidationTask />
<Exec WorkingDirectory="$(ProjectDir)bin\Debug\$(TargetFramework)\"
Command="dotnet Ryujinx.BuildValidationTasks.dll &quot;$(ProjectDir)..\..\\&quot;"
ConsoleToMsBuild="true"
Condition="'$(RuntimeIdentifier)' == ''"
/>
</Target>
</Project>
</Project>

View File

@@ -35,6 +35,8 @@ namespace Ryujinx.Common.Configuration
#pragma warning restore IDE0055
};
}
public static float ToFloatY(this AspectRatio aspectRatio)
{

View File

@@ -0,0 +1,60 @@
using Gommon;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Ryujinx.Common.Configuration
{
[Flags]
public enum DirtyHack : byte
{
Xc2MenuSoftlockFix = 1,
ShaderTranslationDelay = 2
}
public readonly struct EnabledDirtyHack(DirtyHack hack, int value)
{
public DirtyHack Hack => hack;
public int Value => value;
public ulong Pack() => Raw.PackBitFields(PackedFormat);
public static EnabledDirtyHack Unpack(ulong packedHack)
{
var unpackedFields = packedHack.UnpackBitFields(PackedFormat);
if (unpackedFields is not [var hack, var value])
throw new ArgumentException(nameof(packedHack));
return new EnabledDirtyHack((DirtyHack)hack, (int)value);
}
private uint[] Raw => [(uint)Hack, (uint)Value.CoerceAtLeast(0)];
public static readonly byte[] PackedFormat = [8, 32];
}
public class DirtyHacks : Dictionary<DirtyHack, int>
{
public DirtyHacks(IEnumerable<EnabledDirtyHack> hacks)
=> hacks.ForEach(edh => Add(edh.Hack, edh.Value));
public DirtyHacks(ulong[] packedHacks) : this(packedHacks.Select(EnabledDirtyHack.Unpack)) {}
public ulong[] PackEntries()
=> Entries.Select(it => it.Pack()).ToArray();
public EnabledDirtyHack[] Entries
=> this
.Select(it => new EnabledDirtyHack(it.Key, it.Value))
.ToArray();
public static implicit operator DirtyHacks(EnabledDirtyHack[] hacks) => new(hacks);
public static implicit operator DirtyHacks(ulong[] packedHacks) => new(packedHacks);
public new int this[DirtyHack hack] => TryGetValue(hack, out var value) ? value : -1;
public bool IsEnabled(DirtyHack hack) => ContainsKey(hack);
}
}

View File

@@ -9,5 +9,6 @@ namespace Ryujinx.Common.Configuration
Bilinear,
Nearest,
Fsr,
Area,
}
}

View File

@@ -8,10 +8,10 @@ namespace Ryujinx.Common
public static class StreamExtensions
{
/// <summary>
/// Writes a <see cref="ReadOnlySpan{int}" /> to this stream.
/// Writes an int span to this stream.
///
/// This default implementation converts each buffer value to a stack-allocated
/// byte array, then writes it to the Stream using <cref="System.Stream.Write(byte[])" />.
/// byte array, then writes it to the Stream using <see cref="Stream.Write(ReadOnlySpan{byte})" />.
/// </summary>
/// <param name="stream">The stream to be written to</param>
/// <param name="buffer">The buffer of values to be written</param>

View File

@@ -3,7 +3,7 @@ using System;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
namespace Ryujinx.UI.Common.Helper
namespace Ryujinx.Common.Helper
{
public static partial class ConsoleHelper
{

View File

@@ -8,7 +8,7 @@ using System.Linq;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
namespace Ryujinx.UI.Common.Helper
namespace Ryujinx.Common.Helper
{
public static partial class FileAssociationHelper
{
@@ -132,7 +132,7 @@ namespace Ryujinx.UI.Common.Helper
if (uninstall)
{
// If the types don't already exist, there's nothing to do and we can call this operation successful.
// If the types don't already exist, there's nothing to do, and we can call this operation successful.
if (!AreMimeTypesRegisteredWindows())
{
return true;

View File

@@ -3,7 +3,7 @@ using System.Diagnostics;
using System.IO;
using System.Runtime.Versioning;
namespace Ryujinx.UI.Common.Helper
namespace Ryujinx.Common.Helper
{
[SupportedOSPlatform("linux")]
public static class LinuxHelper

View File

@@ -2,7 +2,7 @@ using System;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
namespace Ryujinx.UI.Common.Helper
namespace Ryujinx.Common.Helper
{
[SupportedOSPlatform("macos")]
public static partial class ObjectiveC

View File

@@ -5,7 +5,7 @@ using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
namespace Ryujinx.UI.Common.Helper
namespace Ryujinx.Common.Helper
{
public static partial class OpenHelper
{

View File

@@ -4,6 +4,7 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading;
@@ -157,21 +158,16 @@ namespace Ryujinx.Common.Logging
_time.Restart();
}
private static ILogTarget GetTarget(string targetName)
{
foreach (var target in _logTargets)
{
if (target.Name.Equals(targetName))
{
return target;
}
}
return null;
}
private static ILogTarget GetTarget(string targetName)
=> _logTargets.FirstOrDefault(target => target.Name.Equals(targetName));
public static void AddTarget(ILogTarget target)
{
if (_logTargets.Any(t => t.Name == target.Name))
{
return;
}
_logTargets.Add(target);
Updated += target.Log;

View File

@@ -27,11 +27,7 @@ namespace Ryujinx.Common.Logging.Targets
private readonly int _overflowTimeout;
string ILogTarget.Name { get => _target.Name; }
public AsyncLogTargetWrapper(ILogTarget target)
: this(target, -1)
{ }
string ILogTarget.Name => _target.Name;
public AsyncLogTargetWrapper(ILogTarget target, int queueLimit = -1, AsyncLogTargetOverflowAction overflowAction = AsyncLogTargetOverflowAction.Block)
{

View File

@@ -8,6 +8,8 @@ namespace Ryujinx.Common
{
public static class TitleIDs
{
public static ReactiveObject<Optional<string>> CurrentApplication { get; set; } = new();
public static GraphicsBackend SelectGraphicsBackend(string titleId, GraphicsBackend currentBackend)
{
switch (currentBackend)
@@ -33,6 +35,8 @@ namespace Ryujinx.Common
"010028600EBDA000", // Mario 3D World
"0100152000022000", // Mario Kart 8 Deluxe
"01005CA01580E000", // Persona 5
"0100187003A36000", // Pokémon: Let's Go, Evoli!
"010003f003a34000", // Pokémon: Let's Go, Pikachu!
"01008C0016544000", // Sea of Stars
"01006A800016E000", // Smash Ultimate
"0100000000010000", // Super Mario Odyessy

View File

@@ -1,4 +1,4 @@
namespace Ryujinx.UI.Common
namespace Ryujinx.Common.UI
{
/// <summary>
/// Represent a common error that could be reported to the user by the emulator.

View File

@@ -40,5 +40,35 @@ namespace Ryujinx.Common
return (value >> 32) | (value << 32);
}
// Never actually written bit packing logic before, so I looked it up.
// This code is from https://gist.github.com/Alan-FGR/04938e93e2bffdf5802ceb218a37c195
public static ulong PackBitFields(this uint[] values, byte[] bitFields)
{
ulong retVal = values[0]; //we set the first value right away
for (int f = 1; f < values.Length; f++)
{
retVal <<= bitFields[f]; // we shift the previous value
retVal += values[f];// and add our current value
}
return retVal;
}
public static uint[] UnpackBitFields(this ulong packed, byte[] bitFields)
{
int fields = bitFields.Length - 1; // number of fields to unpack
uint[] retArr = new uint[fields + 1]; // init return array
int curPos = 0; // current field bit position (start)
int lastEnd; // position where last field ended
for (int f = fields; f >= 0; f--) // loop from last
{
lastEnd = curPos; // we store where the last value ended
curPos += bitFields[f]; // we get where the current value starts
int leftShift = 64 - curPos; // we figure how much left shift we gotta apply for the other numbers to overflow into oblivion
retArr[f] = (uint)((packed << leftShift) >> leftShift + lastEnd); // we do magic
}
return retArr;
}
}
}

View File

@@ -1,12 +0,0 @@
namespace Ryujinx.Graphics.GAL
{
public enum AntiAliasing
{
None,
Fxaa,
SmaaLow,
SmaaMedium,
SmaaHigh,
SmaaUltra,
}
}

View File

@@ -1,3 +1,4 @@
using Ryujinx.Common.Configuration;
using System;
namespace Ryujinx.Graphics.GAL

View File

@@ -1,3 +1,4 @@
using Ryujinx.Common.Configuration;
using Ryujinx.Graphics.GAL.Multithreading.Commands.Window;
using Ryujinx.Graphics.GAL.Multithreading.Model;
using Ryujinx.Graphics.GAL.Multithreading.Resources;

View File

@@ -1,10 +0,0 @@
namespace Ryujinx.Graphics.GAL
{
public enum ScalingFilter
{
Bilinear,
Nearest,
Fsr,
Area,
}
}

View File

@@ -1,9 +0,0 @@
namespace Ryujinx.Graphics.GAL
{
public enum VSyncMode
{
Switch,
Unbounded,
Custom
}
}

View File

@@ -1,4 +1,5 @@
using Ryujinx.Common;
using Ryujinx.Common.Configuration;
using Ryujinx.Graphics.Device;
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Gpu.Engine.GPFifo;
@@ -90,6 +91,13 @@ namespace Ryujinx.Graphics.Gpu
/// Support buffer updater.
/// </summary>
internal SupportBufferUpdater SupportBufferUpdater { get; }
/// <summary>
/// Enabled dirty hacks.
/// Used for workarounds to emulator bugs we can't fix/don't know how to fix yet.
/// </summary>
internal DirtyHacks DirtyHacks { get; }
/// <summary>
/// Host hardware capabilities.
@@ -113,7 +121,7 @@ namespace Ryujinx.Graphics.Gpu
/// Creates a new instance of the GPU emulation context.
/// </summary>
/// <param name="renderer">Host renderer</param>
public GpuContext(IRenderer renderer)
public GpuContext(IRenderer renderer, DirtyHacks hacks)
{
Renderer = renderer;
@@ -136,6 +144,8 @@ namespace Ryujinx.Graphics.Gpu
SupportBufferUpdater = new SupportBufferUpdater(renderer);
DirtyHacks = hacks;
_firstTimestamp = ConvertNanosecondsToTicks((ulong)PerformanceCounter.ElapsedNanoseconds);
}

View File

@@ -46,7 +46,7 @@ namespace Ryujinx.Graphics.Gpu
/// Enables or disables high-level emulation of common GPU Macro code.
/// </summary>
public static bool EnableMacroHLE = true;
/// <summary>
/// Title id of the current running game.
/// Used by the shader cache.

View File

@@ -1,3 +1,4 @@
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging;
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Shader;
@@ -366,6 +367,9 @@ namespace Ryujinx.Graphics.Gpu.Shader.DiskCache
{
try
{
if (_context.DirtyHacks.IsEnabled(DirtyHack.ShaderTranslationDelay))
Thread.Sleep(_context.DirtyHacks[DirtyHack.ShaderTranslationDelay]);
AsyncProgramTranslation asyncTranslation = new(guestShaders, specState, programIndex, isCompute);
_asyncTranslationQueue.Add(asyncTranslation, _cancellationToken);
}

View File

@@ -1,3 +1,4 @@
using Ryujinx.Common;
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging;
using Ryujinx.Graphics.GAL;

View File

@@ -1,4 +1,5 @@
using SharpMetal;
using SharpMetal.Foundation;
using SharpMetal.ObjectiveCCore;
using SharpMetal.QuartzCore;
using System.Runtime.Versioning;
@@ -9,22 +10,13 @@ namespace Ryujinx.Graphics.Metal.SharpMetalExtensions
[SupportedOSPlatform("macOS")]
public static class CAMetalLayerExtensions
{
private static readonly Selector sel_displaySyncEnabled = "displaySyncEnabled";
private static readonly Selector sel_setDisplaySyncEnabled = "setDisplaySyncEnabled:";
private static readonly Selector sel_developerHUDProperties = "developerHUDProperties";
private static readonly Selector sel_setDeveloperHUDProperties = "setDeveloperHUDProperties:";
public static bool IsDisplaySyncEnabled(this CAMetalLayer metalLayer)
=> ObjectiveCRuntime.bool_objc_msgSend(metalLayer.NativePtr, sel_displaySyncEnabled);
public static void SetDisplaySyncEnabled(this CAMetalLayer metalLayer, bool enabled)
=> ObjectiveCRuntime.objc_msgSend(metalLayer.NativePtr, sel_setDisplaySyncEnabled, enabled);
public static NSDictionary GetDeveloperHudProperties(this CAMetalLayer metalLayer)
=> new(ObjectiveCRuntime.IntPtr_objc_msgSend(metalLayer.NativePtr, sel_developerHUDProperties));
public static nint GetDeveloperHudProperties(this CAMetalLayer metalLayer)
=> ObjectiveCRuntime.IntPtr_objc_msgSend(metalLayer.NativePtr, sel_developerHUDProperties);
public static void SetDeveloperHudProperties(this CAMetalLayer metalLayer, nint dictionaryPointer)
=> ObjectiveCRuntime.objc_msgSend(metalLayer.NativePtr, sel_setDeveloperHUDProperties, dictionaryPointer);
public static void SetDeveloperHudProperties(this CAMetalLayer metalLayer, NSDictionary dictionary)
=> ObjectiveCRuntime.objc_msgSend(metalLayer.NativePtr, sel_setDeveloperHUDProperties, dictionary);
}
}

View File

@@ -0,0 +1,32 @@
using SharpMetal.Foundation;
using SharpMetal.ObjectiveCCore;
using System.Runtime.Versioning;
// ReSharper disable InconsistentNaming
namespace Ryujinx.Graphics.Metal.SharpMetalExtensions
{
[SupportedOSPlatform("macOS")]
public static class NSHelper
{
private static readonly Selector sel_getCStringMaxLengthEncoding = "getCString:maxLength:encoding:";
private static readonly Selector sel_stringWithUTF8String = "stringWithUTF8String:";
public static unsafe string ToDotNetString(this NSString source)
{
char[] sourceBuffer = new char[source.Length];
fixed (char* pSourceBuffer = sourceBuffer)
{
ObjectiveC.bool_objc_msgSend(source,
sel_getCStringMaxLengthEncoding,
pSourceBuffer,
source.MaximumLengthOfBytes(NSStringEncoding.UTF16) + 1,
(ulong)NSStringEncoding.UTF16);
}
return new string(sourceBuffer);
}
public static NSString ToNSString(this string source)
=> new(ObjectiveC.IntPtr_objc_msgSend(new ObjectiveCClass(nameof(NSString)), sel_stringWithUTF8String, source));
}
}

View File

@@ -2,6 +2,7 @@
<PropertyGroup>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>

View File

@@ -1,7 +1,7 @@
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging;
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Metal.Effects;
using Ryujinx.Graphics.Metal.SharpMetalExtensions;
using SharpMetal.ObjectiveCCore;
using SharpMetal.QuartzCore;
using System;
@@ -15,20 +15,22 @@ namespace Ryujinx.Graphics.Metal
public bool ScreenCaptureRequested { get; set; }
private readonly MetalRenderer _renderer;
private readonly CAMetalLayer _metalLayer;
private CAMetalLayer _metalLayer;
private int _width;
private int _height;
private int _requestedWidth;
private int _requestedHeight;
// private bool _vsyncEnabled;
private AntiAliasing _currentAntiAliasing;
private bool _updateEffect;
private IPostProcessingEffect _effect;
private IScalingFilter _scalingFilter;
private bool _isLinear;
public bool IsVSyncEnabled => _metalLayer.DisplaySyncEnabled;
// private float _scalingFilterLevel;
private bool _updateScalingFilter;
private ScalingFilter _currentScalingFilter;
@@ -40,7 +42,7 @@ namespace Ryujinx.Graphics.Metal
_metalLayer = metalLayer;
}
private unsafe void ResizeIfNeeded()
private void ResizeIfNeeded()
{
if (_requestedWidth != 0 && _requestedHeight != 0)
{
@@ -54,7 +56,7 @@ namespace Ryujinx.Graphics.Metal
}
}
public unsafe void Present(ITexture texture, ImageCrop crop, Action swapBuffersCallback)
public void Present(ITexture texture, ImageCrop crop, Action swapBuffersCallback)
{
if (_renderer.Pipeline is Pipeline pipeline && texture is Texture tex)
{
@@ -141,15 +143,7 @@ namespace Ryujinx.Graphics.Metal
public void ChangeVSyncMode(VSyncMode vSyncMode)
{
switch (vSyncMode)
{
case VSyncMode.Unbounded:
_metalLayer.SetDisplaySyncEnabled(false);
break;
case VSyncMode.Switch:
_metalLayer.SetDisplaySyncEnabled(true);
break;
}
_metalLayer.DisplaySyncEnabled = vSyncMode is VSyncMode.Switch;
}
public void SetAntiAliasing(AntiAliasing effect)

View File

@@ -2,8 +2,8 @@ namespace Ryujinx.Graphics.Nvdec.Vp9
{
internal enum BitDepth
{
Bits8 = 8, /**< 8 bits */
Bits10 = 10, /**< 10 bits */
Bits12 = 12, /**< 12 bits */
Bits8 = 8, // < 8 bits
Bits10 = 10, // < 10 bits
Bits12 = 12, // < 12 bits
}
}

View File

@@ -1,4 +1,5 @@
using OpenTK.Graphics.OpenGL;
using Ryujinx.Common.Configuration;
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.OpenGL.Effects;
using Ryujinx.Graphics.OpenGL.Effects.Smaa;

View File

@@ -1,3 +1,4 @@
using Gommon;
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging;
using Ryujinx.Graphics.GAL;
@@ -890,7 +891,12 @@ namespace Ryujinx.Graphics.Vulkan
private void PrintGpuInformation()
{
Logger.Notice.Print(LogClass.Gpu, $"{GpuVendor} {GpuRenderer} ({GpuVersion})");
string gpuInfoMessage = $"{GpuRenderer} ({GpuVersion})";
if (!GpuRenderer.StartsWithIgnoreCase(GpuVendor))
gpuInfoMessage = gpuInfoMessage.Prepend(GpuVendor);
Logger.Notice.Print(LogClass.Gpu, gpuInfoMessage);
Logger.Notice.Print(LogClass.Gpu, $"GPU Memory: {GetTotalGPUMemory() / (1024 * 1024)} MiB");
}

View File

@@ -1,3 +1,4 @@
using Ryujinx.Common.Configuration;
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Vulkan.Effects;
using Silk.NET.Vulkan;

View File

@@ -1,3 +1,4 @@
using Ryujinx.Common.Configuration;
using Ryujinx.Graphics.GAL;
using System;

View File

@@ -9,7 +9,6 @@ using Ryujinx.HLE.HOS.Services.Account.Acc;
using Ryujinx.HLE.HOS.SystemState;
using Ryujinx.HLE.UI;
using System;
using VSyncMode = Ryujinx.Common.Configuration.VSyncMode;
namespace Ryujinx.HLE
{
@@ -189,6 +188,11 @@ namespace Ryujinx.HLE
/// An action called when HLE force a refresh of output after docked mode changed.
/// </summary>
public Action RefreshInputConfig { internal get; set; }
/// <summary>
/// The desired hacky workarounds.
/// </summary>
public EnabledDirtyHack[] Hacks { internal get; set; }
public HLEConfiguration(VirtualFileSystem virtualFileSystem,
LibHacHorizonManager libHacHorizonManager,
@@ -219,7 +223,8 @@ namespace Ryujinx.HLE
bool multiplayerDisableP2p,
string multiplayerLdnPassphrase,
string multiplayerLdnServer,
int customVSyncInterval)
int customVSyncInterval,
EnabledDirtyHack[] dirtyHacks = null)
{
VirtualFileSystem = virtualFileSystem;
LibHacHorizonManager = libHacHorizonManager;
@@ -251,6 +256,7 @@ namespace Ryujinx.HLE
MultiplayerDisableP2p = multiplayerDisableP2p;
MultiplayerLdnPassphrase = multiplayerLdnPassphrase;
MultiplayerLdnServer = multiplayerLdnServer;
Hacks = dirtyHacks ?? [];
}
}
}

View File

@@ -1,3 +1,4 @@
using Gommon;
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging;
using Ryujinx.Common.Utilities;
@@ -6,12 +7,13 @@ using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace Ryujinx.HLE.HOS.Services.Account.Acc
{
class AccountSaveDataManager
public class AccountSaveDataManager
{
private readonly string _profilesJsonPath = Path.Join(AppDataManager.BaseDirPath, "system", "Profiles.json");
private static readonly string _profilesJsonPath = Path.Join(AppDataManager.BaseDirPath, "system", "Profiles.json");
private static readonly ProfilesJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions());
@@ -49,6 +51,16 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
}
}
public static Optional<UserProfile> GetLastUsedUser()
{
ProfilesJson profilesJson = JsonHelper.DeserializeFromFile(_profilesJsonPath, _serializerContext.ProfilesJson);
return profilesJson.Profiles
.FindFirst(profile => profile.AccountState == AccountState.Open)
.Convert(profileJson => new UserProfile(new UserId(profileJson.UserId), profileJson.Name,
profileJson.Image, profileJson.LastModifiedTimestamp));
}
public void Save(ConcurrentDictionary<string, UserProfile> profiles)
{
ProfilesJson profilesJson = new()

View File

@@ -1,6 +1,9 @@
using LibHac;
using LibHac.Common;
using LibHac.Sf;
using Ryujinx.Common;
using Ryujinx.Common.Configuration;
using System.Threading;
namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
{
@@ -13,6 +16,8 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
_baseStorage = SharedRef<LibHac.FsSrv.Sf.IStorage>.CreateMove(ref baseStorage);
}
private const string Xc2TitleId = "0100e95004038000";
[CommandCmif(0)]
// Read(u64 offset, u64 length) -> buffer<u8, 0x46, 0> buffer
public ResultCode Read(ServiceCtx context)
@@ -33,6 +38,13 @@ namespace Ryujinx.HLE.HOS.Services.Fs.FileSystemProxy
using var region = context.Memory.GetWritableRegion(bufferAddress, (int)bufferLen, true);
Result result = _baseStorage.Get.Read((long)offset, new OutBuffer(region.Memory.Span), (long)size);
if (context.Device.DirtyHacks.IsEnabled(DirtyHack.Xc2MenuSoftlockFix) && TitleIDs.CurrentApplication.Value == Xc2TitleId)
{
// Add a load-bearing sleep to avoid XC2 softlock
// https://web.archive.org/web/20240728045136/https://github.com/Ryujinx/Ryujinx/issues/2357
Thread.Sleep(2);
}
return (ResultCode)result.Value;
}

View File

@@ -114,10 +114,10 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.AmiiboDecryption
}
}
string usedCharacterStr = BitConverter.ToString(usedCharacter).Replace("-", "");
string variationStr = BitConverter.ToString(variation).Replace("-", "");
string amiiboIDStr = BitConverter.ToString(amiiboID).Replace("-", "");
string setIDStr = BitConverter.ToString(setID).Replace("-", "");
string usedCharacterStr = Convert.ToHexString(usedCharacter);
string variationStr = Convert.ToHexString(variation);
string amiiboIDStr = Convert.ToHexString(amiiboID);
string setIDStr = Convert.ToHexString(setID);
string head = usedCharacterStr + variationStr;
string tail = amiiboIDStr + setIDStr + "02";
string finalID = head + tail;
@@ -289,8 +289,8 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.AmiiboDecryption
private static void LogFinalData(byte[] titleId, byte[] appId, string head, string tail, string finalID, string nickName, DateTime initDateTime, DateTime writeDateTime, ushort settingsValue, ushort writeCounterValue, byte[] applicationAreas)
{
Logger.Debug?.Print(LogClass.ServiceNfp, $"Title ID: 0x{BitConverter.ToString(titleId).Replace("-", "")}");
Logger.Debug?.Print(LogClass.ServiceNfp, $"Application Program ID: 0x{BitConverter.ToString(appId).Replace("-", "")}");
Logger.Debug?.Print(LogClass.ServiceNfp, $"Title ID: 0x{Convert.ToHexString(titleId)}");
Logger.Debug?.Print(LogClass.ServiceNfp, $"Application Program ID: 0x{Convert.ToHexString(appId)}");
Logger.Debug?.Print(LogClass.ServiceNfp, $"Head: {head}");
Logger.Debug?.Print(LogClass.ServiceNfp, $"Tail: {tail}");
Logger.Debug?.Print(LogClass.ServiceNfp, $"Final ID: {finalID}");

View File

@@ -10,7 +10,6 @@ using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using VSyncMode = Ryujinx.Common.Configuration.VSyncMode;
namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
{

View File

@@ -4,8 +4,10 @@ using LibHac.Fs.Fsa;
using LibHac.Loader;
using LibHac.Ns;
using LibHac.Tools.FsSystem;
using Ryujinx.Common;
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging;
using Ryujinx.Graphics.Gpu;
using Ryujinx.HLE.Loaders.Executables;
using Ryujinx.Memory;
using System;
@@ -102,7 +104,7 @@ namespace Ryujinx.HLE.Loaders.Processes.Extensions
}
// Initialize GPU.
Graphics.Gpu.GraphicsConfig.TitleId = $"{programId:x16}";
GraphicsConfig.TitleId = programId.ToString("X16");
device.Gpu.HostInitalized.Set();
if (!MemoryBlock.SupportsFlags(MemoryAllocationFlags.ViewCompatible))

View File

@@ -6,7 +6,9 @@ using LibHac.Ns;
using LibHac.Tools.Fs;
using LibHac.Tools.FsSystem;
using LibHac.Tools.FsSystem.NcaUtils;
using Ryujinx.Common;
using Ryujinx.Common.Logging;
using Ryujinx.Graphics.Gpu;
using Ryujinx.HLE.Loaders.Executables;
using Ryujinx.HLE.Loaders.Processes.Extensions;
using System;
@@ -59,6 +61,8 @@ namespace Ryujinx.HLE.Loaders.Processes
{
_latestPid = processResult.ProcessId;
TitleIDs.CurrentApplication.Value = processResult.ProgramIdText;
return true;
}
}
@@ -86,6 +90,8 @@ namespace Ryujinx.HLE.Loaders.Processes
{
_latestPid = processResult.ProcessId;
TitleIDs.CurrentApplication.Value = processResult.ProgramIdText;
return true;
}
}
@@ -113,6 +119,8 @@ namespace Ryujinx.HLE.Loaders.Processes
if (processResult.ProgramId > 0x01000000000007FF)
{
_latestPid = processResult.ProcessId;
TitleIDs.CurrentApplication.Value = processResult.ProgramIdText;
}
return true;
@@ -132,6 +140,8 @@ namespace Ryujinx.HLE.Loaders.Processes
{
_latestPid = processResult.ProcessId;
TitleIDs.CurrentApplication.Value = processResult.ProgramIdText;
return true;
}
}
@@ -183,14 +193,17 @@ namespace Ryujinx.HLE.Loaders.Processes
if (nacpData.Value.PresenceGroupId != 0)
{
programId = nacpData.Value.PresenceGroupId;
TitleIDs.CurrentApplication.Value = programId.ToString("X16");
}
else if (nacpData.Value.SaveDataOwnerId != 0)
{
programId = nacpData.Value.SaveDataOwnerId;
TitleIDs.CurrentApplication.Value = programId.ToString("X16");
}
else if (nacpData.Value.AddOnContentBaseId != 0)
{
programId = nacpData.Value.AddOnContentBaseId - 0x1000;
TitleIDs.CurrentApplication.Value = programId.ToString("X16");
}
}
@@ -204,7 +217,7 @@ namespace Ryujinx.HLE.Loaders.Processes
}
// Explicitly null TitleId to disable the shader cache.
Graphics.Gpu.GraphicsConfig.TitleId = null;
GraphicsConfig.TitleId = null;
_device.Gpu.HostInitalized.Set();
ProcessResult processResult = ProcessLoaderHelper.LoadNsos(_device,

View File

@@ -2,6 +2,7 @@ using LibHac.Common;
using LibHac.Ns;
using Ryujinx.Audio.Backends.CompatLayer;
using Ryujinx.Audio.Integration;
using Ryujinx.Common;
using Ryujinx.Common.Configuration;
using Ryujinx.Graphics.Gpu;
using Ryujinx.HLE.FileSystem;
@@ -17,6 +18,8 @@ namespace Ryujinx.HLE
{
public class Switch : IDisposable
{
public static Switch Shared { get; private set; }
public HLEConfiguration Configuration { get; }
public IHardwareDeviceDriver AudioDeviceDriver { get; }
public MemoryBlock Memory { get; }
@@ -37,6 +40,8 @@ namespace Ryujinx.HLE
public bool IsFrameAvailable => Gpu.Window.IsFrameAvailable;
public DirtyHacks DirtyHacks { get; }
public Switch(HLEConfiguration configuration)
{
ArgumentNullException.ThrowIfNull(configuration.GpuRenderer);
@@ -52,9 +57,10 @@ namespace Ryujinx.HLE
: MemoryAllocationFlags.Reserve | MemoryAllocationFlags.Mirrorable;
#pragma warning disable IDE0055 // Disable formatting
DirtyHacks = new DirtyHacks(Configuration.Hacks);
AudioDeviceDriver = new CompatLayerHardwareDeviceDriver(Configuration.AudioDeviceDriver);
Memory = new MemoryBlock(Configuration.MemoryConfiguration.ToDramSize(), memoryAllocationFlags);
Gpu = new GpuContext(Configuration.GpuRenderer);
Gpu = new GpuContext(Configuration.GpuRenderer, DirtyHacks);
System = new HOS.Horizon(this);
Statistics = new PerformanceStatistics();
Hid = new Hid(this, System.HidStorage);
@@ -72,8 +78,11 @@ namespace Ryujinx.HLE
System.EnablePtc = Configuration.EnablePtc;
System.FsIntegrityCheckLevel = Configuration.FsIntegrityCheckLevel;
System.GlobalAccessLogMode = Configuration.FsGlobalAccessLogMode;
UpdateVSyncInterval();
#pragma warning restore IDE0055
Shared = this;
}
public void ProcessFrame()
@@ -142,6 +151,9 @@ namespace Ryujinx.HLE
AudioDeviceDriver.Dispose();
FileSystem.Dispose();
Memory.Dispose();
TitleIDs.CurrentApplication.Value = null;
Shared = null;
}
}
}

View File

@@ -1,73 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<RuntimeIdentifiers>win-x64;osx-x64;linux-x64</RuntimeIdentifiers>
<OutputType>Exe</OutputType>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<Version>1.0.0-dirty</Version>
<DefineConstants Condition=" '$(ExtraDefineConstants)' != '' ">$(DefineConstants);$(ExtraDefineConstants)</DefineConstants>
<SigningCertificate Condition=" '$(SigningCertificate)' == '' ">-</SigningCertificate>
<TieredPGO>true</TieredPGO>
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="OpenTK.Core" />
<PackageReference Include="Ryujinx.Graphics.Nvdec.Dependencies" />
</ItemGroup>
<Target Name="PostBuild" AfterTargets="PostBuildEvent" Condition="$([MSBuild]::IsOSPlatform('OSX'))">
<Exec Command="codesign --entitlements '$(ProjectDir)..\..\distribution\macos\entitlements.xml' -f -s $(SigningCertificate) '$(TargetDir)$(TargetName)'" />
</Target>
<ItemGroup>
<ProjectReference Include="..\Ryujinx.Graphics.Vulkan\Ryujinx.Graphics.Vulkan.csproj" />
<ProjectReference Include="..\Ryujinx.Input\Ryujinx.Input.csproj" />
<ProjectReference Include="..\Ryujinx.Input.SDL2\Ryujinx.Input.SDL2.csproj" />
<ProjectReference Include="..\Ryujinx.Audio.Backends.SDL2\Ryujinx.Audio.Backends.SDL2.csproj" />
<ProjectReference Include="..\Ryujinx.Common\Ryujinx.Common.csproj" />
<ProjectReference Include="..\Ryujinx.HLE\Ryujinx.HLE.csproj" />
<ProjectReference Include="..\ARMeilleure\ARMeilleure.csproj" />
<ProjectReference Include="..\Ryujinx.Graphics.OpenGL\Ryujinx.Graphics.OpenGL.csproj" />
<ProjectReference Include="..\Ryujinx.Graphics.Metal\Ryujinx.Graphics.Metal.csproj" />
<ProjectReference Include="..\Ryujinx.Graphics.Gpu\Ryujinx.Graphics.Gpu.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="CommandLineParser" />
<PackageReference Include="Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'linux-arm64' AND '$(RuntimeIdentifier)' != 'win-x64'" />
</ItemGroup>
<ItemGroup>
<Content Include="..\..\distribution\legal\THIRDPARTY.md">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<TargetPath>THIRDPARTY.md</TargetPath>
</Content>
<Content Include="..\..\LICENSE.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
<TargetPath>LICENSE.txt</TargetPath>
</Content>
</ItemGroup>
<ItemGroup Condition="'$(RuntimeIdentifier)' == 'linux-x64' OR '$(RuntimeIdentifier)' == 'linux-arm64' OR ('$(RuntimeIdentifier)' == '' AND $([MSBuild]::IsOSPlatform('Linux')))">
<Content Include="..\..\distribution\linux\Ryujinx.sh">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Ryujinx.bmp" />
</ItemGroup>
<!-- Due to .net core 3.1 embedded resource loading -->
<PropertyGroup>
<EmbeddedResourceUseDependentUponConvention>false</EmbeddedResourceUseDependentUponConvention>
<ApplicationIcon>..\Ryujinx\Ryujinx.ico</ApplicationIcon>
</PropertyGroup>
<PropertyGroup Condition="'$(RuntimeIdentifier)' != ''">
<PublishSingleFile>true</PublishSingleFile>
<PublishTrimmed>true</PublishTrimmed>
<TrimMode>partial</TrimMode>
</PropertyGroup>
</Project>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

View File

@@ -1,3 +1,4 @@
using Ryujinx.Common.Logging;
using Ryujinx.SDL2.Common;
using System;
using System.Collections.Generic;
@@ -36,6 +37,7 @@ namespace Ryujinx.Input.SDL2
SDL2Driver.Instance.Initialize();
SDL2Driver.Instance.OnJoyStickConnected += HandleJoyStickConnected;
SDL2Driver.Instance.OnJoystickDisconnected += HandleJoyStickDisconnected;
SDL2Driver.Instance.OnJoyBatteryUpdated += HandleJoyBatteryUpdated;
// Add already connected gamepads
int numJoysticks = SDL_NumJoysticks();
@@ -83,19 +85,30 @@ namespace Ryujinx.Input.SDL2
private void HandleJoyStickDisconnected(int joystickInstanceId)
{
bool joyConPairDisconnected = false;
if (!_gamepadsInstanceIdsMapping.Remove(joystickInstanceId, out string id))
return;
lock (_lock)
{
_gamepadsIds.Remove(id);
if (!SDL2JoyConPair.IsCombinable(_gamepadsIds))
{
_gamepadsIds.Remove(SDL2JoyConPair.Id);
joyConPairDisconnected = true;
}
}
OnGamepadDisconnected?.Invoke(id);
if (joyConPairDisconnected)
{
OnGamepadDisconnected?.Invoke(SDL2JoyConPair.Id);
}
}
private void HandleJoyStickConnected(int joystickDeviceId, int joystickInstanceId)
{
bool joyConPairConnected = false;
if (SDL_IsGameController(joystickDeviceId) == SDL_bool.SDL_TRUE)
{
if (_gamepadsInstanceIdsMapping.ContainsKey(joystickInstanceId))
@@ -120,13 +133,29 @@ namespace Ryujinx.Input.SDL2
_gamepadsIds.Insert(joystickDeviceId, id);
else
_gamepadsIds.Add(id);
if (SDL2JoyConPair.IsCombinable(_gamepadsIds))
{
_gamepadsIds.Remove(SDL2JoyConPair.Id);
_gamepadsIds.Add(SDL2JoyConPair.Id);
joyConPairConnected = true;
}
}
OnGamepadConnected?.Invoke(id);
if (joyConPairConnected)
{
OnGamepadConnected?.Invoke(SDL2JoyConPair.Id);
}
}
}
}
private void HandleJoyBatteryUpdated(int joystickDeviceId, SDL_JoystickPowerLevel powerLevel)
{
Logger.Info?.Print(LogClass.Hid,
$"{SDL_GameControllerNameForIndex(joystickDeviceId)} power level: {powerLevel}");
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
@@ -157,6 +186,14 @@ namespace Ryujinx.Input.SDL2
public IGamepad GetGamepad(string id)
{
if (id == SDL2JoyConPair.Id)
{
lock (_lock)
{
return SDL2JoyConPair.GetGamepad(_gamepadsIds);
}
}
int joystickIndex = GetJoystickIndexByGamepadId(id);
if (joystickIndex == -1)
@@ -165,12 +202,16 @@ namespace Ryujinx.Input.SDL2
}
nint gamepadHandle = SDL_GameControllerOpen(joystickIndex);
if (gamepadHandle == nint.Zero)
{
return null;
}
if (SDL_GameControllerName(gamepadHandle).StartsWith(SDL2JoyCon.Prefix))
{
return new SDL2JoyCon(gamepadHandle, id);
}
return new SDL2Gamepad(gamepadHandle, id);
}
}

View File

@@ -0,0 +1,409 @@
using Ryujinx.Common.Configuration.Hid;
using Ryujinx.Common.Configuration.Hid.Controller;
using Ryujinx.Common.Logging;
using System;
using System.Collections.Generic;
using System.Numerics;
using System.Threading;
using static SDL2.SDL;
namespace Ryujinx.Input.SDL2
{
internal class SDL2JoyCon : IGamepad
{
private bool HasConfiguration => _configuration != null;
private readonly record struct ButtonMappingEntry(GamepadButtonInputId To, GamepadButtonInputId From)
{
public bool IsValid => To is not GamepadButtonInputId.Unbound && From is not GamepadButtonInputId.Unbound;
}
private StandardControllerInputConfig _configuration;
private readonly Dictionary<GamepadButtonInputId,SDL_GameControllerButton> _leftButtonsDriverMapping = new()
{
{ GamepadButtonInputId.LeftStick , SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_LEFTSTICK },
{GamepadButtonInputId.DpadUp ,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_Y},
{GamepadButtonInputId.DpadDown ,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_A},
{GamepadButtonInputId.DpadLeft ,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_B},
{GamepadButtonInputId.DpadRight ,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_X},
{GamepadButtonInputId.Minus ,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_START},
{GamepadButtonInputId.LeftShoulder,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_PADDLE2},
{GamepadButtonInputId.LeftTrigger,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_PADDLE4},
{GamepadButtonInputId.SingleRightTrigger0,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_RIGHTSHOULDER},
{GamepadButtonInputId.SingleLeftTrigger0,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_LEFTSHOULDER},
};
private readonly Dictionary<GamepadButtonInputId,SDL_GameControllerButton> _rightButtonsDriverMapping = new()
{
{GamepadButtonInputId.RightStick,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_LEFTSTICK},
{GamepadButtonInputId.A,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_B},
{GamepadButtonInputId.B,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_Y},
{GamepadButtonInputId.X,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_A},
{GamepadButtonInputId.Y,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_X},
{GamepadButtonInputId.Plus,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_START},
{GamepadButtonInputId.RightShoulder,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_PADDLE1},
{GamepadButtonInputId.RightTrigger,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_PADDLE3},
{GamepadButtonInputId.SingleRightTrigger1,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_RIGHTSHOULDER},
{GamepadButtonInputId.SingleLeftTrigger1,SDL_GameControllerButton.SDL_CONTROLLER_BUTTON_LEFTSHOULDER}
};
private readonly Dictionary<GamepadButtonInputId, SDL_GameControllerButton> _buttonsDriverMapping;
private readonly Lock _userMappingLock = new();
private readonly List<ButtonMappingEntry> _buttonsUserMapping;
private readonly StickInputId[] _stickUserMapping = new StickInputId[(int)StickInputId.Count]
{
StickInputId.Unbound, StickInputId.Left, StickInputId.Right,
};
public GamepadFeaturesFlag Features { get; }
private nint _gamepadHandle;
private enum JoyConType
{
Left, Right
}
public const string Prefix = "Nintendo Switch Joy-Con";
public const string LeftName = "Nintendo Switch Joy-Con (L)";
public const string RightName = "Nintendo Switch Joy-Con (R)";
private readonly JoyConType _joyConType;
public SDL2JoyCon(nint gamepadHandle, string driverId)
{
_gamepadHandle = gamepadHandle;
_buttonsUserMapping = new List<ButtonMappingEntry>(10);
Name = SDL_GameControllerName(_gamepadHandle);
Id = driverId;
Features = GetFeaturesFlag();
// Enable motion tracking
if (Features.HasFlag(GamepadFeaturesFlag.Motion))
{
if (SDL_GameControllerSetSensorEnabled(_gamepadHandle, SDL_SensorType.SDL_SENSOR_ACCEL,
SDL_bool.SDL_TRUE) != 0)
{
Logger.Error?.Print(LogClass.Hid,
$"Could not enable data reporting for SensorType {SDL_SensorType.SDL_SENSOR_ACCEL}.");
}
if (SDL_GameControllerSetSensorEnabled(_gamepadHandle, SDL_SensorType.SDL_SENSOR_GYRO,
SDL_bool.SDL_TRUE) != 0)
{
Logger.Error?.Print(LogClass.Hid,
$"Could not enable data reporting for SensorType {SDL_SensorType.SDL_SENSOR_GYRO}.");
}
}
switch (Name)
{
case LeftName:
{
_buttonsDriverMapping = _leftButtonsDriverMapping;
_joyConType = JoyConType.Left;
break;
}
case RightName:
{
_buttonsDriverMapping = _rightButtonsDriverMapping;
_joyConType = JoyConType.Right;
break;
}
}
}
private GamepadFeaturesFlag GetFeaturesFlag()
{
GamepadFeaturesFlag result = GamepadFeaturesFlag.None;
if (SDL_GameControllerHasSensor(_gamepadHandle, SDL_SensorType.SDL_SENSOR_ACCEL) == SDL_bool.SDL_TRUE &&
SDL_GameControllerHasSensor(_gamepadHandle, SDL_SensorType.SDL_SENSOR_GYRO) == SDL_bool.SDL_TRUE)
{
result |= GamepadFeaturesFlag.Motion;
}
int error = SDL_GameControllerRumble(_gamepadHandle, 0, 0, 100);
if (error == 0)
{
result |= GamepadFeaturesFlag.Rumble;
}
return result;
}
public string Id { get; }
public string Name { get; }
public bool IsConnected => SDL_GameControllerGetAttached(_gamepadHandle) == SDL_bool.SDL_TRUE;
protected virtual void Dispose(bool disposing)
{
if (disposing && _gamepadHandle != nint.Zero)
{
SDL_GameControllerClose(_gamepadHandle);
_gamepadHandle = nint.Zero;
}
}
public void Dispose()
{
Dispose(true);
}
public void SetTriggerThreshold(float triggerThreshold)
{
}
public void Rumble(float lowFrequency, float highFrequency, uint durationMs)
{
if (!Features.HasFlag(GamepadFeaturesFlag.Rumble))
return;
ushort lowFrequencyRaw = (ushort)(lowFrequency * ushort.MaxValue);
ushort highFrequencyRaw = (ushort)(highFrequency * ushort.MaxValue);
if (durationMs == uint.MaxValue)
{
if (SDL_GameControllerRumble(_gamepadHandle, lowFrequencyRaw, highFrequencyRaw, SDL_HAPTIC_INFINITY) !=
0)
Logger.Error?.Print(LogClass.Hid, "Rumble is not supported on this game controller.");
}
else if (durationMs > SDL_HAPTIC_INFINITY)
{
Logger.Error?.Print(LogClass.Hid, $"Unsupported rumble duration {durationMs}");
}
else
{
if (SDL_GameControllerRumble(_gamepadHandle, lowFrequencyRaw, highFrequencyRaw, durationMs) != 0)
Logger.Error?.Print(LogClass.Hid, "Rumble is not supported on this game controller.");
}
}
public Vector3 GetMotionData(MotionInputId inputId)
{
SDL_SensorType sensorType = inputId switch
{
MotionInputId.Accelerometer => SDL_SensorType.SDL_SENSOR_ACCEL,
MotionInputId.Gyroscope => SDL_SensorType.SDL_SENSOR_GYRO,
_ => SDL_SensorType.SDL_SENSOR_INVALID
};
if (!Features.HasFlag(GamepadFeaturesFlag.Motion) || sensorType is SDL_SensorType.SDL_SENSOR_INVALID)
return Vector3.Zero;
const int ElementCount = 3;
unsafe
{
float* values = stackalloc float[ElementCount];
int result = SDL_GameControllerGetSensorData(_gamepadHandle, sensorType, (nint)values, ElementCount);
if (result != 0)
return Vector3.Zero;
Vector3 value = _joyConType switch
{
JoyConType.Left => new Vector3(-values[2], values[1], values[0]),
JoyConType.Right => new Vector3(values[2], values[1], -values[0])
};
return inputId switch
{
MotionInputId.Gyroscope => RadToDegree(value),
MotionInputId.Accelerometer => GsToMs2(value),
_ => value
};
}
}
private static Vector3 RadToDegree(Vector3 rad) => rad * (180 / MathF.PI);
private static Vector3 GsToMs2(Vector3 gs) => gs / SDL_STANDARD_GRAVITY;
public void SetConfiguration(InputConfig configuration)
{
lock (_userMappingLock)
{
_configuration = (StandardControllerInputConfig)configuration;
_buttonsUserMapping.Clear();
// First update sticks
_stickUserMapping[(int)StickInputId.Left] = (StickInputId)_configuration.LeftJoyconStick.Joystick;
_stickUserMapping[(int)StickInputId.Right] = (StickInputId)_configuration.RightJoyconStick.Joystick;
switch (_joyConType)
{
case JoyConType.Left:
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.LeftStick, (GamepadButtonInputId)_configuration.LeftJoyconStick.StickButton));
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadUp, (GamepadButtonInputId)_configuration.LeftJoycon.DpadUp));
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadDown, (GamepadButtonInputId)_configuration.LeftJoycon.DpadDown));
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadLeft, (GamepadButtonInputId)_configuration.LeftJoycon.DpadLeft));
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.DpadRight, (GamepadButtonInputId)_configuration.LeftJoycon.DpadRight));
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.Minus, (GamepadButtonInputId)_configuration.LeftJoycon.ButtonMinus));
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.LeftShoulder, (GamepadButtonInputId)_configuration.LeftJoycon.ButtonL));
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.LeftTrigger, (GamepadButtonInputId)_configuration.LeftJoycon.ButtonZl));
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleRightTrigger0, (GamepadButtonInputId)_configuration.LeftJoycon.ButtonSr));
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleLeftTrigger0, (GamepadButtonInputId)_configuration.LeftJoycon.ButtonSl));
break;
case JoyConType.Right:
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.RightStick, (GamepadButtonInputId)_configuration.RightJoyconStick.StickButton));
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.A, (GamepadButtonInputId)_configuration.RightJoycon.ButtonA));
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.B, (GamepadButtonInputId)_configuration.RightJoycon.ButtonB));
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.X, (GamepadButtonInputId)_configuration.RightJoycon.ButtonX));
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.Y, (GamepadButtonInputId)_configuration.RightJoycon.ButtonY));
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.Plus, (GamepadButtonInputId)_configuration.RightJoycon.ButtonPlus));
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.RightShoulder, (GamepadButtonInputId)_configuration.RightJoycon.ButtonR));
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.RightTrigger, (GamepadButtonInputId)_configuration.RightJoycon.ButtonZr));
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleRightTrigger1, (GamepadButtonInputId)_configuration.RightJoycon.ButtonSr));
_buttonsUserMapping.Add(new ButtonMappingEntry(GamepadButtonInputId.SingleLeftTrigger1, (GamepadButtonInputId)_configuration.RightJoycon.ButtonSl));
break;
default:
throw new ArgumentOutOfRangeException();
}
SetTriggerThreshold(_configuration.TriggerThreshold);
}
}
public GamepadStateSnapshot GetStateSnapshot()
{
return IGamepad.GetStateSnapshot(this);
}
public GamepadStateSnapshot GetMappedStateSnapshot()
{
GamepadStateSnapshot rawState = GetStateSnapshot();
GamepadStateSnapshot result = default;
lock (_userMappingLock)
{
if (_buttonsUserMapping.Count == 0)
return rawState;
// ReSharper disable once ForeachCanBePartlyConvertedToQueryUsingAnotherGetEnumerator
foreach (ButtonMappingEntry entry in _buttonsUserMapping)
{
if (!entry.IsValid)
continue;
// Do not touch state of button already pressed
if (!result.IsPressed(entry.To))
{
result.SetPressed(entry.To, rawState.IsPressed(entry.From));
}
}
(float leftStickX, float leftStickY) = rawState.GetStick(_stickUserMapping[(int)StickInputId.Left]);
(float rightStickX, float rightStickY) = rawState.GetStick(_stickUserMapping[(int)StickInputId.Right]);
result.SetStick(StickInputId.Left, leftStickX, leftStickY);
result.SetStick(StickInputId.Right, rightStickX, rightStickY);
}
return result;
}
private static float ConvertRawStickValue(short value)
{
const float ConvertRate = 1.0f / (short.MaxValue + 0.5f);
return value * ConvertRate;
}
private JoyconConfigControllerStick<GamepadInputId, Common.Configuration.Hid.Controller.StickInputId>
GetLogicalJoyStickConfig(StickInputId inputId)
{
switch (inputId)
{
case StickInputId.Left:
if (_configuration.RightJoyconStick.Joystick ==
Common.Configuration.Hid.Controller.StickInputId.Left)
return _configuration.RightJoyconStick;
else
return _configuration.LeftJoyconStick;
case StickInputId.Right:
if (_configuration.LeftJoyconStick.Joystick ==
Common.Configuration.Hid.Controller.StickInputId.Right)
return _configuration.LeftJoyconStick;
else
return _configuration.RightJoyconStick;
}
return null;
}
public (float, float) GetStick(StickInputId inputId)
{
if (inputId == StickInputId.Unbound)
return (0.0f, 0.0f);
if (inputId == StickInputId.Left && _joyConType == JoyConType.Right || inputId == StickInputId.Right && _joyConType == JoyConType.Left)
{
return (0.0f, 0.0f);
}
(short stickX, short stickY) = GetStickXY();
float resultX = ConvertRawStickValue(stickX);
float resultY = -ConvertRawStickValue(stickY);
if (HasConfiguration)
{
var joyconStickConfig = GetLogicalJoyStickConfig(inputId);
if (joyconStickConfig != null)
{
if (joyconStickConfig.InvertStickX)
resultX = -resultX;
if (joyconStickConfig.InvertStickY)
resultY = -resultY;
if (joyconStickConfig.Rotate90CW)
{
float temp = resultX;
resultX = resultY;
resultY = -temp;
}
}
}
return inputId switch
{
StickInputId.Left when _joyConType == JoyConType.Left => (resultY, -resultX),
StickInputId.Right when _joyConType == JoyConType.Right => (-resultY, resultX),
_ => (0.0f, 0.0f)
};
}
private (short, short) GetStickXY()
{
return (
SDL_GameControllerGetAxis(_gamepadHandle, SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_LEFTX),
SDL_GameControllerGetAxis(_gamepadHandle, SDL_GameControllerAxis.SDL_CONTROLLER_AXIS_LEFTY));
}
public bool IsPressed(GamepadButtonInputId inputId)
{
if (!_buttonsDriverMapping.TryGetValue(inputId, out var button))
{
return false;
}
return SDL_GameControllerGetButton(_gamepadHandle, button) == 1;
}
}
}

View File

@@ -0,0 +1,142 @@
using Ryujinx.Common.Configuration.Hid;
using Ryujinx.Common.Configuration.Hid.Controller;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using static SDL2.SDL;
namespace Ryujinx.Input.SDL2
{
internal class SDL2JoyConPair(IGamepad left, IGamepad right) : IGamepad
{
private StandardControllerInputConfig _configuration;
private readonly StickInputId[] _stickUserMapping =
[
StickInputId.Unbound,
StickInputId.Left,
StickInputId.Right
];
public GamepadFeaturesFlag Features => (left?.Features ?? GamepadFeaturesFlag.None) |
(right?.Features ?? GamepadFeaturesFlag.None);
public const string Id = "JoyConPair";
string IGamepad.Id => Id;
public string Name => "Nintendo Switch Joy-Con (L/R)";
public bool IsConnected => left is { IsConnected: true } && right is { IsConnected: true };
public void Dispose()
{
left?.Dispose();
right?.Dispose();
}
public GamepadStateSnapshot GetMappedStateSnapshot()
{
return GetStateSnapshot();
}
public Vector3 GetMotionData(MotionInputId inputId)
{
return inputId switch
{
MotionInputId.Accelerometer or
MotionInputId.Gyroscope => left.GetMotionData(inputId),
MotionInputId.SecondAccelerometer => right.GetMotionData(MotionInputId.Accelerometer),
MotionInputId.SecondGyroscope => right.GetMotionData(MotionInputId.Gyroscope),
_ => Vector3.Zero
};
}
public GamepadStateSnapshot GetStateSnapshot()
{
return IGamepad.GetStateSnapshot(this);
}
public (float, float) GetStick(StickInputId inputId)
{
return inputId switch
{
StickInputId.Left => left.GetStick(StickInputId.Left),
StickInputId.Right => right.GetStick(StickInputId.Right),
_ => (0, 0)
};
}
public bool IsPressed(GamepadButtonInputId inputId)
{
return left.IsPressed(inputId) || right.IsPressed(inputId);
}
public void Rumble(float lowFrequency, float highFrequency, uint durationMs)
{
if (lowFrequency != 0)
{
right.Rumble(lowFrequency, lowFrequency, durationMs);
}
if (highFrequency != 0)
{
left.Rumble(highFrequency, highFrequency, durationMs);
}
if (lowFrequency == 0 && highFrequency == 0)
{
left.Rumble(0, 0, durationMs);
right.Rumble(0, 0, durationMs);
}
}
public void SetConfiguration(InputConfig configuration)
{
left.SetConfiguration(configuration);
right.SetConfiguration(configuration);
}
public void SetTriggerThreshold(float triggerThreshold)
{
left.SetTriggerThreshold(triggerThreshold);
right.SetTriggerThreshold(triggerThreshold);
}
public static bool IsCombinable(List<string> gamepadsIds)
{
(int leftIndex, int rightIndex) = DetectJoyConPair(gamepadsIds);
return leftIndex >= 0 && rightIndex >= 0;
}
private static (int leftIndex, int rightIndex) DetectJoyConPair(List<string> gamepadsIds)
{
var gamepadNames = gamepadsIds.Where(gamepadId => gamepadId != Id)
.Select((_, index) => SDL_GameControllerNameForIndex(index)).ToList();
int leftIndex = gamepadNames.IndexOf(SDL2JoyCon.LeftName);
int rightIndex = gamepadNames.IndexOf(SDL2JoyCon.RightName);
return (leftIndex, rightIndex);
}
public static IGamepad GetGamepad(List<string> gamepadsIds)
{
(int leftIndex, int rightIndex) = DetectJoyConPair(gamepadsIds);
if (leftIndex == -1 || rightIndex == -1)
{
return null;
}
nint leftGamepadHandle = SDL_GameControllerOpen(leftIndex);
nint rightGamepadHandle = SDL_GameControllerOpen(rightIndex);
if (leftGamepadHandle == nint.Zero || rightGamepadHandle == nint.Zero)
{
return null;
}
return new SDL2JoyConPair(new SDL2JoyCon(leftGamepadHandle, gamepadsIds[leftIndex]),
new SDL2JoyCon(rightGamepadHandle, gamepadsIds[rightIndex]));
}
}
}

View File

@@ -266,6 +266,7 @@ namespace Ryujinx.Input.HLE
if (motionConfig.MotionBackend != MotionInputBackendType.CemuHook)
{
_leftMotionInput = new MotionInput();
_rightMotionInput = new MotionInput();
}
else
{
@@ -298,7 +299,20 @@ namespace Ryujinx.Input.HLE
if (controllerConfig.ControllerType == ConfigControllerType.JoyconPair)
{
_rightMotionInput = _leftMotionInput;
if (gamepad.Id== "JoyConPair")
{
Vector3 rightAccelerometer = gamepad.GetMotionData(MotionInputId.SecondAccelerometer);
Vector3 rightGyroscope = gamepad.GetMotionData(MotionInputId.SecondGyroscope);
rightAccelerometer = new Vector3(rightAccelerometer.X, -rightAccelerometer.Z, rightAccelerometer.Y);
rightGyroscope = new Vector3(rightGyroscope.X, -rightGyroscope.Z, rightGyroscope.Y);
_rightMotionInput.Update(rightAccelerometer, rightGyroscope, (ulong)PerformanceCounter.ElapsedNanoseconds / 1000, controllerConfig.Motion.Sensitivity, (float)controllerConfig.Motion.GyroDeadzone);
}
else
{
_rightMotionInput = _leftMotionInput;
}
}
}
}
@@ -333,6 +347,7 @@ namespace Ryujinx.Input.HLE
// Reset states
State = default;
_leftMotionInput = null;
_rightMotionInput = null;
}
}

View File

@@ -21,5 +21,17 @@ namespace Ryujinx.Input
/// </summary>
/// <remarks>Values are in degrees</remarks>
Gyroscope,
/// <summary>
/// Second accelerometer.
/// </summary>
/// <remarks>Values are in m/s^2</remarks>
SecondAccelerometer,
/// <summary>
/// Second gyroscope.
/// </summary>
/// <remarks>Values are in degrees</remarks>
SecondGyroscope
}
}

View File

@@ -25,14 +25,17 @@ namespace Ryujinx.SDL2.Common
public static Action<Action> MainThreadDispatcher { get; set; }
private const uint SdlInitFlags = SDL_INIT_EVENTS | SDL_INIT_GAMECONTROLLER | SDL_INIT_JOYSTICK | SDL_INIT_AUDIO | SDL_INIT_VIDEO;
private const uint SdlInitFlags = SDL_INIT_EVENTS | SDL_INIT_GAMECONTROLLER | SDL_INIT_JOYSTICK |
SDL_INIT_AUDIO | SDL_INIT_VIDEO;
private bool _isRunning;
private uint _refereceCount;
private Thread _worker;
private const uint SQL_JOYBATTERYUPDATED = 1543;
public event Action<int, int> OnJoyStickConnected;
public event Action<int> OnJoystickDisconnected;
public event Action<int, SDL_JoystickPowerLevel> OnJoyBatteryUpdated;
private ConcurrentDictionary<uint, Action<SDL_Event>> _registeredWindowHandlers;
@@ -78,12 +81,14 @@ namespace Ryujinx.SDL2.Common
// First ensure that we only enable joystick events (for connected/disconnected).
if (SDL_GameControllerEventState(SDL_IGNORE) != SDL_IGNORE)
{
Logger.Error?.PrintMsg(LogClass.Application, "Couldn't change the state of game controller events.");
Logger.Error?.PrintMsg(LogClass.Application,
"Couldn't change the state of game controller events.");
}
if (SDL_JoystickEventState(SDL_ENABLE) < 0)
{
Logger.Error?.PrintMsg(LogClass.Application, $"Failed to enable joystick event polling: {SDL_GetError()}");
Logger.Error?.PrintMsg(LogClass.Application,
$"Failed to enable joystick event polling: {SDL_GetError()}");
}
// Disable all joysticks information, we don't need them no need to flood the event queue for that.
@@ -143,7 +148,12 @@ namespace Ryujinx.SDL2.Common
OnJoystickDisconnected?.Invoke(evnt.cbutton.which);
}
else if (evnt.type is SDL_EventType.SDL_WINDOWEVENT or SDL_EventType.SDL_MOUSEBUTTONDOWN or SDL_EventType.SDL_MOUSEBUTTONUP)
else if ((uint)evnt.type == SQL_JOYBATTERYUPDATED)
{
OnJoyBatteryUpdated?.Invoke(evnt.cbutton.which, (SDL_JoystickPowerLevel)evnt.user.code);
}
else if (evnt.type is SDL_EventType.SDL_WINDOWEVENT or SDL_EventType.SDL_MOUSEBUTTONDOWN
or SDL_EventType.SDL_MOUSEBUTTONUP)
{
if (_registeredWindowHandlers.TryGetValue(evnt.window.windowID, out Action<SDL_Event> handler))
{

View File

@@ -1,16 +0,0 @@
using System.Collections.Generic;
namespace Ryujinx.UI.App.Common
{
public struct LdnGameData
{
public string Id { get; set; }
public int PlayerCount { get; set; }
public int MaxPlayerCount { get; set; }
public string GameName { get; set; }
public string TitleId { get; set; }
public string Mode { get; set; }
public string Status { get; set; }
public IEnumerable<string> Players { get; set; }
}
}

View File

@@ -1,747 +0,0 @@
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Configuration.Hid;
using Ryujinx.Common.Configuration.Hid.Controller;
using Ryujinx.Common.Configuration.Hid.Keyboard;
using Ryujinx.Common.Configuration.Multiplayer;
using Ryujinx.Common.Logging;
using Ryujinx.HLE;
using Ryujinx.UI.Common.Configuration.System;
using Ryujinx.UI.Common.Configuration.UI;
using System;
using System.Collections.Generic;
namespace Ryujinx.UI.Common.Configuration
{
public partial class ConfigurationState
{
public void Load(ConfigurationFileFormat configurationFileFormat, string configurationFilePath)
{
bool configurationFileUpdated = false;
if (configurationFileFormat.Version is < 0 or > ConfigurationFileFormat.CurrentVersion)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Unsupported configuration version {configurationFileFormat.Version}, loading default.");
LoadDefault();
}
if (configurationFileFormat.Version < 2)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 2.");
configurationFileFormat.SystemRegion = Region.USA;
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 3)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 3.");
configurationFileFormat.SystemTimeZone = "UTC";
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 4)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 4.");
configurationFileFormat.MaxAnisotropy = -1;
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 5)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 5.");
configurationFileFormat.SystemTimeOffset = 0;
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 8)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 8.");
configurationFileFormat.EnablePtc = true;
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 9)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 9.");
configurationFileFormat.ColumnSort = new ColumnSort
{
SortColumnId = 0,
SortAscending = false,
};
configurationFileFormat.Hotkeys = new KeyboardHotkeys
{
ToggleVSyncMode = Key.F1,
};
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 10)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 10.");
configurationFileFormat.AudioBackend = AudioBackend.OpenAl;
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 11)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 11.");
configurationFileFormat.ResScale = 1;
configurationFileFormat.ResScaleCustom = 1.0f;
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 12)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 12.");
configurationFileFormat.LoggingGraphicsDebugLevel = GraphicsDebugLevel.None;
configurationFileUpdated = true;
}
// configurationFileFormat.Version == 13 -> LDN1
if (configurationFileFormat.Version < 14)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 14.");
configurationFileFormat.CheckUpdatesOnStart = true;
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 16)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 16.");
configurationFileFormat.EnableShaderCache = true;
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 17)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 17.");
configurationFileFormat.StartFullscreen = false;
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 18)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 18.");
configurationFileFormat.AspectRatio = AspectRatio.Fixed16x9;
configurationFileUpdated = true;
}
// configurationFileFormat.Version == 19 -> LDN2
if (configurationFileFormat.Version < 20)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 20.");
configurationFileFormat.ShowConfirmExit = true;
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 21)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 21.");
// Initialize network config.
configurationFileFormat.MultiplayerMode = MultiplayerMode.Disabled;
configurationFileFormat.MultiplayerLanInterfaceId = "0";
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 22)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 22.");
configurationFileFormat.HideCursor = HideCursorMode.Never;
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 24)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 24.");
configurationFileFormat.InputConfig = new List<InputConfig>
{
new StandardKeyboardInputConfig
{
Version = InputConfig.CurrentVersion,
Backend = InputBackendType.WindowKeyboard,
Id = "0",
PlayerIndex = PlayerIndex.Player1,
ControllerType = ControllerType.ProController,
LeftJoycon = new LeftJoyconCommonConfig<Key>
{
DpadUp = Key.Up,
DpadDown = Key.Down,
DpadLeft = Key.Left,
DpadRight = Key.Right,
ButtonMinus = Key.Minus,
ButtonL = Key.E,
ButtonZl = Key.Q,
ButtonSl = Key.Unbound,
ButtonSr = Key.Unbound,
},
LeftJoyconStick = new JoyconConfigKeyboardStick<Key>
{
StickUp = Key.W,
StickDown = Key.S,
StickLeft = Key.A,
StickRight = Key.D,
StickButton = Key.F,
},
RightJoycon = new RightJoyconCommonConfig<Key>
{
ButtonA = Key.Z,
ButtonB = Key.X,
ButtonX = Key.C,
ButtonY = Key.V,
ButtonPlus = Key.Plus,
ButtonR = Key.U,
ButtonZr = Key.O,
ButtonSl = Key.Unbound,
ButtonSr = Key.Unbound,
},
RightJoyconStick = new JoyconConfigKeyboardStick<Key>
{
StickUp = Key.I,
StickDown = Key.K,
StickLeft = Key.J,
StickRight = Key.L,
StickButton = Key.H,
},
},
};
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 25)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 25.");
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 26)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 26.");
configurationFileFormat.MemoryManagerMode = MemoryManagerMode.HostMappedUnsafe;
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 27)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 27.");
configurationFileFormat.EnableMouse = false;
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 28)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 28.");
configurationFileFormat.Hotkeys = new KeyboardHotkeys
{
ToggleVSyncMode = Key.F1,
Screenshot = Key.F8,
};
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 29)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 29.");
configurationFileFormat.Hotkeys = new KeyboardHotkeys
{
ToggleVSyncMode = Key.F1,
Screenshot = Key.F8,
ShowUI = Key.F4,
};
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 30)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 30.");
foreach (InputConfig config in configurationFileFormat.InputConfig)
{
if (config is StandardControllerInputConfig controllerConfig)
{
controllerConfig.Rumble = new RumbleConfigController
{
EnableRumble = false,
StrongRumble = 1f,
WeakRumble = 1f,
};
}
}
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 31)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 31.");
configurationFileFormat.BackendThreading = BackendThreading.Auto;
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 32)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 32.");
configurationFileFormat.Hotkeys = new KeyboardHotkeys
{
ToggleVSyncMode = configurationFileFormat.Hotkeys.ToggleVSyncMode,
Screenshot = configurationFileFormat.Hotkeys.Screenshot,
ShowUI = configurationFileFormat.Hotkeys.ShowUI,
Pause = Key.F5,
};
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 33)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 33.");
configurationFileFormat.Hotkeys = new KeyboardHotkeys
{
ToggleVSyncMode = configurationFileFormat.Hotkeys.ToggleVSyncMode,
Screenshot = configurationFileFormat.Hotkeys.Screenshot,
ShowUI = configurationFileFormat.Hotkeys.ShowUI,
Pause = configurationFileFormat.Hotkeys.Pause,
ToggleMute = Key.F2,
};
configurationFileFormat.AudioVolume = 1;
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 34)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 34.");
configurationFileFormat.EnableInternetAccess = false;
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 35)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 35.");
foreach (InputConfig config in configurationFileFormat.InputConfig)
{
if (config is StandardControllerInputConfig controllerConfig)
{
controllerConfig.RangeLeft = 1.0f;
controllerConfig.RangeRight = 1.0f;
}
}
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 36)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 36.");
configurationFileFormat.LoggingEnableTrace = false;
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 37)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 37.");
configurationFileFormat.ShowConsole = true;
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 38)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 38.");
configurationFileFormat.BaseStyle = "Dark";
configurationFileFormat.GameListViewMode = 0;
configurationFileFormat.ShowNames = true;
configurationFileFormat.GridSize = 2;
configurationFileFormat.LanguageCode = "en_US";
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 39)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 39.");
configurationFileFormat.Hotkeys = new KeyboardHotkeys
{
ToggleVSyncMode = configurationFileFormat.Hotkeys.ToggleVSyncMode,
Screenshot = configurationFileFormat.Hotkeys.Screenshot,
ShowUI = configurationFileFormat.Hotkeys.ShowUI,
Pause = configurationFileFormat.Hotkeys.Pause,
ToggleMute = configurationFileFormat.Hotkeys.ToggleMute,
ResScaleUp = Key.Unbound,
ResScaleDown = Key.Unbound,
};
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 40)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 40.");
configurationFileFormat.GraphicsBackend = GraphicsBackend.OpenGl;
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 41)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 41.");
configurationFileFormat.Hotkeys = new KeyboardHotkeys
{
ToggleVSyncMode = configurationFileFormat.Hotkeys.ToggleVSyncMode,
Screenshot = configurationFileFormat.Hotkeys.Screenshot,
ShowUI = configurationFileFormat.Hotkeys.ShowUI,
Pause = configurationFileFormat.Hotkeys.Pause,
ToggleMute = configurationFileFormat.Hotkeys.ToggleMute,
ResScaleUp = configurationFileFormat.Hotkeys.ResScaleUp,
ResScaleDown = configurationFileFormat.Hotkeys.ResScaleDown,
VolumeUp = Key.Unbound,
VolumeDown = Key.Unbound,
};
}
if (configurationFileFormat.Version < 42)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 42.");
configurationFileFormat.EnableMacroHLE = true;
}
if (configurationFileFormat.Version < 43)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 43.");
configurationFileFormat.UseHypervisor = true;
}
if (configurationFileFormat.Version < 44)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 44.");
configurationFileFormat.AntiAliasing = AntiAliasing.None;
configurationFileFormat.ScalingFilter = ScalingFilter.Bilinear;
configurationFileFormat.ScalingFilterLevel = 80;
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 45)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 45.");
configurationFileFormat.ShownFileTypes = new ShownFileTypes
{
NSP = true,
PFS0 = true,
XCI = true,
NCA = true,
NRO = true,
NSO = true,
};
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 46)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 46.");
configurationFileFormat.MultiplayerLanInterfaceId = "0";
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 47)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 47.");
configurationFileFormat.WindowStartup = new WindowStartup
{
WindowPositionX = 0,
WindowPositionY = 0,
WindowSizeHeight = 760,
WindowSizeWidth = 1280,
WindowMaximized = false,
};
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 48)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 48.");
configurationFileFormat.EnableColorSpacePassthrough = false;
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 49)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 49.");
if (OperatingSystem.IsMacOS())
{
AppDataManager.FixMacOSConfigurationFolders();
}
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 50)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 50.");
configurationFileFormat.EnableHardwareAcceleration = true;
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 51)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 51.");
configurationFileFormat.RememberWindowState = true;
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 52)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 52.");
configurationFileFormat.AutoloadDirs = [];
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 53)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 53.");
configurationFileFormat.EnableLowPowerPtc = false;
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 54)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 54.");
configurationFileFormat.DramSize = MemoryConfiguration.MemoryConfiguration4GiB;
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 55)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 55.");
configurationFileFormat.IgnoreApplet = false;
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 56)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 56.");
configurationFileFormat.ShowTitleBar = !OperatingSystem.IsWindows();
configurationFileUpdated = true;
}
if (configurationFileFormat.Version < 57)
{
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 57.");
configurationFileFormat.VSyncMode = VSyncMode.Switch;
configurationFileFormat.EnableCustomVSyncInterval = false;
configurationFileFormat.Hotkeys = new KeyboardHotkeys
{
ToggleVSyncMode = Key.F1,
Screenshot = configurationFileFormat.Hotkeys.Screenshot,
ShowUI = configurationFileFormat.Hotkeys.ShowUI,
Pause = configurationFileFormat.Hotkeys.Pause,
ToggleMute = configurationFileFormat.Hotkeys.ToggleMute,
ResScaleUp = configurationFileFormat.Hotkeys.ResScaleUp,
ResScaleDown = configurationFileFormat.Hotkeys.ResScaleDown,
VolumeUp = configurationFileFormat.Hotkeys.VolumeUp,
VolumeDown = configurationFileFormat.Hotkeys.VolumeDown,
CustomVSyncIntervalIncrement = Key.Unbound,
CustomVSyncIntervalDecrement = Key.Unbound,
};
configurationFileFormat.CustomVSyncInterval = 120;
configurationFileUpdated = true;
}
Logger.EnableFileLog.Value = configurationFileFormat.EnableFileLog;
Graphics.ResScale.Value = configurationFileFormat.ResScale;
Graphics.ResScaleCustom.Value = configurationFileFormat.ResScaleCustom;
Graphics.MaxAnisotropy.Value = configurationFileFormat.MaxAnisotropy;
Graphics.AspectRatio.Value = configurationFileFormat.AspectRatio;
Graphics.ShadersDumpPath.Value = configurationFileFormat.GraphicsShadersDumpPath;
Graphics.BackendThreading.Value = configurationFileFormat.BackendThreading;
Graphics.GraphicsBackend.Value = configurationFileFormat.GraphicsBackend;
Graphics.PreferredGpu.Value = configurationFileFormat.PreferredGpu;
Graphics.AntiAliasing.Value = configurationFileFormat.AntiAliasing;
Graphics.ScalingFilter.Value = configurationFileFormat.ScalingFilter;
Graphics.ScalingFilterLevel.Value = configurationFileFormat.ScalingFilterLevel;
Logger.EnableDebug.Value = configurationFileFormat.LoggingEnableDebug;
Logger.EnableStub.Value = configurationFileFormat.LoggingEnableStub;
Logger.EnableInfo.Value = configurationFileFormat.LoggingEnableInfo;
Logger.EnableWarn.Value = configurationFileFormat.LoggingEnableWarn;
Logger.EnableError.Value = configurationFileFormat.LoggingEnableError;
Logger.EnableTrace.Value = configurationFileFormat.LoggingEnableTrace;
Logger.EnableGuest.Value = configurationFileFormat.LoggingEnableGuest;
Logger.EnableFsAccessLog.Value = configurationFileFormat.LoggingEnableFsAccessLog;
Logger.FilteredClasses.Value = configurationFileFormat.LoggingFilteredClasses;
Logger.GraphicsDebugLevel.Value = configurationFileFormat.LoggingGraphicsDebugLevel;
System.Language.Value = configurationFileFormat.SystemLanguage;
System.Region.Value = configurationFileFormat.SystemRegion;
System.TimeZone.Value = configurationFileFormat.SystemTimeZone;
System.SystemTimeOffset.Value = configurationFileFormat.SystemTimeOffset;
System.EnableDockedMode.Value = configurationFileFormat.DockedMode;
EnableDiscordIntegration.Value = configurationFileFormat.EnableDiscordIntegration;
CheckUpdatesOnStart.Value = configurationFileFormat.CheckUpdatesOnStart;
ShowConfirmExit.Value = configurationFileFormat.ShowConfirmExit;
IgnoreApplet.Value = configurationFileFormat.IgnoreApplet;
RememberWindowState.Value = configurationFileFormat.RememberWindowState;
ShowTitleBar.Value = configurationFileFormat.ShowTitleBar;
EnableHardwareAcceleration.Value = configurationFileFormat.EnableHardwareAcceleration;
HideCursor.Value = configurationFileFormat.HideCursor;
Graphics.VSyncMode.Value = configurationFileFormat.VSyncMode;
Graphics.EnableCustomVSyncInterval.Value = configurationFileFormat.EnableCustomVSyncInterval;
Graphics.CustomVSyncInterval.Value = configurationFileFormat.CustomVSyncInterval;
Graphics.EnableShaderCache.Value = configurationFileFormat.EnableShaderCache;
Graphics.EnableTextureRecompression.Value = configurationFileFormat.EnableTextureRecompression;
Graphics.EnableMacroHLE.Value = configurationFileFormat.EnableMacroHLE;
Graphics.EnableColorSpacePassthrough.Value = configurationFileFormat.EnableColorSpacePassthrough;
System.EnablePtc.Value = configurationFileFormat.EnablePtc;
System.EnableLowPowerPtc.Value = configurationFileFormat.EnableLowPowerPtc;
System.EnableInternetAccess.Value = configurationFileFormat.EnableInternetAccess;
System.EnableFsIntegrityChecks.Value = configurationFileFormat.EnableFsIntegrityChecks;
System.FsGlobalAccessLogMode.Value = configurationFileFormat.FsGlobalAccessLogMode;
System.AudioBackend.Value = configurationFileFormat.AudioBackend;
System.AudioVolume.Value = configurationFileFormat.AudioVolume;
System.MemoryManagerMode.Value = configurationFileFormat.MemoryManagerMode;
System.DramSize.Value = configurationFileFormat.DramSize;
System.IgnoreMissingServices.Value = configurationFileFormat.IgnoreMissingServices;
System.UseHypervisor.Value = configurationFileFormat.UseHypervisor;
UI.GuiColumns.FavColumn.Value = configurationFileFormat.GuiColumns.FavColumn;
UI.GuiColumns.IconColumn.Value = configurationFileFormat.GuiColumns.IconColumn;
UI.GuiColumns.AppColumn.Value = configurationFileFormat.GuiColumns.AppColumn;
UI.GuiColumns.DevColumn.Value = configurationFileFormat.GuiColumns.DevColumn;
UI.GuiColumns.VersionColumn.Value = configurationFileFormat.GuiColumns.VersionColumn;
UI.GuiColumns.TimePlayedColumn.Value = configurationFileFormat.GuiColumns.TimePlayedColumn;
UI.GuiColumns.LastPlayedColumn.Value = configurationFileFormat.GuiColumns.LastPlayedColumn;
UI.GuiColumns.FileExtColumn.Value = configurationFileFormat.GuiColumns.FileExtColumn;
UI.GuiColumns.FileSizeColumn.Value = configurationFileFormat.GuiColumns.FileSizeColumn;
UI.GuiColumns.PathColumn.Value = configurationFileFormat.GuiColumns.PathColumn;
UI.ColumnSort.SortColumnId.Value = configurationFileFormat.ColumnSort.SortColumnId;
UI.ColumnSort.SortAscending.Value = configurationFileFormat.ColumnSort.SortAscending;
UI.GameDirs.Value = configurationFileFormat.GameDirs;
UI.AutoloadDirs.Value = configurationFileFormat.AutoloadDirs ?? [];
UI.ShownFileTypes.NSP.Value = configurationFileFormat.ShownFileTypes.NSP;
UI.ShownFileTypes.PFS0.Value = configurationFileFormat.ShownFileTypes.PFS0;
UI.ShownFileTypes.XCI.Value = configurationFileFormat.ShownFileTypes.XCI;
UI.ShownFileTypes.NCA.Value = configurationFileFormat.ShownFileTypes.NCA;
UI.ShownFileTypes.NRO.Value = configurationFileFormat.ShownFileTypes.NRO;
UI.ShownFileTypes.NSO.Value = configurationFileFormat.ShownFileTypes.NSO;
UI.LanguageCode.Value = configurationFileFormat.LanguageCode;
UI.BaseStyle.Value = configurationFileFormat.BaseStyle;
UI.GameListViewMode.Value = configurationFileFormat.GameListViewMode;
UI.ShowNames.Value = configurationFileFormat.ShowNames;
UI.IsAscendingOrder.Value = configurationFileFormat.IsAscendingOrder;
UI.GridSize.Value = configurationFileFormat.GridSize;
UI.ApplicationSort.Value = configurationFileFormat.ApplicationSort;
UI.StartFullscreen.Value = configurationFileFormat.StartFullscreen;
UI.ShowConsole.Value = configurationFileFormat.ShowConsole;
UI.WindowStartup.WindowSizeWidth.Value = configurationFileFormat.WindowStartup.WindowSizeWidth;
UI.WindowStartup.WindowSizeHeight.Value = configurationFileFormat.WindowStartup.WindowSizeHeight;
UI.WindowStartup.WindowPositionX.Value = configurationFileFormat.WindowStartup.WindowPositionX;
UI.WindowStartup.WindowPositionY.Value = configurationFileFormat.WindowStartup.WindowPositionY;
UI.WindowStartup.WindowMaximized.Value = configurationFileFormat.WindowStartup.WindowMaximized;
Hid.EnableKeyboard.Value = configurationFileFormat.EnableKeyboard;
Hid.EnableMouse.Value = configurationFileFormat.EnableMouse;
Hid.Hotkeys.Value = configurationFileFormat.Hotkeys;
Hid.InputConfig.Value = configurationFileFormat.InputConfig ?? [];
Multiplayer.LanInterfaceId.Value = configurationFileFormat.MultiplayerLanInterfaceId;
Multiplayer.Mode.Value = configurationFileFormat.MultiplayerMode;
Multiplayer.DisableP2p.Value = configurationFileFormat.MultiplayerDisableP2p;
Multiplayer.LdnPassphrase.Value = configurationFileFormat.MultiplayerLdnPassphrase;
Multiplayer.LdnServer.Value = configurationFileFormat.LdnServer;
if (configurationFileUpdated)
{
ToFileFormat().SaveConfig(configurationFilePath);
Ryujinx.Common.Logging.Logger.Notice.Print(LogClass.Application, $"Configuration file updated to version {ConfigurationFileFormat.CurrentVersion}");
}
}
}
}

View File

@@ -1,12 +0,0 @@
namespace Ryujinx.UI.Common
{
public enum FileTypes
{
NSP,
PFS0,
XCI,
NCA,
NRO,
NSO
}
}

View File

@@ -1,64 +0,0 @@
using LibHac.Common;
using LibHac.Ncm;
using LibHac.Ns;
using LibHac.Tools.FsSystem.NcaUtils;
using Ryujinx.HLE;
using Ryujinx.HLE.FileSystem;
using Ryujinx.UI.App.Common;
namespace Ryujinx.UI.Common.Helper
{
public readonly struct AppletMetadata
{
private readonly ContentManager _contentManager;
public string Name { get; }
public ulong ProgramId { get; }
public string Version { get; }
public AppletMetadata(ContentManager contentManager, string name, ulong programId, string version = "1.0.0")
: this(name, programId, version)
{
_contentManager = contentManager;
}
public AppletMetadata(string name, ulong programId, string version = "1.0.0")
{
Name = name;
ProgramId = programId;
Version = version;
}
public string GetContentPath(ContentManager contentManager)
=> (contentManager ?? _contentManager)
.GetInstalledContentPath(ProgramId, StorageId.BuiltInSystem, NcaContentType.Program);
public bool CanStart(ContentManager contentManager, out ApplicationData appData, out BlitStruct<ApplicationControlProperty> appControl)
{
contentManager ??= _contentManager;
if (contentManager == null)
{
appData = null;
appControl = new BlitStruct<ApplicationControlProperty>(0);
return false;
}
appData = new()
{
Name = Name,
Id = ProgramId,
Path = GetContentPath(contentManager)
};
if (string.IsNullOrEmpty(appData.Path))
{
appControl = new BlitStruct<ApplicationControlProperty>(0);
return false;
}
appControl = StructHelpers.CreateCustomNacpData(Name, Version);
return true;
}
}
}

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 68 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 66 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 81 KiB

View File

@@ -1,132 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 27.5.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 1050 1050.5"
style="enable-background:new 0 0 1050 1050.5;" xml:space="preserve">
<style type="text/css">
.st0{fill:#20221F;}
.st1{fill:#3B3B3B;}
.st2{fill:#121212;}
.st3{fill:#444542;}
.st4{fill:#FFFFFF;}
.st5{fill:#444542;stroke:#FFFFFF;stroke-width:2;stroke-miterlimit:10;}
.st6{fill:#454644;}
.st7{fill:#454644;stroke:#FFFFFF;stroke-width:2;stroke-miterlimit:10;}
.st8{fill:#3B3C3A;}
.st9{font-family:'Helvetica-Bold';}
.st10{font-size:40px;}
.st11{fill:#0D0D0A;}
</style>
<g id="Front">
<path id="Right_Grip_00000028282943321285403220000008369785803052272051_" class="st0" d="M766,850.5
c34,28.2,27.6,35.9,68.5,108.5c36.7,74.7,64.4,104.4,125.1,84.1v0c95.3-57.9,59.3-145.3,43.6-275.2c-10-60.6-35.6-190.3-35.6-190.3
L766,850.5z"/>
<path id="Left_Grip" class="st0" d="M82.3,577.6c0,0-25.6,129.7-35.6,190.3C31,897.8-5,985.1,90.3,1043v0
c60.8,20.3,88.4-9.4,125.1-84.1c40.9-72.7,34.5-80.3,68.5-108.5L82.3,577.6z"/>
<path id="Right_Bumper_00000006710349871522532470000011078040965381267594_" class="st1" d="M676.3,378.4
c10.1-4.3,39.7-22.5,58.7-19.7c59.5,0.9,166.7,17.7,172.6,81.2"/>
<path id="Left_Bumper_00000024680414077879639570000011759596763560342154_" class="st1" d="M142.4,439.9
c5.9-63.4,113-80.2,172.6-81.2c19-2.8,48.6,15.4,58.7,19.7"/>
<path id="Background_00000141418846164053065470000016150094984198570163_" class="st2" d="M766,850.5
c35.5-30.8,68.5-74.7,96-113.5c26.9-36.3,94.7-136.7,105.6-159.3c0-2.4-6.3-30.1-12.8-56.2C919.1,361.9,702.2,378.1,525,378.1
c-177.4,0-394.1-16.2-429.9,143.3c-6.5,26-12.8,53.8-12.8,56.2c10.9,22.6,78.8,123,105.6,159.3c27.5,38.8,60.5,82.8,96,113.5"/>
<g id="Directional_Pad">
<path id="Background_00000032628022449190479560000015279211462520783249_" class="st3" d="M466.2,683.5h-40c-2.8,0-5-2.2-5-5v-40
c0-2.8-2.2-5-5-5h-30c-2.8,0-5,2.2-5,5v40c0,2.8-2.2,5-5,5h-40c-2.8,0-5,2.2-5,5v30c0,2.8,2.2,5,5,5h40c2.8,0,5,2.2,5,5v40
c0,2.8,2.2,5,5,5h30c2.8,0,5-2.2,5-5v-40c0-2.8,2.2-5,5-5h40c2.8,0,5-2.2,5-5v-30C471.2,685.8,469,683.5,466.2,683.5z"/>
<g id="Arrows">
<g>
<polygon class="st4" points="393.7,746 408.7,746 401.2,761 "/>
</g>
<g>
<polygon class="st4" points="358.7,696 358.7,711 343.7,703.5 "/>
</g>
<g>
<polygon class="st4" points="408.7,661 393.7,661 401.2,646 "/>
</g>
<g>
<polygon class="st4" points="443.7,711 443.7,696 458.7,703.5 "/>
</g>
</g>
</g>
<g id="R_Thumbstick_00000152226188525111835500000011838297421350334865_">
<circle id="Background_00000035532849542660068350000006517224202948159422_" class="st0" cx="650.6" cy="703.5" r="55"/>
<circle id="Stick" class="st5" cx="650.6" cy="703.5" r="45"/>
</g>
<g id="L_Thumbstick_00000047032468231999382210000005512347386782594484_">
<circle id="Background_00000182502673988292164000000007125719133096369561_" class="st0" cx="240.2" cy="564.8" r="55"/>
<circle id="Stick_00000075121990265259598900000000214370239054002365_" class="st5" cx="240.2" cy="564.8" r="45"/>
</g>
<g id="Minus_Button">
<circle id="_Background_00000120554951013892796430000015877571645746699662_" class="st6" cx="401" cy="489.3" r="22.5"/>
<polyline id="Plus_00000039131319101621183460000006196023733899658629_" class="st4" points="386.2,491.8 386.2,486.8
416.2,486.8 416.2,491.8 "/>
</g>
<g id="Plus_Button">
<circle id="_Background" class="st6" cx="650.4" cy="489.6" r="22.5"/>
<polygon id="Plus" class="st4" points="665.6,487.1 653.1,487.1 653.1,474.4 648.1,474.4 648.1,487.1 635.6,487.1 635.6,492.1
648.1,492.1 648.1,504.4 653.1,504.4 653.1,492.1 665.6,492.1 "/>
</g>
<g id="Home_Button_00000029758737660217614780000001403165237001195407_">
<circle id="_Background_00000132788487854287834010000009548421243227981499_" class="st6" cx="605.4" cy="564.8" r="22.5"/>
<path id="Home" class="st4" d="M605.4,549.8l-15,15h5v15h20v-15h5L605.4,549.8z M610.4,574.8h-10v-10h10V574.8z"/>
</g>
<g id="Capture_Button_00000105394663133565750060000017455731898661404072_">
<path class="st6" d="M468.6,586.5h-30c-2.8,0-5-2.2-5-5v-29.5c0-2.8,2.2-5,5-5h30c2.8,0,5,2.2,5,5v29.5
C473.6,584.2,471.4,586.5,468.6,586.5z"/>
<circle class="st7" cx="453.6" cy="566.7" r="15"/>
</g>
<g id="Buttons_00000023239109225132251950000005218343074279628213_">
<g id="A_Button">
<circle id="Background_00000006699118933065716380000004636085088820886913_" class="st8" cx="863.9" cy="564.8" r="35"/>
<text transform="matrix(1 0 0 1 849.4224 578.6607)" class="st4 st9 st10">A</text>
</g>
<g id="X_Button">
<circle id="Background_00000083074713085756701790000016893839312974798515_" class="st8" cx="793.9" cy="494.8" r="35"/>
<text transform="matrix(1 0 0 1 780.5266 508.6604)" class="st4 st9 st10">X</text>
</g>
<g id="Y_Button_00000100344340438574137780000014238704828967683973_">
<circle id="Background_00000137100455694543496620000011124722786613194377_" class="st8" cx="723.9" cy="564.8" r="35"/>
<text transform="matrix(1 0 0 1 710.5263 578.661)" class="st4 st9 st10">Y</text>
</g>
<g id="B_Button_00000041994261956088037220000013468634544777304733_">
<circle id="Background_00000096038108578846046800000001873940014252420514_" class="st8" cx="793.9" cy="634.8" r="35"/>
<text transform="matrix(1 0 0 1 780.9706 648.6605)" class="st4 st9 st10">B</text>
</g>
</g>
</g>
<g id="Top_Down">
<path id="Left_Grip_00000026131988385328425370000016677941743356253314_" class="st0" d="M219.2,78.5
c-12.5-17.6-25.9-42.3-45.6-58.6C153.5,3.3,112.1-4.7,87.1,5.8c-13.9,5.8-33.4,33.1-42.7,52.8C33.9,80.9,30.4,109.9,32,141.4
c1.2,25.1,5.3,51.7,14.2,78.6c0,0,14.3,53.8,42.8,80.8c11.2,10.6,35,26.6,35,26.6l116-217.5C240,109.9,224.6,86.2,219.2,78.5z"/>
<path id="Right_Grip_00000016782759094708820330000002450847065936193693_" class="st0" d="M828.6,78.5
c12.5-17.6,25.9-42.3,45.6-58.6c20.1-16.6,61.4-24.5,86.5-14.1c13.9,5.8,33.4,33.1,42.7,52.8c10.5,22.3,13.9,51.3,12.4,82.8
c-1.2,25.1-5.3,51.7-14.2,78.6c0,0-14.3,53.8-42.8,80.8c-11.2,10.6-35,26.6-35,26.6l-116-217.5C807.8,109.9,823.2,86.2,828.6,78.5z
"/>
<path id="Background_00000169534857628063347190000007586592143875928969_" class="st11" d="M866,122.2
c66.3,18.7,85.1,128.8,69,186c-2.5,54.2-148.9,15.3-265.1,31.2c-41.1,1.7-91.8,2.4-145.9,2.3c-54.1,0-104.8-0.6-145.9-2.3
c-116.2-15.9-262.6,23.1-265.1-31.2c-16.1-57.1,2.6-167.3,69-186l60.5-18.8l38.9-1.9c40.2,0.1,142.8,0,242.7,0
c99.9,0,202.4,0.1,242.7,0l38.9,1.9L866,122.2z"/>
<g id="ZL_Trigger_00000005254517714433203260000014117442438696169895_">
<path id="Background_00000111870097528015387240000017384507710402295183_" class="st1" d="M145.9,239.2
c15.2-97.4,38.1-147.2,141.7-137c8.2,16.4,43.3,83,50.6,105.7C280.6,227.2,204.7,225.6,145.9,239.2z"/>
<text id="ZL_Trigger" transform="matrix(1.0139 0 0 1 218.3906 179.3992)" class="st4 st9 st10">ZL</text>
</g>
<g id="ZR_Trigger">
<path id="Background_00000133526766189752063450000016781240006605114763_" class="st1" d="M716.2,207.9
c7.4-22.7,42.5-89.3,50.6-105.7c103.7-10.2,126.5,39.6,141.7,137C849.8,225.6,773.8,227.2,716.2,207.9z"/>
<text id="ZL_Trigger_00000000206350378518266660000001315160307759857328_" transform="matrix(1.0139 0 0 1 784.2356 179.3992)" class="st4 st9 st10">ZR</text>
</g>
<g id="R_Trigger_00000085939413106284991650000014018840000393673094_">
<path id="Background" class="st1" d="M664,318.5c7-10.1,27.8-78.4,45.4-78.7C1040.8,243.7,897.1,334,664,318.5z"/>
<text id="R_Trigger" transform="matrix(1 0 0 1 769.6461 292.8947)" class="st4 st9 st10">R</text>
</g>
<g id="L_Trigger">
<path id="Background_00000043427985111927735300000011910735497762731703_" class="st1" d="M340.6,238.6
c17.6,0.3,38.4,68.6,45.4,78.7C152.9,332.8,9.2,242.6,340.6,238.6z"/>
<text id="R_Trigger_00000092444210070373642420000009814634285137007748_" transform="matrix(1 0 0 1 253.7327 291.7279)" class="st4 st9 st10">L</text>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 8.0 KiB

View File

@@ -21,34 +21,6 @@
<None Remove="Resources\Logo_Ryujinx.png" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Resources\Controller_JoyConLeft.svg" />
<EmbeddedResource Include="Resources\Controller_JoyConPair.svg" />
<EmbeddedResource Include="Resources\Controller_JoyConRight.svg" />
<EmbeddedResource Include="Resources\Controller_ProCon.svg" />
<EmbeddedResource Include="Resources\Icon_NCA.png" />
<EmbeddedResource Include="Resources\Icon_NRO.png" />
<EmbeddedResource Include="Resources\Icon_NSO.png" />
<EmbeddedResource Include="Resources\Icon_NSP.png" />
<EmbeddedResource Include="Resources\Icon_XCI.png" />
<EmbeddedResource Include="Resources\Logo_Amiibo.png" />
<EmbeddedResource Include="Resources\Logo_Ryujinx.png" />
<EmbeddedResource Include="Resources\Logo_Ryujinx_AntiAlias.png" />
<EmbeddedResource Include="Resources\Logo_Discord_Dark.png" />
<EmbeddedResource Include="Resources\Logo_Discord_Light.png" />
<EmbeddedResource Include="Resources\Logo_GitHub_Dark.png" />
<EmbeddedResource Include="Resources\Logo_GitHub_Light.png" />
</ItemGroup>
<ItemGroup Condition="'$(RuntimeIdentifier)' == 'linux-x64' OR '$(RuntimeIdentifier)' == 'linux-arm64' OR '$(RuntimeIdentifier)' == ''">
<EmbeddedResource Include="..\..\distribution\linux\shortcut-template.desktop" />
</ItemGroup>
<ItemGroup Condition="'$(RuntimeIdentifier)' == 'osx-x64' OR '$(RuntimeIdentifier)' == 'osx-arm64' OR '$(RuntimeIdentifier)' == ''">
<EmbeddedResource Include="..\..\distribution\macos\shortcut-template.plist" />
<EmbeddedResource Include="..\..\distribution\macos\shortcut-launch-script.sh" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="DiscordRichPresence" />
<PackageReference Include="DynamicData" />

View File

@@ -20,11 +20,15 @@ using Ryujinx.Ava.UI.Models;
using Ryujinx.Ava.UI.Renderer;
using Ryujinx.Ava.UI.ViewModels;
using Ryujinx.Ava.UI.Windows;
using Ryujinx.Ava.Utilities;
using Ryujinx.Ava.Utilities.AppLibrary;
using Ryujinx.Ava.Utilities.Configuration;
using Ryujinx.Common;
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Configuration.Multiplayer;
using Ryujinx.Common.Logging;
using Ryujinx.Common.SystemInterop;
using Ryujinx.Common.UI;
using Ryujinx.Common.Utilities;
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.GAL.Multithreading;
@@ -39,10 +43,6 @@ using Ryujinx.HLE.HOS.Services.Account.Acc;
using Ryujinx.HLE.HOS.SystemState;
using Ryujinx.Input;
using Ryujinx.Input.HLE;
using Ryujinx.UI.App.Common;
using Ryujinx.UI.Common;
using Ryujinx.UI.Common.Configuration;
using Ryujinx.UI.Common.Helper;
using Silk.NET.Vulkan;
using SkiaSharp;
using SPB.Graphics.Vulkan;
@@ -289,19 +289,19 @@ namespace Ryujinx.Ava
private void UpdateScalingFilterLevel(object sender, ReactiveEventArgs<int> e)
{
_renderer.Window?.SetScalingFilter((Graphics.GAL.ScalingFilter)ConfigurationState.Instance.Graphics.ScalingFilter.Value);
_renderer.Window?.SetScalingFilterLevel(ConfigurationState.Instance.Graphics.ScalingFilterLevel.Value);
_renderer.Window?.SetScalingFilter(ConfigurationState.Instance.Graphics.ScalingFilter);
_renderer.Window?.SetScalingFilterLevel(ConfigurationState.Instance.Graphics.ScalingFilterLevel);
}
private void UpdateScalingFilter(object sender, ReactiveEventArgs<ScalingFilter> e)
{
_renderer.Window?.SetScalingFilter((Graphics.GAL.ScalingFilter)ConfigurationState.Instance.Graphics.ScalingFilter.Value);
_renderer.Window?.SetScalingFilterLevel(ConfigurationState.Instance.Graphics.ScalingFilterLevel.Value);
_renderer.Window?.SetScalingFilter(ConfigurationState.Instance.Graphics.ScalingFilter);
_renderer.Window?.SetScalingFilterLevel(ConfigurationState.Instance.Graphics.ScalingFilterLevel);
}
private void UpdateColorSpacePassthrough(object sender, ReactiveEventArgs<bool> e)
{
_renderer.Window?.SetColorSpacePassthrough((bool)ConfigurationState.Instance.Graphics.EnableColorSpacePassthrough.Value);
_renderer.Window?.SetColorSpacePassthrough(ConfigurationState.Instance.Graphics.EnableColorSpacePassthrough);
}
public void UpdateVSyncMode(object sender, ReactiveEventArgs<VSyncMode> e)
@@ -311,9 +311,10 @@ namespace Ryujinx.Ava
Device.VSyncMode = e.NewValue;
Device.UpdateVSyncInterval();
}
_renderer.Window?.ChangeVSyncMode((Ryujinx.Graphics.GAL.VSyncMode)e.NewValue);
_renderer.Window?.ChangeVSyncMode(e.NewValue);
_viewModel.ShowCustomVSyncIntervalPicker = (e.NewValue == VSyncMode.Custom);
_viewModel.UpdateVSyncIntervalPicker();
}
public void VSyncModeToggle()
@@ -526,7 +527,7 @@ namespace Ryujinx.Ava
private void UpdateAntiAliasing(object sender, ReactiveEventArgs<AntiAliasing> e)
{
_renderer?.Window?.SetAntiAliasing((Graphics.GAL.AntiAliasing)e.NewValue);
_renderer?.Window?.SetAntiAliasing(e.NewValue);
}
private void UpdateDockedModeState(object sender, ReactiveEventArgs<bool> e)
@@ -577,7 +578,6 @@ namespace Ryujinx.Ava
public void Stop()
{
_isActive = false;
DiscordIntegrationModule.SwitchToMainState();
}
private void Exit()
@@ -861,13 +861,11 @@ namespace Ryujinx.Ava
return false;
}
ApplicationMetadata appMeta = ApplicationLibrary.LoadAndSaveMetaData(Device.Processes.ActiveApplication.ProgramIdText,
ApplicationLibrary.LoadAndSaveMetaData(Device.Processes.ActiveApplication.ProgramIdText,
appMetadata => appMetadata.UpdatePreGame()
);
DiscordIntegrationModule.SwitchToPlayingState(appMeta, Device.Processes.ActiveApplication);
return true;
}
@@ -923,7 +921,7 @@ namespace Ryujinx.Ava
// Initialize Configuration.
var memoryConfiguration = ConfigurationState.Instance.System.DramSize.Value;
Device = new HLE.Switch(new HLEConfiguration(
Device = new Switch(new HLEConfiguration(
VirtualFileSystem,
_viewModel.LibHacHorizonManager,
ContentManager,
@@ -953,7 +951,8 @@ namespace Ryujinx.Ava
ConfigurationState.Instance.Multiplayer.DisableP2p,
ConfigurationState.Instance.Multiplayer.LdnPassphrase,
ConfigurationState.Instance.Multiplayer.LdnServer,
ConfigurationState.Instance.Graphics.CustomVSyncInterval.Value));
ConfigurationState.Instance.Graphics.CustomVSyncInterval.Value,
ConfigurationState.Instance.Hacks.ShowDirtyHacks ? ConfigurationState.Instance.Hacks.EnabledHacks : null));
}
private static IHardwareDeviceDriver InitializeAudio()
@@ -1057,10 +1056,10 @@ namespace Ryujinx.Ava
Device.Gpu.Renderer.Initialize(_glLogLevel);
_renderer?.Window?.SetAntiAliasing((Graphics.GAL.AntiAliasing)ConfigurationState.Instance.Graphics.AntiAliasing.Value);
_renderer?.Window?.SetScalingFilter((Graphics.GAL.ScalingFilter)ConfigurationState.Instance.Graphics.ScalingFilter.Value);
_renderer?.Window?.SetScalingFilterLevel(ConfigurationState.Instance.Graphics.ScalingFilterLevel.Value);
_renderer?.Window?.SetColorSpacePassthrough(ConfigurationState.Instance.Graphics.EnableColorSpacePassthrough.Value);
_renderer?.Window?.SetAntiAliasing(ConfigurationState.Instance.Graphics.AntiAliasing);
_renderer?.Window?.SetScalingFilter(ConfigurationState.Instance.Graphics.ScalingFilter);
_renderer?.Window?.SetScalingFilterLevel(ConfigurationState.Instance.Graphics.ScalingFilterLevel);
_renderer?.Window?.SetColorSpacePassthrough(ConfigurationState.Instance.Graphics.EnableColorSpacePassthrough);
Width = (int)RendererHost.Bounds.Width;
Height = (int)RendererHost.Bounds.Height;
@@ -1074,7 +1073,7 @@ namespace Ryujinx.Ava
Device.Gpu.SetGpuThread();
Device.Gpu.InitializeShaderCache(_gpuCancellationTokenSource.Token);
_renderer.Window.ChangeVSyncMode((Ryujinx.Graphics.GAL.VSyncMode)Device.VSyncMode);
_renderer.Window.ChangeVSyncMode(Device.VSyncMode);
while (_isActive)
{

View File

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View File

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View File

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View File

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View File

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View File

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View File

Before

Width:  |  Height:  |  Size: 9.6 KiB

After

Width:  |  Height:  |  Size: 9.6 KiB

View File

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View File

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

View File

Before

Width:  |  Height:  |  Size: 253 KiB

After

Width:  |  Height:  |  Size: 253 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

File diff suppressed because it is too large Load Diff

View File

@@ -15,12 +15,12 @@ using LibHac.Tools.FsSystem.NcaUtils;
using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.UI.Controls;
using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.Utilities.Configuration;
using Ryujinx.Common.Helper;
using Ryujinx.Common.Logging;
using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.HOS.Services.Account.Acc;
using Ryujinx.HLE.Loaders.Processes.Extensions;
using Ryujinx.UI.Common.Configuration;
using Ryujinx.UI.Common.Helper;
using System;
using System.Buffers;
using System.IO;

View File

@@ -1,8 +1,8 @@
using Gommon;
using Ryujinx.Ava.UI.ViewModels;
using Ryujinx.Ava.Utilities.Configuration;
using Ryujinx.Common;
using Ryujinx.Common.Utilities;
using Ryujinx.UI.Common.Configuration;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;

View File

@@ -2,7 +2,7 @@ using System;
using System.Collections.Generic;
using System.Text.Json.Serialization;
namespace Ryujinx.UI.Common.Models.Amiibo
namespace Ryujinx.Ava.Common.Models.Amiibo
{
public struct AmiiboApi : IEquatable<AmiiboApi>
{

View File

@@ -1,7 +1,7 @@
using System.Collections.Generic;
using System.Text.Json.Serialization;
namespace Ryujinx.UI.Common.Models.Amiibo
namespace Ryujinx.Ava.Common.Models.Amiibo
{
public class AmiiboApiGamesSwitch
{

View File

@@ -1,6 +1,6 @@
using System.Text.Json.Serialization;
namespace Ryujinx.UI.Common.Models.Amiibo
namespace Ryujinx.Ava.Common.Models.Amiibo
{
public class AmiiboApiUsage
{

View File

@@ -2,7 +2,7 @@ using System;
using System.Collections.Generic;
using System.Text.Json.Serialization;
namespace Ryujinx.UI.Common.Models.Amiibo
namespace Ryujinx.Ava.Common.Models.Amiibo
{
public struct AmiiboJson
{

View File

@@ -1,9 +1,7 @@
using System.Text.Json.Serialization;
namespace Ryujinx.UI.Common.Models.Amiibo
namespace Ryujinx.Ava.Common.Models.Amiibo
{
[JsonSerializable(typeof(AmiiboJson))]
public partial class AmiiboJsonSerializerContext : JsonSerializerContext
{
}
public partial class AmiiboJsonSerializerContext : JsonSerializerContext;
}

View File

@@ -1,4 +1,4 @@
namespace Ryujinx.UI.Common.Models
namespace Ryujinx.Ava.Common.Models
{
// NOTE: most consuming code relies on this model being value-comparable
public record DownloadableContentModel(ulong TitleId, string ContainerPath, string FullPath)

View File

@@ -1,4 +1,4 @@
namespace Ryujinx.UI.Common.Models.Github
namespace Ryujinx.Ava.Common.Models.Github
{
public class GithubReleaseAssetJsonResponse
{

View File

@@ -1,6 +1,6 @@
using System.Collections.Generic;
namespace Ryujinx.UI.Common.Models.Github
namespace Ryujinx.Ava.Common.Models.Github
{
public class GithubReleasesJsonResponse
{

View File

@@ -1,9 +1,7 @@
using System.Text.Json.Serialization;
namespace Ryujinx.UI.Common.Models.Github
namespace Ryujinx.Ava.Common.Models.Github
{
[JsonSerializable(typeof(GithubReleasesJsonResponse), GenerationMode = JsonSourceGenerationMode.Metadata)]
public partial class GithubReleasesJsonSerializerContext : JsonSerializerContext
{
}
public partial class GithubReleasesJsonSerializerContext : JsonSerializerContext;
}

View File

@@ -1,4 +1,4 @@
namespace Ryujinx.UI.Common.Models
namespace Ryujinx.Ava.Common.Models
{
// NOTE: most consuming code relies on this model being value-comparable
public record TitleUpdateModel(ulong TitleId, ulong Version, string DisplayVersion, string Path)

View File

@@ -1,8 +1,8 @@
using Ryujinx.Ava.Utilities.AppLibrary;
using Ryujinx.Common.Logging;
using Ryujinx.Common.Utilities;
using Ryujinx.UI.App.Common;
namespace Ryujinx.UI.Common.Models
namespace Ryujinx.Ava.Common.Models
{
public record XCITrimmerFileModel(
string Name,

View File

@@ -1,14 +1,14 @@
using DiscordRPC;
using Humanizer;
using Humanizer.Localisation;
using Ryujinx.Ava.Utilities.AppLibrary;
using Ryujinx.Ava.Utilities.Configuration;
using Ryujinx.Common;
using Ryujinx.HLE;
using Ryujinx.HLE.Loaders.Processes;
using Ryujinx.UI.App.Common;
using Ryujinx.UI.Common.Configuration;
using System.Linq;
using System.Text;
namespace Ryujinx.UI.Common
namespace Ryujinx.Ava
{
public static class DiscordIntegrationModule
{
@@ -45,6 +45,16 @@ namespace Ryujinx.UI.Common
};
ConfigurationState.Instance.EnableDiscordIntegration.Event += Update;
TitleIDs.CurrentApplication.Event += (_, e) =>
{
if (e.NewValue)
SwitchToPlayingState(
ApplicationLibrary.LoadAndSaveMetaData(e.NewValue),
Switch.Shared.Processes.ActiveApplication
);
else
SwitchToMainState();
};
}
private static void Update(object sender, ReactiveEventArgs<bool> evnt)
@@ -70,7 +80,7 @@ namespace Ryujinx.UI.Common
}
}
public static void SwitchToPlayingState(ApplicationMetadata appMeta, ProcessResult procRes)
private static void SwitchToPlayingState(ApplicationMetadata appMeta, ProcessResult procRes)
{
_discordClient?.SetPresence(new RichPresence
{
@@ -89,7 +99,7 @@ namespace Ryujinx.UI.Common
});
}
public static void SwitchToMainState() => _discordClient?.SetPresence(_discordPresenceMain);
private static void SwitchToMainState() => _discordClient?.SetPresence(_discordPresenceMain);
private static string TruncateToByteLength(string input)
{

View File

@@ -2,7 +2,7 @@ using Ryujinx.HLE.UI;
using System.Threading;
using System.Threading.Tasks;
namespace Ryujinx.Headless.SDL2
namespace Ryujinx.Headless
{
/// <summary>
/// Headless text processing class, right now there is no way to forward the input to it.

Some files were not shown because too many files have changed in this diff Show More