Compare commits

..

9 Commits

Author SHA1 Message Date
Evan Husted
2a84656ffc misc: chore: use new array in LdnGameDataReceivedEventArgs instead of collecting the ldn datas into a list 2025-02-20 19:49:17 -06:00
Evan Husted
6c6580ddcc misc: chore: Move the LDN constants into a SharedConstants class 2025-02-20 19:30:00 -06:00
Evan Husted
c47448628c UI: Print LED setting failed on Debug 2025-02-20 19:29:18 -06:00
Evan Husted
d0ac83b493 misc: chore: Prevent firmware installation prompt from showing up multiple times during runtime when using --install-firmware 2025-02-20 18:52:45 -06:00
rrondo
e0ddbe55c0 Ukrainian localization changes (1.2.82) (#678)
Some changes and new lines for Ukrainian (uk_UA) localization.
2025-02-20 18:11:56 -06:00
FluffyOMC
4a4078865f Add Melatonin to compatibility list (#667)
It's playable, no bugs, and can run pretty easily way above intended
FPS, which shows there's not really any performance issues lol.


![image](https://github.com/user-attachments/assets/63402c9f-2412-4b43-9e5d-42a19436ac55)
2025-02-20 16:09:14 -06:00
Milihraim
3f59bade94 Update Russian Translation (#695) 2025-02-20 14:32:35 -06:00
Evan Husted
c2ed0fd5fd UI: --install-firmware startup flag.
Has the normal UI flow, this is just for systems where the file picker doesn't show up.
2025-02-19 23:07:50 -06:00
Evan Husted
de16d8fa3e UI: Remove the ability to select Swedish & Norwegian for System language
Switch doesn't natively support these languages, they should only be UI language.
2025-02-19 18:24:24 -06:00
22 changed files with 324 additions and 528 deletions

View File

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

View File

@@ -1800,6 +1800,7 @@
010005A00B312000,"Megaton Rainfall",gpu;opengl,boots,2022-08-04 18:29:43
0100EA100DF92000,"Meiji Katsugeki Haikara Ryuuseigumi - Seibai Shimaseu, Yonaoshi Kagyou",32-bit;nvdec,playable,2022-12-05 13:19:12
0100B360068B2000,"Mekorama",gpu,boots,2021-06-17 16:37:21
010012301932A000,"Melatonin",,playable,2025-02-16 04:08:17
01000FA010340000,"Melbits World",nvdec;online,menus,2021-11-26 13:51:22
0100F68019636000,"Melon Journey",,playable,2023-04-23 21:20:01
010079C012896000,"Memories Off -Innocent Fille- for Dearest",,playable,2020-08-04 07:31:22
1 title_id game_name labels status last_updated
1800 010005A00B312000 Megaton Rainfall gpu;opengl boots 2022-08-04 18:29:43
1801 0100EA100DF92000 Meiji Katsugeki Haikara Ryuuseigumi - Seibai Shimaseu, Yonaoshi Kagyou 32-bit;nvdec playable 2022-12-05 13:19:12
1802 0100B360068B2000 Mekorama gpu boots 2021-06-17 16:37:21
1803 010012301932A000 Melatonin playable 2025-02-16 04:08:17
1804 01000FA010340000 Melbits World nvdec;online menus 2021-11-26 13:51:22
1805 0100F68019636000 Melon Journey playable 2023-04-23 21:20:01
1806 010079C012896000 Memories Off -Innocent Fille- for Dearest playable 2020-08-04 07:31:22

View File

@@ -1,5 +1,3 @@
using System.Collections.Generic;
namespace Ryujinx.Common.Configuration.Hid
{
public class KeyboardHotkeys
@@ -15,6 +13,5 @@ namespace Ryujinx.Common.Configuration.Hid
public Key VolumeDown { get; set; }
public Key CustomVSyncIntervalIncrement { get; set; }
public Key CustomVSyncIntervalDecrement { get; set; }
public List<Key> CycleControllers { get; set; }
}
}

View File

@@ -0,0 +1,9 @@
namespace Ryujinx.Common
{
public static class SharedConstants
{
public const string DefaultLanPlayHost = "ryuldn.vudjun.com";
public const short LanPlayPort = 30456;
public const string DefaultLanPlayWebHost = "ryuldnweb.vudjun.com";
}
}

View File

@@ -23,9 +23,6 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
{
class IUserLocalCommunicationService : IpcService, IDisposable
{
public static string DefaultLanPlayHost = "ryuldn.vudjun.com";
public static short LanPlayPort = 30456;
public INetworkClient NetworkClient { get; private set; }
private const int NifmRequestID = 90;
@@ -1092,20 +1089,18 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
case MultiplayerMode.LdnRyu:
try
{
string ldnServer = context.Device.Configuration.MultiplayerLdnServer;
if (string.IsNullOrEmpty(ldnServer))
{
ldnServer = DefaultLanPlayHost;
}
string ldnServer = context.Device.Configuration.MultiplayerLdnServer
?? throw new InvalidOperationException("Cannot initialize RyuLDN with a null Multiplayer server.");
if (!IPAddress.TryParse(ldnServer, out IPAddress ipAddress))
{
ipAddress = Dns.GetHostEntry(ldnServer).AddressList[0];
}
NetworkClient = new LdnMasterProxyClient(ipAddress.ToString(), LanPlayPort, context.Device.Configuration);
NetworkClient = new LdnMasterProxyClient(ipAddress.ToString(), SharedConstants.LanPlayPort, context.Device.Configuration);
}
catch (Exception ex)
{
Logger.Error?.Print(LogClass.ServiceLdn, "Could not locate LdnRyu server. Defaulting to stubbed wireless.");
Logger.Error?.Print(LogClass.ServiceLdn, "Could not locate RyuLDN server. Defaulting to stubbed wireless.");
Logger.Error?.Print(LogClass.ServiceLdn, ex.Message);
NetworkClient = new LdnDisabledClient();
}

View File

@@ -111,7 +111,7 @@ namespace Ryujinx.Input.SDL2
byte blue = packedRgb > 0 ? (byte)(packedRgb % 256) : (byte)0;
if (SDL_GameControllerSetLED(_gamepadHandle, red, green, blue) != 0)
Logger.Error?.Print(LogClass.Hid, "LED setting failed; probably in the middle of disconnecting.");
Logger.Debug?.Print(LogClass.Hid, "LED setting failed; probably in the middle of disconnecting.");
}
private GamepadFeaturesFlag GetFeaturesFlag()

View File

@@ -40,7 +40,6 @@ using Ryujinx.HLE;
using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.HOS;
using Ryujinx.HLE.HOS.Services.Account.Acc;
using Ryujinx.HLE.HOS.Services.Hid;
using Ryujinx.HLE.HOS.SystemState;
using Ryujinx.Input;
using Ryujinx.Input.HLE;
@@ -50,7 +49,6 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;
using System.Threading.Tasks;
@@ -953,7 +951,7 @@ namespace Ryujinx.Ava
ConfigurationState.Instance.Multiplayer.Mode,
ConfigurationState.Instance.Multiplayer.DisableP2p,
ConfigurationState.Instance.Multiplayer.LdnPassphrase,
ConfigurationState.Instance.Multiplayer.LdnServer,
ConfigurationState.Instance.Multiplayer.GetLdnServer(),
ConfigurationState.Instance.Graphics.CustomVSyncInterval.Value,
ConfigurationState.Instance.Hacks.ShowDirtyHacks ? ConfigurationState.Instance.Hacks.EnabledHacks : null));
}
@@ -1311,18 +1309,6 @@ namespace Ryujinx.Ava
_viewModel.Volume = Device.GetVolume();
break;
case KeyboardHotkeyState.CycleControllersPlayer1:
case KeyboardHotkeyState.CycleControllersPlayer2:
case KeyboardHotkeyState.CycleControllersPlayer3:
case KeyboardHotkeyState.CycleControllersPlayer4:
case KeyboardHotkeyState.CycleControllersPlayer5:
case KeyboardHotkeyState.CycleControllersPlayer6:
case KeyboardHotkeyState.CycleControllersPlayer7:
case KeyboardHotkeyState.CycleControllersPlayer8:
var player = currentHotkeyState - KeyboardHotkeyState.CycleControllersPlayer1;
var ivm = new UI.ViewModels.Input.InputViewModel();
Dispatcher.UIThread.Invoke(() => ivm.CyclePlayerDevice(player));
break;
case KeyboardHotkeyState.None:
(_keyboardInterface as AvaloniaKeyboard).Clear();
break;
@@ -1405,15 +1391,6 @@ namespace Ryujinx.Ava
state = KeyboardHotkeyState.CustomVSyncIntervalDecrement;
}
foreach (var cycle in ConfigurationState.Instance.Hid.Hotkeys.Value.CycleControllers?.Select((value, index) => (value, index)) ?? [])
{
if (_keyboardInterface.IsPressed((Key)cycle.value))
{
state = KeyboardHotkeyState.CycleControllersPlayer1 + cycle.index;
break;
}
}
return state;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -14,13 +14,5 @@ namespace Ryujinx.Ava.Common
VolumeDown,
CustomVSyncIntervalIncrement,
CustomVSyncIntervalDecrement,
CycleControllersPlayer1,
CycleControllersPlayer2,
CycleControllersPlayer3,
CycleControllersPlayer4,
CycleControllersPlayer5,
CycleControllersPlayer6,
CycleControllersPlayer7,
CycleControllersPlayer8
}
}

