Add games/player count to Avalonia version, and retrieve asynchronously so the games list still loads if the server is down/slow

This commit is contained in:
Vudjun 2024-10-22 18:37:02 +01:00
parent e1c7af129a
commit b8d860192a
5 changed files with 103 additions and 20 deletions

View file

@ -41,6 +41,7 @@ namespace Ryujinx.UI.App.Common
public Language DesiredLanguage { get; set; }
public event EventHandler<ApplicationAddedEventArgs> ApplicationAdded;
public event EventHandler<ApplicationCountUpdatedEventArgs> ApplicationCountUpdated;
public event EventHandler<LdnGameDataReceivedEventArgs> LdnGameDataReceived;
private readonly byte[] _nspIcon;
private readonly byte[] _xciIcon;
@ -565,22 +566,28 @@ namespace Ryujinx.UI.App.Common
}
}
IEnumerable<LdnGameData> ldnGameDataArray = Array.Empty<LdnGameData>();
if (ConfigurationState.Instance.Multiplayer.Mode == MultiplayerMode.LdnRyu)
{
try
_ = Task.Run(async () =>
{
using HttpClient httpClient = new HttpClient();
string ldnGameDataArrayString = await httpClient.GetStringAsync("https://ldn.ryujinx.org/api/public_games");
ldnGameDataArray = JsonHelper.Deserialize(ldnGameDataArrayString, _ldnDataSerializerContext.IEnumerableLdnGameData);
}
catch
{
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.");
}
try
{
IEnumerable<LdnGameData> ldnGameDataArray = Array.Empty<LdnGameData>();
using HttpClient httpClient = new HttpClient();
string ldnGameDataArrayString = await httpClient.GetStringAsync("https://ldn.ryujinx.org/api/public_games");
ldnGameDataArray = JsonHelper.Deserialize(ldnGameDataArrayString, _ldnDataSerializerContext.IEnumerableLdnGameData);
var evt = new LdnGameDataReceivedEventArgs
{
LdnData = ldnGameDataArray
};
LdnGameDataReceived?.Invoke(null, evt);
}
catch
{
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.");
}
});
}
// Loops through applications list, creating a struct and then firing an event containing the struct for each application
@ -595,14 +602,6 @@ namespace Ryujinx.UI.App.Common
{
foreach (var application in applications)
{
if (application.ControlHolder.ByteSpan.Length > 0)
{
IEnumerable<LdnGameData> ldnGameData = ldnGameDataArray.Where(game => application.ControlHolder.Value.LocalCommunicationId.Items.Contains(Convert.ToUInt64(game.TitleId, 16)));
application.PlayerCount = ldnGameData.Sum(game => game.PlayerCount);
application.GameCount = ldnGameData.Count();
}
OnApplicationAdded(new ApplicationAddedEventArgs
{
AppData = application,

View file

@ -0,0 +1,11 @@
using Ryujinx.Ui.Common.App;
using System;
using System.Collections.Generic;
namespace Ryujinx.UI.App.Common
{
public class LdnGameDataReceivedEventArgs : EventArgs
{
public IEnumerable<LdnGameData> LdnData { get; set; }
}
}

View file

@ -7,6 +7,7 @@
xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
xmlns:converters="clr-namespace:Avalonia.Data.Converters;assembly=Avalonia.Base"
d:DesignHeight="450"
d:DesignWidth="800"
Focusable="True"
@ -117,6 +118,11 @@
Text="{Binding FileExtension}"
TextAlignment="Start"
TextWrapping="Wrap" />
<TextBlock
HorizontalAlignment="Stretch"
Text="{Binding Converter={helpers:MultiplayerInfoConverter}}"
TextAlignment="Start"
TextWrapping="Wrap"/>
</StackPanel>
<StackPanel
Grid.Column="4"

View file

@ -0,0 +1,44 @@
using Avalonia.Data.Converters;
using Avalonia.Markup.Xaml;
using Ryujinx.Ava.Common.Locale;
using Ryujinx.UI.App.Common;
using Ryujinx.UI.Common.Helper;
using System;
using System.Globalization;
namespace Ryujinx.Ava.UI.Helpers
{
internal class MultiplayerInfoConverter : MarkupExtension, IValueConverter
{
private static readonly MultiplayerInfoConverter _instance = new();
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is ApplicationData applicationData)
{
if (applicationData.PlayerCount != 0 && applicationData.GameCount != 0)
{
return $"Hosted Games: {applicationData.GameCount}\nOnline Players: {applicationData.PlayerCount}";
}
else
{
return "";
}
}
else
{
return "";
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
public override object ProvideValue(IServiceProvider serviceProvider)
{
return _instance;
}
}
}

View file

@ -19,12 +19,14 @@ using Ryujinx.HLE.HOS;
using Ryujinx.HLE.HOS.Services.Account.Acc;
using Ryujinx.Input.HLE;
using Ryujinx.Input.SDL2;
using Ryujinx.Ui.Common.App;
using Ryujinx.UI.App.Common;
using Ryujinx.UI.Common;
using Ryujinx.UI.Common.Configuration;
using Ryujinx.UI.Common.Helper;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Versioning;
using System.Threading;
using System.Threading.Tasks;
@ -164,6 +166,26 @@ namespace Ryujinx.Ava.UI.Windows
});
}
private void ApplicationLibrary_LdnGameDataReceived(object sender, LdnGameDataReceivedEventArgs e)
{
Dispatcher.UIThread.Post(() =>
{
var ldnGameDataArray = e.LdnData;
foreach (var application in ViewModel.Applications)
{
if (application.ControlHolder.ByteSpan.Length > 0)
{
IEnumerable<LdnGameData> ldnGameData = ldnGameDataArray.Where(game => application.ControlHolder.Value.LocalCommunicationId.Items.Contains(Convert.ToUInt64(game.TitleId, 16)));
application.PlayerCount = ldnGameData.Sum(game => game.PlayerCount);
application.GameCount = ldnGameData.Count();
Console.WriteLine($"PlayerCount: {application.PlayerCount}, GameCount: {application.GameCount}");
}
}
ViewModel.RefreshView();
});
}
public void Application_Opened(object sender, ApplicationOpenedEventArgs args)
{
if (args.Application != null)
@ -475,6 +497,7 @@ namespace Ryujinx.Ava.UI.Windows
ApplicationLibrary.ApplicationCountUpdated += ApplicationLibrary_ApplicationCountUpdated;
ApplicationLibrary.ApplicationAdded += ApplicationLibrary_ApplicationAdded;
ApplicationLibrary.LdnGameDataReceived += ApplicationLibrary_LdnGameDataReceived;
ViewModel.RefreshFirmwareStatus();