Fix ~3500 analyser issues

See merge request ryubing/ryujinx!44
This commit is contained in:
MrKev 2025-05-30 17:08:34 -05:00 committed by LotP
parent 417df486b1
commit 361d0c5632
622 changed files with 3080 additions and 2652 deletions

View file

@ -15,14 +15,14 @@ using Ryujinx.Audio.Integration;
using Ryujinx.Ava.Common;
using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.Input;
using Ryujinx.Ava.Systems.AppLibrary;
using Ryujinx.Ava.Systems.Configuration;
using Ryujinx.Ava.UI.Helpers;
using Ryujinx.Ava.UI.Models;
using Ryujinx.Ava.UI.Renderer;
using Ryujinx.Ava.UI.ViewModels;
using Ryujinx.Ava.UI.Windows;
using Ryujinx.Ava.Utilities;
using Ryujinx.Ava.Systems.AppLibrary;
using Ryujinx.Ava.Systems.Configuration;
using Ryujinx.Common;
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Configuration.Multiplayer;
@ -307,7 +307,7 @@ namespace Ryujinx.Ava.Systems
Device.VSyncMode = e.NewValue;
Device.UpdateVSyncInterval();
}
_renderer.Window?.ChangeVSyncMode(e.NewValue);
_viewModel.UpdateVSyncIntervalPicker();
@ -319,7 +319,7 @@ namespace Ryujinx.Ava.Systems
bool customVSyncIntervalEnabled = ConfigurationState.Instance.Graphics.EnableCustomVSyncInterval.Value;
UpdateVSyncMode(this, new ReactiveEventArgs<VSyncMode>(
oldVSyncMode,
oldVSyncMode,
oldVSyncMode.Next(customVSyncIntervalEnabled))
);
}
@ -480,7 +480,7 @@ namespace Ryujinx.Ava.Systems
_renderingThread.Start();
_viewModel.Volume = ConfigurationState.Instance.System.AudioVolume.Value;
Rainbow.Enable();
MainLoop();
@ -575,7 +575,7 @@ namespace Ryujinx.Ava.Systems
}
DiscordIntegrationModule.GuestAppStartedAt = null;
Rainbow.Disable();
Rainbow.Reset();
@ -610,7 +610,6 @@ namespace Ryujinx.Ava.Systems
if (Device.Processes != null)
MainWindowViewModel.UpdateGameMetadata(Device.Processes.ActiveApplication.ProgramIdText);
ConfigurationState.Instance.System.IgnoreMissingServices.Event -= UpdateIgnoreMissingServicesState;
ConfigurationState.Instance.Graphics.AspectRatio.Event -= UpdateAspectRatioState;
ConfigurationState.Instance.System.EnableDockedMode.Event -= UpdateDockedModeState;
@ -667,7 +666,7 @@ namespace Ryujinx.Ava.Systems
public async Task<bool> LoadGuestApplication(BlitStruct<ApplicationControlProperty>? customNacpData = null)
{
DiscordIntegrationModule.GuestAppStartedAt = Timestamps.Now;
InitEmulatedSwitch();
MainWindow.UpdateGraphicsConfig();
@ -751,7 +750,7 @@ namespace Ryujinx.Ava.Systems
{
romFsFiles = Directory.GetFiles(ApplicationPath, "*.romfs");
}
Logger.Notice.Print(LogClass.Application, $"Loading unpacked content archive from '{ApplicationPath}'.");
if (romFsFiles.Length > 0)
@ -780,7 +779,7 @@ namespace Ryujinx.Ava.Systems
else if (File.Exists(ApplicationPath))
{
Logger.Notice.Print(LogClass.Application, $"Loading content archive from '{ApplicationPath}'.");
switch (Path.GetExtension(ApplicationPath).ToLowerInvariant())
{
case ".xci":
@ -857,7 +856,7 @@ namespace Ryujinx.Ava.Systems
return false;
}
ApplicationLibrary.LoadAndSaveMetaData(Device.Processes.ActiveApplication.ProgramIdText,
appMetadata => appMetadata.UpdatePreGame()
);
@ -1077,7 +1076,7 @@ namespace Ryujinx.Ava.Systems
});
(RendererHost.EmbeddedWindow as EmbeddedWindowOpenGL)?.MakeCurrent(true);
// Reload settings when the game is turned off
// (resets custom settings if there were any)
Program.ReloadConfig();
@ -1160,7 +1159,7 @@ namespace Ryujinx.Ava.Systems
{
if (_displayCount is 0 && _renderer.ProgramCount is 0)
return;
// If there is a mismatch between total program compile and previous count
// this means new shaders have been compiled and should be displayed.
if (_renderer.ProgramCount != _previousCount)
@ -1233,7 +1232,7 @@ namespace Ryujinx.Ava.Systems
{
Device.ToggleTurbo();
}
switch (currentHotkeyState)
{
case KeyboardHotkeyState.ToggleVSyncMode:
@ -1250,6 +1249,7 @@ namespace Ryujinx.Ava.Systems
{
Device.ToggleTurbo();
}
break;
case KeyboardHotkeyState.Screenshot:
ScreenshotRequested = true;
@ -1266,6 +1266,7 @@ namespace Ryujinx.Ava.Systems
{
Pause();
}
break;
case KeyboardHotkeyState.ToggleMute:
if (Device.IsAudioMuted())

View file

@ -9,8 +9,8 @@ using LibHac.Tools.Fs;
using LibHac.Tools.FsSystem;
using LibHac.Tools.FsSystem.NcaUtils;
using Ryujinx.Ava.Common.Locale;
using Ryujinx.Ava.Utilities;
using Ryujinx.Ava.Systems.PlayReport;
using Ryujinx.Ava.Utilities;
using Ryujinx.Common.Logging;
using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.Loaders.Processes.Extensions;
@ -37,13 +37,13 @@ namespace Ryujinx.Ava.Systems.AppLibrary
_id = value;
Compatibility = CompatibilityDatabase.Find(value);
RichPresenceSpec = PlayReports.Analyzer.TryGetSpec(IdString, out GameSpec gameSpec)
? gameSpec
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 Version { get; set; } = "0";
public int PlayerCount { get; set; }
@ -53,7 +53,7 @@ namespace Ryujinx.Ava.Systems.AppLibrary
public bool HasRichPresenceAsset => DiscordIntegrationModule.HasAssetImage(IdString);
public bool HasDynamicRichPresenceSupport => RichPresenceSpec.HasValue;
public TimeSpan TimePlayed { get; set; }
public DateTime? LastPlayed { get; set; }
public string FileExtension { get; set; }
@ -70,22 +70,22 @@ namespace Ryujinx.Ava.Systems.AppLibrary
public string LastPlayedString => ValueFormatUtils.FormatDateTime(LastPlayed)?.Replace(" ", "\n");
public string FileSizeString => ValueFormatUtils.FormatFileSize(FileSize);
public Optional<CompatibilityEntry> Compatibility { get; private set; }
public bool HasPlayabilityInfo => Compatibility.HasValue;
public string LocalizedStatus => Compatibility.Convert(x => x.LocalizedStatus);
public bool HasCompatibilityLabels => !FormattedCompatibilityLabels.Equals(string.Empty);
public string FormattedCompatibilityLabels
=> Compatibility.Convert(x => x.FormattedIssueLabels).OrElse(string.Empty);
public LocaleKeys? PlayabilityStatus => Compatibility.Convert(x => x.Status).OrElse(null);
public string LocalizedStatusTooltip =>
Compatibility.Convert(x =>
Compatibility.Convert(x =>
#pragma warning disable CS8509 // It is exhaustive for all possible values this can contain.
LocaleManager.Instance[x.Status switch
#pragma warning restore CS8509
@ -97,7 +97,7 @@ namespace Ryujinx.Ava.Systems.AppLibrary
LocaleKeys.CompatibilityListNothing => LocaleKeys.CompatibilityListNothingTooltip,
}]
).OrElse(string.Empty);
[JsonIgnore] public string IdString => Id.ToString("x16");
@ -112,7 +112,7 @@ namespace Ryujinx.Ava.Systems.AppLibrary
Logger.Error?.Print(LogClass.Application, $"File \"{titleFilePath}\" does not exist.");
return string.Empty;
}
using FileStream file = new(titleFilePath, FileMode.Open, FileAccess.Read);
Nca mainNca = null;

View file

@ -12,9 +12,9 @@ using LibHac.Tools.Fs;
using LibHac.Tools.FsSystem;
using LibHac.Tools.FsSystem.NcaUtils;
using Ryujinx.Ava.Common.Models;
using Ryujinx.Ava.Utilities;
using Ryujinx.Ava.Systems.Configuration;
using Ryujinx.Ava.Systems.Configuration.System;
using Ryujinx.Ava.Utilities;
using Ryujinx.Common;
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Configuration.Multiplayer;
@ -151,7 +151,7 @@ namespace Ryujinx.Ava.Systems.AppLibrary
if (!DownloadableContents.Keys.FindFirst(x => x.TitleId == id).TryGet(out DownloadableContentModel dlcData))
return id.ToString("X16");
string name = Path.GetFileNameWithoutExtension(dlcData.FileName)!;
int idx = name.IndexOf('[');
if (idx != -1)
@ -167,28 +167,28 @@ namespace Ryujinx.Ava.Systems.AppLibrary
return appData.HasValue;
}
public bool FindUpdate(ulong id, out TitleUpdateModel foundData)
{
Gommon.Optional<TitleUpdateModel> appData =
Gommon.Optional<TitleUpdateModel> appData =
TitleUpdates.Keys.FindFirst(x => x.TitleId == id);
foundData = appData.HasValue ? appData.Value : null;
return appData.HasValue;
}
public TitleUpdateModel[] FindUpdatesFor(ulong id)
=> TitleUpdates.Keys.Where(x => x.TitleIdBase == (id & ~0x1FFFUL)).ToArray();
public (TitleUpdateModel TitleUpdate, bool IsSelected)[] FindUpdateConfigurationFor(ulong id)
=> TitleUpdates.Items.Where(x => x.TitleUpdate.TitleIdBase == (id & ~0x1FFFUL)).ToArray();
public DownloadableContentModel[] FindDlcsFor(ulong id)
=> DownloadableContents.Keys.Where(x => x.TitleIdBase == (id & ~0x1FFFUL)).ToArray();
public (DownloadableContentModel Dlc, bool IsEnabled)[] FindDlcConfigurationFor(ulong id)
=> DownloadableContents.Items.Where(x => x.Dlc.TitleIdBase == (id & ~0x1FFFUL)).ToArray();
public bool HasDlcs(ulong id)
=> DownloadableContents.Keys.Any(x => x.TitleIdBase == (id & ~0x1FFFUL));
@ -260,8 +260,8 @@ namespace Ryujinx.Ava.Systems.AppLibrary
}
}
return isExeFs
? GetApplicationFromExeFs(pfs, filePath)
return isExeFs
? GetApplicationFromExeFs(pfs, filePath)
: null;
}
@ -529,7 +529,7 @@ namespace Ryujinx.Ava.Systems.AppLibrary
if (data.Id != 0)
{
ApplicationMetadata appMetadata = LoadAndSaveMetaData(data.IdString, appMetadata =>
{
{
appMetadata.Title = data.Name;
// Only do the migration if time_played has a value and timespan_played hasn't been updated yet.
@ -550,10 +550,9 @@ namespace Ryujinx.Ava.Systems.AppLibrary
// Migration successful: deleting last_played from the metadata file.
appMetadata.LastPlayedOld = default;
}
}
});
data.Favorite = appMetadata.Favorite;
data.TimePlayed = appMetadata.TimePlayed;
data.LastPlayed = appMetadata.LastPlayed;
@ -788,7 +787,6 @@ namespace Ryujinx.Ava.Systems.AppLibrary
}
}
// Loops through applications list, creating a struct and then firing an event containing the struct for each application
foreach (string applicationPath in applicationPaths)
{
@ -848,9 +846,9 @@ namespace Ryujinx.Ava.Systems.AppLibrary
public Task RefreshTotalTimePlayedAsync()
{
TotalTimePlayed = Gommon.Optional<TimeSpan>.None;
TimeSpan temporary = TimeSpan.Zero;
foreach (var installedApplication in Applications.Items)
{
temporary += LoadAndSaveMetaData(installedApplication.IdString).TimePlayed;
@ -872,7 +870,7 @@ namespace Ryujinx.Ava.Systems.AppLibrary
{
ldnWebHost = SharedConstants.DefaultLanPlayWebHost;
}
using HttpClient httpClient = new();
string ldnGameDataArrayString = await httpClient.GetStringAsync($"https://{ldnWebHost}/api/public_games");
LdnGameData[] ldnGameDataArray = JsonHelper.Deserialize(ldnGameDataArrayString, _ldnDataSerializerContext.IEnumerableLdnGameData).ToArray();
@ -884,7 +882,7 @@ namespace Ryujinx.Ava.Systems.AppLibrary
Logger.Warning?.Print(LogClass.Application, $"Failed to fetch the public games JSON from the API. Player and game count in the game list will be unavailable.\n{ex.Message}");
}
}
LdnGameDataReceived?.Invoke(LdnGameDataReceivedEventArgs.Empty);
}
@ -1148,7 +1146,8 @@ namespace Ryujinx.Ava.Systems.AppLibrary
private bool AddAndAutoSelectUpdate(TitleUpdateModel update)
{
if (update == null) return false;
if (update == null)
return false;
DynamicData.Kernel.Optional<(TitleUpdateModel TitleUpdate, bool IsSelected)> currentlySelected = TitleUpdates.Items.FirstOrOptional(it =>
it.TitleUpdate.TitleIdBase == update.TitleIdBase && it.IsSelected);
@ -1157,7 +1156,7 @@ namespace Ryujinx.Ava.Systems.AppLibrary
currentlySelected.Value.TitleUpdate.Version < update.Version;
_titleUpdates.AddOrUpdate((update, shouldSelect));
if (currentlySelected.HasValue && shouldSelect)
{
_titleUpdates.AddOrUpdate((currentlySelected.Value.TitleUpdate, false));
@ -1557,7 +1556,7 @@ namespace Ryujinx.Ava.Systems.AppLibrary
if (!savedUpdateLookup.Contains(update))
{
bool shouldSelect = false;
if (!selectedUpdate.HasValue || selectedUpdate.Value.Item1.Version < update.Version)
if (!selectedUpdate.HasValue || selectedUpdate.Value.Update.Version < update.Version)
{
shouldSelect = true;
if (selectedUpdate.HasValue)

View file

@ -30,7 +30,7 @@ namespace Ryujinx.Ava.Systems.AppLibrary
public class Array
{
private readonly LdnGameData[] _ldnDatas;
internal Array(IEnumerable<LdnGameData> receivedData)
{
_ldnDatas = receivedData.ToArray();
@ -43,7 +43,7 @@ namespace Ryujinx.Ava.Systems.AppLibrary
public static class LdnGameDataHelper
{
public static LdnGameData.Array Where(this LdnGameData[] unfilteredDatas, ref ApplicationControlProperty acp)
public static LdnGameData.Array Where(this LdnGameData[] unfilteredDatas, ref ApplicationControlProperty acp)
=> LdnGameData.GetArrayForApp(unfilteredDatas, ref acp);
}
}

View file

@ -5,13 +5,13 @@ namespace Ryujinx.Ava.Systems.AppLibrary
public class LdnGameDataReceivedEventArgs : EventArgs
{
public static new readonly LdnGameDataReceivedEventArgs Empty = new(null);
public LdnGameDataReceivedEventArgs(LdnGameData[] ldnData)
{
LdnData = ldnData ?? [];
}
public LdnGameData[] LdnData { get; set; }
}
}

View file

@ -1,4 +1,4 @@
using Gommon;
using Gommon;
using Humanizer;
using nietras.SeparatedValues;
using Ryujinx.Ava.Common.Locale;
@ -28,26 +28,26 @@ namespace Ryujinx.Ava.Systems
.Enumerate(row => new CompatibilityEntry(ref columnIndices, row))
.OrderBy(it => it.GameName)
.ToArray();
Logger.Debug?.Print(LogClass.UI, "Compatibility CSV loaded.", "LoadCompatibility");
}
private static CompatibilityEntry[] _entries;
public static CompatibilityEntry[] Entries
public static CompatibilityEntry[] Entries
{
get
{
if (_entries == null)
Load();
return _entries;
}
}
public static CompatibilityEntry Find(string titleId)
=> Entries.FirstOrDefault(x => x.TitleId.HasValue && x.TitleId.Value.EqualsIgnoreCase(titleId));
public static CompatibilityEntry Find(ulong titleId)
=> Find(titleId.ToString("X16"));
}
@ -57,10 +57,10 @@ namespace Ryujinx.Ava.Systems
public CompatibilityEntry(ref ColumnIndices indices, SepReader.Row row)
{
string titleIdRow = ColStr(row[indices.TitleId]);
TitleId = !string.IsNullOrEmpty(titleIdRow)
? titleIdRow
TitleId = !string.IsNullOrEmpty(titleIdRow)
? titleIdRow
: default(Optional<string>);
GameName = ColStr(row[indices.GameName]);
Labels = ColStr(row[indices.Labels]).Split(';');
@ -78,10 +78,10 @@ namespace Ryujinx.Ava.Systems
LastUpdated = dt;
return;
string ColStr(SepReader.Col col) => col.ToString().Trim('"');
static string ColStr(SepReader.Col col) => col.ToString().Trim('"');
}
public string GameName { get; }
public Optional<string> TitleId { get; }
public string[] Labels { get; }
@ -97,12 +97,12 @@ namespace Ryujinx.Ava.Systems
LocaleKeys.CompatibilityListNothing => LocaleKeys.CompatibilityListNothingTooltip,
_ => null
};
public DateTime LastUpdated { get; }
public string LocalizedLastUpdated =>
LocaleManager.FormatDynamicValue(LocaleKeys.CompatibilityListLastUpdated, LastUpdated.Humanize());
public string LocalizedStatus => LocaleManager.Instance[Status!.Value];
public string LocalizedStatusDescription => LocaleManager.Instance[StatusDescription!.Value];
public string FormattedTitleId => TitleId
@ -117,9 +117,7 @@ namespace Ryujinx.Ava.Systems
new StringBuilder("CompatibilityEntry: {")
.Append($"{nameof(GameName)}=\"{GameName}\", ")
.Append($"{nameof(TitleId)}={TitleId}, ")
.Append($"{nameof(Labels)}={
Labels.FormatCollection(it => $"\"{it}\"", separator: ", ", prefix: "[", suffix: "]")
}, ")
.Append($"{nameof(Labels)}={Labels.FormatCollection(it => $"\"{it}\"", separator: ", ", prefix: "[", suffix: "]")}, ")
.Append($"{nameof(Status)}=\"{Status}\", ")
.Append($"{nameof(LastUpdated)}=\"{LastUpdated}\"")
.Append('}')
@ -169,7 +167,7 @@ namespace Ryujinx.Ava.Systems
_ => null
};
}
public struct ColumnIndices(Func<ReadOnlySpan<char>, int> getIndex)
{
private const string TitleIdCol = "\"title_id\"";
@ -177,7 +175,7 @@ namespace Ryujinx.Ava.Systems
private const string LabelsCol = "\"labels\"";
private const string StatusCol = "\"status\"";
private const string LastUpdatedCol = "\"last_updated\"";
public readonly int TitleId = getIndex(TitleIdCol);
public readonly int GameName = getIndex(GameNameCol);
public readonly int Labels = getIndex(LabelsCol);

View file

@ -111,7 +111,7 @@ namespace Ryujinx.Ava.Systems.Configuration
/// Enables printing FS access log messages
/// </summary>
public bool LoggingEnableFsAccessLog { get; set; }
/// <summary>
/// Enables log messages from Avalonia
/// </summary>
@ -146,7 +146,7 @@ namespace Ryujinx.Ava.Systems.Configuration
/// Change System Time Offset in seconds
/// </summary>
public long SystemTimeOffset { get; set; }
/// <summary>
/// Instead of setting the time via configuration, use the values provided by the system.
/// </summary>
@ -166,12 +166,12 @@ namespace Ryujinx.Ava.Systems.Configuration
/// DEPRECATED: Checks for updates when Ryujinx starts when enabled
/// </summary>
public bool CheckUpdatesOnStart { get; set; }
/// <summary>
/// Checks for updates when Ryujinx starts when enabled, either prompting when an update is found or just showing a notification.
/// </summary>
public UpdaterType UpdateCheckerType { get; set; }
/// <summary>
/// How the emulator should behave when you click off/on the window.
/// </summary>
@ -263,7 +263,7 @@ namespace Ryujinx.Ava.Systems.Configuration
/// Enables or disables low-power profiled translation cache persistency loading
/// </summary>
public bool EnableLowPowerPtc { get; set; }
/// <summary>
/// Clock tick scalar, in percent points (100 = 1.0).
/// </summary>
@ -398,7 +398,7 @@ namespace Ryujinx.Ava.Systems.Configuration
/// Enable or disable mouse support (Independent from controllers binding)
/// </summary>
public bool EnableMouse { get; set; }
/// <summary>
/// Enable/disable the ability to control Ryujinx when it's not the currently focused window.
/// </summary>
@ -413,7 +413,7 @@ namespace Ryujinx.Ava.Systems.Configuration
/// Input configurations
/// </summary>
public List<InputConfig> InputConfig { get; set; }
/// <summary>
/// The speed of spectrum cycling for the Rainbow LED feature.
/// </summary>
@ -458,17 +458,17 @@ namespace Ryujinx.Ava.Systems.Configuration
/// Uses Hypervisor over JIT if available
/// </summary>
public bool UseHypervisor { get; set; }
/// <summary>
/// Show toggles for dirty hacks in the UI.
/// </summary>
public bool ShowDirtyHacks { get; set; }
/// <summary>
/// The packed values of the enabled dirty hacks.
/// </summary>
public ulong[] DirtyHacks { get; set; }
/// <summary>
/// Loads a configuration file from disk
/// </summary>

View file

@ -33,18 +33,18 @@ namespace Ryujinx.Ava.Systems.Configuration
foreach ((int newVersion, Action<ConfigurationFileFormat> migratorFunction)
in _migrations.OrderBy(x => x.Key))
{
if (cff.Version >= newVersion)
if (cff.Version >= newVersion)
continue;
RyuLogger.Warning?.Print(LogClass.Application,
RyuLogger.Warning?.Print(LogClass.Application,
$"Outdated configuration version {cff.Version}, migrating to version {newVersion}.");
migratorFunction(cff);
configurationFileUpdated = true;
}
EnableDiscordIntegration.Value = cff.EnableDiscordIntegration;
UpdateCheckerType.Value = shouldLoadFromFile ? cff.UpdateCheckerType : UpdateCheckerType.Value; // Get from global config only
FocusLostActionType.Value = cff.FocusLostActionType;
@ -53,7 +53,7 @@ namespace Ryujinx.Ava.Systems.Configuration
ShowOldUI.Value = shouldLoadFromFile ? cff.ShowTitleBar : ShowOldUI.Value; // Get from global config only
EnableHardwareAcceleration.Value = shouldLoadFromFile ? cff.EnableHardwareAcceleration : EnableHardwareAcceleration.Value; // Get from global config only
HideCursor.Value = cff.HideCursor;
Logger.EnableFileLog.Value = cff.EnableFileLog;
Logger.EnableDebug.Value = cff.LoggingEnableDebug;
Logger.EnableStub.Value = cff.LoggingEnableStub;
@ -65,7 +65,7 @@ namespace Ryujinx.Ava.Systems.Configuration
Logger.EnableFsAccessLog.Value = cff.LoggingEnableFsAccessLog;
Logger.FilteredClasses.Value = cff.LoggingFilteredClasses;
Logger.GraphicsDebugLevel.Value = cff.LoggingGraphicsDebugLevel;
Graphics.ResScale.Value = cff.ResScale;
Graphics.ResScaleCustom.Value = cff.ResScaleCustom;
Graphics.MaxAnisotropy.Value = cff.MaxAnisotropy;
@ -84,7 +84,7 @@ namespace Ryujinx.Ava.Systems.Configuration
Graphics.EnableTextureRecompression.Value = cff.EnableTextureRecompression;
Graphics.EnableMacroHLE.Value = cff.EnableMacroHLE;
Graphics.EnableColorSpacePassthrough.Value = cff.EnableColorSpacePassthrough;
System.Language.Value = cff.SystemLanguage;
System.Region.Value = cff.SystemRegion;
System.TimeZone.Value = cff.SystemTimeZone;
@ -142,10 +142,9 @@ namespace Ryujinx.Ava.Systems.Configuration
UI.WindowStartup.WindowPositionY.Value = shouldLoadFromFile ? cff.WindowStartup.WindowPositionY : UI.WindowStartup.WindowPositionY.Value;
UI.WindowStartup.WindowMaximized.Value = shouldLoadFromFile ? cff.WindowStartup.WindowMaximized : UI.WindowStartup.WindowMaximized.Value;
Hid.EnableKeyboard.Value = cff.EnableKeyboard;
Hid.EnableMouse.Value = cff.EnableMouse;
Hid.DisableInputWhenOutOfFocus.Value = shouldLoadFromFile ? cff.DisableInputWhenOutOfFocus: Hid.DisableInputWhenOutOfFocus.Value; // Get from global config only
Hid.DisableInputWhenOutOfFocus.Value = shouldLoadFromFile ? cff.DisableInputWhenOutOfFocus : Hid.DisableInputWhenOutOfFocus.Value; // Get from global config only
Hid.Hotkeys.Value = shouldLoadFromFile ? cff.Hotkeys : Hid.Hotkeys.Value; // Get from global config only
Hid.InputConfig.Value = cff.InputConfig ?? [];
Hid.RainbowSpeed.Value = cff.RainbowSpeed;
@ -155,14 +154,14 @@ namespace Ryujinx.Ava.Systems.Configuration
Multiplayer.DisableP2p.Value = cff.MultiplayerDisableP2p;
Multiplayer.LdnPassphrase.Value = cff.MultiplayerLdnPassphrase;
Multiplayer.LdnServer.Value = cff.LdnServer;
{
Hacks.ShowDirtyHacks.Value = shouldLoadFromFile ? cff.ShowDirtyHacks: Hacks.ShowDirtyHacks.Value; // Get from global config only
DirtyHacks hacks = new (cff.DirtyHacks ?? []);
{
Hacks.ShowDirtyHacks.Value = shouldLoadFromFile ? cff.ShowDirtyHacks : Hacks.ShowDirtyHacks.Value; // Get from global config only
DirtyHacks hacks = new(cff.DirtyHacks ?? []);
Hacks.Xc2MenuSoftlockFix.Value = hacks.IsEnabled(DirtyHack.Xc2MenuSoftlockFix);
}
if (configurationFileUpdated)
@ -172,7 +171,7 @@ namespace Ryujinx.Ava.Systems.Configuration
RyuLogger.Notice.Print(LogClass.Application, $"Configuration file updated to version {ConfigurationFileFormat.CurrentVersion}");
}
}
private static readonly Dictionary<int, Action<ConfigurationFileFormat>> _migrations =
Collections.NewDictionary<int, Action<ConfigurationFileFormat>>(
(2, static cff => cff.SystemRegion = Region.USA),
@ -184,13 +183,15 @@ namespace Ryujinx.Ava.Systems.Configuration
{
cff.ColumnSort = new ColumnSort { SortColumnId = 0, SortAscending = false };
cff.Hotkeys = new KeyboardHotkeys { ToggleVSyncMode = Key.F1 };
}),
}
),
(10, static cff => cff.AudioBackend = AudioBackend.OpenAl),
(11, static cff =>
{
cff.ResScale = 1;
cff.ResScaleCustom = 1.0f;
}),
}
),
(12, static cff => cff.LoggingGraphicsDebugLevel = GraphicsDebugLevel.None),
// 13 -> LDN1
(14, static cff => cff.CheckUpdatesOnStart = true),
@ -205,7 +206,8 @@ namespace Ryujinx.Ava.Systems.Configuration
cff.MultiplayerMode = MultiplayerMode.Disabled;
cff.MultiplayerLanInterfaceId = "0";
}),
}
),
(22, static cff => cff.HideCursor = HideCursorMode.Never),
(24, static cff =>
{
@ -260,14 +262,17 @@ namespace Ryujinx.Ava.Systems.Configuration
},
}
];
}),
}
),
(26, static cff => cff.MemoryManagerMode = MemoryManagerMode.HostMappedUnsafe),
(27, static cff => cff.EnableMouse = false),
(29,
static cff =>
cff.Hotkeys = new KeyboardHotkeys
{
ToggleVSyncMode = Key.F1, Screenshot = Key.F8, ShowUI = Key.F4
ToggleVSyncMode = Key.F1,
Screenshot = Key.F8,
ShowUI = Key.F4
}),
(30, static cff =>
{
@ -275,10 +280,13 @@ namespace Ryujinx.Ava.Systems.Configuration
{
config.Rumble = new RumbleConfigController
{
EnableRumble = false, StrongRumble = 1f, WeakRumble = 1f,
EnableRumble = false,
StrongRumble = 1f,
WeakRumble = 1f,
};
}
}),
}
),
(31, static cff => cff.BackendThreading = BackendThreading.Auto),
(32, static cff => cff.Hotkeys = new KeyboardHotkeys
{
@ -299,7 +307,8 @@ namespace Ryujinx.Ava.Systems.Configuration
};
cff.AudioVolume = 1;
}),
}
),
(34, static cff => cff.EnableInternetAccess = false),
(35, static cff =>
{
@ -309,7 +318,8 @@ namespace Ryujinx.Ava.Systems.Configuration
config.RangeLeft = 1.0f;
config.RangeRight = 1.0f;
}
}),
}
),
(36, static cff => cff.LoggingEnableTrace = false),
(37, static cff => cff.ShowConsole = true),
@ -320,7 +330,8 @@ namespace Ryujinx.Ava.Systems.Configuration
cff.ShowNames = true;
cff.GridSize = 2;
cff.LanguageCode = "en_US";
}),
}
),
(39,
static cff => cff.Hotkeys = new KeyboardHotkeys
{
@ -353,7 +364,8 @@ namespace Ryujinx.Ava.Systems.Configuration
cff.AntiAliasing = AntiAliasing.None;
cff.ScalingFilter = ScalingFilter.Bilinear;
cff.ScalingFilterLevel = 80;
}),
}
),
(45,
static cff => cff.ShownFileTypes = new ShownFileTypes
{
@ -381,7 +393,8 @@ namespace Ryujinx.Ava.Systems.Configuration
{
AppDataManager.FixMacOSConfigurationFolders();
}
}),
}
),
(50, static cff => cff.EnableHardwareAcceleration = true),
(51, static cff => cff.RememberWindowState = true),
(52, static cff => cff.AutoloadDirs = []),
@ -410,7 +423,8 @@ namespace Ryujinx.Ava.Systems.Configuration
};
cff.CustomVSyncInterval = 120;
}),
}
),
// 58 migration accidentally got skipped, but it worked with no issues somehow lol
(59, static cff =>
{
@ -420,7 +434,8 @@ namespace Ryujinx.Ava.Systems.Configuration
// This was accidentally enabled by default when it was PRed. That is not what we want,
// so as a compromise users who want to use it will simply need to re-enable it once after updating.
cff.IgnoreApplet = false;
}),
}
),
(60, static cff => cff.StartNoUI = false),
(61, static cff =>
{
@ -434,7 +449,8 @@ namespace Ryujinx.Ava.Systems.Configuration
LedColor = new Color(255, 5, 1, 253).ToUInt32()
};
}
}),
}
),
(62, static cff => cff.RainbowSpeed = 1f),
(63, static cff => cff.MatchSystemTime = false),
(64, static cff => cff.LoggingEnableAvalonia = false),
@ -460,7 +476,8 @@ namespace Ryujinx.Ava.Systems.Configuration
TurboMode = Key.Unbound,
TurboModeWhileHeld = false
};
}),
}
),
(69, static cff => cff.SkipUserProfiles = false)
);
}

