diff --git a/Ryujinx/Configuration.cs b/Ryujinx/Configuration.cs index 4f7fbc9e0e..9f2a08d0bf 100644 --- a/Ryujinx/Configuration.cs +++ b/Ryujinx/Configuration.cs @@ -221,7 +221,7 @@ namespace Ryujinx if (Instance.EnableFileLog) { Logger.AddTarget(new AsyncLogTargetWrapper( - new FileLogTarget(Path.Combine(Program.ApplicationDirectory, "Ryujinx.log")), + new FileLogTarget(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Ryujinx.log")), 1000, AsyncLogTargetOverflowAction.Block )); @@ -253,7 +253,7 @@ namespace Ryujinx } } - Program.DiscordIntegrationEnabled = SwitchConfig.EnableDiscordIntegration; + MainMenu.DiscordIntegrationEnabled = SwitchConfig.EnableDiscordIntergration; device.EnableDeviceVsync = SwitchConfig.EnableVsync; diff --git a/Ryujinx/GUI/GeneralSettings.cs b/Ryujinx/GUI/GeneralSettings.cs index 7c41016bbb..bd137ded9d 100644 --- a/Ryujinx/GUI/GeneralSettings.cs +++ b/Ryujinx/GUI/GeneralSettings.cs @@ -9,7 +9,7 @@ namespace Ryujinx { public class GeneralSettings : Window { - internal HLE.Switch device { get; private set; } + private HLE.Switch device { get; set; } internal static Configuration SwitchConfig { get; private set; } diff --git a/Ryujinx/GUI/MainMenu.cs b/Ryujinx/GUI/MainMenu.cs index 39aa3ebcff..2348d7e8fa 100644 --- a/Ryujinx/GUI/MainMenu.cs +++ b/Ryujinx/GUI/MainMenu.cs @@ -1,19 +1,35 @@ -using Gtk; +using DiscordRPC; +using Gtk; using GUI = Gtk.Builder.ObjectAttribute; +using Ryujinx.Audio; using Ryujinx.Common.Logging; +using Ryujinx.Graphics.Gal; +using Ryujinx.Graphics.Gal.OpenGL; +using Ryujinx.Profiler; using System; using System.IO; +using System.Linq; using System.Reflection; namespace Ryujinx { public class MainMenu : Window { - internal HLE.Switch device { get; private set; } + public static bool DiscordIntegrationEnabled { get; set; } - internal Application gtkapp { get; private set; } + public static DiscordRpcClient DiscordClient; - internal ListStore TableStore { get; private set; } + public static RichPresence DiscordPresence; + + private static IGalRenderer renderer; + + private static IAalOutput audioOut; + + private static HLE.Switch device { get; set; } + + private static Application gtkapp { get; set; } + + private static ListStore TableStore { get; set; } //UI Controls [GUI] Window MainWin; @@ -23,52 +39,88 @@ namespace Ryujinx [GUI] ScrolledWindow GameTableWindow; [GUI] GLArea GLScreen; - public MainMenu(HLE.Switch _device, Application _gtkapp) : this(new Builder("Ryujinx.GUI.MainMenu.glade"), _device, _gtkapp) { } + public MainMenu(string[] args, Application _gtkapp) : this(new Builder("Ryujinx.GUI.MainMenu.glade"), args, _gtkapp) { } - private MainMenu(Builder builder, HLE.Switch _device, Application _gtkapp) : base(builder.GetObject("MainWin").Handle) + private MainMenu(Builder builder, string[] args, Application _gtkapp) : base(builder.GetObject("MainWin").Handle) { - device = _device; + renderer = new OglRenderer(); + + audioOut = InitializeAudioEngine(); + + device = new HLE.Switch(renderer, audioOut); + + Configuration.Load(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.jsonc")); + Configuration.InitialConfigure(device); + gtkapp = _gtkapp; - if (Program.DiscordIntergrationEnabled) - { - Program.DiscordPresence.Details = "Main Menu"; - Program.DiscordPresence.State = "Idling"; - Program.DiscordPresence.Timestamps = new DiscordRPC.Timestamps(DateTime.UtcNow); - - Program.DiscordClient.SetPresence(Program.DiscordPresence); - } - - builder.Autoconnect(this); - MainWin.Icon = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.GUI.assets.ryujinxIcon.png"); - GameTableWindow.Show(); - GLScreen.Hide(); - ApplyTheme(); DeleteEvent += Window_Close; - //disable some buttons - NFC.Sensitive = false; - ControlSettingsMenu.Sensitive = false; - - //Games grid thing - GameTable.AppendColumn("Icon", new CellRendererPixbuf(), "pixbuf", 0); - GameTable.AppendColumn("Game", new CellRendererText(), "text", 1); - GameTable.AppendColumn("Version", new CellRendererText(), "text", 2); - GameTable.AppendColumn("DLC", new CellRendererText(), "text", 3); - GameTable.AppendColumn("Time Played", new CellRendererText(), "text", 4); - GameTable.AppendColumn("Last Played", new CellRendererText(), "text", 5); - GameTable.AppendColumn("Path", new CellRendererText(), "text", 6); - - TableStore = new ListStore(typeof(Gdk.Pixbuf), typeof(string), typeof(string), typeof(string), typeof(string), typeof(string), typeof(string)); - - foreach (ApplicationLibrary.ApplicationData AppData in ApplicationLibrary.ApplicationLibraryData) + if (DiscordIntegrationEnabled) { - TableStore.AppendValues(AppData.Icon, AppData.Game, AppData.Version, AppData.DLC, AppData.TP, AppData.LP, AppData.Path); + DiscordClient = new DiscordRpcClient("568815339807309834"); + DiscordPresence = new RichPresence + { + Assets = new Assets + { + LargeImageKey = "ryujinx", + LargeImageText = "Ryujinx is an emulator for the Nintendo Switch" + }, + Details = "Main Menu", + State = "Idling", + Timestamps = new Timestamps(DateTime.UtcNow) + }; + + DiscordClient.Initialize(); + DiscordClient.SetPresence(DiscordPresence); } - GameTable.Model = TableStore; + builder.Autoconnect(this); + MainWin.Icon = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.GUI.assets.ryujinxIcon.png"); + + if (args.Length == 1) + { + GameTableWindow.Hide(); + GLScreen.Show(); + + LoadApplication(args[0]); + + using (GlScreen screen = new GlScreen(device, renderer)) + { + screen.MainLoop(); + + Profile.FinishProfiling(); + + device.Dispose(); + } + } + else + { + GameTableWindow.Show(); + GLScreen.Hide(); + + NFC.Sensitive = false; + ControlSettingsMenu.Sensitive = false; + + GameTable.AppendColumn("Icon", new CellRendererPixbuf(), "pixbuf", 0); + GameTable.AppendColumn("Game", new CellRendererText(), "text", 1); + GameTable.AppendColumn("Version", new CellRendererText(), "text", 2); + GameTable.AppendColumn("DLC", new CellRendererText(), "text", 3); + GameTable.AppendColumn("Time Played", new CellRendererText(), "text", 4); + GameTable.AppendColumn("Last Played", new CellRendererText(), "text", 5); + GameTable.AppendColumn("Path", new CellRendererText(), "text", 6); + + TableStore = new ListStore(typeof(Gdk.Pixbuf), typeof(string), typeof(string), typeof(string), typeof(string), typeof(string), typeof(string)); + + foreach (ApplicationLibrary.ApplicationData AppData in ApplicationLibrary.ApplicationLibraryData) + { + TableStore.AppendValues(AppData.Icon, AppData.Game, AppData.Version, AppData.DLC, AppData.TP, AppData.LP, AppData.Path); + } + + GameTable.Model = TableStore; + } } public static void ApplyTheme() @@ -93,38 +145,98 @@ namespace Ryujinx StyleContext.AddProviderForScreen(Gdk.Screen.Default, css_provider, 800); } + private static void LoadApplication(string path) + { + 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."); + device.LoadProgram(path); + break; + } + } + else + { + Logger.PrintWarning(LogClass.Application, "Please specify a valid XCI/NCA/NSP/PFS0/NRO file"); + } + + if (DiscordIntegrationEnabled) + { + if (File.ReadAllLines(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "RPsupported.dat")).Contains(device.System.TitleID)) + { + DiscordPresence.Assets.LargeImageKey = device.System.TitleID; + } + + DiscordPresence.Details = $"Playing {device.System.TitleName}"; + DiscordPresence.State = device.System.TitleID.ToUpper(); + DiscordPresence.Assets.LargeImageText = device.System.TitleName; + DiscordPresence.Assets.SmallImageKey = "ryujinx"; + DiscordPresence.Assets.SmallImageText = "Ryujinx is an emulator for the Nintendo Switch"; + DiscordPresence.Timestamps = new Timestamps(DateTime.UtcNow); + + DiscordClient.SetPresence(DiscordPresence); + } + } + //Events private void Row_Activated(object obj, RowActivatedArgs args) { TableStore.GetIter(out TreeIter treeiter, new TreePath(args.Path.ToString())); string path = (string)TableStore.GetValue(treeiter, 6); - 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."); - device.LoadProgram(path); - break; - } + LoadApplication(path); GameTableWindow.Hide(); GLScreen.Show(); Destroy(); - Application.Quit(); + + using (GlScreen screen = new GlScreen(device, renderer)) + { + screen.MainLoop(); + + Profile.FinishProfiling(); + + device.Dispose(); + } + + audioOut.Dispose(); + Logger.Shutdown(); } private void Load_Application_File(object o, EventArgs args) @@ -139,32 +251,24 @@ namespace Ryujinx if (fc.Run() == (int)ResponseType.Accept) { - switch (System.IO.Path.GetExtension(fc.Filename).ToLowerInvariant()) - { - case ".xci": - Logger.PrintInfo(LogClass.Application, "Loading as XCI."); - device.LoadXci(fc.Filename); - break; - case ".nca": - Logger.PrintInfo(LogClass.Application, "Loading as NCA."); - device.LoadNca(fc.Filename); - break; - case ".nsp": - case ".pfs0": - Logger.PrintInfo(LogClass.Application, "Loading as NSP."); - device.LoadNsp(fc.Filename); - break; - default: - Logger.PrintInfo(LogClass.Application, "Loading as homebrew."); - device.LoadProgram(fc.Filename); - break; - } + LoadApplication(fc.Filename); GameTableWindow.Hide(); GLScreen.Show(); Destroy(); - Application.Quit(); + + using (GlScreen screen = new GlScreen(device, renderer)) + { + screen.MainLoop(); + + Profile.FinishProfiling(); + + device.Dispose(); + } + + audioOut.Dispose(); + Logger.Shutdown(); } fc.Destroy(); @@ -176,29 +280,24 @@ namespace Ryujinx if (fc.Run() == (int)ResponseType.Accept) { - string[] romFsFiles = Directory.GetFiles(fc.Filename, "*.istorage"); - - if (romFsFiles.Length == 0) - { - romFsFiles = Directory.GetFiles(fc.Filename, "*.romfs"); - } - - if (romFsFiles.Length > 0) - { - Logger.PrintInfo(LogClass.Application, "Loading as cart with RomFS."); - device.LoadCart(fc.Filename, romFsFiles[0]); - } - else - { - Logger.PrintInfo(LogClass.Application, "Loading as cart WITHOUT RomFS."); - device.LoadCart(fc.Filename); - } + LoadApplication(fc.Filename); GameTableWindow.Hide(); GLScreen.Show(); Destroy(); - Application.Quit(); + + using (GlScreen screen = new GlScreen(device, renderer)) + { + screen.MainLoop(); + + Profile.FinishProfiling(); + + device.Dispose(); + } + + audioOut.Dispose(); + Logger.Shutdown(); } fc.Destroy(); @@ -206,11 +305,17 @@ namespace Ryujinx private void Exit_Pressed(object o, EventArgs args) { + audioOut.Dispose(); + DiscordClient.Dispose(); + Logger.Shutdown(); Environment.Exit(0); } private void Window_Close(object obj, DeleteEventArgs args) { + audioOut.Dispose(); + DiscordClient.Dispose(); + Logger.Shutdown(); Environment.Exit(0); } @@ -252,5 +357,25 @@ namespace Ryujinx about.Run(); about.Destroy(); } + + /// + /// Picks an audio output renderer supported on this machine + /// + /// An supported by this machine + private static IAalOutput InitializeAudioEngine() + { + if (SoundIoAudioOut.IsSupported) + { + return new SoundIoAudioOut(); + } + else if (OpenALAudioOut.IsSupported) + { + return new OpenALAudioOut(); + } + else + { + return new DummyAudioOut(); + } + } } } diff --git a/Ryujinx/Program.cs b/Ryujinx/Program.cs index 3e9d1b5319..3cb594baf3 100644 --- a/Ryujinx/Program.cs +++ b/Ryujinx/Program.cs @@ -1,26 +1,12 @@ -using DiscordRPC; -using Ryujinx.Audio; -using Ryujinx.Common.Logging; -using Ryujinx.Graphics.Gal; -using Ryujinx.Graphics.Gal.OpenGL; -using Ryujinx.HLE; +using Ryujinx.Common.Logging; using Ryujinx.Profiler; using System; using System.IO; -using System.Linq; namespace Ryujinx { class Program { - public static DiscordRpcClient DiscordClient; - - public static RichPresence DiscordPresence; - - public static bool DiscordIntegrationEnabled { get; set; } - - public static string ApplicationDirectory => AppDomain.CurrentDomain.BaseDirectory; - static void Main(string[] args) { Console.Title = "Ryujinx Console"; @@ -29,141 +15,26 @@ namespace Ryujinx string systemPATH = Environment.GetEnvironmentVariable("Path", EnvironmentVariableTarget.Machine); Environment.SetEnvironmentVariable("Path", $"{Path.Combine(parentDir, "bin")};{systemPATH}"); - IGalRenderer renderer = new OglRenderer(); - - IAalOutput audioOut = InitializeAudioEngine(); - - Switch device = new Switch(renderer, audioOut); - - Configuration.Load(Path.Combine(ApplicationDirectory, "Config.jsonc")); - Configuration.InitialConfigure(device); + AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; + AppDomain.CurrentDomain.ProcessExit += CurrentDomain_ProcessExit; Profile.Initialize(); ApplicationLibrary.Init(); - AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; - AppDomain.CurrentDomain.ProcessExit += CurrentDomain_ProcessExit; + var gtkapp = new Gtk.Application("Ryujinx.Ryujinx", GLib.ApplicationFlags.None); + var win = new MainMenu(args, gtkapp); - if (DiscordIntegrationEnabled) - { - DiscordClient = new DiscordRpcClient("568815339807309834"); - DiscordPresence = new RichPresence - { - Assets = new Assets - { - LargeImageKey = "ryujinx", - LargeImageText = "Ryujinx is an emulator for the Nintendo Switch" - } - }; + gtkapp.Register(GLib.Cancellable.Current); + gtkapp.AddWindow(win); + win.Show(); - DiscordClient.Initialize(); - DiscordClient.SetPresence(DiscordPresence); - } - - if (args.Length == 0) - { - Gtk.Application.Init(); - - var gtkapp = new Gtk.Application("Ryujinx.Ryujinx", GLib.ApplicationFlags.None); - var win = new MainMenu(device, gtkapp); - - gtkapp.Register(GLib.Cancellable.Current); - gtkapp.AddWindow(win); - win.Show(); - - Gtk.Application.Run(); - } - - else - { - if (Directory.Exists(args[0])) - { - string[] romFsFiles = Directory.GetFiles(args[0], "*.istorage"); - - if (romFsFiles.Length == 0) - { - romFsFiles = Directory.GetFiles(args[0], "*.romfs"); - } - - if (romFsFiles.Length > 0) - { - Logger.PrintInfo(LogClass.Application, "Loading as cart with RomFS."); - device.LoadCart(args[0], romFsFiles[0]); - } - else - { - Logger.PrintInfo(LogClass.Application, "Loading as cart WITHOUT RomFS."); - device.LoadCart(args[0]); - } - } - else if (File.Exists(args[0])) - { - switch (Path.GetExtension(args[0]).ToLowerInvariant()) - { - case ".xci": - Logger.PrintInfo(LogClass.Application, "Loading as XCI."); - device.LoadXci(args[0]); - break; - case ".nca": - Logger.PrintInfo(LogClass.Application, "Loading as NCA."); - device.LoadNca(args[0]); - break; - case ".nsp": - case ".pfs0": - Logger.PrintInfo(LogClass.Application, "Loading as NSP."); - device.LoadNsp(args[0]); - break; - default: - Logger.PrintInfo(LogClass.Application, "Loading as homebrew."); - device.LoadProgram(args[0]); - break; - } - } - else - { - Logger.PrintWarning(LogClass.Application, "Please specify a valid XCI/NCA/NSP/PFS0/NRO file"); - } - } - - if (DiscordIntegrationEnabled) - { - if (File.ReadAllLines(Path.Combine(ApplicationDirectory, "RPsupported.dat")).Contains(device.System.TitleID)) - { - DiscordPresence.Assets.LargeImageKey = device.System.TitleID; - } - - DiscordPresence.Details = $"Playing {device.System.TitleName}"; - DiscordPresence.State = device.System.TitleID.ToUpper(); - DiscordPresence.Assets.LargeImageText = device.System.TitleName; - DiscordPresence.Assets.SmallImageKey = "ryujinx"; - DiscordPresence.Assets.SmallImageText = "Ryujinx is an emulator for the Nintendo Switch"; - DiscordPresence.Timestamps = new Timestamps(DateTime.UtcNow); - - DiscordClient.SetPresence(DiscordPresence); - } - - using (GlScreen screen = new GlScreen(device, renderer)) - { - screen.MainLoop(); - - Profile.FinishProfiling(); - - device.Dispose(); - } - - audioOut.Dispose(); - - Logger.Shutdown(); - - DiscordClient.Dispose(); + Gtk.Application.Run(); } private static void CurrentDomain_ProcessExit(object sender, EventArgs e) { Logger.Shutdown(); - - DiscordClient.Dispose(); } private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) @@ -175,28 +46,6 @@ namespace Ryujinx if (e.IsTerminating) { Logger.Shutdown(); - - DiscordClient.Dispose(); - } - } - - /// - /// Picks an audio output renderer supported on this machine - /// - /// An supported by this machine - private static IAalOutput InitializeAudioEngine() - { - if (SoundIoAudioOut.IsSupported) - { - return new SoundIoAudioOut(); - } - else if (OpenALAudioOut.IsSupported) - { - return new OpenALAudioOut(); - } - else - { - return new DummyAudioOut(); } } }