public void LoadApplication(string path) { if (_gameLoaded) { GtkDialog.CreateInfoDialog("A game has already been loaded", "Please close it first and try again."); } else { PerformanceCheck(); Logger.RestartTime(); InitializeSwitchInstance(); UpdateGraphicsConfig(); SystemVersion firmwareVersion = _contentManager.GetCurrentFirmwareVersion(); bool isDirectory = Directory.Exists(path); if (!SetupValidator.CanStartApplication(_contentManager, path, out UserError userError)) { if (SetupValidator.CanFixStartApplication(_contentManager, path, userError, out firmwareVersion)) { if (userError == UserError.NoFirmware) { string message = $"Would you like to install the firmware embedded in this game? (Firmware {firmwareVersion.VersionString})"; ResponseType responseDialog = (ResponseType)GtkDialog.CreateConfirmationDialog("No Firmware Installed", message).Run(); if (responseDialog != ResponseType.Yes) { UserErrorDialog.CreateUserErrorDialog(userError); _emulationContext.Dispose(); return; } } if (!SetupValidator.TryFixStartApplication(_contentManager, path, userError, out _)) { UserErrorDialog.CreateUserErrorDialog(userError); _emulationContext.Dispose(); return; } // Tell the user that we installed a firmware for them. if (userError == UserError.NoFirmware) { firmwareVersion = _contentManager.GetCurrentFirmwareVersion(); RefreshFirmwareLabel(); string message = $"No installed firmware was found but Ryujinx was able to install firmware {firmwareVersion.VersionString} from the provided game.\nThe emulator will now start."; GtkDialog.CreateInfoDialog($"Firmware {firmwareVersion.VersionString} was installed", message); } } else { UserErrorDialog.CreateUserErrorDialog(userError); _emulationContext.Dispose(); return; } } Logger.Notice.Print(LogClass.Application, $"Using Firmware Version: {firmwareVersion?.VersionString}"); if (Directory.Exists(path)) { string[] romFsFiles = Directory.GetFiles(path, "*.istorage"); if (romFsFiles.Length == 0) { romFsFiles = Directory.GetFiles(path, "*.romfs"); } if (romFsFiles.Length > 0) { Logger.Info?.Print(LogClass.Application, "Loading as cart with RomFS."); _emulationContext.LoadCart(path, romFsFiles[0]); } else { Logger.Info?.Print(LogClass.Application, "Loading as cart WITHOUT RomFS."); _emulationContext.LoadCart(path); } } else if (File.Exists(path)) { switch (System.IO.Path.GetExtension(path).ToLowerInvariant()) { case ".xci": Logger.Info?.Print(LogClass.Application, "Loading as XCI."); _emulationContext.LoadXci(path); break; case ".nca": Logger.Info?.Print(LogClass.Application, "Loading as NCA."); _emulationContext.LoadNca(path); break; case ".nsp": case ".pfs0": Logger.Info?.Print(LogClass.Application, "Loading as NSP."); _emulationContext.LoadNsp(path); break; default: Logger.Info?.Print(LogClass.Application, "Loading as homebrew."); try { _emulationContext.LoadProgram(path); } catch (ArgumentOutOfRangeException) { Logger.Error?.Print(LogClass.Application, "The file which you have specified is unsupported by Ryujinx."); } break; } } else { Logger.Warning?.Print(LogClass.Application, "Please specify a valid XCI/NCA/NSP/PFS0/NRO file."); _emulationContext.Dispose(); return; } _currentEmulatedGamePath = path; _deviceExitStatus.Reset(); Translator.IsReadyForTranslation.Reset(); #if MACOS_BUILD CreateGameWindow(); #else Thread windowThread = new Thread(() => { CreateGameWindow(); }) { Name = "GUI.WindowThread" }; windowThread.Start(); #endif _gameLoaded = true; _stopEmulation.Sensitive = true; _simulateWakeUpMessage.Sensitive = true; _firmwareInstallFile.Sensitive = false; _firmwareInstallDirectory.Sensitive = false; DiscordIntegrationModule.SwitchToPlayingState(_emulationContext.Application.TitleIdText, _emulationContext.Application.TitleName); _applicationLibrary.LoadAndSaveMetaData(_emulationContext.Application.TitleIdText, appMetadata => { appMetadata.LastPlayed = DateTime.UtcNow.ToString(); }); } }
static void Main(string[] args) { // Parse Arguments. string launchPathArg = null; string baseDirPathArg = null; bool startFullscreenArg = false; for (int i = 0; i < args.Length; ++i) { string arg = args[i]; if (arg == "-r" || arg == "--root-data-dir") { if (i + 1 >= args.Length) { Logger.Error?.Print(LogClass.Application, $"Invalid option '{arg}'"); continue; } baseDirPathArg = args[++i]; } else if (arg == "-f" || arg == "--fullscreen") { startFullscreenArg = true; } else if (launchPathArg == null) { launchPathArg = arg; } } // Delete backup files after updating. Task.Run(Updater.CleanupUpdate); Toolkit.Init(new ToolkitOptions { Backend = PlatformBackend.PreferNative }); Version = Assembly.GetEntryAssembly().GetCustomAttribute <AssemblyInformationalVersionAttribute>().InformationalVersion; Console.Title = $"Ryujinx Console {Version}"; string systemPath = Environment.GetEnvironmentVariable("Path", EnvironmentVariableTarget.Machine); Environment.SetEnvironmentVariable("Path", $"{Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "bin")};{systemPath}"); // Hook unhandled exception and process exit events. GLib.ExceptionManager.UnhandledException += (GLib.UnhandledExceptionArgs e) => ProcessUnhandledException(e.ExceptionObject as Exception, e.IsTerminating); AppDomain.CurrentDomain.UnhandledException += (object sender, UnhandledExceptionEventArgs e) => ProcessUnhandledException(e.ExceptionObject as Exception, e.IsTerminating); AppDomain.CurrentDomain.ProcessExit += (object sender, EventArgs e) => Exit(); // Setup base data directory. AppDataManager.Initialize(baseDirPathArg); // Initialize the configuration. ConfigurationState.Initialize(); // Initialize the logger system. LoggerModule.Initialize(); // Initialize Discord integration. DiscordIntegrationModule.Initialize(); string localConfigurationPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json"); string appDataConfigurationPath = Path.Combine(AppDataManager.BaseDirPath, "Config.json"); // Now load the configuration as the other subsystems are now registered. if (File.Exists(localConfigurationPath)) { ConfigurationPath = localConfigurationPath; ConfigurationFileFormat configurationFileFormat = ConfigurationFileFormat.Load(localConfigurationPath); ConfigurationState.Instance.Load(configurationFileFormat, ConfigurationPath); } else if (File.Exists(appDataConfigurationPath)) { ConfigurationPath = appDataConfigurationPath; ConfigurationFileFormat configurationFileFormat = ConfigurationFileFormat.Load(appDataConfigurationPath); ConfigurationState.Instance.Load(configurationFileFormat, ConfigurationPath); } else { // No configuration, we load the default values and save it on disk. ConfigurationPath = appDataConfigurationPath; ConfigurationState.Instance.LoadDefault(); ConfigurationState.Instance.ToFileFormat().SaveConfig(appDataConfigurationPath); } if (startFullscreenArg) { ConfigurationState.Instance.Ui.StartFullscreen.Value = true; } // Logging system informations. PrintSystemInfo(); // Initialize Gtk. Application.Init(); // Check if keys exists. bool hasGlobalProdKeys = File.Exists(Path.Combine(AppDataManager.KeysDirPath, "prod.keys")); bool hasAltProdKeys = !AppDataManager.IsCustomBasePath && File.Exists(Path.Combine(AppDataManager.KeysDirPathAlt, "prod.keys")); if (!hasGlobalProdKeys && !hasAltProdKeys) { UserErrorDialog.CreateUserErrorDialog(UserError.NoKeys); } // Force dedicated GPU if we can. ForceDedicatedGpu.Nvidia(); // Show the main window UI. MainWindow mainWindow = new MainWindow(); mainWindow.Show(); if (launchPathArg != null) { mainWindow.LoadApplication(launchPathArg); } if (ConfigurationState.Instance.CheckUpdatesOnStart.Value && Updater.CanUpdate(false)) { _ = Updater.BeginParse(mainWindow, false); } Application.Run(); }
private void HandleInstallerDialog(FileChooserDialog fileChooser) { if (fileChooser.Run() == (int)ResponseType.Accept) { try { string filename = fileChooser.Filename; fileChooser.Dispose(); SystemVersion firmwareVersion = _contentManager.VerifyFirmwarePackage(filename); string dialogTitle = $"Install Firmware {firmwareVersion.VersionString}"; if (firmwareVersion == null) { GtkDialog.CreateErrorDialog($"A valid system firmware was not found in {filename}."); return; } SystemVersion currentVersion = _contentManager.GetCurrentFirmwareVersion(); string dialogMessage = $"System version {firmwareVersion.VersionString} will be installed."; if (currentVersion != null) { dialogMessage += $"\n\nThis will replace the current system version {currentVersion.VersionString}. "; } dialogMessage += "\n\nDo you want to continue?"; ResponseType responseInstallDialog = (ResponseType)GtkDialog.CreateConfirmationDialog(dialogTitle, dialogMessage).Run(); MessageDialog waitingDialog = GtkDialog.CreateWaitingDialog(dialogTitle, "Installing firmware..."); if (responseInstallDialog == ResponseType.Yes) { Logger.Info?.Print(LogClass.Application, $"Installing firmware {firmwareVersion.VersionString}"); Thread thread = new Thread(() => { Application.Invoke(delegate { waitingDialog.Run(); }); try { _contentManager.InstallFirmware(filename); Application.Invoke(delegate { waitingDialog.Dispose(); string message = $"System version {firmwareVersion.VersionString} successfully installed."; GtkDialog.CreateInfoDialog(dialogTitle, message); Logger.Info?.Print(LogClass.Application, message); }); } catch (Exception ex) { Application.Invoke(delegate { waitingDialog.Dispose(); GtkDialog.CreateErrorDialog(ex.Message); }); } finally { RefreshFirmwareLabel(); } }); thread.Name = "GUI.FirmwareInstallerThread"; thread.Start(); } } catch (LibHac.MissingKeyException ex) { Logger.Error?.Print(LogClass.Application, ex.ToString()); UserErrorDialog.CreateUserErrorDialog(UserError.NoKeys); } catch (Exception ex) { GtkDialog.CreateErrorDialog(ex.Message); } } else { fileChooser.Dispose(); } }
static void Main(string[] args) { // Parse Arguments. string launchPathArg = null; string baseDirPathArg = null; bool startFullscreenArg = false; for (int i = 0; i < args.Length; ++i) { string arg = args[i]; if (arg == "-r" || arg == "--root-data-dir") { if (i + 1 >= args.Length) { Logger.Error?.Print(LogClass.Application, $"Invalid option '{arg}'"); continue; } baseDirPathArg = args[++i]; } else if (arg == "-f" || arg == "--fullscreen") { startFullscreenArg = true; } else if (launchPathArg == null) { launchPathArg = arg; } } // Make process DPI aware for proper window sizing on high-res screens. ForceDpiAware.Windows(); WindowScaleFactor = ForceDpiAware.GetWindowScaleFactor(); // Delete backup files after updating. Task.Run(Updater.CleanupUpdate); Toolkit.Init(new ToolkitOptions { Backend = PlatformBackend.PreferNative }); Version = Assembly.GetEntryAssembly().GetCustomAttribute <AssemblyInformationalVersionAttribute>().InformationalVersion; Console.Title = $"Ryujinx Console {Version}"; string systemPath = Environment.GetEnvironmentVariable("Path", EnvironmentVariableTarget.Machine); Environment.SetEnvironmentVariable("Path", $"{Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "bin")};{systemPath}"); // Hook unhandled exception and process exit events. GLib.ExceptionManager.UnhandledException += (GLib.UnhandledExceptionArgs e) => ProcessUnhandledException(e.ExceptionObject as Exception, e.IsTerminating); AppDomain.CurrentDomain.UnhandledException += (object sender, UnhandledExceptionEventArgs e) => ProcessUnhandledException(e.ExceptionObject as Exception, e.IsTerminating); AppDomain.CurrentDomain.ProcessExit += (object sender, EventArgs e) => Exit(); // Setup base data directory. AppDataManager.Initialize(baseDirPathArg); // Initialize the configuration. ConfigurationState.Initialize(); // Initialize the logger system. LoggerModule.Initialize(); // Initialize Discord integration. DiscordIntegrationModule.Initialize(); string localConfigurationPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json"); string appDataConfigurationPath = Path.Combine(AppDataManager.BaseDirPath, "Config.json"); // Now load the configuration as the other subsystems are now registered ConfigurationPath = File.Exists(localConfigurationPath) ? localConfigurationPath : File.Exists(appDataConfigurationPath) ? appDataConfigurationPath : null; if (ConfigurationPath == null) { // No configuration, we load the default values and save it to disk ConfigurationPath = appDataConfigurationPath; ConfigurationState.Instance.LoadDefault(); ConfigurationState.Instance.ToFileFormat().SaveConfig(ConfigurationPath); } else { if (ConfigurationFileFormat.TryLoad(ConfigurationPath, out ConfigurationFileFormat configurationFileFormat)) { ConfigurationState.Instance.Load(configurationFileFormat, ConfigurationPath); } else { ConfigurationState.Instance.LoadDefault(); Logger.Warning?.PrintMsg(LogClass.Application, $"Failed to load config! Loading the default config instead.\nFailed config location {ConfigurationPath}"); } } if (startFullscreenArg) { ConfigurationState.Instance.Ui.StartFullscreen.Value = true; } // Logging system information. PrintSystemInfo(); // Force dedicated GPU if we can. ForceDedicatedGpu.Nvidia(); // Enable OGL multithreading on the driver, when available. DriverUtilities.ToggleOGLThreading(true); // Initialize Gtk. Application.Init(); // Check if keys exists. bool hasSystemProdKeys = File.Exists(Path.Combine(AppDataManager.KeysDirPath, "prod.keys")); bool hasCommonProdKeys = AppDataManager.Mode == AppDataManager.LaunchMode.UserProfile && File.Exists(Path.Combine(AppDataManager.KeysDirPathUser, "prod.keys")); if (!hasSystemProdKeys && !hasCommonProdKeys) { UserErrorDialog.CreateUserErrorDialog(UserError.NoKeys); } // Show the main window UI. MainWindow mainWindow = new MainWindow(); mainWindow.Show(); if (launchPathArg != null) { mainWindow.LoadApplication(launchPathArg); } if (ConfigurationState.Instance.CheckUpdatesOnStart.Value && Updater.CanUpdate(false)) { Updater.BeginParse(mainWindow, false).ContinueWith(task => { Logger.Error?.Print(LogClass.Application, $"Updater Error: {task.Exception}"); }, TaskContinuationOptions.OnlyOnFaulted); } Application.Run(); }
static void Main(string[] args) { Version = ReleaseInformations.GetVersion(); if (OperatingSystem.IsWindows() && !OperatingSystem.IsWindowsVersionAtLeast(10, 0, 17134)) { MessageBoxA(IntPtr.Zero, "You are running an outdated version of Windows.\n\nStarting on June 1st 2022, Ryujinx will only support Windows 10 1803 and newer.\n", $"Ryujinx {Version}", MB_ICONWARNING); } // Parse Arguments. string launchPathArg = null; string baseDirPathArg = null; bool startFullscreenArg = false; for (int i = 0; i < args.Length; ++i) { string arg = args[i]; if (arg == "-r" || arg == "--root-data-dir") { if (i + 1 >= args.Length) { Logger.Error?.Print(LogClass.Application, $"Invalid option '{arg}'"); continue; } baseDirPathArg = args[++i]; } else if (arg == "-p" || arg == "--profile") { if (i + 1 >= args.Length) { Logger.Error?.Print(LogClass.Application, $"Invalid option '{arg}'"); continue; } CommandLineProfile = args[++i]; } else if (arg == "-f" || arg == "--fullscreen") { startFullscreenArg = true; } else if (launchPathArg == null) { launchPathArg = arg; } } // Make process DPI aware for proper window sizing on high-res screens. ForceDpiAware.Windows(); WindowScaleFactor = ForceDpiAware.GetWindowScaleFactor(); // Delete backup files after updating. Task.Run(Updater.CleanupUpdate); Console.Title = $"Ryujinx Console {Version}"; // NOTE: GTK3 doesn't init X11 in a multi threaded way. // This ends up causing race condition and abort of XCB when a context is created by SPB (even if SPB do call XInitThreads). if (OperatingSystem.IsLinux()) { XInitThreads(); } string systemPath = Environment.GetEnvironmentVariable("Path", EnvironmentVariableTarget.Machine); Environment.SetEnvironmentVariable("Path", $"{Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "bin")};{systemPath}"); // Hook unhandled exception and process exit events. GLib.ExceptionManager.UnhandledException += (GLib.UnhandledExceptionArgs e) => ProcessUnhandledException(e.ExceptionObject as Exception, e.IsTerminating); AppDomain.CurrentDomain.UnhandledException += (object sender, UnhandledExceptionEventArgs e) => ProcessUnhandledException(e.ExceptionObject as Exception, e.IsTerminating); AppDomain.CurrentDomain.ProcessExit += (object sender, EventArgs e) => Exit(); // Setup base data directory. AppDataManager.Initialize(baseDirPathArg); // Initialize the configuration. ConfigurationState.Initialize(); // Initialize the logger system. LoggerModule.Initialize(); // Initialize Discord integration. DiscordIntegrationModule.Initialize(); // Sets ImageSharp Jpeg Encoder Quality. SixLabors.ImageSharp.Configuration.Default.ImageFormatsManager.SetEncoder(JpegFormat.Instance, new JpegEncoder() { Quality = 100 }); string localConfigurationPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json"); string appDataConfigurationPath = Path.Combine(AppDataManager.BaseDirPath, "Config.json"); // Now load the configuration as the other subsystems are now registered ConfigurationPath = File.Exists(localConfigurationPath) ? localConfigurationPath : File.Exists(appDataConfigurationPath) ? appDataConfigurationPath : null; bool showVulkanPrompt = false; if (ConfigurationPath == null) { // No configuration, we load the default values and save it to disk ConfigurationPath = appDataConfigurationPath; ConfigurationState.Instance.LoadDefault(); ConfigurationState.Instance.ToFileFormat().SaveConfig(ConfigurationPath); showVulkanPrompt = true; } else { if (ConfigurationFileFormat.TryLoad(ConfigurationPath, out ConfigurationFileFormat configurationFileFormat)) { ConfigurationLoadResult result = ConfigurationState.Instance.Load(configurationFileFormat, ConfigurationPath); if ((result & ConfigurationLoadResult.MigratedFromPreVulkan) != 0) { showVulkanPrompt = true; } } else { ConfigurationState.Instance.LoadDefault(); showVulkanPrompt = true; Logger.Warning?.PrintMsg(LogClass.Application, $"Failed to load config! Loading the default config instead.\nFailed config location {ConfigurationPath}"); } } // Logging system information. PrintSystemInfo(); // Enable OGL multithreading on the driver, when available. BackendThreading threadingMode = ConfigurationState.Instance.Graphics.BackendThreading; DriverUtilities.ToggleOGLThreading(threadingMode == BackendThreading.Off); // Initialize Gtk. Application.Init(); // Check if keys exists. bool hasSystemProdKeys = File.Exists(Path.Combine(AppDataManager.KeysDirPath, "prod.keys")); bool hasCommonProdKeys = AppDataManager.Mode == AppDataManager.LaunchMode.UserProfile && File.Exists(Path.Combine(AppDataManager.KeysDirPathUser, "prod.keys")); if (!hasSystemProdKeys && !hasCommonProdKeys) { UserErrorDialog.CreateUserErrorDialog(UserError.NoKeys); } // Show the main window UI. MainWindow mainWindow = new MainWindow(); mainWindow.Show(); if (launchPathArg != null) { mainWindow.LoadApplication(launchPathArg, startFullscreenArg); } if (ConfigurationState.Instance.CheckUpdatesOnStart.Value && Updater.CanUpdate(false)) { Updater.BeginParse(mainWindow, false).ContinueWith(task => { Logger.Error?.Print(LogClass.Application, $"Updater Error: {task.Exception}"); }, TaskContinuationOptions.OnlyOnFaulted); } if (showVulkanPrompt) { var buttonTexts = new Dictionary <int, string>() { { 0, "Yes (Vulkan)" }, { 1, "No (OpenGL)" } }; ResponseType response = GtkDialog.CreateCustomDialog( "Ryujinx - Default graphics backend", "Use Vulkan as default graphics backend?", "Ryujinx now supports the Vulkan API. " + "Vulkan greatly improves shader compilation performance, " + "and fixes some graphical glitches; however, since it is a new feature, " + "you may experience some issues that did not occur with OpenGL.\n\n" + "Note that you will also lose any existing shader cache the first time you start a game " + "on version 1.1.200 onwards, because Vulkan required changes to the shader cache that makes it incompatible with previous versions.\n\n" + "Would you like to set Vulkan as the default graphics backend? " + "You can change this at any time on the settings window.", buttonTexts, MessageType.Question); ConfigurationState.Instance.Graphics.GraphicsBackend.Value = response == 0 ? GraphicsBackend.Vulkan : GraphicsBackend.OpenGl; ConfigurationState.Instance.ToFileFormat().SaveConfig(Program.ConfigurationPath); } Application.Run(); }
static void Main(string[] args) { Version = ReleaseInformations.GetVersion(); if (OperatingSystem.IsWindows() && !OperatingSystem.IsWindowsVersionAtLeast(10, 0, 17134)) { MessageBoxA(IntPtr.Zero, "You are running an outdated version of Windows.\n\nStarting on June 1st 2022, Ryujinx will only support Windows 10 1803 and newer.\n", $"Ryujinx {Version}", MB_ICONWARNING); } // Parse Arguments. string launchPathArg = null; string baseDirPathArg = null; bool startFullscreenArg = false; for (int i = 0; i < args.Length; ++i) { string arg = args[i]; if (arg == "-r" || arg == "--root-data-dir") { if (i + 1 >= args.Length) { Logger.Error?.Print(LogClass.Application, $"Invalid option '{arg}'"); continue; } baseDirPathArg = args[++i]; } else if (arg == "-p" || arg == "--profile") { if (i + 1 >= args.Length) { Logger.Error?.Print(LogClass.Application, $"Invalid option '{arg}'"); continue; } CommandLineProfile = args[++i]; } else if (arg == "-f" || arg == "--fullscreen") { startFullscreenArg = true; } else if (launchPathArg == null) { launchPathArg = arg; } } // Make process DPI aware for proper window sizing on high-res screens. ForceDpiAware.Windows(); WindowScaleFactor = ForceDpiAware.GetWindowScaleFactor(); // Delete backup files after updating. Task.Run(Updater.CleanupUpdate); Console.Title = $"Ryujinx Console {Version}"; // NOTE: GTK3 doesn't init X11 in a multi threaded way. // This ends up causing race condition and abort of XCB when a context is created by SPB (even if SPB do call XInitThreads). if (OperatingSystem.IsLinux()) { XInitThreads(); } string systemPath = Environment.GetEnvironmentVariable("Path", EnvironmentVariableTarget.Machine); Environment.SetEnvironmentVariable("Path", $"{Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "bin")};{systemPath}"); // Hook unhandled exception and process exit events. GLib.ExceptionManager.UnhandledException += (GLib.UnhandledExceptionArgs e) => ProcessUnhandledException(e.ExceptionObject as Exception, e.IsTerminating); AppDomain.CurrentDomain.UnhandledException += (object sender, UnhandledExceptionEventArgs e) => ProcessUnhandledException(e.ExceptionObject as Exception, e.IsTerminating); AppDomain.CurrentDomain.ProcessExit += (object sender, EventArgs e) => Exit(); // Setup base data directory. AppDataManager.Initialize(baseDirPathArg); // Initialize the configuration. ConfigurationState.Initialize(); // Initialize the logger system. LoggerModule.Initialize(); // Initialize Discord integration. DiscordIntegrationModule.Initialize(); // Sets ImageSharp Jpeg Encoder Quality. SixLabors.ImageSharp.Configuration.Default.ImageFormatsManager.SetEncoder(JpegFormat.Instance, new JpegEncoder() { Quality = 100 }); string localConfigurationPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json"); string appDataConfigurationPath = Path.Combine(AppDataManager.BaseDirPath, "Config.json"); // Now load the configuration as the other subsystems are now registered ConfigurationPath = File.Exists(localConfigurationPath) ? localConfigurationPath : File.Exists(appDataConfigurationPath) ? appDataConfigurationPath : null; if (ConfigurationPath == null) { // No configuration, we load the default values and save it to disk ConfigurationPath = appDataConfigurationPath; ConfigurationState.Instance.LoadDefault(); ConfigurationState.Instance.ToFileFormat().SaveConfig(ConfigurationPath); } else { if (ConfigurationFileFormat.TryLoad(ConfigurationPath, out ConfigurationFileFormat configurationFileFormat)) { ConfigurationState.Instance.Load(configurationFileFormat, ConfigurationPath); } else { ConfigurationState.Instance.LoadDefault(); Logger.Warning?.PrintMsg(LogClass.Application, $"Failed to load config! Loading the default config instead.\nFailed config location {ConfigurationPath}"); } } // Logging system information. PrintSystemInfo(); // Enable OGL multithreading on the driver, when available. BackendThreading threadingMode = ConfigurationState.Instance.Graphics.BackendThreading; DriverUtilities.ToggleOGLThreading(threadingMode == BackendThreading.Off); // Initialize Gtk. Application.Init(); // Check if keys exists. bool hasSystemProdKeys = File.Exists(Path.Combine(AppDataManager.KeysDirPath, "prod.keys")); bool hasCommonProdKeys = AppDataManager.Mode == AppDataManager.LaunchMode.UserProfile && File.Exists(Path.Combine(AppDataManager.KeysDirPathUser, "prod.keys")); if (!hasSystemProdKeys && !hasCommonProdKeys) { UserErrorDialog.CreateUserErrorDialog(UserError.NoKeys); } // Show the main window UI. MainWindow mainWindow = new MainWindow(); mainWindow.Show(); if (launchPathArg != null) { mainWindow.LoadApplication(launchPathArg, startFullscreenArg); } if (ConfigurationState.Instance.CheckUpdatesOnStart.Value && Updater.CanUpdate(false)) { Updater.BeginParse(mainWindow, false).ContinueWith(task => { Logger.Error?.Print(LogClass.Application, $"Updater Error: {task.Exception}"); }, TaskContinuationOptions.OnlyOnFaulted); } Application.Run(); }
static void Main(string[] args) { // Parse Arguments string launchPath = null; string baseDirPath = null; for (int i = 0; i < args.Length; ++i) { string arg = args[i]; if (arg == "-r" || arg == "--root-data-dir") { if (i + 1 >= args.Length) { Logger.Error?.Print(LogClass.Application, $"Invalid option '{arg}'"); continue; } baseDirPath = args[++i]; } else if (launchPath == null) { launchPath = arg; } } Toolkit.Init(new ToolkitOptions { Backend = PlatformBackend.PreferNative, EnableHighResolution = true }); Version = Assembly.GetEntryAssembly().GetCustomAttribute <AssemblyInformationalVersionAttribute>().InformationalVersion; Console.Title = $"Ryujinx Console {Version}"; string systemPath = Environment.GetEnvironmentVariable("Path", EnvironmentVariableTarget.Machine); Environment.SetEnvironmentVariable("Path", $"{Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "bin")};{systemPath}"); // Hook unhandled exception and process exit events GLib.ExceptionManager.UnhandledException += (GLib.UnhandledExceptionArgs e) => ProcessUnhandledException(e.ExceptionObject as Exception, e.IsTerminating); AppDomain.CurrentDomain.UnhandledException += (object sender, UnhandledExceptionEventArgs e) => ProcessUnhandledException(e.ExceptionObject as Exception, e.IsTerminating); AppDomain.CurrentDomain.ProcessExit += (object sender, EventArgs e) => ProgramExit(); // Setup base data directory AppDataManager.Initialize(baseDirPath); // Initialize the configuration ConfigurationState.Initialize(); // Initialize the logger system LoggerModule.Initialize(); // Initialize Discord integration DiscordIntegrationModule.Initialize(); string localConfigurationPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json"); string appDataConfigurationPath = Path.Combine(AppDataManager.BaseDirPath, "Config.json"); // Now load the configuration as the other subsystems are now registered if (File.Exists(localConfigurationPath)) { ConfigurationPath = localConfigurationPath; ConfigurationFileFormat configurationFileFormat = ConfigurationFileFormat.Load(localConfigurationPath); ConfigurationState.Instance.Load(configurationFileFormat, ConfigurationPath); } else if (File.Exists(appDataConfigurationPath)) { ConfigurationPath = appDataConfigurationPath; ConfigurationFileFormat configurationFileFormat = ConfigurationFileFormat.Load(appDataConfigurationPath); ConfigurationState.Instance.Load(configurationFileFormat, ConfigurationPath); } else { // No configuration, we load the default values and save it on disk ConfigurationPath = appDataConfigurationPath; ConfigurationState.Instance.LoadDefault(); ConfigurationState.Instance.ToFileFormat().SaveConfig(appDataConfigurationPath); } PrintSystemInfo(); Application.Init(); bool hasGlobalProdKeys = File.Exists(Path.Combine(AppDataManager.KeysDirPath, "prod.keys")); bool hasAltProdKeys = !AppDataManager.IsCustomBasePath && File.Exists(Path.Combine(AppDataManager.KeysDirPathAlt, "prod.keys")); if (!hasGlobalProdKeys && !hasAltProdKeys && !Migration.IsMigrationNeeded()) { UserErrorDialog.CreateUserErrorDialog(UserError.NoKeys); } MainWindow mainWindow = new MainWindow(); mainWindow.Show(); if (launchPath != null) { mainWindow.LoadApplication(launchPath); } Application.Run(); }