diff --git a/Directory.Packages.props b/Directory.Packages.props
index fd61602a8..0029ecee2 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -44,7 +44,7 @@
-
+
@@ -59,4 +59,4 @@
-
\ No newline at end of file
+
diff --git a/src/Ryujinx.Common/Logging/Logger.cs b/src/Ryujinx.Common/Logging/Logger.cs
index 64a76a3e4..fea7895c4 100644
--- a/src/Ryujinx.Common/Logging/Logger.cs
+++ b/src/Ryujinx.Common/Logging/Logger.cs
@@ -12,6 +12,8 @@ namespace Ryujinx.Common.Logging
{
public static class Logger
{
+ public static readonly TextWriter WriterProxy = new TextWriterProxy();
+
private static readonly Stopwatch _time;
private static readonly bool[] _enabledClasses;
diff --git a/src/Ryujinx.Common/Logging/TextWriterProxy.cs b/src/Ryujinx.Common/Logging/TextWriterProxy.cs
new file mode 100644
index 000000000..c923983fa
--- /dev/null
+++ b/src/Ryujinx.Common/Logging/TextWriterProxy.cs
@@ -0,0 +1,21 @@
+using System;
+using System.IO;
+using System.Text;
+
+namespace Ryujinx.Common.Logging
+{
+ internal class TextWriterProxy : TextWriter
+ {
+ public override Encoding Encoding => Console.OutputEncoding;
+
+ public override void Write(string value)
+ {
+ if (value is null) return;
+
+ foreach (var line in value.Split(Console.Out.NewLine))
+ {
+ Logger.Info?.PrintMsg(LogClass.Application, line);
+ }
+ }
+ }
+}
diff --git a/src/Ryujinx/Program.cs b/src/Ryujinx/Program.cs
index 8d03f81da..3949bf6d8 100644
--- a/src/Ryujinx/Program.cs
+++ b/src/Ryujinx/Program.cs
@@ -98,7 +98,14 @@ namespace Ryujinx.Ava
return 0;
}
- Initialize(args);
+ try
+ {
+ Initialize(args);
+ }
+ catch
+ {
+ return 0;
+ }
LoggerAdapter.Register();
@@ -143,7 +150,7 @@ namespace Ryujinx.Ava
DiscordIntegrationModule.EmulatorStartedAt = Timestamps.Now;
// Parse arguments
- CommandLineState.ParseArguments(args);
+ RyujinxOptions.Read(args, out RyujinxOptions options);
if (OperatingSystem.IsMacOS())
{
@@ -163,7 +170,7 @@ namespace Ryujinx.Ava
AppDomain.CurrentDomain.ProcessExit += (_, _) => Exit();
// Setup base data directory.
- AppDataManager.Initialize(CommandLineState.BaseDirPathArg);
+ AppDataManager.Initialize(options.EmuDataBaseDirPath);
// Initialize the configuration.
ConfigurationState.Initialize();
@@ -196,9 +203,9 @@ namespace Ryujinx.Ava
}
}
- if (CommandLineState.LaunchPathArg != null)
+ if (options.LaunchPath != null)
{
- MainWindow.DeferLoadApplication(CommandLineState.LaunchPathArg, CommandLineState.LaunchApplicationId, CommandLineState.StartFullscreenArg);
+ MainWindow.DeferLoadApplication(options.LaunchPath, options.LaunchApplicationId, options.StartFullscreen);
}
}
@@ -222,7 +229,6 @@ namespace Ryujinx.Ava
public static void ReloadConfig(bool isRunGameWithCustomConfig = false)
{
-
string localConfigurationPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ReleaseInformation.ConfigName);
string appDataConfigurationPath = Path.Combine(AppDataManager.BaseDirPath, ReleaseInformation.ConfigName);
@@ -273,74 +279,50 @@ namespace Ryujinx.Ava
UseHardwareAcceleration = ConfigurationState.Instance.EnableHardwareAcceleration;
// Check if graphics backend was overridden
- if (CommandLineState.OverrideGraphicsBackend is not null)
- ConfigurationState.Instance.Graphics.GraphicsBackend.Value = CommandLineState.OverrideGraphicsBackend.ToLower() switch
- {
- "opengl" => GraphicsBackend.OpenGl,
- "vulkan" => GraphicsBackend.Vulkan,
- _ => ConfigurationState.Instance.Graphics.GraphicsBackend
- };
+ if (RyujinxOptions.Shared.GraphicsBackendOverride is not null)
+ ConfigurationState.Instance.Graphics.GraphicsBackend.Value =
+ RyujinxOptions.Shared.GraphicsBackendOverride.Value;
// Check if backend threading was overridden
- if (CommandLineState.OverrideBackendThreading is not null)
- ConfigurationState.Instance.Graphics.BackendThreading.Value = CommandLineState.OverrideBackendThreading.ToLower() switch
- {
- "auto" => BackendThreading.Auto,
- "off" => BackendThreading.Off,
- "on" => BackendThreading.On,
- _ => ConfigurationState.Instance.Graphics.BackendThreading
- };
+ if (RyujinxOptions.Shared.BackendThreadingOverride is not null)
+ ConfigurationState.Instance.Graphics.BackendThreading.Value =
+ RyujinxOptions.Shared.BackendThreadingOverride.Value;
+
+ if (RyujinxOptions.Shared.BackendThreadingOverrideAfterReboot is not null)
+ BackendThreadingArg = RyujinxOptions.Shared.BackendThreadingOverrideAfterReboot.Value.ToString();
- if (CommandLineState.OverrideBackendThreadingAfterReboot is not null)
- {
- BackendThreadingArg = CommandLineState.OverrideBackendThreadingAfterReboot;
- }
// Check if docked mode was overriden.
- if (CommandLineState.OverrideDockedMode.HasValue)
- ConfigurationState.Instance.System.EnableDockedMode.Value = CommandLineState.OverrideDockedMode.Value;
+ if (RyujinxOptions.Shared.DockedModeOverride.HasValue)
+ ConfigurationState.Instance.System.EnableDockedMode.Value =
+ RyujinxOptions.Shared.DockedModeOverride.Value;
// Check if HideCursor was overridden.
- if (CommandLineState.OverrideHideCursor is not null)
- ConfigurationState.Instance.HideCursor.Value = CommandLineState.OverrideHideCursor.ToLower() switch
- {
- "never" => HideCursorMode.Never,
- "onidle" => HideCursorMode.OnIdle,
- "always" => HideCursorMode.Always,
- _ => ConfigurationState.Instance.HideCursor,
- };
+ if (RyujinxOptions.Shared.HideCursorOverride is not null)
+ ConfigurationState.Instance.HideCursor.Value = RyujinxOptions.Shared.HideCursorOverride.Value;
// Check if memoryManagerMode was overridden.
- if (CommandLineState.OverrideMemoryManagerMode is not null)
- if (Enum.TryParse(CommandLineState.OverrideMemoryManagerMode, true, out MemoryManagerMode result))
- {
- ConfigurationState.Instance.System.MemoryManagerMode.Value = result;
- }
+ if (RyujinxOptions.Shared.MemoryManagerModeOverride is not null)
+ ConfigurationState.Instance.System.MemoryManagerMode.Value = RyujinxOptions.Shared.MemoryManagerModeOverride.Value;
// Check if PPTC was overridden.
- if (CommandLineState.OverridePPTC is not null)
- if (Enum.TryParse(CommandLineState.OverridePPTC, true, out bool result))
+ if (RyujinxOptions.Shared.PptcOverride is not null)
+ if (Enum.TryParse(RyujinxOptions.Shared.PptcOverride, true, out bool result))
{
ConfigurationState.Instance.System.EnablePtc.Value = result;
}
// Check if region was overridden.
- if (CommandLineState.OverrideSystemRegion is not null)
- if (Enum.TryParse(CommandLineState.OverrideSystemRegion, true, out Region result))
- {
- ConfigurationState.Instance.System.Region.Value = result;
- }
+ if (RyujinxOptions.Shared.SystemRegionOverride is not null)
+ ConfigurationState.Instance.System.Region.Value = RyujinxOptions.Shared.SystemRegionOverride.Value;
//Check if language was overridden.
- if (CommandLineState.OverrideSystemLanguage is not null)
- if (Enum.TryParse(CommandLineState.OverrideSystemLanguage, true, out Language result))
- {
- ConfigurationState.Instance.System.Language.Value = result;
- }
+ if (RyujinxOptions.Shared.SystemLanguageOverride is not null)
+ ConfigurationState.Instance.System.Language.Value = RyujinxOptions.Shared.SystemLanguageOverride.Value;
// Check if hardware-acceleration was overridden.
- if (CommandLineState.OverrideHardwareAcceleration != null)
- UseHardwareAcceleration = CommandLineState.OverrideHardwareAcceleration.Value;
+ if (RyujinxOptions.Shared.HardwareAccelerationOverride is not null)
+ UseHardwareAcceleration = RyujinxOptions.Shared.HardwareAccelerationOverride.Value;
}
internal static void PrintSystemInfo()
diff --git a/src/Ryujinx/Systems/Updater/Updater.cs b/src/Ryujinx/Systems/Updater/Updater.cs
index bc45f8ff6..2df71f4e4 100644
--- a/src/Ryujinx/Systems/Updater/Updater.cs
+++ b/src/Ryujinx/Systems/Updater/Updater.cs
@@ -181,7 +181,7 @@ namespace Ryujinx.Ava.Systems
if (shouldRestart)
{
- List arguments = CommandLineState.Arguments.ToList();
+ List arguments = RyujinxOptions.Shared.InputArguments.ToList();
string executableDirectory = AppDomain.CurrentDomain.BaseDirectory;
// On macOS we perform the update at relaunch.
@@ -218,7 +218,7 @@ namespace Ryujinx.Ava.Systems
WorkingDirectory = executableDirectory,
};
- foreach (string argument in CommandLineState.Arguments)
+ foreach (string argument in arguments)
{
processStart.ArgumentList.Add(argument);
}
diff --git a/src/Ryujinx/UI/RyujinxApp.axaml.cs b/src/Ryujinx/UI/RyujinxApp.axaml.cs
index c778f27fb..1fcf31ca3 100644
--- a/src/Ryujinx/UI/RyujinxApp.axaml.cs
+++ b/src/Ryujinx/UI/RyujinxApp.axaml.cs
@@ -95,7 +95,7 @@ namespace Ryujinx.Ava
if (result == UserResult.Yes)
{
- _ = Process.Start(Environment.ProcessPath!, CommandLineState.Arguments);
+ _ = Process.Start(Environment.ProcessPath!, RyujinxOptions.Shared.InputArguments);
desktop.Shutdown();
Environment.Exit(0);
}
diff --git a/src/Ryujinx/UI/ViewModels/AmiiboWindowViewModel.cs b/src/Ryujinx/UI/ViewModels/AmiiboWindowViewModel.cs
index 053972c2c..e668f2658 100644
--- a/src/Ryujinx/UI/ViewModels/AmiiboWindowViewModel.cs
+++ b/src/Ryujinx/UI/ViewModels/AmiiboWindowViewModel.cs
@@ -255,41 +255,27 @@ namespace Ryujinx.Ava.UI.ViewModels
return amiiboJson;
}
- private async Task ReadLocalJsonFileAsync()
+ private AmiiboJson? ReadLocalJsonFile()
{
bool isValid = false;
AmiiboJson amiiboJson = new();
try
{
- try
+ if (File.Exists(_amiiboJsonPath))
{
- if (File.Exists(_amiiboJsonPath))
- {
- isValid = TryGetAmiiboJson(await File.ReadAllTextAsync(_amiiboJsonPath), out amiiboJson);
- }
- }
- catch (Exception exception)
- {
- Logger.Warning?.Print(LogClass.Application, $"Unable to read data from '{_amiiboJsonPath}': {exception}");
- isValid = false;
- }
-
- if (!isValid)
- {
- return null;
+ isValid = TryGetAmiiboJson(File.ReadAllText(_amiiboJsonPath), out amiiboJson);
}
}
catch (Exception exception)
{
- if (!isValid)
- {
- Logger.Error?.Print(LogClass.Application, $"Couldn't get valid amiibo data: {exception}");
+ Logger.Warning?.Print(LogClass.Application, $"Unable to read data from '{_amiiboJsonPath}': {exception}");
+ isValid = false;
+ }
- // Neither local file is not valid JSON, close window.
- await ShowInfoDialog();
- Close();
- }
+ if (!isValid)
+ {
+ return null;
}
return amiiboJson;
@@ -299,8 +285,8 @@ namespace Ryujinx.Ava.UI.ViewModels
{
AmiiboJson? amiiboJson;
- if (CommandLineState.OnlyLocalAmiibo)
- amiiboJson = await ReadLocalJsonFileAsync();
+ if (RyujinxOptions.Shared.OnlyLocalAmiibo)
+ amiiboJson = ReadLocalJsonFile();
else
amiiboJson = await GetMostRecentAmiiboListOrDefaultJson();
diff --git a/src/Ryujinx/UI/Windows/MainWindow.axaml.cs b/src/Ryujinx/UI/Windows/MainWindow.axaml.cs
index e7934f38a..b3e2af754 100644
--- a/src/Ryujinx/UI/Windows/MainWindow.axaml.cs
+++ b/src/Ryujinx/UI/Windows/MainWindow.axaml.cs
@@ -139,16 +139,11 @@ namespace Ryujinx.Ava.UI.Windows
Executor.ExecuteBackgroundAsync(async () =>
{
await ShowIntelMacWarningAsync();
- if (CommandLineState.FirmwareToInstallPathArg.TryGet(out FilePath fwPath))
+ if (RyujinxOptions.Shared.FirmwareToInstallPath.TryGet(out FilePath fwPath))
{
- if (fwPath is { ExistsAsFile: true, Extension: "xci" or "zip" } || fwPath.ExistsAsDirectory)
- {
- await Dispatcher.UIThread.InvokeAsync(() =>
- ViewModel.HandleFirmwareInstallation(fwPath));
- CommandLineState.FirmwareToInstallPathArg = default;
- }
- else
- Logger.Notice.Print(LogClass.UI, "Invalid firmware type provided. Path must be a directory, or a .zip or .xci file.");
+ await Dispatcher.UIThread.InvokeAsync(() =>
+ ViewModel.HandleFirmwareInstallation(fwPath));
+ RyujinxOptions.Shared.FirmwareToInstallPath = default;
}
});
}
@@ -278,7 +273,7 @@ namespace Ryujinx.Ava.UI.Windows
// Consider removing this at some point in the future when we don't need to worry about old saves.
VirtualFileSystem.FixExtraData(LibHacHorizonManager.RyujinxClient);
- AccountManager = new AccountManager(LibHacHorizonManager.RyujinxClient, CommandLineState.Profile);
+ AccountManager = new AccountManager(LibHacHorizonManager.RyujinxClient, RyujinxOptions.Shared.Profile);
VirtualFileSystem.ReloadKeySet();
@@ -406,7 +401,7 @@ namespace Ryujinx.Ava.UI.Windows
await Dispatcher.UIThread.InvokeAsync(async () => await UserErrorDialog.ShowUserErrorDialog(UserError.NoKeys));
}
- if (!Updater.CanUpdate() || CommandLineState.HideAvailableUpdates)
+ if (!Updater.CanUpdate() || RyujinxOptions.Shared.HideAvailableUpdates)
return;
switch (ConfigurationState.Instance.UpdateCheckerType.Value)
diff --git a/src/Ryujinx/Utilities/CommandLineState.cs b/src/Ryujinx/Utilities/CommandLineState.cs
deleted file mode 100644
index a4e6cd811..000000000
--- a/src/Ryujinx/Utilities/CommandLineState.cs
+++ /dev/null
@@ -1,221 +0,0 @@
-using Gommon;
-using Ryujinx.Common.Logging;
-using System.Collections.Generic;
-
-namespace Ryujinx.Ava.Utilities
-{
- public static class CommandLineState
- {
- public static string[] Arguments { get; private set; }
- public static int CountArguments { get; private set; }
- public static bool? OverrideDockedMode { get; private set; }
- public static bool? OverrideHardwareAcceleration { get; private set; }
- public static string OverrideGraphicsBackend { get; private set; }
- public static string OverrideBackendThreading { get; private set; }
- public static string OverrideBackendThreadingAfterReboot { get; private set; }
- public static string OverridePPTC { get; private set; }
- public static string OverrideMemoryManagerMode { get; private set; }
- public static string OverrideSystemRegion { get; private set; }
- public static string OverrideSystemLanguage { get; private set; }
- public static string OverrideHideCursor { get; private set; }
- public static string BaseDirPathArg { get; private set; }
-
- public static string RenderDocCaptureTitleFormat { get; private set; } =
- "{EmuVersion}\n{GuestName} {GuestVersion} {GuestTitleId} {GuestArch}";
- public static Optional FirmwareToInstallPathArg { get; set; }
- public static string Profile { get; private set; }
- public static string LaunchPathArg { get; private set; }
- public static string LaunchApplicationId { get; private set; }
- public static bool StartFullscreenArg { get; private set; }
- public static bool HideAvailableUpdates { get; private set; }
- public static bool OnlyLocalAmiibo { get; private set; }
-
- public static void ParseArguments(string[] args)
- {
- List arguments = [];
-
- // Parse Arguments.
- for (int i = 0; i < args.Length; ++i)
- {
- string arg = args[i];
-
- if (arg.Contains('-') || arg.Contains("--"))
- {
- CountArguments++;
- }
-
- switch (arg)
- {
- case "-r":
- case "--root-data-dir":
- if (i + 1 >= args.Length)
- {
- Logger.Error?.Print(LogClass.Application, $"Invalid option '{arg}'");
-
- continue;
- }
-
- BaseDirPathArg = args[++i];
-
- arguments.Add(arg);
- arguments.Add(args[i]);
- break;
- case "-rdct":
- case "--rd-capture-title-format":
- if (i + 1 >= args.Length)
- {
- Logger.Error?.Print(LogClass.Application, $"Invalid option '{arg}'");
-
- continue;
- }
-
- RenderDocCaptureTitleFormat = args[++i];
-
- arguments.Add(arg);
- arguments.Add(args[i]);
- break;
- case "--install-firmware":
- if (i + 1 >= args.Length)
- {
- Logger.Error?.Print(LogClass.Application, $"Invalid option '{arg}'");
-
- continue;
- }
-
- FirmwareToInstallPathArg = new FilePath(args[++i]);
-
- arguments.Add(arg);
- arguments.Add(args[i]);
- break;
- case "-p":
- case "--profile":
- if (i + 1 >= args.Length)
- {
- Logger.Error?.Print(LogClass.Application, $"Invalid option '{arg}'");
-
- continue;
- }
-
- Profile = args[++i];
-
- arguments.Add(arg);
- arguments.Add(args[i]);
- break;
- case "-f":
- case "--fullscreen":
- StartFullscreenArg = true;
-
- arguments.Add(arg);
- break;
- case "-g":
- case "--graphics-backend":
- if (i + 1 >= args.Length)
- {
- Logger.Error?.Print(LogClass.Application, $"Invalid option '{arg}'");
-
- continue;
- }
-
- OverrideGraphicsBackend = args[++i];
- break;
- case "--backend-threading":
- if (i + 1 >= args.Length)
- {
- Logger.Error?.Print(LogClass.Application, $"Invalid option '{arg}'");
-
- continue;
- }
-
- OverrideBackendThreading = args[++i];
- break;
- case "--bt":
- if (i + 1 >= args.Length)
- {
- Logger.Error?.Print(LogClass.Application, $"Invalid option '{arg}'");
-
- continue;
- }
-
- OverrideBackendThreadingAfterReboot = args[++i];
- break;
- case "--pptc":
- if (i + 1 >= args.Length)
- {
- Logger.Error?.Print(LogClass.Application, $"Invalid option '{arg}'");
-
- continue;
- }
-
- OverridePPTC = args[++i];
- break;
- case "-la":
- case "--local-only-amiibo":
- OnlyLocalAmiibo = true;
- break;
- case "-m":
- case "--memory-manager-mode":
- if (i + 1 >= args.Length)
- {
- Logger.Error?.Print(LogClass.Application, $"Invalid option '{arg}'");
-
- continue;
- }
-
- OverrideMemoryManagerMode = args[++i];
- break;
- case "--system-region":
- if (i + 1 >= args.Length)
- {
- Logger.Error?.Print(LogClass.Application, $"Invalid option '{arg}'");
-
- continue;
- }
-
- OverrideSystemRegion = args[++i];
- break;
- case "--system-language":
- if (i + 1 >= args.Length)
- {
- Logger.Error?.Print(LogClass.Application, $"Invalid option '{arg}'");
-
- continue;
- }
-
- OverrideSystemLanguage = args[++i];
- break;
- case "-i":
- case "--application-id":
- LaunchApplicationId = args[++i];
- break;
- case "--docked-mode":
- OverrideDockedMode = true;
- break;
- case "--handheld-mode":
- OverrideDockedMode = false;
- break;
- case "--hide-cursor":
- if (i + 1 >= args.Length)
- {
- Logger.Error?.Print(LogClass.Application, $"Invalid option '{arg}'");
-
- continue;
- }
-
- OverrideHideCursor = args[++i];
- break;
- case "--hide-updates":
- HideAvailableUpdates = true;
- break;
- case "--software-gui":
- OverrideHardwareAcceleration = false;
- break;
- default:
- LaunchPathArg = arg;
- break;
- }
- }
-
- Arguments = arguments.ToArray();
- }
- }
-}
diff --git a/src/Ryujinx/Utilities/RyujinxOptions.Parse.cs b/src/Ryujinx/Utilities/RyujinxOptions.Parse.cs
new file mode 100644
index 000000000..d34b74a76
--- /dev/null
+++ b/src/Ryujinx/Utilities/RyujinxOptions.Parse.cs
@@ -0,0 +1,69 @@
+using CommandLine;
+using Gommon;
+using Ryujinx.Common.Logging;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Error = Gommon.Error;
+
+namespace Ryujinx.Ava.Utilities
+{
+ public partial class RyujinxOptions
+ {
+ public static RyujinxOptions Shared { get; private set; }
+
+ public static Result Read(string[] args, out RyujinxOptions options)
+ {
+ options = null;
+ args = PatchLegacyArgumentNames(args);
+
+ ParserResult parseResult =
+ Parser.ParseArguments(args);
+
+ if (parseResult is NotParsed notParsed)
+ {
+ if (notParsed.Errors.None(x =>
+ x.Tag is ErrorType.HelpRequestedError or ErrorType.HelpVerbRequestedError))
+ {
+ Logger.Notice.Print(LogClass.Application, "Failed to parse command-line arguments:");
+ foreach (var error in notParsed.Errors)
+ {
+ Logger.Notice.Print(LogClass.Application, $" - {error.Tag}");
+ }
+ }
+
+ return Result.Fail;
+ }
+
+ options = Shared = parseResult.Value;
+
+ return parseResult.Value.Init(args);
+ }
+
+ private static readonly Lazy _parser = new(() => new Parser(settings =>
+ {
+ settings.HelpWriter = Logger.WriterProxy;
+ settings.CaseInsensitiveEnumValues = true;
+ settings.CaseSensitive = false;
+ settings.MaximumDisplayWidth -= (int)(settings.MaximumDisplayWidth * 0.175);
+ }));
+
+ public static Parser Parser => _parser.Value;
+
+ private static readonly Dictionary _legacyArgs = new()
+ {
+ { "-rdct", "--rd-capture-title-format" },
+ { "-la", "--local-only-amiibo" }
+ };
+
+ public static string[] PatchLegacyArgumentNames(string[] args)
+ {
+ for (int i = 0; i < args.Length; i++)
+ args[i] = Patch(args[i]);
+
+ return args;
+
+ string Patch(string arg) => _legacyArgs.TryGetValue(arg, out string newArgName) ? newArgName : arg;
+ }
+ }
+}
diff --git a/src/Ryujinx/Utilities/RyujinxOptions.cs b/src/Ryujinx/Utilities/RyujinxOptions.cs
new file mode 100644
index 000000000..1c0f13dbd
--- /dev/null
+++ b/src/Ryujinx/Utilities/RyujinxOptions.cs
@@ -0,0 +1,130 @@
+using Avalonia.Controls;
+using CommandLine;
+using Gommon;
+using Ryujinx.Ava.Systems.Configuration.System;
+using Ryujinx.Common.Configuration;
+using Ryujinx.Common.Logging;
+
+namespace Ryujinx.Ava.Utilities
+{
+ public partial class RyujinxOptions
+ {
+ public string[] InputArguments { get; private set; }
+
+ public bool? DockedModeOverride { get; private set; }
+
+ public bool? HardwareAccelerationOverride { get; private set; }
+
+ public Optional FirmwareToInstallPath { get; set; }
+
+ // Ideally I'd use an enum parse, like --docked-mode=Handheld,
+ // but I want to maintain backwards compatibility with shortcuts made a long time ago, as best we can.
+ public Result Init(string[] args)
+ {
+ InputArguments = args;
+
+ { // Docked Mode Override
+ if (DockedMode && HandheldMode)
+ {
+ return Result.MessageFailure(
+ "Cannot be in both docked and handheld mode at the same time; choose only one.");
+ }
+
+ if (DockedMode) DockedModeOverride = true;
+ if (HandheldMode) DockedModeOverride = false;
+ }
+ { // Hardware Acceleration Override
+ if (SoftwareGui)
+ {
+ HardwareAccelerationOverride = false;
+ }
+ }
+
+ FirmwareToInstallPath = Optional.Of(FirmwareToInstallPathRaw)
+ .Convert(x => new FilePath(x))
+ .OnlyIf(fp =>
+ {
+ bool result = fp is { ExistsAsFile: true, Extension: "xci" or "zip" } || fp.ExistsAsDirectory;
+ if (!result)
+ {
+ Logger.Notice.PrintMsg(LogClass.UI,
+ "Invalid firmware type provided. Path must be a directory, or a .zip or .xci file.");
+ }
+
+ return result;
+ });
+
+ return Result.Success;
+ }
+
+ [Option("docked-mode", Required = false, Default = false, HelpText = "Launch the game in Docked mode.")]
+ public bool DockedMode { get; set; }
+
+ [Option("handheld-mode", Required = false, Default = false, HelpText = "Launch the game in Handheld mode.")]
+ public bool HandheldMode { get; set; }
+
+ [Option("software-gui", Required = false, Default = false,
+ HelpText = "Disables hardware-accelerated rendering for Avalonia. Required for launching with RenderDoc.")]
+ public bool SoftwareGui { get; set; }
+
+ [Option('g', "graphics-backend", Required = false, Default = null,
+ HelpText = "Select the Graphics backend to use when launching.")]
+ public GraphicsBackend? GraphicsBackendOverride { get; set; }
+
+ [Option("backend-threading", Required = false, Default = null,
+ HelpText = "Select the Graphics backend threading option to use when launching.")]
+ public BackendThreading? BackendThreadingOverride { get; set; }
+
+ [Option("bt", Required = false, Default = null, Hidden = true)]
+ public BackendThreading? BackendThreadingOverrideAfterReboot { get; set; }
+
+ [Option("pptc", Required = false, Default = null,
+ HelpText = "Enable/disable PPTC regardless of your settings when launching.")]
+ public string PptcOverride { get; set; }
+
+ [Option('m', "memory-manager-mode", Required = false, Default = null,
+ HelpText = "Select the memory manager mode to use when launching.")]
+ public MemoryManagerMode? MemoryManagerModeOverride { get; set; }
+
+ [Option("system-region", Required = false, Default = null,
+ HelpText = "Select the Region to use for the emulated Switch when launching.")]
+ public Region? SystemRegionOverride { get; set; }
+
+ [Option("system-language", Required = false, Default = null,
+ HelpText = "Select the Language to use for the emulated Switch when launching.")]
+ public Language? SystemLanguageOverride { get; set; }
+
+ [Option("hide-cursor", Required = false, Default = null,
+ HelpText = "Select the cursor hiding strategy to use when launching.")]
+ public HideCursorMode? HideCursorOverride { get; set; }
+
+ [Option('r', "root-data-dir", Required = false, Default = null,
+ HelpText = "Select the folder to use for all of your Ryujinx save data, configs, etc.")]
+ public string EmuDataBaseDirPath { get; set; }
+
+ [Option("rd-capture-title-format", Required = false,
+ HelpText =
+ "Set the format string used for RenderDoc Capture titles when using the Start/Stop Capture buttons in Ryujinx.",
+ Default = "{EmuVersion}\n{GuestName} {GuestVersion} {GuestTitleId} {GuestArch}")]
+ public string RenderDocCaptureTitleFormat { get; set; }
+
+ [Option("install-firmware", Required = false, Default = null, HelpText = "Specify a file path containing Switch firmware to install immediately after starting. Must be a directory or a .zip or .xci file.")]
+ public string FirmwareToInstallPathRaw { get; set; }
+
+ [Option('p', "profile", Required = false, Default = null, HelpText = "The profile name to open the application with. Defaults to your last used profile.")]
+ public string Profile { get; set; }
+ [Option('i', "application-id", Required = false, Default = null, HelpText = "Specify which application ID out of the specified content archive path to launch.")]
+ public string LaunchApplicationId { get; set; }
+ [Option('f', "fullscreen", Required = false, Default = false, HelpText = "Start the emulator in fullscreen mode.")]
+ public bool StartFullscreen { get; set; }
+ [Option("hide-updates", Required = false, Default = false, HelpText = "Hides update prompt/notification.")]
+ public bool HideAvailableUpdates { get; set; }
+ [Option("local-only-amiibo", Required = false, Default = false, HelpText = "Only use the local Amiibo cache; do not update it even if there is an update.")]
+ public bool OnlyLocalAmiibo { get; set; }
+
+ [Value(0, Default = null, Required = false,
+ HelpText =
+ "The Nintendo Switch application content archive to launch immediately after starting, if desired.")]
+ public string LaunchPath { get; set; }
+ }
+}
diff --git a/src/Ryujinx/Utilities/ShortcutHelper.cs b/src/Ryujinx/Utilities/ShortcutHelper.cs
index b92f97f55..4f3d2a7cf 100644
--- a/src/Ryujinx/Utilities/ShortcutHelper.cs
+++ b/src/Ryujinx/Utilities/ShortcutHelper.cs
@@ -126,10 +126,10 @@ namespace Ryujinx.Ava.Utilities
// args are first defined as a list, for easier adjustments in the future
List argsList = [];
- if (!string.IsNullOrEmpty(CommandLineState.BaseDirPathArg))
+ if (!string.IsNullOrEmpty(RyujinxOptions.Shared.EmuDataBaseDirPath))
{
argsList.Add("--root-data-dir");
- argsList.Add($"\"{CommandLineState.BaseDirPathArg}\"");
+ argsList.Add($"\"{RyujinxOptions.Shared.EmuDataBaseDirPath}\"");
}
if (!string.IsNullOrEmpty(config))
diff --git a/src/Ryujinx/Utilities/TitleHelper.cs b/src/Ryujinx/Utilities/TitleHelper.cs
index 3d1e53fd7..b2b3def80 100644
--- a/src/Ryujinx/Utilities/TitleHelper.cs
+++ b/src/Ryujinx/Utilities/TitleHelper.cs
@@ -34,7 +34,7 @@ namespace Ryujinx.Ava.Utilities
string titleIdSection = $"({activeProcess.ProgramIdText.ToUpper()})";
string titleArchSection = activeProcess.Is64Bit ? "(64-bit)" : "(32-bit)";
- return CommandLineState.RenderDocCaptureTitleFormat
+ return RyujinxOptions.Shared.RenderDocCaptureTitleFormat
.ReplaceIgnoreCase("{EmuVersion}", applicationVersion)
.ReplaceIgnoreCase("{GuestName}", titleNameSection)
.ReplaceIgnoreCase("{GuestVersion}", titleVersionSection)