Compare commits

..

4 Commits

Author SHA1 Message Date
Daenorth
89ef52f179 Merge d5678659aa into a1c0c70ec2 2025-01-20 05:31:30 +01:00
Daenorth
d5678659aa Clean up
Just a quick cleanup
2025-01-20 05:29:45 +01:00
Daenorth
03f59b34d9 Delete TitleIDs.cs 2025-01-20 05:29:08 +01:00
Daenorth
d6f83bb3bd Cleanup
Cleanup, no changes
2025-01-20 05:26:12 +01:00
79 changed files with 323 additions and 1342 deletions

4
.github/labeler.yml vendored
View File

@@ -18,10 +18,6 @@ gpu:
- changed-files: - changed-files:
- any-glob-to-any-file: ['src/Ryujinx.Graphics.Vulkan/**', 'src/Spv.Generator/**'] - 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: gui:
- changed-files: - changed-files:
- any-glob-to-any-file: ['src/Ryujinx/**', 'src/Ryujinx.UI.Common/**', 'src/Ryujinx.UI.LocaleGenerator/**'] - any-glob-to-any-file: ['src/Ryujinx/**', 'src/Ryujinx.UI.Common/**', 'src/Ryujinx.UI.LocaleGenerator/**']

View File

@@ -202,7 +202,7 @@ jobs:
macos_release: macos_release:
name: Release MacOS universal name: Release MacOS universal
runs-on: ubuntu-20.04 runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4

View File

@@ -183,7 +183,7 @@ jobs:
macos_release: macos_release:
name: Release MacOS universal name: Release MacOS universal
runs-on: ubuntu-20.04 runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4

View File

@@ -42,7 +42,7 @@
<PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies" Version="5.0.3-build14" /> <PackageVersion Include="Ryujinx.Graphics.Nvdec.Dependencies" Version="5.0.3-build14" />
<PackageVersion Include="Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK" Version="1.2.0" /> <PackageVersion Include="Ryujinx.Graphics.Vulkan.Dependencies.MoltenVK" Version="1.2.0" />
<PackageVersion Include="Ryujinx.SDL2-CS" Version="2.30.0-build32" /> <PackageVersion Include="Ryujinx.SDL2-CS" Version="2.30.0-build32" />
<PackageVersion Include="Gommon" Version="2.7.1" /> <PackageVersion Include="Gommon" Version="2.7.0.2" />
<PackageVersion Include="securifybv.ShellLink" Version="0.1.0" /> <PackageVersion Include="securifybv.ShellLink" Version="0.1.0" />
<PackageVersion Include="Sep" Version="0.6.0" /> <PackageVersion Include="Sep" Version="0.6.0" />
<PackageVersion Include="shaderc.net" Version="0.1.0" /> <PackageVersion Include="shaderc.net" Version="0.1.0" />

View File

@@ -54,13 +54,12 @@ failing to meet this requirement may result in a poor gameplay experience or une
## Latest build ## Latest build
Stable builds are made every so often, based on the `master` branch, that then gets put into the releases you know and love. Stable builds are made every so often onto a separate "release" 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**. 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). 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**. 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. These canary builds are only recommended for experienced users.
@@ -110,7 +109,7 @@ If you are planning to contribute or just want to learn more about this project
- **Configuration** - **Configuration**
The emulator has settings for enabling or disabling some logging, remapping controllers, and more. 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 Ryujinx data 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 user folder which can be accessed by clicking `Open Ryujinx Folder` under the File menu in the GUI.
## License ## License

View File

@@ -1070,7 +1070,6 @@
010017B0102A8000,"Emma: Lost in Memories",nvdec,playable,2021-01-28 16:19:10 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 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 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 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 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 0100B8700BD14000,"Energy Cycle Edge",services,ingame,2021-11-30 05:02:31
@@ -2682,7 +2681,7 @@
01005EA01C0FC000,"SONIC X SHADOW GENERATIONS",crash,ingame,2025-01-07 04:20:45 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 010064F00C212000,"Soul Axiom Rebooted",nvdec;slow,ingame,2020-09-04 12:41:01
0100F2100F0B2000,"Soul Searching",,playable,2020-07-09 18:39:07 0100F2100F0B2000,"Soul Searching",,playable,2020-07-09 18:39:07
01008F2005154000,"South Park™: The Fractured but Whole™ - Standard Edition",slow;online-broken;vulkan-backend-bug;gpu,ingame,2025-01-21 17:35:10 01008F2005154000,"South Park™: The Fractured but Whole™ - Standard Edition",slow;online-broken,playable,2024-07-08 17:47:28
0100B9F00C162000,"Space Blaze",,playable,2020-08-30 16:18:05 0100B9F00C162000,"Space Blaze",,playable,2020-08-30 16:18:05
010005500E81E000,"Space Cows",UE4;crash,menus,2020-06-15 11:33:20 010005500E81E000,"Space Cows",UE4;crash,menus,2020-06-15 11:33:20
0100707011722000,"Space Elite Force",,playable,2020-11-27 15:21:05 0100707011722000,"Space Elite Force",,playable,2020-11-27 15:21:05
1 title_id game_name labels status last_updated
1070 010017B0102A8000 Emma: Lost in Memories nvdec playable 2021-01-28 16:19:10
1071 010068300E08E000 Enchanted in the Moonlight - Kiryu, Chikage & Yukinojo - gpu;nvdec ingame 2022-11-20 16:18:45
1072 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
1073 01004F3011F92000 Endless Fables: Dark Moor gpu;nvdec ingame 2021-03-07 15:31:03
1074 010067B017588000 Endless Ocean™ Luminous services-horizon;crash ingame 2024-05-30 02:05:57
1075 0100B8700BD14000 Energy Cycle Edge services ingame 2021-11-30 05:02:31
2681 01005EA01C0FC000 SONIC X SHADOW GENERATIONS crash ingame 2025-01-07 04:20:45
2682 010064F00C212000 Soul Axiom Rebooted nvdec;slow ingame 2020-09-04 12:41:01
2683 0100F2100F0B2000 Soul Searching playable 2020-07-09 18:39:07
2684 01008F2005154000 South Park™: The Fractured but Whole™ - Standard Edition slow;online-broken;vulkan-backend-bug;gpu slow;online-broken ingame playable 2025-01-21 17:35:10 2024-07-08 17:47:28
2685 0100B9F00C162000 Space Blaze playable 2020-08-30 16:18:05
2686 010005500E81E000 Space Cows UE4;crash menus 2020-06-15 11:33:20
2687 0100707011722000 Space Elite Force playable 2020-11-27 15:21:05

View File

@@ -78,10 +78,5 @@ namespace Ryujinx.Common.Configuration.Hid.Controller
/// Controller Rumble Settings /// Controller Rumble Settings
/// </summary> /// </summary>
public RumbleConfigController Rumble { get; set; } public RumbleConfigController Rumble { get; set; }
/// <summary>
/// Controller LED Settings
/// </summary>
public LedConfigController Led { get; set; }
} }
} }

View File

@@ -1,25 +0,0 @@
namespace Ryujinx.Common.Configuration.Hid.Controller
{
public class LedConfigController
{
/// <summary>
/// Enable LED color changing by the emulator
/// </summary>
public bool EnableLed { get; set; }
/// <summary>
/// Ignores the color and disables the LED entirely.
/// </summary>
public bool TurnOffLed { get; set; }
/// <summary>
/// Ignores the color and uses the rainbow color functionality for the LED.
/// </summary>
public bool UseRainbow { get; set; }
/// <summary>
/// Packed RGB int of the color
/// </summary>
public uint LedColor { get; set; }
}
}

View File

@@ -1,23 +0,0 @@
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);
}
}

View File

@@ -1,6 +1,5 @@
using Gommon; using Gommon;
using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration;
using Ryujinx.Common.Helper;
using System; using System;
using System.Linq; using System.Linq;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
@@ -9,20 +8,19 @@ namespace Ryujinx.Common
{ {
public static class TitleIDs public static class TitleIDs
{ {
public static ReactiveObject<Optional<string>> CurrentApplication { get; } = new(); public static ReactiveObject<Optional<string>> CurrentApplication { get; set; } = new();
public static GraphicsBackend SelectGraphicsBackend(string titleId, GraphicsBackend currentBackend) public static GraphicsBackend SelectGraphicsBackend(string titleId, GraphicsBackend currentBackend)
{ {
switch (currentBackend) switch (currentBackend)
{ {
case GraphicsBackend.Metal when !OperatingSystem.IsMacOS():
case GraphicsBackend.OpenGl when OperatingSystem.IsMacOS(): case GraphicsBackend.OpenGl when OperatingSystem.IsMacOS():
return GraphicsBackend.Vulkan; return GraphicsBackend.Vulkan;
case GraphicsBackend.Vulkan or GraphicsBackend.OpenGl or GraphicsBackend.Metal: case GraphicsBackend.Vulkan or GraphicsBackend.OpenGl or GraphicsBackend.Metal:
return currentBackend; return currentBackend;
} }
if (!RunningPlatform.IsArmMac) if (!(OperatingSystem.IsMacOS() && RuntimeInformation.ProcessArchitecture is Architecture.Arm64))
return GraphicsBackend.Vulkan; return GraphicsBackend.Vulkan;
return GreatMetalTitles.ContainsIgnoreCase(titleId) ? GraphicsBackend.Metal : GraphicsBackend.Vulkan; return GreatMetalTitles.ContainsIgnoreCase(titleId) ? GraphicsBackend.Metal : GraphicsBackend.Vulkan;
@@ -30,28 +28,18 @@ namespace Ryujinx.Common
public static readonly string[] GreatMetalTitles = public static readonly string[] GreatMetalTitles =
[ [
"010076f0049a2000", // Bayonetta "01006f8002326000", // Animal Crossings: New Horizons
"01009bf0072d4000", // Captain Toad: Treasure Tracker
"0100a5c00d162000", // Cuphead "0100a5c00d162000", // Cuphead
"010023800d64a000", // Deltarune "010023800d64a000", // Deltarune
"01003a30012c0000", // LEGO City Undercover
"010028600EBDA000", // Mario 3D World "010028600EBDA000", // Mario 3D World
"0100152000022000", // Mario Kart 8 Deluxe "0100152000022000", // Mario Kart 8 Deluxe
"010075a016a3a000", // Persona 4 Arena Ultimax "01005CA01580E000", // Persona 5
"0100187003A36000", // Pokémon: Let's Go, Eevee! "0100187003A36000", // Pokémon: Let's Go, Evoli!
"010003f003a34000", // Pokémon: Let's Go, Pikachu! "010003f003a34000", // Pokémon: Let's Go, Pikachu!
"01008C0016544000", // Sea of Stars "01008C0016544000", // Sea of Stars
"01006A800016E000", // Smash Ultimate "01006A800016E000", // Smash Ultimate
"01006bb00c6f0000", // The Legend of Zelda: Link's Awakening "0100000000010000", // Super Mario Odyessy
// 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) public static string GetDiscordGameAsset(string titleId)

View File

@@ -1,110 +0,0 @@
using Gommon;
using System;
using System.Drawing;
using System.Threading.Tasks;
namespace Ryujinx.Common.Utilities
{
public static class Rainbow
{
public static bool CyclingEnabled { get; set; }
public static void Enable()
{
if (!CyclingEnabled)
{
CyclingEnabled = true;
Executor.ExecuteBackgroundAsync(async () =>
{
while (CyclingEnabled)
{
await Task.Delay(15);
Tick();
}
});
}
}
public static void Disable()
{
CyclingEnabled = false;
}
public static float Speed { get; set; } = 1;
public static Color Color { get; private set; } = Color.Blue;
public static void Tick()
{
Color = HsbToRgb((Color.GetHue() + Speed) / 360);
UpdatedHandler.Call(Color.ToArgb());
}
public static void Reset()
{
Color = Color.Blue;
UpdatedHandler.Clear();
}
public static event Action<int> Updated
{
add => UpdatedHandler.Add(value);
remove => UpdatedHandler.Remove(value);
}
internal static Event<int> UpdatedHandler = new();
private static Color HsbToRgb(float hue, float saturation = 1, float brightness = 1)
{
int r = 0, g = 0, b = 0;
if (saturation == 0)
{
r = g = b = (int)(brightness * 255.0f + 0.5f);
}
else
{
float h = (hue - (float)Math.Floor(hue)) * 6.0f;
float f = h - (float)Math.Floor(h);
float p = brightness * (1.0f - saturation);
float q = brightness * (1.0f - saturation * f);
float t = brightness * (1.0f - (saturation * (1.0f - f)));
switch ((int)h)
{
case 0:
r = (int)(brightness * 255.0f + 0.5f);
g = (int)(t * 255.0f + 0.5f);
b = (int)(p * 255.0f + 0.5f);
break;
case 1:
r = (int)(q * 255.0f + 0.5f);
g = (int)(brightness * 255.0f + 0.5f);
b = (int)(p * 255.0f + 0.5f);
break;
case 2:
r = (int)(p * 255.0f + 0.5f);
g = (int)(brightness * 255.0f + 0.5f);
b = (int)(t * 255.0f + 0.5f);
break;
case 3:
r = (int)(p * 255.0f + 0.5f);
g = (int)(q * 255.0f + 0.5f);
b = (int)(brightness * 255.0f + 0.5f);
break;
case 4:
r = (int)(t * 255.0f + 0.5f);
g = (int)(p * 255.0f + 0.5f);
b = (int)(brightness * 255.0f + 0.5f);
break;
case 5:
r = (int)(brightness * 255.0f + 0.5f);
g = (int)(p * 255.0f + 0.5f);
b = (int)(q * 255.0f + 0.5f);
break;
}
}
return Color.FromArgb(Convert.ToByte(255), Convert.ToByte(r), Convert.ToByte(g), Convert.ToByte(b));
}
}
}

View File

@@ -118,7 +118,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
private static string GetDiskCachePath() private static string GetDiskCachePath()
{ {
return GraphicsConfig.EnableShaderCache && GraphicsConfig.TitleId != null return GraphicsConfig.EnableShaderCache && GraphicsConfig.TitleId != null
? Path.Combine(AppDataManager.GamesDirPath, GraphicsConfig.TitleId.ToLower(), "cache", "shader") ? Path.Combine(AppDataManager.GamesDirPath, GraphicsConfig.TitleId, "cache", "shader")
: null; : null;
} }

View File

@@ -710,8 +710,9 @@ namespace Ryujinx.HLE.FileSystem
{ {
updateNcasItem.Add((nca.Header.ContentType, entry.FullName)); updateNcasItem.Add((nca.Header.ContentType, entry.FullName));
} }
else if (updateNcas.TryAdd(nca.Header.TitleId, new List<(NcaContentType, string)>())) else
{ {
updateNcas.Add(nca.Header.TitleId, new List<(NcaContentType, string)>());
updateNcas[nca.Header.TitleId].Add((nca.Header.ContentType, entry.FullName)); updateNcas[nca.Header.TitleId].Add((nca.Header.ContentType, entry.FullName));
} }
} }
@@ -897,8 +898,9 @@ namespace Ryujinx.HLE.FileSystem
{ {
updateNcasItem.Add((nca.Header.ContentType, entry.FullPath)); updateNcasItem.Add((nca.Header.ContentType, entry.FullPath));
} }
else if (updateNcas.TryAdd(nca.Header.TitleId, new List<(NcaContentType, string)>())) else
{ {
updateNcas.Add(nca.Header.TitleId, new List<(NcaContentType, string)>());
updateNcas[nca.Header.TitleId].Add((nca.Header.ContentType, entry.FullPath)); updateNcas[nca.Header.TitleId].Add((nca.Header.ContentType, entry.FullPath));
} }

View File

@@ -56,7 +56,7 @@ namespace Ryujinx.HLE.HOS.Services.Account.Acc
ProfilesJson profilesJson = JsonHelper.DeserializeFromFile(_profilesJsonPath, _serializerContext.ProfilesJson); ProfilesJson profilesJson = JsonHelper.DeserializeFromFile(_profilesJsonPath, _serializerContext.ProfilesJson);
return profilesJson.Profiles return profilesJson.Profiles
.FindFirst(profile => profile.UserId == profilesJson.LastOpened) .FindFirst(profile => profile.AccountState == AccountState.Open)
.Convert(profileJson => new UserProfile(new UserId(profileJson.UserId), profileJson.Name, .Convert(profileJson => new UserProfile(new UserId(profileJson.UserId), profileJson.Name,
profileJson.Image, profileJson.LastModifiedTimestamp)); profileJson.Image, profileJson.LastModifiedTimestamp));
} }

View File

@@ -659,7 +659,7 @@ namespace Ryujinx.HLE.HOS.Services.Am.AppletOE.ApplicationProxyService.Applicati
if (string.IsNullOrWhiteSpace(filePath)) 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/Ryubing/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/GreemDev/Ryujinx#requirements for more information)");
} }
context.Device.LoadNca(filePath); context.Device.LoadNca(filePath);

View File

@@ -105,7 +105,7 @@ namespace Ryujinx.HLE.HOS.Services.Sdb.Pl
titleName = "Unknown"; 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/Ryubing/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/GreemDev/Ryujinx#requirements for more information)");
} }
} }
else else

