Compare commits

...

19 Commits

Author SHA1 Message Date
Evan Husted
66fdad6d64 hia: prevent infinite loading 2024-12-14 04:41:43 -06:00
Evan Husted
657bd4a7d0 missed this 2024-12-14 00:24:39 -06:00
Evan Husted
d3a6a8f66e hia: Fix last used profile loading, (hopefully) fixed logo loading 2024-12-11 16:21:13 -06:00
Evan Husted
12a506a644 hia: Fix Window icon loading 2024-12-11 15:41:06 -06:00
Evan Husted
6f56690c1c hia: Only reference AppDataManager properties after they've been initialized 2024-12-11 15:23:31 -06:00
Evan Husted
1398dad67c hia: fix 2 crashes 2024-12-11 15:01:28 -06:00
Evan Husted
2fc58d58a5 Fix accidental null passing 2024-12-11 14:15:57 -06:00
Evan Husted
75fa7c7d4d fixups 2024-12-09 03:28:16 -06:00
Evan Husted
a477658b85 Headless in Avalonia v2 2024-12-09 03:21:07 -06:00
Evan Husted
338777055f I love that I clicked delete on this and it was literally like, still there, not deleted. lol 2024-12-09 01:38:13 -06:00
Evan Husted
90db9a962d Iteration 2: Drop Headless-specific project, drop headless releases. Also prevent duplicate log targets by checking name equality. 2024-12-09 01:36:00 -06:00
Evan Husted
4a545a00c6 Headless in Avalonia, v1
It will get more advanced than this, this is for proof of concept.
2024-12-08 19:01:53 -06:00
Evan Husted
1a005f96e7 Merge remote-tracking branch 'origin/master' 2024-12-08 13:05:47 -06:00
Evan Husted
072cd2824a misc: chore: Simplify Updater version parsing. 2024-12-08 13:05:35 -06:00
Evan Husted
9da97bc911 misc: chore: Collapse XCIFileTrimmerLog implementations into a single class. 2024-12-08 13:05:09 -06:00
Evan Husted
39252b7267 UI: Update About window with the current status of the project. 2024-12-08 13:04:01 -06:00
Evan Husted
ec11bf2af9 i18n: Clean out old translations and reset outdated ones 2024-12-07 08:53:23 -06:00
bangfire
8ae72c1a00 Fix Windows Terminal hide/show functions (#342)
https://stackoverflow.com/a/78577080
2024-12-07 07:17:39 -06:00
Evan Husted
06abba25c1 UI: Adapt accent color to the user's system.
https://amwx.github.io/FluentAvaloniaDocs/pages/FATheme/Accents#using-the-systems-accent-color
2024-12-07 06:22:46 -06:00
58 changed files with 774 additions and 694 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 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' 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 - name: Set executable bit
run: | run: |
chmod +x ./publish/Ryujinx ./publish/Ryujinx.sh 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' if: github.event_name == 'pull_request' && matrix.platform.os == 'ubuntu-latest'
- name: Build AppImage - 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 name: ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-${{ matrix.platform.zip_os_name }}-AppImage
path: publish_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: build_macos:
name: macOS Universal (${{ matrix.configuration }}) name: macOS Universal (${{ matrix.configuration }})
runs-on: ubuntu-latest runs-on: ubuntu-latest
@@ -171,20 +159,9 @@ jobs:
run: | 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" ./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 - name: Upload Ryujinx artifact
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-macos_universal name: ryujinx-${{ matrix.configuration }}-${{ env.RYUJINX_BASE_VERSION }}+${{ steps.git_short_hash.outputs.result }}-macos_universal
path: "publish/*.tar.gz" path: "publish/*.tar.gz"
if: github.event_name == 'pull_request' 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

@@ -104,7 +104,6 @@ jobs:
- name: Publish - name: Publish
run: | 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_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 - name: Packing Windows builds
if: matrix.platform.os == 'windows-latest' if: matrix.platform.os == 'windows-latest'
@@ -113,11 +112,6 @@ jobs:
rm publish/libarmeilleure-jitsupport.dylib rm publish/libarmeilleure-jitsupport.dylib
7z a ../release_output/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip publish 7z a ../release_output/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip publish
popd 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 shell: bash
- name: Packing Linux builds - name: Packing Linux builds
@@ -128,12 +122,6 @@ jobs:
chmod +x publish/Ryujinx.sh publish/Ryujinx 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 tar -czvf ../release_output/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz publish
popd 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 shell: bash
#- name: Build AppImage (Linux) #- name: Build AppImage (Linux)
@@ -179,7 +167,7 @@ jobs:
with: with:
name: ${{ steps.version_info.outputs.build_version }} name: ${{ steps.version_info.outputs.build_version }}
artifacts: "release_output/*.tar.gz,release_output/*.zip" 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 }} tag: ${{ steps.version_info.outputs.build_version }}
body: "**Full Changelog**: https://github.com/${{ github.repository }}/compare/Canary-${{ steps.version_info.outputs.prev_build_version }}...Canary-${{ steps.version_info.outputs.build_version }}" body: "**Full Changelog**: https://github.com/${{ github.repository }}/compare/Canary-${{ steps.version_info.outputs.prev_build_version }}...Canary-${{ steps.version_info.outputs.build_version }}"
omitBodyDuringUpdate: true omitBodyDuringUpdate: true
@@ -238,15 +226,11 @@ jobs:
run: | 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 ./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 - name: Pushing new release
uses: ncipollo/release-action@v1 uses: ncipollo/release-action@v1
with: with:
name: "Canary ${{ steps.version_info.outputs.build_version }}" 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 }} tag: ${{ steps.version_info.outputs.build_version }}
body: "**Full Changelog**: https://github.com/${{ github.repository }}/compare/Canary-${{ steps.version_info.outputs.prev_build_version }}...Canary-${{ steps.version_info.outputs.build_version }}" body: "**Full Changelog**: https://github.com/${{ github.repository }}/compare/Canary-${{ steps.version_info.outputs.prev_build_version }}...Canary-${{ steps.version_info.outputs.build_version }}"
omitBodyDuringUpdate: true omitBodyDuringUpdate: true

View File

