Compare commits

...

19 Commits

Author SHA1 Message Date
e9824c9053 Comment AppImage builds
It randomly started erroring in GitHub actions with exit code 8 but only sometimes, and I don't have the patience to debug it. I don't even use linux lol
2025-07-28 19:35:47 -05:00
d2037da65f Nullify Locales (ryubing/ryujinx!83)
See merge request ryubing/ryujinx!83
2025-07-28 19:35:47 -05:00
8fe7d54f85 Changes to uk_UA (ryubing/ryujinx!84)
See merge request ryubing/ryujinx!84
2025-07-28 19:35:47 -05:00
b8f9f3e16a Edit TileIDs.cs (ryubing/ryujinx!81)
See merge request ryubing/ryujinx!81
2025-07-28 19:35:47 -05:00
7b1c8717ef Edit compatibility.csv (ryubing/ryujinx!80)
See merge request ryubing/ryujinx!80
2025-07-28 19:35:47 -05:00
6122fa204f simplify completion callback 2025-07-28 17:58:54 -05:00
217fd90568 Use a single parser execution per text box update
Before it would: parse, compile, then execute for getting the formatted result, then run the suggestions function which did parsing on its own. It has now been moved to the new ParseAndGetCompletions function which returns the used ParserResult, saving some work.
2025-07-27 17:35:06 -05:00
95157c0cfd make ApplicationLibrary implement IStarscriptObject 2025-07-27 17:32:39 -05:00
8a3ccaafe3 basic starscript support + a textbox that provides the starscript executed result & compiled script as well as suggestions 2025-07-27 01:09:59 -05:00
45b2e613cf Update Ryujinx.LibHac
This should fix crashes with mods that worked on Ryubing 1.3.1.

Thanks @cyphix!

e39169ab50
2025-07-20 03:29:01 -05:00
932c480325 small translation update (ryubing/ryujinx!79)
See merge request ryubing/ryujinx!79
2025-07-16 14:02:26 -05:00
0e24435414 Updated Brazilian Portuguese translation. (ryubing/ryujinx!77)
See merge request ryubing/ryujinx!77
2025-06-30 20:21:14 -05:00
a5cf0482b4 Update to the french translation (ryubing/ryujinx!76)
See merge request ryubing/ryujinx!76
2025-06-30 13:45:29 -05:00
Neo
14e794af84 Update UI Icons (ryubing/ryujinx!75)
See merge request ryubing/ryujinx!75
2025-06-30 03:15:14 -05:00
29a02f4787 docs: compat: Risk of Rain Returns: Playable 2025-06-28 04:24:20 -05:00
e2f9d84b64 docs: Latest update redirect URL
GitLab does not offer a web-page view of the latest release like GitHub does, this is only available on the REST API.
As such, I added this functionality to the update server since it keeps track of what the latest version is for both release channels anyways.
2025-06-28 04:21:04 -05:00
Neo
0cc94fdf37 Update French Translation (ryubing/ryujinx!67)
See merge request ryubing/ryujinx!67
2025-06-23 14:50:47 -05:00
74a9b94227 UI: Properly space total play time separator when loading bar is shown. 2025-06-20 23:06:16 -05:00
d3208a4c44 UI: Don't show total play time if there is none. 2025-06-20 23:02:39 -05:00
22 changed files with 1420 additions and 1020 deletions

View File

@ -105,46 +105,48 @@ jobs:
gli --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/canary --command=UploadGenericPackage "Ryubing-Canary|${{ steps.version_info.outputs.build_version }}|release_output/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz" gli --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/canary --command=UploadGenericPackage "Ryubing-Canary|${{ steps.version_info.outputs.build_version }}|release_output/ryujinx-canary-${{ steps.version_info.outputs.build_version }}-${{ matrix.platform.zip_os_name }}.tar.gz"
shell: bash shell: bash
# If anyone wants to look into why appimagetool randomly errors with exit code 8, that would be cool
- name: Build AppImage (Linux) # - name: Build AppImage (Linux)
if: matrix.platform.os == 'ubuntu-latest' # if: matrix.platform.os == 'ubuntu-latest'
run: | # run: |
BUILD_VERSION="${{ steps.version_info.outputs.build_version }}" # BUILD_VERSION="${{ steps.version_info.outputs.build_version }}"
PLATFORM_NAME="${{ matrix.platform.name }}" # 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 # mkdir -p tools
export PATH="$PATH:$(readlink -f tools)" # export PATH="$PATH:$(readlink -f tools)"
#
# Setup appimagetool # # Setup appimagetool
wget -q -O tools/appimagetool "https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-x86_64.AppImage" # wget -q -O tools/appimagetool "https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-x86_64.AppImage"
chmod +x tools/appimagetool # chmod +x tools/appimagetool
chmod +x distribution/linux/appimage/build-appimage.sh # chmod +x distribution/linux/appimage/build-appimage.sh
#
# Explicitly set $ARCH for appimagetool ($ARCH_NAME is for the file name) # # Explicitly set $ARCH for appimagetool ($ARCH_NAME is for the file name)
if [ "$PLATFORM_NAME" = "linux-x64" ]; then # if [ "$PLATFORM_NAME" = "linux-x64" ]; then
ARCH_NAME=x64 # ARCH_NAME=x64
export ARCH=x86_64 # export ARCH=x86_64
elif [ "$PLATFORM_NAME" = "linux-arm64" ]; then # elif [ "$PLATFORM_NAME" = "linux-arm64" ]; then
ARCH_NAME=arm64 # ARCH_NAME=arm64
export ARCH=aarch64 # export ARCH=aarch64
else # else
echo "Unexpected PLATFORM_NAME "$PLATFORM_NAME"" # echo "Unexpected PLATFORM_NAME "$PLATFORM_NAME""
exit 1 # exit 1
fi # fi
#
export UFLAG="gh-releases-zsync|${{ secrets.RC_OWNER }}${{ secrets.RC_CANARY_NAME }}|latest|*-$ARCH_NAME.AppImage.zsync" # export UFLAG="gh-releases-zsync|${{ secrets.RC_OWNER }}${{ secrets.RC_CANARY_NAME }}|latest|*-$ARCH_NAME.AppImage.zsync"
BUILDDIR=publish OUTDIR=publish_appimage distribution/linux/appimage/build-appimage.sh # BUILDDIR=publish OUTDIR=publish_appimage distribution/linux/appimage/build-appimage.sh
#
pushd publish_appimage # pushd publish_appimage
mv Ryujinx.AppImage ../release_output/ryujinx-canary-$BUILD_VERSION-$ARCH_NAME.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 # mv Ryujinx.AppImage.zsync ../release_output/ryujinx-canary-$BUILD_VERSION-$ARCH_NAME.AppImage.zsync
popd # popd
#
gli --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/canary --command=UploadGenericPackage "Ryubing-Canary|${{ steps.version_info.outputs.build_version }}|release_output/ryujinx-canary-$BUILD_VERSION-$ARCH_NAME.AppImage" # gli --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/canary --command=UploadGenericPackage "Ryubing-Canary|${{ steps.version_info.outputs.build_version }}|release_output/ryujinx-canary-$BUILD_VERSION-$ARCH_NAME.AppImage"
gli --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/canary --command=UploadGenericPackage "Ryubing-Canary|${{ steps.version_info.outputs.build_version }}|release_output/ryujinx-canary-$BUILD_VERSION-$ARCH_NAME.AppImage.zsync" # gli --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/canary --command=UploadGenericPackage "Ryubing-Canary|${{ steps.version_info.outputs.build_version }}|release_output/ryujinx-canary-$BUILD_VERSION-$ARCH_NAME.AppImage.zsync"
shell: bash # shell: bash
macos_release: macos_release:
name: Release MacOS universal name: Release MacOS universal

View File