View File

@@ -244,15 +244,6 @@ namespace Ryujinx.HLE.HOS.Services.Settings
return ResultCode.Success; 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)] [CommandCmif(77)]
// GetDeviceNickName() -> buffer<nn::settings::system::DeviceNickName, 0x16> // GetDeviceNickName() -> buffer<nn::settings::system::DeviceNickName, 0x16>
public ResultCode GetDeviceNickName(ServiceCtx context) public ResultCode GetDeviceNickName(ServiceCtx context)

View File

@@ -51,9 +51,6 @@ namespace Ryujinx.HLE.HOS.Services.Spl
context.ResponseData.Write(configValue); context.ResponseData.Write(configValue);
if (result == SmcResult.Success)
return ResultCode.Success;
return (ResultCode)((int)result << 9) | ResultCode.ModuleId; return (ResultCode)((int)result << 9) | ResultCode.ModuleId;
} }

View File

@@ -161,20 +161,5 @@ namespace Ryujinx.HLE
{ {
return 1000 / _frameRate[FrameTypeGame]; 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}%";
}
} }
} }

View File

@@ -34,8 +34,8 @@ namespace Ryujinx.HLE
public int CpuCoresCount = 4; //Switch 1 has 4 cores public int CpuCoresCount = 4; //Switch 1 has 4 cores
public VSyncMode VSyncMode { get; set; } public VSyncMode VSyncMode { get; set; } = VSyncMode.Switch;
public bool CustomVSyncIntervalEnabled { get; set; } public bool CustomVSyncIntervalEnabled { get; set; } = false;
public int CustomVSyncInterval { get; set; } public int CustomVSyncInterval { get; set; }
public long TargetVSyncInterval { get; set; } = 60; public long TargetVSyncInterval { get; set; } = 60;

View File

@@ -1,9 +1,6 @@
using Ryujinx.Common.Configuration.Hid; using Ryujinx.Common.Configuration.Hid;
using Ryujinx.Common.Configuration.Hid.Controller; using Ryujinx.Common.Configuration.Hid.Controller;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.Common.Utilities;
using Ryujinx.HLE.HOS.Services.Hid;
using SDL2;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Numerics; using System.Numerics;
@@ -88,7 +85,7 @@ namespace Ryujinx.Input.SDL2
Id = driverId; Id = driverId;
Features = GetFeaturesFlag(); Features = GetFeaturesFlag();
_triggerThreshold = 0.0f; _triggerThreshold = 0.0f;
// Enable motion tracking // Enable motion tracking
if (Features.HasFlag(GamepadFeaturesFlag.Motion)) if (Features.HasFlag(GamepadFeaturesFlag.Motion))
{ {
@@ -104,18 +101,6 @@ namespace Ryujinx.Input.SDL2
} }
} }
public void SetLed(uint packedRgb)
{
if (!Features.HasFlag(GamepadFeaturesFlag.Led)) return;
byte red = packedRgb > 0 ? (byte)(packedRgb >> 16) : (byte)0;
byte green = packedRgb > 0 ? (byte)(packedRgb >> 8) : (byte)0;
byte blue = packedRgb > 0 ? (byte)(packedRgb % 256) : (byte)0;
if (SDL_GameControllerSetLED(_gamepadHandle, red, green, blue) != 0)
Logger.Error?.Print(LogClass.Hid, "LED is not supported on this game controller.");
}
private GamepadFeaturesFlag GetFeaturesFlag() private GamepadFeaturesFlag GetFeaturesFlag()
{ {
GamepadFeaturesFlag result = GamepadFeaturesFlag.None; GamepadFeaturesFlag result = GamepadFeaturesFlag.None;
@@ -126,16 +111,13 @@ namespace Ryujinx.Input.SDL2
result |= GamepadFeaturesFlag.Motion; result |= GamepadFeaturesFlag.Motion;
} }
if (SDL_GameControllerHasRumble(_gamepadHandle) == SDL_bool.SDL_TRUE) int error = SDL_GameControllerRumble(_gamepadHandle, 0, 0, 100);
if (error == 0)
{ {
result |= GamepadFeaturesFlag.Rumble; result |= GamepadFeaturesFlag.Rumble;
} }
if (SDL_GameControllerHasLED(_gamepadHandle) == SDL_bool.SDL_TRUE)
{
result |= GamepadFeaturesFlag.Led;
}
return result; return result;
} }
@@ -148,8 +130,6 @@ namespace Ryujinx.Input.SDL2
{ {
if (disposing && _gamepadHandle != nint.Zero) if (disposing && _gamepadHandle != nint.Zero)
{ {
Rainbow.Updated -= RainbowColorChanged;
SDL_GameControllerClose(_gamepadHandle); SDL_GameControllerClose(_gamepadHandle);
_gamepadHandle = nint.Zero; _gamepadHandle = nint.Zero;
@@ -228,41 +208,12 @@ namespace Ryujinx.Input.SDL2
private static Vector3 GsToMs2(Vector3 gs) => gs / SDL_STANDARD_GRAVITY; private static Vector3 GsToMs2(Vector3 gs) => gs / SDL_STANDARD_GRAVITY;
private void RainbowColorChanged(int packedRgb)
{
if (!_configuration.Led.UseRainbow) return;
SetLed((uint)packedRgb);
}
private bool _rainbowColorEnabled;
public void SetConfiguration(InputConfig configuration) public void SetConfiguration(InputConfig configuration)
{ {
lock (_userMappingLock) lock (_userMappingLock)
{ {
_configuration = (StandardControllerInputConfig)configuration; _configuration = (StandardControllerInputConfig)configuration;
if (Features.HasFlag(GamepadFeaturesFlag.Led) && _configuration.Led.EnableLed)
{
if (_configuration.Led.TurnOffLed)
(this as IGamepad).ClearLed();
else switch (_configuration.Led.UseRainbow)
{
case true when !_rainbowColorEnabled:
Rainbow.Updated += RainbowColorChanged;
_rainbowColorEnabled = true;
break;
case false when _rainbowColorEnabled:
Rainbow.Updated -= RainbowColorChanged;
_rainbowColorEnabled = false;
break;
}
if (!_configuration.Led.TurnOffLed && !_rainbowColorEnabled)
SetLed(_configuration.Led.LedColor);
}
_buttonsUserMapping.Clear(); _buttonsUserMapping.Clear();
// First update sticks // First update sticks

View File

@@ -173,16 +173,5 @@ namespace Ryujinx.Input.SDL2
return new SDL2Gamepad(gamepadHandle, id); return new SDL2Gamepad(gamepadHandle, id);
} }
public IEnumerable<IGamepad> GetGamepads()
{
lock (_gamepadsIds)
{
foreach (string gamepadId in _gamepadsIds)
{
yield return GetGamepad(gamepadId);
}
}
}
} }
} }

View File

@@ -1,6 +1,5 @@
using Ryujinx.Common.Configuration.Hid; using Ryujinx.Common.Configuration.Hid;
using Ryujinx.Common.Configuration.Hid.Keyboard; using Ryujinx.Common.Configuration.Hid.Keyboard;
using Ryujinx.Common.Logging;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Numerics; using System.Numerics;
@@ -386,11 +385,6 @@ namespace Ryujinx.Input.SDL2
} }
} }
public void SetLed(uint packedRgb)
{
Logger.Info?.Print(LogClass.UI, "SetLed called on an SDL2Keyboard");
}
public void SetTriggerThreshold(float triggerThreshold) public void SetTriggerThreshold(float triggerThreshold)
{ {
// No operations // No operations

View File

@@ -1,5 +1,4 @@
using Ryujinx.Common.Configuration.Hid; using Ryujinx.Common.Configuration.Hid;
using Ryujinx.Common.Logging;
using System; using System;
using System.Drawing; using System.Drawing;
using System.Numerics; using System.Numerics;
@@ -77,11 +76,6 @@ namespace Ryujinx.Input.SDL2
throw new NotImplementedException(); throw new NotImplementedException();
} }
public void SetLed(uint packedRgb)
{
Logger.Info?.Print(LogClass.UI, "SetLed called on an SDL2Mouse");
}
public void SetTriggerThreshold(float triggerThreshold) public void SetTriggerThreshold(float triggerThreshold)
{ {
throw new NotImplementedException(); throw new NotImplementedException();

View File

@@ -1,7 +1,6 @@
using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using System; using System;
using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Drawing; using System.Drawing;
using System.Numerics; using System.Numerics;
@@ -165,8 +164,6 @@ namespace Ryujinx.Input.SDL2
return new SDL2Mouse(this); return new SDL2Mouse(this);
} }
public IEnumerable<IGamepad> GetGamepads() => [GetGamepad("0")];
public void Dispose() public void Dispose()
{ {
if (_isDisposed) if (_isDisposed)

View File

@@ -1,6 +1,5 @@
using Ryujinx.SDL2.Common; using Ryujinx.SDL2.Common;
using System; using System;
using System.Collections.Generic;
namespace Ryujinx.Input.SDL2 namespace Ryujinx.Input.SDL2
{ {
@@ -52,13 +51,5 @@ namespace Ryujinx.Input.SDL2
return new SDL2Keyboard(this, _keyboardIdentifers[0], "All keyboards"); return new SDL2Keyboard(this, _keyboardIdentifers[0], "All keyboards");
} }
public IEnumerable<IGamepad> GetGamepads()
{
foreach (var keyboardId in _keyboardIdentifers)
{
yield return GetGamepad(keyboardId);
}
}
} }
} }

View File

@@ -24,10 +24,5 @@ namespace Ryujinx.Input
/// <remarks>Also named sixaxis</remarks> /// <remarks>Also named sixaxis</remarks>
/// </summary> /// </summary>
Motion, Motion,
/// <summary>
/// The LED on the back of modern PlayStation controllers (DualSense &amp; DualShock 4).
/// </summary>
Led,
} }
} }

View File

@@ -65,15 +65,6 @@ namespace Ryujinx.Input
/// <param name="configuration">The configuration of the gamepad</param> /// <param name="configuration">The configuration of the gamepad</param>
void SetConfiguration(InputConfig configuration); void SetConfiguration(InputConfig configuration);
/// <summary>
/// Set the LED on the gamepad to a given color.
/// </summary>
/// <remarks>Does nothing on a controller without LED functionality.</remarks>
/// <param name="packedRgb">The packed RGB integer.</param>
void SetLed(uint packedRgb);
public void ClearLed() => SetLed(0);
/// <summary> /// <summary>
/// Starts a rumble effect on the gamepad. /// Starts a rumble effect on the gamepad.
/// </summary> /// </summary>

View File

@@ -1,5 +1,4 @@
using System; using System;
using System.Collections.Generic;
namespace Ryujinx.Input namespace Ryujinx.Input
{ {
@@ -34,11 +33,6 @@ namespace Ryujinx.Input
/// <param name="id">The unique id of the gamepad</param> /// <param name="id">The unique id of the gamepad</param>
/// <returns>An instance of <see cref="IGamepad"/> associated to the gamepad id given or null if not found</returns> /// <returns>An instance of <see cref="IGamepad"/> associated to the gamepad id given or null if not found</returns>
IGamepad GetGamepad(string id); IGamepad GetGamepad(string id);
/// <summary>
/// Returns an <see cref="IEnumerable{T}"/> of the connected gamepads.
/// </summary>
IEnumerable<IGamepad> GetGamepads();
/// <summary> /// <summary>
/// Clear the internal state of the driver. /// Clear the internal state of the driver.

View File

@@ -1,6 +1,5 @@
using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
using Ryujinx.Common.Utilities;
using System; using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;

View File

@@ -501,8 +501,6 @@ namespace Ryujinx.Ava
_renderingThread.Start(); _renderingThread.Start();
_viewModel.Volume = ConfigurationState.Instance.System.AudioVolume.Value; _viewModel.Volume = ConfigurationState.Instance.System.AudioVolume.Value;
Rainbow.Enable();
MainLoop(); MainLoop();
@@ -589,15 +587,6 @@ namespace Ryujinx.Ava
return; return;
} }
foreach (IGamepad gamepad in RyujinxApp.MainWindow.InputManager.GamepadDriver.GetGamepads())
{
gamepad?.ClearLed();
gamepad?.Dispose();
}
Rainbow.Disable();
Rainbow.Reset();
_isStopped = true; _isStopped = true;
Stop(); Stop();
} }
@@ -685,7 +674,7 @@ namespace Ryujinx.Ava
public async Task<bool> LoadGuestApplication(BlitStruct<ApplicationControlProperty>? customNacpData = null) public async Task<bool> LoadGuestApplication(BlitStruct<ApplicationControlProperty>? customNacpData = null)
{ {
InitEmulatedSwitch(); InitializeSwitchInstance();
MainWindow.UpdateGraphicsConfig(); MainWindow.UpdateGraphicsConfig();
SystemVersion firmwareVersion = ContentManager.GetCurrentFirmwareVersion(); SystemVersion firmwareVersion = ContentManager.GetCurrentFirmwareVersion();
@@ -768,8 +757,6 @@ namespace Ryujinx.Ava
{ {
romFsFiles = Directory.GetFiles(ApplicationPath, "*.romfs"); romFsFiles = Directory.GetFiles(ApplicationPath, "*.romfs");
} }
Logger.Notice.Print(LogClass.Application, $"Loading unpacked content archive from '{ApplicationPath}'.");
if (romFsFiles.Length > 0) if (romFsFiles.Length > 0)
{ {
@@ -796,8 +783,6 @@ namespace Ryujinx.Ava
} }
else if (File.Exists(ApplicationPath)) else if (File.Exists(ApplicationPath))
{ {
Logger.Notice.Print(LogClass.Application, $"Loading content archive from '{ApplicationPath}'.");
switch (Path.GetExtension(ApplicationPath).ToLowerInvariant()) switch (Path.GetExtension(ApplicationPath).ToLowerInvariant())
{ {
case ".xci": case ".xci":
@@ -900,7 +885,7 @@ namespace Ryujinx.Ava
Logger.Info?.Print(LogClass.Emulation, "Emulation was paused"); Logger.Info?.Print(LogClass.Emulation, "Emulation was paused");
} }
private void InitEmulatedSwitch() private void InitializeSwitchInstance()
{ {
// Initialize KeySet. // Initialize KeySet.
VirtualFileSystem.ReloadKeySet(); VirtualFileSystem.ReloadKeySet();
@@ -1055,7 +1040,7 @@ namespace Ryujinx.Ava
_viewModel.WindowState = WindowState.FullScreen; _viewModel.WindowState = WindowState.FullScreen;
} }
if (_viewModel.WindowState is WindowState.FullScreen || _viewModel.StartGamesWithoutUI) if (_viewModel.WindowState is WindowState.FullScreen)
{ {
_viewModel.ShowMenuAndStatusBar = false; _viewModel.ShowMenuAndStatusBar = false;
} }
@@ -1162,8 +1147,8 @@ namespace Ryujinx.Ava
LocaleManager.Instance[LocaleKeys.VolumeShort] + $": {(int)(Device.GetVolume() * 100)}%", LocaleManager.Instance[LocaleKeys.VolumeShort] + $": {(int)(Device.GetVolume() * 100)}%",
dockedMode, dockedMode,
ConfigurationState.Instance.Graphics.AspectRatio.Value.ToText(), ConfigurationState.Instance.Graphics.AspectRatio.Value.ToText(),
Device.Statistics.FormatGameFrameRate(), $"{Device.Statistics.GetGameFrameRate():00.00} FPS ({Device.Statistics.GetGameFrameTime():00.00} ms)",
Device.Statistics.FormatFifoPercent(), $"FIFO: {Device.Statistics.GetFifoPercent():00.00} %",
_displayCount)); _displayCount));
} }

View File

@@ -1,13 +0,0 @@
<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>

View File

