Compare commits
26 Commits
Canary-1.2
...
refactor/a
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
66fdad6d64 | ||
|
|
657bd4a7d0 | ||
|
|
d3a6a8f66e | ||
|
|
12a506a644 | ||
|
|
6f56690c1c | ||
|
|
1398dad67c | ||
|
|
2fc58d58a5 | ||
|
|
75fa7c7d4d | ||
|
|
a477658b85 | ||
|
|
338777055f | ||
|
|
90db9a962d | ||
|
|
4a545a00c6 | ||
|
|
1a005f96e7 | ||
|
|
072cd2824a | ||
|
|
9da97bc911 | ||
|
|
39252b7267 | ||
|
|
ec11bf2af9 | ||
|
|
8ae72c1a00 | ||
|
|
06abba25c1 | ||
|
|
de00a71690 | ||
|
|
315a1819c0 | ||
|
|
4ffb8aef12 | ||
|
|
290a6ad5de | ||
|
|
eda4f4349b | ||
|
|
5fbcb1f3a7 | ||
|
|
d00754477e |
23
.github/workflows/build.yml
vendored
23
.github/workflows/build.yml
vendored
@@ -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'
|
|
||||||
|
|||||||
20
.github/workflows/canary.yml
vendored
20
.github/workflows/canary.yml
vendored
@@ -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
|
||||||
|
|||||||
5
.github/workflows/nightly_pr_comment.yml
vendored
5
.github/workflows/nightly_pr_comment.yml
vendored
@@ -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});
|
||||||
|
|||||||
17
.github/workflows/release.yml
vendored
17
.github/workflows/release.yml
vendored
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
namespace Ryujinx.Common.Configuration.Hid.Controller
|
namespace Ryujinx.Common.Configuration.Hid.Controller
|
||||||
{
|
{
|
||||||
public class JoyconConfigControllerStick<TButton, TStick> where TButton : unmanaged where TStick : unmanaged
|
public class JoyconConfigControllerStick<TButton, TStick>
|
||||||
|
where TButton : unmanaged
|
||||||
|
where TStick : unmanaged
|
||||||
{
|
{
|
||||||
public TStick Joystick { get; set; }
|
public TStick Joystick { get; set; }
|
||||||
public bool InvertStickX { get; set; }
|
public bool InvertStickX { get; set; }
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ namespace Ryujinx.HLE.Loaders.Processes.Extensions
|
|||||||
{
|
{
|
||||||
private static readonly TitleUpdateMetadataJsonSerializerContext _applicationSerializerContext = new(JsonHelper.GetDefaultSerializerOptions());
|
private static readonly TitleUpdateMetadataJsonSerializerContext _applicationSerializerContext = new(JsonHelper.GetDefaultSerializerOptions());
|
||||||
|
|
||||||
public static ProcessResult Load(this Nca nca, Switch device, Nca patchNca, Nca controlNca)
|
public static ProcessResult Load(this Nca nca, Switch device, Nca patchNca, Nca controlNca, BlitStruct<ApplicationControlProperty>? customNacpData = null)
|
||||||
{
|
{
|
||||||
// Extract RomFs and ExeFs from NCA.
|
// Extract RomFs and ExeFs from NCA.
|
||||||
IStorage romFs = nca.GetRomFs(device, patchNca);
|
IStorage romFs = nca.GetRomFs(device, patchNca);
|
||||||
@@ -55,6 +55,10 @@ namespace Ryujinx.HLE.Loaders.Processes.Extensions
|
|||||||
{
|
{
|
||||||
nacpData = controlNca.GetNacp(device);
|
nacpData = controlNca.GetNacp(device);
|
||||||
}
|
}
|
||||||
|
else if (customNacpData != null) // if the Application doesn't provide a nacp file but the Application provides an override, use the provided nacp override
|
||||||
|
{
|
||||||
|
nacpData = (BlitStruct<ApplicationControlProperty>)customNacpData;
|
||||||
|
}
|
||||||
|
|
||||||
/* TODO: Rework this since it's wrong and doesn't work as it takes the DisplayVersion from a "potential" non-existent update.
|
/* TODO: Rework this since it's wrong and doesn't work as it takes the DisplayVersion from a "potential" non-existent update.
|
||||||
|
|
||||||
|
|||||||
@@ -98,12 +98,12 @@ namespace Ryujinx.HLE.Loaders.Processes
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool LoadNca(string path)
|
public bool LoadNca(string path, BlitStruct<ApplicationControlProperty>? customNacpData = null)
|
||||||
{
|
{
|
||||||
FileStream file = new(path, FileMode.Open, FileAccess.Read);
|
FileStream file = new(path, FileMode.Open, FileAccess.Read);
|
||||||
Nca nca = new(_device.Configuration.VirtualFileSystem.KeySet, file.AsStorage(false));
|
Nca nca = new(_device.Configuration.VirtualFileSystem.KeySet, file.AsStorage(false));
|
||||||
|
|
||||||
ProcessResult processResult = nca.Load(_device, null, null);
|
ProcessResult processResult = nca.Load(_device, null, null, customNacpData);
|
||||||
|
|
||||||
if (processResult.ProcessId != 0 && _processesByPid.TryAdd(processResult.ProcessId, processResult))
|
if (processResult.ProcessId != 0 && _processesByPid.TryAdd(processResult.ProcessId, processResult))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -84,12 +84,19 @@ namespace Ryujinx.HLE.Loaders.Processes
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isFirmware = ProgramId is >= 0x0100000000000819 and <= 0x010000000000081C;
|
||||||
|
bool isFirmwareApplication = ProgramId <= 0x0100000000007FFF;
|
||||||
|
|
||||||
|
string name = !isFirmware
|
||||||
|
? (isFirmwareApplication ? "Firmware Application " : "") + (!string.IsNullOrWhiteSpace(Name) ? Name : "<Unknown Name>")
|
||||||
|
: "Firmware";
|
||||||
|
|
||||||
// TODO: LibHac npdm currently doesn't support version field.
|
// TODO: LibHac npdm currently doesn't support version field.
|
||||||
string version = ProgramId > 0x0100000000007FFF
|
string version = !isFirmware
|
||||||
? DisplayVersion
|
? (!string.IsNullOrWhiteSpace(DisplayVersion) ? DisplayVersion : "<Unknown Version>")
|
||||||
: device.System.ContentManager.GetCurrentFirmwareVersion()?.VersionString ?? "?";
|
: device.System.ContentManager.GetCurrentFirmwareVersion()?.VersionString ?? "?";
|
||||||
|
|
||||||
Logger.Info?.Print(LogClass.Loader, $"Application Loaded: {Name} v{version} [{ProgramIdText}] [{(Is64Bit ? "64-bit" : "32-bit")}]");
|
Logger.Info?.Print(LogClass.Loader, $"Application Loaded: {name} v{version} [{ProgramIdText}] [{(Is64Bit ? "64-bit" : "32-bit")}]");
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
37
src/Ryujinx.HLE/StructHelpers.cs
Normal file
37
src/Ryujinx.HLE/StructHelpers.cs
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
using LibHac.Common;
|
||||||
|
using LibHac.Ns;
|
||||||
|
using System;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE
|
||||||
|
{
|
||||||
|
public static class StructHelpers
|
||||||
|
{
|
||||||
|
public static BlitStruct<ApplicationControlProperty> CreateCustomNacpData(string name, string version)
|
||||||
|
{
|
||||||
|
// https://switchbrew.org/wiki/NACP
|
||||||
|
const int OffsetOfDisplayVersion = 0x3060;
|
||||||
|
|
||||||
|
// https://switchbrew.org/wiki/NACP#ApplicationTitle
|
||||||
|
const int TotalApplicationTitles = 0x10;
|
||||||
|
const int SizeOfApplicationTitle = 0x300;
|
||||||
|
const int OffsetOfApplicationPublisherStrings = 0x200;
|
||||||
|
|
||||||
|
|
||||||
|
var nacpData = new BlitStruct<ApplicationControlProperty>(1);
|
||||||
|
|
||||||
|
// name and publisher buffer
|
||||||
|
// repeat once for each locale (the ApplicationControlProperty has 16 locales)
|
||||||
|
for (int i = 0; i < TotalApplicationTitles; i++)
|
||||||
|
{
|
||||||
|
Encoding.ASCII.GetBytes(name).AsSpan().CopyTo(nacpData.ByteSpan[(i * SizeOfApplicationTitle)..]);
|
||||||
|
"Ryujinx"u8.CopyTo(nacpData.ByteSpan[(i * SizeOfApplicationTitle + OffsetOfApplicationPublisherStrings)..]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// version buffer
|
||||||
|
Encoding.ASCII.GetBytes(version).AsSpan().CopyTo(nacpData.ByteSpan[OffsetOfDisplayVersion..]);
|
||||||
|
|
||||||
|
return nacpData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
using LibHac.Common;
|
||||||
|
using LibHac.Ns;
|
||||||
using Ryujinx.Audio.Backends.CompatLayer;
|
using Ryujinx.Audio.Backends.CompatLayer;
|
||||||
using Ryujinx.Audio.Integration;
|
using Ryujinx.Audio.Integration;
|
||||||
using Ryujinx.Common.Configuration;
|
using Ryujinx.Common.Configuration;
|
||||||
@@ -111,7 +113,7 @@ namespace Ryujinx.HLE
|
|||||||
|
|
||||||
public bool LoadCart(string exeFsDir, string romFsFile = null) => Processes.LoadUnpackedNca(exeFsDir, romFsFile);
|
public bool LoadCart(string exeFsDir, string romFsFile = null) => Processes.LoadUnpackedNca(exeFsDir, romFsFile);
|
||||||
public bool LoadXci(string xciFile, ulong applicationId = 0) => Processes.LoadXci(xciFile, applicationId);
|
public bool LoadXci(string xciFile, ulong applicationId = 0) => Processes.LoadXci(xciFile, applicationId);
|
||||||
public bool LoadNca(string ncaFile) => Processes.LoadNca(ncaFile);
|
public bool LoadNca(string ncaFile, BlitStruct<ApplicationControlProperty>? customNacpData = null) => Processes.LoadNca(ncaFile, customNacpData);
|
||||||
public bool LoadNsp(string nspFile, ulong applicationId = 0) => Processes.LoadNsp(nspFile, applicationId);
|
public bool LoadNsp(string nspFile, ulong applicationId = 0) => Processes.LoadNsp(nspFile, applicationId);
|
||||||
public bool LoadProgram(string fileName) => Processes.LoadNxo(fileName);
|
public bool LoadProgram(string fileName) => Processes.LoadNxo(fileName);
|
||||||
|
|
||||||
|
|||||||
@@ -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 |
@@ -1,5 +1,4 @@
|
|||||||
using DynamicData;
|
using DynamicData;
|
||||||
using DynamicData.Kernel;
|
|
||||||
using Gommon;
|
using Gommon;
|
||||||
using LibHac;
|
using LibHac;
|
||||||
using LibHac.Common;
|
using LibHac.Common;
|
||||||
@@ -37,14 +36,13 @@ using System.Threading.Tasks;
|
|||||||
using ContentType = LibHac.Ncm.ContentType;
|
using ContentType = LibHac.Ncm.ContentType;
|
||||||
using MissingKeyException = LibHac.Common.Keys.MissingKeyException;
|
using MissingKeyException = LibHac.Common.Keys.MissingKeyException;
|
||||||
using Path = System.IO.Path;
|
using Path = System.IO.Path;
|
||||||
using SpanHelpers = LibHac.Common.SpanHelpers;
|
|
||||||
using TimeSpan = System.TimeSpan;
|
using TimeSpan = System.TimeSpan;
|
||||||
|
|
||||||
namespace Ryujinx.UI.App.Common
|
namespace Ryujinx.UI.App.Common
|
||||||
{
|
{
|
||||||
public class ApplicationLibrary
|
public class ApplicationLibrary
|
||||||
{
|
{
|
||||||
public static string DefaultLanPlayWebHost = "ryuldnweb.vudjun.com";
|
public const string DefaultLanPlayWebHost = "ryuldnweb.vudjun.com";
|
||||||
public Language DesiredLanguage { get; set; }
|
public Language DesiredLanguage { get; set; }
|
||||||
public event EventHandler<ApplicationCountUpdatedEventArgs> ApplicationCountUpdated;
|
public event EventHandler<ApplicationCountUpdatedEventArgs> ApplicationCountUpdated;
|
||||||
public event EventHandler<LdnGameDataReceivedEventArgs> LdnGameDataReceived;
|
public event EventHandler<LdnGameDataReceivedEventArgs> LdnGameDataReceived;
|
||||||
@@ -191,12 +189,9 @@ namespace Ryujinx.UI.App.Common
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isExeFs)
|
return isExeFs
|
||||||
{
|
? GetApplicationFromExeFs(pfs, filePath)
|
||||||
return GetApplicationFromExeFs(pfs, filePath);
|
: null;
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <exception cref="LibHac.Common.Keys.MissingKeyException">The configured key set is missing a key.</exception>
|
/// <exception cref="LibHac.Common.Keys.MissingKeyException">The configured key set is missing a key.</exception>
|
||||||
@@ -512,10 +507,6 @@ namespace Ryujinx.UI.App.Common
|
|||||||
case ".xci":
|
case ".xci":
|
||||||
case ".nsp":
|
case ".nsp":
|
||||||
{
|
{
|
||||||
IntegrityCheckLevel checkLevel = ConfigurationState.Instance.System.EnableFsIntegrityChecks
|
|
||||||
? IntegrityCheckLevel.ErrorOnInvalid
|
|
||||||
: IntegrityCheckLevel.None;
|
|
||||||
|
|
||||||
using IFileSystem pfs = PartitionFileSystemUtils.OpenApplicationFileSystem(filePath, _virtualFileSystem);
|
using IFileSystem pfs = PartitionFileSystemUtils.OpenApplicationFileSystem(filePath, _virtualFileSystem);
|
||||||
|
|
||||||
foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*.nca"))
|
foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*.nca"))
|
||||||
@@ -604,7 +595,7 @@ namespace Ryujinx.UI.App.Common
|
|||||||
controlNca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.None)
|
controlNca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.None)
|
||||||
.OpenFile(ref nacpFile.Ref, "/control.nacp".ToU8Span(), OpenMode.Read)
|
.OpenFile(ref nacpFile.Ref, "/control.nacp".ToU8Span(), OpenMode.Read)
|
||||||
.ThrowIfFailure();
|
.ThrowIfFailure();
|
||||||
nacpFile.Get.Read(out _, 0, SpanHelpers.AsByteSpan(ref controlData),
|
nacpFile.Get.Read(out _, 0, LibHac.Common.SpanHelpers.AsByteSpan(ref controlData),
|
||||||
ReadOption.None).ThrowIfFailure();
|
ReadOption.None).ThrowIfFailure();
|
||||||
|
|
||||||
var displayVersion = controlData.DisplayVersionString.ToString();
|
var displayVersion = controlData.DisplayVersionString.ToString();
|
||||||
@@ -827,7 +818,7 @@ namespace Ryujinx.UI.App.Common
|
|||||||
{
|
{
|
||||||
_downloadableContents.Edit(it =>
|
_downloadableContents.Edit(it =>
|
||||||
{
|
{
|
||||||
DownloadableContentsHelper.SaveDownloadableContentsJson(_virtualFileSystem, application.IdBase, dlcs);
|
DownloadableContentsHelper.SaveDownloadableContentsJson(application.IdBase, dlcs);
|
||||||
|
|
||||||
it.Remove(it.Items.Where(item => item.Dlc.TitleIdBase == application.IdBase));
|
it.Remove(it.Items.Where(item => item.Dlc.TitleIdBase == application.IdBase));
|
||||||
it.AddOrUpdate(dlcs);
|
it.AddOrUpdate(dlcs);
|
||||||
@@ -839,7 +830,7 @@ namespace Ryujinx.UI.App.Common
|
|||||||
{
|
{
|
||||||
_titleUpdates.Edit(it =>
|
_titleUpdates.Edit(it =>
|
||||||
{
|
{
|
||||||
TitleUpdatesHelper.SaveTitleUpdatesJson(_virtualFileSystem, application.IdBase, updates);
|
TitleUpdatesHelper.SaveTitleUpdatesJson(application.IdBase, updates);
|
||||||
|
|
||||||
it.Remove(it.Items.Where(item => item.TitleUpdate.TitleIdBase == application.IdBase));
|
it.Remove(it.Items.Where(item => item.TitleUpdate.TitleIdBase == application.IdBase));
|
||||||
it.AddOrUpdate(updates);
|
it.AddOrUpdate(updates);
|
||||||
@@ -1088,14 +1079,15 @@ namespace Ryujinx.UI.App.Common
|
|||||||
|
|
||||||
private bool AddAndAutoSelectUpdate(TitleUpdateModel update)
|
private bool AddAndAutoSelectUpdate(TitleUpdateModel update)
|
||||||
{
|
{
|
||||||
var currentlySelected = TitleUpdates.Items.FirstOrOptional(it =>
|
if (update == null) return false;
|
||||||
|
|
||||||
|
var currentlySelected = TitleUpdates.Items.FindFirst(it =>
|
||||||
it.TitleUpdate.TitleIdBase == update.TitleIdBase && it.IsSelected);
|
it.TitleUpdate.TitleIdBase == update.TitleIdBase && it.IsSelected);
|
||||||
|
|
||||||
var shouldSelect = !currentlySelected.HasValue ||
|
var shouldSelect = currentlySelected.Check(curr => curr.TitleUpdate?.Version < update.Version);
|
||||||
currentlySelected.Value.TitleUpdate.Version < update.Version;
|
|
||||||
|
|
||||||
_titleUpdates.AddOrUpdate((update, shouldSelect));
|
_titleUpdates.AddOrUpdate((update, shouldSelect));
|
||||||
|
|
||||||
if (currentlySelected.HasValue && shouldSelect)
|
if (currentlySelected.HasValue && shouldSelect)
|
||||||
{
|
{
|
||||||
_titleUpdates.AddOrUpdate((currentlySelected.Value.TitleUpdate, false));
|
_titleUpdates.AddOrUpdate((currentlySelected.Value.TitleUpdate, false));
|
||||||
@@ -1464,7 +1456,7 @@ namespace Ryujinx.UI.App.Common
|
|||||||
if (addedNewDlc)
|
if (addedNewDlc)
|
||||||
{
|
{
|
||||||
var gameDlcs = it.Items.Where(dlc => dlc.Dlc.TitleIdBase == application.IdBase).ToList();
|
var gameDlcs = it.Items.Where(dlc => dlc.Dlc.TitleIdBase == application.IdBase).ToList();
|
||||||
DownloadableContentsHelper.SaveDownloadableContentsJson(_virtualFileSystem, application.IdBase,
|
DownloadableContentsHelper.SaveDownloadableContentsJson(application.IdBase,
|
||||||
gameDlcs);
|
gameDlcs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1483,11 +1475,11 @@ namespace Ryujinx.UI.App.Common
|
|||||||
TitleUpdatesHelper.LoadTitleUpdatesJson(_virtualFileSystem, application.IdBase);
|
TitleUpdatesHelper.LoadTitleUpdatesJson(_virtualFileSystem, application.IdBase);
|
||||||
it.AddOrUpdate(savedUpdates);
|
it.AddOrUpdate(savedUpdates);
|
||||||
|
|
||||||
var selectedUpdate = savedUpdates.FirstOrOptional(update => update.IsSelected);
|
var selectedUpdate = savedUpdates.FindFirst(update => update.IsSelected);
|
||||||
|
|
||||||
if (TryGetTitleUpdatesFromFile(application.Path, out var bundledUpdates))
|
if (TryGetTitleUpdatesFromFile(application.Path, out var bundledUpdates))
|
||||||
{
|
{
|
||||||
var savedUpdateLookup = savedUpdates.Select(update => update.Item1).ToHashSet();
|
var savedUpdateLookup = savedUpdates.Select(update => update.Update).ToHashSet();
|
||||||
bool updatesChanged = false;
|
bool updatesChanged = false;
|
||||||
|
|
||||||
foreach (var update in bundledUpdates.OrderByDescending(bundled => bundled.Version))
|
foreach (var update in bundledUpdates.OrderByDescending(bundled => bundled.Version))
|
||||||
@@ -1495,12 +1487,11 @@ namespace Ryujinx.UI.App.Common
|
|||||||
if (!savedUpdateLookup.Contains(update))
|
if (!savedUpdateLookup.Contains(update))
|
||||||
{
|
{
|
||||||
bool shouldSelect = false;
|
bool shouldSelect = false;
|
||||||
if (!selectedUpdate.HasValue || selectedUpdate.Value.Item1.Version < update.Version)
|
if (selectedUpdate.Check(su => su.Update?.Version < update.Version))
|
||||||
{
|
{
|
||||||
shouldSelect = true;
|
shouldSelect = true;
|
||||||
if (selectedUpdate.HasValue)
|
_titleUpdates.AddOrUpdate((selectedUpdate.Value.Update, false));
|
||||||
_titleUpdates.AddOrUpdate((selectedUpdate.Value.Item1, false));
|
selectedUpdate = (update, true);
|
||||||
selectedUpdate = DynamicData.Kernel.Optional<(TitleUpdateModel, bool IsSelected)>.Create((update, true));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
modifiedVersion = modifiedVersion || shouldSelect;
|
modifiedVersion = modifiedVersion || shouldSelect;
|
||||||
@@ -1513,7 +1504,7 @@ namespace Ryujinx.UI.App.Common
|
|||||||
if (updatesChanged)
|
if (updatesChanged)
|
||||||
{
|
{
|
||||||
var gameUpdates = it.Items.Where(update => update.TitleUpdate.TitleIdBase == application.IdBase).ToList();
|
var gameUpdates = it.Items.Where(update => update.TitleUpdate.TitleIdBase == application.IdBase).ToList();
|
||||||
TitleUpdatesHelper.SaveTitleUpdatesJson(_virtualFileSystem, application.IdBase, gameUpdates);
|
TitleUpdatesHelper.SaveTitleUpdatesJson(application.IdBase, gameUpdates);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -1525,14 +1516,14 @@ namespace Ryujinx.UI.App.Common
|
|||||||
private void SaveDownloadableContentsForGame(ulong titleIdBase)
|
private void SaveDownloadableContentsForGame(ulong titleIdBase)
|
||||||
{
|
{
|
||||||
var dlcs = DownloadableContents.Items.Where(dlc => dlc.Dlc.TitleIdBase == titleIdBase).ToList();
|
var dlcs = DownloadableContents.Items.Where(dlc => dlc.Dlc.TitleIdBase == titleIdBase).ToList();
|
||||||
DownloadableContentsHelper.SaveDownloadableContentsJson(_virtualFileSystem, titleIdBase, dlcs);
|
DownloadableContentsHelper.SaveDownloadableContentsJson(titleIdBase, dlcs);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save the _currently tracked_ update state for the game
|
// Save the _currently tracked_ update state for the game
|
||||||
private void SaveTitleUpdatesForGame(ulong titleIdBase)
|
private void SaveTitleUpdatesForGame(ulong titleIdBase)
|
||||||
{
|
{
|
||||||
var updates = TitleUpdates.Items.Where(update => update.TitleUpdate.TitleIdBase == titleIdBase).ToList();
|
var updates = TitleUpdates.Items.Where(update => update.TitleUpdate.TitleIdBase == titleIdBase).ToList();
|
||||||
TitleUpdatesHelper.SaveTitleUpdatesJson(_virtualFileSystem, titleIdBase, updates);
|
TitleUpdatesHelper.SaveTitleUpdatesJson(titleIdBase, updates);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ApplicationData isnt live-updating (e.g. when an update gets applied) and so this is meant to trigger a refresh
|
// ApplicationData isnt live-updating (e.g. when an update gets applied) and so this is meant to trigger a refresh
|
||||||
|
|||||||
@@ -1,16 +1,12 @@
|
|||||||
using ARMeilleure;
|
|
||||||
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.Keyboard;
|
using Ryujinx.Common.Configuration.Hid.Keyboard;
|
||||||
using Ryujinx.Common.Configuration.Multiplayer;
|
using Ryujinx.Common.Configuration.Multiplayer;
|
||||||
using Ryujinx.Common.Logging;
|
|
||||||
using Ryujinx.Graphics.Vulkan;
|
using Ryujinx.Graphics.Vulkan;
|
||||||
using Ryujinx.HLE;
|
using Ryujinx.HLE;
|
||||||
using Ryujinx.UI.Common.Configuration.System;
|
using Ryujinx.UI.Common.Configuration.System;
|
||||||
using Ryujinx.UI.Common.Configuration.UI;
|
using Ryujinx.UI.Common.Configuration.UI;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace Ryujinx.UI.Common.Configuration
|
namespace Ryujinx.UI.Common.Configuration
|
||||||
{
|
{
|
||||||
@@ -21,10 +17,10 @@ namespace Ryujinx.UI.Common.Configuration
|
|||||||
if (Instance != null)
|
if (Instance != null)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException("Configuration is already initialized");
|
throw new InvalidOperationException("Configuration is already initialized");
|
||||||
}
|
}
|
||||||
|
|
||||||
Instance = new ConfigurationState();
|
Instance = new ConfigurationState();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConfigurationFileFormat ToFileFormat()
|
public ConfigurationFileFormat ToFileFormat()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ namespace Ryujinx.UI.Common.Helper
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SaveDownloadableContentsJson(VirtualFileSystem vfs, ulong applicationIdBase, List<(DownloadableContentModel, bool IsEnabled)> dlcs)
|
public static void SaveDownloadableContentsJson(ulong applicationIdBase, List<(DownloadableContentModel, bool IsEnabled)> dlcs)
|
||||||
{
|
{
|
||||||
DownloadableContentContainer container = default;
|
DownloadableContentContainer container = default;
|
||||||
List<DownloadableContentContainer> downloadableContentContainerList = new();
|
List<DownloadableContentContainer> downloadableContentContainerList = new();
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ namespace Ryujinx.UI.Common.Helper
|
|||||||
{
|
{
|
||||||
private static readonly TitleUpdateMetadataJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions());
|
private static readonly TitleUpdateMetadataJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions());
|
||||||
|
|
||||||
public static List<(TitleUpdateModel, bool IsSelected)> LoadTitleUpdatesJson(VirtualFileSystem vfs, ulong applicationIdBase)
|
public static List<(TitleUpdateModel Update, bool IsSelected)> LoadTitleUpdatesJson(VirtualFileSystem vfs, ulong applicationIdBase)
|
||||||
{
|
{
|
||||||
var titleUpdatesJsonPath = PathToGameUpdatesJson(applicationIdBase);
|
var titleUpdatesJsonPath = PathToGameUpdatesJson(applicationIdBase);
|
||||||
|
|
||||||
@@ -49,7 +49,7 @@ namespace Ryujinx.UI.Common.Helper
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SaveTitleUpdatesJson(VirtualFileSystem vfs, ulong applicationIdBase, List<(TitleUpdateModel, bool IsSelected)> updates)
|
public static void SaveTitleUpdatesJson(ulong applicationIdBase, List<(TitleUpdateModel, bool IsSelected)> updates)
|
||||||
{
|
{
|
||||||
var titleUpdateWindowData = new TitleUpdateMetadata
|
var titleUpdateWindowData = new TitleUpdateMetadata
|
||||||
{
|
{
|
||||||
@@ -77,7 +77,7 @@ namespace Ryujinx.UI.Common.Helper
|
|||||||
JsonHelper.SerializeToFile(titleUpdatesJsonPath, titleUpdateWindowData, _serializerContext.TitleUpdateMetadata);
|
JsonHelper.SerializeToFile(titleUpdatesJsonPath, titleUpdateWindowData, _serializerContext.TitleUpdateMetadata);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<(TitleUpdateModel, bool IsSelected)> LoadTitleUpdates(VirtualFileSystem vfs, TitleUpdateMetadata titleUpdateMetadata, ulong applicationIdBase)
|
private static List<(TitleUpdateModel Update, bool IsSelected)> LoadTitleUpdates(VirtualFileSystem vfs, TitleUpdateMetadata titleUpdateMetadata, ulong applicationIdBase)
|
||||||
{
|
{
|
||||||
var result = new List<(TitleUpdateModel, bool IsSelected)>();
|
var result = new List<(TitleUpdateModel, bool IsSelected)>();
|
||||||
|
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ using Avalonia.Controls;
|
|||||||
using Avalonia.Controls.ApplicationLifetimes;
|
using Avalonia.Controls.ApplicationLifetimes;
|
||||||
using Avalonia.Input;
|
using Avalonia.Input;
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
|
using LibHac.Common;
|
||||||
|
using LibHac.Ns;
|
||||||
using LibHac.Tools.FsSystem;
|
using LibHac.Tools.FsSystem;
|
||||||
using Ryujinx.Audio.Backends.Dummy;
|
using Ryujinx.Audio.Backends.Dummy;
|
||||||
using Ryujinx.Audio.Backends.OpenAL;
|
using Ryujinx.Audio.Backends.OpenAL;
|
||||||
@@ -670,7 +672,7 @@ namespace Ryujinx.Ava
|
|||||||
_cursorState = CursorStates.ForceChangeCursor;
|
_cursorState = CursorStates.ForceChangeCursor;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> LoadGuestApplication()
|
public async Task<bool> LoadGuestApplication(BlitStruct<ApplicationControlProperty>? customNacpData = null)
|
||||||
{
|
{
|
||||||
InitializeSwitchInstance();
|
InitializeSwitchInstance();
|
||||||
MainWindow.UpdateGraphicsConfig();
|
MainWindow.UpdateGraphicsConfig();
|
||||||
@@ -740,7 +742,7 @@ namespace Ryujinx.Ava
|
|||||||
{
|
{
|
||||||
Logger.Info?.Print(LogClass.Application, "Loading as Firmware Title (NCA).");
|
Logger.Info?.Print(LogClass.Application, "Loading as Firmware Title (NCA).");
|
||||||
|
|
||||||
if (!Device.LoadNca(ApplicationPath))
|
if (!Device.LoadNca(ApplicationPath, customNacpData))
|
||||||
{
|
{
|
||||||
Device.Dispose();
|
Device.Dispose();
|
||||||
|
|
||||||
|
|||||||
@@ -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": "فحصه",
|
||||||
@@ -788,7 +786,7 @@
|
|||||||
"CheatWindowHeading": "الغش متوفر لـ {0} [{1}]",
|
"CheatWindowHeading": "الغش متوفر لـ {0} [{1}]",
|
||||||
"BuildId": "معرف البناء:",
|
"BuildId": "معرف البناء:",
|
||||||
"DlcWindowBundledContentNotice": "Bundled DLC cannot be removed, only disabled.",
|
"DlcWindowBundledContentNotice": "Bundled DLC cannot be removed, only disabled.",
|
||||||
"DlcWindowHeading": "المحتويات القابلة للتنزيل {0}",
|
"DlcWindowHeading": "{0} DLC(s) available",
|
||||||
"DlcWindowDlcAddedMessage": "{0} new downloadable content(s) added",
|
"DlcWindowDlcAddedMessage": "{0} new downloadable content(s) added",
|
||||||
"AutoloadDlcAddedMessage": "{0} new downloadable content(s) added",
|
"AutoloadDlcAddedMessage": "{0} new downloadable content(s) added",
|
||||||
"AutoloadDlcRemovedMessage": "{0} missing downloadable content(s) removed",
|
"AutoloadDlcRemovedMessage": "{0} missing downloadable content(s) removed",
|
||||||
|
|||||||
@@ -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",
|
||||||
@@ -788,7 +786,7 @@
|
|||||||
"CheatWindowHeading": "Cheats verfügbar für {0} [{1}]",
|
"CheatWindowHeading": "Cheats verfügbar für {0} [{1}]",
|
||||||
"DlcWindowBundledContentNotice": "Bundled DLC cannot be removed, only disabled.",
|
"DlcWindowBundledContentNotice": "Bundled DLC cannot be removed, only disabled.",
|
||||||
"BuildId": "BuildId:",
|
"BuildId": "BuildId:",
|
||||||
"DlcWindowHeading": "DLC verfügbar für {0} [{1}]",
|
"DlcWindowHeading": "{0} DLC(s) available",
|
||||||
"DlcWindowDlcAddedMessage": "{0} new downloadable content(s) added",
|
"DlcWindowDlcAddedMessage": "{0} new downloadable content(s) added",
|
||||||
"AutoloadDlcAddedMessage": "{0} new downloadable content(s) added",
|
"AutoloadDlcAddedMessage": "{0} new downloadable content(s) added",
|
||||||
"AutoloadDlcRemovedMessage": "{0} missing downloadable content(s) removed",
|
"AutoloadDlcRemovedMessage": "{0} missing downloadable content(s) removed",
|
||||||
|
|||||||
@@ -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": "Σαρώστε το",
|
||||||
@@ -788,7 +786,7 @@
|
|||||||
"CheatWindowHeading": "Διαθέσιμα Cheats για {0} [{1}]",
|
"CheatWindowHeading": "Διαθέσιμα Cheats για {0} [{1}]",
|
||||||
"BuildId": "BuildId:",
|
"BuildId": "BuildId:",
|
||||||
"DlcWindowBundledContentNotice": "Bundled DLC cannot be removed, only disabled.",
|
"DlcWindowBundledContentNotice": "Bundled DLC cannot be removed, only disabled.",
|
||||||
"DlcWindowHeading": "{0} Downloadable Content(s) available for {1} ({2})",
|
"DlcWindowHeading": "{0} DLC(s) available",
|
||||||
"DlcWindowDlcAddedMessage": "{0} new downloadable content(s) added",
|
"DlcWindowDlcAddedMessage": "{0} new downloadable content(s) added",
|
||||||
"AutoloadDlcAddedMessage": "{0} new downloadable content(s) added",
|
"AutoloadDlcAddedMessage": "{0} new downloadable content(s) added",
|
||||||
"AutoloadDlcRemovedMessage": "{0} missing downloadable content(s) removed",
|
"AutoloadDlcRemovedMessage": "{0} missing downloadable content(s) removed",
|
||||||
|
|||||||
@@ -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",
|
||||||
@@ -802,7 +800,7 @@
|
|||||||
"CheatWindowHeading": "Cheats Available for {0} [{1}]",
|
"CheatWindowHeading": "Cheats Available for {0} [{1}]",
|
||||||
"BuildId": "BuildId:",
|
"BuildId": "BuildId:",
|
||||||
"DlcWindowBundledContentNotice": "Bundled DLC cannot be removed, only disabled.",
|
"DlcWindowBundledContentNotice": "Bundled DLC cannot be removed, only disabled.",
|
||||||
"DlcWindowHeading": "{0} Downloadable Content(s) available for {1} ({2})",
|
"DlcWindowHeading": "{0} DLC(s) available",
|
||||||
"DlcWindowDlcAddedMessage": "{0} new downloadable content(s) added",
|
"DlcWindowDlcAddedMessage": "{0} new downloadable content(s) added",
|
||||||
"AutoloadDlcAddedMessage": "{0} new downloadable content(s) added",
|
"AutoloadDlcAddedMessage": "{0} new downloadable content(s) added",
|
||||||
"AutoloadDlcRemovedMessage": "{0} missing downloadable content(s) removed",
|
"AutoloadDlcRemovedMessage": "{0} missing downloadable content(s) removed",
|
||||||
|
|||||||
@@ -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",
|
||||||
@@ -787,7 +785,7 @@
|
|||||||
"UpdateWindowBundledContentNotice": "Las actualizaciones agrupadas no pueden ser eliminadas, solamente deshabilitadas.",
|
"UpdateWindowBundledContentNotice": "Las actualizaciones agrupadas no pueden ser eliminadas, solamente deshabilitadas.",
|
||||||
"CheatWindowHeading": "Cheats disponibles para {0} [{1}]",
|
"CheatWindowHeading": "Cheats disponibles para {0} [{1}]",
|
||||||
"BuildId": "Id de compilación:",
|
"BuildId": "Id de compilación:",
|
||||||
"DlcWindowHeading": "Contenido descargable disponible para {0} [{1}]",
|
"DlcWindowHeading": "{0} DLC(s) available",
|
||||||
"DlcWindowDlcAddedMessage": "Se agregaron {0} nuevo(s) contenido(s) descargable(s)",
|
"DlcWindowDlcAddedMessage": "Se agregaron {0} nuevo(s) contenido(s) descargable(s)",
|
||||||
"AutoloadDlcAddedMessage": "Se agregaron {0} nuevo(s) contenido(s) descargable(s)",
|
"AutoloadDlcAddedMessage": "Se agregaron {0} nuevo(s) contenido(s) descargable(s)",
|
||||||
"AutoloadDlcRemovedMessage": "Se eliminaron {0} contenido(s) descargable(s) faltantes",
|
"AutoloadDlcRemovedMessage": "Se eliminaron {0} contenido(s) descargable(s) faltantes",
|
||||||
|
|||||||
@@ -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",
|
||||||
@@ -788,7 +786,7 @@
|
|||||||
"CheatWindowHeading": "Cheats disponibles pour {0} [{1}]",
|
"CheatWindowHeading": "Cheats disponibles pour {0} [{1}]",
|
||||||
"BuildId": "BuildId :",
|
"BuildId": "BuildId :",
|
||||||
"DlcWindowBundledContentNotice": "Les DLC inclus avec le jeu ne peuvent pas être supprimés mais peuvent être désactivés.",
|
"DlcWindowBundledContentNotice": "Les DLC inclus avec le jeu ne peuvent pas être supprimés mais peuvent être désactivés.",
|
||||||
"DlcWindowHeading": "{0} Contenu(s) téléchargeable(s)",
|
"DlcWindowHeading": "{0} DLC(s) available",
|
||||||
"DlcWindowDlcAddedMessage": "{0} nouveau(x) contenu(s) téléchargeable(s) ajouté(s)",
|
"DlcWindowDlcAddedMessage": "{0} nouveau(x) contenu(s) téléchargeable(s) ajouté(s)",
|
||||||
"AutoloadDlcAddedMessage": "{0} nouveau(x) contenu(s) téléchargeable(s) ajouté(s)",
|
"AutoloadDlcAddedMessage": "{0} nouveau(x) contenu(s) téléchargeable(s) ajouté(s)",
|
||||||
"AutoloadDlcRemovedMessage": "{0} contenu(s) téléchargeable(s) manquant(s) supprimé(s)",
|
"AutoloadDlcRemovedMessage": "{0} contenu(s) téléchargeable(s) manquant(s) supprimé(s)",
|
||||||
|
|||||||
@@ -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": "סרוק את זה",
|
||||||
|
|||||||
@@ -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",
|
||||||
@@ -788,7 +786,7 @@
|
|||||||
"CheatWindowHeading": "Trucchi disponibili per {0} [{1}]",
|
"CheatWindowHeading": "Trucchi disponibili per {0} [{1}]",
|
||||||
"BuildId": "ID Build",
|
"BuildId": "ID Build",
|
||||||
"DlcWindowBundledContentNotice": "i DLC \"impacchettati\" non possono essere rimossi, ma solo disabilitati.",
|
"DlcWindowBundledContentNotice": "i DLC \"impacchettati\" non possono essere rimossi, ma solo disabilitati.",
|
||||||
"DlcWindowHeading": "DLC disponibili per {0} [{1}]",
|
"DlcWindowHeading": "{0} DLC(s) available",
|
||||||
"DlcWindowDlcAddedMessage": "{0} nuovo/i contenuto/i scaricabile/i aggiunto/i",
|
"DlcWindowDlcAddedMessage": "{0} nuovo/i contenuto/i scaricabile/i aggiunto/i",
|
||||||
"AutoloadDlcAddedMessage": "{0} contenuto/i scaricabile/i aggiunto/i",
|
"AutoloadDlcAddedMessage": "{0} contenuto/i scaricabile/i aggiunto/i",
|
||||||
"AutoloadDlcRemovedMessage": "{0} contenuto/i scaricabile/i mancante/i rimosso/i",
|
"AutoloadDlcRemovedMessage": "{0} contenuto/i scaricabile/i mancante/i rimosso/i",
|
||||||
|
|||||||
@@ -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": "スキャン",
|
||||||
@@ -787,7 +785,7 @@
|
|||||||
"UpdateWindowBundledContentNotice": "Bundled updates cannot be removed, only disabled.",
|
"UpdateWindowBundledContentNotice": "Bundled updates cannot be removed, only disabled.",
|
||||||
"CheatWindowHeading": "利用可能なチート {0} [{1}]",
|
"CheatWindowHeading": "利用可能なチート {0} [{1}]",
|
||||||
"BuildId": "ビルドID:",
|
"BuildId": "ビルドID:",
|
||||||
"DlcWindowHeading": "利用可能な DLC {0} [{1}]",
|
"DlcWindowHeading": "{0} DLC(s) available",
|
||||||
"DlcWindowDlcAddedMessage": "{0} new downloadable content(s) added",
|
"DlcWindowDlcAddedMessage": "{0} new downloadable content(s) added",
|
||||||
"AutoloadDlcAddedMessage": "{0} new downloadable content(s) added",
|
"AutoloadDlcAddedMessage": "{0} new downloadable content(s) added",
|
||||||
"AutoloadDlcRemovedMessage": "{0} missing downloadable content(s) removed",
|
"AutoloadDlcRemovedMessage": "{0} missing downloadable content(s) removed",
|
||||||
|
|||||||
@@ -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": "스캔하기",
|
||||||
@@ -788,7 +786,7 @@
|
|||||||
"CheatWindowHeading": "{0} [{1}]에 사용 가능한 치트",
|
"CheatWindowHeading": "{0} [{1}]에 사용 가능한 치트",
|
||||||
"BuildId": "빌드ID:",
|
"BuildId": "빌드ID:",
|
||||||
"DlcWindowBundledContentNotice": "번들 DLC는 제거할 수 없으며 비활성화만 가능합니다.",
|
"DlcWindowBundledContentNotice": "번들 DLC는 제거할 수 없으며 비활성화만 가능합니다.",
|
||||||
"DlcWindowHeading": "{1} ({2})에 내려받기 가능한 콘텐츠 {0}개 사용 가능",
|
"DlcWindowHeading": "{0} DLC(s) available",
|
||||||
"DlcWindowDlcAddedMessage": "{0}개의 새로운 내려받기 가능한 콘텐츠가 추가됨",
|
"DlcWindowDlcAddedMessage": "{0}개의 새로운 내려받기 가능한 콘텐츠가 추가됨",
|
||||||
"AutoloadDlcAddedMessage": "{0}개의 새로운 내려받기 가능한 콘텐츠가 추가됨",
|
"AutoloadDlcAddedMessage": "{0}개의 새로운 내려받기 가능한 콘텐츠가 추가됨",
|
||||||
"AutoloadDlcRemovedMessage": "{0}개의 내려받기 가능한 콘텐츠가 제거됨",
|
"AutoloadDlcRemovedMessage": "{0}개의 내려받기 가능한 콘텐츠가 제거됨",
|
||||||
|
|||||||
@@ -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",
|
||||||
@@ -788,7 +786,7 @@
|
|||||||
"CheatWindowHeading": "Kody Dostępne dla {0} [{1}]",
|
"CheatWindowHeading": "Kody Dostępne dla {0} [{1}]",
|
||||||
"BuildId": "Identyfikator wersji:",
|
"BuildId": "Identyfikator wersji:",
|
||||||
"DlcWindowBundledContentNotice": "Bundled DLC cannot be removed, only disabled.",
|
"DlcWindowBundledContentNotice": "Bundled DLC cannot be removed, only disabled.",
|
||||||
"DlcWindowHeading": "{0} Zawartości do Pobrania dostępna dla {1} ({2})",
|
"DlcWindowHeading": "{0} DLC(s) available",
|
||||||
"DlcWindowDlcAddedMessage": "{0} new downloadable content(s) added",
|
"DlcWindowDlcAddedMessage": "{0} new downloadable content(s) added",
|
||||||
"AutoloadDlcAddedMessage": "{0} new downloadable content(s) added",
|
"AutoloadDlcAddedMessage": "{0} new downloadable content(s) added",
|
||||||
"AutoloadDlcRemovedMessage": "{0} missing downloadable content(s) removed",
|
"AutoloadDlcRemovedMessage": "{0} missing downloadable content(s) removed",
|
||||||
|
|||||||
@@ -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",
|
||||||
@@ -787,7 +785,7 @@
|
|||||||
"CheatWindowHeading": "Cheats disponíveis para {0} [{1}]",
|
"CheatWindowHeading": "Cheats disponíveis para {0} [{1}]",
|
||||||
"BuildId": "ID da Build:",
|
"BuildId": "ID da Build:",
|
||||||
"DlcWindowBundledContentNotice": "DLCs incorporadas não podem ser removidas, apenas desativadas.",
|
"DlcWindowBundledContentNotice": "DLCs incorporadas não podem ser removidas, apenas desativadas.",
|
||||||
"DlcWindowHeading": "{0} DLCs disponíveis para {1} ({2})",
|
"DlcWindowHeading": "{0} DLC(s) available",
|
||||||
"DlcWindowDlcAddedMessage": "{0} novo(s) conteúdo(s) para download adicionado(s)",
|
"DlcWindowDlcAddedMessage": "{0} novo(s) conteúdo(s) para download adicionado(s)",
|
||||||
"AutoloadDlcAddedMessage": "{0} novo(s) conteúdo(s) para download adicionado(s)",
|
"AutoloadDlcAddedMessage": "{0} novo(s) conteúdo(s) para download adicionado(s)",
|
||||||
"AutoloadDlcRemovedMessage": "{0} conteúdo(s) para download ausente(s) removido(s)",
|
"AutoloadDlcRemovedMessage": "{0} conteúdo(s) para download ausente(s) removido(s)",
|
||||||
|
|||||||
@@ -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": "Сканировать",
|
||||||
@@ -788,7 +786,7 @@
|
|||||||
"CheatWindowHeading": "Доступные читы для {0} [{1}]",
|
"CheatWindowHeading": "Доступные читы для {0} [{1}]",
|
||||||
"BuildId": "ID версии:",
|
"BuildId": "ID версии:",
|
||||||
"DlcWindowBundledContentNotice": "Bundled DLC cannot be removed, only disabled.",
|
"DlcWindowBundledContentNotice": "Bundled DLC cannot be removed, only disabled.",
|
||||||
"DlcWindowHeading": "{0} DLC",
|
"DlcWindowHeading": "{0} DLC(s) available",
|
||||||
"DlcWindowDlcAddedMessage": "{0} new downloadable content(s) added",
|
"DlcWindowDlcAddedMessage": "{0} new downloadable content(s) added",
|
||||||
"AutoloadDlcAddedMessage": "{0} new downloadable content(s) added",
|
"AutoloadDlcAddedMessage": "{0} new downloadable content(s) added",
|
||||||
"AutoloadDlcRemovedMessage": "{0} missing downloadable content(s) removed",
|
"AutoloadDlcRemovedMessage": "{0} missing downloadable content(s) removed",
|
||||||
|
|||||||
@@ -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": "สแกนเลย",
|
||||||
@@ -788,7 +786,7 @@
|
|||||||
"CheatWindowHeading": "สูตรโกงมีให้สำหรับ {0} [{1}]",
|
"CheatWindowHeading": "สูตรโกงมีให้สำหรับ {0} [{1}]",
|
||||||
"BuildId": "รหัสการสร้าง:",
|
"BuildId": "รหัสการสร้าง:",
|
||||||
"DlcWindowBundledContentNotice": "แพ็ค DLC ไม่สามารถลบทิ้งได้ สามารถปิดใช้งานได้เท่านั้น",
|
"DlcWindowBundledContentNotice": "แพ็ค DLC ไม่สามารถลบทิ้งได้ สามารถปิดใช้งานได้เท่านั้น",
|
||||||
"DlcWindowHeading": "{0} DLC ที่สามารถดาวน์โหลดได้",
|
"DlcWindowHeading": "{0} DLC(s) available",
|
||||||
"DlcWindowDlcAddedMessage": "{0} DLC ใหม่ที่เพิ่มเข้ามา",
|
"DlcWindowDlcAddedMessage": "{0} DLC ใหม่ที่เพิ่มเข้ามา",
|
||||||
"AutoloadDlcAddedMessage": "{0} ใหม่ที่เพิ่มเข้ามา",
|
"AutoloadDlcAddedMessage": "{0} ใหม่ที่เพิ่มเข้ามา",
|
||||||
"AutoloadDlcRemovedMessage": "{0} missing downloadable content(s) removed",
|
"AutoloadDlcRemovedMessage": "{0} missing downloadable content(s) removed",
|
||||||
|
|||||||
@@ -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",
|
||||||
@@ -788,7 +786,7 @@
|
|||||||
"CheatWindowHeading": "{0} için Hile mevcut [{1}]",
|
"CheatWindowHeading": "{0} için Hile mevcut [{1}]",
|
||||||
"BuildId": "BuildId:",
|
"BuildId": "BuildId:",
|
||||||
"DlcWindowBundledContentNotice": "Bundled DLC cannot be removed, only disabled.",
|
"DlcWindowBundledContentNotice": "Bundled DLC cannot be removed, only disabled.",
|
||||||
"DlcWindowHeading": "{0} Downloadable Content(s) available for {1} ({2})",
|
"DlcWindowHeading": "{0} DLC(s) available",
|
||||||
"DlcWindowDlcAddedMessage": "{0} new downloadable content(s) added",
|
"DlcWindowDlcAddedMessage": "{0} new downloadable content(s) added",
|
||||||
"AutoloadDlcAddedMessage": "{0} new downloadable content(s) added",
|
"AutoloadDlcAddedMessage": "{0} new downloadable content(s) added",
|
||||||
"AutoloadDlcRemovedMessage": "{0} missing downloadable content(s) removed",
|
"AutoloadDlcRemovedMessage": "{0} missing downloadable content(s) removed",
|
||||||
|
|||||||
@@ -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": "Сканувати",
|
||||||
@@ -788,7 +786,7 @@
|
|||||||
"CheatWindowHeading": "Коди доступні для {0} [{1}]",
|
"CheatWindowHeading": "Коди доступні для {0} [{1}]",
|
||||||
"BuildId": "ID збірки:",
|
"BuildId": "ID збірки:",
|
||||||
"DlcWindowBundledContentNotice": "Bundled DLC cannot be removed, only disabled.",
|
"DlcWindowBundledContentNotice": "Bundled DLC cannot be removed, only disabled.",
|
||||||
"DlcWindowHeading": "Вміст для завантаження, доступний для {1} ({2}): {0}",
|
"DlcWindowHeading": "{0} DLC(s) available",
|
||||||
"DlcWindowDlcAddedMessage": "{0} new downloadable content(s) added",
|
"DlcWindowDlcAddedMessage": "{0} new downloadable content(s) added",
|
||||||
"AutoloadDlcAddedMessage": "{0} new downloadable content(s) added",
|
"AutoloadDlcAddedMessage": "{0} new downloadable content(s) added",
|
||||||
"AutoloadDlcRemovedMessage": "{0} missing downloadable content(s) removed",
|
"AutoloadDlcRemovedMessage": "{0} missing downloadable content(s) removed",
|
||||||
|
|||||||
@@ -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": "扫描",
|
||||||
|
|||||||
@@ -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": "掃描",
|
||||||
@@ -788,7 +786,7 @@
|
|||||||
"CheatWindowHeading": "可用於 {0} [{1}] 的密技",
|
"CheatWindowHeading": "可用於 {0} [{1}] 的密技",
|
||||||
"BuildId": "組建識別碼:",
|
"BuildId": "組建識別碼:",
|
||||||
"DlcWindowBundledContentNotice": "附帶的 DLC 只能被停用而無法被刪除。",
|
"DlcWindowBundledContentNotice": "附帶的 DLC 只能被停用而無法被刪除。",
|
||||||
"DlcWindowHeading": "{0} 個可下載內容",
|
"DlcWindowHeading": "{0} DLC(s) available",
|
||||||
"DlcWindowDlcAddedMessage": "已加入 {0} 個 DLC",
|
"DlcWindowDlcAddedMessage": "已加入 {0} 個 DLC",
|
||||||
"AutoloadDlcAddedMessage": "已加入 {0} 個 DLC",
|
"AutoloadDlcAddedMessage": "已加入 {0} 個 DLC",
|
||||||
"AutoloadDlcRemovedMessage": "已刪除 {0} 個遺失的 DLC",
|
"AutoloadDlcRemovedMessage": "已刪除 {0} 個遺失的 DLC",
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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));
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
45
src/Ryujinx/Common/XCITrimmerLog.cs
Normal file
45
src/Ryujinx/Common/XCITrimmerLog.cs
Normal 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));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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.
|
||||||
@@ -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
|
||||||
{
|
{
|
||||||
361
src/Ryujinx/Headless/HeadlessRyujinx.Init.cs
Normal file
361
src/Ryujinx/Headless/HeadlessRyujinx.Init.cs
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,12 +1,9 @@
|
|||||||
using CommandLine;
|
using CommandLine;
|
||||||
using LibHac.Tools.FsSystem;
|
using Gommon;
|
||||||
using Ryujinx.Audio.Backends.SDL2;
|
using Ryujinx.Ava;
|
||||||
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;
|
||||||
@@ -14,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;
|
||||||
@@ -30,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;
|
||||||
@@ -55,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())
|
||||||
{
|
{
|
||||||
@@ -96,242 +80,89 @@ namespace Ryujinx.Headless.SDL2
|
|||||||
}
|
}
|
||||||
|
|
||||||
Parser.Default.ParseArguments<Options>(args)
|
Parser.Default.ParseArguments<Options>(args)
|
||||||
.WithParsed(Load)
|
.WithParsed(options => Load(args, options))
|
||||||
.WithNotParsed(errors => errors.Output());
|
.WithNotParsed(errors =>
|
||||||
|
{
|
||||||
|
Logger.Error?.PrintMsg(LogClass.Application, "Error parsing command-line arguments:");
|
||||||
|
|
||||||
|
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();
|
||||||
|
|
||||||
@@ -346,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())
|
||||||
{
|
{
|
||||||
@@ -357,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}\")");
|
||||||
|
|
||||||
@@ -374,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}\")");
|
||||||
|
|
||||||
@@ -391,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;
|
||||||
|
|
||||||
@@ -404,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);
|
||||||
@@ -414,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)
|
||||||
{
|
{
|
||||||
@@ -425,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);
|
||||||
@@ -509,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,
|
|
||||||
"",
|
|
||||||
"",
|
|
||||||
options.CustomVSyncInterval);
|
|
||||||
|
|
||||||
return new Switch(configuration);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void ExecutionEntrypoint()
|
private static void ExecutionEntrypoint()
|
||||||
{
|
{
|
||||||
if (OperatingSystem.IsWindows())
|
if (OperatingSystem.IsWindows())
|
||||||
@@ -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
|
||||||
{
|
{
|
||||||
@@ -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; }
|
||||||
BIN
src/Ryujinx/Headless/Ryujinx.bmp
Normal file
BIN
src/Ryujinx/Headless/Ryujinx.bmp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.9 KiB |
@@ -1,6 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace Ryujinx.Headless.SDL2
|
namespace Ryujinx.Headless
|
||||||
{
|
{
|
||||||
class StatusUpdatedEventArgs(
|
class StatusUpdatedEventArgs(
|
||||||
string vSyncMode,
|
string vSyncMode,
|
||||||
@@ -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
|
||||||
{
|
{
|
||||||
@@ -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}"));
|
||||||
|
|
||||||
@@ -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();
|
||||||
|
|
||||||
|
|||||||
@@ -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" />
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ using DynamicData;
|
|||||||
using DynamicData.Binding;
|
using DynamicData.Binding;
|
||||||
using FluentAvalonia.UI.Controls;
|
using FluentAvalonia.UI.Controls;
|
||||||
using LibHac.Common;
|
using LibHac.Common;
|
||||||
|
using LibHac.Ns;
|
||||||
using Ryujinx.Ava.Common;
|
using Ryujinx.Ava.Common;
|
||||||
using Ryujinx.Ava.Common.Locale;
|
using Ryujinx.Ava.Common.Locale;
|
||||||
using Ryujinx.Ava.Input;
|
using Ryujinx.Ava.Input;
|
||||||
@@ -401,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;
|
||||||
|
|
||||||
@@ -1897,7 +1898,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task LoadApplication(ApplicationData application, bool startFullscreen = false)
|
public async Task LoadApplication(ApplicationData application, bool startFullscreen = false, BlitStruct<ApplicationControlProperty>? customNacpData = null)
|
||||||
{
|
{
|
||||||
if (AppHost != null)
|
if (AppHost != null)
|
||||||
{
|
{
|
||||||
@@ -1935,7 +1936,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
this,
|
this,
|
||||||
TopLevel);
|
TopLevel);
|
||||||
|
|
||||||
if (!await AppHost.LoadGuestApplication())
|
if (!await AppHost.LoadGuestApplication(customNacpData))
|
||||||
{
|
{
|
||||||
AppHost.DisposeContext();
|
AppHost.DisposeContext();
|
||||||
AppHost = null;
|
AppHost = null;
|
||||||
@@ -2164,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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,9 @@ using Avalonia.Controls;
|
|||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
using Gommon;
|
using Gommon;
|
||||||
|
using LibHac.Common;
|
||||||
using LibHac.Ncm;
|
using LibHac.Ncm;
|
||||||
|
using LibHac.Ns;
|
||||||
using LibHac.Tools.FsSystem.NcaUtils;
|
using LibHac.Tools.FsSystem.NcaUtils;
|
||||||
using Ryujinx.Ava.Common.Locale;
|
using Ryujinx.Ava.Common.Locale;
|
||||||
using Ryujinx.Ava.UI.Helpers;
|
using Ryujinx.Ava.UI.Helpers;
|
||||||
@@ -11,6 +13,7 @@ using Ryujinx.Ava.UI.ViewModels;
|
|||||||
using Ryujinx.Ava.UI.Windows;
|
using Ryujinx.Ava.UI.Windows;
|
||||||
using Ryujinx.Common;
|
using Ryujinx.Common;
|
||||||
using Ryujinx.Common.Utilities;
|
using Ryujinx.Common.Utilities;
|
||||||
|
using Ryujinx.HLE;
|
||||||
using Ryujinx.UI.App.Common;
|
using Ryujinx.UI.App.Common;
|
||||||
using Ryujinx.UI.Common;
|
using Ryujinx.UI.Common;
|
||||||
using Ryujinx.UI.Common.Configuration;
|
using Ryujinx.UI.Common.Configuration;
|
||||||
@@ -19,6 +22,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
namespace Ryujinx.Ava.UI.Views.Main
|
namespace Ryujinx.Ava.UI.Views.Main
|
||||||
{
|
{
|
||||||
@@ -123,18 +127,24 @@ namespace Ryujinx.Ava.UI.Views.Main
|
|||||||
|
|
||||||
public async void OpenMiiApplet(object sender, RoutedEventArgs e)
|
public async void OpenMiiApplet(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
string contentPath = ViewModel.ContentManager.GetInstalledContentPath(0x0100000000001009, StorageId.BuiltInSystem, NcaContentType.Program);
|
const string AppletName = "miiEdit";
|
||||||
|
const ulong AppletProgramId = 0x0100000000001009;
|
||||||
|
const string AppletVersion = "1.0.0";
|
||||||
|
|
||||||
|
string contentPath = ViewModel.ContentManager.GetInstalledContentPath(AppletProgramId, StorageId.BuiltInSystem, NcaContentType.Program);
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(contentPath))
|
if (!string.IsNullOrEmpty(contentPath))
|
||||||
{
|
{
|
||||||
ApplicationData applicationData = new()
|
ApplicationData applicationData = new()
|
||||||
{
|
{
|
||||||
Name = "miiEdit",
|
Name = AppletName,
|
||||||
Id = 0x0100000000001009,
|
Id = AppletProgramId,
|
||||||
Path = contentPath,
|
Path = contentPath
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var nacpData = StructHelpers.CreateCustomNacpData(AppletName, AppletVersion);
|
||||||
|
|
||||||
await ViewModel.LoadApplication(applicationData, ViewModel.IsFullScreen || ViewModel.StartGamesInFullscreen);
|
await ViewModel.LoadApplication(applicationData, ViewModel.IsFullScreen || ViewModel.StartGamesInFullscreen, nacpData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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"));
|
||||||
|
|||||||
@@ -61,23 +61,17 @@ namespace Ryujinx.Ava.UI.Windows
|
|||||||
|
|
||||||
private void RemoveDLC(object sender, RoutedEventArgs e)
|
private void RemoveDLC(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
if (sender is Button button)
|
if (sender is Button { DataContext: DownloadableContentModel dlc })
|
||||||
{
|
{
|
||||||
if (button.DataContext is DownloadableContentModel model)
|
ViewModel.Remove(dlc);
|
||||||
{
|
|
||||||
ViewModel.Remove(model);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OpenLocation(object sender, RoutedEventArgs e)
|
private void OpenLocation(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
if (sender is Button button)
|
if (sender is Button { DataContext: DownloadableContentModel dlc })
|
||||||
{
|
{
|
||||||
if (button.DataContext is DownloadableContentModel model)
|
OpenHelper.LocateFile(dlc.ContainerPath);
|
||||||
{
|
|
||||||
OpenHelper.LocateFile(model.ContainerPath);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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!");
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user