@ -96,46 +96,48 @@ jobs:
shell: bash shell: bash
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Build AppImage (Linux)
if: matrix.platform.os == 'ubuntu-latest'
run: |
BUILD_VERSION="${{ steps.version_info.outputs.build_version }}"
PLATFORM_NAME="${{ matrix.platform.name }}"
sudo apt install -y zsync desktop-file-utils appstream
mkdir -p tools
export PATH="$PATH:$(readlink -f tools)"
# Setup appimagetool
wget -q -O tools/appimagetool "https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-x86_64.AppImage"
chmod +x tools/appimagetool
chmod +x distribution/linux/appimage/build-appimage.sh
# Explicitly set $ARCH for appimagetool ($ARCH_NAME is for the file name)
if [ "$PLATFORM_NAME" = "linux-x64" ]; then
ARCH_NAME=x64
export ARCH=x86_64
elif [ "$PLATFORM_NAME" = "linux-arm64" ]; then
ARCH_NAME=arm64
export ARCH=aarch64
else
echo "Unexpected PLATFORM_NAME "$PLATFORM_NAME""
exit 1
fi
export UFLAG="gh-releases-zsync|${{ github.repository_owner }}|${{ github.event.repository.name }}|latest|*-$ARCH_NAME.AppImage.zsync"
BUILDDIR=publish OUTDIR=publish_appimage distribution/linux/appimage/build-appimage.sh
pushd publish_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
gli --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/ryujinx --command=UploadGenericPackage "Ryubing|${{ steps.version_info.outputs.build_version }}|release_output/ryujinx-$BUILD_VERSION-$ARCH_NAME.AppImage" # If anyone wants to look into why appimagetool randomly errors with exit code 8, that would be cool
gli --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/ryujinx --command=UploadGenericPackage "Ryubing|${{ steps.version_info.outputs.build_version }}|release_output/ryujinx-$BUILD_VERSION-$ARCH_NAME.AppImage.zsync"
shell: bash # - name: Build AppImage (Linux)
# if: matrix.platform.os == 'ubuntu-latest'
# run: |
# BUILD_VERSION="${{ steps.version_info.outputs.build_version }}"
# PLATFORM_NAME="${{ matrix.platform.name }}"
#
# sudo apt install -y zsync desktop-file-utils appstream
#
# mkdir -p tools
# export PATH="$PATH:$(readlink -f tools)"
#
# # Setup appimagetool
# wget -q -O tools/appimagetool "https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-x86_64.AppImage"
# chmod +x tools/appimagetool
# chmod +x distribution/linux/appimage/build-appimage.sh
#
# # Explicitly set $ARCH for appimagetool ($ARCH_NAME is for the file name)
# if [ "$PLATFORM_NAME" = "linux-x64" ]; then
# ARCH_NAME=x64
# export ARCH=x86_64
# elif [ "$PLATFORM_NAME" = "linux-arm64" ]; then
# ARCH_NAME=arm64
# export ARCH=aarch64
# else
# echo "Unexpected PLATFORM_NAME "$PLATFORM_NAME""
# exit 1
# fi
#
# export UFLAG="gh-releases-zsync|${{ github.repository_owner }}|${{ github.event.repository.name }}|latest|*-$ARCH_NAME.AppImage.zsync"
# BUILDDIR=publish OUTDIR=publish_appimage distribution/linux/appimage/build-appimage.sh
#
# pushd publish_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
#
# gli --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/ryujinx --command=UploadGenericPackage "Ryubing|${{ steps.version_info.outputs.build_version }}|release_output/ryujinx-$BUILD_VERSION-$ARCH_NAME.AppImage"
# gli --access-token=${{ secrets.GITLAB_TOKEN }} --project=ryubing/ryujinx --command=UploadGenericPackage "Ryubing|${{ steps.version_info.outputs.build_version }}|release_output/ryujinx-$BUILD_VERSION-$ARCH_NAME.AppImage.zsync"
# shell: bash
macos_release: macos_release:
name: Release MacOS universal name: Release MacOS universal

View File

@ -40,7 +40,7 @@
<PackageVersion Include="Ryujinx.Audio.OpenAL.Dependencies" Version="1.21.0.1" /> <PackageVersion Include="Ryujinx.Audio.OpenAL.Dependencies" Version="1.21.0.1" />
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies.AllArch" Version="6.1.2-build3" /> <PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies.AllArch" Version="6.1.2-build3" />
<PackageVersion Include="Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK" Version="1.2.0" /> <PackageVersion Include="Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK" Version="1.2.0" />
<PackageVersion Include="Ryujinx.LibHac" Version="0.20.0" /> <PackageVersion Include="Ryujinx.LibHac" Version="0.21.0-alpha.116" />
<PackageVersion Include="Ryujinx.SDL2-CS" Version="2.30.0-build32" /> <PackageVersion Include="Ryujinx.SDL2-CS" Version="2.30.0-build32" />
<PackageVersion Include="Ryujinx.UpdateClient" Version="1.0.29" /> <PackageVersion Include="Ryujinx.UpdateClient" Version="1.0.29" />
<PackageVersion Include="Ryujinx.Systems.Update.Common" Version="1.0.29" /> <PackageVersion Include="Ryujinx.Systems.Update.Common" Version="1.0.29" />
@ -55,6 +55,7 @@
<PackageVersion Include="SkiaSharp" Version="2.88.9" /> <PackageVersion Include="SkiaSharp" Version="2.88.9" />
<PackageVersion Include="SkiaSharp.NativeAssets.Linux" Version="2.88.9" /> <PackageVersion Include="SkiaSharp.NativeAssets.Linux" Version="2.88.9" />
<PackageVersion Include="SPB" Version="0.0.4-build32" /> <PackageVersion Include="SPB" Version="0.0.4-build32" />
<PackageVersion Include="Starscript.Net" Version="1.0.36" />
<PackageVersion Include="System.IO.Hashing" Version="9.0.2" /> <PackageVersion Include="System.IO.Hashing" Version="9.0.2" />
<PackageVersion Include="System.Management" Version="9.0.2" /> <PackageVersion Include="System.Management" Version="9.0.2" />
<PackageVersion Include="UnicornEngine.Unicorn" Version="2.0.2-rc1-fb78016" /> <PackageVersion Include="UnicornEngine.Unicorn" Version="2.0.2-rc1-fb78016" />

View File

