static void Main(string[] args) { Version = ReleaseInformations.GetVersion(); Console.Title = $"Ryujinx Console {Version} (Headless SDL2)"; AppDataManager.Initialize(null); _virtualFileSystem = VirtualFileSystem.CreateInstance(); _libHacHorizonManager = new LibHacHorizonManager(); _libHacHorizonManager.InitializeFsServer(_virtualFileSystem); _libHacHorizonManager.InitializeArpServer(); _libHacHorizonManager.InitializeBcatServer(); _libHacHorizonManager.InitializeSystemClients(); _contentManager = new ContentManager(_virtualFileSystem); _accountManager = new AccountManager(_libHacHorizonManager.RyujinxClient); _userChannelPersistence = new UserChannelPersistence(); _inputManager = new InputManager(new SDL2KeyboardDriver(), new SDL2GamepadDriver()); GraphicsConfig.EnableShaderCache = true; Parser.Default.ParseArguments <Options>(args) .WithParsed(options => Load(options)) .WithNotParsed(errors => errors.Output()); _inputManager.Dispose(); }
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed public static bool CanUpdate(bool showWarnings, StyleableWindow parent) { #if !DISABLE_UPDATER if (RuntimeInformation.OSArchitecture != Architecture.X64) { if (showWarnings) { ContentDialogHelper.CreateWarningDialog(parent, LocaleManager.Instance["DialogUpdaterArchNotSupportedMessage"], LocaleManager.Instance["DialogUpdaterArchNotSupportedSubMessage"]); } return(false); } if (!NetworkInterface.GetIsNetworkAvailable()) { if (showWarnings) { ContentDialogHelper.CreateWarningDialog(parent, LocaleManager.Instance["DialogUpdaterNoInternetMessage"], LocaleManager.Instance["DialogUpdaterNoInternetSubMessage"]); } return(false); } if (Program.Version.Contains("dirty") || !ReleaseInformations.IsValid()) { if (showWarnings) { ContentDialogHelper.CreateWarningDialog(parent, LocaleManager.Instance["DialogUpdaterDirtyBuildMessage"], LocaleManager.Instance["DialogUpdaterDirtyBuildSubMessage"]); } return(false); } return(true); #else if (showWarnings) { if (ReleaseInformations.IsFlatHubBuild()) { ContentDialogHelper.CreateWarningDialog(parent, LocaleManager.Instance["UpdaterDisabledWarningTitle"], LocaleManager.Instance["DialogUpdaterFlatpakNotSupportedMessage"]); } else { ContentDialogHelper.CreateWarningDialog(parent, LocaleManager.Instance["UpdaterDisabledWarningTitle"], LocaleManager.Instance["DialogUpdaterDirtyBuildSubMessage"]); } } return(false); #endif }
public void Initialize() { lock (_lock) { _refereceCount++; if (_isRunning) { return; } SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, "1"); SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, "1"); SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1"); SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH_HOME_LED, "0"); SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, "1"); if (SDL_Init(SdlInitFlags) != 0) { string errorMessage = $"SDL2 initlaization failed with error \"{SDL_GetError()}\""; Logger.Error?.Print(LogClass.Application, errorMessage); throw new Exception(errorMessage); } // First ensure that we only enable joystick events (for connected/disconnected). SDL_GameControllerEventState(SDL_DISABLE); SDL_JoystickEventState(SDL_ENABLE); // Disable all joysticks information, we don't need them no need to flood the event queue for that. SDL_EventState(SDL_EventType.SDL_JOYAXISMOTION, SDL_DISABLE); SDL_EventState(SDL_EventType.SDL_JOYBALLMOTION, SDL_DISABLE); SDL_EventState(SDL_EventType.SDL_JOYHATMOTION, SDL_DISABLE); SDL_EventState(SDL_EventType.SDL_JOYBUTTONDOWN, SDL_DISABLE); SDL_EventState(SDL_EventType.SDL_JOYBUTTONUP, SDL_DISABLE); SDL_EventState(SDL_EventType.SDL_CONTROLLERSENSORUPDATE, SDL_DISABLE); string gamepadDbPath = Path.Combine(ReleaseInformations.GetBaseApplicationDirectory(), "SDL_GameControllerDB.txt"); if (File.Exists(gamepadDbPath)) { SDL_GameControllerAddMappingsFromFile(gamepadDbPath); } _registeredWindowHandlers = new ConcurrentDictionary <uint, Action <SDL_Event> >(); _worker = new Thread(EventWorker); _isRunning = true; _worker.Start(); } }
public static bool CanUpdate(bool showWarnings) { #if !DISABLE_UPDATER if (RuntimeInformation.OSArchitecture != Architecture.X64) { if (showWarnings) { GtkDialog.CreateWarningDialog("You are not running a supported system architecture!", "(Only x64 systems are supported!)"); } return(false); } if (!NetworkInterface.GetIsNetworkAvailable()) { if (showWarnings) { GtkDialog.CreateWarningDialog("You are not connected to the Internet!", "Please verify that you have a working Internet connection!"); } return(false); } if (Program.Version.Contains("dirty") || !ReleaseInformations.IsValid()) { if (showWarnings) { GtkDialog.CreateWarningDialog("You cannot update a Dirty build of Ryujinx!", "Please download Ryujinx at https://ryujinx.org/ if you are looking for a supported version."); } return(false); } return(true); #else if (showWarnings) { if (ReleaseInformations.IsFlatHubBuild()) { GtkDialog.CreateWarningDialog("Updater Disabled!", "Please update Ryujinx via FlatHub."); } else { GtkDialog.CreateWarningDialog("Updater Disabled!", "Please download Ryujinx at https://ryujinx.org/ if you are looking for a supported version."); } } return(false); #endif }
private static void ReloadFileLogger(object sender, ReactiveEventArgs <bool> e) { if (e.NewValue) { Logger.AddTarget(new AsyncLogTargetWrapper( new FileLogTarget(ReleaseInformations.GetBaseApplicationDirectory(), "file"), 1000, AsyncLogTargetOverflowAction.Block )); } else { Logger.RemoveTarget("file"); } }
public 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); } PreviewerDetached = true; Initialize(args); RenderTimer = new RenderTimer(); BuildAvaloniaApp().StartWithClassicDesktopLifetime(args); RenderTimer.Dispose(); }
static void Load(Options option) { IGamepad gamepad; if (option.ListInputIds) { Logger.Info?.Print(LogClass.Application, "Input Ids:"); foreach (string id in _inputManager.KeyboardDriver.GamepadsIds) { gamepad = _inputManager.KeyboardDriver.GetGamepad(id); Logger.Info?.Print(LogClass.Application, $"- {id} (\"{gamepad.Name}\")"); gamepad.Dispose(); } foreach (string id in _inputManager.GamepadDriver.GamepadsIds) { gamepad = _inputManager.GamepadDriver.GetGamepad(id); Logger.Info?.Print(LogClass.Application, $"- {id} (\"{gamepad.Name}\")"); gamepad.Dispose(); } return; } if (option.InputPath == null) { Logger.Error?.Print(LogClass.Application, "Please provide a file to load"); return; } _inputConfiguration = new List <InputConfig>(); _enableKeyboard = (bool)option.EnableKeyboard; _enableMouse = (bool)option.EnableMouse; void LoadPlayerConfiguration(string inputProfileName, string inputId, PlayerIndex index) { InputConfig inputConfig = HandlePlayerConfiguration(inputProfileName, inputId, index); if (inputConfig != null) { _inputConfiguration.Add(inputConfig); } } LoadPlayerConfiguration(option.InputProfile1Name, option.InputId1, PlayerIndex.Player1); LoadPlayerConfiguration(option.InputProfile2Name, option.InputId2, PlayerIndex.Player2); LoadPlayerConfiguration(option.InputProfile3Name, option.InputId3, PlayerIndex.Player3); LoadPlayerConfiguration(option.InputProfile4Name, option.InputId4, PlayerIndex.Player4); LoadPlayerConfiguration(option.InputProfile5Name, option.InputId5, PlayerIndex.Player5); LoadPlayerConfiguration(option.InputProfile6Name, option.InputId6, PlayerIndex.Player6); LoadPlayerConfiguration(option.InputProfile7Name, option.InputId7, PlayerIndex.Player7); LoadPlayerConfiguration(option.InputProfile8Name, option.InputId8, PlayerIndex.Player8); LoadPlayerConfiguration(option.InputProfileHandheldName, option.InputIdHandheld, PlayerIndex.Handheld); if (_inputConfiguration.Count == 0) { return; } // Setup logging level Logger.SetEnable(LogLevel.Debug, (bool)option.LoggingEnableDebug); Logger.SetEnable(LogLevel.Stub, (bool)option.LoggingEnableStub); Logger.SetEnable(LogLevel.Info, (bool)option.LoggingEnableInfo); Logger.SetEnable(LogLevel.Warning, (bool)option.LoggingEnableWarning); Logger.SetEnable(LogLevel.Error, (bool)option.LoggingEnableError); Logger.SetEnable(LogLevel.Trace, (bool)option.LoggingEnableTrace); Logger.SetEnable(LogLevel.Guest, (bool)option.LoggingEnableGuest); Logger.SetEnable(LogLevel.AccessLog, (bool)option.LoggingEnableFsAccessLog); if ((bool)option.EnableFileLog) { Logger.AddTarget(new AsyncLogTargetWrapper( new FileLogTarget(ReleaseInformations.GetBaseApplicationDirectory(), "file"), 1000, AsyncLogTargetOverflowAction.Block )); } // Setup graphics configuration GraphicsConfig.EnableShaderCache = (bool)option.EnableShaderCache; GraphicsConfig.ResScale = option.ResScale; GraphicsConfig.MaxAnisotropy = option.MaxAnisotropy; GraphicsConfig.ShadersDumpPath = option.GraphicsShadersDumpPath; while (true) { LoadApplication(option); if (_userChannelPersistence.PreviousIndex == -1 || !_userChannelPersistence.ShouldRestart) { break; } _userChannelPersistence.ShouldRestart = false; } }
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(); }