Compare commits
69 Commits
1.2.49
...
Canary-1.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
abfcfcaf0f | ||
|
|
d404a8b05b | ||
|
|
42cbe24bb1 | ||
|
|
79ba9d1258 | ||
|
|
826ffd4a04 | ||
|
|
7369079459 | ||
|
|
a506d81989 | ||
|
|
15c20920b3 | ||
|
|
285ee276b6 | ||
|
|
617b81e209 | ||
|
|
eb6ce7bcb3 | ||
|
|
69f75f2df1 | ||
|
|
10c8d73b60 | ||
|
|
e01a30016e | ||
|
|
e26625dfd5 | ||
|
|
9c82d98ec4 | ||
|
|
4aae82bad1 | ||
|
|
299be822c4 | ||
|
|
b17e4f79fb | ||
|
|
a7b58df3fe | ||
|
|
8c2d6192ba | ||
|
|
2a23000fed | ||
|
|
ab7d0a2e6d | ||
|
|
bd2681b2f9 | ||
|
|
640d7f9e77 | ||
|
|
02e8278438 | ||
|
|
6acd86c890 | ||
|
|
708256ce96 | ||
|
|
5bf50836e1 | ||
|
|
730ba44043 | ||
|
|
36c374cc7a | ||
|
|
75f714488e | ||
|
|
4831965404 | ||
|
|
47b8145809 | ||
|
|
20cc21add6 | ||
|
|
683baec1af | ||
|
|
f4957d2a09 | ||
|
|
3e1182af22 | ||
|
|
6664ed1b11 | ||
|
|
0c88b9eff7 | ||
|
|
8a064bcd7e | ||
|
|
5ff962be37 | ||
|
|
d9c8b7d937 | ||
|
|
feeeafe8fe | ||
|
|
04f014c777 | ||
|
|
4a677deb50 | ||
|
|
1c07bf3dd0 | ||
|
|
4c83794254 | ||
|
|
6911e288bc | ||
|
|
67ab54e2bb | ||
|
|
139c195eb7 | ||
|
|
9305d171e7 | ||
|
|
fb4ab5ea08 | ||
|
|
d7e17abade | ||
|
|
bdb92224f9 | ||
|
|
b21740c931 | ||
|
|
4f06c343a4 | ||
|
|
6c6f18509b | ||
|
|
70b7c4c1c3 | ||
|
|
7764a74a6d | ||
|
|
5de2c4f292 | ||
|
|
5845787325 | ||
|
|
9c94db1130 | ||
|
|
1c3347c95a | ||
|
|
b70580bc9f | ||
|
|
4926df42a4 | ||
|
|
7038a902c3 | ||
|
|
6be8838043 | ||
|
|
033ea86c1b |
4
.github/workflows/build.yml
vendored
4
.github/workflows/build.yml
vendored
@@ -61,11 +61,11 @@ jobs:
|
|||||||
if: matrix.platform.name != 'linux-arm64'
|
if: matrix.platform.name != 'linux-arm64'
|
||||||
|
|
||||||
- name: Publish Ryujinx
|
- name: Publish Ryujinx
|
||||||
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 true
|
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
|
- 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 true
|
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'
|
if: github.event_name == 'pull_request' && matrix.platform.os != 'macos-13'
|
||||||
|
|
||||||
- name: Set executable bit
|
- name: Set executable bit
|
||||||
|
|||||||
257
.github/workflows/canary.yml
vendored
Normal file
257
.github/workflows/canary.yml
vendored
Normal file
@@ -0,0 +1,257 @@
|
|||||||
|
name: Canary release job
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs: {}
|
||||||
|
push:
|
||||||
|
branches: [ master ]
|
||||||
|
paths-ignore:
|
||||||
|
- '.github/**'
|
||||||
|
- 'docs/**'
|
||||||
|
- 'assets/**'
|
||||||
|
- '*.yml'
|
||||||
|
- '*.json'
|
||||||
|
- '*.config'
|
||||||
|
- '*.md'
|
||||||
|
|
||||||
|
concurrency: release
|
||||||
|
|
||||||
|
env:
|
||||||
|
POWERSHELL_TELEMETRY_OPTOUT: 1
|
||||||
|
DOTNET_CLI_TELEMETRY_OPTOUT: 1
|
||||||
|
RYUJINX_BASE_VERSION: "1.2"
|
||||||
|
RYUJINX_TARGET_RELEASE_CHANNEL_NAME: "canary"
|
||||||
|
RYUJINX_TARGET_RELEASE_CHANNEL_OWNER: "GreemDev"
|
||||||
|
RYUJINX_TARGET_RELEASE_CHANNEL_SOURCE_REPO: "Ryujinx"
|
||||||
|
RYUJINX_TARGET_RELEASE_CHANNEL_REPO: "Ryujinx-Canary"
|
||||||
|
RELEASE: 1
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
tag:
|
||||||
|
name: Create tag
|
||||||
|
runs-on: ubuntu-20.04
|
||||||
|
steps:
|
||||||
|
- name: Get version info
|
||||||
|
id: version_info
|
||||||
|
run: |
|
||||||
|
echo "build_version=${{ env.RYUJINX_BASE_VERSION }}.${{ github.run_number }}" >> $GITHUB_OUTPUT
|
||||||
|
echo "prev_build_version=${{ env.RYUJINX_BASE_VERSION }}.$((${{ github.run_number }} - 1))" >> $GITHUB_OUTPUT
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
- name: Create tag
|
||||||
|
uses: actions/github-script@v7
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
github.rest.git.createRef({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
ref: 'refs/tags/Canary-${{ steps.version_info.outputs.build_version }}',
|
||||||
|
sha: context.sha
|
||||||
|
})
|
||||||
|
|
||||||
|
- name: Create release
|
||||||
|
uses: ncipollo/release-action@v1
|
||||||
|
with:
|
||||||
|
name: "Canary ${{ 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 }}"
|
||||||
|
omitBodyDuringUpdate: true
|
||||||
|
owner: ${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}
|
||||||
|
repo: ${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}
|
||||||
|
token: ${{ secrets.RELEASE_TOKEN }}
|
||||||
|
|
||||||
|
release:
|
||||||
|
name: Release for ${{ matrix.platform.name }}
|
||||||
|
runs-on: ${{ matrix.platform.os }}
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
platform:
|
||||||
|
- { name: win-x64, os: windows-latest, zip_os_name: win_x64 }
|
||||||
|
- { name: linux-x64, os: ubuntu-latest, zip_os_name: linux_x64 }
|
||||||
|
- { name: linux-arm64, os: ubuntu-latest, zip_os_name: linux_arm64 }
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- uses: actions/setup-dotnet@v4
|
||||||
|
with:
|
||||||
|
global-json-file: global.json
|
||||||
|
|
||||||
|
- name: Overwrite csc problem matcher
|
||||||
|
run: echo "::add-matcher::.github/csc.json"
|
||||||
|
|
||||||
|
- name: Get version info
|
||||||
|
id: version_info
|
||||||
|
run: |
|
||||||
|
echo "build_version=${{ env.RYUJINX_BASE_VERSION }}.${{ github.run_number }}" >> $GITHUB_OUTPUT
|
||||||
|
echo "prev_build_version=${{ env.RYUJINX_BASE_VERSION }}.$((${{ github.run_number }} - 1))" >> $GITHUB_OUTPUT
|
||||||
|
echo "git_short_hash=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
- name: Configure for release
|
||||||
|
run: |
|
||||||
|
sed -r --in-place 's/\%\%RYUJINX_BUILD_VERSION\%\%/${{ steps.version_info.outputs.build_version }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||||
|
sed -r --in-place 's/\%\%RYUJINX_BUILD_GIT_HASH\%\%/${{ steps.version_info.outputs.git_short_hash }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||||
|
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_NAME\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_NAME }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||||
|
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_OWNER\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||||
|
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_REPO\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||||
|
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_SOURCE_REPO\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_SOURCE_REPO }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||||
|
sed -r --in-place 's/\%\%RYUJINX_CONFIG_FILE_NAME\%\%/Config\.json/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
- name: Create output dir
|
||||||
|
run: "mkdir release_output"
|
||||||
|
|
||||||
|
- name: Publish
|
||||||
|
run: |
|
||||||
|
dotnet publish -c Release -r "${{ matrix.platform.name }}" -o ./publish_ava/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx --self-contained -p:IncludeNativeLibrariesForSelfExtract=true
|
||||||
|
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 -p:IncludeNativeLibrariesForSelfExtract=true
|
||||||
|
|
||||||
|
- name: Packing Windows builds
|
||||||
|
if: matrix.platform.os == 'windows-latest'
|
||||||
|
run: |
|
||||||
|
pushd publish_ava
|
||||||
|
rm publish/libarmeilleure-jitsupport.dylib
|
||||||
|
7z a ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip publish
|
||||||
|
popd
|
||||||
|
|
||||||
|
pushd publish_sdl2_headless
|
||||||
|
rm publish/libarmeilleure-jitsupport.dylib
|
||||||
|
7z a ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip publish
|
||||||
|
popd
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
- name: Packing Linux builds
|
||||||
|
if: matrix.platform.os == 'ubuntu-latest'
|
||||||
|
run: |
|
||||||
|
pushd publish_ava
|
||||||
|
rm publish/libarmeilleure-jitsupport.dylib
|
||||||
|
chmod +x publish/Ryujinx.sh publish/Ryujinx
|
||||||
|
tar -czvf ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz publish
|
||||||
|
popd
|
||||||
|
|
||||||
|
pushd publish_sdl2_headless
|
||||||
|
rm publish/libarmeilleure-jitsupport.dylib
|
||||||
|
chmod +x publish/Ryujinx.sh publish/Ryujinx.Headless.SDL2
|
||||||
|
tar -czvf ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz publish
|
||||||
|
popd
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
#- name: Build AppImage (Linux)
|
||||||
|
# if: matrix.platform.os == 'ubuntu-latest'
|
||||||
|
# run: |
|
||||||
|
# BUILD_VERSION="${{ steps.version_info.outputs.build_version }}"
|
||||||
|
# PLATFORM_NAME="${{ matrix.platform.name }}"
|
||||||
|
|
||||||
|
# sudo apt install -y zsync desktop-file-utils appstream
|
||||||
|
|
||||||
|
# mkdir -p tools
|
||||||
|
# export PATH="$PATH:$(readlink -f tools)"
|
||||||
|
|
||||||
|
# Setup appimagetool
|
||||||
|
# wget -q -O tools/appimagetool "https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-x86_64.AppImage"
|
||||||
|
# chmod +x tools/appimagetool
|
||||||
|
# chmod +x distribution/linux/appimage/build-appimage.sh
|
||||||
|
|
||||||
|
# Explicitly set $ARCH for appimagetool ($ARCH_NAME is for the file name)
|
||||||
|
# if [ "$PLATFORM_NAME" = "linux-x64" ]; then
|
||||||
|
# ARCH_NAME=x64
|
||||||
|
# export ARCH=x86_64
|
||||||
|
# elif [ "$PLATFORM_NAME" = "linux-arm64" ]; then
|
||||||
|
# ARCH_NAME=arm64
|
||||||
|
# export ARCH=aarch64
|
||||||
|
# else
|
||||||
|
# echo "Unexpected PLATFORM_NAME "$PLATFORM_NAME""
|
||||||
|
# exit 1
|
||||||
|
# fi
|
||||||
|
|
||||||
|
# export UFLAG="gh-releases-zsync|${{ github.repository_owner }}|${{ github.event.repository.name }}|latest|*-$ARCH_NAME.AppImage.zsync"
|
||||||
|
# BUILDDIR=publish_ava OUTDIR=publish_ava_appimage distribution/linux/appimage/build-appimage.sh
|
||||||
|
|
||||||
|
# Add to release output
|
||||||
|
# pushd publish_ava_appimage
|
||||||
|
# mv Ryujinx.AppImage ../release_output/ryujinx-$BUILD_VERSION-$ARCH_NAME.AppImage
|
||||||
|
# mv Ryujinx.AppImage.zsync ../release_output/ryujinx-$BUILD_VERSION-$ARCH_NAME.AppImage.zsync
|
||||||
|
# popd
|
||||||
|
# shell: bash
|
||||||
|
|
||||||
|
- name: Pushing new release
|
||||||
|
uses: ncipollo/release-action@v1
|
||||||
|
with:
|
||||||
|
name: ${{ steps.version_info.outputs.build_version }}
|
||||||
|
artifacts: "release_output/*.tar.gz,release_output/*.zip"
|
||||||
|
#artifacts: "release_output/*.tar.gz,release_output/*.zip/*AppImage*"
|
||||||
|
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 }}"
|
||||||
|
omitBodyDuringUpdate: true
|
||||||
|
allowUpdates: true
|
||||||
|
replacesArtifacts: true
|
||||||
|
owner: ${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}
|
||||||
|
repo: ${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}
|
||||||
|
token: ${{ secrets.RELEASE_TOKEN }}
|
||||||
|
|
||||||
|
macos_release:
|
||||||
|
name: Release MacOS universal
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- uses: actions/setup-dotnet@v4
|
||||||
|
with:
|
||||||
|
global-json-file: global.json
|
||||||
|
|
||||||
|
- name: Setup LLVM 15
|
||||||
|
run: |
|
||||||
|
wget https://apt.llvm.org/llvm.sh
|
||||||
|
chmod +x llvm.sh
|
||||||
|
sudo ./llvm.sh 15
|
||||||
|
|
||||||
|
- name: Install rcodesign
|
||||||
|
run: |
|
||||||
|
mkdir -p $HOME/.bin
|
||||||
|
gh release download -R indygreg/apple-platform-rs -O apple-codesign.tar.gz -p 'apple-codesign-*-x86_64-unknown-linux-musl.tar.gz'
|
||||||
|
tar -xzvf apple-codesign.tar.gz --wildcards '*/rcodesign' --strip-components=1
|
||||||
|
rm apple-codesign.tar.gz
|
||||||
|
mv rcodesign $HOME/.bin/
|
||||||
|
echo "$HOME/.bin" >> $GITHUB_PATH
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Get version info
|
||||||
|
id: version_info
|
||||||
|
run: |
|
||||||
|
echo "build_version=${{ env.RYUJINX_BASE_VERSION }}.${{ github.run_number }}" >> $GITHUB_OUTPUT
|
||||||
|
echo "prev_build_version=${{ env.RYUJINX_BASE_VERSION }}.$((${{ github.run_number }} - 1))" >> $GITHUB_OUTPUT
|
||||||
|
echo "git_short_hash=$(git rev-parse --short "${{ github.sha }}")" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Configure for release
|
||||||
|
run: |
|
||||||
|
sed -r --in-place 's/\%\%RYUJINX_BUILD_VERSION\%\%/${{ steps.version_info.outputs.build_version }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||||
|
sed -r --in-place 's/\%\%RYUJINX_BUILD_GIT_HASH\%\%/${{ steps.version_info.outputs.git_short_hash }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||||
|
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_NAME\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_NAME }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||||
|
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_OWNER\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||||
|
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_REPO\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||||
|
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_SOURCE_REPO\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_SOURCE_REPO }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||||
|
sed -r --in-place 's/\%\%RYUJINX_CONFIG_FILE_NAME\%\%/Config\.json/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||||
|
shell: bash
|
||||||
|
|
||||||
|
- name: Publish macOS Ryujinx
|
||||||
|
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
|
||||||
|
|
||||||
|
- 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
|
||||||
|
|
||||||
|
- name: Pushing new release
|
||||||
|
uses: ncipollo/release-action@v1
|
||||||
|
with:
|
||||||
|
name: "Canary ${{ steps.version_info.outputs.build_version }}"
|
||||||
|
artifacts: "publish_ava/*.tar.gz, publish_headless/*.tar.gz"
|
||||||
|
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 }}"
|
||||||
|
omitBodyDuringUpdate: true
|
||||||
|
allowUpdates: true
|
||||||
|
replacesArtifacts: true
|
||||||
|
owner: ${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}
|
||||||
|
repo: ${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}
|
||||||
|
token: ${{ secrets.RELEASE_TOKEN }}
|
||||||
55
.github/workflows/release.yml
vendored
55
.github/workflows/release.yml
vendored
@@ -4,7 +4,7 @@ on:
|
|||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs: {}
|
inputs: {}
|
||||||
push:
|
push:
|
||||||
branches: [ master ]
|
branches: [ release ]
|
||||||
paths-ignore:
|
paths-ignore:
|
||||||
- '.github/**'
|
- '.github/**'
|
||||||
- 'docs/**'
|
- 'docs/**'
|
||||||
@@ -20,7 +20,7 @@ env:
|
|||||||
POWERSHELL_TELEMETRY_OPTOUT: 1
|
POWERSHELL_TELEMETRY_OPTOUT: 1
|
||||||
DOTNET_CLI_TELEMETRY_OPTOUT: 1
|
DOTNET_CLI_TELEMETRY_OPTOUT: 1
|
||||||
RYUJINX_BASE_VERSION: "1.2"
|
RYUJINX_BASE_VERSION: "1.2"
|
||||||
RYUJINX_TARGET_RELEASE_CHANNEL_NAME: "master"
|
RYUJINX_TARGET_RELEASE_CHANNEL_NAME: "release"
|
||||||
RYUJINX_TARGET_RELEASE_CHANNEL_OWNER: "GreemDev"
|
RYUJINX_TARGET_RELEASE_CHANNEL_OWNER: "GreemDev"
|
||||||
RYUJINX_TARGET_RELEASE_CHANNEL_REPO: "Ryujinx"
|
RYUJINX_TARGET_RELEASE_CHANNEL_REPO: "Ryujinx"
|
||||||
RELEASE: 1
|
RELEASE: 1
|
||||||
@@ -93,6 +93,7 @@ jobs:
|
|||||||
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_NAME\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_NAME }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_NAME\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_NAME }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||||
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_OWNER\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_OWNER\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||||
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_REPO\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_REPO\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||||
|
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_SOURCE_REPO\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||||
sed -r --in-place 's/\%\%RYUJINX_CONFIG_FILE_NAME\%\%/Config\.json/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
sed -r --in-place 's/\%\%RYUJINX_CONFIG_FILE_NAME\%\%/Config\.json/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
@@ -101,32 +102,20 @@ 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 true
|
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 -p:IncludeNativeLibrariesForSelfExtract=true
|
||||||
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 true
|
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 -p:IncludeNativeLibrariesForSelfExtract=true
|
||||||
|
|
||||||
- name: Packing Windows builds
|
- name: Packing Windows builds
|
||||||
if: matrix.platform.os == 'windows-latest'
|
if: matrix.platform.os == 'windows-latest'
|
||||||
run: |
|
run: |
|
||||||
pushd publish_ava
|
pushd publish
|
||||||
7z a ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip publish
|
rm libarmeilleure-jitsupport.dylib
|
||||||
|
7z a ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip ../publish
|
||||||
popd
|
popd
|
||||||
|
|
||||||
pushd publish_sdl2_headless
|
pushd publish_sdl2_headless
|
||||||
7z a ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip publish
|
rm libarmeilleure-jitsupport.dylib
|
||||||
popd
|
7z a ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip ../publish
|
||||||
shell: bash
|
|
||||||
|
|
||||||
- name: Packing Linux builds
|
|
||||||
if: matrix.platform.os == 'ubuntu-latest'
|
|
||||||
run: |
|
|
||||||
pushd publish_ava
|
|
||||||
chmod +x publish/Ryujinx.sh publish/Ryujinx
|
|
||||||
tar -czvf ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz publish
|
|
||||||
popd
|
|
||||||
|
|
||||||
pushd publish_sdl2_headless
|
|
||||||
chmod +x publish/Ryujinx.sh publish/Ryujinx.Headless.SDL2
|
|
||||||
tar -czvf ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz publish
|
|
||||||
popd
|
popd
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
@@ -159,15 +148,28 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
export UFLAG="gh-releases-zsync|${{ github.repository_owner }}|${{ github.event.repository.name }}|latest|*-$ARCH_NAME.AppImage.zsync"
|
export UFLAG="gh-releases-zsync|${{ github.repository_owner }}|${{ github.event.repository.name }}|latest|*-$ARCH_NAME.AppImage.zsync"
|
||||||
BUILDDIR=publish_ava OUTDIR=publish_ava_appimage distribution/linux/appimage/build-appimage.sh
|
BUILDDIR=publish OUTDIR=publish_appimage distribution/linux/appimage/build-appimage.sh
|
||||||
|
|
||||||
# Add to release output
|
pushd publish_appimage
|
||||||
pushd publish_ava_appimage
|
|
||||||
mv Ryujinx.AppImage ../release_output/ryujinx-$BUILD_VERSION-$ARCH_NAME.AppImage
|
mv Ryujinx.AppImage ../release_output/ryujinx-$BUILD_VERSION-$ARCH_NAME.AppImage
|
||||||
mv Ryujinx.AppImage.zsync ../release_output/ryujinx-$BUILD_VERSION-$ARCH_NAME.AppImage.zsync
|
mv Ryujinx.AppImage.zsync ../release_output/ryujinx-$BUILD_VERSION-$ARCH_NAME.AppImage.zsync
|
||||||
popd
|
popd
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
|
- name: Packing Linux builds
|
||||||
|
if: matrix.platform.os == 'ubuntu-latest'
|
||||||
|
run: |
|
||||||
|
pushd publish
|
||||||
|
chmod +x Ryujinx.sh Ryujinx
|
||||||
|
tar -czvf ../release_output/ryujinx-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz ../publish
|
||||||
|
popd
|
||||||
|
|
||||||
|
pushd publish_sdl2_headless
|
||||||
|
chmod +x Ryujinx.sh Ryujinx.Headless.SDL2
|
||||||
|
tar -czvf ../release_output/sdl2-ryujinx-headless-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz ../publish
|
||||||
|
popd
|
||||||
|
shell: bash
|
||||||
|
|
||||||
- name: Pushing new release
|
- name: Pushing new release
|
||||||
uses: ncipollo/release-action@v1
|
uses: ncipollo/release-action@v1
|
||||||
with:
|
with:
|
||||||
@@ -223,12 +225,13 @@ jobs:
|
|||||||
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_NAME\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_NAME }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_NAME\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_NAME }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||||
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_OWNER\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_OWNER\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_OWNER }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||||
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_REPO\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_REPO\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||||
|
sed -r --in-place 's/\%\%RYUJINX_TARGET_RELEASE_CHANNEL_SOURCE_REPO\%\%/${{ env.RYUJINX_TARGET_RELEASE_CHANNEL_REPO }}/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||||
sed -r --in-place 's/\%\%RYUJINX_CONFIG_FILE_NAME\%\%/Config\.json/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
sed -r --in-place 's/\%\%RYUJINX_CONFIG_FILE_NAME\%\%/Config\.json/g;' src/Ryujinx.Common/ReleaseInformation.cs
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|
||||||
- name: Publish macOS Ryujinx
|
- name: Publish macOS Ryujinx
|
||||||
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
|
./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
|
||||||
|
|
||||||
- name: Publish macOS Ryujinx.Headless.SDL2
|
- name: Publish macOS Ryujinx.Headless.SDL2
|
||||||
run: |
|
run: |
|
||||||
@@ -238,7 +241,7 @@ jobs:
|
|||||||
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_ava/*.tar.gz, publish_headless/*.tar.gz"
|
artifacts: "publish/*.tar.gz, publish_headless/*.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
|
||||||
|
|||||||
@@ -12,24 +12,15 @@ Please read the entire document before continuing as it can potentially save eve
|
|||||||
|
|
||||||
We always welcome bug reports, feature proposals and overall feedback. Here are a few tips on how you can make reporting your issue as effective as possible.
|
We always welcome bug reports, feature proposals and overall feedback. Here are a few tips on how you can make reporting your issue as effective as possible.
|
||||||
|
|
||||||
### Identify Where to Report
|
|
||||||
|
|
||||||
The Ryujinx codebase is distributed across multiple repositories in the [Ryujinx organization](https://github.com/Ryujinx). Depending on the feedback you might want to file the issue on a different repo. Here are a few common repos:
|
|
||||||
|
|
||||||
* [Ryujinx/Ryujinx](https://github.com/Ryujinx/Ryujinx) Ryujinx core project files.
|
|
||||||
* [Ryujinx/Ryujinx-Games-List](https://github.com/Ryujinx/Ryujinx-Games-List) Ryujinx game compatibility list.
|
|
||||||
* [Ryujinx/Ryujinx-Website](https://github.com/Ryujinx/Ryujinx-Website) Ryujinx website source code.
|
|
||||||
* [Ryujinx/Ryujinx-Ldn-Website](https://github.com/Ryujinx/Ryujinx-Ldn-Website) Ryujinx LDN website source code.
|
|
||||||
|
|
||||||
### Finding Existing Issues
|
### Finding Existing Issues
|
||||||
|
|
||||||
Before filing a new issue, please search our [open issues](https://github.com/Ryujinx/Ryujinx/issues) to check if it already exists.
|
Before filing a new issue, please search our [open issues](https://github.com/GreemDev/Ryujinx/issues) to check if it already exists.
|
||||||
|
|
||||||
If you do find an existing issue, please include your own feedback in the discussion. Do consider upvoting (👍 reaction) the original post, as this helps us prioritize popular issues in our backlog.
|
If you do find an existing issue, please include your own feedback in the discussion. Do consider upvoting (👍 reaction) the original post, as this helps us prioritize popular issues in our backlog.
|
||||||
|
|
||||||
### Writing a Good Feature Request
|
### Writing a Good Feature Request
|
||||||
|
|
||||||
Please review any feature requests already opened to both check it has not already been suggested, and to familiarize yourself with the format. When ready to submit a proposal, please use the [Feature Request issue template](https://github.com/Ryujinx/Ryujinx/issues/new?assignees=&labels=&projects=&template=feature_request.yml&title=%5BFeature+Request%5D).
|
Please review any feature requests already opened to both check it has not already been suggested, and to familiarize yourself with the format. When ready to submit a proposal, please use the [Feature Request issue template](https://github.com/GreemDev/Ryujinx/issues/new?assignees=&labels=&projects=&template=feature_request.yml&title=%5BFeature+Request%5D).
|
||||||
|
|
||||||
### Writing a Good Bug Report
|
### Writing a Good Bug Report
|
||||||
|
|
||||||
@@ -43,13 +34,13 @@ Ideally, a bug report should contain the following information:
|
|||||||
* A Ryujinx log file of the run instance where the issue occurred. Log files can be found in `[Executable Folder]/Logs` and are named chronologically.
|
* A Ryujinx log file of the run instance where the issue occurred. Log files can be found in `[Executable Folder]/Logs` and are named chronologically.
|
||||||
* Additional information, e.g. is it a regression from previous versions? Are there any known workarounds?
|
* Additional information, e.g. is it a regression from previous versions? Are there any known workarounds?
|
||||||
|
|
||||||
When ready to submit a bug report, please use the [Bug Report issue template](https://github.com/Ryujinx/Ryujinx/issues/new?assignees=&labels=bug&projects=&template=bug_report.yml&title=%5BBug%5D).
|
When ready to submit a bug report, please use the [Bug Report issue template](https://github.com/GreemDev/Ryujinx/issues/new?assignees=&labels=bug&projects=&template=bug_report.yml&title=%5BBug%5D).
|
||||||
|
|
||||||
## Contributing Changes
|
## Contributing Changes
|
||||||
|
|
||||||
Project maintainers will merge changes that both improve the project and meet our standards for code quality.
|
Project maintainers will merge changes that both improve the project and meet our standards for code quality.
|
||||||
|
|
||||||
The [Pull Request Guide](docs/workflow/pr-guide.md) and [License](https://github.com/Ryujinx/Ryujinx/blob/master/LICENSE.txt) docs define additional guidance.
|
The [Pull Request Guide](docs/workflow/pr-guide.md) and [License](https://github.com/GreemDev/Ryujinx/blob/master/LICENSE.txt) docs define additional guidance.
|
||||||
|
|
||||||
### DOs and DON'Ts
|
### DOs and DON'Ts
|
||||||
|
|
||||||
@@ -83,15 +74,15 @@ We use and recommend the following workflow:
|
|||||||
3. In your fork, create a branch off of main (`git checkout -b mybranch`).
|
3. In your fork, create a branch off of main (`git checkout -b mybranch`).
|
||||||
- Branches are useful since they isolate your changes from incoming changes from upstream. They also enable you to create multiple PRs from the same fork.
|
- Branches are useful since they isolate your changes from incoming changes from upstream. They also enable you to create multiple PRs from the same fork.
|
||||||
4. Make and commit your changes to your branch.
|
4. Make and commit your changes to your branch.
|
||||||
- [Build Instructions](https://github.com/Ryujinx/Ryujinx#building) explains how to build and test.
|
- [Build Instructions](https://github.com/GreemDev/Ryujinx#building) explains how to build and test.
|
||||||
- Commit messages should be clear statements of action and intent.
|
- Commit messages should be clear statements of action and intent.
|
||||||
6. Build the repository with your changes.
|
6. Build the repository with your changes.
|
||||||
- Make sure that the builds are clean.
|
- Make sure that the builds are clean.
|
||||||
- Make sure that `dotnet format` has been run and any corrections tested and committed.
|
- Make sure that `dotnet format` has been run and any corrections tested and committed.
|
||||||
7. Create a pull request (PR) against the Ryujinx/Ryujinx repository's **main** branch.
|
7. Create a pull request (PR) against the Ryujinx/Ryujinx repository's **main** branch.
|
||||||
- State in the description what issue or improvement your change is addressing.
|
- State in the description what issue or improvement your change is addressing.
|
||||||
- Check if all the Continuous Integration checks are passing. Refer to [Actions](https://github.com/Ryujinx/Ryujinx/actions) to check for outstanding errors.
|
- Check if all the Continuous Integration checks are passing. Refer to [Actions](https://github.com/GreemDev/Ryujinx/actions) to check for outstanding errors.
|
||||||
8. Wait for feedback or approval of your changes from the [core development team](https://github.com/orgs/Ryujinx/teams/developers)
|
8. Wait for feedback or approval of your changes from the core development team
|
||||||
- Details about the pull request [review procedure](docs/workflow/ci/pr-guide.md).
|
- Details about the pull request [review procedure](docs/workflow/ci/pr-guide.md).
|
||||||
9. When the team members have signed off, and all checks are green, your PR will be merged.
|
9. When the team members have signed off, and all checks are green, your PR will be merged.
|
||||||
- The next official build will automatically include your change.
|
- The next official build will automatically include your change.
|
||||||
@@ -99,7 +90,7 @@ We use and recommend the following workflow:
|
|||||||
|
|
||||||
### Good First Issues
|
### Good First Issues
|
||||||
|
|
||||||
The team marks the most straightforward issues as [good first issues](https://github.com/Ryujinx/Ryujinx/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22). This set of issues is the place to start if you are interested in contributing but new to the codebase.
|
The team marks the most straightforward issues as [good first issues](https://github.com/GreemDev/Ryujinx/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22). This set of issues is the place to start if you are interested in contributing but new to the codebase.
|
||||||
|
|
||||||
### Commit Messages
|
### Commit Messages
|
||||||
|
|
||||||
@@ -122,7 +113,7 @@ Also do your best to factor commits appropriately, not too large with unrelated
|
|||||||
|
|
||||||
### PR - CI Process
|
### PR - CI Process
|
||||||
|
|
||||||
The [Ryujinx continuous integration](https://github.com/Ryujinx/Ryujinx/actions) (CI) system will automatically perform the required builds and run tests (including the ones you are expected to run) for PRs. Builds and test runs must be clean or have bugs properly filed against flaky/unexpected failures that are unrelated to your change.
|
The [Ryujinx continuous integration](https://github.com/GreemDev/Ryujinx/actions) (CI) system will automatically perform the required builds and run tests (including the ones you are expected to run) for PRs. Builds and test runs must be clean or have bugs properly filed against flaky/unexpected failures that are unrelated to your change.
|
||||||
|
|
||||||
If the CI build fails for any reason, the PR actions tab should be consulted for further information on the failure. There are a few usual suspects for such a failure:
|
If the CI build fails for any reason, the PR actions tab should be consulted for further information on the failure. There are a few usual suspects for such a failure:
|
||||||
* `dotnet format` has not been run on the PR and has outstanding stylistic issues.
|
* `dotnet format` has not been run on the PR and has outstanding stylistic issues.
|
||||||
@@ -143,5 +134,5 @@ Ryujinx uses some implementations and frameworks from other projects. The follow
|
|||||||
|
|
||||||
- The license of the file is [permissive](https://en.wikipedia.org/wiki/Permissive_free_software_licence).
|
- The license of the file is [permissive](https://en.wikipedia.org/wiki/Permissive_free_software_licence).
|
||||||
- The license of the file is left in-tact.
|
- The license of the file is left in-tact.
|
||||||
- The contribution is correctly attributed in the [3rd party notices](https://github.com/Ryujinx/Ryujinx/blob/master/distribution/legal/THIRDPARTY.md) file in the repository, as needed.
|
- The contribution is correctly attributed in the [3rd party notices](https://github.com/GreemDev/Ryujinx/blob/master/distribution/legal/THIRDPARTY.md) file in the repository, as needed.
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
<PackageVersion Include="LibHac" Version="0.19.0" />
|
<PackageVersion Include="LibHac" Version="0.19.0" />
|
||||||
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" />
|
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" />
|
||||||
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.9.2" />
|
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.9.2" />
|
||||||
<PackageVersion Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.0.1" />
|
<PackageVersion Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.1.2" />
|
||||||
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
|
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
|
||||||
<PackageVersion Include="Microsoft.IO.RecyclableMemoryStream" Version="3.0.1" />
|
<PackageVersion Include="Microsoft.IO.RecyclableMemoryStream" Version="3.0.1" />
|
||||||
<PackageVersion Include="MsgPack.Cli" Version="1.0.1" />
|
<PackageVersion Include="MsgPack.Cli" Version="1.0.1" />
|
||||||
|
|||||||
47
README.md
47
README.md
@@ -6,6 +6,23 @@
|
|||||||
<br>
|
<br>
|
||||||
<sub><sup><b>(REE-YOU-JINX)</b></sup></sub>
|
<sub><sup><b>(REE-YOU-JINX)</b></sup></sub>
|
||||||
<br>
|
<br>
|
||||||
|
<a href="https://github.com/GreemDev/Ryujinx/actions/workflows/release.yml">
|
||||||
|
<img src="https://github.com/GreemDev/Ryujinx/actions/workflows/release.yml/badge.svg"
|
||||||
|
alt="">
|
||||||
|
</a>
|
||||||
|
<a href="https://github.com/GreemDev/Ryujinx/releases/latest">
|
||||||
|
<img src="https://img.shields.io/github/v/release/GreemDev/Ryujinx"
|
||||||
|
alt="Latest Release">
|
||||||
|
</a>
|
||||||
|
<br>
|
||||||
|
<a href="https://github.com/GreemDev/Ryujinx/actions/workflows/canary.yml">
|
||||||
|
<img src="https://github.com/GreemDev/Ryujinx/actions/workflows/canary.yml/badge.svg"
|
||||||
|
alt="">
|
||||||
|
</a>
|
||||||
|
<a href="https://github.com/GreemDev/Ryujinx-Canary/releases/latest">
|
||||||
|
<img src="https://img.shields.io/github/v/release/GreemDev/Ryujinx-Canary?label=canary"
|
||||||
|
alt="Latest Canary Release">
|
||||||
|
</a>
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
@@ -17,25 +34,22 @@
|
|||||||
</p>
|
</p>
|
||||||
<p align="center">
|
<p align="center">
|
||||||
On October 1st 2024, Ryujinx was discontinued as the creator was forced to abandon the project.
|
On October 1st 2024, Ryujinx was discontinued as the creator was forced to abandon the project.
|
||||||
This fork is intended to be a direct continuation for existing Ryujinx users.
|
<br>
|
||||||
Guides and documentation will not be provided at this time, though you can find the old ones on the Internet Archive.
|
This fork is intended to be a QoL uplift for existing Ryujinx users.
|
||||||
|
<br>
|
||||||
|
This is not a Ryujinx revival project. This is not a Phoenix project.
|
||||||
|
<br>
|
||||||
|
Guides and documentation can be found on the <a href="https://github.com/GreemDev/Ryujinx/wiki">Wiki tab</a>.
|
||||||
</p>
|
</p>
|
||||||
<p align="center">
|
<p align="center">
|
||||||
If you would like a version more true to original Ryujinx, check out <a href="https://github.com/ryujinx-mirror/ryujinx">ryujinx-mirror</a>.
|
If you would like a version more preservative fork of Ryujinx, check out <a href="https://github.com/ryujinx-mirror/ryujinx">ryujinx-mirror</a>.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="https://github.com/GreemDev/Ryujinx/actions/workflows/release.yml">
|
Click below to join the Discord:
|
||||||
<img src="https://github.com/GreemDev/Ryujinx/actions/workflows/release.yml/badge.svg"
|
<br>
|
||||||
alt="">
|
|
||||||
</a>
|
|
||||||
<a href="https://crwd.in/ryujinx">
|
|
||||||
<img src="https://badges.crowdin.net/ryujinx/localized.svg"
|
|
||||||
alt="">
|
|
||||||
</a>
|
|
||||||
<a href="https://discord.gg/dHPrkBkkyA">
|
<a href="https://discord.gg/dHPrkBkkyA">
|
||||||
<img src="https://img.shields.io/discord/1294443224030511104?color=5865F2&label=Ryujinx&logo=discord&logoColor=white"
|
<img src="https://img.shields.io/discord/1294443224030511104?color=5865F2&label=Ryubing&logo=discord&logoColor=white" alt="Discord">
|
||||||
alt="Discord">
|
|
||||||
</a>
|
</a>
|
||||||
<br>
|
<br>
|
||||||
<br>
|
<br>
|
||||||
@@ -56,17 +70,20 @@ Use the search function to see if a game has been tested already!
|
|||||||
To run this emulator, your PC must be equipped with at least 8GiB of RAM;
|
To run this emulator, your PC must be equipped with at least 8GiB of RAM;
|
||||||
failing to meet this requirement may result in a poor gameplay experience or unexpected crashes.
|
failing to meet this requirement may result in a poor gameplay experience or unexpected crashes.
|
||||||
|
|
||||||
## Latest build
|
## Latest release
|
||||||
|
|
||||||
These builds are compiled automatically for each commit on the master branch.
|
Releases are compiled automatically for each commit on the master branch.
|
||||||
While we strive to ensure optimal stability and performance prior to pushing an update, our automated builds **may be unstable or completely broken**.
|
While we strive to ensure optimal stability and performance prior to pushing an update, our automated builds **may be unstable or completely broken**.
|
||||||
|
|
||||||
|
You can find the latest release [here](https://github.com/GreemDev/Ryujinx/releases/latest).
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
If you are planning to contribute or just want to learn more about this project please read through our [documentation](docs/README.md).
|
If you are planning to contribute or just want to learn more about this project please read through our [documentation](docs/README.md).
|
||||||
|
|
||||||
## Building
|
## Building
|
||||||
|
|
||||||
|
Building the project is for advanced users.
|
||||||
If you wish to build the emulator yourself, follow these steps:
|
If you wish to build the emulator yourself, follow these steps:
|
||||||
|
|
||||||
### Step 1
|
### Step 1
|
||||||
|
|||||||
15
Ryujinx.sln
15
Ryujinx.sln
@@ -29,12 +29,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Nvdec", "s
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Audio", "src\Ryujinx.Audio\Ryujinx.Audio.csproj", "{806ACF6D-90B0-45D0-A1AC-5F220F3B3985}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Audio", "src\Ryujinx.Audio\Ryujinx.Audio.csproj", "{806ACF6D-90B0-45D0-A1AC-5F220F3B3985}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{36F870C1-3E5F-485F-B426-F0645AF78751}"
|
|
||||||
ProjectSection(SolutionItems) = preProject
|
|
||||||
.editorconfig = .editorconfig
|
|
||||||
Directory.Packages.props = Directory.Packages.props
|
|
||||||
EndProjectSection
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Memory", "src\Ryujinx.Memory\Ryujinx.Memory.csproj", "{A5E6C691-9E22-4263-8F40-42F002CE66BE}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Memory", "src\Ryujinx.Memory\Ryujinx.Memory.csproj", "{A5E6C691-9E22-4263-8F40-42F002CE66BE}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Tests.Memory", "src\Ryujinx.Tests.Memory\Ryujinx.Tests.Memory.csproj", "{D1CC5322-7325-4F6B-9625-194B30BE1296}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Tests.Memory", "src\Ryujinx.Tests.Memory\Ryujinx.Tests.Memory.csproj", "{D1CC5322-7325-4F6B-9625-194B30BE1296}"
|
||||||
@@ -87,6 +81,15 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Horizon.Kernel.Gene
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.HLE.Generators", "src\Ryujinx.HLE.Generators\Ryujinx.HLE.Generators.csproj", "{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.HLE.Generators", "src\Ryujinx.HLE.Generators\Ryujinx.HLE.Generators.csproj", "{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{36F870C1-3E5F-485F-B426-F0645AF78751}"
|
||||||
|
ProjectSection(SolutionItems) = preProject
|
||||||
|
.editorconfig = .editorconfig
|
||||||
|
Directory.Packages.props = Directory.Packages.props
|
||||||
|
.github/workflows/release.yml = .github/workflows/release.yml
|
||||||
|
.github/workflows/canary.yml = .github/workflows/canary.yml
|
||||||
|
.github/workflows/build.yml = .github/workflows/build.yml
|
||||||
|
EndProjectSection
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
|||||||
Binary file not shown.
@@ -46,5 +46,5 @@ then
|
|||||||
rcodesign sign --entitlements-xml-path "$ENTITLEMENTS_FILE_PATH" "$APP_BUNDLE_DIRECTORY"
|
rcodesign sign --entitlements-xml-path "$ENTITLEMENTS_FILE_PATH" "$APP_BUNDLE_DIRECTORY"
|
||||||
else
|
else
|
||||||
echo "Usign codesign for ad-hoc signing"
|
echo "Usign codesign for ad-hoc signing"
|
||||||
codesign --entitlements "$ENTITLEMENTS_FILE_PATH" -f --deep -s - "$APP_BUNDLE_DIRECTORY"
|
codesign --entitlements "$ENTITLEMENTS_FILE_PATH" -f -s - "$APP_BUNDLE_DIRECTORY"
|
||||||
fi
|
fi
|
||||||
@@ -99,7 +99,7 @@ then
|
|||||||
rcodesign sign --entitlements-xml-path "$ENTITLEMENTS_FILE_PATH" "$UNIVERSAL_APP_BUNDLE"
|
rcodesign sign --entitlements-xml-path "$ENTITLEMENTS_FILE_PATH" "$UNIVERSAL_APP_BUNDLE"
|
||||||
else
|
else
|
||||||
echo "Using codesign for ad-hoc signing"
|
echo "Using codesign for ad-hoc signing"
|
||||||
codesign --entitlements "$ENTITLEMENTS_FILE_PATH" -f --deep -s - "$UNIVERSAL_APP_BUNDLE"
|
codesign --entitlements "$ENTITLEMENTS_FILE_PATH" -f -s - "$UNIVERSAL_APP_BUNDLE"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "Creating archive"
|
echo "Creating archive"
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ else
|
|||||||
echo "Using codesign for ad-hoc signing"
|
echo "Using codesign for ad-hoc signing"
|
||||||
for FILE in "$UNIVERSAL_OUTPUT"/*; do
|
for FILE in "$UNIVERSAL_OUTPUT"/*; do
|
||||||
if [[ $(file "$FILE") == *"Mach-O"* ]]; then
|
if [[ $(file "$FILE") == *"Mach-O"* ]]; then
|
||||||
codesign --entitlements "$ENTITLEMENTS_FILE_PATH" -f --deep -s - "$FILE"
|
codesign --entitlements "$ENTITLEMENTS_FILE_PATH" -f -s - "$FILE"
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 255.76 255.76"><defs><style>.cls-1{fill:#02c5e5;}.cls-2{fill:#ff5f55;}.cls-3{fill:none;}</style></defs><g id="Ebene_2" data-name="Ebene 2"><g id="Ebene_1-2" data-name="Ebene 1"><g id="Ebene_2-2" data-name="Ebene 2"><g id="Ebene_1-2-2" data-name="Ebene 1-2"><path class="cls-1" d="M80.63,0V220.39H44.37c-14,0-35.74-20.74-35.74-39.13V40.13C8.63,19.19,31.36,0,49.06,0Z"/><path class="cls-2" d="M175.13,35.37V255.76h36.26c14,0,35.74-20.74,35.74-39.13V75.5c0-20.94-22.73-40.13-40.43-40.13Z"/><polygon class="cls-1" points="124.34 137.96 122.58 145.57 90.64 145.57 92.89 137.96 124.34 137.96"/><polygon class="cls-2" points="160.29 137.96 157.84 145.57 122.58 145.57 124.34 137.96 160.29 137.96"/><polygon class="cls-1" points="130.39 111.86 128.62 119.47 95.14 119.47 97.39 111.86 130.39 111.86"/><polygon class="cls-2" points="164.79 111.86 162.34 119.47 128.62 119.47 130.39 111.86 164.79 111.86"/><polygon class="cls-1" points="104.24 167.99 122.83 87.77 129.78 87.77 111.19 167.99 104.24 167.99"/><polygon class="cls-2" points="128.18 167.99 146.77 87.77 153.89 87.77 135.3 167.99 128.18 167.99"/></g><rect class="cls-3" width="255.76" height="255.76"/></g></g></g></svg>
|
<svg viewBox="0 0 256 256" xmlns="http://www.w3.org/2000/svg"><path d="M80.63 0V220.39H44.37C30.37 220.39 8.63 199.65 8.63 181.26V40.13C8.63 19.19 31.36 0 49.06 0H80.63Z" fill="url(#g)"/><path d="M175.13 35.37V255.76H211.39C225.39 255.76 247.13 235.02 247.13 216.63V75.5C247.13 54.56 224.4 35.37 206.7 35.37H175.13Z" fill="url(#g)"/><path fill-rule="evenodd" clip-rule="evenodd" d="M109.436 145.57L104.24 167.99H111.19L116.386 145.57H133.376L128.18 167.99H135.3L140.496 145.57H157.84L160.29 137.96H142.259L146.544 119.47H162.34L164.79 111.86H148.307L153.89 87.77H146.77L141.187 111.86H124.197L129.78 87.77H122.83L117.247 111.86H97.39L95.14 119.47H115.484L111.199 137.96H92.89L90.64 145.57H109.436ZM139.424 119.47L135.139 137.96H118.149L122.434 119.47H139.424Z" fill="url(#g)"/><defs><linearGradient id="g" x1="223.76" y1="32" x2="27" y2="228.76" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#686868"/><stop offset="0.14" stop-color="#686868"/><stop offset="0.14" stop-color="#AE9675"/><stop offset="0.28" stop-color="#AE9675"/><stop offset="0.28" stop-color="#FF635E"/><stop offset="0.42" stop-color="#FF635E"/><stop offset="0.42" stop-color="#FE8F63"/><stop offset="0.56" stop-color="#FE8F63"/><stop offset="0.56" stop-color="#FDEF68"/><stop offset="0.7" stop-color="#FDEF68"/><stop offset="0.7" stop-color="#71C56D"/><stop offset="0.84" stop-color="#71C56D"/><stop offset="0.84" stop-color="#32ADDD"/><stop offset="1" stop-color="#32ADDD"/></linearGradient></defs></svg>
|
||||||
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.5 KiB |
BIN
docs/shell.png
BIN
docs/shell.png
Binary file not shown.
|
Before Width: | Height: | Size: 905 KiB After Width: | Height: | Size: 1.4 MiB |
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
## Contributing Rules
|
## Contributing Rules
|
||||||
|
|
||||||
All contributions to Ryujinx/Ryujinx repository are made via pull requests (PRs) rather than through direct commits. The pull requests are reviewed and merged by the maintainers after a review and at least two approvals from the core development team.
|
All contributions to GreemDev/Ryujinx repository are made via pull requests (PRs) rather than through direct commits. The pull requests are reviewed and merged by the maintainers after a review and at least two approvals from the core development team.
|
||||||
|
|
||||||
To merge pull requests, you must have write permissions in the repository.
|
To merge pull requests, you must have write permissions in the repository.
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@ If during the code review process a merge conflict occurs, the PR author is resp
|
|||||||
|
|
||||||
## Pull Request Builds
|
## Pull Request Builds
|
||||||
|
|
||||||
When submitting a PR to the `Ryujinx/Ryujinx` repository, various builds will run validating many areas to ensure we keep developer productivity and product quality high. These various workflows can be tracked in the [Actions](https://github.com/Ryujinx/Ryujinx/actions) tab of the repository. If the job continues to completion, the build artifacts will be uploaded and posted as a comment in the PR discussion.
|
When submitting a PR to the `GreemDev/Ryujinx` repository, various builds will run validating many areas to ensure we keep developer productivity and product quality high. These various workflows can be tracked in the [Actions](https://github.com/GreemDev/Ryujinx/actions) tab of the repository. If the job continues to completion, the build artifacts will be uploaded and posted as a comment in the PR discussion.
|
||||||
|
|
||||||
## Review Turnaround Times
|
## Review Turnaround Times
|
||||||
|
|
||||||
@@ -42,7 +42,7 @@ Anyone with write access can merge a pull request manually when the following co
|
|||||||
|
|
||||||
* The PR has been approved by two reviewers and any other objections are addressed.
|
* The PR has been approved by two reviewers and any other objections are addressed.
|
||||||
* You can request follow up reviews from the original reviewers if they requested changes.
|
* You can request follow up reviews from the original reviewers if they requested changes.
|
||||||
* The PR successfully builds and passes all tests in the Continuous Integration (CI) system. In case of failures, refer to the [Actions](https://github.com/Ryujinx/Ryujinx/actions) tab of your PR.
|
* The PR successfully builds and passes all tests in the Continuous Integration (CI) system. In case of failures, refer to the [Actions](https://github.com/GreemDev/Ryujinx/actions) tab of your PR.
|
||||||
|
|
||||||
Typically, PRs are merged as one commit (squash merges). It creates a simpler history than a Merge Commit. "Special circumstances" are rare, and typically mean that there are a series of cleanly separated changes that will be too hard to understand if squashed together, or for some reason we want to preserve the ability to dissect them.
|
Typically, PRs are merged as one commit (squash merges). It creates a simpler history than a Merge Commit. "Special circumstances" are rare, and typically mean that there are a series of cleanly separated changes that will be too hard to understand if squashed together, or for some reason we want to preserve the ability to dissect them.
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ using System.Collections.Generic;
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
|
using System.Linq;
|
||||||
using System.Runtime;
|
using System.Runtime;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
@@ -848,17 +849,15 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
List<Thread> threads = new();
|
|
||||||
|
|
||||||
for (int i = 0; i < degreeOfParallelism; i++)
|
List<Thread> threads = Enumerable.Range(0, degreeOfParallelism)
|
||||||
{
|
.Select(idx =>
|
||||||
Thread thread = new(TranslateFuncs)
|
new Thread(TranslateFuncs)
|
||||||
{
|
{
|
||||||
IsBackground = true,
|
IsBackground = true,
|
||||||
};
|
Name = "Ptc.TranslateThread." + idx
|
||||||
|
}
|
||||||
threads.Add(thread);
|
).ToList();
|
||||||
}
|
|
||||||
|
|
||||||
Stopwatch sw = Stopwatch.StartNew();
|
Stopwatch sw = Stopwatch.StartNew();
|
||||||
|
|
||||||
@@ -885,6 +884,7 @@ namespace ARMeilleure.Translation.PTC
|
|||||||
Thread preSaveThread = new(PreSave)
|
Thread preSaveThread = new(PreSave)
|
||||||
{
|
{
|
||||||
IsBackground = true,
|
IsBackground = true,
|
||||||
|
Name = "Ptc.DiskWriter"
|
||||||
};
|
};
|
||||||
preSaveThread.Start();
|
preSaveThread.Start();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ namespace Ryujinx.Audio.Backends.OpenAL
|
|||||||
|
|
||||||
public OpenALHardwareDeviceDriver()
|
public OpenALHardwareDeviceDriver()
|
||||||
{
|
{
|
||||||
_device = ALC.OpenDevice("");
|
_device = ALC.OpenDevice(string.Empty);
|
||||||
_context = ALC.CreateContext(_device, new ALContextAttributes());
|
_context = ALC.CreateContext(_device, new ALContextAttributes());
|
||||||
_updateRequiredEvent = new ManualResetEvent(false);
|
_updateRequiredEvent = new ManualResetEvent(false);
|
||||||
_pauseEvent = new ManualResetEvent(true);
|
_pauseEvent = new ManualResetEvent(true);
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ namespace Ryujinx.Audio.Renderer.Dsp
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
private static short GetCoefficientAtIndex(ReadOnlySpan<short> coefficients, int index)
|
private static short GetCoefficientAtIndex(ReadOnlySpan<short> coefficients, int index)
|
||||||
{
|
{
|
||||||
if ((uint)index > (uint)coefficients.Length)
|
if ((uint)index >= (uint)coefficients.Length)
|
||||||
{
|
{
|
||||||
Logger.Error?.Print(LogClass.AudioRenderer, $"Out of bound read for coefficient at index {index}");
|
Logger.Error?.Print(LogClass.AudioRenderer, $"Out of bound read for coefficient at index {index}");
|
||||||
|
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ namespace Ryujinx.Common.Configuration
|
|||||||
|
|
||||||
private static string SetUpLogsDir()
|
private static string SetUpLogsDir()
|
||||||
{
|
{
|
||||||
string logDir = "";
|
string logDir = string.Empty;
|
||||||
|
|
||||||
if (Mode == LaunchMode.Portable)
|
if (Mode == LaunchMode.Portable)
|
||||||
{
|
{
|
||||||
@@ -148,7 +148,7 @@ namespace Ryujinx.Common.Configuration
|
|||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
Logger.Warning?.Print(LogClass.Application, $"Logging directory could not be created '{logDir}'");
|
Logger.Warning?.Print(LogClass.Application, $"Logging directory could not be created '{logDir}'");
|
||||||
logDir = "";
|
logDir = string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(logDir))
|
if (string.IsNullOrEmpty(logDir))
|
||||||
@@ -179,7 +179,7 @@ namespace Ryujinx.Common.Configuration
|
|||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
Logger.Warning?.Print(LogClass.Application, $"Logging directory could not be created '{logDir}'");
|
Logger.Warning?.Print(LogClass.Application, $"Logging directory could not be created '{logDir}'");
|
||||||
logDir = "";
|
logDir = string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(logDir))
|
if (string.IsNullOrEmpty(logDir))
|
||||||
|
|||||||
@@ -121,8 +121,8 @@ namespace Ryujinx.Common.GraphicsDriver
|
|||||||
};
|
};
|
||||||
application.AppName.Set("Ryujinx.exe");
|
application.AppName.Set("Ryujinx.exe");
|
||||||
application.UserFriendlyName.Set("Ryujinx");
|
application.UserFriendlyName.Set("Ryujinx");
|
||||||
application.Launcher.Set("");
|
application.Launcher.Set(string.Empty);
|
||||||
application.FileInFolder.Set("");
|
application.FileInFolder.Set(string.Empty);
|
||||||
|
|
||||||
Check(NvAPI_DRS_CreateApplication(handle, profileHandle, ref application));
|
Check(NvAPI_DRS_CreateApplication(handle, profileHandle, ref application));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,5 +72,6 @@ namespace Ryujinx.Common.Logging
|
|||||||
TamperMachine,
|
TamperMachine,
|
||||||
UI,
|
UI,
|
||||||
Vic,
|
Vic,
|
||||||
|
XCIFileTrimmer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ namespace Ryujinx.Common.Logging
|
|||||||
{
|
{
|
||||||
if (_enabledClasses[(int)logClass])
|
if (_enabledClasses[(int)logClass])
|
||||||
{
|
{
|
||||||
Updated?.Invoke(null, new LogEventArgs(Level, _time.Elapsed, Thread.CurrentThread.Name, FormatMessage(logClass, "", message)));
|
Updated?.Invoke(null, new LogEventArgs(Level, _time.Elapsed, Thread.CurrentThread.Name, FormatMessage(logClass, string.Empty, message)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,10 +30,10 @@ namespace Ryujinx.Common.Logging.Targets
|
|||||||
string ILogTarget.Name { get => _target.Name; }
|
string ILogTarget.Name { get => _target.Name; }
|
||||||
|
|
||||||
public AsyncLogTargetWrapper(ILogTarget target)
|
public AsyncLogTargetWrapper(ILogTarget target)
|
||||||
: this(target, -1, AsyncLogTargetOverflowAction.Block)
|
: this(target, -1)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
public AsyncLogTargetWrapper(ILogTarget target, int queueLimit, AsyncLogTargetOverflowAction overflowAction)
|
public AsyncLogTargetWrapper(ILogTarget target, int queueLimit = -1, AsyncLogTargetOverflowAction overflowAction = AsyncLogTargetOverflowAction.Block)
|
||||||
{
|
{
|
||||||
_target = target;
|
_target = target;
|
||||||
_messageQueue = new BlockingCollection<LogEventArgs>(queueLimit);
|
_messageQueue = new BlockingCollection<LogEventArgs>(queueLimit);
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ namespace Ryujinx.Common.Logging.Targets
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Clean up old logs, should only keep 3
|
// Clean up old logs, should only keep 3
|
||||||
FileInfo[] files = logDir.GetFiles("*.log").OrderBy((info => info.CreationTime)).ToArray();
|
FileInfo[] files = logDir.GetFiles("*.log").OrderBy(info => info.CreationTime).ToArray();
|
||||||
for (int i = 0; i < files.Length - 2; i++)
|
for (int i = 0; i < files.Length - 2; i++)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
|||||||
30
src/Ryujinx.Common/Logging/XCIFileTrimmerLog.cs
Normal file
30
src/Ryujinx.Common/Logging/XCIFileTrimmerLog.cs
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
using Ryujinx.Common.Utilities;
|
||||||
|
|
||||||
|
namespace Ryujinx.Common.Logging
|
||||||
|
{
|
||||||
|
public class XCIFileTrimmerLog : XCIFileTrimmer.ILog
|
||||||
|
{
|
||||||
|
public virtual void Progress(long current, long total, string text, bool complete)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Write(XCIFileTrimmer.LogType logType, string text)
|
||||||
|
{
|
||||||
|
switch (logType)
|
||||||
|
{
|
||||||
|
case XCIFileTrimmer.LogType.Info:
|
||||||
|
Logger.Notice.Print(LogClass.XCIFileTrimmer, text);
|
||||||
|
break;
|
||||||
|
case XCIFileTrimmer.LogType.Warn:
|
||||||
|
Logger.Warning?.Print(LogClass.XCIFileTrimmer, text);
|
||||||
|
break;
|
||||||
|
case XCIFileTrimmer.LogType.Error:
|
||||||
|
Logger.Error?.Print(LogClass.XCIFileTrimmer, text);
|
||||||
|
break;
|
||||||
|
case XCIFileTrimmer.LogType.Progress:
|
||||||
|
Logger.Info?.Print(LogClass.XCIFileTrimmer, text);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,11 +1,13 @@
|
|||||||
|
using Ryujinx.Common.Logging;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
namespace Ryujinx.Common
|
namespace Ryujinx.Common
|
||||||
{
|
{
|
||||||
public class ReactiveObject<T>
|
public class ReactiveObject<T>
|
||||||
{
|
{
|
||||||
private readonly ReaderWriterLockSlim _readerWriterLock = new();
|
private readonly ReaderWriterLockSlim _rwLock = new();
|
||||||
private bool _isInitialized;
|
private bool _isInitialized;
|
||||||
private T _value;
|
private T _value;
|
||||||
|
|
||||||
@@ -15,15 +17,15 @@ namespace Ryujinx.Common
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
_readerWriterLock.EnterReadLock();
|
_rwLock.EnterReadLock();
|
||||||
T value = _value;
|
T value = _value;
|
||||||
_readerWriterLock.ExitReadLock();
|
_rwLock.ExitReadLock();
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
_readerWriterLock.EnterWriteLock();
|
_rwLock.EnterWriteLock();
|
||||||
|
|
||||||
T oldValue = _value;
|
T oldValue = _value;
|
||||||
|
|
||||||
@@ -32,7 +34,7 @@ namespace Ryujinx.Common
|
|||||||
_isInitialized = true;
|
_isInitialized = true;
|
||||||
_value = value;
|
_value = value;
|
||||||
|
|
||||||
_readerWriterLock.ExitWriteLock();
|
_rwLock.ExitWriteLock();
|
||||||
|
|
||||||
if (!oldIsInitialized || oldValue == null || !oldValue.Equals(_value))
|
if (!oldIsInitialized || oldValue == null || !oldValue.Equals(_value))
|
||||||
{
|
{
|
||||||
@@ -41,11 +43,21 @@ namespace Ryujinx.Common
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void LogChangesToValue(string valueName, LogClass logClass = LogClass.Configuration)
|
||||||
|
=> Event += (_, e) => ReactiveObjectHelper.LogValueChange(logClass, e, valueName);
|
||||||
|
|
||||||
public static implicit operator T(ReactiveObject<T> obj) => obj.Value;
|
public static implicit operator T(ReactiveObject<T> obj) => obj.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class ReactiveObjectHelper
|
public static class ReactiveObjectHelper
|
||||||
{
|
{
|
||||||
|
public static void LogValueChange<T>(LogClass logClass, ReactiveEventArgs<T> eventArgs, string valueName)
|
||||||
|
{
|
||||||
|
string message = string.Create(CultureInfo.InvariantCulture, $"{valueName} set to: {eventArgs.NewValue}");
|
||||||
|
|
||||||
|
Logger.Info?.Print(logClass, message);
|
||||||
|
}
|
||||||
|
|
||||||
public static void Toggle(this ReactiveObject<bool> rBoolean) => rBoolean.Value = !rBoolean.Value;
|
public static void Toggle(this ReactiveObject<bool> rBoolean) => rBoolean.Value = !rBoolean.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,9 @@ namespace Ryujinx.Common
|
|||||||
// DO NOT EDIT, filled by CI
|
// DO NOT EDIT, filled by CI
|
||||||
public static class ReleaseInformation
|
public static class ReleaseInformation
|
||||||
{
|
{
|
||||||
private const string FlatHubChannelOwner = "flathub";
|
private const string FlatHubChannel = "flathub";
|
||||||
|
private const string CanaryChannel = "canary";
|
||||||
|
private const string ReleaseChannel = "release";
|
||||||
|
|
||||||
private const string BuildVersion = "%%RYUJINX_BUILD_VERSION%%";
|
private const string BuildVersion = "%%RYUJINX_BUILD_VERSION%%";
|
||||||
public const string BuildGitHash = "%%RYUJINX_BUILD_GIT_HASH%%";
|
public const string BuildGitHash = "%%RYUJINX_BUILD_GIT_HASH%%";
|
||||||
@@ -13,6 +15,7 @@ namespace Ryujinx.Common
|
|||||||
private const string ConfigFileName = "%%RYUJINX_CONFIG_FILE_NAME%%";
|
private const string ConfigFileName = "%%RYUJINX_CONFIG_FILE_NAME%%";
|
||||||
|
|
||||||
public const string ReleaseChannelOwner = "%%RYUJINX_TARGET_RELEASE_CHANNEL_OWNER%%";
|
public const string ReleaseChannelOwner = "%%RYUJINX_TARGET_RELEASE_CHANNEL_OWNER%%";
|
||||||
|
public const string ReleaseChannelSourceRepo = "%%RYUJINX_TARGET_RELEASE_CHANNEL_SOURCE_REPO%%";
|
||||||
public const string ReleaseChannelRepo = "%%RYUJINX_TARGET_RELEASE_CHANNEL_REPO%%";
|
public const string ReleaseChannelRepo = "%%RYUJINX_TARGET_RELEASE_CHANNEL_REPO%%";
|
||||||
|
|
||||||
public static string ConfigName => !ConfigFileName.StartsWith("%%") ? ConfigFileName : "Config.json";
|
public static string ConfigName => !ConfigFileName.StartsWith("%%") ? ConfigFileName : "Config.json";
|
||||||
@@ -21,10 +24,15 @@ namespace Ryujinx.Common
|
|||||||
!BuildGitHash.StartsWith("%%") &&
|
!BuildGitHash.StartsWith("%%") &&
|
||||||
!ReleaseChannelName.StartsWith("%%") &&
|
!ReleaseChannelName.StartsWith("%%") &&
|
||||||
!ReleaseChannelOwner.StartsWith("%%") &&
|
!ReleaseChannelOwner.StartsWith("%%") &&
|
||||||
|
!ReleaseChannelSourceRepo.StartsWith("%%") &&
|
||||||
!ReleaseChannelRepo.StartsWith("%%") &&
|
!ReleaseChannelRepo.StartsWith("%%") &&
|
||||||
!ConfigFileName.StartsWith("%%");
|
!ConfigFileName.StartsWith("%%");
|
||||||
|
|
||||||
public static bool IsFlatHubBuild => IsValid && ReleaseChannelOwner.Equals(FlatHubChannelOwner);
|
public static bool IsFlatHubBuild => IsValid && ReleaseChannelOwner.Equals(FlatHubChannel);
|
||||||
|
|
||||||
|
public static bool IsCanaryBuild => IsValid && ReleaseChannelName.Equals(CanaryChannel);
|
||||||
|
|
||||||
|
public static bool IsReleaseBuild => IsValid && ReleaseChannelName.Equals(ReleaseChannel);
|
||||||
|
|
||||||
public static string Version => IsValid ? BuildVersion : Assembly.GetEntryAssembly()!.GetCustomAttribute<AssemblyInformationalVersionAttribute>()?.InformationalVersion;
|
public static string Version => IsValid ? BuildVersion : Assembly.GetEntryAssembly()!.GetCustomAttribute<AssemblyInformationalVersionAttribute>()?.InformationalVersion;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" />
|
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" />
|
||||||
<PackageReference Include="MsgPack.Cli" />
|
<PackageReference Include="MsgPack.Cli" />
|
||||||
<PackageReference Include="System.Management" />
|
<PackageReference Include="System.Management" />
|
||||||
|
<PackageReference Include="Humanizer" />
|
||||||
<PackageReference Include="Gommon" />
|
<PackageReference Include="Gommon" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -17,29 +17,19 @@ namespace Ryujinx.Common.Utilities
|
|||||||
/// It is REQUIRED for you to save returned options statically or as a part of static serializer context
|
/// It is REQUIRED for you to save returned options statically or as a part of static serializer context
|
||||||
/// in order to avoid performance issues. You can safely modify returned options for your case before storing.
|
/// in order to avoid performance issues. You can safely modify returned options for your case before storing.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
public static JsonSerializerOptions GetDefaultSerializerOptions(bool indented = true)
|
public static JsonSerializerOptions GetDefaultSerializerOptions(bool indented = true) =>
|
||||||
{
|
new()
|
||||||
JsonSerializerOptions options = new()
|
|
||||||
{
|
{
|
||||||
DictionaryKeyPolicy = _snakeCasePolicy,
|
DictionaryKeyPolicy = _snakeCasePolicy,
|
||||||
PropertyNamingPolicy = _snakeCasePolicy,
|
PropertyNamingPolicy = _snakeCasePolicy,
|
||||||
WriteIndented = indented,
|
WriteIndented = indented,
|
||||||
AllowTrailingCommas = true,
|
AllowTrailingCommas = true,
|
||||||
ReadCommentHandling = JsonCommentHandling.Skip,
|
ReadCommentHandling = JsonCommentHandling.Skip
|
||||||
};
|
};
|
||||||
|
|
||||||
return options;
|
public static string Serialize<T>(T value, JsonTypeInfo<T> typeInfo) => JsonSerializer.Serialize(value, typeInfo);
|
||||||
}
|
|
||||||
|
|
||||||
public static string Serialize<T>(T value, JsonTypeInfo<T> typeInfo)
|
public static T Deserialize<T>(string value, JsonTypeInfo<T> typeInfo) => JsonSerializer.Deserialize(value, typeInfo);
|
||||||
{
|
|
||||||
return JsonSerializer.Serialize(value, typeInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static T Deserialize<T>(string value, JsonTypeInfo<T> typeInfo)
|
|
||||||
{
|
|
||||||
return JsonSerializer.Deserialize(value, typeInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void SerializeToFile<T>(string filePath, T value, JsonTypeInfo<T> typeInfo)
|
public static void SerializeToFile<T>(string filePath, T value, JsonTypeInfo<T> typeInfo)
|
||||||
{
|
{
|
||||||
@@ -53,10 +43,7 @@ namespace Ryujinx.Common.Utilities
|
|||||||
return JsonSerializer.Deserialize(file, typeInfo);
|
return JsonSerializer.Deserialize(file, typeInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SerializeToStream<T>(Stream stream, T value, JsonTypeInfo<T> typeInfo)
|
public static void SerializeToStream<T>(Stream stream, T value, JsonTypeInfo<T> typeInfo) => JsonSerializer.Serialize(stream, value, typeInfo);
|
||||||
{
|
|
||||||
JsonSerializer.Serialize(stream, value, typeInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
private class SnakeCaseNamingPolicy : JsonNamingPolicy
|
private class SnakeCaseNamingPolicy : JsonNamingPolicy
|
||||||
{
|
{
|
||||||
|
|||||||
524
src/Ryujinx.Common/Utilities/XCIFileTrimmer.cs
Normal file
524
src/Ryujinx.Common/Utilities/XCIFileTrimmer.cs
Normal file
@@ -0,0 +1,524 @@
|
|||||||
|
// Uncomment the line below to ensure XCIFileTrimmer does not modify files
|
||||||
|
//#define XCI_TRIMMER_READ_ONLY_MODE
|
||||||
|
|
||||||
|
using Gommon;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace Ryujinx.Common.Utilities
|
||||||
|
{
|
||||||
|
public sealed class XCIFileTrimmer
|
||||||
|
{
|
||||||
|
private const long BytesInAMegabyte = 1024 * 1024;
|
||||||
|
private const int BufferSize = 8 * (int)BytesInAMegabyte;
|
||||||
|
|
||||||
|
private const long CartSizeMBinFormattedGB = 952;
|
||||||
|
private const int CartKeyAreaSize = 0x1000;
|
||||||
|
private const byte PaddingByte = 0xFF;
|
||||||
|
private const int HeaderFilePos = 0x100;
|
||||||
|
private const int CartSizeFilePos = 0x10D;
|
||||||
|
private const int DataSizeFilePos = 0x118;
|
||||||
|
private const string HeaderMagicValue = "HEAD";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Cartridge Sizes (ByteIdentifier, SizeInGB)
|
||||||
|
/// </summary>
|
||||||
|
private static readonly Dictionary<byte, long> _cartSizesGB = new()
|
||||||
|
{
|
||||||
|
{ 0xFA, 1 },
|
||||||
|
{ 0xF8, 2 },
|
||||||
|
{ 0xF0, 4 },
|
||||||
|
{ 0xE0, 8 },
|
||||||
|
{ 0xE1, 16 },
|
||||||
|
{ 0xE2, 32 }
|
||||||
|
};
|
||||||
|
|
||||||
|
private static long RecordsToByte(long records)
|
||||||
|
{
|
||||||
|
return 512 + (records * 512);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool CanTrim(string filename, ILog log = null)
|
||||||
|
{
|
||||||
|
if (Path.GetExtension(filename).Equals(".XCI", StringComparison.InvariantCultureIgnoreCase))
|
||||||
|
{
|
||||||
|
var trimmer = new XCIFileTrimmer(filename, log);
|
||||||
|
return trimmer.CanBeTrimmed;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool CanUntrim(string filename, ILog log = null)
|
||||||
|
{
|
||||||
|
if (Path.GetExtension(filename).Equals(".XCI", StringComparison.InvariantCultureIgnoreCase))
|
||||||
|
{
|
||||||
|
var trimmer = new XCIFileTrimmer(filename, log);
|
||||||
|
return trimmer.CanBeUntrimmed;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ILog _log;
|
||||||
|
private string _filename;
|
||||||
|
private FileStream _fileStream;
|
||||||
|
private BinaryReader _binaryReader;
|
||||||
|
private long _offsetB, _dataSizeB, _cartSizeB, _fileSizeB;
|
||||||
|
private bool _fileOK = true;
|
||||||
|
private bool _freeSpaceChecked = false;
|
||||||
|
private bool _freeSpaceValid = false;
|
||||||
|
|
||||||
|
public enum OperationOutcome
|
||||||
|
{
|
||||||
|
Undetermined,
|
||||||
|
InvalidXCIFile,
|
||||||
|
NoTrimNecessary,
|
||||||
|
NoUntrimPossible,
|
||||||
|
FreeSpaceCheckFailed,
|
||||||
|
FileIOWriteError,
|
||||||
|
ReadOnlyFileCannotFix,
|
||||||
|
FileSizeChanged,
|
||||||
|
Successful,
|
||||||
|
Cancelled
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum LogType
|
||||||
|
{
|
||||||
|
Info,
|
||||||
|
Warn,
|
||||||
|
Error,
|
||||||
|
Progress
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface ILog
|
||||||
|
{
|
||||||
|
public void Write(LogType logType, string text);
|
||||||
|
public void Progress(long current, long total, string text, bool complete);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool FileOK => _fileOK;
|
||||||
|
public bool Trimmed => _fileOK && FileSizeB < UntrimmedFileSizeB;
|
||||||
|
public bool ContainsKeyArea => _offsetB != 0;
|
||||||
|
public bool CanBeTrimmed => _fileOK && FileSizeB > TrimmedFileSizeB;
|
||||||
|
public bool CanBeUntrimmed => _fileOK && FileSizeB < UntrimmedFileSizeB;
|
||||||
|
public bool FreeSpaceChecked => _fileOK && _freeSpaceChecked;
|
||||||
|
public bool FreeSpaceValid => _fileOK && _freeSpaceValid;
|
||||||
|
public long DataSizeB => _dataSizeB;
|
||||||
|
public long CartSizeB => _cartSizeB;
|
||||||
|
public long FileSizeB => _fileSizeB;
|
||||||
|
public long DiskSpaceSavedB => CartSizeB - FileSizeB;
|
||||||
|
public long DiskSpaceSavingsB => CartSizeB - DataSizeB;
|
||||||
|
public long TrimmedFileSizeB => _offsetB + _dataSizeB;
|
||||||
|
public long UntrimmedFileSizeB => _offsetB + _cartSizeB;
|
||||||
|
|
||||||
|
public ILog Log
|
||||||
|
{
|
||||||
|
get => _log;
|
||||||
|
set => _log = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String Filename
|
||||||
|
{
|
||||||
|
get => _filename;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_filename = value;
|
||||||
|
Reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public long Pos
|
||||||
|
{
|
||||||
|
get => _fileStream.Position;
|
||||||
|
set => _fileStream.Position = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public XCIFileTrimmer(string path, ILog log = null)
|
||||||
|
{
|
||||||
|
Log = log;
|
||||||
|
Filename = path;
|
||||||
|
ReadHeader();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CheckFreeSpace(CancellationToken? cancelToken = null)
|
||||||
|
{
|
||||||
|
if (FreeSpaceChecked)
|
||||||
|
return;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (CanBeTrimmed)
|
||||||
|
{
|
||||||
|
_freeSpaceValid = false;
|
||||||
|
|
||||||
|
OpenReaders();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Pos = TrimmedFileSizeB;
|
||||||
|
bool freeSpaceValid = true;
|
||||||
|
long readSizeB = FileSizeB - TrimmedFileSizeB;
|
||||||
|
|
||||||
|
Stopwatch timedSw = Lambda.Timed(() =>
|
||||||
|
{
|
||||||
|
freeSpaceValid = CheckPadding(readSizeB, cancelToken);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (timedSw.Elapsed.TotalSeconds > 0)
|
||||||
|
{
|
||||||
|
Log?.Write(LogType.Info, $"Checked at {readSizeB / (double)XCIFileTrimmer.BytesInAMegabyte / timedSw.Elapsed.TotalSeconds:N} Mb/sec");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (freeSpaceValid)
|
||||||
|
Log?.Write(LogType.Info, "Free space is valid");
|
||||||
|
|
||||||
|
_freeSpaceValid = freeSpaceValid;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
CloseReaders();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log?.Write(LogType.Warn, "There is no free space to check.");
|
||||||
|
_freeSpaceValid = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_freeSpaceChecked = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool CheckPadding(long readSizeB, CancellationToken? cancelToken = null)
|
||||||
|
{
|
||||||
|
long maxReads = readSizeB / XCIFileTrimmer.BufferSize;
|
||||||
|
long read = 0;
|
||||||
|
var buffer = new byte[BufferSize];
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (cancelToken.HasValue && cancelToken.Value.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int bytes = _fileStream.Read(buffer, 0, XCIFileTrimmer.BufferSize);
|
||||||
|
if (bytes == 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
Log?.Progress(read, maxReads, "Verifying file can be trimmed", false);
|
||||||
|
if (buffer.Take(bytes).AsParallel().Any(b => b != XCIFileTrimmer.PaddingByte))
|
||||||
|
{
|
||||||
|
Log?.Write(LogType.Warn, "Free space is NOT valid");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
read++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Reset()
|
||||||
|
{
|
||||||
|
_freeSpaceChecked = false;
|
||||||
|
_freeSpaceValid = false;
|
||||||
|
ReadHeader();
|
||||||
|
}
|
||||||
|
|
||||||
|
public OperationOutcome Trim(CancellationToken? cancelToken = null)
|
||||||
|
{
|
||||||
|
if (!FileOK)
|
||||||
|
{
|
||||||
|
return OperationOutcome.InvalidXCIFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!CanBeTrimmed)
|
||||||
|
{
|
||||||
|
return OperationOutcome.NoTrimNecessary;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!FreeSpaceChecked)
|
||||||
|
{
|
||||||
|
CheckFreeSpace(cancelToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!FreeSpaceValid)
|
||||||
|
{
|
||||||
|
if (cancelToken.HasValue && cancelToken.Value.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
return OperationOutcome.Cancelled;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return OperationOutcome.FreeSpaceCheckFailed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Log?.Write(LogType.Info, "Trimming...");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var info = new FileInfo(Filename);
|
||||||
|
if ((info.Attributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Log?.Write(LogType.Info, "Attempting to remove ReadOnly attribute");
|
||||||
|
File.SetAttributes(Filename, info.Attributes & ~FileAttributes.ReadOnly);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log?.Write(LogType.Error, e.ToString());
|
||||||
|
return OperationOutcome.ReadOnlyFileCannotFix;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info.Length != FileSizeB)
|
||||||
|
{
|
||||||
|
Log?.Write(LogType.Error, "File size has changed, cannot safely trim.");
|
||||||
|
return OperationOutcome.FileSizeChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
var outfileStream = new FileStream(_filename, FileMode.Open, FileAccess.Write, FileShare.Write);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
|
||||||
|
#if !XCI_TRIMMER_READ_ONLY_MODE
|
||||||
|
outfileStream.SetLength(TrimmedFileSizeB);
|
||||||
|
#endif
|
||||||
|
return OperationOutcome.Successful;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
outfileStream.Close();
|
||||||
|
Reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log?.Write(LogType.Error, e.ToString());
|
||||||
|
return OperationOutcome.FileIOWriteError;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public OperationOutcome Untrim(CancellationToken? cancelToken = null)
|
||||||
|
{
|
||||||
|
if (!FileOK)
|
||||||
|
{
|
||||||
|
return OperationOutcome.InvalidXCIFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!CanBeUntrimmed)
|
||||||
|
{
|
||||||
|
return OperationOutcome.NoUntrimPossible;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Log?.Write(LogType.Info, "Untrimming...");
|
||||||
|
|
||||||
|
var info = new FileInfo(Filename);
|
||||||
|
if ((info.Attributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Log?.Write(LogType.Info, "Attempting to remove ReadOnly attribute");
|
||||||
|
File.SetAttributes(Filename, info.Attributes & ~FileAttributes.ReadOnly);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log?.Write(LogType.Error, e.ToString());
|
||||||
|
return OperationOutcome.ReadOnlyFileCannotFix;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info.Length != FileSizeB)
|
||||||
|
{
|
||||||
|
Log?.Write(LogType.Error, "File size has changed, cannot safely untrim.");
|
||||||
|
return OperationOutcome.FileSizeChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
var outfileStream = new FileStream(_filename, FileMode.Append, FileAccess.Write, FileShare.Write);
|
||||||
|
long bytesToWriteB = UntrimmedFileSizeB - FileSizeB;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Stopwatch timedSw = Lambda.Timed(() =>
|
||||||
|
{
|
||||||
|
WritePadding(outfileStream, bytesToWriteB, cancelToken);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (timedSw.Elapsed.TotalSeconds > 0)
|
||||||
|
{
|
||||||
|
Log?.Write(LogType.Info, $"Wrote at {bytesToWriteB / (double)XCIFileTrimmer.BytesInAMegabyte / timedSw.Elapsed.TotalSeconds:N} Mb/sec");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cancelToken.HasValue && cancelToken.Value.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
return OperationOutcome.Cancelled;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return OperationOutcome.Successful;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
outfileStream.Close();
|
||||||
|
Reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log?.Write(LogType.Error, e.ToString());
|
||||||
|
return OperationOutcome.FileIOWriteError;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WritePadding(FileStream outfileStream, long bytesToWriteB, CancellationToken? cancelToken = null)
|
||||||
|
{
|
||||||
|
long bytesLeftToWriteB = bytesToWriteB;
|
||||||
|
long writes = bytesLeftToWriteB / XCIFileTrimmer.BufferSize;
|
||||||
|
int write = 0;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var buffer = new byte[BufferSize];
|
||||||
|
Array.Fill<byte>(buffer, XCIFileTrimmer.PaddingByte);
|
||||||
|
|
||||||
|
while (bytesLeftToWriteB > 0)
|
||||||
|
{
|
||||||
|
if (cancelToken.HasValue && cancelToken.Value.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
long bytesToWrite = Math.Min(XCIFileTrimmer.BufferSize, bytesLeftToWriteB);
|
||||||
|
|
||||||
|
#if !XCI_TRIMMER_READ_ONLY_MODE
|
||||||
|
outfileStream.Write(buffer, 0, (int)bytesToWrite);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bytesLeftToWriteB -= bytesToWrite;
|
||||||
|
Log?.Progress(write, writes, "Writing padding data...", false);
|
||||||
|
write++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Log?.Progress(write, writes, "Writing padding data...", true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OpenReaders()
|
||||||
|
{
|
||||||
|
if (_binaryReader == null)
|
||||||
|
{
|
||||||
|
_fileStream = new FileStream(_filename, FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||||
|
_binaryReader = new BinaryReader(_fileStream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CloseReaders()
|
||||||
|
{
|
||||||
|
if (_binaryReader != null && _binaryReader.BaseStream != null)
|
||||||
|
_binaryReader.Close();
|
||||||
|
_binaryReader = null;
|
||||||
|
_fileStream = null;
|
||||||
|
GC.Collect();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ReadHeader()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
OpenReaders();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Attempt without key area
|
||||||
|
bool success = CheckAndReadHeader(false);
|
||||||
|
|
||||||
|
if (!success)
|
||||||
|
{
|
||||||
|
// Attempt with key area
|
||||||
|
success = CheckAndReadHeader(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
_fileOK = success;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
CloseReaders();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log?.Write(LogType.Error, ex.Message);
|
||||||
|
_fileOK = false;
|
||||||
|
_dataSizeB = 0;
|
||||||
|
_cartSizeB = 0;
|
||||||
|
_fileSizeB = 0;
|
||||||
|
_offsetB = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool CheckAndReadHeader(bool assumeKeyArea)
|
||||||
|
{
|
||||||
|
// Read file size
|
||||||
|
_fileSizeB = _fileStream.Length;
|
||||||
|
if (_fileSizeB < 32 * 1024)
|
||||||
|
{
|
||||||
|
Log?.Write(LogType.Error, "The source file doesn't look like an XCI file as the data size is too small");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup offset
|
||||||
|
_offsetB = (long)(assumeKeyArea ? XCIFileTrimmer.CartKeyAreaSize : 0);
|
||||||
|
|
||||||
|
// Check header
|
||||||
|
Pos = _offsetB + XCIFileTrimmer.HeaderFilePos;
|
||||||
|
string head = System.Text.Encoding.ASCII.GetString(_binaryReader.ReadBytes(4));
|
||||||
|
if (head != XCIFileTrimmer.HeaderMagicValue)
|
||||||
|
{
|
||||||
|
if (!assumeKeyArea)
|
||||||
|
{
|
||||||
|
Log?.Write(LogType.Warn, $"Incorrect header found, file mat contain a key area...");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Log?.Write(LogType.Error, "The source file doesn't look like an XCI file as the header is corrupted");
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read Cart Size
|
||||||
|
Pos = _offsetB + XCIFileTrimmer.CartSizeFilePos;
|
||||||
|
byte cartSizeId = _binaryReader.ReadByte();
|
||||||
|
if (!_cartSizesGB.TryGetValue(cartSizeId, out long cartSizeNGB))
|
||||||
|
{
|
||||||
|
Log?.Write(LogType.Error, $"The source file doesn't look like an XCI file as the Cartridge Size is incorrect (0x{cartSizeId:X2})");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
_cartSizeB = cartSizeNGB * XCIFileTrimmer.CartSizeMBinFormattedGB * XCIFileTrimmer.BytesInAMegabyte;
|
||||||
|
|
||||||
|
// Read data size
|
||||||
|
Pos = _offsetB + XCIFileTrimmer.DataSizeFilePos;
|
||||||
|
long records = (long)BitConverter.ToUInt32(_binaryReader.ReadBytes(4), 0);
|
||||||
|
_dataSizeB = RecordsToByte(records);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -152,16 +152,17 @@ namespace Ryujinx.Graphics.Gpu
|
|||||||
/// Creates a new GPU memory manager.
|
/// Creates a new GPU memory manager.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="pid">ID of the process that owns the memory manager</param>
|
/// <param name="pid">ID of the process that owns the memory manager</param>
|
||||||
|
/// <param name="cpuMemorySize">The amount of physical CPU Memory Avaiable on the device.</param>
|
||||||
/// <returns>The memory manager</returns>
|
/// <returns>The memory manager</returns>
|
||||||
/// <exception cref="ArgumentException">Thrown when <paramref name="pid"/> is invalid</exception>
|
/// <exception cref="ArgumentException">Thrown when <paramref name="pid"/> is invalid</exception>
|
||||||
public MemoryManager CreateMemoryManager(ulong pid)
|
public MemoryManager CreateMemoryManager(ulong pid, ulong cpuMemorySize)
|
||||||
{
|
{
|
||||||
if (!PhysicalMemoryRegistry.TryGetValue(pid, out var physicalMemory))
|
if (!PhysicalMemoryRegistry.TryGetValue(pid, out var physicalMemory))
|
||||||
{
|
{
|
||||||
throw new ArgumentException("The PID is invalid or the process was not registered", nameof(pid));
|
throw new ArgumentException("The PID is invalid or the process was not registered", nameof(pid));
|
||||||
}
|
}
|
||||||
|
|
||||||
return new MemoryManager(physicalMemory);
|
return new MemoryManager(physicalMemory, cpuMemorySize);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using Ryujinx.Common.Logging;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@@ -47,11 +48,17 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
{
|
{
|
||||||
private const int MinCountForDeletion = 32;
|
private const int MinCountForDeletion = 32;
|
||||||
private const int MaxCapacity = 2048;
|
private const int MaxCapacity = 2048;
|
||||||
|
private const ulong GiB = 1024 * 1024 * 1024;
|
||||||
|
private ulong MaxTextureSizeCapacity = 4UL * GiB;
|
||||||
private const ulong MinTextureSizeCapacity = 512 * 1024 * 1024;
|
private const ulong MinTextureSizeCapacity = 512 * 1024 * 1024;
|
||||||
private const ulong MaxTextureSizeCapacity = 4UL * 1024 * 1024 * 1024;
|
private const ulong DefaultTextureSizeCapacity = 1 * GiB;
|
||||||
private const ulong DefaultTextureSizeCapacity = 1UL * 1024 * 1024 * 1024;
|
private const ulong TextureSizeCapacity6GiB = 4 * GiB;
|
||||||
|
private const ulong TextureSizeCapacity8GiB = 6 * GiB;
|
||||||
|
private const ulong TextureSizeCapacity12GiB = 12 * GiB;
|
||||||
|
|
||||||
|
|
||||||
private const float MemoryScaleFactor = 0.50f;
|
private const float MemoryScaleFactor = 0.50f;
|
||||||
private ulong _maxCacheMemoryUsage = 0;
|
private ulong _maxCacheMemoryUsage = DefaultTextureSizeCapacity;
|
||||||
|
|
||||||
private readonly LinkedList<Texture> _textures;
|
private readonly LinkedList<Texture> _textures;
|
||||||
private ulong _totalSize;
|
private ulong _totalSize;
|
||||||
@@ -66,18 +73,38 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <remarks>
|
/// <remarks>
|
||||||
/// If the backend GPU has 0 memory capacity, the cache size defaults to `DefaultTextureSizeCapacity`.
|
/// If the backend GPU has 0 memory capacity, the cache size defaults to `DefaultTextureSizeCapacity`.
|
||||||
|
///
|
||||||
|
/// Reads the current Device total CPU Memory, to determine the maximum amount of Vram available. Capped to 50% of Current GPU Memory.
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
/// <param name="context">The GPU context that the cache belongs to</param>
|
/// <param name="context">The GPU context that the cache belongs to</param>
|
||||||
public void Initialize(GpuContext context)
|
/// <param name="cpuMemorySize">The amount of physical CPU Memory Avaiable on the device.</param>
|
||||||
|
public void Initialize(GpuContext context, ulong cpuMemorySize)
|
||||||
{
|
{
|
||||||
|
var cpuMemorySizeGiB = cpuMemorySize / GiB;
|
||||||
|
|
||||||
|
if (cpuMemorySizeGiB < 6 || context.Capabilities.MaximumGpuMemory == 0)
|
||||||
|
{
|
||||||
|
_maxCacheMemoryUsage = DefaultTextureSizeCapacity;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (cpuMemorySizeGiB == 6)
|
||||||
|
{
|
||||||
|
MaxTextureSizeCapacity = TextureSizeCapacity6GiB;
|
||||||
|
}
|
||||||
|
else if (cpuMemorySizeGiB == 8)
|
||||||
|
{
|
||||||
|
MaxTextureSizeCapacity = TextureSizeCapacity8GiB;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MaxTextureSizeCapacity = TextureSizeCapacity12GiB;
|
||||||
|
}
|
||||||
|
|
||||||
var cacheMemory = (ulong)(context.Capabilities.MaximumGpuMemory * MemoryScaleFactor);
|
var cacheMemory = (ulong)(context.Capabilities.MaximumGpuMemory * MemoryScaleFactor);
|
||||||
|
|
||||||
_maxCacheMemoryUsage = Math.Clamp(cacheMemory, MinTextureSizeCapacity, MaxTextureSizeCapacity);
|
_maxCacheMemoryUsage = Math.Clamp(cacheMemory, MinTextureSizeCapacity, MaxTextureSizeCapacity);
|
||||||
|
|
||||||
if (context.Capabilities.MaximumGpuMemory == 0)
|
Logger.Info?.Print(LogClass.Gpu, $"AutoDelete Cache Allocated VRAM : {_maxCacheMemoryUsage / GiB} GiB");
|
||||||
{
|
|
||||||
_maxCacheMemoryUsage = DefaultTextureSizeCapacity;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -71,9 +71,10 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes the cache, setting the maximum texture capacity for the specified GPU context.
|
/// Initializes the cache, setting the maximum texture capacity for the specified GPU context.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void Initialize()
|
/// <param name="cpuMemorySize">The amount of physical CPU Memory Avaiable on the device.</param>
|
||||||
|
public void Initialize(ulong cpuMemorySize)
|
||||||
{
|
{
|
||||||
_cache.Initialize(_context);
|
_cache.Initialize(_context, cpuMemorySize);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -55,7 +55,8 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
/// Creates a new instance of the GPU memory manager.
|
/// Creates a new instance of the GPU memory manager.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="physicalMemory">Physical memory that this memory manager will map into</param>
|
/// <param name="physicalMemory">Physical memory that this memory manager will map into</param>
|
||||||
internal MemoryManager(PhysicalMemory physicalMemory)
|
/// <param name="cpuMemorySize">The amount of physical CPU Memory Avaiable on the device.</param>
|
||||||
|
internal MemoryManager(PhysicalMemory physicalMemory, ulong cpuMemorySize)
|
||||||
{
|
{
|
||||||
Physical = physicalMemory;
|
Physical = physicalMemory;
|
||||||
VirtualRangeCache = new VirtualRangeCache(this);
|
VirtualRangeCache = new VirtualRangeCache(this);
|
||||||
@@ -65,7 +66,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||||||
MemoryUnmapped += Physical.BufferCache.MemoryUnmappedHandler;
|
MemoryUnmapped += Physical.BufferCache.MemoryUnmappedHandler;
|
||||||
MemoryUnmapped += VirtualRangeCache.MemoryUnmappedHandler;
|
MemoryUnmapped += VirtualRangeCache.MemoryUnmappedHandler;
|
||||||
MemoryUnmapped += CounterCache.MemoryUnmappedHandler;
|
MemoryUnmapped += CounterCache.MemoryUnmappedHandler;
|
||||||
Physical.TextureCache.Initialize();
|
Physical.TextureCache.Initialize(cpuMemorySize);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -432,7 +432,7 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
|
|||||||
|
|
||||||
bool colorIsVector = isGather || !isShadow;
|
bool colorIsVector = isGather || !isShadow;
|
||||||
|
|
||||||
texCall += ")" + (colorIsVector ? GetMaskMultiDest(texOp.Index) : "");
|
texCall += ")" + (colorIsVector ? GetMaskMultiDest(texOp.Index) : string.Empty);
|
||||||
|
|
||||||
return texCall;
|
return texCall;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -830,12 +830,12 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
|
|
||||||
if (use.Node != null)
|
if (use.Node != null)
|
||||||
{
|
{
|
||||||
Console.Write($"{indentation} {separator}- ({(use.Inverted ? "INV " : "")}{use.Index})");
|
Console.Write($"{indentation} {separator}- ({(use.Inverted ? "INV " : string.Empty)}{use.Index})");
|
||||||
PrintTreeNode(use.Node, indentation + (last ? " " : " | "));
|
PrintTreeNode(use.Node, indentation + (last ? " " : " | "));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Console.WriteLine($"{indentation} {separator}- ({(use.Inverted ? "INV " : "")}{use.Index}) NULL");
|
Console.WriteLine($"{indentation} {separator}- ({(use.Inverted ? "INV " : string.Empty)}{use.Index}) NULL");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -852,12 +852,12 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||||||
|
|
||||||
if (use.Node != null)
|
if (use.Node != null)
|
||||||
{
|
{
|
||||||
Console.Write($"{indentation} {separator}- ({(use.Inverted ? "INV " : "")}{use.Index})");
|
Console.Write($"{indentation} {separator}- ({(use.Inverted ? "INV " : string.Empty)}{use.Index})");
|
||||||
PrintTreeNode(use.Node, indentation + (last ? " " : " | "));
|
PrintTreeNode(use.Node, indentation + (last ? " " : " | "));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Console.WriteLine($"{indentation} {separator}- ({(use.Inverted ? "INV " : "")}{use.Index}) NULL");
|
Console.WriteLine($"{indentation} {separator}- ({(use.Inverted ? "INV " : string.Empty)}{use.Index}) NULL");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -104,25 +104,27 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
public event EventHandler<ScreenCaptureImageInfo> ScreenCaptured;
|
public event EventHandler<ScreenCaptureImageInfo> ScreenCaptured;
|
||||||
|
|
||||||
public VulkanRenderer(Vk api, Func<Instance, Vk, SurfaceKHR> surfaceFunc, Func<string[]> requiredExtensionsFunc, string preferredGpuId)
|
public VulkanRenderer(Vk api, Func<Instance, Vk, SurfaceKHR> getSurface, Func<string[]> requiredExtensionsFunc, string preferredGpuId)
|
||||||
{
|
{
|
||||||
_getSurface = surfaceFunc;
|
_getSurface = getSurface;
|
||||||
_getRequiredExtensions = requiredExtensionsFunc;
|
_getRequiredExtensions = requiredExtensionsFunc;
|
||||||
_preferredGpuId = preferredGpuId;
|
_preferredGpuId = preferredGpuId;
|
||||||
Api = api;
|
Api = api;
|
||||||
Shaders = new HashSet<ShaderCollection>();
|
Shaders = [];
|
||||||
Textures = new HashSet<ITexture>();
|
Textures = [];
|
||||||
Samplers = new HashSet<SamplerHolder>();
|
Samplers = [];
|
||||||
|
|
||||||
if (OperatingSystem.IsMacOS())
|
// Any device running on MacOS is using MoltenVK, even Intel and AMD vendors.
|
||||||
{
|
if (IsMoltenVk = OperatingSystem.IsMacOS())
|
||||||
MVKInitialization.Initialize();
|
MVKInitialization.Initialize();
|
||||||
|
|
||||||
// Any device running on MacOS is using MoltenVK, even Intel and AMD vendors.
|
|
||||||
IsMoltenVk = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static VulkanRenderer Create(
|
||||||
|
string preferredGpuId,
|
||||||
|
Func<Instance, Vk, SurfaceKHR> getSurface,
|
||||||
|
Func<string[]> getRequiredExtensions
|
||||||
|
) => new(Vk.GetApi(), getSurface, getRequiredExtensions, preferredGpuId);
|
||||||
|
|
||||||
private unsafe void LoadFeatures(uint maxQueueCount, uint queueFamilyIndex)
|
private unsafe void LoadFeatures(uint maxQueueCount, uint queueFamilyIndex)
|
||||||
{
|
{
|
||||||
FormatCapabilities = new FormatCapabilities(Api, _physicalDevice.PhysicalDevice);
|
FormatCapabilities = new FormatCapabilities(Api, _physicalDevice.PhysicalDevice);
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ namespace Ryujinx.HLE.Generators
|
|||||||
var syntaxReceiver = (ServiceSyntaxReceiver)context.SyntaxReceiver;
|
var syntaxReceiver = (ServiceSyntaxReceiver)context.SyntaxReceiver;
|
||||||
CodeGenerator generator = new CodeGenerator();
|
CodeGenerator generator = new CodeGenerator();
|
||||||
|
|
||||||
|
generator.AppendLine("#nullable enable");
|
||||||
generator.AppendLine("using System;");
|
generator.AppendLine("using System;");
|
||||||
generator.EnterScope($"namespace Ryujinx.HLE.HOS.Services.Sm");
|
generator.EnterScope($"namespace Ryujinx.HLE.HOS.Services.Sm");
|
||||||
generator.EnterScope($"partial class IUserInterface");
|
generator.EnterScope($"partial class IUserInterface");
|
||||||
@@ -22,7 +23,7 @@ namespace Ryujinx.HLE.Generators
|
|||||||
{
|
{
|
||||||
if (className.Modifiers.Any(SyntaxKind.AbstractKeyword) || className.Modifiers.Any(SyntaxKind.PrivateKeyword) || !className.AttributeLists.Any(x => x.Attributes.Any(y => y.ToString().StartsWith("Service"))))
|
if (className.Modifiers.Any(SyntaxKind.AbstractKeyword) || className.Modifiers.Any(SyntaxKind.PrivateKeyword) || !className.AttributeLists.Any(x => x.Attributes.Any(y => y.ToString().StartsWith("Service"))))
|
||||||
continue;
|
continue;
|
||||||
var name = GetFullName(className, context).Replace("global::", "");
|
var name = GetFullName(className, context).Replace("global::", string.Empty);
|
||||||
if (!name.StartsWith("Ryujinx.HLE.HOS.Services"))
|
if (!name.StartsWith("Ryujinx.HLE.HOS.Services"))
|
||||||
continue;
|
continue;
|
||||||
var constructors = className.ChildNodes().Where(x => x.IsKind(SyntaxKind.ConstructorDeclaration)).Select(y => y as ConstructorDeclarationSyntax).ToArray();
|
var constructors = className.ChildNodes().Where(x => x.IsKind(SyntaxKind.ConstructorDeclaration)).Select(y => y as ConstructorDeclarationSyntax).ToArray();
|
||||||
@@ -58,6 +59,7 @@ namespace Ryujinx.HLE.Generators
|
|||||||
|
|
||||||
generator.LeaveScope();
|
generator.LeaveScope();
|
||||||
generator.LeaveScope();
|
generator.LeaveScope();
|
||||||
|
generator.AppendLine("#nullable disable");
|
||||||
context.AddSource($"IUserInterface.g.cs", generator.ToString());
|
context.AddSource($"IUserInterface.g.cs", generator.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -523,7 +523,7 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
{
|
{
|
||||||
// Clean up the name and get the NcaId
|
// Clean up the name and get the NcaId
|
||||||
|
|
||||||
string[] pathComponents = entry.FullName.Replace(".cnmt", "").Split('/');
|
string[] pathComponents = entry.FullName.Replace(".cnmt", string.Empty).Split('/');
|
||||||
|
|
||||||
string ncaId = pathComponents[^1];
|
string ncaId = pathComponents[^1];
|
||||||
|
|
||||||
|
|||||||
@@ -132,7 +132,7 @@ namespace Ryujinx.HLE.FileSystem
|
|||||||
|
|
||||||
if (systemPath.StartsWith(baseSystemPath))
|
if (systemPath.StartsWith(baseSystemPath))
|
||||||
{
|
{
|
||||||
string rawPath = systemPath.Replace(baseSystemPath, "");
|
string rawPath = systemPath.Replace(baseSystemPath, string.Empty);
|
||||||
int firstSeparatorOffset = rawPath.IndexOf(Path.DirectorySeparatorChar);
|
int firstSeparatorOffset = rawPath.IndexOf(Path.DirectorySeparatorChar);
|
||||||
|
|
||||||
if (firstSeparatorOffset == -1)
|
if (firstSeparatorOffset == -1)
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.HLE.HOS.Applets.Browser;
|
using Ryujinx.HLE.HOS.Applets.Browser;
|
||||||
|
using Ryujinx.HLE.HOS.Applets.Dummy;
|
||||||
using Ryujinx.HLE.HOS.Applets.Error;
|
using Ryujinx.HLE.HOS.Applets.Error;
|
||||||
using Ryujinx.HLE.HOS.Services.Am.AppletAE;
|
using Ryujinx.HLE.HOS.Services.Am.AppletAE;
|
||||||
using System;
|
using System;
|
||||||
@@ -26,9 +28,13 @@ namespace Ryujinx.HLE.HOS.Applets
|
|||||||
return new BrowserApplet(system);
|
return new BrowserApplet(system);
|
||||||
case AppletId.LibAppletOff:
|
case AppletId.LibAppletOff:
|
||||||
return new BrowserApplet(system);
|
return new BrowserApplet(system);
|
||||||
|
case AppletId.MiiEdit:
|
||||||
|
Logger.Warning?.Print(LogClass.Application, $"Please use the MiiEdit inside File/Open Applet");
|
||||||
|
return new DummyApplet(system);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new NotImplementedException($"{applet} applet is not implemented.");
|
Logger.Warning?.Print(LogClass.Application, $"Applet {applet} not implemented!");
|
||||||
|
return new DummyApplet(system);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
43
src/Ryujinx.HLE/HOS/Applets/Dummy/DummyApplet.cs
Normal file
43
src/Ryujinx.HLE/HOS/Applets/Dummy/DummyApplet.cs
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
using Ryujinx.Common.Logging;
|
||||||
|
using Ryujinx.Common.Memory;
|
||||||
|
using Ryujinx.HLE.HOS.Applets;
|
||||||
|
using Ryujinx.HLE.HOS.Services.Am.AppletAE;
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
namespace Ryujinx.HLE.HOS.Applets.Dummy
|
||||||
|
{
|
||||||
|
internal class DummyApplet : IApplet
|
||||||
|
{
|
||||||
|
private readonly Horizon _system;
|
||||||
|
private AppletSession _normalSession;
|
||||||
|
public event EventHandler AppletStateChanged;
|
||||||
|
public DummyApplet(Horizon system)
|
||||||
|
{
|
||||||
|
_system = system;
|
||||||
|
}
|
||||||
|
public ResultCode Start(AppletSession normalSession, AppletSession interactiveSession)
|
||||||
|
{
|
||||||
|
_normalSession = normalSession;
|
||||||
|
_normalSession.Push(BuildResponse());
|
||||||
|
AppletStateChanged?.Invoke(this, null);
|
||||||
|
_system.ReturnFocus();
|
||||||
|
return ResultCode.Success;
|
||||||
|
}
|
||||||
|
private static T ReadStruct<T>(byte[] data) where T : struct
|
||||||
|
{
|
||||||
|
return MemoryMarshal.Read<T>(data.AsSpan());
|
||||||
|
}
|
||||||
|
private static byte[] BuildResponse()
|
||||||
|
{
|
||||||
|
using MemoryStream stream = MemoryStreamManager.Shared.GetStream();
|
||||||
|
using BinaryWriter writer = new(stream);
|
||||||
|
writer.Write((ulong)ResultCode.Success);
|
||||||
|
return stream.ToArray();
|
||||||
|
}
|
||||||
|
public ResultCode GetResult()
|
||||||
|
{
|
||||||
|
return ResultCode.Success;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -107,7 +107,7 @@ namespace Ryujinx.HLE.HOS.Applets.Error
|
|||||||
|
|
||||||
private static string CleanText(string value)
|
private static string CleanText(string value)
|
||||||
{
|
{
|
||||||
return CleanTextRegex().Replace(value, "").Replace("\0", "");
|
return CleanTextRegex().Replace(value, string.Empty).Replace("\0", string.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetMessageText(uint module, uint description, string key)
|
private string GetMessageText(uint module, uint description, string key)
|
||||||
@@ -129,17 +129,15 @@ namespace Ryujinx.HLE.HOS.Applets.Error
|
|||||||
|
|
||||||
return CleanText(reader.ReadToEnd());
|
return CleanText(reader.ReadToEnd());
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
return string.Empty;
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private string[] GetButtonsText(uint module, uint description, string key)
|
private string[] GetButtonsText(uint module, uint description, string key)
|
||||||
{
|
{
|
||||||
string buttonsText = GetMessageText(module, description, key);
|
string buttonsText = GetMessageText(module, description, key);
|
||||||
|
|
||||||
return (buttonsText == "") ? null : buttonsText.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None);
|
return (buttonsText == string.Empty) ? null : buttonsText.Split(["\r\n", "\r", "\n"], StringSplitOptions.None);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ParseErrorCommonArg()
|
private void ParseErrorCommonArg()
|
||||||
@@ -156,7 +154,7 @@ namespace Ryujinx.HLE.HOS.Applets.Error
|
|||||||
|
|
||||||
string message = GetMessageText(module, description, "DlgMsg");
|
string message = GetMessageText(module, description, "DlgMsg");
|
||||||
|
|
||||||
if (message == "")
|
if (message == string.Empty)
|
||||||
{
|
{
|
||||||
message = "An error has occured.\n\nPlease try again later.";
|
message = "An error has occured.\n\nPlease try again later.";
|
||||||
}
|
}
|
||||||
@@ -190,7 +188,7 @@ namespace Ryujinx.HLE.HOS.Applets.Error
|
|||||||
|
|
||||||
// TODO: Handle the LanguageCode to return the translated "OK" and "Details".
|
// TODO: Handle the LanguageCode to return the translated "OK" and "Details".
|
||||||
|
|
||||||
if (detailsText.Trim() != "")
|
if (detailsText.Trim() != string.Empty)
|
||||||
{
|
{
|
||||||
buttons.Add("Details");
|
buttons.Add("Details");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ namespace Ryujinx.HLE.HOS.Applets
|
|||||||
|
|
||||||
private byte[] _transferMemory;
|
private byte[] _transferMemory;
|
||||||
|
|
||||||
private string _textValue = "";
|
private string _textValue = string.Empty;
|
||||||
private int _cursorBegin = 0;
|
private int _cursorBegin = 0;
|
||||||
private Encoding _encoding = Encoding.Unicode;
|
private Encoding _encoding = Encoding.Unicode;
|
||||||
private KeyboardResult _lastResult = KeyboardResult.NotSet;
|
private KeyboardResult _lastResult = KeyboardResult.NotSet;
|
||||||
|
|||||||
@@ -305,7 +305,7 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
|||||||
{
|
{
|
||||||
SKRect bounds = SKRect.Empty;
|
SKRect bounds = SKRect.Empty;
|
||||||
|
|
||||||
if (text == "")
|
if (text == string.Empty)
|
||||||
{
|
{
|
||||||
paint.MeasureText(" ", ref bounds);
|
paint.MeasureText(" ", ref bounds);
|
||||||
}
|
}
|
||||||
@@ -321,7 +321,7 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
|||||||
{
|
{
|
||||||
SKRect bounds = SKRect.Empty;
|
SKRect bounds = SKRect.Empty;
|
||||||
|
|
||||||
if (text == "")
|
if (text == string.Empty)
|
||||||
{
|
{
|
||||||
paint.MeasureText(" ", ref bounds);
|
paint.MeasureText(" ", ref bounds);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ namespace Ryujinx.HLE.HOS.Applets.SoftwareKeyboard
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
internal class SoftwareKeyboardUIState
|
internal class SoftwareKeyboardUIState
|
||||||
{
|
{
|
||||||
public string InputText = "";
|
public string InputText = string.Empty;
|
||||||
public int CursorBegin = 0;
|
public int CursorBegin = 0;
|
||||||
public int CursorEnd = 0;
|
public int CursorEnd = 0;
|
||||||
public bool AcceptPressed = false;
|
public bool AcceptPressed = false;
|
||||||
|
|||||||
@@ -2463,7 +2463,7 @@ namespace Ryujinx.HLE.HOS.Diagnostics.Demangler
|
|||||||
return ParseIntegerLiteral("unsigned short");
|
return ParseIntegerLiteral("unsigned short");
|
||||||
case 'i':
|
case 'i':
|
||||||
_position++;
|
_position++;
|
||||||
return ParseIntegerLiteral("");
|
return ParseIntegerLiteral(string.Empty);
|
||||||
case 'j':
|
case 'j':
|
||||||
_position++;
|
_position++;
|
||||||
return ParseIntegerLiteral("u");
|
return ParseIntegerLiteral("u");
|
||||||
|
|||||||
@@ -238,7 +238,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
info.SubName = "";
|
info.SubName = string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
info.ImageName = GetGuessedNsoNameFromIndex(imageIndex);
|
info.ImageName = GetGuessedNsoNameFromIndex(imageIndex);
|
||||||
|
|||||||
@@ -116,18 +116,13 @@ namespace Ryujinx.HLE.HOS
|
|||||||
private readonly Dictionary<ulong, ModCache> _appMods; // key is ApplicationId
|
private readonly Dictionary<ulong, ModCache> _appMods; // key is ApplicationId
|
||||||
private PatchCache _patches;
|
private PatchCache _patches;
|
||||||
|
|
||||||
private static readonly EnumerationOptions _dirEnumOptions;
|
private static readonly EnumerationOptions _dirEnumOptions = new()
|
||||||
|
|
||||||
static ModLoader()
|
|
||||||
{
|
{
|
||||||
_dirEnumOptions = new EnumerationOptions
|
MatchCasing = MatchCasing.CaseInsensitive,
|
||||||
{
|
MatchType = MatchType.Simple,
|
||||||
MatchCasing = MatchCasing.CaseInsensitive,
|
RecurseSubdirectories = false,
|
||||||
MatchType = MatchType.Simple,
|
ReturnSpecialDirectories = false,
|
||||||
RecurseSubdirectories = false,
|
};
|
||||||
ReturnSpecialDirectories = false,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public ModLoader()
|
public ModLoader()
|
||||||
{
|
{
|
||||||
@@ -169,7 +164,7 @@ namespace Ryujinx.HLE.HOS
|
|||||||
foreach (var modDir in dir.EnumerateDirectories())
|
foreach (var modDir in dir.EnumerateDirectories())
|
||||||
{
|
{
|
||||||
types.Clear();
|
types.Clear();
|
||||||
Mod<DirectoryInfo> mod = new("", null, true);
|
Mod<DirectoryInfo> mod = new(string.Empty, null, true);
|
||||||
|
|
||||||
if (StrEquals(RomfsDir, modDir.Name))
|
if (StrEquals(RomfsDir, modDir.Name))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
|
|||||||
{
|
{
|
||||||
if (userId.IsNull)
|
if (userId.IsNull)
|
||||||
{
|
{
|
||||||
userId = new UserId(Guid.NewGuid().ToString().Replace("-", ""));
|
userId = new UserId(Guid.NewGuid().ToString().Replace("-", string.Empty));
|
||||||
}
|
}
|
||||||
|
|
||||||
UserProfile profile = new(userId, name, image);
|
UserProfile profile = new(userId, name, image);
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ using Ryujinx.HLE.Exceptions;
|
|||||||
using Ryujinx.HLE.HOS.Kernel.Memory;
|
using Ryujinx.HLE.HOS.Kernel.Memory;
|
||||||
using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory;
|
using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory;
|
||||||
using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Common;
|
using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Common;
|
||||||
|
using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.DebugMouse;
|
||||||
using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.DebugPad;
|
using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.DebugPad;
|
||||||
using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Keyboard;
|
using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Keyboard;
|
||||||
using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Mouse;
|
using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Mouse;
|
||||||
@@ -28,6 +29,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
|||||||
public DebugPadDevice DebugPad;
|
public DebugPadDevice DebugPad;
|
||||||
public TouchDevice Touchscreen;
|
public TouchDevice Touchscreen;
|
||||||
public MouseDevice Mouse;
|
public MouseDevice Mouse;
|
||||||
|
public DebugMouseDevice DebugMouse;
|
||||||
public KeyboardDevice Keyboard;
|
public KeyboardDevice Keyboard;
|
||||||
public NpadDevices Npads;
|
public NpadDevices Npads;
|
||||||
|
|
||||||
@@ -44,6 +46,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
|||||||
CheckTypeSizeOrThrow<RingLifo<DebugPadState>>(0x2c8);
|
CheckTypeSizeOrThrow<RingLifo<DebugPadState>>(0x2c8);
|
||||||
CheckTypeSizeOrThrow<RingLifo<TouchScreenState>>(0x2C38);
|
CheckTypeSizeOrThrow<RingLifo<TouchScreenState>>(0x2C38);
|
||||||
CheckTypeSizeOrThrow<RingLifo<MouseState>>(0x350);
|
CheckTypeSizeOrThrow<RingLifo<MouseState>>(0x350);
|
||||||
|
CheckTypeSizeOrThrow<RingLifo<DebugMouseState>>(0x350);
|
||||||
CheckTypeSizeOrThrow<RingLifo<KeyboardState>>(0x3D8);
|
CheckTypeSizeOrThrow<RingLifo<KeyboardState>>(0x3D8);
|
||||||
CheckTypeSizeOrThrow<Array10<NpadState>>(0x32000);
|
CheckTypeSizeOrThrow<Array10<NpadState>>(0x32000);
|
||||||
CheckTypeSizeOrThrow<SharedMemory>(Horizon.HidSize);
|
CheckTypeSizeOrThrow<SharedMemory>(Horizon.HidSize);
|
||||||
@@ -64,6 +67,7 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
|||||||
DebugPad = new DebugPadDevice(_device, true);
|
DebugPad = new DebugPadDevice(_device, true);
|
||||||
Touchscreen = new TouchDevice(_device, true);
|
Touchscreen = new TouchDevice(_device, true);
|
||||||
Mouse = new MouseDevice(_device, false);
|
Mouse = new MouseDevice(_device, false);
|
||||||
|
DebugMouse = new DebugMouseDevice(_device, false);
|
||||||
Keyboard = new KeyboardDevice(_device, false);
|
Keyboard = new KeyboardDevice(_device, false);
|
||||||
Npads = new NpadDevices(_device, true);
|
Npads = new NpadDevices(_device, true);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,29 @@
|
|||||||
|
using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Common;
|
||||||
|
using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.DebugMouse;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Services.Hid
|
||||||
|
{
|
||||||
|
public class DebugMouseDevice : BaseDevice
|
||||||
|
{
|
||||||
|
public DebugMouseDevice(Switch device, bool active) : base(device, active) { }
|
||||||
|
|
||||||
|
public void Update()
|
||||||
|
{
|
||||||
|
ref RingLifo<DebugMouseState> lifo = ref _device.Hid.SharedMemory.DebugMouse;
|
||||||
|
|
||||||
|
ref DebugMouseState previousEntry = ref lifo.GetCurrentEntryRef();
|
||||||
|
|
||||||
|
DebugMouseState newState = new()
|
||||||
|
{
|
||||||
|
SamplingNumber = previousEntry.SamplingNumber + 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (Active)
|
||||||
|
{
|
||||||
|
// TODO: This is a debug device only present in dev environment, do we want to support it?
|
||||||
|
}
|
||||||
|
|
||||||
|
lifo.Write(ref newState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -131,6 +131,26 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
|||||||
return ResultCode.Success;
|
return ResultCode.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[CommandCmif(26)]
|
||||||
|
// ActivateDebugMouse(nn::applet::AppletResourceUserId)
|
||||||
|
public ResultCode ActivateDebugMouse(ServiceCtx context)
|
||||||
|
{
|
||||||
|
long appletResourceUserId = context.RequestData.ReadInt64();
|
||||||
|
|
||||||
|
context.Device.Hid.DebugMouse.Active = true;
|
||||||
|
|
||||||
|
// Initialize entries to avoid issues with some games.
|
||||||
|
|
||||||
|
for (int entry = 0; entry < Hid.SharedMemEntryCount; entry++)
|
||||||
|
{
|
||||||
|
context.Device.Hid.DebugMouse.Update();
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger.Stub?.PrintStub(LogClass.ServiceHid, new { appletResourceUserId });
|
||||||
|
|
||||||
|
return ResultCode.Success;
|
||||||
|
}
|
||||||
|
|
||||||
[CommandCmif(31)]
|
[CommandCmif(31)]
|
||||||
// ActivateKeyboard(nn::applet::AppletResourceUserId)
|
// ActivateKeyboard(nn::applet::AppletResourceUserId)
|
||||||
public ResultCode ActivateKeyboard(ServiceCtx context)
|
public ResultCode ActivateKeyboard(ServiceCtx context)
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.DebugMouse
|
||||||
|
{
|
||||||
|
[Flags]
|
||||||
|
enum DebugMouseAttribute : uint
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
Transferable = 1 << 0,
|
||||||
|
IsConnected = 1 << 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.DebugMouse
|
||||||
|
{
|
||||||
|
[Flags]
|
||||||
|
enum DebugMouseButton : uint
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
Left = 1 << 0,
|
||||||
|
Right = 1 << 1,
|
||||||
|
Middle = 1 << 2,
|
||||||
|
Forward = 1 << 3,
|
||||||
|
Back = 1 << 4,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Common;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.DebugMouse
|
||||||
|
{
|
||||||
|
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
||||||
|
struct DebugMouseState : ISampledDataStruct
|
||||||
|
{
|
||||||
|
public ulong SamplingNumber;
|
||||||
|
public int X;
|
||||||
|
public int Y;
|
||||||
|
public int DeltaX;
|
||||||
|
public int DeltaY;
|
||||||
|
public int WheelDeltaX;
|
||||||
|
public int WheelDeltaY;
|
||||||
|
public DebugMouseButton Buttons;
|
||||||
|
public DebugMouseAttribute Attributes;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
using Ryujinx.Common.Memory;
|
using Ryujinx.Common.Memory;
|
||||||
using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Common;
|
using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Common;
|
||||||
|
using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.DebugMouse;
|
||||||
using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.DebugPad;
|
using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.DebugPad;
|
||||||
using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Keyboard;
|
using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Keyboard;
|
||||||
using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Mouse;
|
using Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory.Mouse;
|
||||||
@@ -45,6 +46,12 @@ namespace Ryujinx.HLE.HOS.Services.Hid.Types.SharedMemory
|
|||||||
[FieldOffset(0x9A00)]
|
[FieldOffset(0x9A00)]
|
||||||
public Array10<NpadState> Npads;
|
public Array10<NpadState> Npads;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Debug mouse.
|
||||||
|
/// </summary>
|
||||||
|
[FieldOffset(0x3DC00)]
|
||||||
|
public RingLifo<DebugMouseState> DebugMouse;
|
||||||
|
|
||||||
public static SharedMemory Create()
|
public static SharedMemory Create()
|
||||||
{
|
{
|
||||||
SharedMemory result = new()
|
SharedMemory result = new()
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using Gommon;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.Common.Memory;
|
using Ryujinx.Common.Memory;
|
||||||
using Ryujinx.Common.Utilities;
|
using Ryujinx.Common.Utilities;
|
||||||
@@ -143,7 +144,7 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator.LdnMitm
|
|||||||
if (decompressedLdnData.Length != header.DecompressLength)
|
if (decompressedLdnData.Length != header.DecompressLength)
|
||||||
{
|
{
|
||||||
Logger.Error?.PrintMsg(LogClass.ServiceLdn, $"Decompress error: length does not match. ({decompressedLdnData.Length} != {header.DecompressLength})");
|
Logger.Error?.PrintMsg(LogClass.ServiceLdn, $"Decompress error: length does not match. ({decompressedLdnData.Length} != {header.DecompressLength})");
|
||||||
Logger.Error?.PrintMsg(LogClass.ServiceLdn, $"Decompress error data: '{string.Join("", decompressedLdnData.Select(x => (int)x).ToArray())}'");
|
Logger.Error?.PrintMsg(LogClass.ServiceLdn, $"Decompress error data: '{decompressedLdnData.Select(x => (int)x).JoinToString(string.Empty)}'");
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp.NfpManager
|
|||||||
public uint FileVersion { get; set; }
|
public uint FileVersion { get; set; }
|
||||||
public byte[] TagUuid { get; set; }
|
public byte[] TagUuid { get; set; }
|
||||||
public string AmiiboId { get; set; }
|
public string AmiiboId { get; set; }
|
||||||
|
public string NickName { get; set; }
|
||||||
public DateTime FirstWriteDate { get; set; }
|
public DateTime FirstWriteDate { get; set; }
|
||||||
public DateTime LastWriteDate { get; set; }
|
public DateTime LastWriteDate { get; set; }
|
||||||
public ushort WriteCounter { get; set; }
|
public ushort WriteCounter { get; set; }
|
||||||
|
|||||||
@@ -64,16 +64,17 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static RegisterInfo GetRegisterInfo(ITickSource tickSource, string amiiboId, string nickname)
|
public static RegisterInfo GetRegisterInfo(ITickSource tickSource, string amiiboId, string userName)
|
||||||
{
|
{
|
||||||
VirtualAmiiboFile amiiboFile = LoadAmiiboFile(amiiboId);
|
VirtualAmiiboFile amiiboFile = LoadAmiiboFile(amiiboId);
|
||||||
|
string nickname = amiiboFile.NickName ?? "Ryujinx";
|
||||||
UtilityImpl utilityImpl = new(tickSource);
|
UtilityImpl utilityImpl = new(tickSource);
|
||||||
CharInfo charInfo = new();
|
CharInfo charInfo = new();
|
||||||
|
|
||||||
charInfo.SetFromStoreData(StoreData.BuildDefault(utilityImpl, 0));
|
charInfo.SetFromStoreData(StoreData.BuildDefault(utilityImpl, 0));
|
||||||
|
|
||||||
charInfo.Nickname = Nickname.FromString(nickname);
|
// This is the player's name
|
||||||
|
charInfo.Nickname = Nickname.FromString(userName);
|
||||||
|
|
||||||
RegisterInfo registerInfo = new()
|
RegisterInfo registerInfo = new()
|
||||||
{
|
{
|
||||||
@@ -85,7 +86,9 @@ namespace Ryujinx.HLE.HOS.Services.Nfc.Nfp
|
|||||||
Reserved1 = new Array64<byte>(),
|
Reserved1 = new Array64<byte>(),
|
||||||
Reserved2 = new Array58<byte>(),
|
Reserved2 = new Array58<byte>(),
|
||||||
};
|
};
|
||||||
"Ryujinx"u8.CopyTo(registerInfo.Nickname.AsSpan());
|
// This is the amiibo's name
|
||||||
|
byte[] nicknameBytes = System.Text.Encoding.UTF8.GetBytes(nickname);
|
||||||
|
nicknameBytes.CopyTo(registerInfo.Nickname.AsSpan());
|
||||||
|
|
||||||
return registerInfo;
|
return registerInfo;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ namespace Ryujinx.HLE.HOS.Services.Ngct
|
|||||||
ulong bufferSize = context.Request.PtrBuff[0].Size;
|
ulong bufferSize = context.Request.PtrBuff[0].Size;
|
||||||
|
|
||||||
bool isMatch = false;
|
bool isMatch = false;
|
||||||
string text = "";
|
string text = string.Empty;
|
||||||
|
|
||||||
if (bufferSize != 0)
|
if (bufferSize != 0)
|
||||||
{
|
{
|
||||||
@@ -57,8 +57,8 @@ namespace Ryujinx.HLE.HOS.Services.Ngct
|
|||||||
|
|
||||||
ulong bufferFilteredPosition = context.Request.RecvListBuff[0].Position;
|
ulong bufferFilteredPosition = context.Request.RecvListBuff[0].Position;
|
||||||
|
|
||||||
string text = "";
|
string text = string.Empty;
|
||||||
string textFiltered = "";
|
string textFiltered = string.Empty;
|
||||||
|
|
||||||
if (bufferSize != 0)
|
if (bufferSize != 0)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu
|
|||||||
|
|
||||||
public NvHostAsGpuDeviceFile(ServiceCtx context, IVirtualMemoryManager memory, ulong owner) : base(context, owner)
|
public NvHostAsGpuDeviceFile(ServiceCtx context, IVirtualMemoryManager memory, ulong owner) : base(context, owner)
|
||||||
{
|
{
|
||||||
_asContext = new AddressSpaceContext(context.Device.Gpu.CreateMemoryManager(owner));
|
_asContext = new AddressSpaceContext(context.Device.Gpu.CreateMemoryManager(owner, context.Device.Memory.Size));
|
||||||
_memoryAllocator = new NvMemoryAllocator();
|
_memoryAllocator = new NvMemoryAllocator();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -36,7 +36,7 @@ namespace Ryujinx.HLE.HOS.Services.Sockets.Nsd.Manager
|
|||||||
// TODO: Load Environment from the savedata.
|
// TODO: Load Environment from the savedata.
|
||||||
address = address.Replace("%", IManager.NsdSettings.Environment);
|
address = address.Replace("%", IManager.NsdSettings.Environment);
|
||||||
|
|
||||||
resolvedAddress = "";
|
resolvedAddress = string.Empty;
|
||||||
|
|
||||||
if (IManager.NsdSettings == null)
|
if (IManager.NsdSettings == null)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger
|
|||||||
|
|
||||||
if (size < 0)
|
if (size < 0)
|
||||||
{
|
{
|
||||||
return "";
|
return string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReadOnlySpan<byte> data = ReadInPlace((size + 1) * 2);
|
ReadOnlySpan<byte> data = ReadInPlace((size + 1) * 2);
|
||||||
|
|||||||
@@ -166,7 +166,7 @@ namespace Ryujinx.HLE.HOS.Services.Vi.RootService
|
|||||||
|
|
||||||
private ResultCode OpenDisplayImpl(ServiceCtx context, string name)
|
private ResultCode OpenDisplayImpl(ServiceCtx context, string name)
|
||||||
{
|
{
|
||||||
if (name == "")
|
if (name == string.Empty)
|
||||||
{
|
{
|
||||||
return ResultCode.InvalidValue;
|
return ResultCode.InvalidValue;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ namespace Ryujinx.HLE.Loaders.Executables
|
|||||||
Match fsSdkMatch = FsSdkRegex().Match(rawTextBuffer);
|
Match fsSdkMatch = FsSdkRegex().Match(rawTextBuffer);
|
||||||
if (fsSdkMatch.Success)
|
if (fsSdkMatch.Success)
|
||||||
{
|
{
|
||||||
stringBuilder.AppendLine($" FS SDK Version: {fsSdkMatch.Value.Replace("sdk_version: ", "")}");
|
stringBuilder.AppendLine($" FS SDK Version: {fsSdkMatch.Value.Replace("sdk_version: ", string.Empty)}");
|
||||||
}
|
}
|
||||||
|
|
||||||
MatchCollection sdkMwMatches = SdkMwRegex().Matches(rawTextBuffer);
|
MatchCollection sdkMwMatches = SdkMwRegex().Matches(rawTextBuffer);
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ namespace Ryujinx.HLE.Loaders.Processes.Extensions
|
|||||||
Logger.Warning?.Print(LogClass.Ptc, "Detected unsupported ExeFs modifications. PTC disabled.");
|
Logger.Warning?.Print(LogClass.Ptc, "Detected unsupported ExeFs modifications. PTC disabled.");
|
||||||
}
|
}
|
||||||
|
|
||||||
string programName = "";
|
string programName = string.Empty;
|
||||||
|
|
||||||
if (!isHomebrew && programId > 0x010000000000FFFF)
|
if (!isHomebrew && programId > 0x010000000000FFFF)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ namespace Ryujinx.HLE.Loaders.Processes
|
|||||||
var nacpData = new BlitStruct<ApplicationControlProperty>(1);
|
var nacpData = new BlitStruct<ApplicationControlProperty>(1);
|
||||||
ulong programId = metaLoader.GetProgramId();
|
ulong programId = metaLoader.GetProgramId();
|
||||||
|
|
||||||
device.Configuration.VirtualFileSystem.ModLoader.CollectMods(new[] { programId });
|
device.Configuration.VirtualFileSystem.ModLoader.CollectMods([programId]);
|
||||||
|
|
||||||
if (programId != 0)
|
if (programId != 0)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -145,7 +145,7 @@ namespace Ryujinx.HLE.Loaders.Processes
|
|||||||
IFileSystem dummyExeFs = null;
|
IFileSystem dummyExeFs = null;
|
||||||
Stream romfsStream = null;
|
Stream romfsStream = null;
|
||||||
|
|
||||||
string programName = "";
|
string programName = string.Empty;
|
||||||
ulong programId = 0000000000000000;
|
ulong programId = 0000000000000000;
|
||||||
|
|
||||||
// Load executable.
|
// Load executable.
|
||||||
|
|||||||
@@ -255,7 +255,7 @@ namespace Ryujinx.HLE.Loaders.Processes
|
|||||||
{
|
{
|
||||||
NsoExecutable nso => Convert.ToHexString(nso.BuildId.ItemsRo.ToArray()),
|
NsoExecutable nso => Convert.ToHexString(nso.BuildId.ItemsRo.ToArray()),
|
||||||
NroExecutable nro => Convert.ToHexString(nro.Header.BuildId),
|
NroExecutable nro => Convert.ToHexString(nro.Header.BuildId),
|
||||||
_ => "",
|
_ => string.Empty
|
||||||
}).ToUpper());
|
}).ToUpper());
|
||||||
|
|
||||||
ulong[] nsoBase = new ulong[executables.Length];
|
ulong[] nsoBase = new ulong[executables.Length];
|
||||||
|
|||||||
@@ -117,8 +117,9 @@ namespace Ryujinx.Headless.SDL2.OpenGL
|
|||||||
GraphicsDebugLevel glLogLevel,
|
GraphicsDebugLevel glLogLevel,
|
||||||
AspectRatio aspectRatio,
|
AspectRatio aspectRatio,
|
||||||
bool enableMouse,
|
bool enableMouse,
|
||||||
HideCursorMode hideCursorMode)
|
HideCursorMode hideCursorMode,
|
||||||
: base(inputManager, glLogLevel, aspectRatio, enableMouse, hideCursorMode)
|
bool ignoreControllerApplet)
|
||||||
|
: base(inputManager, glLogLevel, aspectRatio, enableMouse, hideCursorMode, ignoreControllerApplet)
|
||||||
{
|
{
|
||||||
_glLogLevel = glLogLevel;
|
_glLogLevel = glLogLevel;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -226,6 +226,9 @@ namespace Ryujinx.Headless.SDL2
|
|||||||
[Option("ignore-missing-services", Required = false, Default = false, HelpText = "Enable ignoring missing services.")]
|
[Option("ignore-missing-services", Required = false, Default = false, HelpText = "Enable ignoring missing services.")]
|
||||||
public bool IgnoreMissingServices { get; set; }
|
public bool IgnoreMissingServices { get; set; }
|
||||||
|
|
||||||
|
[Option("ignore-controller-applet", Required = false, Default = false, HelpText = "Enable ignoring the controller applet when your game loses connection to your controller.")]
|
||||||
|
public bool IgnoreControllerApplet { get; set; }
|
||||||
|
|
||||||
// Values
|
// Values
|
||||||
|
|
||||||
[Value(0, MetaName = "input", HelpText = "Input to load.", Required = true)]
|
[Value(0, MetaName = "input", HelpText = "Input to load.", Required = true)]
|
||||||
|
|||||||
@@ -444,8 +444,7 @@ namespace Ryujinx.Headless.SDL2
|
|||||||
{
|
{
|
||||||
Logger.AddTarget(new AsyncLogTargetWrapper(
|
Logger.AddTarget(new AsyncLogTargetWrapper(
|
||||||
new FileLogTarget("file", logFile),
|
new FileLogTarget("file", logFile),
|
||||||
1000,
|
1000
|
||||||
AsyncLogTargetOverflowAction.Block
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -506,8 +505,8 @@ namespace Ryujinx.Headless.SDL2
|
|||||||
private static WindowBase CreateWindow(Options options)
|
private static WindowBase CreateWindow(Options options)
|
||||||
{
|
{
|
||||||
return options.GraphicsBackend == GraphicsBackend.Vulkan
|
return options.GraphicsBackend == GraphicsBackend.Vulkan
|
||||||
? new VulkanWindow(_inputManager, options.LoggingGraphicsDebugLevel, options.AspectRatio, options.EnableMouse, options.HideCursorMode)
|
? new VulkanWindow(_inputManager, options.LoggingGraphicsDebugLevel, options.AspectRatio, options.EnableMouse, options.HideCursorMode, options.IgnoreControllerApplet)
|
||||||
: new OpenGLWindow(_inputManager, options.LoggingGraphicsDebugLevel, options.AspectRatio, options.EnableMouse, options.HideCursorMode);
|
: new OpenGLWindow(_inputManager, options.LoggingGraphicsDebugLevel, options.AspectRatio, options.EnableMouse, options.HideCursorMode, options.IgnoreControllerApplet);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IRenderer CreateRenderer(Options options, WindowBase window)
|
private static IRenderer CreateRenderer(Options options, WindowBase window)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<Target Name="PostBuild" AfterTargets="PostBuildEvent" Condition="$([MSBuild]::IsOSPlatform('OSX'))">
|
<Target Name="PostBuild" AfterTargets="PostBuildEvent" Condition="$([MSBuild]::IsOSPlatform('OSX'))">
|
||||||
<Exec Command="codesign --entitlements '$(ProjectDir)..\..\distribution\macos\entitlements.xml' -f --deep -s $(SigningCertificate) '$(TargetDir)$(TargetName)'" />
|
<Exec Command="codesign --entitlements '$(ProjectDir)..\..\distribution\macos\entitlements.xml' -f -s $(SigningCertificate) '$(TargetDir)$(TargetName)'" />
|
||||||
</Target>
|
</Target>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -17,8 +17,9 @@ namespace Ryujinx.Headless.SDL2.Vulkan
|
|||||||
GraphicsDebugLevel glLogLevel,
|
GraphicsDebugLevel glLogLevel,
|
||||||
AspectRatio aspectRatio,
|
AspectRatio aspectRatio,
|
||||||
bool enableMouse,
|
bool enableMouse,
|
||||||
HideCursorMode hideCursorMode)
|
HideCursorMode hideCursorMode,
|
||||||
: base(inputManager, glLogLevel, aspectRatio, enableMouse, hideCursorMode)
|
bool ignoreControllerApplet)
|
||||||
|
: base(inputManager, glLogLevel, aspectRatio, enableMouse, hideCursorMode, ignoreControllerApplet)
|
||||||
{
|
{
|
||||||
_glLogLevel = glLogLevel;
|
_glLogLevel = glLogLevel;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using Humanizer;
|
||||||
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;
|
||||||
@@ -85,13 +86,15 @@ namespace Ryujinx.Headless.SDL2
|
|||||||
|
|
||||||
private readonly AspectRatio _aspectRatio;
|
private readonly AspectRatio _aspectRatio;
|
||||||
private readonly bool _enableMouse;
|
private readonly bool _enableMouse;
|
||||||
|
private readonly bool _ignoreControllerApplet;
|
||||||
|
|
||||||
public WindowBase(
|
public WindowBase(
|
||||||
InputManager inputManager,
|
InputManager inputManager,
|
||||||
GraphicsDebugLevel glLogLevel,
|
GraphicsDebugLevel glLogLevel,
|
||||||
AspectRatio aspectRatio,
|
AspectRatio aspectRatio,
|
||||||
bool enableMouse,
|
bool enableMouse,
|
||||||
HideCursorMode hideCursorMode)
|
HideCursorMode hideCursorMode,
|
||||||
|
bool ignoreControllerApplet)
|
||||||
{
|
{
|
||||||
MouseDriver = new SDL2MouseDriver(hideCursorMode);
|
MouseDriver = new SDL2MouseDriver(hideCursorMode);
|
||||||
_inputManager = inputManager;
|
_inputManager = inputManager;
|
||||||
@@ -107,6 +110,7 @@ namespace Ryujinx.Headless.SDL2
|
|||||||
_gpuDoneEvent = new ManualResetEvent(false);
|
_gpuDoneEvent = new ManualResetEvent(false);
|
||||||
_aspectRatio = aspectRatio;
|
_aspectRatio = aspectRatio;
|
||||||
_enableMouse = enableMouse;
|
_enableMouse = enableMouse;
|
||||||
|
_ignoreControllerApplet = ignoreControllerApplet;
|
||||||
HostUITheme = new HeadlessHostUiTheme();
|
HostUITheme = new HeadlessHostUiTheme();
|
||||||
|
|
||||||
SDL2Driver.Instance.Initialize();
|
SDL2Driver.Instance.Initialize();
|
||||||
@@ -483,12 +487,14 @@ namespace Ryujinx.Headless.SDL2
|
|||||||
|
|
||||||
public bool DisplayMessageDialog(ControllerAppletUIArgs args)
|
public bool DisplayMessageDialog(ControllerAppletUIArgs args)
|
||||||
{
|
{
|
||||||
|
if (_ignoreControllerApplet) return false;
|
||||||
|
|
||||||
string playerCount = args.PlayerCountMin == args.PlayerCountMax ? $"exactly {args.PlayerCountMin}" : $"{args.PlayerCountMin}-{args.PlayerCountMax}";
|
string playerCount = args.PlayerCountMin == args.PlayerCountMax ? $"exactly {args.PlayerCountMin}" : $"{args.PlayerCountMin}-{args.PlayerCountMax}";
|
||||||
|
|
||||||
string message = $"Application requests {playerCount} player(s) with:\n\n"
|
string message = $"Application requests {playerCount} {"player".ToQuantity(args.PlayerCountMin + args.PlayerCountMax, ShowQuantityAs.None)} with:\n\n"
|
||||||
+ $"TYPES: {args.SupportedStyles}\n\n"
|
+ $"TYPES: {args.SupportedStyles}\n\n"
|
||||||
+ $"PLAYERS: {string.Join(", ", args.SupportedPlayers)}\n\n"
|
+ $"PLAYERS: {string.Join(", ", args.SupportedPlayers)}\n\n"
|
||||||
+ (args.IsDocked ? "Docked mode set. Handheld is also invalid.\n\n" : "")
|
+ (args.IsDocked ? "Docked mode set. Handheld is also invalid.\n\n" : string.Empty)
|
||||||
+ "Please reconfigure Input now and then press OK.";
|
+ "Please reconfigure Input now and then press OK.";
|
||||||
|
|
||||||
return DisplayMessageDialog("Controller Applet", message);
|
return DisplayMessageDialog("Controller Applet", message);
|
||||||
|
|||||||
@@ -1235,14 +1235,14 @@ namespace Ryujinx.Horizon.Common
|
|||||||
{ 0x412, "NotFound" },
|
{ 0x412, "NotFound" },
|
||||||
{ 0x612, "NotEnoughBuffer" },
|
{ 0x612, "NotEnoughBuffer" },
|
||||||
{ 0xCA12, "Cancelled" },
|
{ 0xCA12, "Cancelled" },
|
||||||
{ 0x7FE12, "" },
|
{ 0x7FE12, string.Empty },
|
||||||
{ 0xFA212, "" },
|
{ 0xFA212, string.Empty },
|
||||||
{ 0xFA612, "InvalidTaskId" },
|
{ 0xFA612, "InvalidTaskId" },
|
||||||
{ 0xFB612, "InvalidSize" },
|
{ 0xFB612, "InvalidSize" },
|
||||||
{ 0xFCA12, "TaskCancelled" },
|
{ 0xFCA12, "TaskCancelled" },
|
||||||
{ 0xFCC12, "TaskNotCompleted" },
|
{ 0xFCC12, "TaskNotCompleted" },
|
||||||
{ 0xFCE12, "TaskQueueNotAvailable" },
|
{ 0xFCE12, "TaskQueueNotAvailable" },
|
||||||
{ 0x106A12, "" },
|
{ 0x106A12, string.Empty },
|
||||||
{ 0x106C12, "OutOfRpcTask" },
|
{ 0x106C12, "OutOfRpcTask" },
|
||||||
{ 0x109612, "InvalidCategory" },
|
{ 0x109612, "InvalidCategory" },
|
||||||
{ 0x214, "OutOfKeyResource" },
|
{ 0x214, "OutOfKeyResource" },
|
||||||
|
|||||||
@@ -221,7 +221,7 @@ namespace Ryujinx.Horizon.Sdk.Ngc.Detail
|
|||||||
if (includeMultiWord)
|
if (includeMultiWord)
|
||||||
{
|
{
|
||||||
int lastMultiWordIndex = 0;
|
int lastMultiWordIndex = 0;
|
||||||
string multiWord = "";
|
string multiWord = string.Empty;
|
||||||
|
|
||||||
while (_multiWordMap.Has(nodePlainIndex))
|
while (_multiWordMap.Has(nodePlainIndex))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ namespace Ryujinx.Input.SDL2
|
|||||||
{
|
{
|
||||||
lock (_lock)
|
lock (_lock)
|
||||||
{
|
{
|
||||||
_gamepadsIds.Add(id);
|
_gamepadsIds.Insert(joystickDeviceId, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
OnGamepadConnected?.Invoke(id);
|
OnGamepadConnected?.Invoke(id);
|
||||||
|
|||||||
@@ -162,7 +162,7 @@ namespace Ryujinx.UI.App.Common
|
|||||||
NsoReader reader = new();
|
NsoReader reader = new();
|
||||||
reader.Initialize(nsoFile.Release().AsStorage().AsFile(OpenMode.Read)).ThrowIfFailure();
|
reader.Initialize(nsoFile.Release().AsStorage().AsFile(OpenMode.Read)).ThrowIfFailure();
|
||||||
|
|
||||||
return BitConverter.ToString(reader.Header.ModuleId.ItemsRo.ToArray()).Replace("-", "").ToUpper()[..16];
|
return BitConverter.ToString(reader.Header.ModuleId.ItemsRo.ToArray()).Replace("-", string.Empty).ToUpper()[..16];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using DynamicData;
|
using DynamicData;
|
||||||
using DynamicData.Kernel;
|
using DynamicData.Kernel;
|
||||||
|
using Gommon;
|
||||||
using LibHac;
|
using LibHac;
|
||||||
using LibHac.Common;
|
using LibHac.Common;
|
||||||
using LibHac.Fs;
|
using LibHac.Fs;
|
||||||
@@ -801,17 +802,31 @@ namespace Ryujinx.UI.App.Common
|
|||||||
|
|
||||||
// Searches the provided directories for DLC NSP files that are _valid for the currently detected games in the
|
// Searches the provided directories for DLC NSP files that are _valid for the currently detected games in the
|
||||||
// library_, and then enables those DLC.
|
// library_, and then enables those DLC.
|
||||||
public int AutoLoadDownloadableContents(List<string> appDirs)
|
public int AutoLoadDownloadableContents(List<string> appDirs, out int numDlcRemoved)
|
||||||
{
|
{
|
||||||
_cancellationToken = new CancellationTokenSource();
|
_cancellationToken = new CancellationTokenSource();
|
||||||
|
|
||||||
List<string> dlcPaths = new();
|
List<string> dlcPaths = new();
|
||||||
int newDlcLoaded = 0;
|
int newDlcLoaded = 0;
|
||||||
|
numDlcRemoved = 0;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
// Remove any downloadable content which can no longer be located on disk
|
||||||
|
Logger.Notice.Print(LogClass.Application, $"Removing non-existing Title DLCs");
|
||||||
|
var dlcToRemove = _downloadableContents.Items
|
||||||
|
.Where(dlc => !File.Exists(dlc.Dlc.ContainerPath))
|
||||||
|
.ToList();
|
||||||
|
dlcToRemove.ForEach(dlc =>
|
||||||
|
Logger.Warning?.Print(LogClass.Application, $"Title DLC removed: {dlc.Dlc.ContainerPath}")
|
||||||
|
);
|
||||||
|
numDlcRemoved += dlcToRemove.Distinct().Count();
|
||||||
|
_downloadableContents.RemoveKeys(dlcToRemove.Select(dlc => dlc.Dlc));
|
||||||
|
|
||||||
foreach (string appDir in appDirs)
|
foreach (string appDir in appDirs)
|
||||||
{
|
{
|
||||||
|
Logger.Notice.Print(LogClass.Application, $"Auto loading DLC from: {appDir}");
|
||||||
|
|
||||||
if (_cancellationToken.Token.IsCancellationRequested)
|
if (_cancellationToken.Token.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
return newDlcLoaded;
|
return newDlcLoaded;
|
||||||
@@ -900,17 +915,37 @@ namespace Ryujinx.UI.App.Common
|
|||||||
// Searches the provided directories for update NSP files that are _valid for the currently detected games in the
|
// Searches the provided directories for update NSP files that are _valid for the currently detected games in the
|
||||||
// library_, and then applies those updates. If a newly-detected update is a newer version than the currently
|
// library_, and then applies those updates. If a newly-detected update is a newer version than the currently
|
||||||
// selected update (or if no update is currently selected), then that update will be selected.
|
// selected update (or if no update is currently selected), then that update will be selected.
|
||||||
public int AutoLoadTitleUpdates(List<string> appDirs)
|
public int AutoLoadTitleUpdates(List<string> appDirs, out int numUpdatesRemoved)
|
||||||
{
|
{
|
||||||
_cancellationToken = new CancellationTokenSource();
|
_cancellationToken = new CancellationTokenSource();
|
||||||
|
|
||||||
List<string> updatePaths = new();
|
List<string> updatePaths = new();
|
||||||
int numUpdatesLoaded = 0;
|
int numUpdatesLoaded = 0;
|
||||||
|
numUpdatesRemoved = 0;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
var titleIdsToSave = new HashSet<ulong>();
|
||||||
|
var titleIdsToRefresh = new HashSet<ulong>();
|
||||||
|
|
||||||
|
// Remove any updates which can no longer be located on disk
|
||||||
|
Logger.Notice.Print(LogClass.Application, $"Removing non-existing Title Updates");
|
||||||
|
var updatesToRemove = _titleUpdates.Items
|
||||||
|
.Where(it => !File.Exists(it.TitleUpdate.Path))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
numUpdatesRemoved += updatesToRemove.Select(it => it.TitleUpdate).Distinct().Count();
|
||||||
|
updatesToRemove.ForEach(ti =>
|
||||||
|
Logger.Warning?.Print(LogClass.Application, $"Title update removed: {ti.TitleUpdate.Path}")
|
||||||
|
);
|
||||||
|
_titleUpdates.RemoveKeys(updatesToRemove.Select(it => it.TitleUpdate));
|
||||||
|
titleIdsToSave.UnionWith(updatesToRemove.Select(it => it.TitleUpdate.TitleIdBase));
|
||||||
|
titleIdsToRefresh.UnionWith(updatesToRemove.Where(it => it.IsSelected).Select(update => update.TitleUpdate.TitleIdBase));
|
||||||
|
|
||||||
foreach (string appDir in appDirs)
|
foreach (string appDir in appDirs)
|
||||||
{
|
{
|
||||||
|
Logger.Notice.Print(LogClass.Application, $"Auto loading updates from: {appDir}");
|
||||||
|
|
||||||
if (_cancellationToken.Token.IsCancellationRequested)
|
if (_cancellationToken.Token.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
return numUpdatesLoaded;
|
return numUpdatesLoaded;
|
||||||
@@ -979,27 +1014,21 @@ namespace Ryujinx.UI.App.Common
|
|||||||
{
|
{
|
||||||
if (!_titleUpdates.Lookup(update).HasValue)
|
if (!_titleUpdates.Lookup(update).HasValue)
|
||||||
{
|
{
|
||||||
var currentlySelected = TitleUpdates.Items.FirstOrOptional(it =>
|
bool shouldSelect = AddAndAutoSelectUpdate(update);
|
||||||
it.TitleUpdate.TitleIdBase == update.TitleIdBase && it.IsSelected);
|
titleIdsToSave.Add(update.TitleIdBase);
|
||||||
|
|
||||||
var shouldSelect = !currentlySelected.HasValue ||
|
|
||||||
currentlySelected.Value.TitleUpdate.Version < update.Version;
|
|
||||||
_titleUpdates.AddOrUpdate((update, shouldSelect));
|
|
||||||
|
|
||||||
if (currentlySelected.HasValue && shouldSelect)
|
|
||||||
_titleUpdates.AddOrUpdate((currentlySelected.Value.TitleUpdate, false));
|
|
||||||
|
|
||||||
SaveTitleUpdatesForGame(update.TitleIdBase);
|
|
||||||
numUpdatesLoaded++;
|
numUpdatesLoaded++;
|
||||||
|
|
||||||
if (shouldSelect)
|
if (shouldSelect)
|
||||||
{
|
{
|
||||||
RefreshApplicationInfo(update.TitleIdBase);
|
titleIdsToRefresh.Add(update.TitleIdBase);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
titleIdsToSave.ForEach(titleId => SaveTitleUpdatesForGame(titleId));
|
||||||
|
titleIdsToRefresh.ForEach(titleId => RefreshApplicationInfo(titleId));
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@@ -1010,6 +1039,24 @@ namespace Ryujinx.UI.App.Common
|
|||||||
return numUpdatesLoaded;
|
return numUpdatesLoaded;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool AddAndAutoSelectUpdate(TitleUpdateModel update)
|
||||||
|
{
|
||||||
|
var currentlySelected = TitleUpdates.Items.FirstOrOptional(it =>
|
||||||
|
it.TitleUpdate.TitleIdBase == update.TitleIdBase && it.IsSelected);
|
||||||
|
|
||||||
|
var shouldSelect = !currentlySelected.HasValue ||
|
||||||
|
currentlySelected.Value.TitleUpdate.Version < update.Version;
|
||||||
|
|
||||||
|
_titleUpdates.AddOrUpdate((update, shouldSelect));
|
||||||
|
|
||||||
|
if (currentlySelected.HasValue && shouldSelect)
|
||||||
|
{
|
||||||
|
_titleUpdates.AddOrUpdate((currentlySelected.Value.TitleUpdate, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
return shouldSelect;
|
||||||
|
}
|
||||||
|
|
||||||
protected void OnApplicationCountUpdated(ApplicationCountUpdatedEventArgs e)
|
protected void OnApplicationCountUpdated(ApplicationCountUpdatedEventArgs e)
|
||||||
{
|
{
|
||||||
ApplicationCountUpdated?.Invoke(null, e);
|
ApplicationCountUpdated?.Invoke(null, e);
|
||||||
@@ -1394,8 +1441,8 @@ namespace Ryujinx.UI.App.Common
|
|||||||
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.Item1).ToHashSet();
|
||||||
|
bool updatesChanged = false;
|
||||||
|
|
||||||
bool addedNewUpdate = false;
|
|
||||||
foreach (var update in bundledUpdates.OrderByDescending(bundled => bundled.Version))
|
foreach (var update in bundledUpdates.OrderByDescending(bundled => bundled.Version))
|
||||||
{
|
{
|
||||||
if (!savedUpdateLookup.Contains(update))
|
if (!savedUpdateLookup.Contains(update))
|
||||||
@@ -1404,17 +1451,19 @@ namespace Ryujinx.UI.App.Common
|
|||||||
if (!selectedUpdate.HasValue || selectedUpdate.Value.Item1.Version < update.Version)
|
if (!selectedUpdate.HasValue || selectedUpdate.Value.Item1.Version < update.Version)
|
||||||
{
|
{
|
||||||
shouldSelect = true;
|
shouldSelect = true;
|
||||||
selectedUpdate = Optional<(TitleUpdateModel, bool IsSelected)>.Create((update, true));
|
if (selectedUpdate.HasValue)
|
||||||
|
_titleUpdates.AddOrUpdate((selectedUpdate.Value.Item1, false));
|
||||||
|
selectedUpdate = DynamicData.Kernel.Optional<(TitleUpdateModel, bool IsSelected)>.Create((update, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
modifiedVersion = modifiedVersion || shouldSelect;
|
modifiedVersion = modifiedVersion || shouldSelect;
|
||||||
it.AddOrUpdate((update, shouldSelect));
|
it.AddOrUpdate((update, shouldSelect));
|
||||||
|
|
||||||
addedNewUpdate = true;
|
updatesChanged = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (addedNewUpdate)
|
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(_virtualFileSystem, application.IdBase, gameUpdates);
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ namespace Ryujinx.UI.Common.Configuration
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The current version of the file format
|
/// The current version of the file format
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const int CurrentVersion = 55;
|
public const int CurrentVersion = 56;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Version of the configuration file format
|
/// Version of the configuration file format
|
||||||
@@ -173,6 +173,11 @@ namespace Ryujinx.UI.Common.Configuration
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool RememberWindowState { get; set; }
|
public bool RememberWindowState { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enables or disables the redesigned title bar
|
||||||
|
/// </summary>
|
||||||
|
public bool ShowTitleBar { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Enables hardware-accelerated rendering for Avalonia
|
/// Enables hardware-accelerated rendering for Avalonia
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -293,16 +298,6 @@ namespace Ryujinx.UI.Common.Configuration
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public string LanguageCode { get; set; }
|
public string LanguageCode { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Enable or disable custom themes in the GUI
|
|
||||||
/// </summary>
|
|
||||||
public bool EnableCustomTheme { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Path to custom GUI theme
|
|
||||||
/// </summary>
|
|
||||||
public string CustomThemePath { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Chooses the base style // Not Used
|
/// Chooses the base style // Not Used
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -0,0 +1,715 @@
|
|||||||
|
using Ryujinx.Common.Configuration;
|
||||||
|
using Ryujinx.Common.Configuration.Hid;
|
||||||
|
using Ryujinx.Common.Configuration.Hid.Controller;
|
||||||
|
using Ryujinx.Common.Configuration.Hid.Keyboard;
|
||||||
|
using Ryujinx.Common.Configuration.Multiplayer;
|
||||||
|
using Ryujinx.Common.Logging;
|
||||||
|
using Ryujinx.HLE;
|
||||||
|
using Ryujinx.UI.Common.Configuration.System;
|
||||||
|
using Ryujinx.UI.Common.Configuration.UI;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Ryujinx.UI.Common.Configuration
|
||||||
|
{
|
||||||
|
public partial class ConfigurationState
|
||||||
|
{
|
||||||
|
public void Load(ConfigurationFileFormat configurationFileFormat, string configurationFilePath)
|
||||||
|
{
|
||||||
|
bool configurationFileUpdated = false;
|
||||||
|
|
||||||
|
if (configurationFileFormat.Version is < 0 or > ConfigurationFileFormat.CurrentVersion)
|
||||||
|
{
|
||||||
|
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Unsupported configuration version {configurationFileFormat.Version}, loading default.");
|
||||||
|
|
||||||
|
LoadDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configurationFileFormat.Version < 2)
|
||||||
|
{
|
||||||
|
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 2.");
|
||||||
|
|
||||||
|
configurationFileFormat.SystemRegion = Region.USA;
|
||||||
|
|
||||||
|
configurationFileUpdated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configurationFileFormat.Version < 3)
|
||||||
|
{
|
||||||
|
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 3.");
|
||||||
|
|
||||||
|
configurationFileFormat.SystemTimeZone = "UTC";
|
||||||
|
|
||||||
|
configurationFileUpdated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configurationFileFormat.Version < 4)
|
||||||
|
{
|
||||||
|
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 4.");
|
||||||
|
|
||||||
|
configurationFileFormat.MaxAnisotropy = -1;
|
||||||
|
|
||||||
|
configurationFileUpdated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configurationFileFormat.Version < 5)
|
||||||
|
{
|
||||||
|
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 5.");
|
||||||
|
|
||||||
|
configurationFileFormat.SystemTimeOffset = 0;
|
||||||
|
|
||||||
|
configurationFileUpdated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configurationFileFormat.Version < 8)
|
||||||
|
{
|
||||||
|
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 8.");
|
||||||
|
|
||||||
|
configurationFileFormat.EnablePtc = true;
|
||||||
|
|
||||||
|
configurationFileUpdated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configurationFileFormat.Version < 9)
|
||||||
|
{
|
||||||
|
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 9.");
|
||||||
|
|
||||||
|
configurationFileFormat.ColumnSort = new ColumnSort
|
||||||
|
{
|
||||||
|
SortColumnId = 0,
|
||||||
|
SortAscending = false,
|
||||||
|
};
|
||||||
|
|
||||||
|
configurationFileFormat.Hotkeys = new KeyboardHotkeys
|
||||||
|
{
|
||||||
|
ToggleVsync = Key.F1,
|
||||||
|
};
|
||||||
|
|
||||||
|
configurationFileUpdated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configurationFileFormat.Version < 10)
|
||||||
|
{
|
||||||
|
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 10.");
|
||||||
|
|
||||||
|
configurationFileFormat.AudioBackend = AudioBackend.OpenAl;
|
||||||
|
|
||||||
|
configurationFileUpdated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configurationFileFormat.Version < 11)
|
||||||
|
{
|
||||||
|
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 11.");
|
||||||
|
|
||||||
|
configurationFileFormat.ResScale = 1;
|
||||||
|
configurationFileFormat.ResScaleCustom = 1.0f;
|
||||||
|
|
||||||
|
configurationFileUpdated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configurationFileFormat.Version < 12)
|
||||||
|
{
|
||||||
|
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 12.");
|
||||||
|
|
||||||
|
configurationFileFormat.LoggingGraphicsDebugLevel = GraphicsDebugLevel.None;
|
||||||
|
|
||||||
|
configurationFileUpdated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// configurationFileFormat.Version == 13 -> LDN1
|
||||||
|
|
||||||
|
if (configurationFileFormat.Version < 14)
|
||||||
|
{
|
||||||
|
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 14.");
|
||||||
|
|
||||||
|
configurationFileFormat.CheckUpdatesOnStart = true;
|
||||||
|
|
||||||
|
configurationFileUpdated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configurationFileFormat.Version < 16)
|
||||||
|
{
|
||||||
|
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 16.");
|
||||||
|
|
||||||
|
configurationFileFormat.EnableShaderCache = true;
|
||||||
|
|
||||||
|
configurationFileUpdated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configurationFileFormat.Version < 17)
|
||||||
|
{
|
||||||
|
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 17.");
|
||||||
|
|
||||||
|
configurationFileFormat.StartFullscreen = false;
|
||||||
|
|
||||||
|
configurationFileUpdated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configurationFileFormat.Version < 18)
|
||||||
|
{
|
||||||
|
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 18.");
|
||||||
|
|
||||||
|
configurationFileFormat.AspectRatio = AspectRatio.Fixed16x9;
|
||||||
|
|
||||||
|
configurationFileUpdated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// configurationFileFormat.Version == 19 -> LDN2
|
||||||
|
|
||||||
|
if (configurationFileFormat.Version < 20)
|
||||||
|
{
|
||||||
|
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 20.");
|
||||||
|
|
||||||
|
configurationFileFormat.ShowConfirmExit = true;
|
||||||
|
|
||||||
|
configurationFileUpdated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configurationFileFormat.Version < 21)
|
||||||
|
{
|
||||||
|
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 21.");
|
||||||
|
|
||||||
|
// Initialize network config.
|
||||||
|
|
||||||
|
configurationFileFormat.MultiplayerMode = MultiplayerMode.Disabled;
|
||||||
|
configurationFileFormat.MultiplayerLanInterfaceId = "0";
|
||||||
|
|
||||||
|
configurationFileUpdated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configurationFileFormat.Version < 22)
|
||||||
|
{
|
||||||
|
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 22.");
|
||||||
|
|
||||||
|
configurationFileFormat.HideCursor = HideCursorMode.Never;
|
||||||
|
|
||||||
|
configurationFileUpdated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configurationFileFormat.Version < 24)
|
||||||
|
{
|
||||||
|
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 24.");
|
||||||
|
|
||||||
|
configurationFileFormat.InputConfig = new List<InputConfig>
|
||||||
|
{
|
||||||
|
new StandardKeyboardInputConfig
|
||||||
|
{
|
||||||
|
Version = InputConfig.CurrentVersion,
|
||||||
|
Backend = InputBackendType.WindowKeyboard,
|
||||||
|
Id = "0",
|
||||||
|
PlayerIndex = PlayerIndex.Player1,
|
||||||
|
ControllerType = ControllerType.ProController,
|
||||||
|
LeftJoycon = new LeftJoyconCommonConfig<Key>
|
||||||
|
{
|
||||||
|
DpadUp = Key.Up,
|
||||||
|
DpadDown = Key.Down,
|
||||||
|
DpadLeft = Key.Left,
|
||||||
|
DpadRight = Key.Right,
|
||||||
|
ButtonMinus = Key.Minus,
|
||||||
|
ButtonL = Key.E,
|
||||||
|
ButtonZl = Key.Q,
|
||||||
|
ButtonSl = Key.Unbound,
|
||||||
|
ButtonSr = Key.Unbound,
|
||||||
|
},
|
||||||
|
LeftJoyconStick = new JoyconConfigKeyboardStick<Key>
|
||||||
|
{
|
||||||
|
StickUp = Key.W,
|
||||||
|
StickDown = Key.S,
|
||||||
|
StickLeft = Key.A,
|
||||||
|
StickRight = Key.D,
|
||||||
|
StickButton = Key.F,
|
||||||
|
},
|
||||||
|
RightJoycon = new RightJoyconCommonConfig<Key>
|
||||||
|
{
|
||||||
|
ButtonA = Key.Z,
|
||||||
|
ButtonB = Key.X,
|
||||||
|
ButtonX = Key.C,
|
||||||
|
ButtonY = Key.V,
|
||||||
|
ButtonPlus = Key.Plus,
|
||||||
|
ButtonR = Key.U,
|
||||||
|
ButtonZr = Key.O,
|
||||||
|
ButtonSl = Key.Unbound,
|
||||||
|
ButtonSr = Key.Unbound,
|
||||||
|
},
|
||||||
|
RightJoyconStick = new JoyconConfigKeyboardStick<Key>
|
||||||
|
{
|
||||||
|
StickUp = Key.I,
|
||||||
|
StickDown = Key.K,
|
||||||
|
StickLeft = Key.J,
|
||||||
|
StickRight = Key.L,
|
||||||
|
StickButton = Key.H,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
configurationFileUpdated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configurationFileFormat.Version < 25)
|
||||||
|
{
|
||||||
|
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 25.");
|
||||||
|
|
||||||
|
configurationFileUpdated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configurationFileFormat.Version < 26)
|
||||||
|
{
|
||||||
|
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 26.");
|
||||||
|
|
||||||
|
configurationFileFormat.MemoryManagerMode = MemoryManagerMode.HostMappedUnsafe;
|
||||||
|
|
||||||
|
configurationFileUpdated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configurationFileFormat.Version < 27)
|
||||||
|
{
|
||||||
|
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 27.");
|
||||||
|
|
||||||
|
configurationFileFormat.EnableMouse = false;
|
||||||
|
|
||||||
|
configurationFileUpdated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configurationFileFormat.Version < 28)
|
||||||
|
{
|
||||||
|
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 28.");
|
||||||
|
|
||||||
|
configurationFileFormat.Hotkeys = new KeyboardHotkeys
|
||||||
|
{
|
||||||
|
ToggleVsync = Key.F1,
|
||||||
|
Screenshot = Key.F8,
|
||||||
|
};
|
||||||
|
|
||||||
|
configurationFileUpdated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configurationFileFormat.Version < 29)
|
||||||
|
{
|
||||||
|
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 29.");
|
||||||
|
|
||||||
|
configurationFileFormat.Hotkeys = new KeyboardHotkeys
|
||||||
|
{
|
||||||
|
ToggleVsync = Key.F1,
|
||||||
|
Screenshot = Key.F8,
|
||||||
|
ShowUI = Key.F4,
|
||||||
|
};
|
||||||
|
|
||||||
|
configurationFileUpdated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configurationFileFormat.Version < 30)
|
||||||
|
{
|
||||||
|
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 30.");
|
||||||
|
|
||||||
|
foreach (InputConfig config in configurationFileFormat.InputConfig)
|
||||||
|
{
|
||||||
|
if (config is StandardControllerInputConfig controllerConfig)
|
||||||
|
{
|
||||||
|
controllerConfig.Rumble = new RumbleConfigController
|
||||||
|
{
|
||||||
|
EnableRumble = false,
|
||||||
|
StrongRumble = 1f,
|
||||||
|
WeakRumble = 1f,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
configurationFileUpdated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configurationFileFormat.Version < 31)
|
||||||
|
{
|
||||||
|
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 31.");
|
||||||
|
|
||||||
|
configurationFileFormat.BackendThreading = BackendThreading.Auto;
|
||||||
|
|
||||||
|
configurationFileUpdated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configurationFileFormat.Version < 32)
|
||||||
|
{
|
||||||
|
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 32.");
|
||||||
|
|
||||||
|
configurationFileFormat.Hotkeys = new KeyboardHotkeys
|
||||||
|
{
|
||||||
|
ToggleVsync = configurationFileFormat.Hotkeys.ToggleVsync,
|
||||||
|
Screenshot = configurationFileFormat.Hotkeys.Screenshot,
|
||||||
|
ShowUI = configurationFileFormat.Hotkeys.ShowUI,
|
||||||
|
Pause = Key.F5,
|
||||||
|
};
|
||||||
|
|
||||||
|
configurationFileUpdated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configurationFileFormat.Version < 33)
|
||||||
|
{
|
||||||
|
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 33.");
|
||||||
|
|
||||||
|
configurationFileFormat.Hotkeys = new KeyboardHotkeys
|
||||||
|
{
|
||||||
|
ToggleVsync = configurationFileFormat.Hotkeys.ToggleVsync,
|
||||||
|
Screenshot = configurationFileFormat.Hotkeys.Screenshot,
|
||||||
|
ShowUI = configurationFileFormat.Hotkeys.ShowUI,
|
||||||
|
Pause = configurationFileFormat.Hotkeys.Pause,
|
||||||
|
ToggleMute = Key.F2,
|
||||||
|
};
|
||||||
|
|
||||||
|
configurationFileFormat.AudioVolume = 1;
|
||||||
|
|
||||||
|
configurationFileUpdated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configurationFileFormat.Version < 34)
|
||||||
|
{
|
||||||
|
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 34.");
|
||||||
|
|
||||||
|
configurationFileFormat.EnableInternetAccess = false;
|
||||||
|
|
||||||
|
configurationFileUpdated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configurationFileFormat.Version < 35)
|
||||||
|
{
|
||||||
|
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 35.");
|
||||||
|
|
||||||
|
foreach (InputConfig config in configurationFileFormat.InputConfig)
|
||||||
|
{
|
||||||
|
if (config is StandardControllerInputConfig controllerConfig)
|
||||||
|
{
|
||||||
|
controllerConfig.RangeLeft = 1.0f;
|
||||||
|
controllerConfig.RangeRight = 1.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
configurationFileUpdated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configurationFileFormat.Version < 36)
|
||||||
|
{
|
||||||
|
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 36.");
|
||||||
|
|
||||||
|
configurationFileFormat.LoggingEnableTrace = false;
|
||||||
|
|
||||||
|
configurationFileUpdated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configurationFileFormat.Version < 37)
|
||||||
|
{
|
||||||
|
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 37.");
|
||||||
|
|
||||||
|
configurationFileFormat.ShowConsole = true;
|
||||||
|
|
||||||
|
configurationFileUpdated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configurationFileFormat.Version < 38)
|
||||||
|
{
|
||||||
|
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 38.");
|
||||||
|
|
||||||
|
configurationFileFormat.BaseStyle = "Dark";
|
||||||
|
configurationFileFormat.GameListViewMode = 0;
|
||||||
|
configurationFileFormat.ShowNames = true;
|
||||||
|
configurationFileFormat.GridSize = 2;
|
||||||
|
configurationFileFormat.LanguageCode = "en_US";
|
||||||
|
|
||||||
|
configurationFileUpdated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configurationFileFormat.Version < 39)
|
||||||
|
{
|
||||||
|
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 39.");
|
||||||
|
|
||||||
|
configurationFileFormat.Hotkeys = new KeyboardHotkeys
|
||||||
|
{
|
||||||
|
ToggleVsync = configurationFileFormat.Hotkeys.ToggleVsync,
|
||||||
|
Screenshot = configurationFileFormat.Hotkeys.Screenshot,
|
||||||
|
ShowUI = configurationFileFormat.Hotkeys.ShowUI,
|
||||||
|
Pause = configurationFileFormat.Hotkeys.Pause,
|
||||||
|
ToggleMute = configurationFileFormat.Hotkeys.ToggleMute,
|
||||||
|
ResScaleUp = Key.Unbound,
|
||||||
|
ResScaleDown = Key.Unbound,
|
||||||
|
};
|
||||||
|
|
||||||
|
configurationFileUpdated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configurationFileFormat.Version < 40)
|
||||||
|
{
|
||||||
|
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 40.");
|
||||||
|
|
||||||
|
configurationFileFormat.GraphicsBackend = GraphicsBackend.OpenGl;
|
||||||
|
|
||||||
|
configurationFileUpdated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configurationFileFormat.Version < 41)
|
||||||
|
{
|
||||||
|
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 41.");
|
||||||
|
|
||||||
|
configurationFileFormat.Hotkeys = new KeyboardHotkeys
|
||||||
|
{
|
||||||
|
ToggleVsync = configurationFileFormat.Hotkeys.ToggleVsync,
|
||||||
|
Screenshot = configurationFileFormat.Hotkeys.Screenshot,
|
||||||
|
ShowUI = configurationFileFormat.Hotkeys.ShowUI,
|
||||||
|
Pause = configurationFileFormat.Hotkeys.Pause,
|
||||||
|
ToggleMute = configurationFileFormat.Hotkeys.ToggleMute,
|
||||||
|
ResScaleUp = configurationFileFormat.Hotkeys.ResScaleUp,
|
||||||
|
ResScaleDown = configurationFileFormat.Hotkeys.ResScaleDown,
|
||||||
|
VolumeUp = Key.Unbound,
|
||||||
|
VolumeDown = Key.Unbound,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configurationFileFormat.Version < 42)
|
||||||
|
{
|
||||||
|
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 42.");
|
||||||
|
|
||||||
|
configurationFileFormat.EnableMacroHLE = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configurationFileFormat.Version < 43)
|
||||||
|
{
|
||||||
|
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 43.");
|
||||||
|
|
||||||
|
configurationFileFormat.UseHypervisor = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configurationFileFormat.Version < 44)
|
||||||
|
{
|
||||||
|
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 44.");
|
||||||
|
|
||||||
|
configurationFileFormat.AntiAliasing = AntiAliasing.None;
|
||||||
|
configurationFileFormat.ScalingFilter = ScalingFilter.Bilinear;
|
||||||
|
configurationFileFormat.ScalingFilterLevel = 80;
|
||||||
|
|
||||||
|
configurationFileUpdated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configurationFileFormat.Version < 45)
|
||||||
|
{
|
||||||
|
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 45.");
|
||||||
|
|
||||||
|
configurationFileFormat.ShownFileTypes = new ShownFileTypes
|
||||||
|
{
|
||||||
|
NSP = true,
|
||||||
|
PFS0 = true,
|
||||||
|
XCI = true,
|
||||||
|
NCA = true,
|
||||||
|
NRO = true,
|
||||||
|
NSO = true,
|
||||||
|
};
|
||||||
|
|
||||||
|
configurationFileUpdated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configurationFileFormat.Version < 46)
|
||||||
|
{
|
||||||
|
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 46.");
|
||||||
|
|
||||||
|
configurationFileFormat.MultiplayerLanInterfaceId = "0";
|
||||||
|
|
||||||
|
configurationFileUpdated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configurationFileFormat.Version < 47)
|
||||||
|
{
|
||||||
|
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 47.");
|
||||||
|
|
||||||
|
configurationFileFormat.WindowStartup = new WindowStartup
|
||||||
|
{
|
||||||
|
WindowPositionX = 0,
|
||||||
|
WindowPositionY = 0,
|
||||||
|
WindowSizeHeight = 760,
|
||||||
|
WindowSizeWidth = 1280,
|
||||||
|
WindowMaximized = false,
|
||||||
|
};
|
||||||
|
|
||||||
|
configurationFileUpdated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configurationFileFormat.Version < 48)
|
||||||
|
{
|
||||||
|
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 48.");
|
||||||
|
|
||||||
|
configurationFileFormat.EnableColorSpacePassthrough = false;
|
||||||
|
|
||||||
|
configurationFileUpdated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configurationFileFormat.Version < 49)
|
||||||
|
{
|
||||||
|
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 49.");
|
||||||
|
|
||||||
|
if (OperatingSystem.IsMacOS())
|
||||||
|
{
|
||||||
|
AppDataManager.FixMacOSConfigurationFolders();
|
||||||
|
}
|
||||||
|
|
||||||
|
configurationFileUpdated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configurationFileFormat.Version < 50)
|
||||||
|
{
|
||||||
|
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 50.");
|
||||||
|
|
||||||
|
configurationFileFormat.EnableHardwareAcceleration = true;
|
||||||
|
|
||||||
|
configurationFileUpdated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configurationFileFormat.Version < 51)
|
||||||
|
{
|
||||||
|
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 51.");
|
||||||
|
|
||||||
|
configurationFileFormat.RememberWindowState = true;
|
||||||
|
|
||||||
|
configurationFileUpdated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configurationFileFormat.Version < 52)
|
||||||
|
{
|
||||||
|
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 52.");
|
||||||
|
|
||||||
|
configurationFileFormat.AutoloadDirs = [];
|
||||||
|
|
||||||
|
configurationFileUpdated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configurationFileFormat.Version < 53)
|
||||||
|
{
|
||||||
|
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 53.");
|
||||||
|
|
||||||
|
configurationFileFormat.EnableLowPowerPtc = false;
|
||||||
|
|
||||||
|
configurationFileUpdated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configurationFileFormat.Version < 54)
|
||||||
|
{
|
||||||
|
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 54.");
|
||||||
|
|
||||||
|
configurationFileFormat.DramSize = MemoryConfiguration.MemoryConfiguration4GiB;
|
||||||
|
|
||||||
|
configurationFileUpdated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configurationFileFormat.Version < 55)
|
||||||
|
{
|
||||||
|
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 55.");
|
||||||
|
|
||||||
|
configurationFileFormat.IgnoreApplet = false;
|
||||||
|
|
||||||
|
configurationFileUpdated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configurationFileFormat.Version < 56)
|
||||||
|
{
|
||||||
|
Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 56.");
|
||||||
|
|
||||||
|
configurationFileFormat.ShowTitleBar = !OperatingSystem.IsWindows();
|
||||||
|
|
||||||
|
configurationFileUpdated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger.EnableFileLog.Value = configurationFileFormat.EnableFileLog;
|
||||||
|
Graphics.ResScale.Value = configurationFileFormat.ResScale;
|
||||||
|
Graphics.ResScaleCustom.Value = configurationFileFormat.ResScaleCustom;
|
||||||
|
Graphics.MaxAnisotropy.Value = configurationFileFormat.MaxAnisotropy;
|
||||||
|
Graphics.AspectRatio.Value = configurationFileFormat.AspectRatio;
|
||||||
|
Graphics.ShadersDumpPath.Value = configurationFileFormat.GraphicsShadersDumpPath;
|
||||||
|
Graphics.BackendThreading.Value = configurationFileFormat.BackendThreading;
|
||||||
|
Graphics.GraphicsBackend.Value = configurationFileFormat.GraphicsBackend;
|
||||||
|
Graphics.PreferredGpu.Value = configurationFileFormat.PreferredGpu;
|
||||||
|
Graphics.AntiAliasing.Value = configurationFileFormat.AntiAliasing;
|
||||||
|
Graphics.ScalingFilter.Value = configurationFileFormat.ScalingFilter;
|
||||||
|
Graphics.ScalingFilterLevel.Value = configurationFileFormat.ScalingFilterLevel;
|
||||||
|
Logger.EnableDebug.Value = configurationFileFormat.LoggingEnableDebug;
|
||||||
|
Logger.EnableStub.Value = configurationFileFormat.LoggingEnableStub;
|
||||||
|
Logger.EnableInfo.Value = configurationFileFormat.LoggingEnableInfo;
|
||||||
|
Logger.EnableWarn.Value = configurationFileFormat.LoggingEnableWarn;
|
||||||
|
Logger.EnableError.Value = configurationFileFormat.LoggingEnableError;
|
||||||
|
Logger.EnableTrace.Value = configurationFileFormat.LoggingEnableTrace;
|
||||||
|
Logger.EnableGuest.Value = configurationFileFormat.LoggingEnableGuest;
|
||||||
|
Logger.EnableFsAccessLog.Value = configurationFileFormat.LoggingEnableFsAccessLog;
|
||||||
|
Logger.FilteredClasses.Value = configurationFileFormat.LoggingFilteredClasses;
|
||||||
|
Logger.GraphicsDebugLevel.Value = configurationFileFormat.LoggingGraphicsDebugLevel;
|
||||||
|
System.Language.Value = configurationFileFormat.SystemLanguage;
|
||||||
|
System.Region.Value = configurationFileFormat.SystemRegion;
|
||||||
|
System.TimeZone.Value = configurationFileFormat.SystemTimeZone;
|
||||||
|
System.SystemTimeOffset.Value = configurationFileFormat.SystemTimeOffset;
|
||||||
|
System.EnableDockedMode.Value = configurationFileFormat.DockedMode;
|
||||||
|
EnableDiscordIntegration.Value = configurationFileFormat.EnableDiscordIntegration;
|
||||||
|
CheckUpdatesOnStart.Value = configurationFileFormat.CheckUpdatesOnStart;
|
||||||
|
ShowConfirmExit.Value = configurationFileFormat.ShowConfirmExit;
|
||||||
|
IgnoreApplet.Value = configurationFileFormat.IgnoreApplet;
|
||||||
|
RememberWindowState.Value = configurationFileFormat.RememberWindowState;
|
||||||
|
ShowTitleBar.Value = configurationFileFormat.ShowTitleBar;
|
||||||
|
EnableHardwareAcceleration.Value = configurationFileFormat.EnableHardwareAcceleration;
|
||||||
|
HideCursor.Value = configurationFileFormat.HideCursor;
|
||||||
|
Graphics.EnableVsync.Value = configurationFileFormat.EnableVsync;
|
||||||
|
Graphics.EnableShaderCache.Value = configurationFileFormat.EnableShaderCache;
|
||||||
|
Graphics.EnableTextureRecompression.Value = configurationFileFormat.EnableTextureRecompression;
|
||||||
|
Graphics.EnableMacroHLE.Value = configurationFileFormat.EnableMacroHLE;
|
||||||
|
Graphics.EnableColorSpacePassthrough.Value = configurationFileFormat.EnableColorSpacePassthrough;
|
||||||
|
System.EnablePtc.Value = configurationFileFormat.EnablePtc;
|
||||||
|
System.EnableLowPowerPtc.Value = configurationFileFormat.EnableLowPowerPtc;
|
||||||
|
System.EnableInternetAccess.Value = configurationFileFormat.EnableInternetAccess;
|
||||||
|
System.EnableFsIntegrityChecks.Value = configurationFileFormat.EnableFsIntegrityChecks;
|
||||||
|
System.FsGlobalAccessLogMode.Value = configurationFileFormat.FsGlobalAccessLogMode;
|
||||||
|
System.AudioBackend.Value = configurationFileFormat.AudioBackend;
|
||||||
|
System.AudioVolume.Value = configurationFileFormat.AudioVolume;
|
||||||
|
System.MemoryManagerMode.Value = configurationFileFormat.MemoryManagerMode;
|
||||||
|
System.DramSize.Value = configurationFileFormat.DramSize;
|
||||||
|
System.IgnoreMissingServices.Value = configurationFileFormat.IgnoreMissingServices;
|
||||||
|
System.UseHypervisor.Value = configurationFileFormat.UseHypervisor;
|
||||||
|
UI.GuiColumns.FavColumn.Value = configurationFileFormat.GuiColumns.FavColumn;
|
||||||
|
UI.GuiColumns.IconColumn.Value = configurationFileFormat.GuiColumns.IconColumn;
|
||||||
|
UI.GuiColumns.AppColumn.Value = configurationFileFormat.GuiColumns.AppColumn;
|
||||||
|
UI.GuiColumns.DevColumn.Value = configurationFileFormat.GuiColumns.DevColumn;
|
||||||
|
UI.GuiColumns.VersionColumn.Value = configurationFileFormat.GuiColumns.VersionColumn;
|
||||||
|
UI.GuiColumns.TimePlayedColumn.Value = configurationFileFormat.GuiColumns.TimePlayedColumn;
|
||||||
|
UI.GuiColumns.LastPlayedColumn.Value = configurationFileFormat.GuiColumns.LastPlayedColumn;
|
||||||
|
UI.GuiColumns.FileExtColumn.Value = configurationFileFormat.GuiColumns.FileExtColumn;
|
||||||
|
UI.GuiColumns.FileSizeColumn.Value = configurationFileFormat.GuiColumns.FileSizeColumn;
|
||||||
|
UI.GuiColumns.PathColumn.Value = configurationFileFormat.GuiColumns.PathColumn;
|
||||||
|
UI.ColumnSort.SortColumnId.Value = configurationFileFormat.ColumnSort.SortColumnId;
|
||||||
|
UI.ColumnSort.SortAscending.Value = configurationFileFormat.ColumnSort.SortAscending;
|
||||||
|
UI.GameDirs.Value = configurationFileFormat.GameDirs;
|
||||||
|
UI.AutoloadDirs.Value = configurationFileFormat.AutoloadDirs ?? [];
|
||||||
|
UI.ShownFileTypes.NSP.Value = configurationFileFormat.ShownFileTypes.NSP;
|
||||||
|
UI.ShownFileTypes.PFS0.Value = configurationFileFormat.ShownFileTypes.PFS0;
|
||||||
|
UI.ShownFileTypes.XCI.Value = configurationFileFormat.ShownFileTypes.XCI;
|
||||||
|
UI.ShownFileTypes.NCA.Value = configurationFileFormat.ShownFileTypes.NCA;
|
||||||
|
UI.ShownFileTypes.NRO.Value = configurationFileFormat.ShownFileTypes.NRO;
|
||||||
|
UI.ShownFileTypes.NSO.Value = configurationFileFormat.ShownFileTypes.NSO;
|
||||||
|
UI.LanguageCode.Value = configurationFileFormat.LanguageCode;
|
||||||
|
UI.BaseStyle.Value = configurationFileFormat.BaseStyle;
|
||||||
|
UI.GameListViewMode.Value = configurationFileFormat.GameListViewMode;
|
||||||
|
UI.ShowNames.Value = configurationFileFormat.ShowNames;
|
||||||
|
UI.IsAscendingOrder.Value = configurationFileFormat.IsAscendingOrder;
|
||||||
|
UI.GridSize.Value = configurationFileFormat.GridSize;
|
||||||
|
UI.ApplicationSort.Value = configurationFileFormat.ApplicationSort;
|
||||||
|
UI.StartFullscreen.Value = configurationFileFormat.StartFullscreen;
|
||||||
|
UI.ShowConsole.Value = configurationFileFormat.ShowConsole;
|
||||||
|
UI.WindowStartup.WindowSizeWidth.Value = configurationFileFormat.WindowStartup.WindowSizeWidth;
|
||||||
|
UI.WindowStartup.WindowSizeHeight.Value = configurationFileFormat.WindowStartup.WindowSizeHeight;
|
||||||
|
UI.WindowStartup.WindowPositionX.Value = configurationFileFormat.WindowStartup.WindowPositionX;
|
||||||
|
UI.WindowStartup.WindowPositionY.Value = configurationFileFormat.WindowStartup.WindowPositionY;
|
||||||
|
UI.WindowStartup.WindowMaximized.Value = configurationFileFormat.WindowStartup.WindowMaximized;
|
||||||
|
Hid.EnableKeyboard.Value = configurationFileFormat.EnableKeyboard;
|
||||||
|
Hid.EnableMouse.Value = configurationFileFormat.EnableMouse;
|
||||||
|
Hid.Hotkeys.Value = configurationFileFormat.Hotkeys;
|
||||||
|
Hid.InputConfig.Value = configurationFileFormat.InputConfig ?? [];
|
||||||
|
|
||||||
|
Multiplayer.LanInterfaceId.Value = configurationFileFormat.MultiplayerLanInterfaceId;
|
||||||
|
Multiplayer.Mode.Value = configurationFileFormat.MultiplayerMode;
|
||||||
|
|
||||||
|
if (configurationFileUpdated)
|
||||||
|
{
|
||||||
|
ToFileFormat().SaveConfig(configurationFilePath);
|
||||||
|
|
||||||
|
Ryujinx.Common.Logging.Logger.Notice.Print(LogClass.Application, $"Configuration file updated to version {ConfigurationFileFormat.CurrentVersion}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
677
src/Ryujinx.UI.Common/Configuration/ConfigurationState.Model.cs
Normal file
677
src/Ryujinx.UI.Common/Configuration/ConfigurationState.Model.cs
Normal file
@@ -0,0 +1,677 @@
|
|||||||
|
using ARMeilleure;
|
||||||
|
using Ryujinx.Common;
|
||||||
|
using Ryujinx.Common.Configuration;
|
||||||
|
using Ryujinx.Common.Configuration.Hid;
|
||||||
|
using Ryujinx.Common.Configuration.Multiplayer;
|
||||||
|
using Ryujinx.Common.Logging;
|
||||||
|
using Ryujinx.HLE;
|
||||||
|
using Ryujinx.UI.Common.Configuration.System;
|
||||||
|
using Ryujinx.UI.Common.Helper;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Ryujinx.UI.Common.Configuration
|
||||||
|
{
|
||||||
|
public partial class ConfigurationState
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// UI configuration section
|
||||||
|
/// </summary>
|
||||||
|
public class UISection
|
||||||
|
{
|
||||||
|
public class Columns
|
||||||
|
{
|
||||||
|
public ReactiveObject<bool> FavColumn { get; private set; }
|
||||||
|
public ReactiveObject<bool> IconColumn { get; private set; }
|
||||||
|
public ReactiveObject<bool> AppColumn { get; private set; }
|
||||||
|
public ReactiveObject<bool> DevColumn { get; private set; }
|
||||||
|
public ReactiveObject<bool> VersionColumn { get; private set; }
|
||||||
|
public ReactiveObject<bool> TimePlayedColumn { get; private set; }
|
||||||
|
public ReactiveObject<bool> LastPlayedColumn { get; private set; }
|
||||||
|
public ReactiveObject<bool> FileExtColumn { get; private set; }
|
||||||
|
public ReactiveObject<bool> FileSizeColumn { get; private set; }
|
||||||
|
public ReactiveObject<bool> PathColumn { get; private set; }
|
||||||
|
|
||||||
|
public Columns()
|
||||||
|
{
|
||||||
|
FavColumn = new ReactiveObject<bool>();
|
||||||
|
IconColumn = new ReactiveObject<bool>();
|
||||||
|
AppColumn = new ReactiveObject<bool>();
|
||||||
|
DevColumn = new ReactiveObject<bool>();
|
||||||
|
VersionColumn = new ReactiveObject<bool>();
|
||||||
|
TimePlayedColumn = new ReactiveObject<bool>();
|
||||||
|
LastPlayedColumn = new ReactiveObject<bool>();
|
||||||
|
FileExtColumn = new ReactiveObject<bool>();
|
||||||
|
FileSizeColumn = new ReactiveObject<bool>();
|
||||||
|
PathColumn = new ReactiveObject<bool>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ColumnSortSettings
|
||||||
|
{
|
||||||
|
public ReactiveObject<int> SortColumnId { get; private set; }
|
||||||
|
public ReactiveObject<bool> SortAscending { get; private set; }
|
||||||
|
|
||||||
|
public ColumnSortSettings()
|
||||||
|
{
|
||||||
|
SortColumnId = new ReactiveObject<int>();
|
||||||
|
SortAscending = new ReactiveObject<bool>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Used to toggle which file types are shown in the UI
|
||||||
|
/// </summary>
|
||||||
|
public class ShownFileTypeSettings
|
||||||
|
{
|
||||||
|
public ReactiveObject<bool> NSP { get; private set; }
|
||||||
|
public ReactiveObject<bool> PFS0 { get; private set; }
|
||||||
|
public ReactiveObject<bool> XCI { get; private set; }
|
||||||
|
public ReactiveObject<bool> NCA { get; private set; }
|
||||||
|
public ReactiveObject<bool> NRO { get; private set; }
|
||||||
|
public ReactiveObject<bool> NSO { get; private set; }
|
||||||
|
|
||||||
|
public ShownFileTypeSettings()
|
||||||
|
{
|
||||||
|
NSP = new ReactiveObject<bool>();
|
||||||
|
PFS0 = new ReactiveObject<bool>();
|
||||||
|
XCI = new ReactiveObject<bool>();
|
||||||
|
NCA = new ReactiveObject<bool>();
|
||||||
|
NRO = new ReactiveObject<bool>();
|
||||||
|
NSO = new ReactiveObject<bool>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// <summary>
|
||||||
|
/// Determines main window start-up position, size and state
|
||||||
|
///<summary>
|
||||||
|
public class WindowStartupSettings
|
||||||
|
{
|
||||||
|
public ReactiveObject<int> WindowSizeWidth { get; private set; }
|
||||||
|
public ReactiveObject<int> WindowSizeHeight { get; private set; }
|
||||||
|
public ReactiveObject<int> WindowPositionX { get; private set; }
|
||||||
|
public ReactiveObject<int> WindowPositionY { get; private set; }
|
||||||
|
public ReactiveObject<bool> WindowMaximized { get; private set; }
|
||||||
|
|
||||||
|
public WindowStartupSettings()
|
||||||
|
{
|
||||||
|
WindowSizeWidth = new ReactiveObject<int>();
|
||||||
|
WindowSizeHeight = new ReactiveObject<int>();
|
||||||
|
WindowPositionX = new ReactiveObject<int>();
|
||||||
|
WindowPositionY = new ReactiveObject<int>();
|
||||||
|
WindowMaximized = new ReactiveObject<bool>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Used to toggle columns in the GUI
|
||||||
|
/// </summary>
|
||||||
|
public Columns GuiColumns { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Used to configure column sort settings in the GUI
|
||||||
|
/// </summary>
|
||||||
|
public ColumnSortSettings ColumnSort { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A list of directories containing games to be used to load games into the games list
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<List<string>> GameDirs { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A list of directories containing DLC/updates the user wants to autoload during library refreshes
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<List<string>> AutoloadDirs { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A list of file types to be hidden in the games List
|
||||||
|
/// </summary>
|
||||||
|
public ShownFileTypeSettings ShownFileTypes { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines main window start-up position, size and state
|
||||||
|
/// </summary>
|
||||||
|
public WindowStartupSettings WindowStartup { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Language Code for the UI
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<string> LanguageCode { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Selects the base style
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<string> BaseStyle { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Start games in fullscreen mode
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<bool> StartFullscreen { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Hide / Show Console Window
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<bool> ShowConsole { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// View Mode of the Game list
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<int> GameListViewMode { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Show application name in Grid Mode
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<bool> ShowNames { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets App Icon Size in Grid Mode
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<int> GridSize { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sorts Apps in Grid Mode
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<int> ApplicationSort { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets if Grid is ordered in Ascending Order
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<bool> IsAscendingOrder { get; private set; }
|
||||||
|
|
||||||
|
public UISection()
|
||||||
|
{
|
||||||
|
GuiColumns = new Columns();
|
||||||
|
ColumnSort = new ColumnSortSettings();
|
||||||
|
GameDirs = new ReactiveObject<List<string>>();
|
||||||
|
AutoloadDirs = new ReactiveObject<List<string>>();
|
||||||
|
ShownFileTypes = new ShownFileTypeSettings();
|
||||||
|
WindowStartup = new WindowStartupSettings();
|
||||||
|
BaseStyle = new ReactiveObject<string>();
|
||||||
|
StartFullscreen = new ReactiveObject<bool>();
|
||||||
|
GameListViewMode = new ReactiveObject<int>();
|
||||||
|
ShowNames = new ReactiveObject<bool>();
|
||||||
|
GridSize = new ReactiveObject<int>();
|
||||||
|
ApplicationSort = new ReactiveObject<int>();
|
||||||
|
IsAscendingOrder = new ReactiveObject<bool>();
|
||||||
|
LanguageCode = new ReactiveObject<string>();
|
||||||
|
ShowConsole = new ReactiveObject<bool>();
|
||||||
|
ShowConsole.Event += static (_, e) => ConsoleHelper.SetConsoleWindowState(e.NewValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Logger configuration section
|
||||||
|
/// </summary>
|
||||||
|
public class LoggerSection
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Enables printing debug log messages
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<bool> EnableDebug { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enables printing stub log messages
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<bool> EnableStub { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enables printing info log messages
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<bool> EnableInfo { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enables printing warning log messages
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<bool> EnableWarn { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enables printing error log messages
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<bool> EnableError { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enables printing trace log messages
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<bool> EnableTrace { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enables printing guest log messages
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<bool> EnableGuest { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enables printing FS access log messages
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<bool> EnableFsAccessLog { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Controls which log messages are written to the log targets
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<LogClass[]> FilteredClasses { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enables or disables logging to a file on disk
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<bool> EnableFileLog { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Controls which OpenGL log messages are recorded in the log
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<GraphicsDebugLevel> GraphicsDebugLevel { get; private set; }
|
||||||
|
|
||||||
|
public LoggerSection()
|
||||||
|
{
|
||||||
|
EnableDebug = new ReactiveObject<bool>();
|
||||||
|
EnableDebug.LogChangesToValue(nameof(EnableDebug));
|
||||||
|
EnableStub = new ReactiveObject<bool>();
|
||||||
|
EnableInfo = new ReactiveObject<bool>();
|
||||||
|
EnableWarn = new ReactiveObject<bool>();
|
||||||
|
EnableError = new ReactiveObject<bool>();
|
||||||
|
EnableTrace = new ReactiveObject<bool>();
|
||||||
|
EnableGuest = new ReactiveObject<bool>();
|
||||||
|
EnableFsAccessLog = new ReactiveObject<bool>();
|
||||||
|
FilteredClasses = new ReactiveObject<LogClass[]>();
|
||||||
|
EnableFileLog = new ReactiveObject<bool>();
|
||||||
|
EnableFileLog.LogChangesToValue(nameof(EnableFileLog));
|
||||||
|
GraphicsDebugLevel = new ReactiveObject<GraphicsDebugLevel>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// System configuration section
|
||||||
|
/// </summary>
|
||||||
|
public class SystemSection
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Change System Language
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<Language> Language { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Change System Region
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<Region> Region { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Change System TimeZone
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<string> TimeZone { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// System Time Offset in Seconds
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<long> SystemTimeOffset { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enables or disables Docked Mode
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<bool> EnableDockedMode { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enables or disables persistent profiled translation cache
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<bool> EnablePtc { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enables or disables low-power persistent profiled translation cache loading
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<bool> EnableLowPowerPtc { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enables or disables guest Internet access
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<bool> EnableInternetAccess { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enables integrity checks on Game content files
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<bool> EnableFsIntegrityChecks { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enables FS access log output to the console. Possible modes are 0-3
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<int> FsGlobalAccessLogMode { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The selected audio backend
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<AudioBackend> AudioBackend { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The audio backend volume
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<float> AudioVolume { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The selected memory manager mode
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<MemoryManagerMode> MemoryManagerMode { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the amount of RAM available on the emulated system, and how it is distributed
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<MemoryConfiguration> DramSize { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enable or disable ignoring missing services
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<bool> IgnoreMissingServices { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Uses Hypervisor over JIT if available
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<bool> UseHypervisor { get; private set; }
|
||||||
|
|
||||||
|
public SystemSection()
|
||||||
|
{
|
||||||
|
Language = new ReactiveObject<Language>();
|
||||||
|
Language.LogChangesToValue(nameof(Language));
|
||||||
|
Region = new ReactiveObject<Region>();
|
||||||
|
Region.LogChangesToValue(nameof(Region));
|
||||||
|
TimeZone = new ReactiveObject<string>();
|
||||||
|
TimeZone.LogChangesToValue(nameof(TimeZone));
|
||||||
|
SystemTimeOffset = new ReactiveObject<long>();
|
||||||
|
SystemTimeOffset.LogChangesToValue(nameof(SystemTimeOffset));
|
||||||
|
EnableDockedMode = new ReactiveObject<bool>();
|
||||||
|
EnableDockedMode.LogChangesToValue(nameof(EnableDockedMode));
|
||||||
|
EnablePtc = new ReactiveObject<bool>();
|
||||||
|
EnablePtc.LogChangesToValue(nameof(EnablePtc));
|
||||||
|
EnableLowPowerPtc = new ReactiveObject<bool>();
|
||||||
|
EnableLowPowerPtc.LogChangesToValue(nameof(EnableLowPowerPtc));
|
||||||
|
EnableLowPowerPtc.Event += (_, evnt)
|
||||||
|
=> Optimizations.LowPower = evnt.NewValue;
|
||||||
|
EnableInternetAccess = new ReactiveObject<bool>();
|
||||||
|
EnableInternetAccess.LogChangesToValue(nameof(EnableInternetAccess));
|
||||||
|
EnableFsIntegrityChecks = new ReactiveObject<bool>();
|
||||||
|
EnableFsIntegrityChecks.LogChangesToValue(nameof(EnableFsIntegrityChecks));
|
||||||
|
FsGlobalAccessLogMode = new ReactiveObject<int>();
|
||||||
|
FsGlobalAccessLogMode.LogChangesToValue(nameof(FsGlobalAccessLogMode));
|
||||||
|
AudioBackend = new ReactiveObject<AudioBackend>();
|
||||||
|
AudioBackend.LogChangesToValue(nameof(AudioBackend));
|
||||||
|
MemoryManagerMode = new ReactiveObject<MemoryManagerMode>();
|
||||||
|
MemoryManagerMode.LogChangesToValue(nameof(MemoryManagerMode));
|
||||||
|
DramSize = new ReactiveObject<MemoryConfiguration>();
|
||||||
|
DramSize.LogChangesToValue(nameof(DramSize));
|
||||||
|
IgnoreMissingServices = new ReactiveObject<bool>();
|
||||||
|
IgnoreMissingServices.LogChangesToValue(nameof(IgnoreMissingServices));
|
||||||
|
AudioVolume = new ReactiveObject<float>();
|
||||||
|
AudioVolume.LogChangesToValue(nameof(AudioVolume));
|
||||||
|
UseHypervisor = new ReactiveObject<bool>();
|
||||||
|
UseHypervisor.LogChangesToValue(nameof(UseHypervisor));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Hid configuration section
|
||||||
|
/// </summary>
|
||||||
|
public class HidSection
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Enable or disable keyboard support (Independent from controllers binding)
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<bool> EnableKeyboard { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enable or disable mouse support (Independent from controllers binding)
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<bool> EnableMouse { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Hotkey Keyboard Bindings
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<KeyboardHotkeys> Hotkeys { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Input device configuration.
|
||||||
|
/// NOTE: This ReactiveObject won't issue an event when the List has elements added or removed.
|
||||||
|
/// TODO: Implement a ReactiveList class.
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<List<InputConfig>> InputConfig { get; private set; }
|
||||||
|
|
||||||
|
public HidSection()
|
||||||
|
{
|
||||||
|
EnableKeyboard = new ReactiveObject<bool>();
|
||||||
|
EnableMouse = new ReactiveObject<bool>();
|
||||||
|
Hotkeys = new ReactiveObject<KeyboardHotkeys>();
|
||||||
|
InputConfig = new ReactiveObject<List<InputConfig>>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Graphics configuration section
|
||||||
|
/// </summary>
|
||||||
|
public class GraphicsSection
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Whether or not backend threading is enabled. The "Auto" setting will determine whether threading should be enabled at runtime.
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<BackendThreading> BackendThreading { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Max Anisotropy. Values range from 0 - 16. Set to -1 to let the game decide.
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<float> MaxAnisotropy { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Aspect Ratio applied to the renderer window.
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<AspectRatio> AspectRatio { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Resolution Scale. An integer scale applied to applicable render targets. Values 1-4, or -1 to use a custom floating point scale instead.
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<int> ResScale { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Custom Resolution Scale. A custom floating point scale applied to applicable render targets. Only active when Resolution Scale is -1.
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<float> ResScaleCustom { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Dumps shaders in this local directory
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<string> ShadersDumpPath { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enables or disables Vertical Sync
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<bool> EnableVsync { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enables or disables Shader cache
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<bool> EnableShaderCache { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enables or disables texture recompression
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<bool> EnableTextureRecompression { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enables or disables Macro high-level emulation
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<bool> EnableMacroHLE { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enables or disables color space passthrough, if available.
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<bool> EnableColorSpacePassthrough { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Graphics backend
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<GraphicsBackend> GraphicsBackend { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Applies anti-aliasing to the renderer.
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<AntiAliasing> AntiAliasing { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the framebuffer upscaling type.
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<ScalingFilter> ScalingFilter { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the framebuffer upscaling level.
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<int> ScalingFilterLevel { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Preferred GPU
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<string> PreferredGpu { get; private set; }
|
||||||
|
|
||||||
|
public GraphicsSection()
|
||||||
|
{
|
||||||
|
BackendThreading = new ReactiveObject<BackendThreading>();
|
||||||
|
BackendThreading.LogChangesToValue(nameof(BackendThreading));
|
||||||
|
ResScale = new ReactiveObject<int>();
|
||||||
|
ResScale.LogChangesToValue(nameof(ResScale));
|
||||||
|
ResScaleCustom = new ReactiveObject<float>();
|
||||||
|
ResScaleCustom.LogChangesToValue(nameof(ResScaleCustom));
|
||||||
|
MaxAnisotropy = new ReactiveObject<float>();
|
||||||
|
MaxAnisotropy.LogChangesToValue(nameof(MaxAnisotropy));
|
||||||
|
AspectRatio = new ReactiveObject<AspectRatio>();
|
||||||
|
AspectRatio.LogChangesToValue(nameof(AspectRatio));
|
||||||
|
ShadersDumpPath = new ReactiveObject<string>();
|
||||||
|
EnableVsync = new ReactiveObject<bool>();
|
||||||
|
EnableVsync.LogChangesToValue(nameof(EnableVsync));
|
||||||
|
EnableShaderCache = new ReactiveObject<bool>();
|
||||||
|
EnableShaderCache.LogChangesToValue(nameof(EnableShaderCache));
|
||||||
|
EnableTextureRecompression = new ReactiveObject<bool>();
|
||||||
|
EnableTextureRecompression.LogChangesToValue(nameof(EnableTextureRecompression));
|
||||||
|
GraphicsBackend = new ReactiveObject<GraphicsBackend>();
|
||||||
|
GraphicsBackend.LogChangesToValue(nameof(GraphicsBackend));
|
||||||
|
PreferredGpu = new ReactiveObject<string>();
|
||||||
|
PreferredGpu.LogChangesToValue(nameof(PreferredGpu));
|
||||||
|
EnableMacroHLE = new ReactiveObject<bool>();
|
||||||
|
EnableMacroHLE.LogChangesToValue(nameof(EnableMacroHLE));
|
||||||
|
EnableColorSpacePassthrough = new ReactiveObject<bool>();
|
||||||
|
EnableColorSpacePassthrough.LogChangesToValue(nameof(EnableColorSpacePassthrough));
|
||||||
|
AntiAliasing = new ReactiveObject<AntiAliasing>();
|
||||||
|
AntiAliasing.LogChangesToValue(nameof(AntiAliasing));
|
||||||
|
ScalingFilter = new ReactiveObject<ScalingFilter>();
|
||||||
|
ScalingFilter.LogChangesToValue(nameof(ScalingFilter));
|
||||||
|
ScalingFilterLevel = new ReactiveObject<int>();
|
||||||
|
ScalingFilterLevel.LogChangesToValue(nameof(ScalingFilterLevel));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Multiplayer configuration section
|
||||||
|
/// </summary>
|
||||||
|
public class MultiplayerSection
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// GUID for the network interface used by LAN (or 0 for default)
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<string> LanInterfaceId { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Multiplayer Mode
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<MultiplayerMode> Mode { get; private set; }
|
||||||
|
|
||||||
|
public MultiplayerSection()
|
||||||
|
{
|
||||||
|
LanInterfaceId = new ReactiveObject<string>();
|
||||||
|
Mode = new ReactiveObject<MultiplayerMode>();
|
||||||
|
Mode.LogChangesToValue(nameof(MultiplayerMode));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The default configuration instance
|
||||||
|
/// </summary>
|
||||||
|
public static ConfigurationState Instance { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The UI section
|
||||||
|
/// </summary>
|
||||||
|
public UISection UI { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Logger section
|
||||||
|
/// </summary>
|
||||||
|
public LoggerSection Logger { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The System section
|
||||||
|
/// </summary>
|
||||||
|
public SystemSection System { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Graphics section
|
||||||
|
/// </summary>
|
||||||
|
public GraphicsSection Graphics { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Hid section
|
||||||
|
/// </summary>
|
||||||
|
public HidSection Hid { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The Multiplayer section
|
||||||
|
/// </summary>
|
||||||
|
public MultiplayerSection Multiplayer { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enables or disables Discord Rich Presence
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<bool> EnableDiscordIntegration { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks for updates when Ryujinx starts when enabled
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<bool> CheckUpdatesOnStart { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Show "Confirm Exit" Dialog
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<bool> ShowConfirmExit { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Ignore Applet
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<bool> IgnoreApplet { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enables or disables save window size, position and state on close.
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<bool> RememberWindowState { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enables or disables the redesigned title bar
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<bool> ShowTitleBar { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enables hardware-accelerated rendering for Avalonia
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<bool> EnableHardwareAcceleration { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Hide Cursor on Idle
|
||||||
|
/// </summary>
|
||||||
|
public ReactiveObject<HideCursorMode> HideCursor { get; private set; }
|
||||||
|
|
||||||
|
private ConfigurationState()
|
||||||
|
{
|
||||||
|
UI = new UISection();
|
||||||
|
Logger = new LoggerSection();
|
||||||
|
System = new SystemSection();
|
||||||
|
Graphics = new GraphicsSection();
|
||||||
|
Hid = new HidSection();
|
||||||
|
Multiplayer = new MultiplayerSection();
|
||||||
|
EnableDiscordIntegration = new ReactiveObject<bool>();
|
||||||
|
CheckUpdatesOnStart = new ReactiveObject<bool>();
|
||||||
|
ShowConfirmExit = new ReactiveObject<bool>();
|
||||||
|
IgnoreApplet = new ReactiveObject<bool>();
|
||||||
|
IgnoreApplet.LogChangesToValue(nameof(IgnoreApplet));
|
||||||
|
RememberWindowState = new ReactiveObject<bool>();
|
||||||
|
ShowTitleBar = new ReactiveObject<bool>();
|
||||||
|
EnableHardwareAcceleration = new ReactiveObject<bool>();
|
||||||
|
HideCursor = new ReactiveObject<HideCursorMode>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,3 @@
|
|||||||
using Ryujinx.Common;
|
|
||||||
using Ryujinx.Common.Configuration;
|
using Ryujinx.Common.Configuration;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.Common.Logging.Targets;
|
using Ryujinx.Common.Logging.Targets;
|
||||||
@@ -11,103 +10,69 @@ namespace Ryujinx.UI.Common.Configuration
|
|||||||
{
|
{
|
||||||
public static void Initialize()
|
public static void Initialize()
|
||||||
{
|
{
|
||||||
ConfigurationState.Instance.Logger.EnableDebug.Event += ReloadEnableDebug;
|
ConfigurationState.Instance.Logger.EnableDebug.Event +=
|
||||||
ConfigurationState.Instance.Logger.EnableStub.Event += ReloadEnableStub;
|
(_, e) => Logger.SetEnable(LogLevel.Debug, e.NewValue);
|
||||||
ConfigurationState.Instance.Logger.EnableInfo.Event += ReloadEnableInfo;
|
ConfigurationState.Instance.Logger.EnableStub.Event +=
|
||||||
ConfigurationState.Instance.Logger.EnableWarn.Event += ReloadEnableWarning;
|
(_, e) => Logger.SetEnable(LogLevel.Stub, e.NewValue);
|
||||||
ConfigurationState.Instance.Logger.EnableError.Event += ReloadEnableError;
|
ConfigurationState.Instance.Logger.EnableInfo.Event +=
|
||||||
ConfigurationState.Instance.Logger.EnableTrace.Event += ReloadEnableTrace;
|
(_, e) => Logger.SetEnable(LogLevel.Info, e.NewValue);
|
||||||
ConfigurationState.Instance.Logger.EnableGuest.Event += ReloadEnableGuest;
|
ConfigurationState.Instance.Logger.EnableWarn.Event +=
|
||||||
ConfigurationState.Instance.Logger.EnableFsAccessLog.Event += ReloadEnableFsAccessLog;
|
(_, e) => Logger.SetEnable(LogLevel.Warning, e.NewValue);
|
||||||
ConfigurationState.Instance.Logger.FilteredClasses.Event += ReloadFilteredClasses;
|
ConfigurationState.Instance.Logger.EnableError.Event +=
|
||||||
ConfigurationState.Instance.Logger.EnableFileLog.Event += ReloadFileLogger;
|
(_, e) => Logger.SetEnable(LogLevel.Error, e.NewValue);
|
||||||
}
|
ConfigurationState.Instance.Logger.EnableTrace.Event +=
|
||||||
|
(_, e) => Logger.SetEnable(LogLevel.Trace, e.NewValue);
|
||||||
|
ConfigurationState.Instance.Logger.EnableGuest.Event +=
|
||||||
|
(_, e) => Logger.SetEnable(LogLevel.Guest, e.NewValue);
|
||||||
|
ConfigurationState.Instance.Logger.EnableFsAccessLog.Event +=
|
||||||
|
(_, e) => Logger.SetEnable(LogLevel.AccessLog, e.NewValue);
|
||||||
|
|
||||||
private static void ReloadEnableDebug(object sender, ReactiveEventArgs<bool> e)
|
ConfigurationState.Instance.Logger.FilteredClasses.Event += (_, e) =>
|
||||||
{
|
|
||||||
Logger.SetEnable(LogLevel.Debug, e.NewValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void ReloadEnableStub(object sender, ReactiveEventArgs<bool> e)
|
|
||||||
{
|
|
||||||
Logger.SetEnable(LogLevel.Stub, e.NewValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void ReloadEnableInfo(object sender, ReactiveEventArgs<bool> e)
|
|
||||||
{
|
|
||||||
Logger.SetEnable(LogLevel.Info, e.NewValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void ReloadEnableWarning(object sender, ReactiveEventArgs<bool> e)
|
|
||||||
{
|
|
||||||
Logger.SetEnable(LogLevel.Warning, e.NewValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void ReloadEnableError(object sender, ReactiveEventArgs<bool> e)
|
|
||||||
{
|
|
||||||
Logger.SetEnable(LogLevel.Error, e.NewValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void ReloadEnableTrace(object sender, ReactiveEventArgs<bool> e)
|
|
||||||
{
|
|
||||||
Logger.SetEnable(LogLevel.Trace, e.NewValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void ReloadEnableGuest(object sender, ReactiveEventArgs<bool> e)
|
|
||||||
{
|
|
||||||
Logger.SetEnable(LogLevel.Guest, e.NewValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void ReloadEnableFsAccessLog(object sender, ReactiveEventArgs<bool> e)
|
|
||||||
{
|
|
||||||
Logger.SetEnable(LogLevel.AccessLog, e.NewValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void ReloadFilteredClasses(object sender, ReactiveEventArgs<LogClass[]> e)
|
|
||||||
{
|
|
||||||
bool noFilter = e.NewValue.Length == 0;
|
|
||||||
|
|
||||||
foreach (var logClass in Enum.GetValues<LogClass>())
|
|
||||||
{
|
{
|
||||||
Logger.SetEnable(logClass, noFilter);
|
bool noFilter = e.NewValue.Length == 0;
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var logClass in e.NewValue)
|
foreach (var logClass in Enum.GetValues<LogClass>())
|
||||||
{
|
|
||||||
Logger.SetEnable(logClass, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void ReloadFileLogger(object sender, ReactiveEventArgs<bool> e)
|
|
||||||
{
|
|
||||||
if (e.NewValue)
|
|
||||||
{
|
|
||||||
string logDir = AppDataManager.LogsDirPath;
|
|
||||||
FileStream logFile = null;
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(logDir))
|
|
||||||
{
|
{
|
||||||
logFile = FileLogTarget.PrepareLogFile(logDir);
|
Logger.SetEnable(logClass, noFilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (logFile == null)
|
foreach (var logClass in e.NewValue)
|
||||||
|
{
|
||||||
|
Logger.SetEnable(logClass, true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ConfigurationState.Instance.Logger.EnableFileLog.Event += (_, e) =>
|
||||||
|
{
|
||||||
|
if (e.NewValue)
|
||||||
|
{
|
||||||
|
string logDir = AppDataManager.LogsDirPath;
|
||||||
|
FileStream logFile = null;
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(logDir))
|
||||||
|
{
|
||||||
|
logFile = FileLogTarget.PrepareLogFile(logDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (logFile == null)
|
||||||
|
{
|
||||||
|
Logger.Error?.Print(LogClass.Application,
|
||||||
|
"No writable log directory available. Make sure either the Logs directory, Application Data, or the Ryujinx directory is writable.");
|
||||||
|
Logger.RemoveTarget("file");
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Logger.AddTarget(new AsyncLogTargetWrapper(
|
||||||
|
new FileLogTarget("file", logFile),
|
||||||
|
1000
|
||||||
|
));
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
Logger.Error?.Print(LogClass.Application, "No writable log directory available. Make sure either the Logs directory, Application Data, or the Ryujinx directory is writable.");
|
|
||||||
Logger.RemoveTarget("file");
|
Logger.RemoveTarget("file");
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
Logger.AddTarget(new AsyncLogTargetWrapper(
|
|
||||||
new FileLogTarget("file", logFile),
|
|
||||||
1000,
|
|
||||||
AsyncLogTargetOverflowAction.Block
|
|
||||||
));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Logger.RemoveTarget("file");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,9 +15,13 @@ namespace Ryujinx.UI.Common
|
|||||||
{
|
{
|
||||||
public static Timestamps StartedAt { get; set; }
|
public static Timestamps StartedAt { get; set; }
|
||||||
|
|
||||||
private static readonly string _description = ReleaseInformation.IsValid
|
private static string VersionString
|
||||||
? $"v{ReleaseInformation.Version} {ReleaseInformation.ReleaseChannelOwner}/{ReleaseInformation.ReleaseChannelRepo}@{ReleaseInformation.BuildGitHash}"
|
=> (ReleaseInformation.IsCanaryBuild ? "Canary " : string.Empty) + $"v{ReleaseInformation.Version}";
|
||||||
: "dev build";
|
|
||||||
|
private static readonly string _description =
|
||||||
|
ReleaseInformation.IsValid
|
||||||
|
? $"{VersionString} {ReleaseInformation.ReleaseChannelOwner}/{ReleaseInformation.ReleaseChannelSourceRepo}@{ReleaseInformation.BuildGitHash}"
|
||||||
|
: "dev build";
|
||||||
|
|
||||||
private const string ApplicationId = "1293250299716173864";
|
private const string ApplicationId = "1293250299716173864";
|
||||||
|
|
||||||
@@ -122,70 +126,145 @@ namespace Ryujinx.UI.Common
|
|||||||
|
|
||||||
private static readonly string[] _discordGameAssetKeys =
|
private static readonly string[] _discordGameAssetKeys =
|
||||||
[
|
[
|
||||||
"01002da013484000", // The Legend of Zelda: Skyward Sword HD
|
"010055d009f78000", // Fire Emblem: Three Houses
|
||||||
|
"0100a12011cc8000", // Fire Emblem: Shadow Dragon
|
||||||
|
"0100a6301214e000", // Fire Emblem Engage
|
||||||
|
"0100f15003e64000", // Fire Emblem Warriors
|
||||||
|
"010071f0143ea000", // Fire Emblem Warriors: Three Hopes
|
||||||
|
|
||||||
|
"01007e3006dda000", // Kirby Star Allies
|
||||||
|
"01004d300c5ae000", // Kirby and the Forgotten Land
|
||||||
|
"01006b601380e000", // Kirby's Return to Dream Land Deluxe
|
||||||
|
"01003fb00c5a8000", // Super Kirby Clash
|
||||||
|
"0100227010460000", // Kirby Fighters 2
|
||||||
|
"0100a8e016236000", // Kirby's Dream Buffet
|
||||||
|
|
||||||
"01007ef00011e000", // The Legend of Zelda: Breath of the Wild
|
"01007ef00011e000", // The Legend of Zelda: Breath of the Wild
|
||||||
|
"01006bb00c6f0000", // The Legend of Zelda: Link's Awakening
|
||||||
|
"01002da013484000", // The Legend of Zelda: Skyward Sword HD
|
||||||
"0100f2c0115b6000", // The Legend of Zelda: Tears of the Kingdom
|
"0100f2c0115b6000", // The Legend of Zelda: Tears of the Kingdom
|
||||||
"01008cf01baac000", // The Legend of Zelda: Echoes of Wisdom
|
"01008cf01baac000", // The Legend of Zelda: Echoes of Wisdom
|
||||||
"01006bb00c6f0000", // The Legend of Zelda: Link's Awakening
|
"01000b900d8b0000", // Cadence of Hyrule
|
||||||
|
"0100ae00096ea000", // Hyrule Warriors: Definitive Edition
|
||||||
"0100000000010000", // SUPER MARIO ODYSSEY
|
"01002b00111a2000", // Hyrule Warriors: Age of Calamity
|
||||||
"010015100b514000", // Super Mario Bros. Wonder
|
|
||||||
"0100152000022000", // Mario Kart 8 Deluxe
|
|
||||||
"01006fe013472000", // Mario Party Superstars
|
|
||||||
"0100965017338000", // Super Mario Party Jamboree
|
|
||||||
"010049900f546000", // Super Mario 3D All-Stars
|
|
||||||
"010028600ebda000", // Super Mario 3D World + Bowser's Fury
|
|
||||||
"0100ecd018ebe000", // Paper Mario: The Thousand-Year Door
|
|
||||||
"010019401051c000", // Mario Strikers League
|
|
||||||
"0100ea80032ea000", // Super Mario Bros. U Deluxe
|
|
||||||
"0100bc0018138000", // Super Mario RPG
|
|
||||||
"0100bde00862a000", // Mario Tennis Aces
|
|
||||||
|
|
||||||
"010048701995e000", // Luigi's Mansion 2 HD
|
"010048701995e000", // Luigi's Mansion 2 HD
|
||||||
"0100dca0064a6000", // Luigi's Mansion 3
|
"0100dca0064a6000", // Luigi's Mansion 3
|
||||||
|
|
||||||
"01008f6008c5e000", // Pokémon Violet
|
"010093801237c000", // Metroid Dread
|
||||||
"0100abf008968000", // Pokémon Sword
|
"010012101468c000", // Metroid Prime Remastered
|
||||||
"01008db008c2c000", // Pokémon Shield
|
|
||||||
"0100000011d90000", // Pokémon Brilliant Diamond
|
"0100000000010000", // SUPER MARIO ODYSSEY
|
||||||
"01001f5010dfa000", // Pokémon Legends: Arceus
|
"0100ea80032ea000", // Super Mario Bros. U Deluxe
|
||||||
|
"01009b90006dc000", // Super Mario Maker 2
|
||||||
|
"010049900f546000", // Super Mario 3D All-Stars
|
||||||
|
"010049900F546001", // ^ 64
|
||||||
|
"010049900F546002", // ^ Sunshine
|
||||||
|
"010049900F546003", // ^ Galaxy
|
||||||
|
"010028600ebda000", // Super Mario 3D World + Bowser's Fury
|
||||||
|
"010015100b514000", // Super Mario Bros. Wonder
|
||||||
|
"0100152000022000", // Mario Kart 8 Deluxe
|
||||||
|
"010036b0034e4000", // Super Mario Party
|
||||||
|
"01006fe013472000", // Mario Party Superstars
|
||||||
|
"0100965017338000", // Super Mario Party Jamboree
|
||||||
|
"01006d0017f7a000", // Mario & Luigi: Brothership
|
||||||
|
"010067300059a000", // Mario + Rabbids: Kingdom Battle
|
||||||
|
"0100317013770000", // Mario + Rabbids: Sparks of Hope
|
||||||
|
"0100a3900c3e2000", // Paper Mario: The Origami King
|
||||||
|
"0100ecd018ebe000", // Paper Mario: The Thousand-Year Door
|
||||||
|
"0100bc0018138000", // Super Mario RPG
|
||||||
|
"0100bde00862a000", // Mario Tennis Aces
|
||||||
|
"0100c9c00e25c000", // Mario Golf: Super Rush
|
||||||
|
"010019401051c000", // Mario Strikers: Battle League
|
||||||
|
"010003000e146000", // Mario & Sonic at the Olympic Games Tokyo 2020
|
||||||
|
"0100b99019412000", // Mario vs. Donkey Kong
|
||||||
|
|
||||||
"0100aa80194b0000", // Pikmin 1
|
"0100aa80194b0000", // Pikmin 1
|
||||||
"0100d680194b2000", // Pikmin 2
|
"0100d680194b2000", // Pikmin 2
|
||||||
"0100f4c009322000", // Pikmin 3 Deluxe
|
"0100f4c009322000", // Pikmin 3 Deluxe
|
||||||
"0100b7c00933a000", // Pikmin 4
|
"0100b7c00933a000", // Pikmin 4
|
||||||
|
|
||||||
|
"010003f003a34000", // Pokémon: Let's Go Pikachu!
|
||||||
|
"0100187003a36000", // Pokémon: Let's Go Eevee!
|
||||||
|
"0100abf008968000", // Pokémon Sword
|
||||||
|
"01008db008c2c000", // Pokémon Shield
|
||||||
|
"0100000011d90000", // Pokémon Brilliant Diamond
|
||||||
|
"010018e011d92000", // Pokémon Shining Pearl
|
||||||
|
"01001f5010dfa000", // Pokémon Legends: Arceus
|
||||||
|
"0100a3d008c5c000", // Pokémon Scarlet
|
||||||
|
"01008f6008c5e000", // Pokémon Violet
|
||||||
|
"0100b3f000be2000", // Pokkén Tournament DX
|
||||||
|
"0100f4300bf2c000", // New Pokémon Snap
|
||||||
|
|
||||||
|
"01003bc0000a0000", // Splatoon 2 (US)
|
||||||
|
"0100f8f0000a2000", // Splatoon 2 (EU)
|
||||||
|
"01003c700009c000", // Splatoon 2 (JP)
|
||||||
|
"0100c2500fc20000", // Splatoon 3
|
||||||
|
"0100ba0018500000", // Splatoon 3: Splatfest World Premiere
|
||||||
|
|
||||||
|
"010040600c5ce000", // Tetris 99
|
||||||
|
"0100277011f1a000", // Super Mario Bros. 35
|
||||||
|
"0100ad9012510000", // PAC-MAN 99
|
||||||
|
"0100ccf019c8c000", // F-ZERO 99
|
||||||
|
"0100d870045b6000", // NES - Nintendo Switch Online
|
||||||
|
"01008d300c50c000", // SNES - Nintendo Switch Online
|
||||||
|
"0100c9a00ece6000", // N64 - Nintendo Switch Online
|
||||||
|
"0100e0601c632000", // N64 - Nintendo Switch Online 18+
|
||||||
|
"0100c62011050000", // GB - Nintendo Switch Online
|
||||||
|
"010012f017576000", // GBA - Nintendo Switch Online
|
||||||
|
|
||||||
|
"01000320000cc000", // 1-2 Switch
|
||||||
|
"0100300012f2a000", // Advance Wars 1+2: Re-Boot Camp
|
||||||
|
"01006f8002326000", // Animal Crossing: New Horizons
|
||||||
|
"0100620012d6e000", // Big Brain Academy: Brain vs. Brain
|
||||||
|
"010018300d006000", // BOXBOY! + BOXGIRL!
|
||||||
|
"0100c1f0051b6000", // Donkey Kong Country: Tropical Freeze
|
||||||
|
"0100ed000d390000", // Dr. Kawashima's Brain Training
|
||||||
|
"010067b017588000", // Endless Ocean Luminous
|
||||||
|
"0100d2f00d5c0000", // Nintendo Switch Sports
|
||||||
|
"01006b5012b32000", // Part Time UFO
|
||||||
|
"0100704000B3A000", // Snipperclips
|
||||||
|
"01006a800016e000", // Super Smash Bros. Ultimate
|
||||||
|
"0100a9400c9c2000", // Tokyo Mirage Sessions #FE Encore
|
||||||
|
|
||||||
|
"010076f0049a2000", // Bayonetta
|
||||||
|
"01007960049a0000", // Bayonetta 2
|
||||||
|
"01004a4010fea000", // Bayonetta 3
|
||||||
|
"0100cf5010fec000", // Bayonetta Origins: Cereza and the Lost Demon
|
||||||
|
|
||||||
|
"0100dcd01525a000", // Persona 3 Portable
|
||||||
|
"010062b01525c000", // Persona 4 Golden
|
||||||
|
"010075a016a3a000", // Persona 4 Arena Ultimax
|
||||||
|
"01005ca01580e000", // Persona 5 Royal
|
||||||
|
"0100801011c3e000", // Persona 5 Strikers
|
||||||
|
"010087701b092000", // Persona 5 Tactica
|
||||||
|
|
||||||
|
"01009aa000faa000", // Sonic Mania
|
||||||
"01004ad014bf0000", // Sonic Frontiers
|
"01004ad014bf0000", // Sonic Frontiers
|
||||||
"01005ea01c0fc000", // SONIC X SHADOW GENERATIONS
|
"01005ea01c0fc000", // SONIC X SHADOW GENERATIONS
|
||||||
"01005ea01c0fc001", // ^
|
"01005ea01c0fc001", // ^
|
||||||
|
|
||||||
"01004d300c5ae000", // Kirby and the Forgotten Land
|
|
||||||
"01006b601380e000", // Kirby's Return to Dreamland Deluxe
|
|
||||||
"01007e3006dda000", // Kirby Star Allies
|
|
||||||
|
|
||||||
"0100c2500fc20000", // Splatoon 3
|
|
||||||
"0100ba0018500000", // Splatoon 3: Splatfest World Premiere
|
|
||||||
"01000a10041ea000", // The Elder Scrolls V: Skyrim
|
|
||||||
"01007820196a6000", // Red Dead Redemption
|
|
||||||
"01008c8012920000", // Dying Light Platinum Edition
|
|
||||||
"0100744001588000", // Cars 3: Driven to Win
|
|
||||||
"0100c1f0051b6000", // Donkey Kong Country: Tropical Freeze
|
|
||||||
"01002b00111a2000", // Hyrule Warriors: Age of Calamity
|
|
||||||
"01006f8002326000", // Animal Crossing: New Horizons
|
|
||||||
"0100853015e86000", // No Man's Sky
|
|
||||||
"01008d100d43e000", // Saints Row IV
|
|
||||||
"0100de600beee000", // Saints Row: The Third - The Full Package
|
|
||||||
"0100d7a01b7a2000", // Star Wars: Bounty Hunter
|
|
||||||
"0100dbf01000a000", // Burnout Paradise Remastered
|
|
||||||
"0100e46006708000", // Terraria
|
|
||||||
"010056e00853a000", // A Hat in Time
|
"010056e00853a000", // A Hat in Time
|
||||||
"01006a800016e000", // Super Smash Bros. Ultimate
|
"0100dbf01000a000", // Burnout Paradise Remastered
|
||||||
|
"0100744001588000", // Cars 3: Driven to Win
|
||||||
|
"0100b41013c82000", // Cruis'n Blast
|
||||||
|
"01008c8012920000", // Dying Light Platinum Edition
|
||||||
|
"01000a10041ea000", // The Elder Scrolls V: Skyrim
|
||||||
|
"0100770008dd8000", // Monster Hunter Generations Ultimate
|
||||||
|
"0100b04011742000", // Monster Hunter Rise
|
||||||
|
"0100853015e86000", // No Man's Sky
|
||||||
"01007bb017812000", // Portal
|
"01007bb017812000", // Portal
|
||||||
"0100abd01785c000", // Portal 2
|
"0100abd01785c000", // Portal 2
|
||||||
"01008e200c5c2000", // Muse Dash
|
"01008e200c5c2000", // Muse Dash
|
||||||
|
"01007820196a6000", // Red Dead Redemption
|
||||||
|
"01002f7013224000", // Rune Factory 5
|
||||||
|
"01008d100d43e000", // Saints Row IV
|
||||||
|
"0100de600beee000", // Saints Row: The Third - The Full Package
|
||||||
"01001180021fa000", // Shovel Knight: Specter of Torment
|
"01001180021fa000", // Shovel Knight: Specter of Torment
|
||||||
"010012101468c000", // Metroid Prime Remastered
|
"0100d7a01b7a2000", // Star Wars: Bounty Hunter
|
||||||
"0100c9a00ece6000", // Nintendo 64 - Nintendo Switch Online
|
"0100800015926000", // Suika Game
|
||||||
|
"0100e46006708000", // Terraria
|
||||||
|
"010080b00ad66000", // Undertale
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ using Ryujinx.Common.Logging;
|
|||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Runtime.Versioning;
|
using System.Runtime.Versioning;
|
||||||
|
|
||||||
@@ -24,6 +25,26 @@ namespace Ryujinx.UI.Common.Helper
|
|||||||
|
|
||||||
public static bool IsTypeAssociationSupported => (OperatingSystem.IsLinux() || OperatingSystem.IsWindows()) && !ReleaseInformation.IsFlatHubBuild;
|
public static bool IsTypeAssociationSupported => (OperatingSystem.IsLinux() || OperatingSystem.IsWindows()) && !ReleaseInformation.IsFlatHubBuild;
|
||||||
|
|
||||||
|
public static bool AreMimeTypesRegistered
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (OperatingSystem.IsLinux())
|
||||||
|
{
|
||||||
|
return AreMimeTypesRegisteredLinux();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (OperatingSystem.IsWindows())
|
||||||
|
{
|
||||||
|
return AreMimeTypesRegisteredWindows();
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Add macOS support.
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[SupportedOSPlatform("linux")]
|
[SupportedOSPlatform("linux")]
|
||||||
private static bool AreMimeTypesRegisteredLinux() => File.Exists(Path.Combine(_mimeDbPath, "packages", "Ryujinx.xml"));
|
private static bool AreMimeTypesRegisteredLinux() => File.Exists(Path.Combine(_mimeDbPath, "packages", "Ryujinx.xml"));
|
||||||
|
|
||||||
@@ -35,7 +56,7 @@ namespace Ryujinx.UI.Common.Helper
|
|||||||
if ((uninstall && AreMimeTypesRegisteredLinux()) || (!uninstall && !AreMimeTypesRegisteredLinux()))
|
if ((uninstall && AreMimeTypesRegisteredLinux()) || (!uninstall && !AreMimeTypesRegisteredLinux()))
|
||||||
{
|
{
|
||||||
string mimeTypesFile = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "mime", "Ryujinx.xml");
|
string mimeTypesFile = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "mime", "Ryujinx.xml");
|
||||||
string additionalArgs = !uninstall ? "--novendor" : "";
|
string additionalArgs = !uninstall ? "--novendor" : string.Empty;
|
||||||
|
|
||||||
using Process mimeProcess = new();
|
using Process mimeProcess = new();
|
||||||
|
|
||||||
@@ -72,6 +93,10 @@ namespace Ryujinx.UI.Common.Helper
|
|||||||
[SupportedOSPlatform("windows")]
|
[SupportedOSPlatform("windows")]
|
||||||
private static bool AreMimeTypesRegisteredWindows()
|
private static bool AreMimeTypesRegisteredWindows()
|
||||||
{
|
{
|
||||||
|
return _fileExtensions.Aggregate(false,
|
||||||
|
(current, ext) => current | CheckRegistering(ext)
|
||||||
|
);
|
||||||
|
|
||||||
static bool CheckRegistering(string ext)
|
static bool CheckRegistering(string ext)
|
||||||
{
|
{
|
||||||
RegistryKey key = Registry.CurrentUser.OpenSubKey(@$"Software\Classes\{ext}");
|
RegistryKey key = Registry.CurrentUser.OpenSubKey(@$"Software\Classes\{ext}");
|
||||||
@@ -83,24 +108,24 @@ namespace Ryujinx.UI.Common.Helper
|
|||||||
|
|
||||||
var openCmd = key.OpenSubKey(@"shell\open\command");
|
var openCmd = key.OpenSubKey(@"shell\open\command");
|
||||||
|
|
||||||
string keyValue = (string)openCmd.GetValue("");
|
string keyValue = (string)openCmd.GetValue(string.Empty);
|
||||||
|
|
||||||
return keyValue is not null && (keyValue.Contains("Ryujinx") || keyValue.Contains(AppDomain.CurrentDomain.FriendlyName));
|
return keyValue is not null && (keyValue.Contains("Ryujinx") || keyValue.Contains(AppDomain.CurrentDomain.FriendlyName));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool registered = false;
|
|
||||||
|
|
||||||
foreach (string ext in _fileExtensions)
|
|
||||||
{
|
|
||||||
registered |= CheckRegistering(ext);
|
|
||||||
}
|
|
||||||
|
|
||||||
return registered;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[SupportedOSPlatform("windows")]
|
[SupportedOSPlatform("windows")]
|
||||||
private static bool InstallWindowsMimeTypes(bool uninstall = false)
|
private static bool InstallWindowsMimeTypes(bool uninstall = false)
|
||||||
{
|
{
|
||||||
|
bool registered = _fileExtensions.Aggregate(false,
|
||||||
|
(current, ext) => current | RegisterExtension(ext, uninstall)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Notify Explorer the file association has been changed.
|
||||||
|
SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_FLUSH, nint.Zero, nint.Zero);
|
||||||
|
|
||||||
|
return registered;
|
||||||
|
|
||||||
static bool RegisterExtension(string ext, bool uninstall = false)
|
static bool RegisterExtension(string ext, bool uninstall = false)
|
||||||
{
|
{
|
||||||
string keyString = @$"Software\Classes\{ext}";
|
string keyString = @$"Software\Classes\{ext}";
|
||||||
@@ -127,42 +152,13 @@ namespace Ryujinx.UI.Common.Helper
|
|||||||
|
|
||||||
Logger.Debug?.Print(LogClass.Application, $"Adding type association {ext}");
|
Logger.Debug?.Print(LogClass.Application, $"Adding type association {ext}");
|
||||||
using var openCmd = key.CreateSubKey(@"shell\open\command");
|
using var openCmd = key.CreateSubKey(@"shell\open\command");
|
||||||
openCmd.SetValue("", $"\"{Environment.ProcessPath}\" \"%1\"");
|
openCmd.SetValue(string.Empty, $"\"{Environment.ProcessPath}\" \"%1\"");
|
||||||
Logger.Debug?.Print(LogClass.Application, $"Added type association {ext}");
|
Logger.Debug?.Print(LogClass.Application, $"Added type association {ext}");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool registered = false;
|
|
||||||
|
|
||||||
foreach (string ext in _fileExtensions)
|
|
||||||
{
|
|
||||||
registered |= RegisterExtension(ext, uninstall);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Notify Explorer the file association has been changed.
|
|
||||||
SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_FLUSH, nint.Zero, nint.Zero);
|
|
||||||
|
|
||||||
return registered;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool AreMimeTypesRegistered()
|
|
||||||
{
|
|
||||||
if (OperatingSystem.IsLinux())
|
|
||||||
{
|
|
||||||
return AreMimeTypesRegisteredLinux();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (OperatingSystem.IsWindows())
|
|
||||||
{
|
|
||||||
return AreMimeTypesRegisteredWindows();
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Add macOS support.
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool Install()
|
public static bool Install()
|
||||||
|
|||||||
@@ -12,18 +12,11 @@ namespace Ryujinx.UI.Common.Helper
|
|||||||
{
|
{
|
||||||
public static bool IsFirmwareValid(ContentManager contentManager, out UserError error)
|
public static bool IsFirmwareValid(ContentManager contentManager, out UserError error)
|
||||||
{
|
{
|
||||||
bool hasFirmware = contentManager.GetCurrentFirmwareVersion() != null;
|
error = contentManager.GetCurrentFirmwareVersion() != null
|
||||||
|
? UserError.Success
|
||||||
|
: UserError.NoFirmware;
|
||||||
|
|
||||||
if (hasFirmware)
|
return error is UserError.Success;
|
||||||
{
|
|
||||||
error = UserError.Success;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
error = UserError.NoFirmware;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool CanFixStartApplication(ContentManager contentManager, string baseApplicationPath, UserError error, out SystemVersion firmwareVersion)
|
public static bool CanFixStartApplication(ContentManager contentManager, string baseApplicationPath, UserError error, out SystemVersion firmwareVersion)
|
||||||
@@ -95,14 +88,18 @@ namespace Ryujinx.UI.Common.Helper
|
|||||||
string baseApplicationExtension = Path.GetExtension(baseApplicationPath).ToLowerInvariant();
|
string baseApplicationExtension = Path.GetExtension(baseApplicationPath).ToLowerInvariant();
|
||||||
|
|
||||||
// NOTE: We don't force homebrew developers to install a system firmware.
|
// NOTE: We don't force homebrew developers to install a system firmware.
|
||||||
if (baseApplicationExtension is not (".nro" or ".nso"))
|
if (baseApplicationExtension is ".nro" or ".nso")
|
||||||
return IsFirmwareValid(contentManager, out error);
|
{
|
||||||
|
error = UserError.Success;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return IsFirmwareValid(contentManager, out error);
|
||||||
}
|
}
|
||||||
|
|
||||||
error = UserError.ApplicationNotFound;
|
error = UserError.ApplicationNotFound;
|
||||||
|
|
||||||
return error is UserError.Success;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ namespace Ryujinx.UI.Common.Helper
|
|||||||
{
|
{
|
||||||
var titleUpdateWindowData = new TitleUpdateMetadata
|
var titleUpdateWindowData = new TitleUpdateMetadata
|
||||||
{
|
{
|
||||||
Selected = "",
|
Selected = string.Empty,
|
||||||
Paths = [],
|
Paths = [],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ namespace Ryujinx.UI.Common.Models.Github
|
|||||||
public class GithubReleasesJsonResponse
|
public class GithubReleasesJsonResponse
|
||||||
{
|
{
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
public string TagName { get; set; }
|
||||||
public List<GithubReleaseAssetJsonResponse> Assets { get; set; }
|
public List<GithubReleaseAssetJsonResponse> Assets { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
55
src/Ryujinx.UI.Common/Models/XCITrimmerFileModel.cs
Normal file
55
src/Ryujinx.UI.Common/Models/XCITrimmerFileModel.cs
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
using Ryujinx.Common.Logging;
|
||||||
|
using Ryujinx.Common.Utilities;
|
||||||
|
using Ryujinx.UI.App.Common;
|
||||||
|
|
||||||
|
namespace Ryujinx.UI.Common.Models
|
||||||
|
{
|
||||||
|
public record XCITrimmerFileModel(
|
||||||
|
string Name,
|
||||||
|
string Path,
|
||||||
|
bool Trimmable,
|
||||||
|
bool Untrimmable,
|
||||||
|
long PotentialSavingsB,
|
||||||
|
long CurrentSavingsB,
|
||||||
|
int? PercentageProgress,
|
||||||
|
XCIFileTrimmer.OperationOutcome ProcessingOutcome)
|
||||||
|
{
|
||||||
|
public static XCITrimmerFileModel FromApplicationData(ApplicationData applicationData, XCIFileTrimmerLog logger)
|
||||||
|
{
|
||||||
|
var trimmer = new XCIFileTrimmer(applicationData.Path, logger);
|
||||||
|
|
||||||
|
return new XCITrimmerFileModel(
|
||||||
|
applicationData.Name,
|
||||||
|
applicationData.Path,
|
||||||
|
trimmer.CanBeTrimmed,
|
||||||
|
trimmer.CanBeUntrimmed,
|
||||||
|
trimmer.DiskSpaceSavingsB,
|
||||||
|
trimmer.DiskSpaceSavedB,
|
||||||
|
null,
|
||||||
|
XCIFileTrimmer.OperationOutcome.Undetermined
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsFailed
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return ProcessingOutcome != XCIFileTrimmer.OperationOutcome.Undetermined &&
|
||||||
|
ProcessingOutcome != XCIFileTrimmer.OperationOutcome.Successful;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual bool Equals(XCITrimmerFileModel obj)
|
||||||
|
{
|
||||||
|
if (obj == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return this.Path == obj.Path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return this.Path.GetHashCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 93 KiB |
@@ -51,7 +51,6 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="DiscordRichPresence" />
|
<PackageReference Include="DiscordRichPresence" />
|
||||||
<PackageReference Include="DynamicData" />
|
<PackageReference Include="DynamicData" />
|
||||||
<PackageReference Include="Humanizer" />
|
|
||||||
<PackageReference Include="securifybv.ShellLink" />
|
<PackageReference Include="securifybv.ShellLink" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ namespace Ryujinx.UI.LocaleGenerator
|
|||||||
|
|
||||||
context.RegisterSourceOutput(contents, (spc, content) =>
|
context.RegisterSourceOutput(contents, (spc, content) =>
|
||||||
{
|
{
|
||||||
var lines = content.Split('\n').Where(x => x.Trim().StartsWith("\"")).Select(x => x.Split(':')[0].Trim().Replace("\"", ""));
|
var lines = content.Split('\n').Where(x => x.Trim().StartsWith("\"")).Select(x => x.Split(':')[0].Trim().Replace("\"", string.Empty));
|
||||||
StringBuilder enumSourceBuilder = new();
|
StringBuilder enumSourceBuilder = new();
|
||||||
enumSourceBuilder.AppendLine("namespace Ryujinx.Ava.Common.Locale;");
|
enumSourceBuilder.AppendLine("namespace Ryujinx.Ava.Common.Locale;");
|
||||||
enumSourceBuilder.AppendLine("internal enum LocaleKeys");
|
enumSourceBuilder.AppendLine("internal enum LocaleKeys");
|
||||||
|
|||||||
@@ -23,8 +23,10 @@ namespace Ryujinx.Ava
|
|||||||
{
|
{
|
||||||
internal static string FormatTitle(LocaleKeys? windowTitleKey = null)
|
internal static string FormatTitle(LocaleKeys? windowTitleKey = null)
|
||||||
=> windowTitleKey is null
|
=> windowTitleKey is null
|
||||||
? $"Ryujinx {Program.Version}"
|
? $"{FullAppName} {Program.Version}"
|
||||||
: $"Ryujinx {Program.Version} - {LocaleManager.Instance[windowTitleKey.Value]}";
|
: $"{FullAppName} {Program.Version} - {LocaleManager.Instance[windowTitleKey.Value]}";
|
||||||
|
|
||||||
|
public static readonly string FullAppName = ReleaseInformation.IsCanaryBuild ? "Ryujinx Canary" : "Ryujinx";
|
||||||
|
|
||||||
public static MainWindow MainWindow => Current!
|
public static MainWindow MainWindow => Current!
|
||||||
.ApplicationLifetime.Cast<IClassicDesktopStyleApplicationLifetime>()
|
.ApplicationLifetime.Cast<IClassicDesktopStyleApplicationLifetime>()
|
||||||
@@ -58,11 +60,9 @@ namespace Ryujinx.Ava
|
|||||||
|
|
||||||
if (Program.PreviewerDetached)
|
if (Program.PreviewerDetached)
|
||||||
{
|
{
|
||||||
ApplyConfiguredTheme();
|
ApplyConfiguredTheme(ConfigurationState.Instance.UI.BaseStyle);
|
||||||
|
|
||||||
ConfigurationState.Instance.UI.BaseStyle.Event += ThemeChanged_Event;
|
ConfigurationState.Instance.UI.BaseStyle.Event += ThemeChanged_Event;
|
||||||
ConfigurationState.Instance.UI.CustomThemePath.Event += ThemeChanged_Event;
|
|
||||||
ConfigurationState.Instance.UI.EnableCustomTheme.Event += CustomThemeChanged_Event;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,16 +89,12 @@ namespace Ryujinx.Ava
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CustomThemeChanged_Event(object _, ReactiveEventArgs<bool> __) => ApplyConfiguredTheme();
|
private void ThemeChanged_Event(object _, ReactiveEventArgs<string> rArgs) => ApplyConfiguredTheme(rArgs.NewValue);
|
||||||
|
|
||||||
private void ThemeChanged_Event(object _, ReactiveEventArgs<string> __) => ApplyConfiguredTheme();
|
public void ApplyConfiguredTheme(string baseStyle)
|
||||||
|
|
||||||
public void ApplyConfiguredTheme()
|
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
string baseStyle = ConfigurationState.Instance.UI.BaseStyle;
|
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(baseStyle))
|
if (string.IsNullOrWhiteSpace(baseStyle))
|
||||||
{
|
{
|
||||||
ConfigurationState.Instance.UI.BaseStyle.Value = "Auto";
|
ConfigurationState.Instance.UI.BaseStyle.Value = "Auto";
|
||||||
|
|||||||
@@ -604,61 +604,59 @@ namespace Ryujinx.Ava
|
|||||||
|
|
||||||
SystemVersion firmwareVersion = ContentManager.GetCurrentFirmwareVersion();
|
SystemVersion firmwareVersion = ContentManager.GetCurrentFirmwareVersion();
|
||||||
|
|
||||||
if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
if (Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime)
|
||||||
{
|
{
|
||||||
if (!SetupValidator.CanStartApplication(ContentManager, ApplicationPath, out UserError userError))
|
if (!SetupValidator.CanStartApplication(ContentManager, ApplicationPath, out UserError userError))
|
||||||
{
|
{
|
||||||
|
if (SetupValidator.CanFixStartApplication(ContentManager, ApplicationPath, userError, out firmwareVersion))
|
||||||
{
|
{
|
||||||
if (SetupValidator.CanFixStartApplication(ContentManager, ApplicationPath, userError, out firmwareVersion))
|
if (userError is UserError.NoFirmware)
|
||||||
{
|
{
|
||||||
if (userError == UserError.NoFirmware)
|
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(
|
||||||
{
|
LocaleManager.Instance[LocaleKeys.DialogFirmwareNoFirmwareInstalledMessage],
|
||||||
UserResult result = await ContentDialogHelper.CreateConfirmationDialog(
|
LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogFirmwareInstallEmbeddedMessage, firmwareVersion.VersionString),
|
||||||
LocaleManager.Instance[LocaleKeys.DialogFirmwareNoFirmwareInstalledMessage],
|
LocaleManager.Instance[LocaleKeys.InputDialogYes],
|
||||||
LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogFirmwareInstallEmbeddedMessage, firmwareVersion.VersionString),
|
LocaleManager.Instance[LocaleKeys.InputDialogNo],
|
||||||
LocaleManager.Instance[LocaleKeys.InputDialogYes],
|
string.Empty);
|
||||||
LocaleManager.Instance[LocaleKeys.InputDialogNo],
|
|
||||||
"");
|
|
||||||
|
|
||||||
if (result != UserResult.Yes)
|
if (result != UserResult.Yes)
|
||||||
{
|
|
||||||
await UserErrorDialog.ShowUserErrorDialog(userError);
|
|
||||||
Device.Dispose();
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!SetupValidator.TryFixStartApplication(ContentManager, ApplicationPath, userError, out _))
|
|
||||||
{
|
{
|
||||||
await UserErrorDialog.ShowUserErrorDialog(userError);
|
await UserErrorDialog.ShowUserErrorDialog(userError);
|
||||||
Device.Dispose();
|
Device.Dispose();
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tell the user that we installed a firmware for them.
|
|
||||||
if (userError == UserError.NoFirmware)
|
|
||||||
{
|
|
||||||
firmwareVersion = ContentManager.GetCurrentFirmwareVersion();
|
|
||||||
|
|
||||||
_viewModel.RefreshFirmwareStatus();
|
|
||||||
|
|
||||||
await ContentDialogHelper.CreateInfoDialog(
|
|
||||||
LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogFirmwareInstalledMessage, firmwareVersion.VersionString),
|
|
||||||
LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogFirmwareInstallEmbeddedSuccessMessage, firmwareVersion.VersionString),
|
|
||||||
LocaleManager.Instance[LocaleKeys.InputDialogOk],
|
|
||||||
"",
|
|
||||||
LocaleManager.Instance[LocaleKeys.RyujinxInfo]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
if (!SetupValidator.TryFixStartApplication(ContentManager, ApplicationPath, userError, out _))
|
||||||
{
|
{
|
||||||
await UserErrorDialog.ShowUserErrorDialog(userError);
|
await UserErrorDialog.ShowUserErrorDialog(userError);
|
||||||
Device.Dispose();
|
Device.Dispose();
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Tell the user that we installed a firmware for them.
|
||||||
|
if (userError is UserError.NoFirmware)
|
||||||
|
{
|
||||||
|
firmwareVersion = ContentManager.GetCurrentFirmwareVersion();
|
||||||
|
|
||||||
|
_viewModel.RefreshFirmwareStatus();
|
||||||
|
|
||||||
|
await ContentDialogHelper.CreateInfoDialog(
|
||||||
|
LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogFirmwareInstalledMessage, firmwareVersion.VersionString),
|
||||||
|
LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogFirmwareInstallEmbeddedSuccessMessage, firmwareVersion.VersionString),
|
||||||
|
LocaleManager.Instance[LocaleKeys.InputDialogOk],
|
||||||
|
string.Empty,
|
||||||
|
LocaleManager.Instance[LocaleKeys.RyujinxInfo]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await UserErrorDialog.ShowUserErrorDialog(userError);
|
||||||
|
Device.Dispose();
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -820,20 +818,12 @@ namespace Ryujinx.Ava
|
|||||||
VirtualFileSystem.ReloadKeySet();
|
VirtualFileSystem.ReloadKeySet();
|
||||||
|
|
||||||
// Initialize Renderer.
|
// Initialize Renderer.
|
||||||
IRenderer renderer;
|
IRenderer renderer = ConfigurationState.Instance.Graphics.GraphicsBackend.Value == GraphicsBackend.OpenGl
|
||||||
|
? new OpenGLRenderer()
|
||||||
if (ConfigurationState.Instance.Graphics.GraphicsBackend.Value == GraphicsBackend.Vulkan)
|
: VulkanRenderer.Create(
|
||||||
{
|
ConfigurationState.Instance.Graphics.PreferredGpu,
|
||||||
renderer = new VulkanRenderer(
|
|
||||||
Vk.GetApi(),
|
|
||||||
(RendererHost.EmbeddedWindow as EmbeddedWindowVulkan)!.CreateSurface,
|
(RendererHost.EmbeddedWindow as EmbeddedWindowVulkan)!.CreateSurface,
|
||||||
VulkanHelper.GetRequiredInstanceExtensions,
|
VulkanHelper.GetRequiredInstanceExtensions);
|
||||||
ConfigurationState.Instance.Graphics.PreferredGpu.Value);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
renderer = new OpenGLRenderer();
|
|
||||||
}
|
|
||||||
|
|
||||||
BackendThreading threadingMode = ConfigurationState.Instance.Graphics.BackendThreading;
|
BackendThreading threadingMode = ConfigurationState.Instance.Graphics.BackendThreading;
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,10 @@
|
|||||||
"SettingsTabSystemUseHypervisor": "استخدم مراقب الأجهزة الافتراضية",
|
"SettingsTabSystemUseHypervisor": "استخدم مراقب الأجهزة الافتراضية",
|
||||||
"MenuBarFile": "_ملف",
|
"MenuBarFile": "_ملف",
|
||||||
"MenuBarFileOpenFromFile": "_تحميل تطبيق من ملف",
|
"MenuBarFileOpenFromFile": "_تحميل تطبيق من ملف",
|
||||||
|
"MenuBarFileOpenFromFileError": "No applications found in selected file.",
|
||||||
"MenuBarFileOpenUnpacked": "تحميل لُعْبَة غير محزومة",
|
"MenuBarFileOpenUnpacked": "تحميل لُعْبَة غير محزومة",
|
||||||
|
"MenuBarFileLoadDlcFromFolder": "Load DLC From Folder",
|
||||||
|
"MenuBarFileLoadTitleUpdatesFromFolder": "Load Title Updates From Folder",
|
||||||
"MenuBarFileOpenEmuFolder": "فتح مجلد Ryujinx",
|
"MenuBarFileOpenEmuFolder": "فتح مجلد Ryujinx",
|
||||||
"MenuBarFileOpenLogsFolder": "فتح مجلد السجلات",
|
"MenuBarFileOpenLogsFolder": "فتح مجلد السجلات",
|
||||||
"MenuBarFileExit": "_خروج",
|
"MenuBarFileExit": "_خروج",
|
||||||
@@ -97,11 +100,14 @@
|
|||||||
"SettingsTabGeneralCheckUpdatesOnLaunch": "التحقق من وجود تحديثات عند التشغيل",
|
"SettingsTabGeneralCheckUpdatesOnLaunch": "التحقق من وجود تحديثات عند التشغيل",
|
||||||
"SettingsTabGeneralShowConfirmExitDialog": "إظهار مربع حوار \"تأكيد الخروج\"",
|
"SettingsTabGeneralShowConfirmExitDialog": "إظهار مربع حوار \"تأكيد الخروج\"",
|
||||||
"SettingsTabGeneralRememberWindowState": "تذكر حجم/موضع النافذة",
|
"SettingsTabGeneralRememberWindowState": "تذكر حجم/موضع النافذة",
|
||||||
|
"SettingsTabGeneralShowTitleBar": "Show Title Bar (Requires restart)",
|
||||||
"SettingsTabGeneralHideCursor": "إخفاء المؤشر:",
|
"SettingsTabGeneralHideCursor": "إخفاء المؤشر:",
|
||||||
"SettingsTabGeneralHideCursorNever": "مطلقا",
|
"SettingsTabGeneralHideCursorNever": "مطلقا",
|
||||||
"SettingsTabGeneralHideCursorOnIdle": "عند الخمول",
|
"SettingsTabGeneralHideCursorOnIdle": "عند الخمول",
|
||||||
"SettingsTabGeneralHideCursorAlways": "دائما",
|
"SettingsTabGeneralHideCursorAlways": "دائما",
|
||||||
"SettingsTabGeneralGameDirectories": "مجلدات الألعاب",
|
"SettingsTabGeneralGameDirectories": "مجلدات الألعاب",
|
||||||
|
"SettingsTabGeneralAutoloadDirectories": "Autoload DLC/Updates Directories",
|
||||||
|
"SettingsTabGeneralAutoloadNote": "DLC and Updates which refer to missing files will be unloaded automatically",
|
||||||
"SettingsTabGeneralAdd": "إضافة",
|
"SettingsTabGeneralAdd": "إضافة",
|
||||||
"SettingsTabGeneralRemove": "إزالة",
|
"SettingsTabGeneralRemove": "إزالة",
|
||||||
"SettingsTabSystem": "النظام",
|
"SettingsTabSystem": "النظام",
|
||||||
@@ -401,6 +407,7 @@
|
|||||||
"AvatarSetBackgroundColor": "تعيين لون الخلفية",
|
"AvatarSetBackgroundColor": "تعيين لون الخلفية",
|
||||||
"AvatarClose": "إغلاق",
|
"AvatarClose": "إغلاق",
|
||||||
"ControllerSettingsLoadProfileToolTip": "تحميل الملف الشخصي",
|
"ControllerSettingsLoadProfileToolTip": "تحميل الملف الشخصي",
|
||||||
|
"ControllerSettingsViewProfileToolTip": "View Profile",
|
||||||
"ControllerSettingsAddProfileToolTip": "إضافة ملف شخصي",
|
"ControllerSettingsAddProfileToolTip": "إضافة ملف شخصي",
|
||||||
"ControllerSettingsRemoveProfileToolTip": "إزالة الملف الشخصي",
|
"ControllerSettingsRemoveProfileToolTip": "إزالة الملف الشخصي",
|
||||||
"ControllerSettingsSaveProfileToolTip": "حفظ الملف الشخصي",
|
"ControllerSettingsSaveProfileToolTip": "حفظ الملف الشخصي",
|
||||||
@@ -410,6 +417,7 @@
|
|||||||
"GameListContextMenuToggleFavorite": "تعيين كمفضل",
|
"GameListContextMenuToggleFavorite": "تعيين كمفضل",
|
||||||
"GameListContextMenuToggleFavoriteToolTip": "تبديل الحالة المفضلة للعبة",
|
"GameListContextMenuToggleFavoriteToolTip": "تبديل الحالة المفضلة للعبة",
|
||||||
"SettingsTabGeneralTheme": "السمة:",
|
"SettingsTabGeneralTheme": "السمة:",
|
||||||
|
"SettingsTabGeneralThemeAuto": "Auto",
|
||||||
"SettingsTabGeneralThemeDark": "داكن",
|
"SettingsTabGeneralThemeDark": "داكن",
|
||||||
"SettingsTabGeneralThemeLight": "فاتح",
|
"SettingsTabGeneralThemeLight": "فاتح",
|
||||||
"ControllerSettingsConfigureGeneral": "ضبط",
|
"ControllerSettingsConfigureGeneral": "ضبط",
|
||||||
@@ -430,7 +438,7 @@
|
|||||||
"DialogMessageFindSaveErrorMessage": "حدث خطأ أثناء البحث عن بيانات الحفظ المحددة: {0}",
|
"DialogMessageFindSaveErrorMessage": "حدث خطأ أثناء البحث عن بيانات الحفظ المحددة: {0}",
|
||||||
"FolderDialogExtractTitle": "اختر المجلد الذي تريد الاستخراج إليه",
|
"FolderDialogExtractTitle": "اختر المجلد الذي تريد الاستخراج إليه",
|
||||||
"DialogNcaExtractionMessage": "استخراج قسم {0} من {1}...",
|
"DialogNcaExtractionMessage": "استخراج قسم {0} من {1}...",
|
||||||
"DialogNcaExtractionTitle": "ريوجينكس - مستخرج قسم NCA",
|
"DialogNcaExtractionTitle": "مستخرج قسم NCA",
|
||||||
"DialogNcaExtractionMainNcaNotFoundErrorMessage": "فشل الاستخراج. لم يكن NCA الرئيسي موجودا في الملف المحدد.",
|
"DialogNcaExtractionMainNcaNotFoundErrorMessage": "فشل الاستخراج. لم يكن NCA الرئيسي موجودا في الملف المحدد.",
|
||||||
"DialogNcaExtractionCheckLogErrorMessage": "فشل الاستخراج. اقرأ ملف التسجيل لمزيد من المعلومات.",
|
"DialogNcaExtractionCheckLogErrorMessage": "فشل الاستخراج. اقرأ ملف التسجيل لمزيد من المعلومات.",
|
||||||
"DialogNcaExtractionSuccessMessage": "تم الاستخراج بنجاح.",
|
"DialogNcaExtractionSuccessMessage": "تم الاستخراج بنجاح.",
|
||||||
@@ -560,6 +568,9 @@
|
|||||||
"AddGameDirBoxTooltip": "أدخل مجلد اللعبة لإضافته إلى القائمة",
|
"AddGameDirBoxTooltip": "أدخل مجلد اللعبة لإضافته إلى القائمة",
|
||||||
"AddGameDirTooltip": "إضافة مجلد اللعبة إلى القائمة",
|
"AddGameDirTooltip": "إضافة مجلد اللعبة إلى القائمة",
|
||||||
"RemoveGameDirTooltip": "إزالة مجلد اللعبة المحدد",
|
"RemoveGameDirTooltip": "إزالة مجلد اللعبة المحدد",
|
||||||
|
"AddAutoloadDirBoxTooltip": "Enter an autoload directory to add to the list",
|
||||||
|
"AddAutoloadDirTooltip": "Add an autoload directory to the list",
|
||||||
|
"RemoveAutoloadDirTooltip": "Remove selected autoload directory",
|
||||||
"CustomThemeCheckTooltip": "استخدم سمة أفالونيا المخصصة لواجهة المستخدم الرسومية لتغيير مظهر قوائم المحاكي",
|
"CustomThemeCheckTooltip": "استخدم سمة أفالونيا المخصصة لواجهة المستخدم الرسومية لتغيير مظهر قوائم المحاكي",
|
||||||
"CustomThemePathTooltip": "مسار سمة واجهة المستخدم المخصصة",
|
"CustomThemePathTooltip": "مسار سمة واجهة المستخدم المخصصة",
|
||||||
"CustomThemeBrowseTooltip": "تصفح للحصول على سمة واجهة المستخدم المخصصة",
|
"CustomThemeBrowseTooltip": "تصفح للحصول على سمة واجهة المستخدم المخصصة",
|
||||||
@@ -605,6 +616,8 @@
|
|||||||
"DebugLogTooltip": "طباعة رسائل سجل التصحيح في وحدة التحكم.\n\nاستخدم هذا فقط إذا طلب منك أحد الموظفين تحديدًا ذلك، لأنه سيجعل من الصعب قراءة السجلات وسيؤدي إلى تدهور أداء المحاكي.",
|
"DebugLogTooltip": "طباعة رسائل سجل التصحيح في وحدة التحكم.\n\nاستخدم هذا فقط إذا طلب منك أحد الموظفين تحديدًا ذلك، لأنه سيجعل من الصعب قراءة السجلات وسيؤدي إلى تدهور أداء المحاكي.",
|
||||||
"LoadApplicationFileTooltip": "افتح مستكشف الملفات لاختيار ملف متوافق مع سويتش لتحميله",
|
"LoadApplicationFileTooltip": "افتح مستكشف الملفات لاختيار ملف متوافق مع سويتش لتحميله",
|
||||||
"LoadApplicationFolderTooltip": "افتح مستكشف الملفات لاختيار تطبيق متوافق مع سويتش للتحميل",
|
"LoadApplicationFolderTooltip": "افتح مستكشف الملفات لاختيار تطبيق متوافق مع سويتش للتحميل",
|
||||||
|
"LoadDlcFromFolderTooltip": "Open a file explorer to choose one or more folders to bulk load DLC from",
|
||||||
|
"LoadTitleUpdatesFromFolderTooltip": "Open a file explorer to choose one or more folders to bulk load title updates from",
|
||||||
"OpenRyujinxFolderTooltip": "فتح مجلد نظام ملفات ريوجينكس",
|
"OpenRyujinxFolderTooltip": "فتح مجلد نظام ملفات ريوجينكس",
|
||||||
"OpenRyujinxLogsTooltip": "يفتح المجلد الذي تتم كتابة السجلات إليه",
|
"OpenRyujinxLogsTooltip": "يفتح المجلد الذي تتم كتابة السجلات إليه",
|
||||||
"ExitTooltip": "الخروج من ريوجينكس",
|
"ExitTooltip": "الخروج من ريوجينكس",
|
||||||
@@ -656,6 +669,8 @@
|
|||||||
"OpenSetupGuideMessage": "فتح دليل الإعداد",
|
"OpenSetupGuideMessage": "فتح دليل الإعداد",
|
||||||
"NoUpdate": "لا يوجد تحديث",
|
"NoUpdate": "لا يوجد تحديث",
|
||||||
"TitleUpdateVersionLabel": "الإصدار: {0}",
|
"TitleUpdateVersionLabel": "الإصدار: {0}",
|
||||||
|
"TitleBundledUpdateVersionLabel": "Bundled: Version {0}",
|
||||||
|
"TitleBundledDlcLabel": "Bundled:",
|
||||||
"RyujinxInfo": "ريوجينكس - معلومات",
|
"RyujinxInfo": "ريوجينكس - معلومات",
|
||||||
"RyujinxConfirm": "ريوجينكس - تأكيد",
|
"RyujinxConfirm": "ريوجينكس - تأكيد",
|
||||||
"FileDialogAllTypes": "كل الأنواع",
|
"FileDialogAllTypes": "كل الأنواع",
|
||||||
@@ -713,9 +728,17 @@
|
|||||||
"DlcWindowTitle": "إدارة المحتوى القابل للتنزيل لـ {0} ({1})",
|
"DlcWindowTitle": "إدارة المحتوى القابل للتنزيل لـ {0} ({1})",
|
||||||
"ModWindowTitle": "إدارة التعديلات لـ {0} ({1})",
|
"ModWindowTitle": "إدارة التعديلات لـ {0} ({1})",
|
||||||
"UpdateWindowTitle": "مدير تحديث العنوان",
|
"UpdateWindowTitle": "مدير تحديث العنوان",
|
||||||
|
"UpdateWindowUpdateAddedMessage": "{0} new update(s) added",
|
||||||
|
"UpdateWindowBundledContentNotice": "Bundled updates cannot be removed, only disabled.",
|
||||||
"CheatWindowHeading": "الغش متوفر لـ {0} [{1}]",
|
"CheatWindowHeading": "الغش متوفر لـ {0} [{1}]",
|
||||||
"BuildId": "معرف البناء:",
|
"BuildId": "معرف البناء:",
|
||||||
|
"DlcWindowBundledContentNotice": "Bundled DLC cannot be removed, only disabled.",
|
||||||
"DlcWindowHeading": "المحتويات القابلة للتنزيل {0}",
|
"DlcWindowHeading": "المحتويات القابلة للتنزيل {0}",
|
||||||
|
"DlcWindowDlcAddedMessage": "{0} new downloadable content(s) added",
|
||||||
|
"AutoloadDlcAddedMessage": "{0} new downloadable content(s) added",
|
||||||
|
"AutoloadDlcRemovedMessage": "{0} missing downloadable content(s) removed",
|
||||||
|
"AutoloadUpdateAddedMessage": "{0} new update(s) added",
|
||||||
|
"AutoloadUpdateRemovedMessage": "{0} missing update(s) removed",
|
||||||
"ModWindowHeading": "{0} تعديل",
|
"ModWindowHeading": "{0} تعديل",
|
||||||
"UserProfilesEditProfile": "تعديل المحدد",
|
"UserProfilesEditProfile": "تعديل المحدد",
|
||||||
"Cancel": "إلغاء",
|
"Cancel": "إلغاء",
|
||||||
@@ -766,6 +789,7 @@
|
|||||||
"GraphicsScalingFilterBilinear": "Bilinear",
|
"GraphicsScalingFilterBilinear": "Bilinear",
|
||||||
"GraphicsScalingFilterNearest": "Nearest",
|
"GraphicsScalingFilterNearest": "Nearest",
|
||||||
"GraphicsScalingFilterFsr": "FSR",
|
"GraphicsScalingFilterFsr": "FSR",
|
||||||
|
"GraphicsScalingFilterArea": "Area",
|
||||||
"GraphicsScalingFilterLevelLabel": "المستوى",
|
"GraphicsScalingFilterLevelLabel": "المستوى",
|
||||||
"GraphicsScalingFilterLevelTooltip": "اضبط مستوى وضوح FSR 1.0. الأعلى هو أكثر وضوحا.",
|
"GraphicsScalingFilterLevelTooltip": "اضبط مستوى وضوح FSR 1.0. الأعلى هو أكثر وضوحا.",
|
||||||
"SmaaLow": "SMAA منخفض",
|
"SmaaLow": "SMAA منخفض",
|
||||||
|
|||||||
@@ -10,7 +10,10 @@
|
|||||||
"SettingsTabSystemUseHypervisor": "Hypervisor verwenden",
|
"SettingsTabSystemUseHypervisor": "Hypervisor verwenden",
|
||||||
"MenuBarFile": "_Datei",
|
"MenuBarFile": "_Datei",
|
||||||
"MenuBarFileOpenFromFile": "Datei _öffnen",
|
"MenuBarFileOpenFromFile": "Datei _öffnen",
|
||||||
|
"MenuBarFileOpenFromFileError": "No applications found in selected file.",
|
||||||
"MenuBarFileOpenUnpacked": "_Entpacktes Spiel öffnen",
|
"MenuBarFileOpenUnpacked": "_Entpacktes Spiel öffnen",
|
||||||
|
"MenuBarFileLoadDlcFromFolder": "Load DLC From Folder",
|
||||||
|
"MenuBarFileLoadTitleUpdatesFromFolder": "Load Title Updates From Folder",
|
||||||
"MenuBarFileOpenEmuFolder": "Ryujinx-Ordner öffnen",
|
"MenuBarFileOpenEmuFolder": "Ryujinx-Ordner öffnen",
|
||||||
"MenuBarFileOpenLogsFolder": "Logs-Ordner öffnen",
|
"MenuBarFileOpenLogsFolder": "Logs-Ordner öffnen",
|
||||||
"MenuBarFileExit": "_Beenden",
|
"MenuBarFileExit": "_Beenden",
|
||||||
@@ -97,11 +100,14 @@
|
|||||||
"SettingsTabGeneralCheckUpdatesOnLaunch": "Beim Start nach Updates suchen",
|
"SettingsTabGeneralCheckUpdatesOnLaunch": "Beim Start nach Updates suchen",
|
||||||
"SettingsTabGeneralShowConfirmExitDialog": "Zeige den \"Beenden bestätigen\"-Dialog",
|
"SettingsTabGeneralShowConfirmExitDialog": "Zeige den \"Beenden bestätigen\"-Dialog",
|
||||||
"SettingsTabGeneralRememberWindowState": "Fenstergröße/-position merken",
|
"SettingsTabGeneralRememberWindowState": "Fenstergröße/-position merken",
|
||||||
|
"SettingsTabGeneralShowTitleBar": "Show Title Bar (Requires restart)",
|
||||||
"SettingsTabGeneralHideCursor": "Mauszeiger ausblenden",
|
"SettingsTabGeneralHideCursor": "Mauszeiger ausblenden",
|
||||||
"SettingsTabGeneralHideCursorNever": "Niemals",
|
"SettingsTabGeneralHideCursorNever": "Niemals",
|
||||||
"SettingsTabGeneralHideCursorOnIdle": "Mauszeiger bei Inaktivität ausblenden",
|
"SettingsTabGeneralHideCursorOnIdle": "Mauszeiger bei Inaktivität ausblenden",
|
||||||
"SettingsTabGeneralHideCursorAlways": "Immer",
|
"SettingsTabGeneralHideCursorAlways": "Immer",
|
||||||
"SettingsTabGeneralGameDirectories": "Spielverzeichnisse",
|
"SettingsTabGeneralGameDirectories": "Spielverzeichnisse",
|
||||||
|
"SettingsTabGeneralAutoloadDirectories": "Autoload DLC/Updates Directories",
|
||||||
|
"SettingsTabGeneralAutoloadNote": "DLC and Updates which refer to missing files will be unloaded automatically",
|
||||||
"SettingsTabGeneralAdd": "Hinzufügen",
|
"SettingsTabGeneralAdd": "Hinzufügen",
|
||||||
"SettingsTabGeneralRemove": "Entfernen",
|
"SettingsTabGeneralRemove": "Entfernen",
|
||||||
"SettingsTabSystem": "System",
|
"SettingsTabSystem": "System",
|
||||||
@@ -401,6 +407,7 @@
|
|||||||
"AvatarSetBackgroundColor": "Hintergrundfarbe auswählen",
|
"AvatarSetBackgroundColor": "Hintergrundfarbe auswählen",
|
||||||
"AvatarClose": "Schließen",
|
"AvatarClose": "Schließen",
|
||||||
"ControllerSettingsLoadProfileToolTip": "Lädt ein Profil",
|
"ControllerSettingsLoadProfileToolTip": "Lädt ein Profil",
|
||||||
|
"ControllerSettingsViewProfileToolTip": "View Profile",
|
||||||
"ControllerSettingsAddProfileToolTip": "Fügt ein Profil hinzu",
|
"ControllerSettingsAddProfileToolTip": "Fügt ein Profil hinzu",
|
||||||
"ControllerSettingsRemoveProfileToolTip": "Entfernt ein Profil",
|
"ControllerSettingsRemoveProfileToolTip": "Entfernt ein Profil",
|
||||||
"ControllerSettingsSaveProfileToolTip": "Speichert ein Profil",
|
"ControllerSettingsSaveProfileToolTip": "Speichert ein Profil",
|
||||||
@@ -410,6 +417,7 @@
|
|||||||
"GameListContextMenuToggleFavorite": "Als Favoriten hinzufügen/entfernen",
|
"GameListContextMenuToggleFavorite": "Als Favoriten hinzufügen/entfernen",
|
||||||
"GameListContextMenuToggleFavoriteToolTip": "Aktiviert den Favoriten-Status des Spiels",
|
"GameListContextMenuToggleFavoriteToolTip": "Aktiviert den Favoriten-Status des Spiels",
|
||||||
"SettingsTabGeneralTheme": "Design:",
|
"SettingsTabGeneralTheme": "Design:",
|
||||||
|
"SettingsTabGeneralThemeAuto": "Auto",
|
||||||
"SettingsTabGeneralThemeDark": "Dunkel",
|
"SettingsTabGeneralThemeDark": "Dunkel",
|
||||||
"SettingsTabGeneralThemeLight": "Hell",
|
"SettingsTabGeneralThemeLight": "Hell",
|
||||||
"ControllerSettingsConfigureGeneral": "Konfigurieren",
|
"ControllerSettingsConfigureGeneral": "Konfigurieren",
|
||||||
@@ -430,7 +438,7 @@
|
|||||||
"DialogMessageFindSaveErrorMessage": "Es ist ein Fehler beim Suchen der angegebenen Speicherdaten aufgetreten: {0}",
|
"DialogMessageFindSaveErrorMessage": "Es ist ein Fehler beim Suchen der angegebenen Speicherdaten aufgetreten: {0}",
|
||||||
"FolderDialogExtractTitle": "Wähle den Ordner, in welchen die Dateien entpackt werden sollen",
|
"FolderDialogExtractTitle": "Wähle den Ordner, in welchen die Dateien entpackt werden sollen",
|
||||||
"DialogNcaExtractionMessage": "Extrahiert {0} abschnitt von {1}...",
|
"DialogNcaExtractionMessage": "Extrahiert {0} abschnitt von {1}...",
|
||||||
"DialogNcaExtractionTitle": "Ryujinx - NCA-Abschnitt-Extraktor",
|
"DialogNcaExtractionTitle": "NCA-Abschnitt-Extraktor",
|
||||||
"DialogNcaExtractionMainNcaNotFoundErrorMessage": "Extraktion fehlgeschlagen. Der Hauptheader der NCA war in der ausgewählten Datei nicht vorhanden.",
|
"DialogNcaExtractionMainNcaNotFoundErrorMessage": "Extraktion fehlgeschlagen. Der Hauptheader der NCA war in der ausgewählten Datei nicht vorhanden.",
|
||||||
"DialogNcaExtractionCheckLogErrorMessage": "Extraktion fehlgeschlagen. Überprüfe die Logs für weitere Informationen.",
|
"DialogNcaExtractionCheckLogErrorMessage": "Extraktion fehlgeschlagen. Überprüfe die Logs für weitere Informationen.",
|
||||||
"DialogNcaExtractionSuccessMessage": "Extraktion erfolgreich abgeschlossen.",
|
"DialogNcaExtractionSuccessMessage": "Extraktion erfolgreich abgeschlossen.",
|
||||||
@@ -560,6 +568,9 @@
|
|||||||
"AddGameDirBoxTooltip": "Gibt das Spielverzeichnis an, das der Liste hinzuzufügt wird",
|
"AddGameDirBoxTooltip": "Gibt das Spielverzeichnis an, das der Liste hinzuzufügt wird",
|
||||||
"AddGameDirTooltip": "Fügt ein neues Spielverzeichnis hinzu",
|
"AddGameDirTooltip": "Fügt ein neues Spielverzeichnis hinzu",
|
||||||
"RemoveGameDirTooltip": "Entfernt das ausgewähltes Spielverzeichnis",
|
"RemoveGameDirTooltip": "Entfernt das ausgewähltes Spielverzeichnis",
|
||||||
|
"AddAutoloadDirBoxTooltip": "Enter an autoload directory to add to the list",
|
||||||
|
"AddAutoloadDirTooltip": "Add an autoload directory to the list",
|
||||||
|
"RemoveAutoloadDirTooltip": "Remove selected autoload directory",
|
||||||
"CustomThemeCheckTooltip": "Verwende ein eigenes Design für die Emulator-Benutzeroberfläche",
|
"CustomThemeCheckTooltip": "Verwende ein eigenes Design für die Emulator-Benutzeroberfläche",
|
||||||
"CustomThemePathTooltip": "Gibt den Pfad zum Design für die Emulator-Benutzeroberfläche an",
|
"CustomThemePathTooltip": "Gibt den Pfad zum Design für die Emulator-Benutzeroberfläche an",
|
||||||
"CustomThemeBrowseTooltip": "Ermöglicht die Suche nach einem benutzerdefinierten Design für die Emulator-Benutzeroberfläche",
|
"CustomThemeBrowseTooltip": "Ermöglicht die Suche nach einem benutzerdefinierten Design für die Emulator-Benutzeroberfläche",
|
||||||
@@ -605,6 +616,8 @@
|
|||||||
"DebugLogTooltip": "Ausgabe von Debug-Logs in der Konsole.\n\nVerwende diese Option nur auf ausdrückliche Anweisung von Ryujinx Entwicklern, da sie das Lesen der Protokolle erschwert und die Leistung des Emulators verschlechtert.",
|
"DebugLogTooltip": "Ausgabe von Debug-Logs in der Konsole.\n\nVerwende diese Option nur auf ausdrückliche Anweisung von Ryujinx Entwicklern, da sie das Lesen der Protokolle erschwert und die Leistung des Emulators verschlechtert.",
|
||||||
"LoadApplicationFileTooltip": "Öffnet die Dateiauswahl um Datei zu laden, welche mit der Switch kompatibel ist",
|
"LoadApplicationFileTooltip": "Öffnet die Dateiauswahl um Datei zu laden, welche mit der Switch kompatibel ist",
|
||||||
"LoadApplicationFolderTooltip": "Öffnet die Dateiauswahl um ein Spiel zu laden, welches mit der Switch kompatibel ist",
|
"LoadApplicationFolderTooltip": "Öffnet die Dateiauswahl um ein Spiel zu laden, welches mit der Switch kompatibel ist",
|
||||||
|
"LoadDlcFromFolderTooltip": "Open a file explorer to choose one or more folders to bulk load DLC from",
|
||||||
|
"LoadTitleUpdatesFromFolderTooltip": "Open a file explorer to choose one or more folders to bulk load title updates from",
|
||||||
"OpenRyujinxFolderTooltip": "Öffnet den Ordner, der das Ryujinx Dateisystem enthält",
|
"OpenRyujinxFolderTooltip": "Öffnet den Ordner, der das Ryujinx Dateisystem enthält",
|
||||||
"OpenRyujinxLogsTooltip": "Öffnet den Ordner, in welchem die Logs gespeichert werden",
|
"OpenRyujinxLogsTooltip": "Öffnet den Ordner, in welchem die Logs gespeichert werden",
|
||||||
"ExitTooltip": "Beendet Ryujinx",
|
"ExitTooltip": "Beendet Ryujinx",
|
||||||
@@ -656,6 +669,8 @@
|
|||||||
"OpenSetupGuideMessage": "Öffne den 'Setup Guide'",
|
"OpenSetupGuideMessage": "Öffne den 'Setup Guide'",
|
||||||
"NoUpdate": "Kein Update",
|
"NoUpdate": "Kein Update",
|
||||||
"TitleUpdateVersionLabel": "Version {0} - {1}",
|
"TitleUpdateVersionLabel": "Version {0} - {1}",
|
||||||
|
"TitleBundledUpdateVersionLabel": "Bundled: Version {0}",
|
||||||
|
"TitleBundledDlcLabel": "Bundled:",
|
||||||
"RyujinxInfo": "Ryujinx - Info",
|
"RyujinxInfo": "Ryujinx - Info",
|
||||||
"RyujinxConfirm": "Ryujinx - Bestätigung",
|
"RyujinxConfirm": "Ryujinx - Bestätigung",
|
||||||
"FileDialogAllTypes": "Alle Typen",
|
"FileDialogAllTypes": "Alle Typen",
|
||||||
@@ -713,9 +728,17 @@
|
|||||||
"DlcWindowTitle": "Spiel-DLC verwalten",
|
"DlcWindowTitle": "Spiel-DLC verwalten",
|
||||||
"ModWindowTitle": "Manage Mods for {0} ({1})",
|
"ModWindowTitle": "Manage Mods for {0} ({1})",
|
||||||
"UpdateWindowTitle": "Spiel-Updates verwalten",
|
"UpdateWindowTitle": "Spiel-Updates verwalten",
|
||||||
|
"UpdateWindowUpdateAddedMessage": "{0} new update(s) added",
|
||||||
|
"UpdateWindowBundledContentNotice": "Bundled updates cannot be removed, only disabled.",
|
||||||
"CheatWindowHeading": "Cheats verfügbar für {0} [{1}]",
|
"CheatWindowHeading": "Cheats verfügbar für {0} [{1}]",
|
||||||
|
"DlcWindowBundledContentNotice": "Bundled DLC cannot be removed, only disabled.",
|
||||||
"BuildId": "BuildId:",
|
"BuildId": "BuildId:",
|
||||||
"DlcWindowHeading": "DLC verfügbar für {0} [{1}]",
|
"DlcWindowHeading": "DLC verfügbar für {0} [{1}]",
|
||||||
|
"DlcWindowDlcAddedMessage": "{0} new downloadable content(s) added",
|
||||||
|
"AutoloadDlcAddedMessage": "{0} new downloadable content(s) added",
|
||||||
|
"AutoloadDlcRemovedMessage": "{0} missing downloadable content(s) removed",
|
||||||
|
"AutoloadUpdateAddedMessage": "{0} new update(s) added",
|
||||||
|
"AutoloadUpdateRemovedMessage": "{0} missing update(s) removed",
|
||||||
"ModWindowHeading": "{0} Mod(s)",
|
"ModWindowHeading": "{0} Mod(s)",
|
||||||
"UserProfilesEditProfile": "Profil bearbeiten",
|
"UserProfilesEditProfile": "Profil bearbeiten",
|
||||||
"Cancel": "Abbrechen",
|
"Cancel": "Abbrechen",
|
||||||
@@ -766,6 +789,7 @@
|
|||||||
"GraphicsScalingFilterBilinear": "Bilinear",
|
"GraphicsScalingFilterBilinear": "Bilinear",
|
||||||
"GraphicsScalingFilterNearest": "Nächstes",
|
"GraphicsScalingFilterNearest": "Nächstes",
|
||||||
"GraphicsScalingFilterFsr": "FSR",
|
"GraphicsScalingFilterFsr": "FSR",
|
||||||
|
"GraphicsScalingFilterArea": "Area",
|
||||||
"GraphicsScalingFilterLevelLabel": "Stufe",
|
"GraphicsScalingFilterLevelLabel": "Stufe",
|
||||||
"GraphicsScalingFilterLevelTooltip": "FSR 1.0 Schärfelevel festlegen. Höher ist schärfer.",
|
"GraphicsScalingFilterLevelTooltip": "FSR 1.0 Schärfelevel festlegen. Höher ist schärfer.",
|
||||||
"SmaaLow": "SMAA Niedrig",
|
"SmaaLow": "SMAA Niedrig",
|
||||||
|
|||||||
@@ -10,7 +10,10 @@
|
|||||||
"SettingsTabSystemUseHypervisor": "Χρήση Hypervisor",
|
"SettingsTabSystemUseHypervisor": "Χρήση Hypervisor",
|
||||||
"MenuBarFile": "_Αρχείο",
|
"MenuBarFile": "_Αρχείο",
|
||||||
"MenuBarFileOpenFromFile": "_Φόρτωση Αρχείου Εφαρμογής",
|
"MenuBarFileOpenFromFile": "_Φόρτωση Αρχείου Εφαρμογής",
|
||||||
|
"MenuBarFileOpenFromFileError": "No applications found in selected file.",
|
||||||
"MenuBarFileOpenUnpacked": "Φόρτωση Απακετάριστου _Παιχνιδιού",
|
"MenuBarFileOpenUnpacked": "Φόρτωση Απακετάριστου _Παιχνιδιού",
|
||||||
|
"MenuBarFileLoadDlcFromFolder": "Load DLC From Folder",
|
||||||
|
"MenuBarFileLoadTitleUpdatesFromFolder": "Load Title Updates From Folder",
|
||||||
"MenuBarFileOpenEmuFolder": "Άνοιγμα Φακέλου Ryujinx",
|
"MenuBarFileOpenEmuFolder": "Άνοιγμα Φακέλου Ryujinx",
|
||||||
"MenuBarFileOpenLogsFolder": "Άνοιγμα Φακέλου Καταγραφής",
|
"MenuBarFileOpenLogsFolder": "Άνοιγμα Φακέλου Καταγραφής",
|
||||||
"MenuBarFileExit": "_Έξοδος",
|
"MenuBarFileExit": "_Έξοδος",
|
||||||
@@ -97,11 +100,14 @@
|
|||||||
"SettingsTabGeneralCheckUpdatesOnLaunch": "Έλεγχος για Ενημερώσεις στην Εκκίνηση",
|
"SettingsTabGeneralCheckUpdatesOnLaunch": "Έλεγχος για Ενημερώσεις στην Εκκίνηση",
|
||||||
"SettingsTabGeneralShowConfirmExitDialog": "Εμφάνιση διαλόγου \"Επιβεβαίωση Εξόδου\".",
|
"SettingsTabGeneralShowConfirmExitDialog": "Εμφάνιση διαλόγου \"Επιβεβαίωση Εξόδου\".",
|
||||||
"SettingsTabGeneralRememberWindowState": "Remember Window Size/Position",
|
"SettingsTabGeneralRememberWindowState": "Remember Window Size/Position",
|
||||||
|
"SettingsTabGeneralShowTitleBar": "Show Title Bar (Requires restart)",
|
||||||
"SettingsTabGeneralHideCursor": "Απόκρυψη Κέρσορα:",
|
"SettingsTabGeneralHideCursor": "Απόκρυψη Κέρσορα:",
|
||||||
"SettingsTabGeneralHideCursorNever": "Ποτέ",
|
"SettingsTabGeneralHideCursorNever": "Ποτέ",
|
||||||
"SettingsTabGeneralHideCursorOnIdle": "Απόκρυψη Δρομέα στην Αδράνεια",
|
"SettingsTabGeneralHideCursorOnIdle": "Απόκρυψη Δρομέα στην Αδράνεια",
|
||||||
"SettingsTabGeneralHideCursorAlways": "Πάντα",
|
"SettingsTabGeneralHideCursorAlways": "Πάντα",
|
||||||
"SettingsTabGeneralGameDirectories": "Τοποθεσίες παιχνιδιών",
|
"SettingsTabGeneralGameDirectories": "Τοποθεσίες παιχνιδιών",
|
||||||
|
"SettingsTabGeneralAutoloadDirectories": "Autoload DLC/Updates Directories",
|
||||||
|
"SettingsTabGeneralAutoloadNote": "DLC and Updates which refer to missing files will be unloaded automatically",
|
||||||
"SettingsTabGeneralAdd": "Προσθήκη",
|
"SettingsTabGeneralAdd": "Προσθήκη",
|
||||||
"SettingsTabGeneralRemove": "Αφαίρεση",
|
"SettingsTabGeneralRemove": "Αφαίρεση",
|
||||||
"SettingsTabSystem": "Σύστημα",
|
"SettingsTabSystem": "Σύστημα",
|
||||||
@@ -401,6 +407,7 @@
|
|||||||
"AvatarSetBackgroundColor": "Ορισμός Χρώματος Φόντου",
|
"AvatarSetBackgroundColor": "Ορισμός Χρώματος Φόντου",
|
||||||
"AvatarClose": "Κλείσιμο",
|
"AvatarClose": "Κλείσιμο",
|
||||||
"ControllerSettingsLoadProfileToolTip": "Φόρτωση Προφίλ",
|
"ControllerSettingsLoadProfileToolTip": "Φόρτωση Προφίλ",
|
||||||
|
"ControllerSettingsViewProfileToolTip": "View Profile",
|
||||||
"ControllerSettingsAddProfileToolTip": "Προσθήκη Προφίλ",
|
"ControllerSettingsAddProfileToolTip": "Προσθήκη Προφίλ",
|
||||||
"ControllerSettingsRemoveProfileToolTip": "Κατάργηση Προφίλ",
|
"ControllerSettingsRemoveProfileToolTip": "Κατάργηση Προφίλ",
|
||||||
"ControllerSettingsSaveProfileToolTip": "Αποθήκευση Προφίλ",
|
"ControllerSettingsSaveProfileToolTip": "Αποθήκευση Προφίλ",
|
||||||
@@ -410,6 +417,7 @@
|
|||||||
"GameListContextMenuToggleFavorite": "Εναλλαγή Αγαπημένου",
|
"GameListContextMenuToggleFavorite": "Εναλλαγή Αγαπημένου",
|
||||||
"GameListContextMenuToggleFavoriteToolTip": "Εναλλαγή της Κατάστασης Αγαπημένο του Παιχνιδιού",
|
"GameListContextMenuToggleFavoriteToolTip": "Εναλλαγή της Κατάστασης Αγαπημένο του Παιχνιδιού",
|
||||||
"SettingsTabGeneralTheme": "Theme:",
|
"SettingsTabGeneralTheme": "Theme:",
|
||||||
|
"SettingsTabGeneralThemeAuto": "Auto",
|
||||||
"SettingsTabGeneralThemeDark": "Dark",
|
"SettingsTabGeneralThemeDark": "Dark",
|
||||||
"SettingsTabGeneralThemeLight": "Light",
|
"SettingsTabGeneralThemeLight": "Light",
|
||||||
"ControllerSettingsConfigureGeneral": "Παραμέτρων",
|
"ControllerSettingsConfigureGeneral": "Παραμέτρων",
|
||||||
@@ -430,7 +438,7 @@
|
|||||||
"DialogMessageFindSaveErrorMessage": "Σφάλμα κατά την εύρεση των αποθηκευμένων δεδομένων: {0}",
|
"DialogMessageFindSaveErrorMessage": "Σφάλμα κατά την εύρεση των αποθηκευμένων δεδομένων: {0}",
|
||||||
"FolderDialogExtractTitle": "Επιλέξτε τον φάκελο στον οποίο θέλετε να εξαγάγετε",
|
"FolderDialogExtractTitle": "Επιλέξτε τον φάκελο στον οποίο θέλετε να εξαγάγετε",
|
||||||
"DialogNcaExtractionMessage": "Εξαγωγή ενότητας {0} από {1}...",
|
"DialogNcaExtractionMessage": "Εξαγωγή ενότητας {0} από {1}...",
|
||||||
"DialogNcaExtractionTitle": "Ryujinx - NCA Εξαγωγέας Τμημάτων",
|
"DialogNcaExtractionTitle": "NCA Εξαγωγέας Τμημάτων",
|
||||||
"DialogNcaExtractionMainNcaNotFoundErrorMessage": "Αποτυχία εξαγωγής. Η κύρια NCA δεν υπήρχε στο επιλεγμένο αρχείο.",
|
"DialogNcaExtractionMainNcaNotFoundErrorMessage": "Αποτυχία εξαγωγής. Η κύρια NCA δεν υπήρχε στο επιλεγμένο αρχείο.",
|
||||||
"DialogNcaExtractionCheckLogErrorMessage": "Αποτυχία εξαγωγής. Διαβάστε το αρχείο καταγραφής για περισσότερες πληροφορίες.",
|
"DialogNcaExtractionCheckLogErrorMessage": "Αποτυχία εξαγωγής. Διαβάστε το αρχείο καταγραφής για περισσότερες πληροφορίες.",
|
||||||
"DialogNcaExtractionSuccessMessage": "Η εξαγωγή ολοκληρώθηκε με επιτυχία.",
|
"DialogNcaExtractionSuccessMessage": "Η εξαγωγή ολοκληρώθηκε με επιτυχία.",
|
||||||
@@ -560,6 +568,9 @@
|
|||||||
"AddGameDirBoxTooltip": "Εισαγάγετε μία τοποθεσία παιχνιδιών για προσθήκη στη λίστα",
|
"AddGameDirBoxTooltip": "Εισαγάγετε μία τοποθεσία παιχνιδιών για προσθήκη στη λίστα",
|
||||||
"AddGameDirTooltip": "Προσθέστε μία τοποθεσία παιχνιδιών στη λίστα",
|
"AddGameDirTooltip": "Προσθέστε μία τοποθεσία παιχνιδιών στη λίστα",
|
||||||
"RemoveGameDirTooltip": "Αφαιρέστε την επιλεγμένη τοποθεσία παιχνιδιών",
|
"RemoveGameDirTooltip": "Αφαιρέστε την επιλεγμένη τοποθεσία παιχνιδιών",
|
||||||
|
"AddAutoloadDirBoxTooltip": "Enter an autoload directory to add to the list",
|
||||||
|
"AddAutoloadDirTooltip": "Add an autoload directory to the list",
|
||||||
|
"RemoveAutoloadDirTooltip": "Remove selected autoload directory",
|
||||||
"CustomThemeCheckTooltip": "Ενεργοποίηση ή απενεργοποίηση προσαρμοσμένων θεμάτων στο GUI",
|
"CustomThemeCheckTooltip": "Ενεργοποίηση ή απενεργοποίηση προσαρμοσμένων θεμάτων στο GUI",
|
||||||
"CustomThemePathTooltip": "Διαδρομή προς το προσαρμοσμένο θέμα GUI",
|
"CustomThemePathTooltip": "Διαδρομή προς το προσαρμοσμένο θέμα GUI",
|
||||||
"CustomThemeBrowseTooltip": "Αναζητήστε ένα προσαρμοσμένο θέμα GUI",
|
"CustomThemeBrowseTooltip": "Αναζητήστε ένα προσαρμοσμένο θέμα GUI",
|
||||||
@@ -605,6 +616,8 @@
|
|||||||
"DebugLogTooltip": "Ενεργοποιεί την εκτύπωση μηνυμάτων αρχείου καταγραφής εντοπισμού σφαλμάτων",
|
"DebugLogTooltip": "Ενεργοποιεί την εκτύπωση μηνυμάτων αρχείου καταγραφής εντοπισμού σφαλμάτων",
|
||||||
"LoadApplicationFileTooltip": "Ανοίξτε έναν επιλογέα αρχείων για να επιλέξετε ένα αρχείο συμβατό με το Switch για φόρτωση",
|
"LoadApplicationFileTooltip": "Ανοίξτε έναν επιλογέα αρχείων για να επιλέξετε ένα αρχείο συμβατό με το Switch για φόρτωση",
|
||||||
"LoadApplicationFolderTooltip": "Ανοίξτε έναν επιλογέα αρχείων για να επιλέξετε μία μη συσκευασμένη εφαρμογή, συμβατή με το Switch για φόρτωση",
|
"LoadApplicationFolderTooltip": "Ανοίξτε έναν επιλογέα αρχείων για να επιλέξετε μία μη συσκευασμένη εφαρμογή, συμβατή με το Switch για φόρτωση",
|
||||||
|
"LoadDlcFromFolderTooltip": "Open a file explorer to choose one or more folders to bulk load DLC from",
|
||||||
|
"LoadTitleUpdatesFromFolderTooltip": "Open a file explorer to choose one or more folders to bulk load title updates from",
|
||||||
"OpenRyujinxFolderTooltip": "Ανοίξτε το φάκελο συστήματος αρχείων Ryujinx",
|
"OpenRyujinxFolderTooltip": "Ανοίξτε το φάκελο συστήματος αρχείων Ryujinx",
|
||||||
"OpenRyujinxLogsTooltip": "Ανοίξτε το φάκελο στον οποίο διατηρούνται τα αρχεία καταγραφής",
|
"OpenRyujinxLogsTooltip": "Ανοίξτε το φάκελο στον οποίο διατηρούνται τα αρχεία καταγραφής",
|
||||||
"ExitTooltip": "Έξοδος από το Ryujinx",
|
"ExitTooltip": "Έξοδος από το Ryujinx",
|
||||||
@@ -656,6 +669,8 @@
|
|||||||
"OpenSetupGuideMessage": "Ανοίξτε τον Οδηγό Εγκατάστασης.",
|
"OpenSetupGuideMessage": "Ανοίξτε τον Οδηγό Εγκατάστασης.",
|
||||||
"NoUpdate": "Καμία Eνημέρωση",
|
"NoUpdate": "Καμία Eνημέρωση",
|
||||||
"TitleUpdateVersionLabel": "Version {0} - {1}",
|
"TitleUpdateVersionLabel": "Version {0} - {1}",
|
||||||
|
"TitleBundledUpdateVersionLabel": "Bundled: Version {0}",
|
||||||
|
"TitleBundledDlcLabel": "Bundled:",
|
||||||
"RyujinxInfo": "Ryujinx - Πληροφορίες",
|
"RyujinxInfo": "Ryujinx - Πληροφορίες",
|
||||||
"RyujinxConfirm": "Ryujinx - Επιβεβαίωση",
|
"RyujinxConfirm": "Ryujinx - Επιβεβαίωση",
|
||||||
"FileDialogAllTypes": "Όλοι οι τύποι",
|
"FileDialogAllTypes": "Όλοι οι τύποι",
|
||||||
@@ -713,9 +728,17 @@
|
|||||||
"DlcWindowTitle": "Downloadable Content Manager",
|
"DlcWindowTitle": "Downloadable Content Manager",
|
||||||
"ModWindowTitle": "Manage Mods for {0} ({1})",
|
"ModWindowTitle": "Manage Mods for {0} ({1})",
|
||||||
"UpdateWindowTitle": "Διαχειριστής Ενημερώσεων Τίτλου",
|
"UpdateWindowTitle": "Διαχειριστής Ενημερώσεων Τίτλου",
|
||||||
|
"UpdateWindowUpdateAddedMessage": "{0} new update(s) added",
|
||||||
|
"UpdateWindowBundledContentNotice": "Bundled updates cannot be removed, only disabled.",
|
||||||
"CheatWindowHeading": "Διαθέσιμα Cheats για {0} [{1}]",
|
"CheatWindowHeading": "Διαθέσιμα Cheats για {0} [{1}]",
|
||||||
"BuildId": "BuildId:",
|
"BuildId": "BuildId:",
|
||||||
|
"DlcWindowBundledContentNotice": "Bundled DLC cannot be removed, only disabled.",
|
||||||
"DlcWindowHeading": "{0} Downloadable Content(s) available for {1} ({2})",
|
"DlcWindowHeading": "{0} Downloadable Content(s) available for {1} ({2})",
|
||||||
|
"DlcWindowDlcAddedMessage": "{0} new downloadable content(s) added",
|
||||||
|
"AutoloadDlcAddedMessage": "{0} new downloadable content(s) added",
|
||||||
|
"AutoloadDlcRemovedMessage": "{0} missing downloadable content(s) removed",
|
||||||
|
"AutoloadUpdateAddedMessage": "{0} new update(s) added",
|
||||||
|
"AutoloadUpdateRemovedMessage": "{0} missing update(s) removed",
|
||||||
"ModWindowHeading": "{0} Mod(s)",
|
"ModWindowHeading": "{0} Mod(s)",
|
||||||
"UserProfilesEditProfile": "Επεξεργασία Επιλεγμένων",
|
"UserProfilesEditProfile": "Επεξεργασία Επιλεγμένων",
|
||||||
"Cancel": "Ακύρωση",
|
"Cancel": "Ακύρωση",
|
||||||
@@ -766,6 +789,7 @@
|
|||||||
"GraphicsScalingFilterBilinear": "Bilinear",
|
"GraphicsScalingFilterBilinear": "Bilinear",
|
||||||
"GraphicsScalingFilterNearest": "Nearest",
|
"GraphicsScalingFilterNearest": "Nearest",
|
||||||
"GraphicsScalingFilterFsr": "FSR",
|
"GraphicsScalingFilterFsr": "FSR",
|
||||||
|
"GraphicsScalingFilterArea": "Area",
|
||||||
"GraphicsScalingFilterLevelLabel": "Επίπεδο",
|
"GraphicsScalingFilterLevelLabel": "Επίπεδο",
|
||||||
"GraphicsScalingFilterLevelTooltip": "Set FSR 1.0 sharpening level. Higher is sharper.",
|
"GraphicsScalingFilterLevelTooltip": "Set FSR 1.0 sharpening level. Higher is sharper.",
|
||||||
"SmaaLow": "Χαμηλό SMAA",
|
"SmaaLow": "Χαμηλό SMAA",
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user