mirror of
https://git.ryujinx.app/ryubing/ryujinx.git
synced 2025-08-01 02:30:08 -06:00
Compare commits
101 Commits
Canary-1.2
...
1.2.80
Author | SHA1 | Date | |
---|---|---|---|
a1c0c70ec2 | |||
290ac405ac | |||
bbd64fd5f0 | |||
09446fd80e | |||
4f014a89cf | |||
6482e566ab | |||
7fcd9b792e | |||
e676fd8b17 | |||
dd16e3cee1 | |||
31e5f74e05 | |||
f2f099bddb | |||
2616dc57fb | |||
0cdf7cfe21 | |||
2ecf999569 | |||
b612fc5155 | |||
25eb545409 | |||
52269964b6 | |||
ccdddac8fc | |||
1bc30bf3ba | |||
4868fface8 | |||
6fca4492d0 | |||
ade2f256e0 | |||
580b150c9a | |||
e6bad52945 | |||
beda3206e0 | |||
2f93a0f706 | |||
80f44d9547 | |||
b08e5db6d8 | |||
6a291d4116 | |||
6fc827fe67 | |||
6cd4866d76 | |||
4d7ca5c0f0 | |||
a375faecc1 | |||
1728b0f20c | |||
5aa071c59b | |||
1018c9db8b | |||
01ccd18726 | |||
abfbc6f4bc | |||
6a4bc02d7a | |||
814c0526d2 | |||
a5a4ef38e6 | |||
c17e3bfcdf | |||
017f46f318 | |||
fd4d801bfd | |||
f1dee50275 | |||
c2ae49eb47 | |||
47c71966d0 | |||
f9e8f4bc29 | |||
7694c8c046 | |||
0dd789e8a5 | |||
4e0aafd005 | |||
c5091f499e | |||
41c8fd8194 | |||
d4a7ee25ea | |||
3141c560fb | |||
de341b285b | |||
cc95e80ee9 | |||
d75ce52bd4 | |||
4a4ea557de | |||
33f42adb11 | |||
918ec1bde3 | |||
cca429d46a | |||
845c86f545 | |||
27993b789f | |||
bdd890cf6f | |||
c5574b41a1 | |||
292e27f0da | |||
606e149bd3 | |||
a8c3407d11 | |||
daa8168985 | |||
f580521e99 | |||
2226521f6c | |||
384416953d | |||
1343fabe41 | |||
1e52af5e29 | |||
672f5df0f9 | |||
804d9c1efe | |||
9270b35648 | |||
5a6d01db3c | |||
ef9c1416ec | |||
5efa7d5dfa | |||
a82569d615 | |||
ed5832ca73 | |||
574aa9ff9c | |||
8a29428de2 | |||
f4272b05fa | |||
d8265f7772 | |||
259526430c | |||
b5fafb6394 | |||
323c356d9c | |||
30b22ce6ba | |||
9acecc9eb2 | |||
4193a37a91 | |||
c4cc657b89 | |||
9726b0feb0 | |||
159ff828a1 | |||
6fa2bfc736 | |||
2c24df0247 | |||
13efc3e544 | |||
845dd9a8db | |||
b661bdd997 |
2
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
2
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
@ -22,7 +22,7 @@ body:
|
||||
id: log
|
||||
attributes:
|
||||
label: Log file
|
||||
description: A log file will help our developers to better diagnose and fix the issue.
|
||||
description: "A log file will help our developers to better diagnose and fix the issue. UPLOAD THE FILE. DO NOT COPY AND PASTE THE FILE'S CONTENT."
|
||||
placeholder: Logs files can be found under "Logs" folder in Ryujinx program folder. They can also be accessed by opening Ryujinx, then going to File > Open Logs Folder. You can drag and drop the log on to the text area (do not copy paste).
|
||||
validations:
|
||||
required: true
|
||||
|
4
.github/workflows/build.yml
vendored
4
.github/workflows/build.yml
vendored
@ -129,11 +129,11 @@ jobs:
|
||||
with:
|
||||
global-json-file: global.json
|
||||
|
||||
- name: Setup LLVM 14
|
||||
- name: Setup LLVM 17
|
||||
run: |
|
||||
wget https://apt.llvm.org/llvm.sh
|
||||
chmod +x llvm.sh
|
||||
sudo ./llvm.sh 14
|
||||
sudo ./llvm.sh 17
|
||||
|
||||
- name: Install rcodesign
|
||||
run: |
|
||||
|
81
.github/workflows/canary.yml
vendored
81
.github/workflows/canary.yml
vendored
@ -108,6 +108,7 @@ jobs:
|
||||
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
|
||||
sed -r --in-place '/^Name=Ryujinx$/s/Name=Ryujinx/Name=Ryujinx-Canary/' distribution/linux/Ryujinx.desktop
|
||||
shell: bash
|
||||
|
||||
- name: Create output dir
|
||||
@ -115,71 +116,69 @@ jobs:
|
||||
|
||||
- name: Publish
|
||||
run: |
|
||||
dotnet publish -c Release -r "${{ matrix.platform.name }}" -o ./publish_ava/publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx --self-contained
|
||||
dotnet publish -c Release -r "${{ matrix.platform.name }}" -o ./publish -p:Version="${{ steps.version_info.outputs.build_version }}" -p:SourceRevisionId="${{ steps.version_info.outputs.git_short_hash }}" -p:DebugType=embedded src/Ryujinx --self-contained
|
||||
|
||||
- name: Packing Windows builds
|
||||
if: matrix.platform.os == 'windows-latest'
|
||||
run: |
|
||||
pushd publish_ava
|
||||
rm publish/libarmeilleure-jitsupport.dylib
|
||||
7z a ../release_output/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.zip publish
|
||||
pushd publish
|
||||
rm libarmeilleure-jitsupport.dylib
|
||||
7z a ../release_output/ryujinx-canary-${{ 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-canary-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz publish
|
||||
pushd publish
|
||||
rm libarmeilleure-jitsupport.dylib
|
||||
chmod +x Ryujinx.sh Ryujinx
|
||||
tar -czvf ../release_output/ryujinx-canary-${{ 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 }}"
|
||||
- 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
|
||||
sudo apt install -y zsync desktop-file-utils appstream
|
||||
|
||||
# mkdir -p tools
|
||||
# export PATH="$PATH:$(readlink -f tools)"
|
||||
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
|
||||
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
|
||||
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
|
||||
export UFLAG="gh-releases-zsync|${{ github.repository_owner }}|Canary-Releases|latest|*-$ARCH_NAME.AppImage.zsync"
|
||||
BUILDDIR=publish OUTDIR=publish_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
|
||||
pushd publish_appimage
|
||||
mv Ryujinx.AppImage ../release_output/ryujinx-canary-$BUILD_VERSION-$ARCH_NAME.AppImage
|
||||
mv Ryujinx.AppImage.zsync ../release_output/ryujinx-canary-$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,release_output/*AppImage*"
|
||||
artifacts: "release_output/*.tar.gz,release_output/*.zip,release_output/*AppImage*"
|
||||
tag: ${{ steps.version_info.outputs.build_version }}
|
||||
body: |
|
||||
# Canary builds:
|
||||
@ -211,11 +210,11 @@ jobs:
|
||||
with:
|
||||
global-json-file: global.json
|
||||
|
||||
- name: Setup LLVM 15
|
||||
- name: Setup LLVM 17
|
||||
run: |
|
||||
wget https://apt.llvm.org/llvm.sh
|
||||
chmod +x llvm.sh
|
||||
sudo ./llvm.sh 15
|
||||
sudo ./llvm.sh 17
|
||||
|
||||
- name: Install rcodesign
|
||||
run: |
|
||||
|
6
.github/workflows/nightly_pr_comment.yml
vendored
6
.github/workflows/nightly_pr_comment.yml
vendored
@ -37,11 +37,11 @@ jobs:
|
||||
if (!artifacts.length) {
|
||||
return core.error(`No artifacts found`);
|
||||
}
|
||||
let body = `*You need to be logged into GitHub to download these files.*\n\nDownload the artifacts for this pull request:\n`;
|
||||
let body = `Download the artifacts for this pull request:\n`;
|
||||
let hidden_debug_artifacts = `\n\n <details><summary>Only for Developers</summary>\n`;
|
||||
for (const art of artifacts) {
|
||||
const url = `https://github.com/Ryubing/Ryujinx/actions/runs/${run_id}/artifacts/${art.id}`;
|
||||
if(art.name.includes('Debug')) {
|
||||
const url = `https://nightly.link/${owner}/${repo}/actions/artifacts/${art.id}.zip`;
|
||||
if (art.name.includes('Debug')) {
|
||||
hidden_debug_artifacts += `\n* [${art.name}](${url})`;
|
||||
} else {
|
||||
body += `\n* [${art.name}](${url})`;
|
||||
|
32
.github/workflows/release.yml
vendored
32
.github/workflows/release.yml
vendored
@ -3,16 +3,6 @@ name: Release job
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs: {}
|
||||
push:
|
||||
branches: [ release ]
|
||||
paths-ignore:
|
||||
- '.github/**'
|
||||
- 'docs/**'
|
||||
- 'assets/**'
|
||||
- '*.yml'
|
||||
- '*.json'
|
||||
- '*.config'
|
||||
- '*.md'
|
||||
|
||||
concurrency: release
|
||||
|
||||
@ -121,6 +111,15 @@ jobs:
|
||||
7z a ../release_output/ryujinx-${{ 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
|
||||
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
|
||||
shell: bash
|
||||
|
||||
- name: Build AppImage (Linux)
|
||||
if: matrix.platform.os == 'ubuntu-latest'
|
||||
@ -157,15 +156,6 @@ jobs:
|
||||
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: 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
|
||||
shell: bash
|
||||
|
||||
- name: Pushing new release
|
||||
@ -201,11 +191,11 @@ jobs:
|
||||
with:
|
||||
global-json-file: global.json
|
||||
|
||||
- name: Setup LLVM 15
|
||||
- name: Setup LLVM 17
|
||||
run: |
|
||||
wget https://apt.llvm.org/llvm.sh
|
||||
chmod +x llvm.sh
|
||||
sudo ./llvm.sh 15
|
||||
sudo ./llvm.sh 17
|
||||
|
||||
- name: Install rcodesign
|
||||
run: |
|
||||
|
@ -3,13 +3,13 @@
|
||||
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageVersion Include="Avalonia" Version="11.0.10" />
|
||||
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.0.10" />
|
||||
<PackageVersion Include="Avalonia.Desktop" Version="11.0.10" />
|
||||
<PackageVersion Include="Avalonia.Diagnostics" Version="11.0.10" />
|
||||
<PackageVersion Include="Avalonia.Markup.Xaml.Loader" Version="11.0.10" />
|
||||
<PackageVersion Include="Avalonia.Svg" Version="11.0.0.18" />
|
||||
<PackageVersion Include="Avalonia.Svg.Skia" Version="11.0.0.18" />
|
||||
<PackageVersion Include="Avalonia" Version="11.0.13" />
|
||||
<PackageVersion Include="Avalonia.Controls.DataGrid" Version="11.0.13" />
|
||||
<PackageVersion Include="Avalonia.Desktop" Version="11.0.13" />
|
||||
<PackageVersion Include="Avalonia.Diagnostics" Version="11.0.13" />
|
||||
<PackageVersion Include="Avalonia.Markup.Xaml.Loader" Version="11.0.13" />
|
||||
<PackageVersion Include="Avalonia.Svg" Version="11.0.0.19" />
|
||||
<PackageVersion Include="Avalonia.Svg.Skia" Version="11.0.0.19" />
|
||||
<PackageVersion Include="Microsoft.Build.Framework" Version="17.11.4" />
|
||||
<PackageVersion Include="Microsoft.Build.Utilities.Core" Version="17.12.6" />
|
||||
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
@ -18,7 +18,7 @@
|
||||
<PackageVersion Include="Projektanker.Icons.Avalonia.MaterialDesign" Version="9.4.0"/>
|
||||
<PackageVersion Include="CommandLineParser" Version="2.9.1" />
|
||||
<PackageVersion Include="CommunityToolkit.Mvvm" Version="8.4.0"/>
|
||||
<PackageVersion Include="Concentus" Version="2.2.0" />
|
||||
<PackageVersion Include="Concentus" Version="2.2.2" />
|
||||
<PackageVersion Include="DiscordRichPresence" Version="1.2.1.24" />
|
||||
<PackageVersion Include="DynamicData" Version="9.0.4" />
|
||||
<PackageVersion Include="FluentAvaloniaUI" Version="2.0.5" />
|
||||
@ -26,7 +26,7 @@
|
||||
<PackageVersion Include="LibHac" Version="0.19.0" />
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.Analyzers" Version="3.3.4" />
|
||||
<PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.9.2" />
|
||||
<PackageVersion Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.1.2" />
|
||||
<PackageVersion Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.3.0" />
|
||||
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
|
||||
<PackageVersion Include="Microsoft.IO.RecyclableMemoryStream" Version="3.0.1" />
|
||||
<PackageVersion Include="MsgPack.Cli" Version="1.0.1" />
|
||||
@ -42,16 +42,17 @@
|
||||
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies" Version="5.0.3-build14" />
|
||||
<PackageVersion Include="Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK" Version="1.2.0" />
|
||||
<PackageVersion Include="Ryujinx.SDL2-CS" Version="2.30.0-build32" />
|
||||
<PackageVersion Include="Gommon" Version="2.7.0.1" />
|
||||
<PackageVersion Include="Gommon" Version="2.7.0.2" />
|
||||
<PackageVersion Include="securifybv.ShellLink" Version="0.1.0" />
|
||||
<PackageVersion Include="Sep" Version="0.6.0" />
|
||||
<PackageVersion Include="shaderc.net" Version="0.1.0" />
|
||||
<PackageVersion Include="SharpMetal" Version="1.0.0-preview21" />
|
||||
<PackageVersion Include="SharpZipLib" Version="1.4.2" />
|
||||
<PackageVersion Include="Silk.NET.Vulkan" Version="2.21.0" />
|
||||
<PackageVersion Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.21.0" />
|
||||
<PackageVersion Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.21.0" />
|
||||
<PackageVersion Include="SkiaSharp" Version="2.88.7" />
|
||||
<PackageVersion Include="SkiaSharp.NativeAssets.Linux" Version="2.88.7" />
|
||||
<PackageVersion Include="Silk.NET.Vulkan" Version="2.22.0" />
|
||||
<PackageVersion Include="Silk.NET.Vulkan.Extensions.EXT" Version="2.22.0" />
|
||||
<PackageVersion Include="Silk.NET.Vulkan.Extensions.KHR" Version="2.22.0" />
|
||||
<PackageVersion Include="SkiaSharp" Version="2.88.9" />
|
||||
<PackageVersion Include="SkiaSharp.NativeAssets.Linux" Version="2.88.9" />
|
||||
<PackageVersion Include="SPB" Version="0.0.4-build32" />
|
||||
<PackageVersion Include="System.IO.Hashing" Version="9.0.0" />
|
||||
<PackageVersion Include="System.Management" Version="9.0.0" />
|
||||
|
269
Ryujinx.sln
Normal file
269
Ryujinx.sln
Normal file
@ -0,0 +1,269 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.1.32228.430
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Tests", "src\Ryujinx.Tests\Ryujinx.Tests.csproj", "{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Tests.Unicorn", "src\Ryujinx.Tests.Unicorn\Ryujinx.Tests.Unicorn.csproj", "{D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.HLE", "src\Ryujinx.HLE\Ryujinx.HLE.csproj", "{CB92CFF9-1D62-4D4F-9E88-8130EF61E351}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.ShaderTools", "src\Ryujinx.ShaderTools\Ryujinx.ShaderTools.csproj", "{3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Common", "src\Ryujinx.Common\Ryujinx.Common.csproj", "{5FD4E4F6-8928-4B3C-BE07-28A675C17226}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ARMeilleure", "src\ARMeilleure\ARMeilleure.csproj", "{ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Gpu", "src\Ryujinx.Graphics.Gpu\Ryujinx.Graphics.Gpu.csproj", "{ADA7EA87-0D63-4D97-9433-922A2124401F}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.GAL", "src\Ryujinx.Graphics.GAL\Ryujinx.Graphics.GAL.csproj", "{A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.OpenGL", "src\Ryujinx.Graphics.OpenGL\Ryujinx.Graphics.OpenGL.csproj", "{9558FB96-075D-4219-8FFF-401979DC0B69}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Texture", "src\Ryujinx.Graphics.Texture\Ryujinx.Graphics.Texture.csproj", "{E1B1AD28-289D-47B7-A106-326972240207}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Shader", "src\Ryujinx.Graphics.Shader\Ryujinx.Graphics.Shader.csproj", "{03B955CD-AD84-4B93-AAA7-BF17923BBAA5}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Nvdec", "src\Ryujinx.Graphics.Nvdec\Ryujinx.Graphics.Nvdec.csproj", "{85A0FA56-DC01-4A42-8808-70DAC76BD66D}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Audio", "src\Ryujinx.Audio\Ryujinx.Audio.csproj", "{806ACF6D-90B0-45D0-A1AC-5F220F3B3985}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Memory", "src\Ryujinx.Memory\Ryujinx.Memory.csproj", "{A5E6C691-9E22-4263-8F40-42F002CE66BE}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Tests.Memory", "src\Ryujinx.Tests.Memory\Ryujinx.Tests.Memory.csproj", "{D1CC5322-7325-4F6B-9625-194B30BE1296}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Cpu", "src\Ryujinx.Cpu\Ryujinx.Cpu.csproj", "{3DF35E3D-D844-4399-A9A1-A9E923264C17}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Device", "src\Ryujinx.Graphics.Device\Ryujinx.Graphics.Device.csproj", "{C3002C3C-7B09-4FE7-894A-372EDA22FC6E}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Host1x", "src\Ryujinx.Graphics.Host1x\Ryujinx.Graphics.Host1x.csproj", "{C35F1536-7DE5-4F9D-9604-B5B4E1561947}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Nvdec.Vp9", "src\Ryujinx.Graphics.Nvdec.Vp9\Ryujinx.Graphics.Nvdec.Vp9.csproj", "{B9AECA11-E248-4886-A10B-81B631CAAF29}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Vic", "src\Ryujinx.Graphics.Vic\Ryujinx.Graphics.Vic.csproj", "{81BB2C11-9408-4EA3-822E-42987AF54429}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Video", "src\Ryujinx.Graphics.Video\Ryujinx.Graphics.Video.csproj", "{FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Audio.Backends.OpenAL", "src\Ryujinx.Audio.Backends.OpenAL\Ryujinx.Audio.Backends.OpenAL.csproj", "{0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Audio.Backends.SoundIo", "src\Ryujinx.Audio.Backends.SoundIo\Ryujinx.Audio.Backends.SoundIo.csproj", "{716364DE-B988-41A6-BAB4-327964266ECC}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Input", "src\Ryujinx.Input\Ryujinx.Input.csproj", "{C16F112F-38C3-40BC-9F5F-4791112063D6}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Input.SDL2", "src\Ryujinx.Input.SDL2\Ryujinx.Input.SDL2.csproj", "{DFAB6F2D-B9BF-4AFF-B22B-7684A328EBA3}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.SDL2.Common", "src\Ryujinx.SDL2.Common\Ryujinx.SDL2.Common.csproj", "{2D5D3A1D-5730-4648-B0AB-06C53CB910C0}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Audio.Backends.SDL2", "src\Ryujinx.Audio.Backends.SDL2\Ryujinx.Audio.Backends.SDL2.csproj", "{D99A395A-8569-4DB0-B336-900647890052}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Nvdec.FFmpeg", "src\Ryujinx.Graphics.Nvdec.FFmpeg\Ryujinx.Graphics.Nvdec.FFmpeg.csproj", "{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx", "src\Ryujinx\Ryujinx.csproj", "{7C1B2721-13DA-4B62-B046-C626605ECCE6}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Horizon.Generators", "src\Ryujinx.Horizon.Generators\Ryujinx.Horizon.Generators.csproj", "{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Graphics.Vulkan", "src\Ryujinx.Graphics.Vulkan\Ryujinx.Graphics.Vulkan.csproj", "{D4D09B08-D580-4D69-B886-C35D2853F6C8}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Spv.Generator", "src\Spv.Generator\Spv.Generator.csproj", "{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.UI.LocaleGenerator", "src\Ryujinx.UI.LocaleGenerator\Ryujinx.UI.LocaleGenerator.csproj", "{77D01AD9-2C98-478E-AE1D-8F7100738FB4}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Horizon.Common", "src\Ryujinx.Horizon.Common\Ryujinx.Horizon.Common.csproj", "{77F96ECE-4952-42DB-A528-DED25572A573}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Horizon", "src\Ryujinx.Horizon\Ryujinx.Horizon.csproj", "{AF34127A-3A92-43E5-8496-14960A50B1F1}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Horizon.Kernel.Generators", "src\Ryujinx.Horizon.Kernel.Generators\Ryujinx.Horizon.Kernel.Generators.csproj", "{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.HLE.Generators", "src\Ryujinx.HLE.Generators\Ryujinx.HLE.Generators.csproj", "{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryujinx.Graphics.Metal", "src\Ryujinx.Graphics.Metal\Ryujinx.Graphics.Metal.csproj", "{C08931FA-1191-417A-864F-3882D93E683B}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E} = {A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryujinx.BuildValidationTasks", "src\Ryujinx.BuildValidationTasks\Ryujinx.BuildValidationTasks.csproj", "{4A89A234-4F19-497D-A576-DDE8CDFC5B22}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryujinx.Graphics.Metal.SharpMetalExtensions", "src/Ryujinx.Graphics.Metal.SharpMetalExtensions\Ryujinx.Graphics.Metal.SharpMetalExtensions.csproj", "{81EA598C-DBA1-40B0-8DA4-4796B78F2037}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{36F870C1-3E5F-485F-B426-F0645AF78751}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
.editorconfig = .editorconfig
|
||||
.github\workflows\build.yml = .github\workflows\build.yml
|
||||
.github\workflows\canary.yml = .github\workflows\canary.yml
|
||||
Directory.Packages.props = Directory.Packages.props
|
||||
.github\workflows\release.yml = .github\workflows\release.yml
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{EBB55AEA-C7D7-4DEB-BF96-FA1789E225E9}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D8F72938-78EF-4E8C-BAFE-531C9C3C8F15}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{CB92CFF9-1D62-4D4F-9E88-8130EF61E351}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{CB92CFF9-1D62-4D4F-9E88-8130EF61E351}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{CB92CFF9-1D62-4D4F-9E88-8130EF61E351}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{CB92CFF9-1D62-4D4F-9E88-8130EF61E351}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3AB294D0-2230-468F-9EB3-BDFCAEAE99A5}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{5FD4E4F6-8928-4B3C-BE07-28A675C17226}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{5FD4E4F6-8928-4B3C-BE07-28A675C17226}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{5FD4E4F6-8928-4B3C-BE07-28A675C17226}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{5FD4E4F6-8928-4B3C-BE07-28A675C17226}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{ABF09A5E-2D8B-4B6F-A51D-5CE414DDB15A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{ADA7EA87-0D63-4D97-9433-922A2124401F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{ADA7EA87-0D63-4D97-9433-922A2124401F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{ADA7EA87-0D63-4D97-9433-922A2124401F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{ADA7EA87-0D63-4D97-9433-922A2124401F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{9558FB96-075D-4219-8FFF-401979DC0B69}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{9558FB96-075D-4219-8FFF-401979DC0B69}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{9558FB96-075D-4219-8FFF-401979DC0B69}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{9558FB96-075D-4219-8FFF-401979DC0B69}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{E1B1AD28-289D-47B7-A106-326972240207}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{E1B1AD28-289D-47B7-A106-326972240207}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{E1B1AD28-289D-47B7-A106-326972240207}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{E1B1AD28-289D-47B7-A106-326972240207}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{03B955CD-AD84-4B93-AAA7-BF17923BBAA5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{03B955CD-AD84-4B93-AAA7-BF17923BBAA5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{03B955CD-AD84-4B93-AAA7-BF17923BBAA5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{03B955CD-AD84-4B93-AAA7-BF17923BBAA5}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{85A0FA56-DC01-4A42-8808-70DAC76BD66D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{85A0FA56-DC01-4A42-8808-70DAC76BD66D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{85A0FA56-DC01-4A42-8808-70DAC76BD66D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{85A0FA56-DC01-4A42-8808-70DAC76BD66D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{806ACF6D-90B0-45D0-A1AC-5F220F3B3985}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{806ACF6D-90B0-45D0-A1AC-5F220F3B3985}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{806ACF6D-90B0-45D0-A1AC-5F220F3B3985}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{806ACF6D-90B0-45D0-A1AC-5F220F3B3985}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{A5E6C691-9E22-4263-8F40-42F002CE66BE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A5E6C691-9E22-4263-8F40-42F002CE66BE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A5E6C691-9E22-4263-8F40-42F002CE66BE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A5E6C691-9E22-4263-8F40-42F002CE66BE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{D1CC5322-7325-4F6B-9625-194B30BE1296}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D1CC5322-7325-4F6B-9625-194B30BE1296}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D1CC5322-7325-4F6B-9625-194B30BE1296}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D1CC5322-7325-4F6B-9625-194B30BE1296}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{3DF35E3D-D844-4399-A9A1-A9E923264C17}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3DF35E3D-D844-4399-A9A1-A9E923264C17}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3DF35E3D-D844-4399-A9A1-A9E923264C17}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3DF35E3D-D844-4399-A9A1-A9E923264C17}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C3002C3C-7B09-4FE7-894A-372EDA22FC6E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C3002C3C-7B09-4FE7-894A-372EDA22FC6E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C3002C3C-7B09-4FE7-894A-372EDA22FC6E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C3002C3C-7B09-4FE7-894A-372EDA22FC6E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C35F1536-7DE5-4F9D-9604-B5B4E1561947}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C35F1536-7DE5-4F9D-9604-B5B4E1561947}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C35F1536-7DE5-4F9D-9604-B5B4E1561947}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C35F1536-7DE5-4F9D-9604-B5B4E1561947}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{B9AECA11-E248-4886-A10B-81B631CAAF29}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B9AECA11-E248-4886-A10B-81B631CAAF29}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B9AECA11-E248-4886-A10B-81B631CAAF29}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B9AECA11-E248-4886-A10B-81B631CAAF29}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{81BB2C11-9408-4EA3-822E-42987AF54429}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{81BB2C11-9408-4EA3-822E-42987AF54429}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{81BB2C11-9408-4EA3-822E-42987AF54429}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{81BB2C11-9408-4EA3-822E-42987AF54429}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{FD4A2C14-8E3D-4957-ABBE-3C38897B3E2D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0BE11899-DF2D-4BDE-B9EE-2489E8D35E7D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{716364DE-B988-41A6-BAB4-327964266ECC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{716364DE-B988-41A6-BAB4-327964266ECC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{716364DE-B988-41A6-BAB4-327964266ECC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{716364DE-B988-41A6-BAB4-327964266ECC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C16F112F-38C3-40BC-9F5F-4791112063D6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C16F112F-38C3-40BC-9F5F-4791112063D6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C16F112F-38C3-40BC-9F5F-4791112063D6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C16F112F-38C3-40BC-9F5F-4791112063D6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{DFAB6F2D-B9BF-4AFF-B22B-7684A328EBA3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{DFAB6F2D-B9BF-4AFF-B22B-7684A328EBA3}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{DFAB6F2D-B9BF-4AFF-B22B-7684A328EBA3}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{DFAB6F2D-B9BF-4AFF-B22B-7684A328EBA3}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{2D5D3A1D-5730-4648-B0AB-06C53CB910C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{2D5D3A1D-5730-4648-B0AB-06C53CB910C0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2D5D3A1D-5730-4648-B0AB-06C53CB910C0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{2D5D3A1D-5730-4648-B0AB-06C53CB910C0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{D99A395A-8569-4DB0-B336-900647890052}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D99A395A-8569-4DB0-B336-900647890052}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D99A395A-8569-4DB0-B336-900647890052}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D99A395A-8569-4DB0-B336-900647890052}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{BEE1C184-C9A4-410B-8DFC-FB74D5C93AEB}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{7C1B2721-13DA-4B62-B046-C626605ECCE6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{7C1B2721-13DA-4B62-B046-C626605ECCE6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{7C1B2721-13DA-4B62-B046-C626605ECCE6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{7C1B2721-13DA-4B62-B046-C626605ECCE6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{6AE2A5E8-4C5A-48B9-997B-E1455C0355C6}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{D4D09B08-D580-4D69-B886-C35D2853F6C8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D4D09B08-D580-4D69-B886-C35D2853F6C8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D4D09B08-D580-4D69-B886-C35D2853F6C8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D4D09B08-D580-4D69-B886-C35D2853F6C8}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{2BCB3D7A-38C0-4FE7-8FDA-374C6AD56D0E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{77D01AD9-2C98-478E-AE1D-8F7100738FB4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{77F96ECE-4952-42DB-A528-DED25572A573}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{77F96ECE-4952-42DB-A528-DED25572A573}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{77F96ECE-4952-42DB-A528-DED25572A573}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{77F96ECE-4952-42DB-A528-DED25572A573}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{AF34127A-3A92-43E5-8496-14960A50B1F1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{AF34127A-3A92-43E5-8496-14960A50B1F1}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{AF34127A-3A92-43E5-8496-14960A50B1F1}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{AF34127A-3A92-43E5-8496-14960A50B1F1}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C08931FA-1191-417A-864F-3882D93E683B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{C08931FA-1191-417A-864F-3882D93E683B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{C08931FA-1191-417A-864F-3882D93E683B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{C08931FA-1191-417A-864F-3882D93E683B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{4A89A234-4F19-497D-A576-DDE8CDFC5B22}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{4A89A234-4F19-497D-A576-DDE8CDFC5B22}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{81EA598C-DBA1-40B0-8DA4-4796B78F2037}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{81EA598C-DBA1-40B0-8DA4-4796B78F2037}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{81EA598C-DBA1-40B0-8DA4-4796B78F2037}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{81EA598C-DBA1-40B0-8DA4-4796B78F2037}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {110169B3-3328-4730-8AB0-BA05BEF75C1A}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
52
Ryujinx.slnx
52
Ryujinx.slnx
@ -1,52 +0,0 @@
|
||||
<Solution>
|
||||
<Folder Name="/Solution Items/">
|
||||
<File Path=".editorconfig" />
|
||||
<File Path=".github\workflows\build.yml" />
|
||||
<File Path=".github\workflows\canary.yml" />
|
||||
<File Path="Directory.Packages.props" />
|
||||
<File Path=".github\workflows\release.yml" />
|
||||
</Folder>
|
||||
<Project Path="src/Ryujinx.Graphics.Metal.SharpMetalExtensions\Ryujinx.Graphics.Metal.SharpMetalExtensions.csproj" Type="Classic C#" />
|
||||
<Project Path="src\ARMeilleure\ARMeilleure.csproj" />
|
||||
<Project Path="src\Ryujinx.Audio.Backends.OpenAL\Ryujinx.Audio.Backends.OpenAL.csproj" />
|
||||
<Project Path="src\Ryujinx.Audio.Backends.SDL2\Ryujinx.Audio.Backends.SDL2.csproj" />
|
||||
<Project Path="src\Ryujinx.Audio.Backends.SoundIo\Ryujinx.Audio.Backends.SoundIo.csproj" />
|
||||
<Project Path="src\Ryujinx.Audio\Ryujinx.Audio.csproj" />
|
||||
<Project Path="src\Ryujinx.BuildValidationTasks\Ryujinx.BuildValidationTasks.csproj" Type="Classic C#">
|
||||
<Configuration Solution="Debug|Any CPU" Project="Debug|Any CPU|NoBuild" />
|
||||
<Configuration Solution="Release|Any CPU" Project="Release|Any CPU|NoBuild" />
|
||||
</Project>
|
||||
<Project Path="src\Ryujinx.Common\Ryujinx.Common.csproj" />
|
||||
<Project Path="src\Ryujinx.Cpu\Ryujinx.Cpu.csproj" />
|
||||
<Project Path="src\Ryujinx.Graphics.Device\Ryujinx.Graphics.Device.csproj" />
|
||||
<Project Path="src\Ryujinx.Graphics.GAL\Ryujinx.Graphics.GAL.csproj" />
|
||||
<Project Path="src\Ryujinx.Graphics.Gpu\Ryujinx.Graphics.Gpu.csproj" />
|
||||
<Project Path="src\Ryujinx.Graphics.Host1x\Ryujinx.Graphics.Host1x.csproj" />
|
||||
<Project Path="src\Ryujinx.Graphics.Metal\Ryujinx.Graphics.Metal.csproj"/>
|
||||
<Project Path="src\Ryujinx.Graphics.Nvdec.FFmpeg\Ryujinx.Graphics.Nvdec.FFmpeg.csproj" />
|
||||
<Project Path="src\Ryujinx.Graphics.Nvdec.Vp9\Ryujinx.Graphics.Nvdec.Vp9.csproj" />
|
||||
<Project Path="src\Ryujinx.Graphics.Nvdec\Ryujinx.Graphics.Nvdec.csproj" />
|
||||
<Project Path="src\Ryujinx.Graphics.OpenGL\Ryujinx.Graphics.OpenGL.csproj" />
|
||||
<Project Path="src\Ryujinx.Graphics.Shader\Ryujinx.Graphics.Shader.csproj" />
|
||||
<Project Path="src\Ryujinx.Graphics.Texture\Ryujinx.Graphics.Texture.csproj" />
|
||||
<Project Path="src\Ryujinx.Graphics.Vic\Ryujinx.Graphics.Vic.csproj" />
|
||||
<Project Path="src\Ryujinx.Graphics.Video\Ryujinx.Graphics.Video.csproj" />
|
||||
<Project Path="src\Ryujinx.Graphics.Vulkan\Ryujinx.Graphics.Vulkan.csproj" />
|
||||
<Project Path="src\Ryujinx.HLE.Generators\Ryujinx.HLE.Generators.csproj" />
|
||||
<Project Path="src\Ryujinx.HLE\Ryujinx.HLE.csproj" />
|
||||
<Project Path="src\Ryujinx.Horizon.Common\Ryujinx.Horizon.Common.csproj" />
|
||||
<Project Path="src\Ryujinx.Horizon.Generators\Ryujinx.Horizon.Generators.csproj" />
|
||||
<Project Path="src\Ryujinx.Horizon.Kernel.Generators\Ryujinx.Horizon.Kernel.Generators.csproj" />
|
||||
<Project Path="src\Ryujinx.Horizon\Ryujinx.Horizon.csproj" />
|
||||
<Project Path="src\Ryujinx.Input.SDL2\Ryujinx.Input.SDL2.csproj" />
|
||||
<Project Path="src\Ryujinx.Input\Ryujinx.Input.csproj" />
|
||||
<Project Path="src\Ryujinx.Memory\Ryujinx.Memory.csproj" />
|
||||
<Project Path="src\Ryujinx.SDL2.Common\Ryujinx.SDL2.Common.csproj" />
|
||||
<Project Path="src\Ryujinx.ShaderTools\Ryujinx.ShaderTools.csproj" />
|
||||
<Project Path="src\Ryujinx.Tests.Memory\Ryujinx.Tests.Memory.csproj" />
|
||||
<Project Path="src\Ryujinx.Tests.Unicorn\Ryujinx.Tests.Unicorn.csproj" />
|
||||
<Project Path="src\Ryujinx.Tests\Ryujinx.Tests.csproj" />
|
||||
<Project Path="src\Ryujinx.UI.LocaleGenerator\Ryujinx.UI.LocaleGenerator.csproj" />
|
||||
<Project Path="src\Ryujinx\Ryujinx.csproj" />
|
||||
<Project Path="src\Spv.Generator\Spv.Generator.csproj" />
|
||||
</Solution>
|
@ -6,7 +6,7 @@ cd "$ROOTDIR"
|
||||
|
||||
BUILDDIR=${BUILDDIR:-publish}
|
||||
OUTDIR=${OUTDIR:-publish_appimage}
|
||||
UFLAG=${UFLAG:-"gh-releases-zsync|GreemDev|ryujinx|latest|*-x64.AppImage.zsync"}
|
||||
UFLAG=${UFLAG:-"gh-releases-zsync|Ryubing|ryujinx|latest|*-x64.AppImage.zsync"}
|
||||
|
||||
rm -rf AppDir
|
||||
mkdir -p AppDir/usr/bin
|
||||
|
@ -19,7 +19,7 @@ if platform.system() == "Darwin":
|
||||
else:
|
||||
OTOOL = shutil.which("llvm-otool")
|
||||
if OTOOL is None:
|
||||
for llvm_ver in [15, 14, 13]:
|
||||
for llvm_ver in [17, 16, 15, 14, 13]:
|
||||
otool_path = shutil.which(f"llvm-otool-{llvm_ver}")
|
||||
if otool_path is not None:
|
||||
OTOOL = otool_path
|
||||
|
@ -26,7 +26,7 @@ else:
|
||||
LIPO = shutil.which("llvm-lipo")
|
||||
|
||||
if LIPO is None:
|
||||
for llvm_ver in [15, 14, 13]:
|
||||
for llvm_ver in [17, 16, 15, 14, 13]:
|
||||
lipo_path = shutil.which(f"llvm-lipo-{llvm_ver}")
|
||||
if lipo_path is not None:
|
||||
LIPO = lipo_path
|
||||
|
@ -67,11 +67,11 @@ python3 "$BASE_DIR/distribution/macos/construct_universal_dylib.py" "$ARM64_APP_
|
||||
|
||||
if ! [ -x "$(command -v lipo)" ];
|
||||
then
|
||||
if ! [ -x "$(command -v llvm-lipo-14)" ];
|
||||
if ! [ -x "$(command -v llvm-lipo-17)" ];
|
||||
then
|
||||
LIPO=llvm-lipo
|
||||
else
|
||||
LIPO=llvm-lipo-14
|
||||
LIPO=llvm-lipo-17
|
||||
fi
|
||||
else
|
||||
LIPO=lipo
|
||||
|
@ -62,11 +62,11 @@ python3 "$BASE_DIR/distribution/macos/construct_universal_dylib.py" "$ARM64_OUTP
|
||||
|
||||
if ! [ -x "$(command -v lipo)" ];
|
||||
then
|
||||
if ! [ -x "$(command -v llvm-lipo-14)" ];
|
||||
if ! [ -x "$(command -v llvm-lipo-17)" ];
|
||||
then
|
||||
LIPO=llvm-lipo
|
||||
else
|
||||
LIPO=llvm-lipo-14
|
||||
LIPO=llvm-lipo-17
|
||||
fi
|
||||
else
|
||||
LIPO=lipo
|
||||
|
@ -19,7 +19,7 @@
|
||||
<key>CSResourcesFileMapped</key>
|
||||
<true/>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright © 2018 - 2023 Ryujinx Team and Contributors.</string>
|
||||
<string>Copyright © 2018 - 2025 Ryujinx Team and Contributors.</string>
|
||||
<key>LSApplicationCategoryType</key>
|
||||
<string>public.app-category.games</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
|
3424
docs/compatibility.csv
Normal file
3424
docs/compatibility.csv
Normal file
File diff suppressed because it is too large
Load Diff
10
src/Ryujinx.Common/RyujinxException.cs
Normal file
10
src/Ryujinx.Common/RyujinxException.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Common
|
||||
{
|
||||
public class RyujinxException : Exception
|
||||
{
|
||||
public RyujinxException(string message) : base(message)
|
||||
{ }
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
using Gommon;
|
||||
using Gommon;
|
||||
using Ryujinx.Common.Configuration;
|
||||
using System;
|
||||
using System.Linq;
|
||||
@ -47,6 +47,9 @@ namespace Ryujinx.Common
|
||||
|
||||
public static readonly string[] DiscordGameAssetKeys =
|
||||
[
|
||||
"010008900705c000", // Dragon Quest Builders
|
||||
"010042000a986000", // Dragon Quest Builders 2
|
||||
|
||||
"010055d009f78000", // Fire Emblem: Three Houses
|
||||
"0100a12011cc8000", // Fire Emblem: Shadow Dragon
|
||||
"0100a6301214e000", // Fire Emblem Engage
|
||||
@ -105,17 +108,18 @@ namespace Ryujinx.Common
|
||||
"0100f4c009322000", // Pikmin 3 Deluxe
|
||||
"0100b7c00933a000", // Pikmin 4
|
||||
|
||||
"0100f4300bf2c000", // New Pokémon Snap
|
||||
"0100000011d90000", // Pokémon Brilliant Diamond
|
||||
"01001f5010dfa000", // Pokémon Legends: Arceus
|
||||
"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
|
||||
"01003d200baa2000", // Pokémon Mystery Dungeon - Rescue Team DX
|
||||
"0100a3d008c5c000", // Pokémon Scarlet
|
||||
"01008db008c2c000", // Pokémon Shield
|
||||
"010018e011d92000", // Pokémon Shining Pearl
|
||||
"0100abf008968000", // Pokémon Sword
|
||||
"01008f6008c5e000", // Pokémon Violet
|
||||
"0100b3f000be2000", // Pokkén Tournament DX
|
||||
"0100f4300bf2c000", // New Pokémon Snap
|
||||
|
||||
"01003bc0000a0000", // Splatoon 2 (US)
|
||||
"0100f8f0000a2000", // Splatoon 2 (EU)
|
||||
@ -165,13 +169,21 @@ namespace Ryujinx.Common
|
||||
"01005ea01c0fc000", // SONIC X SHADOW GENERATIONS
|
||||
"01005ea01c0fc001", // ^
|
||||
|
||||
"0100ff500e34a000", // Xenoblade Chronicles - Definitive Edition
|
||||
"0100e95004038000", // Xenoblade Chronicles 2
|
||||
"010074f013262000", // Xenoblade Chronicles 3
|
||||
|
||||
"010056e00853a000", // A Hat in Time
|
||||
"0100fd1014726000", // Baldurs Gate: Dark Alliance
|
||||
"0100dbf01000a000", // Burnout Paradise Remastered
|
||||
"0100744001588000", // Cars 3: Driven to Win
|
||||
"0100b41013c82000", // Cruis'n Blast
|
||||
"010085900337e000", // Death Squared
|
||||
"01001b300b9be000", // Diablo III: Eternal Collection
|
||||
"01008c8012920000", // Dying Light Platinum Edition
|
||||
"01001cc01b2d4000", // Goat Simulator 3
|
||||
"01003620068ea000", // Hand of Fate 2
|
||||
"010085500130a000", // Lego City: Undercover
|
||||
"010073c01af34000", // LEGO Horizon Adventures
|
||||
"0100770008dd8000", // Monster Hunter Generations Ultimate
|
||||
"0100b04011742000", // Monster Hunter Rise
|
||||
@ -190,6 +202,8 @@ namespace Ryujinx.Common
|
||||
"01000a10041ea000", // The Elder Scrolls V: Skyrim
|
||||
"010057a01e4d4000", // TSUKIHIME -A piece of blue glass moon-
|
||||
"010080b00ad66000", // Undertale
|
||||
"010069401adb8000", // Unicorn Overlord
|
||||
"0100534009ff2000", // Yonder - The cloud catcher chronicles
|
||||
];
|
||||
}
|
||||
}
|
||||
|
@ -168,13 +168,15 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
return BinarySearch(list, offset, size) >= 0;
|
||||
}
|
||||
|
||||
public readonly IEnumerable<Range> FindOverlaps(int offset, int size)
|
||||
public readonly List<Range> FindOverlaps(int offset, int size)
|
||||
{
|
||||
var list = _ranges;
|
||||
if (list == null)
|
||||
{
|
||||
yield break;
|
||||
return null;
|
||||
}
|
||||
|
||||
List<Range> result = null;
|
||||
|
||||
int index = BinarySearch(list, offset, size);
|
||||
|
||||
@ -187,10 +189,12 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
|
||||
do
|
||||
{
|
||||
yield return list[index++];
|
||||
(result ??= []).Add(list[index++]);
|
||||
}
|
||||
while (index < list.Count && list[index].OverlapsWith(offset, size));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static int BinarySearch(List<Range> list, int offset, int size)
|
||||
|
@ -92,7 +92,7 @@ namespace Ryujinx.Graphics.Vulkan
|
||||
DriverId.MesaDozen => "Dozen",
|
||||
DriverId.MesaNvk => "NVK",
|
||||
DriverId.ImaginationOpenSourceMesa => "Imagination (Open)",
|
||||
DriverId.MesaAgxv => "Honeykrisp",
|
||||
DriverId.MesaHoneykrisp => "Honeykrisp",
|
||||
_ => id.ToString(),
|
||||
};
|
||||
}
|
||||
|
@ -26,10 +26,20 @@ namespace Ryujinx.HLE.HOS.Applets
|
||||
{
|
||||
_normalSession = normalSession;
|
||||
_interactiveSession = interactiveSession;
|
||||
|
||||
// TODO(jduncanator): Parse PlayerSelectConfig from input data
|
||||
_normalSession.Push(BuildResponse());
|
||||
|
||||
|
||||
UserProfile selected = _system.Device.UIHandler.ShowPlayerSelectDialog();
|
||||
if (selected == null)
|
||||
{
|
||||
_normalSession.Push(BuildResponse());
|
||||
}
|
||||
else if (selected.UserId == new UserId("00000000000000000000000000000080"))
|
||||
{
|
||||
_normalSession.Push(BuildGuestResponse());
|
||||
}
|
||||
else
|
||||
{
|
||||
_normalSession.Push(BuildResponse(selected));
|
||||
}
|
||||
AppletStateChanged?.Invoke(this, null);
|
||||
|
||||
_system.ReturnFocus();
|
||||
@ -37,16 +47,34 @@ namespace Ryujinx.HLE.HOS.Applets
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
private byte[] BuildResponse()
|
||||
private byte[] BuildResponse(UserProfile selectedUser)
|
||||
{
|
||||
UserProfile currentUser = _system.AccountManager.LastOpenedUser;
|
||||
|
||||
using MemoryStream stream = MemoryStreamManager.Shared.GetStream();
|
||||
using BinaryWriter writer = new(stream);
|
||||
|
||||
writer.Write((ulong)PlayerSelectResult.Success);
|
||||
|
||||
currentUser.UserId.Write(writer);
|
||||
selectedUser.UserId.Write(writer);
|
||||
|
||||
return stream.ToArray();
|
||||
}
|
||||
|
||||
private byte[] BuildGuestResponse()
|
||||
{
|
||||
using MemoryStream stream = MemoryStreamManager.Shared.GetStream();
|
||||
using BinaryWriter writer = new(stream);
|
||||
|
||||
writer.Write(new byte());
|
||||
|
||||
return stream.ToArray();
|
||||
}
|
||||
|
||||
private byte[] BuildResponse()
|
||||
{
|
||||
using MemoryStream stream = MemoryStreamManager.Shared.GetStream();
|
||||
using BinaryWriter writer = new(stream);
|
||||
|
||||
writer.Write((ulong)PlayerSelectResult.Failure);
|
||||
|
||||
return stream.ToArray();
|
||||
}
|
||||
|
@ -284,7 +284,7 @@ namespace Ryujinx.HLE.HOS
|
||||
ProcessCreationInfo creationInfo = new("Service", 1, 0, 0x8000000, 1, Flags, 0, 0);
|
||||
|
||||
uint[] defaultCapabilities = {
|
||||
0x030363F7,
|
||||
(((uint)KScheduler.CpuCoresCount - 1) << 24) + (((uint)KScheduler.CpuCoresCount - 1) << 16) + 0x63F7u,
|
||||
0x1FFFFFCF,
|
||||
0x207FFFEF,
|
||||
0x47E0060F,
|
||||
|
@ -63,6 +63,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
TickSource = tickSource;
|
||||
Device = device;
|
||||
Memory = memory;
|
||||
KScheduler.CpuCoresCount = device.CpuCoresCount;
|
||||
|
||||
Running = true;
|
||||
|
||||
|
@ -37,7 +37,7 @@ namespace Ryujinx.HLE.HOS.Kernel
|
||||
return result;
|
||||
}
|
||||
|
||||
process.DefaultCpuCore = 3;
|
||||
process.DefaultCpuCore = KScheduler.CpuCoresCount - 1;
|
||||
|
||||
context.Processes.TryAdd(process.Pid, process);
|
||||
|
||||
|
@ -277,7 +277,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||
return result;
|
||||
}
|
||||
|
||||
result = Capabilities.InitializeForUser(capabilities, MemoryManager);
|
||||
result = Capabilities.InitializeForUser(capabilities, MemoryManager, IsApplication);
|
||||
|
||||
if (result != Result.Success)
|
||||
{
|
||||
|
@ -35,15 +35,15 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||
DebuggingFlags &= ~3u;
|
||||
KernelReleaseVersion = KProcess.KernelVersionPacked;
|
||||
|
||||
return Parse(capabilities, memoryManager);
|
||||
return Parse(capabilities, memoryManager, false);
|
||||
}
|
||||
|
||||
public Result InitializeForUser(ReadOnlySpan<uint> capabilities, KPageTableBase memoryManager)
|
||||
public Result InitializeForUser(ReadOnlySpan<uint> capabilities, KPageTableBase memoryManager, bool isApplication)
|
||||
{
|
||||
return Parse(capabilities, memoryManager);
|
||||
return Parse(capabilities, memoryManager, isApplication);
|
||||
}
|
||||
|
||||
private Result Parse(ReadOnlySpan<uint> capabilities, KPageTableBase memoryManager)
|
||||
private Result Parse(ReadOnlySpan<uint> capabilities, KPageTableBase memoryManager, bool isApplication)
|
||||
{
|
||||
int mask0 = 0;
|
||||
int mask1 = 0;
|
||||
@ -54,7 +54,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||
|
||||
if (cap.GetCapabilityType() != CapabilityType.MapRange)
|
||||
{
|
||||
Result result = ParseCapability(cap, ref mask0, ref mask1, memoryManager);
|
||||
Result result = ParseCapability(cap, ref mask0, ref mask1, memoryManager, isApplication);
|
||||
|
||||
if (result != Result.Success)
|
||||
{
|
||||
@ -120,7 +120,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||
return Result.Success;
|
||||
}
|
||||
|
||||
private Result ParseCapability(uint cap, ref int mask0, ref int mask1, KPageTableBase memoryManager)
|
||||
private Result ParseCapability(uint cap, ref int mask0, ref int mask1, KPageTableBase memoryManager, bool isApplication)
|
||||
{
|
||||
CapabilityType code = cap.GetCapabilityType();
|
||||
|
||||
@ -176,6 +176,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
||||
AllowedCpuCoresMask = GetMaskFromMinMax(lowestCpuCore, highestCpuCore);
|
||||
AllowedThreadPriosMask = GetMaskFromMinMax(lowestThreadPrio, highestThreadPrio);
|
||||
|
||||
if (isApplication)
|
||||
Ryujinx.Common.Logging.Logger.Info?.Print(Ryujinx.Common.Logging.LogClass.Application, $"Application requested cores with index range {lowestCpuCore} to {highestCpuCore}");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -2683,7 +2683,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
||||
return KernelResult.InvalidCombination;
|
||||
}
|
||||
|
||||
if ((uint)preferredCore > 3)
|
||||
if ((uint)preferredCore > KScheduler.CpuCoresCount - 1)
|
||||
{
|
||||
if ((preferredCore | 2) != -1)
|
||||
{
|
||||
|
@ -9,13 +9,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||
partial class KScheduler : IDisposable
|
||||
{
|
||||
public const int PrioritiesCount = 64;
|
||||
public const int CpuCoresCount = 4;
|
||||
public static int CpuCoresCount;
|
||||
|
||||
private const int RoundRobinTimeQuantumMs = 10;
|
||||
|
||||
private static readonly int[] _preemptionPriorities = { 59, 59, 59, 63 };
|
||||
|
||||
private static readonly int[] _srcCoresHighestPrioThreads = new int[CpuCoresCount];
|
||||
private static int[] _srcCoresHighestPrioThreads;
|
||||
|
||||
private readonly KernelContext _context;
|
||||
private readonly int _coreId;
|
||||
@ -47,6 +45,16 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||
_coreId = coreId;
|
||||
|
||||
_currentThread = null;
|
||||
|
||||
if (_srcCoresHighestPrioThreads == null)
|
||||
{
|
||||
_srcCoresHighestPrioThreads = new int[CpuCoresCount];
|
||||
}
|
||||
}
|
||||
|
||||
private static int PreemptionPriorities(int index)
|
||||
{
|
||||
return index == CpuCoresCount - 1 ? 63 : 59;
|
||||
}
|
||||
|
||||
public static ulong SelectThreads(KernelContext context)
|
||||
@ -437,7 +445,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
||||
|
||||
for (int core = 0; core < CpuCoresCount; core++)
|
||||
{
|
||||
RotateScheduledQueue(context, core, _preemptionPriorities[core]);
|
||||
RotateScheduledQueue(context, core, PreemptionPriorities(core));
|
||||
}
|
||||
|
||||
context.CriticalSection.Leave();
|
||||
|
BIN
src/Ryujinx.HLE/HOS/Services/Account/Acc/GuestUserImage.jpg
Normal file
BIN
src/Ryujinx.HLE/HOS/Services/Account/Acc/GuestUserImage.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.8 KiB |
@ -702,6 +702,18 @@ namespace Ryujinx.HLE.HOS.Services.Hid
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[CommandCmif(92)]
|
||||
// SetGestureOutputRanges(pid, ushort Unknown0)
|
||||
public ResultCode SetGestureOutputRanges(ServiceCtx context)
|
||||
{
|
||||
ulong pid = context.Request.HandleDesc.PId;
|
||||
ushort unknown0 = context.RequestData.ReadUInt16();
|
||||
|
||||
Logger.Stub?.PrintStub(LogClass.ServiceHid, new { pid, unknown0 });
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[CommandCmif(100)]
|
||||
// SetSupportedNpadStyleSet(pid, nn::applet::AppletResourceUserId, nn::hid::NpadStyleTag)
|
||||
|
@ -24,14 +24,14 @@ namespace Ryujinx.HLE.HOS.Services
|
||||
// not large enough.
|
||||
private const int PointerBufferSize = 0x8000;
|
||||
|
||||
private readonly static uint[] _defaultCapabilities = {
|
||||
0x030363F7,
|
||||
private static uint[] _defaultCapabilities => [
|
||||
(((uint)KScheduler.CpuCoresCount - 1) << 24) + (((uint)KScheduler.CpuCoresCount - 1) << 16) + 0x63F7u,
|
||||
0x1FFFFFCF,
|
||||
0x207FFFEF,
|
||||
0x47E0060F,
|
||||
0x0048BFFF,
|
||||
0x01007FFF,
|
||||
};
|
||||
];
|
||||
|
||||
// The amount of time Dispose() will wait to Join() the thread executing the ServerLoop()
|
||||
private static readonly TimeSpan _threadJoinTimeout = TimeSpan.FromSeconds(3);
|
||||
|
@ -26,7 +26,17 @@ namespace Ryujinx.HLE.Loaders.Processes
|
||||
|
||||
private ulong _latestPid;
|
||||
|
||||
public ProcessResult ActiveApplication => _processesByPid[_latestPid];
|
||||
public ProcessResult ActiveApplication
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!_processesByPid.TryGetValue(_latestPid, out ProcessResult value))
|
||||
throw new RyujinxException(
|
||||
$"The HLE Process map did not have a process with ID {_latestPid}. Are you missing firmware?");
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
public ProcessLoader(Switch device)
|
||||
{
|
||||
|
@ -48,6 +48,7 @@
|
||||
<EmbeddedResource Include="HOS\Applets\SoftwareKeyboard\Resources\Icon_BtnB.png" />
|
||||
<EmbeddedResource Include="HOS\Applets\SoftwareKeyboard\Resources\Icon_KeyF6.png" />
|
||||
<EmbeddedResource Include="HOS\Services\Account\Acc\DefaultUserImage.jpg" />
|
||||
<EmbeddedResource Include="HOS\Services\Account\Acc\GuestUserImage.jpg" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
@ -32,6 +32,8 @@ namespace Ryujinx.HLE
|
||||
public TamperMachine TamperMachine { get; }
|
||||
public IHostUIHandler UIHandler { get; }
|
||||
|
||||
public int CpuCoresCount = 4; //Switch 1 has 4 cores
|
||||
|
||||
public VSyncMode VSyncMode { get; set; } = VSyncMode.Switch;
|
||||
public bool CustomVSyncIntervalEnabled { get; set; } = false;
|
||||
public int CustomVSyncInterval { get; set; }
|
||||
|
@ -1,4 +1,5 @@
|
||||
using Ryujinx.HLE.HOS.Applets;
|
||||
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
||||
using Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.ApplicationProxy.Types;
|
||||
|
||||
namespace Ryujinx.HLE.UI
|
||||
@ -59,5 +60,11 @@ namespace Ryujinx.HLE.UI
|
||||
/// Gets fonts and colors used by the host.
|
||||
/// </summary>
|
||||
IHostUITheme HostUITheme { get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Displays the player select dialog and returns the selected profile.
|
||||
/// </summary>
|
||||
UserProfile ShowPlayerSelectDialog();
|
||||
}
|
||||
}
|
||||
|
@ -1,36 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<DefaultItemExcludes>$(DefaultItemExcludes);._*</DefaultItemExcludes>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="Resources\Controller_JoyConLeft.svg" />
|
||||
<None Remove="Resources\Controller_JoyConPair.svg" />
|
||||
<None Remove="Resources\Controller_JoyConRight.svg" />
|
||||
<None Remove="Resources\Controller_ProCon.svg" />
|
||||
<None Remove="Resources\Icon_NCA.png" />
|
||||
<None Remove="Resources\Icon_NRO.png" />
|
||||
<None Remove="Resources\Icon_NSO.png" />
|
||||
<None Remove="Resources\Icon_NSP.png" />
|
||||
<None Remove="Resources\Icon_XCI.png" />
|
||||
<None Remove="Resources\Logo_Amiibo.png" />
|
||||
<None Remove="Resources\Logo_Discord.png" />
|
||||
<None Remove="Resources\Logo_GitHub.png" />
|
||||
<None Remove="Resources\Logo_Ryujinx.png" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DiscordRichPresence" />
|
||||
<PackageReference Include="DynamicData" />
|
||||
<PackageReference Include="securifybv.ShellLink" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Ryujinx.Common\Ryujinx.Common.csproj" />
|
||||
<ProjectReference Include="..\Ryujinx.HLE\Ryujinx.HLE.csproj" />
|
||||
<ProjectReference Include="..\Ryujinx.Graphics.Vulkan\Ryujinx.Graphics.Vulkan.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
@ -19,7 +19,7 @@ namespace Ryujinx.UI.LocaleGenerator
|
||||
|
||||
StringBuilder enumSourceBuilder = new();
|
||||
enumSourceBuilder.AppendLine("namespace Ryujinx.Ava.Common.Locale;");
|
||||
enumSourceBuilder.AppendLine("internal enum LocaleKeys");
|
||||
enumSourceBuilder.AppendLine("public enum LocaleKeys");
|
||||
enumSourceBuilder.AppendLine("{");
|
||||
foreach (var line in lines)
|
||||
{
|
||||
|
@ -489,7 +489,7 @@ namespace Ryujinx.Ava
|
||||
|
||||
Dispatcher.UIThread.InvokeAsync(() =>
|
||||
{
|
||||
_viewModel.Title = TitleHelper.ActiveApplicationTitle(Device.Processes.ActiveApplication, Program.Version);
|
||||
_viewModel.Title = TitleHelper.ActiveApplicationTitle(Device.Processes.ActiveApplication, Program.Version, !ConfigurationState.Instance.ShowTitleBar);
|
||||
});
|
||||
|
||||
_viewModel.SetUiProgressHandlers(Device);
|
||||
@ -872,7 +872,7 @@ namespace Ryujinx.Ava
|
||||
Device?.System.TogglePauseEmulation(false);
|
||||
|
||||
_viewModel.IsPaused = false;
|
||||
_viewModel.Title = TitleHelper.ActiveApplicationTitle(Device?.Processes.ActiveApplication, Program.Version);
|
||||
_viewModel.Title = TitleHelper.ActiveApplicationTitle(Device?.Processes.ActiveApplication, Program.Version, !ConfigurationState.Instance.ShowTitleBar);
|
||||
Logger.Info?.Print(LogClass.Emulation, "Emulation was resumed");
|
||||
}
|
||||
|
||||
@ -881,7 +881,7 @@ namespace Ryujinx.Ava
|
||||
Device?.System.TogglePauseEmulation(true);
|
||||
|
||||
_viewModel.IsPaused = true;
|
||||
_viewModel.Title = TitleHelper.ActiveApplicationTitle(Device?.Processes.ActiveApplication, Program.Version, LocaleManager.Instance[LocaleKeys.Paused]);
|
||||
_viewModel.Title = TitleHelper.ActiveApplicationTitle(Device?.Processes.ActiveApplication, Program.Version, !ConfigurationState.Instance.ShowTitleBar, LocaleManager.Instance[LocaleKeys.Paused]);
|
||||
Logger.Info?.Print(LogClass.Emulation, "Emulation was paused");
|
||||
}
|
||||
|
||||
|
10
src/Ryujinx/Assets/Fonts/Mono/AUTHORS.txt
Normal file
10
src/Ryujinx/Assets/Fonts/Mono/AUTHORS.txt
Normal file
@ -0,0 +1,10 @@
|
||||
# This is the official list of project authors for copyright purposes.
|
||||
# This file is distinct from the CONTRIBUTORS.txt file.
|
||||
# See the latter for an explanation.
|
||||
#
|
||||
# Names should be added to this file as:
|
||||
# Name or Organization <email address>
|
||||
|
||||
JetBrains <>
|
||||
Philipp Nurullin <philipp.nurullin@jetbrains.com>
|
||||
Konstantin Bulenkov <kb@jetbrains.com>
|
BIN
src/Ryujinx/Assets/Fonts/Mono/JetBrainsMonoNL-Bold.ttf
Normal file
BIN
src/Ryujinx/Assets/Fonts/Mono/JetBrainsMonoNL-Bold.ttf
Normal file
Binary file not shown.
BIN
src/Ryujinx/Assets/Fonts/Mono/JetBrainsMonoNL-BoldItalic.ttf
Normal file
BIN
src/Ryujinx/Assets/Fonts/Mono/JetBrainsMonoNL-BoldItalic.ttf
Normal file
Binary file not shown.
BIN
src/Ryujinx/Assets/Fonts/Mono/JetBrainsMonoNL-Italic.ttf
Normal file
BIN
src/Ryujinx/Assets/Fonts/Mono/JetBrainsMonoNL-Italic.ttf
Normal file
Binary file not shown.
BIN
src/Ryujinx/Assets/Fonts/Mono/JetBrainsMonoNL-Regular.ttf
Normal file
BIN
src/Ryujinx/Assets/Fonts/Mono/JetBrainsMonoNL-Regular.ttf
Normal file
Binary file not shown.
93
src/Ryujinx/Assets/Fonts/Mono/OFL.txt
Normal file
93
src/Ryujinx/Assets/Fonts/Mono/OFL.txt
Normal file
@ -0,0 +1,93 @@
|
||||
Copyright 2020 The JetBrains Mono Project Authors (https://github.com/JetBrains/JetBrainsMono)
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
https://scripts.sil.org/OFL
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
@ -402,7 +402,7 @@
|
||||
<x:Double x:Key="ControlContentThemeFontSize">13</x:Double>
|
||||
<x:Double x:Key="MenuItemHeight">26</x:Double>
|
||||
<x:Double x:Key="TabItemMinHeight">28</x:Double>
|
||||
<x:Double x:Key="ContentDialogMaxWidth">700</x:Double>
|
||||
<x:Double x:Key="ContentDialogMaxWidth">900</x:Double>
|
||||
<x:Double x:Key="ContentDialogMaxHeight">756</x:Double>
|
||||
</Styles.Resources>
|
||||
</Styles>
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -4,11 +4,11 @@ namespace Ryujinx.Ava.Common
|
||||
{
|
||||
public static class ThemeManager
|
||||
{
|
||||
public static event EventHandler ThemeChanged;
|
||||
public static event Action ThemeChanged;
|
||||
|
||||
public static void OnThemeChanged()
|
||||
{
|
||||
ThemeChanged?.Invoke(null, EventArgs.Empty);
|
||||
ThemeChanged?.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
using DiscordRPC;
|
||||
using Gommon;
|
||||
using Humanizer;
|
||||
using Humanizer.Localisation;
|
||||
using Ryujinx.Ava.Utilities;
|
||||
using Ryujinx.Ava.Utilities.AppLibrary;
|
||||
using Ryujinx.Ava.Utilities.Configuration;
|
||||
using Ryujinx.Common;
|
||||
@ -45,16 +47,7 @@ namespace Ryujinx.Ava
|
||||
};
|
||||
|
||||
ConfigurationState.Instance.EnableDiscordIntegration.Event += Update;
|
||||
TitleIDs.CurrentApplication.Event += (_, e) =>
|
||||
{
|
||||
if (e.NewValue)
|
||||
SwitchToPlayingState(
|
||||
ApplicationLibrary.LoadAndSaveMetaData(e.NewValue),
|
||||
Switch.Shared.Processes.ActiveApplication
|
||||
);
|
||||
else
|
||||
SwitchToMainState();
|
||||
};
|
||||
TitleIDs.CurrentApplication.Event += (_, e) => Use(e.NewValue);
|
||||
}
|
||||
|
||||
private static void Update(object sender, ReactiveEventArgs<bool> evnt)
|
||||
@ -75,11 +68,23 @@ namespace Ryujinx.Ava
|
||||
_discordClient = new DiscordRpcClient(ApplicationId);
|
||||
|
||||
_discordClient.Initialize();
|
||||
_discordClient.SetPresence(_discordPresenceMain);
|
||||
|
||||
Use(TitleIDs.CurrentApplication);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void Use(Optional<string> titleId)
|
||||
{
|
||||
if (titleId.TryGet(out string tid))
|
||||
SwitchToPlayingState(
|
||||
ApplicationLibrary.LoadAndSaveMetaData(tid),
|
||||
Switch.Shared.Processes.ActiveApplication
|
||||
);
|
||||
else
|
||||
SwitchToMainState();
|
||||
}
|
||||
|
||||
private static void SwitchToPlayingState(ApplicationMetadata appMeta, ProcessResult procRes)
|
||||
{
|
||||
_discordClient?.SetPresence(new RichPresence
|
||||
@ -93,7 +98,7 @@ namespace Ryujinx.Ava
|
||||
},
|
||||
Details = TruncateToByteLength($"Playing {appMeta.Title}"),
|
||||
State = appMeta.LastPlayed.HasValue && appMeta.TimePlayed.TotalSeconds > 5
|
||||
? $"Total play time: {appMeta.TimePlayed.Humanize(2, false, maxUnit: TimeUnit.Hour)}"
|
||||
? $"Total play time: {ValueFormatUtils.FormatTimeSpan(appMeta.TimePlayed)}"
|
||||
: "Never played",
|
||||
Timestamps = Timestamps.Now
|
||||
});
|
||||
|
@ -1,4 +1,4 @@
|
||||
using DiscordRPC;
|
||||
using DiscordRPC;
|
||||
using LibHac.Tools.FsSystem;
|
||||
using Ryujinx.Audio.Backends.SDL2;
|
||||
using Ryujinx.Ava;
|
||||
|
@ -228,8 +228,6 @@ namespace Ryujinx.Headless
|
||||
_inputConfiguration ??= [];
|
||||
_enableKeyboard = option.EnableKeyboard;
|
||||
_enableMouse = option.EnableMouse;
|
||||
|
||||
|
||||
|
||||
LoadPlayerConfiguration(option.InputProfile1Name, option.InputId1, PlayerIndex.Player1);
|
||||
LoadPlayerConfiguration(option.InputProfile2Name, option.InputId2, PlayerIndex.Player2);
|
||||
@ -301,7 +299,10 @@ namespace Ryujinx.Headless
|
||||
_userChannelPersistence.ShouldRestart = false;
|
||||
}
|
||||
|
||||
_inputManager.Dispose();
|
||||
try
|
||||
{
|
||||
_inputManager.Dispose();
|
||||
} catch {}
|
||||
|
||||
return;
|
||||
|
||||
@ -338,12 +339,12 @@ namespace Ryujinx.Headless
|
||||
{
|
||||
string label = state switch
|
||||
{
|
||||
LoadState => $"PTC : {current}/{total}",
|
||||
ShaderCacheState => $"Shaders : {current}/{total}",
|
||||
_ => throw new ArgumentException($"Unknown Progress Handler type {typeof(T)}"),
|
||||
LoadState => "PTC",
|
||||
ShaderCacheState => "Shaders",
|
||||
_ => throw new ArgumentException($"Unknown Progress Handler type {typeof(T)}")
|
||||
};
|
||||
|
||||
Logger.Info?.Print(LogClass.Application, label);
|
||||
Logger.Info?.Print(LogClass.Application, $"{label} : {current}/{total}");
|
||||
}
|
||||
|
||||
private static WindowBase CreateWindow(Options options)
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 3.9 KiB |
@ -1,21 +0,0 @@
|
||||
using System;
|
||||
|
||||
namespace Ryujinx.Headless
|
||||
{
|
||||
class StatusUpdatedEventArgs(
|
||||
string vSyncMode,
|
||||
string dockedMode,
|
||||
string aspectRatio,
|
||||
string gameStatus,
|
||||
string fifoStatus,
|
||||
string gpuName)
|
||||
: EventArgs
|
||||
{
|
||||
public string VSyncMode = vSyncMode;
|
||||
public string DockedMode = dockedMode;
|
||||
public string AspectRatio = aspectRatio;
|
||||
public string GameStatus = gameStatus;
|
||||
public string FifoStatus = fifoStatus;
|
||||
public string GpuName = gpuName;
|
||||
}
|
||||
}
|
@ -26,7 +26,7 @@ namespace Ryujinx.Headless
|
||||
bool ignoreControllerApplet)
|
||||
: base(inputManager, glLogLevel, aspectRatio, enableMouse, hideCursorMode, ignoreControllerApplet) { }
|
||||
|
||||
public override SDL_WindowFlags GetWindowFlags() => SDL_WindowFlags.SDL_WINDOW_METAL;
|
||||
public override SDL_WindowFlags WindowFlags => SDL_WindowFlags.SDL_WINDOW_METAL;
|
||||
|
||||
protected override void InitializeWindowRenderer()
|
||||
{
|
@ -108,8 +108,7 @@ namespace Ryujinx.Headless
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private readonly GraphicsDebugLevel _glLogLevel;
|
||||
|
||||
private SDL2OpenGLContext _openGLContext;
|
||||
|
||||
public OpenGLWindow(
|
||||
@ -121,15 +120,14 @@ namespace Ryujinx.Headless
|
||||
bool ignoreControllerApplet)
|
||||
: base(inputManager, glLogLevel, aspectRatio, enableMouse, hideCursorMode, ignoreControllerApplet)
|
||||
{
|
||||
_glLogLevel = glLogLevel;
|
||||
}
|
||||
|
||||
public override SDL_WindowFlags GetWindowFlags() => SDL_WindowFlags.SDL_WINDOW_OPENGL;
|
||||
public override SDL_WindowFlags WindowFlags => SDL_WindowFlags.SDL_WINDOW_OPENGL;
|
||||
|
||||
protected override void InitializeWindowRenderer()
|
||||
{
|
||||
// Ensure to not share this context with other contexts before this point.
|
||||
SetupOpenGLAttributes(false, _glLogLevel);
|
||||
SetupOpenGLAttributes(false, GlLogLevel);
|
||||
nint context = SDL_GL_CreateContext(WindowHandle);
|
||||
CheckResult(SDL_GL_SetSwapInterval(1));
|
||||
|
@ -10,8 +10,6 @@ namespace Ryujinx.Headless
|
||||
{
|
||||
class VulkanWindow : WindowBase
|
||||
{
|
||||
private readonly GraphicsDebugLevel _glLogLevel;
|
||||
|
||||
public VulkanWindow(
|
||||
InputManager inputManager,
|
||||
GraphicsDebugLevel glLogLevel,
|
||||
@ -21,10 +19,9 @@ namespace Ryujinx.Headless
|
||||
bool ignoreControllerApplet)
|
||||
: base(inputManager, glLogLevel, aspectRatio, enableMouse, hideCursorMode, ignoreControllerApplet)
|
||||
{
|
||||
_glLogLevel = glLogLevel;
|
||||
}
|
||||
|
||||
public override SDL_WindowFlags GetWindowFlags() => SDL_WindowFlags.SDL_WINDOW_VULKAN;
|
||||
public override SDL_WindowFlags WindowFlags => SDL_WindowFlags.SDL_WINDOW_VULKAN;
|
||||
|
||||
protected override void InitializeWindowRenderer() { }
|
||||
|
@ -1,14 +1,15 @@
|
||||
using Humanizer;
|
||||
using LibHac.Tools.Fs;
|
||||
using Ryujinx.Ava;
|
||||
using Ryujinx.Ava.UI.Models;
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Common.Configuration;
|
||||
using Ryujinx.Common.Configuration.Hid;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Graphics.GAL;
|
||||
using Ryujinx.Graphics.GAL.Multithreading;
|
||||
using Ryujinx.Graphics.Gpu;
|
||||
using Ryujinx.Graphics.OpenGL;
|
||||
using Ryujinx.HLE.HOS.Applets;
|
||||
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
||||
using Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.ApplicationProxy.Types;
|
||||
using Ryujinx.HLE.UI;
|
||||
using Ryujinx.Input;
|
||||
@ -26,6 +27,7 @@ using static SDL2.SDL;
|
||||
using AntiAliasing = Ryujinx.Common.Configuration.AntiAliasing;
|
||||
using ScalingFilter = Ryujinx.Common.Configuration.ScalingFilter;
|
||||
using Switch = Ryujinx.HLE.Switch;
|
||||
using UserProfile = Ryujinx.HLE.HOS.Services.Account.Acc.UserProfile;
|
||||
|
||||
namespace Ryujinx.Headless
|
||||
{
|
||||
@ -53,8 +55,6 @@ namespace Ryujinx.Headless
|
||||
public Switch Device { get; private set; }
|
||||
public IRenderer Renderer { get; private set; }
|
||||
|
||||
public event EventHandler<StatusUpdatedEventArgs> StatusUpdatedEvent;
|
||||
|
||||
protected nint WindowHandle { get; set; }
|
||||
|
||||
public IHostUITheme HostUITheme { get; }
|
||||
@ -72,7 +72,7 @@ namespace Ryujinx.Headless
|
||||
protected SDL2MouseDriver MouseDriver;
|
||||
private readonly InputManager _inputManager;
|
||||
private readonly IKeyboard _keyboardInterface;
|
||||
private readonly GraphicsDebugLevel _glLogLevel;
|
||||
protected readonly GraphicsDebugLevel GlLogLevel;
|
||||
private readonly Stopwatch _chrono;
|
||||
private readonly long _ticksPerFrame;
|
||||
private readonly CancellationTokenSource _gpuCancellationTokenSource;
|
||||
@ -104,7 +104,7 @@ namespace Ryujinx.Headless
|
||||
NpadManager = _inputManager.CreateNpadManager();
|
||||
TouchScreenManager = _inputManager.CreateTouchScreenManager();
|
||||
_keyboardInterface = (IKeyboard)_inputManager.KeyboardDriver.GetGamepad("0");
|
||||
_glLogLevel = glLogLevel;
|
||||
GlLogLevel = glLogLevel;
|
||||
_chrono = new Stopwatch();
|
||||
_ticksPerFrame = Stopwatch.Frequency / TargetFps;
|
||||
_gpuCancellationTokenSource = new CancellationTokenSource();
|
||||
@ -137,7 +137,7 @@ namespace Ryujinx.Headless
|
||||
|
||||
private void SetWindowIcon()
|
||||
{
|
||||
Stream iconStream = typeof(Program).Assembly.GetManifestResourceStream("HeadlessLogo");
|
||||
Stream iconStream = EmbeddedResources.GetStream("Ryujinx/Assets/UIImages/Logo_Ryujinx.png");
|
||||
byte[] iconBytes = new byte[iconStream!.Length];
|
||||
|
||||
if (iconStream.Read(iconBytes, 0, iconBytes.Length) != iconBytes.Length)
|
||||
@ -191,7 +191,7 @@ namespace Ryujinx.Headless
|
||||
FullscreenFlag = SDL_WindowFlags.SDL_WINDOW_FULLSCREEN_DESKTOP;
|
||||
}
|
||||
|
||||
WindowHandle = SDL_CreateWindow($"Ryujinx {Program.Version}{titleNameSection}{titleVersionSection}{titleIdSection}{titleArchSection}", SDL_WINDOWPOS_CENTERED_DISPLAY(DisplayId), SDL_WINDOWPOS_CENTERED_DISPLAY(DisplayId), Width, Height, DefaultFlags | FullscreenFlag | GetWindowFlags());
|
||||
WindowHandle = SDL_CreateWindow($"Ryujinx {Program.Version}{titleNameSection}{titleVersionSection}{titleIdSection}{titleArchSection}", SDL_WINDOWPOS_CENTERED_DISPLAY(DisplayId), SDL_WINDOWPOS_CENTERED_DISPLAY(DisplayId), Width, Height, DefaultFlags | FullscreenFlag | WindowFlags);
|
||||
|
||||
if (WindowHandle == nint.Zero)
|
||||
{
|
||||
@ -246,7 +246,7 @@ namespace Ryujinx.Headless
|
||||
|
||||
protected abstract void SwapBuffers();
|
||||
|
||||
public abstract SDL_WindowFlags GetWindowFlags();
|
||||
public abstract SDL_WindowFlags WindowFlags { get; }
|
||||
|
||||
private string GetGpuDriverName()
|
||||
{
|
||||
@ -268,7 +268,7 @@ namespace Ryujinx.Headless
|
||||
{
|
||||
InitializeWindowRenderer();
|
||||
|
||||
Device.Gpu.Renderer.Initialize(_glLogLevel);
|
||||
Device.Gpu.Renderer.Initialize(GlLogLevel);
|
||||
|
||||
InitializeRenderer();
|
||||
|
||||
@ -308,21 +308,6 @@ namespace Ryujinx.Headless
|
||||
|
||||
if (_ticks >= _ticksPerFrame)
|
||||
{
|
||||
string dockedMode = Device.System.State.DockedMode ? "Docked" : "Handheld";
|
||||
float scale = GraphicsConfig.ResScale;
|
||||
if (scale != 1)
|
||||
{
|
||||
dockedMode += $" ({scale}x)";
|
||||
}
|
||||
|
||||
StatusUpdatedEvent?.Invoke(this, new StatusUpdatedEventArgs(
|
||||
Device.VSyncMode.ToString(),
|
||||
dockedMode,
|
||||
Device.Configuration.AspectRatio.ToText(),
|
||||
$"{Device.Statistics.GetGameFrameRate():00.00} FPS ({Device.Statistics.GetGameFrameTime():00.00} ms)",
|
||||
$"FIFO: {Device.Statistics.GetFifoPercent():0.00} %",
|
||||
$"GPU: {_gpuDriverName}"));
|
||||
|
||||
_ticks = Math.Min(_ticks - _ticksPerFrame, _ticksPerFrame);
|
||||
}
|
||||
}
|
||||
@ -572,5 +557,10 @@ namespace Ryujinx.Headless
|
||||
SDL2Driver.Instance.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public UserProfile ShowPlayerSelectDialog()
|
||||
{
|
||||
return AccountSaveDataManager.GetLastUsedUser();
|
||||
}
|
||||
}
|
||||
}
|
@ -21,6 +21,7 @@ using Ryujinx.Graphics.Vulkan.MoltenVK;
|
||||
using Ryujinx.Headless;
|
||||
using Ryujinx.SDL2.Common;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
@ -243,16 +244,33 @@ namespace Ryujinx.Ava
|
||||
: $"Launch Mode: {AppDataManager.Mode}");
|
||||
}
|
||||
|
||||
internal static void ProcessUnhandledException(object sender, Exception ex, bool isTerminating)
|
||||
internal static void ProcessUnhandledException(object sender, Exception initialException, bool isTerminating)
|
||||
{
|
||||
Logger.Log log = Logger.Error ?? Logger.Notice;
|
||||
string message = $"Unhandled exception caught: {ex}";
|
||||
|
||||
// ReSharper disable once ConstantConditionalAccessQualifier
|
||||
if (sender?.GetType()?.AsPrettyString() is { } senderName)
|
||||
log.Print(LogClass.Application, message, senderName);
|
||||
List<Exception> exceptions = [];
|
||||
|
||||
if (initialException is AggregateException ae)
|
||||
{
|
||||
exceptions.AddRange(ae.InnerExceptions);
|
||||
}
|
||||
else
|
||||
log.PrintMsg(LogClass.Application, message);
|
||||
{
|
||||
exceptions.Add(initialException);
|
||||
}
|
||||
|
||||
foreach (var e in exceptions)
|
||||
{
|
||||
string message = $"Unhandled exception caught: {e}";
|
||||
// ReSharper disable once ConstantConditionalAccessQualifier
|
||||
if (sender?.GetType()?.AsPrettyString() is { } senderName)
|
||||
log.Print(LogClass.Application, message, senderName);
|
||||
else
|
||||
log.PrintMsg(LogClass.Application, message);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
if (isTerminating)
|
||||
Exit();
|
||||
|
@ -61,6 +61,7 @@
|
||||
<PackageReference Include="Ryujinx.Graphics.Nvdec.Dependencies" />
|
||||
<PackageReference Include="Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK" Condition="'$(RuntimeIdentifier)' != 'linux-x64' AND '$(RuntimeIdentifier)' != 'linux-arm64' AND '$(RuntimeIdentifier)' != 'win-x64'" />
|
||||
<PackageReference Include="securifybv.ShellLink" />
|
||||
<PackageReference Include="Sep" />
|
||||
<PackageReference Include="Silk.NET.Vulkan" />
|
||||
<PackageReference Include="Silk.NET.Vulkan.Extensions.EXT" />
|
||||
<PackageReference Include="Silk.NET.Vulkan.Extensions.KHR" />
|
||||
@ -113,6 +114,10 @@
|
||||
<AvaloniaResource Include="UI\**\*.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</AvaloniaResource>
|
||||
<AvaloniaResource Include="Assets\Fonts\Mono\JetBrainsMonoNL-Bold.ttf" />
|
||||
<AvaloniaResource Include="Assets\Fonts\Mono\JetBrainsMonoNL-BoldItalic.ttf" />
|
||||
<AvaloniaResource Include="Assets\Fonts\Mono\JetBrainsMonoNL-Italic.ttf" />
|
||||
<AvaloniaResource Include="Assets\Fonts\Mono\JetBrainsMonoNL-Regular.ttf" />
|
||||
<AvaloniaResource Include="Assets\Fonts\SegoeFluentIcons.ttf" />
|
||||
<AvaloniaResource Include="Assets\Styles\Themes.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
@ -140,6 +145,9 @@
|
||||
<EmbeddedResource Include="..\..\distribution\macos\shortcut-template.plist">
|
||||
<Link>Assets\ShortcutFiles\shortcut-template.plist</Link>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="..\..\docs\compatibility.csv" LogicalName="RyujinxGameCompatibilityList">
|
||||
<Link>Assets\RyujinxGameCompatibility.csv</Link>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Assets\locales.json" />
|
||||
<EmbeddedResource Include="Assets\Styles\Styles.xaml" />
|
||||
<EmbeddedResource Include="Assets\Icons\Controller_JoyConLeft.svg" />
|
||||
@ -158,9 +166,17 @@
|
||||
<EmbeddedResource Include="Assets\UIImages\Logo_GitHub_Light.png" />
|
||||
<EmbeddedResource Include="Assets\UIImages\Logo_Ryujinx.png" />
|
||||
<EmbeddedResource Include="Assets\UIImages\Logo_Ryujinx_AntiAlias.png" />
|
||||
<EmbeddedResource Include="Headless\Ryujinx.bmp" LogicalName="HeadlessLogo" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<AdditionalFiles Include="Assets\locales.json" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="Assets\Fonts\Mono\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Update="UI\Applet\UserSelectorDialog.axaml.cs">
|
||||
<DependentUpon>UserSelectorDialog.axaml</DependentUpon>
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
@ -6,6 +6,9 @@
|
||||
<Application.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary>
|
||||
<FontFamily x:Key="JetBrainsMono">avares://Ryujinx/Assets/Fonts/Mono/#JetBrains Mono</FontFamily>
|
||||
</ResourceDictionary>
|
||||
<MergeResourceInclude Source="/Assets/Styles/Themes.xaml"/>
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
|
@ -1,17 +1,24 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Threading;
|
||||
using FluentAvalonia.UI.Controls;
|
||||
using Gommon;
|
||||
using Ryujinx.Ava.Common.Locale;
|
||||
using Ryujinx.Ava.UI.Controls;
|
||||
using Ryujinx.Ava.UI.Helpers;
|
||||
using Ryujinx.Ava.UI.ViewModels;
|
||||
using Ryujinx.Ava.UI.ViewModels.Input;
|
||||
using Ryujinx.Ava.UI.Windows;
|
||||
using Ryujinx.Ava.Utilities.Configuration;
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.HLE;
|
||||
using Ryujinx.HLE.HOS.Applets;
|
||||
using Ryujinx.HLE.HOS.Applets.SoftwareKeyboard;
|
||||
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
||||
using Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.ApplicationProxy.Types;
|
||||
using Ryujinx.HLE.UI;
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
|
||||
namespace Ryujinx.Ava.UI.Applet
|
||||
@ -253,5 +260,59 @@ namespace Ryujinx.Ava.UI.Applet
|
||||
}
|
||||
|
||||
public IDynamicTextInputHandler CreateDynamicTextInputHandler() => new AvaloniaDynamicTextInputHandler(_parent);
|
||||
|
||||
public UserProfile ShowPlayerSelectDialog()
|
||||
{
|
||||
UserId selected = UserId.Null;
|
||||
byte[] defaultGuestImage = EmbeddedResources.Read("Ryujinx.HLE/HOS/Services/Account/Acc/GuestUserImage.jpg");
|
||||
UserProfile guest = new UserProfile(new UserId("00000000000000000000000000000080"), "Guest", defaultGuestImage);
|
||||
|
||||
ManualResetEvent dialogCloseEvent = new(false);
|
||||
|
||||
Dispatcher.UIThread.InvokeAsync(async () =>
|
||||
{
|
||||
ObservableCollection<BaseModel> profiles = [];
|
||||
NavigationDialogHost nav = new();
|
||||
|
||||
_parent.AccountManager.GetAllUsers()
|
||||
.OrderBy(x => x.Name)
|
||||
.ForEach(profile => profiles.Add(new Models.UserProfile(profile, nav)));
|
||||
|
||||
profiles.Add(new Models.UserProfile(guest, nav));
|
||||
UserSelectorDialogViewModel viewModel = new()
|
||||
{
|
||||
Profiles = profiles,
|
||||
SelectedUserId = _parent.AccountManager.LastOpenedUser.UserId
|
||||
};
|
||||
UserSelectorDialog content = new(viewModel);
|
||||
(selected, _) = await UserSelectorDialog.ShowInputDialog(content);
|
||||
|
||||
dialogCloseEvent.Set();
|
||||
});
|
||||
|
||||
dialogCloseEvent.WaitOne();
|
||||
|
||||
UserProfile profile = _parent.AccountManager.LastOpenedUser;
|
||||
if (selected == guest.UserId)
|
||||
{
|
||||
profile = guest;
|
||||
}
|
||||
else if (selected == UserId.Null)
|
||||
{
|
||||
profile = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (UserProfile p in _parent.AccountManager.GetAllUsers())
|
||||
{
|
||||
if (p.UserId == selected)
|
||||
{
|
||||
profile = p;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return profile;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
121
src/Ryujinx/UI/Applet/UserSelectorDialog.axaml
Normal file
121
src/Ryujinx/UI/Applet/UserSelectorDialog.axaml
Normal file
@ -0,0 +1,121 @@
|
||||
<UserControl
|
||||
x:Class="Ryujinx.Ava.UI.Applet.UserSelectorDialog"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers"
|
||||
xmlns:models="clr-namespace:Ryujinx.Ava.UI.Models"
|
||||
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
|
||||
d:DesignHeight="450"
|
||||
MinWidth="500"
|
||||
d:DesignWidth="800"
|
||||
mc:Ignorable="d"
|
||||
Focusable="True"
|
||||
x:DataType="viewModels:UserSelectorDialogViewModel">
|
||||
|
||||
<UserControl.Resources>
|
||||
<helpers:BitmapArrayValueConverter x:Key="ByteImage" />
|
||||
</UserControl.Resources>
|
||||
|
||||
<Design.DataContext>
|
||||
<viewModels:UserSelectorDialogViewModel />
|
||||
</Design.DataContext>
|
||||
|
||||
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Border
|
||||
CornerRadius="5"
|
||||
BorderBrush="{DynamicResource AppListHoverBackgroundColor}"
|
||||
BorderThickness="1">
|
||||
|
||||
<ListBox
|
||||
MaxHeight="300"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Center"
|
||||
Background="Transparent"
|
||||
ItemsSource="{Binding Profiles}"
|
||||
SelectionChanged="ProfilesList_SelectionChanged">
|
||||
|
||||
<ListBox.ItemsPanel>
|
||||
<ItemsPanelTemplate>
|
||||
<WrapPanel
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Orientation="Horizontal" />
|
||||
</ItemsPanelTemplate>
|
||||
</ListBox.ItemsPanel>
|
||||
|
||||
<ListBox.Styles>
|
||||
<Style Selector="ListBoxItem">
|
||||
<Setter Property="Margin" Value="5 5 0 5" />
|
||||
<Setter Property="CornerRadius" Value="5" />
|
||||
</Style>
|
||||
<Style Selector="Rectangle#SelectionIndicator">
|
||||
<Setter Property="Opacity" Value="0" />
|
||||
</Style>
|
||||
</ListBox.Styles>
|
||||
|
||||
<ListBox.DataTemplates>
|
||||
<DataTemplate
|
||||
DataType="models:UserProfile">
|
||||
<Grid
|
||||
PointerEntered="Grid_PointerEntered"
|
||||
PointerExited="Grid_OnPointerExited">
|
||||
<Border
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch"
|
||||
ClipToBounds="True"
|
||||
CornerRadius="5"
|
||||
Background="{Binding BackgroundColor}">
|
||||
<StackPanel
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Stretch">
|
||||
<Image
|
||||
Width="96"
|
||||
Height="96"
|
||||
HorizontalAlignment="Stretch"
|
||||
VerticalAlignment="Top"
|
||||
Source="{Binding Image, Converter={StaticResource ByteImage}}" />
|
||||
<TextBlock
|
||||
HorizontalAlignment="Stretch"
|
||||
MaxWidth="90"
|
||||
Text="{Binding Name}"
|
||||
TextAlignment="Center"
|
||||
TextWrapping="Wrap"
|
||||
TextTrimming="CharacterEllipsis"
|
||||
MaxLines="2"
|
||||
Margin="5" />
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
<DataTemplate
|
||||
DataType="viewModels:BaseModel">
|
||||
<Panel
|
||||
Height="118"
|
||||
Width="96">
|
||||
<Panel.Styles>
|
||||
<Style Selector="Panel">
|
||||
<Setter Property="Background" Value="{DynamicResource ListBoxBackground}" />
|
||||
</Style>
|
||||
</Panel.Styles>
|
||||
</Panel>
|
||||
</DataTemplate>
|
||||
</ListBox.DataTemplates>
|
||||
</ListBox>
|
||||
</Border>
|
||||
|
||||
<StackPanel
|
||||
Grid.Row="1"
|
||||
Margin="0 24 0 0"
|
||||
HorizontalAlignment="Left"
|
||||
Orientation="Horizontal"
|
||||
Spacing="10">
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</UserControl>
|
123
src/Ryujinx/UI/Applet/UserSelectorDialog.axaml.cs
Normal file
123
src/Ryujinx/UI/Applet/UserSelectorDialog.axaml.cs
Normal file
@ -0,0 +1,123 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Input;
|
||||
using FluentAvalonia.UI.Controls;
|
||||
using Ryujinx.Ava.Common.Locale;
|
||||
using Ryujinx.Ava.UI.Controls;
|
||||
using Ryujinx.Ava.UI.Helpers;
|
||||
using Ryujinx.Ava.UI.ViewModels;
|
||||
using Ryujinx.Ava.UI.ViewModels.Input;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading.Tasks;
|
||||
using UserProfile = Ryujinx.Ava.UI.Models.UserProfile;
|
||||
using UserProfileSft = Ryujinx.HLE.HOS.Services.Account.Acc.UserProfile;
|
||||
|
||||
namespace Ryujinx.Ava.UI.Applet
|
||||
{
|
||||
public partial class UserSelectorDialog : UserControl, INotifyPropertyChanged
|
||||
{
|
||||
public UserSelectorDialogViewModel ViewModel { get; set; }
|
||||
|
||||
public UserSelectorDialog(UserSelectorDialogViewModel viewModel)
|
||||
{
|
||||
InitializeComponent();
|
||||
ViewModel = viewModel;
|
||||
DataContext = ViewModel;
|
||||
}
|
||||
|
||||
private void Grid_PointerEntered(object sender, PointerEventArgs e)
|
||||
{
|
||||
if (sender is Grid { DataContext: UserProfile profile })
|
||||
{
|
||||
profile.IsPointerOver = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void Grid_OnPointerExited(object sender, PointerEventArgs e)
|
||||
{
|
||||
if (sender is Grid { DataContext: UserProfile profile })
|
||||
{
|
||||
profile.IsPointerOver = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void ProfilesList_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
if (sender is ListBox listBox)
|
||||
{
|
||||
int selectedIndex = listBox.SelectedIndex;
|
||||
|
||||
if (selectedIndex >= 0 && selectedIndex < ViewModel.Profiles.Count)
|
||||
{
|
||||
if (ViewModel.Profiles[selectedIndex] is UserProfile userProfile)
|
||||
{
|
||||
ViewModel.SelectedUserId = userProfile.UserId;
|
||||
Logger.Info?.Print(LogClass.UI, $"Selected user: {userProfile.UserId}");
|
||||
|
||||
ObservableCollection<BaseModel> newProfiles = [];
|
||||
|
||||
foreach (var item in ViewModel.Profiles)
|
||||
{
|
||||
if (item is UserProfile originalItem)
|
||||
{
|
||||
var profile = new UserProfileSft(originalItem.UserId, originalItem.Name, originalItem.Image);
|
||||
|
||||
if (profile.UserId == ViewModel.SelectedUserId)
|
||||
{
|
||||
profile.AccountState = AccountState.Open;
|
||||
}
|
||||
|
||||
newProfiles.Add(new UserProfile(profile, new NavigationDialogHost()));
|
||||
}
|
||||
}
|
||||
|
||||
ViewModel.Profiles = newProfiles;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task<(UserId Id, bool Result)> ShowInputDialog(UserSelectorDialog content)
|
||||
{
|
||||
ContentDialog contentDialog = new()
|
||||
{
|
||||
Title = LocaleManager.Instance[LocaleKeys.UserProfileWindowTitle],
|
||||
PrimaryButtonText = LocaleManager.Instance[LocaleKeys.Continue],
|
||||
SecondaryButtonText = string.Empty,
|
||||
CloseButtonText = LocaleManager.Instance[LocaleKeys.Cancel],
|
||||
Content = content,
|
||||
Padding = new Thickness(0)
|
||||
};
|
||||
|
||||
UserId result = UserId.Null;
|
||||
bool input = false;
|
||||
|
||||
void Handler(ContentDialog sender, ContentDialogClosedEventArgs eventArgs)
|
||||
{
|
||||
if (eventArgs.Result == ContentDialogResult.Primary)
|
||||
{
|
||||
if (contentDialog.Content is UserSelectorDialog view)
|
||||
{
|
||||
result = view.ViewModel.SelectedUserId;
|
||||
input = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result = UserId.Null;
|
||||
input = false;
|
||||
}
|
||||
}
|
||||
|
||||
contentDialog.Closed += Handler;
|
||||
|
||||
await ContentDialogHelper.ShowAsync(contentDialog);
|
||||
|
||||
return (result, input);
|
||||
}
|
||||
}
|
||||
}
|
@ -133,12 +133,13 @@
|
||||
Spacing="5">
|
||||
<TextBlock
|
||||
HorizontalAlignment="Stretch"
|
||||
Text="{Binding TimePlayedString}"
|
||||
Text="{Binding LastPlayedString}"
|
||||
TextAlignment="End"
|
||||
TextWrapping="Wrap" />
|
||||
<TextBlock
|
||||
HorizontalAlignment="Stretch"
|
||||
Text="{Binding LastPlayedString}"
|
||||
Text="{Binding TimePlayedString}"
|
||||
IsVisible="{Binding HasPlayedPreviously}"
|
||||
TextAlignment="End"
|
||||
TextWrapping="Wrap" />
|
||||
<TextBlock
|
||||
|
@ -7,6 +7,7 @@
|
||||
Title="Ryujinx - Waiting"
|
||||
SizeToContent="WidthAndHeight"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
CanResize="False"
|
||||
mc:Ignorable="d"
|
||||
Focusable="True">
|
||||
<Grid
|
||||
|
48
src/Ryujinx/UI/Helpers/Commands.cs
Normal file
48
src/Ryujinx/UI/Helpers/Commands.cs
Normal file
@ -0,0 +1,48 @@
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Ryujinx.Ava.UI.Helpers
|
||||
{
|
||||
#nullable enable
|
||||
public static class Commands
|
||||
{
|
||||
public static RelayCommand Create(Action action)
|
||||
=> new(action);
|
||||
public static RelayCommand CreateConditional(Action action, Func<bool> canExecute)
|
||||
=> new(action, canExecute);
|
||||
|
||||
public static RelayCommand<T> CreateWithArg<T>(Action<T?> action)
|
||||
=> new(action);
|
||||
public static RelayCommand<T> CreateConditionalWithArg<T>(Action<T?> action, Predicate<T?> canExecute)
|
||||
=> new(action, canExecute);
|
||||
|
||||
public static AsyncRelayCommand Create(Func<Task> action)
|
||||
=> new(action, AsyncRelayCommandOptions.None);
|
||||
public static AsyncRelayCommand CreateConcurrent(Func<Task> action)
|
||||
=> new(action, AsyncRelayCommandOptions.AllowConcurrentExecutions);
|
||||
public static AsyncRelayCommand CreateSilentFail(Func<Task> action)
|
||||
=> new(action, AsyncRelayCommandOptions.FlowExceptionsToTaskScheduler);
|
||||
|
||||
public static AsyncRelayCommand<T> CreateWithArg<T>(Func<T?, Task> action)
|
||||
=> new(action, AsyncRelayCommandOptions.None);
|
||||
public static AsyncRelayCommand<T> CreateConcurrentWithArg<T>(Func<T?, Task> action)
|
||||
=> new(action, AsyncRelayCommandOptions.AllowConcurrentExecutions);
|
||||
public static AsyncRelayCommand<T> CreateSilentFailWithArg<T>(Func<T?, Task> action)
|
||||
=> new(action, AsyncRelayCommandOptions.FlowExceptionsToTaskScheduler);
|
||||
|
||||
public static AsyncRelayCommand CreateConditional(Func<Task> action, Func<bool> canExecute)
|
||||
=> new(action, canExecute, AsyncRelayCommandOptions.None);
|
||||
public static AsyncRelayCommand CreateConcurrentConditional(Func<Task> action, Func<bool> canExecute)
|
||||
=> new(action, canExecute, AsyncRelayCommandOptions.AllowConcurrentExecutions);
|
||||
public static AsyncRelayCommand CreateSilentFailConditional(Func<Task> action, Func<bool> canExecute)
|
||||
=> new(action, canExecute, AsyncRelayCommandOptions.FlowExceptionsToTaskScheduler);
|
||||
|
||||
public static AsyncRelayCommand<T> CreateConditionalWithArg<T>(Func<T?, Task> action, Predicate<T?> canExecute)
|
||||
=> new(action, canExecute, AsyncRelayCommandOptions.None);
|
||||
public static AsyncRelayCommand<T> CreateConcurrentConditionalWithArg<T>(Func<T?, Task> action, Predicate<T?> canExecute)
|
||||
=> new(action, canExecute, AsyncRelayCommandOptions.AllowConcurrentExecutions);
|
||||
public static AsyncRelayCommand<T> CreateSilentFailConditionalWithArg<T>(Func<T?, Task> action, Predicate<T?> canExecute)
|
||||
=> new(action, canExecute, AsyncRelayCommandOptions.FlowExceptionsToTaskScheduler);
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
using Avalonia.Data.Converters;
|
||||
using Avalonia.Media;
|
||||
using Gommon;
|
||||
using Ryujinx.Ava.Common.Locale;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Ryujinx.Ava.UI.Helpers
|
||||
{
|
||||
public class PlayabilityStatusConverter : IValueConverter
|
||||
{
|
||||
private static readonly Lazy<PlayabilityStatusConverter> _shared = new(() => new());
|
||||
public static PlayabilityStatusConverter Shared => _shared.Value;
|
||||
|
||||
public object Convert(object value, Type _, object __, CultureInfo ___)
|
||||
=> value.Cast<LocaleKeys>() switch
|
||||
{
|
||||
LocaleKeys.CompatibilityListNothing or
|
||||
LocaleKeys.CompatibilityListBoots or
|
||||
LocaleKeys.CompatibilityListMenus => Brushes.Red,
|
||||
LocaleKeys.CompatibilityListIngame => Brushes.Yellow,
|
||||
_ => Brushes.ForestGreen
|
||||
};
|
||||
|
||||
public object ConvertBack(object value, Type _, object __, CultureInfo ___)
|
||||
=> throw new NotSupportedException();
|
||||
}
|
||||
}
|
@ -63,6 +63,7 @@ namespace Ryujinx.Ava.UI.Helpers
|
||||
public static MiniCommand Create(Action callback) => new MiniCommand<object>(_ => callback());
|
||||
public static MiniCommand Create<TArg>(Action<TArg> callback) => new MiniCommand<TArg>(callback);
|
||||
public static MiniCommand CreateFromTask(Func<Task> callback) => new MiniCommand<object>(_ => callback());
|
||||
public static MiniCommand CreateFromTask<TArg>(Func<TArg, Task> callback) => new MiniCommand<TArg>(callback);
|
||||
|
||||
public abstract bool CanExecute(object parameter);
|
||||
public abstract void Execute(object parameter);
|
||||
|
@ -1,152 +1,53 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Ryujinx.Ava.UI.ViewModels;
|
||||
using Ryujinx.Common.Configuration.Hid;
|
||||
|
||||
namespace Ryujinx.Ava.UI.Models.Input
|
||||
{
|
||||
public class HotkeyConfig : BaseModel
|
||||
public partial class HotkeyConfig : BaseModel
|
||||
{
|
||||
private Key _toggleVSyncMode;
|
||||
public Key ToggleVSyncMode
|
||||
{
|
||||
get => _toggleVSyncMode;
|
||||
set
|
||||
{
|
||||
_toggleVSyncMode = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
[ObservableProperty] private Key _toggleVSyncMode;
|
||||
|
||||
private Key _screenshot;
|
||||
public Key Screenshot
|
||||
{
|
||||
get => _screenshot;
|
||||
set
|
||||
{
|
||||
_screenshot = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
[ObservableProperty] private Key _screenshot;
|
||||
|
||||
private Key _showUI;
|
||||
public Key ShowUI
|
||||
{
|
||||
get => _showUI;
|
||||
set
|
||||
{
|
||||
_showUI = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
[ObservableProperty] private Key _showUI;
|
||||
|
||||
private Key _pause;
|
||||
public Key Pause
|
||||
{
|
||||
get => _pause;
|
||||
set
|
||||
{
|
||||
_pause = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
[ObservableProperty] private Key _pause;
|
||||
|
||||
private Key _toggleMute;
|
||||
public Key ToggleMute
|
||||
{
|
||||
get => _toggleMute;
|
||||
set
|
||||
{
|
||||
_toggleMute = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
[ObservableProperty] private Key _toggleMute;
|
||||
|
||||
private Key _resScaleUp;
|
||||
public Key ResScaleUp
|
||||
{
|
||||
get => _resScaleUp;
|
||||
set
|
||||
{
|
||||
_resScaleUp = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
[ObservableProperty] private Key _resScaleUp;
|
||||
|
||||
private Key _resScaleDown;
|
||||
public Key ResScaleDown
|
||||
{
|
||||
get => _resScaleDown;
|
||||
set
|
||||
{
|
||||
_resScaleDown = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
[ObservableProperty] private Key _resScaleDown;
|
||||
|
||||
private Key _volumeUp;
|
||||
public Key VolumeUp
|
||||
{
|
||||
get => _volumeUp;
|
||||
set
|
||||
{
|
||||
_volumeUp = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
[ObservableProperty] private Key _volumeUp;
|
||||
|
||||
private Key _volumeDown;
|
||||
public Key VolumeDown
|
||||
{
|
||||
get => _volumeDown;
|
||||
set
|
||||
{
|
||||
_volumeDown = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
[ObservableProperty] private Key _volumeDown;
|
||||
|
||||
private Key _customVSyncIntervalIncrement;
|
||||
public Key CustomVSyncIntervalIncrement
|
||||
{
|
||||
get => _customVSyncIntervalIncrement;
|
||||
set
|
||||
{
|
||||
_customVSyncIntervalIncrement = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
[ObservableProperty] private Key _customVSyncIntervalIncrement;
|
||||
|
||||
private Key _customVSyncIntervalDecrement;
|
||||
public Key CustomVSyncIntervalDecrement
|
||||
{
|
||||
get => _customVSyncIntervalDecrement;
|
||||
set
|
||||
{
|
||||
_customVSyncIntervalDecrement = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
[ObservableProperty] private Key _customVSyncIntervalDecrement;
|
||||
|
||||
public HotkeyConfig(KeyboardHotkeys config)
|
||||
{
|
||||
if (config != null)
|
||||
{
|
||||
ToggleVSyncMode = config.ToggleVSyncMode;
|
||||
Screenshot = config.Screenshot;
|
||||
ShowUI = config.ShowUI;
|
||||
Pause = config.Pause;
|
||||
ToggleMute = config.ToggleMute;
|
||||
ResScaleUp = config.ResScaleUp;
|
||||
ResScaleDown = config.ResScaleDown;
|
||||
VolumeUp = config.VolumeUp;
|
||||
VolumeDown = config.VolumeDown;
|
||||
CustomVSyncIntervalIncrement = config.CustomVSyncIntervalIncrement;
|
||||
CustomVSyncIntervalDecrement = config.CustomVSyncIntervalDecrement;
|
||||
}
|
||||
if (config == null)
|
||||
return;
|
||||
|
||||
ToggleVSyncMode = config.ToggleVSyncMode;
|
||||
Screenshot = config.Screenshot;
|
||||
ShowUI = config.ShowUI;
|
||||
Pause = config.Pause;
|
||||
ToggleMute = config.ToggleMute;
|
||||
ResScaleUp = config.ResScaleUp;
|
||||
ResScaleDown = config.ResScaleDown;
|
||||
VolumeUp = config.VolumeUp;
|
||||
VolumeDown = config.VolumeDown;
|
||||
CustomVSyncIntervalIncrement = config.CustomVSyncIntervalIncrement;
|
||||
CustomVSyncIntervalDecrement = config.CustomVSyncIntervalDecrement;
|
||||
}
|
||||
|
||||
public KeyboardHotkeys GetConfig()
|
||||
{
|
||||
var config = new KeyboardHotkeys
|
||||
public KeyboardHotkeys GetConfig() =>
|
||||
new()
|
||||
{
|
||||
ToggleVSyncMode = ToggleVSyncMode,
|
||||
Screenshot = Screenshot,
|
||||
@ -160,8 +61,5 @@ namespace Ryujinx.Ava.UI.Models.Input
|
||||
CustomVSyncIntervalIncrement = CustomVSyncIntervalIncrement,
|
||||
CustomVSyncIntervalDecrement = CustomVSyncIntervalDecrement,
|
||||
};
|
||||
|
||||
return config;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -22,5 +22,22 @@ namespace Ryujinx.Ava.UI.Models
|
||||
FifoStatus = fifoStatus;
|
||||
ShaderCount = shaderCount;
|
||||
}
|
||||
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj is not StatusUpdatedEventArgs suea) return false;
|
||||
return
|
||||
VSyncMode == suea.VSyncMode &&
|
||||
VolumeStatus == suea.VolumeStatus &&
|
||||
DockedMode == suea.DockedMode &&
|
||||
AspectRatio == suea.AspectRatio &&
|
||||
GameStatus == suea.GameStatus &&
|
||||
FifoStatus == suea.FifoStatus &&
|
||||
ShaderCount == suea.ShaderCount;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
=> HashCode.Combine(VSyncMode, VolumeStatus, AspectRatio, DockedMode, FifoStatus, GameStatus, ShaderCount);
|
||||
}
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
ThemeManager.ThemeChanged += ThemeManager_ThemeChanged;
|
||||
}
|
||||
|
||||
private void ThemeManager_ThemeChanged(object sender, EventArgs e)
|
||||
private void ThemeManager_ThemeChanged()
|
||||
{
|
||||
Dispatcher.UIThread.Post(() => UpdateLogoTheme(ConfigurationState.Instance.UI.BaseStyle.Value));
|
||||
}
|
||||
|
@ -1,21 +1,13 @@
|
||||
using Avalonia.Svg.Skia;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Ryujinx.Ava.UI.Models.Input;
|
||||
using Ryujinx.Ava.UI.Views.Input;
|
||||
|
||||
namespace Ryujinx.Ava.UI.ViewModels.Input
|
||||
{
|
||||
public class ControllerInputViewModel : BaseModel
|
||||
public partial class ControllerInputViewModel : BaseModel
|
||||
{
|
||||
private GamepadInputConfig _config;
|
||||
public GamepadInputConfig Config
|
||||
{
|
||||
get => _config;
|
||||
set
|
||||
{
|
||||
_config = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
[ObservableProperty] private GamepadInputConfig _config;
|
||||
|
||||
private bool _isLeft;
|
||||
public bool IsLeft
|
||||
@ -43,16 +35,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
|
||||
|
||||
public bool HasSides => IsLeft ^ IsRight;
|
||||
|
||||
private SvgImage _image;
|
||||
public SvgImage Image
|
||||
{
|
||||
get => _image;
|
||||
set
|
||||
{
|
||||
_image = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
[ObservableProperty] private SvgImage _image;
|
||||
|
||||
public readonly InputViewModel ParentModel;
|
||||
|
||||
|
@ -1,9 +1,8 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Collections;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls.ApplicationLifetimes;
|
||||
using Avalonia.Svg.Skia;
|
||||
using Avalonia.Threading;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Ryujinx.Ava.Common.Locale;
|
||||
using Ryujinx.Ava.Input;
|
||||
using Ryujinx.Ava.UI.Helpers;
|
||||
@ -32,7 +31,7 @@ using Key = Ryujinx.Common.Configuration.Hid.Key;
|
||||
|
||||
namespace Ryujinx.Ava.UI.ViewModels.Input
|
||||
{
|
||||
public class InputViewModel : BaseModel, IDisposable
|
||||
public partial class InputViewModel : BaseModel, IDisposable
|
||||
{
|
||||
private const string Disabled = "disabled";
|
||||
private const string ProControllerResource = "Ryujinx/Assets/Icons/Controller_ProCon.svg";
|
||||
@ -48,8 +47,8 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
|
||||
private int _controller;
|
||||
private string _controllerImage;
|
||||
private int _device;
|
||||
private object _configViewModel;
|
||||
private string _profileName;
|
||||
[ObservableProperty] private object _configViewModel;
|
||||
[ObservableProperty] private string _profileName;
|
||||
private bool _isLoaded;
|
||||
|
||||
private static readonly InputConfigJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions());
|
||||
@ -73,17 +72,6 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
|
||||
public bool IsModified { get; set; }
|
||||
public event Action NotifyChangesEvent;
|
||||
|
||||
public object ConfigViewModel
|
||||
{
|
||||
get => _configViewModel;
|
||||
set
|
||||
{
|
||||
_configViewModel = value;
|
||||
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public PlayerIndex PlayerIdChoose
|
||||
{
|
||||
get => _playerIdChoose;
|
||||
@ -200,16 +188,6 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
|
||||
}
|
||||
}
|
||||
|
||||
public string ProfileName
|
||||
{
|
||||
get => _profileName; set
|
||||
{
|
||||
_profileName = value;
|
||||
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public int Device
|
||||
{
|
||||
get => _device;
|
||||
|
@ -1,20 +1,12 @@
|
||||
using Avalonia.Svg.Skia;
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Ryujinx.Ava.UI.Models.Input;
|
||||
|
||||
namespace Ryujinx.Ava.UI.ViewModels.Input
|
||||
{
|
||||
public class KeyboardInputViewModel : BaseModel
|
||||
public partial class KeyboardInputViewModel : BaseModel
|
||||
{
|
||||
private KeyboardInputConfig _config;
|
||||
public KeyboardInputConfig Config
|
||||
{
|
||||
get => _config;
|
||||
set
|
||||
{
|
||||
_config = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
[ObservableProperty] private KeyboardInputConfig _config;
|
||||
|
||||
private bool _isLeft;
|
||||
public bool IsLeft
|
||||
@ -42,16 +34,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
|
||||
|
||||
public bool HasSides => IsLeft ^ IsRight;
|
||||
|
||||
private SvgImage _image;
|
||||
public SvgImage Image
|
||||
{
|
||||
get => _image;
|
||||
set
|
||||
{
|
||||
_image = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
[ObservableProperty] private SvgImage _image;
|
||||
|
||||
public readonly InputViewModel ParentModel;
|
||||
|
||||
|
@ -1,93 +1,23 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
|
||||
namespace Ryujinx.Ava.UI.ViewModels.Input
|
||||
{
|
||||
public class MotionInputViewModel : BaseModel
|
||||
public partial class MotionInputViewModel : BaseModel
|
||||
{
|
||||
private int _slot;
|
||||
public int Slot
|
||||
{
|
||||
get => _slot;
|
||||
set
|
||||
{
|
||||
_slot = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
[ObservableProperty] private int _slot;
|
||||
|
||||
private int _altSlot;
|
||||
public int AltSlot
|
||||
{
|
||||
get => _altSlot;
|
||||
set
|
||||
{
|
||||
_altSlot = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
[ObservableProperty] private int _altSlot;
|
||||
|
||||
private string _dsuServerHost;
|
||||
public string DsuServerHost
|
||||
{
|
||||
get => _dsuServerHost;
|
||||
set
|
||||
{
|
||||
_dsuServerHost = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
[ObservableProperty] private string _dsuServerHost;
|
||||
|
||||
private int _dsuServerPort;
|
||||
public int DsuServerPort
|
||||
{
|
||||
get => _dsuServerPort;
|
||||
set
|
||||
{
|
||||
_dsuServerPort = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
[ObservableProperty] private int _dsuServerPort;
|
||||
|
||||
private bool _mirrorInput;
|
||||
public bool MirrorInput
|
||||
{
|
||||
get => _mirrorInput;
|
||||
set
|
||||
{
|
||||
_mirrorInput = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
[ObservableProperty] private bool _mirrorInput;
|
||||
|
||||
private int _sensitivity;
|
||||
public int Sensitivity
|
||||
{
|
||||
get => _sensitivity;
|
||||
set
|
||||
{
|
||||
_sensitivity = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
[ObservableProperty] private int _sensitivity;
|
||||
|
||||
private double _gryoDeadzone;
|
||||
public double GyroDeadzone
|
||||
{
|
||||
get => _gryoDeadzone;
|
||||
set
|
||||
{
|
||||
_gryoDeadzone = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
[ObservableProperty] private double _gyroDeadzone;
|
||||
|
||||
private bool _enableCemuHookMotion;
|
||||
public bool EnableCemuHookMotion
|
||||
{
|
||||
get => _enableCemuHookMotion;
|
||||
set
|
||||
{
|
||||
_enableCemuHookMotion = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
[ObservableProperty] private bool _enableCemuHookMotion;
|
||||
}
|
||||
}
|
||||
|
@ -1,27 +1,11 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
|
||||
namespace Ryujinx.Ava.UI.ViewModels.Input
|
||||
{
|
||||
public class RumbleInputViewModel : BaseModel
|
||||
public partial class RumbleInputViewModel : BaseModel
|
||||
{
|
||||
private float _strongRumble;
|
||||
public float StrongRumble
|
||||
{
|
||||
get => _strongRumble;
|
||||
set
|
||||
{
|
||||
_strongRumble = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
[ObservableProperty] private float _strongRumble;
|
||||
|
||||
private float _weakRumble;
|
||||
public float WeakRumble
|
||||
{
|
||||
get => _weakRumble;
|
||||
set
|
||||
{
|
||||
_weakRumble = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
[ObservableProperty] private float _weakRumble;
|
||||
}
|
||||
}
|
||||
|
@ -38,7 +38,6 @@ using Ryujinx.HLE.HOS.Services.Account.Acc;
|
||||
using Ryujinx.HLE.HOS.Services.Nfc.AmiiboDecryption;
|
||||
using Ryujinx.HLE.UI;
|
||||
using Ryujinx.Input.HLE;
|
||||
using Silk.NET.Vulkan;
|
||||
using SkiaSharp;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@ -741,7 +740,10 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
Applications.ToObservableChangeSet()
|
||||
.Filter(Filter)
|
||||
.Sort(GetComparer())
|
||||
.Bind(out _appsObservableList).AsObservableList();
|
||||
#pragma warning disable MVVMTK0034
|
||||
.Bind(out _appsObservableList)
|
||||
#pragma warning restore MVVMTK0034
|
||||
.AsObservableList();
|
||||
|
||||
OnPropertyChanged(nameof(AppsObservableList));
|
||||
}
|
||||
|
14
src/Ryujinx/UI/ViewModels/UserSelectorDialogViewModel.cs
Normal file
14
src/Ryujinx/UI/ViewModels/UserSelectorDialogViewModel.cs
Normal file
@ -0,0 +1,14 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Ryujinx.HLE.HOS.Services.Account.Acc;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace Ryujinx.Ava.UI.ViewModels
|
||||
{
|
||||
public partial class UserSelectorDialogViewModel : BaseModel
|
||||
{
|
||||
|
||||
[ObservableProperty] private UserId _selectedUserId;
|
||||
|
||||
[ObservableProperty] private ObservableCollection<BaseModel> _profiles = [];
|
||||
}
|
||||
}
|
@ -56,7 +56,7 @@
|
||||
ToolTip.Tip="{ext:Locale LoadTitleUpdatesFromFolderTooltip}" />
|
||||
<MenuItem Header="{ext:Locale MenuBarFileOpenApplet}" IsEnabled="{Binding IsAppletMenuActive}" Icon="{ext:Icon mdi-launch}">
|
||||
<MenuItem
|
||||
Click="OpenMiiApplet"
|
||||
Name="MiiAppletMenuItem"
|
||||
Header="{ext:Locale MenuBarFileOpenAppletOpenMiiApplet}"
|
||||
Icon="{ext:Icon fa-solid fa-person}"
|
||||
ToolTip.Tip="{ext:Locale MenuBarFileOpenAppletOpenMiiAppletToolTip}" />
|
||||
@ -72,7 +72,7 @@
|
||||
ToolTip.Tip="{ext:Locale OpenRyujinxLogsTooltip}" />
|
||||
<Separator />
|
||||
<MenuItem
|
||||
Click="CloseWindow"
|
||||
Name="CloseRyujinxMenuItem"
|
||||
Header="{ext:Locale MenuBarFileExit}"
|
||||
Icon="{ext:Icon fa-solid fa-xmark}"
|
||||
ToolTip.Tip="{ext:Locale ExitTooltip}" />
|
||||
@ -167,7 +167,7 @@
|
||||
Header="{ext:Locale MenuBarShowFileTypes}" />
|
||||
<Separator />
|
||||
<MenuItem
|
||||
Click="OpenSettings"
|
||||
Name="OpenSettingsMenuItem"
|
||||
Padding="0"
|
||||
Header="{ext:Locale MenuBarOptionsSettings}"
|
||||
Icon="{ext:Icon fa-solid fa-gear}"
|
||||
@ -210,21 +210,21 @@
|
||||
Header="{ext:Locale MenuBarActions}"
|
||||
IsEnabled="{Binding IsGameRunning}">
|
||||
<MenuItem
|
||||
Click="PauseEmulation_Click"
|
||||
Name="PauseEmulationMenuItem"
|
||||
Header="{ext:Locale MenuBarOptionsPauseEmulation}"
|
||||
Icon="{ext:Icon fa-solid fa-pause}"
|
||||
InputGesture="{Binding PauseKey}"
|
||||
IsEnabled="{Binding !IsPaused}"
|
||||
IsVisible="{Binding !IsPaused}" />
|
||||
<MenuItem
|
||||
Click="ResumeEmulation_Click"
|
||||
Name="ResumeEmulationMenuItem"
|
||||
Header="{ext:Locale MenuBarOptionsResumeEmulation}"
|
||||
Icon="{ext:Icon fa-solid fa-play}"
|
||||
InputGesture="{Binding PauseKey}"
|
||||
IsEnabled="{Binding IsPaused}"
|
||||
IsVisible="{Binding IsPaused}" />
|
||||
<MenuItem
|
||||
Click="StopEmulation_Click"
|
||||
Name="StopEmulationMenuItem"
|
||||
Header="{ext:Locale MenuBarOptionsStopEmulation}"
|
||||
Icon="{ext:Icon fa-solid fa-stop}"
|
||||
InputGesture="Escape"
|
||||
@ -233,17 +233,15 @@
|
||||
<MenuItem Command="{Binding SimulateWakeUpMessage}" Header="{ext:Locale MenuBarOptionsSimulateWakeUpMessage}" />
|
||||
<Separator />
|
||||
<MenuItem
|
||||
Name="ScanAmiiboMenuItem"
|
||||
Command="{Binding OpenAmiiboWindow}"
|
||||
AttachedToVisualTree="ScanAmiiboMenuItem_AttachedToVisualTree"
|
||||
Click="OpenAmiiboWindow"
|
||||
Header="{ext:Locale MenuBarActionsScanAmiibo}"
|
||||
Icon="{ext:Icon mdi-cube-scan}"
|
||||
InputGesture="Ctrl + A"
|
||||
IsEnabled="{Binding IsAmiiboRequested}" />
|
||||
<MenuItem
|
||||
Name="ScanAmiiboMenuItemFromBin"
|
||||
Command="{Binding OpenBinFile}"
|
||||
AttachedToVisualTree="ScanBinAmiiboMenuItem_AttachedToVisualTree"
|
||||
Click="OpenBinFile"
|
||||
Header="{ext:Locale MenuBarActionsScanAmiiboBin}"
|
||||
Icon="{ext:Icon mdi-cube-scan}"
|
||||
IsVisible="{Binding CanScanAmiiboBinaries}"
|
||||
@ -262,7 +260,7 @@
|
||||
InputGesture="{Binding ShowUiKey}"
|
||||
IsEnabled="{Binding IsGameRunning}" />
|
||||
<MenuItem
|
||||
Click="OpenCheatManagerForCurrentApp"
|
||||
Name="CheatManagerMenuItem"
|
||||
Header="{ext:Locale GameListContextMenuManageCheat}"
|
||||
Icon="{ext:Icon fa-solid fa-code}"
|
||||
IsEnabled="{Binding IsGameRunning}" />
|
||||
@ -277,52 +275,55 @@
|
||||
<MenuItem Command="{Binding InstallFirmwareFromFolder}" Header="{ext:Locale MenuBarFileToolsInstallFirmwareFromDirectory}" Icon="{ext:Icon mdi-folder-cog}" />
|
||||
</MenuItem>
|
||||
<MenuItem Header="{ext:Locale MenuBarToolsManageFileTypes}" IsVisible="{Binding ManageFileTypesVisible}">
|
||||
<MenuItem Header="{ext:Locale MenuBarToolsInstallFileTypes}" Click="InstallFileTypes_Click" IsEnabled="{Binding AreMimeTypesRegistered, Converter={x:Static BoolConverters.Not}}" />
|
||||
<MenuItem Header="{ext:Locale MenuBarToolsUninstallFileTypes}" Click="UninstallFileTypes_Click" IsEnabled="{Binding AreMimeTypesRegistered}" />
|
||||
<MenuItem Name="InstallFileTypesMenuItem" Header="{ext:Locale MenuBarToolsInstallFileTypes}" IsEnabled="{Binding AreMimeTypesRegistered, Converter={x:Static BoolConverters.Not}}" />
|
||||
<MenuItem Name="UninstallFileTypesMenuItem" Header="{ext:Locale MenuBarToolsUninstallFileTypes}" IsEnabled="{Binding AreMimeTypesRegistered}" />
|
||||
</MenuItem>
|
||||
<Separator />
|
||||
<MenuItem Header="{ext:Locale MenuBarToolsXCITrimmer}" IsEnabled="{Binding EnableNonGameRunningControls}" Click="OpenXCITrimmerWindow" Icon="{ext:Icon fa-solid fa-scissors}" />
|
||||
<MenuItem Name="XciTrimmerMenuItem" Header="{ext:Locale MenuBarToolsXCITrimmer}" IsEnabled="{Binding EnableNonGameRunningControls}" Icon="{ext:Icon fa-solid fa-scissors}" />
|
||||
</MenuItem>
|
||||
<MenuItem VerticalAlignment="Center" Header="{ext:Locale MenuBarView}">
|
||||
<MenuItem VerticalAlignment="Center" Header="{ext:Locale MenuBarViewWindow}">
|
||||
<MenuItem Header="{ext:Locale MenuBarViewWindow720}" Tag="1280 720" Click="ChangeWindowSize_Click" />
|
||||
<MenuItem Header="{ext:Locale MenuBarViewWindow1080}" Tag="1920 1080" Click="ChangeWindowSize_Click" />
|
||||
<MenuItem Header="{ext:Locale MenuBarViewWindow1440}" Tag="2560 1440" Click="ChangeWindowSize_Click" />
|
||||
<MenuItem Header="{ext:Locale MenuBarViewWindow2160}" Tag="3840 2160" Click="ChangeWindowSize_Click" />
|
||||
<MenuItem Name="WindowSize720PMenuItem" Header="{ext:Locale MenuBarViewWindow720}" CommandParameter="1280 720" />
|
||||
<MenuItem Name="WindowSize1080PMenuItem" Header="{ext:Locale MenuBarViewWindow1080}" CommandParameter="1920 1080" />
|
||||
<MenuItem Name="WindowSize1440PMenuItem" Header="{ext:Locale MenuBarViewWindow1440}" CommandParameter="2560 1440" />
|
||||
<MenuItem Name="WindowSize2160PMenuItem" Header="{ext:Locale MenuBarViewWindow2160}" CommandParameter="3840 2160" />
|
||||
</MenuItem>
|
||||
</MenuItem>
|
||||
<MenuItem VerticalAlignment="Center" Header="{ext:Locale MenuBarHelp}">
|
||||
<MenuItem
|
||||
Click="OpenAboutWindow"
|
||||
Name="AboutWindowMenuItem"
|
||||
Header="{ext:Locale MenuBarHelpAbout}"
|
||||
Icon="{ext:Icon fa-solid fa-circle-info}"
|
||||
ToolTip.Tip="{ext:Locale OpenAboutTooltip}" />
|
||||
<MenuItem
|
||||
Name="UpdateMenuItem"
|
||||
IsEnabled="{Binding CanUpdate}"
|
||||
Click="CheckForUpdates"
|
||||
Header="{ext:Locale MenuBarHelpCheckForUpdates}"
|
||||
Icon="{ext:Icon mdi-update}"
|
||||
ToolTip.Tip="{ext:Locale CheckUpdatesTooltip}" />
|
||||
<MenuItem
|
||||
Name="CompatibilityListMenuItem"
|
||||
Header="{ext:Locale CompatibilityListOpen}"
|
||||
Icon="{ext:Icon mdi-gamepad}"/>
|
||||
<Separator />
|
||||
<MenuItem VerticalAlignment="Center" Header="{ext:Locale MenuBarHelpFaqAndGuides}" Icon="{ext:Icon fa-solid fa-question}" >
|
||||
<MenuItem
|
||||
Click="MenuItem_OnClick"
|
||||
Name="FaqMenuItem"
|
||||
Header="{ext:Locale MenuBarHelpFaq}"
|
||||
Icon="{ext:Icon fa-github}"
|
||||
Tag="https://github.com/GreemDev/Ryujinx/wiki/FAQ-and-Troubleshooting"
|
||||
CommandParameter="https://github.com/GreemDev/Ryujinx/wiki/FAQ-and-Troubleshooting"
|
||||
ToolTip.Tip="{ext:Locale MenuBarHelpFaqTooltip}" />
|
||||
<MenuItem
|
||||
Click="MenuItem_OnClick"
|
||||
Name="SetupGuideMenuItem"
|
||||
Header="{ext:Locale MenuBarHelpSetup}"
|
||||
Icon="{ext:Icon fa-github}"
|
||||
Tag="https://github.com/GreemDev/Ryujinx/wiki/Ryujinx-Setup-&-Configuration-Guide"
|
||||
CommandParameter="https://github.com/GreemDev/Ryujinx/wiki/Ryujinx-Setup-&-Configuration-Guide"
|
||||
ToolTip.Tip="{ext:Locale MenuBarHelpSetupTooltip}" />
|
||||
<MenuItem
|
||||
Click="MenuItem_OnClick"
|
||||
Name="LdnGuideMenuItem"
|
||||
Header="{ext:Locale MenuBarHelpMultiplayer}"
|
||||
Icon="{ext:Icon fa-github}"
|
||||
Tag="https://github.com/GreemDev/Ryujinx/wiki/Multiplayer%E2%80%90(LDN%E2%80%90Local%E2%80%90Wireless)%E2%80%90Guide"
|
||||
CommandParameter="https://github.com/GreemDev/Ryujinx/wiki/Multiplayer%E2%80%90(LDN%E2%80%90Local%E2%80%90Wireless)%E2%80%90Guide"
|
||||
ToolTip.Tip="{ext:Locale MenuBarHelpMultiplayerTooltip}" />
|
||||
</MenuItem>
|
||||
</MenuItem>
|
||||
|
@ -1,13 +1,15 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Layout;
|
||||
using Avalonia.Threading;
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
using Gommon;
|
||||
using Ryujinx.Ava.Common.Locale;
|
||||
using Ryujinx.Ava.UI.Helpers;
|
||||
using Ryujinx.Ava.UI.ViewModels;
|
||||
using Ryujinx.Ava.UI.Windows;
|
||||
using Ryujinx.Ava.Utilities;
|
||||
using Ryujinx.Ava.Utilities.Compat;
|
||||
using Ryujinx.Ava.Utilities.Configuration;
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Common.Helper;
|
||||
@ -16,6 +18,7 @@ using Ryujinx.HLE.HOS.Services.Nfc.AmiiboDecryption;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Ryujinx.Ava.UI.Views.Main
|
||||
{
|
||||
@ -33,9 +36,43 @@ namespace Ryujinx.Ava.UI.Views.Main
|
||||
|
||||
ToggleFileTypesMenuItem.ItemsSource = GenerateToggleFileTypeItems();
|
||||
ChangeLanguageMenuItem.ItemsSource = GenerateLanguageMenuItems();
|
||||
|
||||
MiiAppletMenuItem.Command = new AsyncRelayCommand(OpenMiiApplet);
|
||||
CloseRyujinxMenuItem.Command = new RelayCommand(CloseWindow);
|
||||
OpenSettingsMenuItem.Command = new AsyncRelayCommand(OpenSettings);
|
||||
PauseEmulationMenuItem.Command = new RelayCommand(() => ViewModel.AppHost?.Pause());
|
||||
ResumeEmulationMenuItem.Command = new RelayCommand(() => ViewModel.AppHost?.Resume());
|
||||
StopEmulationMenuItem.Command = new AsyncRelayCommand(() => ViewModel.AppHost?.ShowExitPrompt().OrCompleted());
|
||||
CheatManagerMenuItem.Command = new AsyncRelayCommand(async () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
await OpenCheatManagerForCurrentApp();
|
||||
} catch {}
|
||||
});
|
||||
InstallFileTypesMenuItem.Command = new AsyncRelayCommand(InstallFileTypes);
|
||||
UninstallFileTypesMenuItem.Command = new AsyncRelayCommand(UninstallFileTypes);
|
||||
XciTrimmerMenuItem.Command = new AsyncRelayCommand(() => XCITrimmerWindow.Show(ViewModel));
|
||||
AboutWindowMenuItem.Command = new AsyncRelayCommand(AboutWindow.Show);
|
||||
CompatibilityListMenuItem.Command = new AsyncRelayCommand(CompatibilityList.Show);
|
||||
|
||||
UpdateMenuItem.Command = new AsyncRelayCommand(async () =>
|
||||
{
|
||||
if (Updater.CanUpdate(true))
|
||||
await Updater.BeginUpdateAsync(true);
|
||||
});
|
||||
|
||||
FaqMenuItem.Command =
|
||||
SetupGuideMenuItem.Command =
|
||||
LdnGuideMenuItem.Command = new RelayCommand<string>(OpenHelper.OpenUrl);
|
||||
|
||||
WindowSize720PMenuItem.Command =
|
||||
WindowSize1080PMenuItem.Command =
|
||||
WindowSize1440PMenuItem.Command =
|
||||
WindowSize2160PMenuItem.Command = new RelayCommand<string>(ChangeWindowSize);
|
||||
}
|
||||
|
||||
private CheckBox[] GenerateToggleFileTypeItems() =>
|
||||
private IEnumerable<CheckBox> GenerateToggleFileTypeItems() =>
|
||||
Enum.GetValues<FileTypes>()
|
||||
.Select(it => (FileName: Enum.GetName(it)!, FileType: it))
|
||||
.Select(it =>
|
||||
@ -45,15 +82,13 @@ namespace Ryujinx.Ava.UI.Views.Main
|
||||
IsChecked = it.FileType.GetConfigValue(ConfigurationState.Instance.UI.ShownFileTypes),
|
||||
Command = MiniCommand.Create(() => Window.ToggleFileType(it.FileName))
|
||||
}
|
||||
).ToArray();
|
||||
);
|
||||
|
||||
private static MenuItem[] GenerateLanguageMenuItems()
|
||||
private static IEnumerable<MenuItem> GenerateLanguageMenuItems()
|
||||
{
|
||||
List<MenuItem> menuItems = new();
|
||||
const string LocalePath = "Ryujinx/Assets/locales.json";
|
||||
|
||||
string localePath = "Ryujinx/Assets/locales.json";
|
||||
|
||||
string languageJson = EmbeddedResources.ReadAllText(localePath);
|
||||
string languageJson = EmbeddedResources.ReadAllText(LocalePath);
|
||||
|
||||
LocalesJson locales = JsonHelper.Deserialize(languageJson, LocalesJsonContext.Default.LocalesJson);
|
||||
|
||||
@ -68,20 +103,23 @@ namespace Ryujinx.Ava.UI.Views.Main
|
||||
}
|
||||
else
|
||||
{
|
||||
languageName = locales.Locales[index].Translations[language] == "" ? language : locales.Locales[index].Translations[language];
|
||||
string tr = locales.Locales[index].Translations[language];
|
||||
languageName = string.IsNullOrEmpty(tr)
|
||||
? language
|
||||
: tr;
|
||||
}
|
||||
|
||||
MenuItem menuItem = new()
|
||||
{
|
||||
Padding = new Thickness(10, 0, 0, 0),
|
||||
Header = " " + languageName,
|
||||
Padding = new Thickness(15, 0, 0, 0),
|
||||
Margin = new Thickness(3, 0, 3, 0),
|
||||
HorizontalAlignment = HorizontalAlignment.Stretch,
|
||||
Header = languageName,
|
||||
Command = MiniCommand.Create(() => MainWindowViewModel.ChangeLanguage(language))
|
||||
};
|
||||
|
||||
menuItems.Add(menuItem);
|
||||
yield return menuItem;
|
||||
}
|
||||
|
||||
return menuItems.ToArray();
|
||||
}
|
||||
|
||||
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
|
||||
@ -95,22 +133,7 @@ namespace Ryujinx.Ava.UI.Views.Main
|
||||
}
|
||||
}
|
||||
|
||||
private async void StopEmulation_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
await ViewModel.AppHost?.ShowExitPrompt().OrCompleted()!;
|
||||
}
|
||||
|
||||
private void PauseEmulation_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
ViewModel.AppHost?.Pause();
|
||||
}
|
||||
|
||||
private void ResumeEmulation_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
ViewModel.AppHost?.Resume();
|
||||
}
|
||||
|
||||
public async void OpenSettings(object sender, RoutedEventArgs e)
|
||||
public async Task OpenSettings()
|
||||
{
|
||||
Window.SettingsWindow = new(Window.VirtualFileSystem, Window.ContentManager);
|
||||
|
||||
@ -121,23 +144,17 @@ namespace Ryujinx.Ava.UI.Views.Main
|
||||
ViewModel.LoadConfigurableHotKeys();
|
||||
}
|
||||
|
||||
public static readonly AppletMetadata MiiApplet = new("miiEdit", 0x0100000000001009);
|
||||
|
||||
public async void OpenMiiApplet(object sender, RoutedEventArgs e)
|
||||
public AppletMetadata MiiApplet => new(ViewModel.ContentManager, "miiEdit", 0x0100000000001009);
|
||||
|
||||
public async Task OpenMiiApplet()
|
||||
{
|
||||
if (MiiApplet.CanStart(ViewModel.ContentManager, out var appData, out var nacpData))
|
||||
{
|
||||
await ViewModel.LoadApplication(appData, ViewModel.IsFullScreen || ViewModel.StartGamesInFullscreen, nacpData);
|
||||
}
|
||||
if (!MiiApplet.CanStart(out var appData, out var nacpData))
|
||||
return;
|
||||
|
||||
await ViewModel.LoadApplication(appData, ViewModel.IsFullScreen || ViewModel.StartGamesInFullscreen, nacpData);
|
||||
}
|
||||
|
||||
public async void OpenAmiiboWindow(object sender, RoutedEventArgs e)
|
||||
=> await ViewModel.OpenAmiiboWindow();
|
||||
|
||||
public async void OpenBinFile(object sender, RoutedEventArgs e)
|
||||
=> await ViewModel.OpenBinFile();
|
||||
|
||||
public async void OpenCheatManagerForCurrentApp(object sender, RoutedEventArgs e)
|
||||
public async Task OpenCheatManagerForCurrentApp()
|
||||
{
|
||||
if (!ViewModel.IsGameRunning)
|
||||
return;
|
||||
@ -165,7 +182,7 @@ namespace Ryujinx.Ava.UI.Views.Main
|
||||
ViewModel.IsAmiiboBinRequested = ViewModel.IsAmiiboRequested && AmiiboBinReader.HasAmiiboKeyFile;
|
||||
}
|
||||
|
||||
private async void InstallFileTypes_Click(object sender, RoutedEventArgs e)
|
||||
private async Task InstallFileTypes()
|
||||
{
|
||||
ViewModel.AreMimeTypesRegistered = FileAssociationHelper.Install();
|
||||
if (ViewModel.AreMimeTypesRegistered)
|
||||
@ -174,7 +191,7 @@ namespace Ryujinx.Ava.UI.Views.Main
|
||||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogInstallFileTypesErrorMessage]);
|
||||
}
|
||||
|
||||
private async void UninstallFileTypes_Click(object sender, RoutedEventArgs e)
|
||||
private async Task UninstallFileTypes()
|
||||
{
|
||||
ViewModel.AreMimeTypesRegistered = !FileAssociationHelper.Uninstall();
|
||||
if (!ViewModel.AreMimeTypesRegistered)
|
||||
@ -183,11 +200,8 @@ namespace Ryujinx.Ava.UI.Views.Main
|
||||
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogUninstallFileTypesErrorMessage]);
|
||||
}
|
||||
|
||||
private async void ChangeWindowSize_Click(object sender, RoutedEventArgs e)
|
||||
private void ChangeWindowSize(string resolution)
|
||||
{
|
||||
if (sender is not MenuItem { Tag: string resolution })
|
||||
return;
|
||||
|
||||
(int resolutionWidth, int resolutionHeight) = resolution.Split(' ', 2)
|
||||
.Into(parts =>
|
||||
(int.Parse(parts[0]), int.Parse(parts[1]))
|
||||
@ -200,7 +214,7 @@ namespace Ryujinx.Ava.UI.Views.Main
|
||||
double windowWidthScaled = (resolutionWidth * Program.WindowScaleFactor);
|
||||
double windowHeightScaled = ((resolutionHeight + barsHeight) * Program.WindowScaleFactor);
|
||||
|
||||
await Dispatcher.UIThread.InvokeAsync(() =>
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
{
|
||||
ViewModel.WindowState = WindowState.Normal;
|
||||
|
||||
@ -208,22 +222,7 @@ namespace Ryujinx.Ava.UI.Views.Main
|
||||
});
|
||||
}
|
||||
|
||||
public async void CheckForUpdates(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (Updater.CanUpdate(true))
|
||||
await Updater.BeginUpdateAsync(true);
|
||||
}
|
||||
|
||||
private void MenuItem_OnClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is MenuItem { Tag: string url })
|
||||
OpenHelper.OpenUrl(url);
|
||||
}
|
||||
|
||||
public async void OpenXCITrimmerWindow(object sender, RoutedEventArgs e) => await XCITrimmerWindow.Show(ViewModel);
|
||||
|
||||
public async void OpenAboutWindow(object sender, RoutedEventArgs e) => await AboutWindow.Show();
|
||||
|
||||
public void CloseWindow(object sender, RoutedEventArgs e) => Window.Close();
|
||||
public void CloseWindow() => Window.Close();
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -136,6 +136,12 @@
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{ext:Locale SettingsTabSystemSystemLanguageBrazilianPortuguese}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{ext:Locale SettingsTabSystemSystemLanguageSwedish}" />
|
||||
</ComboBoxItem>
|
||||
<ComboBoxItem>
|
||||
<TextBlock Text="{ext:Locale SettingsTabSystemSystemLanguageNorwegian}" />
|
||||
</ComboBoxItem>
|
||||
</ComboBox>
|
||||
</StackPanel>
|
||||
<StackPanel
|
||||
|
@ -32,6 +32,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reactive.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Runtime.Versioning;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
@ -136,6 +137,8 @@ namespace Ryujinx.Ava.UI.Windows
|
||||
base.OnApplyTemplate(e);
|
||||
|
||||
NotificationHelper.SetNotificationManager(this);
|
||||
|
||||
Executor.ExecuteBackgroundAsync(ShowIntelMacWarningAsync);
|
||||
}
|
||||
|
||||
private void OnScalingChanged(object sender, EventArgs e)
|
||||
@ -164,7 +167,7 @@ namespace Ryujinx.Ava.UI.Windows
|
||||
});
|
||||
}
|
||||
|
||||
private void ApplicationLibrary_LdnGameDataReceived(object sender, LdnGameDataReceivedEventArgs e)
|
||||
private void ApplicationLibrary_LdnGameDataReceived(LdnGameDataReceivedEventArgs e)
|
||||
{
|
||||
Dispatcher.UIThread.Post(() =>
|
||||
{
|
||||
@ -408,13 +411,10 @@ namespace Ryujinx.Ava.UI.Windows
|
||||
{
|
||||
StatusBarView.VolumeStatus.Click += VolumeStatus_CheckedChanged;
|
||||
|
||||
ApplicationGrid.DataContext = ApplicationList.DataContext = ViewModel;
|
||||
|
||||
ApplicationGrid.ApplicationOpened += Application_Opened;
|
||||
|
||||
ApplicationGrid.DataContext = ViewModel;
|
||||
|
||||
ApplicationList.ApplicationOpened += Application_Opened;
|
||||
|
||||
ApplicationList.DataContext = ViewModel;
|
||||
}
|
||||
|
||||
private void SetWindowSizePosition()
|
||||
@ -734,5 +734,20 @@ namespace Ryujinx.Ava.UI.Windows
|
||||
(int)Symbol.Checkmark);
|
||||
});
|
||||
}
|
||||
|
||||
private static bool _intelMacWarningShown = !(OperatingSystem.IsMacOS() &&
|
||||
(RuntimeInformation.OSArchitecture == Architecture.X64 ||
|
||||
RuntimeInformation.OSArchitecture == Architecture.X86));
|
||||
|
||||
public static async Task ShowIntelMacWarningAsync()
|
||||
{
|
||||
if (_intelMacWarningShown) return;
|
||||
|
||||
await Dispatcher.UIThread.InvokeAsync(async () => await ContentDialogHelper.CreateWarningDialog(
|
||||
"Intel Mac Warning",
|
||||
"Intel Macs are not supported and will not work properly.\nIf you continue, do not come to our Discord asking for support;\nand do not report bugs on the GitHub. They will be closed."));
|
||||
|
||||
_intelMacWarningShown = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,6 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Input;
|
||||
using FluentAvalonia.Core;
|
||||
using FluentAvalonia.UI.Controls;
|
||||
using Ryujinx.Ava.Common.Locale;
|
||||
@ -23,6 +25,11 @@ namespace Ryujinx.Ava.UI.Windows
|
||||
|
||||
InitializeComponent();
|
||||
Load();
|
||||
|
||||
#if DEBUG
|
||||
this.AttachDevTools(new KeyGesture(Key.F12, KeyModifiers.Alt));
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
public SettingsWindow()
|
||||
|
@ -37,6 +37,8 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
|
||||
|
||||
public string TimePlayedString => ValueFormatUtils.FormatTimeSpan(TimePlayed);
|
||||
|
||||
public bool HasPlayedPreviously => TimePlayedString != string.Empty;
|
||||
|
||||
public string LastPlayedString => ValueFormatUtils.FormatDateTime(LastPlayed)?.Replace(" ", "\n");
|
||||
|
||||
public string FileSizeString => ValueFormatUtils.FormatFileSize(FileSize);
|
||||
|
@ -45,7 +45,7 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
|
||||
public const string DefaultLanPlayWebHost = "ryuldnweb.vudjun.com";
|
||||
public Language DesiredLanguage { get; set; }
|
||||
public event EventHandler<ApplicationCountUpdatedEventArgs> ApplicationCountUpdated;
|
||||
public event EventHandler<LdnGameDataReceivedEventArgs> LdnGameDataReceived;
|
||||
public event Action<LdnGameDataReceivedEventArgs> LdnGameDataReceived;
|
||||
|
||||
public readonly IObservableCache<ApplicationData, ulong> Applications;
|
||||
public readonly IObservableCache<(TitleUpdateModel TitleUpdate, bool IsSelected), TitleUpdateModel> TitleUpdates;
|
||||
@ -779,7 +779,7 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
|
||||
using HttpClient httpClient = new HttpClient();
|
||||
string ldnGameDataArrayString = await httpClient.GetStringAsync($"https://{ldnWebHost}/api/public_games");
|
||||
ldnGameDataArray = JsonHelper.Deserialize(ldnGameDataArrayString, _ldnDataSerializerContext.IEnumerableLdnGameData);
|
||||
LdnGameDataReceived?.Invoke(null, new LdnGameDataReceivedEventArgs
|
||||
LdnGameDataReceived?.Invoke(new LdnGameDataReceivedEventArgs
|
||||
{
|
||||
LdnData = ldnGameDataArray
|
||||
});
|
||||
@ -787,7 +787,7 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Warning?.Print(LogClass.Application, $"Failed to fetch the public games JSON from the API. Player and game count in the game list will be unavailable.\n{ex.Message}");
|
||||
LdnGameDataReceived?.Invoke(null, new LdnGameDataReceivedEventArgs
|
||||
LdnGameDataReceived?.Invoke(new LdnGameDataReceivedEventArgs
|
||||
{
|
||||
LdnData = Array.Empty<LdnGameData>()
|
||||
});
|
||||
@ -795,7 +795,7 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
|
||||
}
|
||||
else
|
||||
{
|
||||
LdnGameDataReceived?.Invoke(null, new LdnGameDataReceivedEventArgs
|
||||
LdnGameDataReceived?.Invoke(new LdnGameDataReceivedEventArgs
|
||||
{
|
||||
LdnData = Array.Empty<LdnGameData>()
|
||||
});
|
||||
|
@ -32,29 +32,31 @@ namespace Ryujinx.Ava.Utilities
|
||||
|
||||
public string GetContentPath(ContentManager contentManager)
|
||||
=> (contentManager ?? _contentManager)
|
||||
.GetInstalledContentPath(ProgramId, StorageId.BuiltInSystem, NcaContentType.Program);
|
||||
?.GetInstalledContentPath(ProgramId, StorageId.BuiltInSystem, NcaContentType.Program);
|
||||
|
||||
public bool CanStart(ContentManager contentManager, out ApplicationData appData,
|
||||
out BlitStruct<ApplicationControlProperty> appControl)
|
||||
{
|
||||
contentManager ??= _contentManager;
|
||||
if (contentManager == null)
|
||||
{
|
||||
appData = null;
|
||||
appControl = new BlitStruct<ApplicationControlProperty>(0);
|
||||
return false;
|
||||
}
|
||||
if (contentManager == null)
|
||||
goto BadData;
|
||||
|
||||
string contentPath = GetContentPath(contentManager);
|
||||
if (string.IsNullOrEmpty(contentPath))
|
||||
goto BadData;
|
||||
|
||||
appData = new() { Name = Name, Id = ProgramId, Path = GetContentPath(contentManager) };
|
||||
|
||||
if (string.IsNullOrEmpty(appData.Path))
|
||||
{
|
||||
appControl = new BlitStruct<ApplicationControlProperty>(0);
|
||||
return false;
|
||||
}
|
||||
|
||||
appControl = StructHelpers.CreateCustomNacpData(Name, Version);
|
||||
return true;
|
||||
|
||||
BadData:
|
||||
appData = null;
|
||||
appControl = new BlitStruct<ApplicationControlProperty>(0);
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool CanStart(out ApplicationData appData,
|
||||
out BlitStruct<ApplicationControlProperty> appControl)
|
||||
=> CanStart(null, out appData, out appControl);
|
||||
}
|
||||
}
|
||||
|
187
src/Ryujinx/Utilities/Compat/CompatibilityCsv.cs
Normal file
187
src/Ryujinx/Utilities/Compat/CompatibilityCsv.cs
Normal file
@ -0,0 +1,187 @@
|
||||
using Gommon;
|
||||
using Humanizer;
|
||||
using nietras.SeparatedValues;
|
||||
using Ryujinx.Ava.Common.Locale;
|
||||
using Ryujinx.Common.Logging;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
|
||||
namespace Ryujinx.Ava.Utilities.Compat
|
||||
{
|
||||
public struct ColumnIndices(Func<ReadOnlySpan<char>, int> getIndex)
|
||||
{
|
||||
public const string TitleIdCol = "\"title_id\"";
|
||||
public const string GameNameCol = "\"game_name\"";
|
||||
public const string LabelsCol = "\"labels\"";
|
||||
public const string StatusCol = "\"status\"";
|
||||
public const string LastUpdatedCol = "\"last_updated\"";
|
||||
|
||||
public readonly int TitleId = getIndex(TitleIdCol);
|
||||
public readonly int GameName = getIndex(GameNameCol);
|
||||
public readonly int Labels = getIndex(LabelsCol);
|
||||
public readonly int Status = getIndex(StatusCol);
|
||||
public readonly int LastUpdated = getIndex(LastUpdatedCol);
|
||||
}
|
||||
|
||||
public class CompatibilityCsv
|
||||
{
|
||||
static CompatibilityCsv() => Load();
|
||||
|
||||
public static void Load()
|
||||
{
|
||||
using Stream csvStream = Assembly.GetExecutingAssembly()
|
||||
.GetManifestResourceStream("RyujinxGameCompatibilityList")!;
|
||||
csvStream.Position = 0;
|
||||
|
||||
using SepReader reader = Sep.Reader().From(csvStream);
|
||||
ColumnIndices columnIndices = new(reader.Header.IndexOf);
|
||||
|
||||
_entries = reader
|
||||
.Enumerate(row => new CompatibilityEntry(ref columnIndices, row))
|
||||
.OrderBy(it => it.GameName)
|
||||
.ToArray();
|
||||
|
||||
Logger.Debug?.Print(LogClass.UI, "Compatibility CSV loaded.", "LoadCompatibility");
|
||||
}
|
||||
|
||||
public static void Unload()
|
||||
{
|
||||
_entries = null;
|
||||
}
|
||||
|
||||
private static CompatibilityEntry[] _entries;
|
||||
|
||||
public static CompatibilityEntry[] Entries
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_entries == null)
|
||||
Load();
|
||||
|
||||
return _entries;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class CompatibilityEntry
|
||||
{
|
||||
public CompatibilityEntry(ref ColumnIndices indices, SepReader.Row row)
|
||||
{
|
||||
string titleIdRow = ColStr(row[indices.TitleId]);
|
||||
TitleId = !string.IsNullOrEmpty(titleIdRow)
|
||||
? titleIdRow
|
||||
: default(Optional<string>);
|
||||
|
||||
GameName = ColStr(row[indices.GameName]);
|
||||
|
||||
Labels = ColStr(row[indices.Labels]).Split(';');
|
||||
Status = ColStr(row[indices.Status]).ToLower() switch
|
||||
{
|
||||
"playable" => LocaleKeys.CompatibilityListPlayable,
|
||||
"ingame" => LocaleKeys.CompatibilityListIngame,
|
||||
"menus" => LocaleKeys.CompatibilityListMenus,
|
||||
"boots" => LocaleKeys.CompatibilityListBoots,
|
||||
"nothing" => LocaleKeys.CompatibilityListNothing,
|
||||
_ => null
|
||||
};
|
||||
|
||||
if (DateTime.TryParse(ColStr(row[indices.LastUpdated]), out var dt))
|
||||
LastUpdated = dt;
|
||||
|
||||
return;
|
||||
|
||||
string ColStr(SepReader.Col col) => col.ToString().Trim('"');
|
||||
}
|
||||
|
||||
public string GameName { get; }
|
||||
public Optional<string> TitleId { get; }
|
||||
public string[] Labels { get; }
|
||||
public LocaleKeys? Status { get; }
|
||||
public DateTime LastUpdated { get; }
|
||||
|
||||
public string LocalizedLastUpdated =>
|
||||
LocaleManager.FormatDynamicValue(LocaleKeys.CompatibilityListLastUpdated, LastUpdated.Humanize());
|
||||
|
||||
public string LocalizedStatus => LocaleManager.Instance[Status!.Value];
|
||||
public string FormattedTitleId => TitleId
|
||||
.OrElse(new string(' ', 16));
|
||||
|
||||
public string FormattedIssueLabels => Labels
|
||||
.Select(FormatLabelName)
|
||||
.JoinToString(", ");
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
StringBuilder sb = new("CompatibilityEntry: {");
|
||||
sb.Append($"{nameof(GameName)}=\"{GameName}\", ");
|
||||
sb.Append($"{nameof(TitleId)}={TitleId}, ");
|
||||
sb.Append($"{nameof(Labels)}={
|
||||
Labels.FormatCollection(it => $"\"{it}\"", separator: ", ", prefix: "[", suffix: "]")
|
||||
}, ");
|
||||
sb.Append($"{nameof(Status)}=\"{Status}\", ");
|
||||
sb.Append($"{nameof(LastUpdated)}=\"{LastUpdated}\"");
|
||||
sb.Append('}');
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public static string FormatLabelName(string labelName) => labelName.ToLower() switch
|
||||
{
|
||||
"audio" => "Audio",
|
||||
"bug" => "Bug",
|
||||
"cpu" => "CPU",
|
||||
"gpu" => "GPU",
|
||||
"gui" => "GUI",
|
||||
"help wanted" => "Help Wanted",
|
||||
"horizon" => "Horizon",
|
||||
"infra" => "Project Infra",
|
||||
"invalid" => "Invalid",
|
||||
"kernel" => "Kernel",
|
||||
"ldn" => "LDN",
|
||||
"linux" => "Linux",
|
||||
"macos" => "macOS",
|
||||
"question" => "Question",
|
||||
"windows" => "Windows",
|
||||
"graphics-backend:opengl" => "Graphics: OpenGL",
|
||||
"graphics-backend:vulkan" => "Graphics: Vulkan",
|
||||
"ldn-works" => "LDN Works",
|
||||
"ldn-untested" => "LDN Untested",
|
||||
"ldn-broken" => "LDN Broken",
|
||||
"ldn-partial" => "Partial LDN",
|
||||
"nvdec" => "NVDEC",
|
||||
"services" => "NX Services",
|
||||
"services-horizon" => "Horizon OS Services",
|
||||
"slow" => "Runs Slow",
|
||||
"crash" => "Crashes",
|
||||
"deadlock" => "Deadlock",
|
||||
"regression" => "Regression",
|
||||
"opengl" => "OpenGL",
|
||||
"opengl-backend-bug" => "OpenGL Backend Bug",
|
||||
"vulkan-backend-bug" => "Vulkan Backend Bug",
|
||||
"mac-bug" => "Mac-specific Bug(s)",
|
||||
"amd-vendor-bug" => "AMD GPU Bug",
|
||||
"intel-vendor-bug" => "Intel GPU Bug",
|
||||
"loader-allocator" => "Loader Allocator",
|
||||
"audout" => "AudOut",
|
||||
"32-bit" => "32-bit Game",
|
||||
"UE4" => "Unreal Engine 4",
|
||||
"homebrew" => "Homebrew Content",
|
||||
"online-broken" => "Online Broken",
|
||||
_ => Capitalize(labelName)
|
||||
};
|
||||
|
||||
public static string Capitalize(string value)
|
||||
{
|
||||
if (value == string.Empty)
|
||||
return string.Empty;
|
||||
|
||||
char firstChar = value[0];
|
||||
string rest = value[1..];
|
||||
|
||||
return $"{char.ToUpper(firstChar)}{rest}";
|
||||
}
|
||||
}
|
||||
}
|
79
src/Ryujinx/Utilities/Compat/CompatibilityList.axaml
Normal file
79
src/Ryujinx/Utilities/Compat/CompatibilityList.axaml
Normal file
@ -0,0 +1,79 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="using:Ryujinx.Ava.Utilities.Compat"
|
||||
xmlns:helpers="using:Ryujinx.Ava.UI.Helpers"
|
||||
xmlns:ext="using:Ryujinx.Ava.Common.Markup"
|
||||
xmlns:ui="using:FluentAvalonia.UI.Controls"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="Ryujinx.Ava.Utilities.Compat.CompatibilityList"
|
||||
x:DataType="local:CompatibilityViewModel">
|
||||
<UserControl.DataContext>
|
||||
<local:CompatibilityViewModel />
|
||||
</UserControl.DataContext>
|
||||
<Grid RowDefinitions="*,Auto,*">
|
||||
<Grid
|
||||
Grid.Row="0"
|
||||
HorizontalAlignment="Center"
|
||||
ColumnDefinitions="Auto,*"
|
||||
Margin="0 0 0 10">
|
||||
<ui:FontIcon
|
||||
Grid.Column="0"
|
||||
Margin="0"
|
||||
HorizontalAlignment="Stretch"
|
||||
FontFamily="avares://FluentAvalonia/Fonts#Symbols"
|
||||
Glyph="{helpers:GlyphValueConverter Important}" />
|
||||
<!-- NOTE: aligning to bottom for better visual alignment with glyph -->
|
||||
<TextBlock
|
||||
Grid.Column="1"
|
||||
Margin="5, 0, 0, 0"
|
||||
FontStyle="Italic"
|
||||
VerticalAlignment="Center"
|
||||
TextWrapping="Wrap"
|
||||
Text="{ext:Locale CompatibilityListWarning}" />
|
||||
</Grid>
|
||||
<Grid Grid.Row="1" ColumnDefinitions="*,Auto,Auto">
|
||||
<TextBox Grid.Column="0" HorizontalAlignment="Stretch" Watermark="{ext:Locale CompatibilityListSearchBoxWatermark}" TextChanged="TextBox_OnTextChanged" />
|
||||
<CheckBox Grid.Column="1" Margin="7, 0, 0, 0" IsChecked="{Binding OnlyShowOwnedGames}" />
|
||||
<TextBlock Grid.Column="2" Margin="-10, 0, 0, 0" Text="{ext:Locale CompatibilityListOnlyShowOwnedGames}" />
|
||||
</Grid>
|
||||
<ScrollViewer Grid.Row="2">
|
||||
<ListBox Margin="0,5, 0, 0"
|
||||
Background="Transparent"
|
||||
ItemsSource="{Binding CurrentEntries}">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate DataType="{x:Type local:CompatibilityEntry}">
|
||||
<Grid Width="750"
|
||||
Margin="5"
|
||||
ColumnDefinitions="Auto,Auto,Auto,*"
|
||||
Background="Transparent"
|
||||
ToolTip.Tip="{Binding LocalizedLastUpdated}">
|
||||
<TextBlock Grid.Column="0"
|
||||
Text="{Binding GameName}"
|
||||
Width="320"
|
||||
TextWrapping="Wrap" />
|
||||
<TextBlock Grid.Column="1"
|
||||
Width="135"
|
||||
Padding="7, 0, 0, 0"
|
||||
FontFamily="{StaticResource JetBrainsMono}"
|
||||
Text="{Binding FormattedTitleId}"
|
||||
TextWrapping="Wrap" />
|
||||
<TextBlock Grid.Column="2"
|
||||
Padding="7, 0"
|
||||
VerticalAlignment="Center"
|
||||
Text="{Binding LocalizedStatus}"
|
||||
Width="85"
|
||||
Foreground="{Binding Status, Converter={x:Static helpers:PlayabilityStatusConverter.Shared}}"
|
||||
TextWrapping="NoWrap" />
|
||||
<TextBlock Grid.Column="3"
|
||||
VerticalAlignment="Center"
|
||||
Text="{Binding FormattedIssueLabels}"
|
||||
TextWrapping="WrapWithOverflow" />
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</UserControl>
|
55
src/Ryujinx/Utilities/Compat/CompatibilityList.axaml.cs
Normal file
55
src/Ryujinx/Utilities/Compat/CompatibilityList.axaml.cs
Normal file
@ -0,0 +1,55 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Styling;
|
||||
using FluentAvalonia.UI.Controls;
|
||||
using Ryujinx.Ava.Common.Locale;
|
||||
using Ryujinx.Ava.UI.Helpers;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Ryujinx.Ava.Utilities.Compat
|
||||
{
|
||||
public partial class CompatibilityList : UserControl
|
||||
{
|
||||
public static async Task Show()
|
||||
{
|
||||
ContentDialog contentDialog = new()
|
||||
{
|
||||
PrimaryButtonText = string.Empty,
|
||||
SecondaryButtonText = string.Empty,
|
||||
CloseButtonText = LocaleManager.Instance[LocaleKeys.SettingsButtonClose],
|
||||
Content = new CompatibilityList
|
||||
{
|
||||
DataContext = new CompatibilityViewModel(RyujinxApp.MainWindow.ViewModel.ApplicationLibrary)
|
||||
}
|
||||
};
|
||||
|
||||
Style closeButton = new(x => x.Name("CloseButton"));
|
||||
closeButton.Setters.Add(new Setter(WidthProperty, 80d));
|
||||
|
||||
Style closeButtonParent = new(x => x.Name("CommandSpace"));
|
||||
closeButtonParent.Setters.Add(new Setter(HorizontalAlignmentProperty, Avalonia.Layout.HorizontalAlignment.Right));
|
||||
|
||||
contentDialog.Styles.Add(closeButton);
|
||||
contentDialog.Styles.Add(closeButtonParent);
|
||||
|
||||
await ContentDialogHelper.ShowAsync(contentDialog);
|
||||
|
||||
CompatibilityCsv.Unload();
|
||||
}
|
||||
|
||||
public CompatibilityList()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void TextBox_OnTextChanged(object sender, TextChangedEventArgs e)
|
||||
{
|
||||
if (DataContext is not CompatibilityViewModel cvm)
|
||||
return;
|
||||
|
||||
if (sender is not TextBox searchBox)
|
||||
return;
|
||||
|
||||
cvm.Search(searchBox.Text);
|
||||
}
|
||||
}
|
||||
}
|
66
src/Ryujinx/Utilities/Compat/CompatibilityViewModel.cs
Normal file
66
src/Ryujinx/Utilities/Compat/CompatibilityViewModel.cs
Normal file
@ -0,0 +1,66 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Gommon;
|
||||
using Ryujinx.Ava.UI.ViewModels;
|
||||
using Ryujinx.Ava.Utilities.AppLibrary;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Ryujinx.Ava.Utilities.Compat
|
||||
{
|
||||
public class CompatibilityViewModel : BaseModel
|
||||
{
|
||||
private bool _onlyShowOwnedGames = true;
|
||||
|
||||
private IEnumerable<CompatibilityEntry> _currentEntries = CompatibilityCsv.Entries;
|
||||
private string[] _ownedGameTitleIds = [];
|
||||
|
||||
public IEnumerable<CompatibilityEntry> CurrentEntries => OnlyShowOwnedGames
|
||||
? _currentEntries.Where(x =>
|
||||
x.TitleId.Check(tid => _ownedGameTitleIds.ContainsIgnoreCase(tid)))
|
||||
: _currentEntries;
|
||||
|
||||
public CompatibilityViewModel() {}
|
||||
|
||||
public CompatibilityViewModel(ApplicationLibrary appLibrary)
|
||||
{
|
||||
appLibrary.ApplicationCountUpdated += (_, _)
|
||||
=> _ownedGameTitleIds = appLibrary.Applications.Keys.Select(x => x.ToString("X16")).ToArray();
|
||||
|
||||
_ownedGameTitleIds = appLibrary.Applications.Keys.Select(x => x.ToString("X16")).ToArray();
|
||||
}
|
||||
|
||||
public bool OnlyShowOwnedGames
|
||||
{
|
||||
get => _onlyShowOwnedGames;
|
||||
set
|
||||
{
|
||||
OnPropertyChanging();
|
||||
OnPropertyChanging(nameof(CurrentEntries));
|
||||
_onlyShowOwnedGames = value;
|
||||
OnPropertyChanged();
|
||||
OnPropertyChanged(nameof(CurrentEntries));
|
||||
}
|
||||
}
|
||||
|
||||
public void Search(string searchTerm)
|
||||
{
|
||||
if (string.IsNullOrEmpty(searchTerm))
|
||||
{
|
||||
SetEntries(CompatibilityCsv.Entries);
|
||||
return;
|
||||
}
|
||||
|
||||
SetEntries(CompatibilityCsv.Entries.Where(x =>
|
||||
x.GameName.ContainsIgnoreCase(searchTerm)
|
||||
|| x.TitleId.Check(tid => tid.ContainsIgnoreCase(searchTerm))));
|
||||
}
|
||||
|
||||
private void SetEntries(IEnumerable<CompatibilityEntry> entries)
|
||||
{
|
||||
#pragma warning disable MVVMTK0034
|
||||
_currentEntries = entries.ToList();
|
||||
#pragma warning restore MVVMTK0034
|
||||
OnPropertyChanged(nameof(CurrentEntries));
|
||||
}
|
||||
}
|
||||
}
|
@ -4,7 +4,7 @@ namespace Ryujinx.Ava.Utilities
|
||||
{
|
||||
public static class TitleHelper
|
||||
{
|
||||
public static string ActiveApplicationTitle(ProcessResult activeProcess, string applicationVersion, string pauseString = "")
|
||||
public static string ActiveApplicationTitle(ProcessResult activeProcess, string applicationVersion, bool customTitlebar, string pauseString = "")
|
||||
{
|
||||
if (activeProcess == null)
|
||||
return string.Empty;
|
||||
@ -14,7 +14,9 @@ namespace Ryujinx.Ava.Utilities
|
||||
string titleIdSection = $" ({activeProcess.ProgramIdText.ToUpper()})";
|
||||
string titleArchSection = activeProcess.Is64Bit ? " (64-bit)" : " (32-bit)";
|
||||
|
||||
string appTitle = $"Ryujinx {applicationVersion} -{titleNameSection}{titleVersionSection}{titleIdSection}{titleArchSection}";
|
||||
string appTitle = customTitlebar
|
||||
? $"Ryujinx {applicationVersion}\n{titleNameSection.Trim()}\n{titleVersionSection.Trim()}\n{titleIdSection.Trim()}{titleArchSection}"
|
||||
: $"Ryujinx {applicationVersion} -{titleNameSection}{titleVersionSection}{titleIdSection}{titleArchSection}";
|
||||
|
||||
return !string.IsNullOrEmpty(pauseString)
|
||||
? appTitle + $" ({pauseString})"
|
||||
|
@ -1,3 +1,5 @@
|
||||
using Humanizer;
|
||||
using Humanizer.Localisation;
|
||||
using Ryujinx.Ava.Common.Locale;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
@ -31,7 +33,7 @@ namespace Ryujinx.Ava.Utilities
|
||||
Gigabytes = 9,
|
||||
Terabytes = 10,
|
||||
Petabytes = 11,
|
||||
Exabytes = 12,
|
||||
Exabytes = 12
|
||||
}
|
||||
|
||||
private const double SizeBase10 = 1000;
|
||||
@ -48,22 +50,24 @@ namespace Ryujinx.Ava.Utilities
|
||||
public static string FormatTimeSpan(TimeSpan? timeSpan)
|
||||
{
|
||||
if (!timeSpan.HasValue || timeSpan.Value.TotalSeconds < 1)
|
||||
{
|
||||
// Game was never played
|
||||
return TimeSpan.Zero.ToString("c", CultureInfo.InvariantCulture);
|
||||
}
|
||||
return string.Empty;
|
||||
|
||||
if (timeSpan.Value.TotalSeconds < 60)
|
||||
return timeSpan.Value.Humanize(1,
|
||||
countEmptyUnits: false,
|
||||
maxUnit: TimeUnit.Second,
|
||||
minUnit: TimeUnit.Second);
|
||||
|
||||
if (timeSpan.Value.TotalDays < 1)
|
||||
{
|
||||
// Game was played for less than a day
|
||||
return timeSpan.Value.ToString("c", CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
// Game was played for more than a day
|
||||
TimeSpan onlyTime = timeSpan.Value.Subtract(TimeSpan.FromDays(timeSpan.Value.Days));
|
||||
string onlyTimeString = onlyTime.ToString("c", CultureInfo.InvariantCulture);
|
||||
|
||||
return $"{timeSpan.Value.Days}d, {onlyTimeString}";
|
||||
if (timeSpan.Value.TotalMinutes < 60)
|
||||
return timeSpan.Value.Humanize(1,
|
||||
countEmptyUnits: false,
|
||||
maxUnit: TimeUnit.Minute,
|
||||
minUnit: TimeUnit.Minute);
|
||||
|
||||
return timeSpan.Value.Humanize(1,
|
||||
countEmptyUnits: false,
|
||||
maxUnit: TimeUnit.Hour,
|
||||
minUnit: TimeUnit.Hour);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
Reference in New Issue
Block a user