mirror of
https://git.ryujinx.app/ryubing/ryujinx.git
synced 2026-03-06 14:41:08 +00:00
Compare commits
2 Commits
Canary-1.3
...
feature/co
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e4abc3a960 | ||
|
|
8ccbf33327 |
@@ -44,7 +44,7 @@
|
|||||||
<PackageVersion Include="Ryujinx.LibHac" Version="0.21.0-alpha.126" />
|
<PackageVersion Include="Ryujinx.LibHac" Version="0.21.0-alpha.126" />
|
||||||
<PackageVersion Include="Ryujinx.UpdateClient" Version="1.0.44" />
|
<PackageVersion Include="Ryujinx.UpdateClient" Version="1.0.44" />
|
||||||
<PackageVersion Include="Ryujinx.Systems.Update.Common" 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="securifybv.ShellLink" Version="0.1.0" />
|
||||||
<PackageVersion Include="Sep" Version="0.11.1" />
|
<PackageVersion Include="Sep" Version="0.11.1" />
|
||||||
<PackageVersion Include="shaderc.net" Version="0.1.0" />
|
<PackageVersion Include="shaderc.net" Version="0.1.0" />
|
||||||
@@ -59,4 +59,4 @@
|
|||||||
<PackageVersion Include="System.Management" Version="9.0.2" />
|
<PackageVersion Include="System.Management" Version="9.0.2" />
|
||||||
<PackageVersion Include="UnicornEngine.Unicorn" Version="2.0.2-rc1-fb78016" />
|
<PackageVersion Include="UnicornEngine.Unicorn" Version="2.0.2-rc1-fb78016" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -12,6 +12,8 @@ namespace Ryujinx.Common.Logging
|
|||||||
{
|
{
|
||||||
public static class Logger
|
public static class Logger
|
||||||
{
|
{
|
||||||
|
public static readonly TextWriter WriterProxy = new TextWriterProxy();
|
||||||
|
|
||||||
private static readonly Stopwatch _time;
|
private static readonly Stopwatch _time;
|
||||||
|
|
||||||
private static readonly bool[] _enabledClasses;
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
using Avalonia;
|
using Avalonia;
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
|
using CommandLine;
|
||||||
using DiscordRPC;
|
using DiscordRPC;
|
||||||
using Gommon;
|
using Gommon;
|
||||||
using Projektanker.Icons.Avalonia;
|
using Projektanker.Icons.Avalonia;
|
||||||
@@ -78,28 +79,38 @@ namespace Ryujinx.Ava
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool noGuiArg = ConsumeCommandLineArgument(ref args, "--no-gui") || ConsumeCommandLineArgument(ref args, "nogui");
|
PreviewerDetached = true;
|
||||||
bool coreDumpArg = ConsumeCommandLineArgument(ref args, "--core-dumps");
|
|
||||||
|
if (ConsumeCommandLineArgument(ref args, "--no-gui")
|
||||||
|
|| ConsumeCommandLineArgument(ref args, "nogui"))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
HeadlessRyujinx.Entrypoint(args);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Logger.Error?.PrintMsg(LogClass.Application, $"Exception occurred when running Headless Ryujinx: {e.Message}\n{e.StackTrace}");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Initialize(args, out RyujinxOptions options))
|
||||||
|
{
|
||||||
|
Logger.Flush();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Ryujinx causes core dumps on Linux when it exits "uncleanly", eg. through an unhandled exception.
|
// TODO: Ryujinx causes core dumps on Linux when it exits "uncleanly", eg. through an unhandled exception.
|
||||||
// This is undesirable and causes very odd behavior during development (the process stops responding,
|
// This is undesirable and causes very odd behavior during development (the process stops responding,
|
||||||
// the .NET debugger freezes or suddenly detaches, /tmp/ gets filled etc.), unless explicitly requested by the user.
|
// the .NET debugger freezes or suddenly detaches, /tmp/ gets filled etc.), unless explicitly requested by the user.
|
||||||
// This needs to be investigated, but calling prctl() is better than modifying system-wide settings or leaving this be.
|
// This needs to be investigated, but calling prctl() is better than modifying system-wide settings or leaving this be.
|
||||||
if (!coreDumpArg)
|
if (!options.CoreDumpsEnabled)
|
||||||
{
|
{
|
||||||
OsUtils.SetCoreDumpable(false);
|
OsUtils.SetCoreDumpable(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
PreviewerDetached = true;
|
|
||||||
|
|
||||||
if (noGuiArg)
|
|
||||||
{
|
|
||||||
HeadlessRyujinx.Entrypoint(args);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Initialize(args);
|
|
||||||
|
|
||||||
LoggerAdapter.Register();
|
LoggerAdapter.Register();
|
||||||
|
|
||||||
IconProvider.Current
|
IconProvider.Current
|
||||||
@@ -137,13 +148,14 @@ namespace Ryujinx.Ava
|
|||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void Initialize(string[] args)
|
private static Result Initialize(string[] args, out RyujinxOptions options)
|
||||||
{
|
{
|
||||||
// Ensure Discord presence timestamp begins at the absolute start of when Ryujinx is launched
|
// Ensure Discord presence timestamp begins at the absolute start of when Ryujinx is launched
|
||||||
DiscordIntegrationModule.EmulatorStartedAt = Timestamps.Now;
|
DiscordIntegrationModule.EmulatorStartedAt = Timestamps.Now;
|
||||||
|
|
||||||
// Parse arguments
|
// Parse arguments
|
||||||
CommandLineState.ParseArguments(args);
|
Result res = RyujinxOptions.Read(args, out options);
|
||||||
|
if (!res) return res;
|
||||||
|
|
||||||
if (OperatingSystem.IsMacOS())
|
if (OperatingSystem.IsMacOS())
|
||||||
{
|
{
|
||||||
@@ -163,7 +175,7 @@ namespace Ryujinx.Ava
|
|||||||
AppDomain.CurrentDomain.ProcessExit += (_, _) => Exit();
|
AppDomain.CurrentDomain.ProcessExit += (_, _) => Exit();
|
||||||
|
|
||||||
// Setup base data directory.
|
// Setup base data directory.
|
||||||
AppDataManager.Initialize(CommandLineState.BaseDirPathArg);
|
AppDataManager.Initialize(options.EmuDataBaseDirPath);
|
||||||
|
|
||||||
// Initialize the configuration.
|
// Initialize the configuration.
|
||||||
ConfigurationState.Initialize();
|
ConfigurationState.Initialize();
|
||||||
@@ -196,10 +208,12 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return Result.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GetDirGameUserConfig(string gameId, bool changeFolderForGame = false)
|
public static string GetDirGameUserConfig(string gameId, bool changeFolderForGame = false)
|
||||||
@@ -222,7 +236,6 @@ namespace Ryujinx.Ava
|
|||||||
|
|
||||||
public static void ReloadConfig(bool isRunGameWithCustomConfig = false)
|
public static void ReloadConfig(bool isRunGameWithCustomConfig = false)
|
||||||
{
|
{
|
||||||
|
|
||||||
string localConfigurationPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ReleaseInformation.ConfigName);
|
string localConfigurationPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, ReleaseInformation.ConfigName);
|
||||||
string appDataConfigurationPath = Path.Combine(AppDataManager.BaseDirPath, ReleaseInformation.ConfigName);
|
string appDataConfigurationPath = Path.Combine(AppDataManager.BaseDirPath, ReleaseInformation.ConfigName);
|
||||||
|
|
||||||
@@ -273,74 +286,50 @@ namespace Ryujinx.Ava
|
|||||||
UseHardwareAcceleration = ConfigurationState.Instance.EnableHardwareAcceleration;
|
UseHardwareAcceleration = ConfigurationState.Instance.EnableHardwareAcceleration;
|
||||||
|
|
||||||
// Check if graphics backend was overridden
|
// Check if graphics backend was overridden
|
||||||
if (CommandLineState.OverrideGraphicsBackend is not null)
|
if (RyujinxOptions.Shared.GraphicsBackendOverride is not null)
|
||||||
ConfigurationState.Instance.Graphics.GraphicsBackend.Value = CommandLineState.OverrideGraphicsBackend.ToLower() switch
|
ConfigurationState.Instance.Graphics.GraphicsBackend.Value =
|
||||||
{
|
RyujinxOptions.Shared.GraphicsBackendOverride.Value;
|
||||||
"opengl" => GraphicsBackend.OpenGl,
|
|
||||||
"vulkan" => GraphicsBackend.Vulkan,
|
|
||||||
_ => ConfigurationState.Instance.Graphics.GraphicsBackend
|
|
||||||
};
|
|
||||||
|
|
||||||
// Check if backend threading was overridden
|
// Check if backend threading was overridden
|
||||||
if (CommandLineState.OverrideBackendThreading is not null)
|
if (RyujinxOptions.Shared.BackendThreadingOverride is not null)
|
||||||
ConfigurationState.Instance.Graphics.BackendThreading.Value = CommandLineState.OverrideBackendThreading.ToLower() switch
|
ConfigurationState.Instance.Graphics.BackendThreading.Value =
|
||||||
{
|
RyujinxOptions.Shared.BackendThreadingOverride.Value;
|
||||||
"auto" => BackendThreading.Auto,
|
|
||||||
"off" => BackendThreading.Off,
|
if (RyujinxOptions.Shared.BackendThreadingOverrideAfterReboot is not null)
|
||||||
"on" => BackendThreading.On,
|
BackendThreadingArg = RyujinxOptions.Shared.BackendThreadingOverrideAfterReboot.Value.ToString();
|
||||||
_ => ConfigurationState.Instance.Graphics.BackendThreading
|
|
||||||
};
|
|
||||||
|
|
||||||
if (CommandLineState.OverrideBackendThreadingAfterReboot is not null)
|
|
||||||
{
|
|
||||||
BackendThreadingArg = CommandLineState.OverrideBackendThreadingAfterReboot;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if docked mode was overriden.
|
// Check if docked mode was overriden.
|
||||||
if (CommandLineState.OverrideDockedMode.HasValue)
|
if (RyujinxOptions.Shared.DockedModeOverride.HasValue)
|
||||||
ConfigurationState.Instance.System.EnableDockedMode.Value = CommandLineState.OverrideDockedMode.Value;
|
ConfigurationState.Instance.System.EnableDockedMode.Value =
|
||||||
|
RyujinxOptions.Shared.DockedModeOverride.Value;
|
||||||
|
|
||||||
// Check if HideCursor was overridden.
|
// Check if HideCursor was overridden.
|
||||||
if (CommandLineState.OverrideHideCursor is not null)
|
if (RyujinxOptions.Shared.HideCursorOverride is not null)
|
||||||
ConfigurationState.Instance.HideCursor.Value = CommandLineState.OverrideHideCursor.ToLower() switch
|
ConfigurationState.Instance.HideCursor.Value = RyujinxOptions.Shared.HideCursorOverride.Value;
|
||||||
{
|
|
||||||
"never" => HideCursorMode.Never,
|
|
||||||
"onidle" => HideCursorMode.OnIdle,
|
|
||||||
"always" => HideCursorMode.Always,
|
|
||||||
_ => ConfigurationState.Instance.HideCursor,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Check if memoryManagerMode was overridden.
|
// Check if memoryManagerMode was overridden.
|
||||||
if (CommandLineState.OverrideMemoryManagerMode is not null)
|
if (RyujinxOptions.Shared.MemoryManagerModeOverride is not null)
|
||||||
if (Enum.TryParse(CommandLineState.OverrideMemoryManagerMode, true, out MemoryManagerMode result))
|
ConfigurationState.Instance.System.MemoryManagerMode.Value = RyujinxOptions.Shared.MemoryManagerModeOverride.Value;
|
||||||
{
|
|
||||||
ConfigurationState.Instance.System.MemoryManagerMode.Value = result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if PPTC was overridden.
|
// Check if PPTC was overridden.
|
||||||
if (CommandLineState.OverridePPTC is not null)
|
if (RyujinxOptions.Shared.PptcOverride is not null)
|
||||||
if (Enum.TryParse(CommandLineState.OverridePPTC, true, out bool result))
|
if (Enum.TryParse(RyujinxOptions.Shared.PptcOverride, true, out bool result))
|
||||||
{
|
{
|
||||||
ConfigurationState.Instance.System.EnablePtc.Value = result;
|
ConfigurationState.Instance.System.EnablePtc.Value = result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if region was overridden.
|
// Check if region was overridden.
|
||||||
if (CommandLineState.OverrideSystemRegion is not null)
|
if (RyujinxOptions.Shared.SystemRegionOverride is not null)
|
||||||
if (Enum.TryParse(CommandLineState.OverrideSystemRegion, true, out Region result))
|
ConfigurationState.Instance.System.Region.Value = RyujinxOptions.Shared.SystemRegionOverride.Value;
|
||||||
{
|
|
||||||
ConfigurationState.Instance.System.Region.Value = result;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Check if language was overridden.
|
//Check if language was overridden.
|
||||||
if (CommandLineState.OverrideSystemLanguage is not null)
|
if (RyujinxOptions.Shared.SystemLanguageOverride is not null)
|
||||||
if (Enum.TryParse(CommandLineState.OverrideSystemLanguage, true, out Language result))
|
ConfigurationState.Instance.System.Language.Value = RyujinxOptions.Shared.SystemLanguageOverride.Value;
|
||||||
{
|
|
||||||
ConfigurationState.Instance.System.Language.Value = result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if hardware-acceleration was overridden.
|
// Check if hardware-acceleration was overridden.
|
||||||
if (CommandLineState.OverrideHardwareAcceleration != null)
|
if (RyujinxOptions.Shared.HardwareAccelerationOverride is not null)
|
||||||
UseHardwareAcceleration = CommandLineState.OverrideHardwareAcceleration.Value;
|
UseHardwareAcceleration = RyujinxOptions.Shared.HardwareAccelerationOverride.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void PrintSystemInfo()
|
internal static void PrintSystemInfo()
|
||||||
|
|||||||
@@ -181,7 +181,7 @@ namespace Ryujinx.Ava.Systems
|
|||||||
|
|
||||||
if (shouldRestart)
|
if (shouldRestart)
|
||||||
{
|
{
|
||||||
List<string> arguments = CommandLineState.Arguments.ToList();
|
List<string> arguments = RyujinxOptions.Shared.InputArguments.ToList();
|
||||||
string executableDirectory = AppDomain.CurrentDomain.BaseDirectory;
|
string executableDirectory = AppDomain.CurrentDomain.BaseDirectory;
|
||||||
|
|
||||||
// On macOS we perform the update at relaunch.
|
// On macOS we perform the update at relaunch.
|
||||||
@@ -218,7 +218,7 @@ namespace Ryujinx.Ava.Systems
|
|||||||
WorkingDirectory = executableDirectory,
|
WorkingDirectory = executableDirectory,
|
||||||
};
|
};
|
||||||
|
|
||||||
foreach (string argument in CommandLineState.Arguments)
|
foreach (string argument in arguments)
|
||||||
{
|
{
|
||||||
processStart.ArgumentList.Add(argument);
|
processStart.ArgumentList.Add(argument);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ namespace Ryujinx.Ava
|
|||||||
|
|
||||||
if (result == UserResult.Yes)
|
if (result == UserResult.Yes)
|
||||||
{
|
{
|
||||||
_ = Process.Start(Environment.ProcessPath!, CommandLineState.Arguments);
|
_ = Process.Start(Environment.ProcessPath!, RyujinxOptions.Shared.InputArguments);
|
||||||
desktop.Shutdown();
|
desktop.Shutdown();
|
||||||
Environment.Exit(0);
|
Environment.Exit(0);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -255,41 +255,27 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
return amiiboJson;
|
return amiiboJson;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<AmiiboJson?> ReadLocalJsonFileAsync()
|
private AmiiboJson? ReadLocalJsonFile()
|
||||||
{
|
{
|
||||||
bool isValid = false;
|
bool isValid = false;
|
||||||
AmiiboJson amiiboJson = new();
|
AmiiboJson amiiboJson = new();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
try
|
if (File.Exists(_amiiboJsonPath))
|
||||||
{
|
{
|
||||||
if (File.Exists(_amiiboJsonPath))
|
isValid = TryGetAmiiboJson(File.ReadAllText(_amiiboJsonPath), out amiiboJson);
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception exception)
|
catch (Exception exception)
|
||||||
{
|
{
|
||||||
if (!isValid)
|
Logger.Warning?.Print(LogClass.Application, $"Unable to read data from '{_amiiboJsonPath}': {exception}");
|
||||||
{
|
isValid = false;
|
||||||
Logger.Error?.Print(LogClass.Application, $"Couldn't get valid amiibo data: {exception}");
|
}
|
||||||
|
|
||||||
// Neither local file is not valid JSON, close window.
|
if (!isValid)
|
||||||
await ShowInfoDialog();
|
{
|
||||||
Close();
|
return null;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return amiiboJson;
|
return amiiboJson;
|
||||||
@@ -299,8 +285,8 @@ namespace Ryujinx.Ava.UI.ViewModels
|
|||||||
{
|
{
|
||||||
AmiiboJson? amiiboJson;
|
AmiiboJson? amiiboJson;
|
||||||
|
|
||||||
if (CommandLineState.OnlyLocalAmiibo)
|
if (RyujinxOptions.Shared.OnlyLocalAmiibo)
|
||||||
amiiboJson = await ReadLocalJsonFileAsync();
|
amiiboJson = ReadLocalJsonFile();
|
||||||
else
|
else
|
||||||
amiiboJson = await GetMostRecentAmiiboListOrDefaultJson();
|
amiiboJson = await GetMostRecentAmiiboListOrDefaultJson();
|
||||||
|
|
||||||
|
|||||||
@@ -139,16 +139,11 @@ namespace Ryujinx.Ava.UI.Windows
|
|||||||
Executor.ExecuteBackgroundAsync(async () =>
|
Executor.ExecuteBackgroundAsync(async () =>
|
||||||
{
|
{
|
||||||
await ShowIntelMacWarningAsync();
|
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));
|
||||||
await Dispatcher.UIThread.InvokeAsync(() =>
|
RyujinxOptions.Shared.FirmwareToInstallPath = default;
|
||||||
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.");
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -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.
|
// Consider removing this at some point in the future when we don't need to worry about old saves.
|
||||||
VirtualFileSystem.FixExtraData(LibHacHorizonManager.RyujinxClient);
|
VirtualFileSystem.FixExtraData(LibHacHorizonManager.RyujinxClient);
|
||||||
|
|
||||||
AccountManager = new AccountManager(LibHacHorizonManager.RyujinxClient, CommandLineState.Profile);
|
AccountManager = new AccountManager(LibHacHorizonManager.RyujinxClient, RyujinxOptions.Shared.Profile);
|
||||||
|
|
||||||
VirtualFileSystem.ReloadKeySet();
|
VirtualFileSystem.ReloadKeySet();
|
||||||
|
|
||||||
@@ -406,7 +401,7 @@ namespace Ryujinx.Ava.UI.Windows
|
|||||||
await Dispatcher.UIThread.InvokeAsync(async () => await UserErrorDialog.ShowUserErrorDialog(UserError.NoKeys));
|
await Dispatcher.UIThread.InvokeAsync(async () => await UserErrorDialog.ShowUserErrorDialog(UserError.NoKeys));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Updater.CanUpdate() || CommandLineState.HideAvailableUpdates)
|
if (!Updater.CanUpdate() || RyujinxOptions.Shared.HideAvailableUpdates)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
switch (ConfigurationState.Instance.UpdateCheckerType.Value)
|
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
58
src/Ryujinx/Utilities/RyujinxOptions.Parse.cs
Normal file
58
src/Ryujinx/Utilities/RyujinxOptions.Parse.cs
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
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; }
|
||||||
|
|
||||||
|
// ReSharper disable once UnusedMethodReturnValue.Global
|
||||||
|
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>)
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
148
src/Ryujinx/Utilities/RyujinxOptions.cs
Normal file
148
src/Ryujinx/Utilities/RyujinxOptions.cs
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
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. Causes an error if used in tandem with --handheld-mode.")]
|
||||||
|
public bool DockedMode { get; set; }
|
||||||
|
|
||||||
|
[Option("handheld-mode", Required = false, Default = false,
|
||||||
|
HelpText = "Launch the game in Handheld mode. Causes an error if used in tandem with --docked-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; }
|
||||||
|
|
||||||
|
[Option("core-dumps", Required = false, Default = false,
|
||||||
|
HelpText = "Enable coredumps on Linux platforms. They are disabled by default.")]
|
||||||
|
public bool CoreDumpsEnabled { 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
|
// args are first defined as a list, for easier adjustments in the future
|
||||||
List<string> argsList = [];
|
List<string> argsList = [];
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(CommandLineState.BaseDirPathArg))
|
if (!string.IsNullOrEmpty(RyujinxOptions.Shared.EmuDataBaseDirPath))
|
||||||
{
|
{
|
||||||
argsList.Add("--root-data-dir");
|
argsList.Add("--root-data-dir");
|
||||||
argsList.Add($"\"{CommandLineState.BaseDirPathArg}\"");
|
argsList.Add($"\"{RyujinxOptions.Shared.EmuDataBaseDirPath}\"");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(config))
|
if (!string.IsNullOrEmpty(config))
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ namespace Ryujinx.Ava.Utilities
|
|||||||
string titleIdSection = $"({activeProcess.ProgramIdText.ToUpper()})";
|
string titleIdSection = $"({activeProcess.ProgramIdText.ToUpper()})";
|
||||||
string titleArchSection = activeProcess.Is64Bit ? "(64-bit)" : "(32-bit)";
|
string titleArchSection = activeProcess.Is64Bit ? "(64-bit)" : "(32-bit)";
|
||||||
|
|
||||||
return CommandLineState.RenderDocCaptureTitleFormat
|
return RyujinxOptions.Shared.RenderDocCaptureTitleFormat
|
||||||
.ReplaceIgnoreCase("{EmuVersion}", applicationVersion)
|
.ReplaceIgnoreCase("{EmuVersion}", applicationVersion)
|
||||||
.ReplaceIgnoreCase("{GuestName}", titleNameSection)
|
.ReplaceIgnoreCase("{GuestName}", titleNameSection)
|
||||||
.ReplaceIgnoreCase("{GuestVersion}", titleVersionSection)
|
.ReplaceIgnoreCase("{GuestVersion}", titleVersionSection)
|
||||||
|
|||||||
Reference in New Issue
Block a user