View file

@ -256,7 +256,7 @@ namespace Ryujinx.Ava.Systems.Configuration
/// Enables printing FS access log messages
/// </summary>
public ReactiveObject<bool> EnableFsAccessLog { get; private set; }
/// <summary>
/// Enables log messages from Avalonia
/// </summary>
@ -320,7 +320,7 @@ namespace Ryujinx.Ava.Systems.Configuration
/// System Time Offset in Seconds
/// </summary>
public ReactiveObject<long> SystemTimeOffset { get; private set; }
/// <summary>
/// Instead of setting the time via configuration, use the values provided by the system.
/// </summary>
@ -335,7 +335,7 @@ namespace Ryujinx.Ava.Systems.Configuration
/// Enables or disables persistent profiled translation cache
/// </summary>
public ReactiveObject<bool> EnablePtc { get; private set; }
/// <summary>
/// Clock tick scalar, in percent points (100 = 1.0).
/// </summary>
@ -389,7 +389,7 @@ namespace Ryujinx.Ava.Systems.Configuration
/// Enable or disable ignoring missing services
/// </summary>
public ReactiveObject<bool> IgnoreMissingServices { get; private set; }
/// <summary>
/// Ignore Controller Applet
/// </summary>
@ -423,7 +423,7 @@ namespace Ryujinx.Ava.Systems.Configuration
EnablePtc.LogChangesToValue(nameof(EnablePtc));
EnableLowPowerPtc = new ReactiveObject<bool>();
EnableLowPowerPtc.LogChangesToValue(nameof(EnableLowPowerPtc));
EnableLowPowerPtc.Event += (_, evnt)
EnableLowPowerPtc.Event += (_, evnt)
=> Optimizations.LowPower = evnt.NewValue;
TickScalar = new ReactiveObject<long>();
TickScalar.LogChangesToValue(nameof(TickScalar));
@ -473,7 +473,7 @@ namespace Ryujinx.Ava.Systems.Configuration
/// Enable or disable mouse support (Independent from controllers binding)
/// </summary>
public ReactiveObject<bool> EnableMouse { get; private set; }
/// <summary>
/// Enable/disable the ability to control Ryujinx when it's not the currently focused window.
/// </summary>
@ -490,7 +490,7 @@ namespace Ryujinx.Ava.Systems.Configuration
/// TODO: Implement a ReactiveList class.
/// </summary>
public ReactiveObject<List<InputConfig>> InputConfig { get; private set; }
/// <summary>
/// The speed of spectrum cycling for the Rainbow LED feature.
/// </summary>
@ -676,8 +676,8 @@ namespace Ryujinx.Ava.Systems.Configuration
public string GetLdnServer()
{
string ldnServer = LdnServer;
return string.IsNullOrEmpty(ldnServer)
? SharedConstants.DefaultLanPlayHost
return string.IsNullOrEmpty(ldnServer)
? SharedConstants.DefaultLanPlayHost
: ldnServer;
}
@ -701,9 +701,9 @@ namespace Ryujinx.Ava.Systems.Configuration
/// Show toggles for dirty hacks in the UI.
/// </summary>
public ReactiveObject<bool> ShowDirtyHacks { get; private set; }
public ReactiveObject<bool> Xc2MenuSoftlockFix { get; private set; }
public ReactiveObject<bool> DisableNifmIsAnyInternetRequestAccepted { get; private set; }
public HacksSection()
@ -717,15 +717,15 @@ namespace Ryujinx.Ava.Systems.Configuration
private void HackChanged(object sender, ReactiveEventArgs<bool> rxe)
{
if (!ShowDirtyHacks)
if (!ShowDirtyHacks)
return;
string newHacks = EnabledHacks.Select(x => x.Hack)
.JoinToString(", ");
if (newHacks != _lastHackCollection)
{
RyuLogger.Info?.Print(LogClass.Configuration,
RyuLogger.Info?.Print(LogClass.Configuration,
$"EnabledDirtyHacks set to: [{newHacks}]", "LogValueChange");
_lastHackCollection = newHacks;
@ -739,13 +739,13 @@ namespace Ryujinx.Ava.Systems.Configuration
get
{
List<EnabledDirtyHack> enabledHacks = [];
if (Xc2MenuSoftlockFix)
Apply(DirtyHack.Xc2MenuSoftlockFix);
if (DisableNifmIsAnyInternetRequestAccepted)
Apply(DirtyHack.NifmServiceDisableIsAnyInternetRequestAccepted);
return enabledHacks.ToArray();
void Apply(DirtyHack hack, int value = 0)
@ -790,7 +790,7 @@ namespace Ryujinx.Ava.Systems.Configuration
/// The Multiplayer section
/// </summary>
public MultiplayerSection Multiplayer { get; private set; }
/// <summary>
/// The Dirty Hacks section
/// </summary>
@ -800,12 +800,12 @@ namespace Ryujinx.Ava.Systems.Configuration
/// Enables or disables Discord Rich Presence
/// </summary>
public ReactiveObject<bool> EnableDiscordIntegration { get; private set; }
/// <summary>
/// Checks for updates when Ryujinx starts when enabled, either prompting when an update is found or just showing a notification.
/// </summary>
public ReactiveObject<UpdaterType> UpdateCheckerType { get; private set; }
/// <summary>
/// How the emulator should behave when you click off/on the window.
/// </summary>
@ -865,8 +865,8 @@ namespace Ryujinx.Ava.Systems.Configuration
System.EnablePtc,
System.TickScalar,
System.EnableInternetAccess,
System.EnableFsIntegrityChecks
? IntegrityCheckLevel.ErrorOnInvalid
System.EnableFsIntegrityChecks
? IntegrityCheckLevel.ErrorOnInvalid
: IntegrityCheckLevel.None,
System.FsGlobalAccessLogMode,
System.MatchSystemTime

View file

@ -13,7 +13,7 @@ namespace Ryujinx.Ava.Systems.Configuration
NRO,
NSO
}
public static class FileTypesExtensions
{
/// <summary>

View file

@ -10,23 +10,23 @@ namespace Ryujinx.Ava.Systems.Configuration
{
public static void Initialize()
{
ConfigurationState.Instance.Logger.EnableDebug.Event +=
ConfigurationState.Instance.Logger.EnableDebug.Event +=
(_, e) => Logger.SetEnable(LogLevel.Debug, e.NewValue);
ConfigurationState.Instance.Logger.EnableStub.Event +=
ConfigurationState.Instance.Logger.EnableStub.Event +=
(_, e) => Logger.SetEnable(LogLevel.Stub, e.NewValue);
ConfigurationState.Instance.Logger.EnableInfo.Event +=
ConfigurationState.Instance.Logger.EnableInfo.Event +=
(_, e) => Logger.SetEnable(LogLevel.Info, e.NewValue);
ConfigurationState.Instance.Logger.EnableWarn.Event +=
ConfigurationState.Instance.Logger.EnableWarn.Event +=
(_, e) => Logger.SetEnable(LogLevel.Warning, e.NewValue);
ConfigurationState.Instance.Logger.EnableError.Event +=
ConfigurationState.Instance.Logger.EnableError.Event +=
(_, e) => Logger.SetEnable(LogLevel.Error, e.NewValue);
ConfigurationState.Instance.Logger.EnableTrace.Event +=
ConfigurationState.Instance.Logger.EnableTrace.Event +=
(_, e) => Logger.SetEnable(LogLevel.Trace, e.NewValue);
ConfigurationState.Instance.Logger.EnableGuest.Event +=
ConfigurationState.Instance.Logger.EnableGuest.Event +=
(_, e) => Logger.SetEnable(LogLevel.Guest, e.NewValue);
ConfigurationState.Instance.Logger.EnableFsAccessLog.Event +=
(_, e) => Logger.SetEnable(LogLevel.AccessLog, e.NewValue);
ConfigurationState.Instance.Logger.FilteredClasses.Event += (_, e) =>
{
bool noFilter = e.NewValue.Length == 0;

View file

@ -14,7 +14,7 @@ namespace Ryujinx.Ava.Systems.Configuration.System
Korea,
Taiwan,
}
public static class RegionEnumHelper
{
public static Region ToUI(this HLE.HOS.SystemState.RegionCode hleRegion)

View file

@ -1,4 +1,4 @@
using Ryujinx.Common.Utilities;
using Ryujinx.Common.Utilities;
using System.Text.Json.Serialization;
namespace Ryujinx.Ava.Systems.Configuration.UI

View file

@ -1,4 +1,4 @@
using Ryujinx.Common.Utilities;
using Ryujinx.Common.Utilities;
using System.Text.Json.Serialization;
namespace Ryujinx.Ava.Systems.Configuration.UI

View file

@ -1,9 +1,9 @@
using DiscordRPC;
using Gommon;
using Ryujinx.Ava.Utilities;
using Ryujinx.Ava.Systems.AppLibrary;
using Ryujinx.Ava.Systems.Configuration;
using Ryujinx.Ava.Systems.PlayReport;
using Ryujinx.Ava.Utilities;
using Ryujinx.Common;
using Ryujinx.Common.Logging;
using Ryujinx.HLE;
@ -42,7 +42,8 @@ namespace Ryujinx.Ava.Systems
{
Assets = new Assets
{
LargeImageKey = "ryujinx", LargeImageText = TruncateToByteLength(_description)
LargeImageKey = "ryujinx",
LargeImageText = TruncateToByteLength(_description)
},
Details = "Main Menu",
State = "Idling",
@ -122,14 +123,18 @@ namespace Ryujinx.Ava.Systems
private static void HandlePlayReport(Horizon.Prepo.Types.PlayReport playReport)
{
if (_discordClient is null) return;
if (!TitleIDs.CurrentApplication.Value.HasValue) return;
if (_discordPresencePlaying is null) return;
if (_discordClient is null)
return;
if (!TitleIDs.CurrentApplication.Value.HasValue)
return;
if (_discordPresencePlaying is null)
return;
FormattedValue formattedValue =
PlayReports.Analyzer.Format(TitleIDs.CurrentApplication.Value, _currentApp, playReport);
if (!formattedValue.Handled) return;
if (!formattedValue.Handled)
return;
_discordPresencePlaying.Details = TruncateToByteLength(
formattedValue.Reset

View file

@ -1,4 +1,4 @@
using Gommon;
using Gommon;
using Ryujinx.Ava.Systems.AppLibrary;
using Ryujinx.Common.Logging;
using System;
@ -71,14 +71,12 @@ namespace Ryujinx.Ava.Systems.PlayReport
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(
$"Tried to add a {nameof(GameSpec)} with a non-hexadecimal title ID value. Input: '{tids.FormatCollection(
x => x,
separator: ", ",
prefix: "[",
suffix: "]"
)
}'");
)}'");
return this;
}
@ -95,14 +93,12 @@ namespace Ryujinx.Ava.Systems.PlayReport
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(
$"Tried to add a {nameof(GameSpec)} with a non-hexadecimal title ID value. Input: '{tids.FormatCollection(
x => x,
separator: ", ",
prefix: "[",
suffix: "]"
)
}'");
)}'");
return this;
}
@ -117,7 +113,6 @@ namespace Ryujinx.Ava.Systems.PlayReport
return this;
}
/// <summary>
/// Runs the configured <see cref="FormatterSpec"/> for the specified game title ID.
/// </summary>
@ -133,7 +128,7 @@ namespace Ryujinx.Ava.Systems.PlayReport
{
if (!playReport.ReportData.IsDictionary)
return FormattedValue.Unhandled;
if (!TryGetSpec(runningGameId, out GameSpec spec))
return FormattedValue.Unhandled;

View file

@ -1,4 +1,4 @@
namespace Ryujinx.Ava.Systems.PlayReport
namespace Ryujinx.Ava.Systems.PlayReport
{
/// <summary>
/// The delegate type that powers single value formatters.<br/>

View file

@ -1,4 +1,4 @@
using MsgPack;
using MsgPack;
using Ryujinx.Ava.Systems.AppLibrary;
using System.Collections.Generic;
@ -10,12 +10,12 @@ namespace Ryujinx.Ava.Systems.PlayReport
{
Matched = matched;
}
/// <summary>
/// The currently running application's <see cref="ApplicationMetadata"/>.
/// </summary>
public ApplicationMetadata Application { get; init; }
/// <summary>
/// The entire play report.
/// </summary>
@ -26,7 +26,7 @@ namespace Ryujinx.Ava.Systems.PlayReport
/// </summary>
public T Matched { get; init; }
}
/// <summary>
/// The input data to a <see cref="SingleValueFormatter"/>,
/// containing the currently running application's <see cref="ApplicationMetadata"/>,
@ -65,7 +65,7 @@ namespace Ryujinx.Ava.Systems.PlayReport
public SparseMultiValue(Dictionary<string, Value> matched) : base(matched)
{
}
public SparseMultiValue(Dictionary<string, MessagePackObject> matched) : base(Value.ConvertPackedObjectMap(matched))
{
}

View file

@ -1,4 +1,4 @@
using Gommon;
using Gommon;
using Humanizer;
using System;
using System.Buffers.Binary;
@ -19,7 +19,7 @@ namespace Ryujinx.Ava.Systems.PlayReport
< -201d => "Exploring the Depths",
_ => "Roaming Hyrule"
};
private static FormattedValue SkywardSwordHD_Rupees(SingleValue value)
=> "rupee".ToQuantity(value.Matched.IntValue);
@ -59,13 +59,13 @@ namespace Ryujinx.Ava.Systems.PlayReport
"Race" => "Racing",
_ => FormattedValue.ForceReset
};
private static FormattedValue PokemonSV(MultiValue values)
{
string playStatus = values.Matched[0].BoxedValue is 0 ? "Playing Alone" : "Playing in a group";
FormattedValue locations = values.Matched[1].ToString() switch
FormattedValue locations = values.Matched[1].ToString() switch
{
// Base Game Locations
"a_w01" => "South Area One",
@ -97,8 +97,8 @@ namespace Ryujinx.Ava.Systems.PlayReport
//TODO DLC Locations
_ => FormattedValue.ForceReset
};
return$"{playStatus} in {locations}";
return $"{playStatus} in {locations}";
}
private static FormattedValue SuperSmashBrosUltimate_Mode(SparseMultiValue values)
@ -121,7 +121,7 @@ namespace Ryujinx.Ava.Systems.PlayReport
if (values.Matched.ContainsKey("is_created"))
{
return "Edited a Custom Stage!";
return "Edited a Custom Stage!";
}
if (values.Matched.ContainsKey("adv_slot"))
@ -179,97 +179,97 @@ namespace Ryujinx.Ava.Systems.PlayReport
private static string SuperSmashBrosUltimate_Character(Value value) =>
BinaryPrimitives.ReverseEndianness(
BitConverter.ToInt64(((MsgPack.MessagePackExtendedTypeObject)value.BoxedValue).GetBody(), 0)) switch
{
0x0 => "Mario",
0x1 => "Donkey Kong",
0x2 => "Link",
0x3 => "Samus",
0x4 => "Dark Samus",
0x5 => "Yoshi",
0x6 => "Kirby",
0x7 => "Fox",
0x8 => "Pikachu",
0x9 => "Luigi",
0xA => "Ness",
0xB => "Captain Falcon",
0xC => "Jigglypuff",
0xD => "Peach",
0xE => "Daisy",
0xF => "Bowser",
0x10 => "Ice Climbers",
0x11 => "Sheik",
0x12 => "Zelda",
0x13 => "Dr. Mario",
0x14 => "Pichu",
0x15 => "Falco",
0x16 => "Marth",
0x17 => "Lucina",
0x18 => "Young Link",
0x19 => "Ganondorf",
0x1A => "Mewtwo",
0x1B => "Roy",
0x1C => "Chrom",
0x1D => "Mr Game & Watch",
0x1E => "Meta Knight",
0x1F => "Pit",
0x20 => "Dark Pit",
0x21 => "Zero Suit Samus",
0x22 => "Wario",
0x23 => "Snake",
0x24 => "Ike",
0x25 => "Pokémon Trainer",
0x26 => "Diddy Kong",
0x27 => "Lucas",
0x28 => "Sonic",
0x29 => "King Dedede",
0x2A => "Olimar",
0x2B => "Lucario",
0x2C => "R.O.B.",
0x2D => "Toon Link",
0x2E => "Wolf",
0x2F => "Villager",
0x30 => "Mega Man",
0x31 => "Wii Fit Trainer",
0x32 => "Rosalina & Luma",
0x33 => "Little Mac",
0x34 => "Greninja",
0x35 => "Palutena",
0x36 => "Pac-Man",
0x37 => "Robin",
0x38 => "Shulk",
0x39 => "Bowser Jr.",
0x3A => "Duck Hunt",
0x3B => "Ryu",
0x3C => "Ken",
0x3D => "Cloud",
0x3E => "Corrin",
0x3F => "Bayonetta",
0x40 => "Richter",
0x41 => "Inkling",
0x42 => "Ridley",
0x43 => "King K. Rool",
0x44 => "Simon",
0x45 => "Isabelle",
0x46 => "Incineroar",
0x47 => "Mii Brawler",
0x48 => "Mii Swordfighter",
0x49 => "Mii Gunner",
0x4A => "Piranha Plant",
0x4B => "Joker",
0x4C => "Hero",
0x4D => "Banjo",
0x4E => "Terry",
0x4F => "Byleth",
0x50 => "Min Min",
0x51 => "Steve",
0x52 => "Sephiroth",
0x53 => "Pyra/Mythra",
0x54 => "Kazuya",
0x55 => "Sora",
0xFE => "Random",
0xFF => "Scripted Entity",
_ => "Unknown"
};
{
0x0 => "Mario",
0x1 => "Donkey Kong",
0x2 => "Link",
0x3 => "Samus",
0x4 => "Dark Samus",
0x5 => "Yoshi",
0x6 => "Kirby",
0x7 => "Fox",
0x8 => "Pikachu",
0x9 => "Luigi",
0xA => "Ness",
0xB => "Captain Falcon",
0xC => "Jigglypuff",
0xD => "Peach",
0xE => "Daisy",
0xF => "Bowser",
0x10 => "Ice Climbers",
0x11 => "Sheik",
0x12 => "Zelda",
0x13 => "Dr. Mario",
0x14 => "Pichu",
0x15 => "Falco",
0x16 => "Marth",
0x17 => "Lucina",
0x18 => "Young Link",
0x19 => "Ganondorf",
0x1A => "Mewtwo",
0x1B => "Roy",
0x1C => "Chrom",
0x1D => "Mr Game & Watch",
0x1E => "Meta Knight",
0x1F => "Pit",
0x20 => "Dark Pit",
0x21 => "Zero Suit Samus",
0x22 => "Wario",
0x23 => "Snake",
0x24 => "Ike",
0x25 => "Pokémon Trainer",
0x26 => "Diddy Kong",
0x27 => "Lucas",
0x28 => "Sonic",
0x29 => "King Dedede",
0x2A => "Olimar",
0x2B => "Lucario",
0x2C => "R.O.B.",
0x2D => "Toon Link",
0x2E => "Wolf",
0x2F => "Villager",
0x30 => "Mega Man",
0x31 => "Wii Fit Trainer",
0x32 => "Rosalina & Luma",
0x33 => "Little Mac",
0x34 => "Greninja",
0x35 => "Palutena",
0x36 => "Pac-Man",
0x37 => "Robin",
0x38 => "Shulk",
0x39 => "Bowser Jr.",
0x3A => "Duck Hunt",
0x3B => "Ryu",
0x3C => "Ken",
0x3D => "Cloud",
0x3E => "Corrin",
0x3F => "Bayonetta",
0x40 => "Richter",
0x41 => "Inkling",
0x42 => "Ridley",
0x43 => "King K. Rool",
0x44 => "Simon",
0x45 => "Isabelle",
0x46 => "Incineroar",
0x47 => "Mii Brawler",
0x48 => "Mii Swordfighter",
0x49 => "Mii Gunner",
0x4A => "Piranha Plant",
0x4B => "Joker",
0x4C => "Hero",
0x4D => "Banjo",
0x4E => "Terry",
0x4F => "Byleth",
0x50 => "Min Min",
0x51 => "Steve",
0x52 => "Sephiroth",
0x53 => "Pyra/Mythra",
0x54 => "Kazuya",
0x55 => "Sora",
0xFE => "Random",
0xFF => "Scripted Entity",
_ => "Unknown"
};
private static string SuperSmashBrosUltimate_PlayerListing(SparseMultiValue values)
{
@ -295,16 +295,14 @@ namespace Ryujinx.Ava.Systems.PlayReport
players = players.OrderBy(p => p.Rank ?? int.MaxValue).ToList();
return players.Count > 4
? $"{players.Count} Players - {
players.Take(3)
? $"{players.Count} Players - {players.Take(3)
.Select(p => $"{p.Character}({p.PlayerNumber}){RankMedal(p.Rank)}")
.JoinToString(", ")
}"
.JoinToString(", ")}"
: players
.Select(p => $"{p.Character}({p.PlayerNumber}){RankMedal(p.Rank)}")
.JoinToString(", ");
string RankMedal(int? rank) => rank switch
static string RankMedal(int? rank) => rank switch
{
0 => "🥇",
1 => "🥈",
@ -371,7 +369,7 @@ namespace Ryujinx.Ava.Systems.PlayReport
"m_9417_e" => Playing("Zero Wing"),
#endregion
#region Nintendo 64
"n_1653_e" or "n_1653_p" => Playing("1080º ™ Snowboarding"),

View file

@ -1,4 +1,4 @@
using System;
using System;
namespace Ryujinx.Ava.Systems.PlayReport
{

View file

@ -1,4 +1,4 @@
using MsgPack;
using MsgPack;
using Ryujinx.Ava.Systems.AppLibrary;
using System;
using System.Collections.Generic;
@ -36,9 +36,8 @@ namespace Ryujinx.Ava.Systems.PlayReport
: null;
return this;
}
public List<FormatterSpecBase> ValueFormatters { get; } = [];
public List<FormatterSpecBase> ValueFormatters { get; } = [];
/// <summary>
/// Add a value formatter to the current <see cref="GameSpec"/>
@ -66,7 +65,9 @@ namespace Ryujinx.Ava.Systems.PlayReport
SingleValueFormatter valueFormatter
) => AddValueFormatter(new FormatterSpec
{
Priority = priority, ReportKeys = [reportKey], Formatter = valueFormatter
Priority = priority,
ReportKeys = [reportKey],
Formatter = valueFormatter
});
/// <summary>
@ -95,7 +96,9 @@ namespace Ryujinx.Ava.Systems.PlayReport
MultiValueFormatter valueFormatter
) => AddValueFormatter(new MultiFormatterSpec
{
Priority = priority, ReportKeys = reportKeys, Formatter = valueFormatter
Priority = priority,
ReportKeys = reportKeys,
Formatter = valueFormatter
});
/// <summary>
@ -130,7 +133,9 @@ namespace Ryujinx.Ava.Systems.PlayReport
SparseMultiValueFormatter valueFormatter
) => AddValueFormatter(new SparseMultiFormatterSpec
{
Priority = priority, ReportKeys = reportKeys, Formatter = valueFormatter
Priority = priority,
ReportKeys = reportKeys,
Formatter = valueFormatter
});
private GameSpec AddValueFormatter<T>(T formatterSpec) where T : FormatterSpecBase

