mirror of
https://git.ryujinx.app/ryubing/ryujinx.git
synced 2026-01-11 20:10:38 +00:00
Replace CommandLineState with a more user-friendly CLI experience.
This commit is contained in:
parent
fa55608587
commit
8ccbf33327
13 changed files with 283 additions and 319 deletions
|
|
@ -44,7 +44,7 @@
|
|||
<PackageVersion Include="Ryujinx.LibHac" Version="0.21.0-alpha.126" />
|
||||
<PackageVersion Include="Ryujinx.UpdateClient" Version="1.0.44" />
|
||||
<PackageVersion Include="Ryujinx.Systems.Update.Common" Version="1.0.44" />
|
||||
<PackageVersion Include="Gommon" Version="2.8.0.1" />
|
||||
<PackageVersion Include="Gommon" Version="2.8.0.4" />
|
||||
<PackageVersion Include="securifybv.ShellLink" Version="0.1.0" />
|
||||
<PackageVersion Include="Sep" Version="0.11.1" />
|
||||
<PackageVersion Include="shaderc.net" Version="0.1.0" />
|
||||
|
|
@ -59,4 +59,4 @@
|
|||
<PackageVersion Include="System.Management" Version="9.0.2" />
|
||||
<PackageVersion Include="UnicornEngine.Unicorn" Version="2.0.2-rc1-fb78016" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
21
src/Ryujinx.Common/Logging/TextWriterProxy.cs
Normal file
21
src/Ryujinx.Common/Logging/TextWriterProxy.cs
Normal file
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -181,7 +181,7 @@ namespace Ryujinx.Ava.Systems
|
|||
|
||||
if (shouldRestart)
|
||||
{
|
||||
List<string> arguments = CommandLineState.Arguments.ToList();
|
||||
List<string> 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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -255,41 +255,27 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||
return amiiboJson;
|
||||
}
|
||||
|
||||
private async Task<AmiiboJson?> 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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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<FilePath> 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<string> 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
69
src/Ryujinx/Utilities/RyujinxOptions.Parse.cs
Normal file
69
src/Ryujinx/Utilities/RyujinxOptions.Parse.cs
Normal file
|
|
@ -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<RyujinxOptions> parseResult =
|
||||
Parser.ParseArguments<RyujinxOptions>(args);
|
||||
|
||||
if (parseResult is NotParsed<RyujinxOptions> 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> _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<string, string> _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;
|
||||
}
|
||||
}
|
||||
}
|
||||
130
src/Ryujinx/Utilities/RyujinxOptions.cs
Normal file
130
src/Ryujinx/Utilities/RyujinxOptions.cs
Normal file
|
|
@ -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<FilePath> 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; }
|
||||
}
|
||||
}
|
||||
|
|
@ -126,10 +126,10 @@ namespace Ryujinx.Ava.Utilities
|
|||
// args are first defined as a list, for easier adjustments in the future
|
||||
List<string> 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))
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Reference in a new issue