@@ -38,20 +38,15 @@ jobs:
return core.error(`No artifacts found`); return core.error(`No artifacts found`);
} }
let body = `Download the artifacts for this pull request:\n`; let body = `Download the artifacts for this pull request:\n`;
let hidden_headless_artifacts = `\n\n <details><summary>GUI-less</summary>\n`;
let hidden_debug_artifacts = `\n\n <details><summary>Only for Developers</summary>\n`; let hidden_debug_artifacts = `\n\n <details><summary>Only for Developers</summary>\n`;
for (const art of artifacts) { for (const art of artifacts) {
if(art.name.includes('Debug')) { if(art.name.includes('Debug')) {
hidden_debug_artifacts += `\n* [${art.name}](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`; 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)`;
} else { } else {
body += `\n* [${art.name}](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`; body += `\n* [${art.name}](https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip)`;
} }
} }
hidden_headless_artifacts += `\n</details>`;
hidden_debug_artifacts += `\n</details>`; hidden_debug_artifacts += `\n</details>`;
body += hidden_headless_artifacts;
body += hidden_debug_artifacts; body += hidden_debug_artifacts;
const {data: comments} = await github.rest.issues.listComments({repo, owner, issue_number}); const {data: comments} = await github.rest.issues.listComments({repo, owner, issue_number});

View File

@@ -103,7 +103,6 @@ jobs:
- name: Publish - name: Publish
run: | 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 -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 - name: Packing Windows builds
if: matrix.platform.os == 'windows-latest' if: matrix.platform.os == 'windows-latest'
@@ -112,11 +111,6 @@ jobs:
rm libarmeilleure-jitsupport.dylib rm libarmeilleure-jitsupport.dylib
7z a ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip ../publish 7z a ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip ../publish
popd 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 shell: bash
- name: Build AppImage (Linux) - name: Build AppImage (Linux)
@@ -163,11 +157,6 @@ jobs:
chmod +x Ryujinx.sh Ryujinx chmod +x Ryujinx.sh Ryujinx
tar -czvf ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz ../publish tar -czvf ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz ../publish
popd 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 shell: bash
- name: Pushing new release - name: Pushing new release
@@ -233,15 +222,11 @@ jobs:
run: | 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 ./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 - name: Pushing new release
uses: ncipollo/release-action@v1 uses: ncipollo/release-action@v1
with: with:
name: ${{ steps.version_info.outputs.build_version }} 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 }} tag: ${{ steps.version_info.outputs.build_version }}
body: "**Full Changelog**: https://github.com/${{ github.repository }}/compare/${{ steps.version_info.outputs.prev_build_version }}...${{ steps.version_info.outputs.build_version }}" body: "**Full Changelog**: https://github.com/${{ github.repository }}/compare/${{ steps.version_info.outputs.prev_build_version }}...${{ steps.version_info.outputs.build_version }}"
omitBodyDuringUpdate: true omitBodyDuringUpdate: true

View File

@@ -57,8 +57,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.SDL2.Common", "src\
EndProject 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}" 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 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}" 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 EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx", "src\Ryujinx\Ryujinx.csproj", "{7C1B2721-13DA-4B62-B046-C626605ECCE6}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx", "src\Ryujinx\Ryujinx.csproj", "{7C1B2721-13DA-4B62-B046-C626605ECCE6}"
@@ -204,10 +202,6 @@ Global
{D99A395A-8569-4DB0-B336-900647890052}.Debug|Any CPU.Build.0 = Debug|Any CPU {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.ActiveCfg = Release|Any CPU
{D99A395A-8569-4DB0-B336-900647890052}.Release|Any CPU.Build.0 = 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.ActiveCfg = Debug|Any CPU
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Debug|Any CPU.Build.0 = 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 {BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Release|Any CPU.ActiveCfg = Release|Any CPU

View File

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

View File

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

View File

@@ -1,3 +1,4 @@
using Gommon;
using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.Common.Utilities; using Ryujinx.Common.Utilities;
@@ -6,12 +7,13 @@ using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq;
namespace Ryujinx.HLE.HOS.Services.Account.Acc 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()); 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) public void Save(ConcurrentDictionary<string, UserProfile> profiles)
{ {
ProfilesJson profilesJson = new() ProfilesJson profilesJson = new()

View File

@@ -1,73 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<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.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,4 +1,5 @@
using Ryujinx.Common.Utilities; using Ryujinx.Common.Utilities;
using Ryujinx.HLE.HOS.SystemState;
using System.Text.Json.Serialization; using System.Text.Json.Serialization;
namespace Ryujinx.UI.Common.Configuration.System namespace Ryujinx.UI.Common.Configuration.System

View File

@@ -7,6 +7,24 @@ namespace Ryujinx.UI.Common.Helper
{ {
public static partial class ConsoleHelper public static partial class ConsoleHelper
{ {
[SupportedOSPlatform("windows")]
[LibraryImport("kernel32")]
private static partial nint GetConsoleWindow();
[SupportedOSPlatform("windows")]
[LibraryImport("user32")]
[return: MarshalAs(UnmanagedType.Bool)]
private static partial bool ShowWindow(nint hWnd, int nCmdShow);
[SupportedOSPlatform("windows")]
[LibraryImport("user32")]
private static partial nint GetForegroundWindow();
[SupportedOSPlatform("windows")]
[LibraryImport("user32")]
[return: MarshalAs(UnmanagedType.Bool)]
private static partial bool SetForegroundWindow(nint hWnd);
public static bool SetConsoleWindowStateSupported => OperatingSystem.IsWindows(); public static bool SetConsoleWindowStateSupported => OperatingSystem.IsWindows();
public static void SetConsoleWindowState(bool show) public static void SetConsoleWindowState(bool show)
@@ -35,16 +53,11 @@ namespace Ryujinx.UI.Common.Helper
return; return;
} }
SetForegroundWindow(hWnd);
hWnd = GetForegroundWindow();
ShowWindow(hWnd, show ? SW_SHOW : SW_HIDE); ShowWindow(hWnd, show ? SW_SHOW : SW_HIDE);
} }
[SupportedOSPlatform("windows")]
[LibraryImport("kernel32")]
private static partial nint GetConsoleWindow();
[SupportedOSPlatform("windows")]
[LibraryImport("user32")]
[return: MarshalAs(UnmanagedType.Bool)]
private static partial bool ShowWindow(nint hWnd, int nCmdShow);
} }
} }

View File

@@ -132,7 +132,7 @@ namespace Ryujinx.UI.Common.Helper
if (uninstall) 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()) if (!AreMimeTypesRegisteredWindows())
{ {
return true; return true;

View File

@@ -11,7 +11,7 @@
</ResourceDictionary> </ResourceDictionary>
</Application.Resources> </Application.Resources>
<Application.Styles> <Application.Styles>
<sty:FluentAvaloniaTheme PreferSystemTheme="False" /> <sty:FluentAvaloniaTheme PreferUserAccentColor="True" PreferSystemTheme="False" />
<StyleInclude Source="/Assets/Styles/Styles.xaml" /> <StyleInclude Source="/Assets/Styles/Styles.xaml" />
</Application.Styles> </Application.Styles>
</Application> </Application>

View File

@@ -552,15 +552,13 @@
"AboutUrlTooltipMessage": "انقر لفتح موقع ريوجينكس في متصفحك الافتراضي.", "AboutUrlTooltipMessage": "انقر لفتح موقع ريوجينكس في متصفحك الافتراضي.",
"AboutDisclaimerMessage": "ريوجينكس لا ينتمي إلى نينتندو™،\nأو أي من شركائها بأي شكل من الأشكال.", "AboutDisclaimerMessage": "ريوجينكس لا ينتمي إلى نينتندو™،\nأو أي من شركائها بأي شكل من الأشكال.",
"AboutAmiiboDisclaimerMessage": "AmiiboAPI (www.amiiboapi.com) يتم \nاستخدامه في محاكاة أمبيو لدينا.", "AboutAmiiboDisclaimerMessage": "AmiiboAPI (www.amiiboapi.com) يتم \nاستخدامه في محاكاة أمبيو لدينا.",
"AboutPatreonUrlTooltipMessage": "انقر لفتح صفحة ريوجينكس في باتريون في متصفحك الافتراضي.",
"AboutGithubUrlTooltipMessage": "انقر لفتح صفحة ريوجينكس في غيت هاب في متصفحك الافتراضي.", "AboutGithubUrlTooltipMessage": "انقر لفتح صفحة ريوجينكس في غيت هاب في متصفحك الافتراضي.",
"AboutDiscordUrlTooltipMessage": "انقر لفتح دعوة إلى خادم ريوجينكس في ديكسورد في متصفحك الافتراضي.", "AboutDiscordUrlTooltipMessage": "انقر لفتح دعوة إلى خادم ريوجينكس في ديكسورد في متصفحك الافتراضي.",
"AboutTwitterUrlTooltipMessage": "انقر لفتح صفحة ريوجينكس في تويتر في متصفحك الافتراضي.",
"AboutRyujinxAboutTitle": "حول:", "AboutRyujinxAboutTitle": "حول:",
"AboutRyujinxAboutContent": "ريوجينكس هو محاكي لجهاز نينتندو سويتش™.\nمن فضلك ادعمنا على باتريون.\nاحصل على آخر الأخبار على تويتر أو ديسكورد.\nيمكن للمطورين المهتمين بالمساهمة معرفة المزيد على غيت هاب أو ديسكورد.", "AboutRyujinxAboutContent": "Ryujinx is an emulator for the Nintendo Switch™.\nGet all the latest news in our Discord.\nDevelopers interested in contributing can find out more on our GitHub or Discord.",
"AboutRyujinxMaintainersTitle": "تتم صيانته بواسطة:", "AboutRyujinxMaintainersTitle": "تتم صيانته بواسطة:",
"AboutRyujinxFormerMaintainersTitle": "Formerly Maintained By:",
"AboutRyujinxMaintainersContentTooltipMessage": "انقر لفتح صفحة المساهمين في متصفحك الافتراضي.", "AboutRyujinxMaintainersContentTooltipMessage": "انقر لفتح صفحة المساهمين في متصفحك الافتراضي.",
"AboutRyujinxSupprtersTitle": "مدعوم على باتريون بواسطة:",
"AmiiboSeriesLabel": "مجموعة أميبو", "AmiiboSeriesLabel": "مجموعة أميبو",
"AmiiboCharacterLabel": "شخصية", "AmiiboCharacterLabel": "شخصية",
"AmiiboScanButtonLabel": "فحصه", "AmiiboScanButtonLabel": "فحصه",

View File

@@ -552,15 +552,13 @@
"AboutUrlTooltipMessage": "Klicke hier, um die Ryujinx Website im Standardbrowser zu öffnen.", "AboutUrlTooltipMessage": "Klicke hier, um die Ryujinx Website im Standardbrowser zu öffnen.",
"AboutDisclaimerMessage": "Ryujinx ist in keinster Weise weder mit Nintendo™, \nnoch mit deren Partnern verbunden.", "AboutDisclaimerMessage": "Ryujinx ist in keinster Weise weder mit Nintendo™, \nnoch mit deren Partnern verbunden.",
"AboutAmiiboDisclaimerMessage": "AmiiboAPI (www.amiiboapi.com) wird in unserer Amiibo \nEmulation benutzt.", "AboutAmiiboDisclaimerMessage": "AmiiboAPI (www.amiiboapi.com) wird in unserer Amiibo \nEmulation benutzt.",
"AboutPatreonUrlTooltipMessage": "Klicke hier, um die Ryujinx Patreon Seite im Standardbrowser zu öffnen.",
"AboutGithubUrlTooltipMessage": "Klicke hier, um die Ryujinx GitHub Seite im Standardbrowser zu öffnen.", "AboutGithubUrlTooltipMessage": "Klicke hier, um die Ryujinx GitHub Seite im Standardbrowser zu öffnen.",
"AboutDiscordUrlTooltipMessage": "Klicke hier, um eine Einladung zum Ryujinx Discord Server im Standardbrowser zu öffnen.", "AboutDiscordUrlTooltipMessage": "Klicke hier, um eine Einladung zum Ryujinx Discord Server im Standardbrowser zu öffnen.",
"AboutTwitterUrlTooltipMessage": "Klicke hier, um die Ryujinx Twitter Seite im Standardbrowser zu öffnen.",
"AboutRyujinxAboutTitle": "Über:", "AboutRyujinxAboutTitle": "Über:",
"AboutRyujinxAboutContent": "Ryujinx ist ein Nintendo Switch™ Emulator.\nBitte unterstütze uns auf Patreon.\nAuf Twitter oder Discord erfährst du alle Neuigkeiten.\nEntwickler, die an einer Mitarbeit interessiert sind, können auf GitHub oder Discord mehr erfahren.", "AboutRyujinxAboutContent": "Ryujinx is an emulator for the Nintendo Switch™.\nGet all the latest news in our Discord.\nDevelopers interested in contributing can find out more on our GitHub or Discord.",
"AboutRyujinxMaintainersTitle": "Entwickelt von:", "AboutRyujinxMaintainersTitle": "Entwickelt von:",
"AboutRyujinxFormerMaintainersTitle": "Formerly Maintained By:",
"AboutRyujinxMaintainersContentTooltipMessage": "Klicke hier, um die Liste der Mitwirkenden im Standardbrowser zu öffnen.", "AboutRyujinxMaintainersContentTooltipMessage": "Klicke hier, um die Liste der Mitwirkenden im Standardbrowser zu öffnen.",
"AboutRyujinxSupprtersTitle": "Unterstützt auf Patreon von:",
"AmiiboSeriesLabel": "Amiibo-Serie", "AmiiboSeriesLabel": "Amiibo-Serie",
"AmiiboCharacterLabel": "Charakter", "AmiiboCharacterLabel": "Charakter",
"AmiiboScanButtonLabel": "Einscannen", "AmiiboScanButtonLabel": "Einscannen",

View File

@@ -552,15 +552,13 @@
"AboutUrlTooltipMessage": "Κάντε κλικ για να ανοίξετε τον ιστότοπο Ryujinx στο προεπιλεγμένο πρόγραμμα περιήγησης.", "AboutUrlTooltipMessage": "Κάντε κλικ για να ανοίξετε τον ιστότοπο Ryujinx στο προεπιλεγμένο πρόγραμμα περιήγησης.",
"AboutDisclaimerMessage": "Το Ryujinx δεν είναι συνδεδεμένο με τη Nintendo™,\nούτε με κανέναν από τους συνεργάτες της, με οποιονδήποτε τρόπο.", "AboutDisclaimerMessage": "Το Ryujinx δεν είναι συνδεδεμένο με τη Nintendo™,\nούτε με κανέναν από τους συνεργάτες της, με οποιονδήποτε τρόπο.",
"AboutAmiiboDisclaimerMessage": "Το AmiiboAPI (www.amiiboapi.com) χρησιμοποιείται\nστην προσομοίωση Amiibo.", "AboutAmiiboDisclaimerMessage": "Το AmiiboAPI (www.amiiboapi.com) χρησιμοποιείται\nστην προσομοίωση Amiibo.",
"AboutPatreonUrlTooltipMessage": "Κάντε κλικ για να ανοίξετε τη σελίδα Ryujinx Patreon στο προεπιλεγμένο πρόγραμμα περιήγησης.",
"AboutGithubUrlTooltipMessage": "Κάντε κλικ για να ανοίξετε τη σελίδα Ryujinx GitHub στο προεπιλεγμένο πρόγραμμα περιήγησης.", "AboutGithubUrlTooltipMessage": "Κάντε κλικ για να ανοίξετε τη σελίδα Ryujinx GitHub στο προεπιλεγμένο πρόγραμμα περιήγησης.",
"AboutDiscordUrlTooltipMessage": "Κάντε κλικ για να ανοίξετε μία πρόσκληση στον διακομιστή Ryujinx Discord στο προεπιλεγμένο πρόγραμμα περιήγησης.", "AboutDiscordUrlTooltipMessage": "Κάντε κλικ για να ανοίξετε μία πρόσκληση στον διακομιστή Ryujinx Discord στο προεπιλεγμένο πρόγραμμα περιήγησης.",
"AboutTwitterUrlTooltipMessage": "Κάντε κλικ για να ανοίξετε τη σελίδα Ryujinx Twitter στο προεπιλεγμένο πρόγραμμα περιήγησης.",
"AboutRyujinxAboutTitle": "Σχετικά με:", "AboutRyujinxAboutTitle": "Σχετικά με:",
"AboutRyujinxAboutContent": "Το Ryujinx είναι ένας εξομοιωτής για το Nintendo Switch™.\nΥποστηρίξτε μας στο Patreon.\nΛάβετε όλα τα τελευταία νέα στο Twitter ή στο Discord.\nΟι προγραμματιστές που ενδιαφέρονται να συνεισφέρουν μπορούν να μάθουν περισσότερα στο GitHub ή στο Discord μας.", "AboutRyujinxAboutContent": "Ryujinx is an emulator for the Nintendo Switch™.\nGet all the latest news in our Discord.\nDevelopers interested in contributing can find out more on our GitHub or Discord.",
"AboutRyujinxMaintainersTitle": "Συντηρείται από:", "AboutRyujinxMaintainersTitle": "Συντηρείται από:",
"AboutRyujinxFormerMaintainersTitle": "Formerly Maintained By:",
"AboutRyujinxMaintainersContentTooltipMessage": "Κάντε κλικ για να ανοίξετε τη σελίδα Συνεισφέροντες στο προεπιλεγμένο πρόγραμμα περιήγησης.", "AboutRyujinxMaintainersContentTooltipMessage": "Κάντε κλικ για να ανοίξετε τη σελίδα Συνεισφέροντες στο προεπιλεγμένο πρόγραμμα περιήγησης.",
"AboutRyujinxSupprtersTitle": "Υποστηρίζεται στο Patreon από:",
"AmiiboSeriesLabel": "Σειρά Amiibo", "AmiiboSeriesLabel": "Σειρά Amiibo",
"AmiiboCharacterLabel": "Χαρακτήρας", "AmiiboCharacterLabel": "Χαρακτήρας",
"AmiiboScanButtonLabel": "Σαρώστε το", "AmiiboScanButtonLabel": "Σαρώστε το",

View File

@@ -564,15 +564,13 @@
"AboutUrlTooltipMessage": "Click to open the Ryujinx website in your default browser.", "AboutUrlTooltipMessage": "Click to open the Ryujinx website in your default browser.",
"AboutDisclaimerMessage": "Ryujinx is not affiliated with Nintendo™,\nor any of its partners, in any way.", "AboutDisclaimerMessage": "Ryujinx is not affiliated with Nintendo™,\nor any of its partners, in any way.",
"AboutAmiiboDisclaimerMessage": "AmiiboAPI (www.amiiboapi.com) is used\nin our Amiibo emulation.", "AboutAmiiboDisclaimerMessage": "AmiiboAPI (www.amiiboapi.com) is used\nin our Amiibo emulation.",
"AboutPatreonUrlTooltipMessage": "Click to open the Ryujinx Patreon page in your default browser.",
"AboutGithubUrlTooltipMessage": "Click to open the Ryujinx GitHub page in your default browser.", "AboutGithubUrlTooltipMessage": "Click to open the Ryujinx GitHub page in your default browser.",
"AboutDiscordUrlTooltipMessage": "Click to open an invite to the Ryujinx Discord server in your default browser.", "AboutDiscordUrlTooltipMessage": "Click to open an invite to the Ryujinx Discord server in your default browser.",
"AboutTwitterUrlTooltipMessage": "Click to open the Ryujinx Twitter page in your default browser.",
"AboutRyujinxAboutTitle": "About:", "AboutRyujinxAboutTitle": "About:",
"AboutRyujinxAboutContent": "Ryujinx is an emulator for the Nintendo Switch™.\nPlease support us on Patreon.\nGet all the latest news on our Twitter or Discord.\nDevelopers interested in contributing can find out more on our GitHub or Discord.", "AboutRyujinxAboutContent": "Ryujinx is an emulator for the Nintendo Switch™.\nGet all the latest news in our Discord.\nDevelopers interested in contributing can find out more on our GitHub or Discord.",
"AboutRyujinxMaintainersTitle": "Maintained By:", "AboutRyujinxMaintainersTitle": "Maintained By:",
"AboutRyujinxFormerMaintainersTitle": "Formerly Maintained By:",
"AboutRyujinxMaintainersContentTooltipMessage": "Click to open the Contributors page in your default browser.", "AboutRyujinxMaintainersContentTooltipMessage": "Click to open the Contributors page in your default browser.",
"AboutRyujinxSupprtersTitle": "Supported on Patreon By:",
"AmiiboSeriesLabel": "Amiibo Series", "AmiiboSeriesLabel": "Amiibo Series",
"AmiiboCharacterLabel": "Character", "AmiiboCharacterLabel": "Character",
"AmiiboScanButtonLabel": "Scan It", "AmiiboScanButtonLabel": "Scan It",

View File

@@ -552,15 +552,13 @@
"AboutUrlTooltipMessage": "Haz clic para abrir el sitio web de Ryujinx en tu navegador predeterminado.", "AboutUrlTooltipMessage": "Haz clic para abrir el sitio web de Ryujinx en tu navegador predeterminado.",
"AboutDisclaimerMessage": "Ryujinx no tiene afiliación alguna con Nintendo™,\nni con ninguno de sus socios.", "AboutDisclaimerMessage": "Ryujinx no tiene afiliación alguna con Nintendo™,\nni con ninguno de sus socios.",
"AboutAmiiboDisclaimerMessage": "Utilizamos AmiiboAPI (www.amiiboapi.com)\nen nuestra emulación de Amiibo.", "AboutAmiiboDisclaimerMessage": "Utilizamos AmiiboAPI (www.amiiboapi.com)\nen nuestra emulación de Amiibo.",
"AboutPatreonUrlTooltipMessage": "Haz clic para abrir el Patreon de Ryujinx en tu navegador predeterminado.",
"AboutGithubUrlTooltipMessage": "Haz clic para abrir el GitHub de Ryujinx en tu navegador predeterminado.", "AboutGithubUrlTooltipMessage": "Haz clic para abrir el GitHub de Ryujinx en tu navegador predeterminado.",
"AboutDiscordUrlTooltipMessage": "Haz clic para recibir una invitación al Discord de Ryujinx en tu navegador predeterminado.", "AboutDiscordUrlTooltipMessage": "Haz clic para recibir una invitación al Discord de Ryujinx en tu navegador predeterminado.",
"AboutTwitterUrlTooltipMessage": "Haz clic para abrir el Twitter de Ryujinx en tu navegador predeterminado.",
"AboutRyujinxAboutTitle": "Acerca de:", "AboutRyujinxAboutTitle": "Acerca de:",
"AboutRyujinxAboutContent": "Ryujinx es un emulador para Nintendo Switch™.\nPor favor, apóyanos en Patreon.\nEncuentra las noticias más recientes en nuestro Twitter o Discord.\nDesarrolladores interesados en contribuir pueden encontrar más información en GitHub o Discord.", "AboutRyujinxAboutContent": "Ryujinx is an emulator for the Nintendo Switch™.\nGet all the latest news in our Discord.\nDevelopers interested in contributing can find out more on our GitHub or Discord.",
"AboutRyujinxMaintainersTitle": "Mantenido por:", "AboutRyujinxMaintainersTitle": "Mantenido por:",
"AboutRyujinxFormerMaintainersTitle": "Formerly Maintained By:",
"AboutRyujinxMaintainersContentTooltipMessage": "Haz clic para abrir la página de contribuidores en tu navegador predeterminado.", "AboutRyujinxMaintainersContentTooltipMessage": "Haz clic para abrir la página de contribuidores en tu navegador predeterminado.",
"AboutRyujinxSupprtersTitle": "Apoyado en Patreon Por:",
"AmiiboSeriesLabel": "Serie de Amiibo", "AmiiboSeriesLabel": "Serie de Amiibo",
"AmiiboCharacterLabel": "Personaje", "AmiiboCharacterLabel": "Personaje",
"AmiiboScanButtonLabel": "Escanear", "AmiiboScanButtonLabel": "Escanear",

View File

@@ -552,15 +552,13 @@
"AboutUrlTooltipMessage": "Cliquez pour ouvrir le site de Ryujinx dans votre navigateur par défaut.", "AboutUrlTooltipMessage": "Cliquez pour ouvrir le site de Ryujinx dans votre navigateur par défaut.",
"AboutDisclaimerMessage": "Ryujinx n'est pas affilié à Nintendo™,\nou à aucun de ses partenaires, de quelque manière que ce soit.", "AboutDisclaimerMessage": "Ryujinx n'est pas affilié à Nintendo™,\nou à aucun de ses partenaires, de quelque manière que ce soit.",
"AboutAmiiboDisclaimerMessage": "AmiiboAPI (www.amiiboapi.com) est utilisé\ndans notre émulation Amiibo.", "AboutAmiiboDisclaimerMessage": "AmiiboAPI (www.amiiboapi.com) est utilisé\ndans notre émulation Amiibo.",
"AboutPatreonUrlTooltipMessage": "Cliquez pour ouvrir la page Patreon de Ryujinx dans votre navigateur par défaut.",
"AboutGithubUrlTooltipMessage": "Cliquez pour ouvrir la page GitHub de Ryujinx dans votre navigateur par défaut.", "AboutGithubUrlTooltipMessage": "Cliquez pour ouvrir la page GitHub de Ryujinx dans votre navigateur par défaut.",
"AboutDiscordUrlTooltipMessage": "Cliquez pour ouvrir une invitation au serveur Discord de Ryujinx dans votre navigateur par défaut.", "AboutDiscordUrlTooltipMessage": "Cliquez pour ouvrir une invitation au serveur Discord de Ryujinx dans votre navigateur par défaut.",
"AboutTwitterUrlTooltipMessage": "Cliquez pour ouvrir la page Twitter de Ryujinx dans votre navigateur par défaut.",
"AboutRyujinxAboutTitle": "À propos :", "AboutRyujinxAboutTitle": "À propos :",
"AboutRyujinxAboutContent": "Ryujinx est un émulateur pour la Nintendo Switch™.\nMerci de nous soutenir sur Patreon.\nObtenez toutes les dernières actualités sur notre Twitter ou notre Discord.\nLes développeurs intéressés à contribuer peuvent en savoir plus sur notre GitHub ou notre Discord.", "AboutRyujinxAboutContent": "Ryujinx is an emulator for the Nintendo Switch™.\nGet all the latest news in our Discord.\nDevelopers interested in contributing can find out more on our GitHub or Discord.",
"AboutRyujinxMaintainersTitle": "Maintenu par :", "AboutRyujinxMaintainersTitle": "Maintenu par :",
"AboutRyujinxFormerMaintainersTitle": "Formerly Maintained By:",
"AboutRyujinxMaintainersContentTooltipMessage": "Cliquez pour ouvrir la page Contributeurs dans votre navigateur par défaut.", "AboutRyujinxMaintainersContentTooltipMessage": "Cliquez pour ouvrir la page Contributeurs dans votre navigateur par défaut.",
"AboutRyujinxSupprtersTitle": "Supporté sur Patreon par :",
"AmiiboSeriesLabel": "Séries Amiibo", "AmiiboSeriesLabel": "Séries Amiibo",
"AmiiboCharacterLabel": "Personnage", "AmiiboCharacterLabel": "Personnage",
"AmiiboScanButtonLabel": "Scanner", "AmiiboScanButtonLabel": "Scanner",

View File

@@ -552,15 +552,13 @@
"AboutUrlTooltipMessage": "לחץ כדי לפתוח את אתר ריוג'ינקס בדפדפן ברירת המחדל שלך.", "AboutUrlTooltipMessage": "לחץ כדי לפתוח את אתר ריוג'ינקס בדפדפן ברירת המחדל שלך.",
"AboutDisclaimerMessage": "ריוג'ינקס אינה מזוהת עם נינטנדו,\nאו שוטפייה בכל דרך שהיא.", "AboutDisclaimerMessage": "ריוג'ינקס אינה מזוהת עם נינטנדו,\nאו שוטפייה בכל דרך שהיא.",
"AboutAmiiboDisclaimerMessage": "ממשק אמיבו (www.amiiboapi.com) משומש בהדמיית האמיבו שלנו.", "AboutAmiiboDisclaimerMessage": "ממשק אמיבו (www.amiiboapi.com) משומש בהדמיית האמיבו שלנו.",
"AboutPatreonUrlTooltipMessage": "לחץ כדי לפתוח את דף הפטראון של ריוג'ינקס בדפדפן ברירת המחדל שלך.",
"AboutGithubUrlTooltipMessage": "לחץ כדי לפתוח את דף הגיטהב של ריוג'ינקס בדפדפן ברירת המחדל שלך.", "AboutGithubUrlTooltipMessage": "לחץ כדי לפתוח את דף הגיטהב של ריוג'ינקס בדפדפן ברירת המחדל שלך.",
"AboutDiscordUrlTooltipMessage": "לחץ כדי לפתוח הזמנה לשרת הדיסקורד של ריוג'ינקס בדפדפן ברירת המחדל שלך.", "AboutDiscordUrlTooltipMessage": "לחץ כדי לפתוח הזמנה לשרת הדיסקורד של ריוג'ינקס בדפדפן ברירת המחדל שלך.",
"AboutTwitterUrlTooltipMessage": "לחץ כדי לפתוח את דף הטוויטר של Ryujinx בדפדפן ברירת המחדל שלך.",
"AboutRyujinxAboutTitle": "אודות:", "AboutRyujinxAboutTitle": "אודות:",
"AboutRyujinxAboutContent": "ריוג'ינקס הוא אמולטור עבור הנינטנדו סוויץ' (כל הזכויות שמורות).\nבבקשה תתמכו בנו בפטראון.\nקבל את כל החדשות האחרונות בטוויטר או בדיסקורד שלנו.\nמפתחים המעוניינים לתרום יכולים לקבל מידע נוסף ב-גיטהאב או ב-דיסקורד שלנו.", "AboutRyujinxAboutContent": "Ryujinx is an emulator for the Nintendo Switch™.\nGet all the latest news in our Discord.\nDevelopers interested in contributing can find out more on our GitHub or Discord.",
"AboutRyujinxMaintainersTitle": "מתוחזק על ידי:", "AboutRyujinxMaintainersTitle": "מתוחזק על ידי:",
"AboutRyujinxFormerMaintainersTitle": "Formerly Maintained By:",
"AboutRyujinxMaintainersContentTooltipMessage": "לחץ כדי לפתוח את דף התורמים בדפדפן ברירת המחדל שלך.", "AboutRyujinxMaintainersContentTooltipMessage": "לחץ כדי לפתוח את דף התורמים בדפדפן ברירת המחדל שלך.",
"AboutRyujinxSupprtersTitle": "תמוך באמצעות Patreon",
"AmiiboSeriesLabel": "סדרת אמיבו", "AmiiboSeriesLabel": "סדרת אמיבו",
"AmiiboCharacterLabel": "דמות", "AmiiboCharacterLabel": "דמות",
"AmiiboScanButtonLabel": "סרוק את זה", "AmiiboScanButtonLabel": "סרוק את זה",

View File

@@ -552,15 +552,13 @@
"AboutUrlTooltipMessage": "Clicca per aprire il sito web di Ryujinx nel tuo browser predefinito.", "AboutUrlTooltipMessage": "Clicca per aprire il sito web di Ryujinx nel tuo browser predefinito.",
"AboutDisclaimerMessage": "Ryujinx non è affiliato con Nintendo™,\no i suoi partner, in alcun modo.", "AboutDisclaimerMessage": "Ryujinx non è affiliato con Nintendo™,\no i suoi partner, in alcun modo.",
"AboutAmiiboDisclaimerMessage": "AmiiboAPI (www.amiiboapi.com) è usata\nnella nostra emulazione Amiibo.", "AboutAmiiboDisclaimerMessage": "AmiiboAPI (www.amiiboapi.com) è usata\nnella nostra emulazione Amiibo.",
"AboutPatreonUrlTooltipMessage": "Clicca per aprire la pagina Patreon di Ryujinx nel tuo browser predefinito.",
"AboutGithubUrlTooltipMessage": "Clicca per aprire la pagina GitHub di Ryujinx nel tuo browser predefinito.", "AboutGithubUrlTooltipMessage": "Clicca per aprire la pagina GitHub di Ryujinx nel tuo browser predefinito.",
"AboutDiscordUrlTooltipMessage": "Clicca per aprire un invito al server Discord di Ryujinx nel tuo browser predefinito.", "AboutDiscordUrlTooltipMessage": "Clicca per aprire un invito al server Discord di Ryujinx nel tuo browser predefinito.",
"AboutTwitterUrlTooltipMessage": "Clicca per aprire la pagina Twitter di Ryujinx nel tuo browser predefinito.",
"AboutRyujinxAboutTitle": "Informazioni:", "AboutRyujinxAboutTitle": "Informazioni:",
"AboutRyujinxAboutContent": "Ryujinx è un emulatore per la console Nintendo Switch™.\nSostienici su Patreon.\nRicevi tutte le ultime notizie sul nostro Twitter o su Discord.\nGli sviluppatori interessati a contribuire possono trovare più informazioni sul nostro GitHub o Discord.", "AboutRyujinxAboutContent": "Ryujinx is an emulator for the Nintendo Switch™.\nGet all the latest news in our Discord.\nDevelopers interested in contributing can find out more on our GitHub or Discord.",
"AboutRyujinxMaintainersTitle": "Mantenuto da:", "AboutRyujinxMaintainersTitle": "Mantenuto da:",
"AboutRyujinxFormerMaintainersTitle": "Formerly Maintained By:",
"AboutRyujinxMaintainersContentTooltipMessage": "Clicca per aprire la pagina dei contributori nel tuo browser predefinito.", "AboutRyujinxMaintainersContentTooltipMessage": "Clicca per aprire la pagina dei contributori nel tuo browser predefinito.",
"AboutRyujinxSupprtersTitle": "Supportato su Patreon da:",
"AmiiboSeriesLabel": "Serie Amiibo", "AmiiboSeriesLabel": "Serie Amiibo",
"AmiiboCharacterLabel": "Personaggio", "AmiiboCharacterLabel": "Personaggio",
"AmiiboScanButtonLabel": "Scansiona", "AmiiboScanButtonLabel": "Scansiona",

View File

@@ -552,15 +552,13 @@
"AboutUrlTooltipMessage": "クリックするとデフォルトのブラウザで Ryujinx のウェブサイトを開きます.", "AboutUrlTooltipMessage": "クリックするとデフォルトのブラウザで Ryujinx のウェブサイトを開きます.",
"AboutDisclaimerMessage": "Ryujinx は Nintendo™ および\nそのパートナー企業とは一切関係ありません.", "AboutDisclaimerMessage": "Ryujinx は Nintendo™ および\nそのパートナー企業とは一切関係ありません.",
"AboutAmiiboDisclaimerMessage": "AmiiboAPI (www.amiiboapi.com) は\nAmiibo エミュレーションに使用されています.", "AboutAmiiboDisclaimerMessage": "AmiiboAPI (www.amiiboapi.com) は\nAmiibo エミュレーションに使用されています.",
"AboutPatreonUrlTooltipMessage": "クリックするとデフォルトのブラウザで Ryujinx の Patreon ページを開きます.",
"AboutGithubUrlTooltipMessage": "クリックするとデフォルトのブラウザで Ryujinx の Github ページを開きます.", "AboutGithubUrlTooltipMessage": "クリックするとデフォルトのブラウザで Ryujinx の Github ページを開きます.",
"AboutDiscordUrlTooltipMessage": "クリックするとデフォルトのブラウザで Ryujinx の Discord サーバを開きます.", "AboutDiscordUrlTooltipMessage": "クリックするとデフォルトのブラウザで Ryujinx の Discord サーバを開きます.",
"AboutTwitterUrlTooltipMessage": "クリックするとデフォルトのブラウザで Ryujinx の Twitter ページを開きます.",
"AboutRyujinxAboutTitle": "Ryujinx について:", "AboutRyujinxAboutTitle": "Ryujinx について:",
"AboutRyujinxAboutContent": "Ryujinx は Nintendo Switch™ のエミュレータです.\nPatreon で私達の活動を支援してください.\n最新の情報は Twitter または Discord から取得できます.\n貢献したい開発者の方は GitHub または Discord で詳細をご確認ください.", "AboutRyujinxAboutContent": "Ryujinx is an emulator for the Nintendo Switch™.\nGet all the latest news in our Discord.\nDevelopers interested in contributing can find out more on our GitHub or Discord.",
"AboutRyujinxMaintainersTitle": "開発者:", "AboutRyujinxMaintainersTitle": "開発者:",
"AboutRyujinxFormerMaintainersTitle": "Formerly Maintained By:",
"AboutRyujinxMaintainersContentTooltipMessage": "クリックするとデフォルトのブラウザで 貢献者のページを開きます.", "AboutRyujinxMaintainersContentTooltipMessage": "クリックするとデフォルトのブラウザで 貢献者のページを開きます.",
"AboutRyujinxSupprtersTitle": "Patreon での支援者:",
"AmiiboSeriesLabel": "Amiibo シリーズ", "AmiiboSeriesLabel": "Amiibo シリーズ",
"AmiiboCharacterLabel": "キャラクタ", "AmiiboCharacterLabel": "キャラクタ",
"AmiiboScanButtonLabel": "スキャン", "AmiiboScanButtonLabel": "スキャン",

View File

@@ -552,15 +552,13 @@
"AboutUrlTooltipMessage": "클릭하면 기본 브라우저에서 Ryujinx 웹사이트가 열립니다.", "AboutUrlTooltipMessage": "클릭하면 기본 브라우저에서 Ryujinx 웹사이트가 열립니다.",
"AboutDisclaimerMessage": "Ryujinx는 Nintendo™\n또는 그 파트너와 제휴한 바가 없습니다.", "AboutDisclaimerMessage": "Ryujinx는 Nintendo™\n또는 그 파트너와 제휴한 바가 없습니다.",
"AboutAmiiboDisclaimerMessage": "AmiiboAPI(www.amiiboapi.com)는\nAmiibo 에뮬레이션에 사용됩니다.", "AboutAmiiboDisclaimerMessage": "AmiiboAPI(www.amiiboapi.com)는\nAmiibo 에뮬레이션에 사용됩니다.",
"AboutPatreonUrlTooltipMessage": "클릭하면 기본 브라우저에서 Ryujinx Patreon 페이지가 열립니다.",
"AboutGithubUrlTooltipMessage": "클릭하면 기본 브라우저에서 Ryujinx GitHub 페이지가 열립니다.", "AboutGithubUrlTooltipMessage": "클릭하면 기본 브라우저에서 Ryujinx GitHub 페이지가 열립니다.",
"AboutDiscordUrlTooltipMessage": "클릭하면 기본 브라우저에서 Ryujinx 디스코드 서버 초대장이 열립니다.", "AboutDiscordUrlTooltipMessage": "클릭하면 기본 브라우저에서 Ryujinx 디스코드 서버 초대장이 열립니다.",
"AboutTwitterUrlTooltipMessage": "클릭하면 기본 브라우저에서 Ryujinx 트위터 페이지가 열립니다.",
"AboutRyujinxAboutTitle": "정보 :", "AboutRyujinxAboutTitle": "정보 :",
"AboutRyujinxAboutContent": "Ryujinx는 Nintendo Switch™용 에뮬레이터입니다.\nPatreon에서 저희를 후원해 주세요.\nTwitter나 Discord에서 최신 뉴스를 모두 받아보세요.\n기여에 관심이 있는 개발자는 GitHub이나 Discord에서 자세한 내용을 알아볼 수 있습니다.", "AboutRyujinxAboutContent": "Ryujinx is an emulator for the Nintendo Switch™.\nGet all the latest news in our Discord.\nDevelopers interested in contributing can find out more on our GitHub or Discord.",
"AboutRyujinxMaintainersTitle": "유지 관리 :", "AboutRyujinxMaintainersTitle": "유지 관리 :",
"AboutRyujinxFormerMaintainersTitle": "Formerly Maintained By:",
"AboutRyujinxMaintainersContentTooltipMessage": "클릭하면 기본 브라우저에서 기여자 페이지가 열립니다.", "AboutRyujinxMaintainersContentTooltipMessage": "클릭하면 기본 브라우저에서 기여자 페이지가 열립니다.",
"AboutRyujinxSupprtersTitle": "Patreon에서 후원 :",
"AmiiboSeriesLabel": "Amiibo 시리즈", "AmiiboSeriesLabel": "Amiibo 시리즈",
"AmiiboCharacterLabel": "캐릭터", "AmiiboCharacterLabel": "캐릭터",
"AmiiboScanButtonLabel": "스캔하기", "AmiiboScanButtonLabel": "스캔하기",

View File

@@ -552,15 +552,13 @@
"AboutUrlTooltipMessage": "Kliknij, aby otworzyć stronę Ryujinx w domyślnej przeglądarce.", "AboutUrlTooltipMessage": "Kliknij, aby otworzyć stronę Ryujinx w domyślnej przeglądarce.",
"AboutDisclaimerMessage": "Ryujinx nie jest w żaden sposób powiązany z Nintendo™,\nani z żadnym z jej partnerów.", "AboutDisclaimerMessage": "Ryujinx nie jest w żaden sposób powiązany z Nintendo™,\nani z żadnym z jej partnerów.",
"AboutAmiiboDisclaimerMessage": "AmiiboAPI (www.amiiboapi.com) jest używane\nw naszej emulacji Amiibo.", "AboutAmiiboDisclaimerMessage": "AmiiboAPI (www.amiiboapi.com) jest używane\nw naszej emulacji Amiibo.",
"AboutPatreonUrlTooltipMessage": "Kliknij, aby otworzyć stronę Patreon Ryujinx w domyślnej przeglądarce.",
"AboutGithubUrlTooltipMessage": "Kliknij, aby otworzyć stronę GitHub Ryujinx w domyślnej przeglądarce.", "AboutGithubUrlTooltipMessage": "Kliknij, aby otworzyć stronę GitHub Ryujinx w domyślnej przeglądarce.",
"AboutDiscordUrlTooltipMessage": "Kliknij, aby otworzyć zaproszenie na serwer Discord Ryujinx w domyślnej przeglądarce.", "AboutDiscordUrlTooltipMessage": "Kliknij, aby otworzyć zaproszenie na serwer Discord Ryujinx w domyślnej przeglądarce.",
"AboutTwitterUrlTooltipMessage": "Kliknij, aby otworzyć stronę Twitter Ryujinx w domyślnej przeglądarce.",
"AboutRyujinxAboutTitle": "O Aplikacji:", "AboutRyujinxAboutTitle": "O Aplikacji:",
"AboutRyujinxAboutContent": "Ryujinx to emulator Nintendo Switch™.\nWspieraj nas na Patreonie.\nOtrzymuj najnowsze wiadomości na naszym Twitterze lub Discordzie.\nDeweloperzy zainteresowani współpracą mogą dowiedzieć się więcej na naszym GitHubie lub Discordzie.", "AboutRyujinxAboutContent": "Ryujinx is an emulator for the Nintendo Switch™.\nGet all the latest news in our Discord.\nDevelopers interested in contributing can find out more on our GitHub or Discord.",
"AboutRyujinxMaintainersTitle": "Utrzymywany Przez:", "AboutRyujinxMaintainersTitle": "Utrzymywany Przez:",
"AboutRyujinxFormerMaintainersTitle": "Formerly Maintained By:",
"AboutRyujinxMaintainersContentTooltipMessage": "Kliknij, aby otworzyć stronę Współtwórcy w domyślnej przeglądarce.", "AboutRyujinxMaintainersContentTooltipMessage": "Kliknij, aby otworzyć stronę Współtwórcy w domyślnej przeglądarce.",
"AboutRyujinxSupprtersTitle": "Wspierani na Patreonie Przez:",
"AmiiboSeriesLabel": "Seria Amiibo", "AmiiboSeriesLabel": "Seria Amiibo",
"AmiiboCharacterLabel": "Postać", "AmiiboCharacterLabel": "Postać",
"AmiiboScanButtonLabel": "Zeskanuj", "AmiiboScanButtonLabel": "Zeskanuj",

View File

@@ -552,15 +552,13 @@
"AboutUrlTooltipMessage": "Clique para abrir o site do Ryujinx no seu navegador padrão.", "AboutUrlTooltipMessage": "Clique para abrir o site do Ryujinx no seu navegador padrão.",
"AboutDisclaimerMessage": "Ryujinx não é afiliado com a Nintendo™,\nou qualquer um de seus parceiros, de nenhum modo.", "AboutDisclaimerMessage": "Ryujinx não é afiliado com a Nintendo™,\nou qualquer um de seus parceiros, de nenhum modo.",
"AboutAmiiboDisclaimerMessage": "AmiiboAPI (www.amiiboapi.com) é usado\nem nossa emulação de Amiibo.", "AboutAmiiboDisclaimerMessage": "AmiiboAPI (www.amiiboapi.com) é usado\nem nossa emulação de Amiibo.",
"AboutPatreonUrlTooltipMessage": "Clique para abrir a página do Patreon do Ryujinx no seu navegador padrão.",
"AboutGithubUrlTooltipMessage": "Clique para abrir a página do GitHub do Ryujinx no seu navegador padrão.", "AboutGithubUrlTooltipMessage": "Clique para abrir a página do GitHub do Ryujinx no seu navegador padrão.",
"AboutDiscordUrlTooltipMessage": "Clique para abrir um convite ao servidor do Discord do Ryujinx no seu navegador padrão.", "AboutDiscordUrlTooltipMessage": "Clique para abrir um convite ao servidor do Discord do Ryujinx no seu navegador padrão.",
"AboutTwitterUrlTooltipMessage": "Clique para abrir a página do Twitter do Ryujinx no seu navegador padrão.",
"AboutRyujinxAboutTitle": "Sobre:", "AboutRyujinxAboutTitle": "Sobre:",
"AboutRyujinxAboutContent": "Ryujinx é um emulador de Nintendo Switch™.\nPor favor, nos dê apoio no Patreon.\nFique por dentro de todas as novidades no Twitter ou Discord.\nDesenvolvedores com interesse em contribuir podem conseguir mais informações no GitHub ou Discord.", "AboutRyujinxAboutContent": "Ryujinx is an emulator for the Nintendo Switch™.\nGet all the latest news in our Discord.\nDevelopers interested in contributing can find out more on our GitHub or Discord.",
"AboutRyujinxMaintainersTitle": "Mantido por:", "AboutRyujinxMaintainersTitle": "Mantido por:",
"AboutRyujinxFormerMaintainersTitle": "Formerly Maintained By:",
"AboutRyujinxMaintainersContentTooltipMessage": "Clique para abrir a página de contribuidores no seu navegador padrão.", "AboutRyujinxMaintainersContentTooltipMessage": "Clique para abrir a página de contribuidores no seu navegador padrão.",
"AboutRyujinxSupprtersTitle": "Apoiado no Patreon por:",
"AmiiboSeriesLabel": "Franquia Amiibo", "AmiiboSeriesLabel": "Franquia Amiibo",
"AmiiboCharacterLabel": "Personagem", "AmiiboCharacterLabel": "Personagem",
"AmiiboScanButtonLabel": "Escanear", "AmiiboScanButtonLabel": "Escanear",

View File

@@ -552,15 +552,13 @@
"AboutUrlTooltipMessage": "Нажмите, чтобы открыть веб-сайт Ryujinx", "AboutUrlTooltipMessage": "Нажмите, чтобы открыть веб-сайт Ryujinx",
"AboutDisclaimerMessage": "Ryujinx никоим образом не связан ни с Nintendo™, ни с кем-либо из ее партнеров.", "AboutDisclaimerMessage": "Ryujinx никоим образом не связан ни с Nintendo™, ни с кем-либо из ее партнеров.",
"AboutAmiiboDisclaimerMessage": "Amiibo API (www.amiiboapi.com) используется для эмуляции Amiibo.", "AboutAmiiboDisclaimerMessage": "Amiibo API (www.amiiboapi.com) используется для эмуляции Amiibo.",
"AboutPatreonUrlTooltipMessage": "Нажмите, чтобы открыть страницу Ryujinx на Patreon",
"AboutGithubUrlTooltipMessage": "Нажмите, чтобы открыть страницу Ryujinx на GitHub", "AboutGithubUrlTooltipMessage": "Нажмите, чтобы открыть страницу Ryujinx на GitHub",
"AboutDiscordUrlTooltipMessage": "Нажмите, чтобы открыть приглашение на сервер Ryujinx в Discord", "AboutDiscordUrlTooltipMessage": "Нажмите, чтобы открыть приглашение на сервер Ryujinx в Discord",
"AboutTwitterUrlTooltipMessage": "Нажмите, чтобы открыть страницу Ryujinx в X (бывший Twitter)",
"AboutRyujinxAboutTitle": "О программе:", "AboutRyujinxAboutTitle": "О программе:",
"AboutRyujinxAboutContent": "Ryujinx — это эмулятор Nintendo Switch™.\nПожалуйста, поддержите нас на Patreon.\nЧитайте последние новости в наших X (Twitter) или Discord.\nРазработчики, заинтересованные в участии, могут ознакомиться с проектом на GitHub или в Discord.", "AboutRyujinxAboutContent": "Ryujinx is an emulator for the Nintendo Switch™.\nGet all the latest news in our Discord.\nDevelopers interested in contributing can find out more on our GitHub or Discord.",
"AboutRyujinxMaintainersTitle": "Разработка:", "AboutRyujinxMaintainersTitle": "Разработка:",
"AboutRyujinxFormerMaintainersTitle": "Formerly Maintained By:",
"AboutRyujinxMaintainersContentTooltipMessage": "Нажмите, чтобы открыть страницу с участниками", "AboutRyujinxMaintainersContentTooltipMessage": "Нажмите, чтобы открыть страницу с участниками",
"AboutRyujinxSupprtersTitle": "Поддержка на Patreon:",
"AmiiboSeriesLabel": "Серия Amiibo", "AmiiboSeriesLabel": "Серия Amiibo",
"AmiiboCharacterLabel": "Персонаж", "AmiiboCharacterLabel": "Персонаж",
"AmiiboScanButtonLabel": "Сканировать", "AmiiboScanButtonLabel": "Сканировать",

View File

@@ -552,15 +552,13 @@
"AboutUrlTooltipMessage": "คลิกเพื่อเปิดเว็บไซต์ Ryujinx บนเบราว์เซอร์เริ่มต้นของคุณ", "AboutUrlTooltipMessage": "คลิกเพื่อเปิดเว็บไซต์ Ryujinx บนเบราว์เซอร์เริ่มต้นของคุณ",
"AboutDisclaimerMessage": "ทางผู้พัฒนาโปรแกรม Ryujinx ไม่มีส่วนเกี่ยวข้องกับทางบริษัท Nintendo™\nหรือพันธมิตรใดๆ ทั้งสิ้น!", "AboutDisclaimerMessage": "ทางผู้พัฒนาโปรแกรม Ryujinx ไม่มีส่วนเกี่ยวข้องกับทางบริษัท Nintendo™\nหรือพันธมิตรใดๆ ทั้งสิ้น!",
"AboutAmiiboDisclaimerMessage": "AmiiboAPI (www.amiiboapi.com) ถูกใช้\nในการจำลอง อะมิโบ ของเรา", "AboutAmiiboDisclaimerMessage": "AmiiboAPI (www.amiiboapi.com) ถูกใช้\nในการจำลอง อะมิโบ ของเรา",
"AboutPatreonUrlTooltipMessage": "คลิกเพื่อเปิดหน้า Patreon ของ Ryujinx บนเบราว์เซอร์เริ่มต้นของคุณ",
"AboutGithubUrlTooltipMessage": "คลิกเพื่อเปิดหน้า Github ของ Ryujinx บนเบราว์เซอร์เริ่มต้นของคุณ", "AboutGithubUrlTooltipMessage": "คลิกเพื่อเปิดหน้า Github ของ Ryujinx บนเบราว์เซอร์เริ่มต้นของคุณ",
"AboutDiscordUrlTooltipMessage": "คลิกเพื่อเปิดคำเชิญเข้าสู่เซิร์ฟเวอร์ Discord ของ Ryujinx บนเบราว์เซอร์เริ่มต้นของคุณ", "AboutDiscordUrlTooltipMessage": "คลิกเพื่อเปิดคำเชิญเข้าสู่เซิร์ฟเวอร์ Discord ของ Ryujinx บนเบราว์เซอร์เริ่มต้นของคุณ",
"AboutTwitterUrlTooltipMessage": "คลิกเพื่อเปิดหน้าเพจ Twitter ของ Ryujinx บนเบราว์เซอร์เริ่มต้นของคุณ",
"AboutRyujinxAboutTitle": "เกี่ยวกับ:", "AboutRyujinxAboutTitle": "เกี่ยวกับ:",
"AboutRyujinxAboutContent": "Ryujinx เป็นอีมูเลเตอร์สำหรับ Nintendo Switch™\nโปรดสนับสนุนเราบน Patreon\nรับข่าวสารล่าสุดทั้งหมดบน Twitter หรือ Discord ของเรา\nนักพัฒนาที่สนใจจะมีส่วนร่วมสามารถดูข้อมูลเพิ่มเติมได้ที่ GitHub หรือ Discord ของเรา", "AboutRyujinxAboutContent": "Ryujinx is an emulator for the Nintendo Switch™.\nGet all the latest news in our Discord.\nDevelopers interested in contributing can find out more on our GitHub or Discord.",
"AboutRyujinxMaintainersTitle": "ได้รับการดูแลโดย:", "AboutRyujinxMaintainersTitle": "ได้รับการดูแลโดย:",
"AboutRyujinxFormerMaintainersTitle": "Formerly Maintained By:",
"AboutRyujinxMaintainersContentTooltipMessage": "คลิกเพื่อเปิดหน้าผู้มีส่วนร่วมบนเบราว์เซอร์เริ่มต้นของคุณ", "AboutRyujinxMaintainersContentTooltipMessage": "คลิกเพื่อเปิดหน้าผู้มีส่วนร่วมบนเบราว์เซอร์เริ่มต้นของคุณ",
"AboutRyujinxSupprtersTitle": "ผู้สนับสนุนบน Patreon:",
"AmiiboSeriesLabel": "Amiibo Series", "AmiiboSeriesLabel": "Amiibo Series",
"AmiiboCharacterLabel": "ตัวละคร", "AmiiboCharacterLabel": "ตัวละคร",
"AmiiboScanButtonLabel": "สแกนเลย", "AmiiboScanButtonLabel": "สแกนเลย",

View File

@@ -552,15 +552,13 @@
"AboutUrlTooltipMessage": "Ryujinx'in websitesini varsayılan tarayıcınızda açmak için tıklayın.", "AboutUrlTooltipMessage": "Ryujinx'in websitesini varsayılan tarayıcınızda açmak için tıklayın.",
"AboutDisclaimerMessage": "Ryujinx, Nintendo™ veya ortaklarıyla herhangi bir şekilde bağlantılı değildir.", "AboutDisclaimerMessage": "Ryujinx, Nintendo™ veya ortaklarıyla herhangi bir şekilde bağlantılı değildir.",
"AboutAmiiboDisclaimerMessage": "Amiibo emülasyonumuzda \nAmiiboAPI (www.amiiboapi.com) kullanılmaktadır.", "AboutAmiiboDisclaimerMessage": "Amiibo emülasyonumuzda \nAmiiboAPI (www.amiiboapi.com) kullanılmaktadır.",
"AboutPatreonUrlTooltipMessage": "Ryujinx'in Patreon sayfasını varsayılan tarayıcınızda açmak için tıklayın.",
"AboutGithubUrlTooltipMessage": "Ryujinx'in GitHub sayfasını varsayılan tarayıcınızda açmak için tıklayın.", "AboutGithubUrlTooltipMessage": "Ryujinx'in GitHub sayfasını varsayılan tarayıcınızda açmak için tıklayın.",
"AboutDiscordUrlTooltipMessage": "Varsayılan tarayıcınızda Ryujinx'in Discord'una bir davet açmak için tıklayın.", "AboutDiscordUrlTooltipMessage": "Varsayılan tarayıcınızda Ryujinx'in Discord'una bir davet açmak için tıklayın.",
"AboutTwitterUrlTooltipMessage": "Ryujinx'in Twitter sayfasını varsayılan tarayıcınızda açmak için tıklayın.",
"AboutRyujinxAboutTitle": "Hakkında:", "AboutRyujinxAboutTitle": "Hakkında:",
"AboutRyujinxAboutContent": "Ryujinx bir Nintendo Switch™ emülatörüdür.\nLütfen bizi Patreon'da destekleyin.\nEn son haberleri Twitter veya Discord'umuzdan alın.\nKatkıda bulunmak isteyen geliştiriciler GitHub veya Discord üzerinden daha fazla bilgi edinebilir.", "AboutRyujinxAboutContent": "Ryujinx is an emulator for the Nintendo Switch™.\nGet all the latest news in our Discord.\nDevelopers interested in contributing can find out more on our GitHub or Discord.",
"AboutRyujinxMaintainersTitle": "Geliştiriciler:", "AboutRyujinxMaintainersTitle": "Geliştiriciler:",
"AboutRyujinxFormerMaintainersTitle": "Formerly Maintained By:",
"AboutRyujinxMaintainersContentTooltipMessage": "Katkıda bulunanlar sayfasını varsayılan tarayıcınızda açmak için tıklayın.", "AboutRyujinxMaintainersContentTooltipMessage": "Katkıda bulunanlar sayfasını varsayılan tarayıcınızda açmak için tıklayın.",
"AboutRyujinxSupprtersTitle": "Patreon Destekleyicileri:",
"AmiiboSeriesLabel": "Amiibo Serisi", "AmiiboSeriesLabel": "Amiibo Serisi",
"AmiiboCharacterLabel": "Karakter", "AmiiboCharacterLabel": "Karakter",
"AmiiboScanButtonLabel": "Tarat", "AmiiboScanButtonLabel": "Tarat",

View File

@@ -552,15 +552,13 @@
"AboutUrlTooltipMessage": "Натисніть, щоб відкрити сайт Ryujinx у браузері за замовчування.", "AboutUrlTooltipMessage": "Натисніть, щоб відкрити сайт Ryujinx у браузері за замовчування.",
"AboutDisclaimerMessage": "Ryujinx жодним чином не пов’язано з Nintendo™,\nчи будь-яким із їхніх партнерів.", "AboutDisclaimerMessage": "Ryujinx жодним чином не пов’язано з Nintendo™,\nчи будь-яким із їхніх партнерів.",
"AboutAmiiboDisclaimerMessage": "AmiiboAPI (www.amiiboapi.com) використовується в нашій емуляції Amiibo.", "AboutAmiiboDisclaimerMessage": "AmiiboAPI (www.amiiboapi.com) використовується в нашій емуляції Amiibo.",
"AboutPatreonUrlTooltipMessage": "Натисніть, щоб відкрити сторінку Patreon Ryujinx у вашому браузері за замовчування.",
"AboutGithubUrlTooltipMessage": "Натисніть, щоб відкрити сторінку GitHub Ryujinx у браузері за замовчуванням.", "AboutGithubUrlTooltipMessage": "Натисніть, щоб відкрити сторінку GitHub Ryujinx у браузері за замовчуванням.",
"AboutDiscordUrlTooltipMessage": "Натисніть, щоб відкрити запрошення на сервер Discord Ryujinx у браузері за замовчуванням.", "AboutDiscordUrlTooltipMessage": "Натисніть, щоб відкрити запрошення на сервер Discord Ryujinx у браузері за замовчуванням.",
"AboutTwitterUrlTooltipMessage": "Натисніть, щоб відкрити сторінку Twitter Ryujinx у браузері за замовчуванням.",
"AboutRyujinxAboutTitle": "Про програму:", "AboutRyujinxAboutTitle": "Про програму:",
"AboutRyujinxAboutContent": "Ryujinx — це емулятор для Nintendo Switch™.\nБудь ласка, підтримайте нас на Patreon.\nОтримуйте всі останні новини в нашому Twitter або Discord.\nРозробники, які хочуть зробити внесок, можуть дізнатися більше на нашому GitHub або в Discord.", "AboutRyujinxAboutContent": "Ryujinx is an emulator for the Nintendo Switch™.\nGet all the latest news in our Discord.\nDevelopers interested in contributing can find out more on our GitHub or Discord.",
"AboutRyujinxMaintainersTitle": "Підтримується:", "AboutRyujinxMaintainersTitle": "Підтримується:",
"AboutRyujinxFormerMaintainersTitle": "Formerly Maintained By:",
"AboutRyujinxMaintainersContentTooltipMessage": "Натисніть, щоб відкрити сторінку співавторів у вашому браузері за замовчування.", "AboutRyujinxMaintainersContentTooltipMessage": "Натисніть, щоб відкрити сторінку співавторів у вашому браузері за замовчування.",
"AboutRyujinxSupprtersTitle": "Підтримується на Patreon:",
"AmiiboSeriesLabel": "Серія Amiibo", "AmiiboSeriesLabel": "Серія Amiibo",
"AmiiboCharacterLabel": "Персонаж", "AmiiboCharacterLabel": "Персонаж",
"AmiiboScanButtonLabel": "Сканувати", "AmiiboScanButtonLabel": "Сканувати",

View File

@@ -552,15 +552,13 @@
"AboutUrlTooltipMessage": "在浏览器中打开 Ryujinx 模拟器官网。", "AboutUrlTooltipMessage": "在浏览器中打开 Ryujinx 模拟器官网。",
"AboutDisclaimerMessage": "Ryujinx 与 Nintendo™ 以及其合作伙伴没有任何关联。", "AboutDisclaimerMessage": "Ryujinx 与 Nintendo™ 以及其合作伙伴没有任何关联。",
"AboutAmiiboDisclaimerMessage": "我们的 Amiibo 模拟使用了\nAmiiboAPI (www.amiiboapi.com)。", "AboutAmiiboDisclaimerMessage": "我们的 Amiibo 模拟使用了\nAmiiboAPI (www.amiiboapi.com)。",
"AboutPatreonUrlTooltipMessage": "在浏览器中打开 Ryujinx 的 Patreon 赞助页。",
"AboutGithubUrlTooltipMessage": "在浏览器中打开 Ryujinx 的 GitHub 代码库。", "AboutGithubUrlTooltipMessage": "在浏览器中打开 Ryujinx 的 GitHub 代码库。",
"AboutDiscordUrlTooltipMessage": "在浏览器中打开 Ryujinx 的 Discord 邀请链接。", "AboutDiscordUrlTooltipMessage": "在浏览器中打开 Ryujinx 的 Discord 邀请链接。",
"AboutTwitterUrlTooltipMessage": "在浏览器中打开 Ryujinx 的 Twitter 主页。",
"AboutRyujinxAboutTitle": "关于:", "AboutRyujinxAboutTitle": "关于:",
"AboutRyujinxAboutContent": "Ryujinx 是一款 Nintendo Switch™ 模拟器。\n您可以在 Patreon 上赞助 Ryujinx。\n关注 Twitter 或 Discord 可以获取模拟器最新动态。\n如果您对开发感兴趣欢迎来 GitHub Discord 加入我们!", "AboutRyujinxAboutContent": "Ryujinx is an emulator for the Nintendo Switch™.\nGet all the latest news in our Discord.\nDevelopers interested in contributing can find out more on our GitHub or Discord.",
"AboutRyujinxMaintainersTitle": "开发维护人员名单:", "AboutRyujinxMaintainersTitle": "开发维护人员名单:",
"AboutRyujinxFormerMaintainersTitle": "Formerly Maintained By:",
"AboutRyujinxMaintainersContentTooltipMessage": "在浏览器中打开贡献者页面", "AboutRyujinxMaintainersContentTooltipMessage": "在浏览器中打开贡献者页面",
"AboutRyujinxSupprtersTitle": "感谢 Patreon 上的赞助者:",
"AmiiboSeriesLabel": "Amiibo 系列", "AmiiboSeriesLabel": "Amiibo 系列",
"AmiiboCharacterLabel": "角色", "AmiiboCharacterLabel": "角色",
"AmiiboScanButtonLabel": "扫描", "AmiiboScanButtonLabel": "扫描",

View File

@@ -552,15 +552,13 @@
"AboutUrlTooltipMessage": "在預設瀏覽器中開啟 Ryujinx 網站。", "AboutUrlTooltipMessage": "在預設瀏覽器中開啟 Ryujinx 網站。",
"AboutDisclaimerMessage": "Ryujinx 和 Nintendo™\n或其任何合作夥伴完全沒有關聯。", "AboutDisclaimerMessage": "Ryujinx 和 Nintendo™\n或其任何合作夥伴完全沒有關聯。",
"AboutAmiiboDisclaimerMessage": "我們在 Amiibo 模擬中\n使用了 AmiiboAPI (www.amiiboapi.com)。", "AboutAmiiboDisclaimerMessage": "我們在 Amiibo 模擬中\n使用了 AmiiboAPI (www.amiiboapi.com)。",
"AboutPatreonUrlTooltipMessage": "在預設瀏覽器中開啟 Ryujinx 的 Patreon 網頁。",
"AboutGithubUrlTooltipMessage": "在預設瀏覽器中開啟 Ryujinx 的 GitHub 網頁。", "AboutGithubUrlTooltipMessage": "在預設瀏覽器中開啟 Ryujinx 的 GitHub 網頁。",
"AboutDiscordUrlTooltipMessage": "在預設瀏覽器中開啟 Ryujinx 的 Discord 邀請連結。", "AboutDiscordUrlTooltipMessage": "在預設瀏覽器中開啟 Ryujinx 的 Discord 邀請連結。",
"AboutTwitterUrlTooltipMessage": "在預設瀏覽器中開啟 Ryujinx 的 Twitter 網頁。",
"AboutRyujinxAboutTitle": "關於:", "AboutRyujinxAboutTitle": "關於:",
"AboutRyujinxAboutContent": "Ryujinx 是一款 Nintendo Switch™ 模擬器。\n請在 Patreon 上支持我們。\n關注我們的 Twitter 或 Discord 取得所有最新消息。\n對於有興趣貢獻的開發者可以在我們的 GitHub Discord 上了解更多資訊。", "AboutRyujinxAboutContent": "Ryujinx is an emulator for the Nintendo Switch™.\nGet all the latest news in our Discord.\nDevelopers interested in contributing can find out more on our GitHub or Discord.",
"AboutRyujinxMaintainersTitle": "維護者:", "AboutRyujinxMaintainersTitle": "維護者:",
"AboutRyujinxFormerMaintainersTitle": "Formerly Maintained By:",
"AboutRyujinxMaintainersContentTooltipMessage": "在預設瀏覽器中開啟貢獻者的網頁", "AboutRyujinxMaintainersContentTooltipMessage": "在預設瀏覽器中開啟貢獻者的網頁",
"AboutRyujinxSupprtersTitle": "Patreon 支持者:",
"AmiiboSeriesLabel": "Amiibo 系列", "AmiiboSeriesLabel": "Amiibo 系列",
"AmiiboCharacterLabel": "角色", "AmiiboCharacterLabel": "角色",
"AmiiboScanButtonLabel": "掃描", "AmiiboScanButtonLabel": "掃描",

View File

@@ -4,18 +4,6 @@
<ResourceDictionary x:Key="Default"> <ResourceDictionary x:Key="Default">
<SolidColorBrush x:Key="DataGridSelectionBackgroundBrush" <SolidColorBrush x:Key="DataGridSelectionBackgroundBrush"
Color="{DynamicResource DataGridSelectionColor}" /> Color="{DynamicResource DataGridSelectionColor}" />
<SolidColorBrush x:Key="ThemeAccentColorBrush"
Color="{DynamicResource SystemAccentColor}" />
<SolidColorBrush x:Key="ThemeAccentBrush4"
Color="{DynamicResource ThemeAccentColor4}" />
<Color x:Key="SystemAccentColor">#FF00C3E3</Color>
<Color x:Key="SystemAccentColorDark1">#FF00C3E3</Color>
<Color x:Key="SystemAccentColorDark2">#FF00C3E3</Color>
<Color x:Key="SystemAccentColorDark3">#FF00C3E3</Color>
<Color x:Key="SystemAccentColorLight1">#FF00C3E3</Color>
<Color x:Key="SystemAccentColorLight2">#FF00C3E3</Color>
<Color x:Key="SystemAccentColorLight3">#FF00C3E3</Color>
<Color x:Key="ThemeAccentColor4">#FFe8e8e8</Color>
<Color x:Key="DataGridSelectionColor">#FF00FABB</Color> <Color x:Key="DataGridSelectionColor">#FF00FABB</Color>
<Color x:Key="ThemeContentBackgroundColor">#FFF0F0F0</Color> <Color x:Key="ThemeContentBackgroundColor">#FFF0F0F0</Color>
<Color x:Key="ThemeControlBorderColor">#FFd6d6d6</Color> <Color x:Key="ThemeControlBorderColor">#FFd6d6d6</Color>
@@ -26,6 +14,7 @@
<Color x:Key="AppListBackgroundColor">#b3ffffff</Color> <Color x:Key="AppListBackgroundColor">#b3ffffff</Color>
<Color x:Key="AppListHoverBackgroundColor">#80cccccc</Color> <Color x:Key="AppListHoverBackgroundColor">#80cccccc</Color>
<Color x:Key="SecondaryTextColor">#A0000000</Color> <Color x:Key="SecondaryTextColor">#A0000000</Color>
<Color x:Key="FavoriteApplicationIconColor">#fffcd12a</Color>
<Color x:Key="Switch">#FF2EEAC9</Color> <Color x:Key="Switch">#FF2EEAC9</Color>
<Color x:Key="Unbounded">#FFFF4554</Color> <Color x:Key="Unbounded">#FFFF4554</Color>
<Color x:Key="Custom">#6483F5</Color> <Color x:Key="Custom">#6483F5</Color>
@@ -33,18 +22,6 @@
<ResourceDictionary x:Key="Light"> <ResourceDictionary x:Key="Light">
<SolidColorBrush x:Key="DataGridSelectionBackgroundBrush" <SolidColorBrush x:Key="DataGridSelectionBackgroundBrush"
Color="{DynamicResource DataGridSelectionColor}" /> Color="{DynamicResource DataGridSelectionColor}" />
<SolidColorBrush x:Key="ThemeAccentColorBrush"
Color="{DynamicResource SystemAccentColor}" />
<SolidColorBrush x:Key="ThemeAccentBrush4"
Color="{DynamicResource ThemeAccentColor4}" />
<Color x:Key="SystemAccentColor">#FF00C3E3</Color>
<Color x:Key="SystemAccentColorDark1">#FF00C3E3</Color>
<Color x:Key="SystemAccentColorDark2">#FF00C3E3</Color>
<Color x:Key="SystemAccentColorDark3">#FF00C3E3</Color>
<Color x:Key="SystemAccentColorLight1">#FF00C3E3</Color>
<Color x:Key="SystemAccentColorLight2">#FF00C3E3</Color>
<Color x:Key="SystemAccentColorLight3">#FF00C3E3</Color>
<Color x:Key="ThemeAccentColor4">#FFe8e8e8</Color>
<Color x:Key="DataGridSelectionColor">#FF00FABB</Color> <Color x:Key="DataGridSelectionColor">#FF00FABB</Color>
<Color x:Key="ThemeContentBackgroundColor">#FFF0F0F0</Color> <Color x:Key="ThemeContentBackgroundColor">#FFF0F0F0</Color>
<Color x:Key="ThemeControlBorderColor">#FFd6d6d6</Color> <Color x:Key="ThemeControlBorderColor">#FFd6d6d6</Color>
@@ -59,18 +36,7 @@
<ResourceDictionary x:Key="Dark"> <ResourceDictionary x:Key="Dark">
<SolidColorBrush x:Key="DataGridSelectionBackgroundBrush" <SolidColorBrush x:Key="DataGridSelectionBackgroundBrush"
Color="{DynamicResource DataGridSelectionColor}" /> Color="{DynamicResource DataGridSelectionColor}" />
<SolidColorBrush x:Key="ThemeAccentColorBrush"
Color="{DynamicResource SystemAccentColor}" />
<SolidColorBrush x:Key="ThemeAccentBrush4"
Color="{DynamicResource ThemeAccentColor4}" />
<Color x:Key="ControlFillColorSecondary">#008AA8</Color> <Color x:Key="ControlFillColorSecondary">#008AA8</Color>
<Color x:Key="SystemAccentColor">#FF00C3E3</Color>
<Color x:Key="SystemAccentColorDark1">#FF99b000</Color>
<Color x:Key="SystemAccentColorDark2">#FF006d7d</Color>
<Color x:Key="SystemAccentColorDark3">#FF00525E</Color>
<Color x:Key="SystemAccentColorLight1">#FF00dbff</Color>
<Color x:Key="SystemAccentColorLight2">#FF19dfff</Color>
<Color x:Key="SystemAccentColorLight3">#FF33e3ff</Color>
<Color x:Key="DataGridSelectionColor">#FF00FABB</Color> <Color x:Key="DataGridSelectionColor">#FF00FABB</Color>
<Color x:Key="ThemeContentBackgroundColor">#FF2D2D2D</Color> <Color x:Key="ThemeContentBackgroundColor">#FF2D2D2D</Color>
<Color x:Key="ThemeControlBorderColor">#FF505050</Color> <Color x:Key="ThemeControlBorderColor">#FF505050</Color>

View File

@@ -17,13 +17,13 @@ namespace Ryujinx.Ava.Common.Markup
public virtual string Name => "Item"; public virtual string Name => "Item";
public virtual Action<object, T?>? Setter => null; public virtual Action<object, T?>? Setter => null;
protected abstract T? GetValue(); protected abstract T? Value { get; }
protected virtual void ConfigureBindingExtension(CompiledBindingExtension _) { } protected virtual void ConfigureBindingExtension(CompiledBindingExtension _) { }
private ClrPropertyInfo PropertyInfo => private ClrPropertyInfo PropertyInfo =>
new(Name, new(Name,
_ => GetValue(), _ => Value,
Setter as Action<object, object?>, Setter as Action<object, object?>,
typeof(T)); typeof(T));

View File

@@ -6,17 +6,17 @@ namespace Ryujinx.Ava.Common.Markup
{ {
internal class IconExtension(string iconString) : BasicMarkupExtension<Icon> internal class IconExtension(string iconString) : BasicMarkupExtension<Icon>
{ {
protected override Icon GetValue() => new() { Value = iconString }; protected override Icon Value => new() { Value = iconString };
} }
internal class SpinningIconExtension(string iconString) : BasicMarkupExtension<Icon> internal class SpinningIconExtension(string iconString) : BasicMarkupExtension<Icon>
{ {
protected override Icon GetValue() => new() { Value = iconString, Animation = IconAnimation.Spin }; protected override Icon Value => new() { Value = iconString, Animation = IconAnimation.Spin };
} }
internal class LocaleExtension(LocaleKeys key) : BasicMarkupExtension<string> internal class LocaleExtension(LocaleKeys key) : BasicMarkupExtension<string>
{ {
protected override string GetValue() => LocaleManager.Instance[key]; protected override string Value => LocaleManager.Instance[key];
protected override void ConfigureBindingExtension(CompiledBindingExtension bindingExtension) protected override void ConfigureBindingExtension(CompiledBindingExtension bindingExtension)
=> bindingExtension.Source = LocaleManager.Instance; => bindingExtension.Source = LocaleManager.Instance;

View File

@@ -1,24 +0,0 @@
using Avalonia.Threading;
using Ryujinx.Ava.UI.ViewModels;
namespace Ryujinx.Ava.Common
{
internal class XCIFileTrimmerMainWindowLog : Ryujinx.Common.Logging.XCIFileTrimmerLog
{
private readonly MainWindowViewModel _viewModel;
public XCIFileTrimmerMainWindowLog(MainWindowViewModel viewModel)
{
_viewModel = viewModel;
}
public override void Progress(long current, long total, string text, bool complete)
{
Dispatcher.UIThread.Post(() =>
{
_viewModel.StatusBarProgressMaximum = (int)(total);
_viewModel.StatusBarProgressValue = (int)(current);
});
}
}
}

View File

@@ -1,23 +0,0 @@
using Avalonia.Threading;
using Ryujinx.Ava.UI.ViewModels;
namespace Ryujinx.Ava.Common
{
internal class XCIFileTrimmerWindowLog : Ryujinx.Common.Logging.XCIFileTrimmerLog
{
private readonly XCITrimmerViewModel _viewModel;
public XCIFileTrimmerWindowLog(XCITrimmerViewModel viewModel)
{
_viewModel = viewModel;
}
public override void Progress(long current, long total, string text, bool complete)
{
Dispatcher.UIThread.Post(() =>
{
_viewModel.SetProgress((int)(current), (int)(total));
});
}
}
}

View File

@@ -0,0 +1,45 @@
using Avalonia.Threading;
using Ryujinx.Ava.UI.ViewModels;
namespace Ryujinx.Ava.Common
{
public static class XCITrimmerLog
{
internal class MainWindow : Ryujinx.Common.Logging.XCIFileTrimmerLog
{
private readonly MainWindowViewModel _viewModel;
public MainWindow(MainWindowViewModel viewModel)
{
_viewModel = viewModel;
}
public override void Progress(long current, long total, string text, bool complete)
{
Dispatcher.UIThread.Post(() =>
{
_viewModel.StatusBarProgressMaximum = (int)(total);
_viewModel.StatusBarProgressValue = (int)(current);
});
}
}
internal class TrimmerWindow : Ryujinx.Common.Logging.XCIFileTrimmerLog
{
private readonly XCITrimmerViewModel _viewModel;
public TrimmerWindow(XCITrimmerViewModel viewModel)
{
_viewModel = viewModel;
}
public override void Progress(long current, long total, string text, bool complete)
{
Dispatcher.UIThread.Post(() =>
{
_viewModel.SetProgress((int)(current), (int)(total));
});
}
}
}
}

View File

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

View File

@@ -1,6 +1,6 @@
using Ryujinx.HLE.UI; using Ryujinx.HLE.UI;
namespace Ryujinx.Headless.SDL2 namespace Ryujinx.Headless
{ {
internal class HeadlessHostUiTheme : IHostUITheme internal class HeadlessHostUiTheme : IHostUITheme
{ {

View File

@@ -0,0 +1,361 @@
using DiscordRPC;
using LibHac.Tools.FsSystem;
using Ryujinx.Audio.Backends.SDL2;
using Ryujinx.Ava;
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Configuration.Hid;
using Ryujinx.Common.Configuration.Hid.Controller;
using Ryujinx.Common.Configuration.Hid.Controller.Motion;
using Ryujinx.Common.Configuration.Hid.Keyboard;
using Ryujinx.Common.Logging;
using Ryujinx.Common.Utilities;
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.GAL.Multithreading;
using Ryujinx.Graphics.OpenGL;
using Ryujinx.Graphics.Vulkan;
using Ryujinx.HLE;
using Ryujinx.Input;
using Ryujinx.UI.Common;
using Ryujinx.UI.Common.Configuration;
using Silk.NET.Vulkan;
using System;
using System.IO;
using System.Text.Json;
using System.Threading.Tasks;
using ConfigGamepadInputId = Ryujinx.Common.Configuration.Hid.Controller.GamepadInputId;
using ConfigStickInputId = Ryujinx.Common.Configuration.Hid.Controller.StickInputId;
using Key = Ryujinx.Common.Configuration.Hid.Key;
namespace Ryujinx.Headless
{
public partial class HeadlessRyujinx
{
public static void Initialize()
{
// Ensure Discord presence timestamp begins at the absolute start of when Ryujinx is launched
DiscordIntegrationModule.StartedAt = Timestamps.Now;
// Delete backup files after updating.
Task.Run(Updater.CleanupUpdate);
// Hook unhandled exception and process exit events.
AppDomain.CurrentDomain.UnhandledException += (sender, e)
=> Program.ProcessUnhandledException(sender, e.ExceptionObject as Exception, e.IsTerminating);
AppDomain.CurrentDomain.ProcessExit += (_, _) => Program.Exit();
// Initialize the configuration.
ConfigurationState.Initialize();
// Initialize Discord integration.
DiscordIntegrationModule.Initialize();
// Logging system information.
Program.PrintSystemInfo();
}
private static InputConfig HandlePlayerConfiguration(string inputProfileName, string inputId, PlayerIndex index)
{
if (inputId == null)
{
if (index == PlayerIndex.Player1)
{
Logger.Info?.Print(LogClass.Application, $"{index} not configured, defaulting to default keyboard.");
// Default to keyboard
inputId = "0";
}
else
{
Logger.Info?.Print(LogClass.Application, $"{index} not configured");
return null;
}
}
IGamepad gamepad = _inputManager.KeyboardDriver.GetGamepad(inputId);
bool isKeyboard = true;
if (gamepad == null)
{
gamepad = _inputManager.GamepadDriver.GetGamepad(inputId);
isKeyboard = false;
if (gamepad == null)
{
Logger.Error?.Print(LogClass.Application, $"{index} gamepad not found (\"{inputId}\")");
return null;
}
}
string gamepadName = gamepad.Name;
gamepad.Dispose();
InputConfig config;
if (inputProfileName == null || inputProfileName.Equals("default"))
{
if (isKeyboard)
{
config = new StandardKeyboardInputConfig
{
Version = InputConfig.CurrentVersion,
Backend = InputBackendType.WindowKeyboard,
Id = null,
ControllerType = ControllerType.JoyconPair,
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,
},
};
}
else
{
bool isNintendoStyle = gamepadName.Contains("Nintendo");
config = new StandardControllerInputConfig
{
Version = InputConfig.CurrentVersion,
Backend = InputBackendType.GamepadSDL2,
Id = null,
ControllerType = ControllerType.JoyconPair,
DeadzoneLeft = 0.1f,
DeadzoneRight = 0.1f,
RangeLeft = 1.0f,
RangeRight = 1.0f,
TriggerThreshold = 0.5f,
LeftJoycon = new LeftJoyconCommonConfig<ConfigGamepadInputId>
{
DpadUp = ConfigGamepadInputId.DpadUp,
DpadDown = ConfigGamepadInputId.DpadDown,
DpadLeft = ConfigGamepadInputId.DpadLeft,
DpadRight = ConfigGamepadInputId.DpadRight,
ButtonMinus = ConfigGamepadInputId.Minus,
ButtonL = ConfigGamepadInputId.LeftShoulder,
ButtonZl = ConfigGamepadInputId.LeftTrigger,
ButtonSl = ConfigGamepadInputId.Unbound,
ButtonSr = ConfigGamepadInputId.Unbound,
},
LeftJoyconStick = new JoyconConfigControllerStick<ConfigGamepadInputId, ConfigStickInputId>
{
Joystick = ConfigStickInputId.Left,
StickButton = ConfigGamepadInputId.LeftStick,
InvertStickX = false,
InvertStickY = false,
Rotate90CW = false,
},
RightJoycon = new RightJoyconCommonConfig<ConfigGamepadInputId>
{
ButtonA = isNintendoStyle ? ConfigGamepadInputId.A : ConfigGamepadInputId.B,
ButtonB = isNintendoStyle ? ConfigGamepadInputId.B : ConfigGamepadInputId.A,
ButtonX = isNintendoStyle ? ConfigGamepadInputId.X : ConfigGamepadInputId.Y,
ButtonY = isNintendoStyle ? ConfigGamepadInputId.Y : ConfigGamepadInputId.X,
ButtonPlus = ConfigGamepadInputId.Plus,
ButtonR = ConfigGamepadInputId.RightShoulder,
ButtonZr = ConfigGamepadInputId.RightTrigger,
ButtonSl = ConfigGamepadInputId.Unbound,
ButtonSr = ConfigGamepadInputId.Unbound,
},
RightJoyconStick = new JoyconConfigControllerStick<ConfigGamepadInputId, ConfigStickInputId>
{
Joystick = ConfigStickInputId.Right,
StickButton = ConfigGamepadInputId.RightStick,
InvertStickX = false,
InvertStickY = false,
Rotate90CW = false,
},
Motion = new StandardMotionConfigController
{
MotionBackend = MotionInputBackendType.GamepadDriver,
EnableMotion = true,
Sensitivity = 100,
GyroDeadzone = 1,
},
Rumble = new RumbleConfigController
{
StrongRumble = 1f,
WeakRumble = 1f,
EnableRumble = false,
},
};
}
}
else
{
string profileBasePath;
if (isKeyboard)
{
profileBasePath = Path.Combine(AppDataManager.ProfilesDirPath, "keyboard");
}
else
{
profileBasePath = Path.Combine(AppDataManager.ProfilesDirPath, "controller");
}
string path = Path.Combine(profileBasePath, inputProfileName + ".json");
if (!File.Exists(path))
{
Logger.Error?.Print(LogClass.Application, $"Input profile \"{inputProfileName}\" not found for \"{inputId}\"");
return null;
}
try
{
config = JsonHelper.DeserializeFromFile(path, _serializerContext.InputConfig);
}
catch (JsonException)
{
Logger.Error?.Print(LogClass.Application, $"Input profile \"{inputProfileName}\" parsing failed for \"{inputId}\"");
return null;
}
}
config.Id = inputId;
config.PlayerIndex = index;
string inputTypeName = isKeyboard ? "Keyboard" : "Gamepad";
Logger.Info?.Print(LogClass.Application, $"{config.PlayerIndex} configured with {inputTypeName} \"{config.Id}\"");
// If both stick ranges are 0 (usually indicative of an outdated profile load) then both sticks will be set to 1.0.
if (config is StandardControllerInputConfig controllerConfig)
{
if (controllerConfig.RangeLeft <= 0.0f && controllerConfig.RangeRight <= 0.0f)
{
controllerConfig.RangeLeft = 1.0f;
controllerConfig.RangeRight = 1.0f;
Logger.Info?.Print(LogClass.Application, $"{config.PlayerIndex} stick range reset. Save the profile now to update your configuration");
}
}
return config;
}
private static IRenderer CreateRenderer(Options options, WindowBase window)
{
if (options.GraphicsBackend == GraphicsBackend.Vulkan && window is VulkanWindow vulkanWindow)
{
string preferredGpuId = string.Empty;
Vk api = Vk.GetApi();
if (!string.IsNullOrEmpty(options.PreferredGPUVendor))
{
string preferredGpuVendor = options.PreferredGPUVendor.ToLowerInvariant();
var devices = VulkanRenderer.GetPhysicalDevices(api);
foreach (var device in devices)
{
if (device.Vendor.ToLowerInvariant() == preferredGpuVendor)
{
preferredGpuId = device.Id;
break;
}
}
}
return new VulkanRenderer(
api,
(instance, vk) => new SurfaceKHR((ulong)(vulkanWindow.CreateWindowSurface(instance.Handle))),
vulkanWindow.GetRequiredInstanceExtensions,
preferredGpuId);
}
return new OpenGLRenderer();
}
private static Switch InitializeEmulationContext(WindowBase window, IRenderer renderer, Options options)
{
BackendThreading threadingMode = options.BackendThreading;
bool threadedGAL = threadingMode == BackendThreading.On || (threadingMode == BackendThreading.Auto && renderer.PreferThreading);
if (threadedGAL)
{
renderer = new ThreadedRenderer(renderer);
}
HLEConfiguration configuration = new(_virtualFileSystem,
_libHacHorizonManager,
_contentManager,
_accountManager,
_userChannelPersistence,
renderer,
new SDL2HardwareDeviceDriver(),
options.DramSize,
window,
options.SystemLanguage,
options.SystemRegion,
options.VSyncMode,
!options.DisableDockedMode,
!options.DisablePTC,
options.EnableInternetAccess,
!options.DisableFsIntegrityChecks ? IntegrityCheckLevel.ErrorOnInvalid : IntegrityCheckLevel.None,
options.FsGlobalAccessLogMode,
options.SystemTimeOffset,
options.SystemTimeZone,
options.MemoryManagerMode,
options.IgnoreMissingServices,
options.AspectRatio,
options.AudioVolume,
options.UseHypervisor ?? true,
options.MultiplayerLanInterfaceId,
Common.Configuration.Multiplayer.MultiplayerMode.Disabled,
false,
string.Empty,
string.Empty,
options.CustomVSyncInterval);
return new Switch(configuration);
}
}
}

View File

@@ -1,13 +1,9 @@
using CommandLine; using CommandLine;
using Gommon; using Gommon;
using LibHac.Tools.FsSystem; using Ryujinx.Ava;
using Ryujinx.Audio.Backends.SDL2;
using Ryujinx.Common; using Ryujinx.Common;
using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration;
using Ryujinx.Common.Configuration.Hid; using Ryujinx.Common.Configuration.Hid;
using Ryujinx.Common.Configuration.Hid.Controller;
using Ryujinx.Common.Configuration.Hid.Controller.Motion;
using Ryujinx.Common.Configuration.Hid.Keyboard;
using Ryujinx.Common.GraphicsDriver; using Ryujinx.Common.GraphicsDriver;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.Common.Logging.Targets; using Ryujinx.Common.Logging.Targets;
@@ -15,14 +11,9 @@ using Ryujinx.Common.SystemInterop;
using Ryujinx.Common.Utilities; using Ryujinx.Common.Utilities;
using Ryujinx.Cpu; using Ryujinx.Cpu;
using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.GAL.Multithreading;
using Ryujinx.Graphics.Gpu; using Ryujinx.Graphics.Gpu;
using Ryujinx.Graphics.Gpu.Shader; using Ryujinx.Graphics.Gpu.Shader;
using Ryujinx.Graphics.OpenGL;
using Ryujinx.Graphics.Vulkan;
using Ryujinx.Graphics.Vulkan.MoltenVK; using Ryujinx.Graphics.Vulkan.MoltenVK;
using Ryujinx.Headless.SDL2.OpenGL;
using Ryujinx.Headless.SDL2.Vulkan;
using Ryujinx.HLE; using Ryujinx.HLE;
using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.HOS; using Ryujinx.HLE.HOS;
@@ -31,22 +22,16 @@ using Ryujinx.Input;
using Ryujinx.Input.HLE; using Ryujinx.Input.HLE;
using Ryujinx.Input.SDL2; using Ryujinx.Input.SDL2;
using Ryujinx.SDL2.Common; using Ryujinx.SDL2.Common;
using Silk.NET.Vulkan; using Ryujinx.UI.Common.Configuration;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Text.Json;
using System.Threading; using System.Threading;
using ConfigGamepadInputId = Ryujinx.Common.Configuration.Hid.Controller.GamepadInputId;
using ConfigStickInputId = Ryujinx.Common.Configuration.Hid.Controller.StickInputId;
using Key = Ryujinx.Common.Configuration.Hid.Key;
namespace Ryujinx.Headless.SDL2 namespace Ryujinx.Headless
{ {
class Program public partial class HeadlessRyujinx
{ {
public static string Version { get; private set; }
private static VirtualFileSystem _virtualFileSystem; private static VirtualFileSystem _virtualFileSystem;
private static ContentManager _contentManager; private static ContentManager _contentManager;
private static AccountManager _accountManager; private static AccountManager _accountManager;
@@ -56,20 +41,18 @@ namespace Ryujinx.Headless.SDL2
private static Switch _emulationContext; private static Switch _emulationContext;
private static WindowBase _window; private static WindowBase _window;
private static WindowsMultimediaTimerResolution _windowsMultimediaTimerResolution; private static WindowsMultimediaTimerResolution _windowsMultimediaTimerResolution;
private static List<InputConfig> _inputConfiguration; private static List<InputConfig> _inputConfiguration = [];
private static bool _enableKeyboard; private static bool _enableKeyboard;
private static bool _enableMouse; private static bool _enableMouse;
private static readonly InputConfigJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions()); private static readonly InputConfigJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions());
static void Main(string[] args) public static void Entrypoint(string[] args)
{ {
Version = ReleaseInformation.Version;
// Make process DPI aware for proper window sizing on high-res screens. // Make process DPI aware for proper window sizing on high-res screens.
ForceDpiAware.Windows(); ForceDpiAware.Windows();
Console.Title = $"Ryujinx Console {Version} (Headless SDL2)"; Console.Title = $"Ryujinx Console {Program.Version} (Headless)";
if (OperatingSystem.IsMacOS() || OperatingSystem.IsLinux()) if (OperatingSystem.IsMacOS() || OperatingSystem.IsLinux())
{ {
@@ -97,7 +80,7 @@ namespace Ryujinx.Headless.SDL2
} }
Parser.Default.ParseArguments<Options>(args) Parser.Default.ParseArguments<Options>(args)
.WithParsed(Load) .WithParsed(options => Load(args, options))
.WithNotParsed(errors => .WithNotParsed(errors =>
{ {
Logger.Error?.PrintMsg(LogClass.Application, "Error parsing command-line arguments:"); Logger.Error?.PrintMsg(LogClass.Application, "Error parsing command-line arguments:");
@@ -105,239 +88,81 @@ namespace Ryujinx.Headless.SDL2
errors.ForEach(err => Logger.Error?.PrintMsg(LogClass.Application, $" - {err.Tag}")); errors.ForEach(err => Logger.Error?.PrintMsg(LogClass.Application, $" - {err.Tag}"));
}); });
} }
private static InputConfig HandlePlayerConfiguration(string inputProfileName, string inputId, PlayerIndex index) public static void ReloadConfig(string customConfigPath = null)
{ {
if (inputId == null) string localConfigurationPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ReleaseInformation.ConfigName);
string appDataConfigurationPath = Path.Combine(AppDataManager.BaseDirPath, ReleaseInformation.ConfigName);
string configurationPath = null;
// Now load the configuration as the other subsystems are now registered
if (customConfigPath != null && File.Exists(customConfigPath))
{ {
if (index == PlayerIndex.Player1) configurationPath = customConfigPath;
{ }
Logger.Info?.Print(LogClass.Application, $"{index} not configured, defaulting to default keyboard."); else if (File.Exists(localConfigurationPath))
{
// Default to keyboard configurationPath = localConfigurationPath;
inputId = "0"; }
} else if (File.Exists(appDataConfigurationPath))
else {
{ configurationPath = appDataConfigurationPath;
Logger.Info?.Print(LogClass.Application, $"{index} not configured");
return null;
}
} }
IGamepad gamepad = _inputManager.KeyboardDriver.GetGamepad(inputId); if (configurationPath == null)
bool isKeyboard = true;
if (gamepad == null)
{ {
gamepad = _inputManager.GamepadDriver.GetGamepad(inputId); // No configuration, we load the default values and save it to disk
isKeyboard = false; configurationPath = appDataConfigurationPath;
Logger.Notice.Print(LogClass.Application, $"No configuration file found. Saving default configuration to: {configurationPath}");
if (gamepad == null) ConfigurationState.Instance.LoadDefault();
{ ConfigurationState.Instance.ToFileFormat().SaveConfig(configurationPath);
Logger.Error?.Print(LogClass.Application, $"{index} gamepad not found (\"{inputId}\")");
return null;
}
}
string gamepadName = gamepad.Name;
gamepad.Dispose();
InputConfig config;
if (inputProfileName == null || inputProfileName.Equals("default"))
{
if (isKeyboard)
{
config = new StandardKeyboardInputConfig
{
Version = InputConfig.CurrentVersion,
Backend = InputBackendType.WindowKeyboard,
Id = null,
ControllerType = ControllerType.JoyconPair,
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,
},
};
}
else
{
bool isNintendoStyle = gamepadName.Contains("Nintendo");
config = new StandardControllerInputConfig
{
Version = InputConfig.CurrentVersion,
Backend = InputBackendType.GamepadSDL2,
Id = null,
ControllerType = ControllerType.JoyconPair,
DeadzoneLeft = 0.1f,
DeadzoneRight = 0.1f,
RangeLeft = 1.0f,
RangeRight = 1.0f,
TriggerThreshold = 0.5f,
LeftJoycon = new LeftJoyconCommonConfig<ConfigGamepadInputId>
{
DpadUp = ConfigGamepadInputId.DpadUp,
DpadDown = ConfigGamepadInputId.DpadDown,
DpadLeft = ConfigGamepadInputId.DpadLeft,
DpadRight = ConfigGamepadInputId.DpadRight,
ButtonMinus = ConfigGamepadInputId.Minus,
ButtonL = ConfigGamepadInputId.LeftShoulder,
ButtonZl = ConfigGamepadInputId.LeftTrigger,
ButtonSl = ConfigGamepadInputId.Unbound,
ButtonSr = ConfigGamepadInputId.Unbound,
},
LeftJoyconStick = new JoyconConfigControllerStick<ConfigGamepadInputId, ConfigStickInputId>
{
Joystick = ConfigStickInputId.Left,
StickButton = ConfigGamepadInputId.LeftStick,
InvertStickX = false,
InvertStickY = false,
Rotate90CW = false,
},
RightJoycon = new RightJoyconCommonConfig<ConfigGamepadInputId>
{
ButtonA = isNintendoStyle ? ConfigGamepadInputId.A : ConfigGamepadInputId.B,
ButtonB = isNintendoStyle ? ConfigGamepadInputId.B : ConfigGamepadInputId.A,
ButtonX = isNintendoStyle ? ConfigGamepadInputId.X : ConfigGamepadInputId.Y,
ButtonY = isNintendoStyle ? ConfigGamepadInputId.Y : ConfigGamepadInputId.X,
ButtonPlus = ConfigGamepadInputId.Plus,
ButtonR = ConfigGamepadInputId.RightShoulder,
ButtonZr = ConfigGamepadInputId.RightTrigger,
ButtonSl = ConfigGamepadInputId.Unbound,
ButtonSr = ConfigGamepadInputId.Unbound,
},
RightJoyconStick = new JoyconConfigControllerStick<ConfigGamepadInputId, ConfigStickInputId>
{
Joystick = ConfigStickInputId.Right,
StickButton = ConfigGamepadInputId.RightStick,
InvertStickX = false,
InvertStickY = false,
Rotate90CW = false,
},
Motion = new StandardMotionConfigController
{
MotionBackend = MotionInputBackendType.GamepadDriver,
EnableMotion = true,
Sensitivity = 100,
GyroDeadzone = 1,
},
Rumble = new RumbleConfigController
{
StrongRumble = 1f,
WeakRumble = 1f,
EnableRumble = false,
},
};
}
} }
else else
{ {
string profileBasePath; Logger.Notice.Print(LogClass.Application, $"Loading configuration from: {configurationPath}");
if (isKeyboard) if (ConfigurationFileFormat.TryLoad(configurationPath, out ConfigurationFileFormat configurationFileFormat))
{ {
profileBasePath = Path.Combine(AppDataManager.ProfilesDirPath, "keyboard"); ConfigurationState.Instance.Load(configurationFileFormat, configurationPath);
} }
else else
{ {
profileBasePath = Path.Combine(AppDataManager.ProfilesDirPath, "controller"); Logger.Warning?.PrintMsg(LogClass.Application, $"Failed to load config! Loading the default config instead.\nFailed config location: {configurationPath}");
}
string path = Path.Combine(profileBasePath, inputProfileName + ".json"); ConfigurationState.Instance.LoadDefault();
if (!File.Exists(path))
{
Logger.Error?.Print(LogClass.Application, $"Input profile \"{inputProfileName}\" not found for \"{inputId}\"");
return null;
}
try
{
config = JsonHelper.DeserializeFromFile(path, _serializerContext.InputConfig);
}
catch (JsonException)
{
Logger.Error?.Print(LogClass.Application, $"Input profile \"{inputProfileName}\" parsing failed for \"{inputId}\"");
return null;
} }
} }
config.Id = inputId;
config.PlayerIndex = index;
string inputTypeName = isKeyboard ? "Keyboard" : "Gamepad";
Logger.Info?.Print(LogClass.Application, $"{config.PlayerIndex} configured with {inputTypeName} \"{config.Id}\"");
// If both stick ranges are 0 (usually indicative of an outdated profile load) then both sticks will be set to 1.0.
if (config is StandardControllerInputConfig controllerConfig)
{
if (controllerConfig.RangeLeft <= 0.0f && controllerConfig.RangeRight <= 0.0f)
{
controllerConfig.RangeLeft = 1.0f;
controllerConfig.RangeRight = 1.0f;
Logger.Info?.Print(LogClass.Application, $"{config.PlayerIndex} stick range reset. Save the profile now to update your configuration");
}
}
return config;
} }
static void Load(Options option) static void Load(string[] originalArgs, Options option)
{ {
AppDataManager.Initialize(option.BaseDataDir); Initialize();
bool useLastUsedProfile = false;
if (option.InheritConfig)
{
option.InheritMainConfig(originalArgs, ConfigurationState.Instance, out useLastUsedProfile);
}
AppDataManager.Initialize(option.BaseDataDir);
if (useLastUsedProfile && AccountSaveDataManager.GetLastUsedUser().TryGet(out var profile))
option.UserProfile = profile.Name;
// Check if keys exists.
if (!File.Exists(Path.Combine(AppDataManager.KeysDirPath, "prod.keys")))
{
if (!(AppDataManager.Mode == AppDataManager.LaunchMode.UserProfile && File.Exists(Path.Combine(AppDataManager.KeysDirPathUser, "prod.keys"))))
{
Logger.Error?.Print(LogClass.Application, "Keys not found");
}
}
ReloadConfig();
_virtualFileSystem = VirtualFileSystem.CreateInstance(); _virtualFileSystem = VirtualFileSystem.CreateInstance();
_libHacHorizonManager = new LibHacHorizonManager(); _libHacHorizonManager = new LibHacHorizonManager();
@@ -352,7 +177,7 @@ namespace Ryujinx.Headless.SDL2
_inputManager = new InputManager(new SDL2KeyboardDriver(), new SDL2GamepadDriver()); _inputManager = new InputManager(new SDL2KeyboardDriver(), new SDL2GamepadDriver());
GraphicsConfig.EnableShaderCache = true; GraphicsConfig.EnableShaderCache = !option.DisableShaderCache;
if (OperatingSystem.IsMacOS()) if (OperatingSystem.IsMacOS())
{ {
@@ -363,15 +188,13 @@ namespace Ryujinx.Headless.SDL2
} }
} }
IGamepad gamepad;
if (option.ListInputIds) if (option.ListInputIds)
{ {
Logger.Info?.Print(LogClass.Application, "Input Ids:"); Logger.Info?.Print(LogClass.Application, "Input Ids:");
foreach (string id in _inputManager.KeyboardDriver.GamepadsIds) foreach (string id in _inputManager.KeyboardDriver.GamepadsIds)
{ {
gamepad = _inputManager.KeyboardDriver.GetGamepad(id); IGamepad gamepad = _inputManager.KeyboardDriver.GetGamepad(id);
Logger.Info?.Print(LogClass.Application, $"- {id} (\"{gamepad.Name}\")"); Logger.Info?.Print(LogClass.Application, $"- {id} (\"{gamepad.Name}\")");
@@ -380,7 +203,7 @@ namespace Ryujinx.Headless.SDL2
foreach (string id in _inputManager.GamepadDriver.GamepadsIds) foreach (string id in _inputManager.GamepadDriver.GamepadsIds)
{ {
gamepad = _inputManager.GamepadDriver.GetGamepad(id); IGamepad gamepad = _inputManager.GamepadDriver.GetGamepad(id);
Logger.Info?.Print(LogClass.Application, $"- {id} (\"{gamepad.Name}\")"); Logger.Info?.Print(LogClass.Application, $"- {id} (\"{gamepad.Name}\")");
@@ -397,7 +220,7 @@ namespace Ryujinx.Headless.SDL2
return; return;
} }
_inputConfiguration = new List<InputConfig>(); _inputConfiguration ??= [];
_enableKeyboard = option.EnableKeyboard; _enableKeyboard = option.EnableKeyboard;
_enableMouse = option.EnableMouse; _enableMouse = option.EnableMouse;
@@ -410,9 +233,9 @@ namespace Ryujinx.Headless.SDL2
_inputConfiguration.Add(inputConfig); _inputConfiguration.Add(inputConfig);
} }
} }
LoadPlayerConfiguration(option.InputProfile1Name, option.InputId1, PlayerIndex.Player1); LoadPlayerConfiguration(option.InputProfile1Name, option.InputId1, PlayerIndex.Player1);
LoadPlayerConfiguration(option.InputProfile2Name, option.InputId2, PlayerIndex.Player2); LoadPlayerConfiguration(option.InputProfile2Name, option.InputId2, PlayerIndex.Player2);
LoadPlayerConfiguration(option.InputProfile3Name, option.InputId3, PlayerIndex.Player3); LoadPlayerConfiguration(option.InputProfile3Name, option.InputId3, PlayerIndex.Player3);
LoadPlayerConfiguration(option.InputProfile4Name, option.InputId4, PlayerIndex.Player4); LoadPlayerConfiguration(option.InputProfile4Name, option.InputId4, PlayerIndex.Player4);
LoadPlayerConfiguration(option.InputProfile5Name, option.InputId5, PlayerIndex.Player5); LoadPlayerConfiguration(option.InputProfile5Name, option.InputId5, PlayerIndex.Player5);
@@ -420,6 +243,7 @@ namespace Ryujinx.Headless.SDL2
LoadPlayerConfiguration(option.InputProfile7Name, option.InputId7, PlayerIndex.Player7); LoadPlayerConfiguration(option.InputProfile7Name, option.InputId7, PlayerIndex.Player7);
LoadPlayerConfiguration(option.InputProfile8Name, option.InputId8, PlayerIndex.Player8); LoadPlayerConfiguration(option.InputProfile8Name, option.InputId8, PlayerIndex.Player8);
LoadPlayerConfiguration(option.InputProfileHandheldName, option.InputIdHandheld, PlayerIndex.Handheld); LoadPlayerConfiguration(option.InputProfileHandheldName, option.InputIdHandheld, PlayerIndex.Handheld);
if (_inputConfiguration.Count == 0) if (_inputConfiguration.Count == 0)
{ {
@@ -431,7 +255,7 @@ namespace Ryujinx.Headless.SDL2
Logger.SetEnable(LogLevel.Stub, !option.LoggingDisableStub); Logger.SetEnable(LogLevel.Stub, !option.LoggingDisableStub);
Logger.SetEnable(LogLevel.Info, !option.LoggingDisableInfo); Logger.SetEnable(LogLevel.Info, !option.LoggingDisableInfo);
Logger.SetEnable(LogLevel.Warning, !option.LoggingDisableWarning); Logger.SetEnable(LogLevel.Warning, !option.LoggingDisableWarning);
Logger.SetEnable(LogLevel.Error, option.LoggingEnableError); Logger.SetEnable(LogLevel.Error, !option.LoggingDisableError);
Logger.SetEnable(LogLevel.Trace, option.LoggingEnableTrace); Logger.SetEnable(LogLevel.Trace, option.LoggingEnableTrace);
Logger.SetEnable(LogLevel.Guest, !option.LoggingDisableGuest); Logger.SetEnable(LogLevel.Guest, !option.LoggingDisableGuest);
Logger.SetEnable(LogLevel.AccessLog, option.LoggingEnableFsAccessLog); Logger.SetEnable(LogLevel.AccessLog, option.LoggingEnableFsAccessLog);
@@ -515,83 +339,6 @@ namespace Ryujinx.Headless.SDL2
: new OpenGLWindow(_inputManager, options.LoggingGraphicsDebugLevel, options.AspectRatio, options.EnableMouse, options.HideCursorMode, options.IgnoreControllerApplet); : new OpenGLWindow(_inputManager, options.LoggingGraphicsDebugLevel, options.AspectRatio, options.EnableMouse, options.HideCursorMode, options.IgnoreControllerApplet);
} }
private static IRenderer CreateRenderer(Options options, WindowBase window)
{
if (options.GraphicsBackend == GraphicsBackend.Vulkan && window is VulkanWindow vulkanWindow)
{
string preferredGpuId = string.Empty;
Vk api = Vk.GetApi();
if (!string.IsNullOrEmpty(options.PreferredGPUVendor))
{
string preferredGpuVendor = options.PreferredGPUVendor.ToLowerInvariant();
var devices = VulkanRenderer.GetPhysicalDevices(api);
foreach (var device in devices)
{
if (device.Vendor.ToLowerInvariant() == preferredGpuVendor)
{
preferredGpuId = device.Id;
break;
}
}
}
return new VulkanRenderer(
api,
(instance, vk) => new SurfaceKHR((ulong)(vulkanWindow.CreateWindowSurface(instance.Handle))),
vulkanWindow.GetRequiredInstanceExtensions,
preferredGpuId);
}
return new OpenGLRenderer();
}
private static Switch InitializeEmulationContext(WindowBase window, IRenderer renderer, Options options)
{
BackendThreading threadingMode = options.BackendThreading;
bool threadedGAL = threadingMode == BackendThreading.On || (threadingMode == BackendThreading.Auto && renderer.PreferThreading);
if (threadedGAL)
{
renderer = new ThreadedRenderer(renderer);
}
HLEConfiguration configuration = new(_virtualFileSystem,
_libHacHorizonManager,
_contentManager,
_accountManager,
_userChannelPersistence,
renderer,
new SDL2HardwareDeviceDriver(),
options.DramSize,
window,
options.SystemLanguage,
options.SystemRegion,
options.VSyncMode,
!options.DisableDockedMode,
!options.DisablePTC,
options.EnableInternetAccess,
!options.DisableFsIntegrityChecks ? IntegrityCheckLevel.ErrorOnInvalid : IntegrityCheckLevel.None,
options.FsGlobalAccessLogMode,
options.SystemTimeOffset,
options.SystemTimeZone,
options.MemoryManagerMode,
options.IgnoreMissingServices,
options.AspectRatio,
options.AudioVolume,
options.UseHypervisor ?? true,
options.MultiplayerLanInterfaceId,
Common.Configuration.Multiplayer.MultiplayerMode.Disabled,
false,
string.Empty,
string.Empty,
options.CustomVSyncInterval);
return new Switch(configuration);
}
private static void ExecutionEntrypoint() private static void ExecutionEntrypoint()
{ {
if (OperatingSystem.IsWindows()) if (OperatingSystem.IsWindows())

View File

@@ -7,7 +7,7 @@ using Ryujinx.Input.HLE;
using System; using System;
using static SDL2.SDL; using static SDL2.SDL;
namespace Ryujinx.Headless.SDL2.OpenGL namespace Ryujinx.Headless
{ {
class OpenGLWindow : WindowBase class OpenGLWindow : WindowBase
{ {

View File

@@ -1,13 +1,168 @@
using CommandLine; using CommandLine;
using Gommon;
using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration;
using Ryujinx.Common.Configuration.Hid;
using Ryujinx.HLE; using Ryujinx.HLE;
using Ryujinx.HLE.HOS.Services.Account.Acc;
using Ryujinx.HLE.HOS.SystemState; using Ryujinx.HLE.HOS.SystemState;
using Ryujinx.UI.Common.Configuration;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace Ryujinx.Headless.SDL2 namespace Ryujinx.Headless
{ {
public class Options public class Options
{ {
public void InheritMainConfig(string[] originalArgs, ConfigurationState configurationState, out bool needsProfileSet)
{
needsProfileSet = NeedsOverride(nameof(UserProfile));
if (NeedsOverride(nameof(IsFullscreen)))
IsFullscreen = configurationState.UI.StartFullscreen;
if (NeedsOverride(nameof(EnableKeyboard)))
EnableKeyboard = configurationState.Hid.EnableKeyboard;
if (NeedsOverride(nameof(EnableMouse)))
EnableMouse = configurationState.Hid.EnableMouse;
if (NeedsOverride(nameof(HideCursorMode)))
HideCursorMode = configurationState.HideCursor;
if (NeedsOverride(nameof(DisablePTC)))
DisablePTC = !configurationState.System.EnablePtc;
if (NeedsOverride(nameof(EnableInternetAccess)))
EnableInternetAccess = configurationState.System.EnableInternetAccess;
if (NeedsOverride(nameof(DisableFsIntegrityChecks)))
DisableFsIntegrityChecks = configurationState.System.EnableFsIntegrityChecks;
if (NeedsOverride(nameof(FsGlobalAccessLogMode)))
FsGlobalAccessLogMode = configurationState.System.FsGlobalAccessLogMode;
if (NeedsOverride(nameof(VSyncMode)))
VSyncMode = configurationState.Graphics.VSyncMode;
if (NeedsOverride(nameof(CustomVSyncInterval)))
CustomVSyncInterval = configurationState.Graphics.CustomVSyncInterval;
if (NeedsOverride(nameof(DisableShaderCache)))
DisableShaderCache = !configurationState.Graphics.EnableShaderCache;
if (NeedsOverride(nameof(EnableTextureRecompression)))
EnableTextureRecompression = configurationState.Graphics.EnableTextureRecompression;
if (NeedsOverride(nameof(DisableDockedMode)))
DisableDockedMode = !configurationState.System.EnableDockedMode;
if (NeedsOverride(nameof(SystemLanguage)))
SystemLanguage = (SystemLanguage)(int)configurationState.System.Language.Value;
if (NeedsOverride(nameof(SystemRegion)))
SystemRegion = (RegionCode)(int)configurationState.System.Region.Value;
if (NeedsOverride(nameof(SystemTimeZone)))
SystemTimeZone = configurationState.System.TimeZone;
if (NeedsOverride(nameof(SystemTimeOffset)))
SystemTimeOffset = configurationState.System.SystemTimeOffset;
if (NeedsOverride(nameof(MemoryManagerMode)))
MemoryManagerMode = configurationState.System.MemoryManagerMode;
if (NeedsOverride(nameof(AudioVolume)))
AudioVolume = configurationState.System.AudioVolume;
if (NeedsOverride(nameof(UseHypervisor)) && OperatingSystem.IsMacOS())
UseHypervisor = configurationState.System.UseHypervisor;
if (NeedsOverride(nameof(MultiplayerLanInterfaceId)))
MultiplayerLanInterfaceId = configurationState.Multiplayer.LanInterfaceId;
if (NeedsOverride(nameof(DisableFileLog)))
DisableFileLog = !configurationState.Logger.EnableFileLog;
if (NeedsOverride(nameof(LoggingEnableDebug)))
LoggingEnableDebug = configurationState.Logger.EnableDebug;
if (NeedsOverride(nameof(LoggingDisableStub)))
LoggingDisableStub = !configurationState.Logger.EnableStub;
if (NeedsOverride(nameof(LoggingDisableInfo)))
LoggingDisableInfo = !configurationState.Logger.EnableInfo;
if (NeedsOverride(nameof(LoggingDisableWarning)))
LoggingDisableWarning = !configurationState.Logger.EnableWarn;
if (NeedsOverride(nameof(LoggingDisableError)))
LoggingDisableError = !configurationState.Logger.EnableError;
if (NeedsOverride(nameof(LoggingEnableTrace)))
LoggingEnableTrace = configurationState.Logger.EnableTrace;
if (NeedsOverride(nameof(LoggingDisableGuest)))
LoggingDisableGuest = !configurationState.Logger.EnableGuest;
if (NeedsOverride(nameof(LoggingEnableFsAccessLog)))
LoggingEnableFsAccessLog = configurationState.Logger.EnableFsAccessLog;
if (NeedsOverride(nameof(LoggingGraphicsDebugLevel)))
LoggingGraphicsDebugLevel = configurationState.Logger.GraphicsDebugLevel;
if (NeedsOverride(nameof(ResScale)))
ResScale = configurationState.Graphics.ResScale;
if (NeedsOverride(nameof(MaxAnisotropy)))
MaxAnisotropy = configurationState.Graphics.MaxAnisotropy;
if (NeedsOverride(nameof(AspectRatio)))
AspectRatio = configurationState.Graphics.AspectRatio;
if (NeedsOverride(nameof(BackendThreading)))
BackendThreading = configurationState.Graphics.BackendThreading;
if (NeedsOverride(nameof(DisableMacroHLE)))
DisableMacroHLE = !configurationState.Graphics.EnableMacroHLE;
if (NeedsOverride(nameof(GraphicsShadersDumpPath)))
GraphicsShadersDumpPath = configurationState.Graphics.ShadersDumpPath;
if (NeedsOverride(nameof(GraphicsBackend)))
GraphicsBackend = configurationState.Graphics.GraphicsBackend;
if (NeedsOverride(nameof(AntiAliasing)))
AntiAliasing = configurationState.Graphics.AntiAliasing;
if (NeedsOverride(nameof(ScalingFilter)))
ScalingFilter = configurationState.Graphics.ScalingFilter;
if (NeedsOverride(nameof(ScalingFilterLevel)))
ScalingFilterLevel = configurationState.Graphics.ScalingFilterLevel;
if (NeedsOverride(nameof(DramSize)))
DramSize = configurationState.System.DramSize;
if (NeedsOverride(nameof(IgnoreMissingServices)))
IgnoreMissingServices = configurationState.System.IgnoreMissingServices;
if (NeedsOverride(nameof(IgnoreControllerApplet)))
IgnoreControllerApplet = configurationState.IgnoreApplet;
return;
bool NeedsOverride(string argKey) => originalArgs.None(arg => arg.TrimStart('-').EqualsIgnoreCase(OptionName(argKey)));
string OptionName(string propertyName) =>
typeof(Options)!.GetProperty(propertyName)!.GetCustomAttribute<OptionAttribute>()!.LongName;
}
// General // General
[Option("use-main-config", Required = false, Default = false, HelpText = "Use the settings from what was configured via the UI.")]
public bool InheritConfig { get; set; }
[Option("root-data-dir", Required = false, HelpText = "Set the custom folder path for Ryujinx data.")] [Option("root-data-dir", Required = false, HelpText = "Set the custom folder path for Ryujinx data.")]
public string BaseDataDir { get; set; } public string BaseDataDir { get; set; }
@@ -172,7 +327,7 @@ namespace Ryujinx.Headless.SDL2
public bool LoggingDisableWarning { get; set; } public bool LoggingDisableWarning { get; set; }
[Option("disable-error-logs", Required = false, HelpText = "Disables printing error log messages.")] [Option("disable-error-logs", Required = false, HelpText = "Disables printing error log messages.")]
public bool LoggingEnableError { get; set; } public bool LoggingDisableError { get; set; }
[Option("enable-trace-logs", Required = false, Default = false, HelpText = "Enables printing trace log messages.")] [Option("enable-trace-logs", Required = false, Default = false, HelpText = "Enables printing trace log messages.")]
public bool LoggingEnableTrace { get; set; } public bool LoggingEnableTrace { get; set; }

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@@ -1,6 +1,6 @@
using System; using System;
namespace Ryujinx.Headless.SDL2 namespace Ryujinx.Headless
{ {
class StatusUpdatedEventArgs( class StatusUpdatedEventArgs(
string vSyncMode, string vSyncMode,

View File

@@ -6,7 +6,7 @@ using System;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using static SDL2.SDL; using static SDL2.SDL;
namespace Ryujinx.Headless.SDL2.Vulkan namespace Ryujinx.Headless
{ {
class VulkanWindow : WindowBase class VulkanWindow : WindowBase
{ {

View File

@@ -1,5 +1,6 @@
using Humanizer; using Humanizer;
using LibHac.Tools.Fs; using LibHac.Tools.Fs;
using Ryujinx.Ava;
using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration;
using Ryujinx.Common.Configuration.Hid; using Ryujinx.Common.Configuration.Hid;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
@@ -26,7 +27,7 @@ using AntiAliasing = Ryujinx.Common.Configuration.AntiAliasing;
using ScalingFilter = Ryujinx.Common.Configuration.ScalingFilter; using ScalingFilter = Ryujinx.Common.Configuration.ScalingFilter;
using Switch = Ryujinx.HLE.Switch; using Switch = Ryujinx.HLE.Switch;
namespace Ryujinx.Headless.SDL2 namespace Ryujinx.Headless
{ {
abstract partial class WindowBase : IHostUIHandler, IDisposable abstract partial class WindowBase : IHostUIHandler, IDisposable
{ {
@@ -136,7 +137,7 @@ namespace Ryujinx.Headless.SDL2
private void SetWindowIcon() private void SetWindowIcon()
{ {
Stream iconStream = typeof(WindowBase).Assembly.GetManifestResourceStream("Ryujinx.Headless.SDL2.Ryujinx.bmp"); Stream iconStream = typeof(Program).Assembly.GetManifestResourceStream("HeadlessLogo");
byte[] iconBytes = new byte[iconStream!.Length]; byte[] iconBytes = new byte[iconStream!.Length];
if (iconStream.Read(iconBytes, 0, iconBytes.Length) != iconBytes.Length) if (iconStream.Read(iconBytes, 0, iconBytes.Length) != iconBytes.Length)
@@ -318,7 +319,7 @@ namespace Ryujinx.Headless.SDL2
Device.VSyncMode.ToString(), Device.VSyncMode.ToString(),
dockedMode, dockedMode,
Device.Configuration.AspectRatio.ToText(), Device.Configuration.AspectRatio.ToText(),
$"Game: {Device.Statistics.GetGameFrameRate():00.00} FPS ({Device.Statistics.GetGameFrameTime():00.00} ms)", $"{Device.Statistics.GetGameFrameRate():00.00} FPS ({Device.Statistics.GetGameFrameTime():00.00} ms)",
$"FIFO: {Device.Statistics.GetFifoPercent():0.00} %", $"FIFO: {Device.Statistics.GetFifoPercent():0.00} %",
$"GPU: {_gpuDriverName}")); $"GPU: {_gpuDriverName}"));

View File

@@ -14,6 +14,7 @@ using Ryujinx.Common.GraphicsDriver;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.Common.SystemInterop; using Ryujinx.Common.SystemInterop;
using Ryujinx.Graphics.Vulkan.MoltenVK; using Ryujinx.Graphics.Vulkan.MoltenVK;
using Ryujinx.Headless;
using Ryujinx.SDL2.Common; using Ryujinx.SDL2.Common;
using Ryujinx.UI.App.Common; using Ryujinx.UI.App.Common;
using Ryujinx.UI.Common; using Ryujinx.UI.Common;
@@ -52,9 +53,15 @@ namespace Ryujinx.Ava
} }
PreviewerDetached = true; PreviewerDetached = true;
if (args.Length > 0 && args[0] is "--no-gui" or "nogui")
{
HeadlessRyujinx.Entrypoint(args[1..]);
return 0;
}
Initialize(args); Initialize(args);
LoggerAdapter.Register(); LoggerAdapter.Register();
IconProvider.Current IconProvider.Current
@@ -106,7 +113,7 @@ namespace Ryujinx.Ava
AppDomain.CurrentDomain.UnhandledException += (sender, e) AppDomain.CurrentDomain.UnhandledException += (sender, e)
=> ProcessUnhandledException(sender, e.ExceptionObject as Exception, e.IsTerminating); => ProcessUnhandledException(sender, e.ExceptionObject as Exception, e.IsTerminating);
AppDomain.CurrentDomain.ProcessExit += (_, _) => Exit(); AppDomain.CurrentDomain.ProcessExit += (_, _) => Exit();
// Setup base data directory. // Setup base data directory.
AppDataManager.Initialize(CommandLineState.BaseDirPathArg); AppDataManager.Initialize(CommandLineState.BaseDirPathArg);
@@ -222,7 +229,7 @@ namespace Ryujinx.Ava
UseHardwareAcceleration = CommandLineState.OverrideHardwareAcceleration.Value; UseHardwareAcceleration = CommandLineState.OverrideHardwareAcceleration.Value;
} }
private static void PrintSystemInfo() internal static void PrintSystemInfo()
{ {
Logger.Notice.Print(LogClass.Application, $"{App.FullAppName} Version: {Version}"); Logger.Notice.Print(LogClass.Application, $"{App.FullAppName} Version: {Version}");
SystemInfo.Gather().Print(); SystemInfo.Gather().Print();
@@ -239,7 +246,7 @@ namespace Ryujinx.Ava
: $"Launch Mode: {AppDataManager.Mode}"); : $"Launch Mode: {AppDataManager.Mode}");
} }
private static void ProcessUnhandledException(object sender, Exception ex, bool isTerminating) internal static void ProcessUnhandledException(object sender, Exception ex, bool isTerminating)
{ {
Logger.Log log = Logger.Error ?? Logger.Notice; Logger.Log log = Logger.Error ?? Logger.Notice;
string message = $"Unhandled exception caught: {ex}"; string message = $"Unhandled exception caught: {ex}";
@@ -254,7 +261,7 @@ namespace Ryujinx.Ava
Exit(); Exit();
} }
public static void Exit() internal static void Exit()
{ {
DiscordIntegrationModule.Exit(); DiscordIntegrationModule.Exit();

View File

@@ -43,6 +43,7 @@
<PackageReference Include="Avalonia.Markup.Xaml.Loader" /> <PackageReference Include="Avalonia.Markup.Xaml.Loader" />
<PackageReference Include="Avalonia.Svg" /> <PackageReference Include="Avalonia.Svg" />
<PackageReference Include="Avalonia.Svg.Skia" /> <PackageReference Include="Avalonia.Svg.Skia" />
<PackageReference Include="CommandLineParser" />
<PackageReference Include="DynamicData" /> <PackageReference Include="DynamicData" />
<PackageReference Include="FluentAvaloniaUI" /> <PackageReference Include="FluentAvaloniaUI" />
<PackageReference Include="Projektanker.Icons.Avalonia" /> <PackageReference Include="Projektanker.Icons.Avalonia" />
@@ -162,6 +163,7 @@
<EmbeddedResource Include="Assets\Icons\Controller_JoyConPair.svg" /> <EmbeddedResource Include="Assets\Icons\Controller_JoyConPair.svg" />
<EmbeddedResource Include="Assets\Icons\Controller_JoyConRight.svg" /> <EmbeddedResource Include="Assets\Icons\Controller_JoyConRight.svg" />
<EmbeddedResource Include="Assets\Icons\Controller_ProCon.svg" /> <EmbeddedResource Include="Assets\Icons\Controller_ProCon.svg" />
<EmbeddedResource Include="Headless\Ryujinx.bmp" LogicalName="HeadlessLogo" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<AdditionalFiles Include="Assets\Locales\en_US.json" /> <AdditionalFiles Include="Assets\Locales\en_US.json" />

View File

@@ -91,7 +91,7 @@
HorizontalAlignment="Left" HorizontalAlignment="Left"
VerticalAlignment="Top" VerticalAlignment="Top"
FontSize="16" FontSize="16"
Foreground="{DynamicResource SystemAccentColor}" Foreground="{DynamicResource FavoriteApplicationIconColor}"
IsVisible="{Binding Favorite}" IsVisible="{Binding Favorite}"
Symbol="StarFilled" /> Symbol="StarFilled" />
</Grid> </Grid>

View File

@@ -146,7 +146,7 @@
HorizontalAlignment="Left" HorizontalAlignment="Left"
VerticalAlignment="Top" VerticalAlignment="Top"
FontSize="16" FontSize="16"
Foreground="{DynamicResource SystemAccentColor}" Foreground="{DynamicResource FavoriteApplicationIconColor}"
IsVisible="{Binding Favorite}" IsVisible="{Binding Favorite}"
Symbol="StarFilled" /> Symbol="StarFilled" />
</Grid> </Grid>

View File

@@ -45,7 +45,9 @@ namespace Ryujinx.Ava.UI.ViewModels
} }
} }
public string Developers => LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.AboutPageDeveloperListMore, "gdkchan, Ac_K, marysaka, rip in peri peri, LDj3SNuD, emmaus, Thealexbarney, GoffyDude, TSRBerry, IsaacMarovitz, GreemDev"); public string Developers => "GreemDev";
public string FormerDevelopers => LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.AboutPageDeveloperListMore, "gdkchan, Ac_K, marysaka, rip in peri peri, LDj3SNuD, emmaus, Thealexbarney, GoffyDude, TSRBerry, IsaacMarovitz");
public AboutWindowViewModel() public AboutWindowViewModel()
{ {

View File

@@ -402,7 +402,7 @@ namespace Ryujinx.Ava.UI.ViewModels
public bool OpenDeviceSaveDirectoryEnabled => !SelectedApplication.ControlHolder.ByteSpan.IsZeros() && SelectedApplication.ControlHolder.Value.DeviceSaveDataSize > 0; public bool OpenDeviceSaveDirectoryEnabled => !SelectedApplication.ControlHolder.ByteSpan.IsZeros() && SelectedApplication.ControlHolder.Value.DeviceSaveDataSize > 0;
public bool TrimXCIEnabled => Ryujinx.Common.Utilities.XCIFileTrimmer.CanTrim(SelectedApplication.Path, new Common.XCIFileTrimmerMainWindowLog(this)); public bool TrimXCIEnabled => XCIFileTrimmer.CanTrim(SelectedApplication.Path, new XCITrimmerLog.MainWindow(this));
public bool OpenBcatSaveDirectoryEnabled => !SelectedApplication.ControlHolder.ByteSpan.IsZeros() && SelectedApplication.ControlHolder.Value.BcatDeliveryCacheStorageSize > 0; public bool OpenBcatSaveDirectoryEnabled => !SelectedApplication.ControlHolder.ByteSpan.IsZeros() && SelectedApplication.ControlHolder.Value.BcatDeliveryCacheStorageSize > 0;
@@ -2165,7 +2165,7 @@ namespace Ryujinx.Ava.UI.ViewModels
return; return;
} }
var trimmer = new XCIFileTrimmer(filename, new Common.XCIFileTrimmerMainWindowLog(this)); var trimmer = new XCIFileTrimmer(filename, new XCITrimmerLog.MainWindow(this));
if (trimmer.CanBeTrimmed) if (trimmer.CanBeTrimmed)
{ {

View File

@@ -33,7 +33,7 @@ namespace Ryujinx.Ava.UI.ViewModels
private const string _FileExtXCI = "XCI"; private const string _FileExtXCI = "XCI";
private readonly Ryujinx.Common.Logging.XCIFileTrimmerLog _logger; private readonly Ryujinx.Common.Logging.XCIFileTrimmerLog _logger;
private readonly ApplicationLibrary _applicationLibrary; private ApplicationLibrary ApplicationLibrary => _mainWindowViewModel.ApplicationLibrary;
private Optional<XCITrimmerFileModel> _processingApplication = null; private Optional<XCITrimmerFileModel> _processingApplication = null;
private AvaloniaList<XCITrimmerFileModel> _allXCIFiles = new(); private AvaloniaList<XCITrimmerFileModel> _allXCIFiles = new();
private AvaloniaList<XCITrimmerFileModel> _selectedXCIFiles = new(); private AvaloniaList<XCITrimmerFileModel> _selectedXCIFiles = new();
@@ -47,15 +47,14 @@ namespace Ryujinx.Ava.UI.ViewModels
public XCITrimmerViewModel(MainWindowViewModel mainWindowViewModel) public XCITrimmerViewModel(MainWindowViewModel mainWindowViewModel)
{ {
_logger = new XCIFileTrimmerWindowLog(this); _logger = new XCITrimmerLog.TrimmerWindow(this);
_mainWindowViewModel = mainWindowViewModel; _mainWindowViewModel = mainWindowViewModel;
_applicationLibrary = _mainWindowViewModel.ApplicationLibrary;
LoadXCIApplications(); LoadXCIApplications();
} }
private void LoadXCIApplications() private void LoadXCIApplications()
{ {
var apps = _applicationLibrary.Applications.Items var apps = ApplicationLibrary.Applications.Items
.Where(app => app.FileExtension == _FileExtXCI); .Where(app => app.FileExtension == _FileExtXCI);
foreach (var xciApp in apps) foreach (var xciApp in apps)
@@ -68,7 +67,7 @@ namespace Ryujinx.Ava.UI.ViewModels
string path, string path,
OperationOutcome operationOutcome = OperationOutcome.Undetermined) OperationOutcome operationOutcome = OperationOutcome.Undetermined)
{ {
var xciApp = _applicationLibrary.Applications.Items.First(app => app.FileExtension == _FileExtXCI && app.Path == path); var xciApp = ApplicationLibrary.Applications.Items.First(app => app.FileExtension == _FileExtXCI && app.Path == path);
return XCITrimmerFileModel.FromApplicationData(xciApp, _logger) with { ProcessingOutcome = operationOutcome }; return XCITrimmerFileModel.FromApplicationData(xciApp, _logger) with { ProcessingOutcome = operationOutcome };
} }
@@ -538,4 +537,4 @@ namespace Ryujinx.Ava.UI.ViewModels
} }
} }
} }
} }

View File

@@ -165,7 +165,16 @@
Text="{ext:Locale AboutRyujinxMaintainersTitle}" /> Text="{ext:Locale AboutRyujinxMaintainersTitle}" />
<TextBlock <TextBlock
FontSize="10" FontSize="10"
Text="{Binding Developers}" Margin="0, 0, 0, 5"
TextWrapping="Wrap"
Text="{Binding Developers}"/>
<TextBlock
FontSize="15"
FontWeight="Bold"
Text="{ext:Locale AboutRyujinxFormerMaintainersTitle}" />
<TextBlock
FontSize="10"
Text="{Binding FormerDevelopers}"
TextWrapping="Wrap" /> TextWrapping="Wrap" />
<Button <Button
Padding="5" Padding="5"

View File

@@ -33,7 +33,7 @@ namespace Ryujinx.Ava.UI.Windows
PrimaryButtonText = string.Empty, PrimaryButtonText = string.Empty,
SecondaryButtonText = string.Empty, SecondaryButtonText = string.Empty,
CloseButtonText = LocaleManager.Instance[LocaleKeys.UserProfilesClose], CloseButtonText = LocaleManager.Instance[LocaleKeys.UserProfilesClose],
Content = new AboutWindow(), Content = new AboutWindow()
}; };
Style closeButton = new(x => x.Name("CloseButton")); Style closeButton = new(x => x.Name("CloseButton"));

View File

@@ -74,14 +74,7 @@ namespace Ryujinx.Ava
_platformExt = $"linux_{arch}.tar.gz"; _platformExt = $"linux_{arch}.tar.gz";
} }
Version newVersion; if (!Version.TryParse(Program.Version, out Version currentVersion))
Version currentVersion;
try
{
currentVersion = Version.Parse(Program.Version);
}
catch
{ {
Logger.Error?.Print(LogClass.Application, $"Failed to convert the current {App.FullAppName} version!"); Logger.Error?.Print(LogClass.Application, $"Failed to convert the current {App.FullAppName} version!");
@@ -164,11 +157,7 @@ namespace Ryujinx.Ava
return; return;
} }
try if (!Version.TryParse(_buildVer, out Version newVersion))
{
newVersion = Version.Parse(_buildVer);
}
catch
{ {
Logger.Error?.Print(LogClass.Application, $"Failed to convert the received {App.FullAppName} version from GitHub!"); Logger.Error?.Print(LogClass.Application, $"Failed to convert the received {App.FullAppName} version from GitHub!");