View file

@ -1,4 +1,4 @@
using MsgPack;
using MsgPack;
using System;
using System.Collections.Generic;
using System.Linq;
@ -130,7 +130,7 @@ namespace Ryujinx.Ava.Systems.PlayReport
/// A delegate singleton you can use to always return <see cref="ForceReset"/> in a <see cref="MultiValueFormatter"/>.
/// </summary>
public static readonly MultiValueFormatter MultiAlwaysResets = _ => ForceReset;
/// <summary>
/// A delegate singleton you can use to always return <see cref="ForceReset"/> in a <see cref="SparseMultiValueFormatter"/>.
/// </summary>
@ -142,14 +142,14 @@ namespace Ryujinx.Ava.Systems.PlayReport
/// </summary>
/// <param name="formattedValue">The string to always return for this delegate instance.</param>
public static SingleValueFormatter SingleAlwaysReturns(string formattedValue) => _ => formattedValue;
/// <summary>
/// A delegate factory you can use to always return the specified
/// <paramref name="formattedValue"/> in a <see cref="MultiValueFormatter"/>.
/// </summary>
/// <param name="formattedValue">The string to always return for this delegate instance.</param>
public static MultiValueFormatter MultiAlwaysReturns(string formattedValue) => _ => formattedValue;
/// <summary>
/// A delegate factory you can use to always return the specified
/// <paramref name="formattedValue"/> in a <see cref="SparseMultiValueFormatter"/>.

