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/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. /// 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"; 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}"; }