@@ -572,31 +572,6 @@
"zh_TW": "使用全螢幕模式啟動遊戲" "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", "ID": "MenuBarOptionsStopEmulation",
"Translations": { "Translations": {
@@ -773,7 +748,32 @@
} }
}, },
{ {
"ID": "MenuBarActionsInstallFirmware", "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",
"Translations": { "Translations": {
"ar_SA": "تثبيت البرنامج الثابت", "ar_SA": "تثبيت البرنامج الثابت",
"de_DE": "Firmware installieren", "de_DE": "Firmware installieren",
@@ -798,7 +798,7 @@
} }
}, },
{ {
"ID": "MenuBarActionsInstallFirmwareFromFile", "ID": "MenuBarFileToolsInstallFirmwareFromFile",
"Translations": { "Translations": {
"ar_SA": "تثبيت برنامج ثابت من XCI أو ZIP", "ar_SA": "تثبيت برنامج ثابت من XCI أو ZIP",
"de_DE": "Firmware von einer XCI- oder einer ZIP-Datei installieren", "de_DE": "Firmware von einer XCI- oder einer ZIP-Datei installieren",
@@ -823,7 +823,7 @@
} }
}, },
{ {
"ID": "MenuBarActionsInstallFirmwareFromDirectory", "ID": "MenuBarFileToolsInstallFirmwareFromDirectory",
"Translations": { "Translations": {
"ar_SA": "تثبيت برنامج ثابت من مجلد", "ar_SA": "تثبيت برنامج ثابت من مجلد",
"de_DE": "Firmware aus einem Verzeichnis installieren", "de_DE": "Firmware aus einem Verzeichnis installieren",
@@ -848,7 +848,7 @@
} }
}, },
{ {
"ID": "MenuBarActionsInstallKeys", "ID": "MenuBarToolsInstallKeys",
"Translations": { "Translations": {
"ar_SA": "", "ar_SA": "",
"de_DE": "", "de_DE": "",
@@ -873,7 +873,7 @@
} }
}, },
{ {
"ID": "MenuBarFileActionsInstallKeysFromFile", "ID": "MenuBarFileToolsInstallKeysFromFile",
"Translations": { "Translations": {
"ar_SA": "", "ar_SA": "",
"de_DE": "", "de_DE": "",
@@ -898,7 +898,7 @@
} }
}, },
{ {
"ID": "MenuBarFileActionsInstallKeysFromFolder", "ID": "MenuBarFileToolsInstallKeysFromFolder",
"Translations": { "Translations": {
"ar_SA": "", "ar_SA": "",
"de_DE": "", "de_DE": "",
@@ -923,7 +923,7 @@
} }
}, },
{ {
"ID": "MenuBarActionsManageFileTypes", "ID": "MenuBarToolsManageFileTypes",
"Translations": { "Translations": {
"ar_SA": "إدارة أنواع الملفات", "ar_SA": "إدارة أنواع الملفات",
"de_DE": "Dateitypen verwalten", "de_DE": "Dateitypen verwalten",
@@ -948,7 +948,7 @@
} }
}, },
{ {
"ID": "MenuBarActionsInstallFileTypes", "ID": "MenuBarToolsInstallFileTypes",
"Translations": { "Translations": {
"ar_SA": "تثبيت أنواع الملفات", "ar_SA": "تثبيت أنواع الملفات",
"de_DE": "Dateitypen installieren", "de_DE": "Dateitypen installieren",
@@ -973,7 +973,7 @@
} }
}, },
{ {
"ID": "MenuBarActionsUninstallFileTypes", "ID": "MenuBarToolsUninstallFileTypes",
"Translations": { "Translations": {
"ar_SA": "إزالة أنواع الملفات", "ar_SA": "إزالة أنواع الملفات",
"de_DE": "Dateitypen deinstallieren", "de_DE": "Dateitypen deinstallieren",
@@ -998,7 +998,7 @@
} }
}, },
{ {
"ID": "MenuBarActionsXCITrimmer", "ID": "MenuBarToolsXCITrimmer",
"Translations": { "Translations": {
"ar_SA": "", "ar_SA": "",
"de_DE": "", "de_DE": "",
@@ -2297,56 +2297,6 @@
"zh_TW": "從應用程式的目前配置中提取 RomFS 分區 (包含更新)" "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", "ID": "GameListContextMenuExtractDataLogo",
"Translations": { "Translations": {
@@ -7622,81 +7572,6 @@
"zh_TW": "陀螺儀無感帶:" "zh_TW": "陀螺儀無感帶:"
} }
}, },
{
"ID": "ControllerSettingsLedColor",
"Translations": {
"ar_SA": "",
"de_DE": "",
"el_GR": "",
"en_US": "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": "ControllerSettingsLedColorDisable",
"Translations": {
"ar_SA": "",
"de_DE": "",
"el_GR": "",
"en_US": "Disable",
"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": "ControllerSettingsLedColorRainbow",
"Translations": {
"ar_SA": "",
"de_DE": "",
"el_GR": "",
"en_US": "Rainbow",
"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", "ID": "ControllerSettingsSave",
"Translations": { "Translations": {
@@ -23021,31 +22896,6 @@
"zh_CN": "什么都没有", "zh_CN": "什么都没有",
"zh_TW": "無法啟動 (Nothing)" "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": ""
}
} }
] ]
} }

View File

@@ -1,6 +1,6 @@
using Avalonia.Controls.Notifications;
using Avalonia.Platform.Storage; using Avalonia.Platform.Storage;
using Avalonia.Threading; using Avalonia.Threading;
using Gommon;
using LibHac; using LibHac;
using LibHac.Account; using LibHac.Account;
using LibHac.Common; using LibHac.Common;
@@ -15,7 +15,6 @@ using LibHac.Tools.FsSystem.NcaUtils;
using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.UI.Controls; using Ryujinx.Ava.UI.Controls;
using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.Utilities;
using Ryujinx.Ava.Utilities.Configuration; using Ryujinx.Ava.Utilities.Configuration;
using Ryujinx.Common.Helper; using Ryujinx.Common.Helper;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
@@ -296,150 +295,22 @@ namespace Ryujinx.Ava.Common
}; };
extractorThread.Start(); extractorThread.Start();
} }
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.Data, Path.GetFileName(updateFilePath)),
cancellationToken);
Thread extractorThread = new(() =>
{
Dispatcher.UIThread.Post(waitingDialog.Show);
using FileStream file = new(updateFilePath, FileMode.Open, FileAccess.Read);
Nca publicDataNca = null;
string extension = Path.GetExtension(updateFilePath).ToLower();
if (extension is ".nsp")
{
var pfsTemp = new PartitionFileSystem();
pfsTemp.Initialize(file.AsStorage()).ThrowIfFailure();
IFileSystem pfs = pfsTemp;
foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*.nca"))
{
using var ncaFile = new UniqueRef<IFile>();
pfs.OpenFile(ref ncaFile.Ref, fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure();
Nca nca = new(_virtualFileSystem.KeySet, ncaFile.Get.AsStorage());
if (nca.Header.ContentType is NcaContentType.PublicData && nca.SectionExists(NcaSectionType.Data))
{
publicDataNca = nca;
}
}
}
if (publicDataNca is null)
{
Logger.Error?.Print(LogClass.Application, "Extraction failure. The NCA was not present in the selected file");
Dispatcher.UIThread.InvokeAsync(async () =>
{
waitingDialog.Close();
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogNcaExtractionMainNcaNotFoundErrorMessage]);
});
return;
}
IntegrityCheckLevel checkLevel = ConfigurationState.Instance.System.EnableFsIntegrityChecks
? IntegrityCheckLevel.ErrorOnInvalid
: IntegrityCheckLevel.None;
int index = Nca.GetSectionIndexFromType(NcaSectionType.Data, publicDataNca.Header.ContentType);
try
{
IFileSystem ncaFileSystem = publicDataNca.OpenFileSystem(index, IntegrityCheckLevel.ErrorOnInvalid);
FileSystemClient fsClient = _horizonClient.Fs;
string source = DateTime.Now.ToFileTime().ToString()[10..];
string output = DateTime.Now.ToFileTime().ToString()[10..];
using var uniqueSourceFs = new UniqueRef<IFileSystem>(ncaFileSystem);
using var uniqueOutputFs = new UniqueRef<IFileSystem>(new LocalFileSystem(destination));
fsClient.Register(source.ToU8Span(), ref uniqueSourceFs.Ref);
fsClient.Register(output.ToU8Span(), ref uniqueOutputFs.Ref);
(Result? resultCode, bool canceled) = CopyDirectory(fsClient, $"{source}:/", $"{output}:/", cancellationToken.Token);
if (!canceled)
{
if (resultCode.Value.IsFailure())
{
Logger.Error?.Print(LogClass.Application, $"LibHac returned error code: {resultCode.Value.ErrorCode}");
Dispatcher.UIThread.InvokeAsync(async () =>
{
waitingDialog.Close();
await ContentDialogHelper.CreateErrorDialog(LocaleManager.Instance[LocaleKeys.DialogNcaExtractionCheckLogErrorMessage]);
});
}
else if (resultCode.Value.IsSuccess())
{
Dispatcher.UIThread.Post(waitingDialog.Close);
NotificationHelper.ShowInformation(
RyujinxApp.FormatTitle(LocaleKeys.DialogNcaExtractionTitle),
$"{updateName}\n\n{LocaleManager.Instance[LocaleKeys.DialogNcaExtractionSuccessMessage]}");
}
}
fsClient.Unmount(source.ToU8Span());
fsClient.Unmount(output.ToU8Span());
}
catch (ArgumentException ex)
{
Logger.Error?.Print(LogClass.Application, $"{ex.Message}");
Dispatcher.UIThread.InvokeAsync(async () =>
{
waitingDialog.Close();
await ContentDialogHelper.CreateErrorDialog(ex.Message);
});
}
})
{
Name = "GUI.AocExtractorThread",
IsBackground = true,
};
extractorThread.Start();
}
public static async Task ExtractAoc(IStorageProvider storageProvider, string updateFilePath, string updateName)
{
Optional<IStorageFolder> result = await storageProvider.OpenSingleFolderPickerAsync(new FolderPickerOpenOptions
{
Title = LocaleManager.Instance[LocaleKeys.FolderDialogExtractTitle]
});
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) public static async Task ExtractSection(IStorageProvider storageProvider, NcaSectionType ncaSectionType, string titleFilePath, string titleName, int programIndex = 0)
{ {
Optional<IStorageFolder> result = await storageProvider.OpenSingleFolderPickerAsync(new FolderPickerOpenOptions var result = await storageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions
{ {
Title = LocaleManager.Instance[LocaleKeys.FolderDialogExtractTitle] Title = LocaleManager.Instance[LocaleKeys.FolderDialogExtractTitle],
AllowMultiple = false,
}); });
if (!result.HasValue) return; if (result.Count == 0)
{
return;
}
ExtractSection(result.Value.Path.LocalPath, ncaSectionType, titleFilePath, titleName, programIndex); ExtractSection(result[0].Path.LocalPath, ncaSectionType, titleFilePath, titleName, programIndex);
} }
public static (Result? result, bool canceled) CopyDirectory(FileSystemClient fs, string sourcePath, string destPath, CancellationToken token) public static (Result? result, bool canceled) CopyDirectory(FileSystemClient fs, string sourcePath, string destPath, CancellationToken token)

View File

@@ -6,7 +6,7 @@ namespace Ryujinx.Ava.Common.Models
public bool IsBundled { get; } = System.IO.Path.GetExtension(ContainerPath)?.ToLower() == ".xci"; public bool IsBundled { get; } = System.IO.Path.GetExtension(ContainerPath)?.ToLower() == ".xci";
public string FileName => System.IO.Path.GetFileName(ContainerPath); public string FileName => System.IO.Path.GetFileName(ContainerPath);
public string TitleIdStr => TitleId.ToString("x16").ToUpper(); public string TitleIdStr => TitleId.ToString("x16");
public ulong TitleIdBase => TitleId & ~0x1FFFUL; public ulong TitleIdBase => TitleId & ~0x1FFFUL;
} }
} }

View File

@@ -149,7 +149,7 @@ namespace Ryujinx.Headless
IgnoreMissingServices = configurationState.System.IgnoreMissingServices; IgnoreMissingServices = configurationState.System.IgnoreMissingServices;
if (NeedsOverride(nameof(IgnoreControllerApplet))) if (NeedsOverride(nameof(IgnoreControllerApplet)))
IgnoreControllerApplet = configurationState.System.IgnoreApplet; IgnoreControllerApplet = configurationState.IgnoreApplet;
return; return;

View File

@@ -1,6 +1,5 @@
using Ryujinx.Common.Configuration.Hid; using Ryujinx.Common.Configuration.Hid;
using Ryujinx.Common.Configuration.Hid.Keyboard; using Ryujinx.Common.Configuration.Hid.Keyboard;
using Ryujinx.Common.Logging;
using Ryujinx.Input; using Ryujinx.Input;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@@ -144,11 +143,6 @@ namespace Ryujinx.Ava.Input
} }
} }
public void SetLed(uint packedRgb)
{
Logger.Info?.Print(LogClass.UI, "SetLed called on an AvaloniaKeyboard");
}
public void SetTriggerThreshold(float triggerThreshold) { } public void SetTriggerThreshold(float triggerThreshold) { }
public void Rumble(float lowFrequency, float highFrequency, uint durationMs) { } public void Rumble(float lowFrequency, float highFrequency, uint durationMs) { }

View File