@ -7,8 +7,8 @@
# Ryujinx # Ryujinx
[![Latest release](https://img.shields.io/gitlab/v/release/ryubing%2Fryujinx?gitlab_url=https%3A%2F%2Fgit.ryujinx.app&label=stable&color=32cd32)](https://git.ryujinx.app/ryubing/ryujinx/-/releases) [![Latest release](https://img.shields.io/gitlab/v/release/ryubing%2Fryujinx?gitlab_url=https%3A%2F%2Fgit.ryujinx.app&label=stable&color=32cd32)](https://update.ryujinx.app/latest/stable)
[![Latest canary release](https://img.shields.io/gitlab/v/release/ryubing%2Fcanary?gitlab_url=https%3A%2F%2Fgit.ryujinx.app&label=canary&color=FF4500)](https://git.ryujinx.app/ryubing/canary/-/releases) [![Latest canary release](https://img.shields.io/gitlab/v/release/ryubing%2Fcanary?gitlab_url=https%3A%2F%2Fgit.ryujinx.app&label=canary&color=FF4500)](https://update.ryujinx.app/latest/canary)
<br> <br>
<a href="https://discord.gg/PEuzjrFXUA"> <a href="https://discord.gg/PEuzjrFXUA">
<img src="https://img.shields.io/discord/1294443224030511104?color=5865F2&label=Ryubing&logo=discord&logoColor=white" alt="Discord"> <img src="https://img.shields.io/discord/1294443224030511104?color=5865F2&label=Ryubing&logo=discord&logoColor=white" alt="Discord">

File diff suppressed because it is too large Load Diff

View File

@ -2257,6 +2257,7 @@
010086F0064CE000,"Poi: Explorer Edition",nvdec,playable,2021-01-21 19:32:00 010086F0064CE000,"Poi: Explorer Edition",nvdec,playable,2021-01-21 19:32:00
0100EB6012FD2000,"Poison Control",,playable,2021-05-16 14:01:54 0100EB6012FD2000,"Poison Control",,playable,2021-05-16 14:01:54
010072400E04A000,"Pokémon Café ReMix",,playable,2021-08-17 20:00:04 010072400E04A000,"Pokémon Café ReMix",,playable,2021-08-17 20:00:04
010008c01e742000,"Pokémon Friends",crash;services,menus,2025-07-24 13:32:00
01003D200BAA2000,"Pokémon Mystery Dungeon™: Rescue Team DX",mac-bug,playable,2024-01-21 00:16:32 01003D200BAA2000,"Pokémon Mystery Dungeon™: Rescue Team DX",mac-bug,playable,2024-01-21 00:16:32
01008DB008C2C000,"Pokémon Shield + Pokémon Shield Expansion Pass",deadlock;crash;online-broken;ldn-works;LAN,ingame,2024-08-12 07:20:22 01008DB008C2C000,"Pokémon Shield + Pokémon Shield Expansion Pass",deadlock;crash;online-broken;ldn-works;LAN,ingame,2024-08-12 07:20:22
0100ABF008968000,"Pokémon Sword + Pokémon Sword Expansion Pass",deadlock;crash;online-broken;ldn-works;LAN,ingame,2024-08-26 15:40:37 0100ABF008968000,"Pokémon Sword + Pokémon Sword Expansion Pass",deadlock;crash;online-broken;ldn-works;LAN,ingame,2024-08-26 15:40:37
@ -2436,6 +2437,7 @@
0100E9C010EA8000,"Rise of Insanity",,playable,2020-08-30 15:42:14 0100E9C010EA8000,"Rise of Insanity",,playable,2020-08-30 15:42:14
01006BA00E652000,"Rise: Race The Future",,playable,2021-02-27 13:29:06 01006BA00E652000,"Rise: Race The Future",,playable,2021-02-27 13:29:06
010020C012F48000,"Rising Hell",,playable,2022-10-31 13:54:02 010020C012F48000,"Rising Hell",,playable,2022-10-31 13:54:02
0100D1801A0F4000,"Risk of Rain Returns",,playable,2025-06-28 04:24:04
010076D00E4BA000,"Risk of Rain 2",online-broken,playable,2024-03-04 17:01:05 010076D00E4BA000,"Risk of Rain 2",online-broken,playable,2024-03-04 17:01:05
0100E8300A67A000,"RISK® Global Domination",nvdec;online-broken,playable,2022-08-01 18:53:28 0100E8300A67A000,"RISK® Global Domination",nvdec;online-broken,playable,2022-08-01 18:53:28
010042500FABA000,"Ritual: Crown of Horns",,playable,2021-01-26 16:01:47 010042500FABA000,"Ritual: Crown of Horns",,playable,2021-01-26 16:01:47

1 title_id game_name labels status last_updated
2257 010086F0064CE000 Poi: Explorer Edition nvdec playable 2021-01-21 19:32:00
2258 0100EB6012FD2000 Poison Control playable 2021-05-16 14:01:54
2259 010072400E04A000 Pokémon Café ReMix playable 2021-08-17 20:00:04
2260 010008c01e742000 Pokémon Friends crash;services menus 2025-07-24 13:32:00
2261 01003D200BAA2000 Pokémon Mystery Dungeon™: Rescue Team DX mac-bug playable 2024-01-21 00:16:32
2262 01008DB008C2C000 Pokémon Shield + Pokémon Shield Expansion Pass deadlock;crash;online-broken;ldn-works;LAN ingame 2024-08-12 07:20:22
2263 0100ABF008968000 Pokémon Sword + Pokémon Sword Expansion Pass deadlock;crash;online-broken;ldn-works;LAN ingame 2024-08-26 15:40:37
2437 0100E9C010EA8000 Rise of Insanity playable 2020-08-30 15:42:14
2438 01006BA00E652000 Rise: Race The Future playable 2021-02-27 13:29:06
2439 010020C012F48000 Rising Hell playable 2022-10-31 13:54:02
2440 0100D1801A0F4000 Risk of Rain Returns playable 2025-06-28 04:24:04
2441 010076D00E4BA000 Risk of Rain 2 online-broken playable 2024-03-04 17:01:05
2442 0100E8300A67A000 RISK® Global Domination nvdec;online-broken playable 2022-08-01 18:53:28
2443 010042500FABA000 Ritual: Crown of Horns playable 2021-01-26 16:01:47

View File

@ -5,7 +5,7 @@
<clear /> <clear />
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" /> <add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
<!-- Only needed when using pre-release versions of Ryujinx.LibHac. --> <!-- Only needed when using pre-release versions of Ryujinx.LibHac. -->
<!--<add key="LibHacAlpha" value="https://git.ryujinx.app/api/v4/projects/17/packages/nuget/index.json" />--> <add key="LibHacAlpha" value="https://git.ryujinx.app/api/v4/projects/17/packages/nuget/index.json" />
<add key="Ryujinx.UpdateClient" value="https://git.ryujinx.app/api/v4/projects/71/packages/nuget/index.json" /> <add key="Ryujinx.UpdateClient" value="https://git.ryujinx.app/api/v4/projects/71/packages/nuget/index.json" />
</packageSources> </packageSources>
<packageSourceMapping> <packageSourceMapping>
@ -18,8 +18,8 @@
<package pattern="Ryujinx.UpdateClient" /> <package pattern="Ryujinx.UpdateClient" />
<package pattern="Ryujinx.Systems.Update.Common" /> <package pattern="Ryujinx.Systems.Update.Common" />
</packageSource> </packageSource>
<!--<packageSource key="LibHacAlpha"> <packageSource key="LibHacAlpha">
<package pattern="Ryujinx.LibHac" /> <package pattern="Ryujinx.LibHac" />
</packageSource>--> </packageSource>
</packageSourceMapping> </packageSourceMapping>
</configuration> </configuration>

View File

@ -33,7 +33,7 @@ namespace Ryujinx.BuildValidationTasks
LocalesJson json; LocalesJson json;
if (isGitRunner && data.Contains("\r\n")) if (isGitRunner && data.Contains("\r\n"))
throw new FormatException("locales.json is using CRLF line endings! It should be using LF line endings, build locally to fix..."); throw new FormatException("locales.json is using CRLF line endings! It should be using LF line endings, rebuild locally to fix...");
try try
{ {
@ -86,7 +86,7 @@ namespace Ryujinx.BuildValidationTasks
} }
if (isGitRunner && encounteredIssue) if (isGitRunner && encounteredIssue)
throw new JsonException("1 or more locales are invalid!"); throw new JsonException("1 or more locales are invalid! Rebuild locally to fix...");
string jsonString = JsonSerializer.Serialize(json, _jsonOptions); string jsonString = JsonSerializer.Serialize(json, _jsonOptions);
@ -102,6 +102,7 @@ namespace Ryujinx.BuildValidationTasks
struct LocalesJson struct LocalesJson
{ {
public Dictionary<string, string> Info { get; set; }
public List<string> Languages { get; set; } public List<string> Languages { get; set; }
public List<LocalesEntry> Locales { get; set; } public List<LocalesEntry> Locales { get; set; }
} }

View File

@ -10,8 +10,18 @@
<Exec WorkingDirectory="$(ProjectDir)bin\Debug\$(TargetFramework)\" <Exec WorkingDirectory="$(ProjectDir)bin\Debug\$(TargetFramework)\"
Command="dotnet Ryujinx.BuildValidationTasks.dll &quot;$(ProjectDir)..\..\\&quot;" Command="dotnet Ryujinx.BuildValidationTasks.dll &quot;$(ProjectDir)..\..\\&quot;"
ConsoleToMsBuild="true" ConsoleToMsBuild="true"
Condition="'$(RuntimeIdentifier)' == ''" Condition="'$(RuntimeIdentifier)' == ''"
/> IgnoreExitCode="true">
<Output TaskParameter="ConsoleOutput" PropertyName="OutputOfExec" />
<Output TaskParameter="ExitCode" PropertyName="BuildExitCode"/>
</Exec>
<PropertyGroup Condition=" '$(OutputOfExec.IndexOf(Unhandled exception))' != '-1'">
<ErrorOutput>$(OutputOfExec.Substring($(OutputOfExec.IndexOf("Unhandled exception"))))</ErrorOutput>
<ErrorOutput>$(ErrorOutput.Substring(0, $(ErrorOutput.IndexOf(';'))))</ErrorOutput>
</PropertyGroup>
<Error Text="$(ErrorOutput)" Condition=" '$(BuildExitCode)' != '0'"/>
</Target> </Target>
</Project> </Project>

View File

@ -93,6 +93,7 @@ namespace Ryujinx.Common
//The Pokémon Franchise //The Pokémon Franchise
"0100f4300bf2c000", // New Pokémon Snap "0100f4300bf2c000", // New Pokémon Snap
"0100000011d90000", // Pokémon Brilliant Diamond "0100000011d90000", // Pokémon Brilliant Diamond
"010008c01e742000", // Pokémon Friends
"01001f5010dfa000", // Pokémon Legends: Arceus "01001f5010dfa000", // Pokémon Legends: Arceus
"01003d200baa2000", // Pokémon Mystery Dungeon - Rescue Team DX "01003d200baa2000", // Pokémon Mystery Dungeon - Rescue Team DX
"0100a3d008c5c000", // Pokémon Scarlet "0100a3d008c5c000", // Pokémon Scarlet

View File

@ -73,6 +73,7 @@
<PackageReference Include="Silk.NET.Vulkan.Extensions.EXT" /> <PackageReference Include="Silk.NET.Vulkan.Extensions.EXT" />
<PackageReference Include="Silk.NET.Vulkan.Extensions.KHR" /> <PackageReference Include="Silk.NET.Vulkan.Extensions.KHR" />
<PackageReference Include="SPB" /> <PackageReference Include="SPB" />
<PackageReference Include="Starscript.Net"/>
<PackageReference Include="SharpZipLib" /> <PackageReference Include="SharpZipLib" />
</ItemGroup> </ItemGroup>

View File

@ -14,6 +14,7 @@ using LibHac.Tools.FsSystem.NcaUtils;
using Ryujinx.Ava.Common.Models; using Ryujinx.Ava.Common.Models;
using Ryujinx.Ava.Systems.Configuration; using Ryujinx.Ava.Systems.Configuration;
using Ryujinx.Ava.Systems.Configuration.System; using Ryujinx.Ava.Systems.Configuration.System;
using Ryujinx.Ava.Systems.Starscript;
using Ryujinx.Ava.Utilities; using Ryujinx.Ava.Utilities;
using Ryujinx.Common; using Ryujinx.Common;
using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration;
@ -25,6 +26,7 @@ using Ryujinx.HLE.HOS.SystemState;
using Ryujinx.HLE.Loaders.Npdm; using Ryujinx.HLE.Loaders.Npdm;
using Ryujinx.HLE.Loaders.Processes.Extensions; using Ryujinx.HLE.Loaders.Processes.Extensions;
using Ryujinx.HLE.Utilities; using Ryujinx.HLE.Utilities;
using Starscript;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
@ -41,7 +43,7 @@ using TimeSpan = System.TimeSpan;
namespace Ryujinx.Ava.Systems.AppLibrary namespace Ryujinx.Ava.Systems.AppLibrary
{ {
public class ApplicationLibrary public class ApplicationLibrary : IStarscriptObject
{ {
public Language DesiredLanguage { get; set; } public Language DesiredLanguage { get; set; }
public event EventHandler<ApplicationCountUpdatedEventArgs> ApplicationCountUpdated; public event EventHandler<ApplicationCountUpdatedEventArgs> ApplicationCountUpdated;
@ -1611,5 +1613,14 @@ namespace Ryujinx.Ava.Systems.AppLibrary
ApplicationData newApplication = newApplications.First(it => it.IdBase == appIdBase); ApplicationData newApplication = newApplications.First(it => it.IdBase == appIdBase);
_applications.AddOrUpdate(newApplication); _applications.AddOrUpdate(newApplication);
} }
private ValueMap _starscriptMap;
public ValueMap ToStarscript()
{
_starscriptMap ??= StarscriptHelper.Wrap(this);
return _starscriptMap;
}
} }
} }

View File

@ -0,0 +1,29 @@
using Ryujinx.Ava.Systems.AppLibrary;
using Ryujinx.Common;
using Starscript;
namespace Ryujinx.Ava.Systems.Starscript
{
public static class RyujinxStarscript
{
public static readonly StarscriptHypervisor Hypervisor = StarscriptHypervisor.Create().WithStandardLibrary(true);
static RyujinxStarscript()
{
Hypervisor.Set("ryujinx.releaseChannel",
ReleaseInformation.IsCanaryBuild
? "Canary"
: ReleaseInformation.IsReleaseBuild
? "Stable"
: "Custom");
Hypervisor.Set("ryujinx.version", Program.Version);
Hypervisor.Set("appLibrary", RyujinxApp.MainWindow.ApplicationLibrary);
Hypervisor.Set("currentApplication", () =>
RyujinxApp.MainWindow.ApplicationLibrary.FindApplication(
RyujinxApp.MainWindow.ViewModel.AppHost?.ApplicationId ?? 0,
out ApplicationData appData)
? StarscriptHelper.Wrap(appData)
: Value.Null);
}
}
}

View File

@ -0,0 +1,68 @@
using Gommon;
using Ryujinx.Ava.Systems.AppLibrary;
using Starscript;
using System;
namespace Ryujinx.Ava.Systems.Starscript
{
public static class StarscriptHelper
{
public static ValueMap Wrap(ApplicationLibrary appLib)
{
ValueMap lMap = new();
lMap.Set("appCount", () => appLib.Applications.Count);
lMap.Set("dlcCount", () => appLib.DownloadableContents.Count);
lMap.Set("updateCount", () => appLib.TitleUpdates.Count);
lMap.Set("has", ctx =>
{
ulong titleId;
try
{
titleId = ctx.Constrain(Constraint.ExactlyOneArgument).NextString(1).ToULong();
}
catch (FormatException)
{
throw ctx.Error(
$"Invalid input to {ctx.FormattedName}; input must be a hexadecimal number in a string.");
}
return appLib.FindApplication(titleId, out _);
});
lMap.Set("get", ctx =>
{
ulong titleId;
try
{
titleId = ctx.Constrain(Constraint.ExactlyOneArgument).NextString(1).ToULong();
}
catch (FormatException)
{
throw ctx.Error(
$"Invalid input to {ctx.FormattedName}; input must be a hexadecimal number in a string.");
}
return appLib.FindApplication(titleId,
out ApplicationData applicationData)
? Wrap(applicationData)
: null;
});
return lMap;
}
public static ValueMap Wrap(ApplicationData appData)
{
ValueMap aMap = new();
aMap.Set("name", appData.Name);
aMap.Set("version", appData.Version);
aMap.Set("developer", appData.Developer);
aMap.Set("fileExtension", appData.FileExtension);
aMap.Set("fileSize", appData.FileSizeString);
aMap.Set("hasLdnGames", appData.HasLdnGames);
aMap.Set("timePlayed", appData.TimePlayedString);
aMap.Set("isFavorite", appData.Favorite);
return aMap;
}
}
}

View File

@ -0,0 +1,21 @@
<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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="using:Ryujinx.Ava.Systems.Starscript"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Ryujinx.Ava.Systems.Starscript.StarscriptTextBox"
x:DataType="local:StarscriptTextBoxViewModel">
<StackPanel Spacing="10">
<TextBlock Text="{Binding ErrorMessage}" IsVisible="{Binding HasError}"/>
<TextBlock Text="{Binding CurrentScriptResult}" IsVisible="{Binding !HasError}"/>
<AutoCompleteBox Name="InputBox"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
FilterMode="Custom"
MinimumPrefixLength="0"
MaxDropDownHeight="400">
</AutoCompleteBox>
</StackPanel>
</UserControl>

View File

@ -0,0 +1,87 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Styling;
using FluentAvalonia.UI.Controls;
using Humanizer;
using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.UI.Controls;
using Ryujinx.Ava.UI.Helpers;
using Starscript;
using Starscript.Internal;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Ryujinx.Ava.Systems.Starscript
{
public partial class StarscriptTextBox : RyujinxControl<StarscriptTextBoxViewModel>
{
public IReadOnlyList<string> CurrentSuggestions => ViewModel.CurrentSuggestions;
public ParserResult CurrentScriptSource => ViewModel.CurrentScriptSource;
public Exception Exception => ViewModel.Exception;
public Script CurrentScript => ViewModel.CurrentScript;
public StringSegment CurrentScriptResult => ViewModel.CurrentScriptResult;
public StarscriptTextBox()
{
InitializeComponent();
InputBox.AsyncPopulator = GetSuggestionsAsync;
InputBox.MinimumPopulateDelay = 0.Seconds();
InputBox.TextFilter = (_, _) => true;
InputBox.TextSelector = (text, suggestion) =>
{
if (text is not null && suggestion is null)
return text;
if (text is null && suggestion is not null)
return suggestion;
// ReSharper disable once ConditionIsAlwaysTrueOrFalse
if (text is null && suggestion is null)
return string.Empty;
var sb = new StringBuilder(text.Length + suggestion.Length + 1);
sb.Append(text);
for (int i = 0; i < suggestion.Length - 1; i++)
{
if (text.EndsWith(suggestion[..(suggestion.Length - i - 1)]))
{
suggestion = suggestion[(suggestion.Length - i - 1)..];
break;
}
}
sb.Append(suggestion);
return sb.ToString();
};
Style textStyle = new(x => x.OfType<AutoCompleteBox>().Descendant().OfType<TextBlock>());
textStyle.Setters.Add(new Setter(MarginProperty, new Thickness(0, 0)));
Styles.Add(textStyle);
}
private Task<IEnumerable<object>> GetSuggestionsAsync(string input, CancellationToken token)
=> Task.FromResult(ViewModel.GetSuggestions(input, token));
public static StarscriptTextBox Create(StarscriptHypervisor hv)
=> new() { ViewModel = new StarscriptTextBoxViewModel(hv) };
public static async Task Show()
{
ContentDialog contentDialog = new()
{
PrimaryButtonText = string.Empty,
SecondaryButtonText = string.Empty,
CloseButtonText = LocaleManager.Instance[LocaleKeys.UserProfilesClose],
Content = new StarscriptTextBox { ViewModel = new() }
};
await ContentDialogHelper.ShowAsync(contentDialog.ApplyStyles());
}
}
}

View File

@ -0,0 +1,126 @@
using CommunityToolkit.Mvvm.ComponentModel;
using Ryujinx.Ava.UI.ViewModels;
using Starscript;
using Starscript.Internal;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading;
namespace Ryujinx.Ava.Systems.Starscript
{
public partial class StarscriptTextBoxViewModel : BaseModel
{
private readonly StarscriptHypervisor _hv;
public StarscriptTextBoxViewModel(StarscriptHypervisor hv = null)
{
_hv = hv ?? RyujinxStarscript.Hypervisor;
}
public ObservableCollection<string> CurrentSuggestions { get; } = [];
[ObservableProperty] private bool _hasError;
[ObservableProperty] private StringSegment _currentScriptResult;
[ObservableProperty] private string _errorMessage;
private Exception _exception;
private ParserResult _currentScriptSource;
private Script _currentScript;
public Exception Exception
{
get => _exception;
set
{
ErrorMessage = (_exception = value) switch
{
ParseException pe => pe.Error.ToString(),
StarscriptException se => se.Message,
_ => string.Empty
};
HasError = value is not null;
OnPropertyChanged();
}
}
public ParserResult CurrentScriptSource
{
get => _currentScriptSource;
set
{
_currentScriptSource = value;
if (value is null)
{
CurrentScript = null;
CurrentScriptResult = null;
Exception = null;
return;
}
CurrentScript = Compiler.SingleCompile(value);
Exception = null;
OnPropertyChanged();
}
}
public Script CurrentScript
{
get => _currentScript;
private set
{
try
{
CurrentScriptResult = value?.Execute(_hv)!;
_currentScript = value;
Exception = null;
}
catch (StarscriptException se)
{
_currentScript = null;
CurrentScriptResult = null;
Exception = se;
}
OnPropertyChanged();
}
}
public void ReExecuteScript()
{
if (_currentScript is null) return;
try
{
CurrentScriptResult = _currentScript.Execute(_hv)!;
}
catch (StarscriptException se)
{
CurrentScriptResult = null;
Exception = se;
}
}
public IEnumerable<object> GetSuggestions(string input, CancellationToken token)
{
CurrentSuggestions.Clear();
CurrentScriptSource = _hv.ParseAndGetCompletions(input, input.Length, CompletionCallback, token);
if (CurrentScriptSource.HasErrors)
{
Exception = new ParseException(CurrentScriptSource.Errors.First());
}
OnPropertyChanged(nameof(CurrentSuggestions));
return CurrentSuggestions;
}
private void CompletionCallback(string result, bool isFunction) => CurrentSuggestions.Add(isFunction ? $"{result}(" : result);
}
}

29
src/Ryujinx/UI/Controls/ApplicationContextMenu.axaml Normal file → Executable file
View File

@ -41,32 +41,34 @@
Command="{Binding OpenApplicationCompatibility}" Command="{Binding OpenApplicationCompatibility}"
CommandParameter="{Binding}" CommandParameter="{Binding}"
Header="{ext:Locale GameListContextMenuShowCompatEntry}" Header="{ext:Locale GameListContextMenuShowCompatEntry}"
Icon="{ext:Icon mdi-gamepad}" Icon="{ext:Icon fa-solid fa-database}"
ToolTip.Tip="{ext:Locale GameListContextMenuShowCompatEntryToolTip}"/> ToolTip.Tip="{ext:Locale GameListContextMenuShowCompatEntryToolTip}"/>
<MenuItem <MenuItem
Command="{Binding OpenApplicationData}" Command="{Binding OpenApplicationData}"
CommandParameter="{Binding}" CommandParameter="{Binding}"
Header="{ext:Locale GameListContextMenuShowGameData}" Header="{ext:Locale GameListContextMenuShowGameData}"
Icon="{ext:Icon mdi-chart-line}" Icon="{ext:Icon fa-solid fa-chart-line}"
ToolTip.Tip="{ext:Locale GameListContextMenuShowGameDataToolTip}"/> ToolTip.Tip="{ext:Locale GameListContextMenuShowGameDataToolTip}"/>
<Separator /> <Separator />
<MenuItem <MenuItem
Command="{Binding OpenUserSaveDirectory}" Command="{Binding OpenUserSaveDirectory}"
CommandParameter="{Binding}" CommandParameter="{Binding}"
Header="{ext:Locale GameListContextMenuOpenUserSaveDirectory}" Header="{ext:Locale GameListContextMenuOpenUserSaveDirectory}"
Icon="{ext:Icon mdi-folder-account}" Icon="{ext:Icon fa-solid fa-sd-card}"
IsEnabled="{Binding OpenUserSaveDirectoryEnabled}" IsEnabled="{Binding OpenUserSaveDirectoryEnabled}"
ToolTip.Tip="{ext:Locale GameListContextMenuOpenUserSaveDirectoryToolTip}" /> ToolTip.Tip="{ext:Locale GameListContextMenuOpenUserSaveDirectoryToolTip}" />
<MenuItem <MenuItem
Command="{Binding OpenDeviceSaveDirectory}" Command="{Binding OpenDeviceSaveDirectory}"
CommandParameter="{Binding}" CommandParameter="{Binding}"
Header="{ext:Locale GameListContextMenuOpenDeviceSaveDirectory}" Header="{ext:Locale GameListContextMenuOpenDeviceSaveDirectory}"
Icon="{ext:Icon fa-solid fa-hard-drive}"
IsEnabled="{Binding OpenDeviceSaveDirectoryEnabled}" IsEnabled="{Binding OpenDeviceSaveDirectoryEnabled}"
ToolTip.Tip="{ext:Locale GameListContextMenuOpenDeviceSaveDirectoryToolTip}" /> ToolTip.Tip="{ext:Locale GameListContextMenuOpenDeviceSaveDirectoryToolTip}" />
<MenuItem <MenuItem
Command="{Binding OpenBcatSaveDirectory}" Command="{Binding OpenBcatSaveDirectory}"
CommandParameter="{Binding}" CommandParameter="{Binding}"
Header="{ext:Locale GameListContextMenuOpenBcatSaveDirectory}" Header="{ext:Locale GameListContextMenuOpenBcatSaveDirectory}"
Icon="{ext:Icon fa-solid fa-box-archive}"
IsEnabled="{Binding OpenBcatSaveDirectoryEnabled}" IsEnabled="{Binding OpenBcatSaveDirectoryEnabled}"
ToolTip.Tip="{ext:Locale GameListContextMenuOpenBcatSaveDirectoryToolTip}" /> ToolTip.Tip="{ext:Locale GameListContextMenuOpenBcatSaveDirectoryToolTip}" />
<Separator /> <Separator />
@ -92,20 +94,20 @@
Command="{Binding OpenModManager}" Command="{Binding OpenModManager}"
CommandParameter="{Binding}" CommandParameter="{Binding}"
Header="{ext:Locale GameListContextMenuManageMod}" Header="{ext:Locale GameListContextMenuManageMod}"
Icon="{ext:Icon mdi-view-module}" Icon="{ext:Icon fa-solid fa-sliders}"
ToolTip.Tip="{ext:Locale GameListContextMenuManageModToolTip}" /> ToolTip.Tip="{ext:Locale GameListContextMenuManageModToolTip}" />
<Separator /> <Separator />
<MenuItem <MenuItem
Command="{Binding OpenModsDirectory}" Command="{Binding OpenModsDirectory}"
CommandParameter="{Binding}" CommandParameter="{Binding}"
Header="{ext:Locale GameListContextMenuOpenModsDirectory}" Header="{ext:Locale GameListContextMenuOpenModsDirectory}"
Icon="{ext:Icon mdi-folder-file}" Icon="{ext:Icon fa-solid fa-folder}"
ToolTip.Tip="{ext:Locale GameListContextMenuOpenModsDirectoryToolTip}" /> ToolTip.Tip="{ext:Locale GameListContextMenuOpenModsDirectoryToolTip}" />
<MenuItem <MenuItem
Command="{Binding OpenSdModsDirectory}" Command="{Binding OpenSdModsDirectory}"
CommandParameter="{Binding}" CommandParameter="{Binding}"
Header="{ext:Locale GameListContextMenuOpenSdModsDirectory}" Header="{ext:Locale GameListContextMenuOpenSdModsDirectory}"
Icon="{ext:Icon mdi-folder-file}" Icon="{ext:Icon fa-solid fa-folder}"
ToolTip.Tip="{ext:Locale GameListContextMenuOpenSdModsDirectoryToolTip}" /> ToolTip.Tip="{ext:Locale GameListContextMenuOpenSdModsDirectoryToolTip}" />
<Separator /> <Separator />
<MenuItem <MenuItem
@ -113,40 +115,41 @@
CommandParameter="{Binding}" CommandParameter="{Binding}"
Header="{ext:Locale GameListContextMenuTrimXCI}" Header="{ext:Locale GameListContextMenuTrimXCI}"
IsEnabled="{Binding TrimXCIEnabled}" IsEnabled="{Binding TrimXCIEnabled}"
Icon="{ext:Icon fa-solid fa-scissors}"
ToolTip.Tip="{ext:Locale GameListContextMenuTrimXCIToolTip}" /> ToolTip.Tip="{ext:Locale GameListContextMenuTrimXCIToolTip}" />
<MenuItem Header="{ext:Locale GameListContextMenuCacheManagement}" Icon="{ext:Icon mdi-cached}"> <MenuItem Header="{ext:Locale GameListContextMenuCacheManagement}" Icon="{ext:Icon fa-solid fa-memory}">
<MenuItem <MenuItem
Command="{Binding PurgePtcCache}" Command="{Binding PurgePtcCache}"
CommandParameter="{Binding}" CommandParameter="{Binding}"
Header="{ext:Locale GameListContextMenuCacheManagementPurgePptc}" Header="{ext:Locale GameListContextMenuCacheManagementPurgePptc}"
Icon="{ext:Icon mdi-refresh}" Icon="{ext:Icon fa-solid fa-arrow-rotate-right}"
ToolTip.Tip="{ext:Locale GameListContextMenuCacheManagementPurgePptcToolTip}" /> ToolTip.Tip="{ext:Locale GameListContextMenuCacheManagementPurgePptcToolTip}" />
<MenuItem <MenuItem
Command="{Binding NukePtcCache}" Command="{Binding NukePtcCache}"
CommandParameter="{Binding}" CommandParameter="{Binding}"
Header="{ext:Locale GameListContextMenuCacheManagementNukePptc}" Header="{ext:Locale GameListContextMenuCacheManagementNukePptc}"
Icon="{ext:Icon mdi-delete-alert}" Icon="{ext:Icon fa-solid fa-trash-can}"
ToolTip.Tip="{ext:Locale GameListContextMenuCacheManagementNukePptcToolTip}" /> ToolTip.Tip="{ext:Locale GameListContextMenuCacheManagementNukePptcToolTip}" />
<MenuItem <MenuItem
Command="{Binding PurgeShaderCache}" Command="{Binding PurgeShaderCache}"
CommandParameter="{Binding}" CommandParameter="{Binding}"
Header="{ext:Locale GameListContextMenuCacheManagementPurgeShaderCache}" Header="{ext:Locale GameListContextMenuCacheManagementPurgeShaderCache}"
Icon="{ext:Icon mdi-delete-alert}" Icon="{ext:Icon fa-solid fa-trash-can}"
ToolTip.Tip="{ext:Locale GameListContextMenuCacheManagementPurgeShaderCacheToolTip}" /> ToolTip.Tip="{ext:Locale GameListContextMenuCacheManagementPurgeShaderCacheToolTip}" />
<MenuItem <MenuItem
Command="{Binding OpenPtcDirectory}" Command="{Binding OpenPtcDirectory}"
CommandParameter="{Binding}" CommandParameter="{Binding}"
Header="{ext:Locale GameListContextMenuCacheManagementOpenPptcDirectory}" Header="{ext:Locale GameListContextMenuCacheManagementOpenPptcDirectory}"
Icon="{ext:Icon mdi-folder-arrow-up-down}" Icon="{ext:Icon fa-solid fa-folder}"
ToolTip.Tip="{ext:Locale GameListContextMenuCacheManagementOpenPptcDirectoryToolTip}" /> ToolTip.Tip="{ext:Locale GameListContextMenuCacheManagementOpenPptcDirectoryToolTip}" />
<MenuItem <MenuItem
Command="{Binding OpenShaderCacheDirectory}" Command="{Binding OpenShaderCacheDirectory}"
CommandParameter="{Binding}" CommandParameter="{Binding}"
Header="{ext:Locale GameListContextMenuCacheManagementOpenShaderCacheDirectory}" Header="{ext:Locale GameListContextMenuCacheManagementOpenShaderCacheDirectory}"
Icon="{ext:Icon mdi-folder-arrow-up-down}" Icon="{ext:Icon fa-solid fa-folder}"
ToolTip.Tip="{ext:Locale GameListContextMenuCacheManagementOpenShaderCacheDirectoryToolTip}" /> ToolTip.Tip="{ext:Locale GameListContextMenuCacheManagementOpenShaderCacheDirectoryToolTip}" />
</MenuItem> </MenuItem>
<MenuItem Header="{ext:Locale GameListContextMenuExtractData}"> <MenuItem Header="{ext:Locale GameListContextMenuExtractData}" Icon="{ext:Icon fa-solid fa-file-export}">
<MenuItem <MenuItem
Command="{Binding ExtractApplicationExeFs}" Command="{Binding ExtractApplicationExeFs}"
CommandParameter="{Binding}" CommandParameter="{Binding}"

View File

@ -310,10 +310,15 @@ namespace Ryujinx.Ava.UI.ViewModels
private void TotalTimePlayed_Recalculated(Optional<TimeSpan> ts) private void TotalTimePlayed_Recalculated(Optional<TimeSpan> ts)
{ {
ShowTotalTimePlayed = ts.HasValue;
if (ts.HasValue) if (ts.HasValue)
LocaleManager.Instance.SetDynamicValues(LocaleKeys.GameListLabelTotalTimePlayed, ValueFormatUtils.FormatTimeSpan(ts.Value)); {
var formattedPlayTime = ValueFormatUtils.FormatTimeSpan(ts.Value);
LocaleManager.Instance.SetDynamicValues(LocaleKeys.GameListLabelTotalTimePlayed, formattedPlayTime);
ShowTotalTimePlayed = formattedPlayTime != string.Empty;
return;
}
ShowTotalTimePlayed = ts.HasValue;
} }
public bool ShowTotalTimePlayed public bool ShowTotalTimePlayed
@ -334,7 +339,6 @@ namespace Ryujinx.Ava.UI.ViewModels
_listSelectedApplication = value; _listSelectedApplication = value;
if (_listSelectedApplication != null && ListAppContextMenu == null) if (_listSelectedApplication != null && ListAppContextMenu == null)
ListAppContextMenu = new ApplicationContextMenu(); ListAppContextMenu = new ApplicationContextMenu();
else if (_listSelectedApplication == null && ListAppContextMenu != null) else if (_listSelectedApplication == null && ListAppContextMenu != null)
ListAppContextMenu = null!; ListAppContextMenu = null!;

47
src/Ryujinx/UI/Views/Main/MainMenuBarView.axaml Normal file → Executable file
View File

@ -37,7 +37,7 @@
<MenuItem <MenuItem
Command="{Binding OpenFolder}" Command="{Binding OpenFolder}"
Header="{ext:Locale MenuBarFileOpenUnpacked}" Header="{ext:Locale MenuBarFileOpenUnpacked}"
Icon="{ext:Icon fa-solid fa-folder}" Icon="{ext:Icon fa-solid fa-folder-open}"
IsEnabled="{Binding EnableNonGameRunningControls}" IsEnabled="{Binding EnableNonGameRunningControls}"
ToolTip.Tip="{ext:Locale LoadApplicationFolderTooltip}" /> ToolTip.Tip="{ext:Locale LoadApplicationFolderTooltip}" />
<MenuItem <MenuItem
@ -52,7 +52,7 @@
Icon="{ext:Icon fa-solid fa-code-compare}" Icon="{ext:Icon fa-solid fa-code-compare}"
IsEnabled="{Binding EnableNonGameRunningControls}" IsEnabled="{Binding EnableNonGameRunningControls}"
ToolTip.Tip="{ext:Locale LoadTitleUpdatesFromFolderTooltip}" /> ToolTip.Tip="{ext:Locale LoadTitleUpdatesFromFolderTooltip}" />
<MenuItem Header="{ext:Locale MenuBarFileOpenApplet}" IsEnabled="{Binding IsAppletMenuActive}" Icon="{ext:Icon mdi-launch}"> <MenuItem Header="{ext:Locale MenuBarFileOpenApplet}" IsEnabled="{Binding IsAppletMenuActive}" Icon="{ext:Icon fa-solid fa-microchip}">
<MenuItem <MenuItem
Name="MiiAppletMenuItem" Name="MiiAppletMenuItem"
Header="{ext:Locale MenuBarFileOpenAppletOpenMiiApplet}" Header="{ext:Locale MenuBarFileOpenAppletOpenMiiApplet}"
@ -63,20 +63,23 @@
<MenuItem <MenuItem
Command="{Binding OpenRyujinxFolder}" Command="{Binding OpenRyujinxFolder}"
Header="{ext:Locale MenuBarFileOpenEmuFolder}" Header="{ext:Locale MenuBarFileOpenEmuFolder}"
Icon="{ext:Icon fa-solid fa-folder-closed}"
ToolTip.Tip="{ext:Locale OpenRyujinxFolderTooltip}" /> ToolTip.Tip="{ext:Locale OpenRyujinxFolderTooltip}" />
<MenuItem <MenuItem
Command="{Binding OpenScreenshotsFolder}" Command="{Binding OpenScreenshotsFolder}"
Header="{ext:Locale MenuBarFileOpenScreenshotsFolder}" Header="{ext:Locale MenuBarFileOpenScreenshotsFolder}"
Icon="{ext:Icon fa-solid fa-desktop}"
ToolTip.Tip="{ext:Locale OpenScreenshotFolderTooltip}"/> ToolTip.Tip="{ext:Locale OpenScreenshotFolderTooltip}"/>
<MenuItem <MenuItem
Command="{Binding OpenLogsFolder}" Command="{Binding OpenLogsFolder}"
Header="{ext:Locale MenuBarFileOpenLogsFolder}" Header="{ext:Locale MenuBarFileOpenLogsFolder}"
Icon="{ext:Icon fa-solid fa-file-lines}"
ToolTip.Tip="{ext:Locale OpenRyujinxLogsTooltip}" /> ToolTip.Tip="{ext:Locale OpenRyujinxLogsTooltip}" />
<Separator /> <Separator />
<MenuItem <MenuItem
Name="CloseRyujinxMenuItem" Name="CloseRyujinxMenuItem"
Header="{ext:Locale MenuBarFileExit}" Header="{ext:Locale MenuBarFileExit}"
Icon="{ext:Icon fa-solid fa-xmark}" Icon="{ext:Icon fa-solid fa-power-off}"
ToolTip.Tip="{ext:Locale ExitTooltip}" /> ToolTip.Tip="{ext:Locale ExitTooltip}" />
</MenuItem> </MenuItem>
<MenuItem VerticalAlignment="Center" Header="{ext:Locale MenuBarOptions}"> <MenuItem VerticalAlignment="Center" Header="{ext:Locale MenuBarOptions}">
@ -133,7 +136,7 @@
Name="ChangeLanguageMenuItem" Name="ChangeLanguageMenuItem"
Padding="0" Padding="0"
Header="{ext:Locale MenuBarOptionsChangeLanguage}" Header="{ext:Locale MenuBarOptionsChangeLanguage}"
Icon="{ext:Icon fa-solid fa-language}" Icon="{ext:Icon fa-solid fa-globe}"
Classes="withCheckbox"> Classes="withCheckbox">
</MenuItem> </MenuItem>
<MenuItem <MenuItem
@ -153,7 +156,7 @@
Command="{Binding ManageProfiles}" Command="{Binding ManageProfiles}"
Padding="0" Padding="0"
Header="{ext:Locale MenuBarOptionsManageUserProfiles}" Header="{ext:Locale MenuBarOptionsManageUserProfiles}"
Icon="{ext:Icon mdi-account}" Icon="{ext:Icon fa-solid fa-user}"
IsEnabled="{Binding EnableNonGameRunningControls}" IsEnabled="{Binding EnableNonGameRunningControls}"
ToolTip.Tip="{ext:Locale OpenProfileManagerTooltip}" ToolTip.Tip="{ext:Locale OpenProfileManagerTooltip}"
Classes="withCheckbox"> Classes="withCheckbox">
@ -185,33 +188,33 @@
InputGesture="Escape" InputGesture="Escape"
IsEnabled="{Binding IsGameRunning}" IsEnabled="{Binding IsGameRunning}"
ToolTip.Tip="{ext:Locale StopEmulationTooltip}" /> ToolTip.Tip="{ext:Locale StopEmulationTooltip}" />
<MenuItem Command="{Binding SimulateWakeUpMessage}" Header="{ext:Locale MenuBarOptionsSimulateWakeUpMessage}" /> <MenuItem Command="{Binding SimulateWakeUpMessage}" Header="{ext:Locale MenuBarOptionsSimulateWakeUpMessage}" Icon="{ext:Icon fa-solid fa-sun}" />
<Separator /> <Separator />
<MenuItem <MenuItem
Command="{Binding OpenAmiiboWindow}" Command="{Binding OpenAmiiboWindow}"
AttachedToVisualTree="ScanAmiiboMenuItem_AttachedToVisualTree" AttachedToVisualTree="ScanAmiiboMenuItem_AttachedToVisualTree"
Header="{ext:Locale MenuBarActionsScanAmiibo}" Header="{ext:Locale MenuBarActionsScanAmiibo}"
Icon="{ext:Icon mdi-cube-scan}" Icon="{ext:Icon fa-solid fa-cube}"
InputGesture="Ctrl + A" InputGesture="Ctrl + A"
IsEnabled="{Binding IsAmiiboRequested}" /> IsEnabled="{Binding IsAmiiboRequested}" />
<MenuItem <MenuItem
Command="{Binding OpenBinFile}" Command="{Binding OpenBinFile}"
AttachedToVisualTree="ScanBinAmiiboMenuItem_AttachedToVisualTree" AttachedToVisualTree="ScanBinAmiiboMenuItem_AttachedToVisualTree"
Header="{ext:Locale MenuBarActionsScanAmiiboBin}" Header="{ext:Locale MenuBarActionsScanAmiiboBin}"
Icon="{ext:Icon mdi-cube-scan}" Icon="{ext:Icon fa-solid fa-cube}"
IsVisible="{Binding CanScanAmiiboBinaries}" IsVisible="{Binding CanScanAmiiboBinaries}"
InputGesture="Ctrl + B" InputGesture="Ctrl + B"
IsEnabled="{Binding IsAmiiboBinRequested}" /> IsEnabled="{Binding IsAmiiboBinRequested}" />
<MenuItem <MenuItem
Command="{Binding TakeScreenshot}" Command="{Binding TakeScreenshot}"
Header="{ext:Locale MenuBarFileToolsTakeScreenshot}" Header="{ext:Locale MenuBarFileToolsTakeScreenshot}"
Icon="{ext:Icon mdi-monitor-screenshot}" Icon="{ext:Icon fa-solid fa-camera}"
InputGesture="{Binding ScreenshotKey}" InputGesture="{Binding ScreenshotKey}"
IsEnabled="{Binding IsGameRunning}" /> IsEnabled="{Binding IsGameRunning}" />
<MenuItem <MenuItem
Command="{Binding HideUi}" Command="{Binding HideUi}"
Header="{ext:Locale MenuBarFileToolsHideUi}" Header="{ext:Locale MenuBarFileToolsHideUi}"
Icon="{ext:Icon mdi-eye-off}" Icon="{ext:Icon fa-solid fa-eye-slash}"
InputGesture="{Binding ShowUiKey}" InputGesture="{Binding ShowUiKey}"
IsEnabled="{Binding IsGameRunning}" /> IsEnabled="{Binding IsGameRunning}" />
<MenuItem <MenuItem
@ -222,12 +225,12 @@
</MenuItem> </MenuItem>
<MenuItem VerticalAlignment="Center" Header="{ext:Locale MenuBarActions}" IsVisible="{Binding EnableNonGameRunningControls}"> <MenuItem VerticalAlignment="Center" Header="{ext:Locale MenuBarActions}" IsVisible="{Binding EnableNonGameRunningControls}">
<MenuItem Header="{ext:Locale MenuBarActionsInstallKeys}" Icon="{ext:Icon fa-solid fa-key}"> <MenuItem Header="{ext:Locale MenuBarActionsInstallKeys}" Icon="{ext:Icon fa-solid fa-key}">
<MenuItem Command="{Binding InstallKeysFromFile}" Header="{ext:Locale MenuBarFileActionsInstallKeysFromFile}" Icon="{ext:Icon mdi-file-cog}" /> <MenuItem Command="{Binding InstallKeysFromFile}" Header="{ext:Locale MenuBarFileActionsInstallKeysFromFile}" Icon="{ext:Icon fa-solid fa-file-code}" />
<MenuItem Command="{Binding InstallKeysFromFolder}" Header="{ext:Locale MenuBarFileActionsInstallKeysFromFolder}" Icon="{ext:Icon mdi-folder-cog}" /> <MenuItem Command="{Binding InstallKeysFromFolder}" Header="{ext:Locale MenuBarFileActionsInstallKeysFromFolder}" Icon="{ext:Icon fa-solid fa-folder-closed}" />
</MenuItem> </MenuItem>
<MenuItem Header="{ext:Locale MenuBarActionsInstallFirmware}" Icon="{ext:Icon fa-solid fa-download}"> <MenuItem Header="{ext:Locale MenuBarActionsInstallFirmware}" Icon="{ext:Icon fa-solid fa-floppy-disk}">
<MenuItem Command="{Binding InstallFirmwareFromFile}" Header="{ext:Locale MenuBarActionsInstallFirmwareFromFile}" Icon="{ext:Icon mdi-file-cog}" /> <MenuItem Command="{Binding InstallFirmwareFromFile}" Header="{ext:Locale MenuBarActionsInstallFirmwareFromFile}" Icon="{ext:Icon fa-solid fa-file-code}" />
<MenuItem Command="{Binding InstallFirmwareFromFolder}" Header="{ext:Locale MenuBarActionsInstallFirmwareFromDirectory}" Icon="{ext:Icon mdi-folder-cog}" /> <MenuItem Command="{Binding InstallFirmwareFromFolder}" Header="{ext:Locale MenuBarActionsInstallFirmwareFromDirectory}" Icon="{ext:Icon fa-solid fa-folder-closed}" />
</MenuItem> </MenuItem>
<MenuItem Header="{ext:Locale MenuBarActionsManageFileTypes}" IsVisible="{Binding ManageFileTypesVisible}"> <MenuItem Header="{ext:Locale MenuBarActionsManageFileTypes}" IsVisible="{Binding ManageFileTypesVisible}">
<MenuItem Name="InstallFileTypesMenuItem" Header="{ext:Locale MenuBarActionsInstallFileTypes}" IsEnabled="{Binding AreMimeTypesRegistered, Converter={x:Static BoolConverters.Not}}" /> <MenuItem Name="InstallFileTypesMenuItem" Header="{ext:Locale MenuBarActionsInstallFileTypes}" IsEnabled="{Binding AreMimeTypesRegistered, Converter={x:Static BoolConverters.Not}}" />
@ -250,34 +253,38 @@
Header="{ext:Locale MenuBarHelpAbout}" Header="{ext:Locale MenuBarHelpAbout}"
Icon="{ext:Icon fa-solid fa-circle-info}" Icon="{ext:Icon fa-solid fa-circle-info}"
ToolTip.Tip="{ext:Locale OpenAboutTooltip}" /> ToolTip.Tip="{ext:Locale OpenAboutTooltip}" />
<MenuItem
Name="StarscriptDebugMenuItem"
Header="Debug Starscript"
Icon="{ext:Icon fa-solid fa-star}" />
<MenuItem <MenuItem
Name="UpdateMenuItem" Name="UpdateMenuItem"
IsEnabled="{Binding CanUpdate}" IsEnabled="{Binding CanUpdate}"
Header="{ext:Locale MenuBarHelpCheckForUpdates}" Header="{ext:Locale MenuBarHelpCheckForUpdates}"
Icon="{ext:Icon mdi-update}" Icon="{ext:Icon fa-solid fa-rotate}"
ToolTip.Tip="{ext:Locale CheckUpdatesTooltip}" /> ToolTip.Tip="{ext:Locale CheckUpdatesTooltip}" />
<MenuItem <MenuItem
Name="CompatibilityListMenuItem" Name="CompatibilityListMenuItem"
Header="{ext:Locale CompatibilityListOpen}" Header="{ext:Locale CompatibilityListOpen}"
Icon="{ext:Icon mdi-gamepad}"/> Icon="{ext:Icon fa-solid fa-database}"/>
<Separator /> <Separator />
<MenuItem VerticalAlignment="Center" Header="{ext:Locale MenuBarHelpFaqAndGuides}" Icon="{ext:Icon fa-solid fa-question}" > <MenuItem VerticalAlignment="Center" Header="{ext:Locale MenuBarHelpFaqAndGuides}" Icon="{ext:Icon fa-solid fa-question}" >
<MenuItem <MenuItem
Name="FaqMenuItem" Name="FaqMenuItem"
Header="{ext:Locale MenuBarHelpFaq}" Header="{ext:Locale MenuBarHelpFaq}"
Icon="{ext:Icon fa-github}" Icon="{ext:Icon fa-brands fa-gitlab}"
CommandParameter="https://git.ryujinx.app/ryubing/ryujinx/-/wikis/FAQ-&amp;-Troubleshooting" CommandParameter="https://git.ryujinx.app/ryubing/ryujinx/-/wikis/FAQ-&amp;-Troubleshooting"
ToolTip.Tip="{ext:Locale MenuBarHelpFaqTooltip}" /> ToolTip.Tip="{ext:Locale MenuBarHelpFaqTooltip}" />
<MenuItem <MenuItem
Name="SetupGuideMenuItem" Name="SetupGuideMenuItem"
Header="{ext:Locale MenuBarHelpSetup}" Header="{ext:Locale MenuBarHelpSetup}"
Icon="{ext:Icon fa-github}" Icon="{ext:Icon fa-brands fa-gitlab}"
CommandParameter="https://git.ryujinx.app/ryubing/ryujinx/-/wikis/Setup-&amp;-Configuration-Guide" CommandParameter="https://git.ryujinx.app/ryubing/ryujinx/-/wikis/Setup-&amp;-Configuration-Guide"
ToolTip.Tip="{ext:Locale MenuBarHelpSetupTooltip}" /> ToolTip.Tip="{ext:Locale MenuBarHelpSetupTooltip}" />
<MenuItem <MenuItem
Name="LdnGuideMenuItem" Name="LdnGuideMenuItem"
Header="{ext:Locale MenuBarHelpMultiplayer}" Header="{ext:Locale MenuBarHelpMultiplayer}"
Icon="{ext:Icon fa-github}" Icon="{ext:Icon fa-brands fa-gitlab}"
CommandParameter="https://git.ryujinx.app/ryubing/ryujinx/-/wikis/Multiplayer-(LDN-Local-Wireless)-Guide" CommandParameter="https://git.ryujinx.app/ryubing/ryujinx/-/wikis/Multiplayer-(LDN-Local-Wireless)-Guide"
ToolTip.Tip="{ext:Locale MenuBarHelpMultiplayerTooltip}" /> ToolTip.Tip="{ext:Locale MenuBarHelpMultiplayerTooltip}" />
</MenuItem> </MenuItem>

View File

@ -8,6 +8,7 @@ using LibHac.Ns;
using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.Systems.AppLibrary; using Ryujinx.Ava.Systems.AppLibrary;
using Ryujinx.Ava.Systems.Configuration; using Ryujinx.Ava.Systems.Configuration;
using Ryujinx.Ava.Systems.Starscript;
using Ryujinx.Ava.UI.Controls; using Ryujinx.Ava.UI.Controls;
using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.UI.ViewModels; using Ryujinx.Ava.UI.ViewModels;
@ -51,6 +52,8 @@ namespace Ryujinx.Ava.UI.Views.Main
CompatibilityListMenuItem.Command = Commands.Create(() => CompatibilityListWindow.Show()); CompatibilityListMenuItem.Command = Commands.Create(() => CompatibilityListWindow.Show());
UpdateMenuItem.Command = MainWindowViewModel.UpdateCommand; UpdateMenuItem.Command = MainWindowViewModel.UpdateCommand;
StarscriptDebugMenuItem.Command = Commands.Create(StarscriptTextBox.Show);
FaqMenuItem.Command = FaqMenuItem.Command =
SetupGuideMenuItem.Command = SetupGuideMenuItem.Command =

View File

@ -64,6 +64,7 @@
MinWidth="200" MinWidth="200"
Height="6" Height="6"
VerticalAlignment="Center" VerticalAlignment="Center"
Margin="0, 0, 5, 0"
Foreground="{DynamicResource SystemAccentColorLight2}" Foreground="{DynamicResource SystemAccentColorLight2}"
IsVisible="{Binding StatusBarVisible}" IsVisible="{Binding StatusBarVisible}"
Maximum="{Binding StatusBarProgressMaximum}" Maximum="{Binding StatusBarProgressMaximum}"