From 13d2498405289d230dcaace9924e10ff67003448 Mon Sep 17 00:00:00 2001 From: Vova Date: Tue, 22 Oct 2024 20:35:31 +1000 Subject: [PATCH 01/17] test --- src/Ryujinx/Program.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Ryujinx/Program.cs b/src/Ryujinx/Program.cs index 5087d5d82..a79b99d17 100644 --- a/src/Ryujinx/Program.cs +++ b/src/Ryujinx/Program.cs @@ -31,6 +31,7 @@ namespace Ryujinx.Ava { internal partial class Program { + // public static double WindowScaleFactor { get; set; } public static double DesktopScaleFactor { get; set; } = 1.0; public static string Version { get; private set; } From 8074a4dd870a283936c21fad437bbf8b919a38db Mon Sep 17 00:00:00 2001 From: Vova Date: Wed, 30 Oct 2024 22:17:29 +1000 Subject: [PATCH 02/17] Fixed a visual bug in "input settings", when switching between players the settings were reset to default --- src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs b/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs index c133f25fa..090ce000f 100644 --- a/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs @@ -100,6 +100,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input { _playerId = PlayerIndex.Player1; } + _isLoaded = false; LoadConfiguration(); LoadDevice(); From d83da7d2fbdde2c73cd52e0f3b8b404f69bb2337 Mon Sep 17 00:00:00 2001 From: Vova Date: Sat, 2 Nov 2024 22:42:57 +1000 Subject: [PATCH 03/17] Fixed the logic of saving the input section. Added a new dialog box when changing parameters --- src/Ryujinx/Assets/Locales/en_US.json | 1 + src/Ryujinx/UI/Helpers/ContentDialogHelper.cs | 18 ++++++ .../UI/ViewModels/Input/InputViewModel.cs | 10 ++++ .../Views/Input/ControllerInputView.axaml.cs | 60 ++++++++++++++++++- src/Ryujinx/UI/Views/Input/InputView.axaml | 2 +- src/Ryujinx/UI/Views/Input/InputView.axaml.cs | 34 +++++++++-- 6 files changed, 118 insertions(+), 7 deletions(-) diff --git a/src/Ryujinx/Assets/Locales/en_US.json b/src/Ryujinx/Assets/Locales/en_US.json index 68b48146b..a826e49f1 100644 --- a/src/Ryujinx/Assets/Locales/en_US.json +++ b/src/Ryujinx/Assets/Locales/en_US.json @@ -407,6 +407,7 @@ "AvatarSetBackgroundColor": "Set Background Color", "AvatarClose": "Close", "ControllerSettingsLoadProfileToolTip": "Load Profile", + "ControllerSettingsViewProfileToolTip": "View Profile", "ControllerSettingsAddProfileToolTip": "Add Profile", "ControllerSettingsRemoveProfileToolTip": "Remove Profile", "ControllerSettingsSaveProfileToolTip": "Save Profile", diff --git a/src/Ryujinx/UI/Helpers/ContentDialogHelper.cs b/src/Ryujinx/UI/Helpers/ContentDialogHelper.cs index 67a3642a9..bd8c1e3a7 100644 --- a/src/Ryujinx/UI/Helpers/ContentDialogHelper.cs +++ b/src/Ryujinx/UI/Helpers/ContentDialogHelper.cs @@ -226,6 +226,24 @@ namespace Ryujinx.Ava.UI.Helpers (int)Symbol.Help, primaryButtonResult); + internal static async Task CreateConfirmationDialogExtended( + string primaryText, + string secondaryText, + string acceptButtonText, + string noacceptButtonText, + string cancelButtonText, + string title, + UserResult primaryButtonResult = UserResult.Yes) + => await ShowTextDialog( + string.IsNullOrWhiteSpace(title) ? LocaleManager.Instance[LocaleKeys.DialogConfirmationTitle] : title, + primaryText, + secondaryText, + acceptButtonText, + noacceptButtonText, + cancelButtonText, + (int)Symbol.Help, + primaryButtonResult); + internal static async Task CreateLocalizedConfirmationDialog(string primaryText, string secondaryText) => await CreateConfirmationDialog( primaryText, diff --git a/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs b/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs index 090ce000f..54f278cec 100644 --- a/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/Input/InputViewModel.cs @@ -44,6 +44,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input private readonly MainWindow _mainWindow; private PlayerIndex _playerId; + private PlayerIndex _playerIdChoose; private int _controller; private string _controllerImage; private int _device; @@ -83,6 +84,12 @@ namespace Ryujinx.Ava.UI.ViewModels.Input } } + public PlayerIndex PlayerIdChoose + { + get => _playerIdChoose; + set { } + } + public PlayerIndex PlayerId { get => _playerId; @@ -90,6 +97,8 @@ namespace Ryujinx.Ava.UI.ViewModels.Input { if (IsModified) { + + _playerIdChoose = value; return; } @@ -99,6 +108,7 @@ namespace Ryujinx.Ava.UI.ViewModels.Input if (!Enum.IsDefined(typeof(PlayerIndex), _playerId)) { _playerId = PlayerIndex.Player1; + } _isLoaded = false; diff --git a/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml.cs b/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml.cs index b76648da7..47e6ad53d 100644 --- a/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml.cs +++ b/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml.cs @@ -4,11 +4,14 @@ using Avalonia.Controls.Primitives; using Avalonia.Input; using Avalonia.Interactivity; using Avalonia.LogicalTree; +using DiscordRPC; using Ryujinx.Ava.UI.Helpers; using Ryujinx.Ava.UI.ViewModels.Input; using Ryujinx.Common.Configuration.Hid.Controller; +using Ryujinx.Common.Logging; using Ryujinx.Input; using Ryujinx.Input.Assigner; +using System; using StickInputId = Ryujinx.Common.Configuration.Hid.Controller.StickInputId; namespace Ryujinx.Ava.UI.Views.Input @@ -27,6 +30,16 @@ namespace Ryujinx.Ava.UI.Views.Input { button.IsCheckedChanged += Button_IsCheckedChanged; } + + if (visual is CheckBox check) + { + check.IsCheckedChanged += CheckBox_IsCheckedChanged; + } + + if (visual is Slider slider) + { + slider.PropertyChanged += Slider_IsCheckedChanged; + } } } @@ -40,9 +53,52 @@ namespace Ryujinx.Ava.UI.Views.Input } } + private float _changeSlider = -1.0f; + + private void Slider_IsCheckedChanged(object? sender, AvaloniaPropertyChangedEventArgs e) + { + if (sender is Slider check) + { + if ((bool)check.IsPointerOver && _changeSlider == -1.0f) + { + _changeSlider = (float)check.Value; + + } + else if (!(bool)check.IsPointerOver) + { + _changeSlider = -1.0f; + } + + if (_changeSlider != -1.0f && _changeSlider != (float)check.Value) + { + + var viewModel = (DataContext as ControllerInputViewModel); + viewModel.ParentModel.IsModified = true; + //Logger.Notice.Print(LogClass.Application, $"IsEnabled: {temp}\" \"{check.Value} {check.IsPointerOver}"); + _changeSlider = (float)check.Value; + } + } + } + + private void CheckBox_IsCheckedChanged(object sender, RoutedEventArgs e) + { + if (sender is CheckBox check) + { + if ((bool)check.IsPointerOver) + { + + var viewModel = (DataContext as ControllerInputViewModel); + viewModel.ParentModel.IsModified = true; + _currentAssigner?.Cancel(); + _currentAssigner = null; + } + } + } + + private void Button_IsCheckedChanged(object sender, RoutedEventArgs e) { - if (sender is ToggleButton button) + if (sender is ToggleButton button ) { if ((bool)button.IsChecked) { @@ -149,7 +205,7 @@ namespace Ryujinx.Ava.UI.Views.Input } else { - if (_currentAssigner != null) + if (_currentAssigner != null ) { _currentAssigner.Cancel(); _currentAssigner = null; diff --git a/src/Ryujinx/UI/Views/Input/InputView.axaml b/src/Ryujinx/UI/Views/Input/InputView.axaml index 851c9c626..b5bfa666d 100644 --- a/src/Ryujinx/UI/Views/Input/InputView.axaml +++ b/src/Ryujinx/UI/Views/Input/InputView.axaml @@ -108,7 +108,7 @@ ToolTip.Tip="{ext:Locale ControllerSettingsLoadProfileToolTip}" Command="{Binding LoadProfile}"> diff --git a/src/Ryujinx/UI/Views/Input/InputView.axaml.cs b/src/Ryujinx/UI/Views/Input/InputView.axaml.cs index 356381a8a..5fda7ef6a 100644 --- a/src/Ryujinx/UI/Views/Input/InputView.axaml.cs +++ b/src/Ryujinx/UI/Views/Input/InputView.axaml.cs @@ -25,17 +25,27 @@ namespace Ryujinx.Ava.UI.Views.Input private async void PlayerIndexBox_OnSelectionChanged(object sender, SelectionChangedEventArgs e) { + if (PlayerIndexBox != null) + { + if (PlayerIndexBox.SelectedIndex != (int)ViewModel.PlayerId) + { + PlayerIndexBox.SelectedIndex = (int)ViewModel.PlayerId; + } + } + if (ViewModel.IsModified && !_dialogOpen) { _dialogOpen = true; - var result = await ContentDialogHelper.CreateConfirmationDialog( + var result = await ContentDialogHelper.CreateConfirmationDialogExtended( LocaleManager.Instance[LocaleKeys.DialogControllerSettingsModifiedConfirmMessage], LocaleManager.Instance[LocaleKeys.DialogControllerSettingsModifiedConfirmSubMessage], LocaleManager.Instance[LocaleKeys.InputDialogYes], LocaleManager.Instance[LocaleKeys.InputDialogNo], + LocaleManager.Instance[LocaleKeys.Cancel], LocaleManager.Instance[LocaleKeys.RyujinxConfirm]); + if (result == UserResult.Yes) { ViewModel.Save(); @@ -43,14 +53,30 @@ namespace Ryujinx.Ava.UI.Views.Input _dialogOpen = false; + if (result == UserResult.Cancel) + { + + return; + } + ViewModel.IsModified = false; - if (e.AddedItems.Count > 0) + if (result != UserResult.Cancel) { - var player = (PlayerModel)e.AddedItems[0]; - ViewModel.PlayerId = player.Id; + ViewModel.PlayerId = ViewModel.PlayerIdChoose; + } + + if (result == UserResult.Cancel) + { + if (e.AddedItems.Count > 0) + { + ViewModel.IsModified = true; + var player = (PlayerModel)e.AddedItems[0]; + ViewModel.PlayerId = player.Id; + } } } + } public void Dispose() From b9012e291baa69dee2bb7d11c50d2a3e7600a6be Mon Sep 17 00:00:00 2001 From: Vova Date: Sun, 10 Nov 2024 14:32:45 +1000 Subject: [PATCH 04/17] code cleaning --- src/Ryujinx/UI/Views/Input/ControllerInputView.axaml.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml.cs b/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml.cs index 47e6ad53d..c900ea532 100644 --- a/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml.cs +++ b/src/Ryujinx/UI/Views/Input/ControllerInputView.axaml.cs @@ -55,7 +55,7 @@ namespace Ryujinx.Ava.UI.Views.Input private float _changeSlider = -1.0f; - private void Slider_IsCheckedChanged(object? sender, AvaloniaPropertyChangedEventArgs e) + private void Slider_IsCheckedChanged(object sender, AvaloniaPropertyChangedEventArgs e) { if (sender is Slider check) { @@ -74,7 +74,6 @@ namespace Ryujinx.Ava.UI.Views.Input var viewModel = (DataContext as ControllerInputViewModel); viewModel.ParentModel.IsModified = true; - //Logger.Notice.Print(LogClass.Application, $"IsEnabled: {temp}\" \"{check.Value} {check.IsPointerOver}"); _changeSlider = (float)check.Value; } } From 372d7f2ee4c816db5a1197a02592e9fdebeb318f Mon Sep 17 00:00:00 2001 From: Vova Date: Fri, 13 Dec 2024 22:07:59 +1000 Subject: [PATCH 05/17] test --- .../Engine/GPFifo/GPFifoProcessor.cs | 3 +- src/Ryujinx.Graphics.Gpu/Window.cs | 2 +- .../Services/SurfaceFlinger/SurfaceFlinger.cs | 83 +++++++++++-------- 3 files changed, 53 insertions(+), 35 deletions(-) diff --git a/src/Ryujinx.Graphics.Gpu/Engine/GPFifo/GPFifoProcessor.cs b/src/Ryujinx.Graphics.Gpu/Engine/GPFifo/GPFifoProcessor.cs index 984a9cff8..6ff980f15 100644 --- a/src/Ryujinx.Graphics.Gpu/Engine/GPFifo/GPFifoProcessor.cs +++ b/src/Ryujinx.Graphics.Gpu/Engine/GPFifo/GPFifoProcessor.cs @@ -134,7 +134,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.GPFifo _state.NonIncrementing = meth.SecOp == SecOp.NonIncMethod; break; case SecOp.ImmdDataMethod: - Send(gpuVa, meth.MethodAddress, meth.ImmdData, meth.MethodSubchannel, true); + // Send(gpuVa, meth.MethodAddress, meth.ImmdData, meth.MethodSubchannel, true); break; } } @@ -228,6 +228,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.GPFifo { case 0: _3dClass.Write(offset, argument); + //_2dClass.Write(offset, argument); break; case 1: _computeClass.Write(offset, argument); diff --git a/src/Ryujinx.Graphics.Gpu/Window.cs b/src/Ryujinx.Graphics.Gpu/Window.cs index 59cd4c8a6..8a40891b9 100644 --- a/src/Ryujinx.Graphics.Gpu/Window.cs +++ b/src/Ryujinx.Graphics.Gpu/Window.cs @@ -141,7 +141,7 @@ namespace Ryujinx.Graphics.Gpu { return false; } - + //return false; FormatInfo formatInfo = new(format, 1, 1, bytesPerPixel, 4); TextureInfo info = new( diff --git a/src/Ryujinx.HLE/HOS/Services/SurfaceFlinger/SurfaceFlinger.cs b/src/Ryujinx.HLE/HOS/Services/SurfaceFlinger/SurfaceFlinger.cs index 601e85867..a5d23f78c 100644 --- a/src/Ryujinx.HLE/HOS/Services/SurfaceFlinger/SurfaceFlinger.cs +++ b/src/Ryujinx.HLE/HOS/Services/SurfaceFlinger/SurfaceFlinger.cs @@ -10,6 +10,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Threading; +using System.Xml.Schema; using VSyncMode = Ryujinx.Common.Configuration.VSyncMode; namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger @@ -304,15 +305,16 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger while (_isRunning) { + //continue; long ticks = PerformanceCounter.ElapsedTicks; if (_swapInterval == 0) { Compose(); - _device.System?.SignalVsync(); + //_device.System?.SignalVsync(); - _nextFrameEvent.WaitOne(17); + _nextFrameEvent.WaitOne(2);//17 lastTicks = ticks; } else @@ -355,6 +357,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger } } } + int l = 0; } public void Compose() @@ -392,6 +395,7 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger } PostFrameBuffer(layer, item); + } else if (acquireStatus != Status.NoBufferAvailaible && acquireStatus != Status.InvalidOperation) { @@ -399,10 +403,17 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger } } } - + static int xx = 0; private void PostFrameBuffer(Layer layer, BufferItem item) { - int frameBufferWidth = item.GraphicBuffer.Object.Width; + TextureCallbackInformation textureCallbackInformation = new() + { + Layer = layer, + Item = item, + }; + if (xx == 0) + { + int frameBufferWidth = item.GraphicBuffer.Object.Width; int frameBufferHeight = item.GraphicBuffer.Object.Height; int nvMapHandle = item.GraphicBuffer.Object.Buffer.Surfaces[0].NvMapHandle; @@ -412,7 +423,8 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger nvMapHandle = item.GraphicBuffer.Object.Buffer.NvMapId; } - ulong bufferOffset = (ulong)item.GraphicBuffer.Object.Buffer.Surfaces[0].Offset; + + ulong bufferOffset = (ulong)item.GraphicBuffer.Object.Buffer.Surfaces[0].Offset; NvMapHandle map = NvMapDeviceFile.GetMapFromHandle(layer.Owner, nvMapHandle); @@ -446,44 +458,49 @@ namespace Ryujinx.HLE.HOS.Services.SurfaceFlinger aspectRatio.ToFloatX(), aspectRatio.ToFloatY()); - TextureCallbackInformation textureCallbackInformation = new() - { - Layer = layer, - Item = item, - }; - if (_device.Gpu.Window.EnqueueFrameThreadSafe( - layer.Owner, - frameBufferAddress, - frameBufferWidth, - frameBufferHeight, - 0, - false, - gobBlocksInY, - format, - bytesPerPixel, - crop, - AcquireBuffer, - ReleaseBuffer, - textureCallbackInformation)) - { - if (item.Fence.FenceCount == 0) + + if (_device.Gpu.Window.EnqueueFrameThreadSafe( + layer.Owner, + frameBufferAddress, + frameBufferWidth, + frameBufferHeight, + 0, + false, + gobBlocksInY, + format, + bytesPerPixel, + crop, + AcquireBuffer, + ReleaseBuffer, + textureCallbackInformation)) { - _device.Gpu.Window.SignalFrameReady(); - _device.Gpu.GPFifo.Interrupt(); - } - else - { - item.Fence.RegisterCallback(_device.Gpu, (x) => + if (item.Fence.FenceCount == 0) { _device.Gpu.Window.SignalFrameReady(); _device.Gpu.GPFifo.Interrupt(); - }); + } + else + { + item.Fence.RegisterCallback(_device.Gpu, (x) => + { + _device.Gpu.Window.SignalFrameReady(); + _device.Gpu.GPFifo.Interrupt(); + }); + } } + else + { + ReleaseBuffer(textureCallbackInformation); + } + xx++; } else { ReleaseBuffer(textureCallbackInformation); + xx++; + if (xx > 1000) + { xx = 0; } } } From 5e5e180feae749cecd6f12e17c8da06681ac481a Mon Sep 17 00:00:00 2001 From: Piplup <100526773+piplup55@users.noreply.github.com> Date: Thu, 6 Feb 2025 00:32:27 +0000 Subject: [PATCH 06/17] PlayReportAnalyzer: Added Pokemon Scarlet and Violet (#630) Every base game location excluding buildings are done, DLC locations will be added at a later point --- src/Ryujinx/Utilities/PlayReport.cs | 43 +++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/src/Ryujinx/Utilities/PlayReport.cs b/src/Ryujinx/Utilities/PlayReport.cs index f518fb902..7ebf53482 100644 --- a/src/Ryujinx/Utilities/PlayReport.cs +++ b/src/Ryujinx/Utilities/PlayReport.cs @@ -32,6 +32,12 @@ namespace Ryujinx.Ava.Utilities .AddSpec( // Global & China IDs ["0100152000022000", "010075100e8ec000"], spec => spec.AddValueFormatter("To", MarioKart8Deluxe_Mode) + ) + .AddSpec( + ["0100a3d008c5c000", "01008f6008c5e000"], + spec => spec + .AddValueFormatter("area_no", PokemonSVArea) + .AddValueFormatter("team_circle", PokemonSVUnionCircle) ); private static PlayReportFormattedValue BreathOfTheWild_MasterMode(PlayReportValue value) @@ -81,5 +87,42 @@ namespace Ryujinx.Ava.Utilities "Race" => "Racing", _ => PlayReportFormattedValue.ForceReset }; + + private static PlayReportFormattedValue PokemonSVUnionCircle(PlayReportValue value) + => value.BoxedValue is 0 ? "Playing Alone" : "Playing in a group"; + + private static PlayReportFormattedValue PokemonSVArea(PlayReportValue value) + => value.StringValue switch + { + // Base Game Locations + "a_w01" => "South Area One", + "a_w02" => "Mesagoza", + "a_w03" => "The Pokemon League", + "a_w04" => "South Area Two", + "a_w05" => "South Area Four", + "a_w06" => "South Area Six", + "a_w07" => "South Area Five", + "a_w08" => "South Area Three", + "a_w09" => "West Area One", + "a_w10" => "Asado Desert", + "a_w11" => "West Area Two", + "a_w12" => "Medali", + "a_w13" => "Tagtree Thicket", + "a_w14" => "East Area Three", + "a_w15" => "Artazon", + "a_w16" => "East Area Two", + "a_w18" => "Casseroya Lake", + "a_w19" => "Glaseado Mountain", + "a_w20" => "North Area Three", + "a_w21" => "North Area One", + "a_w22" => "North Area Two", + "a_w23" => "The Great Crater of Paldea", + "a_w24" => "South Paldean Sea", + "a_w25" => "West Paldean Sea", + "a_w26" => "East Paldean Sea", + "a_w27" => "Nouth Paldean Sea", + //TODO DLC Locations + _ => PlayReportFormattedValue.ForceReset + }; } } From c638a7daf8c1f33daaef8e8cbf5141cafd7945b5 Mon Sep 17 00:00:00 2001 From: Evan Husted Date: Wed, 5 Feb 2025 19:27:44 -0600 Subject: [PATCH 07/17] misc: chore: Move Play Report analyzer into a dedicated namespace and remove the PlayReport name prefix on types --- src/Ryujinx/DiscordIntegrationModule.cs | 10 +-- .../Analyzer.cs} | 74 +++++++++---------- .../PlayReports.cs} | 32 ++++---- 3 files changed, 56 insertions(+), 60 deletions(-) rename src/Ryujinx/Utilities/{PlayReportAnalyzer.cs => PlayReport/Analyzer.cs} (78%) rename src/Ryujinx/Utilities/{PlayReport.cs => PlayReport/PlayReports.cs} (76%) diff --git a/src/Ryujinx/DiscordIntegrationModule.cs b/src/Ryujinx/DiscordIntegrationModule.cs index 20b296511..d95bb80dd 100644 --- a/src/Ryujinx/DiscordIntegrationModule.cs +++ b/src/Ryujinx/DiscordIntegrationModule.cs @@ -4,16 +4,12 @@ using MsgPack; using Ryujinx.Ava.Utilities; using Ryujinx.Ava.Utilities.AppLibrary; using Ryujinx.Ava.Utilities.Configuration; +using Ryujinx.Ava.Utilities.PlayReport; using Ryujinx.Common; -using Ryujinx.Common.Helper; using Ryujinx.Common.Logging; using Ryujinx.HLE; using Ryujinx.HLE.Loaders.Processes; using Ryujinx.Horizon; -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Linq; using System.Text; namespace Ryujinx.Ava @@ -130,8 +126,8 @@ namespace Ryujinx.Ava if (!TitleIDs.CurrentApplication.Value.HasValue) return; if (_discordPresencePlaying is null) return; - PlayReportAnalyzer.FormattedValue formattedValue = - PlayReport.Analyzer.Format(TitleIDs.CurrentApplication.Value, _currentApp, playReport); + Analyzer.FormattedValue formattedValue = + PlayReports.Analyzer.Format(TitleIDs.CurrentApplication.Value, _currentApp, playReport); if (!formattedValue.Handled) return; diff --git a/src/Ryujinx/Utilities/PlayReportAnalyzer.cs b/src/Ryujinx/Utilities/PlayReport/Analyzer.cs similarity index 78% rename from src/Ryujinx/Utilities/PlayReportAnalyzer.cs rename to src/Ryujinx/Utilities/PlayReport/Analyzer.cs index 47c36a396..ae5abbf9d 100644 --- a/src/Ryujinx/Utilities/PlayReportAnalyzer.cs +++ b/src/Ryujinx/Utilities/PlayReport/Analyzer.cs @@ -6,27 +6,27 @@ using System.Collections.Generic; using System.Globalization; using System.Linq; -namespace Ryujinx.Ava.Utilities +namespace Ryujinx.Ava.Utilities.PlayReport { /// /// The entrypoint for the Play Report analysis system. /// - public class PlayReportAnalyzer + public class Analyzer { - private readonly List _specs = []; + private readonly List _specs = []; /// /// Add an analysis spec matching a specific game by title ID, with the provided spec configuration. /// /// The ID of the game to listen to Play Reports in. /// The configuration function for the analysis spec. - /// The current , for chaining convenience. - public PlayReportAnalyzer AddSpec(string titleId, Func transform) + /// The current , for chaining convenience. + public Analyzer AddSpec(string titleId, Func transform) { Guard.Ensure(ulong.TryParse(titleId, NumberStyles.HexNumber, null, out _), - $"Cannot use a non-hexadecimal string as the Title ID for a {nameof(PlayReportGameSpec)}."); + $"Cannot use a non-hexadecimal string as the Title ID for a {nameof(GameSpec)}."); - _specs.Add(transform(new PlayReportGameSpec { TitleIds = [titleId] })); + _specs.Add(transform(new GameSpec { TitleIds = [titleId] })); return this; } @@ -35,13 +35,13 @@ namespace Ryujinx.Ava.Utilities /// /// The ID of the game to listen to Play Reports in. /// The configuration function for the analysis spec. - /// The current , for chaining convenience. - public PlayReportAnalyzer AddSpec(string titleId, Action transform) + /// The current , for chaining convenience. + public Analyzer AddSpec(string titleId, Action transform) { Guard.Ensure(ulong.TryParse(titleId, NumberStyles.HexNumber, null, out _), - $"Cannot use a non-hexadecimal string as the Title ID for a {nameof(PlayReportGameSpec)}."); + $"Cannot use a non-hexadecimal string as the Title ID for a {nameof(GameSpec)}."); - _specs.Add(new PlayReportGameSpec { TitleIds = [titleId] }.Apply(transform)); + _specs.Add(new GameSpec { TitleIds = [titleId] }.Apply(transform)); return this; } @@ -50,15 +50,15 @@ namespace Ryujinx.Ava.Utilities /// /// The IDs of the games to listen to Play Reports in. /// The configuration function for the analysis spec. - /// The current , for chaining convenience. - public PlayReportAnalyzer AddSpec(IEnumerable titleIds, - Func transform) + /// The current , for chaining convenience. + public Analyzer AddSpec(IEnumerable titleIds, + Func transform) { string[] tids = titleIds.ToArray(); Guard.Ensure(tids.All(x => ulong.TryParse(x, NumberStyles.HexNumber, null, out _)), - $"Cannot use a non-hexadecimal string as the Title ID for a {nameof(PlayReportGameSpec)}."); + $"Cannot use a non-hexadecimal string as the Title ID for a {nameof(GameSpec)}."); - _specs.Add(transform(new PlayReportGameSpec { TitleIds = [..tids] })); + _specs.Add(transform(new GameSpec { TitleIds = [..tids] })); return this; } @@ -67,20 +67,20 @@ namespace Ryujinx.Ava.Utilities /// /// The IDs of the games to listen to Play Reports in. /// The configuration function for the analysis spec. - /// The current , for chaining convenience. - public PlayReportAnalyzer AddSpec(IEnumerable titleIds, Action transform) + /// The current , for chaining convenience. + public Analyzer AddSpec(IEnumerable titleIds, Action transform) { string[] tids = titleIds.ToArray(); Guard.Ensure(tids.All(x => ulong.TryParse(x, NumberStyles.HexNumber, null, out _)), - $"Cannot use a non-hexadecimal string as the Title ID for a {nameof(PlayReportGameSpec)}."); + $"Cannot use a non-hexadecimal string as the Title ID for a {nameof(GameSpec)}."); - _specs.Add(new PlayReportGameSpec { TitleIds = [..tids] }.Apply(transform)); + _specs.Add(new GameSpec { TitleIds = [..tids] }.Apply(transform)); return this; } /// - /// Runs the configured for the specified game title ID. + /// Runs the configured for the specified game title ID. /// /// The game currently running. /// The Application metadata information, including localized game name and play time information. @@ -95,15 +95,15 @@ namespace Ryujinx.Ava.Utilities if (!playReport.IsDictionary) return FormattedValue.Unhandled; - if (!_specs.TryGetFirst(s => runningGameId.EqualsAnyIgnoreCase(s.TitleIds), out PlayReportGameSpec spec)) + if (!_specs.TryGetFirst(s => runningGameId.EqualsAnyIgnoreCase(s.TitleIds), out GameSpec spec)) return FormattedValue.Unhandled; - foreach (PlayReportGameSpec.FormatterSpec formatSpec in spec.SimpleValueFormatters.OrderBy(x => x.Priority)) + foreach (GameSpec.FormatterSpec formatSpec in spec.SimpleValueFormatters.OrderBy(x => x.Priority)) { if (!playReport.AsDictionary().TryGetValue(formatSpec.ReportKey, out MessagePackObject valuePackObject)) continue; - return formatSpec.ValueFormatter(new PlayReportValue + return formatSpec.ValueFormatter(new Value { Application = appMeta, PackedValue = valuePackObject }); @@ -123,7 +123,7 @@ namespace Ryujinx.Ava.Utilities public bool Handled { get; private init; } /// - /// Did the handler request the caller of the to reset the existing value? + /// Did the handler request the caller of the to reset the existing value? /// public bool Reset { get; private init; } @@ -151,7 +151,7 @@ namespace Ryujinx.Ava.Utilities public static FormattedValue Unhandled => default; /// - /// Return this to suggest the caller reset the value it's using the for. + /// Return this to suggest the caller reset the value it's using the for. /// public static FormattedValue ForceReset => new() { Handled = true, Reset = true }; @@ -172,21 +172,21 @@ namespace Ryujinx.Ava.Utilities /// /// A mapping of title IDs to value formatter specs. /// - /// Generally speaking, use the .AddSpec(...) methods instead of creating this class yourself. + /// Generally speaking, use the .AddSpec(...) methods instead of creating this class yourself. /// - public class PlayReportGameSpec + public class GameSpec { public required string[] TitleIds { get; init; } public List SimpleValueFormatters { get; } = []; /// - /// Add a value formatter to the current + /// Add a value formatter to the current /// matching a specific key that could exist in a Play Report for the previously specified title IDs. /// /// The key name to match. /// The function which can return a potential formatted value. - /// The current , for chaining convenience. - public PlayReportGameSpec AddValueFormatter(string reportKey, PlayReportValueFormatter valueFormatter) + /// The current , for chaining convenience. + public GameSpec AddValueFormatter(string reportKey, PlayReportValueFormatter valueFormatter) { SimpleValueFormatters.Add(new FormatterSpec { @@ -196,14 +196,14 @@ namespace Ryujinx.Ava.Utilities } /// - /// Add a value formatter at a specific priority to the current + /// Add a value formatter at a specific priority to the current /// matching a specific key that could exist in a Play Report for the previously specified title IDs. /// /// The resolution priority of this value formatter. Higher resolves sooner. /// The key name to match. /// The function which can return a potential formatted value. - /// The current , for chaining convenience. - public PlayReportGameSpec AddValueFormatter(int priority, string reportKey, + /// The current , for chaining convenience. + public GameSpec AddValueFormatter(int priority, string reportKey, PlayReportValueFormatter valueFormatter) { SimpleValueFormatters.Add(new FormatterSpec @@ -229,7 +229,7 @@ namespace Ryujinx.Ava.Utilities /// containing the currently running application's , /// and the matched from the Play Report. /// - public class PlayReportValue + public class Value { /// /// The currently running application's . @@ -276,7 +276,7 @@ namespace Ryujinx.Ava.Utilities ///
/// a signal that nothing was available to handle it, ///
- /// OR a signal to reset the value that the caller is using the for. + /// OR a signal to reset the value that the caller is using the for. ///
- public delegate PlayReportAnalyzer.FormattedValue PlayReportValueFormatter(PlayReportValue value); + public delegate Analyzer.FormattedValue PlayReportValueFormatter(Value value); } diff --git a/src/Ryujinx/Utilities/PlayReport.cs b/src/Ryujinx/Utilities/PlayReport/PlayReports.cs similarity index 76% rename from src/Ryujinx/Utilities/PlayReport.cs rename to src/Ryujinx/Utilities/PlayReport/PlayReports.cs index 7ebf53482..ce35cae89 100644 --- a/src/Ryujinx/Utilities/PlayReport.cs +++ b/src/Ryujinx/Utilities/PlayReport/PlayReports.cs @@ -1,16 +1,16 @@ -using PlayReportFormattedValue = Ryujinx.Ava.Utilities.PlayReportAnalyzer.FormattedValue; +using static Ryujinx.Ava.Utilities.PlayReport.Analyzer; -namespace Ryujinx.Ava.Utilities +namespace Ryujinx.Ava.Utilities.PlayReport { - public static class PlayReport + public static class PlayReports { - public static PlayReportAnalyzer Analyzer { get; } = new PlayReportAnalyzer() + public static Analyzer Analyzer { get; } = new Analyzer() .AddSpec( "01007ef00011e000", spec => spec .AddValueFormatter("IsHardMode", BreathOfTheWild_MasterMode) // reset to normal status when switching between normal & master mode in title screen - .AddValueFormatter("AoCVer", PlayReportFormattedValue.AlwaysResets) + .AddValueFormatter("AoCVer", FormattedValue.AlwaysResets) ) .AddSpec( "0100f2c0115b6000", @@ -40,10 +40,10 @@ namespace Ryujinx.Ava.Utilities .AddValueFormatter("team_circle", PokemonSVUnionCircle) ); - private static PlayReportFormattedValue BreathOfTheWild_MasterMode(PlayReportValue value) - => value.BoxedValue is 1 ? "Playing Master Mode" : PlayReportFormattedValue.ForceReset; + private static FormattedValue BreathOfTheWild_MasterMode(Value value) + => value.BoxedValue is 1 ? "Playing Master Mode" : FormattedValue.ForceReset; - private static PlayReportFormattedValue TearsOfTheKingdom_CurrentField(PlayReportValue value) => + private static FormattedValue TearsOfTheKingdom_CurrentField(Value value) => value.DoubleValue switch { > 800d => "Exploring the Sky Islands", @@ -51,16 +51,16 @@ namespace Ryujinx.Ava.Utilities _ => "Roaming Hyrule" }; - private static PlayReportFormattedValue SuperMarioOdyssey_AssistMode(PlayReportValue value) + private static FormattedValue SuperMarioOdyssey_AssistMode(Value value) => value.BoxedValue is 1 ? "Playing in Assist Mode" : "Playing in Regular Mode"; - private static PlayReportFormattedValue SuperMarioOdysseyChina_AssistMode(PlayReportValue value) + private static FormattedValue SuperMarioOdysseyChina_AssistMode(Value value) => value.BoxedValue is 1 ? "Playing in 帮助模式" : "Playing in 普通模式"; - private static PlayReportFormattedValue SuperMario3DWorldOrBowsersFury(PlayReportValue value) + private static FormattedValue SuperMario3DWorldOrBowsersFury(Value value) => value.BoxedValue is 0 ? "Playing Super Mario 3D World" : "Playing Bowser's Fury"; - private static PlayReportFormattedValue MarioKart8Deluxe_Mode(PlayReportValue value) + private static FormattedValue MarioKart8Deluxe_Mode(Value value) => value.StringValue switch { // Single Player @@ -85,13 +85,13 @@ namespace Ryujinx.Ava.Utilities "Battle" => "Battle Mode", "RaceStart" => "Selecting a Course", "Race" => "Racing", - _ => PlayReportFormattedValue.ForceReset + _ => FormattedValue.ForceReset }; - private static PlayReportFormattedValue PokemonSVUnionCircle(PlayReportValue value) + private static FormattedValue PokemonSVUnionCircle(Value value) => value.BoxedValue is 0 ? "Playing Alone" : "Playing in a group"; - private static PlayReportFormattedValue PokemonSVArea(PlayReportValue value) + private static FormattedValue PokemonSVArea(Value value) => value.StringValue switch { // Base Game Locations @@ -122,7 +122,7 @@ namespace Ryujinx.Ava.Utilities "a_w26" => "East Paldean Sea", "a_w27" => "Nouth Paldean Sea", //TODO DLC Locations - _ => PlayReportFormattedValue.ForceReset + _ => FormattedValue.ForceReset }; } } From e55629a90855e02c6f1ca517c63c3f9fb781b905 Mon Sep 17 00:00:00 2001 From: Evan Husted Date: Wed, 5 Feb 2025 19:42:36 -0600 Subject: [PATCH 08/17] misc: chore: [ci skip] Play Report Analyzer: Added Multi Value formatters --- src/Ryujinx/Assets/locales.json | 2 +- src/Ryujinx/Utilities/PlayReport/Analyzer.cs | 63 ++++++++++++++++++- .../Utilities/PlayReport/PlayReports.cs | 8 ++- 3 files changed, 70 insertions(+), 3 deletions(-) diff --git a/src/Ryujinx/Assets/locales.json b/src/Ryujinx/Assets/locales.json index 8cf5b0d7c..5afb46c13 100644 --- a/src/Ryujinx/Assets/locales.json +++ b/src/Ryujinx/Assets/locales.json @@ -23698,4 +23698,4 @@ } } ] -} +} \ No newline at end of file diff --git a/src/Ryujinx/Utilities/PlayReport/Analyzer.cs b/src/Ryujinx/Utilities/PlayReport/Analyzer.cs index ae5abbf9d..3d0963b5a 100644 --- a/src/Ryujinx/Utilities/PlayReport/Analyzer.cs +++ b/src/Ryujinx/Utilities/PlayReport/Analyzer.cs @@ -108,6 +108,25 @@ namespace Ryujinx.Ava.Utilities.PlayReport Application = appMeta, PackedValue = valuePackObject }); } + + foreach (GameSpec.MultiFormatterSpec formatSpec in spec.MultiValueFormatters.OrderBy(x => x.Priority)) + { + List packedObjects = []; + foreach (var reportKey in formatSpec.ReportKeys) + { + if (!playReport.AsDictionary().TryGetValue(reportKey, out MessagePackObject valuePackObject)) + continue; + + packedObjects.Add(valuePackObject); + } + + if (packedObjects.Count != formatSpec.ReportKeys.Length) + return FormattedValue.Unhandled; + + return formatSpec.ValueFormatter(packedObjects + .Select(packObject => new Value { Application = appMeta, PackedValue = packObject }) + .ToArray()); + } return FormattedValue.Unhandled; } @@ -178,6 +197,7 @@ namespace Ryujinx.Ava.Utilities.PlayReport { public required string[] TitleIds { get; init; } public List SimpleValueFormatters { get; } = []; + public List MultiValueFormatters { get; } = []; /// /// Add a value formatter to the current @@ -212,6 +232,25 @@ namespace Ryujinx.Ava.Utilities.PlayReport }); return this; } + + public GameSpec AddMultiValueFormatter(string[] reportKeys, PlayReportMultiValueFormatter valueFormatter) + { + MultiValueFormatters.Add(new MultiFormatterSpec + { + Priority = SimpleValueFormatters.Count, ReportKeys = reportKeys, ValueFormatter = valueFormatter + }); + return this; + } + + public GameSpec AddMultiValueFormatter(int priority, string[] reportKeys, + PlayReportMultiValueFormatter valueFormatter) + { + MultiValueFormatters.Add(new MultiFormatterSpec + { + Priority = priority, ReportKeys = reportKeys, ValueFormatter = valueFormatter + }); + return this; + } /// /// A struct containing the data for a mapping of a key in a Play Report to a formatter for its potential value. @@ -222,6 +261,16 @@ namespace Ryujinx.Ava.Utilities.PlayReport public required string ReportKey { get; init; } public PlayReportValueFormatter ValueFormatter { get; init; } } + + /// + /// A struct containing the data for a mapping of an arbitrary key set in a Play Report to a formatter for their potential values. + /// + public struct MultiFormatterSpec + { + public required int Priority { get; init; } + public required string[] ReportKeys { get; init; } + public PlayReportMultiValueFormatter ValueFormatter { get; init; } + } } /// @@ -269,7 +318,7 @@ namespace Ryujinx.Ava.Utilities.PlayReport } /// - /// The delegate type that powers the entire analysis system (as it currently is).
+ /// The delegate type that powers single value formatters.
/// Takes in the result value from the Play Report, and outputs: ///
/// a formatted string, @@ -279,4 +328,16 @@ namespace Ryujinx.Ava.Utilities.PlayReport /// OR a signal to reset the value that the caller is using the for. ///
public delegate Analyzer.FormattedValue PlayReportValueFormatter(Value value); + + /// + /// The delegate type that powers multiple value formatters.
+ /// Takes in the result value from the Play Report, and outputs: + ///
+ /// a formatted string, + ///
+ /// a signal that nothing was available to handle it, + ///
+ /// OR a signal to reset the value that the caller is using the for. + ///
+ public delegate Analyzer.FormattedValue PlayReportMultiValueFormatter(Value[] value); } diff --git a/src/Ryujinx/Utilities/PlayReport/PlayReports.cs b/src/Ryujinx/Utilities/PlayReport/PlayReports.cs index ce35cae89..068d6bb9a 100644 --- a/src/Ryujinx/Utilities/PlayReport/PlayReports.cs +++ b/src/Ryujinx/Utilities/PlayReport/PlayReports.cs @@ -14,7 +14,8 @@ namespace Ryujinx.Ava.Utilities.PlayReport ) .AddSpec( "0100f2c0115b6000", - spec => spec.AddValueFormatter("PlayerPosY", TearsOfTheKingdom_CurrentField)) + spec => spec + .AddValueFormatter("PlayerPosY", TearsOfTheKingdom_CurrentField)) .AddSpec( "0100000000010000", spec => @@ -40,6 +41,11 @@ namespace Ryujinx.Ava.Utilities.PlayReport .AddValueFormatter("team_circle", PokemonSVUnionCircle) ); + private static FormattedValue Botw(Value[] values) + { + return $"{values[0].BoxedValue}, {values[1].BoxedValue}"; + } + private static FormattedValue BreathOfTheWild_MasterMode(Value value) => value.BoxedValue is 1 ? "Playing Master Mode" : FormattedValue.ForceReset; From 4a8f98126f38a3f82aa6e7385f9c686f4ca70a90 Mon Sep 17 00:00:00 2001 From: Evan Husted Date: Wed, 5 Feb 2025 19:45:29 -0600 Subject: [PATCH 09/17] [ci skip] remove test --- src/Ryujinx/Utilities/PlayReport/PlayReports.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/Ryujinx/Utilities/PlayReport/PlayReports.cs b/src/Ryujinx/Utilities/PlayReport/PlayReports.cs index 068d6bb9a..25457744e 100644 --- a/src/Ryujinx/Utilities/PlayReport/PlayReports.cs +++ b/src/Ryujinx/Utilities/PlayReport/PlayReports.cs @@ -41,11 +41,6 @@ namespace Ryujinx.Ava.Utilities.PlayReport .AddValueFormatter("team_circle", PokemonSVUnionCircle) ); - private static FormattedValue Botw(Value[] values) - { - return $"{values[0].BoxedValue}, {values[1].BoxedValue}"; - } - private static FormattedValue BreathOfTheWild_MasterMode(Value value) => value.BoxedValue is 1 ? "Playing Master Mode" : FormattedValue.ForceReset; From d1da937fce8861ea8b5de073394dc68f8b6a6eba Mon Sep 17 00:00:00 2001 From: Evan Husted Date: Wed, 5 Feb 2025 19:51:43 -0600 Subject: [PATCH 10/17] misc: chore: [ci skip] XMLdocs on new Play Report Analyzer members --- src/Ryujinx/Utilities/PlayReport/Analyzer.cs | 45 +++++++++++++------- 1 file changed, 30 insertions(+), 15 deletions(-) diff --git a/src/Ryujinx/Utilities/PlayReport/Analyzer.cs b/src/Ryujinx/Utilities/PlayReport/Analyzer.cs index 3d0963b5a..84bdbf085 100644 --- a/src/Ryujinx/Utilities/PlayReport/Analyzer.cs +++ b/src/Ryujinx/Utilities/PlayReport/Analyzer.cs @@ -132,7 +132,7 @@ namespace Ryujinx.Ava.Utilities.PlayReport } /// - /// A potential formatted value returned by a . + /// A potential formatted value returned by a . /// public readonly struct FormattedValue { @@ -175,16 +175,16 @@ namespace Ryujinx.Ava.Utilities.PlayReport public static FormattedValue ForceReset => new() { Handled = true, Reset = true }; /// - /// A delegate singleton you can use to always return in a . + /// A delegate singleton you can use to always return in a . /// - public static readonly PlayReportValueFormatter AlwaysResets = _ => ForceReset; + public static readonly ValueFormatter AlwaysResets = _ => ForceReset; /// /// A delegate factory you can use to always return the specified - /// in a . + /// in a . /// /// The string to always return for this delegate instance. - public static PlayReportValueFormatter AlwaysReturns(string formattedValue) => _ => formattedValue; + public static ValueFormatter AlwaysReturns(string formattedValue) => _ => formattedValue; } } @@ -206,7 +206,7 @@ namespace Ryujinx.Ava.Utilities.PlayReport /// The key name to match. /// The function which can return a potential formatted value. /// The current , for chaining convenience. - public GameSpec AddValueFormatter(string reportKey, PlayReportValueFormatter valueFormatter) + public GameSpec AddValueFormatter(string reportKey, ValueFormatter valueFormatter) { SimpleValueFormatters.Add(new FormatterSpec { @@ -224,7 +224,7 @@ namespace Ryujinx.Ava.Utilities.PlayReport /// The function which can return a potential formatted value. /// The current , for chaining convenience. public GameSpec AddValueFormatter(int priority, string reportKey, - PlayReportValueFormatter valueFormatter) + ValueFormatter valueFormatter) { SimpleValueFormatters.Add(new FormatterSpec { @@ -233,7 +233,14 @@ namespace Ryujinx.Ava.Utilities.PlayReport return this; } - public GameSpec AddMultiValueFormatter(string[] reportKeys, PlayReportMultiValueFormatter valueFormatter) + /// + /// Add a multi-value formatter to the current + /// matching a specific set of keys that could exist in a Play Report for the previously specified title IDs. + /// + /// The key names to match. + /// The function which can format the values. + /// The current , for chaining convenience. + public GameSpec AddMultiValueFormatter(string[] reportKeys, MultiValueFormatter valueFormatter) { MultiValueFormatters.Add(new MultiFormatterSpec { @@ -242,8 +249,16 @@ namespace Ryujinx.Ava.Utilities.PlayReport return this; } + /// + /// Add a multi-value formatter at a specific priority to the current + /// matching a specific set of keys that could exist in a Play Report for the previously specified title IDs. + /// + /// The resolution priority of this value formatter. Higher resolves sooner. + /// The key names to match. + /// The function which can format the values. + /// The current , for chaining convenience. public GameSpec AddMultiValueFormatter(int priority, string[] reportKeys, - PlayReportMultiValueFormatter valueFormatter) + MultiValueFormatter valueFormatter) { MultiValueFormatters.Add(new MultiFormatterSpec { @@ -259,7 +274,7 @@ namespace Ryujinx.Ava.Utilities.PlayReport { public required int Priority { get; init; } public required string ReportKey { get; init; } - public PlayReportValueFormatter ValueFormatter { get; init; } + public ValueFormatter ValueFormatter { get; init; } } /// @@ -269,12 +284,12 @@ namespace Ryujinx.Ava.Utilities.PlayReport { public required int Priority { get; init; } public required string[] ReportKeys { get; init; } - public PlayReportMultiValueFormatter ValueFormatter { get; init; } + public MultiValueFormatter ValueFormatter { get; init; } } } /// - /// The input data to a , + /// The input data to a , /// containing the currently running application's , /// and the matched from the Play Report. /// @@ -294,7 +309,7 @@ namespace Ryujinx.Ava.Utilities.PlayReport /// Access the as its underlying .NET type.
/// /// Does not seem to work well with comparing numeric types, - /// so use and the AsX (where X is a numerical type name i.e. Int32) methods for that. + /// so use XValue properties for that. ///
public object BoxedValue => PackedValue.ToObject(); @@ -327,7 +342,7 @@ namespace Ryujinx.Ava.Utilities.PlayReport ///
/// OR a signal to reset the value that the caller is using the for. ///
- public delegate Analyzer.FormattedValue PlayReportValueFormatter(Value value); + public delegate Analyzer.FormattedValue ValueFormatter(Value value); /// /// The delegate type that powers multiple value formatters.
@@ -339,5 +354,5 @@ namespace Ryujinx.Ava.Utilities.PlayReport ///
/// OR a signal to reset the value that the caller is using the for. ///
- public delegate Analyzer.FormattedValue PlayReportMultiValueFormatter(Value[] value); + public delegate Analyzer.FormattedValue MultiValueFormatter(Value[] value); } From 7e3c2534493a4e8915fcedfcacd748bb22083c61 Mon Sep 17 00:00:00 2001 From: Vova Date: Thu, 6 Feb 2025 15:49:17 +1000 Subject: [PATCH 11/17] Added custom configuration for games --- src/Ryujinx/AppHost.cs | 4 + src/Ryujinx/Assets/Styles/Styles.xaml | 23 +- src/Ryujinx/Assets/Styles/Themes.xaml | 5 +- src/Ryujinx/Assets/locales.json | 27 ++- src/Ryujinx/Program.cs | 58 ++++- src/Ryujinx/Ryujinx.csproj | 7 +- .../UI/Controls/ApplicationContextMenu.axaml | 5 + .../Controls/ApplicationContextMenu.axaml.cs | 33 ++- .../UI/Controls/ApplicationGridView.axaml | 38 +++- .../UI/Controls/ApplicationListView.axaml | 7 + .../UI/Controls/ApplicationListView.axaml.cs | 14 ++ .../UI/ViewModels/MainWindowViewModel.cs | 11 +- .../UI/ViewModels/SettingsViewModel.cs | 212 +++++++++++++++--- .../UI/Windows/UserConfigWindows.axaml | 139 ++++++++++++ .../UI/Windows/UserConfigWindows.axaml.cs | 108 +++++++++ .../Utilities/AppLibrary/ApplicationData.cs | 1 + .../AppLibrary/ApplicationLibrary.cs | 5 +- src/Ryujinx/Utilities/CommandLineState.cs | 57 ++++- .../ConfigurationState.Migration.cs | 99 ++++---- src/Ryujinx/Utilities/ShortcutHelper.cs | 27 ++- 20 files changed, 777 insertions(+), 103 deletions(-) create mode 100644 src/Ryujinx/UI/Windows/UserConfigWindows.axaml create mode 100644 src/Ryujinx/UI/Windows/UserConfigWindows.axaml.cs diff --git a/src/Ryujinx/AppHost.cs b/src/Ryujinx/AppHost.cs index 25f451858..d49456b9a 100644 --- a/src/Ryujinx/AppHost.cs +++ b/src/Ryujinx/AppHost.cs @@ -582,6 +582,10 @@ namespace Ryujinx.Ava Rainbow.Disable(); Rainbow.Reset(); + //Reload settings when the game is turned off + //(resets custom settings if there were any) + Program.ReloadConfig(); + _isStopped = true; Stop(); } diff --git a/src/Ryujinx/Assets/Styles/Styles.xaml b/src/Ryujinx/Assets/Styles/Styles.xaml index 5523f551a..c3bc27efd 100644 --- a/src/Ryujinx/Assets/Styles/Styles.xaml +++ b/src/Ryujinx/Assets/Styles/Styles.xaml @@ -1,7 +1,8 @@ - -