From 395bbd144a1f52225be77529601b9961b17e0e90 Mon Sep 17 00:00:00 2001 From: Evan Husted Date: Sat, 15 Feb 2025 19:01:24 -0600 Subject: [PATCH 1/6] misc: chore: Change Analyzer AddSpec logic to log the non-hexadecimal value and ignore the added entry instead of throwing an exception --- src/Ryujinx/Utilities/PlayReport/Analyzer.cs | 49 ++++++++++++++------ 1 file changed, 36 insertions(+), 13 deletions(-) diff --git a/src/Ryujinx/Utilities/PlayReport/Analyzer.cs b/src/Ryujinx/Utilities/PlayReport/Analyzer.cs index 51047cc32..cd4021bc4 100644 --- a/src/Ryujinx/Utilities/PlayReport/Analyzer.cs +++ b/src/Ryujinx/Utilities/PlayReport/Analyzer.cs @@ -1,5 +1,6 @@ using Gommon; using Ryujinx.Ava.Utilities.AppLibrary; +using Ryujinx.Common.Logging; using System; using System.Collections.Generic; using System.Collections.ObjectModel; @@ -27,10 +28,12 @@ namespace Ryujinx.Ava.Utilities.PlayReport /// 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(GameSpec)}."); + if (ulong.TryParse(titleId, NumberStyles.HexNumber, null, out _)) + return AddSpec(transform(GameSpec.Create(titleId))); - return AddSpec(transform(GameSpec.Create(titleId))); + Logger.Notice.PrintMsg(LogClass.Application, + $"Tried to add a {nameof(GameSpec)} with a non-hexadecimal title ID value. Input: '{titleId}'"); + return this; } /// @@ -41,10 +44,12 @@ namespace Ryujinx.Ava.Utilities.PlayReport /// 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(GameSpec)}."); + if (ulong.TryParse(titleId, NumberStyles.HexNumber, null, out _)) + return AddSpec(GameSpec.Create(titleId).Apply(transform)); - return AddSpec(GameSpec.Create(titleId).Apply(transform)); + Logger.Notice.PrintMsg(LogClass.Application, + $"Tried to add a {nameof(GameSpec)} with a non-hexadecimal title ID value. Input: '{titleId}'"); + return this; } /// @@ -57,10 +62,19 @@ namespace Ryujinx.Ava.Utilities.PlayReport 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(GameSpec)}."); + if (tids.All(x => ulong.TryParse(x, NumberStyles.HexNumber, null, out _) && !string.IsNullOrEmpty(x))) + return AddSpec(transform(GameSpec.Create(tids))); - return AddSpec(transform(GameSpec.Create(tids))); + Logger.Notice.PrintMsg(LogClass.Application, + $"Tried to add a {nameof(GameSpec)} with a non-hexadecimal title ID value. Input: '{ + tids.FormatCollection( + x => x, + separator: ", ", + prefix: "[", + suffix: "]" + ) + }'"); + return this; } /// @@ -72,12 +86,21 @@ namespace Ryujinx.Ava.Utilities.PlayReport 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(GameSpec)}."); + if (tids.All(x => ulong.TryParse(x, NumberStyles.HexNumber, null, out _) && !string.IsNullOrEmpty(x))) + return AddSpec(GameSpec.Create(tids).Apply(transform)); - return AddSpec(GameSpec.Create(tids).Apply(transform)); + Logger.Notice.PrintMsg(LogClass.Application, + $"Tried to add a {nameof(GameSpec)} with a non-hexadecimal title ID value. Input: '{ + tids.FormatCollection( + x => x, + separator: ", ", + prefix: "[", + suffix: "]" + ) + }'"); + return this; } - + /// /// Add an analysis spec matching a specific game by title ID, with the provided pre-configured spec. /// From 45ee8cd0e875c94d378e3af76233e2ba94925f55 Mon Sep 17 00:00:00 2001 From: Evan Husted Date: Sat, 15 Feb 2025 19:02:04 -0600 Subject: [PATCH 2/6] misc: Play Report Analyzer: Skyward Sword HD rupee count --- src/Ryujinx/Utilities/PlayReport/PlayReports.Formatters.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Ryujinx/Utilities/PlayReport/PlayReports.Formatters.cs b/src/Ryujinx/Utilities/PlayReport/PlayReports.Formatters.cs index cabace6bb..43e830819 100644 --- a/src/Ryujinx/Utilities/PlayReport/PlayReports.Formatters.cs +++ b/src/Ryujinx/Utilities/PlayReport/PlayReports.Formatters.cs @@ -1,4 +1,5 @@ using Gommon; +using Humanizer; using System; using System.Buffers.Binary; using System.Collections.Generic; @@ -18,6 +19,9 @@ namespace Ryujinx.Ava.Utilities.PlayReport < -201d => "Exploring the Depths", _ => "Roaming Hyrule" }; + + private static FormattedValue SkywardSwordHD_Rupees(SingleValue value) + => "rupee".ToQuantity(value.Matched.IntValue); private static FormattedValue SuperMarioOdyssey_AssistMode(SingleValue value) => value.Matched.BoxedValue is 1 ? "Playing in Assist Mode" : "Playing in Regular Mode"; From f92d09711bc5ab03703af4422b721b7bb3cbf52f Mon Sep 17 00:00:00 2001 From: Evan Husted Date: Sat, 15 Feb 2025 19:02:37 -0600 Subject: [PATCH 3/6] misc: chore: rewrite PlayReports.Analyzer creation to use Lazy and create the value alongside DiscordIntegrationModule init --- src/Ryujinx/DiscordIntegrationModule.cs | 1 + .../Utilities/PlayReport/PlayReports.cs | 136 ++++++++++-------- 2 files changed, 76 insertions(+), 61 deletions(-) diff --git a/src/Ryujinx/DiscordIntegrationModule.cs b/src/Ryujinx/DiscordIntegrationModule.cs index 47fc8ad69..075dc65da 100644 --- a/src/Ryujinx/DiscordIntegrationModule.cs +++ b/src/Ryujinx/DiscordIntegrationModule.cs @@ -56,6 +56,7 @@ namespace Ryujinx.Ava ConfigurationState.Instance.EnableDiscordIntegration.Event += Update; TitleIDs.CurrentApplication.Event += (_, e) => Use(e.NewValue); HorizonStatic.PlayReport += HandlePlayReport; + PlayReports.Initialize(); } private static void Update(object sender, ReactiveEventArgs evnt) diff --git a/src/Ryujinx/Utilities/PlayReport/PlayReports.cs b/src/Ryujinx/Utilities/PlayReport/PlayReports.cs index d5568962e..27330c808 100644 --- a/src/Ryujinx/Utilities/PlayReport/PlayReports.cs +++ b/src/Ryujinx/Utilities/PlayReport/PlayReports.cs @@ -1,67 +1,81 @@ -namespace Ryujinx.Ava.Utilities.PlayReport +using System; + +namespace Ryujinx.Ava.Utilities.PlayReport { public static partial class PlayReports { - 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", FormattedValue.SingleAlwaysResets) - ) - .AddSpec( - "0100f2c0115b6000", - spec => spec - .AddValueFormatter("PlayerPosY", TearsOfTheKingdom_CurrentField)) - .AddSpec( - "0100000000010000", - spec => - spec.AddValueFormatter("is_kids_mode", SuperMarioOdyssey_AssistMode) - ) - .AddSpec( - "010075000ecbe000", - spec => - spec.AddValueFormatter("is_kids_mode", SuperMarioOdysseyChina_AssistMode) - ) - .AddSpec( - "010028600ebda000", - spec => spec.AddValueFormatter("mode", SuperMario3DWorldOrBowsersFury) - ) - .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) - ) - .AddSpec( - "01006a800016e000", - spec => spec - .AddSparseMultiValueFormatter( - [ - // Metadata to figure out what PlayReport we have. - "match_mode", "match_submode", "anniversary", "fighter", "reason", "challenge_count", - "adv_slot", - // List of Fighters - "player_1_fighter", "player_2_fighter", "player_3_fighter", "player_4_fighter", - "player_5_fighter", "player_6_fighter", "player_7_fighter", "player_8_fighter", - // List of rankings/placements - "player_1_rank", "player_2_rank", "player_3_rank", "player_4_rank", "player_5_rank", - "player_6_rank", "player_7_rank", "player_8_rank" - ], - SuperSmashBrosUltimate_Mode - ) - ) - .AddSpec( - [ - "0100c9a00ece6000", "01008d300c50c000", "0100d870045b6000", - "010012f017576000", "0100c62011050000", "0100b3c014bda000"], - spec => spec.AddValueFormatter("launch_title_id", NsoEmulator_LaunchedGame) - ); + public static void Initialize() + { + // init lazy value + _ = Analyzer; + } + + public static Analyzer Analyzer => _analyzerLazy.Value; + + private static readonly Lazy _analyzerLazy = new(() => + 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", FormattedValue.SingleAlwaysResets) + ) + .AddSpec( + "0100f2c0115b6000", + spec => spec + .AddValueFormatter("PlayerPosY", TearsOfTheKingdom_CurrentField)) + .AddSpec( + "0100000000010000", + spec => + spec.AddValueFormatter("is_kids_mode", SuperMarioOdyssey_AssistMode) + ) + .AddSpec( + "010075000ecbe000", + spec => + spec.AddValueFormatter("is_kids_mode", SuperMarioOdysseyChina_AssistMode) + ) + .AddSpec( + "010028600ebda000", + spec => spec.AddValueFormatter("mode", SuperMario3DWorldOrBowsersFury) + ) + .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) + ) + .AddSpec( + "01006a800016e000", + spec => spec + .AddSparseMultiValueFormatter( + [ + // Metadata to figure out what PlayReport we have. + "match_mode", "match_submode", "anniversary", "fighter", "reason", "challenge_count", + "adv_slot", + // List of Fighters + "player_1_fighter", "player_2_fighter", "player_3_fighter", "player_4_fighter", + "player_5_fighter", "player_6_fighter", "player_7_fighter", "player_8_fighter", + // List of rankings/placements + "player_1_rank", "player_2_rank", "player_3_rank", "player_4_rank", "player_5_rank", + "player_6_rank", "player_7_rank", "player_8_rank" + ], + SuperSmashBrosUltimate_Mode + ) + ) + .AddSpec( + [ + "0100c9a00ece6000", "01008d300c50c000", "0100d870045b6000", + "010012f017576000", "0100c62011050000", "0100b3c014bda000" + ], + spec => spec.AddValueFormatter("launch_title_id", NsoEmulator_LaunchedGame) + ) + .AddSpec("01002da013484000", spec => spec.AddValueFormatter("rupees", SkywardSwordHD_Rupees)) + ); private static string Playing(string game) => $"Playing {game}"; } From aa2178dbe5eee7079035e4098900b10f0e09bbe3 Mon Sep 17 00:00:00 2001 From: Evan Husted Date: Sat, 15 Feb 2025 20:25:17 -0600 Subject: [PATCH 4/6] UI: Button to open screenshots folder in File menu --- src/Ryujinx/Assets/locales.json | 50 +++++++++++++++++++ .../UI/ViewModels/MainWindowViewModel.cs | 19 +++++++ .../UI/Views/Main/MainMenuBarView.axaml | 4 ++ 3 files changed, 73 insertions(+) diff --git a/src/Ryujinx/Assets/locales.json b/src/Ryujinx/Assets/locales.json index 555c6d3c3..3623a0073 100644 --- a/src/Ryujinx/Assets/locales.json +++ b/src/Ryujinx/Assets/locales.json @@ -447,6 +447,31 @@ "zh_TW": "開啟 Ryujinx 資料夾" } }, + { + "ID": "MenuBarFileOpenScreenshotsFolder", + "Translations": { + "ar_SA": "", + "de_DE": "", + "el_GR": "", + "en_US": "Open Screenshots Folder", + "es_ES": "", + "fr_FR": "", + "he_IL": "", + "it_IT": "", + "ja_JP": "", + "ko_KR": "", + "no_NO": "", + "pl_PL": "", + "pt_BR": "", + "ru_RU": "", + "sv_SE": "", + "th_TH": "", + "tr_TR": "", + "uk_UA": "", + "zh_CN": "", + "zh_TW": "" + } + }, { "ID": "MenuBarFileOpenLogsFolder", "Translations": { @@ -17197,6 +17222,31 @@ "zh_TW": "開啟 Ryujinx 檔案系統資料夾" } }, + { + "ID": "OpenScreenshotFolderTooltip", + "Translations": { + "ar_SA": "", + "de_DE": "", + "el_GR": "", + "en_US": "Open Ryujinx screenshots folder", + "es_ES": "", + "fr_FR": "", + "he_IL": "", + "it_IT": "", + "ja_JP": "", + "ko_KR": "", + "no_NO": "", + "pl_PL": "", + "pt_BR": "", + "ru_RU": "", + "sv_SE": "", + "th_TH": "", + "tr_TR": "", + "uk_UA": "", + "zh_CN": "", + "zh_TW": "" + } + }, { "ID": "OpenRyujinxLogsTooltip", "Translations": { diff --git a/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs b/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs index bbfe80570..7d7674c4e 100644 --- a/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs +++ b/src/Ryujinx/UI/ViewModels/MainWindowViewModel.cs @@ -1347,6 +1347,25 @@ namespace Ryujinx.Ava.UI.ViewModels OpenHelper.OpenFolder(AppDataManager.BaseDirPath); } + public void OpenScreenshotsFolder() + { + string screenshotsDir = Path.Combine(AppDataManager.BaseDirPath, "screenshots"); + + try + { + if (!Directory.Exists(screenshotsDir)) + Directory.CreateDirectory(screenshotsDir); + } + catch (Exception ex) + { + Logger.Error?.Print(LogClass.Application, $"Failed to create directory at path {screenshotsDir}. Error : {ex.GetType().Name}", "Screenshot"); + + return; + } + + OpenHelper.OpenFolder(screenshotsDir); + } + public void OpenLogsFolder() { string logPath = AppDataManager.GetOrCreateLogsDir(); diff --git a/src/Ryujinx/UI/Views/Main/MainMenuBarView.axaml b/src/Ryujinx/UI/Views/Main/MainMenuBarView.axaml index cacb4b130..1da91c388 100644 --- a/src/Ryujinx/UI/Views/Main/MainMenuBarView.axaml +++ b/src/Ryujinx/UI/Views/Main/MainMenuBarView.axaml @@ -66,6 +66,10 @@ Command="{Binding OpenRyujinxFolder}" Header="{ext:Locale MenuBarFileOpenEmuFolder}" ToolTip.Tip="{ext:Locale OpenRyujinxFolderTooltip}" /> + Date: Sat, 15 Feb 2025 20:45:27 -0600 Subject: [PATCH 5/6] UI: Add descriptions of what each dynamic RPC formatter actually shows when hovering whether it has support in the game info popup --- .../UI/Controls/ApplicationDataView.axaml | 14 +++++--- .../UI/ViewModels/ApplicationDataViewModel.cs | 6 ++++ .../Utilities/AppLibrary/ApplicationData.cs | 10 ++++-- src/Ryujinx/Utilities/PlayReport/Analyzer.cs | 11 +++++-- .../Utilities/PlayReport/PlayReports.cs | 32 ++++++++++++++----- src/Ryujinx/Utilities/PlayReport/Specs.cs | 16 +++++++++- 6 files changed, 71 insertions(+), 18 deletions(-) diff --git a/src/Ryujinx/UI/Controls/ApplicationDataView.axaml b/src/Ryujinx/UI/Controls/ApplicationDataView.axaml index aee8f7b36..92e4d1ac3 100644 --- a/src/Ryujinx/UI/Controls/ApplicationDataView.axaml +++ b/src/Ryujinx/UI/Controls/ApplicationDataView.axaml @@ -119,17 +119,23 @@ TextWrapping="Wrap" > - - + + + TextWrapping="Wrap"> - + AppData = appData; + public string DynamicRichPresenceDescription => + AppData.HasDynamicRichPresenceSupport + ? AppData.RichPresenceSpec.Value.Description + : GameSpec.DefaultDescription; + public string FormattedVersion => LocaleManager.Instance[LocaleKeys.GameListHeaderVersion].Format(AppData.Version); public string FormattedDeveloper => LocaleManager.Instance[LocaleKeys.GameListHeaderDeveloper].Format(AppData.Developer); public string FormattedFileExtension => LocaleManager.Instance[LocaleKeys.GameListHeaderFileExtension].Format(AppData.FileExtension); diff --git a/src/Ryujinx/Utilities/AppLibrary/ApplicationData.cs b/src/Ryujinx/Utilities/AppLibrary/ApplicationData.cs index 747ead8ca..2658352d7 100644 --- a/src/Ryujinx/Utilities/AppLibrary/ApplicationData.cs +++ b/src/Ryujinx/Utilities/AppLibrary/ApplicationData.cs @@ -10,6 +10,7 @@ using LibHac.Tools.FsSystem; using LibHac.Tools.FsSystem.NcaUtils; using Ryujinx.Ava.Common.Locale; using Ryujinx.Ava.Utilities.Compat; +using Ryujinx.Ava.Utilities.PlayReport; using Ryujinx.Common.Logging; using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.Loaders.Processes.Extensions; @@ -35,9 +36,14 @@ namespace Ryujinx.Ava.Utilities.AppLibrary { _id = value; - Compatibility = CompatibilityCsv.Find(Id); + Compatibility = CompatibilityCsv.Find(value); + RichPresenceSpec = PlayReports.Analyzer.TryGetSpec(IdString, out GameSpec gameSpec) + ? gameSpec + : default(Optional); } } + public Optional RichPresenceSpec { get; set; } + public string Developer { get; set; } = "Unknown"; public string Version { get; set; } = "0"; public int PlayerCount { get; set; } @@ -46,7 +52,7 @@ namespace Ryujinx.Ava.Utilities.AppLibrary public bool HasLdnGames => PlayerCount != 0 && GameCount != 0; public bool HasRichPresenceAsset => DiscordIntegrationModule.HasAssetImage(IdString); - public bool HasDynamicRichPresenceSupport => DiscordIntegrationModule.HasAnalyzer(IdString); + public bool HasDynamicRichPresenceSupport => RichPresenceSpec.HasValue; public TimeSpan TimePlayed { get; set; } public DateTime? LastPlayed { get; set; } diff --git a/src/Ryujinx/Utilities/PlayReport/Analyzer.cs b/src/Ryujinx/Utilities/PlayReport/Analyzer.cs index cd4021bc4..8faf4fb31 100644 --- a/src/Ryujinx/Utilities/PlayReport/Analyzer.cs +++ b/src/Ryujinx/Utilities/PlayReport/Analyzer.cs @@ -20,6 +20,11 @@ namespace Ryujinx.Ava.Utilities.PlayReport public IReadOnlyList Specs => new ReadOnlyCollection(_specs); + public GameSpec GetSpec(string titleId) => _specs.First(x => x.TitleIds.ContainsIgnoreCase(titleId)); + + public bool TryGetSpec(string titleId, out GameSpec gameSpec) + => (gameSpec = _specs.FirstOrDefault(x => x.TitleIds.ContainsIgnoreCase(titleId))) != null; + /// /// Add an analysis spec matching a specific game by title ID, with the provided spec configuration. /// @@ -128,13 +133,13 @@ namespace Ryujinx.Ava.Utilities.PlayReport { if (!playReport.ReportData.IsDictionary) return FormattedValue.Unhandled; - - if (!_specs.TryGetFirst(s => runningGameId.EqualsAnyIgnoreCase(s.TitleIds), out GameSpec spec)) + + if (!TryGetSpec(runningGameId, out GameSpec spec)) return FormattedValue.Unhandled; foreach (FormatterSpecBase formatSpec in spec.ValueFormatters.OrderBy(x => x.Priority)) { - if (!formatSpec.Format(appMeta, playReport, out FormattedValue value)) + if (!formatSpec.TryFormat(appMeta, playReport, out FormattedValue value)) continue; return value; diff --git a/src/Ryujinx/Utilities/PlayReport/PlayReports.cs b/src/Ryujinx/Utilities/PlayReport/PlayReports.cs index 27330c808..7602c1de8 100644 --- a/src/Ryujinx/Utilities/PlayReport/PlayReports.cs +++ b/src/Ryujinx/Utilities/PlayReport/PlayReports.cs @@ -17,6 +17,7 @@ namespace Ryujinx.Ava.Utilities.PlayReport .AddSpec( "01007ef00011e000", spec => spec + .WithDescription("based on being in Master Mode.") .AddValueFormatter("IsHardMode", BreathOfTheWild_MasterMode) // reset to normal status when switching between normal & master mode in title screen .AddValueFormatter("AoCVer", FormattedValue.SingleAlwaysResets) @@ -24,34 +25,48 @@ namespace Ryujinx.Ava.Utilities.PlayReport .AddSpec( "0100f2c0115b6000", spec => spec + .WithDescription("based on where you are in Hyrule (Depths, Surface, Sky).") .AddValueFormatter("PlayerPosY", TearsOfTheKingdom_CurrentField)) + .AddSpec( + "01002da013484000", + spec => spec + .WithDescription("based on how many Rupees you have.") + .AddValueFormatter("rupees", SkywardSwordHD_Rupees)) .AddSpec( "0100000000010000", - spec => - spec.AddValueFormatter("is_kids_mode", SuperMarioOdyssey_AssistMode) + spec => spec + .WithDescription("based on if you're playing with Assist Mode.") + .AddValueFormatter("is_kids_mode", SuperMarioOdyssey_AssistMode) ) .AddSpec( "010075000ecbe000", - spec => - spec.AddValueFormatter("is_kids_mode", SuperMarioOdysseyChina_AssistMode) + spec => spec + .WithDescription("based on if you're playing with Assist Mode.") + .AddValueFormatter("is_kids_mode", SuperMarioOdysseyChina_AssistMode) ) .AddSpec( "010028600ebda000", - spec => spec.AddValueFormatter("mode", SuperMario3DWorldOrBowsersFury) + spec => spec + .WithDescription("based on being in either Super Mario 3D World or Bowser's Fury.") + .AddValueFormatter("mode", SuperMario3DWorldOrBowsersFury) ) .AddSpec( // Global & China IDs ["0100152000022000", "010075100e8ec000"], - spec => spec.AddValueFormatter("To", MarioKart8Deluxe_Mode) + spec => spec + .WithDescription("based on what modes you're selecting in the menu & whether or not you're in a race.") + .AddValueFormatter("To", MarioKart8Deluxe_Mode) ) .AddSpec( ["0100a3d008c5c000", "01008f6008c5e000"], spec => spec + .WithDescription("based on what area of Paldea you're exploring.") .AddValueFormatter("area_no", PokemonSVArea) .AddValueFormatter("team_circle", PokemonSVUnionCircle) ) .AddSpec( "01006a800016e000", spec => spec + .WithDescription("based on what mode you're playing, who won, and what characters were present.") .AddSparseMultiValueFormatter( [ // Metadata to figure out what PlayReport we have. @@ -72,9 +87,10 @@ namespace Ryujinx.Ava.Utilities.PlayReport "0100c9a00ece6000", "01008d300c50c000", "0100d870045b6000", "010012f017576000", "0100c62011050000", "0100b3c014bda000" ], - spec => spec.AddValueFormatter("launch_title_id", NsoEmulator_LaunchedGame) + spec => spec + .WithDescription("based on what game you first launch.\n\nNSO emulators do not print any Play Report information past the first game launch so it's all we got.") + .AddValueFormatter("launch_title_id", NsoEmulator_LaunchedGame) ) - .AddSpec("01002da013484000", spec => spec.AddValueFormatter("rupees", SkywardSwordHD_Rupees)) ); private static string Playing(string game) => $"Playing {game}"; diff --git a/src/Ryujinx/Utilities/PlayReport/Specs.cs b/src/Ryujinx/Utilities/PlayReport/Specs.cs index f1b94de68..c162d4c2c 100644 --- a/src/Ryujinx/Utilities/PlayReport/Specs.cs +++ b/src/Ryujinx/Utilities/PlayReport/Specs.cs @@ -23,6 +23,20 @@ namespace Ryujinx.Ava.Utilities.PlayReport public required string[] TitleIds { get; init; } + public const string DefaultDescription = "Formats the details on your Discord presence based on logged data from the game."; + + private string _valueDescription; + + public string Description => _valueDescription ?? DefaultDescription; + + public GameSpec WithDescription(string description) + { + _valueDescription = description != null + ? $"Formats the details on your Discord presence {description}" + : null; + return this; + } + public List ValueFormatters { get; } = []; @@ -197,7 +211,7 @@ namespace Ryujinx.Ava.Utilities.PlayReport public string[] ReportKeys { get; init; } public Delegate Formatter { get; init; } - public bool Format(ApplicationMetadata appMeta, Horizon.Prepo.Types.PlayReport playReport, + public bool TryFormat(ApplicationMetadata appMeta, Horizon.Prepo.Types.PlayReport playReport, out FormattedValue formattedValue) { formattedValue = default; From b1f61e5143cf7c29cfa5f742d96d2cd5f4ee51f7 Mon Sep 17 00:00:00 2001 From: Evan Husted Date: Sat, 15 Feb 2025 20:52:03 -0600 Subject: [PATCH 6/6] misc: chore: [ci skip] Reformat PlayReports.cs --- .../Utilities/PlayReport/PlayReports.cs | 161 +++++++++--------- 1 file changed, 81 insertions(+), 80 deletions(-) diff --git a/src/Ryujinx/Utilities/PlayReport/PlayReports.cs b/src/Ryujinx/Utilities/PlayReport/PlayReports.cs index 7602c1de8..9feb888b3 100644 --- a/src/Ryujinx/Utilities/PlayReport/PlayReports.cs +++ b/src/Ryujinx/Utilities/PlayReport/PlayReports.cs @@ -9,88 +9,89 @@ namespace Ryujinx.Ava.Utilities.PlayReport // init lazy value _ = Analyzer; } - + public static Analyzer Analyzer => _analyzerLazy.Value; - private static readonly Lazy _analyzerLazy = new(() => - new Analyzer() - .AddSpec( - "01007ef00011e000", - spec => spec - .WithDescription("based on being in Master Mode.") - .AddValueFormatter("IsHardMode", BreathOfTheWild_MasterMode) - // reset to normal status when switching between normal & master mode in title screen - .AddValueFormatter("AoCVer", FormattedValue.SingleAlwaysResets) - ) - .AddSpec( - "0100f2c0115b6000", - spec => spec - .WithDescription("based on where you are in Hyrule (Depths, Surface, Sky).") - .AddValueFormatter("PlayerPosY", TearsOfTheKingdom_CurrentField)) - .AddSpec( - "01002da013484000", - spec => spec - .WithDescription("based on how many Rupees you have.") - .AddValueFormatter("rupees", SkywardSwordHD_Rupees)) - .AddSpec( - "0100000000010000", - spec => spec - .WithDescription("based on if you're playing with Assist Mode.") - .AddValueFormatter("is_kids_mode", SuperMarioOdyssey_AssistMode) - ) - .AddSpec( - "010075000ecbe000", - spec => spec - .WithDescription("based on if you're playing with Assist Mode.") - .AddValueFormatter("is_kids_mode", SuperMarioOdysseyChina_AssistMode) - ) - .AddSpec( - "010028600ebda000", - spec => spec - .WithDescription("based on being in either Super Mario 3D World or Bowser's Fury.") - .AddValueFormatter("mode", SuperMario3DWorldOrBowsersFury) - ) - .AddSpec( // Global & China IDs - ["0100152000022000", "010075100e8ec000"], - spec => spec - .WithDescription("based on what modes you're selecting in the menu & whether or not you're in a race.") - .AddValueFormatter("To", MarioKart8Deluxe_Mode) - ) - .AddSpec( - ["0100a3d008c5c000", "01008f6008c5e000"], - spec => spec - .WithDescription("based on what area of Paldea you're exploring.") - .AddValueFormatter("area_no", PokemonSVArea) - .AddValueFormatter("team_circle", PokemonSVUnionCircle) - ) - .AddSpec( - "01006a800016e000", - spec => spec - .WithDescription("based on what mode you're playing, who won, and what characters were present.") - .AddSparseMultiValueFormatter( - [ - // Metadata to figure out what PlayReport we have. - "match_mode", "match_submode", "anniversary", "fighter", "reason", "challenge_count", - "adv_slot", - // List of Fighters - "player_1_fighter", "player_2_fighter", "player_3_fighter", "player_4_fighter", - "player_5_fighter", "player_6_fighter", "player_7_fighter", "player_8_fighter", - // List of rankings/placements - "player_1_rank", "player_2_rank", "player_3_rank", "player_4_rank", "player_5_rank", - "player_6_rank", "player_7_rank", "player_8_rank" - ], - SuperSmashBrosUltimate_Mode - ) - ) - .AddSpec( - [ - "0100c9a00ece6000", "01008d300c50c000", "0100d870045b6000", - "010012f017576000", "0100c62011050000", "0100b3c014bda000" - ], - spec => spec - .WithDescription("based on what game you first launch.\n\nNSO emulators do not print any Play Report information past the first game launch so it's all we got.") - .AddValueFormatter("launch_title_id", NsoEmulator_LaunchedGame) - ) + private static readonly Lazy _analyzerLazy = new(() => new Analyzer() + .AddSpec( + "01007ef00011e000", + spec => spec + .WithDescription("based on being in Master Mode.") + .AddValueFormatter("IsHardMode", BreathOfTheWild_MasterMode) + // reset to normal status when switching between normal & master mode in title screen + .AddValueFormatter("AoCVer", FormattedValue.SingleAlwaysResets) + ) + .AddSpec( + "0100f2c0115b6000", + spec => spec + .WithDescription("based on where you are in Hyrule (Depths, Surface, Sky).") + .AddValueFormatter("PlayerPosY", TearsOfTheKingdom_CurrentField)) + .AddSpec( + "01002da013484000", + spec => spec + .WithDescription("based on how many Rupees you have.") + .AddValueFormatter("rupees", SkywardSwordHD_Rupees)) + .AddSpec( + "0100000000010000", + spec => spec + .WithDescription("based on if you're playing with Assist Mode.") + .AddValueFormatter("is_kids_mode", SuperMarioOdyssey_AssistMode) + ) + .AddSpec( + "010075000ecbe000", + spec => spec + .WithDescription("based on if you're playing with Assist Mode.") + .AddValueFormatter("is_kids_mode", SuperMarioOdysseyChina_AssistMode) + ) + .AddSpec( + "010028600ebda000", + spec => spec + .WithDescription("based on being in either Super Mario 3D World or Bowser's Fury.") + .AddValueFormatter("mode", SuperMario3DWorldOrBowsersFury) + ) + .AddSpec( // Global & China IDs + ["0100152000022000", "010075100e8ec000"], + spec => spec + .WithDescription( + "based on what modes you're selecting in the menu & whether or not you're in a race.") + .AddValueFormatter("To", MarioKart8Deluxe_Mode) + ) + .AddSpec( + ["0100a3d008c5c000", "01008f6008c5e000"], + spec => spec + .WithDescription("based on what area of Paldea you're exploring.") + .AddValueFormatter("area_no", PokemonSVArea) + .AddValueFormatter("team_circle", PokemonSVUnionCircle) + ) + .AddSpec( + "01006a800016e000", + spec => spec + .WithDescription("based on what mode you're playing, who won, and what characters were present.") + .AddSparseMultiValueFormatter( + [ + // Metadata to figure out what PlayReport we have. + "match_mode", "match_submode", "anniversary", "fighter", "reason", "challenge_count", + "adv_slot", + // List of Fighters + "player_1_fighter", "player_2_fighter", "player_3_fighter", "player_4_fighter", + "player_5_fighter", "player_6_fighter", "player_7_fighter", "player_8_fighter", + // List of rankings/placements + "player_1_rank", "player_2_rank", "player_3_rank", "player_4_rank", "player_5_rank", + "player_6_rank", "player_7_rank", "player_8_rank" + ], + SuperSmashBrosUltimate_Mode + ) + ) + .AddSpec( + [ + "0100c9a00ece6000", "01008d300c50c000", "0100d870045b6000", + "010012f017576000", "0100c62011050000", "0100b3c014bda000" + ], + spec => spec + .WithDescription( + "based on what game you first launch.\n\nNSO emulators do not print any Play Report information past the first game launch so it's all we got.") + .AddValueFormatter("launch_title_id", NsoEmulator_LaunchedGame) + ) ); private static string Playing(string game) => $"Playing {game}";