Compare commits

..

7 Commits

Author SHA1 Message Date
在中国的泰国青年_ f0e4af3673 Merge 05475de925 into 55536f5d78 2025-02-02 23:13:54 -06:00
在中国的泰国青年_ 05475de925 Merge branch 'Ryubing:master' into master 2025-02-02 10:23:42 +07:00
LotP1 6aa2b9f02c remove duplicate entries
you should not add entries to your language if they match the english entry
2025-02-01 17:41:18 +01:00
在中国的泰国青年_ d691da72b6 Update locales.json 2025-02-01 23:38:48 +07:00
在中国的泰国青年_ 17e6815416 Update locales.json 2025-02-01 23:32:26 +07:00
在中国的泰国青年_ 4e87e2708b Update locales.json 2025-02-01 20:11:48 +07:00
在中国的泰国青年_ 911a63fc7b Update locales.json 2025-02-01 19:41:36 +07:00
21 changed files with 507 additions and 569 deletions
+1 -2
View File
@@ -47,8 +47,7 @@ namespace Ryujinx.Common
"01006f8002326000", // Animal Crossings: New Horizons "01006f8002326000", // Animal Crossings: New Horizons
"01009bf0072d4000", // Captain Toad: Treasure Tracker "01009bf0072d4000", // Captain Toad: Treasure Tracker
"01009510001ca000", // Fast RMX "01009510001ca000", // Fast RMX
"01005CA01580E000", // Persona 5 Royal "01005CA01580E000", // Persona 5 Royale
"0100b880154fc000", // Persona 5 The Royal (Japan)
"010015100b514000", // Super Mario Bros. Wonder "010015100b514000", // Super Mario Bros. Wonder
"0100000000010000", // Super Mario Odyssey "0100000000010000", // Super Mario Odyssey
+23 -24
View File
@@ -2,36 +2,35 @@ using MsgPack;
using Ryujinx.Horizon.Common; using Ryujinx.Horizon.Common;
using Ryujinx.Memory; using Ryujinx.Memory;
using System; using System;
using System.Threading;
namespace Ryujinx.Horizon namespace Ryujinx.Horizon
{ {
public static class HorizonStatic public static class HorizonStatic
{ {
internal static void HandlePlayReport(MessagePackObject report) => internal static void HandlePlayReport(MessagePackObject report) => PlayReportPrinted?.Invoke(report);
new Thread(() => PlayReport?.Invoke(report))
{
Name = "HLE.PlayReportEvent",
IsBackground = true,
Priority = ThreadPriority.AboveNormal
}.Start();
public static event Action<MessagePackObject> PlayReport; public static event Action<MessagePackObject> PlayReportPrinted;
[ThreadStatic]
private static HorizonOptions _options;
[field: ThreadStatic] [ThreadStatic]
public static HorizonOptions Options { get; private set; } private static ISyscallApi _syscall;
[field: ThreadStatic] [ThreadStatic]
public static ISyscallApi Syscall { get; private set; } private static IVirtualMemoryManager _addressSpace;
[field: ThreadStatic] [ThreadStatic]
public static IVirtualMemoryManager AddressSpace { get; private set; } private static IThreadContext _threadContext;
[field: ThreadStatic] [ThreadStatic]
public static IThreadContext ThreadContext { get; private set; } private static int _threadHandle;
[field: ThreadStatic] public static HorizonOptions Options => _options;
public static int CurrentThreadHandle { get; private set; } public static ISyscallApi Syscall => _syscall;
public static IVirtualMemoryManager AddressSpace => _addressSpace;
public static IThreadContext ThreadContext => _threadContext;
public static int CurrentThreadHandle => _threadHandle;
public static void Register( public static void Register(
HorizonOptions options, HorizonOptions options,
@@ -40,11 +39,11 @@ namespace Ryujinx.Horizon
IThreadContext threadContext, IThreadContext threadContext,
int threadHandle) int threadHandle)
{ {
Options = options; _options = options;
Syscall = syscallApi; _syscall = syscallApi;
AddressSpace = addressSpace; _addressSpace = addressSpace;
ThreadContext = threadContext; _threadContext = threadContext;
CurrentThreadHandle = threadHandle; _threadHandle = threadHandle;
} }
} }
} }
@@ -1,4 +1,3 @@
using Gommon;
using MsgPack; using MsgPack;
using MsgPack.Serialization; using MsgPack.Serialization;
using Ryujinx.Common.Logging; using Ryujinx.Common.Logging;
@@ -12,7 +11,6 @@ using Ryujinx.Horizon.Sdk.Sf;
using Ryujinx.Horizon.Sdk.Sf.Hipc; using Ryujinx.Horizon.Sdk.Sf.Hipc;
using System; using System;
using System.Text; using System.Text;
using System.Threading;
using ApplicationId = Ryujinx.Horizon.Sdk.Ncm.ApplicationId; using ApplicationId = Ryujinx.Horizon.Sdk.Ncm.ApplicationId;
namespace Ryujinx.Horizon.Prepo.Ipc namespace Ryujinx.Horizon.Prepo.Ipc
+1 -3
View File
@@ -938,9 +938,7 @@ namespace Ryujinx.Ava
ConfigurationState.Instance.System.EnableInternetAccess, ConfigurationState.Instance.System.EnableInternetAccess,
ConfigurationState.Instance.System.EnableFsIntegrityChecks ? IntegrityCheckLevel.ErrorOnInvalid : IntegrityCheckLevel.None, ConfigurationState.Instance.System.EnableFsIntegrityChecks ? IntegrityCheckLevel.ErrorOnInvalid : IntegrityCheckLevel.None,
ConfigurationState.Instance.System.FsGlobalAccessLogMode, ConfigurationState.Instance.System.FsGlobalAccessLogMode,
ConfigurationState.Instance.System.MatchSystemTime ConfigurationState.Instance.System.SystemTimeOffset,
? 0
: ConfigurationState.Instance.System.SystemTimeOffset,
ConfigurationState.Instance.System.TimeZone, ConfigurationState.Instance.System.TimeZone,
ConfigurationState.Instance.System.MemoryManagerMode, ConfigurationState.Instance.System.MemoryManagerMode,
ConfigurationState.Instance.System.IgnoreMissingServices, ConfigurationState.Instance.System.IgnoreMissingServices,
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -56,7 +56,7 @@ namespace Ryujinx.Ava
ConfigurationState.Instance.EnableDiscordIntegration.Event += Update; ConfigurationState.Instance.EnableDiscordIntegration.Event += Update;
TitleIDs.CurrentApplication.Event += (_, e) => Use(e.NewValue); TitleIDs.CurrentApplication.Event += (_, e) => Use(e.NewValue);
HorizonStatic.PlayReport += HandlePlayReport; HorizonStatic.PlayReportPrinted += HandlePlayReport;
} }
private static void Update(object sender, ReactiveEventArgs<bool> evnt) private static void Update(object sender, ReactiveEventArgs<bool> evnt)
@@ -86,13 +86,6 @@
Text="{Binding Version}" Text="{Binding Version}"
TextAlignment="Start" TextAlignment="Start"
TextWrapping="Wrap" /> TextWrapping="Wrap" />
<TextBlock
IsVisible="{Binding HasPlayabilityInfo}"
HorizontalAlignment="Stretch"
Text="{Binding LocalizedStatus}"
Foreground="{Binding PlayabilityStatus, Converter={x:Static helpers:PlayabilityStatusConverter.Shared}}"
TextAlignment="Start"
TextWrapping="Wrap" />
</StackPanel> </StackPanel>
</Border> </Border>
<StackPanel <StackPanel
+17 -7
View File
@@ -116,6 +116,10 @@ namespace Ryujinx.Ava.UI.ViewModels
public bool IsOpenGLAvailable => !OperatingSystem.IsMacOS(); public bool IsOpenGLAvailable => !OperatingSystem.IsMacOS();
public bool IsAppleSiliconMac => OperatingSystem.IsMacOS() && RuntimeInformation.ProcessArchitecture == Architecture.Arm64;
public bool IsMacOS => OperatingSystem.IsMacOS();
public bool EnableDiscordIntegration { get; set; } public bool EnableDiscordIntegration { get; set; }
public bool CheckUpdatesOnStart { get; set; } public bool CheckUpdatesOnStart { get; set; }
public bool ShowConfirmExit { get; set; } public bool ShowConfirmExit { get; set; }
@@ -197,7 +201,7 @@ namespace Ryujinx.Ava.UI.ViewModels
public bool EnableTextureRecompression { get; set; } public bool EnableTextureRecompression { get; set; }
public bool EnableMacroHLE { get; set; } public bool EnableMacroHLE { get; set; }
public bool EnableColorSpacePassthrough { get; set; } public bool EnableColorSpacePassthrough { get; set; }
public bool ColorSpacePassthroughAvailable => RunningPlatform.IsMacOS; public bool ColorSpacePassthroughAvailable => IsMacOS;
public bool EnableFileLog { get; set; } public bool EnableFileLog { get; set; }
public bool EnableStub { get; set; } public bool EnableStub { get; set; }
public bool EnableInfo { get; set; } public bool EnableInfo { get; set; }
@@ -293,8 +297,6 @@ namespace Ryujinx.Ava.UI.ViewModels
} }
} }
[ObservableProperty] private bool _matchSystemTime;
public DateTimeOffset CurrentDate { get; set; } public DateTimeOffset CurrentDate { get; set; }
public TimeSpan CurrentTime { get; set; } public TimeSpan CurrentTime { get; set; }
@@ -410,6 +412,17 @@ namespace Ryujinx.Ava.UI.ViewModels
Dispatcher.UIThread.Post(() => OnPropertyChanged(nameof(PreferredGpuIndex))); Dispatcher.UIThread.Post(() => OnPropertyChanged(nameof(PreferredGpuIndex)));
} }
public void MatchSystemTime()
{
(DateTimeOffset dto, TimeSpan timeOfDay) = DateTimeOffset.Now.Extract();
CurrentDate = dto;
CurrentTime = timeOfDay;
OnPropertyChanged(nameof(CurrentDate));
OnPropertyChanged(nameof(CurrentTime));
}
public async Task LoadTimeZones() public async Task LoadTimeZones()
{ {
_timeZoneContentManager = new TimeZoneContentManager(); _timeZoneContentManager = new TimeZoneContentManager();
@@ -511,9 +524,7 @@ namespace Ryujinx.Ava.UI.ViewModels
CurrentDate = currentDateTime.Date; CurrentDate = currentDateTime.Date;
CurrentTime = currentDateTime.TimeOfDay; CurrentTime = currentDateTime.TimeOfDay;
MatchSystemTime = config.System.MatchSystemTime; EnableCustomVSyncInterval = config.Graphics.EnableCustomVSyncInterval.Value;
EnableCustomVSyncInterval = config.Graphics.EnableCustomVSyncInterval;
CustomVSyncInterval = config.Graphics.CustomVSyncInterval; CustomVSyncInterval = config.Graphics.CustomVSyncInterval;
VSyncMode = config.Graphics.VSyncMode; VSyncMode = config.Graphics.VSyncMode;
EnableFsIntegrityChecks = config.System.EnableFsIntegrityChecks; EnableFsIntegrityChecks = config.System.EnableFsIntegrityChecks;
@@ -618,7 +629,6 @@ namespace Ryujinx.Ava.UI.ViewModels
config.System.TimeZone.Value = TimeZone; config.System.TimeZone.Value = TimeZone;
} }
config.System.MatchSystemTime.Value = MatchSystemTime;
config.System.SystemTimeOffset.Value = Convert.ToInt64((CurrentDate.ToUnixTimeSeconds() + CurrentTime.TotalSeconds) - DateTimeOffset.Now.ToUnixTimeSeconds()); config.System.SystemTimeOffset.Value = Convert.ToInt64((CurrentDate.ToUnixTimeSeconds() + CurrentTime.TotalSeconds) - DateTimeOffset.Now.ToUnixTimeSeconds());
config.System.EnableFsIntegrityChecks.Value = EnableFsIntegrityChecks; config.System.EnableFsIntegrityChecks.Value = EnableFsIntegrityChecks;
config.System.DramSize.Value = DramSize; config.System.DramSize.Value = DramSize;
@@ -6,7 +6,6 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:ext="clr-namespace:Ryujinx.Ava.Common.Markup" xmlns:ext="clr-namespace:Ryujinx.Ava.Common.Markup"
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels" xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
xmlns:helper="clr-namespace:Ryujinx.Common.Helper;assembly=Ryujinx.Common"
mc:Ignorable="d" mc:Ignorable="d"
x:DataType="viewModels:SettingsViewModel"> x:DataType="viewModels:SettingsViewModel">
<Design.DataContext> <Design.DataContext>
@@ -70,7 +69,7 @@
</ComboBox> </ComboBox>
</StackPanel> </StackPanel>
<CheckBox IsChecked="{Binding UseHypervisor}" <CheckBox IsChecked="{Binding UseHypervisor}"
IsVisible="{x:Static helper:RunningPlatform.IsArmMac}" IsVisible="{Binding IsAppleSiliconMac}"
ToolTip.Tip="{ext:Locale UseHypervisorTooltip}"> ToolTip.Tip="{ext:Locale UseHypervisorTooltip}">
<TextBlock Text="{ext:Locale SettingsTabSystemUseHypervisor}" <TextBlock Text="{ext:Locale SettingsTabSystemUseHypervisor}"
ToolTip.Tip="{ext:Locale UseHypervisorTooltip}" /> ToolTip.Tip="{ext:Locale UseHypervisorTooltip}" />
@@ -8,7 +8,6 @@
xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia" xmlns:ui="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
xmlns:ext="clr-namespace:Ryujinx.Ava.Common.Markup" xmlns:ext="clr-namespace:Ryujinx.Ava.Common.Markup"
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels" xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
xmlns:helper="clr-namespace:Ryujinx.Common.Helper;assembly=Ryujinx.Common"
Design.Width="1000" Design.Width="1000"
mc:Ignorable="d" mc:Ignorable="d"
x:DataType="viewModels:SettingsViewModel"> x:DataType="viewModels:SettingsViewModel">
@@ -49,7 +48,7 @@
<ComboBoxItem IsEnabled="{Binding IsOpenGLAvailable}"> <ComboBoxItem IsEnabled="{Binding IsOpenGLAvailable}">
<TextBlock Text="OpenGL" /> <TextBlock Text="OpenGL" />
</ComboBoxItem> </ComboBoxItem>
<ComboBoxItem IsEnabled="{x:Static helper:RunningPlatform.IsArmMac}"> <ComboBoxItem IsEnabled="{Binding IsAppleSiliconMac}">
<TextBlock Text="Metal (ARM Mac only, Experimental)" /> <TextBlock Text="Metal (ARM Mac only, Experimental)" />
</ComboBoxItem> </ComboBoxItem>
</ComboBox> </ComboBox>
@@ -170,8 +170,7 @@
ToolTip.Tip="{ext:Locale TimeTooltip}" ToolTip.Tip="{ext:Locale TimeTooltip}"
Width="250"/> Width="250"/>
<DatePicker <DatePicker
VerticalAlignment="Center" VerticalAlignment="Center"
IsEnabled="{Binding !MatchSystemTime}"
SelectedDate="{Binding CurrentDate}" SelectedDate="{Binding CurrentDate}"
ToolTip.Tip="{ext:Locale TimeTooltip}" ToolTip.Tip="{ext:Locale TimeTooltip}"
Width="350" /> Width="350" />
@@ -182,21 +181,17 @@
<TimePicker <TimePicker
VerticalAlignment="Center" VerticalAlignment="Center"
ClockIdentifier="24HourClock" ClockIdentifier="24HourClock"
IsEnabled="{Binding !MatchSystemTime}"
SelectedTime="{Binding CurrentTime}" SelectedTime="{Binding CurrentTime}"
Width="350" Width="350"
ToolTip.Tip="{ext:Locale TimeTooltip}" /> ToolTip.Tip="{ext:Locale TimeTooltip}" />
</StackPanel> <Button
<StackPanel Orientation="Horizontal"> Margin="10, 0, 0, 0"
<TextBlock
VerticalAlignment="Center" VerticalAlignment="Center"
Text="{ext:Locale SettingsTabSystemSystemTimeMatch}" Click="MatchSystemTime_OnClick"
ToolTip.Tip="{ext:Locale MatchTimeTooltip}" Background="{DynamicResource SystemAccentColor}"
Width="250"/> ToolTip.Tip="{ext:Locale MatchTimeTooltip}">
<CheckBox <TextBlock Text="{ext:Locale SettingsTabSystemSystemTimeMatch}" />
VerticalAlignment="Center" </Button>
IsChecked="{Binding MatchSystemTime}"
ToolTip.Tip="{ext:Locale MatchTimeTooltip}"/>
</StackPanel> </StackPanel>
<Separator /> <Separator />
<StackPanel Margin="0,10,0,10" <StackPanel Margin="0,10,0,10"
@@ -34,5 +34,7 @@ namespace Ryujinx.Ava.UI.Views.Settings
ViewModel.ValidateAndSetTimeZone(timeZone.Location); ViewModel.ValidateAndSetTimeZone(timeZone.Location);
} }
} }
private void MatchSystemTime_OnClick(object sender, RoutedEventArgs e) => ViewModel.MatchSystemTime();
} }
} }
+1 -2
View File
@@ -10,7 +10,6 @@
xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels" xmlns:viewModels="clr-namespace:Ryujinx.Ava.UI.ViewModels"
xmlns:settings="clr-namespace:Ryujinx.Ava.UI.Views.Settings" xmlns:settings="clr-namespace:Ryujinx.Ava.UI.Views.Settings"
xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers" xmlns:helpers="clr-namespace:Ryujinx.Ava.UI.Helpers"
xmlns:helper="clr-namespace:Ryujinx.Common.Helper;assembly=Ryujinx.Common"
Width="1100" Width="1100"
Height="768" Height="768"
MinWidth="800" MinWidth="800"
@@ -114,7 +113,7 @@
Spacing="10" Spacing="10"
Orientation="Horizontal" Orientation="Horizontal"
HorizontalAlignment="Right" HorizontalAlignment="Right"
ReverseOrder="{x:Static helper:RunningPlatform.IsMacOS}"> ReverseOrder="{Binding IsMacOS}">
<Button <Button
Classes="accent" Classes="accent"
Content="{ext:Locale SettingsButtonOk}" Content="{ext:Locale SettingsButtonOk}"
@@ -7,8 +7,6 @@ using LibHac.Ns;
using LibHac.Tools.Fs; using LibHac.Tools.Fs;
using LibHac.Tools.FsSystem; using LibHac.Tools.FsSystem;
using LibHac.Tools.FsSystem.NcaUtils; using LibHac.Tools.FsSystem.NcaUtils;
using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.Utilities.Compat;
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;
@@ -23,30 +21,9 @@ namespace Ryujinx.Ava.Utilities.AppLibrary
public bool Favorite { get; set; } public bool Favorite { get; set; }
public byte[] Icon { get; set; } public byte[] Icon { get; set; }
public string Name { get; set; } = "Unknown"; public string Name { get; set; } = "Unknown";
public ulong Id { get; set; }
private ulong _id;
public ulong Id
{
get => _id;
set
{
_id = value;
PlayabilityStatus = CompatibilityCsv.GetStatus(Id);
}
}
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 bool HasPlayabilityInfo => PlayabilityStatus != null;
public string LocalizedStatus =>
PlayabilityStatus.HasValue
? LocaleManager.Instance[PlayabilityStatus!.Value]
: string.Empty;
public LocaleKeys? PlayabilityStatus { get; set; }
public int PlayerCount { get; set; } public int PlayerCount { get; set; }
public int GameCount { get; set; } public int GameCount { get; set; }
public TimeSpan TimePlayed { get; set; } public TimeSpan TimePlayed { get; set; }
@@ -47,6 +47,11 @@ namespace Ryujinx.Ava.Utilities.Compat
Logger.Debug?.Print(LogClass.UI, "Compatibility CSV loaded.", "LoadCompatibility"); Logger.Debug?.Print(LogClass.UI, "Compatibility CSV loaded.", "LoadCompatibility");
} }
public static void Unload()
{
_entries = null;
}
private static CompatibilityEntry[] _entries; private static CompatibilityEntry[] _entries;
public static CompatibilityEntry[] Entries public static CompatibilityEntry[] Entries
@@ -59,11 +64,6 @@ namespace Ryujinx.Ava.Utilities.Compat
return _entries; return _entries;
} }
} }
public static LocaleKeys? GetStatus(string titleId)
=> Entries.FirstOrDefault(x => x.TitleId.HasValue && x.TitleId.Value.EqualsIgnoreCase(titleId))?.Status;
public static LocaleKeys? GetStatus(ulong titleId) => GetStatus(titleId.ToString("X16"));
} }
public class CompatibilityEntry public class CompatibilityEntry
@@ -32,6 +32,8 @@ namespace Ryujinx.Ava.Utilities.Compat
contentDialog.Styles.Add(closeButtonParent); contentDialog.Styles.Add(closeButtonParent);
await ContentDialogHelper.ShowAsync(contentDialog); await ContentDialogHelper.ShowAsync(contentDialog);
CompatibilityCsv.Unload();
} }
public CompatibilityList() public CompatibilityList()
@@ -15,7 +15,7 @@ namespace Ryujinx.Ava.Utilities.Configuration
/// <summary> /// <summary>
/// The current version of the file format /// The current version of the file format
/// </summary> /// </summary>
public const int CurrentVersion = 63; public const int CurrentVersion = 62;
/// <summary> /// <summary>
/// Version of the configuration file format /// Version of the configuration file format
@@ -141,11 +141,6 @@ namespace Ryujinx.Ava.Utilities.Configuration
/// Change System Time Offset in seconds /// Change System Time Offset in seconds
/// </summary> /// </summary>
public long SystemTimeOffset { get; set; } public long SystemTimeOffset { get; set; }
/// <summary>
/// Instead of setting the time via configuration, use the values provided by the system.
/// </summary>
public bool MatchSystemTime { get; set; }
/// <summary> /// <summary>
/// Enables or disables Docked Mode /// Enables or disables Docked Mode
@@ -429,8 +429,7 @@ namespace Ryujinx.Ava.Utilities.Configuration
}; };
} }
}), }),
(62, static cff => cff.RainbowSpeed = 1f), (62, static cff => cff.RainbowSpeed = 1f)
(63, static cff => cff.MatchSystemTime = false)
); );
} }
} }
@@ -312,11 +312,6 @@ namespace Ryujinx.Ava.Utilities.Configuration
/// System Time Offset in Seconds /// System Time Offset in Seconds
/// </summary> /// </summary>
public ReactiveObject<long> SystemTimeOffset { get; private set; } public ReactiveObject<long> SystemTimeOffset { get; private set; }
/// <summary>
/// Instead of setting the time via configuration, use the values provided by the system.
/// </summary>
public ReactiveObject<bool> MatchSystemTime { get; private set; }
/// <summary> /// <summary>
/// Enables or disables Docked Mode /// Enables or disables Docked Mode
@@ -393,8 +388,6 @@ namespace Ryujinx.Ava.Utilities.Configuration
TimeZone.LogChangesToValue(nameof(TimeZone)); TimeZone.LogChangesToValue(nameof(TimeZone));
SystemTimeOffset = new ReactiveObject<long>(); SystemTimeOffset = new ReactiveObject<long>();
SystemTimeOffset.LogChangesToValue(nameof(SystemTimeOffset)); SystemTimeOffset.LogChangesToValue(nameof(SystemTimeOffset));
MatchSystemTime = new ReactiveObject<bool>();
MatchSystemTime.LogChangesToValue(nameof(MatchSystemTime));
EnableDockedMode = new ReactiveObject<bool>(); EnableDockedMode = new ReactiveObject<bool>();
EnableDockedMode.LogChangesToValue(nameof(EnableDockedMode)); EnableDockedMode.LogChangesToValue(nameof(EnableDockedMode));
EnablePtc = new ReactiveObject<bool>(); EnablePtc = new ReactiveObject<bool>();
+125 -15
View File
@@ -15,24 +15,21 @@ namespace Ryujinx.Ava.Utilities
"01007ef00011e000", "01007ef00011e000",
spec => spec.AddValueFormatter("IsHardMode", BreathOfTheWild_MasterMode) spec => spec.AddValueFormatter("IsHardMode", BreathOfTheWild_MasterMode)
) )
.AddSpec( .AddSpec( // Super Mario Odyssey
"0100f2c0115b6000",
spec => spec.AddValueFormatter("PlayerPosY", TearsOfTheKingdom_CurrentField))
.AddSpec(
"0100000000010000", "0100000000010000",
spec => spec =>
spec.AddValueFormatter("is_kids_mode", SuperMarioOdyssey_AssistMode) spec.AddValueFormatter("is_kids_mode", SuperMarioOdyssey_AssistMode)
) )
.AddSpec( .AddSpec( // Super Mario Odyssey (China)
"010075000ECBE000", "010075000ECBE000",
spec => spec =>
spec.AddValueFormatter("is_kids_mode", SuperMarioOdysseyChina_AssistMode) spec.AddValueFormatter("is_kids_mode", SuperMarioOdysseyChina_AssistMode)
) )
.AddSpec( .AddSpec( // Super Mario 3D World + Bowser's Fury
"010028600EBDA000", "010028600EBDA000",
spec => spec.AddValueFormatter("mode", SuperMario3DWorldOrBowsersFury) spec => spec.AddValueFormatter("mode", SuperMario3DWorldOrBowsersFury)
) )
.AddSpec( // Global & China IDs .AddSpec( // Mario Kart 8 Deluxe, Mario Kart 8 Deluxe (China)
["0100152000022000", "010075100E8EC000"], ["0100152000022000", "010075100E8EC000"],
spec => spec.AddValueFormatter("To", MarioKart8Deluxe_Mode) spec => spec.AddValueFormatter("To", MarioKart8Deluxe_Mode)
); );
@@ -40,14 +37,6 @@ namespace Ryujinx.Ava.Utilities
private static PlayReportFormattedValue BreathOfTheWild_MasterMode(ref PlayReportValue value) private static PlayReportFormattedValue BreathOfTheWild_MasterMode(ref PlayReportValue value)
=> value.BoxedValue is 1 ? "Playing Master Mode" : PlayReportFormattedValue.ForceReset; => value.BoxedValue is 1 ? "Playing Master Mode" : PlayReportFormattedValue.ForceReset;
private static PlayReportFormattedValue TearsOfTheKingdom_CurrentField(ref PlayReportValue value) =>
value.PackedValue.AsDouble() switch
{
> 800d => "Exploring the Sky Islands",
< -201d => "Exploring the Depths",
_ => "Roaming Hyrule"
};
private static PlayReportFormattedValue SuperMarioOdyssey_AssistMode(ref PlayReportValue value) private static PlayReportFormattedValue SuperMarioOdyssey_AssistMode(ref PlayReportValue value)
=> value.BoxedValue is 1 ? "Playing in Assist Mode" : "Playing in Regular Mode"; => value.BoxedValue is 1 ? "Playing in Assist Mode" : "Playing in Regular Mode";
@@ -85,4 +74,125 @@ namespace Ryujinx.Ava.Utilities
_ => PlayReportFormattedValue.ForceReset _ => PlayReportFormattedValue.ForceReset
}; };
} }
#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 { TitleIds = [titleId] }));
return this;
}
public PlayReportAnalyzer AddSpec(string titleId, Action<PlayReportGameSpec> transform)
{
_specs.Add(new PlayReportGameSpec { TitleIds = [titleId] }.Apply(transform));
return this;
}
public PlayReportAnalyzer AddSpec(IEnumerable<string> titleIds, Func<PlayReportGameSpec, PlayReportGameSpec> transform)
{
_specs.Add(transform(new PlayReportGameSpec { TitleIds = [..titleIds] }));
return this;
}
public PlayReportAnalyzer AddSpec(IEnumerable<string> titleIds, Action<PlayReportGameSpec> transform)
{
_specs.Add(new PlayReportGameSpec { TitleIds = [..titleIds] }.Apply(transform));
return this;
}
public PlayReportFormattedValue Run(string runningGameId, ApplicationMetadata appMeta, MessagePackObject playReport)
{
if (!playReport.IsDictionary)
return PlayReportFormattedValue.Unhandled;
if (!_specs.TryGetFirst(s => runningGameId.EqualsAnyIgnoreCase(s.TitleIds), out PlayReportGameSpec spec))
return PlayReportFormattedValue.Unhandled;
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 PlayReportFormattedValue.Unhandled;
}
}
public class PlayReportGameSpec
{
public required string[] TitleIds { 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 PlayReportFormattedValue
{
public bool Handled { get; private init; }
public bool Reset { get; private init; }
public string FormattedString { get; private init; }
public static implicit operator PlayReportFormattedValue(string formattedValue)
=> new() { Handled = true, FormattedString = formattedValue };
public static PlayReportFormattedValue Unhandled => default;
public static PlayReportFormattedValue ForceReset => new() { Handled = true, Reset = true };
public static PlayReportValueFormatter AlwaysResets = AlwaysResetsImpl;
private static PlayReportFormattedValue AlwaysResetsImpl(ref PlayReportValue _) => ForceReset;
}
public struct PlayReportValueFormatterSpec
{
public required int Priority { get; init; }
public required string ReportKey { get; init; }
public PlayReportValueFormatter ValueFormatter { get; init; }
}
public delegate PlayReportFormattedValue PlayReportValueFormatter(ref PlayReportValue value);
#endregion
} }
-129
View File
@@ -1,129 +0,0 @@
using Gommon;
using MsgPack;
using Ryujinx.Ava.Utilities.AppLibrary;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Ryujinx.Ava.Utilities
{
public class PlayReportAnalyzer
{
private readonly List<PlayReportGameSpec> _specs = [];
public PlayReportAnalyzer AddSpec(string titleId, Func<PlayReportGameSpec, PlayReportGameSpec> transform)
{
_specs.Add(transform(new PlayReportGameSpec { TitleIds = [titleId] }));
return this;
}
public PlayReportAnalyzer AddSpec(string titleId, Action<PlayReportGameSpec> transform)
{
_specs.Add(new PlayReportGameSpec { TitleIds = [titleId] }.Apply(transform));
return this;
}
public PlayReportAnalyzer AddSpec(IEnumerable<string> titleIds, Func<PlayReportGameSpec, PlayReportGameSpec> transform)
{
_specs.Add(transform(new PlayReportGameSpec { TitleIds = [..titleIds] }));
return this;
}
public PlayReportAnalyzer AddSpec(IEnumerable<string> titleIds, Action<PlayReportGameSpec> transform)
{
_specs.Add(new PlayReportGameSpec { TitleIds = [..titleIds] }.Apply(transform));
return this;
}
public PlayReportFormattedValue Run(string runningGameId, ApplicationMetadata appMeta, MessagePackObject playReport)
{
if (!playReport.IsDictionary)
return PlayReportFormattedValue.Unhandled;
if (!_specs.TryGetFirst(s => runningGameId.EqualsAnyIgnoreCase(s.TitleIds), out PlayReportGameSpec spec))
return PlayReportFormattedValue.Unhandled;
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,
PackedValue = valuePackObject
};
return formatSpec.ValueFormatter(ref value);
}
return PlayReportFormattedValue.Unhandled;
}
}
public class PlayReportGameSpec
{
public required string[] TitleIds { 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 readonly struct PlayReportValue
{
public ApplicationMetadata Application { get; init; }
public MessagePackObject PackedValue { get; init; }
public object BoxedValue => PackedValue.ToObject();
}
public struct PlayReportFormattedValue
{
public bool Handled { get; private init; }
public bool Reset { get; private init; }
public string FormattedString { get; private init; }
public static implicit operator PlayReportFormattedValue(string formattedValue)
=> new() { Handled = true, FormattedString = formattedValue };
public static PlayReportFormattedValue Unhandled => default;
public static PlayReportFormattedValue ForceReset => new() { Handled = true, Reset = true };
public static PlayReportValueFormatter AlwaysResets = AlwaysResetsImpl;
private static PlayReportFormattedValue AlwaysResetsImpl(ref PlayReportValue _) => ForceReset;
}
public struct PlayReportValueFormatterSpec
{
public required int Priority { get; init; }
public required string ReportKey { get; init; }
public PlayReportValueFormatter ValueFormatter { get; init; }
}
public delegate PlayReportFormattedValue PlayReportValueFormatter(ref PlayReportValue value);
}