Skip to content

Commit

Permalink
UI: The argument to Play Report value formatters is now a struct cont…
Browse files Browse the repository at this point in the history
…aining the current ApplicationMetadata & the BoxedValue that was the only argument previously.

This allows for the title of Mario Kart to be localized when one of the value checkers doesn't match.
  • Loading branch information
GreemDev committed Feb 3, 2025
1 parent 8117e16 commit fe43c32
Show file tree
Hide file tree
Showing 3 changed files with 112 additions and 94 deletions.
80 changes: 0 additions & 80 deletions src/Ryujinx.Common/Helpers/PlayReportAnalyzer.cs

This file was deleted.

5 changes: 4 additions & 1 deletion src/Ryujinx/DiscordIntegrationModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ private static string VersionString
private static DiscordRpcClient _discordClient;
private static RichPresence _discordPresenceMain;
private static RichPresence _discordPresencePlaying;
private static ApplicationMetadata _currentApp;

public static void Initialize()
{
Expand Down Expand Up @@ -113,6 +114,7 @@ private static RichPresence CreatePlayingState(ApplicationMetadata appMeta, Proc
private static void SwitchToPlayingState(ApplicationMetadata appMeta, ProcessResult procRes)
{
_discordClient?.SetPresence(_discordPresencePlaying ??= CreatePlayingState(appMeta, procRes));
_currentApp = appMeta;
}

private static void UpdatePlayingState()
Expand All @@ -124,14 +126,15 @@ private static void SwitchToMainState()
{
_discordClient?.SetPresence(_discordPresenceMain);
_discordPresencePlaying = null;
_currentApp = null;
}

private static void HandlePlayReport(MessagePackObject playReport)
{
if (!TitleIDs.CurrentApplication.Value.HasValue) return;
if (_discordPresencePlaying is null) return;

Optional<string> details = PlayReport.Analyzer.Run(TitleIDs.CurrentApplication.Value, playReport);
Optional<string> details = PlayReport.Analyzer.Run(TitleIDs.CurrentApplication.Value, _currentApp, playReport);

if (!details.HasValue) return;

Expand Down
121 changes: 108 additions & 13 deletions src/Ryujinx/Utilities/PlayReport.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
using Ryujinx.Common.Helper;
using Gommon;
using MsgPack;
using Ryujinx.Ava.Utilities.AppLibrary;
using Ryujinx.Common.Helper;
using System;
using System.Collections.Generic;
using System.Linq;

namespace Ryujinx.Ava.Utilities
{
Expand Down Expand Up @@ -32,20 +38,20 @@ public static class PlayReport
spec => spec.AddValueFormatter("To", MarioKart8Deluxe_Mode)
);

private static string BreathOfTheWild_MasterMode(object val)
=> val is 1 ? "Playing Master Mode" : "Playing Normal Mode";
private static string BreathOfTheWild_MasterMode(ref PlayReportValue value)
=> value.BoxedValue is 1 ? "Playing Master Mode" : "Playing Normal Mode";

private static string SuperMarioOdyssey_AssistMode(object val)
=> val is 1 ? "Playing in Assist Mode" : "Playing in Regular Mode";
private static string SuperMarioOdyssey_AssistMode(ref PlayReportValue value)
=> value.BoxedValue is 1 ? "Playing in Assist Mode" : "Playing in Regular Mode";

private static string SuperMarioOdysseyChina_AssistMode(object val)
=> val is 1 ? "Playing in 帮助模式" : "Playing in 普通模式";
private static string SuperMarioOdysseyChina_AssistMode(ref PlayReportValue value)
=> value.BoxedValue is 1 ? "Playing in 帮助模式" : "Playing in 普通模式";

private static string SuperMario3DWorldOrBowsersFury(object val)
=> val is 0 ? "Playing Super Mario 3D World" : "Playing Bowser's Fury";
private static string SuperMario3DWorldOrBowsersFury(ref PlayReportValue value)
=> value.BoxedValue is 0 ? "Playing Super Mario 3D World" : "Playing Bowser's Fury";

private static string MarioKart8Deluxe_Mode(object obj)
=> obj switch
private static string MarioKart8Deluxe_Mode(ref PlayReportValue value)
=> value.BoxedValue switch
{
// Single Player
"Single" => "Single Player",
Expand All @@ -69,8 +75,97 @@ private static string MarioKart8Deluxe_Mode(object obj)
"Battle" => "Battle Mode",
"RaceStart" => "Selecting a Course",
"Race" => "Racing",
//TODO: refactor value formatting system to pass in the name from the content archive so this can be localized properly
_ => "Playing Mario Kart 8 Deluxe"
_ => $"Playing {value.Application.Title}"
};
}

#region Analyzer implementation

public class PlayReportAnalyzer
{
private readonly List<PlayReportGameSpec> _specs = [];

public PlayReportAnalyzer AddSpec(string titleId, Func<PlayReportGameSpec, PlayReportGameSpec> transform)
{
_specs.Add(transform(new PlayReportGameSpec { TitleIdStr = titleId }));
return this;
}

public PlayReportAnalyzer AddSpec(string titleId, Action<PlayReportGameSpec> transform)
{
_specs.Add(new PlayReportGameSpec { TitleIdStr = titleId }.Apply(transform));
return this;
}

public Optional<string> Run(string runningGameId, ApplicationMetadata appMeta, MessagePackObject playReport)
{
if (!playReport.IsDictionary)
return Optional<string>.None;

if (!_specs.TryGetFirst(s => s.TitleIdStr.EqualsIgnoreCase(runningGameId), out PlayReportGameSpec spec))
return Optional<string>.None;

foreach (PlayReportValueFormatterSpec formatSpec in spec.Analyses.OrderBy(x => x.Priority))
{
if (!playReport.AsDictionary().TryGetValue(formatSpec.ReportKey, out MessagePackObject valuePackObject))
continue;

PlayReportValue value = new()
{
Application = appMeta,
BoxedValue = valuePackObject.ToObject()
};

return formatSpec.ValueFormatter(ref value);
}

return Optional<string>.None;
}

}

public class PlayReportGameSpec
{
public required string TitleIdStr { get; init; }
public List<PlayReportValueFormatterSpec> Analyses { get; } = [];

public PlayReportGameSpec AddValueFormatter(string reportKey, PlayReportValueFormatter valueFormatter)
{
Analyses.Add(new PlayReportValueFormatterSpec
{
Priority = Analyses.Count,
ReportKey = reportKey,
ValueFormatter = valueFormatter
});
return this;
}

public PlayReportGameSpec AddValueFormatter(int priority, string reportKey, PlayReportValueFormatter valueFormatter)
{
Analyses.Add(new PlayReportValueFormatterSpec
{
Priority = priority,
ReportKey = reportKey,
ValueFormatter = valueFormatter
});
return this;
}
}

public struct PlayReportValue
{
public ApplicationMetadata Application { get; init; }
public object BoxedValue { get; init; }
}

public struct PlayReportValueFormatterSpec
{
public required int Priority { get; init; }
public required string ReportKey { get; init; }
public required PlayReportValueFormatter ValueFormatter { get; init; }
}

public delegate string PlayReportValueFormatter(ref PlayReportValue value);

#endregion
}

0 comments on commit fe43c32

Please sign in to comment.