diff --git a/.github/workflows/canary.yml b/.github/workflows/canary.yml index 3100671e9..ffbf1ebf7 100644 --- a/.github/workflows/canary.yml +++ b/.github/workflows/canary.yml @@ -21,9 +21,9 @@ 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: "Ryubing" RYUJINX_TARGET_RELEASE_CHANNEL_SOURCE_REPO: "Ryujinx" - RYUJINX_TARGET_RELEASE_CHANNEL_REPO: "Ryujinx-Canary" + RYUJINX_TARGET_RELEASE_CHANNEL_REPO: "Canary-Releases" RELEASE: 1 jobs: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 59c31c71b..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: "GreemDev" + RYUJINX_TARGET_RELEASE_CHANNEL_OWNER: "Ryubing" RYUJINX_TARGET_RELEASE_CHANNEL_REPO: "Ryujinx" RELEASE: 1 diff --git a/Ryujinx.sln b/Ryujinx.sln index 71d5f6dd9..e9f57df39 100644 --- a/Ryujinx.sln +++ b/Ryujinx.sln @@ -80,11 +80,16 @@ EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.Horizon.Kernel.Generators", "src\Ryujinx.Horizon.Kernel.Generators\Ryujinx.Horizon.Kernel.Generators.csproj", "{7F55A45D-4E1D-4A36-ADD3-87F29A285AA2}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ryujinx.HLE.Generators", "src\Ryujinx.HLE.Generators\Ryujinx.HLE.Generators.csproj", "{B575BCDE-2FD8-4A5D-8756-31CDD7FE81F0}" +EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryujinx.Graphics.Metal", "src\Ryujinx.Graphics.Metal\Ryujinx.Graphics.Metal.csproj", "{C08931FA-1191-417A-864F-3882D93E683B}" ProjectSection(ProjectDependencies) = postProject {A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E} = {A602AE97-91A5-4608-8DF1-EBF4ED7A0B9E} EndProjectSection EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryujinx.BuildValidationTasks", "src\Ryujinx.BuildValidationTasks\Ryujinx.BuildValidationTasks.csproj", "{4A89A234-4F19-497D-A576-DDE8CDFC5B22}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryujinx.Graphics.Metal.SharpMetalExtensions", "src/Ryujinx.Graphics.Metal.SharpMetalExtensions\Ryujinx.Graphics.Metal.SharpMetalExtensions.csproj", "{81EA598C-DBA1-40B0-8DA4-4796B78F2037}" +EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{36F870C1-3E5F-485F-B426-F0645AF78751}" ProjectSection(SolutionItems) = preProject .editorconfig = .editorconfig @@ -94,8 +99,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution .github\workflows\release.yml = .github\workflows\release.yml EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Ryujinx.BuildValidationTasks", "src\Ryujinx.BuildValidationTasks\Ryujinx.BuildValidationTasks.csproj", "{4A89A234-4F19-497D-A576-DDE8CDFC5B22}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -265,6 +268,10 @@ Global {C08931FA-1191-417A-864F-3882D93E683B}.Debug|Any CPU.Build.0 = Debug|Any CPU {C08931FA-1191-417A-864F-3882D93E683B}.Release|Any CPU.ActiveCfg = Release|Any CPU {C08931FA-1191-417A-864F-3882D93E683B}.Release|Any CPU.Build.0 = Release|Any CPU + {81EA598C-DBA1-40B0-8DA4-4796B78F2037}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {81EA598C-DBA1-40B0-8DA4-4796B78F2037}.Debug|Any CPU.Build.0 = Debug|Any CPU + {81EA598C-DBA1-40B0-8DA4-4796B78F2037}.Release|Any CPU.ActiveCfg = Release|Any CPU + {81EA598C-DBA1-40B0-8DA4-4796B78F2037}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE 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.SharpMetalExtensions/CAMetalLayerExtensions.cs b/src/Ryujinx.Graphics.Metal.SharpMetalExtensions/CAMetalLayerExtensions.cs new file mode 100644 index 000000000..0d29a502b --- /dev/null +++ b/src/Ryujinx.Graphics.Metal.SharpMetalExtensions/CAMetalLayerExtensions.cs @@ -0,0 +1,30 @@ +using SharpMetal; +using SharpMetal.ObjectiveCCore; +using SharpMetal.QuartzCore; +using System.Runtime.Versioning; +// ReSharper disable InconsistentNaming + +namespace Ryujinx.Graphics.Metal.SharpMetalExtensions +{ + [SupportedOSPlatform("macOS")] + public static class CAMetalLayerExtensions + { + private static readonly Selector sel_displaySyncEnabled = "displaySyncEnabled"; + private static readonly Selector sel_setDisplaySyncEnabled = "setDisplaySyncEnabled:"; + + private static readonly Selector sel_developerHUDProperties = "developerHUDProperties"; + private static readonly Selector sel_setDeveloperHUDProperties = "setDeveloperHUDProperties:"; + + public static bool IsDisplaySyncEnabled(this CAMetalLayer metalLayer) + => ObjectiveCRuntime.bool_objc_msgSend(metalLayer.NativePtr, sel_displaySyncEnabled); + + public static void SetDisplaySyncEnabled(this CAMetalLayer metalLayer, bool enabled) + => ObjectiveCRuntime.objc_msgSend(metalLayer.NativePtr, sel_setDisplaySyncEnabled, enabled); + + public static nint GetDeveloperHudProperties(this CAMetalLayer metalLayer) + => ObjectiveCRuntime.IntPtr_objc_msgSend(metalLayer.NativePtr, sel_developerHUDProperties); + + public static void SetDeveloperHudProperties(this CAMetalLayer metalLayer, nint dictionaryPointer) + => ObjectiveCRuntime.objc_msgSend(metalLayer.NativePtr, sel_setDeveloperHUDProperties, dictionaryPointer); + } +} diff --git a/src/Ryujinx.Graphics.Metal.SharpMetalExtensions/Ryujinx.Graphics.Metal.SharpMetalExtensions.csproj b/src/Ryujinx.Graphics.Metal.SharpMetalExtensions/Ryujinx.Graphics.Metal.SharpMetalExtensions.csproj new file mode 100644 index 000000000..9836063a3 --- /dev/null +++ b/src/Ryujinx.Graphics.Metal.SharpMetalExtensions/Ryujinx.Graphics.Metal.SharpMetalExtensions.csproj @@ -0,0 +1,10 @@ + + + enable + enable + + + + + + diff --git a/src/Ryujinx.Graphics.Metal/Ryujinx.Graphics.Metal.csproj b/src/Ryujinx.Graphics.Metal/Ryujinx.Graphics.Metal.csproj index 02afb150a..364aa5a8b 100644 --- a/src/Ryujinx.Graphics.Metal/Ryujinx.Graphics.Metal.csproj +++ b/src/Ryujinx.Graphics.Metal/Ryujinx.Graphics.Metal.csproj @@ -5,12 +5,9 @@ - - - - - - + + + diff --git a/src/Ryujinx.Graphics.Metal/Window.cs b/src/Ryujinx.Graphics.Metal/Window.cs index 65a47d217..203a29ebc 100644 --- a/src/Ryujinx.Graphics.Metal/Window.cs +++ b/src/Ryujinx.Graphics.Metal/Window.cs @@ -1,10 +1,14 @@ +using Ryujinx.Common.Configuration; using Ryujinx.Common.Logging; using Ryujinx.Graphics.GAL; using Ryujinx.Graphics.Metal.Effects; +using Ryujinx.Graphics.Metal.SharpMetalExtensions; 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 { @@ -140,7 +144,15 @@ namespace Ryujinx.Graphics.Metal public void ChangeVSyncMode(VSyncMode vSyncMode) { - //_vSyncMode = vSyncMode; + switch (vSyncMode) + { + case VSyncMode.Unbounded: + _metalLayer.SetDisplaySyncEnabled(false); + break; + case VSyncMode.Switch: + _metalLayer.SetDisplaySyncEnabled(true); + break; + } } public void SetAntiAliasing(AntiAliasing effect) 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 { 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/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) { diff --git a/src/Ryujinx/RyujinxApp.axaml.cs b/src/Ryujinx/RyujinxApp.axaml.cs index bbef20aa0..c2f92f2f7 100644 --- a/src/Ryujinx/RyujinxApp.axaml.cs +++ b/src/Ryujinx/RyujinxApp.axaml.cs @@ -33,11 +33,8 @@ namespace Ryujinx.Ava .ApplicationLifetime.Cast() .MainWindow.Cast(); - public static bool IsClipboardAvailable(out IClipboard clipboard) - { - clipboard = MainWindow.Clipboard; - return clipboard != null; - } + public static bool IsClipboardAvailable(out IClipboard clipboard) + => (clipboard = MainWindow.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/Helpers/LoggerAdapter.cs b/src/Ryujinx/UI/Helpers/LoggerAdapter.cs index 7982c17a6..2d26bd090 100644 --- a/src/Ryujinx/UI/Helpers/LoggerAdapter.cs +++ b/src/Ryujinx/UI/Helpers/LoggerAdapter.cs @@ -19,7 +19,7 @@ namespace Ryujinx.Ava.UI.Helpers AvaLogger.Sink = new LoggerAdapter(); } - private static RyuLogger.Log? GetLog(AvaLogLevel level) + private static RyuLogger.Log? GetLog(AvaLogLevel level, string area) { return level switch { @@ -27,7 +27,7 @@ namespace Ryujinx.Ava.UI.Helpers AvaLogLevel.Debug => RyuLogger.Debug, AvaLogLevel.Information => RyuLogger.Debug, AvaLogLevel.Warning => RyuLogger.Debug, - AvaLogLevel.Error => RyuLogger.Error, + AvaLogLevel.Error => area is "IME" ? RyuLogger.Debug : RyuLogger.Error, AvaLogLevel.Fatal => RyuLogger.Error, _ => throw new ArgumentOutOfRangeException(nameof(level), level, null), }; @@ -35,17 +35,17 @@ namespace Ryujinx.Ava.UI.Helpers public bool IsEnabled(AvaLogLevel level, string area) { - return GetLog(level) != null; + return GetLog(level, area) != null; } public void Log(AvaLogLevel level, string area, object source, string messageTemplate) { - GetLog(level)?.PrintMsg(RyuLogClass.UI, Format(level, area, messageTemplate, source, null)); + GetLog(level, area)?.PrintMsg(RyuLogClass.UI, Format(level, area, messageTemplate, source, null)); } public void Log(AvaLogLevel level, string area, object source, string messageTemplate, params object[] propertyValues) { - GetLog(level)?.PrintMsg(RyuLogClass.UI, Format(level, area, messageTemplate, source, propertyValues)); + GetLog(level, area)?.PrintMsg(RyuLogClass.UI, Format(level, area, messageTemplate, source, propertyValues)); } private static string Format(AvaLogLevel level, string area, string template, object source, object[] v) 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/MainWindowViewModel.cs b/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs index 04881b58d..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; @@ -109,13 +110,8 @@ 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; @@ -124,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. @@ -216,7 +213,7 @@ namespace Ryujinx.Ava.UI.ViewModels public bool CanUpdate { - get => _canUpdate && EnableNonGameRunningControls && Updater.CanUpdate(false); + get => _canUpdate && EnableNonGameRunningControls && Updater.CanUpdate(); set { _canUpdate = value; @@ -226,12 +223,8 @@ namespace Ryujinx.Ava.UI.ViewModels public Cursor Cursor { - get => _cursor; - set - { - _cursor = value; - OnPropertyChanged(); - } + get => Window.Cursor; + set => Window.Cursor = value; } public ReadOnlyObservableCollection AppsObservableList @@ -813,35 +806,23 @@ namespace Ryujinx.Ava.UI.ViewModels public WindowState WindowState { - get => _windowState; + get => Window.WindowState; internal set { - _windowState = value; - - OnPropertyChanged(); + Window.WindowState = value; } } public double WindowWidth { - get => _windowWidth; - set - { - _windowWidth = value; - - OnPropertyChanged(); - } + get => Window.Width; + set => Window.Width = value; } public double WindowHeight { - get => _windowHeight; - set - { - _windowHeight = value; - - OnPropertyChanged(); - } + get => Window.Height; + set => Window.Height = value; } public bool IsGrid => Glyph == Glyph.Grid; @@ -889,11 +870,11 @@ namespace Ryujinx.Ava.UI.ViewModels public string Title { - get => _title; + get => Window.Title; set { - _title = value; - + Window.Title = value; + OnPropertyChanged(); } } 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/Views/Main/MainMenuBarView.axaml b/src/Ryujinx/UI/Views/Main/MainMenuBarView.axaml index 8207f8e03..2c07bd8ef 100644 --- a/src/Ryujinx/UI/Views/Main/MainMenuBarView.axaml +++ b/src/Ryujinx/UI/Views/Main/MainMenuBarView.axaml @@ -17,8 +17,7 @@ Margin="7, 0" Height="25" Width="25" - ToolTip.Tip="{Binding Title}" - Source="resm:Ryujinx.UI.Common.Resources.Logo_Ryujinx_AntiAlias.png?assembly=Ryujinx.UI.Common" /> + ToolTip.Tip="{Binding Title}" /> { - 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 {