Compare commits
35 Commits
Canary-1.2
...
fa4f80ebdf
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fa4f80ebdf | ||
|
|
c06f16c5e6 | ||
|
|
7829fd8ee7 | ||
|
|
33079422fe | ||
|
|
f81cb093fc | ||
|
|
dc0c7a2912 | ||
|
|
1fbee5a584 | ||
|
|
c140e9b23c | ||
|
|
9c8055440e | ||
|
|
c03cd50fa3 | ||
|
|
069f630776 | ||
|
|
1fb1530ea3 | ||
|
|
13d411e4de | ||
|
|
9f53b07491 | ||
|
|
cd8113dadf | ||
|
|
9089c4ffe5 | ||
|
|
fe9d8d05bd | ||
|
|
880a8ae748 | ||
|
|
11531dacb6 | ||
|
|
3974739ed3 | ||
|
|
440a3447fb | ||
|
|
65374ed6cb | ||
|
|
789d6ab959 | ||
|
|
182db31343 | ||
|
|
ea296b134d | ||
|
|
bf584442b2 | ||
|
|
cb7c294dbf | ||
|
|
eaf1e7efd2 | ||
|
|
471e7ed2e4 | ||
|
|
ad3e80b383 | ||
|
|
ed64a63094 | ||
|
|
8df7ba2d56 | ||
|
|
e743d78115 | ||
|
|
04ba762710 | ||
|
|
f42b2ed59d |
4
.github/labeler.yml
vendored
4
.github/labeler.yml
vendored
@@ -18,6 +18,10 @@ gpu:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: ['src/Ryujinx.Graphics.Vulkan/**', 'src/Spv.Generator/**']
|
||||
|
||||
'graphics-backend:metal':
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: ['src/Ryujinx.Graphics.Metal/**', 'src/Ryujinx.Graphics.Metal.SharpMetalExtensions/**']
|
||||
|
||||
gui:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: ['src/Ryujinx/**', 'src/Ryujinx.UI.Common/**', 'src/Ryujinx.UI.LocaleGenerator/**']
|
||||
|
||||
2
.github/workflows/canary.yml
vendored
2
.github/workflows/canary.yml
vendored
@@ -202,7 +202,7 @@ jobs:
|
||||
|
||||
macos_release:
|
||||
name: Release MacOS universal
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
|
||||
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@@ -183,7 +183,7 @@ jobs:
|
||||
|
||||
macos_release:
|
||||
name: Release MacOS universal
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
|
||||
@@ -54,12 +54,13 @@ failing to meet this requirement may result in a poor gameplay experience or une
|
||||
|
||||
## Latest build
|
||||
|
||||
Stable builds are made every so often onto a separate "release" branch that then gets put into the releases you know and love.
|
||||
Stable builds are made every so often, based on the `master` branch, that then gets put into the releases you know and love.
|
||||
These stable builds exist so that the end user can get a more **enjoyable and stable experience**.
|
||||
They are released every month or so, to ensure consistent updates, while not being an annoying amount of individual updates to download over the course of that month.
|
||||
|
||||
You can find the latest stable release [here](https://github.com/GreemDev/Ryujinx/releases/latest).
|
||||
|
||||
Canary builds are compiled automatically for each commit on the master branch.
|
||||
Canary builds are compiled automatically for each commit on the `master` branch.
|
||||
While we strive to ensure optimal stability and performance prior to pushing an update, these builds **may be unstable or completely broken**.
|
||||
These canary builds are only recommended for experienced users.
|
||||
|
||||
@@ -109,7 +110,7 @@ If you are planning to contribute or just want to learn more about this project
|
||||
- **Configuration**
|
||||
|
||||
The emulator has settings for enabling or disabling some logging, remapping controllers, and more.
|
||||
You can configure all of them through the graphical interface or manually through the config file, `Config.json`, found in the user folder which can be accessed by clicking `Open Ryujinx Folder` under the File menu in the GUI.
|
||||
You can configure all of them through the graphical interface or manually through the config file, `Config.json`, found in the Ryujinx data folder which can be accessed by clicking `Open Ryujinx Folder` under the File menu in the GUI.
|
||||
|
||||
## License
|
||||
|
||||
|
||||
@@ -1070,6 +1070,7 @@
|
||||
010017B0102A8000,"Emma: Lost in Memories",nvdec,playable,2021-01-28 16:19:10
|
||||
010068300E08E000,"Enchanted in the Moonlight - Kiryu, Chikage & Yukinojo -",gpu;nvdec,ingame,2022-11-20 16:18:45
|
||||
01007A4008486000,"Enchanting Mahjong Match",gpu,ingame,2020-04-17 22:01:31
|
||||
0100EF901E552000,"ENDER MAGNOLIA: Bloom in the Mist",deadlock,boots,2025-01-22 17:59:00
|
||||
01004F3011F92000,"Endless Fables: Dark Moor",gpu;nvdec,ingame,2021-03-07 15:31:03
|
||||
010067B017588000,"Endless Ocean™ Luminous",services-horizon;crash,ingame,2024-05-30 02:05:57
|
||||
0100B8700BD14000,"Energy Cycle Edge",services,ingame,2021-11-30 05:02:31
|
||||
@@ -2681,7 +2682,7 @@
|
||||
01005EA01C0FC000,"SONIC X SHADOW GENERATIONS",crash,ingame,2025-01-07 04:20:45
|
||||
010064F00C212000,"Soul Axiom Rebooted",nvdec;slow,ingame,2020-09-04 12:41:01
|
||||
0100F2100F0B2000,"Soul Searching",,playable,2020-07-09 18:39:07
|
||||
01008F2005154000,"South Park™: The Fractured but Whole™ - Standard Edition",slow;online-broken,playable,2024-07-08 17:47:28
|
||||
01008F2005154000,"South Park™: The Fractured but Whole™ - Standard Edition",slow;online-broken;vulkan-backend-bug;gpu,ingame,2025-01-21 17:35:10
|
||||
0100B9F00C162000,"Space Blaze",,playable,2020-08-30 16:18:05
|
||||
010005500E81E000,"Space Cows",UE4;crash,menus,2020-06-15 11:33:20
|
||||
0100707011722000,"Space Elite Force",,playable,2020-11-27 15:21:05
|
||||
|
||||
|
@@ -78,5 +78,10 @@ namespace Ryujinx.Common.Configuration.Hid.Controller
|
||||
/// Controller Rumble Settings
|
||||
/// </summary>
|
||||
public RumbleConfigController Rumble { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Controller LED Settings
|
||||
/// </summary>
|
||||
public LedConfigController Led { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
namespace Ryujinx.Common.Configuration.Hid.Controller
|
||||
{
|
||||
public class LedConfigController
|
||||
{
|
||||
/// <summary>
|
||||
/// Packed RGB int of the color
|
||||
/// </summary>
|
||||
public uint LedColor { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Enable LED color changing by the emulator
|
||||
/// </summary>
|
||||
public bool EnableLed { get; set; }
|
||||
}
|
||||
}
|
||||
23
src/Ryujinx.Common/Helpers/RunningPlatform.cs
Normal file
23
src/Ryujinx.Common/Helpers/RunningPlatform.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
// ReSharper disable MemberCanBePrivate.Global
|
||||
// ReSharper disable InconsistentNaming
|
||||
|
||||
namespace Ryujinx.Common.Helper
|
||||
{
|
||||
public static class RunningPlatform
|
||||
{
|
||||
public static bool IsMacOS => OperatingSystem.IsMacOS();
|
||||
public static bool IsWindows => OperatingSystem.IsWindows();
|
||||
public static bool IsLinux => OperatingSystem.IsLinux();
|
||||
|
||||
public static bool IsIntelMac => IsMacOS && RuntimeInformation.OSArchitecture is Architecture.X64;
|
||||
public static bool IsArmMac => IsMacOS && RuntimeInformation.OSArchitecture is Architecture.Arm64;
|
||||
|
||||
public static bool IsX64Windows => IsWindows && (RuntimeInformation.OSArchitecture is Architecture.X64);
|
||||
public static bool IsArmWindows => IsWindows && (RuntimeInformation.OSArchitecture is Architecture.Arm64);
|
||||
|
||||
public static bool IsX64Linux => IsLinux && (RuntimeInformation.OSArchitecture is Architecture.X64);
|
||||
public static bool IsArmLinux => IsLinux && (RuntimeInformation.OSArchitecture is Architecture.Arm64);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using Gommon;
|
||||
using Ryujinx.Common.Configuration;
|
||||
using Ryujinx.Common.Helper;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
@@ -8,19 +9,20 @@ namespace Ryujinx.Common
|
||||
{
|
||||
public static class TitleIDs
|
||||
{
|
||||
public static ReactiveObject<Optional<string>> CurrentApplication { get; set; } = new();
|
||||
public static ReactiveObject<Optional<string>> CurrentApplication { get; } = new();
|
||||
|
||||
public static GraphicsBackend SelectGraphicsBackend(string titleId, GraphicsBackend currentBackend)
|
||||
{
|
||||
switch (currentBackend)
|
||||
{
|
||||
case GraphicsBackend.Metal when !OperatingSystem.IsMacOS():
|
||||
case GraphicsBackend.OpenGl when OperatingSystem.IsMacOS():
|
||||
return GraphicsBackend.Vulkan;
|
||||
case GraphicsBackend.Vulkan or GraphicsBackend.OpenGl or GraphicsBackend.Metal:
|
||||
return currentBackend;
|
||||
}
|
||||
|
||||
if (!(OperatingSystem.IsMacOS() && RuntimeInformation.ProcessArchitecture is Architecture.Arm64))
|
||||
if (!RunningPlatform.IsArmMac)
|
||||
return GraphicsBackend.Vulkan;
|
||||
|
||||
return GreatMetalTitles.ContainsIgnoreCase(titleId) ? GraphicsBackend.Metal : GraphicsBackend.Vulkan;
|
||||
@@ -28,18 +30,28 @@ namespace Ryujinx.Common
|
||||
|
||||
public static readonly string[] GreatMetalTitles =
|
||||
[
|
||||
"01006f8002326000", // Animal Crossings: New Horizons
|
||||
"01009bf0072d4000", // Captain Toad: Treasure Tracker
|
||||
"010076f0049a2000", // Bayonetta
|
||||
"0100a5c00d162000", // Cuphead
|
||||
"010023800d64a000", // Deltarune
|
||||
"01003a30012c0000", // LEGO City Undercover
|
||||
"010028600EBDA000", // Mario 3D World
|
||||
"0100152000022000", // Mario Kart 8 Deluxe
|
||||
"01005CA01580E000", // Persona 5
|
||||
"0100187003A36000", // Pokémon: Let's Go, Evoli!
|
||||
"010075a016a3a000", // Persona 4 Arena Ultimax
|
||||
"0100187003A36000", // Pokémon: Let's Go, Eevee!
|
||||
"010003f003a34000", // Pokémon: Let's Go, Pikachu!
|
||||
"01008C0016544000", // Sea of Stars
|
||||
"01006A800016E000", // Smash Ultimate
|
||||
"0100000000010000", // Super Mario Odyessy
|
||||
"01006bb00c6f0000", // The Legend of Zelda: Link's Awakening
|
||||
|
||||
// These ones have small issues, but those happen on Vulkan as well:
|
||||
"01006f8002326000", // Animal Crossings: New Horizons
|
||||
"01009bf0072d4000", // Captain Toad: Treasure Tracker
|
||||
"01009510001ca000", // Fast RMX
|
||||
"01005CA01580E000", // Persona 5 Royale
|
||||
"0100000000010000", // Super Mario Odyssey
|
||||
|
||||
//Isaac claims it has a issue in level 2, but I am not able to replicate it on my M3. More testing would be appreciated:
|
||||
"010015100b514000", // Super Mario Bros. Wonder
|
||||
];
|
||||
|
||||
public static string GetDiscordGameAsset(string titleId)
|
||||
@@ -47,72 +59,87 @@ namespace Ryujinx.Common
|
||||
|
||||
public static readonly string[] DiscordGameAssetKeys =
|
||||
[
|
||||
//All games are in Alphabetical order by Game name.
|
||||
|
||||
//Dragon Quest Franchise
|
||||
"010008900705c000", // Dragon Quest Builders
|
||||
"010042000a986000", // Dragon Quest Builders 2
|
||||
|
||||
"010055d009f78000", // Fire Emblem: Three Houses
|
||||
"0100a12011cc8000", // Fire Emblem: Shadow Dragon
|
||||
//Fire Emblem Franchise
|
||||
"0100a6301214e000", // Fire Emblem Engage
|
||||
"0100a12011cc8000", // Fire Emblem: Shadow Dragon
|
||||
"010055d009f78000", // Fire Emblem: Three Houses
|
||||
"0100f15003e64000", // Fire Emblem Warriors
|
||||
"010071f0143ea000", // Fire Emblem Warriors: Three Hopes
|
||||
|
||||
"01007e3006dda000", // Kirby Star Allies
|
||||
|
||||
//Kirby Franchise
|
||||
"01004d300c5ae000", // Kirby and the Forgotten Land
|
||||
"01006b601380e000", // Kirby's Return to Dream Land Deluxe
|
||||
"01003fb00c5a8000", // Super Kirby Clash
|
||||
"0100227010460000", // Kirby Fighters 2
|
||||
"0100a8e016236000", // Kirby's Dream Buffet
|
||||
|
||||
"0100227010460000", // Kirby Fighters 2
|
||||
"01006b601380e000", // Kirby's Return to Dream Land Deluxe
|
||||
"01007e3006dda000", // Kirby Star Allies
|
||||
"01003fb00c5a8000", // Super Kirby Clash
|
||||
|
||||
|
||||
//The Zelda Franchise
|
||||
"01000b900d8b0000", // Cadence of Hyrule
|
||||
"0100ae00096ea000", // Hyrule Warriors: Definitive Edition
|
||||
"01002b00111a2000", // Hyrule Warriors: Age of Calamity
|
||||
"01007ef00011e000", // The Legend of Zelda: Breath of the Wild
|
||||
"01006bb00c6f0000", // The Legend of Zelda: Link's Awakening
|
||||
"01002da013484000", // The Legend of Zelda: Skyward Sword HD
|
||||
"0100f2c0115b6000", // The Legend of Zelda: Tears of the Kingdom
|
||||
"01008cf01baac000", // The Legend of Zelda: Echoes of Wisdom
|
||||
"01000b900d8b0000", // Cadence of Hyrule
|
||||
"0100ae00096ea000", // Hyrule Warriors: Definitive Edition
|
||||
"01002b00111a2000", // Hyrule Warriors: Age of Calamity
|
||||
|
||||
|
||||
//Luigi Franchise
|
||||
"010048701995e000", // Luigi's Mansion 2 HD
|
||||
"0100dca0064a6000", // Luigi's Mansion 3
|
||||
|
||||
//Metroid Franchise
|
||||
"010093801237c000", // Metroid Dread
|
||||
"010012101468c000", // Metroid Prime Remastered
|
||||
|
||||
"0100000000010000", // SUPER MARIO ODYSSEY
|
||||
"0100ea80032ea000", // Super Mario Bros. U Deluxe
|
||||
"01009b90006dc000", // Super Mario Maker 2
|
||||
"010049900f546000", // Super Mario 3D All-Stars
|
||||
"010049900F546001", // ^ 64
|
||||
"010049900F546002", // ^ Sunshine
|
||||
"010049900F546003", // ^ Galaxy
|
||||
"010028600ebda000", // Super Mario 3D World + Bowser's Fury
|
||||
"010015100b514000", // Super Mario Bros. Wonder
|
||||
"0100152000022000", // Mario Kart 8 Deluxe
|
||||
"010036b0034e4000", // Super Mario Party
|
||||
"01006fe013472000", // Mario Party Superstars
|
||||
"0100965017338000", // Super Mario Party Jamboree
|
||||
//Monster Hunter Franchise
|
||||
"0100770008dd8000", // Monster Hunter Generations Ultimate
|
||||
"0100b04011742000", // Monster Hunter Rise
|
||||
|
||||
//Mario Franchise
|
||||
"01006d0017f7a000", // Mario & Luigi: Brothership
|
||||
"010003000e146000", // Mario & Sonic at the Olympic Games Tokyo 2020
|
||||
"010067300059a000", // Mario + Rabbids: Kingdom Battle
|
||||
"0100317013770000", // Mario + Rabbids: Sparks of Hope
|
||||
"0100c9c00e25c000", // Mario Golf: Super Rush
|
||||
"0100152000022000", // Mario Kart 8 Deluxe
|
||||
"01006fe013472000", // Mario Party Superstars
|
||||
"010019401051c000", // Mario Strikers: Battle League
|
||||
"0100bde00862a000", // Mario Tennis Aces
|
||||
"0100b99019412000", // Mario vs. Donkey Kong
|
||||
"010049900f546000", // Super Mario 3D All-Stars
|
||||
"010028600ebda000", // Super Mario 3D World + Bowser's Fury
|
||||
"010049900F546001", // Super Mario 64
|
||||
"0100ea80032ea000", // Super Mario Bros. U Deluxe
|
||||
"010015100b514000", // Super Mario Bros. Wonder
|
||||
"010049900F546003", // Super Mario Galaxy
|
||||
"01009b90006dc000", // Super Mario Maker 2
|
||||
"0100000000010000", // SUPER MARIO ODYSSEY
|
||||
"010036b0034e4000", // Super Mario Party
|
||||
"0100965017338000", // Super Mario Party Jamboree
|
||||
"0100bc0018138000", // Super Mario RPG
|
||||
"010049900F546002", // Super Mario Sunshine
|
||||
"0100a3900c3e2000", // Paper Mario: The Origami King
|
||||
"0100ecd018ebe000", // Paper Mario: The Thousand-Year Door
|
||||
"0100bc0018138000", // Super Mario RPG
|
||||
"0100bde00862a000", // Mario Tennis Aces
|
||||
"0100c9c00e25c000", // Mario Golf: Super Rush
|
||||
"010019401051c000", // Mario Strikers: Battle League
|
||||
"010003000e146000", // Mario & Sonic at the Olympic Games Tokyo 2020
|
||||
"0100b99019412000", // Mario vs. Donkey Kong
|
||||
|
||||
//Pikmin Franchise
|
||||
"0100aa80194b0000", // Pikmin 1
|
||||
"0100d680194b2000", // Pikmin 2
|
||||
"0100f4c009322000", // Pikmin 3 Deluxe
|
||||
"0100b7c00933a000", // Pikmin 4
|
||||
|
||||
//The Pokémon Franchise
|
||||
"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!
|
||||
"01003d200baa2000", // Pokémon Mystery Dungeon - Rescue Team DX
|
||||
"0100a3d008c5c000", // Pokémon Scarlet
|
||||
"01008db008c2c000", // Pokémon Shield
|
||||
@@ -120,24 +147,29 @@ namespace Ryujinx.Common
|
||||
"0100abf008968000", // Pokémon Sword
|
||||
"01008f6008c5e000", // Pokémon Violet
|
||||
"0100b3f000be2000", // Pokkén Tournament DX
|
||||
"0100187003a36000", // Pokémon: Let's Go Eevee!
|
||||
"010003f003a34000", // Pokémon: Let's Go Pikachu!
|
||||
|
||||
"01003bc0000a0000", // Splatoon 2 (US)
|
||||
//Splatoon Franchise
|
||||
"0100f8f0000a2000", // Splatoon 2 (EU)
|
||||
"01003c700009c000", // Splatoon 2 (JP)
|
||||
"01003bc0000a0000", // Splatoon 2 (US)
|
||||
"0100c2500fc20000", // Splatoon 3
|
||||
"0100ba0018500000", // Splatoon 3: Splatfest World Premiere
|
||||
|
||||
"010040600c5ce000", // Tetris 99
|
||||
"0100277011f1a000", // Super Mario Bros. 35
|
||||
"0100ad9012510000", // PAC-MAN 99
|
||||
//NSO Membership games
|
||||
"0100ccf019c8c000", // F-ZERO 99
|
||||
"0100d870045b6000", // NES - Nintendo Switch Online
|
||||
"01008d300c50c000", // SNES - Nintendo Switch Online
|
||||
"0100c9a00ece6000", // N64 - Nintendo Switch Online
|
||||
"0100e0601c632000", // N64 - Nintendo Switch Online 18+
|
||||
"0100c62011050000", // GB - Nintendo Switch Online
|
||||
"010012f017576000", // GBA - Nintendo Switch Online
|
||||
"0100c9a00ece6000", // N64 - Nintendo Switch Online
|
||||
"0100e0601c632000", // N64 - Nintendo Switch Online 18+
|
||||
"0100d870045b6000", // NES - Nintendo Switch Online
|
||||
"0100ad9012510000", // PAC-MAN 99
|
||||
"010040600c5ce000", // Tetris 99
|
||||
"01008d300c50c000", // SNES - Nintendo Switch Online
|
||||
"0100277011f1a000", // Super Mario Bros. 35
|
||||
|
||||
//Misc Nintendo 1st party games
|
||||
"01000320000cc000", // 1-2 Switch
|
||||
"0100300012f2a000", // Advance Wars 1+2: Re-Boot Camp
|
||||
"01006f8002326000", // Animal Crossing: New Horizons
|
||||
@@ -152,27 +184,32 @@ namespace Ryujinx.Common
|
||||
"01006a800016e000", // Super Smash Bros. Ultimate
|
||||
"0100a9400c9c2000", // Tokyo Mirage Sessions #FE Encore
|
||||
|
||||
//Bayonetta Franchise
|
||||
"010076f0049a2000", // Bayonetta
|
||||
"01007960049a0000", // Bayonetta 2
|
||||
"01004a4010fea000", // Bayonetta 3
|
||||
"0100cf5010fec000", // Bayonetta Origins: Cereza and the Lost Demon
|
||||
|
||||
//Persona Franchise
|
||||
"0100dcd01525a000", // Persona 3 Portable
|
||||
"010062b01525c000", // Persona 4 Golden
|
||||
"010075a016a3a000", // Persona 4 Arena Ultimax
|
||||
"010062b01525c000", // Persona 4 Golden
|
||||
"01005ca01580e000", // Persona 5 Royal
|
||||
"0100801011c3e000", // Persona 5 Strikers
|
||||
"010087701b092000", // Persona 5 Tactica
|
||||
|
||||
"01009aa000faa000", // Sonic Mania
|
||||
//Sonic Franchise
|
||||
"01004ad014bf0000", // Sonic Frontiers
|
||||
"01009aa000faa000", // Sonic Mania
|
||||
"01005ea01c0fc000", // SONIC X SHADOW GENERATIONS
|
||||
"01005ea01c0fc001", // ^
|
||||
|
||||
//Xenoblade Franchise
|
||||
"0100ff500e34a000", // Xenoblade Chronicles - Definitive Edition
|
||||
"0100e95004038000", // Xenoblade Chronicles 2
|
||||
"010074f013262000", // Xenoblade Chronicles 3
|
||||
|
||||
//Misc Games
|
||||
"010056e00853a000", // A Hat in Time
|
||||
"0100fd1014726000", // Baldurs Gate: Dark Alliance
|
||||
"0100dbf01000a000", // Burnout Paradise Remastered
|
||||
@@ -185,8 +222,6 @@ namespace Ryujinx.Common
|
||||
"01003620068ea000", // Hand of Fate 2
|
||||
"010085500130a000", // Lego City: Undercover
|
||||
"010073c01af34000", // LEGO Horizon Adventures
|
||||
"0100770008dd8000", // Monster Hunter Generations Ultimate
|
||||
"0100b04011742000", // Monster Hunter Rise
|
||||
"0100853015e86000", // No Man's Sky
|
||||
"01007bb017812000", // Portal
|
||||
"0100abd01785c000", // Portal 2
|
||||
|
||||
@@ -118,7 +118,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
|
||||
private static string GetDiskCachePath()
|
||||
{
|
||||
return GraphicsConfig.EnableShaderCache && GraphicsConfig.TitleId != null
|
||||
? Path.Combine(AppDataManager.GamesDirPath, GraphicsConfig.TitleId, "cache", "shader")
|
||||
? Path.Combine(AppDataManager.GamesDirPath, GraphicsConfig.TitleId.ToLower(), "cache", "shader")
|
||||
: null;
|
||||
}
|
||||
|
||||
|
||||
@@ -710,9 +710,8 @@ namespace Ryujinx.HLE.FileSystem
|
||||
{
|
||||
updateNcasItem.Add((nca.Header.ContentType, entry.FullName));
|
||||
}
|
||||
else
|
||||
else if (updateNcas.TryAdd(nca.Header.TitleId, new List<(NcaContentType, string)>()))
|
||||
{
|
||||
updateNcas.Add(nca.Header.TitleId, new List<(NcaContentType, string)>());
|
||||
updateNcas[nca.Header.TitleId].Add((nca.Header.ContentType, entry.FullName));
|
||||
}
|
||||
}
|
||||
@@ -898,9 +897,8 @@ namespace Ryujinx.HLE.FileSystem
|
||||
{
|
||||
updateNcasItem.Add((nca.Header.ContentType, entry.FullPath));
|
||||
}
|
||||
else
|
||||
else if (updateNcas.TryAdd(nca.Header.TitleId, new List<(NcaContentType, string)>()))
|
||||
{
|
||||
updateNcas.Add(nca.Header.TitleId, new List<(NcaContentType, string)>());
|
||||
updateNcas[nca.Header.TitleId].Add((nca.Header.ContentType, entry.FullPath));
|
||||
}
|
||||
|
||||
|
||||
@@ -56,7 +56,7 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
|
||||
ProfilesJson profilesJson = JsonHelper.DeserializeFromFile(_profilesJsonPath, _serializerContext.ProfilesJson);
|
||||
|
||||
return profilesJson.Profiles
|
||||
.FindFirst(profile => profile.AccountState == AccountState.Open)
|
||||
.FindFirst(profile => profile.UserId == profilesJson.LastOpened)
|
||||
.Convert(profileJson => new UserProfile(new UserId(profileJson.UserId), profileJson.Name,
|
||||
profileJson.Image, profileJson.LastModifiedTimestamp));
|
||||
}
|
||||
|
||||
@@ -659,7 +659,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
|
||||
|
||||
if (string.IsNullOrWhiteSpace(filePath))
|
||||
{
|
||||
throw new InvalidSystemResourceException("JIT (010000000000003B) system title not found! The JIT will not work, provide the system archive to fix this error. (See https://github.com/GreemDev/Ryujinx#requirements for more information)");
|
||||
throw new InvalidSystemResourceException("JIT (010000000000003B) system title not found! The JIT will not work, provide the system archive to fix this error. (See https://github.com/Ryubing/Ryujinx#requirements for more information)");
|
||||
}
|
||||
|
||||
context.Device.LoadNca(filePath);
|
||||
|
||||
@@ -105,7 +105,7 @@ namespace Ryujinx.HLE.HOS.Services.Sdb.Pl
|
||||
titleName = "Unknown";
|
||||
}
|
||||
|
||||
throw new InvalidSystemResourceException($"{titleName} ({fontTitle:x8}) system title not found! This font will not work, provide the system archive to fix this error. (See https://github.com/GreemDev/Ryujinx#requirements for more information)");
|
||||
throw new InvalidSystemResourceException($"{titleName} ({fontTitle:x8}) system title not found! This font will not work, provide the system archive to fix this error. (See https://github.com/Ryubing/Ryujinx#requirements for more information)");
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -244,6 +244,15 @@ namespace Ryujinx.HLE.HOS.Services.Settings
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[CommandCmif(68)]
|
||||
// GetSerialNumber() -> buffer<nn::settings::system::SerialNumber, 0x16>
|
||||
public ResultCode GetSerialNumber(ServiceCtx context)
|
||||
{
|
||||
context.ResponseData.Write(Encoding.ASCII.GetBytes("RYU00000000000"));
|
||||
|
||||
return ResultCode.Success;
|
||||
}
|
||||
|
||||
[CommandCmif(77)]
|
||||
// GetDeviceNickName() -> buffer<nn::settings::system::DeviceNickName, 0x16>
|
||||
public ResultCode GetDeviceNickName(ServiceCtx context)
|
||||
|
||||
@@ -51,6 +51,9 @@ namespace Ryujinx.HLE.HOS.Services.Spl
|
||||
|
||||
context.ResponseData.Write(configValue);
|
||||
|
||||
if (result == SmcResult.Success)
|
||||
return ResultCode.Success;
|
||||
|
||||
return (ResultCode)((int)result << 9) | ResultCode.ModuleId;
|
||||
}
|
||||
|
||||
|
||||
@@ -161,5 +161,20 @@ namespace Ryujinx.HLE
|
||||
{
|
||||
return 1000 / _frameRate[FrameTypeGame];
|
||||
}
|
||||
|
||||
public string FormatGameFrameRate()
|
||||
{
|
||||
double frameRate = GetGameFrameRate();
|
||||
double frameTime = GetGameFrameTime();
|
||||
|
||||
return $"{frameRate:00.00} FPS ({frameTime:00.00}ms)";
|
||||
}
|
||||
|
||||
public string FormatFifoPercent()
|
||||
{
|
||||
double fifoPercent = GetFifoPercent();
|
||||
|
||||
return $"FIFO: {fifoPercent:00.00}%";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,8 +34,8 @@ namespace Ryujinx.HLE
|
||||
|
||||
public int CpuCoresCount = 4; //Switch 1 has 4 cores
|
||||
|
||||
public VSyncMode VSyncMode { get; set; } = VSyncMode.Switch;
|
||||
public bool CustomVSyncIntervalEnabled { get; set; } = false;
|
||||
public VSyncMode VSyncMode { get; set; }
|
||||
public bool CustomVSyncIntervalEnabled { get; set; }
|
||||
public int CustomVSyncInterval { get; set; }
|
||||
|
||||
public long TargetVSyncInterval { get; set; } = 60;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Ryujinx.Common.Configuration.Hid;
|
||||
using Ryujinx.Common.Configuration.Hid.Controller;
|
||||
using Ryujinx.Common.Logging;
|
||||
using SDL2;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Numerics;
|
||||
@@ -118,6 +119,11 @@ namespace Ryujinx.Input.SDL2
|
||||
result |= GamepadFeaturesFlag.Rumble;
|
||||
}
|
||||
|
||||
if (SDL_GameControllerHasLED(_gamepadHandle) == SDL_bool.SDL_TRUE)
|
||||
{
|
||||
result |= GamepadFeaturesFlag.Led;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,5 +24,10 @@ namespace Ryujinx.Input
|
||||
/// <remarks>Also named sixaxis</remarks>
|
||||
/// </summary>
|
||||
Motion,
|
||||
|
||||
/// <summary>
|
||||
/// The LED on the back of modern PlayStation controllers (DualSense & DualShock 4).
|
||||
/// </summary>
|
||||
Led,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -674,7 +674,7 @@ namespace Ryujinx.Ava
|
||||
|
||||
public async Task<bool> LoadGuestApplication(BlitStruct<ApplicationControlProperty>? customNacpData = null)
|
||||
{
|
||||
InitializeSwitchInstance();
|
||||
InitEmulatedSwitch();
|
||||
MainWindow.UpdateGraphicsConfig();
|
||||
|
||||
SystemVersion firmwareVersion = ContentManager.GetCurrentFirmwareVersion();
|
||||
@@ -757,6 +757,8 @@ namespace Ryujinx.Ava
|
||||
{
|
||||
romFsFiles = Directory.GetFiles(ApplicationPath, "*.romfs");
|
||||
}
|
||||
|
||||
Logger.Notice.Print(LogClass.Application, $"Loading unpacked content archive from '{ApplicationPath}'.");
|
||||
|
||||
if (romFsFiles.Length > 0)
|
||||
{
|
||||
@@ -783,6 +785,8 @@ namespace Ryujinx.Ava
|
||||
}
|
||||
else if (File.Exists(ApplicationPath))
|
||||
{
|
||||
Logger.Notice.Print(LogClass.Application, $"Loading content archive from '{ApplicationPath}'.");
|
||||
|
||||
switch (Path.GetExtension(ApplicationPath).ToLowerInvariant())
|
||||
{
|
||||
case ".xci":
|
||||
@@ -885,7 +889,7 @@ namespace Ryujinx.Ava
|
||||
Logger.Info?.Print(LogClass.Emulation, "Emulation was paused");
|
||||
}
|
||||
|
||||
private void InitializeSwitchInstance()
|
||||
private void InitEmulatedSwitch()
|
||||
{
|
||||
// Initialize KeySet.
|
||||
VirtualFileSystem.ReloadKeySet();
|
||||
@@ -1040,7 +1044,7 @@ namespace Ryujinx.Ava
|
||||
_viewModel.WindowState = WindowState.FullScreen;
|
||||
}
|
||||
|
||||
if (_viewModel.WindowState is WindowState.FullScreen)
|
||||
if (_viewModel.WindowState is WindowState.FullScreen || _viewModel.StartGamesWithoutUI)
|
||||
{
|
||||
_viewModel.ShowMenuAndStatusBar = false;
|
||||
}
|
||||
@@ -1147,8 +1151,8 @@ namespace Ryujinx.Ava
|
||||
LocaleManager.Instance[LocaleKeys.VolumeShort] + $": {(int)(Device.GetVolume() * 100)}%",
|
||||
dockedMode,
|
||||
ConfigurationState.Instance.Graphics.AspectRatio.Value.ToText(),
|
||||
$"{Device.Statistics.GetGameFrameRate():00.00} FPS ({Device.Statistics.GetGameFrameTime():00.00} ms)",
|
||||
$"FIFO: {Device.Statistics.GetFifoPercent():00.00} %",
|
||||
Device.Statistics.FormatGameFrameRate(),
|
||||
Device.Statistics.FormatFifoPercent(),
|
||||
_displayCount));
|
||||
}
|
||||
|
||||
|
||||
13
src/Ryujinx/Assets/Styles/CheckboxMenuItemStyle.axaml
Normal file
13
src/Ryujinx/Assets/Styles/CheckboxMenuItemStyle.axaml
Normal file
@@ -0,0 +1,13 @@
|
||||
<Styles xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Style Selector="MenuItem.withCheckbox Viewbox#PART_IconPresenter">
|
||||
<Setter Property="MaxHeight" Value="36" />
|
||||
<Setter Property="MinHeight" Value="36" />
|
||||
<Setter Property="MaxWidth" Value="36" />
|
||||
<Setter Property="MinWidth" Value="36" />
|
||||
</Style>
|
||||
<Style Selector="MenuItem.withCheckbox ContentPresenter#PART_HeaderPresenter">
|
||||
<Setter Property="Padding" Value="-10,0,0,0" />
|
||||
</Style>
|
||||
</Styles>
|
||||
|
||||
@@ -393,7 +393,7 @@
|
||||
"th_TH": "โหลด DLC จากโฟลเดอร์",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "Завантажити DLC з теки",
|
||||
"zh_CN": "从文件夹加载DLC",
|
||||
"zh_CN": "从文件夹加载 DLC",
|
||||
"zh_TW": "從資料夾中載入 DLC"
|
||||
}
|
||||
},
|
||||
@@ -572,6 +572,31 @@
|
||||
"zh_TW": "使用全螢幕模式啟動遊戲"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "MenuBarOptionsStartGamesWithoutUI",
|
||||
"Translations": {
|
||||
"ar_SA": "",
|
||||
"de_DE": "",
|
||||
"el_GR": "",
|
||||
"en_US": "Start Games with UI Hidden",
|
||||
"es_ES": "",
|
||||
"fr_FR": "",
|
||||
"he_IL": "",
|
||||
"it_IT": "",
|
||||
"ja_JP": "",
|
||||
"ko_KR": "",
|
||||
"no_NO": "",
|
||||
"pl_PL": "",
|
||||
"pt_BR": "",
|
||||
"ru_RU": "",
|
||||
"sv_SE": "",
|
||||
"th_TH": "",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "",
|
||||
"zh_CN": "",
|
||||
"zh_TW": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "MenuBarOptionsStopEmulation",
|
||||
"Translations": {
|
||||
@@ -743,37 +768,12 @@
|
||||
"th_TH": "",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "Сканувати Amiibo (з теки Bin)",
|
||||
"zh_CN": "从bin文件扫描 Amiibo",
|
||||
"zh_CN": "扫描 Amiibo (从 bin 文件)",
|
||||
"zh_TW": "掃瞄 Amiibo (從 Bin 檔案)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "MenuBarTools",
|
||||
"Translations": {
|
||||
"ar_SA": "_الأدوات",
|
||||
"de_DE": "",
|
||||
"el_GR": "_Εργαλεία",
|
||||
"en_US": "_Tools",
|
||||
"es_ES": "_Herramientas",
|
||||
"fr_FR": "_Outils",
|
||||
"he_IL": "_כלים",
|
||||
"it_IT": "_Strumenti",
|
||||
"ja_JP": "ツール(_T)",
|
||||
"ko_KR": "도구(_T)",
|
||||
"no_NO": "_Verktøy",
|
||||
"pl_PL": "_Narzędzia",
|
||||
"pt_BR": "_Ferramentas",
|
||||
"ru_RU": "_Инструменты",
|
||||
"sv_SE": "V_erktyg",
|
||||
"th_TH": "_เครื่องมือ",
|
||||
"tr_TR": "_Araçlar",
|
||||
"uk_UA": "_Інструменти",
|
||||
"zh_CN": "工具(_T)",
|
||||
"zh_TW": "工具(_T)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "MenuBarToolsInstallFirmware",
|
||||
"ID": "MenuBarActionsInstallFirmware",
|
||||
"Translations": {
|
||||
"ar_SA": "تثبيت البرنامج الثابت",
|
||||
"de_DE": "Firmware installieren",
|
||||
@@ -798,7 +798,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "MenuBarFileToolsInstallFirmwareFromFile",
|
||||
"ID": "MenuBarActionsInstallFirmwareFromFile",
|
||||
"Translations": {
|
||||
"ar_SA": "تثبيت برنامج ثابت من XCI أو ZIP",
|
||||
"de_DE": "Firmware von einer XCI- oder einer ZIP-Datei installieren",
|
||||
@@ -818,12 +818,12 @@
|
||||
"th_TH": "ติดตั้งเฟิร์มแวร์จาก ไฟล์ XCI หรือ ไฟล์ ZIP",
|
||||
"tr_TR": "XCI veya ZIP'ten Yazılım Yükle",
|
||||
"uk_UA": "Встановити прошивку з XCI або ZIP",
|
||||
"zh_CN": "从 XCI 或 ZIP 文件中安装系统固件",
|
||||
"zh_CN": "从 XCI 或 ZIP 文件安装系统固件",
|
||||
"zh_TW": "從 XCI 或 ZIP 安裝韌體"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "MenuBarFileToolsInstallFirmwareFromDirectory",
|
||||
"ID": "MenuBarActionsInstallFirmwareFromDirectory",
|
||||
"Translations": {
|
||||
"ar_SA": "تثبيت برنامج ثابت من مجلد",
|
||||
"de_DE": "Firmware aus einem Verzeichnis installieren",
|
||||
@@ -843,12 +843,12 @@
|
||||
"th_TH": "ติดตั้งเฟิร์มแวร์จากไดเร็กทอรี",
|
||||
"tr_TR": "Bir Dizin Üzerinden Yazılım Yükle",
|
||||
"uk_UA": "Встановити прошивку з теки",
|
||||
"zh_CN": "从文件夹中安装系统固件",
|
||||
"zh_CN": "从文件夹安装系统固件",
|
||||
"zh_TW": "從資料夾安裝韌體"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "MenuBarToolsInstallKeys",
|
||||
"ID": "MenuBarActionsInstallKeys",
|
||||
"Translations": {
|
||||
"ar_SA": "",
|
||||
"de_DE": "",
|
||||
@@ -873,7 +873,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "MenuBarFileToolsInstallKeysFromFile",
|
||||
"ID": "MenuBarFileActionsInstallKeysFromFile",
|
||||
"Translations": {
|
||||
"ar_SA": "",
|
||||
"de_DE": "",
|
||||
@@ -893,12 +893,12 @@
|
||||
"th_TH": "",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "Встановити ключі з файлу .KEYS або .ZIP",
|
||||
"zh_CN": "从.KEYS文件或ZIP压缩包安装密匙",
|
||||
"zh_CN": "从 .KEYS 文件或 .ZIP 压缩包安装密匙",
|
||||
"zh_TW": "從 .KEYS 或 .ZIP 安裝金鑰"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "MenuBarFileToolsInstallKeysFromFolder",
|
||||
"ID": "MenuBarFileActionsInstallKeysFromFolder",
|
||||
"Translations": {
|
||||
"ar_SA": "",
|
||||
"de_DE": "",
|
||||
@@ -923,7 +923,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "MenuBarToolsManageFileTypes",
|
||||
"ID": "MenuBarActionsManageFileTypes",
|
||||
"Translations": {
|
||||
"ar_SA": "إدارة أنواع الملفات",
|
||||
"de_DE": "Dateitypen verwalten",
|
||||
@@ -948,7 +948,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "MenuBarToolsInstallFileTypes",
|
||||
"ID": "MenuBarActionsInstallFileTypes",
|
||||
"Translations": {
|
||||
"ar_SA": "تثبيت أنواع الملفات",
|
||||
"de_DE": "Dateitypen installieren",
|
||||
@@ -973,7 +973,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "MenuBarToolsUninstallFileTypes",
|
||||
"ID": "MenuBarActionsUninstallFileTypes",
|
||||
"Translations": {
|
||||
"ar_SA": "إزالة أنواع الملفات",
|
||||
"de_DE": "Dateitypen deinstallieren",
|
||||
@@ -998,7 +998,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "MenuBarToolsXCITrimmer",
|
||||
"ID": "MenuBarActionsXCITrimmer",
|
||||
"Translations": {
|
||||
"ar_SA": "",
|
||||
"de_DE": "",
|
||||
@@ -1018,7 +1018,7 @@
|
||||
"th_TH": "",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "Обрізати XCI файли",
|
||||
"zh_CN": "XCI文件瘦身",
|
||||
"zh_CN": "瘦身 XCI 文件",
|
||||
"zh_TW": "修剪 XCI 檔案"
|
||||
}
|
||||
},
|
||||
@@ -1293,7 +1293,7 @@
|
||||
"th_TH": "",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "Відкриває сторінку з Посібником по усуненню помилок та несправностей на офіційній вікі-сторінці Ryujinx (англійською)",
|
||||
"zh_CN": "打开Ryujinx官方wiki的常见问题和问题排除页面",
|
||||
"zh_CN": "打开 Ryujinx 官方 Wiki 的常见问题和问题排除页面",
|
||||
"zh_TW": "開啟官方 Ryujinx Wiki 常見問題 (FAQ) 和疑難排解頁面"
|
||||
}
|
||||
},
|
||||
@@ -1343,7 +1343,7 @@
|
||||
"th_TH": "",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "Відкриває посібник з Налаштування та конфігурації на офіційній вікі-сторінці Ryujinx (англійською)",
|
||||
"zh_CN": "打开Ryujinx官方wiki的安装与配置指南",
|
||||
"zh_CN": "打开 Ryujinx 官方 Wiki 的安装与配置指南",
|
||||
"zh_TW": "開啟官方 Ryujinx Wiki 設定和配置指南"
|
||||
}
|
||||
},
|
||||
@@ -1393,7 +1393,7 @@
|
||||
"th_TH": "",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "Відкриває посібник з налаштування Мультиплеєру на офіційній вікі-сторінці Ryujinx (англійською)",
|
||||
"zh_CN": "打开Ryujinx官方wiki的多人游戏指南",
|
||||
"zh_CN": "打开 Ryujinx 官方 Wiki 的多人游戏指南",
|
||||
"zh_TW": "開啟官方 Ryujinx Wiki 多人遊戲 (LDN/LAN) 指南"
|
||||
}
|
||||
},
|
||||
@@ -1443,7 +1443,7 @@
|
||||
"th_TH": "กำลังค้นหา...",
|
||||
"tr_TR": "Ara...",
|
||||
"uk_UA": "Пошук...",
|
||||
"zh_CN": "搜索…",
|
||||
"zh_CN": "搜索...",
|
||||
"zh_TW": "搜尋..."
|
||||
}
|
||||
},
|
||||
@@ -2297,6 +2297,56 @@
|
||||
"zh_TW": "從應用程式的目前配置中提取 RomFS 分區 (包含更新)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "GameListContextMenuExtractDataAocRomFS",
|
||||
"Translations": {
|
||||
"ar_SA": "",
|
||||
"de_DE": "",
|
||||
"el_GR": "",
|
||||
"en_US": "DLC RomFS",
|
||||
"es_ES": "",
|
||||
"fr_FR": "RomFS de DLC",
|
||||
"he_IL": "",
|
||||
"it_IT": "",
|
||||
"ja_JP": "",
|
||||
"ko_KR": "",
|
||||
"no_NO": "",
|
||||
"pl_PL": "",
|
||||
"pt_BR": "",
|
||||
"ru_RU": "",
|
||||
"sv_SE": "",
|
||||
"th_TH": "",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "",
|
||||
"zh_CN": "",
|
||||
"zh_TW": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "GameListContextMenuExtractDataAocRomFSToolTip",
|
||||
"Translations": {
|
||||
"ar_SA": "",
|
||||
"de_DE": "",
|
||||
"el_GR": "",
|
||||
"en_US": "Extract the RomFS from a selected DLC file",
|
||||
"es_ES": "",
|
||||
"fr_FR": "Extraire les RomFS d'un fichier DLC choisi",
|
||||
"he_IL": "",
|
||||
"it_IT": "",
|
||||
"ja_JP": "",
|
||||
"ko_KR": "",
|
||||
"no_NO": "Pakk ut RomFS filene fra valgt DLC fil",
|
||||
"pl_PL": "",
|
||||
"pt_BR": "",
|
||||
"ru_RU": "",
|
||||
"sv_SE": "",
|
||||
"th_TH": "",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "",
|
||||
"zh_CN": "",
|
||||
"zh_TW": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "GameListContextMenuExtractDataLogo",
|
||||
"Translations": {
|
||||
@@ -2543,7 +2593,7 @@
|
||||
"th_TH": "",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "Перевірка та нарізка XCI Файлу",
|
||||
"zh_CN": "检查并瘦身XCI文件",
|
||||
"zh_CN": "检查并瘦身 XCI 文件",
|
||||
"zh_TW": "檢查及修剪 XCI 檔案"
|
||||
}
|
||||
},
|
||||
@@ -2568,7 +2618,7 @@
|
||||
"th_TH": "",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "Перевірити та обрізати XCI Файл задля збереження місця на диску",
|
||||
"zh_CN": "检查并瘦身XCI文件以节约磁盘空间",
|
||||
"zh_CN": "检查并瘦身 XCI 文件以节约磁盘空间",
|
||||
"zh_TW": "檢查及修剪 XCI 檔案以節省儲存空間"
|
||||
}
|
||||
},
|
||||
@@ -2643,7 +2693,7 @@
|
||||
"th_TH": "",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "Обрізається XCI Файлів '{0}'",
|
||||
"zh_CN": "XCI文件瘦身中'{0}'",
|
||||
"zh_CN": "正在瘦身 XCI 文件 '{0}'",
|
||||
"zh_TW": "正在修剪 XCI 檔案 '{0}'"
|
||||
}
|
||||
},
|
||||
@@ -3168,7 +3218,7 @@
|
||||
"th_TH": "โหลดไดเรกทอรี DLC/ไฟล์อัปเดต อัตโนมัติ",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "Автозавантаження теки DLC/Оновлень",
|
||||
"zh_CN": "自动加载DLC/游戏更新目录",
|
||||
"zh_CN": "自动加载 DLC 及 游戏更新 的目录",
|
||||
"zh_TW": "自動載入 DLC/遊戲更新資料夾"
|
||||
}
|
||||
},
|
||||
@@ -3193,7 +3243,7 @@
|
||||
"th_TH": "",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "DLC та Оновлення, які посилаються на відсутні файли, будуть автоматично вимкнуті.",
|
||||
"zh_CN": "DLC/游戏更新可自动加载和卸载",
|
||||
"zh_CN": "DLC 及 游戏更新 可自动加载和卸载",
|
||||
"zh_TW": "遺失的 DLC 及遊戲更新檔案將會在自動載入中移除"
|
||||
}
|
||||
},
|
||||
@@ -7572,6 +7622,31 @@
|
||||
"zh_TW": "陀螺儀無感帶:"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "ControllerSettingsLedColor",
|
||||
"Translations": {
|
||||
"ar_SA": "",
|
||||
"de_DE": "",
|
||||
"el_GR": "",
|
||||
"en_US": "Custom LED",
|
||||
"es_ES": "",
|
||||
"fr_FR": "",
|
||||
"he_IL": "",
|
||||
"it_IT": "",
|
||||
"ja_JP": "",
|
||||
"ko_KR": "",
|
||||
"no_NO": "",
|
||||
"pl_PL": "",
|
||||
"pt_BR": "",
|
||||
"ru_RU": "",
|
||||
"sv_SE": "",
|
||||
"th_TH": "",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "",
|
||||
"zh_CN": "",
|
||||
"zh_TW": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "ControllerSettingsSave",
|
||||
"Translations": {
|
||||
@@ -11218,7 +11293,7 @@
|
||||
"th_TH": "ไม่มีข้อมูลบันทึกไว้สำหรับ {0} [{1:x16}]",
|
||||
"tr_TR": "{0} [{1:x16}] için kayıt verisi bulunamadı",
|
||||
"uk_UA": "Немає збережених даних для {0} [{1:x16}]",
|
||||
"zh_CN": "没有{0} [{1:x16}]的游戏存档",
|
||||
"zh_CN": "没有 {0} [{1:x16}] 的游戏存档",
|
||||
"zh_TW": "沒有 {0} [{1:x16}] 的存檔"
|
||||
}
|
||||
},
|
||||
@@ -12368,7 +12443,7 @@
|
||||
"th_TH": "",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "Вікно XCI Тримера",
|
||||
"zh_CN": "XCI文件瘦身窗口",
|
||||
"zh_CN": "XCI 文件瘦身窗口",
|
||||
"zh_TW": "XCI 修剪器視窗"
|
||||
}
|
||||
},
|
||||
@@ -13093,7 +13168,7 @@
|
||||
"th_TH": "",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "",
|
||||
"zh_CN": "在{0}发现了一个无效的密匙文件",
|
||||
"zh_CN": "在 {0} 发现了一个无效的密匙文件",
|
||||
"zh_TW": "找到無效的金鑰檔案 {0}"
|
||||
}
|
||||
},
|
||||
@@ -14443,7 +14518,7 @@
|
||||
"th_TH": "แฮ็ค: สุ่มแท็ก Uuid",
|
||||
"tr_TR": "Hack: Rastgele bir Uuid kullan",
|
||||
"uk_UA": "Хитрість: Використовувати випадковий тег Uuid",
|
||||
"zh_CN": "修改:使用随机生成的Amiibo ID",
|
||||
"zh_CN": "修改:使用随机生成的 Amiibo ID",
|
||||
"zh_TW": "補釘修正:使用隨機標記的 Uuid"
|
||||
}
|
||||
},
|
||||
@@ -15393,7 +15468,7 @@
|
||||
"th_TH": "โหลด PPTC โดยใช้หนึ่งในสามของจำนวนคอร์",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "Завантажувати PPTC використовуючи третину від кількості ядер.",
|
||||
"zh_CN": "使用三分之一的核心数加载PPTC.",
|
||||
"zh_CN": "使用三分之一的核心数加载 PPTC.",
|
||||
"zh_TW": "使用 CPU 核心數量的三分之一載入 PPTC。"
|
||||
}
|
||||
},
|
||||
@@ -16218,7 +16293,7 @@
|
||||
"th_TH": "เปิดตัวสำรวจไฟล์เพื่อเลือกหนึ่งโฟลเดอร์ขึ้นไปเพื่อโหลด DLC จำนวนมาก",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "Відкриває Файловий провідник для обрання однієї або декількох тек для масового завантаження DLC",
|
||||
"zh_CN": "打开文件资源管理器以选择一个或多个文件夹来批量加载DLC。",
|
||||
"zh_CN": "打开文件资源管理器以选择一个或多个文件夹来批量加载 DLC。",
|
||||
"zh_TW": "開啟檔案總管,選擇一個或多個資料夾來大量載入 DLC"
|
||||
}
|
||||
},
|
||||
@@ -19043,7 +19118,7 @@
|
||||
"th_TH": "",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "Перевірити та Обрізати XCI файл",
|
||||
"zh_CN": "检查并瘦身XCI文件",
|
||||
"zh_CN": "检查并瘦身 XCI 文件",
|
||||
"zh_TW": "檢查及修剪 XCI 檔案"
|
||||
}
|
||||
},
|
||||
@@ -19068,7 +19143,7 @@
|
||||
"th_TH": "",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "Ця функція спочатку перевірить наявність порожнього місця, після чого обріже файл XCI для економії місця на диску.",
|
||||
"zh_CN": "这个功能将会先检查XCI文件,再对其执行瘦身操作以节约磁盘空间。",
|
||||
"zh_CN": "这个功能将会先检查 XCI 文件,再对其执行瘦身操作以节约磁盘空间。",
|
||||
"zh_TW": "此功能首先檢查 XCI 檔案是否有可修剪的字元,然後修剪檔案以節省儲存空間。"
|
||||
}
|
||||
},
|
||||
@@ -19118,7 +19193,7 @@
|
||||
"th_TH": "",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "XCI файл не потребує обрізання. Перевірте журнали (logs) для отримання додаткової інформації",
|
||||
"zh_CN": "XCI文件不需要被瘦身。查看日志以获得更多细节。",
|
||||
"zh_CN": "XCI 文件不需要被瘦身。查看日志以获得更多细节。",
|
||||
"zh_TW": "XCI 檔案不需要修剪。檢查日誌以取得更多資訊"
|
||||
}
|
||||
},
|
||||
@@ -19143,7 +19218,7 @@
|
||||
"th_TH": "",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "XCI файл не може бути обрізаний. Перевірте журнали (logs) для отримання додаткової інформації",
|
||||
"zh_CN": "XCI文件不能被瘦身。查看日志以获得更多细节。",
|
||||
"zh_CN": "XCI 文件不能被瘦身。查看日志以获得更多细节。",
|
||||
"zh_TW": "XCI 檔案不能被修剪。檢查日誌以取得更多資訊"
|
||||
}
|
||||
},
|
||||
@@ -19168,7 +19243,7 @@
|
||||
"th_TH": "",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "XCI файл Тільки для Читання і не може бути прочитаним. Перевірте журнали (logs) для отримання додаткової інформації",
|
||||
"zh_CN": "XCI文件是只读的,且不可以被标记为可读取的。查看日志以获得更多细节。",
|
||||
"zh_CN": "XCI 文件是只读的,且不可以被标记为可读取的。查看日志以获得更多细节。",
|
||||
"zh_TW": "XCI 檔案是唯讀,並且無法改成可寫入。檢查日誌以取得更多資訊"
|
||||
}
|
||||
},
|
||||
@@ -19193,7 +19268,7 @@
|
||||
"th_TH": "",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "Розмір файлу XCI змінився з моменту сканування. Перевірте, чи не записується файл, та спробуйте знову",
|
||||
"zh_CN": "XCI文件在扫描后大小发生了变化。请检查文件是否未被写入,然后重试。",
|
||||
"zh_CN": "XCI 文件在扫描后大小发生了变化。请检查文件是否未被写入,然后重试。",
|
||||
"zh_TW": "XCI 檔案大小比較上次的掃瞄已經改變。請檢查檔案是否未被寫入,然後再嘗試。"
|
||||
}
|
||||
},
|
||||
@@ -19218,7 +19293,7 @@
|
||||
"th_TH": "",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "Файл XCI містить дані в зоні вільного простору, тому обрізка небезпечна",
|
||||
"zh_CN": "XCI文件的空闲区域内有数据,不能安全瘦身。",
|
||||
"zh_CN": "XCI 文件的空闲区域内有数据,不能安全瘦身。",
|
||||
"zh_TW": "XCI 檔案有數據儲存於可節省儲存空間的區域,所以試圖修剪並不安全"
|
||||
}
|
||||
},
|
||||
@@ -19243,7 +19318,7 @@
|
||||
"th_TH": "",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "XCI Файл містить недійсні дані. Перевірте журнали (logs) для отримання додаткової інформації",
|
||||
"zh_CN": "XCI文件含有无效数据。查看日志以获得更多细节。",
|
||||
"zh_CN": "XCI 文件含有无效数据。查看日志以获得更多细节。",
|
||||
"zh_TW": "XCI 檔案帶有無效的數據。檢查日誌以取得更多資訊"
|
||||
}
|
||||
},
|
||||
@@ -19268,7 +19343,7 @@
|
||||
"th_TH": "",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "XCI Файл файл не вдалося відкрити для запису. Перевірте журнали для додаткової інформації",
|
||||
"zh_CN": "XCI文件不能被读写。查看日志以获得更多细节。",
|
||||
"zh_CN": "XCI 文件不能被读写。查看日志以获得更多细节。",
|
||||
"zh_TW": "XCI 檔案不能被寫入。檢查日誌以取得更多資訊"
|
||||
}
|
||||
},
|
||||
@@ -19293,7 +19368,7 @@
|
||||
"th_TH": "",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "Не вдалося обрізати файл XCI",
|
||||
"zh_CN": "XCI文件瘦身失败",
|
||||
"zh_CN": "XCI 文件瘦身失败",
|
||||
"zh_TW": "修剪 XCI 檔案失敗"
|
||||
}
|
||||
},
|
||||
@@ -19493,7 +19568,7 @@
|
||||
"th_TH": "",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "Обрізка XCI Файлів",
|
||||
"zh_CN": "XCI文件瘦身器",
|
||||
"zh_CN": "XCI 文件瘦身器",
|
||||
"zh_TW": "XCI 檔案修剪器"
|
||||
}
|
||||
},
|
||||
@@ -19968,7 +20043,7 @@
|
||||
"th_TH": "แพ็ค DLC ไม่สามารถลบทิ้งได้ สามารถปิดใช้งานได้เท่านั้น",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "Комплектні DLC (бандли) не можуть бути видаленими, лише вимкненими.",
|
||||
"zh_CN": "游戏整合的DLC无法移除,可尝试禁用。",
|
||||
"zh_CN": "游戏整合的 DLC 无法移除,可尝试禁用。",
|
||||
"zh_TW": "附帶的 DLC 只能被停用而無法被刪除。"
|
||||
}
|
||||
},
|
||||
@@ -20018,7 +20093,7 @@
|
||||
"th_TH": "{0} DLC ใหม่ที่เพิ่มเข้ามา",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "{0} нового завантажувального вмісту додано",
|
||||
"zh_CN": "{0} 个DLC被添加",
|
||||
"zh_CN": "{0} 个 DLC 被添加",
|
||||
"zh_TW": "已加入 {0} 個 DLC"
|
||||
}
|
||||
},
|
||||
@@ -20043,7 +20118,7 @@
|
||||
"th_TH": "{0} ใหม่ที่เพิ่มเข้ามา",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "{0} нового завантажувального вмісту додано",
|
||||
"zh_CN": "{0} 个DLC被添加",
|
||||
"zh_CN": "{0} 个 DLC 被添加",
|
||||
"zh_TW": "已加入 {0} 個 DLC"
|
||||
}
|
||||
},
|
||||
@@ -20068,7 +20143,7 @@
|
||||
"th_TH": "",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "{0} відсутнього завантажувального вмісту видалено",
|
||||
"zh_CN": "{0} 个失效的DLC已移除",
|
||||
"zh_CN": "{0} 个失效的 DLC 已移除",
|
||||
"zh_TW": "已刪除 {0} 個遺失的 DLC"
|
||||
}
|
||||
},
|
||||
@@ -20593,7 +20668,7 @@
|
||||
"th_TH": "",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "",
|
||||
"zh_CN": "使用Vulkan。\n在ARM Mac上,当玩在其下运行良好的游戏时,使用Metal后端。",
|
||||
"zh_CN": "使用 Vulkan。\n在 ARM Mac 上,当玩在其下运行良好的游戏时,使用 Metal 后端。",
|
||||
"zh_TW": "使用Vulkan。\n在 ARM Mac 上,如果遊戲執行性能良好時,則將使用 Metal 後端。"
|
||||
}
|
||||
},
|
||||
@@ -21993,7 +22068,7 @@
|
||||
"th_TH": "",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "Вимкнути хостинг P2P мережі (може збільшити затримку)",
|
||||
"zh_CN": "禁用P2P网络连接 (也许会增加延迟)",
|
||||
"zh_CN": "禁用 P2P 网络连接 (也许会增加延迟)",
|
||||
"zh_TW": "停用對等網路代管 (P2P Network Hosting) (可能增加網路延遲)"
|
||||
}
|
||||
},
|
||||
@@ -22018,7 +22093,7 @@
|
||||
"th_TH": "",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "Вимкнути хостинг P2P мережі, піри будуть підключатися через майстер-сервер замість прямого з'єднання з вами.",
|
||||
"zh_CN": "禁用P2P网络连接,对方将通过主服务器进行连接,而不是直接连接到您。",
|
||||
"zh_CN": "禁用 P2P 网络连接,对方将通过主服务器进行连接,而不是直接连接到您。",
|
||||
"zh_TW": "停用對等網路代管 (P2P Network Hosting), 用戶群會經過代理何服器而非直接連線至你的主機。"
|
||||
}
|
||||
},
|
||||
@@ -22093,7 +22168,7 @@
|
||||
"th_TH": "",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "Введіть пароль у форматі Ryujinx-<8 символів>. Ви зможете бачити лише ті ігри, які мають такий самий пароль, як і у вас.",
|
||||
"zh_CN": "以Ryujinx-<8个十六进制字符>的格式输入密码。您只能看到与您使用相同密码的游戏房间。",
|
||||
"zh_CN": "以 Ryujinx-<8个十六进制字符> 的格式输入密码。您只能看到与您使用相同密码的游戏房间。",
|
||||
"zh_TW": "以「Ryujinx-<8 個十六進制數字>」的格式輸入密碼片語 (passphrase)。你只會看到與你的密碼片語 (passphrase) 相同的遊戲房間。"
|
||||
}
|
||||
},
|
||||
@@ -22393,7 +22468,7 @@
|
||||
"th_TH": "",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "Емульована вертикальна синхронізація кадрів. 'Switch' емулює частоту оновлення консолі Nintendo Switch (60 Гц). 'Необмежена' — частота оновлення не матиме обмежень.",
|
||||
"zh_CN": "模拟垂直同步。“Switch”模拟了Switch的60Hz刷新率。“无限制”没有刷新率限制。",
|
||||
"zh_CN": "模拟垂直同步。“Switch”模拟了 Switch 的 60Hz 刷新率。“无限制”没有刷新率限制。",
|
||||
"zh_TW": "模擬垂直同步。「Switch」 模擬 Nintendo Switch 的 60Hz 重新整理頻率。「沒有限制」是沒有限制的重新整理頻率。"
|
||||
}
|
||||
},
|
||||
@@ -22418,7 +22493,7 @@
|
||||
"th_TH": "",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "Емульована вертикальна синхронізація кадрів. 'Switch' емулює частоту оновлення консолі Nintendo Switch (60 Гц). 'Необмежена' — частота оновлення не матиме обмежень. 'Користувацька' емулює вказану користувацьку частоту оновлення.",
|
||||
"zh_CN": "模拟垂直同步。“Switch”模拟了Switch的60Hz刷新率。“无限制”没有刷新率限制。“自定义刷新率”模拟指定的自定义刷新率。",
|
||||
"zh_CN": "模拟垂直同步。“Switch”模拟了 Switch 的 60Hz 刷新率。“无限制”没有刷新率限制。“自定义刷新率”模拟指定的自定义刷新率。",
|
||||
"zh_TW": "模擬垂直同步。「Switch」 模擬 Nintendo Switch 的 60Hz 重新整理頻率。「沒有限制」是沒有限制的重新整理頻率。「自訂的重新整理頻率」模擬所自訂的重新整理頻率。"
|
||||
}
|
||||
},
|
||||
@@ -22443,7 +22518,7 @@
|
||||
"th_TH": "",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "Дозволяє користувачу вказати емульовану частоту оновлення. У деяких іграх це може прискорити або сповільнити логіку гри. Натомість в інших іграх ця функція може дозволити обмежити FPS на певні кратні частоти оновлення або призвести до непередбачуваної поведінки. Це експериментальна функція, без гарантій того, як вона вплине на ігровий процес. \n\nЗалиште ВИМКНЕНИМ, якщо не впевнені.",
|
||||
"zh_CN": "允许用户指定模拟刷新率。在某些游戏中,这可能会加快或减慢游戏逻辑的速度。在其他游戏中,它可能允许将FPS限制在刷新率的某个倍数,或者导致不可预测的行为。这是一个实验性功能,无法保证游戏会受到怎样的影响。\n\n如果不确定,请关闭。",
|
||||
"zh_CN": "允许用户指定模拟刷新率。在某些游戏中,这可能会加快或减慢游戏逻辑的速度。在其他游戏中,它可能允许将 FPS 限制在刷新率的某个倍数,或者导致不可预测的行为。这是一个实验性功能,无法保证游戏会受到怎样的影响。\n\n如果不确定,请关闭。",
|
||||
"zh_TW": "容許使用者自訂模擬的重新整理頻率。你可能會在某些遊戲裡感受到加快或減慢的遊戲速度;其他遊戲裡則可能會容許限制最高的 FPS 至重新整理頻率的倍數,或引起未知遊戲行為。這是實驗性功能,且沒有保證遊戲會穩定執行。\n\n如果不確定,請保持關閉狀態。"
|
||||
}
|
||||
},
|
||||
@@ -22896,6 +22971,31 @@
|
||||
"zh_CN": "什么都没有",
|
||||
"zh_TW": "無法啟動 (Nothing)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": "ExtractAocListHeader",
|
||||
"Translations": {
|
||||
"ar_SA": "",
|
||||
"de_DE": "",
|
||||
"el_GR": "",
|
||||
"en_US": "Select a DLC to Extract",
|
||||
"es_ES": "",
|
||||
"fr_FR": "Choisissez un DLC à extraire",
|
||||
"he_IL": "",
|
||||
"it_IT": "",
|
||||
"ja_JP": "",
|
||||
"ko_KR": "",
|
||||
"no_NO": "Velg en DLC og hente ut",
|
||||
"pl_PL": "",
|
||||
"pt_BR": "",
|
||||
"ru_RU": "",
|
||||
"sv_SE": "",
|
||||
"th_TH": "",
|
||||
"tr_TR": "",
|
||||
"uk_UA": "",
|
||||
"zh_CN": "",
|
||||
"zh_TW": ""
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
using Avalonia.Controls.Notifications;
|
||||
using Avalonia.Platform.Storage;
|
||||
using Avalonia.Threading;
|
||||
using Gommon;
|
||||
using LibHac;
|
||||
using LibHac.Account;
|
||||
using LibHac.Common;
|
||||
@@ -15,6 +15,7 @@ using LibHac.Tools.FsSystem.NcaUtils;
|
||||
using Ryujinx.Ava.Common.Locale;
|
||||
using Ryujinx.Ava.UI.Controls;
|
||||
using Ryujinx.Ava.UI.Helpers;
|
||||
using Ryujinx.Ava.Utilities;
|
||||
using Ryujinx.Ava.Utilities.Configuration;
|
||||
using Ryujinx.Common.Helper;
|
||||
using Ryujinx.Common.Logging;
|
||||
@@ -296,13 +297,13 @@ namespace Ryujinx.Ava.Common
|
||||
extractorThread.Start();
|
||||
}
|
||||
|
||||
public static void ExtractAoc(string destination, NcaSectionType ncaSectionType, string updateFilePath, string updateName)
|
||||
public static void ExtractAoc(string destination, string updateFilePath, string updateName)
|
||||
{
|
||||
var cancellationToken = new CancellationTokenSource();
|
||||
|
||||
UpdateWaitWindow waitingDialog = new(
|
||||
RyujinxApp.FormatTitle(LocaleKeys.DialogNcaExtractionTitle),
|
||||
LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogNcaExtractionMessage, ncaSectionType, Path.GetFileName(updateFilePath)),
|
||||
LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.DialogNcaExtractionMessage, NcaSectionType.Data, Path.GetFileName(updateFilePath)),
|
||||
cancellationToken);
|
||||
|
||||
Thread extractorThread = new(() =>
|
||||
@@ -352,7 +353,7 @@ namespace Ryujinx.Ava.Common
|
||||
? IntegrityCheckLevel.ErrorOnInvalid
|
||||
: IntegrityCheckLevel.None;
|
||||
|
||||
int index = Nca.GetSectionIndexFromType(ncaSectionType, publicDataNca.Header.ContentType);
|
||||
int index = Nca.GetSectionIndexFromType(NcaSectionType.Data, publicDataNca.Header.ContentType);
|
||||
|
||||
try
|
||||
{
|
||||
@@ -410,44 +411,35 @@ namespace Ryujinx.Ava.Common
|
||||
}
|
||||
})
|
||||
{
|
||||
Name = "GUI.NcaSectionExtractorThread",
|
||||
Name = "GUI.AocExtractorThread",
|
||||
IsBackground = true,
|
||||
};
|
||||
extractorThread.Start();
|
||||
}
|
||||
|
||||
public static async Task ExtractAoc(IStorageProvider storageProvider, NcaSectionType ncaSectionType,
|
||||
string updateFilePath, string updateName)
|
||||
public static async Task ExtractAoc(IStorageProvider storageProvider, string updateFilePath, string updateName)
|
||||
{
|
||||
var result = await storageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions
|
||||
Optional<IStorageFolder> result = await storageProvider.OpenSingleFolderPickerAsync(new FolderPickerOpenOptions
|
||||
{
|
||||
Title = LocaleManager.Instance[LocaleKeys.FolderDialogExtractTitle],
|
||||
AllowMultiple = false,
|
||||
Title = LocaleManager.Instance[LocaleKeys.FolderDialogExtractTitle]
|
||||
});
|
||||
|
||||
if (result.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ExtractAoc(result[0].Path.LocalPath, ncaSectionType, updateFilePath, updateName);
|
||||
if (!result.HasValue) return;
|
||||
|
||||
ExtractAoc(result.Value.Path.LocalPath, updateFilePath, updateName);
|
||||
}
|
||||
|
||||
|
||||
public static async Task ExtractSection(IStorageProvider storageProvider, NcaSectionType ncaSectionType, string titleFilePath, string titleName, int programIndex = 0)
|
||||
{
|
||||
var result = await storageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions
|
||||
Optional<IStorageFolder> result = await storageProvider.OpenSingleFolderPickerAsync(new FolderPickerOpenOptions
|
||||
{
|
||||
Title = LocaleManager.Instance[LocaleKeys.FolderDialogExtractTitle],
|
||||
AllowMultiple = false,
|
||||
Title = LocaleManager.Instance[LocaleKeys.FolderDialogExtractTitle]
|
||||
});
|
||||
|
||||
if (result.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!result.HasValue) return;
|
||||
|
||||
ExtractSection(result[0].Path.LocalPath, ncaSectionType, titleFilePath, titleName, programIndex);
|
||||
ExtractSection(result.Value.Path.LocalPath, ncaSectionType, titleFilePath, titleName, programIndex);
|
||||
}
|
||||
|
||||
public static (Result? result, bool canceled) CopyDirectory(FileSystemClient fs, string sourcePath, string destPath, CancellationToken token)
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace Ryujinx.Ava.Common.Models
|
||||
public bool IsBundled { get; } = System.IO.Path.GetExtension(ContainerPath)?.ToLower() == ".xci";
|
||||
|
||||
public string FileName => System.IO.Path.GetFileName(ContainerPath);
|
||||
public string TitleIdStr => TitleId.ToString("x16");
|
||||
public string TitleIdStr => TitleId.ToString("x16").ToUpper();
|
||||
public ulong TitleIdBase => TitleId & ~0x1FFFUL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,7 +149,7 @@ namespace Ryujinx.Headless
|
||||
IgnoreMissingServices = configurationState.System.IgnoreMissingServices;
|
||||
|
||||
if (NeedsOverride(nameof(IgnoreControllerApplet)))
|
||||
IgnoreControllerApplet = configurationState.IgnoreApplet;
|
||||
IgnoreControllerApplet = configurationState.System.IgnoreApplet;
|
||||
|
||||
return;
|
||||
|
||||
|
||||
@@ -47,9 +47,9 @@ namespace Ryujinx.Ava
|
||||
{
|
||||
Version = ReleaseInformation.Version;
|
||||
|
||||
if (OperatingSystem.IsWindows() && !OperatingSystem.IsWindowsVersionAtLeast(10, 0, 17134))
|
||||
if (OperatingSystem.IsWindows() && !OperatingSystem.IsWindowsVersionAtLeast(10, 0, 19041))
|
||||
{
|
||||
_ = MessageBoxA(nint.Zero, "You are running an outdated version of Windows.\n\nRyujinx supports Windows 10 version 1803 and newer.\n", $"Ryujinx {Version}", MbIconwarning);
|
||||
_ = MessageBoxA(nint.Zero, "You are running an outdated version of Windows.\n\nRyujinx supports Windows 10 version 20H1 and newer.\n", $"Ryujinx {Version}", MbIconwarning);
|
||||
}
|
||||
|
||||
PreviewerDetached = true;
|
||||
@@ -230,13 +230,16 @@ namespace Ryujinx.Ava
|
||||
internal static void PrintSystemInfo()
|
||||
{
|
||||
Logger.Notice.Print(LogClass.Application, $"{RyujinxApp.FullAppName} Version: {Version}");
|
||||
Logger.Notice.Print(LogClass.Application, $".NET Runtime: {RuntimeInformation.FrameworkDescription}");
|
||||
SystemInfo.Gather().Print();
|
||||
|
||||
var enabledLogLevels = Logger.GetEnabledLevels().ToArray();
|
||||
|
||||
Logger.Notice.Print(LogClass.Application, $"Logs Enabled: {(enabledLogLevels.Length is 0
|
||||
? "<None>"
|
||||
: enabledLogLevels.JoinToString(", "))}");
|
||||
Logger.Notice.Print(LogClass.Application, $"Logs Enabled: {
|
||||
Logger.GetEnabledLevels()
|
||||
.FormatCollection(
|
||||
x => x.ToString(),
|
||||
separator: ", ",
|
||||
emptyCollectionFallback: "<None>")
|
||||
}");
|
||||
|
||||
Logger.Notice.Print(LogClass.Application,
|
||||
AppDataManager.Mode == AppDataManager.LaunchMode.Custom
|
||||
|
||||
@@ -123,12 +123,13 @@
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</AvaloniaResource>
|
||||
<AvaloniaResource Include="Assets\Styles\Styles.xaml" />
|
||||
<AvaloniaResource Include="Assets\Styles\CheckboxMenuItemStyle.axaml" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="Assets\locales.json" />
|
||||
<None Remove="Assets\Styles\Styles.xaml" />
|
||||
<None Remove="Assets\Styles\Themes.xaml" />
|
||||
<None Remove="Assets\Styles\CheckboxMenuItemStyle.xaml" />
|
||||
<None Remove="Assets\Icons\Controller_JoyConLeft.svg" />
|
||||
<None Remove="Assets\Icons\Controller_JoyConPair.svg" />
|
||||
<None Remove="Assets\Icons\Controller_JoyConRight.svg" />
|
||||
@@ -150,6 +151,7 @@
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Assets\locales.json" />
|
||||
<EmbeddedResource Include="Assets\Styles\Styles.xaml" />
|
||||
<EmbeddedResource Include="Assets\Styles\CheckboxMenuItemStyle.axaml" />
|
||||
<EmbeddedResource Include="Assets\Icons\Controller_JoyConLeft.svg" />
|
||||
<EmbeddedResource Include="Assets\Icons\Controller_JoyConPair.svg" />
|
||||
<EmbeddedResource Include="Assets\Icons\Controller_JoyConRight.svg" />
|
||||
@@ -173,10 +175,5 @@
|
||||
<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>
|
||||
|
||||
@@ -16,5 +16,6 @@
|
||||
<Application.Styles>
|
||||
<sty:FluentAvaloniaTheme PreferUserAccentColor="True" PreferSystemTheme="False" />
|
||||
<StyleInclude Source="/Assets/Styles/Styles.xaml" />
|
||||
<StyleInclude Source="/Assets/Styles/CheckboxMenuItemStyle.axaml"/>
|
||||
</Application.Styles>
|
||||
</Application>
|
||||
|
||||
@@ -6,7 +6,6 @@ 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;
|
||||
@@ -42,7 +41,7 @@ namespace Ryujinx.Ava.UI.Applet
|
||||
|
||||
bool okPressed = false;
|
||||
|
||||
if (ConfigurationState.Instance.IgnoreApplet)
|
||||
if (ConfigurationState.Instance.System.IgnoreApplet)
|
||||
return false;
|
||||
|
||||
Dispatcher.UIThread.InvokeAsync(async () =>
|
||||
|
||||
@@ -106,6 +106,10 @@
|
||||
Click="ExtractApplicationRomFs_Click"
|
||||
Header="{ext:Locale GameListContextMenuExtractDataRomFS}"
|
||||
ToolTip.Tip="{ext:Locale GameListContextMenuExtractDataRomFSToolTip}" />
|
||||
<MenuItem
|
||||
Click="ExtractAocRomFs_Click"
|
||||
Header="{ext:Locale GameListContextMenuExtractDataAocRomFS}"
|
||||
ToolTip.Tip="{ext:Locale GameListContextMenuExtractDataAocRomFSToolTip}" />
|
||||
<MenuItem
|
||||
Click="ExtractApplicationLogo_Click"
|
||||
Header="{ext:Locale GameListContextMenuExtractDataLogo}"
|
||||
|
||||
@@ -3,10 +3,13 @@ using Avalonia.Interactivity;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Avalonia.Platform.Storage;
|
||||
using Avalonia.Threading;
|
||||
using FluentAvalonia.UI.Controls;
|
||||
using LibHac;
|
||||
using LibHac.Fs;
|
||||
using LibHac.Tools.FsSystem.NcaUtils;
|
||||
using Ryujinx.Ava.Common;
|
||||
using Ryujinx.Ava.Common.Locale;
|
||||
using Ryujinx.Ava.Common.Models;
|
||||
using Ryujinx.Ava.UI.Helpers;
|
||||
using Ryujinx.Ava.UI.ViewModels;
|
||||
using Ryujinx.Ava.UI.Windows;
|
||||
@@ -14,6 +17,7 @@ using Ryujinx.Ava.Utilities;
|
||||
using Ryujinx.Ava.Utilities.AppLibrary;
|
||||
using Ryujinx.Common.Configuration;
|
||||
using Ryujinx.Common.Helper;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE.HOS;
|
||||
using SkiaSharp;
|
||||
using System;
|
||||
@@ -247,7 +251,7 @@ namespace Ryujinx.Ava.UI.Controls
|
||||
{
|
||||
if (sender is MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel })
|
||||
{
|
||||
string shaderCacheDir = Path.Combine(AppDataManager.GamesDirPath, viewModel.SelectedApplication.IdString, "cache", "shader");
|
||||
string shaderCacheDir = Path.Combine(AppDataManager.GamesDirPath, viewModel.SelectedApplication.IdString.ToLower(), "cache", "shader");
|
||||
|
||||
if (!Directory.Exists(shaderCacheDir))
|
||||
{
|
||||
@@ -279,6 +283,22 @@ namespace Ryujinx.Ava.UI.Controls
|
||||
viewModel.SelectedApplication.Path,
|
||||
viewModel.SelectedApplication.Name);
|
||||
}
|
||||
|
||||
public async void ExtractAocRomFs_Click(object sender, RoutedEventArgs args)
|
||||
{
|
||||
if (sender is not MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel })
|
||||
return;
|
||||
|
||||
DownloadableContentModel selectedDlc = await DlcSelectView.Show(viewModel.SelectedApplication.IdBase, viewModel.ApplicationLibrary);
|
||||
|
||||
if (selectedDlc is not null)
|
||||
{
|
||||
await ApplicationHelper.ExtractAoc(
|
||||
viewModel.StorageProvider,
|
||||
selectedDlc.ContainerPath,
|
||||
selectedDlc.FileName);
|
||||
}
|
||||
}
|
||||
|
||||
public async void ExtractApplicationLogo_Click(object sender, RoutedEventArgs args)
|
||||
{
|
||||
|
||||
@@ -2,11 +2,10 @@
|
||||
x:Class="Ryujinx.Ava.UI.Controls.ApplicationListView"
|
||||
xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="clr-namespace:Ryujinx.Ava.UI.Controls"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
d:DesignHeight="450"
|
||||
d:DesignWidth="800"
|
||||
Focusable="True"
|
||||
|
||||
67
src/Ryujinx/UI/Controls/DlcSelectView.axaml
Normal file
67
src/Ryujinx/UI/Controls/DlcSelectView.axaml
Normal file
@@ -0,0 +1,67 @@
|
||||
<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:helpers="using:Ryujinx.Ava.UI.Helpers"
|
||||
xmlns:ext="using:Ryujinx.Ava.Common.Markup"
|
||||
xmlns:models="using:Ryujinx.Ava.Common.Models"
|
||||
xmlns:viewModels="using:Ryujinx.Ava.UI.ViewModels"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="Ryujinx.Ava.UI.Controls.DlcSelectView"
|
||||
x:DataType="viewModels:DlcSelectViewModel">
|
||||
<Grid RowDefinitions="*,Auto,*">
|
||||
<TextBlock
|
||||
Classes="h1"
|
||||
Margin="5, -5, 0, 15"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"
|
||||
TextWrapping="Wrap"
|
||||
Text="{ext:Locale ExtractAocListHeader}" />
|
||||
<ScrollViewer Grid.Row="2">
|
||||
<ListBox
|
||||
AutoScrollToSelectedItem="False"
|
||||
SelectionMode="Single"
|
||||
Background="Transparent"
|
||||
SelectedItem="{Binding SelectedDlc}"
|
||||
ItemsSource="{Binding Dlcs}">
|
||||
<ListBox.DataTemplates>
|
||||
<DataTemplate
|
||||
DataType="models:DownloadableContentModel">
|
||||
<Panel Margin="10" Background="Transparent">
|
||||
<Grid ColumnDefinitions="*,Auto">
|
||||
<Grid
|
||||
Grid.Column="0" ColumnDefinitions="*,Auto">
|
||||
<TextBlock
|
||||
Grid.Column="0"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
MaxLines="2"
|
||||
TextWrapping="Wrap"
|
||||
TextTrimming="CharacterEllipsis">
|
||||
<TextBlock.Text>
|
||||
<MultiBinding Converter="{x:Static helpers:DownloadableContentLabelConverter.Instance}">
|
||||
<Binding Path="FileName" />
|
||||
<Binding Path="IsBundled" />
|
||||
</MultiBinding>
|
||||
</TextBlock.Text>
|
||||
</TextBlock>
|
||||
<TextBlock
|
||||
Grid.Column="1"
|
||||
Margin="10, 0, 0, 0"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Text="{Binding TitleIdStr}" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Panel>
|
||||
</DataTemplate>
|
||||
</ListBox.DataTemplates>
|
||||
<ListBox.Styles>
|
||||
<Style Selector="ListBoxItem">
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
</Style>
|
||||
</ListBox.Styles>
|
||||
</ListBox>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
51
src/Ryujinx/UI/Controls/DlcSelectView.axaml.cs
Normal file
51
src/Ryujinx/UI/Controls/DlcSelectView.axaml.cs
Normal file
@@ -0,0 +1,51 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Avalonia.Styling;
|
||||
using FluentAvalonia.UI.Controls;
|
||||
using Ryujinx.Ava.Common.Locale;
|
||||
using Ryujinx.Ava.Common.Models;
|
||||
using Ryujinx.Ava.UI.Helpers;
|
||||
using Ryujinx.Ava.UI.ViewModels;
|
||||
using Ryujinx.Ava.Utilities.AppLibrary;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Ryujinx.Ava.UI.Controls
|
||||
{
|
||||
public partial class DlcSelectView : UserControl
|
||||
{
|
||||
public DlcSelectView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
#nullable enable
|
||||
public static async Task<DownloadableContentModel?> Show(ulong selectedTitleId, ApplicationLibrary appLibrary)
|
||||
#nullable disable
|
||||
{
|
||||
DlcSelectViewModel viewModel = new(selectedTitleId, appLibrary);
|
||||
|
||||
ContentDialog contentDialog = new()
|
||||
{
|
||||
PrimaryButtonText = LocaleManager.Instance[LocaleKeys.Continue],
|
||||
SecondaryButtonText = string.Empty,
|
||||
CloseButtonText = string.Empty,
|
||||
Content = new DlcSelectView { DataContext = viewModel }
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
return viewModel.SelectedDlc;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -69,7 +69,7 @@ namespace Ryujinx.Ava.UI.Controls
|
||||
VirtualFileSystem ownerVirtualFileSystem,
|
||||
HorizonClient ownerHorizonClient)
|
||||
{
|
||||
var content = new NavigationDialogHost(ownerAccountManager, ownerContentManager, ownerVirtualFileSystem, ownerHorizonClient);
|
||||
NavigationDialogHost content = new(ownerAccountManager, ownerContentManager, ownerVirtualFileSystem, ownerHorizonClient);
|
||||
ContentDialog contentDialog = new()
|
||||
{
|
||||
Title = LocaleManager.Instance[LocaleKeys.UserProfileWindowTitle],
|
||||
|
||||
@@ -12,9 +12,9 @@ namespace Ryujinx.Ava.UI.Helpers
|
||||
public static RelayCommand CreateConditional(Action action, Func<bool> canExecute)
|
||||
=> new(action, canExecute);
|
||||
|
||||
public static RelayCommand<T> CreateWithArg<T>(Action<T?> action)
|
||||
public static RelayCommand<T> Create<T>(Action<T?> action)
|
||||
=> new(action);
|
||||
public static RelayCommand<T> CreateConditionalWithArg<T>(Action<T?> action, Predicate<T?> canExecute)
|
||||
public static RelayCommand<T> CreateConditional<T>(Action<T?> action, Predicate<T?> canExecute)
|
||||
=> new(action, canExecute);
|
||||
|
||||
public static AsyncRelayCommand Create(Func<Task> action)
|
||||
@@ -24,11 +24,11 @@ namespace Ryujinx.Ava.UI.Helpers
|
||||
public static AsyncRelayCommand CreateSilentFail(Func<Task> action)
|
||||
=> new(action, AsyncRelayCommandOptions.FlowExceptionsToTaskScheduler);
|
||||
|
||||
public static AsyncRelayCommand<T> CreateWithArg<T>(Func<T?, Task> action)
|
||||
public static AsyncRelayCommand<T> Create<T>(Func<T?, Task> action)
|
||||
=> new(action, AsyncRelayCommandOptions.None);
|
||||
public static AsyncRelayCommand<T> CreateConcurrentWithArg<T>(Func<T?, Task> action)
|
||||
public static AsyncRelayCommand<T> CreateConcurrent<T>(Func<T?, Task> action)
|
||||
=> new(action, AsyncRelayCommandOptions.AllowConcurrentExecutions);
|
||||
public static AsyncRelayCommand<T> CreateSilentFailWithArg<T>(Func<T?, Task> action)
|
||||
public static AsyncRelayCommand<T> CreateSilentFail<T>(Func<T?, Task> action)
|
||||
=> new(action, AsyncRelayCommandOptions.FlowExceptionsToTaskScheduler);
|
||||
|
||||
public static AsyncRelayCommand CreateConditional(Func<Task> action, Func<bool> canExecute)
|
||||
@@ -38,11 +38,11 @@ namespace Ryujinx.Ava.UI.Helpers
|
||||
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)
|
||||
public static AsyncRelayCommand<T> CreateConditional<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)
|
||||
public static AsyncRelayCommand<T> CreateConcurrentConditional<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)
|
||||
public static AsyncRelayCommand<T> CreateSilentFailConditional<T>(Func<T?, Task> action, Predicate<T?> canExecute)
|
||||
=> new(action, canExecute, AsyncRelayCommandOptions.FlowExceptionsToTaskScheduler);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Avalonia.Media;
|
||||
using Ryujinx.Ava.UI.ViewModels;
|
||||
using Ryujinx.Common.Configuration.Hid;
|
||||
using Ryujinx.Common.Configuration.Hid.Controller;
|
||||
@@ -387,6 +388,30 @@ namespace Ryujinx.Ava.UI.Models.Input
|
||||
}
|
||||
}
|
||||
|
||||
private bool _enableLedChanging;
|
||||
|
||||
public bool EnableLedChanging
|
||||
{
|
||||
get => _enableLedChanging;
|
||||
set
|
||||
{
|
||||
_enableLedChanging = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private Color _ledColor;
|
||||
|
||||
public Color LedColor
|
||||
{
|
||||
get => _ledColor;
|
||||
set
|
||||
{
|
||||
_ledColor = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private bool _enableMotion;
|
||||
public bool EnableMotion
|
||||
{
|
||||
@@ -483,12 +508,23 @@ namespace Ryujinx.Ava.UI.Models.Input
|
||||
WeakRumble = controllerInput.Rumble.WeakRumble;
|
||||
StrongRumble = controllerInput.Rumble.StrongRumble;
|
||||
}
|
||||
|
||||
if (controllerInput.Led != null)
|
||||
{
|
||||
EnableLedChanging = controllerInput.Led.EnableLed;
|
||||
uint rawColor = controllerInput.Led.LedColor;
|
||||
byte alpha = (byte)(rawColor >> 24);
|
||||
byte red = (byte)(rawColor >> 16);
|
||||
byte green = (byte)(rawColor >> 8);
|
||||
byte blue = (byte)(rawColor % 256);
|
||||
LedColor = new Color(alpha, red, green, blue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public InputConfig GetConfig()
|
||||
{
|
||||
var config = new StandardControllerInputConfig
|
||||
StandardControllerInputConfig config = new()
|
||||
{
|
||||
Id = Id,
|
||||
Backend = InputBackendType.GamepadSDL2,
|
||||
@@ -540,6 +576,11 @@ namespace Ryujinx.Ava.UI.Models.Input
|
||||
WeakRumble = WeakRumble,
|
||||
StrongRumble = StrongRumble,
|
||||
},
|
||||
Led = new LedConfigController
|
||||
{
|
||||
EnableLed = EnableLedChanging,
|
||||
LedColor = LedColor.ToUInt32()
|
||||
},
|
||||
Version = InputConfig.CurrentVersion,
|
||||
DeadzoneLeft = DeadzoneLeft,
|
||||
DeadzoneRight = DeadzoneRight,
|
||||
|
||||
@@ -432,7 +432,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
{
|
||||
try
|
||||
{
|
||||
HttpResponseMessage response = await _httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Head, "https://raw.githubusercontent.com/GreemDev/Ryujinx/refs/heads/master/assets/amiibo/Amiibo.json"));
|
||||
HttpResponseMessage response = await _httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Head, "https://raw.githubusercontent.com/Ryubing/Ryujinx/refs/heads/master/assets/amiibo/Amiibo.json"));
|
||||
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
@@ -451,7 +451,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
{
|
||||
try
|
||||
{
|
||||
HttpResponseMessage response = await _httpClient.GetAsync($"https://raw.githubusercontent.com/GreemDev/Ryujinx/refs/heads/master/assets/amiibo/Amiibo.json");
|
||||
HttpResponseMessage response = await _httpClient.GetAsync($"https://raw.githubusercontent.com/Ryubing/Ryujinx/refs/heads/master/assets/amiibo/Amiibo.json");
|
||||
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
|
||||
25
src/Ryujinx/UI/ViewModels/DlcSelectViewModel.cs
Normal file
25
src/Ryujinx/UI/ViewModels/DlcSelectViewModel.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using CommunityToolkit.Mvvm.ComponentModel;
|
||||
using Ryujinx.Ava.Common.Models;
|
||||
using Ryujinx.Ava.Utilities.AppLibrary;
|
||||
using System.Linq;
|
||||
|
||||
namespace Ryujinx.Ava.UI.ViewModels
|
||||
{
|
||||
public partial class DlcSelectViewModel : BaseModel
|
||||
{
|
||||
[ObservableProperty] private DownloadableContentModel[] _dlcs;
|
||||
#nullable enable
|
||||
[ObservableProperty] private DownloadableContentModel? _selectedDlc;
|
||||
#nullable disable
|
||||
|
||||
public DlcSelectViewModel(ulong titleId, ApplicationLibrary appLibrary)
|
||||
{
|
||||
_dlcs = appLibrary.DownloadableContents.Items
|
||||
.Where(x => x.Dlc.TitleIdBase == titleId)
|
||||
.Select(x => x.Dlc)
|
||||
.OrderBy(it => it.IsBundled ? 0 : 1)
|
||||
.ThenBy(it => it.TitleId)
|
||||
.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -37,7 +37,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
|
||||
|
||||
[ObservableProperty] private SvgImage _image;
|
||||
|
||||
public readonly InputViewModel ParentModel;
|
||||
public InputViewModel ParentModel { get; }
|
||||
|
||||
public ControllerInputViewModel(InputViewModel model, GamepadInputConfig config)
|
||||
{
|
||||
|
||||
@@ -69,6 +69,9 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
|
||||
public bool IsRight { get; set; }
|
||||
public bool IsLeft { get; set; }
|
||||
|
||||
public bool HasLed => false; //temporary
|
||||
//SelectedGamepad.Features.HasFlag(GamepadFeaturesFlag.Led);
|
||||
|
||||
public bool IsModified { get; set; }
|
||||
public event Action NotifyChangesEvent;
|
||||
|
||||
|
||||
@@ -488,6 +488,19 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
public bool StartGamesWithoutUI
|
||||
{
|
||||
get => ConfigurationState.Instance.UI.StartNoUI;
|
||||
set
|
||||
{
|
||||
ConfigurationState.Instance.UI.StartNoUI.Value = value;
|
||||
|
||||
ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath);
|
||||
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public bool ShowConsole
|
||||
{
|
||||
get => ConfigurationState.Instance.UI.ShowConsole;
|
||||
@@ -624,6 +637,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
ApplicationSort.FileSize => LocaleManager.Instance[LocaleKeys.GameListHeaderFileSize],
|
||||
ApplicationSort.Path => LocaleManager.Instance[LocaleKeys.GameListHeaderPath],
|
||||
ApplicationSort.Favorite => LocaleManager.Instance[LocaleKeys.CommonFavorite],
|
||||
ApplicationSort.TitleId => LocaleManager.Instance[LocaleKeys.DlcManagerTableHeadingTitleIdLabel],
|
||||
_ => string.Empty,
|
||||
};
|
||||
}
|
||||
@@ -694,6 +708,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
public IHostUIHandler UiHandler { get; internal set; }
|
||||
public bool IsSortedByFavorite => SortMode == ApplicationSort.Favorite;
|
||||
public bool IsSortedByTitle => SortMode == ApplicationSort.Title;
|
||||
public bool IsSortedByTitleId => SortMode == ApplicationSort.TitleId;
|
||||
public bool IsSortedByDeveloper => SortMode == ApplicationSort.Developer;
|
||||
public bool IsSortedByLastPlayed => SortMode == ApplicationSort.LastPlayed;
|
||||
public bool IsSortedByTimePlayed => SortMode == ApplicationSort.TotalTimePlayed;
|
||||
@@ -726,6 +741,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
ApplicationSort.FileSize => CreateComparer(IsAscending, app => app.FileSize),
|
||||
ApplicationSort.Path => CreateComparer(IsAscending, app => app.Path),
|
||||
ApplicationSort.Favorite => CreateComparer(IsAscending, app => new AppListFavoriteComparable(app)),
|
||||
ApplicationSort.TitleId => CreateComparer(IsAscending, app => app.Id),
|
||||
_ => null,
|
||||
#pragma warning restore IDE0055
|
||||
};
|
||||
@@ -1195,6 +1211,11 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
StartGamesInFullscreen = !StartGamesInFullscreen;
|
||||
}
|
||||
|
||||
public void ToggleStartGamesWithoutUI()
|
||||
{
|
||||
StartGamesWithoutUI = !StartGamesWithoutUI;
|
||||
}
|
||||
|
||||
public void ToggleShowConsole()
|
||||
{
|
||||
ShowConsole = !ShowConsole;
|
||||
@@ -1641,10 +1662,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
|
||||
public async Task OpenAmiiboWindow()
|
||||
{
|
||||
if (!IsAmiiboRequested)
|
||||
return;
|
||||
|
||||
if (AppHost.Device.System.SearchingForAmiibo(out int deviceId))
|
||||
if (AppHost.Device.System.SearchingForAmiibo(out int deviceId) && IsGameRunning)
|
||||
{
|
||||
string titleId = AppHost.Device.Processes.ActiveApplication.ProgramIdText.ToUpper();
|
||||
AmiiboWindow window = new(ShowAll, LastScannedAmiiboId, titleId);
|
||||
@@ -1662,10 +1680,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
}
|
||||
public async Task OpenBinFile()
|
||||
{
|
||||
if (!IsAmiiboRequested)
|
||||
return;
|
||||
|
||||
if (AppHost.Device.System.SearchingForAmiibo(out int deviceId))
|
||||
if (AppHost.Device.System.SearchingForAmiibo(out _) && IsGameRunning)
|
||||
{
|
||||
var result = await StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
|
||||
{
|
||||
|
||||
@@ -488,7 +488,6 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
EnableDiscordIntegration = config.EnableDiscordIntegration;
|
||||
CheckUpdatesOnStart = config.CheckUpdatesOnStart;
|
||||
ShowConfirmExit = config.ShowConfirmExit;
|
||||
IgnoreApplet = config.IgnoreApplet;
|
||||
RememberWindowState = config.RememberWindowState;
|
||||
ShowTitleBar = config.ShowTitleBar;
|
||||
HideCursor = (int)config.HideCursor.Value;
|
||||
@@ -532,6 +531,7 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
EnableFsIntegrityChecks = config.System.EnableFsIntegrityChecks;
|
||||
DramSize = config.System.DramSize;
|
||||
IgnoreMissingServices = config.System.IgnoreMissingServices;
|
||||
IgnoreApplet = config.System.IgnoreApplet;
|
||||
|
||||
// CPU
|
||||
EnablePptc = config.System.EnablePtc;
|
||||
@@ -591,7 +591,6 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
config.EnableDiscordIntegration.Value = EnableDiscordIntegration;
|
||||
config.CheckUpdatesOnStart.Value = CheckUpdatesOnStart;
|
||||
config.ShowConfirmExit.Value = ShowConfirmExit;
|
||||
config.IgnoreApplet.Value = IgnoreApplet;
|
||||
config.RememberWindowState.Value = RememberWindowState;
|
||||
config.ShowTitleBar.Value = ShowTitleBar;
|
||||
config.HideCursor.Value = (HideCursorMode)HideCursor;
|
||||
@@ -632,12 +631,10 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
}
|
||||
|
||||
config.System.SystemTimeOffset.Value = Convert.ToInt64((CurrentDate.ToUnixTimeSeconds() + CurrentTime.TotalSeconds) - DateTimeOffset.Now.ToUnixTimeSeconds());
|
||||
config.Graphics.VSyncMode.Value = VSyncMode;
|
||||
config.Graphics.EnableCustomVSyncInterval.Value = EnableCustomVSyncInterval;
|
||||
config.Graphics.CustomVSyncInterval.Value = CustomVSyncInterval;
|
||||
config.System.EnableFsIntegrityChecks.Value = EnableFsIntegrityChecks;
|
||||
config.System.DramSize.Value = DramSize;
|
||||
config.System.IgnoreMissingServices.Value = IgnoreMissingServices;
|
||||
config.System.IgnoreApplet.Value = IgnoreApplet;
|
||||
|
||||
// CPU
|
||||
config.System.EnablePtc.Value = EnablePptc;
|
||||
@@ -646,6 +643,9 @@ namespace Ryujinx.Ava.UI.ViewModels
|
||||
config.System.UseHypervisor.Value = UseHypervisor;
|
||||
|
||||
// Graphics
|
||||
config.Graphics.VSyncMode.Value = VSyncMode;
|
||||
config.Graphics.EnableCustomVSyncInterval.Value = EnableCustomVSyncInterval;
|
||||
config.Graphics.CustomVSyncInterval.Value = CustomVSyncInterval;
|
||||
config.Graphics.GraphicsBackend.Value = (GraphicsBackend)GraphicsBackendIndex;
|
||||
config.Graphics.PreferredGpu.Value = _gpuIds.ElementAtOrDefault(PreferredGpuIndex);
|
||||
config.Graphics.EnableShaderCache.Value = EnableShaderCache;
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
xmlns:ext="clr-namespace:Ryujinx.Ava.Common.Markup"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||
xmlns:controls="clr-namespace:Ryujinx.Ava.UI.Controls"
|
||||
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels.Input"
|
||||
xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers"
|
||||
@@ -486,6 +487,37 @@
|
||||
</Button>
|
||||
</Grid>
|
||||
</Border>
|
||||
<Border
|
||||
BorderBrush="{DynamicResource ThemeControlBorderColor}"
|
||||
BorderThickness="1"
|
||||
CornerRadius="5"
|
||||
HorizontalAlignment="Stretch"
|
||||
Margin="0,-1,0,0">
|
||||
<Grid IsVisible="{Binding ParentModel.HasLed}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<CheckBox
|
||||
Margin="10"
|
||||
MinWidth="0"
|
||||
Grid.Column="0"
|
||||
IsChecked="{Binding Config.EnableLedChanging, Mode=TwoWay}">
|
||||
<TextBlock Text="{ext:Locale ControllerSettingsLedColor}" />
|
||||
</CheckBox>
|
||||
<ui:ColorPickerButton
|
||||
Grid.Column="1"
|
||||
Margin="10"
|
||||
IsMoreButtonVisible="False"
|
||||
UseColorPalette="False"
|
||||
UseColorTriangle="False"
|
||||
UseColorWheel="False"
|
||||
ShowAcceptDismissButtons="False"
|
||||
IsAlphaEnabled="False"
|
||||
Color="{Binding Config.LedColor, Mode=TwoWay}">
|
||||
</ui:ColorPickerButton>
|
||||
</Grid>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
<!-- Right Controls -->
|
||||
|
||||
@@ -4,14 +4,11 @@ using Avalonia.Controls.Primitives;
|
||||
using Avalonia.Input;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.LogicalTree;
|
||||
using DiscordRPC;
|
||||
using Ryujinx.Ava.UI.Helpers;
|
||||
using Ryujinx.Ava.UI.ViewModels.Input;
|
||||
using Ryujinx.Common.Configuration.Hid.Controller;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.Input;
|
||||
using Ryujinx.Input.Assigner;
|
||||
using System;
|
||||
using StickInputId = Ryujinx.Common.Configuration.Hid.Controller.StickInputId;
|
||||
|
||||
namespace Ryujinx.Ava.UI.Views.Input
|
||||
|
||||
@@ -81,25 +81,16 @@
|
||||
<MenuItem
|
||||
Command="{Binding ToggleFullscreen}"
|
||||
Header="{ext:Locale MenuBarOptionsToggleFullscreen}"
|
||||
Classes="withCheckbox"
|
||||
Padding="0"
|
||||
Icon="{ext:Icon fa-solid fa-expand}"
|
||||
InputGesture="F11">
|
||||
<MenuItem.Styles>
|
||||
<Style Selector="Viewbox#PART_IconPresenter">
|
||||
<Setter Property="MaxHeight" Value="36" />
|
||||
<Setter Property="MinHeight" Value="36" />
|
||||
<Setter Property="MaxWidth" Value="36" />
|
||||
<Setter Property="MinWidth" Value="36" />
|
||||
</Style>
|
||||
<Style Selector="ContentPresenter#PART_HeaderPresenter">
|
||||
<Setter Property="Padding" Value="-10,0,0,0" />
|
||||
</Style>
|
||||
</MenuItem.Styles>
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
Padding="0"
|
||||
Command="{Binding ToggleStartGamesInFullscreen}"
|
||||
Header="{ext:Locale MenuBarOptionsStartGamesInFullscreen}">
|
||||
Header="{ext:Locale MenuBarOptionsStartGamesInFullscreen}"
|
||||
Classes="withCheckbox">
|
||||
<MenuItem.Icon>
|
||||
<CheckBox
|
||||
MinWidth="{DynamicResource CheckBoxSize}"
|
||||
@@ -107,23 +98,26 @@
|
||||
IsChecked="{Binding StartGamesInFullscreen, Mode=TwoWay}"
|
||||
Padding="0" />
|
||||
</MenuItem.Icon>
|
||||
<MenuItem.Styles>
|
||||
<Style Selector="Viewbox#PART_IconPresenter">
|
||||
<Setter Property="MaxHeight" Value="36" />
|
||||
<Setter Property="MinHeight" Value="36" />
|
||||
<Setter Property="MaxWidth" Value="36" />
|
||||
<Setter Property="MinWidth" Value="36" />
|
||||
</Style>
|
||||
<Style Selector="ContentPresenter#PART_HeaderPresenter">
|
||||
<Setter Property="Padding" Value="-10,0,0,0" />
|
||||
</Style>
|
||||
</MenuItem.Styles>
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
Padding="0"
|
||||
Command="{Binding ToggleStartGamesWithoutUI}"
|
||||
Header="{ext:Locale MenuBarOptionsStartGamesWithoutUI}"
|
||||
Classes="withCheckbox">
|
||||
<MenuItem.Icon>
|
||||
<CheckBox
|
||||
MinWidth="{DynamicResource CheckBoxSize}"
|
||||
MinHeight="{DynamicResource CheckBoxSize}"
|
||||
IsChecked="{Binding StartGamesWithoutUI, Mode=TwoWay}"
|
||||
Padding="0" />
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
Padding="0"
|
||||
IsVisible="{Binding ShowConsoleVisible}"
|
||||
Command="{Binding ToggleShowConsole}"
|
||||
Header="{ext:Locale MenuBarOptionsShowConsole}">
|
||||
Header="{ext:Locale MenuBarOptionsShowConsole}"
|
||||
Classes="withCheckbox">
|
||||
<MenuItem.Icon>
|
||||
<CheckBox
|
||||
MinWidth="{DynamicResource CheckBoxSize}"
|
||||
@@ -131,35 +125,14 @@
|
||||
IsChecked="{Binding ShowConsole, Mode=TwoWay}"
|
||||
Padding="0" />
|
||||
</MenuItem.Icon>
|
||||
<MenuItem.Styles>
|
||||
<Style Selector="Viewbox#PART_IconPresenter">
|
||||
<Setter Property="MaxHeight" Value="36" />
|
||||
<Setter Property="MinHeight" Value="36" />
|
||||
<Setter Property="MaxWidth" Value="36" />
|
||||
<Setter Property="MinWidth" Value="36" />
|
||||
</Style>
|
||||
<Style Selector="ContentPresenter#PART_HeaderPresenter">
|
||||
<Setter Property="Padding" Value="-10,0,0,0" />
|
||||
</Style>
|
||||
</MenuItem.Styles>
|
||||
</MenuItem>
|
||||
<Separator/>
|
||||
<MenuItem
|
||||
Name="ChangeLanguageMenuItem"
|
||||
Padding="0"
|
||||
Header="{ext:Locale MenuBarOptionsChangeLanguage}"
|
||||
Icon="{ext:Icon fa-solid fa-language}">
|
||||
<MenuItem.Styles>
|
||||
<Style Selector="Viewbox#PART_IconPresenter">
|
||||
<Setter Property="MaxHeight" Value="36" />
|
||||
<Setter Property="MinHeight" Value="36" />
|
||||
<Setter Property="MaxWidth" Value="36" />
|
||||
<Setter Property="MinWidth" Value="36" />
|
||||
</Style>
|
||||
<Style Selector="ContentPresenter#PART_HeaderPresenter">
|
||||
<Setter Property="Padding" Value="-10,0,0,0" />
|
||||
</Style>
|
||||
</MenuItem.Styles>
|
||||
Icon="{ext:Icon fa-solid fa-language}"
|
||||
Classes="withCheckbox">
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
Name="ToggleFileTypesMenuItem"
|
||||
@@ -171,18 +144,8 @@
|
||||
Padding="0"
|
||||
Header="{ext:Locale MenuBarOptionsSettings}"
|
||||
Icon="{ext:Icon fa-solid fa-gear}"
|
||||
ToolTip.Tip="{ext:Locale OpenSettingsTooltip}">
|
||||
<MenuItem.Styles>
|
||||
<Style Selector="Viewbox#PART_IconPresenter">
|
||||
<Setter Property="MaxHeight" Value="36" />
|
||||
<Setter Property="MinHeight" Value="36" />
|
||||
<Setter Property="MaxWidth" Value="36" />
|
||||
<Setter Property="MinWidth" Value="36" />
|
||||
</Style>
|
||||
<Style Selector="ContentPresenter#PART_HeaderPresenter">
|
||||
<Setter Property="Padding" Value="-10,0,0,0" />
|
||||
</Style>
|
||||
</MenuItem.Styles>
|
||||
ToolTip.Tip="{ext:Locale OpenSettingsTooltip}"
|
||||
Classes="withCheckbox">
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
Command="{Binding ManageProfiles}"
|
||||
@@ -190,25 +153,15 @@
|
||||
Header="{ext:Locale MenuBarOptionsManageUserProfiles}"
|
||||
Icon="{ext:Icon mdi-account}"
|
||||
IsEnabled="{Binding EnableNonGameRunningControls}"
|
||||
ToolTip.Tip="{ext:Locale OpenProfileManagerTooltip}">
|
||||
<MenuItem.Styles>
|
||||
<Style Selector="Viewbox#PART_IconPresenter">
|
||||
<Setter Property="MaxHeight" Value="36" />
|
||||
<Setter Property="MinHeight" Value="36" />
|
||||
<Setter Property="MaxWidth" Value="36" />
|
||||
<Setter Property="MinWidth" Value="36" />
|
||||
</Style>
|
||||
<Style Selector="ContentPresenter#PART_HeaderPresenter">
|
||||
<Setter Property="Padding" Value="-10,0,0,0" />
|
||||
</Style>
|
||||
</MenuItem.Styles>
|
||||
ToolTip.Tip="{ext:Locale OpenProfileManagerTooltip}"
|
||||
Classes="withCheckbox">
|
||||
</MenuItem>
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
Name="ActionsMenuItem"
|
||||
VerticalAlignment="Center"
|
||||
Header="{ext:Locale MenuBarActions}"
|
||||
IsEnabled="{Binding IsGameRunning}">
|
||||
IsVisible="{Binding !EnableNonGameRunningControls}">
|
||||
<MenuItem
|
||||
Name="PauseEmulationMenuItem"
|
||||
Header="{ext:Locale MenuBarOptionsPauseEmulation}"
|
||||
@@ -265,21 +218,21 @@
|
||||
Icon="{ext:Icon fa-solid fa-code}"
|
||||
IsEnabled="{Binding IsGameRunning}" />
|
||||
</MenuItem>
|
||||
<MenuItem VerticalAlignment="Center" Header="{ext:Locale MenuBarTools}">
|
||||
<MenuItem Header="{ext:Locale MenuBarToolsInstallKeys}" Icon="{ext:Icon fa-solid fa-key}" IsEnabled="{Binding EnableNonGameRunningControls}">
|
||||
<MenuItem Command="{Binding InstallKeysFromFile}" Header="{ext:Locale MenuBarFileToolsInstallKeysFromFile}" Icon="{ext:Icon mdi-file-cog}" />
|
||||
<MenuItem Command="{Binding InstallKeysFromFolder}" Header="{ext:Locale MenuBarFileToolsInstallKeysFromFolder}" Icon="{ext:Icon mdi-folder-cog}" />
|
||||
<MenuItem VerticalAlignment="Center" Header="{ext:Locale MenuBarActions}" IsVisible="{Binding EnableNonGameRunningControls}">
|
||||
<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 InstallKeysFromFolder}" Header="{ext:Locale MenuBarFileActionsInstallKeysFromFolder}" Icon="{ext:Icon mdi-folder-cog}" />
|
||||
</MenuItem>
|
||||
<MenuItem Header="{ext:Locale MenuBarToolsInstallFirmware}" Icon="{ext:Icon fa-solid fa-download}" IsEnabled="{Binding EnableNonGameRunningControls}">
|
||||
<MenuItem Command="{Binding InstallFirmwareFromFile}" Header="{ext:Locale MenuBarFileToolsInstallFirmwareFromFile}" Icon="{ext:Icon mdi-file-cog}" />
|
||||
<MenuItem Command="{Binding InstallFirmwareFromFolder}" Header="{ext:Locale MenuBarFileToolsInstallFirmwareFromDirectory}" Icon="{ext:Icon mdi-folder-cog}" />
|
||||
<MenuItem Header="{ext:Locale MenuBarActionsInstallFirmware}" Icon="{ext:Icon fa-solid fa-download}">
|
||||
<MenuItem Command="{Binding InstallFirmwareFromFile}" Header="{ext:Locale MenuBarActionsInstallFirmwareFromFile}" Icon="{ext:Icon mdi-file-cog}" />
|
||||
<MenuItem Command="{Binding InstallFirmwareFromFolder}" Header="{ext:Locale MenuBarActionsInstallFirmwareFromDirectory}" Icon="{ext:Icon mdi-folder-cog}" />
|
||||
</MenuItem>
|
||||
<MenuItem Header="{ext:Locale MenuBarToolsManageFileTypes}" IsVisible="{Binding ManageFileTypesVisible}">
|
||||
<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 Header="{ext:Locale MenuBarActionsManageFileTypes}" IsVisible="{Binding ManageFileTypesVisible}">
|
||||
<MenuItem Name="InstallFileTypesMenuItem" Header="{ext:Locale MenuBarActionsInstallFileTypes}" IsEnabled="{Binding AreMimeTypesRegistered, Converter={x:Static BoolConverters.Not}}" />
|
||||
<MenuItem Name="UninstallFileTypesMenuItem" Header="{ext:Locale MenuBarActionsUninstallFileTypes}" IsEnabled="{Binding AreMimeTypesRegistered}" />
|
||||
</MenuItem>
|
||||
<Separator />
|
||||
<MenuItem Name="XciTrimmerMenuItem" Header="{ext:Locale MenuBarToolsXCITrimmer}" IsEnabled="{Binding EnableNonGameRunningControls}" Icon="{ext:Icon fa-solid fa-scissors}" />
|
||||
<MenuItem Name="XciTrimmerMenuItem" Header="{ext:Locale MenuBarActionsXCITrimmer}" Icon="{ext:Icon fa-solid fa-scissors}" />
|
||||
</MenuItem>
|
||||
<MenuItem VerticalAlignment="Center" Header="{ext:Locale MenuBarView}">
|
||||
<MenuItem VerticalAlignment="Center" Header="{ext:Locale MenuBarViewWindow}">
|
||||
@@ -311,19 +264,19 @@
|
||||
Name="FaqMenuItem"
|
||||
Header="{ext:Locale MenuBarHelpFaq}"
|
||||
Icon="{ext:Icon fa-github}"
|
||||
CommandParameter="https://github.com/GreemDev/Ryujinx/wiki/FAQ-and-Troubleshooting"
|
||||
CommandParameter="https://github.com/Ryubing/Ryujinx/wiki/FAQ-and-Troubleshooting"
|
||||
ToolTip.Tip="{ext:Locale MenuBarHelpFaqTooltip}" />
|
||||
<MenuItem
|
||||
Name="SetupGuideMenuItem"
|
||||
Header="{ext:Locale MenuBarHelpSetup}"
|
||||
Icon="{ext:Icon fa-github}"
|
||||
CommandParameter="https://github.com/GreemDev/Ryujinx/wiki/Ryujinx-Setup-&-Configuration-Guide"
|
||||
CommandParameter="https://github.com/Ryubing/Ryujinx/wiki/Ryujinx-Setup-&-Configuration-Guide"
|
||||
ToolTip.Tip="{ext:Locale MenuBarHelpSetupTooltip}" />
|
||||
<MenuItem
|
||||
Name="LdnGuideMenuItem"
|
||||
Header="{ext:Locale MenuBarHelpMultiplayer}"
|
||||
Icon="{ext:Icon fa-github}"
|
||||
CommandParameter="https://github.com/GreemDev/Ryujinx/wiki/Multiplayer%E2%80%90(LDN%E2%80%90Local%E2%80%90Wireless)%E2%80%90Guide"
|
||||
CommandParameter="https://github.com/Ryubing/Ryujinx/wiki/Multiplayer%E2%80%90(LDN%E2%80%90Local%E2%80%90Wireless)%E2%80%90Guide"
|
||||
ToolTip.Tip="{ext:Locale MenuBarHelpMultiplayerTooltip}" />
|
||||
</MenuItem>
|
||||
</MenuItem>
|
||||
|
||||
@@ -37,26 +37,20 @@ 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);
|
||||
MiiAppletMenuItem.Command = Commands.Create(OpenMiiApplet);
|
||||
CloseRyujinxMenuItem.Command = Commands.Create(CloseWindow);
|
||||
OpenSettingsMenuItem.Command = Commands.Create(OpenSettings);
|
||||
PauseEmulationMenuItem.Command = Commands.Create(() => ViewModel.AppHost?.Pause());
|
||||
ResumeEmulationMenuItem.Command = Commands.Create(() => ViewModel.AppHost?.Resume());
|
||||
StopEmulationMenuItem.Command = Commands.Create(() => ViewModel.AppHost?.ShowExitPrompt().OrCompleted());
|
||||
CheatManagerMenuItem.Command = Commands.CreateSilentFail(OpenCheatManagerForCurrentApp);
|
||||
InstallFileTypesMenuItem.Command = Commands.Create(InstallFileTypes);
|
||||
UninstallFileTypesMenuItem.Command = Commands.Create(UninstallFileTypes);
|
||||
XciTrimmerMenuItem.Command = Commands.Create(XCITrimmerWindow.Show);
|
||||
AboutWindowMenuItem.Command = Commands.Create(AboutWindow.Show);
|
||||
CompatibilityListMenuItem.Command = Commands.Create(CompatibilityList.Show);
|
||||
|
||||
UpdateMenuItem.Command = new AsyncRelayCommand(async () =>
|
||||
UpdateMenuItem.Command = Commands.Create(async () =>
|
||||
{
|
||||
if (Updater.CanUpdate(true))
|
||||
await Updater.BeginUpdateAsync(true);
|
||||
@@ -64,12 +58,12 @@ namespace Ryujinx.Ava.UI.Views.Main
|
||||
|
||||
FaqMenuItem.Command =
|
||||
SetupGuideMenuItem.Command =
|
||||
LdnGuideMenuItem.Command = new RelayCommand<string>(OpenHelper.OpenUrl);
|
||||
LdnGuideMenuItem.Command = Commands.Create<string>(OpenHelper.OpenUrl);
|
||||
|
||||
WindowSize720PMenuItem.Command =
|
||||
WindowSize1080PMenuItem.Command =
|
||||
WindowSize1440PMenuItem.Command =
|
||||
WindowSize2160PMenuItem.Command = new RelayCommand<string>(ChangeWindowSize);
|
||||
WindowSize2160PMenuItem.Command = Commands.Create<string>(ChangeWindowSize);
|
||||
}
|
||||
|
||||
private IEnumerable<CheckBox> GenerateToggleFileTypeItems() =>
|
||||
|
||||
@@ -105,6 +105,12 @@
|
||||
GroupName="Sort"
|
||||
IsChecked="{Binding IsSortedByTitle, Mode=OneTime}"
|
||||
Tag="Title" />
|
||||
<RadioButton
|
||||
Checked="Sort_Checked"
|
||||
Content="{ext:Locale DlcManagerTableHeadingTitleIdLabel}"
|
||||
GroupName="Sort"
|
||||
IsChecked="{Binding IsSortedByTitleId, Mode=OneTime}"
|
||||
Tag="TitleId" />
|
||||
<RadioButton
|
||||
Checked="Sort_Checked"
|
||||
Content="{ext:Locale GameListHeaderDeveloper}"
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
<TextBlock
|
||||
Foreground="{DynamicResource SecondaryTextColor}"
|
||||
TextDecorations="Underline"
|
||||
Text="Game-specific hacks & tricks to alleviate performance issues or crashing. Will cause issues." />
|
||||
Text="Highly specific hacks & tricks to alleviate performance issues, crashing, or freezing. Will cause issues." />
|
||||
<StackPanel
|
||||
Margin="0,10,0,0"
|
||||
Orientation="Horizontal"
|
||||
|
||||
@@ -114,8 +114,7 @@
|
||||
Grid.Column="1"
|
||||
MinWidth="90"
|
||||
Margin="10,0,0,0"
|
||||
ToolTip.Tip="{ext:Locale AddGameDirTooltip}"
|
||||
Click="AddGameDirButton_OnClick">
|
||||
ToolTip.Tip="{ext:Locale AddGameDirTooltip}">
|
||||
<TextBlock HorizontalAlignment="Center"
|
||||
Text="{ext:Locale SettingsTabGeneralAdd}" />
|
||||
</Button>
|
||||
@@ -168,8 +167,7 @@
|
||||
Grid.Column="1"
|
||||
MinWidth="90"
|
||||
Margin="10,0,0,0"
|
||||
ToolTip.Tip="{ext:Locale AddAutoloadDirTooltip}"
|
||||
Click="AddAutoloadDirButton_OnClick">
|
||||
ToolTip.Tip="{ext:Locale AddAutoloadDirTooltip}">
|
||||
<TextBlock HorizontalAlignment="Center"
|
||||
Text="{ext:Locale SettingsTabGeneralAdd}" />
|
||||
</Button>
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
using Avalonia.Collections;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Platform.Storage;
|
||||
using Avalonia.VisualTree;
|
||||
using Gommon;
|
||||
using Ryujinx.Ava.UI.Helpers;
|
||||
using Ryujinx.Ava.UI.ViewModels;
|
||||
using Ryujinx.Ava.Utilities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Ryujinx.Ava.UI.Views.Settings
|
||||
{
|
||||
@@ -18,31 +23,39 @@ namespace Ryujinx.Ava.UI.Views.Settings
|
||||
{
|
||||
InitializeComponent();
|
||||
ShowTitleBarBox.IsVisible = OperatingSystem.IsWindows();
|
||||
AddGameDirButton.Command =
|
||||
Commands.Create(() => AddDirButton(GameDirPathBox, ViewModel.GameDirectories, true));
|
||||
AddAutoloadDirButton.Command =
|
||||
Commands.Create(() => AddDirButton(AutoloadDirPathBox, ViewModel.AutoloadDirectories, false));
|
||||
}
|
||||
|
||||
private async void AddGameDirButton_OnClick(object sender, RoutedEventArgs e)
|
||||
private async Task AddDirButton(TextBox addDirBox, AvaloniaList<string> directories, bool isGameList)
|
||||
{
|
||||
string path = GameDirPathBox.Text;
|
||||
string path = addDirBox.Text;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(path) && Directory.Exists(path) && !ViewModel.GameDirectories.Contains(path))
|
||||
if (!string.IsNullOrWhiteSpace(path) && Directory.Exists(path) && !directories.Contains(path))
|
||||
{
|
||||
ViewModel.GameDirectories.Add(path);
|
||||
ViewModel.GameDirectoryChanged = true;
|
||||
directories.Add(path);
|
||||
|
||||
addDirBox.Clear();
|
||||
|
||||
if (isGameList)
|
||||
ViewModel.GameDirectoryChanged = true;
|
||||
else
|
||||
ViewModel.AutoloadDirectoryChanged = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.GetVisualRoot() is Window window)
|
||||
{
|
||||
var result = await window.StorageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions
|
||||
{
|
||||
AllowMultiple = false,
|
||||
});
|
||||
Optional<IStorageFolder> folder = await RyujinxApp.MainWindow.ViewModel.StorageProvider.OpenSingleFolderPickerAsync();
|
||||
|
||||
if (result.Count > 0)
|
||||
{
|
||||
ViewModel.GameDirectories.Add(result[0].Path.LocalPath);
|
||||
if (folder.HasValue)
|
||||
{
|
||||
directories.Add(folder.Value.Path.LocalPath);
|
||||
|
||||
if (isGameList)
|
||||
ViewModel.GameDirectoryChanged = true;
|
||||
}
|
||||
else
|
||||
ViewModel.AutoloadDirectoryChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -63,33 +76,6 @@ namespace Ryujinx.Ava.UI.Views.Settings
|
||||
}
|
||||
}
|
||||
|
||||
private async void AddAutoloadDirButton_OnClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
string path = AutoloadDirPathBox.Text;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(path) && Directory.Exists(path) && !ViewModel.AutoloadDirectories.Contains(path))
|
||||
{
|
||||
ViewModel.AutoloadDirectories.Add(path);
|
||||
ViewModel.AutoloadDirectoryChanged = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (this.GetVisualRoot() is Window window)
|
||||
{
|
||||
var result = await window.StorageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions
|
||||
{
|
||||
AllowMultiple = false,
|
||||
});
|
||||
|
||||
if (result.Count > 0)
|
||||
{
|
||||
ViewModel.AutoloadDirectories.Add(result[0].Path.LocalPath);
|
||||
ViewModel.AutoloadDirectoryChanged = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void RemoveAutoloadDirButton_OnClick(object sender, RoutedEventArgs e)
|
||||
{
|
||||
int oldIndex = AutoloadDirsList.SelectedIndex;
|
||||
|
||||
@@ -182,7 +182,7 @@
|
||||
HorizontalAlignment="Left"
|
||||
Background="Transparent"
|
||||
Click="Button_OnClick"
|
||||
Tag="https://github.com/GreemDev/Ryujinx/graphs/contributors?type=a">
|
||||
Tag="https://github.com/Ryubing/Ryujinx/graphs/contributors?type=a">
|
||||
<TextBlock
|
||||
FontSize="10"
|
||||
Text="{ext:Locale AboutRyujinxContributorsButtonHeader}"
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
|
||||
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||
xmlns:pi="using:Projektanker.Icons.Avalonia"
|
||||
xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers"
|
||||
xmlns:models="clr-namespace:Ryujinx.Ava.Common.Models"
|
||||
Width="500"
|
||||
@@ -15,9 +14,6 @@
|
||||
mc:Ignorable="d"
|
||||
x:DataType="viewModels:DownloadableContentManagerViewModel"
|
||||
Focusable="True">
|
||||
<UserControl.Resources>
|
||||
<helpers:DownloadableContentLabelConverter x:Key="DownloadableContentLabel" />
|
||||
</UserControl.Resources>
|
||||
<Grid RowDefinitions="Auto,Auto,*,Auto">
|
||||
<StackPanel
|
||||
Grid.Row="0"
|
||||
@@ -102,7 +98,7 @@
|
||||
TextWrapping="Wrap"
|
||||
TextTrimming="CharacterEllipsis">
|
||||
<TextBlock.Text>
|
||||
<MultiBinding Converter="{StaticResource DownloadableContentLabel}">
|
||||
<MultiBinding Converter="{x:Static helpers:DownloadableContentLabelConverter.Instance}">
|
||||
<Binding Path="FileName" />
|
||||
<Binding Path="IsBundled" />
|
||||
</MultiBinding>
|
||||
@@ -113,22 +109,13 @@
|
||||
Margin="10 0"
|
||||
HorizontalAlignment="Left"
|
||||
VerticalAlignment="Center"
|
||||
Text="{Binding TitleId}" />
|
||||
Text="{Binding TitleIdStr}" />
|
||||
</Grid>
|
||||
<StackPanel
|
||||
Grid.Column="1"
|
||||
Spacing="10"
|
||||
Orientation="Horizontal"
|
||||
HorizontalAlignment="Right">
|
||||
<Button
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Right"
|
||||
Padding="10"
|
||||
MinWidth="0"
|
||||
MinHeight="0"
|
||||
Click="DlcItem_DumpRomfs">
|
||||
<ui:SymbolIcon Symbol="MoveToFolder"/>
|
||||
</Button>
|
||||
<Button
|
||||
VerticalAlignment="Center"
|
||||
HorizontalAlignment="Right"
|
||||
|
||||
@@ -95,18 +95,5 @@ namespace Ryujinx.Ava.UI.Windows
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async void DlcItem_DumpRomfs(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender is not Button { DataContext: DownloadableContentModel dlc }) return;
|
||||
if (RyujinxApp.MainWindow.ViewModel is not { } viewModel)
|
||||
return;
|
||||
|
||||
await ApplicationHelper.ExtractAoc(
|
||||
viewModel.StorageProvider,
|
||||
NcaSectionType.Data,
|
||||
dlc.ContainerPath,
|
||||
dlc.FileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -691,6 +691,7 @@ namespace Ryujinx.Ava.UI.Windows
|
||||
ApplicationLibrary.LoadApplications(ConfigurationState.Instance.UI.GameDirs);
|
||||
|
||||
var autoloadDirs = ConfigurationState.Instance.UI.AutoloadDirs.Value;
|
||||
autoloadDirs.ForEach(dir => Logger.Info?.Print(LogClass.Application, $"Auto loading DLC & updates from: {dir}"));
|
||||
if (autoloadDirs.Count > 0)
|
||||
{
|
||||
var updatesLoaded = ApplicationLibrary.AutoLoadTitleUpdates(autoloadDirs, out int updatesRemoved);
|
||||
@@ -735,9 +736,7 @@ namespace Ryujinx.Ava.UI.Windows
|
||||
});
|
||||
}
|
||||
|
||||
private static bool _intelMacWarningShown = !(OperatingSystem.IsMacOS() &&
|
||||
(RuntimeInformation.OSArchitecture == Architecture.X64 ||
|
||||
RuntimeInformation.OSArchitecture == Architecture.X86));
|
||||
private static bool _intelMacWarningShown = !RunningPlatform.IsIntelMac;
|
||||
|
||||
public static async Task ShowIntelMacWarningAsync()
|
||||
{
|
||||
|
||||
@@ -28,15 +28,15 @@ namespace Ryujinx.Ava.UI.Windows
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public static async Task Show(MainWindowViewModel mainWindowViewModel)
|
||||
public static async Task Show()
|
||||
{
|
||||
ContentDialog contentDialog = new()
|
||||
{
|
||||
PrimaryButtonText = string.Empty,
|
||||
SecondaryButtonText = string.Empty,
|
||||
CloseButtonText = string.Empty,
|
||||
Content = new XCITrimmerWindow(mainWindowViewModel),
|
||||
Title = string.Format(LocaleManager.Instance[LocaleKeys.XCITrimmerWindowTitle]),
|
||||
Content = new XCITrimmerWindow(RyujinxApp.MainWindow.ViewModel),
|
||||
Title = LocaleManager.Instance[LocaleKeys.XCITrimmerWindowTitle]
|
||||
};
|
||||
|
||||
Style bottomBorder = new(x => x.OfType<Grid>().Name("DialogSpace").Child().OfType<Border>());
|
||||
|
||||
@@ -87,6 +87,8 @@ namespace Ryujinx.Ava
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Logger.Info?.Print(LogClass.Application, "Checking for updates.");
|
||||
|
||||
// Get latest version number from GitHub API
|
||||
try
|
||||
@@ -140,6 +142,8 @@ namespace Ryujinx.Ava
|
||||
OpenHelper.OpenUrl(ReleaseInformation.GetChangelogForVersion(currentVersion));
|
||||
}
|
||||
}
|
||||
|
||||
Logger.Info?.Print(LogClass.Application, "Up to date.");
|
||||
|
||||
_running = false;
|
||||
|
||||
@@ -214,6 +218,8 @@ namespace Ryujinx.Ava
|
||||
? $"Canary {currentVersion} -> Canary {newVersion}"
|
||||
: $"{currentVersion} -> {newVersion}";
|
||||
|
||||
Logger.Info?.Print(LogClass.Application, $"Version found: {newVersionString}");
|
||||
|
||||
RequestUserToUpdate:
|
||||
// Show a message asking the user if they want to update
|
||||
UserResult shouldUpdate = await ContentDialogHelper.CreateUpdaterChoiceDialog(
|
||||
|
||||
@@ -840,7 +840,6 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
|
||||
try
|
||||
{
|
||||
// Remove any downloadable content which can no longer be located on disk
|
||||
Logger.Notice.Print(LogClass.Application, $"Removing non-existing Title DLCs");
|
||||
var dlcToRemove = _downloadableContents.Items
|
||||
.Where(dlc => !File.Exists(dlc.Dlc.ContainerPath))
|
||||
.ToList();
|
||||
@@ -852,8 +851,6 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
|
||||
|
||||
foreach (string appDir in appDirs)
|
||||
{
|
||||
Logger.Notice.Print(LogClass.Application, $"Auto loading DLC from: {appDir}");
|
||||
|
||||
if (_cancellationToken.Token.IsCancellationRequested)
|
||||
{
|
||||
return newDlcLoaded;
|
||||
@@ -956,7 +953,6 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
|
||||
var titleIdsToRefresh = new HashSet<ulong>();
|
||||
|
||||
// Remove any updates which can no longer be located on disk
|
||||
Logger.Notice.Print(LogClass.Application, $"Removing non-existing Title Updates");
|
||||
var updatesToRemove = _titleUpdates.Items
|
||||
.Where(it => !File.Exists(it.TitleUpdate.Path))
|
||||
.ToList();
|
||||
@@ -971,8 +967,6 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
|
||||
|
||||
foreach (string appDir in appDirs)
|
||||
{
|
||||
Logger.Notice.Print(LogClass.Application, $"Auto loading updates from: {appDir}");
|
||||
|
||||
if (_cancellationToken.Token.IsCancellationRequested)
|
||||
{
|
||||
return numUpdatesLoaded;
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace Ryujinx.Ava.Utilities.Configuration
|
||||
/// <summary>
|
||||
/// The current version of the file format
|
||||
/// </summary>
|
||||
public const int CurrentVersion = 59;
|
||||
public const int CurrentVersion = 61;
|
||||
|
||||
/// <summary>
|
||||
/// Version of the configuration file format
|
||||
@@ -351,6 +351,11 @@ namespace Ryujinx.Ava.Utilities.Configuration
|
||||
/// </summary>
|
||||
public bool StartFullscreen { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Start games with UI hidden
|
||||
/// </summary>
|
||||
public bool StartNoUI { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Show console window
|
||||
/// </summary>
|
||||
|
||||
@@ -45,7 +45,6 @@ namespace Ryujinx.Ava.Utilities.Configuration
|
||||
EnableDiscordIntegration.Value = cff.EnableDiscordIntegration;
|
||||
CheckUpdatesOnStart.Value = cff.CheckUpdatesOnStart;
|
||||
ShowConfirmExit.Value = cff.ShowConfirmExit;
|
||||
IgnoreApplet.Value = cff.IgnoreApplet;
|
||||
RememberWindowState.Value = cff.RememberWindowState;
|
||||
ShowTitleBar.Value = cff.ShowTitleBar;
|
||||
EnableHardwareAcceleration.Value = cff.EnableHardwareAcceleration;
|
||||
@@ -97,6 +96,7 @@ namespace Ryujinx.Ava.Utilities.Configuration
|
||||
System.MemoryManagerMode.Value = cff.MemoryManagerMode;
|
||||
System.DramSize.Value = cff.DramSize;
|
||||
System.IgnoreMissingServices.Value = cff.IgnoreMissingServices;
|
||||
System.IgnoreApplet.Value = cff.IgnoreApplet;
|
||||
System.UseHypervisor.Value = cff.UseHypervisor;
|
||||
|
||||
UI.GuiColumns.FavColumn.Value = cff.GuiColumns.FavColumn;
|
||||
@@ -127,6 +127,7 @@ namespace Ryujinx.Ava.Utilities.Configuration
|
||||
UI.GridSize.Value = cff.GridSize;
|
||||
UI.ApplicationSort.Value = cff.ApplicationSort;
|
||||
UI.StartFullscreen.Value = cff.StartFullscreen;
|
||||
UI.StartNoUI.Value = cff.StartNoUI;
|
||||
UI.ShowConsole.Value = cff.ShowConsole;
|
||||
UI.WindowStartup.WindowSizeWidth.Value = cff.WindowStartup.WindowSizeWidth;
|
||||
UI.WindowStartup.WindowSizeHeight.Value = cff.WindowStartup.WindowSizeHeight;
|
||||
@@ -262,15 +263,12 @@ namespace Ryujinx.Ava.Utilities.Configuration
|
||||
}),
|
||||
(30, static cff =>
|
||||
{
|
||||
foreach (InputConfig config in cff.InputConfig)
|
||||
foreach (StandardControllerInputConfig config in cff.InputConfig.OfType<StandardControllerInputConfig>())
|
||||
{
|
||||
if (config is StandardControllerInputConfig controllerConfig)
|
||||
config.Rumble = new RumbleConfigController
|
||||
{
|
||||
controllerConfig.Rumble = new RumbleConfigController
|
||||
{
|
||||
EnableRumble = false, StrongRumble = 1f, WeakRumble = 1f,
|
||||
};
|
||||
}
|
||||
EnableRumble = false, StrongRumble = 1f, WeakRumble = 1f,
|
||||
};
|
||||
}
|
||||
}),
|
||||
(31, static cff => cff.BackendThreading = BackendThreading.Auto),
|
||||
@@ -414,6 +412,18 @@ namespace Ryujinx.Ava.Utilities.Configuration
|
||||
// This was accidentally enabled by default when it was PRed. That is not what we want,
|
||||
// so as a compromise users who want to use it will simply need to re-enable it once after updating.
|
||||
cff.IgnoreApplet = false;
|
||||
}),
|
||||
(60, static cff => cff.StartNoUI = false),
|
||||
(61, static cff =>
|
||||
{
|
||||
foreach (StandardControllerInputConfig config in cff.InputConfig.OfType<StandardControllerInputConfig>())
|
||||
{
|
||||
config.Led = new LedConfigController
|
||||
{
|
||||
EnableLed = false,
|
||||
LedColor = 328189
|
||||
};
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
@@ -152,6 +152,11 @@ namespace Ryujinx.Ava.Utilities.Configuration
|
||||
/// </summary>
|
||||
public ReactiveObject<bool> StartFullscreen { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Start games with UI hidden
|
||||
/// </summary>
|
||||
public ReactiveObject<bool> StartNoUI { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Hide / Show Console Window
|
||||
/// </summary>
|
||||
@@ -192,6 +197,7 @@ namespace Ryujinx.Ava.Utilities.Configuration
|
||||
WindowStartup = new WindowStartupSettings();
|
||||
BaseStyle = new ReactiveObject<string>();
|
||||
StartFullscreen = new ReactiveObject<bool>();
|
||||
StartNoUI = new ReactiveObject<bool>();
|
||||
GameListViewMode = new ReactiveObject<int>();
|
||||
ShowNames = new ReactiveObject<bool>();
|
||||
GridSize = new ReactiveObject<int>();
|
||||
@@ -360,6 +366,11 @@ namespace Ryujinx.Ava.Utilities.Configuration
|
||||
/// Enable or disable ignoring missing services
|
||||
/// </summary>
|
||||
public ReactiveObject<bool> IgnoreMissingServices { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Ignore Controller Applet
|
||||
/// </summary>
|
||||
public ReactiveObject<bool> IgnoreApplet { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Uses Hypervisor over JIT if available
|
||||
@@ -398,6 +409,8 @@ namespace Ryujinx.Ava.Utilities.Configuration
|
||||
DramSize.LogChangesToValue(nameof(DramSize));
|
||||
IgnoreMissingServices = new ReactiveObject<bool>();
|
||||
IgnoreMissingServices.LogChangesToValue(nameof(IgnoreMissingServices));
|
||||
IgnoreApplet = new ReactiveObject<bool>();
|
||||
IgnoreApplet.LogChangesToValue(nameof(IgnoreApplet));
|
||||
AudioVolume = new ReactiveObject<float>();
|
||||
AudioVolume.LogChangesToValue(nameof(AudioVolume));
|
||||
UseHypervisor = new ReactiveObject<bool>();
|
||||
@@ -739,11 +752,6 @@ namespace Ryujinx.Ava.Utilities.Configuration
|
||||
/// </summary>
|
||||
public ReactiveObject<bool> ShowConfirmExit { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Ignore Applet
|
||||
/// </summary>
|
||||
public ReactiveObject<bool> IgnoreApplet { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Enables or disables save window size, position and state on close.
|
||||
/// </summary>
|
||||
@@ -776,8 +784,6 @@ namespace Ryujinx.Ava.Utilities.Configuration
|
||||
EnableDiscordIntegration = new ReactiveObject<bool>();
|
||||
CheckUpdatesOnStart = new ReactiveObject<bool>();
|
||||
ShowConfirmExit = new ReactiveObject<bool>();
|
||||
IgnoreApplet = new ReactiveObject<bool>();
|
||||
IgnoreApplet.LogChangesToValue(nameof(IgnoreApplet));
|
||||
RememberWindowState = new ReactiveObject<bool>();
|
||||
ShowTitleBar = new ReactiveObject<bool>();
|
||||
EnableHardwareAcceleration = new ReactiveObject<bool>();
|
||||
|
||||
@@ -56,7 +56,6 @@ namespace Ryujinx.Ava.Utilities.Configuration
|
||||
EnableDiscordIntegration = EnableDiscordIntegration,
|
||||
CheckUpdatesOnStart = CheckUpdatesOnStart,
|
||||
ShowConfirmExit = ShowConfirmExit,
|
||||
IgnoreApplet = IgnoreApplet,
|
||||
RememberWindowState = RememberWindowState,
|
||||
ShowTitleBar = ShowTitleBar,
|
||||
EnableHardwareAcceleration = EnableHardwareAcceleration,
|
||||
@@ -78,6 +77,7 @@ namespace Ryujinx.Ava.Utilities.Configuration
|
||||
MemoryManagerMode = System.MemoryManagerMode,
|
||||
DramSize = System.DramSize,
|
||||
IgnoreMissingServices = System.IgnoreMissingServices,
|
||||
IgnoreApplet = System.IgnoreApplet,
|
||||
UseHypervisor = System.UseHypervisor,
|
||||
GuiColumns = new GuiColumns
|
||||
{
|
||||
@@ -125,6 +125,7 @@ namespace Ryujinx.Ava.Utilities.Configuration
|
||||
ApplicationSort = UI.ApplicationSort,
|
||||
IsAscendingOrder = UI.IsAscendingOrder,
|
||||
StartFullscreen = UI.StartFullscreen,
|
||||
StartNoUI = UI.StartNoUI,
|
||||
ShowConsole = UI.ShowConsole,
|
||||
EnableKeyboard = Hid.EnableKeyboard,
|
||||
EnableMouse = Hid.EnableMouse,
|
||||
@@ -175,7 +176,6 @@ namespace Ryujinx.Ava.Utilities.Configuration
|
||||
EnableDiscordIntegration.Value = true;
|
||||
CheckUpdatesOnStart.Value = true;
|
||||
ShowConfirmExit.Value = true;
|
||||
IgnoreApplet.Value = false;
|
||||
RememberWindowState.Value = true;
|
||||
ShowTitleBar.Value = !OperatingSystem.IsWindows();
|
||||
EnableHardwareAcceleration.Value = true;
|
||||
@@ -199,6 +199,7 @@ namespace Ryujinx.Ava.Utilities.Configuration
|
||||
System.MemoryManagerMode.Value = MemoryManagerMode.HostMappedUnsafe;
|
||||
System.DramSize.Value = MemoryConfiguration.MemoryConfiguration4GiB;
|
||||
System.IgnoreMissingServices.Value = false;
|
||||
System.IgnoreApplet.Value = false;
|
||||
System.UseHypervisor.Value = true;
|
||||
Multiplayer.LanInterfaceId.Value = "0";
|
||||
Multiplayer.Mode.Value = MultiplayerMode.Disabled;
|
||||
@@ -233,6 +234,7 @@ namespace Ryujinx.Ava.Utilities.Configuration
|
||||
UI.ApplicationSort.Value = 0;
|
||||
UI.IsAscendingOrder.Value = true;
|
||||
UI.StartFullscreen.Value = false;
|
||||
UI.StartNoUI.Value = false;
|
||||
UI.ShowConsole.Value = true;
|
||||
UI.WindowStartup.WindowSizeWidth.Value = 1280;
|
||||
UI.WindowStartup.WindowSizeHeight.Value = 760;
|
||||
|
||||
47
src/Ryujinx/Utilities/StorageProviderExtensions.cs
Normal file
47
src/Ryujinx/Utilities/StorageProviderExtensions.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using Avalonia.Platform.Storage;
|
||||
using Gommon;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Ryujinx.Ava.Utilities
|
||||
{
|
||||
public static class StorageProviderExtensions
|
||||
{
|
||||
public static async Task<Optional<IStorageFolder>> OpenSingleFolderPickerAsync(this IStorageProvider storageProvider, FolderPickerOpenOptions openOptions = null) =>
|
||||
await storageProvider.OpenFolderPickerAsync(FixOpenOptions(openOptions, false))
|
||||
.Then(folders => folders.FindFirst());
|
||||
|
||||
public static async Task<Optional<IStorageFile>> OpenSingleFilePickerAsync(this IStorageProvider storageProvider, FilePickerOpenOptions openOptions = null) =>
|
||||
await storageProvider.OpenFilePickerAsync(FixOpenOptions(openOptions, false))
|
||||
.Then(files => files.FindFirst());
|
||||
|
||||
public static async Task<Optional<IReadOnlyList<IStorageFolder>>> OpenMultiFolderPickerAsync(this IStorageProvider storageProvider, FolderPickerOpenOptions openOptions = null) =>
|
||||
await storageProvider.OpenFolderPickerAsync(FixOpenOptions(openOptions, true))
|
||||
.Then(folders => folders.Count > 0 ? Optional.Of(folders) : default);
|
||||
|
||||
public static async Task<Optional<IReadOnlyList<IStorageFile>>> OpenMultiFilePickerAsync(this IStorageProvider storageProvider, FilePickerOpenOptions openOptions = null) =>
|
||||
await storageProvider.OpenFilePickerAsync(FixOpenOptions(openOptions, true))
|
||||
.Then(files => files.Count > 0 ? Optional.Of(files) : default);
|
||||
|
||||
private static FilePickerOpenOptions FixOpenOptions(this FilePickerOpenOptions openOptions, bool allowMultiple)
|
||||
{
|
||||
if (openOptions is null)
|
||||
return new FilePickerOpenOptions { AllowMultiple = allowMultiple };
|
||||
|
||||
openOptions.AllowMultiple = allowMultiple;
|
||||
|
||||
return openOptions;
|
||||
}
|
||||
|
||||
private static FolderPickerOpenOptions FixOpenOptions(this FolderPickerOpenOptions openOptions, bool allowMultiple)
|
||||
{
|
||||
if (openOptions is null)
|
||||
return new FolderPickerOpenOptions { AllowMultiple = allowMultiple };
|
||||
|
||||
openOptions.AllowMultiple = allowMultiple;
|
||||
|
||||
return openOptions;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user