@@ -59,8 +59,6 @@ namespace Ryujinx.Ava.Input
return new AvaloniaKeyboard(this, _keyboardIdentifers[0], LocaleManager.Instance[LocaleKeys.AllKeyboards]); return new AvaloniaKeyboard(this, _keyboardIdentifers[0], LocaleManager.Instance[LocaleKeys.AllKeyboards]);
} }
public IEnumerable<IGamepad> GetGamepads() => [GetGamepad("0")];
protected virtual void Dispose(bool disposing) protected virtual void Dispose(bool disposing)
{ {
if (disposing) if (disposing)

View File

@@ -1,5 +1,4 @@
using Ryujinx.Common.Configuration.Hid; using Ryujinx.Common.Configuration.Hid;
using Ryujinx.Common.Logging;
using Ryujinx.Input; using Ryujinx.Input;
using System; using System;
using System.Drawing; using System.Drawing;
@@ -75,11 +74,6 @@ namespace Ryujinx.Ava.Input
throw new NotImplementedException(); throw new NotImplementedException();
} }
public void SetLed(uint packedRgb)
{
Logger.Info?.Print(LogClass.UI, "SetLed called on an AvaloniaMouse");
}
public void SetTriggerThreshold(float triggerThreshold) public void SetTriggerThreshold(float triggerThreshold)
{ {
throw new NotImplementedException(); throw new NotImplementedException();

View File

@@ -3,7 +3,6 @@ using Avalonia.Controls;
using Avalonia.Input; using Avalonia.Input;
using Ryujinx.Input; using Ryujinx.Input;
using System; using System;
using System.Collections.Generic;
using System.Numerics; using System.Numerics;
using MouseButton = Ryujinx.Input.MouseButton; using MouseButton = Ryujinx.Input.MouseButton;
using Size = System.Drawing.Size; using Size = System.Drawing.Size;
@@ -135,8 +134,6 @@ namespace Ryujinx.Ava.Input
return new AvaloniaMouse(this); return new AvaloniaMouse(this);
} }
public IEnumerable<IGamepad> GetGamepads() => [GetGamepad("0")];
public void Dispose() public void Dispose()
{ {
if (_isDisposed) if (_isDisposed)

View File

@@ -47,9 +47,9 @@ namespace Ryujinx.Ava
{ {
Version = ReleaseInformation.Version; Version = ReleaseInformation.Version;
if (OperatingSystem.IsWindows() && !OperatingSystem.IsWindowsVersionAtLeast(10, 0, 19041)) if (OperatingSystem.IsWindows() && !OperatingSystem.IsWindowsVersionAtLeast(10, 0, 17134))
{ {
_ = MessageBoxA(nint.Zero, "You are running an outdated version of Windows.\n\nRyujinx supports Windows 10 version 20H1 and newer.\n", $"Ryujinx {Version}", MbIconwarning); _ = MessageBoxA(nint.Zero, "You are running an outdated version of Windows.\n\nRyujinx supports Windows 10 version 1803 and newer.\n", $"Ryujinx {Version}", MbIconwarning);
} }
PreviewerDetached = true; PreviewerDetached = true;
@@ -230,16 +230,13 @@ namespace Ryujinx.Ava
internal static void PrintSystemInfo() internal static void PrintSystemInfo()
{ {
Logger.Notice.Print(LogClass.Application, $"{RyujinxApp.FullAppName} Version: {Version}"); Logger.Notice.Print(LogClass.Application, $"{RyujinxApp.FullAppName} Version: {Version}");
Logger.Notice.Print(LogClass.Application, $".NET Runtime: {RuntimeInformation.FrameworkDescription}");
SystemInfo.Gather().Print(); SystemInfo.Gather().Print();
Logger.Notice.Print(LogClass.Application, $"Logs Enabled: { var enabledLogLevels = Logger.GetEnabledLevels().ToArray();
Logger.GetEnabledLevels()
.FormatCollection( Logger.Notice.Print(LogClass.Application, $"Logs Enabled: {(enabledLogLevels.Length is 0
x => x.ToString(), ? "<None>"
separator: ", ", : enabledLogLevels.JoinToString(", "))}");
emptyCollectionFallback: "<None>")
}");
Logger.Notice.Print(LogClass.Application, Logger.Notice.Print(LogClass.Application,
AppDataManager.Mode == AppDataManager.LaunchMode.Custom AppDataManager.Mode == AppDataManager.LaunchMode.Custom

View File

@@ -123,13 +123,12 @@
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</AvaloniaResource> </AvaloniaResource>
<AvaloniaResource Include="Assets\Styles\Styles.xaml" /> <AvaloniaResource Include="Assets\Styles\Styles.xaml" />
<AvaloniaResource Include="Assets\Styles\CheckboxMenuItemStyle.axaml" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Remove="Assets\locales.json" /> <None Remove="Assets\locales.json" />
<None Remove="Assets\Styles\Styles.xaml" />
<None Remove="Assets\Styles\Themes.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_JoyConLeft.svg" />
<None Remove="Assets\Icons\Controller_JoyConPair.svg" /> <None Remove="Assets\Icons\Controller_JoyConPair.svg" />
<None Remove="Assets\Icons\Controller_JoyConRight.svg" /> <None Remove="Assets\Icons\Controller_JoyConRight.svg" />
@@ -151,7 +150,6 @@
</EmbeddedResource> </EmbeddedResource>
<EmbeddedResource Include="Assets\locales.json" /> <EmbeddedResource Include="Assets\locales.json" />
<EmbeddedResource Include="Assets\Styles\Styles.xaml" /> <EmbeddedResource Include="Assets\Styles\Styles.xaml" />
<EmbeddedResource Include="Assets\Styles\CheckboxMenuItemStyle.axaml" />
<EmbeddedResource Include="Assets\Icons\Controller_JoyConLeft.svg" /> <EmbeddedResource Include="Assets\Icons\Controller_JoyConLeft.svg" />
<EmbeddedResource Include="Assets\Icons\Controller_JoyConPair.svg" /> <EmbeddedResource Include="Assets\Icons\Controller_JoyConPair.svg" />
<EmbeddedResource Include="Assets\Icons\Controller_JoyConRight.svg" /> <EmbeddedResource Include="Assets\Icons\Controller_JoyConRight.svg" />
@@ -175,5 +173,10 @@
<ItemGroup> <ItemGroup>
<Folder Include="Assets\Fonts\Mono\" /> <Folder Include="Assets\Fonts\Mono\" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Compile Update="UI\Applet\UserSelectorDialog.axaml.cs">
<DependentUpon>UserSelectorDialog.axaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
</ItemGroup>
</Project> </Project>

View File

@@ -16,6 +16,5 @@
<Application.Styles> <Application.Styles>
<sty:FluentAvaloniaTheme PreferUserAccentColor="True" PreferSystemTheme="False" /> <sty:FluentAvaloniaTheme PreferUserAccentColor="True" PreferSystemTheme="False" />
<StyleInclude Source="/Assets/Styles/Styles.xaml" /> <StyleInclude Source="/Assets/Styles/Styles.xaml" />
<StyleInclude Source="/Assets/Styles/CheckboxMenuItemStyle.axaml"/>
</Application.Styles> </Application.Styles>
</Application> </Application>

View File

@@ -6,6 +6,7 @@ using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.UI.Controls; using Ryujinx.Ava.UI.Controls;
using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.UI.ViewModels; using Ryujinx.Ava.UI.ViewModels;
using Ryujinx.Ava.UI.ViewModels.Input;
using Ryujinx.Ava.UI.Windows; using Ryujinx.Ava.UI.Windows;
using Ryujinx.Ava.Utilities.Configuration; using Ryujinx.Ava.Utilities.Configuration;
using Ryujinx.Common; using Ryujinx.Common;
@@ -41,7 +42,7 @@ namespace Ryujinx.Ava.UI.Applet
bool okPressed = false; bool okPressed = false;
if (ConfigurationState.Instance.System.IgnoreApplet) if (ConfigurationState.Instance.IgnoreApplet)
return false; return false;
Dispatcher.UIThread.InvokeAsync(async () => Dispatcher.UIThread.InvokeAsync(async () =>

View File

@@ -106,10 +106,6 @@
Click="ExtractApplicationRomFs_Click" Click="ExtractApplicationRomFs_Click"
Header="{ext:Locale GameListContextMenuExtractDataRomFS}" Header="{ext:Locale GameListContextMenuExtractDataRomFS}"
ToolTip.Tip="{ext:Locale GameListContextMenuExtractDataRomFSToolTip}" /> ToolTip.Tip="{ext:Locale GameListContextMenuExtractDataRomFSToolTip}" />
<MenuItem
Click="ExtractAocRomFs_Click"
Header="{ext:Locale GameListContextMenuExtractDataAocRomFS}"
ToolTip.Tip="{ext:Locale GameListContextMenuExtractDataAocRomFSToolTip}" />
<MenuItem <MenuItem
Click="ExtractApplicationLogo_Click" Click="ExtractApplicationLogo_Click"
Header="{ext:Locale GameListContextMenuExtractDataLogo}" Header="{ext:Locale GameListContextMenuExtractDataLogo}"

View File

@@ -3,13 +3,10 @@ using Avalonia.Interactivity;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
using Avalonia.Platform.Storage; using Avalonia.Platform.Storage;
using Avalonia.Threading; using Avalonia.Threading;
using FluentAvalonia.UI.Controls;
using LibHac;
using LibHac.Fs; using LibHac.Fs;
using LibHac.Tools.FsSystem.NcaUtils; using LibHac.Tools.FsSystem.NcaUtils;
using Ryujinx.Ava.Common; using Ryujinx.Ava.Common;
using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.Common.Models;
using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.UI.ViewModels; using Ryujinx.Ava.UI.ViewModels;
using Ryujinx.Ava.UI.Windows; using Ryujinx.Ava.UI.Windows;
@@ -17,7 +14,6 @@ using Ryujinx.Ava.Utilities;
using Ryujinx.Ava.Utilities.AppLibrary; using Ryujinx.Ava.Utilities.AppLibrary;
using Ryujinx.Common.Configuration; using Ryujinx.Common.Configuration;
using Ryujinx.Common.Helper; using Ryujinx.Common.Helper;
using Ryujinx.Common.Logging;
using Ryujinx.HLE.HOS; using Ryujinx.HLE.HOS;
using SkiaSharp; using SkiaSharp;
using System; using System;
@@ -251,7 +247,7 @@ namespace Ryujinx.Ava.UI.Controls
{ {
if (sender is MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel }) if (sender is MenuItem { DataContext: MainWindowViewModel { SelectedApplication: not null } viewModel })
{ {
string shaderCacheDir = Path.Combine(AppDataManager.GamesDirPath, viewModel.SelectedApplication.IdString.ToLower(), "cache", "shader"); string shaderCacheDir = Path.Combine(AppDataManager.GamesDirPath, viewModel.SelectedApplication.IdString, "cache", "shader");
if (!Directory.Exists(shaderCacheDir)) if (!Directory.Exists(shaderCacheDir))
{ {
@@ -283,22 +279,6 @@ namespace Ryujinx.Ava.UI.Controls
viewModel.SelectedApplication.Path, viewModel.SelectedApplication.Path,
viewModel.SelectedApplication.Name); 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) public async void ExtractApplicationLogo_Click(object sender, RoutedEventArgs args)
{ {

View File

@@ -2,10 +2,11 @@
x:Class="Ryujinx.Ava.UI.Controls.ApplicationListView" x:Class="Ryujinx.Ava.UI.Controls.ApplicationListView"
xmlns="https://github.com/avaloniaui" xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 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:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers" xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers"
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
d:DesignHeight="450" d:DesignHeight="450"
d:DesignWidth="800" d:DesignWidth="800"
Focusable="True" Focusable="True"

View File

@@ -1,67 +0,0 @@
<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>

View File

@@ -1,51 +0,0 @@
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;
}
}
}

View File

@@ -69,7 +69,7 @@ namespace Ryujinx.Ava.UI.Controls
VirtualFileSystem ownerVirtualFileSystem, VirtualFileSystem ownerVirtualFileSystem,
HorizonClient ownerHorizonClient) HorizonClient ownerHorizonClient)
{ {
NavigationDialogHost content = new(ownerAccountManager, ownerContentManager, ownerVirtualFileSystem, ownerHorizonClient); var content = new NavigationDialogHost(ownerAccountManager, ownerContentManager, ownerVirtualFileSystem, ownerHorizonClient);
ContentDialog contentDialog = new() ContentDialog contentDialog = new()
{ {
Title = LocaleManager.Instance[LocaleKeys.UserProfileWindowTitle], Title = LocaleManager.Instance[LocaleKeys.UserProfileWindowTitle],

View File

@@ -12,9 +12,9 @@ namespace Ryujinx.Ava.UI.Helpers
public static RelayCommand CreateConditional(Action action, Func<bool> canExecute) public static RelayCommand CreateConditional(Action action, Func<bool> canExecute)
=> new(action, canExecute); => new(action, canExecute);
public static RelayCommand<T> Create<T>(Action<T?> action) public static RelayCommand<T> CreateWithArg<T>(Action<T?> action)
=> new(action); => new(action);
public static RelayCommand<T> CreateConditional<T>(Action<T?> action, Predicate<T?> canExecute) public static RelayCommand<T> CreateConditionalWithArg<T>(Action<T?> action, Predicate<T?> canExecute)
=> new(action, canExecute); => new(action, canExecute);
public static AsyncRelayCommand Create(Func<Task> action) public static AsyncRelayCommand Create(Func<Task> action)
@@ -24,11 +24,11 @@ namespace Ryujinx.Ava.UI.Helpers
public static AsyncRelayCommand CreateSilentFail(Func<Task> action) public static AsyncRelayCommand CreateSilentFail(Func<Task> action)
=> new(action, AsyncRelayCommandOptions.FlowExceptionsToTaskScheduler); => new(action, AsyncRelayCommandOptions.FlowExceptionsToTaskScheduler);
public static AsyncRelayCommand<T> Create<T>(Func<T?, Task> action) public static AsyncRelayCommand<T> CreateWithArg<T>(Func<T?, Task> action)
=> new(action, AsyncRelayCommandOptions.None); => new(action, AsyncRelayCommandOptions.None);
public static AsyncRelayCommand<T> CreateConcurrent<T>(Func<T?, Task> action) public static AsyncRelayCommand<T> CreateConcurrentWithArg<T>(Func<T?, Task> action)
=> new(action, AsyncRelayCommandOptions.AllowConcurrentExecutions); => new(action, AsyncRelayCommandOptions.AllowConcurrentExecutions);
public static AsyncRelayCommand<T> CreateSilentFail<T>(Func<T?, Task> action) public static AsyncRelayCommand<T> CreateSilentFailWithArg<T>(Func<T?, Task> action)
=> new(action, AsyncRelayCommandOptions.FlowExceptionsToTaskScheduler); => new(action, AsyncRelayCommandOptions.FlowExceptionsToTaskScheduler);
public static AsyncRelayCommand CreateConditional(Func<Task> action, Func<bool> canExecute) 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) public static AsyncRelayCommand CreateSilentFailConditional(Func<Task> action, Func<bool> canExecute)
=> new(action, canExecute, AsyncRelayCommandOptions.FlowExceptionsToTaskScheduler); => new(action, canExecute, AsyncRelayCommandOptions.FlowExceptionsToTaskScheduler);
public static AsyncRelayCommand<T> CreateConditional<T>(Func<T?, Task> action, Predicate<T?> canExecute) public static AsyncRelayCommand<T> CreateConditionalWithArg<T>(Func<T?, Task> action, Predicate<T?> canExecute)
=> new(action, canExecute, AsyncRelayCommandOptions.None); => new(action, canExecute, AsyncRelayCommandOptions.None);
public static AsyncRelayCommand<T> CreateConcurrentConditional<T>(Func<T?, Task> action, Predicate<T?> canExecute) public static AsyncRelayCommand<T> CreateConcurrentConditionalWithArg<T>(Func<T?, Task> action, Predicate<T?> canExecute)
=> new(action, canExecute, AsyncRelayCommandOptions.AllowConcurrentExecutions); => new(action, canExecute, AsyncRelayCommandOptions.AllowConcurrentExecutions);
public static AsyncRelayCommand<T> CreateSilentFailConditional<T>(Func<T?, Task> action, Predicate<T?> canExecute) public static AsyncRelayCommand<T> CreateSilentFailConditionalWithArg<T>(Func<T?, Task> action, Predicate<T?> canExecute)
=> new(action, canExecute, AsyncRelayCommandOptions.FlowExceptionsToTaskScheduler); => new(action, canExecute, AsyncRelayCommandOptions.FlowExceptionsToTaskScheduler);
} }
} }

View File

@@ -1,4 +1,3 @@
using Avalonia.Media;
using Ryujinx.Ava.UI.ViewModels; using Ryujinx.Ava.UI.ViewModels;
using Ryujinx.Common.Configuration.Hid; using Ryujinx.Common.Configuration.Hid;
using Ryujinx.Common.Configuration.Hid.Controller; using Ryujinx.Common.Configuration.Hid.Controller;
@@ -409,58 +408,6 @@ namespace Ryujinx.Ava.UI.Models.Input
OnPropertyChanged(); OnPropertyChanged();
} }
} }
private bool _enableLedChanging;
public bool EnableLedChanging
{
get => _enableLedChanging;
set
{
_enableLedChanging = value;
OnPropertyChanged();
}
}
public bool ShowLedColorPicker => !TurnOffLed && !UseRainbowLed;
private bool _turnOffLed;
public bool TurnOffLed
{
get => _turnOffLed;
set
{
_turnOffLed = value;
OnPropertyChanged();
OnPropertyChanged(nameof(ShowLedColorPicker));
}
}
private bool _useRainbowLed;
public bool UseRainbowLed
{
get => _useRainbowLed;
set
{
_useRainbowLed = value;
OnPropertyChanged();
OnPropertyChanged(nameof(ShowLedColorPicker));
}
}
private Color _ledColor;
public Color LedColor
{
get => _ledColor;
set
{
_ledColor = value;
OnPropertyChanged();
}
}
public GamepadInputConfig(InputConfig config) public GamepadInputConfig(InputConfig config)
{ {
@@ -536,25 +483,12 @@ namespace Ryujinx.Ava.UI.Models.Input
WeakRumble = controllerInput.Rumble.WeakRumble; WeakRumble = controllerInput.Rumble.WeakRumble;
StrongRumble = controllerInput.Rumble.StrongRumble; StrongRumble = controllerInput.Rumble.StrongRumble;
} }
if (controllerInput.Led != null)
{
EnableLedChanging = controllerInput.Led.EnableLed;
TurnOffLed = controllerInput.Led.TurnOffLed;
UseRainbowLed = controllerInput.Led.UseRainbow;
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() public InputConfig GetConfig()
{ {
StandardControllerInputConfig config = new() var config = new StandardControllerInputConfig
{ {
Id = Id, Id = Id,
Backend = InputBackendType.GamepadSDL2, Backend = InputBackendType.GamepadSDL2,
@@ -606,13 +540,6 @@ namespace Ryujinx.Ava.UI.Models.Input
WeakRumble = WeakRumble, WeakRumble = WeakRumble,
StrongRumble = StrongRumble, StrongRumble = StrongRumble,
}, },
Led = new LedConfigController
{
EnableLed = EnableLedChanging,
TurnOffLed = this.TurnOffLed,
UseRainbow = UseRainbowLed,
LedColor = LedColor.ToUInt32()
},
Version = InputConfig.CurrentVersion, Version = InputConfig.CurrentVersion,
DeadzoneLeft = DeadzoneLeft, DeadzoneLeft = DeadzoneLeft,
DeadzoneRight = DeadzoneRight, DeadzoneRight = DeadzoneRight,

View File

@@ -432,7 +432,7 @@ namespace Ryujinx.Ava.UI.ViewModels
{ {
try try
{ {
HttpResponseMessage response = await _httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Head, "https://raw.githubusercontent.com/Ryubing/Ryujinx/refs/heads/master/assets/amiibo/Amiibo.json")); HttpResponseMessage response = await _httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Head, "https://raw.githubusercontent.com/GreemDev/Ryujinx/refs/heads/master/assets/amiibo/Amiibo.json"));
if (response.IsSuccessStatusCode) if (response.IsSuccessStatusCode)
{ {
@@ -451,7 +451,7 @@ namespace Ryujinx.Ava.UI.ViewModels
{ {
try try
{ {
HttpResponseMessage response = await _httpClient.GetAsync($"https://raw.githubusercontent.com/Ryubing/Ryujinx/refs/heads/master/assets/amiibo/Amiibo.json"); HttpResponseMessage response = await _httpClient.GetAsync($"https://raw.githubusercontent.com/GreemDev/Ryujinx/refs/heads/master/assets/amiibo/Amiibo.json");
if (response.IsSuccessStatusCode) if (response.IsSuccessStatusCode)
{ {

View File

@@ -1,25 +0,0 @@
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();
}
}
}

View File

@@ -1,8 +1,5 @@
using Avalonia.Svg.Skia; using Avalonia.Svg.Skia;
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using FluentAvalonia.UI.Controls;
using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.UI.Models.Input; using Ryujinx.Ava.UI.Models.Input;
using Ryujinx.Ava.UI.Views.Input; using Ryujinx.Ava.UI.Views.Input;
@@ -40,7 +37,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
[ObservableProperty] private SvgImage _image; [ObservableProperty] private SvgImage _image;
public InputViewModel ParentModel { get; } public readonly InputViewModel ParentModel;
public ControllerInputViewModel(InputViewModel model, GamepadInputConfig config) public ControllerInputViewModel(InputViewModel model, GamepadInputConfig config)
{ {
@@ -60,16 +57,6 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
await RumbleInputView.Show(this); await RumbleInputView.Show(this);
} }
public RelayCommand LedDisabledChanged => Commands.Create(() =>
{
if (!Config.EnableLedChanging) return;
if (Config.TurnOffLed)
ParentModel.SelectedGamepad.ClearLed();
else
ParentModel.SelectedGamepad.SetLed(Config.LedColor.ToUInt32());
});
public void OnParentModelChanged() public void OnParentModelChanged()
{ {
IsLeft = ParentModel.IsLeft; IsLeft = ParentModel.IsLeft;

View File

@@ -3,7 +3,6 @@ using Avalonia.Controls;
using Avalonia.Svg.Skia; using Avalonia.Svg.Skia;
using Avalonia.Threading; using Avalonia.Threading;
using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.ComponentModel;
using Gommon;
using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.Input; using Ryujinx.Ava.Input;
using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.Helpers;
@@ -55,18 +54,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
private static readonly InputConfigJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions()); private static readonly InputConfigJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions());
public IGamepadDriver AvaloniaKeyboardDriver { get; } public IGamepadDriver AvaloniaKeyboardDriver { get; }
public IGamepad SelectedGamepad { get; private set; }
private IGamepad _selectedGamepad;
public IGamepad SelectedGamepad
{
get => _selectedGamepad;
private set
{
_selectedGamepad = value;
OnPropertiesChanged(nameof(HasLed), nameof(CanClearLed));
}
}
public ObservableCollection<PlayerModel> PlayerIndexes { get; set; } public ObservableCollection<PlayerModel> PlayerIndexes { get; set; }
public ObservableCollection<(DeviceType Type, string Id, string Name)> Devices { get; set; } public ObservableCollection<(DeviceType Type, string Id, string Name)> Devices { get; set; }
@@ -81,9 +69,6 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
public bool IsRight { get; set; } public bool IsRight { get; set; }
public bool IsLeft { get; set; } public bool IsLeft { get; set; }
public bool HasLed => SelectedGamepad.Features.HasFlag(GamepadFeaturesFlag.Led);
public bool CanClearLed => SelectedGamepad.Name.ContainsIgnoreCase("DualSense");
public bool IsModified { get; set; } public bool IsModified { get; set; }
public event Action NotifyChangesEvent; public event Action NotifyChangesEvent;

View File

@@ -488,19 +488,6 @@ 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 public bool ShowConsole
{ {
get => ConfigurationState.Instance.UI.ShowConsole; get => ConfigurationState.Instance.UI.ShowConsole;
@@ -637,7 +624,6 @@ namespace Ryujinx.Ava.UI.ViewModels
ApplicationSort.FileSize => LocaleManager.Instance[LocaleKeys.GameListHeaderFileSize], ApplicationSort.FileSize => LocaleManager.Instance[LocaleKeys.GameListHeaderFileSize],
ApplicationSort.Path => LocaleManager.Instance[LocaleKeys.GameListHeaderPath], ApplicationSort.Path => LocaleManager.Instance[LocaleKeys.GameListHeaderPath],
ApplicationSort.Favorite => LocaleManager.Instance[LocaleKeys.CommonFavorite], ApplicationSort.Favorite => LocaleManager.Instance[LocaleKeys.CommonFavorite],
ApplicationSort.TitleId => LocaleManager.Instance[LocaleKeys.DlcManagerTableHeadingTitleIdLabel],
_ => string.Empty, _ => string.Empty,
}; };
} }
@@ -708,7 +694,6 @@ namespace Ryujinx.Ava.UI.ViewModels
public IHostUIHandler UiHandler { get; internal set; } public IHostUIHandler UiHandler { get; internal set; }
public bool IsSortedByFavorite => SortMode == ApplicationSort.Favorite; public bool IsSortedByFavorite => SortMode == ApplicationSort.Favorite;
public bool IsSortedByTitle => SortMode == ApplicationSort.Title; public bool IsSortedByTitle => SortMode == ApplicationSort.Title;
public bool IsSortedByTitleId => SortMode == ApplicationSort.TitleId;
public bool IsSortedByDeveloper => SortMode == ApplicationSort.Developer; public bool IsSortedByDeveloper => SortMode == ApplicationSort.Developer;
public bool IsSortedByLastPlayed => SortMode == ApplicationSort.LastPlayed; public bool IsSortedByLastPlayed => SortMode == ApplicationSort.LastPlayed;
public bool IsSortedByTimePlayed => SortMode == ApplicationSort.TotalTimePlayed; public bool IsSortedByTimePlayed => SortMode == ApplicationSort.TotalTimePlayed;
@@ -741,7 +726,6 @@ namespace Ryujinx.Ava.UI.ViewModels
ApplicationSort.FileSize => CreateComparer(IsAscending, app => app.FileSize), ApplicationSort.FileSize => CreateComparer(IsAscending, app => app.FileSize),
ApplicationSort.Path => CreateComparer(IsAscending, app => app.Path), ApplicationSort.Path => CreateComparer(IsAscending, app => app.Path),
ApplicationSort.Favorite => CreateComparer(IsAscending, app => new AppListFavoriteComparable(app)), ApplicationSort.Favorite => CreateComparer(IsAscending, app => new AppListFavoriteComparable(app)),
ApplicationSort.TitleId => CreateComparer(IsAscending, app => app.Id),
_ => null, _ => null,
#pragma warning restore IDE0055 #pragma warning restore IDE0055
}; };
@@ -1211,11 +1195,6 @@ namespace Ryujinx.Ava.UI.ViewModels
StartGamesInFullscreen = !StartGamesInFullscreen; StartGamesInFullscreen = !StartGamesInFullscreen;
} }
public void ToggleStartGamesWithoutUI()
{
StartGamesWithoutUI = !StartGamesWithoutUI;
}
public void ToggleShowConsole() public void ToggleShowConsole()
{ {
ShowConsole = !ShowConsole; ShowConsole = !ShowConsole;
@@ -1662,7 +1641,10 @@ namespace Ryujinx.Ava.UI.ViewModels
public async Task OpenAmiiboWindow() public async Task OpenAmiiboWindow()
{ {
if (AppHost.Device.System.SearchingForAmiibo(out int deviceId) && IsGameRunning) if (!IsAmiiboRequested)
return;
if (AppHost.Device.System.SearchingForAmiibo(out int deviceId))
{ {
string titleId = AppHost.Device.Processes.ActiveApplication.ProgramIdText.ToUpper(); string titleId = AppHost.Device.Processes.ActiveApplication.ProgramIdText.ToUpper();
AmiiboWindow window = new(ShowAll, LastScannedAmiiboId, titleId); AmiiboWindow window = new(ShowAll, LastScannedAmiiboId, titleId);
@@ -1680,7 +1662,10 @@ namespace Ryujinx.Ava.UI.ViewModels
} }
public async Task OpenBinFile() public async Task OpenBinFile()
{ {
if (AppHost.Device.System.SearchingForAmiibo(out _) && IsGameRunning) if (!IsAmiiboRequested)
return;
if (AppHost.Device.System.SearchingForAmiibo(out int deviceId))
{ {
var result = await StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions var result = await StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
{ {

View File

@@ -488,6 +488,7 @@ namespace Ryujinx.Ava.UI.ViewModels
EnableDiscordIntegration = config.EnableDiscordIntegration; EnableDiscordIntegration = config.EnableDiscordIntegration;
CheckUpdatesOnStart = config.CheckUpdatesOnStart; CheckUpdatesOnStart = config.CheckUpdatesOnStart;
ShowConfirmExit = config.ShowConfirmExit; ShowConfirmExit = config.ShowConfirmExit;
IgnoreApplet = config.IgnoreApplet;
RememberWindowState = config.RememberWindowState; RememberWindowState = config.RememberWindowState;
ShowTitleBar = config.ShowTitleBar; ShowTitleBar = config.ShowTitleBar;
HideCursor = (int)config.HideCursor.Value; HideCursor = (int)config.HideCursor.Value;
@@ -531,7 +532,6 @@ namespace Ryujinx.Ava.UI.ViewModels
EnableFsIntegrityChecks = config.System.EnableFsIntegrityChecks; EnableFsIntegrityChecks = config.System.EnableFsIntegrityChecks;
DramSize = config.System.DramSize; DramSize = config.System.DramSize;
IgnoreMissingServices = config.System.IgnoreMissingServices; IgnoreMissingServices = config.System.IgnoreMissingServices;
IgnoreApplet = config.System.IgnoreApplet;
// CPU // CPU
EnablePptc = config.System.EnablePtc; EnablePptc = config.System.EnablePtc;
@@ -591,6 +591,7 @@ namespace Ryujinx.Ava.UI.ViewModels
config.EnableDiscordIntegration.Value = EnableDiscordIntegration; config.EnableDiscordIntegration.Value = EnableDiscordIntegration;
config.CheckUpdatesOnStart.Value = CheckUpdatesOnStart; config.CheckUpdatesOnStart.Value = CheckUpdatesOnStart;
config.ShowConfirmExit.Value = ShowConfirmExit; config.ShowConfirmExit.Value = ShowConfirmExit;
config.IgnoreApplet.Value = IgnoreApplet;
config.RememberWindowState.Value = RememberWindowState; config.RememberWindowState.Value = RememberWindowState;
config.ShowTitleBar.Value = ShowTitleBar; config.ShowTitleBar.Value = ShowTitleBar;
config.HideCursor.Value = (HideCursorMode)HideCursor; config.HideCursor.Value = (HideCursorMode)HideCursor;
@@ -631,10 +632,12 @@ namespace Ryujinx.Ava.UI.ViewModels
} }
config.System.SystemTimeOffset.Value = Convert.ToInt64((CurrentDate.ToUnixTimeSeconds() + CurrentTime.TotalSeconds) - DateTimeOffset.Now.ToUnixTimeSeconds()); 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.EnableFsIntegrityChecks.Value = EnableFsIntegrityChecks;
config.System.DramSize.Value = DramSize; config.System.DramSize.Value = DramSize;
config.System.IgnoreMissingServices.Value = IgnoreMissingServices; config.System.IgnoreMissingServices.Value = IgnoreMissingServices;
config.System.IgnoreApplet.Value = IgnoreApplet;
// CPU // CPU
config.System.EnablePtc.Value = EnablePptc; config.System.EnablePtc.Value = EnablePptc;
@@ -643,9 +646,6 @@ namespace Ryujinx.Ava.UI.ViewModels
config.System.UseHypervisor.Value = UseHypervisor; config.System.UseHypervisor.Value = UseHypervisor;
// Graphics // Graphics
config.Graphics.VSyncMode.Value = VSyncMode;
config.Graphics.EnableCustomVSyncInterval.Value = EnableCustomVSyncInterval;
config.Graphics.CustomVSyncInterval.Value = CustomVSyncInterval;
config.Graphics.GraphicsBackend.Value = (GraphicsBackend)GraphicsBackendIndex; config.Graphics.GraphicsBackend.Value = (GraphicsBackend)GraphicsBackendIndex;
config.Graphics.PreferredGpu.Value = _gpuIds.ElementAtOrDefault(PreferredGpuIndex); config.Graphics.PreferredGpu.Value = _gpuIds.ElementAtOrDefault(PreferredGpuIndex);
config.Graphics.EnableShaderCache.Value = EnableShaderCache; config.Graphics.EnableShaderCache.Value = EnableShaderCache;

View File

@@ -4,7 +4,6 @@
xmlns:ext="clr-namespace:Ryujinx.Ava.Common.Markup" xmlns:ext="clr-namespace:Ryujinx.Ava.Common.Markup"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 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:controls="clr-namespace:Ryujinx.Ava.UI.Controls"
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels.Input" xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels.Input"
xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers" xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers"
@@ -429,7 +428,7 @@
</StackPanel> </StackPanel>
</StackPanel> </StackPanel>
</Border> </Border>
<!-- Motion, Rumble, LED --> <!-- Motion + Rumble -->
<StackPanel <StackPanel
Margin="0,10,0,0" Margin="0,10,0,0"
Spacing="5" Spacing="5"
@@ -487,59 +486,6 @@
</Button> </Button>
</Grid> </Grid>
</Border> </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="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<CheckBox
Margin="10, 10, 5, 10"
MinWidth="0"
Grid.Column="0"
IsChecked="{Binding Config.EnableLedChanging, Mode=TwoWay}">
<TextBlock Text="{ext:Locale ControllerSettingsLedColor}" />
</CheckBox>
<CheckBox
Margin="5, 10, 5, 10"
MinWidth="0"
Grid.Column="1"
IsVisible="{Binding ParentModel.CanClearLed}"
IsChecked="{Binding Config.TurnOffLed, Mode=TwoWay}"
Command="{Binding LedDisabledChanged}">
<TextBlock Text="{ext:Locale ControllerSettingsLedColorDisable}" />
</CheckBox>
<CheckBox
Margin="5, 10 5,10"
MinWidth="0"
Grid.Column="2"
IsEnabled="{Binding !Config.TurnOffLed}"
IsChecked="{Binding Config.UseRainbowLed, Mode=TwoWay}">
<TextBlock Text="{ext:Locale ControllerSettingsLedColorRainbow}" />
</CheckBox>
<ui:ColorPickerButton
Grid.Column="3"
IsEnabled="{Binding Config.ShowLedColorPicker}"
Margin="5, 10, 10, 10"
IsMoreButtonVisible="False"
UseColorPalette="False"
UseColorTriangle="False"
UseColorWheel="False"
ShowAcceptDismissButtons="False"
IsAlphaEnabled="False"
AttachedToVisualTree="ColorPickerButton_OnAttachedToVisualTree"
ColorChanged="ColorPickerButton_OnColorChanged"
Color="{Binding Config.LedColor, Mode=TwoWay}">
</ui:ColorPickerButton>
</Grid>
</Border>
</StackPanel> </StackPanel>
</StackPanel> </StackPanel>
<!-- Right Controls --> <!-- Right Controls -->

View File

@@ -4,14 +4,14 @@ using Avalonia.Controls.Primitives;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Interactivity; using Avalonia.Interactivity;
using Avalonia.LogicalTree; using Avalonia.LogicalTree;
using FluentAvalonia.UI.Controls; using DiscordRPC;
using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.UI.Models;
using Ryujinx.Ava.UI.ViewModels.Input; using Ryujinx.Ava.UI.ViewModels.Input;
using Ryujinx.Common.Configuration.Hid.Controller; using Ryujinx.Common.Configuration.Hid.Controller;
using Ryujinx.Common.Logging;
using Ryujinx.Input; using Ryujinx.Input;
using Ryujinx.Input.Assigner; using Ryujinx.Input.Assigner;
using System.Linq; using System;
using StickInputId = Ryujinx.Common.Configuration.Hid.Controller.StickInputId; using StickInputId = Ryujinx.Common.Configuration.Hid.Controller.StickInputId;
namespace Ryujinx.Ava.UI.Views.Input namespace Ryujinx.Ava.UI.Views.Input
@@ -85,7 +85,7 @@ namespace Ryujinx.Ava.UI.Views.Input
private void Button_IsCheckedChanged(object sender, RoutedEventArgs e) private void Button_IsCheckedChanged(object sender, RoutedEventArgs e)
{ {
if (sender is ToggleButton button) if (sender is ToggleButton button)
{ {
if (button.IsChecked is true) if (button.IsChecked is true)
{ {
@@ -106,9 +106,7 @@ namespace Ryujinx.Ava.UI.Views.Input
var viewModel = (DataContext as ControllerInputViewModel); var viewModel = (DataContext as ControllerInputViewModel);
IKeyboard keyboard = IKeyboard keyboard = (IKeyboard)viewModel.ParentModel.AvaloniaKeyboardDriver.GetGamepad("0"); // Open Avalonia keyboard for cancel operations.
(IKeyboard)viewModel.ParentModel.AvaloniaKeyboardDriver
.GetGamepad("0"); // Open Avalonia keyboard for cancel operations.
IButtonAssigner assigner = CreateButtonAssigner(isStick); IButtonAssigner assigner = CreateButtonAssigner(isStick);
_currentAssigner.ButtonAssigned += (sender, e) => _currentAssigner.ButtonAssigned += (sender, e) =>
@@ -236,31 +234,8 @@ namespace Ryujinx.Ava.UI.Views.Input
protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e) protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
{ {
base.OnDetachedFromVisualTree(e); base.OnDetachedFromVisualTree(e);
foreach (IGamepad gamepad in RyujinxApp.MainWindow.InputManager.GamepadDriver.GetGamepads())
{
gamepad?.ClearLed();
}
_currentAssigner?.Cancel(); _currentAssigner?.Cancel();
_currentAssigner = null; _currentAssigner = null;
} }
private void ColorPickerButton_OnColorChanged(ColorPickerButton sender, ColorButtonColorChangedEventArgs args)
{
if (!args.NewColor.HasValue) return;
if (DataContext is not ControllerInputViewModel cVm) return;
if (!cVm.Config.EnableLedChanging) return;
cVm.ParentModel.SelectedGamepad.SetLed(args.NewColor.Value.ToUInt32());
}
private void ColorPickerButton_OnAttachedToVisualTree(object sender, VisualTreeAttachmentEventArgs e)
{
if (DataContext is not ControllerInputViewModel cVm) return;
if (!cVm.Config.EnableLedChanging) return;
cVm.ParentModel.SelectedGamepad.SetLed(cVm.Config.LedColor.ToUInt32());
}
} }
} }

View File

@@ -81,16 +81,25 @@
<MenuItem <MenuItem
Command="{Binding ToggleFullscreen}" Command="{Binding ToggleFullscreen}"
Header="{ext:Locale MenuBarOptionsToggleFullscreen}" Header="{ext:Locale MenuBarOptionsToggleFullscreen}"
Classes="withCheckbox"
Padding="0" Padding="0"
Icon="{ext:Icon fa-solid fa-expand}" Icon="{ext:Icon fa-solid fa-expand}"
InputGesture="F11"> 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>
<MenuItem <MenuItem
Padding="0" Padding="0"
Command="{Binding ToggleStartGamesInFullscreen}" Command="{Binding ToggleStartGamesInFullscreen}"
Header="{ext:Locale MenuBarOptionsStartGamesInFullscreen}" Header="{ext:Locale MenuBarOptionsStartGamesInFullscreen}">
Classes="withCheckbox">
<MenuItem.Icon> <MenuItem.Icon>
<CheckBox <CheckBox
MinWidth="{DynamicResource CheckBoxSize}" MinWidth="{DynamicResource CheckBoxSize}"
@@ -98,26 +107,23 @@
IsChecked="{Binding StartGamesInFullscreen, Mode=TwoWay}" IsChecked="{Binding StartGamesInFullscreen, Mode=TwoWay}"
Padding="0" /> Padding="0" />
</MenuItem.Icon> </MenuItem.Icon>
</MenuItem> <MenuItem.Styles>
<MenuItem <Style Selector="Viewbox#PART_IconPresenter">
Padding="0" <Setter Property="MaxHeight" Value="36" />
Command="{Binding ToggleStartGamesWithoutUI}" <Setter Property="MinHeight" Value="36" />
Header="{ext:Locale MenuBarOptionsStartGamesWithoutUI}" <Setter Property="MaxWidth" Value="36" />
Classes="withCheckbox"> <Setter Property="MinWidth" Value="36" />
<MenuItem.Icon> </Style>
<CheckBox <Style Selector="ContentPresenter#PART_HeaderPresenter">
MinWidth="{DynamicResource CheckBoxSize}" <Setter Property="Padding" Value="-10,0,0,0" />
MinHeight="{DynamicResource CheckBoxSize}" </Style>
IsChecked="{Binding StartGamesWithoutUI, Mode=TwoWay}" </MenuItem.Styles>
Padding="0" />
</MenuItem.Icon>
</MenuItem> </MenuItem>
<MenuItem <MenuItem
Padding="0" Padding="0"
IsVisible="{Binding ShowConsoleVisible}" IsVisible="{Binding ShowConsoleVisible}"
Command="{Binding ToggleShowConsole}" Command="{Binding ToggleShowConsole}"
Header="{ext:Locale MenuBarOptionsShowConsole}" Header="{ext:Locale MenuBarOptionsShowConsole}">
Classes="withCheckbox">
<MenuItem.Icon> <MenuItem.Icon>
<CheckBox <CheckBox
MinWidth="{DynamicResource CheckBoxSize}" MinWidth="{DynamicResource CheckBoxSize}"
@@ -125,14 +131,35 @@
IsChecked="{Binding ShowConsole, Mode=TwoWay}" IsChecked="{Binding ShowConsole, Mode=TwoWay}"
Padding="0" /> Padding="0" />
</MenuItem.Icon> </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>
<Separator/> <Separator/>
<MenuItem <MenuItem
Name="ChangeLanguageMenuItem" Name="ChangeLanguageMenuItem"
Padding="0" Padding="0"
Header="{ext:Locale MenuBarOptionsChangeLanguage}" Header="{ext:Locale MenuBarOptionsChangeLanguage}"
Icon="{ext:Icon fa-solid fa-language}" Icon="{ext:Icon fa-solid fa-language}">
Classes="withCheckbox"> <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>
<MenuItem <MenuItem
Name="ToggleFileTypesMenuItem" Name="ToggleFileTypesMenuItem"
@@ -144,8 +171,18 @@
Padding="0" Padding="0"
Header="{ext:Locale MenuBarOptionsSettings}" Header="{ext:Locale MenuBarOptionsSettings}"
Icon="{ext:Icon fa-solid fa-gear}" Icon="{ext:Icon fa-solid fa-gear}"
ToolTip.Tip="{ext:Locale OpenSettingsTooltip}" ToolTip.Tip="{ext:Locale OpenSettingsTooltip}">
Classes="withCheckbox"> <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>
<MenuItem <MenuItem
Command="{Binding ManageProfiles}" Command="{Binding ManageProfiles}"
@@ -153,15 +190,25 @@
Header="{ext:Locale MenuBarOptionsManageUserProfiles}" Header="{ext:Locale MenuBarOptionsManageUserProfiles}"
Icon="{ext:Icon mdi-account}" Icon="{ext:Icon mdi-account}"
IsEnabled="{Binding EnableNonGameRunningControls}" IsEnabled="{Binding EnableNonGameRunningControls}"
ToolTip.Tip="{ext:Locale OpenProfileManagerTooltip}" ToolTip.Tip="{ext:Locale OpenProfileManagerTooltip}">
Classes="withCheckbox"> <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>
</MenuItem> </MenuItem>
<MenuItem <MenuItem
Name="ActionsMenuItem" Name="ActionsMenuItem"
VerticalAlignment="Center" VerticalAlignment="Center"
Header="{ext:Locale MenuBarActions}" Header="{ext:Locale MenuBarActions}"
IsVisible="{Binding !EnableNonGameRunningControls}"> IsEnabled="{Binding IsGameRunning}">
<MenuItem <MenuItem
Name="PauseEmulationMenuItem" Name="PauseEmulationMenuItem"
Header="{ext:Locale MenuBarOptionsPauseEmulation}" Header="{ext:Locale MenuBarOptionsPauseEmulation}"
@@ -218,21 +265,21 @@
Icon="{ext:Icon fa-solid fa-code}" Icon="{ext:Icon fa-solid fa-code}"
IsEnabled="{Binding IsGameRunning}" /> IsEnabled="{Binding IsGameRunning}" />
</MenuItem> </MenuItem>
<MenuItem VerticalAlignment="Center" Header="{ext:Locale MenuBarActions}" IsVisible="{Binding EnableNonGameRunningControls}"> <MenuItem VerticalAlignment="Center" Header="{ext:Locale MenuBarTools}">
<MenuItem Header="{ext:Locale MenuBarActionsInstallKeys}" Icon="{ext:Icon fa-solid fa-key}"> <MenuItem Header="{ext:Locale MenuBarToolsInstallKeys}" Icon="{ext:Icon fa-solid fa-key}" IsEnabled="{Binding EnableNonGameRunningControls}">
<MenuItem Command="{Binding InstallKeysFromFile}" Header="{ext:Locale MenuBarFileActionsInstallKeysFromFile}" Icon="{ext:Icon mdi-file-cog}" /> <MenuItem Command="{Binding InstallKeysFromFile}" Header="{ext:Locale MenuBarFileToolsInstallKeysFromFile}" Icon="{ext:Icon mdi-file-cog}" />
<MenuItem Command="{Binding InstallKeysFromFolder}" Header="{ext:Locale MenuBarFileActionsInstallKeysFromFolder}" Icon="{ext:Icon mdi-folder-cog}" /> <MenuItem Command="{Binding InstallKeysFromFolder}" Header="{ext:Locale MenuBarFileToolsInstallKeysFromFolder}" Icon="{ext:Icon mdi-folder-cog}" />
</MenuItem> </MenuItem>
<MenuItem Header="{ext:Locale MenuBarActionsInstallFirmware}" Icon="{ext:Icon fa-solid fa-download}"> <MenuItem Header="{ext:Locale MenuBarToolsInstallFirmware}" Icon="{ext:Icon fa-solid fa-download}" IsEnabled="{Binding EnableNonGameRunningControls}">
<MenuItem Command="{Binding InstallFirmwareFromFile}" Header="{ext:Locale MenuBarActionsInstallFirmwareFromFile}" Icon="{ext:Icon mdi-file-cog}" /> <MenuItem Command="{Binding InstallFirmwareFromFile}" Header="{ext:Locale MenuBarFileToolsInstallFirmwareFromFile}" Icon="{ext:Icon mdi-file-cog}" />
<MenuItem Command="{Binding InstallFirmwareFromFolder}" Header="{ext:Locale MenuBarActionsInstallFirmwareFromDirectory}" Icon="{ext:Icon mdi-folder-cog}" /> <MenuItem Command="{Binding InstallFirmwareFromFolder}" Header="{ext:Locale MenuBarFileToolsInstallFirmwareFromDirectory}" Icon="{ext:Icon mdi-folder-cog}" />
</MenuItem> </MenuItem>
<MenuItem Header="{ext:Locale MenuBarActionsManageFileTypes}" IsVisible="{Binding ManageFileTypesVisible}"> <MenuItem Header="{ext:Locale MenuBarToolsManageFileTypes}" IsVisible="{Binding ManageFileTypesVisible}">
<MenuItem Name="InstallFileTypesMenuItem" Header="{ext:Locale MenuBarActionsInstallFileTypes}" IsEnabled="{Binding AreMimeTypesRegistered, Converter={x:Static BoolConverters.Not}}" /> <MenuItem Name="InstallFileTypesMenuItem" Header="{ext:Locale MenuBarToolsInstallFileTypes}" IsEnabled="{Binding AreMimeTypesRegistered, Converter={x:Static BoolConverters.Not}}" />
<MenuItem Name="UninstallFileTypesMenuItem" Header="{ext:Locale MenuBarActionsUninstallFileTypes}" IsEnabled="{Binding AreMimeTypesRegistered}" /> <MenuItem Name="UninstallFileTypesMenuItem" Header="{ext:Locale MenuBarToolsUninstallFileTypes}" IsEnabled="{Binding AreMimeTypesRegistered}" />
</MenuItem> </MenuItem>
<Separator /> <Separator />
<MenuItem Name="XciTrimmerMenuItem" Header="{ext:Locale MenuBarActionsXCITrimmer}" Icon="{ext:Icon fa-solid fa-scissors}" /> <MenuItem Name="XciTrimmerMenuItem" Header="{ext:Locale MenuBarToolsXCITrimmer}" IsEnabled="{Binding EnableNonGameRunningControls}" Icon="{ext:Icon fa-solid fa-scissors}" />
</MenuItem> </MenuItem>
<MenuItem VerticalAlignment="Center" Header="{ext:Locale MenuBarView}"> <MenuItem VerticalAlignment="Center" Header="{ext:Locale MenuBarView}">
<MenuItem VerticalAlignment="Center" Header="{ext:Locale MenuBarViewWindow}"> <MenuItem VerticalAlignment="Center" Header="{ext:Locale MenuBarViewWindow}">
@@ -264,19 +311,19 @@
Name="FaqMenuItem" Name="FaqMenuItem"
Header="{ext:Locale MenuBarHelpFaq}" Header="{ext:Locale MenuBarHelpFaq}"
Icon="{ext:Icon fa-github}" Icon="{ext:Icon fa-github}"
CommandParameter="https://github.com/Ryubing/Ryujinx/wiki/FAQ-and-Troubleshooting" CommandParameter="https://github.com/GreemDev/Ryujinx/wiki/FAQ-and-Troubleshooting"
ToolTip.Tip="{ext:Locale MenuBarHelpFaqTooltip}" /> ToolTip.Tip="{ext:Locale MenuBarHelpFaqTooltip}" />
<MenuItem <MenuItem
Name="SetupGuideMenuItem" Name="SetupGuideMenuItem"
Header="{ext:Locale MenuBarHelpSetup}" Header="{ext:Locale MenuBarHelpSetup}"
Icon="{ext:Icon fa-github}" Icon="{ext:Icon fa-github}"
CommandParameter="https://github.com/Ryubing/Ryujinx/wiki/Ryujinx-Setup-&amp;-Configuration-Guide" CommandParameter="https://github.com/GreemDev/Ryujinx/wiki/Ryujinx-Setup-&amp;-Configuration-Guide"
ToolTip.Tip="{ext:Locale MenuBarHelpSetupTooltip}" /> ToolTip.Tip="{ext:Locale MenuBarHelpSetupTooltip}" />
<MenuItem <MenuItem
Name="LdnGuideMenuItem" Name="LdnGuideMenuItem"
Header="{ext:Locale MenuBarHelpMultiplayer}" Header="{ext:Locale MenuBarHelpMultiplayer}"
Icon="{ext:Icon fa-github}" Icon="{ext:Icon fa-github}"
CommandParameter="https://github.com/Ryubing/Ryujinx/wiki/Multiplayer%E2%80%90(LDN%E2%80%90Local%E2%80%90Wireless)%E2%80%90Guide" CommandParameter="https://github.com/GreemDev/Ryujinx/wiki/Multiplayer%E2%80%90(LDN%E2%80%90Local%E2%80%90Wireless)%E2%80%90Guide"
ToolTip.Tip="{ext:Locale MenuBarHelpMultiplayerTooltip}" /> ToolTip.Tip="{ext:Locale MenuBarHelpMultiplayerTooltip}" />
</MenuItem> </MenuItem>
</MenuItem> </MenuItem>

View File

@@ -37,20 +37,26 @@ namespace Ryujinx.Ava.UI.Views.Main
ToggleFileTypesMenuItem.ItemsSource = GenerateToggleFileTypeItems(); ToggleFileTypesMenuItem.ItemsSource = GenerateToggleFileTypeItems();
ChangeLanguageMenuItem.ItemsSource = GenerateLanguageMenuItems(); ChangeLanguageMenuItem.ItemsSource = GenerateLanguageMenuItems();
MiiAppletMenuItem.Command = Commands.Create(OpenMiiApplet); MiiAppletMenuItem.Command = new AsyncRelayCommand(OpenMiiApplet);
CloseRyujinxMenuItem.Command = Commands.Create(CloseWindow); CloseRyujinxMenuItem.Command = new RelayCommand(CloseWindow);
OpenSettingsMenuItem.Command = Commands.Create(OpenSettings); OpenSettingsMenuItem.Command = new AsyncRelayCommand(OpenSettings);
PauseEmulationMenuItem.Command = Commands.Create(() => ViewModel.AppHost?.Pause()); PauseEmulationMenuItem.Command = new RelayCommand(() => ViewModel.AppHost?.Pause());
ResumeEmulationMenuItem.Command = Commands.Create(() => ViewModel.AppHost?.Resume()); ResumeEmulationMenuItem.Command = new RelayCommand(() => ViewModel.AppHost?.Resume());
StopEmulationMenuItem.Command = Commands.Create(() => ViewModel.AppHost?.ShowExitPrompt().OrCompleted()); StopEmulationMenuItem.Command = new AsyncRelayCommand(() => ViewModel.AppHost?.ShowExitPrompt().OrCompleted());
CheatManagerMenuItem.Command = Commands.CreateSilentFail(OpenCheatManagerForCurrentApp); CheatManagerMenuItem.Command = new AsyncRelayCommand(async () =>
InstallFileTypesMenuItem.Command = Commands.Create(InstallFileTypes); {
UninstallFileTypesMenuItem.Command = Commands.Create(UninstallFileTypes); try
XciTrimmerMenuItem.Command = Commands.Create(XCITrimmerWindow.Show); {
AboutWindowMenuItem.Command = Commands.Create(AboutWindow.Show); await OpenCheatManagerForCurrentApp();
CompatibilityListMenuItem.Command = Commands.Create(CompatibilityList.Show); } catch {}
});
InstallFileTypesMenuItem.Command = new AsyncRelayCommand(InstallFileTypes);
UninstallFileTypesMenuItem.Command = new AsyncRelayCommand(UninstallFileTypes);
XciTrimmerMenuItem.Command = new AsyncRelayCommand(() => XCITrimmerWindow.Show(ViewModel));
AboutWindowMenuItem.Command = new AsyncRelayCommand(AboutWindow.Show);
CompatibilityListMenuItem.Command = new AsyncRelayCommand(CompatibilityList.Show);
UpdateMenuItem.Command = Commands.Create(async () => UpdateMenuItem.Command = new AsyncRelayCommand(async () =>
{ {
if (Updater.CanUpdate(true)) if (Updater.CanUpdate(true))
await Updater.BeginUpdateAsync(true); await Updater.BeginUpdateAsync(true);
@@ -58,12 +64,12 @@ namespace Ryujinx.Ava.UI.Views.Main
FaqMenuItem.Command = FaqMenuItem.Command =
SetupGuideMenuItem.Command = SetupGuideMenuItem.Command =
LdnGuideMenuItem.Command = Commands.Create<string>(OpenHelper.OpenUrl); LdnGuideMenuItem.Command = new RelayCommand<string>(OpenHelper.OpenUrl);
WindowSize720PMenuItem.Command = WindowSize720PMenuItem.Command =
WindowSize1080PMenuItem.Command = WindowSize1080PMenuItem.Command =
WindowSize1440PMenuItem.Command = WindowSize1440PMenuItem.Command =
WindowSize2160PMenuItem.Command = Commands.Create<string>(ChangeWindowSize); WindowSize2160PMenuItem.Command = new RelayCommand<string>(ChangeWindowSize);
} }
private IEnumerable<CheckBox> GenerateToggleFileTypeItems() => private IEnumerable<CheckBox> GenerateToggleFileTypeItems() =>

View File

@@ -105,12 +105,6 @@
GroupName="Sort" GroupName="Sort"
IsChecked="{Binding IsSortedByTitle, Mode=OneTime}" IsChecked="{Binding IsSortedByTitle, Mode=OneTime}"
Tag="Title" /> Tag="Title" />
<RadioButton
Checked="Sort_Checked"
Content="{ext:Locale DlcManagerTableHeadingTitleIdLabel}"
GroupName="Sort"
IsChecked="{Binding IsSortedByTitleId, Mode=OneTime}"
Tag="TitleId" />
<RadioButton <RadioButton
Checked="Sort_Checked" Checked="Sort_Checked"
Content="{ext:Locale GameListHeaderDeveloper}" Content="{ext:Locale GameListHeaderDeveloper}"

View File

@@ -29,7 +29,7 @@
<TextBlock <TextBlock
Foreground="{DynamicResource SecondaryTextColor}" Foreground="{DynamicResource SecondaryTextColor}"
TextDecorations="Underline" TextDecorations="Underline"
Text="Highly specific hacks &amp; tricks to alleviate performance issues, crashing, or freezing. Will cause issues." /> Text="Game-specific hacks &amp; tricks to alleviate performance issues or crashing. Will cause issues." />
<StackPanel <StackPanel
Margin="0,10,0,0" Margin="0,10,0,0"
Orientation="Horizontal" Orientation="Horizontal"

View File

@@ -114,7 +114,8 @@
Grid.Column="1" Grid.Column="1"
MinWidth="90" MinWidth="90"
Margin="10,0,0,0" Margin="10,0,0,0"
ToolTip.Tip="{ext:Locale AddGameDirTooltip}"> ToolTip.Tip="{ext:Locale AddGameDirTooltip}"
Click="AddGameDirButton_OnClick">
<TextBlock HorizontalAlignment="Center" <TextBlock HorizontalAlignment="Center"
Text="{ext:Locale SettingsTabGeneralAdd}" /> Text="{ext:Locale SettingsTabGeneralAdd}" />
</Button> </Button>
@@ -167,7 +168,8 @@
Grid.Column="1" Grid.Column="1"
MinWidth="90" MinWidth="90"
Margin="10,0,0,0" Margin="10,0,0,0"
ToolTip.Tip="{ext:Locale AddAutoloadDirTooltip}"> ToolTip.Tip="{ext:Locale AddAutoloadDirTooltip}"
Click="AddAutoloadDirButton_OnClick">
<TextBlock HorizontalAlignment="Center" <TextBlock HorizontalAlignment="Center"
Text="{ext:Locale SettingsTabGeneralAdd}" /> Text="{ext:Locale SettingsTabGeneralAdd}" />
</Button> </Button>

View File

@@ -1,17 +1,12 @@
using Avalonia.Collections;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Interactivity; using Avalonia.Interactivity;
using Avalonia.Platform.Storage; using Avalonia.Platform.Storage;
using Avalonia.VisualTree; using Avalonia.VisualTree;
using Gommon;
using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.UI.ViewModels; using Ryujinx.Ava.UI.ViewModels;
using Ryujinx.Ava.Utilities;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
namespace Ryujinx.Ava.UI.Views.Settings namespace Ryujinx.Ava.UI.Views.Settings
{ {
@@ -23,39 +18,31 @@ namespace Ryujinx.Ava.UI.Views.Settings
{ {
InitializeComponent(); InitializeComponent();
ShowTitleBarBox.IsVisible = OperatingSystem.IsWindows(); ShowTitleBarBox.IsVisible = OperatingSystem.IsWindows();
AddGameDirButton.Command =
Commands.Create(() => AddDirButton(GameDirPathBox, ViewModel.GameDirectories, true));
AddAutoloadDirButton.Command =
Commands.Create(() => AddDirButton(AutoloadDirPathBox, ViewModel.AutoloadDirectories, false));
} }
private async Task AddDirButton(TextBox addDirBox, AvaloniaList<string> directories, bool isGameList) private async void AddGameDirButton_OnClick(object sender, RoutedEventArgs e)
{ {
string path = addDirBox.Text; string path = GameDirPathBox.Text;
if (!string.IsNullOrWhiteSpace(path) && Directory.Exists(path) && !directories.Contains(path)) if (!string.IsNullOrWhiteSpace(path) && Directory.Exists(path) && !ViewModel.GameDirectories.Contains(path))
{ {
directories.Add(path); ViewModel.GameDirectories.Add(path);
ViewModel.GameDirectoryChanged = true;
addDirBox.Clear();
if (isGameList)
ViewModel.GameDirectoryChanged = true;
else
ViewModel.AutoloadDirectoryChanged = true;
} }
else else
{ {
Optional<IStorageFolder> folder = await RyujinxApp.MainWindow.ViewModel.StorageProvider.OpenSingleFolderPickerAsync(); if (this.GetVisualRoot() is Window window)
if (folder.HasValue)
{ {
directories.Add(folder.Value.Path.LocalPath); var result = await window.StorageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions
{
if (isGameList) AllowMultiple = false,
});
if (result.Count > 0)
{
ViewModel.GameDirectories.Add(result[0].Path.LocalPath);
ViewModel.GameDirectoryChanged = true; ViewModel.GameDirectoryChanged = true;
else }
ViewModel.AutoloadDirectoryChanged = true;
} }
} }
} }
@@ -76,6 +63,33 @@ 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) private void RemoveAutoloadDirButton_OnClick(object sender, RoutedEventArgs e)
{ {
int oldIndex = AutoloadDirsList.SelectedIndex; int oldIndex = AutoloadDirsList.SelectedIndex;

View File

@@ -182,7 +182,7 @@
HorizontalAlignment="Left" HorizontalAlignment="Left"
Background="Transparent" Background="Transparent"
Click="Button_OnClick" Click="Button_OnClick"
Tag="https://github.com/Ryubing/Ryujinx/graphs/contributors?type=a"> Tag="https://github.com/GreemDev/Ryujinx/graphs/contributors?type=a">
<TextBlock <TextBlock
FontSize="10" FontSize="10"
Text="{ext:Locale AboutRyujinxContributorsButtonHeader}" Text="{ext:Locale AboutRyujinxContributorsButtonHeader}"

View File

@@ -14,6 +14,9 @@
mc:Ignorable="d" mc:Ignorable="d"
x:DataType="viewModels:DownloadableContentManagerViewModel" x:DataType="viewModels:DownloadableContentManagerViewModel"
Focusable="True"> Focusable="True">
<UserControl.Resources>
<helpers:DownloadableContentLabelConverter x:Key="DownloadableContentLabel" />
</UserControl.Resources>
<Grid RowDefinitions="Auto,Auto,*,Auto"> <Grid RowDefinitions="Auto,Auto,*,Auto">
<StackPanel <StackPanel
Grid.Row="0" Grid.Row="0"
@@ -86,7 +89,7 @@
<ListBox.DataTemplates> <ListBox.DataTemplates>
<DataTemplate <DataTemplate
DataType="models:DownloadableContentModel"> DataType="models:DownloadableContentModel">
<Panel Margin="10" Background="Transparent"> <Panel Margin="10">
<Grid ColumnDefinitions="*,Auto"> <Grid ColumnDefinitions="*,Auto">
<Grid <Grid
Grid.Column="0" ColumnDefinitions="*,Auto"> Grid.Column="0" ColumnDefinitions="*,Auto">
@@ -98,7 +101,7 @@
TextWrapping="Wrap" TextWrapping="Wrap"
TextTrimming="CharacterEllipsis"> TextTrimming="CharacterEllipsis">
<TextBlock.Text> <TextBlock.Text>
<MultiBinding Converter="{x:Static helpers:DownloadableContentLabelConverter.Instance}"> <MultiBinding Converter="{StaticResource DownloadableContentLabel}">
<Binding Path="FileName" /> <Binding Path="FileName" />
<Binding Path="IsBundled" /> <Binding Path="IsBundled" />
</MultiBinding> </MultiBinding>
@@ -109,7 +112,7 @@
Margin="10 0" Margin="10 0"
HorizontalAlignment="Left" HorizontalAlignment="Left"
VerticalAlignment="Center" VerticalAlignment="Center"
Text="{Binding TitleIdStr}" /> Text="{Binding TitleId}" />
</Grid> </Grid>
<StackPanel <StackPanel
Grid.Column="1" Grid.Column="1"

View File

@@ -2,8 +2,6 @@ using Avalonia.Controls;
using Avalonia.Interactivity; using Avalonia.Interactivity;
using Avalonia.Styling; using Avalonia.Styling;
using FluentAvalonia.UI.Controls; using FluentAvalonia.UI.Controls;
using LibHac.Tools.FsSystem.NcaUtils;
using Ryujinx.Ava.Common;
using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.Common.Models; using Ryujinx.Ava.Common.Models;
using Ryujinx.Ava.UI.ViewModels; using Ryujinx.Ava.UI.ViewModels;

View File

@@ -691,7 +691,6 @@ namespace Ryujinx.Ava.UI.Windows
ApplicationLibrary.LoadApplications(ConfigurationState.Instance.UI.GameDirs); ApplicationLibrary.LoadApplications(ConfigurationState.Instance.UI.GameDirs);
var autoloadDirs = ConfigurationState.Instance.UI.AutoloadDirs.Value; 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) if (autoloadDirs.Count > 0)
{ {
var updatesLoaded = ApplicationLibrary.AutoLoadTitleUpdates(autoloadDirs, out int updatesRemoved); var updatesLoaded = ApplicationLibrary.AutoLoadTitleUpdates(autoloadDirs, out int updatesRemoved);
@@ -736,7 +735,9 @@ namespace Ryujinx.Ava.UI.Windows
}); });
} }
private static bool _intelMacWarningShown = !RunningPlatform.IsIntelMac; private static bool _intelMacWarningShown = !(OperatingSystem.IsMacOS() &&
(RuntimeInformation.OSArchitecture == Architecture.X64 ||
RuntimeInformation.OSArchitecture == Architecture.X86));
public static async Task ShowIntelMacWarningAsync() public static async Task ShowIntelMacWarningAsync()
{ {

View File

@@ -4,14 +4,9 @@ using Avalonia.Input;
using FluentAvalonia.Core; using FluentAvalonia.Core;
using FluentAvalonia.UI.Controls; using FluentAvalonia.UI.Controls;
using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.UI.Models;
using Ryujinx.Ava.UI.ViewModels; using Ryujinx.Ava.UI.ViewModels;
using Ryujinx.Ava.UI.ViewModels.Input;
using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.FileSystem;
using Ryujinx.Input;
using System; using System;
using System.Linq;
using Key = Avalonia.Input.Key;
namespace Ryujinx.Ava.UI.Windows namespace Ryujinx.Ava.UI.Windows
{ {
@@ -111,12 +106,6 @@ namespace Ryujinx.Ava.UI.Windows
protected override void OnClosing(WindowClosingEventArgs e) protected override void OnClosing(WindowClosingEventArgs e)
{ {
HotkeysPage.Dispose(); HotkeysPage.Dispose();
foreach (IGamepad gamepad in RyujinxApp.MainWindow.InputManager.GamepadDriver.GetGamepads())
{
gamepad?.ClearLed();
}
InputPage.Dispose(); InputPage.Dispose();
base.OnClosing(e); base.OnClosing(e);
} }

View File

@@ -28,15 +28,15 @@ namespace Ryujinx.Ava.UI.Windows
InitializeComponent(); InitializeComponent();
} }
public static async Task Show() public static async Task Show(MainWindowViewModel mainWindowViewModel)
{ {
ContentDialog contentDialog = new() ContentDialog contentDialog = new()
{ {
PrimaryButtonText = string.Empty, PrimaryButtonText = string.Empty,
SecondaryButtonText = string.Empty, SecondaryButtonText = string.Empty,
CloseButtonText = string.Empty, CloseButtonText = string.Empty,
Content = new XCITrimmerWindow(RyujinxApp.MainWindow.ViewModel), Content = new XCITrimmerWindow(mainWindowViewModel),
Title = LocaleManager.Instance[LocaleKeys.XCITrimmerWindowTitle] Title = string.Format(LocaleManager.Instance[LocaleKeys.XCITrimmerWindowTitle]),
}; };
Style bottomBorder = new(x => x.OfType<Grid>().Name("DialogSpace").Child().OfType<Border>()); Style bottomBorder = new(x => x.OfType<Grid>().Name("DialogSpace").Child().OfType<Border>());

View File

@@ -87,8 +87,6 @@ namespace Ryujinx.Ava
return; return;
} }
Logger.Info?.Print(LogClass.Application, "Checking for updates.");
// Get latest version number from GitHub API // Get latest version number from GitHub API
try try
@@ -118,8 +116,6 @@ namespace Ryujinx.Ava
OpenHelper.OpenUrl(ReleaseInformation.GetChangelogForVersion(currentVersion)); OpenHelper.OpenUrl(ReleaseInformation.GetChangelogForVersion(currentVersion));
} }
} }
Logger.Info?.Print(LogClass.Application, "Up to date.");
_running = false; _running = false;
@@ -144,8 +140,6 @@ namespace Ryujinx.Ava
OpenHelper.OpenUrl(ReleaseInformation.GetChangelogForVersion(currentVersion)); OpenHelper.OpenUrl(ReleaseInformation.GetChangelogForVersion(currentVersion));
} }
} }
Logger.Info?.Print(LogClass.Application, "Up to date.");
_running = false; _running = false;
@@ -190,8 +184,6 @@ namespace Ryujinx.Ava
OpenHelper.OpenUrl(ReleaseInformation.GetChangelogForVersion(currentVersion)); OpenHelper.OpenUrl(ReleaseInformation.GetChangelogForVersion(currentVersion));
} }
} }
Logger.Info?.Print(LogClass.Application, "Up to date.");
_running = false; _running = false;
@@ -222,8 +214,6 @@ namespace Ryujinx.Ava
? $"Canary {currentVersion} -> Canary {newVersion}" ? $"Canary {currentVersion} -> Canary {newVersion}"
: $"{currentVersion} -> {newVersion}"; : $"{currentVersion} -> {newVersion}";
Logger.Info?.Print(LogClass.Application, $"Version found: {newVersionString}");
RequestUserToUpdate: RequestUserToUpdate:
// Show a message asking the user if they want to update // Show a message asking the user if they want to update
UserResult shouldUpdate = await ContentDialogHelper.CreateUpdaterChoiceDialog( UserResult shouldUpdate = await ContentDialogHelper.CreateUpdaterChoiceDialog(

View File

@@ -840,6 +840,7 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
try try
{ {
// Remove any downloadable content which can no longer be located on disk // 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 var dlcToRemove = _downloadableContents.Items
.Where(dlc => !File.Exists(dlc.Dlc.ContainerPath)) .Where(dlc => !File.Exists(dlc.Dlc.ContainerPath))
.ToList(); .ToList();
@@ -851,6 +852,8 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
foreach (string appDir in appDirs) foreach (string appDir in appDirs)
{ {
Logger.Notice.Print(LogClass.Application, $"Auto loading DLC from: {appDir}");
if (_cancellationToken.Token.IsCancellationRequested) if (_cancellationToken.Token.IsCancellationRequested)
{ {
return newDlcLoaded; return newDlcLoaded;
@@ -953,6 +956,7 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
var titleIdsToRefresh = new HashSet<ulong>(); var titleIdsToRefresh = new HashSet<ulong>();
// Remove any updates which can no longer be located on disk // 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 var updatesToRemove = _titleUpdates.Items
.Where(it => !File.Exists(it.TitleUpdate.Path)) .Where(it => !File.Exists(it.TitleUpdate.Path))
.ToList(); .ToList();
@@ -967,6 +971,8 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
foreach (string appDir in appDirs) foreach (string appDir in appDirs)
{ {
Logger.Notice.Print(LogClass.Application, $"Auto loading updates from: {appDir}");
if (_cancellationToken.Token.IsCancellationRequested) if (_cancellationToken.Token.IsCancellationRequested)
{ {
return numUpdatesLoaded; return numUpdatesLoaded;

View File

@@ -17,7 +17,7 @@ namespace Ryujinx.Ava.Utilities.Configuration
/// <summary> /// <summary>
/// The current version of the file format /// The current version of the file format
/// </summary> /// </summary>
public const int CurrentVersion = 61; public const int CurrentVersion = 59;
/// <summary> /// <summary>
/// Version of the configuration file format /// Version of the configuration file format
@@ -351,11 +351,6 @@ namespace Ryujinx.Ava.Utilities.Configuration
/// </summary> /// </summary>
public bool StartFullscreen { get; set; } public bool StartFullscreen { get; set; }
/// <summary>
/// Start games with UI hidden
/// </summary>
public bool StartNoUI { get; set; }
/// <summary> /// <summary>
/// Show console window /// Show console window
/// </summary> /// </summary>

View File

@@ -1,4 +1,3 @@
using Avalonia.Media;
using Gommon; using Gommon;
using Ryujinx.Ava.Utilities.Configuration.System; using Ryujinx.Ava.Utilities.Configuration.System;
using Ryujinx.Ava.Utilities.Configuration.UI; using Ryujinx.Ava.Utilities.Configuration.UI;
@@ -46,6 +45,7 @@ namespace Ryujinx.Ava.Utilities.Configuration
EnableDiscordIntegration.Value = cff.EnableDiscordIntegration; EnableDiscordIntegration.Value = cff.EnableDiscordIntegration;
CheckUpdatesOnStart.Value = cff.CheckUpdatesOnStart; CheckUpdatesOnStart.Value = cff.CheckUpdatesOnStart;
ShowConfirmExit.Value = cff.ShowConfirmExit; ShowConfirmExit.Value = cff.ShowConfirmExit;
IgnoreApplet.Value = cff.IgnoreApplet;
RememberWindowState.Value = cff.RememberWindowState; RememberWindowState.Value = cff.RememberWindowState;
ShowTitleBar.Value = cff.ShowTitleBar; ShowTitleBar.Value = cff.ShowTitleBar;
EnableHardwareAcceleration.Value = cff.EnableHardwareAcceleration; EnableHardwareAcceleration.Value = cff.EnableHardwareAcceleration;
@@ -97,7 +97,6 @@ namespace Ryujinx.Ava.Utilities.Configuration
System.MemoryManagerMode.Value = cff.MemoryManagerMode; System.MemoryManagerMode.Value = cff.MemoryManagerMode;
System.DramSize.Value = cff.DramSize; System.DramSize.Value = cff.DramSize;
System.IgnoreMissingServices.Value = cff.IgnoreMissingServices; System.IgnoreMissingServices.Value = cff.IgnoreMissingServices;
System.IgnoreApplet.Value = cff.IgnoreApplet;
System.UseHypervisor.Value = cff.UseHypervisor; System.UseHypervisor.Value = cff.UseHypervisor;
UI.GuiColumns.FavColumn.Value = cff.GuiColumns.FavColumn; UI.GuiColumns.FavColumn.Value = cff.GuiColumns.FavColumn;
@@ -128,7 +127,6 @@ namespace Ryujinx.Ava.Utilities.Configuration
UI.GridSize.Value = cff.GridSize; UI.GridSize.Value = cff.GridSize;
UI.ApplicationSort.Value = cff.ApplicationSort; UI.ApplicationSort.Value = cff.ApplicationSort;
UI.StartFullscreen.Value = cff.StartFullscreen; UI.StartFullscreen.Value = cff.StartFullscreen;
UI.StartNoUI.Value = cff.StartNoUI;
UI.ShowConsole.Value = cff.ShowConsole; UI.ShowConsole.Value = cff.ShowConsole;
UI.WindowStartup.WindowSizeWidth.Value = cff.WindowStartup.WindowSizeWidth; UI.WindowStartup.WindowSizeWidth.Value = cff.WindowStartup.WindowSizeWidth;
UI.WindowStartup.WindowSizeHeight.Value = cff.WindowStartup.WindowSizeHeight; UI.WindowStartup.WindowSizeHeight.Value = cff.WindowStartup.WindowSizeHeight;
@@ -264,12 +262,15 @@ namespace Ryujinx.Ava.Utilities.Configuration
}), }),
(30, static cff => (30, static cff =>
{ {
foreach (StandardControllerInputConfig config in cff.InputConfig.OfType<StandardControllerInputConfig>()) foreach (InputConfig config in cff.InputConfig)
{ {
config.Rumble = new RumbleConfigController if (config is StandardControllerInputConfig controllerConfig)
{ {
EnableRumble = false, StrongRumble = 1f, WeakRumble = 1f, controllerConfig.Rumble = new RumbleConfigController
}; {
EnableRumble = false, StrongRumble = 1f, WeakRumble = 1f,
};
}
} }
}), }),
(31, static cff => cff.BackendThreading = BackendThreading.Auto), (31, static cff => cff.BackendThreading = BackendThreading.Auto),
@@ -413,20 +414,6 @@ namespace Ryujinx.Ava.Utilities.Configuration
// This was accidentally enabled by default when it was PRed. That is not what we want, // 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. // so as a compromise users who want to use it will simply need to re-enable it once after updating.
cff.IgnoreApplet = false; 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,
TurnOffLed = false,
UseRainbow = false,
LedColor = new Color(255, 5, 1, 253).ToUInt32()
};
}
}) })
); );
} }

View File

@@ -152,11 +152,6 @@ namespace Ryujinx.Ava.Utilities.Configuration
/// </summary> /// </summary>
public ReactiveObject<bool> StartFullscreen { get; private set; } public ReactiveObject<bool> StartFullscreen { get; private set; }
/// <summary>
/// Start games with UI hidden
/// </summary>
public ReactiveObject<bool> StartNoUI { get; private set; }
/// <summary> /// <summary>
/// Hide / Show Console Window /// Hide / Show Console Window
/// </summary> /// </summary>
@@ -197,7 +192,6 @@ namespace Ryujinx.Ava.Utilities.Configuration
WindowStartup = new WindowStartupSettings(); WindowStartup = new WindowStartupSettings();
BaseStyle = new ReactiveObject<string>(); BaseStyle = new ReactiveObject<string>();
StartFullscreen = new ReactiveObject<bool>(); StartFullscreen = new ReactiveObject<bool>();
StartNoUI = new ReactiveObject<bool>();
GameListViewMode = new ReactiveObject<int>(); GameListViewMode = new ReactiveObject<int>();
ShowNames = new ReactiveObject<bool>(); ShowNames = new ReactiveObject<bool>();
GridSize = new ReactiveObject<int>(); GridSize = new ReactiveObject<int>();
@@ -366,11 +360,6 @@ namespace Ryujinx.Ava.Utilities.Configuration
/// Enable or disable ignoring missing services /// Enable or disable ignoring missing services
/// </summary> /// </summary>
public ReactiveObject<bool> IgnoreMissingServices { get; private set; } public ReactiveObject<bool> IgnoreMissingServices { get; private set; }
/// <summary>
/// Ignore Controller Applet
/// </summary>
public ReactiveObject<bool> IgnoreApplet { get; private set; }
/// <summary> /// <summary>
/// Uses Hypervisor over JIT if available /// Uses Hypervisor over JIT if available
@@ -409,8 +398,6 @@ namespace Ryujinx.Ava.Utilities.Configuration
DramSize.LogChangesToValue(nameof(DramSize)); DramSize.LogChangesToValue(nameof(DramSize));
IgnoreMissingServices = new ReactiveObject<bool>(); IgnoreMissingServices = new ReactiveObject<bool>();
IgnoreMissingServices.LogChangesToValue(nameof(IgnoreMissingServices)); IgnoreMissingServices.LogChangesToValue(nameof(IgnoreMissingServices));
IgnoreApplet = new ReactiveObject<bool>();
IgnoreApplet.LogChangesToValue(nameof(IgnoreApplet));
AudioVolume = new ReactiveObject<float>(); AudioVolume = new ReactiveObject<float>();
AudioVolume.LogChangesToValue(nameof(AudioVolume)); AudioVolume.LogChangesToValue(nameof(AudioVolume));
UseHypervisor = new ReactiveObject<bool>(); UseHypervisor = new ReactiveObject<bool>();
@@ -752,6 +739,11 @@ namespace Ryujinx.Ava.Utilities.Configuration
/// </summary> /// </summary>
public ReactiveObject<bool> ShowConfirmExit { get; private set; } public ReactiveObject<bool> ShowConfirmExit { get; private set; }
/// <summary>
/// Ignore Applet
/// </summary>
public ReactiveObject<bool> IgnoreApplet { get; private set; }
/// <summary> /// <summary>
/// Enables or disables save window size, position and state on close. /// Enables or disables save window size, position and state on close.
/// </summary> /// </summary>
@@ -784,6 +776,8 @@ namespace Ryujinx.Ava.Utilities.Configuration
EnableDiscordIntegration = new ReactiveObject<bool>(); EnableDiscordIntegration = new ReactiveObject<bool>();
CheckUpdatesOnStart = new ReactiveObject<bool>(); CheckUpdatesOnStart = new ReactiveObject<bool>();
ShowConfirmExit = new ReactiveObject<bool>(); ShowConfirmExit = new ReactiveObject<bool>();
IgnoreApplet = new ReactiveObject<bool>();
IgnoreApplet.LogChangesToValue(nameof(IgnoreApplet));
RememberWindowState = new ReactiveObject<bool>(); RememberWindowState = new ReactiveObject<bool>();
ShowTitleBar = new ReactiveObject<bool>(); ShowTitleBar = new ReactiveObject<bool>();
EnableHardwareAcceleration = new ReactiveObject<bool>(); EnableHardwareAcceleration = new ReactiveObject<bool>();

View File

@@ -56,6 +56,7 @@ namespace Ryujinx.Ava.Utilities.Configuration
EnableDiscordIntegration = EnableDiscordIntegration, EnableDiscordIntegration = EnableDiscordIntegration,
CheckUpdatesOnStart = CheckUpdatesOnStart, CheckUpdatesOnStart = CheckUpdatesOnStart,
ShowConfirmExit = ShowConfirmExit, ShowConfirmExit = ShowConfirmExit,
IgnoreApplet = IgnoreApplet,
RememberWindowState = RememberWindowState, RememberWindowState = RememberWindowState,
ShowTitleBar = ShowTitleBar, ShowTitleBar = ShowTitleBar,
EnableHardwareAcceleration = EnableHardwareAcceleration, EnableHardwareAcceleration = EnableHardwareAcceleration,
@@ -77,7 +78,6 @@ namespace Ryujinx.Ava.Utilities.Configuration
MemoryManagerMode = System.MemoryManagerMode, MemoryManagerMode = System.MemoryManagerMode,
DramSize = System.DramSize, DramSize = System.DramSize,
IgnoreMissingServices = System.IgnoreMissingServices, IgnoreMissingServices = System.IgnoreMissingServices,
IgnoreApplet = System.IgnoreApplet,
UseHypervisor = System.UseHypervisor, UseHypervisor = System.UseHypervisor,
GuiColumns = new GuiColumns GuiColumns = new GuiColumns
{ {
@@ -125,7 +125,6 @@ namespace Ryujinx.Ava.Utilities.Configuration
ApplicationSort = UI.ApplicationSort, ApplicationSort = UI.ApplicationSort,
IsAscendingOrder = UI.IsAscendingOrder, IsAscendingOrder = UI.IsAscendingOrder,
StartFullscreen = UI.StartFullscreen, StartFullscreen = UI.StartFullscreen,
StartNoUI = UI.StartNoUI,
ShowConsole = UI.ShowConsole, ShowConsole = UI.ShowConsole,
EnableKeyboard = Hid.EnableKeyboard, EnableKeyboard = Hid.EnableKeyboard,
EnableMouse = Hid.EnableMouse, EnableMouse = Hid.EnableMouse,
@@ -176,6 +175,7 @@ namespace Ryujinx.Ava.Utilities.Configuration
EnableDiscordIntegration.Value = true; EnableDiscordIntegration.Value = true;
CheckUpdatesOnStart.Value = true; CheckUpdatesOnStart.Value = true;
ShowConfirmExit.Value = true; ShowConfirmExit.Value = true;
IgnoreApplet.Value = false;
RememberWindowState.Value = true; RememberWindowState.Value = true;
ShowTitleBar.Value = !OperatingSystem.IsWindows(); ShowTitleBar.Value = !OperatingSystem.IsWindows();
EnableHardwareAcceleration.Value = true; EnableHardwareAcceleration.Value = true;
@@ -199,7 +199,6 @@ namespace Ryujinx.Ava.Utilities.Configuration
System.MemoryManagerMode.Value = MemoryManagerMode.HostMappedUnsafe; System.MemoryManagerMode.Value = MemoryManagerMode.HostMappedUnsafe;
System.DramSize.Value = MemoryConfiguration.MemoryConfiguration4GiB; System.DramSize.Value = MemoryConfiguration.MemoryConfiguration4GiB;
System.IgnoreMissingServices.Value = false; System.IgnoreMissingServices.Value = false;
System.IgnoreApplet.Value = false;
System.UseHypervisor.Value = true; System.UseHypervisor.Value = true;
Multiplayer.LanInterfaceId.Value = "0"; Multiplayer.LanInterfaceId.Value = "0";
Multiplayer.Mode.Value = MultiplayerMode.Disabled; Multiplayer.Mode.Value = MultiplayerMode.Disabled;
@@ -234,7 +233,6 @@ namespace Ryujinx.Ava.Utilities.Configuration
UI.ApplicationSort.Value = 0; UI.ApplicationSort.Value = 0;
UI.IsAscendingOrder.Value = true; UI.IsAscendingOrder.Value = true;
UI.StartFullscreen.Value = false; UI.StartFullscreen.Value = false;
UI.StartNoUI.Value = false;
UI.ShowConsole.Value = true; UI.ShowConsole.Value = true;
UI.WindowStartup.WindowSizeWidth.Value = 1280; UI.WindowStartup.WindowSizeWidth.Value = 1280;
UI.WindowStartup.WindowSizeHeight.Value = 760; UI.WindowStartup.WindowSizeHeight.Value = 760;

View File

@@ -1,47 +0,0 @@
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;
}
}
}