mirror of
https://git.ryujinx.app/ryubing/ryujinx.git
synced 2025-04-21 18:13:14 +02:00
117 lines
5.2 KiB
C#
117 lines
5.2 KiB
C#
using Gommon;
|
|
using MsgPack;
|
|
using Ryujinx.Ava.Utilities.AppLibrary;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Collections.ObjectModel;
|
|
using System.Globalization;
|
|
using System.Linq;
|
|
|
|
namespace Ryujinx.Ava.Utilities.PlayReport
|
|
{
|
|
/// <summary>
|
|
/// The entrypoint for the Play Report analysis system.
|
|
/// </summary>
|
|
public class Analyzer
|
|
{
|
|
private readonly List<GameSpec> _specs = [];
|
|
|
|
public string[] TitleIds => Specs.SelectMany(x => x.TitleIds).ToArray();
|
|
|
|
public IReadOnlyList<GameSpec> Specs => new ReadOnlyCollection<GameSpec>(_specs);
|
|
|
|
/// <summary>
|
|
/// Add an analysis spec matching a specific game by title ID, with the provided spec configuration.
|
|
/// </summary>
|
|
/// <param name="titleId">The ID of the game to listen to Play Reports in.</param>
|
|
/// <param name="transform">The configuration function for the analysis spec.</param>
|
|
/// <returns>The current <see cref="Analyzer"/>, for chaining convenience.</returns>
|
|
public Analyzer AddSpec(string titleId, Func<GameSpec, GameSpec> transform)
|
|
{
|
|
Guard.Ensure(ulong.TryParse(titleId, NumberStyles.HexNumber, null, out _),
|
|
$"Cannot use a non-hexadecimal string as the Title ID for a {nameof(GameSpec)}.");
|
|
|
|
_specs.Add(transform(new GameSpec { TitleIds = [titleId] }));
|
|
return this;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Add an analysis spec matching a specific game by title ID, with the provided spec configuration.
|
|
/// </summary>
|
|
/// <param name="titleId">The ID of the game to listen to Play Reports in.</param>
|
|
/// <param name="transform">The configuration function for the analysis spec.</param>
|
|
/// <returns>The current <see cref="Analyzer"/>, for chaining convenience.</returns>
|
|
public Analyzer AddSpec(string titleId, Action<GameSpec> transform)
|
|
{
|
|
Guard.Ensure(ulong.TryParse(titleId, NumberStyles.HexNumber, null, out _),
|
|
$"Cannot use a non-hexadecimal string as the Title ID for a {nameof(GameSpec)}.");
|
|
|
|
_specs.Add(new GameSpec { TitleIds = [titleId] }.Apply(transform));
|
|
return this;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Add an analysis spec matching a specific set of games by title IDs, with the provided spec configuration.
|
|
/// </summary>
|
|
/// <param name="titleIds">The IDs of the games to listen to Play Reports in.</param>
|
|
/// <param name="transform">The configuration function for the analysis spec.</param>
|
|
/// <returns>The current <see cref="Analyzer"/>, for chaining convenience.</returns>
|
|
public Analyzer AddSpec(IEnumerable<string> titleIds,
|
|
Func<GameSpec, GameSpec> 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)}.");
|
|
|
|
_specs.Add(transform(new GameSpec { TitleIds = [..tids] }));
|
|
return this;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Add an analysis spec matching a specific set of games by title IDs, with the provided spec configuration.
|
|
/// </summary>
|
|
/// <param name="titleIds">The IDs of the games to listen to Play Reports in.</param>
|
|
/// <param name="transform">The configuration function for the analysis spec.</param>
|
|
/// <returns>The current <see cref="Analyzer"/>, for chaining convenience.</returns>
|
|
public Analyzer AddSpec(IEnumerable<string> titleIds, Action<GameSpec> 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)}.");
|
|
|
|
_specs.Add(new GameSpec { TitleIds = [..tids] }.Apply(transform));
|
|
return this;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Runs the configured <see cref="FormatterSpec"/> for the specified game title ID.
|
|
/// </summary>
|
|
/// <param name="runningGameId">The game currently running.</param>
|
|
/// <param name="appMeta">The Application metadata information, including localized game name and play time information.</param>
|
|
/// <param name="playReport">The Play Report received from HLE.</param>
|
|
/// <returns>A struct representing a possible formatted value.</returns>
|
|
public FormattedValue Format(
|
|
string runningGameId,
|
|
ApplicationMetadata appMeta,
|
|
Horizon.Prepo.Types.PlayReport playReport
|
|
)
|
|
{
|
|
if (!playReport.ReportData.IsDictionary)
|
|
return FormattedValue.Unhandled;
|
|
|
|
if (!_specs.TryGetFirst(s => runningGameId.EqualsAnyIgnoreCase(s.TitleIds), out GameSpec spec))
|
|
return FormattedValue.Unhandled;
|
|
|
|
foreach (FormatterSpecBase formatSpec in spec.ValueFormatters.OrderBy(x => x.Priority))
|
|
{
|
|
if (!formatSpec.Format(appMeta, playReport, out FormattedValue value))
|
|
continue;
|
|
|
|
return value;
|
|
}
|
|
|
|
return FormattedValue.Unhandled;
|
|
}
|
|
}
|
|
}
|