From d3bc3a1081863d07fc8d4bdc48e6b69fafa5e41c Mon Sep 17 00:00:00 2001 From: Evan Husted Date: Fri, 27 Dec 2024 01:32:23 -0600 Subject: [PATCH] UI: Simplify LDN data logic --- src/Ryujinx.UI.Common/App/ApplicationData.cs | 2 ++ .../App/ApplicationLibrary.cs | 9 ++++--- src/Ryujinx.UI.Common/App/LdnGameDataList.cs | 24 +++++++++++++++++++ .../UI/ViewModels/MainWindowViewModel.cs | 6 +++-- src/Ryujinx/UI/Windows/MainWindow.axaml.cs | 18 ++++++++------ 5 files changed, 45 insertions(+), 14 deletions(-) create mode 100644 src/Ryujinx.UI.Common/App/LdnGameDataList.cs diff --git a/src/Ryujinx.UI.Common/App/ApplicationData.cs b/src/Ryujinx.UI.Common/App/ApplicationData.cs index 657b9a022..ee5545dde 100644 --- a/src/Ryujinx.UI.Common/App/ApplicationData.cs +++ b/src/Ryujinx.UI.Common/App/ApplicationData.cs @@ -36,6 +36,8 @@ namespace Ryujinx.UI.App.Common public string Path { get; set; } public BlitStruct ControlHolder { get; set; } + public bool HasControlHolder => ControlHolder.ByteSpan.Length > 0; + public string TimePlayedString => ValueFormatUtils.FormatTimeSpan(TimePlayed); public string LastPlayedString => ValueFormatUtils.FormatDateTime(LastPlayed)?.Replace(" ", "\n") ?? LocalizedNever(); diff --git a/src/Ryujinx.UI.Common/App/ApplicationLibrary.cs b/src/Ryujinx.UI.Common/App/ApplicationLibrary.cs index cb6467f5e..e78af3121 100644 --- a/src/Ryujinx.UI.Common/App/ApplicationLibrary.cs +++ b/src/Ryujinx.UI.Common/App/ApplicationLibrary.cs @@ -789,16 +789,15 @@ namespace Ryujinx.UI.App.Common using HttpClient httpClient = new HttpClient(); string ldnGameDataArrayString = await httpClient.GetStringAsync($"https://{ldnWebHost}/api/public_games"); ldnGameDataArray = JsonHelper.Deserialize(ldnGameDataArrayString, _ldnDataSerializerContext.IEnumerableLdnGameData); - var evt = new LdnGameDataReceivedEventArgs + LdnGameDataReceived?.Invoke(null, new LdnGameDataReceivedEventArgs { LdnData = ldnGameDataArray - }; - LdnGameDataReceived?.Invoke(null, evt); + }); } 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(null, new LdnGameDataReceivedEventArgs() + LdnGameDataReceived?.Invoke(null, new LdnGameDataReceivedEventArgs { LdnData = Array.Empty() }); @@ -806,7 +805,7 @@ namespace Ryujinx.UI.App.Common } else { - LdnGameDataReceived?.Invoke(null, new LdnGameDataReceivedEventArgs() + LdnGameDataReceived?.Invoke(null, new LdnGameDataReceivedEventArgs { LdnData = Array.Empty() }); diff --git a/src/Ryujinx.UI.Common/App/LdnGameDataList.cs b/src/Ryujinx.UI.Common/App/LdnGameDataList.cs new file mode 100644 index 000000000..d98fd081d --- /dev/null +++ b/src/Ryujinx.UI.Common/App/LdnGameDataList.cs @@ -0,0 +1,24 @@ +using LibHac.Ns; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Ryujinx.UI.App.Common +{ + public class LdnGameDataArray + { + private readonly LdnGameData[] _ldnDatas; + + public LdnGameDataArray(IEnumerable receivedData, ref ApplicationControlProperty acp) + { + LibHac.Common.FixedArrays.Array8 communicationId = acp.LocalCommunicationId; + + _ldnDatas = receivedData.Where(game => + communicationId.Items.Contains(Convert.ToUInt64(game.TitleId, 16)) + ).ToArray(); + } + + public int PlayerCount => _ldnDatas.Sum(it => it.PlayerCount); + public int GameCount => _ldnDatas.Length; + } +} diff --git a/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs b/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs index d0ea64c37..3b98a7aa3 100644 --- a/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs @@ -9,6 +9,7 @@ using Avalonia.Threading; using DynamicData; using DynamicData.Binding; using FluentAvalonia.UI.Controls; +using Gommon; using LibHac.Common; using LibHac.Ns; using Ryujinx.Ava.Common; @@ -119,8 +120,9 @@ namespace Ryujinx.Ava.UI.ViewModels public ApplicationData ListSelectedApplication; public ApplicationData GridSelectedApplication; - - public IEnumerable LastLdnGameData; + + // Key is Title ID + public SafeDictionary LdnData = []; // The UI specifically uses a thicker bordered variant of the icon to avoid crunching out the border at lower resolutions. // For an example of this, download canary 1.2.95, then open the settings menu, and look at the icon in the top-left. diff --git a/src/Ryujinx/UI/Windows/MainWindow.axaml.cs b/src/Ryujinx/UI/Windows/MainWindow.axaml.cs index ca91b180f..832674541 100644 --- a/src/Ryujinx/UI/Windows/MainWindow.axaml.cs +++ b/src/Ryujinx/UI/Windows/MainWindow.axaml.cs @@ -167,24 +167,28 @@ namespace Ryujinx.Ava.UI.Windows { Dispatcher.UIThread.Post(() => { - var ldnGameDataArray = e.LdnData; - ViewModel.LastLdnGameData = ldnGameDataArray; + var ldnGameDataArray = e.LdnData.ToList(); + ViewModel.LdnData.Clear(); foreach (var application in ViewModel.Applications) { + ViewModel.LdnData[application.IdString] = new LdnGameDataArray( + ldnGameDataArray, + ref application.ControlHolder.Value + ); + UpdateApplicationWithLdnData(application); } + ViewModel.RefreshView(); }); } private void UpdateApplicationWithLdnData(ApplicationData application) { - if (application.ControlHolder.ByteSpan.Length > 0 && ViewModel.LastLdnGameData != null) + if (application.HasControlHolder && ViewModel.LdnData.TryGetValue(application.IdString, out var ldnGameDatas)) { - IEnumerable ldnGameData = ViewModel.LastLdnGameData.Where(game => application.ControlHolder.Value.LocalCommunicationId.Items.Contains(Convert.ToUInt64(game.TitleId, 16))); - - application.PlayerCount = ldnGameData.Sum(game => game.PlayerCount); - application.GameCount = ldnGameData.Count(); + application.PlayerCount = ldnGameDatas.PlayerCount; + application.GameCount = ldnGameDatas.GameCount; } else {