mirror of
https://github.com/GreemDev/Ryujinx.git
synced 2025-02-22 13:20:20 +01:00
UI: Add descriptions of what each dynamic RPC formatter actually shows when hovering whether it has support in the game info popup
This commit is contained in:
parent
aa2178dbe5
commit
0d7d0e8092
@ -119,17 +119,23 @@
|
|||||||
TextWrapping="Wrap" >
|
TextWrapping="Wrap" >
|
||||||
</TextBlock>
|
</TextBlock>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<StackPanel Orientation="Horizontal" Spacing="5">
|
<StackPanel Orientation="Horizontal" Spacing="5" ToolTip.Tip="{Binding DynamicRichPresenceDescription}">
|
||||||
<ui:SymbolIcon Foreground="ForestGreen" Symbol="Checkmark" IsVisible="{Binding AppData.HasDynamicRichPresenceSupport}"/>
|
<ui:SymbolIcon
|
||||||
|
Foreground="ForestGreen"
|
||||||
|
Symbol="Checkmark"
|
||||||
|
IsVisible="{Binding AppData.HasDynamicRichPresenceSupport}"/>
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Foreground="ForestGreen"
|
Foreground="ForestGreen"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
IsVisible="{Binding AppData.HasDynamicRichPresenceSupport}"
|
IsVisible="{Binding AppData.HasDynamicRichPresenceSupport}"
|
||||||
Text="{ext:Locale GameInfoRpcDynamic}"
|
Text="{ext:Locale GameInfoRpcDynamic}"
|
||||||
TextAlignment="Start"
|
TextAlignment="Start"
|
||||||
TextWrapping="Wrap" >
|
TextWrapping="Wrap">
|
||||||
</TextBlock>
|
</TextBlock>
|
||||||
<ui:SymbolIcon Foreground="Red" Symbol="Cancel" IsVisible="{Binding !AppData.HasDynamicRichPresenceSupport}"/>
|
<ui:SymbolIcon
|
||||||
|
Foreground="Red"
|
||||||
|
Symbol="Cancel"
|
||||||
|
IsVisible="{Binding !AppData.HasDynamicRichPresenceSupport}"/>
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Foreground="Red"
|
Foreground="Red"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using Gommon;
|
using Gommon;
|
||||||
using Ryujinx.Ava.Common.Locale;
|
using Ryujinx.Ava.Common.Locale;
|
||||||
using Ryujinx.Ava.Utilities.AppLibrary;
|
using Ryujinx.Ava.Utilities.AppLibrary;
|
||||||
|
using Ryujinx.Ava.Utilities.PlayReport;
|
||||||
|
|
||||||
namespace Ryujinx.Ava.UI.ViewModels
|
namespace Ryujinx.Ava.UI.ViewModels
|
||||||
{
|
{
|
||||||
@ -10,6 +11,11 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
|
|
||||||
public ApplicationDataViewModel(ApplicationData appData) => AppData = appData;
|
public ApplicationDataViewModel(ApplicationData appData) => 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 FormattedVersion => LocaleManager.Instance[LocaleKeys.GameListHeaderVersion].Format(AppData.Version);
|
||||||
public string FormattedDeveloper => LocaleManager.Instance[LocaleKeys.GameListHeaderDeveloper].Format(AppData.Developer);
|
public string FormattedDeveloper => LocaleManager.Instance[LocaleKeys.GameListHeaderDeveloper].Format(AppData.Developer);
|
||||||
public string FormattedFileExtension => LocaleManager.Instance[LocaleKeys.GameListHeaderFileExtension].Format(AppData.FileExtension);
|
public string FormattedFileExtension => LocaleManager.Instance[LocaleKeys.GameListHeaderFileExtension].Format(AppData.FileExtension);
|
||||||
|
@ -10,6 +10,7 @@ using LibHac.Tools.FsSystem;
|
|||||||
using LibHac.Tools.FsSystem.NcaUtils;
|
using LibHac.Tools.FsSystem.NcaUtils;
|
||||||
using Ryujinx.Ava.Common.Locale;
|
using Ryujinx.Ava.Common.Locale;
|
||||||
using Ryujinx.Ava.Utilities.Compat;
|
using Ryujinx.Ava.Utilities.Compat;
|
||||||
|
using Ryujinx.Ava.Utilities.PlayReport;
|
||||||
using Ryujinx.Common.Logging;
|
using Ryujinx.Common.Logging;
|
||||||
using Ryujinx.HLE.FileSystem;
|
using Ryujinx.HLE.FileSystem;
|
||||||
using Ryujinx.HLE.Loaders.Processes.Extensions;
|
using Ryujinx.HLE.Loaders.Processes.Extensions;
|
||||||
@ -35,9 +36,14 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
|
|||||||
{
|
{
|
||||||
_id = value;
|
_id = value;
|
||||||
|
|
||||||
Compatibility = CompatibilityCsv.Find(Id);
|
Compatibility = CompatibilityCsv.Find(value);
|
||||||
|
RichPresenceSpec = PlayReports.Analyzer.TryGetSpec(IdString, out GameSpec gameSpec)
|
||||||
|
? gameSpec
|
||||||
|
: default(Optional<GameSpec>);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public Optional<GameSpec> RichPresenceSpec { get; set; }
|
||||||
|
|
||||||
public string Developer { get; set; } = "Unknown";
|
public string Developer { get; set; } = "Unknown";
|
||||||
public string Version { get; set; } = "0";
|
public string Version { get; set; } = "0";
|
||||||
public int PlayerCount { get; set; }
|
public int PlayerCount { get; set; }
|
||||||
@ -46,7 +52,7 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
|
|||||||
public bool HasLdnGames => PlayerCount != 0 && GameCount != 0;
|
public bool HasLdnGames => PlayerCount != 0 && GameCount != 0;
|
||||||
|
|
||||||
public bool HasRichPresenceAsset => DiscordIntegrationModule.HasAssetImage(IdString);
|
public bool HasRichPresenceAsset => DiscordIntegrationModule.HasAssetImage(IdString);
|
||||||
public bool HasDynamicRichPresenceSupport => DiscordIntegrationModule.HasAnalyzer(IdString);
|
public bool HasDynamicRichPresenceSupport => RichPresenceSpec.HasValue;
|
||||||
|
|
||||||
public TimeSpan TimePlayed { get; set; }
|
public TimeSpan TimePlayed { get; set; }
|
||||||
public DateTime? LastPlayed { get; set; }
|
public DateTime? LastPlayed { get; set; }
|
||||||
|
@ -20,6 +20,11 @@ namespace Ryujinx.Ava.Utilities.PlayReport
|
|||||||
|
|
||||||
public IReadOnlyList<GameSpec> Specs => new ReadOnlyCollection<GameSpec>(_specs);
|
public IReadOnlyList<GameSpec> Specs => new ReadOnlyCollection<GameSpec>(_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;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Add an analysis spec matching a specific game by title ID, with the provided spec configuration.
|
/// Add an analysis spec matching a specific game by title ID, with the provided spec configuration.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -128,13 +133,13 @@ namespace Ryujinx.Ava.Utilities.PlayReport
|
|||||||
{
|
{
|
||||||
if (!playReport.ReportData.IsDictionary)
|
if (!playReport.ReportData.IsDictionary)
|
||||||
return FormattedValue.Unhandled;
|
return FormattedValue.Unhandled;
|
||||||
|
|
||||||
if (!_specs.TryGetFirst(s => runningGameId.EqualsAnyIgnoreCase(s.TitleIds), out GameSpec spec))
|
if (!TryGetSpec(runningGameId, out GameSpec spec))
|
||||||
return FormattedValue.Unhandled;
|
return FormattedValue.Unhandled;
|
||||||
|
|
||||||
foreach (FormatterSpecBase formatSpec in spec.ValueFormatters.OrderBy(x => x.Priority))
|
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;
|
continue;
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
|
@ -17,6 +17,7 @@ namespace Ryujinx.Ava.Utilities.PlayReport
|
|||||||
.AddSpec(
|
.AddSpec(
|
||||||
"01007ef00011e000",
|
"01007ef00011e000",
|
||||||
spec => spec
|
spec => spec
|
||||||
|
.WithDescription("based on being in Master Mode.")
|
||||||
.AddValueFormatter("IsHardMode", BreathOfTheWild_MasterMode)
|
.AddValueFormatter("IsHardMode", BreathOfTheWild_MasterMode)
|
||||||
// reset to normal status when switching between normal & master mode in title screen
|
// reset to normal status when switching between normal & master mode in title screen
|
||||||
.AddValueFormatter("AoCVer", FormattedValue.SingleAlwaysResets)
|
.AddValueFormatter("AoCVer", FormattedValue.SingleAlwaysResets)
|
||||||
@ -24,34 +25,48 @@ namespace Ryujinx.Ava.Utilities.PlayReport
|
|||||||
.AddSpec(
|
.AddSpec(
|
||||||
"0100f2c0115b6000",
|
"0100f2c0115b6000",
|
||||||
spec => spec
|
spec => spec
|
||||||
|
.WithDescription("based on where you are in Hyrule (Depths, Surface, Sky).")
|
||||||
.AddValueFormatter("PlayerPosY", TearsOfTheKingdom_CurrentField))
|
.AddValueFormatter("PlayerPosY", TearsOfTheKingdom_CurrentField))
|
||||||
|
.AddSpec(
|
||||||
|
"01002da013484000",
|
||||||
|
spec => spec
|
||||||
|
.WithDescription("based on how many Rupees you have.")
|
||||||
|
.AddValueFormatter("rupees", SkywardSwordHD_Rupees))
|
||||||
.AddSpec(
|
.AddSpec(
|
||||||
"0100000000010000",
|
"0100000000010000",
|
||||||
spec =>
|
spec => spec
|
||||||
spec.AddValueFormatter("is_kids_mode", SuperMarioOdyssey_AssistMode)
|
.WithDescription("based on if you're playing with Assist Mode.")
|
||||||
|
.AddValueFormatter("is_kids_mode", SuperMarioOdyssey_AssistMode)
|
||||||
)
|
)
|
||||||
.AddSpec(
|
.AddSpec(
|
||||||
"010075000ecbe000",
|
"010075000ecbe000",
|
||||||
spec =>
|
spec => spec
|
||||||
spec.AddValueFormatter("is_kids_mode", SuperMarioOdysseyChina_AssistMode)
|
.WithDescription("based on if you're playing with Assist Mode.")
|
||||||
|
.AddValueFormatter("is_kids_mode", SuperMarioOdysseyChina_AssistMode)
|
||||||
)
|
)
|
||||||
.AddSpec(
|
.AddSpec(
|
||||||
"010028600ebda000",
|
"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
|
.AddSpec( // Global & China IDs
|
||||||
["0100152000022000", "010075100e8ec000"],
|
["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(
|
.AddSpec(
|
||||||
["0100a3d008c5c000", "01008f6008c5e000"],
|
["0100a3d008c5c000", "01008f6008c5e000"],
|
||||||
spec => spec
|
spec => spec
|
||||||
|
.WithDescription("based on what area of Paldea you're exploring.")
|
||||||
.AddValueFormatter("area_no", PokemonSVArea)
|
.AddValueFormatter("area_no", PokemonSVArea)
|
||||||
.AddValueFormatter("team_circle", PokemonSVUnionCircle)
|
.AddValueFormatter("team_circle", PokemonSVUnionCircle)
|
||||||
)
|
)
|
||||||
.AddSpec(
|
.AddSpec(
|
||||||
"01006a800016e000",
|
"01006a800016e000",
|
||||||
spec => spec
|
spec => spec
|
||||||
|
.WithDescription("based on what mode you're playing, who won, and what characters were present.")
|
||||||
.AddSparseMultiValueFormatter(
|
.AddSparseMultiValueFormatter(
|
||||||
[
|
[
|
||||||
// Metadata to figure out what PlayReport we have.
|
// Metadata to figure out what PlayReport we have.
|
||||||
@ -72,9 +87,10 @@ namespace Ryujinx.Ava.Utilities.PlayReport
|
|||||||
"0100c9a00ece6000", "01008d300c50c000", "0100d870045b6000",
|
"0100c9a00ece6000", "01008d300c50c000", "0100d870045b6000",
|
||||||
"010012f017576000", "0100c62011050000", "0100b3c014bda000"
|
"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}";
|
private static string Playing(string game) => $"Playing {game}";
|
||||||
|
@ -23,6 +23,20 @@ namespace Ryujinx.Ava.Utilities.PlayReport
|
|||||||
|
|
||||||
public required string[] TitleIds { get; init; }
|
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<FormatterSpecBase> ValueFormatters { get; } = [];
|
public List<FormatterSpecBase> ValueFormatters { get; } = [];
|
||||||
|
|
||||||
|
|
||||||
@ -197,7 +211,7 @@ namespace Ryujinx.Ava.Utilities.PlayReport
|
|||||||
public string[] ReportKeys { get; init; }
|
public string[] ReportKeys { get; init; }
|
||||||
public Delegate Formatter { 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)
|
out FormattedValue formattedValue)
|
||||||
{
|
{
|
||||||
formattedValue = default;
|
formattedValue = default;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user