From 0733b7d0a1bdfe4063af2c9d73528d03b62f02fe Mon Sep 17 00:00:00 2001 From: Evan Husted Date: Fri, 27 Dec 2024 00:38:12 -0600 Subject: [PATCH 01/12] chore: Remove duplicate VSyncMode enum in GAL --- src/Ryujinx.Graphics.GAL/IWindow.cs | 1 + .../Multithreading/ThreadedWindow.cs | 1 + src/Ryujinx.Graphics.GAL/VSyncMode.cs | 9 --------- src/Ryujinx.Graphics.Metal/Window.cs | 3 +++ src/Ryujinx.Graphics.OpenGL/Window.cs | 3 +++ src/Ryujinx.Graphics.Vulkan/Window.cs | 3 +++ src/Ryujinx.Graphics.Vulkan/WindowBase.cs | 3 +++ src/Ryujinx.HLE/HLEConfiguration.cs | 1 - .../HOS/Services/SurfaceFlinger/SurfaceFlinger.cs | 1 - 9 files changed, 14 insertions(+), 11 deletions(-) delete mode 100644 src/Ryujinx.Graphics.GAL/VSyncMode.cs diff --git a/src/Ryujinx.Graphics.GAL/IWindow.cs b/src/Ryujinx.Graphics.GAL/IWindow.cs index 12686cb28..48144f0b0 100644 --- a/src/Ryujinx.Graphics.GAL/IWindow.cs +++ b/src/Ryujinx.Graphics.GAL/IWindow.cs @@ -1,3 +1,4 @@ +using Ryujinx.Common.Configuration; using System; namespace Ryujinx.Graphics.GAL diff --git a/src/Ryujinx.Graphics.GAL/Multithreading/ThreadedWindow.cs b/src/Ryujinx.Graphics.GAL/Multithreading/ThreadedWindow.cs index 102fdb1bb..7a4836982 100644 --- a/src/Ryujinx.Graphics.GAL/Multithreading/ThreadedWindow.cs +++ b/src/Ryujinx.Graphics.GAL/Multithreading/ThreadedWindow.cs @@ -1,3 +1,4 @@ +using Ryujinx.Common.Configuration; using Ryujinx.Graphics.GAL.Multithreading.Commands.Window; using Ryujinx.Graphics.GAL.Multithreading.Model; using Ryujinx.Graphics.GAL.Multithreading.Resources; diff --git a/src/Ryujinx.Graphics.GAL/VSyncMode.cs b/src/Ryujinx.Graphics.GAL/VSyncMode.cs deleted file mode 100644 index c5794b8f7..000000000 --- a/src/Ryujinx.Graphics.GAL/VSyncMode.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Ryujinx.Graphics.GAL -{ - public enum VSyncMode - { - Switch, - Unbounded, - Custom - } -} diff --git a/src/Ryujinx.Graphics.Metal/Window.cs b/src/Ryujinx.Graphics.Metal/Window.cs index 29099e7b1..203a29ebc 100644 --- a/src/Ryujinx.Graphics.Metal/Window.cs +++ b/src/Ryujinx.Graphics.Metal/Window.cs @@ -1,3 +1,4 @@ +using Ryujinx.Common.Configuration; using Ryujinx.Common.Logging; using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.Metal.Effects; @@ -6,6 +7,8 @@ using SharpMetal.ObjectiveCCore; using SharpMetal.QuartzCore; using System; using System.Runtime.Versioning; +using AntiAliasing = Ryujinx.Graphics.GAL.AntiAliasing; +using ScalingFilter = Ryujinx.Graphics.GAL.ScalingFilter; namespace Ryujinx.Graphics.Metal { diff --git a/src/Ryujinx.Graphics.OpenGL/Window.cs b/src/Ryujinx.Graphics.OpenGL/Window.cs index 1dc8a51f6..8c35663ab 100644 --- a/src/Ryujinx.Graphics.OpenGL/Window.cs +++ b/src/Ryujinx.Graphics.OpenGL/Window.cs @@ -1,9 +1,12 @@ using OpenTK.Graphics.OpenGL; +using Ryujinx.Common.Configuration; using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.OpenGL.Effects; using Ryujinx.Graphics.OpenGL.Effects.Smaa; using Ryujinx.Graphics.OpenGL.Image; using System; +using AntiAliasing = Ryujinx.Graphics.GAL.AntiAliasing; +using ScalingFilter = Ryujinx.Graphics.GAL.ScalingFilter; namespace Ryujinx.Graphics.OpenGL { diff --git a/src/Ryujinx.Graphics.Vulkan/Window.cs b/src/Ryujinx.Graphics.Vulkan/Window.cs index 3e8d3b375..d135d0076 100644 --- a/src/Ryujinx.Graphics.Vulkan/Window.cs +++ b/src/Ryujinx.Graphics.Vulkan/Window.cs @@ -1,9 +1,12 @@ +using Ryujinx.Common.Configuration; using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.Vulkan.Effects; using Silk.NET.Vulkan; using Silk.NET.Vulkan.Extensions.KHR; using System; using System.Linq; +using AntiAliasing = Ryujinx.Graphics.GAL.AntiAliasing; +using ScalingFilter = Ryujinx.Graphics.GAL.ScalingFilter; using VkFormat = Silk.NET.Vulkan.Format; namespace Ryujinx.Graphics.Vulkan diff --git a/src/Ryujinx.Graphics.Vulkan/WindowBase.cs b/src/Ryujinx.Graphics.Vulkan/WindowBase.cs index ca06ec0b8..807bb65e5 100644 --- a/src/Ryujinx.Graphics.Vulkan/WindowBase.cs +++ b/src/Ryujinx.Graphics.Vulkan/WindowBase.cs @@ -1,5 +1,8 @@ +using Ryujinx.Common.Configuration; using Ryujinx.Graphics.GAL; using System; +using AntiAliasing = Ryujinx.Graphics.GAL.AntiAliasing; +using ScalingFilter = Ryujinx.Graphics.GAL.ScalingFilter; namespace Ryujinx.Graphics.Vulkan { diff --git a/src/Ryujinx.HLE/HLEConfiguration.cs b/src/Ryujinx.HLE/HLEConfiguration.cs index f75ead588..52c2b3da4 100644 --- a/src/Ryujinx.HLE/HLEConfiguration.cs +++ b/src/Ryujinx.HLE/HLEConfiguration.cs @@ -9,7 +9,6 @@ using Ryujinx.HLE.HOS.Services.Account.Acc; using Ryujinx.HLE.HOS.SystemState; using Ryujinx.HLE.UI; using System; -using VSyncMode = Ryujinx.Common.Configuration.VSyncMode; namespace Ryujinx.HLE { diff --git a/src/Ryujinx.HLE/HOS/Services/SurfaceFlinger/SurfaceFlinger.cs b/src/Ryujinx.HLE/HOS/Services/SurfaceFlinger/SurfaceFlinger.cs index 23bf8bcfc..935e9895e 100644 --- a/src/Ryujinx.HLE/HOS/Services/SurfaceFlinger/SurfaceFlinger.cs +++ b/src/Ryujinx.HLE/HOS/Services/SurfaceFlinger/SurfaceFlinger.cs @@ -10,7 +10,6 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading; -using VSyncMode = Ryujinx.Common.Configuration.VSyncMode; namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger { -- 2.47.1 From c7270334ea6f720664a66b4d18ed89f58561c61e Mon Sep 17 00:00:00 2001 From: Your Name Date: Sun, 22 Dec 2024 16:55:29 -0800 Subject: [PATCH 02/12] UI: Option to automatically Hide UI when game launches Quality of life feature. Removes the need to manually hide UI every time the game launches --- .../Configuration/ConfigurationFileFormat.cs | 7 +++++- .../ConfigurationState.Migration.cs | 10 ++++++++ .../Configuration/ConfigurationState.Model.cs | 6 +++++ .../Configuration/ConfigurationState.cs | 2 ++ src/Ryujinx/AppHost.cs | 8 +++++++ src/Ryujinx/Assets/locales.json | 24 +++++++++++++++++++ .../UI/ViewModels/MainWindowViewModel.cs | 18 ++++++++++++++ .../UI/Views/Main/MainMenuBarView.axaml | 23 ++++++++++++++++++ 8 files changed, 97 insertions(+), 1 deletion(-) diff --git a/src/Ryujinx.UI.Common/Configuration/ConfigurationFileFormat.cs b/src/Ryujinx.UI.Common/Configuration/ConfigurationFileFormat.cs index 027e1052b..5f19f137f 100644 --- a/src/Ryujinx.UI.Common/Configuration/ConfigurationFileFormat.cs +++ b/src/Ryujinx.UI.Common/Configuration/ConfigurationFileFormat.cs @@ -17,7 +17,7 @@ namespace Ryujinx.UI.Common.Configuration /// /// The current version of the file format /// - public const int CurrentVersion = 57; + public const int CurrentVersion = 58; /// /// Version of the configuration file format @@ -351,6 +351,11 @@ namespace Ryujinx.UI.Common.Configuration /// public bool StartFullscreen { get; set; } + /// + /// Start games with UI hidden + /// + public bool StartNoUI { get; set; } + /// /// Show console window /// diff --git a/src/Ryujinx.UI.Common/Configuration/ConfigurationState.Migration.cs b/src/Ryujinx.UI.Common/Configuration/ConfigurationState.Migration.cs index a41ea2cd7..9579e15eb 100644 --- a/src/Ryujinx.UI.Common/Configuration/ConfigurationState.Migration.cs +++ b/src/Ryujinx.UI.Common/Configuration/ConfigurationState.Migration.cs @@ -638,6 +638,15 @@ namespace Ryujinx.UI.Common.Configuration configurationFileUpdated = true; } + if (configurationFileFormat.Version < 58) + { + Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 17."); + + configurationFileFormat.StartNoUI = false; + + configurationFileUpdated = true; + } + Logger.EnableFileLog.Value = configurationFileFormat.EnableFileLog; Graphics.ResScale.Value = configurationFileFormat.ResScale; Graphics.ResScaleCustom.Value = configurationFileFormat.ResScaleCustom; @@ -719,6 +728,7 @@ namespace Ryujinx.UI.Common.Configuration UI.GridSize.Value = configurationFileFormat.GridSize; UI.ApplicationSort.Value = configurationFileFormat.ApplicationSort; UI.StartFullscreen.Value = configurationFileFormat.StartFullscreen; + UI.StartNoUI.Value = configurationFileFormat.StartNoUI; UI.ShowConsole.Value = configurationFileFormat.ShowConsole; UI.WindowStartup.WindowSizeWidth.Value = configurationFileFormat.WindowStartup.WindowSizeWidth; UI.WindowStartup.WindowSizeHeight.Value = configurationFileFormat.WindowStartup.WindowSizeHeight; diff --git a/src/Ryujinx.UI.Common/Configuration/ConfigurationState.Model.cs b/src/Ryujinx.UI.Common/Configuration/ConfigurationState.Model.cs index f28ce0348..9da0e8968 100644 --- a/src/Ryujinx.UI.Common/Configuration/ConfigurationState.Model.cs +++ b/src/Ryujinx.UI.Common/Configuration/ConfigurationState.Model.cs @@ -149,6 +149,11 @@ namespace Ryujinx.UI.Common.Configuration /// public ReactiveObject StartFullscreen { get; private set; } + /// + /// Start games with UI hidden + /// + public ReactiveObject StartNoUI { get; private set; } + /// /// Hide / Show Console Window /// @@ -189,6 +194,7 @@ namespace Ryujinx.UI.Common.Configuration WindowStartup = new WindowStartupSettings(); BaseStyle = new ReactiveObject(); StartFullscreen = new ReactiveObject(); + StartNoUI = new ReactiveObject(); GameListViewMode = new ReactiveObject(); ShowNames = new ReactiveObject(); GridSize = new ReactiveObject(); diff --git a/src/Ryujinx.UI.Common/Configuration/ConfigurationState.cs b/src/Ryujinx.UI.Common/Configuration/ConfigurationState.cs index 90bdc3409..5eb652868 100644 --- a/src/Ryujinx.UI.Common/Configuration/ConfigurationState.cs +++ b/src/Ryujinx.UI.Common/Configuration/ConfigurationState.cs @@ -124,6 +124,7 @@ namespace Ryujinx.UI.Common.Configuration ApplicationSort = UI.ApplicationSort, IsAscendingOrder = UI.IsAscendingOrder, StartFullscreen = UI.StartFullscreen, + StartNoUI = UI.StartNoUI, ShowConsole = UI.ShowConsole, EnableKeyboard = Hid.EnableKeyboard, EnableMouse = Hid.EnableMouse, @@ -230,6 +231,7 @@ namespace Ryujinx.UI.Common.Configuration UI.ApplicationSort.Value = 0; UI.IsAscendingOrder.Value = true; UI.StartFullscreen.Value = false; + UI.StartNoUI.Value = false; UI.ShowConsole.Value = true; UI.WindowStartup.WindowSizeWidth.Value = 1280; UI.WindowStartup.WindowSizeHeight.Value = 760; diff --git a/src/Ryujinx/AppHost.cs b/src/Ryujinx/AppHost.cs index f976ecdf1..fad362ab5 100644 --- a/src/Ryujinx/AppHost.cs +++ b/src/Ryujinx/AppHost.cs @@ -1049,6 +1049,14 @@ namespace Ryujinx.Ava } }); + Dispatcher.UIThread.InvokeAsync(() => + { + if (_viewModel.StartGamesWithoutUI) + { + _viewModel.ShowMenuAndStatusBar = false; + } + }); + _renderer = Device.Gpu.Renderer is ThreadedRenderer tr ? tr.BaseRenderer : Device.Gpu.Renderer; _renderer.ScreenCaptured += Renderer_ScreenCaptured; diff --git a/src/Ryujinx/Assets/locales.json b/src/Ryujinx/Assets/locales.json index cdf43f474..7c6559955 100644 --- a/src/Ryujinx/Assets/locales.json +++ b/src/Ryujinx/Assets/locales.json @@ -549,6 +549,30 @@ "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": "", + "th_TH": "", + "tr_TR": "", + "uk_UA": "", + "zh_CN": "", + "zh_TW": "" + } + }, { "ID": "MenuBarOptionsStopEmulation", "Translations": { diff --git a/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs b/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs index d0ea64c37..c01174e15 100644 --- a/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs @@ -853,6 +853,19 @@ 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 { get => ConfigurationState.Instance.UI.ShowConsole; @@ -1590,6 +1603,11 @@ namespace Ryujinx.Ava.UI.ViewModels StartGamesInFullscreen = !StartGamesInFullscreen; } + public void ToggleStartGamesWithoutUI() + { + StartGamesWithoutUI = !StartGamesWithoutUI; + } + public void ToggleShowConsole() { ShowConsole = !ShowConsole; diff --git a/src/Ryujinx/UI/Views/Main/MainMenuBarView.axaml b/src/Ryujinx/UI/Views/Main/MainMenuBarView.axaml index 2c07bd8ef..b665c5762 100644 --- a/src/Ryujinx/UI/Views/Main/MainMenuBarView.axaml +++ b/src/Ryujinx/UI/Views/Main/MainMenuBarView.axaml @@ -119,6 +119,29 @@ + + + + + + + + + Date: Fri, 27 Dec 2024 00:41:50 -0600 Subject: [PATCH 03/12] Once again, I am stupid --- src/Ryujinx/AppHost.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Ryujinx/AppHost.cs b/src/Ryujinx/AppHost.cs index f976ecdf1..9a9c1d226 100644 --- a/src/Ryujinx/AppHost.cs +++ b/src/Ryujinx/AppHost.cs @@ -311,7 +311,7 @@ namespace Ryujinx.Ava Device.VSyncMode = e.NewValue; Device.UpdateVSyncInterval(); } - _renderer.Window?.ChangeVSyncMode((Ryujinx.Graphics.GAL.VSyncMode)e.NewValue); + _renderer.Window?.ChangeVSyncMode(e.NewValue); _viewModel.ShowCustomVSyncIntervalPicker = (e.NewValue == VSyncMode.Custom); } @@ -1074,7 +1074,7 @@ namespace Ryujinx.Ava Device.Gpu.SetGpuThread(); Device.Gpu.InitializeShaderCache(_gpuCancellationTokenSource.Token); - _renderer.Window.ChangeVSyncMode((Ryujinx.Graphics.GAL.VSyncMode)Device.VSyncMode); + _renderer.Window.ChangeVSyncMode(Device.VSyncMode); while (_isActive) { -- 2.47.1 From c69881a0a22104986a7141f40f8c4dd0e2963f09 Mon Sep 17 00:00:00 2001 From: Evan Husted Date: Fri, 27 Dec 2024 00:47:57 -0600 Subject: [PATCH 04/12] UI: chore: remove direct static MainWindowViewModel reference --- src/Ryujinx/UI/Models/SaveModel.cs | 3 ++- src/Ryujinx/UI/ViewModels/SettingsViewModel.cs | 2 +- src/Ryujinx/UI/Windows/MainWindow.axaml.cs | 4 +--- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/Ryujinx/UI/Models/SaveModel.cs b/src/Ryujinx/UI/Models/SaveModel.cs index cfc397c6e..578538d21 100644 --- a/src/Ryujinx/UI/Models/SaveModel.cs +++ b/src/Ryujinx/UI/Models/SaveModel.cs @@ -1,3 +1,4 @@ +using Gommon; using LibHac.Fs; using LibHac.Ncm; using Ryujinx.Ava.UI.ViewModels; @@ -47,7 +48,7 @@ namespace Ryujinx.Ava.UI.Models TitleId = info.ProgramId; UserId = info.UserId; - var appData = MainWindow.MainWindowViewModel.Applications.FirstOrDefault(x => x.IdString.Equals(TitleIdString, StringComparison.OrdinalIgnoreCase)); + var appData = RyujinxApp.MainWindow.ViewModel.Applications.FirstOrDefault(x => x.IdString.EqualsIgnoreCase(TitleIdString)); InGameList = appData != null; diff --git a/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs b/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs index 7504147b2..9feaaba9b 100644 --- a/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/SettingsViewModel.cs @@ -750,7 +750,7 @@ namespace Ryujinx.Ava.UI.ViewModels config.ToFileFormat().SaveConfig(Program.ConfigurationPath); MainWindow.UpdateGraphicsConfig(); - MainWindow.MainWindowViewModel.VSyncModeSettingChanged(); + RyujinxApp.MainWindow.ViewModel.VSyncModeSettingChanged(); SaveSettingsEvent?.Invoke(); diff --git a/src/Ryujinx/UI/Windows/MainWindow.axaml.cs b/src/Ryujinx/UI/Windows/MainWindow.axaml.cs index 660caa605..ca91b180f 100644 --- a/src/Ryujinx/UI/Windows/MainWindow.axaml.cs +++ b/src/Ryujinx/UI/Windows/MainWindow.axaml.cs @@ -39,8 +39,6 @@ namespace Ryujinx.Ava.UI.Windows { public partial class MainWindow : StyleableAppWindow { - internal static MainWindowViewModel MainWindowViewModel { get; private set; } - public MainWindowViewModel ViewModel { get; } internal readonly AvaHostUIHandler UiHandler; @@ -76,7 +74,7 @@ namespace Ryujinx.Ava.UI.Windows public MainWindow() { - DataContext = ViewModel = MainWindowViewModel = new MainWindowViewModel + DataContext = ViewModel = new MainWindowViewModel { Window = this }; -- 2.47.1 From d3bc3a1081863d07fc8d4bdc48e6b69fafa5e41c Mon Sep 17 00:00:00 2001 From: Evan Husted Date: Fri, 27 Dec 2024 01:32:23 -0600 Subject: [PATCH 05/12] 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 { -- 2.47.1 From 4c646721d6b57d462186f96de69b88de5f9f314e Mon Sep 17 00:00:00 2001 From: Evan Husted Date: Fri, 27 Dec 2024 01:38:51 -0600 Subject: [PATCH 06/12] infra: Testing moving canary to the future home of this fork --- .github/workflows/canary.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/canary.yml b/.github/workflows/canary.yml index 3100671e9..cc57e7d5b 100644 --- a/.github/workflows/canary.yml +++ b/.github/workflows/canary.yml @@ -21,7 +21,7 @@ env: DOTNET_CLI_TELEMETRY_OPTOUT: 1 RYUJINX_BASE_VERSION: "1.2" RYUJINX_TARGET_RELEASE_CHANNEL_NAME: "canary" - RYUJINX_TARGET_RELEASE_CHANNEL_OWNER: "GreemDev" + RYUJINX_TARGET_RELEASE_CHANNEL_OWNER: "Hydra-NX" RYUJINX_TARGET_RELEASE_CHANNEL_SOURCE_REPO: "Ryujinx" RYUJINX_TARGET_RELEASE_CHANNEL_REPO: "Ryujinx-Canary" RELEASE: 1 -- 2.47.1 From 01c2e67334fc84ebc781c9413aa7f3f7a5203555 Mon Sep 17 00:00:00 2001 From: Evan Husted Date: Fri, 27 Dec 2024 01:41:48 -0600 Subject: [PATCH 07/12] lol --- .github/workflows/canary.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/canary.yml b/.github/workflows/canary.yml index cc57e7d5b..03247ff6d 100644 --- a/.github/workflows/canary.yml +++ b/.github/workflows/canary.yml @@ -23,7 +23,7 @@ env: RYUJINX_TARGET_RELEASE_CHANNEL_NAME: "canary" RYUJINX_TARGET_RELEASE_CHANNEL_OWNER: "Hydra-NX" RYUJINX_TARGET_RELEASE_CHANNEL_SOURCE_REPO: "Ryujinx" - RYUJINX_TARGET_RELEASE_CHANNEL_REPO: "Ryujinx-Canary" + RYUJINX_TARGET_RELEASE_CHANNEL_REPO: "Canary-Releases" RELEASE: 1 jobs: -- 2.47.1 From ccddaa77d1dd422dd8f09dc8f89ab5e4704f8b30 Mon Sep 17 00:00:00 2001 From: Evan Husted Date: Fri, 27 Dec 2024 01:59:29 -0600 Subject: [PATCH 08/12] infra: Org --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 59c31c71b..825a23ae6 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -21,7 +21,7 @@ env: DOTNET_CLI_TELEMETRY_OPTOUT: 1 RYUJINX_BASE_VERSION: "1.2" RYUJINX_TARGET_RELEASE_CHANNEL_NAME: "release" - RYUJINX_TARGET_RELEASE_CHANNEL_OWNER: "GreemDev" + RYUJINX_TARGET_RELEASE_CHANNEL_OWNER: "Hydra-NX" RYUJINX_TARGET_RELEASE_CHANNEL_REPO: "Ryujinx" RELEASE: 1 -- 2.47.1 From 9eb273a0f754ac50de1485e3d5782652993af647 Mon Sep 17 00:00:00 2001 From: Evan Husted Date: Fri, 27 Dec 2024 02:05:37 -0600 Subject: [PATCH 09/12] Org rename (they call me indecisive) --- .github/workflows/canary.yml | 2 +- .github/workflows/release.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/canary.yml b/.github/workflows/canary.yml index 03247ff6d..ffbf1ebf7 100644 --- a/.github/workflows/canary.yml +++ b/.github/workflows/canary.yml @@ -21,7 +21,7 @@ env: DOTNET_CLI_TELEMETRY_OPTOUT: 1 RYUJINX_BASE_VERSION: "1.2" RYUJINX_TARGET_RELEASE_CHANNEL_NAME: "canary" - RYUJINX_TARGET_RELEASE_CHANNEL_OWNER: "Hydra-NX" + RYUJINX_TARGET_RELEASE_CHANNEL_OWNER: "Ryubing" RYUJINX_TARGET_RELEASE_CHANNEL_SOURCE_REPO: "Ryujinx" RYUJINX_TARGET_RELEASE_CHANNEL_REPO: "Canary-Releases" RELEASE: 1 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 825a23ae6..066b978c5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -21,7 +21,7 @@ env: DOTNET_CLI_TELEMETRY_OPTOUT: 1 RYUJINX_BASE_VERSION: "1.2" RYUJINX_TARGET_RELEASE_CHANNEL_NAME: "release" - RYUJINX_TARGET_RELEASE_CHANNEL_OWNER: "Hydra-NX" + RYUJINX_TARGET_RELEASE_CHANNEL_OWNER: "Ryubing" RYUJINX_TARGET_RELEASE_CHANNEL_REPO: "Ryujinx" RELEASE: 1 -- 2.47.1 From 07074272ca327cb3ae1c2d34c0d5bbef290e6d26 Mon Sep 17 00:00:00 2001 From: Evan Husted Date: Fri, 27 Dec 2024 15:24:57 -0600 Subject: [PATCH 10/12] Revert "UI: Directly proxy window properties on the view model back to the stored window" This reverts commit 9754d247b59a064f9888423ef6c227c6f209e784. --- src/Ryujinx/RyujinxApp.axaml.cs | 7 ++- .../UI/ViewModels/MainWindowViewModel.cs | 45 ++++++++++++++----- src/Ryujinx/UI/Windows/MainWindow.axaml | 5 +++ 3 files changed, 43 insertions(+), 14 deletions(-) diff --git a/src/Ryujinx/RyujinxApp.axaml.cs b/src/Ryujinx/RyujinxApp.axaml.cs index c2f92f2f7..bbef20aa0 100644 --- a/src/Ryujinx/RyujinxApp.axaml.cs +++ b/src/Ryujinx/RyujinxApp.axaml.cs @@ -33,8 +33,11 @@ namespace Ryujinx.Ava .ApplicationLifetime.Cast() .MainWindow.Cast(); - public static bool IsClipboardAvailable(out IClipboard clipboard) - => (clipboard = MainWindow.Clipboard) != null; + public static bool IsClipboardAvailable(out IClipboard clipboard) + { + clipboard = MainWindow.Clipboard; + return clipboard != null; + } public static void SetTaskbarProgress(TaskBarProgressBarState state) => MainWindow.PlatformFeatures.SetTaskBarProgressBarState(state); public static void SetTaskbarProgressValue(ulong current, ulong total) => MainWindow.PlatformFeatures.SetTaskBarProgressBarValue(current, total); diff --git a/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs b/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs index 3b98a7aa3..39799c117 100644 --- a/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs @@ -110,8 +110,13 @@ namespace Ryujinx.Ava.UI.ViewModels private bool _areMimeTypesRegistered = FileAssociationHelper.AreMimeTypesRegistered; private bool _canUpdate = true; + private Cursor _cursor; + private string _title; private ApplicationData _currentApplicationData; private readonly AutoResetEvent _rendererWaitEvent; + private WindowState _windowState; + private double _windowWidth; + private double _windowHeight; private int _customVSyncInterval; private int _customVSyncIntervalPercentageProxy; @@ -213,7 +218,7 @@ namespace Ryujinx.Ava.UI.ViewModels public bool CanUpdate { - get => _canUpdate && EnableNonGameRunningControls && Updater.CanUpdate(); + get => _canUpdate && EnableNonGameRunningControls && Updater.CanUpdate(false); set { _canUpdate = value; @@ -223,8 +228,12 @@ namespace Ryujinx.Ava.UI.ViewModels public Cursor Cursor { - get => Window.Cursor; - set => Window.Cursor = value; + get => _cursor; + set + { + _cursor = value; + OnPropertyChanged(); + } } public ReadOnlyObservableCollection AppsObservableList @@ -806,23 +815,35 @@ namespace Ryujinx.Ava.UI.ViewModels public WindowState WindowState { - get => Window.WindowState; + get => _windowState; internal set { - Window.WindowState = value; + _windowState = value; + + OnPropertyChanged(); } } public double WindowWidth { - get => Window.Width; - set => Window.Width = value; + get => _windowWidth; + set + { + _windowWidth = value; + + OnPropertyChanged(); + } } public double WindowHeight { - get => Window.Height; - set => Window.Height = value; + get => _windowHeight; + set + { + _windowHeight = value; + + OnPropertyChanged(); + } } public bool IsGrid => Glyph == Glyph.Grid; @@ -870,11 +891,11 @@ namespace Ryujinx.Ava.UI.ViewModels public string Title { - get => Window.Title; + get => _title; set { - Window.Title = value; - + _title = value; + OnPropertyChanged(); } } diff --git a/src/Ryujinx/UI/Windows/MainWindow.axaml b/src/Ryujinx/UI/Windows/MainWindow.axaml index e3b6cf912..cb2e5936d 100644 --- a/src/Ryujinx/UI/Windows/MainWindow.axaml +++ b/src/Ryujinx/UI/Windows/MainWindow.axaml @@ -9,6 +9,11 @@ xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers" xmlns:controls="clr-namespace:Ryujinx.Ava.UI.Controls" xmlns:main="clr-namespace:Ryujinx.Ava.UI.Views.Main" + Cursor="{Binding Cursor}" + Title="{Binding Title}" + WindowState="{Binding WindowState}" + Width="{Binding WindowWidth}" + Height="{Binding WindowHeight}" MinWidth="800" MinHeight="500" d:DesignHeight="720" -- 2.47.1 From 56e45ae64861b3d0b61b7e918e7c4c9aad94a0a5 Mon Sep 17 00:00:00 2001 From: Evan Husted Date: Fri, 27 Dec 2024 15:33:31 -0600 Subject: [PATCH 11/12] misc: Collapse LdnGameDataArray into the main class as an inner class - privated the constructor; only obtainable by the static helper on the main LdnGameData class. - constructor logic now in the static helper; constructor just directly sets the data it's given. --- src/Ryujinx.UI.Common/App/LdnGameData.cs | 26 +++++++++++++++++++ src/Ryujinx.UI.Common/App/LdnGameDataList.cs | 24 ----------------- .../UI/ViewModels/MainWindowViewModel.cs | 2 +- src/Ryujinx/UI/Windows/MainWindow.axaml.cs | 9 ++++--- 4 files changed, 33 insertions(+), 28 deletions(-) delete mode 100644 src/Ryujinx.UI.Common/App/LdnGameDataList.cs diff --git a/src/Ryujinx.UI.Common/App/LdnGameData.cs b/src/Ryujinx.UI.Common/App/LdnGameData.cs index 6c784c991..f7a98e136 100644 --- a/src/Ryujinx.UI.Common/App/LdnGameData.cs +++ b/src/Ryujinx.UI.Common/App/LdnGameData.cs @@ -1,4 +1,7 @@ +using LibHac.Ns; +using System; using System.Collections.Generic; +using System.Linq; namespace Ryujinx.UI.App.Common { @@ -12,5 +15,28 @@ namespace Ryujinx.UI.App.Common public string Mode { get; set; } public string Status { get; set; } public IEnumerable Players { get; set; } + + public static Array GetArrayForApp( + IEnumerable receivedData, ref ApplicationControlProperty acp) + { + LibHac.Common.FixedArrays.Array8 communicationId = acp.LocalCommunicationId; + + return new Array(receivedData.Where(game => + communicationId.Items.Contains(Convert.ToUInt64(game.TitleId, 16)) + )); + } + + public class Array + { + private readonly LdnGameData[] _ldnDatas; + + internal Array(IEnumerable receivedData) + { + _ldnDatas = receivedData.ToArray(); + } + + public int PlayerCount => _ldnDatas.Sum(it => it.PlayerCount); + public int GameCount => _ldnDatas.Length; + } } } diff --git a/src/Ryujinx.UI.Common/App/LdnGameDataList.cs b/src/Ryujinx.UI.Common/App/LdnGameDataList.cs deleted file mode 100644 index d98fd081d..000000000 --- a/src/Ryujinx.UI.Common/App/LdnGameDataList.cs +++ /dev/null @@ -1,24 +0,0 @@ -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 39799c117..2f1800290 100644 --- a/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs @@ -127,7 +127,7 @@ namespace Ryujinx.Ava.UI.ViewModels public ApplicationData GridSelectedApplication; // Key is Title ID - public SafeDictionary LdnData = []; + 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 832674541..da4314e79 100644 --- a/src/Ryujinx/UI/Windows/MainWindow.axaml.cs +++ b/src/Ryujinx/UI/Windows/MainWindow.axaml.cs @@ -171,9 +171,12 @@ namespace Ryujinx.Ava.UI.Windows ViewModel.LdnData.Clear(); foreach (var application in ViewModel.Applications) { - ViewModel.LdnData[application.IdString] = new LdnGameDataArray( - ldnGameDataArray, - ref application.ControlHolder.Value + ref var controlHolder = ref application.ControlHolder.Value; + + ViewModel.LdnData[application.IdString] = + LdnGameData.GetArrayForApp( + ldnGameDataArray, + ref controlHolder ); UpdateApplicationWithLdnData(application); -- 2.47.1 From 6a462fa9c9bc8ed08e20a1285ef87e2ef3a820bd Mon Sep 17 00:00:00 2001 From: Your Name Date: Sun, 22 Dec 2024 23:42:10 -0800 Subject: [PATCH 12/12] Small cleanup --- .../Configuration/ConfigurationState.Migration.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Ryujinx.UI.Common/Configuration/ConfigurationState.Migration.cs b/src/Ryujinx.UI.Common/Configuration/ConfigurationState.Migration.cs index 9579e15eb..f15371483 100644 --- a/src/Ryujinx.UI.Common/Configuration/ConfigurationState.Migration.cs +++ b/src/Ryujinx.UI.Common/Configuration/ConfigurationState.Migration.cs @@ -640,7 +640,7 @@ namespace Ryujinx.UI.Common.Configuration if (configurationFileFormat.Version < 58) { - Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 17."); + Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 58."); configurationFileFormat.StartNoUI = false; -- 2.47.1