From ba74f814e9eb4846aaaf306aac6589571ab7a224 Mon Sep 17 00:00:00 2001 From: Thog Date: Thu, 21 Nov 2019 19:39:12 +0100 Subject: [PATCH] Start rewriting the Configuration system TODO: - Move ConfigurationState to Ryujinx.Common or a new project - Make controllers reloadable --- Ryujinx.Common/Logging/Logger.cs | 38 ++ .../Logging/Targets/AsyncLogTargetWrapper.cs | 5 + .../Logging/Targets/ConsoleLogTarget.cs | 10 +- .../Logging/Targets/FileLogTarget.cs | 13 +- Ryujinx.Common/Logging/Targets/ILogTarget.cs | 2 + .../Logging/Targets/JsonLogTarget.cs | 9 +- Ryujinx.Common/ReactiveObject.cs | 57 +++ Ryujinx.HLE/Switch.cs | 26 ++ Ryujinx/Configuration/Configuration.cs | 391 ++++++++++++++++++ .../ConfigurationFileFormat.cs} | 128 +----- .../Configuration/DiscordIntegrationModule.cs | 90 ++++ Ryujinx/Configuration/LoggerModule.cs | 112 +++++ Ryujinx/Program.cs | 35 +- Ryujinx/Ui/GLScreen.cs | 22 +- Ryujinx/Ui/MainWindow.cs | 306 ++++++-------- Ryujinx/Ui/SwitchSettings.cs | 158 ++++--- 16 files changed, 978 insertions(+), 424 deletions(-) create mode 100644 Ryujinx.Common/ReactiveObject.cs create mode 100644 Ryujinx/Configuration/Configuration.cs rename Ryujinx/{Configuration.cs => Configuration/ConfigurationFileFormat.cs} (56%) create mode 100644 Ryujinx/Configuration/DiscordIntegrationModule.cs create mode 100644 Ryujinx/Configuration/LoggerModule.cs diff --git a/Ryujinx.Common/Logging/Logger.cs b/Ryujinx.Common/Logging/Logger.cs index 10b1d97037..df1954540f 100644 --- a/Ryujinx.Common/Logging/Logger.cs +++ b/Ryujinx.Common/Logging/Logger.cs @@ -37,6 +37,13 @@ namespace Ryujinx.Common.Logging m_LogTargets = new List(); m_Time = Stopwatch.StartNew(); + + // logger should log to console by default + AddTarget(new AsyncLogTargetWrapper( + new ConsoleLogTarget("console"), + 1000, + AsyncLogTargetOverflowAction.Block + )); } public static void RestartTime() @@ -44,6 +51,19 @@ namespace Ryujinx.Common.Logging m_Time.Restart(); } + private static ILogTarget GetTarget(string targetName) + { + foreach (var target in m_LogTargets) + { + if (target.GetName().Equals(targetName)) + { + return target; + } + } + + return null; + } + public static void AddTarget(ILogTarget target) { m_LogTargets.Add(target); @@ -51,6 +71,24 @@ namespace Ryujinx.Common.Logging Updated += target.Log; } + public static void RemoveTarget(string target) + { + ILogTarget logTarget = GetTarget(target); + + // TODO: remove this + if (logTarget == null) + throw new Exception(); + + if (logTarget != null) + { + Updated -= logTarget.Log; + + m_LogTargets.Remove(logTarget); + + logTarget.Dispose(); + } + } + public static void Shutdown() { Updated = null; diff --git a/Ryujinx.Common/Logging/Targets/AsyncLogTargetWrapper.cs b/Ryujinx.Common/Logging/Targets/AsyncLogTargetWrapper.cs index a805a83b6e..f8efd7b252 100644 --- a/Ryujinx.Common/Logging/Targets/AsyncLogTargetWrapper.cs +++ b/Ryujinx.Common/Logging/Targets/AsyncLogTargetWrapper.cs @@ -72,5 +72,10 @@ namespace Ryujinx.Common.Logging _messageQueue.CompleteAdding(); _messageThread.Join(); } + + public string GetName() + { + return _target.GetName(); + } } } \ No newline at end of file diff --git a/Ryujinx.Common/Logging/Targets/ConsoleLogTarget.cs b/Ryujinx.Common/Logging/Targets/ConsoleLogTarget.cs index 871076a41a..6b04dd820c 100644 --- a/Ryujinx.Common/Logging/Targets/ConsoleLogTarget.cs +++ b/Ryujinx.Common/Logging/Targets/ConsoleLogTarget.cs @@ -9,6 +9,8 @@ namespace Ryujinx.Common.Logging private readonly ILogFormatter _formatter; + private readonly string _name; + static ConsoleLogTarget() { _logColors = new ConcurrentDictionary { @@ -19,9 +21,10 @@ namespace Ryujinx.Common.Logging }; } - public ConsoleLogTarget() + public ConsoleLogTarget(string name) { _formatter = new DefaultLogFormatter(); + _name = name; } public void Log(object sender, LogEventArgs args) @@ -44,5 +47,10 @@ namespace Ryujinx.Common.Logging { Console.ResetColor(); } + + public string GetName() + { + return _name; + } } } diff --git a/Ryujinx.Common/Logging/Targets/FileLogTarget.cs b/Ryujinx.Common/Logging/Targets/FileLogTarget.cs index 85dc82497a..16d1c74d26 100644 --- a/Ryujinx.Common/Logging/Targets/FileLogTarget.cs +++ b/Ryujinx.Common/Logging/Targets/FileLogTarget.cs @@ -9,13 +9,15 @@ namespace Ryujinx.Common.Logging private readonly StreamWriter _logWriter; private readonly ILogFormatter _formatter; + private readonly string _name; - public FileLogTarget(string path) - : this(path, FileShare.Read, FileMode.Append) + public FileLogTarget(string path, string name) + : this(path, name, FileShare.Read, FileMode.Append) { } - public FileLogTarget(string path, FileShare fileShare, FileMode fileMode) + public FileLogTarget(string path, string name, FileShare fileShare, FileMode fileMode) { + _name = name; _logWriter = new StreamWriter(File.Open(path, fileMode, FileAccess.Write, fileShare)); _formatter = new DefaultLogFormatter(); } @@ -32,5 +34,10 @@ namespace Ryujinx.Common.Logging _logWriter.Flush(); _logWriter.Dispose(); } + + public string GetName() + { + return _name; + } } } diff --git a/Ryujinx.Common/Logging/Targets/ILogTarget.cs b/Ryujinx.Common/Logging/Targets/ILogTarget.cs index 261c5e64b2..cee1705942 100644 --- a/Ryujinx.Common/Logging/Targets/ILogTarget.cs +++ b/Ryujinx.Common/Logging/Targets/ILogTarget.cs @@ -5,5 +5,7 @@ namespace Ryujinx.Common.Logging public interface ILogTarget : IDisposable { void Log(object sender, LogEventArgs args); + + string GetName(); } } diff --git a/Ryujinx.Common/Logging/Targets/JsonLogTarget.cs b/Ryujinx.Common/Logging/Targets/JsonLogTarget.cs index 410394aa2d..1b7cb1a7fd 100644 --- a/Ryujinx.Common/Logging/Targets/JsonLogTarget.cs +++ b/Ryujinx.Common/Logging/Targets/JsonLogTarget.cs @@ -7,10 +7,12 @@ namespace Ryujinx.Common.Logging { private Stream _stream; private bool _leaveOpen; + private string _name; - public JsonLogTarget(Stream stream) + public JsonLogTarget(Stream stream, string name) { _stream = stream; + _name = name; } public JsonLogTarget(Stream stream, bool leaveOpen) @@ -31,5 +33,10 @@ namespace Ryujinx.Common.Logging _stream.Dispose(); } } + + public string GetName() + { + return _name; + } } } diff --git a/Ryujinx.Common/ReactiveObject.cs b/Ryujinx.Common/ReactiveObject.cs new file mode 100644 index 0000000000..6fa18d3e1a --- /dev/null +++ b/Ryujinx.Common/ReactiveObject.cs @@ -0,0 +1,57 @@ +using System; +using System.Threading; + +namespace Ryujinx.Common +{ + public class ReactiveObject + { + private ReaderWriterLock _readerWriterLock = new ReaderWriterLock(); + private T _value; + + public event EventHandler> Event; + + public T Value + { + get + { + _readerWriterLock.AcquireReaderLock(int.MaxValue); + T value = _value; + _readerWriterLock.ReleaseReaderLock(); + + return value; + } + set + { + _readerWriterLock.AcquireWriterLock(int.MaxValue); + + T oldValue = _value; + + _value = value; + + _readerWriterLock.ReleaseWriterLock(); + + if (oldValue == null || !oldValue.Equals(_value)) + { + Event?.Invoke(this, new ReactiveEventArgs(oldValue, value)); + } + } + } + + public static implicit operator T(ReactiveObject obj) + { + return obj.Value; + } + } + + public class ReactiveEventArgs + { + public T OldValue { get; private set; } + public T Value { get; private set; } + + public ReactiveEventArgs(T oldValue, T value) + { + OldValue = oldValue; + Value = value; + } + } +} diff --git a/Ryujinx.HLE/Switch.cs b/Ryujinx.HLE/Switch.cs index 4a15f616e7..cbfc003849 100644 --- a/Ryujinx.HLE/Switch.cs +++ b/Ryujinx.HLE/Switch.cs @@ -1,8 +1,11 @@ +using LibHac.FsSystem; using Ryujinx.Audio; using Ryujinx.Graphics; using Ryujinx.Graphics.Gal; using Ryujinx.HLE.FileSystem; using Ryujinx.HLE.HOS; +using Ryujinx.HLE.HOS.Services; +using Ryujinx.HLE.HOS.SystemState; using Ryujinx.HLE.Input; using System; using System.Threading; @@ -60,6 +63,29 @@ namespace Ryujinx.HLE VsyncEvent = new AutoResetEvent(true); } + // TODO: Use Configuration when it will be moved to Common. + public void Initialize(SystemLanguage language, bool enableMulticoreScheduling, bool enableDockedMode, bool enableVsync, bool enableFsIntegrityChecks, int fsGlobalAccessLogMode, bool ignoreMissingServices) + { + System.State.SetLanguage(language); + + EnableDeviceVsync = enableVsync; + + System.State.DockedMode = enableDockedMode; + + if (enableMulticoreScheduling) + { + System.EnableMultiCoreScheduling(); + } + + System.FsIntegrityCheckLevel = enableFsIntegrityChecks + ? IntegrityCheckLevel.ErrorOnInvalid + : IntegrityCheckLevel.None; + + System.GlobalAccessLogMode = fsGlobalAccessLogMode; + + ServiceConfiguration.IgnoreMissingServices = ignoreMissingServices; + } + public void LoadCart(string exeFsDir, string romFsFile = null) { System.LoadCart(exeFsDir, romFsFile); diff --git a/Ryujinx/Configuration/Configuration.cs b/Ryujinx/Configuration/Configuration.cs new file mode 100644 index 0000000000..ca1870ccf2 --- /dev/null +++ b/Ryujinx/Configuration/Configuration.cs @@ -0,0 +1,391 @@ +using Ryujinx.Common; +using Ryujinx.Common.Logging; +using Ryujinx.HLE.HOS.SystemState; +using Ryujinx.HLE.Input; +using Ryujinx.Ui.Input; +using System; +using System.Collections.Generic; + +namespace Ryujinx.Configuration +{ + public class ConfigurationState + { + /// + /// UI configuration section + /// + public class UiSection + { + public class Columns + { + public ReactiveObject FavColumn { get; private set; } + public ReactiveObject IconColumn { get; private set; } + public ReactiveObject AppColumn { get; private set; } + public ReactiveObject DevColumn { get; private set; } + public ReactiveObject VersionColumn { get; private set; } + public ReactiveObject TimePlayedColumn { get; private set; } + public ReactiveObject LastPlayedColumn { get; private set; } + public ReactiveObject FileExtColumn { get; private set; } + public ReactiveObject FileSizeColumn { get; private set; } + public ReactiveObject PathColumn { get; private set; } + + public Columns() + { + FavColumn = new ReactiveObject(); + IconColumn = new ReactiveObject(); + AppColumn = new ReactiveObject(); + DevColumn = new ReactiveObject(); + VersionColumn = new ReactiveObject(); + TimePlayedColumn = new ReactiveObject(); + LastPlayedColumn = new ReactiveObject(); + FileExtColumn = new ReactiveObject(); + FileSizeColumn = new ReactiveObject(); + PathColumn = new ReactiveObject(); + } + } + + /// + /// Used to toggle columns in the GUI + /// + // TODO: UPDATE THIS TO MASTER + public Columns GuiColumns { get; private set; } + + /// + /// A list of directories containing games to be used to load games into the games list + /// + public ReactiveObject> GameDirs { get; private set; } + + /// + /// Enable or disable custom themes in the GUI + /// + public ReactiveObject EnableCustomTheme { get; private set; } + + /// + /// Path to custom GUI theme + /// + public ReactiveObject CustomThemePath { get; private set; } + + public UiSection() + { + GuiColumns = new Columns(); + GameDirs = new ReactiveObject>(); + EnableCustomTheme = new ReactiveObject(); + CustomThemePath = new ReactiveObject(); + } + } + + /// + /// Logger configuration section + /// + public class LoggerSection + { + /// + /// Enables printing debug log messages + /// + public ReactiveObject EnableDebug { get; private set; } + + /// + /// Enables printing stub log messages + /// + public ReactiveObject EnableStub { get; private set; } + + /// + /// Enables printing info log messages + /// + public ReactiveObject EnableInfo { get; private set; } + + /// + /// Enables printing warning log messages + /// + public ReactiveObject EnableWarn { get; private set; } + + /// + /// Enables printing error log messages + /// + public ReactiveObject EnableError { get; private set; } + + /// + /// Enables printing guest log messages + /// + public ReactiveObject EnableGuest { get; private set; } + + /// + /// Enables printing FS access log messages + /// + public ReactiveObject EnableFsAccessLog { get; private set; } + + /// + /// Controls which log messages are written to the log targets + /// + public ReactiveObject FilteredClasses { get; private set; } + + /// + /// Enables or disables logging to a file on disk + /// + public ReactiveObject EnableFileLog { get; private set; } + + public LoggerSection() + { + EnableDebug = new ReactiveObject(); + EnableStub = new ReactiveObject(); + EnableInfo = new ReactiveObject(); + EnableWarn = new ReactiveObject(); + EnableError = new ReactiveObject(); + EnableGuest = new ReactiveObject(); + EnableFsAccessLog = new ReactiveObject(); + FilteredClasses = new ReactiveObject(); + EnableFileLog = new ReactiveObject(); + } + } + + /// + /// System configuration section + /// + public class SystemSection + { + /// + /// Change System Language + /// + public ReactiveObject Language { get; private set; } + + /// + /// Enables or disables Docked Mode + /// + public ReactiveObject EnableDockedMode { get; private set; } + + /// + /// Enables or disables multi-core scheduling of threads + /// + public ReactiveObject EnableMulticoreScheduling { get; private set; } + + /// + /// Enables integrity checks on Game content files + /// + public ReactiveObject EnableFsIntegrityChecks { get; private set; } + + /// + /// Enables FS access log output to the console. Possible modes are 0-3 + /// + public ReactiveObject FsGlobalAccessLogMode { get; private set; } + + /// + /// Enable or disable ignoring missing services + /// + public ReactiveObject IgnoreMissingServices { get; private set; } + + public SystemSection() + { + Language = new ReactiveObject(); + EnableDockedMode = new ReactiveObject(); + EnableMulticoreScheduling = new ReactiveObject(); + EnableFsIntegrityChecks = new ReactiveObject(); + FsGlobalAccessLogMode = new ReactiveObject(); + IgnoreMissingServices = new ReactiveObject(); + } + } + + /// + /// Hid configuration section + /// + public class HidSection + { + /// + /// The primary controller's type + /// + public ReactiveObject ControllerType { get; private set; } + + /// + /// Enable or disable keyboard support (Independent from controllers binding) + /// + public ReactiveObject EnableKeyboard { get; private set; } + + /// + /// Keyboard control bindings + /// + public ReactiveObject KeyboardControls { get; private set; } + + /// + /// Controller control bindings + /// + public ReactiveObject JoystickControls { get; private set; } + + public HidSection() + { + ControllerType = new ReactiveObject(); + EnableKeyboard = new ReactiveObject(); + KeyboardControls = new ReactiveObject(); + JoystickControls = new ReactiveObject(); + } + } + + /// + /// Graphics configuration section + /// + public class GraphicsSection + { + /// + /// Dumps shaders in this local directory + /// + public ReactiveObject ShadersDumpPath { get; private set; } + + /// + /// Enables or disables Vertical Sync + /// + public ReactiveObject EnableVsync { get; private set; } + + public GraphicsSection() + { + ShadersDumpPath = new ReactiveObject(); + EnableVsync = new ReactiveObject(); + } + } + + /// + /// The default configuration instance + /// + public static ConfigurationState Instance { get; private set; } + + /// + /// The Ui section + /// + public UiSection Ui { get; private set; } + + /// + /// The Logger section + /// + public LoggerSection Logger { get; private set; } + + /// + /// The System section + /// + public SystemSection System { get; private set; } + + /// + /// The Graphics section + /// + public GraphicsSection Graphics { get; private set; } + + /// + /// The Hid section + /// + public HidSection Hid { get; private set; } + + /// + /// Enables or disables Discord Rich Presence + /// + public ReactiveObject EnableDiscordIntegration { get; private set; } + + private ConfigurationState() + { + Ui = new UiSection(); + Logger = new LoggerSection(); + System = new SystemSection(); + Graphics = new GraphicsSection(); + Hid = new HidSection(); + EnableDiscordIntegration = new ReactiveObject(); + } + + public ConfigurationFileFormat ToFileFormat() + { + ConfigurationFileFormat configurationFile = new ConfigurationFileFormat + { + Version = 1, + GraphicsShadersDumpPath = Graphics.ShadersDumpPath, + LoggingEnableDebug = Logger.EnableDebug, + LoggingEnableStub = Logger.EnableStub, + LoggingEnableInfo = Logger.EnableInfo, + LoggingEnableWarn = Logger.EnableWarn, + LoggingEnableError = Logger.EnableError, + LoggingEnableGuest = Logger.EnableGuest, + LoggingEnableFsAccessLog = Logger.EnableFsAccessLog, + LoggingFilteredClasses = Logger.FilteredClasses, + EnableFileLog = Logger.EnableFileLog, + SystemLanguage = System.Language, + DockedMode = System.EnableDockedMode, + EnableDiscordIntegration = EnableDiscordIntegration, + EnableVsync = Graphics.EnableVsync, + EnableMulticoreScheduling = System.EnableMulticoreScheduling, + EnableFsIntegrityChecks = System.EnableFsIntegrityChecks, + FsGlobalAccessLogMode = System.FsGlobalAccessLogMode, + IgnoreMissingServices = System.IgnoreMissingServices, + ControllerType = Hid.ControllerType, + GuiColumns = new Ui.GuiColumns() + { + FavColumn = Ui.GuiColumns.FavColumn, + IconColumn = Ui.GuiColumns.IconColumn, + AppColumn = Ui.GuiColumns.AppColumn, + DevColumn = Ui.GuiColumns.DevColumn, + VersionColumn = Ui.GuiColumns.VersionColumn, + TimePlayedColumn = Ui.GuiColumns.TimePlayedColumn, + LastPlayedColumn = Ui.GuiColumns.LastPlayedColumn, + FileExtColumn = Ui.GuiColumns.FileExtColumn, + FileSizeColumn = Ui.GuiColumns.FileSizeColumn, + PathColumn = Ui.GuiColumns.PathColumn, + }, + GameDirs = Ui.GameDirs, + EnableCustomTheme = Ui.EnableCustomTheme, + CustomThemePath = Ui.CustomThemePath, + EnableKeyboard = Hid.EnableKeyboard, + KeyboardControls = Hid.KeyboardControls, + JoystickControls = Hid.JoystickControls + }; + + return configurationFile; + } + + public void Load(ConfigurationFileFormat configurationFileFormat) + { + if (configurationFileFormat.Version != 1 && configurationFileFormat.Version != 0) + { + // TODO: load default configuration + throw new System.NotSupportedException($"Unsupported configuration version {configurationFileFormat.Version}"); + } + + Graphics.ShadersDumpPath.Value = configurationFileFormat.GraphicsShadersDumpPath; + Logger.EnableDebug.Value = configurationFileFormat.LoggingEnableDebug; + Logger.EnableStub.Value = configurationFileFormat.LoggingEnableStub; + Logger.EnableInfo.Value = configurationFileFormat.LoggingEnableInfo; + Logger.EnableWarn.Value = configurationFileFormat.LoggingEnableWarn; + Logger.EnableError.Value = configurationFileFormat.LoggingEnableError; + Logger.EnableGuest.Value = configurationFileFormat.LoggingEnableGuest; + Logger.EnableFsAccessLog.Value = configurationFileFormat.LoggingEnableFsAccessLog; + Logger.FilteredClasses.Value = configurationFileFormat.LoggingFilteredClasses; + Logger.EnableFileLog.Value = configurationFileFormat.EnableFileLog; + System.Language.Value = configurationFileFormat.SystemLanguage; + System.EnableDockedMode.Value = configurationFileFormat.DockedMode; + System.EnableDockedMode.Value = configurationFileFormat.DockedMode; + EnableDiscordIntegration.Value = configurationFileFormat.EnableDiscordIntegration; + Graphics.EnableVsync.Value = configurationFileFormat.EnableVsync; + System.EnableMulticoreScheduling.Value = configurationFileFormat.EnableMulticoreScheduling; + System.EnableFsIntegrityChecks.Value = configurationFileFormat.EnableFsIntegrityChecks; + System.FsGlobalAccessLogMode.Value = configurationFileFormat.FsGlobalAccessLogMode; + System.IgnoreMissingServices.Value = configurationFileFormat.IgnoreMissingServices; + Hid.ControllerType.Value = configurationFileFormat.ControllerType; + Ui.GuiColumns.FavColumn.Value = configurationFileFormat.GuiColumns.FavColumn; + Ui.GuiColumns.IconColumn.Value = configurationFileFormat.GuiColumns.IconColumn; + Ui.GuiColumns.AppColumn.Value = configurationFileFormat.GuiColumns.AppColumn; + Ui.GuiColumns.DevColumn.Value = configurationFileFormat.GuiColumns.DevColumn; + Ui.GuiColumns.VersionColumn.Value = configurationFileFormat.GuiColumns.VersionColumn; + Ui.GuiColumns.TimePlayedColumn.Value = configurationFileFormat.GuiColumns.TimePlayedColumn; + Ui.GuiColumns.LastPlayedColumn.Value = configurationFileFormat.GuiColumns.LastPlayedColumn; + Ui.GuiColumns.FileExtColumn.Value = configurationFileFormat.GuiColumns.FileExtColumn; + Ui.GuiColumns.FileSizeColumn.Value = configurationFileFormat.GuiColumns.FileSizeColumn; + Ui.GuiColumns.PathColumn.Value = configurationFileFormat.GuiColumns.PathColumn; + Ui.GameDirs.Value = configurationFileFormat.GameDirs; + Ui.EnableCustomTheme.Value = configurationFileFormat.EnableCustomTheme; + Ui.CustomThemePath.Value = configurationFileFormat.CustomThemePath; + Hid.EnableKeyboard.Value = configurationFileFormat.EnableKeyboard; + Hid.KeyboardControls.Value = configurationFileFormat.KeyboardControls; + Hid.JoystickControls.Value = configurationFileFormat.JoystickControls; + } + + public static void Initialize() + { + if (Instance != null) + { + throw new InvalidOperationException("Configuration is already initialized!"); + } + + Instance = new ConfigurationState(); + } + } +} diff --git a/Ryujinx/Configuration.cs b/Ryujinx/Configuration/ConfigurationFileFormat.cs similarity index 56% rename from Ryujinx/Configuration.cs rename to Ryujinx/Configuration/ConfigurationFileFormat.cs index c259f9e9d4..4c9ec26ba8 100644 --- a/Ryujinx/Configuration.cs +++ b/Ryujinx/Configuration/ConfigurationFileFormat.cs @@ -13,18 +13,14 @@ using System; using System.Collections.Generic; using System.IO; using System.Text; -using System.Threading.Tasks; using Utf8Json; using Utf8Json.Resolvers; -namespace Ryujinx +namespace Ryujinx.Configuration { - public class Configuration + public class ConfigurationFileFormat { - /// - /// The default configuration instance - /// - public static Configuration Instance { get; private set; } + public int Version { get; set; } /// /// Dumps shaders in this local directory @@ -154,13 +150,13 @@ namespace Ryujinx /// /// Controller control bindings /// - public Ui.Input.NpadController JoystickControls { get; private set; } + public Ui.Input.NpadController JoystickControls { get; set; } /// /// Loads a configuration file from disk /// /// The path to the JSON configuration file - public static void Load(string path) + public static ConfigurationFileFormat Load(string path) { var resolver = CompositeResolver.Create( new[] { new ConfigurationEnumFormatter() }, @@ -169,24 +165,7 @@ namespace Ryujinx using (Stream stream = File.OpenRead(path)) { - Instance = JsonSerializer.Deserialize(stream, resolver); - } - } - - /// - /// Loads a configuration file asynchronously from disk - /// - /// The path to the JSON configuration file - public static async Task LoadAsync(string path) - { - IJsonFormatterResolver resolver = CompositeResolver.Create( - new[] { new ConfigurationEnumFormatter() }, - new[] { StandardResolver.AllowPrivateSnakeCase } - ); - - using (Stream stream = File.OpenRead(path)) - { - Instance = await JsonSerializer.DeserializeAsync(stream, resolver); + return JsonSerializer.Deserialize(stream, resolver); } } @@ -194,108 +173,17 @@ namespace Ryujinx /// Save a configuration file to disk /// /// The path to the JSON configuration file - public static void SaveConfig(Configuration config, string path) + public void SaveConfig(string path) { IJsonFormatterResolver resolver = CompositeResolver.Create( new[] { new ConfigurationEnumFormatter() }, new[] { StandardResolver.AllowPrivateSnakeCase } ); - byte[] data = JsonSerializer.Serialize(config, resolver); + byte[] data = JsonSerializer.Serialize(this, resolver); File.WriteAllText(path, Encoding.UTF8.GetString(data, 0, data.Length).PrettyPrintJson()); } - /// - /// Configures a instance - /// - /// The instance to configure - public static void InitialConfigure(Switch device) - { - if (Instance == null) - { - throw new InvalidOperationException("Configuration has not been loaded yet."); - } - - SwitchSettings.ConfigureSettings(Instance); - - Logger.AddTarget(new AsyncLogTargetWrapper( - new ConsoleLogTarget(), - 1000, - AsyncLogTargetOverflowAction.Block - )); - - if (Instance.EnableFileLog) - { - Logger.AddTarget(new AsyncLogTargetWrapper( - new FileLogTarget(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Ryujinx.log")), - 1000, - AsyncLogTargetOverflowAction.Block - )); - } - - Configure(device, Instance); - } - - public static void Configure(Switch device, Configuration SwitchConfig) - { - GraphicsConfig.ShadersDumpPath = SwitchConfig.GraphicsShadersDumpPath; - - Logger.SetEnable(LogLevel.Debug, SwitchConfig.LoggingEnableDebug ); - Logger.SetEnable(LogLevel.Stub, SwitchConfig.LoggingEnableStub ); - Logger.SetEnable(LogLevel.Info, SwitchConfig.LoggingEnableInfo ); - Logger.SetEnable(LogLevel.Warning, SwitchConfig.LoggingEnableWarn ); - Logger.SetEnable(LogLevel.Error, SwitchConfig.LoggingEnableError ); - Logger.SetEnable(LogLevel.Guest, SwitchConfig.LoggingEnableGuest ); - Logger.SetEnable(LogLevel.AccessLog, SwitchConfig.LoggingEnableFsAccessLog); - - if (SwitchConfig.LoggingFilteredClasses.Length > 0) - { - foreach (var logClass in EnumExtensions.GetValues()) - { - Logger.SetEnable(logClass, false); - } - - foreach (var logClass in SwitchConfig.LoggingFilteredClasses) - { - Logger.SetEnable(logClass, true); - } - } - - MainWindow.DiscordIntegrationEnabled = SwitchConfig.EnableDiscordIntegration; - - device.EnableDeviceVsync = SwitchConfig.EnableVsync; - - device.System.State.DockedMode = SwitchConfig.DockedMode; - - device.System.State.SetLanguage(SwitchConfig.SystemLanguage); - - if (SwitchConfig.EnableMulticoreScheduling) - { - device.System.EnableMultiCoreScheduling(); - } - - device.System.FsIntegrityCheckLevel = SwitchConfig.EnableFsIntegrityChecks - ? IntegrityCheckLevel.ErrorOnInvalid - : IntegrityCheckLevel.None; - - device.System.GlobalAccessLogMode = SwitchConfig.FsGlobalAccessLogMode; - - ServiceConfiguration.IgnoreMissingServices = SwitchConfig.IgnoreMissingServices; - } - - public static void ConfigureHid(Switch device, Configuration SwitchConfig) - { - if (SwitchConfig.JoystickControls.Enabled) - { - if (!Joystick.GetState(SwitchConfig.JoystickControls.Index).IsConnected) - { - SwitchConfig.JoystickControls.SetEnabled(false); - } - } - device.Hid.InitializePrimaryController(SwitchConfig.ControllerType); - device.Hid.InitializeKeyboard(); - } - private class ConfigurationEnumFormatter : IJsonFormatter where T : struct { diff --git a/Ryujinx/Configuration/DiscordIntegrationModule.cs b/Ryujinx/Configuration/DiscordIntegrationModule.cs new file mode 100644 index 0000000000..4619353f10 --- /dev/null +++ b/Ryujinx/Configuration/DiscordIntegrationModule.cs @@ -0,0 +1,90 @@ +using DiscordRPC; +using Ryujinx.Common; +using System; +using System.IO; +using System.Linq; + +namespace Ryujinx.Configuration +{ + static class DiscordIntegrationModule + { + private static DiscordRpcClient DiscordClient; + + public static RichPresence DiscordPresence { get; private set; } + + public static void Initialize() + { + 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) + }; + + ConfigurationState.Instance.EnableDiscordIntegration.Event += Update; + } + + private static void Update(object sender, ReactiveEventArgs e) + { + if (e.OldValue != e.Value) + { + // If the integration was active, disable it and unload everything + if (e.OldValue) + { + DiscordClient?.Dispose(); + + DiscordClient = null; + } + + // If we need to activate it and the client isn't active, initialize it + if (e.Value && DiscordClient == null) + { + DiscordClient = new DiscordRpcClient("568815339807309834"); + + DiscordClient.Initialize(); + DiscordClient.SetPresence(DiscordPresence); + } + } + } + + public static void SwitchToPlayingState(string titleId, string titleName) + { + if (File.ReadAllLines(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "RPsupported.dat")).Contains(titleId)) + { + DiscordPresence.Assets.LargeImageKey = titleId; + } + + string state = titleId; + + if (state == null) + { + state = "Ryujinx"; + } + else + { + state = state.ToUpper(); + } + + string details = "Idling"; + + if (titleName != null) + { + details = $"Playing {titleName}"; + } + + DiscordPresence.Details = details; + DiscordPresence.State = state; + DiscordPresence.Assets.LargeImageText = 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); + } + } +} diff --git a/Ryujinx/Configuration/LoggerModule.cs b/Ryujinx/Configuration/LoggerModule.cs new file mode 100644 index 0000000000..f5db0eed92 --- /dev/null +++ b/Ryujinx/Configuration/LoggerModule.cs @@ -0,0 +1,112 @@ +using Ryujinx.Common; +using Ryujinx.Common.Logging; +using System; +using System.IO; + +namespace Ryujinx.Configuration +{ + public static class LoggerModule + { + public static void Initialize() + { + AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; + AppDomain.CurrentDomain.ProcessExit += CurrentDomain_ProcessExit; + + ConfigurationState.Instance.Logger.EnableDebug.Event += ReloadEnableDebug; + ConfigurationState.Instance.Logger.EnableStub.Event += ReloadEnableStub; + ConfigurationState.Instance.Logger.EnableInfo.Event += ReloadEnableInfo; + ConfigurationState.Instance.Logger.EnableWarn.Event += ReloadEnableWarning; + ConfigurationState.Instance.Logger.EnableError.Event += ReloadEnableError; + ConfigurationState.Instance.Logger.EnableGuest.Event += ReloadEnableGuest; + ConfigurationState.Instance.Logger.EnableFsAccessLog.Event += ReloadEnableFsAccessLog; + ConfigurationState.Instance.Logger.FilteredClasses.Event += ReloadFilteredClasses; + ConfigurationState.Instance.Logger.EnableFileLog.Event += ReloadFileLogger; + } + + private static void ReloadEnableDebug(object sender, ReactiveEventArgs e) + { + Logger.SetEnable(LogLevel.Debug, e.Value); + } + + private static void ReloadEnableStub(object sender, ReactiveEventArgs e) + { + Logger.SetEnable(LogLevel.Stub, e.Value); + } + + private static void ReloadEnableInfo(object sender, ReactiveEventArgs e) + { + Logger.SetEnable(LogLevel.Info, e.Value); + } + + private static void ReloadEnableWarning(object sender, ReactiveEventArgs e) + { + Logger.SetEnable(LogLevel.Warning, e.Value); + } + + private static void ReloadEnableError(object sender, ReactiveEventArgs e) + { + Logger.SetEnable(LogLevel.Error, e.Value); + } + + private static void ReloadEnableGuest(object sender, ReactiveEventArgs e) + { + Logger.SetEnable(LogLevel.Guest, e.Value); + } + + private static void ReloadEnableFsAccessLog(object sender, ReactiveEventArgs e) + { + Logger.SetEnable(LogLevel.AccessLog, e.Value); + } + + private static void ReloadFilteredClasses(object sender, ReactiveEventArgs e) + { + bool noFilter = e.Value.Length == 0; + + foreach (var logClass in EnumExtensions.GetValues()) + { + Logger.SetEnable(logClass, noFilter); + } + + foreach (var logClass in e.Value) + { + Logger.SetEnable(logClass, true); + } + } + + private static void ReloadFileLogger(object sender, ReactiveEventArgs e) + { + if (e.Value != e.OldValue) + { + if (e.Value) + { + Logger.AddTarget(new AsyncLogTargetWrapper( + new FileLogTarget(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Ryujinx.log"), "file"), + 1000, + AsyncLogTargetOverflowAction.Block + )); + } + else + { + Logger.RemoveTarget("file"); + } + } + } + + private static void CurrentDomain_ProcessExit(object sender, EventArgs e) + { + Logger.Shutdown(); + } + + private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) + { + var exception = e.ExceptionObject as Exception; + + Logger.PrintError(LogClass.Emulation, $"Unhandled exception caught: {exception}"); + + if (e.IsTerminating) + { + Logger.Shutdown(); + } + } + } +} diff --git a/Ryujinx/Program.cs b/Ryujinx/Program.cs index 96e9e8dec2..1c02ec66c6 100644 --- a/Ryujinx/Program.cs +++ b/Ryujinx/Program.cs @@ -1,5 +1,6 @@ using Gtk; using Ryujinx.Common.Logging; +using Ryujinx.Configuration; using Ryujinx.Profiler; using Ryujinx.Ui; using System; @@ -16,9 +17,20 @@ namespace Ryujinx string systemPath = Environment.GetEnvironmentVariable("Path", EnvironmentVariableTarget.Machine); Environment.SetEnvironmentVariable("Path", $"{Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "bin")};{systemPath}"); - AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; - AppDomain.CurrentDomain.ProcessExit += CurrentDomain_ProcessExit; - GLib.ExceptionManager.UnhandledException += Glib_UnhandledException; + GLib.ExceptionManager.UnhandledException += Glib_UnhandledException; + + // Initialize the configuration + ConfigurationState.Initialize(); + + // Initialize the logger system + LoggerModule.Initialize(); + + // Initialize Discord integration + DiscordIntegrationModule.Initialize(); + + // Now load the configuration as the other subsystem are now registered + ConfigurationFileFormat configurationFileFormat = ConfigurationFileFormat.Load(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json")); + ConfigurationState.Instance.Load(configurationFileFormat); Profile.Initialize(); @@ -42,23 +54,6 @@ namespace Ryujinx Application.Run(); } - private static void CurrentDomain_ProcessExit(object sender, EventArgs e) - { - Logger.Shutdown(); - } - - private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) - { - Exception exception = e.ExceptionObject as Exception; - - Logger.PrintError(LogClass.Emulation, $"Unhandled exception caught: {exception}"); - - if (e.IsTerminating) - { - Logger.Shutdown(); - } - } - private static void Glib_UnhandledException(GLib.UnhandledExceptionArgs e) { Exception exception = e.ExceptionObject as Exception; diff --git a/Ryujinx/Ui/GLScreen.cs b/Ryujinx/Ui/GLScreen.cs index c23a369294..3ed522e10d 100644 --- a/Ryujinx/Ui/GLScreen.cs +++ b/Ryujinx/Ui/GLScreen.cs @@ -1,10 +1,10 @@ using OpenTK; using OpenTK.Graphics; using OpenTK.Input; +using Ryujinx.Configuration; using Ryujinx.Graphics.Gal; using Ryujinx.HLE; using Ryujinx.HLE.Input; -using Ryujinx.Profiler.UI; using System; using System.Threading; @@ -162,16 +162,16 @@ namespace Ryujinx.Ui #endif // Normal Input - currentHotkeyButtons = Configuration.Instance.KeyboardControls.GetHotkeyButtons(keyboard); - currentButton = Configuration.Instance.KeyboardControls.GetButtons(keyboard); + currentHotkeyButtons = ConfigurationState.Instance.Hid.KeyboardControls.Value.GetHotkeyButtons(keyboard); + currentButton = ConfigurationState.Instance.Hid.KeyboardControls.Value.GetButtons(keyboard); - if (Configuration.Instance.EnableKeyboard) + if (ConfigurationState.Instance.Hid.EnableKeyboard) { - hidKeyboard = Configuration.Instance.KeyboardControls.GetKeysDown(keyboard); + hidKeyboard = ConfigurationState.Instance.Hid.KeyboardControls.Value.GetKeysDown(keyboard); } - (leftJoystickDx, leftJoystickDy) = Configuration.Instance.KeyboardControls.GetLeftStick(keyboard); - (rightJoystickDx, rightJoystickDy) = Configuration.Instance.KeyboardControls.GetRightStick(keyboard); + (leftJoystickDx, leftJoystickDy) = ConfigurationState.Instance.Hid.KeyboardControls.Value.GetLeftStick(keyboard); + (rightJoystickDx, rightJoystickDy) = ConfigurationState.Instance.Hid.KeyboardControls.Value.GetRightStick(keyboard); } if (!hidKeyboard.HasValue) @@ -183,17 +183,17 @@ namespace Ryujinx.Ui }; } - currentButton |= Configuration.Instance.JoystickControls.GetButtons(); + currentButton |= ConfigurationState.Instance.Hid.JoystickControls.Value.GetButtons(); // Keyboard has priority stick-wise if (leftJoystickDx == 0 && leftJoystickDy == 0) { - (leftJoystickDx, leftJoystickDy) = Configuration.Instance.JoystickControls.GetLeftStick(); + (leftJoystickDx, leftJoystickDy) = ConfigurationState.Instance.Hid.JoystickControls.Value.GetLeftStick(); } if (rightJoystickDx == 0 && rightJoystickDy == 0) { - (rightJoystickDx, rightJoystickDy) = Configuration.Instance.JoystickControls.GetRightStick(); + (rightJoystickDx, rightJoystickDy) = ConfigurationState.Instance.Hid.JoystickControls.Value.GetRightStick(); } leftJoystick = new JoystickPosition @@ -269,7 +269,7 @@ namespace Ryujinx.Ui _device.Hid.SetTouchPoints(); } - if (Configuration.Instance.EnableKeyboard && hidKeyboard.HasValue) + if (ConfigurationState.Instance.Hid.EnableKeyboard && hidKeyboard.HasValue) { _device.Hid.WriteKeyboard(hidKeyboard.Value); } diff --git a/Ryujinx/Ui/MainWindow.cs b/Ryujinx/Ui/MainWindow.cs index a24f3ed050..58595f1d1c 100644 --- a/Ryujinx/Ui/MainWindow.cs +++ b/Ryujinx/Ui/MainWindow.cs @@ -1,24 +1,25 @@ -using DiscordRPC; using Gtk; -using JsonPrettyPrinterPlus; using Ryujinx.Audio; using Ryujinx.Common.Logging; -using Ryujinx.Graphics.Gal.OpenGL; using Ryujinx.Graphics.Gal; -using Ryujinx.HLE.FileSystem; +using Ryujinx.Graphics.Gal.OpenGL; using Ryujinx.Profiler; using System; -using System.Diagnostics; using System.IO; -using System.Linq; using System.Reflection; using System.Text; -using System.Threading.Tasks; using System.Threading; -using Utf8Json; -using Utf8Json.Resolvers; +using Ryujinx.Configuration; +using System.Diagnostics; +using OpenTK.Input; +using Ryujinx.Ui.Input; using GUI = Gtk.Builder.ObjectAttribute; +using System.Threading.Tasks; +using Utf8Json; +using JsonPrettyPrinterPlus; +using Utf8Json.Resolvers; +using Ryujinx.HLE.FileSystem; namespace Ryujinx.Ui { @@ -50,12 +51,6 @@ namespace Ryujinx.Ui private static TreeView _treeView; - public static bool DiscordIntegrationEnabled { get; set; } - - public static DiscordRpcClient DiscordClient; - - public static RichPresence DiscordPresence; - #pragma warning disable CS0649 #pragma warning disable IDE0044 [GUI] Window _mainWin; @@ -71,7 +66,9 @@ namespace Ryujinx.Ui [GUI] CheckMenuItem _fileExtToggle; [GUI] CheckMenuItem _fileSizeToggle; [GUI] CheckMenuItem _pathToggle; + [GUI] Box _box; [GUI] TreeView _gameTable; + [GUI] GLArea _glScreen; [GUI] Label _progressLabel; [GUI] LevelBar _progressBar; #pragma warning restore CS0649 @@ -91,60 +88,39 @@ namespace Ryujinx.Ui _audioOut = InitializeAudioEngine(); - _device = new HLE.Switch(_renderer, _audioOut); + // TODO: Initialization and dispose of HLE.Switch when starting/stoping emulation. + _device = InitializeSwitchInstance(); _treeView = _gameTable; - Configuration.Load(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json")); - Configuration.InitialConfigure(_device); - ApplyTheme(); - if (DiscordIntegrationEnabled) - { - 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); - } - _mainWin.Icon = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.Icon.png"); _stopEmulation.Sensitive = false; - if (SwitchSettings.SwitchConfig.GuiColumns.FavColumn) { _favToggle.Active = true; } - if (SwitchSettings.SwitchConfig.GuiColumns.IconColumn) { _iconToggle.Active = true; } - if (SwitchSettings.SwitchConfig.GuiColumns.AppColumn) { _appToggle.Active = true; } - if (SwitchSettings.SwitchConfig.GuiColumns.DevColumn) { _developerToggle.Active = true; } - if (SwitchSettings.SwitchConfig.GuiColumns.VersionColumn) { _versionToggle.Active = true; } - if (SwitchSettings.SwitchConfig.GuiColumns.TimePlayedColumn) { _timePlayedToggle.Active = true; } - if (SwitchSettings.SwitchConfig.GuiColumns.LastPlayedColumn) { _lastPlayedToggle.Active = true; } - if (SwitchSettings.SwitchConfig.GuiColumns.FileExtColumn) { _fileExtToggle.Active = true; } - if (SwitchSettings.SwitchConfig.GuiColumns.FileSizeColumn) { _fileSizeToggle.Active = true; } - if (SwitchSettings.SwitchConfig.GuiColumns.PathColumn) { _pathToggle.Active = true; } + if (ConfigurationState.Instance.Ui.GuiColumns.FavColumn) { _favToggle.Active = true; } + if (ConfigurationState.Instance.Ui.GuiColumns.IconColumn) { _iconToggle.Active = true; } + if (ConfigurationState.Instance.Ui.GuiColumns.AppColumn) { _appToggle.Active = true; } + if (ConfigurationState.Instance.Ui.GuiColumns.DevColumn) { _developerToggle.Active = true; } + if (ConfigurationState.Instance.Ui.GuiColumns.VersionColumn) { _versionToggle.Active = true; } + if (ConfigurationState.Instance.Ui.GuiColumns.TimePlayedColumn) { _timePlayedToggle.Active = true; } + if (ConfigurationState.Instance.Ui.GuiColumns.LastPlayedColumn) { _lastPlayedToggle.Active = true; } + if (ConfigurationState.Instance.Ui.GuiColumns.FileExtColumn) { _fileExtToggle.Active = true; } + if (ConfigurationState.Instance.Ui.GuiColumns.FileSizeColumn) { _fileSizeToggle.Active = true; } + if (ConfigurationState.Instance.Ui.GuiColumns.PathColumn) { _pathToggle.Active = true; } _gameTable.Model = _tableStore = new ListStore( - typeof(bool), - typeof(Gdk.Pixbuf), - typeof(string), - typeof(string), - typeof(string), - typeof(string), - typeof(string), - typeof(string), - typeof(string), + typeof(bool), + typeof(Gdk.Pixbuf), + typeof(string), + typeof(string), + typeof(string), + typeof(string), + typeof(string), + typeof(string), + typeof(string), typeof(string)); - + _tableStore.SetSortFunc(5, TimePlayedSort); _tableStore.SetSortFunc(6, LastPlayedSort); _tableStore.SetSortFunc(8, FileSizeSort); @@ -158,22 +134,22 @@ namespace Ryujinx.Ui internal static void ApplyTheme() { - if (!SwitchSettings.SwitchConfig.EnableCustomTheme) + if (!ConfigurationState.Instance.Ui.EnableCustomTheme) { return; } - if (File.Exists(SwitchSettings.SwitchConfig.CustomThemePath) && (System.IO.Path.GetExtension(SwitchSettings.SwitchConfig.CustomThemePath) == ".css")) + if (File.Exists(ConfigurationState.Instance.Ui.CustomThemePath) && (System.IO.Path.GetExtension(ConfigurationState.Instance.Ui.CustomThemePath) == ".css")) { CssProvider cssProvider = new CssProvider(); - cssProvider.LoadFromPath(SwitchSettings.SwitchConfig.CustomThemePath); + cssProvider.LoadFromPath(ConfigurationState.Instance.Ui.CustomThemePath); StyleContext.AddProviderForScreen(Gdk.Screen.Default, cssProvider, 800); } else { - Logger.PrintWarning(LogClass.Application, $"The \"custom_theme_path\" section in \"Config.json\" contains an invalid path: \"{SwitchSettings.SwitchConfig.CustomThemePath}\"."); + Logger.PrintWarning(LogClass.Application, $"The \"custom_theme_path\" section in \"Config.json\" contains an invalid path: \"{ConfigurationState.Instance.Ui.CustomThemePath}\"."); } } @@ -187,16 +163,16 @@ namespace Ryujinx.Ui CellRendererToggle favToggle = new CellRendererToggle(); favToggle.Toggled += FavToggle_Toggled; - if (SwitchSettings.SwitchConfig.GuiColumns.FavColumn) { _gameTable.AppendColumn("Fav", favToggle, "active", 0); } - if (SwitchSettings.SwitchConfig.GuiColumns.IconColumn) { _gameTable.AppendColumn("Icon", new CellRendererPixbuf(), "pixbuf", 1); } - if (SwitchSettings.SwitchConfig.GuiColumns.AppColumn) { _gameTable.AppendColumn("Application", new CellRendererText(), "text", 2); } - if (SwitchSettings.SwitchConfig.GuiColumns.DevColumn) { _gameTable.AppendColumn("Developer", new CellRendererText(), "text", 3); } - if (SwitchSettings.SwitchConfig.GuiColumns.VersionColumn) { _gameTable.AppendColumn("Version", new CellRendererText(), "text", 4); } - if (SwitchSettings.SwitchConfig.GuiColumns.TimePlayedColumn) { _gameTable.AppendColumn("Time Played", new CellRendererText(), "text", 5); } - if (SwitchSettings.SwitchConfig.GuiColumns.LastPlayedColumn) { _gameTable.AppendColumn("Last Played", new CellRendererText(), "text", 6); } - if (SwitchSettings.SwitchConfig.GuiColumns.FileExtColumn) { _gameTable.AppendColumn("File Ext", new CellRendererText(), "text", 7); } - if (SwitchSettings.SwitchConfig.GuiColumns.FileSizeColumn) { _gameTable.AppendColumn("File Size", new CellRendererText(), "text", 8); } - if (SwitchSettings.SwitchConfig.GuiColumns.PathColumn) { _gameTable.AppendColumn("Path", new CellRendererText(), "text", 9); } + if (ConfigurationState.Instance.Ui.GuiColumns.FavColumn) { _gameTable.AppendColumn("Fav", favToggle, "active", 0); } + if (ConfigurationState.Instance.Ui.GuiColumns.IconColumn) { _gameTable.AppendColumn("Icon", new CellRendererPixbuf(), "pixbuf", 1); } + if (ConfigurationState.Instance.Ui.GuiColumns.AppColumn) { _gameTable.AppendColumn("Application", new CellRendererText(), "text", 2); } + if (ConfigurationState.Instance.Ui.GuiColumns.DevColumn) { _gameTable.AppendColumn("Developer", new CellRendererText(), "text", 3); } + if (ConfigurationState.Instance.Ui.GuiColumns.VersionColumn) { _gameTable.AppendColumn("Version", new CellRendererText(), "text", 4); } + if (ConfigurationState.Instance.Ui.GuiColumns.TimePlayedColumn) { _gameTable.AppendColumn("Time Played", new CellRendererText(), "text", 5); } + if (ConfigurationState.Instance.Ui.GuiColumns.LastPlayedColumn) { _gameTable.AppendColumn("Last Played", new CellRendererText(), "text", 6); } + if (ConfigurationState.Instance.Ui.GuiColumns.FileExtColumn) { _gameTable.AppendColumn("File Ext", new CellRendererText(), "text", 7); } + if (ConfigurationState.Instance.Ui.GuiColumns.FileSizeColumn) { _gameTable.AppendColumn("File Size", new CellRendererText(), "text", 8); } + if (ConfigurationState.Instance.Ui.GuiColumns.PathColumn) { _gameTable.AppendColumn("Path", new CellRendererText(), "text", 9); } foreach (TreeViewColumn column in _gameTable.Columns) { @@ -211,15 +187,24 @@ namespace Ryujinx.Ui else if (column.Title == "Path") { _pathColumn = column; } } - if (SwitchSettings.SwitchConfig.GuiColumns.FavColumn) { _favColumn.SortColumnId = 0; } - if (SwitchSettings.SwitchConfig.GuiColumns.IconColumn) { _appColumn.SortColumnId = 2; } - if (SwitchSettings.SwitchConfig.GuiColumns.AppColumn) { _devColumn.SortColumnId = 3; } - if (SwitchSettings.SwitchConfig.GuiColumns.DevColumn) { _versionColumn.SortColumnId = 4; } - if (SwitchSettings.SwitchConfig.GuiColumns.TimePlayedColumn) { _timePlayedColumn.SortColumnId = 5; } - if (SwitchSettings.SwitchConfig.GuiColumns.LastPlayedColumn) { _lastPlayedColumn.SortColumnId = 6; } - if (SwitchSettings.SwitchConfig.GuiColumns.FileExtColumn) { _fileExtColumn.SortColumnId = 7; } - if (SwitchSettings.SwitchConfig.GuiColumns.FileSizeColumn) { _fileSizeColumn.SortColumnId = 8; } - if (SwitchSettings.SwitchConfig.GuiColumns.PathColumn) { _pathColumn.SortColumnId = 9; } + if (ConfigurationState.Instance.Ui.GuiColumns.FavColumn) { _favColumn.SortColumnId = 0; } + if (ConfigurationState.Instance.Ui.GuiColumns.IconColumn) { _appColumn.SortColumnId = 2; } + if (ConfigurationState.Instance.Ui.GuiColumns.AppColumn) { _devColumn.SortColumnId = 3; } + if (ConfigurationState.Instance.Ui.GuiColumns.DevColumn) { _versionColumn.SortColumnId = 4; } + if (ConfigurationState.Instance.Ui.GuiColumns.TimePlayedColumn) { _timePlayedColumn.SortColumnId = 5; } + if (ConfigurationState.Instance.Ui.GuiColumns.LastPlayedColumn) { _lastPlayedColumn.SortColumnId = 6; } + if (ConfigurationState.Instance.Ui.GuiColumns.FileExtColumn) { _fileExtColumn.SortColumnId = 7; } + if (ConfigurationState.Instance.Ui.GuiColumns.FileSizeColumn) { _fileSizeColumn.SortColumnId = 8; } + if (ConfigurationState.Instance.Ui.GuiColumns.PathColumn) { _pathColumn.SortColumnId = 9; } + } + + private HLE.Switch InitializeSwitchInstance() + { + HLE.Switch instance = new HLE.Switch(_renderer, _audioOut); + + instance.Initialize(ConfigurationState.Instance.System.Language, ConfigurationState.Instance.System.EnableMulticoreScheduling, ConfigurationState.Instance.System.EnableDockedMode, ConfigurationState.Instance.Graphics.EnableVsync, ConfigurationState.Instance.System.EnableFsIntegrityChecks, ConfigurationState.Instance.System.FsGlobalAccessLogMode, ConfigurationState.Instance.System.IgnoreMissingServices); + + return instance; } internal static async Task UpdateGameTable() @@ -233,7 +218,7 @@ namespace Ryujinx.Ui _tableStore.Clear(); - await Task.Run(() => ApplicationLibrary.LoadApplications(SwitchSettings.SwitchConfig.GameDirs, _device.System.KeySet, _device.System.State.DesiredTitleLanguage)); + await Task.Run(() => ApplicationLibrary.LoadApplications(ConfigurationState.Instance.Ui.GameDirs, _device.System.KeySet, _device.System.State.DesiredTitleLanguage)); _updatingGameTable = false; } @@ -248,6 +233,9 @@ namespace Ryujinx.Ui { Logger.RestartTime(); + // TODO: move this somewhere else + reloadable + GraphicsConfig.ShadersDumpPath = ConfigurationState.Instance.Graphics.ShadersDumpPath; + if (Directory.Exists(path)) { string[] romFsFiles = Directory.GetFiles(path, "*.istorage"); @@ -313,40 +301,7 @@ namespace Ryujinx.Ui _gameLoaded = true; _stopEmulation.Sensitive = true; - if (DiscordIntegrationEnabled) - { - if (File.ReadAllLines(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "RPsupported.dat")).Contains(_device.System.TitleId)) - { - DiscordPresence.Assets.LargeImageKey = _device.System.TitleId; - } - - string state = _device.System.TitleId; - - if (state == null) - { - state = "Ryujinx"; - } - else - { - state = state.ToUpper(); - } - - string details = "Idling"; - - if (_device.System.TitleName != null) - { - details = $"Playing {_device.System.TitleName}"; - } - - DiscordPresence.Details = details; - DiscordPresence.State = state; - 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); - } + 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"); @@ -382,10 +337,26 @@ namespace Ryujinx.Ui } } + // TODO: Make HLE.Switch handle the state itself + reloading + private static void ConfigureHid() + { + NpadController controller = ConfigurationState.Instance.Hid.JoystickControls.Value; + + if (controller.Enabled) + { + if (!Joystick.GetState(controller.Index).IsConnected) + { + controller.SetEnabled(false); + } + } + _device.Hid.InitializePrimaryController(ConfigurationState.Instance.Hid.ControllerType); + _device.Hid.InitializeKeyboard(); + } + private static void CreateGameWindow() { - Configuration.ConfigureHid(_device, SwitchSettings.SwitchConfig); - + ConfigureHid(); + using (_screen = new GlScreen(_device, _renderer)) { _screen.MainLoop(); @@ -394,6 +365,7 @@ namespace Ryujinx.Ui } } + private static void End() { if (_ending) @@ -444,7 +416,6 @@ namespace Ryujinx.Ui Profile.FinishProfiling(); _device.Dispose(); _audioOut.Dispose(); - DiscordClient?.Dispose(); Logger.Shutdown(); Environment.Exit(0); } @@ -527,7 +498,7 @@ namespace Ryujinx.Ui private void Row_Activated(object sender, RowActivatedArgs args) { _tableStore.GetIter(out TreeIter treeIter, new TreePath(args.Path.ToString())); - string path = (string)_tableStore.GetValue(treeIter, 9); + string path = (string)_tableStore.GetValue(treeIter, 8); LoadApplication(path); } @@ -607,13 +578,13 @@ namespace Ryujinx.Ui private void Settings_Pressed(object sender, EventArgs args) { - SwitchSettings settingsWin = new SwitchSettings(_device); + SwitchSettings settingsWin = new SwitchSettings(); settingsWin.Show(); } - private void Update_Pressed(object sender, EventArgs args) + private void Update_Pressed(object o, EventArgs args) { - string ryuUpdater = System.IO.Path.Combine(new VirtualFileSystem().GetBasePath(), "RyuUpdater.exe"); + string ryuUpdater = System.IO.Path.Combine(new VirtualFileSystem().GetBasePath(), "RyuFS", "RyuUpdater.exe"); try { @@ -633,121 +604,81 @@ namespace Ryujinx.Ui private void Fav_Toggled(object sender, EventArgs args) { - GuiColumns updatedColumns = SwitchSettings.SwitchConfig.GuiColumns; - - updatedColumns.FavColumn = _favToggle.Active; - SwitchSettings.SwitchConfig.GuiColumns = updatedColumns; - - Configuration.SaveConfig(SwitchSettings.SwitchConfig, System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json")); + ConfigurationState.Instance.Ui.GuiColumns.FavColumn.Value = _favToggle.Active; + SaveConfig(); UpdateColumns(); } private void Icon_Toggled(object sender, EventArgs args) { - GuiColumns updatedColumns = SwitchSettings.SwitchConfig.GuiColumns; - - updatedColumns.IconColumn = _iconToggle.Active; - SwitchSettings.SwitchConfig.GuiColumns = updatedColumns; - - Configuration.SaveConfig(SwitchSettings.SwitchConfig, System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json")); + ConfigurationState.Instance.Ui.GuiColumns.IconColumn.Value = _iconToggle.Active; + SaveConfig(); UpdateColumns(); } private void Title_Toggled(object sender, EventArgs args) { - GuiColumns updatedColumns = SwitchSettings.SwitchConfig.GuiColumns; - - updatedColumns.AppColumn = _appToggle.Active; - SwitchSettings.SwitchConfig.GuiColumns = updatedColumns; - - Configuration.SaveConfig(SwitchSettings.SwitchConfig, System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json")); + ConfigurationState.Instance.Ui.GuiColumns.AppColumn.Value = _appToggle.Active; + SaveConfig(); UpdateColumns(); } private void Developer_Toggled(object sender, EventArgs args) { - GuiColumns updatedColumns = SwitchSettings.SwitchConfig.GuiColumns; - - updatedColumns.DevColumn = _developerToggle.Active; - SwitchSettings.SwitchConfig.GuiColumns = updatedColumns; - - Configuration.SaveConfig(SwitchSettings.SwitchConfig, System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json")); + ConfigurationState.Instance.Ui.GuiColumns.DevColumn.Value = _developerToggle.Active; + SaveConfig(); UpdateColumns(); } private void Version_Toggled(object sender, EventArgs args) { - GuiColumns updatedColumns = SwitchSettings.SwitchConfig.GuiColumns; - - updatedColumns.VersionColumn = _versionToggle.Active; - SwitchSettings.SwitchConfig.GuiColumns = updatedColumns; - - Configuration.SaveConfig(SwitchSettings.SwitchConfig, System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json")); + ConfigurationState.Instance.Ui.GuiColumns.VersionColumn.Value = _versionToggle.Active; + SaveConfig(); UpdateColumns(); } private void TimePlayed_Toggled(object sender, EventArgs args) { - GuiColumns updatedColumns = SwitchSettings.SwitchConfig.GuiColumns; - - updatedColumns.TimePlayedColumn = _timePlayedToggle.Active; - SwitchSettings.SwitchConfig.GuiColumns = updatedColumns; - - Configuration.SaveConfig(SwitchSettings.SwitchConfig, System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json")); + ConfigurationState.Instance.Ui.GuiColumns.TimePlayedColumn.Value = _timePlayedToggle.Active; + SaveConfig(); UpdateColumns(); } private void LastPlayed_Toggled(object sender, EventArgs args) { - GuiColumns updatedColumns = SwitchSettings.SwitchConfig.GuiColumns; - - updatedColumns.LastPlayedColumn = _lastPlayedToggle.Active; - SwitchSettings.SwitchConfig.GuiColumns = updatedColumns; - - Configuration.SaveConfig(SwitchSettings.SwitchConfig, System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json")); + ConfigurationState.Instance.Ui.GuiColumns.LastPlayedColumn.Value = _lastPlayedToggle.Active; + SaveConfig(); UpdateColumns(); } private void FileExt_Toggled(object sender, EventArgs args) { - GuiColumns updatedColumns = SwitchSettings.SwitchConfig.GuiColumns; - - updatedColumns.FileExtColumn = _fileExtToggle.Active; - SwitchSettings.SwitchConfig.GuiColumns = updatedColumns; - - Configuration.SaveConfig(SwitchSettings.SwitchConfig, System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json")); + ConfigurationState.Instance.Ui.GuiColumns.FileExtColumn.Value = _fileExtToggle.Active; + SaveConfig(); UpdateColumns(); } - private void FileSize_Toggled(object sender, EventArgs args) + private void FileSize_Toggled(object o, EventArgs args) { - GuiColumns updatedColumns = SwitchSettings.SwitchConfig.GuiColumns; - - updatedColumns.FileSizeColumn = _fileSizeToggle.Active; - SwitchSettings.SwitchConfig.GuiColumns = updatedColumns; - - Configuration.SaveConfig(SwitchSettings.SwitchConfig, System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json")); + ConfigurationState.Instance.Ui.GuiColumns.FileSizeColumn.Value = _fileSizeToggle.Active; + SaveConfig(); UpdateColumns(); } - private void Path_Toggled(object sender, EventArgs args) + private void Path_Toggled(object o, EventArgs args) { - GuiColumns updatedColumns = SwitchSettings.SwitchConfig.GuiColumns; - - updatedColumns.PathColumn = _pathToggle.Active; - SwitchSettings.SwitchConfig.GuiColumns = updatedColumns; - - Configuration.SaveConfig(SwitchSettings.SwitchConfig, System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json")); + ConfigurationState.Instance.Ui.GuiColumns.PathColumn.Value = _pathToggle.Active; + SaveConfig(); UpdateColumns(); } @@ -865,5 +796,10 @@ namespace Ryujinx.Ui return 0; } } + + public static void SaveConfig() + { + ConfigurationState.Instance.ToFileFormat().SaveConfig(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json")); + } } } diff --git a/Ryujinx/Ui/SwitchSettings.cs b/Ryujinx/Ui/SwitchSettings.cs index 955c6b0b64..25aff2de06 100644 --- a/Ryujinx/Ui/SwitchSettings.cs +++ b/Ryujinx/Ui/SwitchSettings.cs @@ -7,6 +7,8 @@ using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; +using Ryujinx.Configuration; +using Ryujinx.Common.Logging; using GUI = Gtk.Builder.ObjectAttribute; @@ -14,10 +16,6 @@ namespace Ryujinx.Ui { public class SwitchSettings : Window { - internal static Configuration SwitchConfig { get; set; } - - private readonly HLE.Switch _device; - private static ListStore _gameDirsBoxStore; private static bool _listeningForKeypress; @@ -83,16 +81,12 @@ namespace Ryujinx.Ui #pragma warning restore CS0649 #pragma warning restore IDE0044 - public static void ConfigureSettings(Configuration instance) { SwitchConfig = instance; } + public SwitchSettings() : this(new Builder("Ryujinx.Ui.SwitchSettings.glade")) { } - public SwitchSettings(HLE.Switch device) : this(new Builder("Ryujinx.Ui.SwitchSettings.glade"), device) { } - - private SwitchSettings(Builder builder, HLE.Switch device) : base(builder.GetObject("_settingsWin").Handle) + private SwitchSettings(Builder builder) : base(builder.GetObject("_settingsWin").Handle) { builder.Autoconnect(this); - _device = device; - _settingsWin.Icon = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.Icon.png"); _controller1Image.Pixbuf = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.JoyCon.png", 500, 500); @@ -124,60 +118,60 @@ namespace Ryujinx.Ui _controller1Type.Changed += (sender, args) => Controller_Changed(sender, args, _controller1Type.ActiveId, _controller1Image); //Setup Currents - if (SwitchConfig.EnableFileLog) _fileLogToggle.Click(); - if (SwitchConfig.LoggingEnableError) _errorLogToggle.Click(); - if (SwitchConfig.LoggingEnableWarn) _warningLogToggle.Click(); - if (SwitchConfig.LoggingEnableInfo) _infoLogToggle.Click(); - if (SwitchConfig.LoggingEnableStub) _stubLogToggle.Click(); - if (SwitchConfig.LoggingEnableDebug) _debugLogToggle.Click(); - if (SwitchConfig.LoggingEnableGuest) _guestLogToggle.Click(); - if (SwitchConfig.LoggingEnableFsAccessLog) _fsAccessLogToggle.Click(); - if (SwitchConfig.DockedMode) _dockedModeToggle.Click(); - if (SwitchConfig.EnableDiscordIntegration) _discordToggle.Click(); - if (SwitchConfig.EnableVsync) _vSyncToggle.Click(); - if (SwitchConfig.EnableMulticoreScheduling) _multiSchedToggle.Click(); - if (SwitchConfig.EnableFsIntegrityChecks) _fsicToggle.Click(); - if (SwitchConfig.IgnoreMissingServices) _ignoreToggle.Click(); - if (SwitchConfig.EnableKeyboard) _directKeyboardAccess.Click(); - if (SwitchConfig.EnableCustomTheme) _custThemeToggle.Click(); + if (ConfigurationState.Instance.Logger.EnableFileLog) { _fileLogToggle.Click(); } + if (ConfigurationState.Instance.Logger.EnableError) { _errorLogToggle.Click(); } + if (ConfigurationState.Instance.Logger.EnableWarn) { _warningLogToggle.Click(); } + if (ConfigurationState.Instance.Logger.EnableInfo) { _infoLogToggle.Click(); } + if (ConfigurationState.Instance.Logger.EnableStub) { _stubLogToggle.Click(); } + if (ConfigurationState.Instance.Logger.EnableDebug) { _debugLogToggle.Click(); } + if (ConfigurationState.Instance.Logger.EnableGuest) { _guestLogToggle.Click(); } + if (ConfigurationState.Instance.Logger.EnableFsAccessLog) { _fsAccessLogToggle.Click(); } + if (ConfigurationState.Instance.System.EnableDockedMode) { _dockedModeToggle.Click(); } + if (ConfigurationState.Instance.EnableDiscordIntegration) { _discordToggle.Click(); } + if (ConfigurationState.Instance.Graphics.EnableVsync) { _vSyncToggle.Click(); } + if (ConfigurationState.Instance.System.EnableMulticoreScheduling) { _multiSchedToggle.Click(); } + if (ConfigurationState.Instance.System.EnableFsIntegrityChecks) { _fsicToggle.Click(); } + if (ConfigurationState.Instance.System.IgnoreMissingServices) { _ignoreToggle.Click(); } + if (ConfigurationState.Instance.Hid.EnableKeyboard) { _directKeyboardAccess.Click(); } + if (ConfigurationState.Instance.Ui.EnableCustomTheme) { _custThemeToggle.Click(); } - _systemLanguageSelect.SetActiveId(SwitchConfig.SystemLanguage.ToString()); - _controller1Type .SetActiveId(SwitchConfig.ControllerType.ToString()); + _systemLanguageSelect.SetActiveId(ConfigurationState.Instance.System.Language.Value.ToString()); + _controller1Type .SetActiveId(ConfigurationState.Instance.Hid.ControllerType.Value.ToString()); Controller_Changed(null, null, _controller1Type.ActiveId, _controller1Image); - _lStickUp1.Label = SwitchConfig.KeyboardControls.LeftJoycon.StickUp.ToString(); - _lStickDown1.Label = SwitchConfig.KeyboardControls.LeftJoycon.StickDown.ToString(); - _lStickLeft1.Label = SwitchConfig.KeyboardControls.LeftJoycon.StickLeft.ToString(); - _lStickRight1.Label = SwitchConfig.KeyboardControls.LeftJoycon.StickRight.ToString(); - _lStickButton1.Label = SwitchConfig.KeyboardControls.LeftJoycon.StickButton.ToString(); - _dpadUp1.Label = SwitchConfig.KeyboardControls.LeftJoycon.DPadUp.ToString(); - _dpadDown1.Label = SwitchConfig.KeyboardControls.LeftJoycon.DPadDown.ToString(); - _dpadLeft1.Label = SwitchConfig.KeyboardControls.LeftJoycon.DPadLeft.ToString(); - _dpadRight1.Label = SwitchConfig.KeyboardControls.LeftJoycon.DPadRight.ToString(); - _minus1.Label = SwitchConfig.KeyboardControls.LeftJoycon.ButtonMinus.ToString(); - _l1.Label = SwitchConfig.KeyboardControls.LeftJoycon.ButtonL.ToString(); - _zL1.Label = SwitchConfig.KeyboardControls.LeftJoycon.ButtonZl.ToString(); - _rStickUp1.Label = SwitchConfig.KeyboardControls.RightJoycon.StickUp.ToString(); - _rStickDown1.Label = SwitchConfig.KeyboardControls.RightJoycon.StickDown.ToString(); - _rStickLeft1.Label = SwitchConfig.KeyboardControls.RightJoycon.StickLeft.ToString(); - _rStickRight1.Label = SwitchConfig.KeyboardControls.RightJoycon.StickRight.ToString(); - _rStickButton1.Label = SwitchConfig.KeyboardControls.RightJoycon.StickButton.ToString(); - _a1.Label = SwitchConfig.KeyboardControls.RightJoycon.ButtonA.ToString(); - _b1.Label = SwitchConfig.KeyboardControls.RightJoycon.ButtonB.ToString(); - _x1.Label = SwitchConfig.KeyboardControls.RightJoycon.ButtonX.ToString(); - _y1.Label = SwitchConfig.KeyboardControls.RightJoycon.ButtonY.ToString(); - _plus1.Label = SwitchConfig.KeyboardControls.RightJoycon.ButtonPlus.ToString(); - _r1.Label = SwitchConfig.KeyboardControls.RightJoycon.ButtonR.ToString(); - _zR1.Label = SwitchConfig.KeyboardControls.RightJoycon.ButtonZr.ToString(); + _lStickUp1.Label = ConfigurationState.Instance.Hid.KeyboardControls.Value.LeftJoycon.StickUp.ToString(); + _lStickDown1.Label = ConfigurationState.Instance.Hid.KeyboardControls.Value.LeftJoycon.StickDown.ToString(); + _lStickLeft1.Label = ConfigurationState.Instance.Hid.KeyboardControls.Value.LeftJoycon.StickLeft.ToString(); + _lStickRight1.Label = ConfigurationState.Instance.Hid.KeyboardControls.Value.LeftJoycon.StickRight.ToString(); + _lStickButton1.Label = ConfigurationState.Instance.Hid.KeyboardControls.Value.LeftJoycon.StickButton.ToString(); + _dpadUp1.Label = ConfigurationState.Instance.Hid.KeyboardControls.Value.LeftJoycon.DPadUp.ToString(); + _dpadDown1.Label = ConfigurationState.Instance.Hid.KeyboardControls.Value.LeftJoycon.DPadDown.ToString(); + _dpadLeft1.Label = ConfigurationState.Instance.Hid.KeyboardControls.Value.LeftJoycon.DPadLeft.ToString(); + _dpadRight1.Label = ConfigurationState.Instance.Hid.KeyboardControls.Value.LeftJoycon.DPadRight.ToString(); + _minus1.Label = ConfigurationState.Instance.Hid.KeyboardControls.Value.LeftJoycon.ButtonMinus.ToString(); + _l1.Label = ConfigurationState.Instance.Hid.KeyboardControls.Value.LeftJoycon.ButtonL.ToString(); + _zL1.Label = ConfigurationState.Instance.Hid.KeyboardControls.Value.LeftJoycon.ButtonZl.ToString(); + _rStickUp1.Label = ConfigurationState.Instance.Hid.KeyboardControls.Value.RightJoycon.StickUp.ToString(); + _rStickDown1.Label = ConfigurationState.Instance.Hid.KeyboardControls.Value.RightJoycon.StickDown.ToString(); + _rStickLeft1.Label = ConfigurationState.Instance.Hid.KeyboardControls.Value.RightJoycon.StickLeft.ToString(); + _rStickRight1.Label = ConfigurationState.Instance.Hid.KeyboardControls.Value.RightJoycon.StickRight.ToString(); + _rStickButton1.Label = ConfigurationState.Instance.Hid.KeyboardControls.Value.RightJoycon.StickButton.ToString(); + _a1.Label = ConfigurationState.Instance.Hid.KeyboardControls.Value.RightJoycon.ButtonA.ToString(); + _b1.Label = ConfigurationState.Instance.Hid.KeyboardControls.Value.RightJoycon.ButtonB.ToString(); + _x1.Label = ConfigurationState.Instance.Hid.KeyboardControls.Value.RightJoycon.ButtonX.ToString(); + _y1.Label = ConfigurationState.Instance.Hid.KeyboardControls.Value.RightJoycon.ButtonY.ToString(); + _plus1.Label = ConfigurationState.Instance.Hid.KeyboardControls.Value.RightJoycon.ButtonPlus.ToString(); + _r1.Label = ConfigurationState.Instance.Hid.KeyboardControls.Value.RightJoycon.ButtonR.ToString(); + _zR1.Label = ConfigurationState.Instance.Hid.KeyboardControls.Value.RightJoycon.ButtonZr.ToString(); - _custThemePath.Buffer.Text = SwitchConfig.CustomThemePath; - _graphicsShadersDumpPath.Buffer.Text = SwitchConfig.GraphicsShadersDumpPath; - _fsLogSpinAdjustment.Value = SwitchConfig.FsGlobalAccessLogMode; + _custThemePath.Buffer.Text = ConfigurationState.Instance.Ui.CustomThemePath; + _graphicsShadersDumpPath.Buffer.Text = ConfigurationState.Instance.Graphics.ShadersDumpPath; + _fsLogSpinAdjustment.Value = ConfigurationState.Instance.System.FsGlobalAccessLogMode; _gameDirsBox.AppendColumn("", new CellRendererText(), "text", 0); _gameDirsBoxStore = new ListStore(typeof(string)); _gameDirsBox.Model = _gameDirsBoxStore; - foreach (string gameDir in SwitchConfig.GameDirs) + foreach (string gameDir in ConfigurationState.Instance.Ui.GameDirs.Value) { _gameDirsBoxStore.AppendValues(gameDir); } @@ -325,24 +319,24 @@ namespace Ryujinx.Ui _gameDirsBoxStore.IterNext(ref treeIter); } - SwitchConfig.LoggingEnableError = _errorLogToggle.Active; - SwitchConfig.LoggingEnableWarn = _warningLogToggle.Active; - SwitchConfig.LoggingEnableInfo = _infoLogToggle.Active; - SwitchConfig.LoggingEnableStub = _stubLogToggle.Active; - SwitchConfig.LoggingEnableDebug = _debugLogToggle.Active; - SwitchConfig.LoggingEnableGuest = _guestLogToggle.Active; - SwitchConfig.LoggingEnableFsAccessLog = _fsAccessLogToggle.Active; - SwitchConfig.EnableFileLog = _fileLogToggle.Active; - SwitchConfig.DockedMode = _dockedModeToggle.Active; - SwitchConfig.EnableDiscordIntegration = _discordToggle.Active; - SwitchConfig.EnableVsync = _vSyncToggle.Active; - SwitchConfig.EnableMulticoreScheduling = _multiSchedToggle.Active; - SwitchConfig.EnableFsIntegrityChecks = _fsicToggle.Active; - SwitchConfig.IgnoreMissingServices = _ignoreToggle.Active; - SwitchConfig.EnableKeyboard = _directKeyboardAccess.Active; - SwitchConfig.EnableCustomTheme = _custThemeToggle.Active; + ConfigurationState.Instance.Logger.EnableError.Value = _errorLogToggle.Active; + ConfigurationState.Instance.Logger.EnableWarn.Value = _warningLogToggle.Active; + ConfigurationState.Instance.Logger.EnableInfo.Value = _infoLogToggle.Active; + ConfigurationState.Instance.Logger.EnableStub.Value = _stubLogToggle.Active; + ConfigurationState.Instance.Logger.EnableDebug.Value = _debugLogToggle.Active; + ConfigurationState.Instance.Logger.EnableGuest.Value = _guestLogToggle.Active; + ConfigurationState.Instance.Logger.EnableFsAccessLog.Value = _fsAccessLogToggle.Active; + ConfigurationState.Instance.Logger.EnableFileLog.Value = _fileLogToggle.Active; + ConfigurationState.Instance.System.EnableDockedMode.Value = _dockedModeToggle.Active; + ConfigurationState.Instance.EnableDiscordIntegration.Value = _discordToggle.Active; + ConfigurationState.Instance.Graphics.EnableVsync.Value = _vSyncToggle.Active; + ConfigurationState.Instance.System.EnableMulticoreScheduling.Value = _multiSchedToggle.Active; + ConfigurationState.Instance.System.EnableFsIntegrityChecks.Value = _fsicToggle.Active; + ConfigurationState.Instance.System.IgnoreMissingServices.Value = _ignoreToggle.Active; + ConfigurationState.Instance.Hid.EnableKeyboard.Value = _directKeyboardAccess.Active; + ConfigurationState.Instance.Ui.EnableCustomTheme.Value = _custThemeToggle.Active; - SwitchConfig.KeyboardControls.LeftJoycon = new NpadKeyboardLeft() + ConfigurationState.Instance.Hid.KeyboardControls.Value.LeftJoycon = new NpadKeyboardLeft() { StickUp = (OpenTK.Input.Key)Enum.Parse(typeof(OpenTK.Input.Key), _lStickUp1.Label), StickDown = (OpenTK.Input.Key)Enum.Parse(typeof(OpenTK.Input.Key), _lStickDown1.Label), @@ -358,7 +352,7 @@ namespace Ryujinx.Ui ButtonZl = (OpenTK.Input.Key)Enum.Parse(typeof(OpenTK.Input.Key), _zL1.Label), }; - SwitchConfig.KeyboardControls.RightJoycon = new NpadKeyboardRight() + ConfigurationState.Instance.Hid.KeyboardControls.Value.RightJoycon = new NpadKeyboardRight() { StickUp = (OpenTK.Input.Key)Enum.Parse(typeof(OpenTK.Input.Key), _rStickUp1.Label), StickDown = (OpenTK.Input.Key)Enum.Parse(typeof(OpenTK.Input.Key), _rStickDown1.Label), @@ -374,16 +368,14 @@ namespace Ryujinx.Ui ButtonZr = (OpenTK.Input.Key)Enum.Parse(typeof(OpenTK.Input.Key), _zR1.Label), }; - SwitchConfig.SystemLanguage = (SystemLanguage)Enum.Parse(typeof(SystemLanguage), _systemLanguageSelect.ActiveId); - SwitchConfig.ControllerType = (ControllerStatus)Enum.Parse(typeof(ControllerStatus), _controller1Type.ActiveId); - SwitchConfig.CustomThemePath = _custThemePath.Buffer.Text; - SwitchConfig.GraphicsShadersDumpPath = _graphicsShadersDumpPath.Buffer.Text; - SwitchConfig.GameDirs = gameDirs; - SwitchConfig.FsGlobalAccessLogMode = (int)_fsLogSpinAdjustment.Value; - - Configuration.SaveConfig(SwitchConfig, System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json")); - Configuration.Configure(_device, SwitchConfig); + ConfigurationState.Instance.System.Language.Value = (SystemLanguage)Enum.Parse(typeof(SystemLanguage), _systemLanguageSelect.ActiveId); + ConfigurationState.Instance.Hid.ControllerType.Value = (ControllerStatus)Enum.Parse(typeof(ControllerStatus), _controller1Type.ActiveId); + ConfigurationState.Instance.Ui.CustomThemePath.Value = _custThemePath.Buffer.Text; + ConfigurationState.Instance.Graphics.ShadersDumpPath.Value = _graphicsShadersDumpPath.Buffer.Text; + ConfigurationState.Instance.Ui.GameDirs.Value = gameDirs; + ConfigurationState.Instance.System.FsGlobalAccessLogMode.Value = (int)_fsLogSpinAdjustment.Value; + MainWindow.SaveConfig(); MainWindow.ApplyTheme(); #pragma warning disable CS4014 MainWindow.UpdateGameTable();