private void End(HLE.Switch device) { #if USE_DEBUGGING _debugger.Dispose(); #endif if (_ending) { return; } _ending = true; if (device != null) { UpdateGameMetadata(device.System.TitleIdText); if (_gLWidget != null) { _gLWidget.Exit(); _screenExitStatus.WaitOne(); } } Dispose(); Profile.FinishProfiling(); DiscordIntegrationModule.Exit(); Logger.Shutdown(); Application.Quit(); }
private void CreateGameWindow(HLE.Switch device) { device.Hid.InitializePrimaryController(ConfigurationState.Instance.Hid.ControllerType); using (_screen = new GlScreen(device)) { _screen.MainLoop(); } device.Dispose(); _emulationContext = null; _screen = null; _gameLoaded = false; DiscordIntegrationModule.SwitchToMainMenu(); _screenExitStatus.Set(); Application.Invoke(delegate { _stopEmulation.Sensitive = false; _firmwareInstallFile.Sensitive = true; _firmwareInstallDirectory.Sensitive = true; }); }
private void CreateGameWindow(HLE.Switch device) { device.Hid.InitializePrimaryController(ConfigurationState.Instance.Hid.ControllerType); _gLWidget = new GLRenderer(_emulationContext); Application.Invoke(delegate { _viewBox.Remove(_gameTableWindow); _gLWidget.Expand = true; _viewBox.Child = _gLWidget; _gLWidget.ShowAll(); EditFooterForGameRender(); }); _gLWidget.WaitEvent.WaitOne(); _gLWidget.Start(); device.Dispose(); _deviceExitStatus.Set(); // NOTE: Everything that is here will not be executed when you close the UI. Application.Invoke(delegate { _viewBox.Remove(_gLWidget); _gLWidget.Exit(); if (_gLWidget.Window != this.Window && _gLWidget.Window != null) { _gLWidget.Window.Dispose(); } _gLWidget.Dispose(); _viewBox.Add(_gameTableWindow); _gameTableWindow.Expand = true; this.Window.Title = $"Ryujinx {Program.Version}"; _emulationContext = null; _gameLoaded = false; _gLWidget = null; DiscordIntegrationModule.SwitchToMainMenu(); RecreateFooterForMenu(); UpdateColumns(); UpdateGameTable(); Task.Run(RefreshFirmwareLabel); _stopEmulation.Sensitive = false; _firmwareInstallFile.Sensitive = true; _firmwareInstallDirectory.Sensitive = true; }); }
private void End(HLE.Switch device) { #if USE_DEBUGGING _debugger.Dispose(); #endif if (_ending) { return; } _ending = true; if (device != null) { UpdateGameMetadata(device.System.TitleIdText); if (_gLWidget != null) { // We tell the widget that we are exiting _gLWidget.Exit(); // Wait for the other thread to dispose the HLE context before exiting. _deviceExitStatus.WaitOne(); } } Dispose(); Profile.FinishProfiling(); DiscordIntegrationModule.Exit(); Logger.Shutdown(); Application.Quit(); }
static void Main(string[] args) { Console.Title = "Ryujinx Console"; string systemPath = Environment.GetEnvironmentVariable("Path", EnvironmentVariableTarget.Machine); Environment.SetEnvironmentVariable("Path", $"{Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "bin")};{systemPath}"); GLib.ExceptionManager.UnhandledException += Glib_UnhandledException; // Initialize the configuration ConfigurationState.Initialize(); // Initialize the logger system LoggerModule.Initialize(); // Initialize Discord integration DiscordIntegrationModule.Initialize(); string configurationPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json"); // Now load the configuration as the other subsystems are now registered if (File.Exists(configurationPath)) { ConfigurationFileFormat configurationFileFormat = ConfigurationFileFormat.Load(configurationPath); ConfigurationState.Instance.Load(configurationFileFormat); } else { // No configuration, we load the default values and save it on disk ConfigurationState.Instance.LoadDefault(); ConfigurationState.Instance.ToFileFormat().SaveConfig(configurationPath); } Profile.Initialize(); Application.Init(); string appDataPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Ryujinx", "system", "prod.keys"); string userProfilePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".switch", "prod.keys"); if (!File.Exists(appDataPath) && !File.Exists(userProfilePath) && !Migration.IsMigrationNeeded()) { GtkDialog.CreateErrorDialog("Key file was not found. Please refer to `KEYS.md` for more info"); } MainWindow mainWindow = new MainWindow(); mainWindow.Show(); if (args.Length == 1) { mainWindow.LoadApplication(args[0]); } Application.Run(); }
public static void Exit() { DiscordIntegrationModule.Exit(); Ptc.Dispose(); PtcProfiler.Dispose(); Logger.Shutdown(); }
private void End(HLE.Switch device) { if (_ending) { return; } _ending = true; if (device != null) { UpdateGameMetadata(device.System.TitleIdText); } Dispose(); Profile.FinishProfiling(); device?.Dispose(); DiscordIntegrationModule.Exit(); Logger.Shutdown(); Application.Quit(); }
internal void LoadApplication(string path) { if (_gameLoaded) { GtkDialog.CreateDialog("Ryujinx", "A game has already been loaded", "Please close it first and try again."); } else { Logger.RestartTime(); HLE.Switch device = InitializeSwitchInstance(); // TODO: Move this somewhere else + reloadable? Graphics.Gpu.GraphicsConfig.ShadersDumpPath = ConfigurationState.Instance.Graphics.ShadersDumpPath; if (Directory.Exists(path)) { string[] romFsFiles = Directory.GetFiles(path, "*.istorage"); if (romFsFiles.Length == 0) { romFsFiles = Directory.GetFiles(path, "*.romfs"); } if (romFsFiles.Length > 0) { Logger.PrintInfo(LogClass.Application, "Loading as cart with RomFS."); device.LoadCart(path, romFsFiles[0]); } else { Logger.PrintInfo(LogClass.Application, "Loading as cart WITHOUT RomFS."); device.LoadCart(path); } } else if (File.Exists(path)) { switch (System.IO.Path.GetExtension(path).ToLowerInvariant()) { case ".xci": Logger.PrintInfo(LogClass.Application, "Loading as XCI."); device.LoadXci(path); break; case ".nca": Logger.PrintInfo(LogClass.Application, "Loading as NCA."); device.LoadNca(path); break; case ".nsp": case ".pfs0": Logger.PrintInfo(LogClass.Application, "Loading as NSP."); device.LoadNsp(path); break; default: Logger.PrintInfo(LogClass.Application, "Loading as homebrew."); try { device.LoadProgram(path); } catch (ArgumentOutOfRangeException) { Logger.PrintError(LogClass.Application, "The file which you have specified is unsupported by Ryujinx."); } break; } } else { Logger.PrintWarning(LogClass.Application, "Please specify a valid XCI/NCA/NSP/PFS0/NRO file."); End(device); } _emulationContext = device; _deviceExitStatus.Reset(); #if MACOS_BUILD CreateGameWindow(device); #else var windowThread = new Thread(() => { CreateGameWindow(device); }) { Name = "GUI.WindowThread" }; windowThread.Start(); #endif _gameLoaded = true; _stopEmulation.Sensitive = true; _firmwareInstallFile.Sensitive = false; _firmwareInstallDirectory.Sensitive = false; DiscordIntegrationModule.SwitchToPlayingState(device.System.TitleIdText, device.System.TitleName); ApplicationLibrary.LoadAndSaveMetaData(device.System.TitleIdText, appMetadata => { appMetadata.LastPlayed = DateTime.UtcNow.ToString(); }); } }
static void Main(string[] args) { 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}"); GLib.ExceptionManager.UnhandledException += Glib_UnhandledException; // 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 globalBasePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "Ryujinx"); string globalConfigurationPath = Path.Combine(globalBasePath, "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(globalConfigurationPath)) { ConfigurationPath = globalConfigurationPath; ConfigurationFileFormat configurationFileFormat = ConfigurationFileFormat.Load(globalConfigurationPath); ConfigurationState.Instance.Load(configurationFileFormat, ConfigurationPath); } else { // No configuration, we load the default values and save it on disk ConfigurationPath = globalConfigurationPath; // Make sure to create the Ryujinx directory if needed. Directory.CreateDirectory(globalBasePath); ConfigurationState.Instance.LoadDefault(); ConfigurationState.Instance.ToFileFormat().SaveConfig(globalConfigurationPath); } Logger.PrintInfo(LogClass.Application, $"Ryujinx Version: {Version}"); Logger.PrintInfo(LogClass.Application, $"Operating System: {SystemInfo.Instance.OsDescription}"); Logger.PrintInfo(LogClass.Application, $"CPU: {SystemInfo.Instance.CpuName}"); Logger.PrintInfo(LogClass.Application, $"Total RAM: {SystemInfo.Instance.RamSizeInMB}"); Profile.Initialize(); Application.Init(); string globalProdKeysPath = Path.Combine(globalBasePath, "system", "prod.keys"); string userProfilePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".switch", "prod.keys"); if (!File.Exists(globalProdKeysPath) && !File.Exists(userProfilePath) && !Migration.IsMigrationNeeded()) { GtkDialog.CreateWarningDialog("Key file was not found", "Please refer to `KEYS.md` for more info"); } MainWindow mainWindow = new MainWindow(); mainWindow.Show(); if (args.Length == 1) { mainWindow.LoadApplication(args[0]); } Application.Run(); }
private void CreateGameWindow(HLE.Switch device) { if (Environment.OSVersion.Platform == PlatformID.Win32NT) { _windowsMultimediaTimerResolution = new WindowsMultimediaTimerResolution(1); } _glWidget = new GlRenderer(_emulationContext, ConfigurationState.Instance.Logger.GraphicsDebugLevel); Application.Invoke(delegate { _viewBox.Remove(_gameTableWindow); _glWidget.Expand = true; _viewBox.Child = _glWidget; _glWidget.ShowAll(); EditFooterForGameRender(); if (this.Window.State.HasFlag(Gdk.WindowState.Fullscreen)) { ToggleExtraWidgets(false); } }); _glWidget.WaitEvent.WaitOne(); _glWidget.Start(); Ptc.Close(); PtcProfiler.Stop(); device.Dispose(); _deviceExitStatus.Set(); // NOTE: Everything that is here will not be executed when you close the UI. Application.Invoke(delegate { if (this.Window.State.HasFlag(Gdk.WindowState.Fullscreen)) { ToggleExtraWidgets(true); } _viewBox.Remove(_glWidget); _glWidget.Exit(); if (_glWidget.Window != this.Window && _glWidget.Window != null) { _glWidget.Window.Dispose(); } _glWidget.Dispose(); _windowsMultimediaTimerResolution?.Dispose(); _windowsMultimediaTimerResolution = null; _viewBox.Add(_gameTableWindow); _gameTableWindow.Expand = true; this.Window.Title = $"Ryujinx {Program.Version}"; _emulationContext = null; _gameLoaded = false; _glWidget = null; DiscordIntegrationModule.SwitchToMainMenu(); RecreateFooterForMenu(); UpdateColumns(); UpdateGameTable(); Task.Run(RefreshFirmwareLabel); _stopEmulation.Sensitive = false; _firmwareInstallFile.Sensitive = true; _firmwareInstallDirectory.Sensitive = true; }); }
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; } } // 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; 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(); }
private static void Initialize(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 == "-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 { launchPathArg = arg; } } // Delete backup files after updating. Task.Run(Updater.CleanupUpdate); Console.Title = $"Ryujinx Console {Version}"; // Hook unhandled exception and process exit events. 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(); ReloadConfig(); UseVulkan = PreviewerDetached ? ConfigurationState.Instance.Graphics.GraphicsBackend.Value == GraphicsBackend.Vulkan : false; if (UseVulkan) { if (VulkanRenderer.GetPhysicalDevices().Length == 0) { UseVulkan = false; ConfigurationState.Instance.Graphics.GraphicsBackend.Value = GraphicsBackend.OpenGl; Logger.Warning?.PrintMsg(LogClass.Application, "A suitable Vulkan physical device is not available. Falling back to OpenGL"); } } if (UseVulkan) { // With a custom gpu backend, avalonia doesn't enable dpi awareness, so the backend must handle it. This isn't so for the opengl backed, // as that uses avalonia's gpu backend and it's enabled there. ForceDpiAware.Windows(); } WindowScaleFactor = ForceDpiAware.GetWindowScaleFactor(); ActualScaleFactor = ForceDpiAware.GetActualScaleFactor() / BaseDpi; // Logging system information. PrintSystemInfo(); // Enable OGL multithreading on the driver, when available. BackendThreading threadingMode = ConfigurationState.Instance.Graphics.BackendThreading; DriverUtilities.ToggleOGLThreading(threadingMode == BackendThreading.Off); // Check if keys exists. bool hasSystemProdKeys = File.Exists(Path.Combine(AppDataManager.KeysDirPath, "prod.keys")); if (!hasSystemProdKeys) { if (!(AppDataManager.Mode == AppDataManager.LaunchMode.UserProfile && File.Exists(Path.Combine(AppDataManager.KeysDirPathUser, "prod.keys")))) { MainWindow.ShowKeyErrorOnLoad = true; } } if (launchPathArg != null) { MainWindow.DeferLoadApplication(launchPathArg, startFullscreenArg); } }
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(); }
private void CreateGameWindow(HLE.Switch device) { device.Hid.InitializePrimaryController(ConfigurationState.Instance.Hid.ControllerType); _gLWidget?.Exit(); _gLWidget?.Dispose(); _gLWidget = new GLRenderer(_emulationContext); Application.Invoke(delegate { _viewBox.Remove(_gameTableWindow); _gLWidget.Expand = true; _viewBox.Child = _gLWidget; _gLWidget.ShowAll(); _listStatusBox.Hide(); }); _gLWidget.WaitEvent.WaitOne(); _gLWidget.Start(); Application.Invoke(delegate { _viewBox.Remove(_gLWidget); _gLWidget.Exit(); if (_gLWidget.Window != this.Window && _gLWidget.Window != null) { _gLWidget.Window.Dispose(); } _viewBox.Add(_gameTableWindow); _gameTableWindow.Expand = true; this.Window.Title = "Ryujinx"; _listStatusBox.ShowAll(); UpdateColumns(); UpdateGameTable(); Task.Run(RefreshFirmwareLabel); }); device.Dispose(); _emulationContext = null; _gameLoaded = false; _gLWidget = null; DiscordIntegrationModule.SwitchToMainMenu(); Application.Invoke(delegate { _stopEmulation.Sensitive = false; _firmwareInstallFile.Sensitive = true; _firmwareInstallDirectory.Sensitive = true; }); _screenExitStatus.Set(); }
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(); }
internal void LoadApplication(string path) { if (_gameLoaded) { GtkDialog.CreateInfoDialog("Ryujinx", "A game has already been loaded", "Please close it first and try again."); } else { if (ConfigurationState.Instance.Logger.EnableDebug.Value) { MessageDialog debugWarningDialog = new MessageDialog(this, DialogFlags.Modal, MessageType.Warning, ButtonsType.YesNo, null) { Title = "Ryujinx - Warning", Text = "You have debug logging enabled, which is designed to be used by developers only.", SecondaryText = "For optimal performance, it's recommended to disable debug logging. Would you like to disable debug logging now?" }; if (debugWarningDialog.Run() == (int)ResponseType.Yes) { ConfigurationState.Instance.Logger.EnableDebug.Value = false; SaveConfig(); } debugWarningDialog.Dispose(); } if (!string.IsNullOrWhiteSpace(ConfigurationState.Instance.Graphics.ShadersDumpPath.Value)) { MessageDialog shadersDumpWarningDialog = new MessageDialog(this, DialogFlags.Modal, MessageType.Warning, ButtonsType.YesNo, null) { Title = "Ryujinx - Warning", Text = "You have shader dumping enabled, which is designed to be used by developers only.", SecondaryText = "For optimal performance, it's recommended to disable shader dumping. Would you like to disable shader dumping now?" }; if (shadersDumpWarningDialog.Run() == (int)ResponseType.Yes) { ConfigurationState.Instance.Graphics.ShadersDumpPath.Value = ""; SaveConfig(); } shadersDumpWarningDialog.Dispose(); } Logger.RestartTime(); HLE.Switch device = InitializeSwitchInstance(); UpdateGraphicsConfig(); Logger.Notice.Print(LogClass.Application, $"Using Firmware Version: {_contentManager.GetCurrentFirmwareVersion()?.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."); device.LoadCart(path, romFsFiles[0]); } else { Logger.Info?.Print(LogClass.Application, "Loading as cart WITHOUT RomFS."); device.LoadCart(path); } } else if (File.Exists(path)) { switch (System.IO.Path.GetExtension(path).ToLowerInvariant()) { case ".xci": Logger.Info?.Print(LogClass.Application, "Loading as XCI."); device.LoadXci(path); break; case ".nca": Logger.Info?.Print(LogClass.Application, "Loading as NCA."); device.LoadNca(path); break; case ".nsp": case ".pfs0": Logger.Info?.Print(LogClass.Application, "Loading as NSP."); device.LoadNsp(path); break; default: Logger.Info?.Print(LogClass.Application, "Loading as homebrew."); try { device.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."); device.Dispose(); return; } _emulationContext = device; _deviceExitStatus.Reset(); #if MACOS_BUILD CreateGameWindow(device); #else Thread windowThread = new Thread(() => { CreateGameWindow(device); }) { Name = "GUI.WindowThread" }; windowThread.Start(); #endif _gameLoaded = true; _stopEmulation.Sensitive = true; _firmwareInstallFile.Sensitive = false; _firmwareInstallDirectory.Sensitive = false; DiscordIntegrationModule.SwitchToPlayingState(device.Application.TitleIdText, device.Application.TitleName); ApplicationLibrary.LoadAndSaveMetaData(device.Application.TitleIdText, appMetadata => { appMetadata.LastPlayed = DateTime.UtcNow.ToString(); }); } }
internal void LoadApplication(string path) { if (_gameLoaded) { GtkDialog.CreateErrorDialog("A game has already been loaded. Please close the emulator and try again"); } else { Logger.RestartTime(); // TODO: Move this somewhere else + reloadable? GraphicsConfig.ShadersDumpPath = ConfigurationState.Instance.Graphics.ShadersDumpPath; if (Directory.Exists(path)) { string[] romFsFiles = Directory.GetFiles(path, "*.istorage"); if (romFsFiles.Length == 0) { romFsFiles = Directory.GetFiles(path, "*.romfs"); } if (romFsFiles.Length > 0) { Logger.PrintInfo(LogClass.Application, "Loading as cart with RomFS."); _device.LoadCart(path, romFsFiles[0]); } else { Logger.PrintInfo(LogClass.Application, "Loading as cart WITHOUT RomFS."); _device.LoadCart(path); } } else if (File.Exists(path)) { switch (System.IO.Path.GetExtension(path).ToLowerInvariant()) { case ".xci": Logger.PrintInfo(LogClass.Application, "Loading as XCI."); _device.LoadXci(path); break; case ".nca": Logger.PrintInfo(LogClass.Application, "Loading as NCA."); _device.LoadNca(path); break; case ".nsp": case ".pfs0": Logger.PrintInfo(LogClass.Application, "Loading as NSP."); _device.LoadNsp(path); break; default: Logger.PrintInfo(LogClass.Application, "Loading as homebrew."); try { _device.LoadProgram(path); } catch (ArgumentOutOfRangeException) { Logger.PrintError(LogClass.Application, "The file which you have specified is unsupported by Ryujinx."); } break; } } else { Logger.PrintWarning(LogClass.Application, "Please specify a valid XCI/NCA/NSP/PFS0/NRO file."); End(); } #if MACOS_BUILD CreateGameWindow(); #else new Thread(CreateGameWindow).Start(); #endif _gameLoaded = true; _stopEmulation.Sensitive = true; DiscordIntegrationModule.SwitchToPlayingState(_device.System.TitleId, _device.System.TitleName); string metadataFolder = System.IO.Path.Combine(new VirtualFileSystem().GetBasePath(), "games", _device.System.TitleId, "gui"); string metadataFile = System.IO.Path.Combine(metadataFolder, "metadata.json"); IJsonFormatterResolver resolver = CompositeResolver.Create(new[] { StandardResolver.AllowPrivateSnakeCase }); ApplicationMetadata appMetadata; if (!File.Exists(metadataFile)) { Directory.CreateDirectory(metadataFolder); appMetadata = new ApplicationMetadata { Favorite = false, TimePlayed = 0, LastPlayed = "Never" }; byte[] data = JsonSerializer.Serialize(appMetadata, resolver); File.WriteAllText(metadataFile, Encoding.UTF8.GetString(data, 0, data.Length).PrettyPrintJson()); } using (Stream stream = File.OpenRead(metadataFile)) { appMetadata = JsonSerializer.Deserialize <ApplicationMetadata>(stream, resolver); } appMetadata.LastPlayed = DateTime.UtcNow.ToString(); byte[] saveData = JsonSerializer.Serialize(appMetadata, resolver); File.WriteAllText(metadataFile, Encoding.UTF8.GetString(saveData, 0, saveData.Length).PrettyPrintJson()); } }
private void CreateGameWindow(HLE.Switch device) { device.Hid.Npads.AddControllers(ConfigurationState.Instance.Hid.InputConfig.Value.Select(inputConfig => new HLE.HOS.Services.Hid.ControllerConfig { Player = (PlayerIndex)inputConfig.PlayerIndex, Type = (ControllerType)inputConfig.ControllerType } ).ToArray()); _glWidget = new GlRenderer(_emulationContext, ConfigurationState.Instance.Logger.GraphicsDebugLevel); Application.Invoke(delegate { _viewBox.Remove(_gameTableWindow); _glWidget.Expand = true; _viewBox.Child = _glWidget; _glWidget.ShowAll(); EditFooterForGameRender(); if (this.Window.State.HasFlag(Gdk.WindowState.Fullscreen)) { ToggleExtraWidgets(false); } }); _glWidget.WaitEvent.WaitOne(); _glWidget.Start(); Ptc.Close(); PtcProfiler.Stop(); device.Dispose(); _deviceExitStatus.Set(); // NOTE: Everything that is here will not be executed when you close the UI. Application.Invoke(delegate { if (this.Window.State.HasFlag(Gdk.WindowState.Fullscreen)) { ToggleExtraWidgets(true); } _viewBox.Remove(_glWidget); _glWidget.Exit(); if (_glWidget.Window != this.Window && _glWidget.Window != null) { _glWidget.Window.Dispose(); } _glWidget.Dispose(); _viewBox.Add(_gameTableWindow); _gameTableWindow.Expand = true; this.Window.Title = $"Ryujinx {Program.Version}"; _emulationContext = null; _gameLoaded = false; _glWidget = null; DiscordIntegrationModule.SwitchToMainMenu(); RecreateFooterForMenu(); UpdateColumns(); UpdateGameTable(); Task.Run(RefreshFirmwareLabel); _stopEmulation.Sensitive = false; _firmwareInstallFile.Sensitive = true; _firmwareInstallDirectory.Sensitive = true; }); }
private void CreateGameWindow() { if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { _windowsMultimediaTimerResolution = new WindowsMultimediaTimerResolution(1); } DisplaySleep.Prevent(); GlRendererWidget = new GlRenderer(_emulationContext, ConfigurationState.Instance.Logger.GraphicsDebugLevel); Application.Invoke(delegate { _viewBox.Remove(_gameTableWindow); GlRendererWidget.Expand = true; _viewBox.Child = GlRendererWidget; GlRendererWidget.ShowAll(); EditFooterForGameRenderer(); if (Window.State.HasFlag(Gdk.WindowState.Fullscreen)) { ToggleExtraWidgets(false); } else if (ConfigurationState.Instance.Ui.StartFullscreen.Value) { FullScreen_Toggled(null, null); } }); GlRendererWidget.WaitEvent.WaitOne(); GlRendererWidget.Start(); Ptc.Close(); PtcProfiler.Stop(); _emulationContext.Dispose(); _deviceExitStatus.Set(); // NOTE: Everything that is here will not be executed when you close the UI. Application.Invoke(delegate { if (Window.State.HasFlag(Gdk.WindowState.Fullscreen)) { ToggleExtraWidgets(true); } GlRendererWidget.Exit(); if (GlRendererWidget.Window != Window && GlRendererWidget.Window != null) { GlRendererWidget.Window.Dispose(); } GlRendererWidget.Dispose(); _windowsMultimediaTimerResolution?.Dispose(); _windowsMultimediaTimerResolution = null; DisplaySleep.Restore(); _viewBox.Remove(GlRendererWidget); _viewBox.Add(_gameTableWindow); _gameTableWindow.Expand = true; Window.Title = $"Ryujinx {Program.Version}"; _emulationContext = null; _gameLoaded = false; GlRendererWidget = null; DiscordIntegrationModule.SwitchToMainMenu(); RecreateFooterForMenu(); UpdateColumns(); UpdateGameTable(); Task.Run(RefreshFirmwareLabel); Task.Run(HandleRelaunch); _stopEmulation.Sensitive = false; _simulateWakeUpMessage.Sensitive = false; _firmwareInstallFile.Sensitive = true; _firmwareInstallDirectory.Sensitive = true; }); }
private void CreateGameWindow(HLE.Switch device) { ControllerType type = (Ryujinx.Configuration.Hid.ControllerType)ConfigurationState.Instance.Hid.ControllerType switch { Ryujinx.Configuration.Hid.ControllerType.ProController => ControllerType.ProController, Ryujinx.Configuration.Hid.ControllerType.Handheld => ControllerType.Handheld, Ryujinx.Configuration.Hid.ControllerType.NpadPair => ControllerType.JoyconPair, Ryujinx.Configuration.Hid.ControllerType.NpadLeft => ControllerType.JoyconLeft, Ryujinx.Configuration.Hid.ControllerType.NpadRight => ControllerType.JoyconRight, _ => ControllerType.Handheld }; device.Hid.Npads.AddControllers(new ControllerConfig { PlayerId = HidControllerID.Player1, Type = type }); _gLWidget = new GLRenderer(_emulationContext); Application.Invoke(delegate { _viewBox.Remove(_gameTableWindow); _gLWidget.Expand = true; _viewBox.Child = _gLWidget; _gLWidget.ShowAll(); EditFooterForGameRender(); }); _gLWidget.WaitEvent.WaitOne(); _gLWidget.Start(); device.Dispose(); _deviceExitStatus.Set(); // NOTE: Everything that is here will not be executed when you close the UI. Application.Invoke(delegate { _viewBox.Remove(_gLWidget); _gLWidget.Exit(); if (_gLWidget.Window != this.Window && _gLWidget.Window != null) { _gLWidget.Window.Dispose(); } _gLWidget.Dispose(); _viewBox.Add(_gameTableWindow); _gameTableWindow.Expand = true; this.Window.Title = $"Ryujinx {Program.Version}"; _emulationContext = null; _gameLoaded = false; _gLWidget = null; DiscordIntegrationModule.SwitchToMainMenu(); RecreateFooterForMenu(); UpdateColumns(); UpdateGameTable(); Task.Run(RefreshFirmwareLabel); _stopEmulation.Sensitive = false; _firmwareInstallFile.Sensitive = true; _firmwareInstallDirectory.Sensitive = true; }); }
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 static void Initialize(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 == "-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 { launchPathArg = arg; } } // Make process DPI aware for proper window sizing on high-res screens. WindowScaleFactor = ForceDpiAware.GetWindowScaleFactor(); // Delete backup files after updating. Task.Run(Updater.CleanupUpdate); Console.Title = $"Ryujinx Console {Version}"; // Hook unhandled exception and process exit events. 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(); ReloadConfig(); // Logging system information. PrintSystemInfo(); // Enable OGL multithreading on the driver, when available. BackendThreading threadingMode = ConfigurationState.Instance.Graphics.BackendThreading; DriverUtilities.ToggleOGLThreading(threadingMode == BackendThreading.Off); // Check if keys exists. bool hasSystemProdKeys = File.Exists(Path.Combine(AppDataManager.KeysDirPath, "prod.keys")); if (!hasSystemProdKeys) { if (!(AppDataManager.Mode == AppDataManager.LaunchMode.UserProfile && File.Exists(Path.Combine(AppDataManager.KeysDirPathUser, "prod.keys")))) { MainWindow.ShowKeyErrorOnLoad = true; } } if (launchPathArg != null) { MainWindow.DeferLoadApplication(launchPathArg, startFullscreenArg); } }