View File

@@ -1,11 +1,6 @@
using CommunityToolkit.Mvvm.ComponentModel;
using DynamicData;
using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.UI.ViewModels;
using Ryujinx.Common.Configuration.Hid;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows.Input;
namespace Ryujinx.Ava.UI.Models.Input
{
@@ -33,15 +28,8 @@ namespace Ryujinx.Ava.UI.Models.Input
[ObservableProperty] private Key _customVSyncIntervalDecrement;
public ObservableCollection<CycleController> CycleControllers { get; set; } = new ObservableCollection<CycleController>();
public ICommand AddCycleController { get; set; }
public ICommand RemoveCycleController { get; set; }
public bool CanRemoveCycleController => CycleControllers.Count > 0 && CycleControllers.Count < 8;
public HotkeyConfig(KeyboardHotkeys config)
{
AddCycleController = MiniCommand.Create(() => CycleControllers.Add(new CycleController(CycleControllers.Count + 1, Key.Unbound)));
RemoveCycleController = MiniCommand.Create(() => CycleControllers.Remove(CycleControllers.Last()));
if (config == null)
return;
@@ -56,7 +44,6 @@ namespace Ryujinx.Ava.UI.Models.Input
VolumeDown = config.VolumeDown;
CustomVSyncIntervalIncrement = config.CustomVSyncIntervalIncrement;
CustomVSyncIntervalDecrement = config.CustomVSyncIntervalDecrement;
CycleControllers.AddRange((config.CycleControllers ?? []).Select((x, i) => new CycleController(i + 1, x)));
}
public KeyboardHotkeys GetConfig() =>
@@ -73,7 +60,6 @@ namespace Ryujinx.Ava.UI.Models.Input
VolumeDown = VolumeDown,
CustomVSyncIntervalIncrement = CustomVSyncIntervalIncrement,
CustomVSyncIntervalDecrement = CustomVSyncIntervalDecrement,
CycleControllers = CycleControllers.Select(x => x.Hotkey).ToList()
};
}
}