View file

@ -15,7 +15,6 @@ namespace Ryujinx.Ava.Systems
private static readonly string _updateDir = Path.Combine(Path.GetTempPath(), "Ryujinx", "update");
public static void RebootAppWithGame(string gamePath, List<string> args)
{
_ = Reboot(gamePath, args);
@ -37,10 +36,9 @@ namespace Ryujinx.Ava.Systems
if (shouldRestart)
{
List<string> arguments = CommandLineState.Arguments.ToList();
string executableDirectory = AppDomain.CurrentDomain.BaseDirectory;
var dialogTask = taskDialog.ShowAsync(true);
_ = taskDialog.ShowAsync(true);
await Task.Delay(500);
// Find the process name.

View file

@ -32,9 +32,9 @@ namespace Ryujinx.Ava.Systems
internal static class Updater
{
private static ReleaseChannels.Channel? _currentReleaseChannel;
private const string GitHubApiUrl = "https://api.github.com";
private static readonly GithubReleasesJsonSerializerContext _serializerContext = new(JsonHelper.GetDefaultSerializerOptions());
private static readonly string _homeDir = AppDomain.CurrentDomain.BaseDirectory;
@ -43,10 +43,10 @@ namespace Ryujinx.Ava.Systems
private const int ConnectionCount = 4;
private static string _buildVer;
private static readonly string _platformExt = BuildPlatformExtension();
private static string _buildUrl;
private static long _buildSize;
private static bool _updateSuccessful;
@ -68,14 +68,14 @@ namespace Ryujinx.Ava.Systems
return default;
}
Logger.Info?.Print(LogClass.Application, "Checking for updates.");
// Get latest version number from GitHub API
try
{
using HttpClient jsonClient = ConstructHttpClient();
if (_currentReleaseChannel == null)
{
ReleaseChannels releaseChannels = await ReleaseInformation.GetReleaseChannelsAsync(jsonClient);
@ -84,7 +84,7 @@ namespace Ryujinx.Ava.Systems
? releaseChannels.Canary
: releaseChannels.Stable;
}
string fetchedJson = await jsonClient.GetStringAsync(_currentReleaseChannel.Value.GetLatestReleaseApiUrl());
GithubReleasesJsonResponse fetched = JsonHelper.Deserialize(fetchedJson, _serializerContext.GithubReleasesJsonResponse);
_buildVer = fetched.TagName;
@ -108,7 +108,7 @@ namespace Ryujinx.Ava.Systems
OpenHelper.OpenUrl(ReleaseInformation.GetChangelogForVersion(currentVersion, _currentReleaseChannel.Value));
}
}
Logger.Info?.Print(LogClass.Application, "Up to date.");
_running = false;
@ -134,7 +134,7 @@ namespace Ryujinx.Ava.Systems
OpenHelper.OpenUrl(ReleaseInformation.GetChangelogForVersion(currentVersion, _currentReleaseChannel.Value));
}
}
Logger.Info?.Print(LogClass.Application, "Up to date.");
_running = false;
@ -169,7 +169,7 @@ namespace Ryujinx.Ava.Systems
return (currentVersion, newVersion);
}
public static async Task BeginUpdateAsync(bool showVersionUpToDate = false)
{
if (_running)
@ -181,7 +181,8 @@ namespace Ryujinx.Ava.Systems
Optional<(Version, Version)> versionTuple = await CheckVersionAsync(showVersionUpToDate);
if (_running is false || !versionTuple.HasValue) return;
if (_running is false || !versionTuple.HasValue)
return;
(Version currentVersion, Version newVersion) = versionTuple.Value;
@ -198,7 +199,7 @@ namespace Ryujinx.Ava.Systems
OpenHelper.OpenUrl(ReleaseInformation.GetChangelogForVersion(currentVersion, _currentReleaseChannel.Value));
}
}
Logger.Info?.Print(LogClass.Application, "Up to date.");
_running = false;
@ -229,9 +230,9 @@ namespace Ryujinx.Ava.Systems
string newVersionString = ReleaseInformation.IsCanaryBuild
? $"Canary {currentVersion} -> Canary {newVersion}"
: $"{currentVersion} -> {newVersion}";
Logger.Info?.Print(LogClass.Application, $"Version found: {newVersionString}");
RequestUserToUpdate:
// Show a message asking the user if they want to update
UserResult shouldUpdate = await ContentDialogHelper.CreateUpdaterChoiceDialog(
@ -442,8 +443,8 @@ namespace Ryujinx.Ava.Systems
// On macOS, ensure that we remove the quarantine bit to prevent Gatekeeper from blocking execution.
if (OperatingSystem.IsMacOS())
{
using Process xattrProcess = Process.Start("xattr",
[ "-d", "com.apple.quarantine", updateFile ]);
using Process xattrProcess = Process.Start("xattr",
["-d", "com.apple.quarantine", updateFile]);
xattrProcess.WaitForExit();
}
@ -491,7 +492,7 @@ namespace Ryujinx.Ava.Systems
using HttpResponseMessage response = client.GetAsync(downloadUrl, HttpCompletionOption.ResponseHeadersRead).Result;
using Stream remoteFileStream = response.Content.ReadAsStreamAsync().Result;
using Stream updateFileStream = File.Open(updateFile, FileMode.Create);
using FileStream updateFileStream = File.Open(updateFile, FileMode.Create);
long totalBytes = response.Content.Headers.ContentLength.Value;
long bytesWritten = 0;
@ -538,7 +539,7 @@ namespace Ryujinx.Ava.Systems
[SupportedOSPlatform("macos")]
private static void ExtractTarGzipFile(TaskDialog taskDialog, string archivePath, string outputDirectoryPath)
{
using Stream inStream = File.OpenRead(archivePath);
using FileStream inStream = File.OpenRead(archivePath);
using GZipInputStream gzipStream = new(inStream);
using TarInputStream tarStream = new(gzipStream, Encoding.ASCII);
@ -781,7 +782,7 @@ namespace Ryujinx.Ava.Systems
public static void CleanupUpdate() =>
Directory.GetFiles(_homeDir, "*.ryuold", SearchOption.AllDirectories)
.ForEach(File.Delete);
private static string BuildPlatformExtension()
{
if (RunningPlatform.IsMacOS)
@ -800,7 +801,7 @@ namespace Ryujinx.Ava.Systems
Architecture.X64 => "x64",
_ => throw new PlatformNotSupportedException($"Unknown architecture {Enum.GetName(RunningPlatform.Architecture)}."),
};
string fileExtension = RunningPlatform.CurrentOS switch
#pragma warning restore CS8509
{