Compare commits

..

6 Commits

16 changed files with 64 additions and 84 deletions
+1 -1
View File
@@ -1436,7 +1436,7 @@
010083A018262000,"Hitman: Blood Money — Reprisal",deadlock,ingame,2024-09-28 16:28:50 010083A018262000,"Hitman: Blood Money — Reprisal",deadlock,ingame,2024-09-28 16:28:50
01004B100A5CC000,"Hob: The Definitive Edition",,playable,2021-01-13 09:39:19 01004B100A5CC000,"Hob: The Definitive Edition",,playable,2021-01-13 09:39:19
0100F7300ED2C000,"Hoggy2",,playable,2022-10-10 13:53:35 0100F7300ED2C000,"Hoggy2",,playable,2022-10-10 13:53:35
0100F7E00C70E000,"Hogwarts Legacy",slow,ingame,2024-09-03 19:53:58 0100F7E00C70E000,"Hogwarts Legacy",UE4;slow,ingame,2024-09-03 19:53:58
0100633007D48000,"Hollow Knight",nvdec,playable,2023-01-16 15:44:56 0100633007D48000,"Hollow Knight",nvdec,playable,2023-01-16 15:44:56
0100F2100061E800,"Hollow0",UE4;gpu,ingame,2021-03-03 23:42:56 0100F2100061E800,"Hollow0",UE4;gpu,ingame,2021-03-03 23:42:56
0100342009E16000,"Holy Potatoes! What The Hell?!",,playable,2020-07-03 10:48:56 0100342009E16000,"Holy Potatoes! What The Hell?!",,playable,2020-07-03 10:48:56
1 title_id game_name labels status last_updated
1436 010083A018262000 Hitman: Blood Money — Reprisal deadlock ingame 2024-09-28 16:28:50
1437 01004B100A5CC000 Hob: The Definitive Edition playable 2021-01-13 09:39:19
1438 0100F7300ED2C000 Hoggy2 playable 2022-10-10 13:53:35
1439 0100F7E00C70E000 Hogwarts Legacy slow UE4;slow ingame 2024-09-03 19:53:58
1440 0100633007D48000 Hollow Knight nvdec playable 2023-01-16 15:44:56
1441 0100F2100061E800 Hollow0 UE4;gpu ingame 2021-03-03 23:42:56
1442 0100342009E16000 Holy Potatoes! What The Hell?! playable 2020-07-03 10:48:56
+9
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";
}
}
@@ -23,9 +23,6 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
{ {
class IUserLocalCommunicationService : IpcService, IDisposable class IUserLocalCommunicationService : IpcService, IDisposable
{ {
public static string DefaultLanPlayHost = "ryuldn.vudjun.com";
public static short LanPlayPort = 30456;
public INetworkClient NetworkClient { get; private set; } public INetworkClient NetworkClient { get; private set; }
private const int NifmRequestID = 90; private const int NifmRequestID = 90;
@@ -1092,20 +1089,18 @@ namespace Ryujinx.HLE.HOS.Services.Ldn.UserServiceCreator
case MultiplayerMode.LdnRyu: case MultiplayerMode.LdnRyu:
try try
{ {
string ldnServer = context.Device.Configuration.MultiplayerLdnServer; string ldnServer = context.Device.Configuration.MultiplayerLdnServer
if (string.IsNullOrEmpty(ldnServer)) ?? throw new InvalidOperationException("Cannot initialize RyuLDN with a null Multiplayer server.");
{
ldnServer = DefaultLanPlayHost;
}
if (!IPAddress.TryParse(ldnServer, out IPAddress ipAddress)) if (!IPAddress.TryParse(ldnServer, out IPAddress ipAddress))
{ {
ipAddress = Dns.GetHostEntry(ldnServer).AddressList[0]; 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) 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); Logger.Error?.Print(LogClass.ServiceLdn, ex.Message);
NetworkClient = new LdnDisabledClient(); NetworkClient = new LdnDisabledClient();
} }
+1 -1
View File
@@ -111,7 +111,7 @@ namespace Ryujinx.Input.SDL2
byte blue = packedRgb > 0 ? (byte)(packedRgb % 256) : (byte)0; byte blue = packedRgb > 0 ? (byte)(packedRgb % 256) : (byte)0;
if (SDL_GameControllerSetLED(_gamepadHandle, red, green, blue) != 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() private GamepadFeaturesFlag GetFeaturesFlag()
+1 -1
View File
@@ -951,7 +951,7 @@ namespace Ryujinx.Ava
ConfigurationState.Instance.Multiplayer.Mode, ConfigurationState.Instance.Multiplayer.Mode,
ConfigurationState.Instance.Multiplayer.DisableP2p, ConfigurationState.Instance.Multiplayer.DisableP2p,
ConfigurationState.Instance.Multiplayer.LdnPassphrase, ConfigurationState.Instance.Multiplayer.LdnPassphrase,
ConfigurationState.Instance.Multiplayer.LdnServer, ConfigurationState.Instance.Multiplayer.GetLdnServer(),
ConfigurationState.Instance.Graphics.CustomVSyncInterval.Value, ConfigurationState.Instance.Graphics.CustomVSyncInterval.Value,
ConfigurationState.Instance.Hacks.ShowDirtyHacks ? ConfigurationState.Instance.Hacks.EnabledHacks : null)); ConfigurationState.Instance.Hacks.ShowDirtyHacks ? ConfigurationState.Instance.Hacks.EnabledHacks : null));
} }
+5 -5
View File
@@ -468,7 +468,7 @@
"th_TH": "", "th_TH": "",
"tr_TR": "", "tr_TR": "",
"uk_UA": "Відкрити теку скріншотів", "uk_UA": "Відкрити теку скріншотів",
"zh_CN": "", "zh_CN": "打开截图文件夹",
"zh_TW": "" "zh_TW": ""
} }
}, },
@@ -5143,7 +5143,7 @@
"th_TH": "", "th_TH": "",
"tr_TR": "", "tr_TR": "",
"uk_UA": "Ігнорувати Аплет Контролера", "uk_UA": "Ігнорувати Аплет Контролера",
"zh_CN": "", "zh_CN": "忽略控制器小程序",
"zh_TW": "" "zh_TW": ""
} }
}, },
@@ -16518,7 +16518,7 @@
"th_TH": "", "th_TH": "",
"tr_TR": "", "tr_TR": "",
"uk_UA": "Діалогове вікно Аплету Контролера не з'явиться, якщо геймпад було відключено під час роботи програми.\n\nЗалиште вимкненим якщо не впевнені.", "uk_UA": "Діалогове вікно Аплету Контролера не з'явиться, якщо геймпад було відключено під час роботи програми.\n\nЗалиште вимкненим якщо не впевнені.",
"zh_CN": "", "zh_CN": "在应用程序运行时如果游戏手柄断开连接则不会显示控制器小程序对话框。\n\n如果不确定,请保持关闭状态。",
"zh_TW": "" "zh_TW": ""
} }
}, },
@@ -17193,7 +17193,7 @@
"th_TH": "", "th_TH": "",
"tr_TR": "", "tr_TR": "",
"uk_UA": "Відкрити теку куди зберігаються скріншоти Ryujinx", "uk_UA": "Відкрити теку куди зберігаються скріншоти Ryujinx",
"zh_CN": "", "zh_CN": "打开 Ryujinx 截图文件夹",
"zh_TW": "" "zh_TW": ""
} }
}, },
@@ -24073,4 +24073,4 @@
} }
} }
] ]
} }
@@ -52,7 +52,6 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
[ObservableProperty] private object _configViewModel; [ObservableProperty] private object _configViewModel;
[ObservableProperty] private string _profileName; [ObservableProperty] private string _profileName;
private bool _isLoaded; private bool _isLoaded;
public bool InitInputPage { get; set; }
private static readonly InputConfigJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions()); private static readonly InputConfigJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions());
@@ -93,8 +92,6 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
public bool CanClearLed => SelectedGamepad.Name.ContainsIgnoreCase("DualSense"); public bool CanClearLed => SelectedGamepad.Name.ContainsIgnoreCase("DualSense");
public bool IsModified { get; set; } public bool IsModified { get; set; }
public bool IsInputConfigChanged { get; set; }
public event Action NotifyChangesEvent; public event Action NotifyChangesEvent;
public PlayerIndex PlayerIdChoose public PlayerIndex PlayerIdChoose
@@ -124,12 +121,13 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
} }
_isLoaded = false; _isLoaded = false;
LoadConfiguration(); LoadConfiguration();
LoadDevice(); LoadDevice();
LoadProfiles(); LoadProfiles();
_isLoaded = true; _isLoaded = true;
OnPropertyChanged(); OnPropertyChanged();
} }
} }
@@ -298,10 +296,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
{ {
ConfigViewModel = new ControllerInputViewModel(this, new GamepadInputConfig(controllerInputConfig)); ConfigViewModel = new ControllerInputViewModel(this, new GamepadInputConfig(controllerInputConfig));
} }
}
IsInputConfigChanged |= InitInputPage; // If the field has been changed, the control settings will be overwritten
InitInputPage = true; // initialization variable
}
public void LoadDevice() public void LoadDevice()
{ {
@@ -822,13 +817,6 @@ namespace Ryujinx.Ava.UI.ViewModels.Input
{ {
IsModified = false; IsModified = false;
if (!IsInputConfigChanged)
{
return; //If the input settings were not touched, then do nothing
}
IsInputConfigChanged = false; // Input settings have been changed
List<InputConfig> newConfig = []; List<InputConfig> newConfig = [];
newConfig.AddRange(ConfigurationState.Instance.Hid.InputConfig.Value); newConfig.AddRange(ConfigurationState.Instance.Hid.InputConfig.Value);
@@ -65,9 +65,6 @@ namespace Ryujinx.Ava.UI.Views.Input
if (!float.IsNaN(_changeSlider) && _changeSlider != (float)check.Value) if (!float.IsNaN(_changeSlider) && _changeSlider != (float)check.Value)
{ {
(DataContext as ControllerInputViewModel)!.ParentModel.IsModified = true; (DataContext as ControllerInputViewModel)!.ParentModel.IsModified = true;
FlagInputConfigChanged();
_changeSlider = (float)check.Value; _changeSlider = (float)check.Value;
} }
} }
@@ -78,9 +75,6 @@ namespace Ryujinx.Ava.UI.Views.Input
if (sender is CheckBox { IsPointerOver: true }) if (sender is CheckBox { IsPointerOver: true })
{ {
(DataContext as ControllerInputViewModel)!.ParentModel.IsModified = true; (DataContext as ControllerInputViewModel)!.ParentModel.IsModified = true;
FlagInputConfigChanged();
_currentAssigner?.Cancel(); _currentAssigner?.Cancel();
_currentAssigner = null; _currentAssigner = null;
} }
@@ -108,8 +102,6 @@ namespace Ryujinx.Ava.UI.Views.Input
PointerPressed += MouseClick; PointerPressed += MouseClick;
FlagInputConfigChanged();
ControllerInputViewModel viewModel = (DataContext as ControllerInputViewModel); ControllerInputViewModel viewModel = (DataContext as ControllerInputViewModel);
IKeyboard keyboard = IKeyboard keyboard =
@@ -216,11 +208,6 @@ namespace Ryujinx.Ava.UI.Views.Input
} }
} }
private void FlagInputConfigChanged()
{
(DataContext as ControllerInputViewModel)!.ParentModel.IsInputConfigChanged = true;
}
private void MouseClick(object sender, PointerPressedEventArgs e) private void MouseClick(object sender, PointerPressedEventArgs e)
{ {
bool shouldUnbind = e.GetCurrentPoint(this).Properties.IsMiddleButtonPressed; bool shouldUnbind = e.GetCurrentPoint(this).Properties.IsMiddleButtonPressed;
@@ -252,6 +239,7 @@ namespace Ryujinx.Ava.UI.Views.Input
{ {
gamepad?.ClearLed(); gamepad?.ClearLed();
} }
_currentAssigner?.Cancel(); _currentAssigner?.Cancel();
_currentAssigner = null; _currentAssigner = null;
} }
@@ -48,7 +48,6 @@ namespace Ryujinx.Ava.UI.Views.Input
if (result == UserResult.Yes) if (result == UserResult.Yes)
{ {
ViewModel.InitInputPage = false;
ViewModel.Save(); ViewModel.Save();
} }
@@ -60,8 +60,6 @@ namespace Ryujinx.Ava.UI.Views.Input
PointerPressed += MouseClick; PointerPressed += MouseClick;
FlagInputConfigChanged();
if (DataContext is not KeyboardInputViewModel viewModel) if (DataContext is not KeyboardInputViewModel viewModel)
return; return;
@@ -186,11 +184,6 @@ namespace Ryujinx.Ava.UI.Views.Input
} }
} }
private void FlagInputConfigChanged()
{
(DataContext as KeyboardInputViewModel)!.ParentModel.IsInputConfigChanged = true;
}
private void MouseClick(object sender, PointerPressedEventArgs e) private void MouseClick(object sender, PointerPressedEventArgs e)
{ {
bool shouldUnbind = e.GetCurrentPoint(this).Properties.IsMiddleButtonPressed; bool shouldUnbind = e.GetCurrentPoint(this).Properties.IsMiddleButtonPressed;
+5 -7
View File
@@ -148,8 +148,11 @@ namespace Ryujinx.Ava.UI.Windows
{ {
if ((firmwarePath.ExistsAsFile && firmwarePath.Extension is "xci" or "zip") || if ((firmwarePath.ExistsAsFile && firmwarePath.Extension is "xci" or "zip") ||
firmwarePath.ExistsAsDirectory) firmwarePath.ExistsAsDirectory)
{
await Dispatcher.UIThread.InvokeAsync(() => await Dispatcher.UIThread.InvokeAsync(() =>
ViewModel.HandleFirmwareInstallation(firmwarePath)); ViewModel.HandleFirmwareInstallation(firmwarePath));
CommandLineState.FirmwareToInstallPathArg = null;
}
else else
Logger.Notice.Print(LogClass.UI, "Invalid firmware type provided. Path must be a directory, or a .zip or .xci file."); Logger.Notice.Print(LogClass.UI, "Invalid firmware type provided. Path must be a directory, or a .zip or .xci file.");
} }
@@ -186,17 +189,12 @@ namespace Ryujinx.Ava.UI.Windows
{ {
Dispatcher.UIThread.Post(() => Dispatcher.UIThread.Post(() =>
{ {
List<LdnGameData> ldnGameDataArray = e.LdnData.ToList();
ViewModel.LdnData.Clear(); ViewModel.LdnData.Clear();
foreach (ApplicationData application in ViewModel.Applications.Where(it => it.HasControlHolder)) foreach (ApplicationData application in ViewModel.Applications.Where(it => it.HasControlHolder))
{ {
ref ApplicationControlProperty controlHolder = ref application.ControlHolder.Value; ref ApplicationControlProperty controlHolder = ref application.ControlHolder.Value;
ViewModel.LdnData[application.IdString] = ViewModel.LdnData[application.IdString] = e.LdnData.Where(ref controlHolder);
LdnGameData.GetArrayForApp(
ldnGameDataArray,
ref controlHolder
);
UpdateApplicationWithLdnData(application); UpdateApplicationWithLdnData(application);
} }
@@ -42,7 +42,6 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
{ {
public class ApplicationLibrary public class ApplicationLibrary
{ {
public const string DefaultLanPlayWebHost = "ryuldnweb.vudjun.com";
public Language DesiredLanguage { get; set; } public Language DesiredLanguage { get; set; }
public event EventHandler<ApplicationCountUpdatedEventArgs> ApplicationCountUpdated; public event EventHandler<ApplicationCountUpdatedEventArgs> ApplicationCountUpdated;
public event Action<LdnGameDataReceivedEventArgs> LdnGameDataReceived; public event Action<LdnGameDataReceivedEventArgs> LdnGameDataReceived;
@@ -826,7 +825,6 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
public async Task RefreshLdn() public async Task RefreshLdn()
{ {
if (ConfigurationState.Instance.Multiplayer.Mode == MultiplayerMode.LdnRyu) if (ConfigurationState.Instance.Multiplayer.Mode == MultiplayerMode.LdnRyu)
{ {
try try
@@ -834,33 +832,22 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
string ldnWebHost = ConfigurationState.Instance.Multiplayer.LdnServer; string ldnWebHost = ConfigurationState.Instance.Multiplayer.LdnServer;
if (string.IsNullOrEmpty(ldnWebHost)) if (string.IsNullOrEmpty(ldnWebHost))
{ {
ldnWebHost = DefaultLanPlayWebHost; ldnWebHost = SharedConstants.DefaultLanPlayWebHost;
} }
IEnumerable<LdnGameData> ldnGameDataArray = Array.Empty<LdnGameData>();
using HttpClient httpClient = new(); using HttpClient httpClient = new();
string ldnGameDataArrayString = await httpClient.GetStringAsync($"https://{ldnWebHost}/api/public_games"); string ldnGameDataArrayString = await httpClient.GetStringAsync($"https://{ldnWebHost}/api/public_games");
ldnGameDataArray = JsonHelper.Deserialize(ldnGameDataArrayString, _ldnDataSerializerContext.IEnumerableLdnGameData); LdnGameData[] ldnGameDataArray = JsonHelper.Deserialize(ldnGameDataArrayString, _ldnDataSerializerContext.IEnumerableLdnGameData).ToArray();
LdnGameDataReceived?.Invoke(new LdnGameDataReceivedEventArgs LdnGameDataReceived?.Invoke(new LdnGameDataReceivedEventArgs(ldnGameDataArray));
{ return;
LdnData = ldnGameDataArray
});
} }
catch (Exception ex) 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}"); 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(LdnGameDataReceivedEventArgs.Empty);
LdnGameDataReceived?.Invoke(new LdnGameDataReceivedEventArgs
{
LdnData = Array.Empty<LdnGameData>()
});
}
} }
// Replace the currently stored DLC state for the game with the provided DLC state. // Replace the currently stored DLC state for the game with the provided DLC state.
@@ -18,7 +18,7 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
public IEnumerable<string> Players { get; set; } public IEnumerable<string> Players { get; set; }
public static Array GetArrayForApp( public static Array GetArrayForApp(
IEnumerable<LdnGameData> receivedData, ref ApplicationControlProperty acp) LdnGameData[] receivedData, ref ApplicationControlProperty acp)
{ {
LibHac.Common.FixedArrays.Array8<ulong> communicationId = acp.LocalCommunicationId; LibHac.Common.FixedArrays.Array8<ulong> communicationId = acp.LocalCommunicationId;
@@ -40,4 +40,10 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
public int GameCount => _ldnDatas.Length; 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);
}
} }
@@ -5,6 +5,14 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
{ {
public class LdnGameDataReceivedEventArgs : EventArgs 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; }
} }
} }
+1 -1
View File
@@ -14,7 +14,7 @@ namespace Ryujinx.Ava.Utilities
public static string OverrideBackendThreading { get; private set; } public static string OverrideBackendThreading { get; private set; }
public static string OverrideHideCursor { get; private set; } public static string OverrideHideCursor { get; private set; }
public static string BaseDirPathArg { get; private set; } public static string BaseDirPathArg { get; private set; }
public static FilePath FirmwareToInstallPathArg { get; private set; } public static FilePath FirmwareToInstallPathArg { get; set; }
public static string Profile { get; private set; } public static string Profile { get; private set; }
public static string LaunchPathArg { get; private set; } public static string LaunchPathArg { get; private set; }
public static string LaunchApplicationId { get; private set; } public static string LaunchApplicationId { get; private set; }
@@ -1,5 +1,6 @@
using ARMeilleure; using ARMeilleure;
using Gommon; using Gommon;
using Ryujinx.Ava.Utilities.AppLibrary;
using Ryujinx.Ava.Utilities.Configuration.System; using Ryujinx.Ava.Utilities.Configuration.System;
using Ryujinx.Ava.Utilities.Configuration.UI; using Ryujinx.Ava.Utilities.Configuration.UI;
using Ryujinx.Common; using Ryujinx.Common;
@@ -647,6 +648,14 @@ namespace Ryujinx.Ava.Utilities.Configuration
/// </summary> /// </summary>
public ReactiveObject<string> LdnServer { get; private set; } public ReactiveObject<string> LdnServer { get; private set; }
public string GetLdnServer()
{
string ldnServer = LdnServer;
return string.IsNullOrEmpty(ldnServer)
? SharedConstants.DefaultLanPlayHost
: ldnServer;
}
public MultiplayerSection() public MultiplayerSection()
{ {
LanInterfaceId = new ReactiveObject<string>(); LanInterfaceId = new ReactiveObject<string>();