View File

@@ -1,48 +0,0 @@
using Ryujinx.Ava.Common.Locale;
using Ryujinx.Common.Configuration.Hid;
namespace Ryujinx.Ava.UI.ViewModels
{
public class CycleController : BaseModel
{
private string _player;
private Key _hotkey;
public string Player
{
get => _player;
set
{
_player = value;
OnPropertyChanged(nameof(Player));
}
}
public Key Hotkey
{
get => _hotkey;
set
{
_hotkey = value;
OnPropertyChanged(nameof(Hotkey));
}
}
public CycleController(int v, Key x)
{
Player = v switch
{
1 => LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer1],
2 => LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer2],
3 => LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer3],
4 => LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer4],
5 => LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer5],
6 => LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer6],
7 => LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer7],
8 => LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer8],
_ => LocaleManager.Instance[LocaleKeys.ControllerSettingsPlayer] + " " + v
};
Hotkey = x;
}
}
}

View File

@@ -897,13 +897,5 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
AvaloniaKeyboardDriver.Dispose();
}
public void CyclePlayerDevice(int player)
{
LoadDevices();
PlayerId = (PlayerIndex)player;
Device = (Device + 1) % Devices.Count;
Save();
}
}
}

View File

@@ -793,7 +793,7 @@ namespace Ryujinx.Ava.UI.ViewModels
return false;
}
private async Task HandleFirmwareInstallation(string filename)
public async Task HandleFirmwareInstallation(string filename)
{
try
{

View File

@@ -1,4 +1,4 @@
<UserControl
<UserControl
x:Class="Ryujinx.Ava.UI.Views.Settings.SettingsHotkeysView"
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
@@ -15,18 +15,17 @@
<viewModels:SettingsViewModel />
</Design.DataContext>
<UserControl.Styles>
<Style Selector="StackPanel StackPanel">
<Style Selector="StackPanel > StackPanel">
<Setter Property="Margin" Value="10, 0, 0, 0" />
<Setter Property="Orientation" Value="Horizontal" />
</Style>
<Style Selector="StackPanel StackPanel > TextBlock">
<Style Selector="StackPanel > StackPanel > TextBlock">
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="Width" Value="230" />
</Style>
<Style Selector="ToggleButton, Button">
<Style Selector="ToggleButton">
<Setter Property="Width" Value="90" />
<Setter Property="Height" Value="27" />
<Setter Property="Padding" Value="0,5,0,5" /> <!-- Added vertical padding -->
</Style>
<Style Selector="ToggleButton > TextBlock">
<Setter Property="TextAlignment" Value="Center" />
@@ -40,123 +39,79 @@
VerticalScrollBarVisibility="Auto">
<Border Classes="settings">
<StackPanel
Name="SettingButtons"
Margin="10"
HorizontalAlignment="Stretch"
Orientation="Vertical"
Spacing="10"
Name="SettingButtons">
Spacing="10">
<TextBlock
Classes="h1"
Text="{ext:Locale SettingsTabHotkeysHotkeys}" />
<StackPanel
Margin="10,0,0,0"
Spacing="10"
Orientation="Vertical">
<StackPanel>
<TextBlock Text="{ext:Locale SettingsTabHotkeysToggleVSyncModeHotkey}" />
<ToggleButton Name="ToggleVSyncMode">
<TextBlock Text="{Binding KeyboardHotkey.ToggleVSyncMode, Converter={x:Static helpers:KeyValueConverter.Instance}}" />
</ToggleButton>
</StackPanel>
<StackPanel>
<TextBlock Text="{ext:Locale SettingsTabHotkeysScreenshotHotkey}" />
<ToggleButton Name="Screenshot">
<TextBlock Text="{Binding KeyboardHotkey.Screenshot, Converter={x:Static helpers:KeyValueConverter.Instance}}" />
</ToggleButton>
</StackPanel>
<StackPanel>
<TextBlock Text="{ext:Locale SettingsTabHotkeysShowUiHotkey}" />
<ToggleButton Name="ShowUI">
<TextBlock Text="{Binding KeyboardHotkey.ShowUI, Converter={x:Static helpers:KeyValueConverter.Instance}}" />
</ToggleButton>
</StackPanel>
<StackPanel>
<TextBlock Text="{ext:Locale SettingsTabHotkeysPauseHotkey}" />
<ToggleButton Name="Pause">
<TextBlock Text="{Binding KeyboardHotkey.Pause, Converter={x:Static helpers:KeyValueConverter.Instance}}" />
</ToggleButton>
</StackPanel>
<StackPanel>
<TextBlock Text="{ext:Locale SettingsTabHotkeysToggleMuteHotkey}" />
<ToggleButton Name="ToggleMute">
<TextBlock Text="{Binding KeyboardHotkey.ToggleMute, Converter={x:Static helpers:KeyValueConverter.Instance}}" />
</ToggleButton>
</StackPanel>
<StackPanel>
<TextBlock Text="{ext:Locale SettingsTabHotkeysResScaleUpHotkey}" />
<ToggleButton Name="ResScaleUp">
<TextBlock Text="{Binding KeyboardHotkey.ResScaleUp, Converter={x:Static helpers:KeyValueConverter.Instance}}" />
</ToggleButton>
</StackPanel>
<StackPanel>
<TextBlock Text="{ext:Locale SettingsTabHotkeysResScaleDownHotkey}" />
<ToggleButton Name="ResScaleDown">
<TextBlock Text="{Binding KeyboardHotkey.ResScaleDown, Converter={x:Static helpers:KeyValueConverter.Instance}}" />
</ToggleButton>
</StackPanel>
<StackPanel>
<TextBlock Text="{ext:Locale SettingsTabHotkeysVolumeUpHotkey}" />
<ToggleButton Name="VolumeUp">
<TextBlock Text="{Binding KeyboardHotkey.VolumeUp, Converter={x:Static helpers:KeyValueConverter.Instance}}" />
</ToggleButton>
</StackPanel>
<StackPanel>
<TextBlock Text="{ext:Locale SettingsTabHotkeysVolumeDownHotkey}" />
<ToggleButton Name="VolumeDown">
<TextBlock Text="{Binding KeyboardHotkey.VolumeDown, Converter={x:Static helpers:KeyValueConverter.Instance}}" />
</ToggleButton>
</StackPanel>
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
<TextBlock Text="{ext:Locale SettingsTabHotkeysIncrementCustomVSyncIntervalHotkey}" />
<ToggleButton Name="CustomVSyncIntervalIncrement">
<TextBlock Text="{Binding KeyboardHotkey.CustomVSyncIntervalIncrement, Converter={x:Static helpers:KeyValueConverter.Instance}}" />
</ToggleButton>
</StackPanel>
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
<TextBlock Text="{ext:Locale SettingsTabHotkeysDecrementCustomVSyncIntervalHotkey}" />
<ToggleButton Name="CustomVSyncIntervalDecrement">
<TextBlock Text="{Binding KeyboardHotkey.CustomVSyncIntervalDecrement, Converter={x:Static helpers:KeyValueConverter.Instance}}" />
</ToggleButton>
</StackPanel>
<StackPanel>
<TextBlock Text="{ext:Locale SettingsTabHotkeysToggleVSyncModeHotkey}" />
<ToggleButton Name="ToggleVSyncMode">
<TextBlock Text="{Binding KeyboardHotkey.ToggleVSyncMode, Converter={x:Static helpers:KeyValueConverter.Instance}}" />
</ToggleButton>
</StackPanel>
<Separator Height="1" />
<StackPanel Margin="0">
<TextBlock
Classes="h1"
Text="{ext:Locale SettingsTabHotkeysCycleControllers}" />
<StackPanel Orientation="Horizontal" Spacing="10">
<Button
Content="{ext:Locale SettingsTabGeneralAdd}"
Margin="10,0,0,0"
Command="{Binding KeyboardHotkey.AddCycleController}" />
<Button
Content="{ext:Locale SettingsTabGeneralRemove}"
IsEnabled="{Binding KeyboardHotkey.CanRemoveCycleController}"
Command="{Binding KeyboardHotkey.RemoveCycleController}" />
</StackPanel>
<StackPanel>
<TextBlock Text="{ext:Locale SettingsTabHotkeysScreenshotHotkey}" />
<ToggleButton Name="Screenshot">
<TextBlock Text="{Binding KeyboardHotkey.Screenshot, Converter={x:Static helpers:KeyValueConverter.Instance}}" />
</ToggleButton>
</StackPanel>
<StackPanel>
<TextBlock Text="{ext:Locale SettingsTabHotkeysShowUiHotkey}" />
<ToggleButton Name="ShowUI">
<TextBlock Text="{Binding KeyboardHotkey.ShowUI, Converter={x:Static helpers:KeyValueConverter.Instance}}" />
</ToggleButton>
</StackPanel>
<StackPanel>
<TextBlock Text="{ext:Locale SettingsTabHotkeysPauseHotkey}" />
<ToggleButton Name="Pause">
<TextBlock Text="{Binding KeyboardHotkey.Pause, Converter={x:Static helpers:KeyValueConverter.Instance}}" />
</ToggleButton>
</StackPanel>
<StackPanel>
<TextBlock Text="{ext:Locale SettingsTabHotkeysToggleMuteHotkey}" />
<ToggleButton Name="ToggleMute">
<TextBlock Text="{Binding KeyboardHotkey.ToggleMute, Converter={x:Static helpers:KeyValueConverter.Instance}}" />
</ToggleButton>
</StackPanel>
<StackPanel>
<TextBlock Text="{ext:Locale SettingsTabHotkeysResScaleUpHotkey}" />
<ToggleButton Name="ResScaleUp">
<TextBlock Text="{Binding KeyboardHotkey.ResScaleUp, Converter={x:Static helpers:KeyValueConverter.Instance}}" />
</ToggleButton>
</StackPanel>
<StackPanel>
<TextBlock Text="{ext:Locale SettingsTabHotkeysResScaleDownHotkey}" />
<ToggleButton Name="ResScaleDown">
<TextBlock Text="{Binding KeyboardHotkey.ResScaleDown, Converter={x:Static helpers:KeyValueConverter.Instance}}" />
</ToggleButton>
</StackPanel>
<StackPanel>
<TextBlock Text="{ext:Locale SettingsTabHotkeysVolumeUpHotkey}" />
<ToggleButton Name="VolumeUp">
<TextBlock Text="{Binding KeyboardHotkey.VolumeUp, Converter={x:Static helpers:KeyValueConverter.Instance}}" />
</ToggleButton>
</StackPanel>
<StackPanel>
<TextBlock Text="{ext:Locale SettingsTabHotkeysVolumeDownHotkey}" />
<ToggleButton Name="VolumeDown">
<TextBlock Text="{Binding KeyboardHotkey.VolumeDown, Converter={x:Static helpers:KeyValueConverter.Instance}}" />
</ToggleButton>
</StackPanel>
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
<TextBlock Text="{ext:Locale SettingsTabHotkeysIncrementCustomVSyncIntervalHotkey}" />
<ToggleButton Name="CustomVSyncIntervalIncrement">
<TextBlock Text="{Binding KeyboardHotkey.CustomVSyncIntervalIncrement, Converter={x:Static helpers:KeyValueConverter.Instance}}" />
</ToggleButton>
</StackPanel>
<StackPanel Margin="10,0,0,0" Orientation="Horizontal">
<TextBlock Text="{ext:Locale SettingsTabHotkeysDecrementCustomVSyncIntervalHotkey}" />
<ToggleButton Name="CustomVSyncIntervalDecrement">
<TextBlock Text="{Binding KeyboardHotkey.CustomVSyncIntervalDecrement, Converter={x:Static helpers:KeyValueConverter.Instance}}" />
</ToggleButton>
</StackPanel>
<ItemsControl ItemsSource="{Binding KeyboardHotkey.CycleControllers}"
Name="CycleControllers">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel
Margin="10,0,0,0"
Orientation="Vertical"
Spacing="10" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Player}" />
<ToggleButton>
<TextBlock
Text="{Binding Hotkey, Converter={x:Static helpers:KeyValueConverter.Instance}}" />
</ToggleButton>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</Border>
</ScrollViewer>

View File

@@ -3,14 +3,11 @@ using Avalonia.Controls.Primitives;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.LogicalTree;
using Avalonia.VisualTree;
using DynamicData;
using Ryujinx.Ava.Input;
using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.UI.ViewModels;
using Ryujinx.Input;
using Ryujinx.Input.Assigner;
using System.Linq;
using Button = Ryujinx.Input.Button;
using Key = Ryujinx.Common.Configuration.Hid.Key;
@@ -24,21 +21,16 @@ namespace Ryujinx.Ava.UI.Views.Settings
public SettingsHotkeysView()
{
InitializeComponent();
RegisterEvents();
_avaloniaKeyboardDriver = new AvaloniaKeyboardDriver(this);
CycleControllers.LayoutUpdated += (_, _1) => RegisterEvents();
}
private void RegisterEvents()
{
foreach (ILogical visual in SettingButtons.GetLogicalDescendants())
{
if (visual is ToggleButton button and not CheckBox)
{
button.IsCheckedChanged -= Button_IsCheckedChanged;
button.IsCheckedChanged += Button_IsCheckedChanged;
}
}
_avaloniaKeyboardDriver = new AvaloniaKeyboardDriver(this);
}
protected override void OnPointerReleased(PointerReleasedEventArgs e)
@@ -124,13 +116,6 @@ namespace Ryujinx.Ava.UI.Views.Settings
case "CustomVSyncIntervalDecrement":
viewModel.KeyboardHotkey.CustomVSyncIntervalDecrement = buttonValue.AsHidType<Key>();
break;
default:
var index = button.FindAncestorOfType<ItemsControl>().GetLogicalDescendants().OfType<ToggleButton>().IndexOf(button);
if (index >= 0 && viewModel.KeyboardHotkey.CycleControllers != null)
{
viewModel.KeyboardHotkey.CycleControllers[index].Hotkey = buttonValue.AsHidType<Key>();
}
break;
}
}
};

View File

@@ -133,12 +133,6 @@
<ComboBoxItem>
<TextBlock Text="{ext:Locale SettingsTabSystemSystemLanguageBrazilianPortuguese}" />
</ComboBoxItem>
<ComboBoxItem>
<TextBlock Text="{ext:Locale SettingsTabSystemSystemLanguageSwedish}" />
</ComboBoxItem>
<ComboBoxItem>
<TextBlock Text="{ext:Locale SettingsTabSystemSystemLanguageNorwegian}" />
</ComboBoxItem>
</ComboBox>
</StackPanel>
<StackPanel

View File

@@ -139,8 +139,24 @@ namespace Ryujinx.Ava.UI.Windows
base.OnApplyTemplate(e);
NotificationHelper.SetNotificationManager(this);
Executor.ExecuteBackgroundAsync(ShowIntelMacWarningAsync);
Executor.ExecuteBackgroundAsync(async () =>
{
await ShowIntelMacWarningAsync();
FilePath firmwarePath = CommandLineState.FirmwareToInstallPathArg;
if (firmwarePath is not null)
{
if ((firmwarePath.ExistsAsFile && firmwarePath.Extension is "xci" or "zip") ||
firmwarePath.ExistsAsDirectory)
{
await Dispatcher.UIThread.InvokeAsync(() =>
ViewModel.HandleFirmwareInstallation(firmwarePath));
CommandLineState.FirmwareToInstallPathArg = null;
}
else
Logger.Notice.Print(LogClass.UI, "Invalid firmware type provided. Path must be a directory, or a .zip or .xci file.");
}
});
}
private void OnScalingChanged(object sender, EventArgs e)
@@ -173,17 +189,12 @@ namespace Ryujinx.Ava.UI.Windows
{
Dispatcher.UIThread.Post(() =>
{
List<LdnGameData> ldnGameDataArray = e.LdnData.ToList();
ViewModel.LdnData.Clear();
foreach (ApplicationData application in ViewModel.Applications.Where(it => it.HasControlHolder))
{
ref ApplicationControlProperty controlHolder = ref application.ControlHolder.Value;
ViewModel.LdnData[application.IdString] =
LdnGameData.GetArrayForApp(
ldnGameDataArray,
ref controlHolder
);
ViewModel.LdnData[application.IdString] = e.LdnData.Where(ref controlHolder);
UpdateApplicationWithLdnData(application);
}

View File

@@ -42,7 +42,6 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
{
public class ApplicationLibrary
{
public const string DefaultLanPlayWebHost = "ryuldnweb.vudjun.com";
public Language DesiredLanguage { get; set; }
public event EventHandler<ApplicationCountUpdatedEventArgs> ApplicationCountUpdated;
public event Action<LdnGameDataReceivedEventArgs> LdnGameDataReceived;
@@ -826,7 +825,6 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
public async Task RefreshLdn()
{
if (ConfigurationState.Instance.Multiplayer.Mode == MultiplayerMode.LdnRyu)
{
try
@@ -834,33 +832,22 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
string ldnWebHost = ConfigurationState.Instance.Multiplayer.LdnServer;
if (string.IsNullOrEmpty(ldnWebHost))
{
ldnWebHost = DefaultLanPlayWebHost;
ldnWebHost = SharedConstants.DefaultLanPlayWebHost;
}
IEnumerable<LdnGameData> ldnGameDataArray = Array.Empty<LdnGameData>();
using HttpClient httpClient = new();
string ldnGameDataArrayString = await httpClient.GetStringAsync($"https://{ldnWebHost}/api/public_games");
ldnGameDataArray = JsonHelper.Deserialize(ldnGameDataArrayString, _ldnDataSerializerContext.IEnumerableLdnGameData);
LdnGameDataReceived?.Invoke(new LdnGameDataReceivedEventArgs
{
LdnData = ldnGameDataArray
});
LdnGameData[] ldnGameDataArray = JsonHelper.Deserialize(ldnGameDataArrayString, _ldnDataSerializerContext.IEnumerableLdnGameData).ToArray();
LdnGameDataReceived?.Invoke(new LdnGameDataReceivedEventArgs(ldnGameDataArray));
return;
}
catch (Exception ex)
{
Logger.Warning?.Print(LogClass.Application, $"Failed to fetch the public games JSON from the API. Player and game count in the game list will be unavailable.\n{ex.Message}");
LdnGameDataReceived?.Invoke(new LdnGameDataReceivedEventArgs
{
LdnData = Array.Empty<LdnGameData>()
});
}
}
else
{
LdnGameDataReceived?.Invoke(new LdnGameDataReceivedEventArgs
{
LdnData = Array.Empty<LdnGameData>()
});
}
LdnGameDataReceived?.Invoke(LdnGameDataReceivedEventArgs.Empty);
}
// Replace the currently stored DLC state for the game with the provided DLC state.

View File

@@ -18,7 +18,7 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
public IEnumerable<string> Players { get; set; }
public static Array GetArrayForApp(
IEnumerable<LdnGameData> receivedData, ref ApplicationControlProperty acp)
LdnGameData[] receivedData, ref ApplicationControlProperty acp)
{
LibHac.Common.FixedArrays.Array8<ulong> communicationId = acp.LocalCommunicationId;
@@ -40,4 +40,10 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
public int GameCount => _ldnDatas.Length;
}
}
public static class LdnGameDataHelper
{
public static LdnGameData.Array Where(this LdnGameData[] unfilteredDatas, ref ApplicationControlProperty acp)
=> LdnGameData.GetArrayForApp(unfilteredDatas, ref acp);
}
}

View File

@@ -5,6 +5,14 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
{
public class LdnGameDataReceivedEventArgs : EventArgs
{
public IEnumerable<LdnGameData> LdnData { get; set; }
public static new readonly LdnGameDataReceivedEventArgs Empty = new(null);
public LdnGameDataReceivedEventArgs(LdnGameData[] ldnData)
{
LdnData = ldnData ?? [];
}
public LdnGameData[] LdnData { get; set; }
}
}

View File

@@ -1,3 +1,4 @@
using Gommon;
using Ryujinx.Common.Logging;
using System.Collections.Generic;
@@ -13,6 +14,7 @@ namespace Ryujinx.Ava.Utilities
public static string OverrideBackendThreading { get; private set; }
public static string OverrideHideCursor { get; private set; }
public static string BaseDirPathArg { get; private set; }
public static FilePath FirmwareToInstallPathArg { get; set; }
public static string Profile { get; private set; }
public static string LaunchPathArg { get; private set; }
public static string LaunchApplicationId { get; private set; }
@@ -41,6 +43,19 @@ namespace Ryujinx.Ava.Utilities
BaseDirPathArg = args[++i];
arguments.Add(arg);
arguments.Add(args[i]);
break;
case "--install-firmware":
if (i + 1 >= args.Length)
{
Logger.Error?.Print(LogClass.Application, $"Invalid option '{arg}'");
continue;
}
FirmwareToInstallPathArg = new FilePath(args[++i]);
arguments.Add(arg);
arguments.Add(args[i]);
break;

View File

@@ -1,5 +1,6 @@
using ARMeilleure;
using Gommon;
using Ryujinx.Ava.Utilities.AppLibrary;
using Ryujinx.Ava.Utilities.Configuration.System;
using Ryujinx.Ava.Utilities.Configuration.UI;
using Ryujinx.Common;
@@ -647,6 +648,14 @@ namespace Ryujinx.Ava.Utilities.Configuration
/// </summary>
public ReactiveObject<string> LdnServer { get; private set; }
public string GetLdnServer()
{
string ldnServer = LdnServer;
return string.IsNullOrEmpty(ldnServer)
? SharedConstants.DefaultLanPlayHost
: ldnServer;
}
public MultiplayerSection()
{
LanInterfaceId = new ReactiveObject<string>();