/ src / Ryujinx.UI.Common / Configuration / ConfigurationState.cs
ConfigurationState.cs
   1  using Ryujinx.Common;
   2  using Ryujinx.Common.Configuration;
   3  using Ryujinx.Common.Configuration.Hid;
   4  using Ryujinx.Common.Configuration.Hid.Controller;
   5  using Ryujinx.Common.Configuration.Hid.Keyboard;
   6  using Ryujinx.Common.Configuration.Multiplayer;
   7  using Ryujinx.Common.Logging;
   8  using Ryujinx.Graphics.Vulkan;
   9  using Ryujinx.UI.Common.Configuration.System;
  10  using Ryujinx.UI.Common.Configuration.UI;
  11  using Ryujinx.UI.Common.Helper;
  12  using System;
  13  using System.Collections.Generic;
  14  using System.Globalization;
  15  using System.Text.Json.Nodes;
  16  
  17  namespace Ryujinx.UI.Common.Configuration
  18  {
  19      public class ConfigurationState
  20      {
  21          /// <summary>
  22          /// UI configuration section
  23          /// </summary>
  24          public class UISection
  25          {
  26              public class Columns
  27              {
  28                  public ReactiveObject<bool> FavColumn { get; private set; }
  29                  public ReactiveObject<bool> IconColumn { get; private set; }
  30                  public ReactiveObject<bool> AppColumn { get; private set; }
  31                  public ReactiveObject<bool> DevColumn { get; private set; }
  32                  public ReactiveObject<bool> VersionColumn { get; private set; }
  33                  public ReactiveObject<bool> TimePlayedColumn { get; private set; }
  34                  public ReactiveObject<bool> LastPlayedColumn { get; private set; }
  35                  public ReactiveObject<bool> FileExtColumn { get; private set; }
  36                  public ReactiveObject<bool> FileSizeColumn { get; private set; }
  37                  public ReactiveObject<bool> PathColumn { get; private set; }
  38  
  39                  public Columns()
  40                  {
  41                      FavColumn = new ReactiveObject<bool>();
  42                      IconColumn = new ReactiveObject<bool>();
  43                      AppColumn = new ReactiveObject<bool>();
  44                      DevColumn = new ReactiveObject<bool>();
  45                      VersionColumn = new ReactiveObject<bool>();
  46                      TimePlayedColumn = new ReactiveObject<bool>();
  47                      LastPlayedColumn = new ReactiveObject<bool>();
  48                      FileExtColumn = new ReactiveObject<bool>();
  49                      FileSizeColumn = new ReactiveObject<bool>();
  50                      PathColumn = new ReactiveObject<bool>();
  51                  }
  52              }
  53  
  54              public class ColumnSortSettings
  55              {
  56                  public ReactiveObject<int> SortColumnId { get; private set; }
  57                  public ReactiveObject<bool> SortAscending { get; private set; }
  58  
  59                  public ColumnSortSettings()
  60                  {
  61                      SortColumnId = new ReactiveObject<int>();
  62                      SortAscending = new ReactiveObject<bool>();
  63                  }
  64              }
  65  
  66              /// <summary>
  67              /// Used to toggle which file types are shown in the UI
  68              /// </summary>
  69              public class ShownFileTypeSettings
  70              {
  71                  public ReactiveObject<bool> NSP { get; private set; }
  72                  public ReactiveObject<bool> PFS0 { get; private set; }
  73                  public ReactiveObject<bool> XCI { get; private set; }
  74                  public ReactiveObject<bool> NCA { get; private set; }
  75                  public ReactiveObject<bool> NRO { get; private set; }
  76                  public ReactiveObject<bool> NSO { get; private set; }
  77  
  78                  public ShownFileTypeSettings()
  79                  {
  80                      NSP = new ReactiveObject<bool>();
  81                      PFS0 = new ReactiveObject<bool>();
  82                      XCI = new ReactiveObject<bool>();
  83                      NCA = new ReactiveObject<bool>();
  84                      NRO = new ReactiveObject<bool>();
  85                      NSO = new ReactiveObject<bool>();
  86                  }
  87              }
  88  
  89              // <summary>
  90              /// Determines main window start-up position, size and state
  91              ///<summary>
  92              public class WindowStartupSettings
  93              {
  94                  public ReactiveObject<int> WindowSizeWidth { get; private set; }
  95                  public ReactiveObject<int> WindowSizeHeight { get; private set; }
  96                  public ReactiveObject<int> WindowPositionX { get; private set; }
  97                  public ReactiveObject<int> WindowPositionY { get; private set; }
  98                  public ReactiveObject<bool> WindowMaximized { get; private set; }
  99  
 100                  public WindowStartupSettings()
 101                  {
 102                      WindowSizeWidth = new ReactiveObject<int>();
 103                      WindowSizeHeight = new ReactiveObject<int>();
 104                      WindowPositionX = new ReactiveObject<int>();
 105                      WindowPositionY = new ReactiveObject<int>();
 106                      WindowMaximized = new ReactiveObject<bool>();
 107                  }
 108              }
 109  
 110              /// <summary>
 111              /// Used to toggle columns in the GUI
 112              /// </summary>
 113              public Columns GuiColumns { get; private set; }
 114  
 115              /// <summary>
 116              /// Used to configure column sort settings in the GUI
 117              /// </summary>
 118              public ColumnSortSettings ColumnSort { get; private set; }
 119  
 120              /// <summary>
 121              /// A list of directories containing games to be used to load games into the games list
 122              /// </summary>
 123              public ReactiveObject<List<string>> GameDirs { get; private set; }
 124  
 125              /// <summary>
 126              /// A list of file types to be hidden in the games List
 127              /// </summary>
 128              public ShownFileTypeSettings ShownFileTypes { get; private set; }
 129  
 130              /// <summary>
 131              /// Determines main window start-up position, size and state
 132              /// </summary>
 133              public WindowStartupSettings WindowStartup { get; private set; }
 134  
 135              /// <summary>
 136              /// Language Code for the UI
 137              /// </summary>
 138              public ReactiveObject<string> LanguageCode { get; private set; }
 139  
 140              /// <summary>
 141              /// Enable or disable custom themes in the GUI
 142              /// </summary>
 143              public ReactiveObject<bool> EnableCustomTheme { get; private set; }
 144  
 145              /// <summary>
 146              /// Path to custom GUI theme
 147              /// </summary>
 148              public ReactiveObject<string> CustomThemePath { get; private set; }
 149  
 150              /// <summary>
 151              /// Selects the base style
 152              /// </summary>
 153              public ReactiveObject<string> BaseStyle { get; private set; }
 154  
 155              /// <summary>
 156              /// Start games in fullscreen mode
 157              /// </summary>
 158              public ReactiveObject<bool> StartFullscreen { get; private set; }
 159  
 160              /// <summary>
 161              /// Hide / Show Console Window
 162              /// </summary>
 163              public ReactiveObject<bool> ShowConsole { get; private set; }
 164  
 165              /// <summary>
 166              /// View Mode of the Game list
 167              /// </summary>
 168              public ReactiveObject<int> GameListViewMode { get; private set; }
 169  
 170              /// <summary>
 171              /// Show application name in Grid Mode
 172              /// </summary>
 173              public ReactiveObject<bool> ShowNames { get; private set; }
 174  
 175              /// <summary>
 176              /// Sets App Icon Size in Grid Mode
 177              /// </summary>
 178              public ReactiveObject<int> GridSize { get; private set; }
 179  
 180              /// <summary>
 181              /// Sorts Apps in Grid Mode
 182              /// </summary>
 183              public ReactiveObject<int> ApplicationSort { get; private set; }
 184  
 185              /// <summary>
 186              /// Sets if Grid is ordered in Ascending Order
 187              /// </summary>
 188              public ReactiveObject<bool> IsAscendingOrder { get; private set; }
 189  
 190              public UISection()
 191              {
 192                  GuiColumns = new Columns();
 193                  ColumnSort = new ColumnSortSettings();
 194                  GameDirs = new ReactiveObject<List<string>>();
 195                  ShownFileTypes = new ShownFileTypeSettings();
 196                  WindowStartup = new WindowStartupSettings();
 197                  EnableCustomTheme = new ReactiveObject<bool>();
 198                  CustomThemePath = new ReactiveObject<string>();
 199                  BaseStyle = new ReactiveObject<string>();
 200                  StartFullscreen = new ReactiveObject<bool>();
 201                  GameListViewMode = new ReactiveObject<int>();
 202                  ShowNames = new ReactiveObject<bool>();
 203                  GridSize = new ReactiveObject<int>();
 204                  ApplicationSort = new ReactiveObject<int>();
 205                  IsAscendingOrder = new ReactiveObject<bool>();
 206                  LanguageCode = new ReactiveObject<string>();
 207                  ShowConsole = new ReactiveObject<bool>();
 208                  ShowConsole.Event += static (s, e) => { ConsoleHelper.SetConsoleWindowState(e.NewValue); };
 209              }
 210          }
 211  
 212          /// <summary>
 213          /// Logger configuration section
 214          /// </summary>
 215          public class LoggerSection
 216          {
 217              /// <summary>
 218              /// Enables printing debug log messages
 219              /// </summary>
 220              public ReactiveObject<bool> EnableDebug { get; private set; }
 221  
 222              /// <summary>
 223              /// Enables printing stub log messages
 224              /// </summary>
 225              public ReactiveObject<bool> EnableStub { get; private set; }
 226  
 227              /// <summary>
 228              /// Enables printing info log messages
 229              /// </summary>
 230              public ReactiveObject<bool> EnableInfo { get; private set; }
 231  
 232              /// <summary>
 233              /// Enables printing warning log messages
 234              /// </summary>
 235              public ReactiveObject<bool> EnableWarn { get; private set; }
 236  
 237              /// <summary>
 238              /// Enables printing error log messages
 239              /// </summary>
 240              public ReactiveObject<bool> EnableError { get; private set; }
 241  
 242              /// <summary>
 243              /// Enables printing trace log messages
 244              /// </summary>
 245              public ReactiveObject<bool> EnableTrace { get; private set; }
 246  
 247              /// <summary>
 248              /// Enables printing guest log messages
 249              /// </summary>
 250              public ReactiveObject<bool> EnableGuest { get; private set; }
 251  
 252              /// <summary>
 253              /// Enables printing FS access log messages
 254              /// </summary>
 255              public ReactiveObject<bool> EnableFsAccessLog { get; private set; }
 256  
 257              /// <summary>
 258              /// Controls which log messages are written to the log targets
 259              /// </summary>
 260              public ReactiveObject<LogClass[]> FilteredClasses { get; private set; }
 261  
 262              /// <summary>
 263              /// Enables or disables logging to a file on disk
 264              /// </summary>
 265              public ReactiveObject<bool> EnableFileLog { get; private set; }
 266  
 267              /// <summary>
 268              /// Controls which OpenGL log messages are recorded in the log
 269              /// </summary>
 270              public ReactiveObject<GraphicsDebugLevel> GraphicsDebugLevel { get; private set; }
 271  
 272              public LoggerSection()
 273              {
 274                  EnableDebug = new ReactiveObject<bool>();
 275                  EnableStub = new ReactiveObject<bool>();
 276                  EnableInfo = new ReactiveObject<bool>();
 277                  EnableWarn = new ReactiveObject<bool>();
 278                  EnableError = new ReactiveObject<bool>();
 279                  EnableTrace = new ReactiveObject<bool>();
 280                  EnableGuest = new ReactiveObject<bool>();
 281                  EnableFsAccessLog = new ReactiveObject<bool>();
 282                  FilteredClasses = new ReactiveObject<LogClass[]>();
 283                  EnableFileLog = new ReactiveObject<bool>();
 284                  EnableFileLog.Event += static (sender, e) => LogValueChange(e, nameof(EnableFileLog));
 285                  GraphicsDebugLevel = new ReactiveObject<GraphicsDebugLevel>();
 286              }
 287          }
 288  
 289          /// <summary>
 290          /// System configuration section
 291          /// </summary>
 292          public class SystemSection
 293          {
 294              /// <summary>
 295              /// Change System Language
 296              /// </summary>
 297              public ReactiveObject<Language> Language { get; private set; }
 298  
 299              /// <summary>
 300              /// Change System Region
 301              /// </summary>
 302              public ReactiveObject<Region> Region { get; private set; }
 303  
 304              /// <summary>
 305              /// Change System TimeZone
 306              /// </summary>
 307              public ReactiveObject<string> TimeZone { get; private set; }
 308  
 309              /// <summary>
 310              /// System Time Offset in Seconds
 311              /// </summary>
 312              public ReactiveObject<long> SystemTimeOffset { get; private set; }
 313  
 314              /// <summary>
 315              /// Enables or disables Docked Mode
 316              /// </summary>
 317              public ReactiveObject<bool> EnableDockedMode { get; private set; }
 318  
 319              /// <summary>
 320              /// Enables or disables profiled translation cache persistency
 321              /// </summary>
 322              public ReactiveObject<bool> EnablePtc { get; private set; }
 323  
 324              /// <summary>
 325              /// Enables or disables guest Internet access
 326              /// </summary>
 327              public ReactiveObject<bool> EnableInternetAccess { get; private set; }
 328  
 329              /// <summary>
 330              /// Enables integrity checks on Game content files
 331              /// </summary>
 332              public ReactiveObject<bool> EnableFsIntegrityChecks { get; private set; }
 333  
 334              /// <summary>
 335              /// Enables FS access log output to the console. Possible modes are 0-3
 336              /// </summary>
 337              public ReactiveObject<int> FsGlobalAccessLogMode { get; private set; }
 338  
 339              /// <summary>
 340              /// The selected audio backend
 341              /// </summary>
 342              public ReactiveObject<AudioBackend> AudioBackend { get; private set; }
 343  
 344              /// <summary>
 345              /// The audio backend volume
 346              /// </summary>
 347              public ReactiveObject<float> AudioVolume { get; private set; }
 348  
 349              /// <summary>
 350              /// The selected memory manager mode
 351              /// </summary>
 352              public ReactiveObject<MemoryManagerMode> MemoryManagerMode { get; private set; }
 353  
 354              /// <summary>
 355              /// Defines the amount of RAM available on the emulated system, and how it is distributed
 356              /// </summary>
 357              public ReactiveObject<bool> ExpandRam { get; private set; }
 358  
 359              /// <summary>
 360              /// Enable or disable ignoring missing services
 361              /// </summary>
 362              public ReactiveObject<bool> IgnoreMissingServices { get; private set; }
 363  
 364              /// <summary>
 365              /// Uses Hypervisor over JIT if available
 366              /// </summary>
 367              public ReactiveObject<bool> UseHypervisor { get; private set; }
 368  
 369              public SystemSection()
 370              {
 371                  Language = new ReactiveObject<Language>();
 372                  Region = new ReactiveObject<Region>();
 373                  TimeZone = new ReactiveObject<string>();
 374                  SystemTimeOffset = new ReactiveObject<long>();
 375                  EnableDockedMode = new ReactiveObject<bool>();
 376                  EnableDockedMode.Event += static (sender, e) => LogValueChange(e, nameof(EnableDockedMode));
 377                  EnablePtc = new ReactiveObject<bool>();
 378                  EnablePtc.Event += static (sender, e) => LogValueChange(e, nameof(EnablePtc));
 379                  EnableInternetAccess = new ReactiveObject<bool>();
 380                  EnableInternetAccess.Event += static (sender, e) => LogValueChange(e, nameof(EnableInternetAccess));
 381                  EnableFsIntegrityChecks = new ReactiveObject<bool>();
 382                  EnableFsIntegrityChecks.Event += static (sender, e) => LogValueChange(e, nameof(EnableFsIntegrityChecks));
 383                  FsGlobalAccessLogMode = new ReactiveObject<int>();
 384                  FsGlobalAccessLogMode.Event += static (sender, e) => LogValueChange(e, nameof(FsGlobalAccessLogMode));
 385                  AudioBackend = new ReactiveObject<AudioBackend>();
 386                  AudioBackend.Event += static (sender, e) => LogValueChange(e, nameof(AudioBackend));
 387                  MemoryManagerMode = new ReactiveObject<MemoryManagerMode>();
 388                  MemoryManagerMode.Event += static (sender, e) => LogValueChange(e, nameof(MemoryManagerMode));
 389                  ExpandRam = new ReactiveObject<bool>();
 390                  ExpandRam.Event += static (sender, e) => LogValueChange(e, nameof(ExpandRam));
 391                  IgnoreMissingServices = new ReactiveObject<bool>();
 392                  IgnoreMissingServices.Event += static (sender, e) => LogValueChange(e, nameof(IgnoreMissingServices));
 393                  AudioVolume = new ReactiveObject<float>();
 394                  AudioVolume.Event += static (sender, e) => LogValueChange(e, nameof(AudioVolume));
 395                  UseHypervisor = new ReactiveObject<bool>();
 396                  UseHypervisor.Event += static (sender, e) => LogValueChange(e, nameof(UseHypervisor));
 397              }
 398          }
 399  
 400          /// <summary>
 401          /// Hid configuration section
 402          /// </summary>
 403          public class HidSection
 404          {
 405              /// <summary>
 406              /// Enable or disable keyboard support (Independent from controllers binding)
 407              /// </summary>
 408              public ReactiveObject<bool> EnableKeyboard { get; private set; }
 409  
 410              /// <summary>
 411              /// Enable or disable mouse support (Independent from controllers binding)
 412              /// </summary>
 413              public ReactiveObject<bool> EnableMouse { get; private set; }
 414  
 415              /// <summary>
 416              /// Hotkey Keyboard Bindings
 417              /// </summary>
 418              public ReactiveObject<KeyboardHotkeys> Hotkeys { get; private set; }
 419  
 420              /// <summary>
 421              /// Input device configuration.
 422              /// NOTE: This ReactiveObject won't issue an event when the List has elements added or removed.
 423              /// TODO: Implement a ReactiveList class.
 424              /// </summary>
 425              public ReactiveObject<List<InputConfig>> InputConfig { get; private set; }
 426  
 427              public HidSection()
 428              {
 429                  EnableKeyboard = new ReactiveObject<bool>();
 430                  EnableMouse = new ReactiveObject<bool>();
 431                  Hotkeys = new ReactiveObject<KeyboardHotkeys>();
 432                  InputConfig = new ReactiveObject<List<InputConfig>>();
 433              }
 434          }
 435  
 436          /// <summary>
 437          /// Graphics configuration section
 438          /// </summary>
 439          public class GraphicsSection
 440          {
 441              /// <summary>
 442              /// Whether or not backend threading is enabled. The "Auto" setting will determine whether threading should be enabled at runtime.
 443              /// </summary>
 444              public ReactiveObject<BackendThreading> BackendThreading { get; private set; }
 445  
 446              /// <summary>
 447              /// Max Anisotropy. Values range from 0 - 16. Set to -1 to let the game decide.
 448              /// </summary>
 449              public ReactiveObject<float> MaxAnisotropy { get; private set; }
 450  
 451              /// <summary>
 452              /// Aspect Ratio applied to the renderer window.
 453              /// </summary>
 454              public ReactiveObject<AspectRatio> AspectRatio { get; private set; }
 455  
 456              /// <summary>
 457              /// Resolution Scale. An integer scale applied to applicable render targets. Values 1-4, or -1 to use a custom floating point scale instead.
 458              /// </summary>
 459              public ReactiveObject<int> ResScale { get; private set; }
 460  
 461              /// <summary>
 462              /// Custom Resolution Scale. A custom floating point scale applied to applicable render targets. Only active when Resolution Scale is -1.
 463              /// </summary>
 464              public ReactiveObject<float> ResScaleCustom { get; private set; }
 465  
 466              /// <summary>
 467              /// Dumps shaders in this local directory
 468              /// </summary>
 469              public ReactiveObject<string> ShadersDumpPath { get; private set; }
 470  
 471              /// <summary>
 472              /// Enables or disables Vertical Sync
 473              /// </summary>
 474              public ReactiveObject<bool> EnableVsync { get; private set; }
 475  
 476              /// <summary>
 477              /// Enables or disables Shader cache
 478              /// </summary>
 479              public ReactiveObject<bool> EnableShaderCache { get; private set; }
 480  
 481              /// <summary>
 482              /// Enables or disables texture recompression
 483              /// </summary>
 484              public ReactiveObject<bool> EnableTextureRecompression { get; private set; }
 485  
 486              /// <summary>
 487              /// Enables or disables Macro high-level emulation
 488              /// </summary>
 489              public ReactiveObject<bool> EnableMacroHLE { get; private set; }
 490  
 491              /// <summary>
 492              /// Enables or disables color space passthrough, if available.
 493              /// </summary>
 494              public ReactiveObject<bool> EnableColorSpacePassthrough { get; private set; }
 495  
 496              /// <summary>
 497              /// Graphics backend
 498              /// </summary>
 499              public ReactiveObject<GraphicsBackend> GraphicsBackend { get; private set; }
 500  
 501              /// <summary>
 502              /// Applies anti-aliasing to the renderer.
 503              /// </summary>
 504              public ReactiveObject<AntiAliasing> AntiAliasing { get; private set; }
 505  
 506              /// <summary>
 507              /// Sets the framebuffer upscaling type.
 508              /// </summary>
 509              public ReactiveObject<ScalingFilter> ScalingFilter { get; private set; }
 510  
 511              /// <summary>
 512              /// Sets the framebuffer upscaling level.
 513              /// </summary>
 514              public ReactiveObject<int> ScalingFilterLevel { get; private set; }
 515  
 516              /// <summary>
 517              /// Preferred GPU
 518              /// </summary>
 519              public ReactiveObject<string> PreferredGpu { get; private set; }
 520  
 521              public GraphicsSection()
 522              {
 523                  BackendThreading = new ReactiveObject<BackendThreading>();
 524                  BackendThreading.Event += static (sender, e) => LogValueChange(e, nameof(BackendThreading));
 525                  ResScale = new ReactiveObject<int>();
 526                  ResScale.Event += static (sender, e) => LogValueChange(e, nameof(ResScale));
 527                  ResScaleCustom = new ReactiveObject<float>();
 528                  ResScaleCustom.Event += static (sender, e) => LogValueChange(e, nameof(ResScaleCustom));
 529                  MaxAnisotropy = new ReactiveObject<float>();
 530                  MaxAnisotropy.Event += static (sender, e) => LogValueChange(e, nameof(MaxAnisotropy));
 531                  AspectRatio = new ReactiveObject<AspectRatio>();
 532                  AspectRatio.Event += static (sender, e) => LogValueChange(e, nameof(AspectRatio));
 533                  ShadersDumpPath = new ReactiveObject<string>();
 534                  EnableVsync = new ReactiveObject<bool>();
 535                  EnableVsync.Event += static (sender, e) => LogValueChange(e, nameof(EnableVsync));
 536                  EnableShaderCache = new ReactiveObject<bool>();
 537                  EnableShaderCache.Event += static (sender, e) => LogValueChange(e, nameof(EnableShaderCache));
 538                  EnableTextureRecompression = new ReactiveObject<bool>();
 539                  EnableTextureRecompression.Event += static (sender, e) => LogValueChange(e, nameof(EnableTextureRecompression));
 540                  GraphicsBackend = new ReactiveObject<GraphicsBackend>();
 541                  GraphicsBackend.Event += static (sender, e) => LogValueChange(e, nameof(GraphicsBackend));
 542                  PreferredGpu = new ReactiveObject<string>();
 543                  PreferredGpu.Event += static (sender, e) => LogValueChange(e, nameof(PreferredGpu));
 544                  EnableMacroHLE = new ReactiveObject<bool>();
 545                  EnableMacroHLE.Event += static (sender, e) => LogValueChange(e, nameof(EnableMacroHLE));
 546                  EnableColorSpacePassthrough = new ReactiveObject<bool>();
 547                  EnableColorSpacePassthrough.Event += static (sender, e) => LogValueChange(e, nameof(EnableColorSpacePassthrough));
 548                  AntiAliasing = new ReactiveObject<AntiAliasing>();
 549                  AntiAliasing.Event += static (sender, e) => LogValueChange(e, nameof(AntiAliasing));
 550                  ScalingFilter = new ReactiveObject<ScalingFilter>();
 551                  ScalingFilter.Event += static (sender, e) => LogValueChange(e, nameof(ScalingFilter));
 552                  ScalingFilterLevel = new ReactiveObject<int>();
 553                  ScalingFilterLevel.Event += static (sender, e) => LogValueChange(e, nameof(ScalingFilterLevel));
 554              }
 555          }
 556  
 557          /// <summary>
 558          /// Multiplayer configuration section
 559          /// </summary>
 560          public class MultiplayerSection
 561          {
 562              /// <summary>
 563              /// GUID for the network interface used by LAN (or 0 for default)
 564              /// </summary>
 565              public ReactiveObject<string> LanInterfaceId { get; private set; }
 566  
 567              /// <summary>
 568              /// Multiplayer Mode
 569              /// </summary>
 570              public ReactiveObject<MultiplayerMode> Mode { get; private set; }
 571  
 572              public MultiplayerSection()
 573              {
 574                  LanInterfaceId = new ReactiveObject<string>();
 575                  Mode = new ReactiveObject<MultiplayerMode>();
 576                  Mode.Event += static (_, e) => LogValueChange(e, nameof(MultiplayerMode));
 577              }
 578          }
 579  
 580          /// <summary>
 581          /// The default configuration instance
 582          /// </summary>
 583          public static ConfigurationState Instance { get; private set; }
 584  
 585          /// <summary>
 586          /// The UI section
 587          /// </summary>
 588          public UISection UI { get; private set; }
 589  
 590          /// <summary>
 591          /// The Logger section
 592          /// </summary>
 593          public LoggerSection Logger { get; private set; }
 594  
 595          /// <summary>
 596          /// The System section
 597          /// </summary>
 598          public SystemSection System { get; private set; }
 599  
 600          /// <summary>
 601          /// The Graphics section
 602          /// </summary>
 603          public GraphicsSection Graphics { get; private set; }
 604  
 605          /// <summary>
 606          /// The Hid section
 607          /// </summary>
 608          public HidSection Hid { get; private set; }
 609  
 610          /// <summary>
 611          /// The Multiplayer section
 612          /// </summary>
 613          public MultiplayerSection Multiplayer { get; private set; }
 614  
 615          /// <summary>
 616          /// Enables or disables Discord Rich Presence
 617          /// </summary>
 618          public ReactiveObject<bool> EnableDiscordIntegration { get; private set; }
 619  
 620          /// <summary>
 621          /// Checks for updates when Ryujinx starts when enabled
 622          /// </summary>
 623          public ReactiveObject<bool> CheckUpdatesOnStart { get; private set; }
 624  
 625          /// <summary>
 626          /// Show "Confirm Exit" Dialog
 627          /// </summary>
 628          public ReactiveObject<bool> ShowConfirmExit { get; private set; }
 629  
 630          /// <summary>
 631          /// Enables or disables save window size, position and state on close.
 632          /// </summary>
 633          public ReactiveObject<bool> RememberWindowState { get; private set; }
 634  
 635          /// <summary>
 636          /// Enables hardware-accelerated rendering for Avalonia
 637          /// </summary>
 638          public ReactiveObject<bool> EnableHardwareAcceleration { get; private set; }
 639  
 640          /// <summary>
 641          /// Hide Cursor on Idle
 642          /// </summary>
 643          public ReactiveObject<HideCursorMode> HideCursor { get; private set; }
 644  
 645          private ConfigurationState()
 646          {
 647              UI = new UISection();
 648              Logger = new LoggerSection();
 649              System = new SystemSection();
 650              Graphics = new GraphicsSection();
 651              Hid = new HidSection();
 652              Multiplayer = new MultiplayerSection();
 653              EnableDiscordIntegration = new ReactiveObject<bool>();
 654              CheckUpdatesOnStart = new ReactiveObject<bool>();
 655              ShowConfirmExit = new ReactiveObject<bool>();
 656              RememberWindowState = new ReactiveObject<bool>();
 657              EnableHardwareAcceleration = new ReactiveObject<bool>();
 658              HideCursor = new ReactiveObject<HideCursorMode>();
 659          }
 660  
 661          public ConfigurationFileFormat ToFileFormat()
 662          {
 663              ConfigurationFileFormat configurationFile = new()
 664              {
 665                  Version = ConfigurationFileFormat.CurrentVersion,
 666                  BackendThreading = Graphics.BackendThreading,
 667                  EnableFileLog = Logger.EnableFileLog,
 668                  ResScale = Graphics.ResScale,
 669                  ResScaleCustom = Graphics.ResScaleCustom,
 670                  MaxAnisotropy = Graphics.MaxAnisotropy,
 671                  AspectRatio = Graphics.AspectRatio,
 672                  AntiAliasing = Graphics.AntiAliasing,
 673                  ScalingFilter = Graphics.ScalingFilter,
 674                  ScalingFilterLevel = Graphics.ScalingFilterLevel,
 675                  GraphicsShadersDumpPath = Graphics.ShadersDumpPath,
 676                  LoggingEnableDebug = Logger.EnableDebug,
 677                  LoggingEnableStub = Logger.EnableStub,
 678                  LoggingEnableInfo = Logger.EnableInfo,
 679                  LoggingEnableWarn = Logger.EnableWarn,
 680                  LoggingEnableError = Logger.EnableError,
 681                  LoggingEnableTrace = Logger.EnableTrace,
 682                  LoggingEnableGuest = Logger.EnableGuest,
 683                  LoggingEnableFsAccessLog = Logger.EnableFsAccessLog,
 684                  LoggingFilteredClasses = Logger.FilteredClasses,
 685                  LoggingGraphicsDebugLevel = Logger.GraphicsDebugLevel,
 686                  SystemLanguage = System.Language,
 687                  SystemRegion = System.Region,
 688                  SystemTimeZone = System.TimeZone,
 689                  SystemTimeOffset = System.SystemTimeOffset,
 690                  DockedMode = System.EnableDockedMode,
 691                  EnableDiscordIntegration = EnableDiscordIntegration,
 692                  CheckUpdatesOnStart = CheckUpdatesOnStart,
 693                  ShowConfirmExit = ShowConfirmExit,
 694                  RememberWindowState = RememberWindowState,
 695                  EnableHardwareAcceleration = EnableHardwareAcceleration,
 696                  HideCursor = HideCursor,
 697                  EnableVsync = Graphics.EnableVsync,
 698                  EnableShaderCache = Graphics.EnableShaderCache,
 699                  EnableTextureRecompression = Graphics.EnableTextureRecompression,
 700                  EnableMacroHLE = Graphics.EnableMacroHLE,
 701                  EnableColorSpacePassthrough = Graphics.EnableColorSpacePassthrough,
 702                  EnablePtc = System.EnablePtc,
 703                  EnableInternetAccess = System.EnableInternetAccess,
 704                  EnableFsIntegrityChecks = System.EnableFsIntegrityChecks,
 705                  FsGlobalAccessLogMode = System.FsGlobalAccessLogMode,
 706                  AudioBackend = System.AudioBackend,
 707                  AudioVolume = System.AudioVolume,
 708                  MemoryManagerMode = System.MemoryManagerMode,
 709                  ExpandRam = System.ExpandRam,
 710                  IgnoreMissingServices = System.IgnoreMissingServices,
 711                  UseHypervisor = System.UseHypervisor,
 712                  GuiColumns = new GuiColumns
 713                  {
 714                      FavColumn = UI.GuiColumns.FavColumn,
 715                      IconColumn = UI.GuiColumns.IconColumn,
 716                      AppColumn = UI.GuiColumns.AppColumn,
 717                      DevColumn = UI.GuiColumns.DevColumn,
 718                      VersionColumn = UI.GuiColumns.VersionColumn,
 719                      TimePlayedColumn = UI.GuiColumns.TimePlayedColumn,
 720                      LastPlayedColumn = UI.GuiColumns.LastPlayedColumn,
 721                      FileExtColumn = UI.GuiColumns.FileExtColumn,
 722                      FileSizeColumn = UI.GuiColumns.FileSizeColumn,
 723                      PathColumn = UI.GuiColumns.PathColumn,
 724                  },
 725                  ColumnSort = new ColumnSort
 726                  {
 727                      SortColumnId = UI.ColumnSort.SortColumnId,
 728                      SortAscending = UI.ColumnSort.SortAscending,
 729                  },
 730                  GameDirs = UI.GameDirs,
 731                  ShownFileTypes = new ShownFileTypes
 732                  {
 733                      NSP = UI.ShownFileTypes.NSP,
 734                      PFS0 = UI.ShownFileTypes.PFS0,
 735                      XCI = UI.ShownFileTypes.XCI,
 736                      NCA = UI.ShownFileTypes.NCA,
 737                      NRO = UI.ShownFileTypes.NRO,
 738                      NSO = UI.ShownFileTypes.NSO,
 739                  },
 740                  WindowStartup = new WindowStartup
 741                  {
 742                      WindowSizeWidth = UI.WindowStartup.WindowSizeWidth,
 743                      WindowSizeHeight = UI.WindowStartup.WindowSizeHeight,
 744                      WindowPositionX = UI.WindowStartup.WindowPositionX,
 745                      WindowPositionY = UI.WindowStartup.WindowPositionY,
 746                      WindowMaximized = UI.WindowStartup.WindowMaximized,
 747                  },
 748                  LanguageCode = UI.LanguageCode,
 749                  EnableCustomTheme = UI.EnableCustomTheme,
 750                  CustomThemePath = UI.CustomThemePath,
 751                  BaseStyle = UI.BaseStyle,
 752                  GameListViewMode = UI.GameListViewMode,
 753                  ShowNames = UI.ShowNames,
 754                  GridSize = UI.GridSize,
 755                  ApplicationSort = UI.ApplicationSort,
 756                  IsAscendingOrder = UI.IsAscendingOrder,
 757                  StartFullscreen = UI.StartFullscreen,
 758                  ShowConsole = UI.ShowConsole,
 759                  EnableKeyboard = Hid.EnableKeyboard,
 760                  EnableMouse = Hid.EnableMouse,
 761                  Hotkeys = Hid.Hotkeys,
 762                  KeyboardConfig = new List<JsonObject>(),
 763                  ControllerConfig = new List<JsonObject>(),
 764                  InputConfig = Hid.InputConfig,
 765                  GraphicsBackend = Graphics.GraphicsBackend,
 766                  PreferredGpu = Graphics.PreferredGpu,
 767                  MultiplayerLanInterfaceId = Multiplayer.LanInterfaceId,
 768                  MultiplayerMode = Multiplayer.Mode,
 769              };
 770  
 771              return configurationFile;
 772          }
 773  
 774          public void LoadDefault()
 775          {
 776              Logger.EnableFileLog.Value = true;
 777              Graphics.BackendThreading.Value = BackendThreading.Auto;
 778              Graphics.ResScale.Value = 1;
 779              Graphics.ResScaleCustom.Value = 1.0f;
 780              Graphics.MaxAnisotropy.Value = -1.0f;
 781              Graphics.AspectRatio.Value = AspectRatio.Fixed16x9;
 782              Graphics.GraphicsBackend.Value = DefaultGraphicsBackend();
 783              Graphics.PreferredGpu.Value = "";
 784              Graphics.ShadersDumpPath.Value = "";
 785              Logger.EnableDebug.Value = false;
 786              Logger.EnableStub.Value = true;
 787              Logger.EnableInfo.Value = true;
 788              Logger.EnableWarn.Value = true;
 789              Logger.EnableError.Value = true;
 790              Logger.EnableTrace.Value = false;
 791              Logger.EnableGuest.Value = true;
 792              Logger.EnableFsAccessLog.Value = false;
 793              Logger.FilteredClasses.Value = Array.Empty<LogClass>();
 794              Logger.GraphicsDebugLevel.Value = GraphicsDebugLevel.None;
 795              System.Language.Value = Language.AmericanEnglish;
 796              System.Region.Value = Region.USA;
 797              System.TimeZone.Value = "UTC";
 798              System.SystemTimeOffset.Value = 0;
 799              System.EnableDockedMode.Value = true;
 800              EnableDiscordIntegration.Value = true;
 801              CheckUpdatesOnStart.Value = true;
 802              ShowConfirmExit.Value = true;
 803              RememberWindowState.Value = true;
 804              EnableHardwareAcceleration.Value = true;
 805              HideCursor.Value = HideCursorMode.OnIdle;
 806              Graphics.EnableVsync.Value = true;
 807              Graphics.EnableShaderCache.Value = true;
 808              Graphics.EnableTextureRecompression.Value = false;
 809              Graphics.EnableMacroHLE.Value = true;
 810              Graphics.EnableColorSpacePassthrough.Value = false;
 811              Graphics.AntiAliasing.Value = AntiAliasing.None;
 812              Graphics.ScalingFilter.Value = ScalingFilter.Bilinear;
 813              Graphics.ScalingFilterLevel.Value = 80;
 814              System.EnablePtc.Value = true;
 815              System.EnableInternetAccess.Value = false;
 816              System.EnableFsIntegrityChecks.Value = true;
 817              System.FsGlobalAccessLogMode.Value = 0;
 818              System.AudioBackend.Value = AudioBackend.SDL2;
 819              System.AudioVolume.Value = 1;
 820              System.MemoryManagerMode.Value = MemoryManagerMode.HostMappedUnsafe;
 821              System.ExpandRam.Value = false;
 822              System.IgnoreMissingServices.Value = false;
 823              System.UseHypervisor.Value = true;
 824              Multiplayer.LanInterfaceId.Value = "0";
 825              Multiplayer.Mode.Value = MultiplayerMode.Disabled;
 826              UI.GuiColumns.FavColumn.Value = true;
 827              UI.GuiColumns.IconColumn.Value = true;
 828              UI.GuiColumns.AppColumn.Value = true;
 829              UI.GuiColumns.DevColumn.Value = true;
 830              UI.GuiColumns.VersionColumn.Value = true;
 831              UI.GuiColumns.TimePlayedColumn.Value = true;
 832              UI.GuiColumns.LastPlayedColumn.Value = true;
 833              UI.GuiColumns.FileExtColumn.Value = true;
 834              UI.GuiColumns.FileSizeColumn.Value = true;
 835              UI.GuiColumns.PathColumn.Value = true;
 836              UI.ColumnSort.SortColumnId.Value = 0;
 837              UI.ColumnSort.SortAscending.Value = false;
 838              UI.GameDirs.Value = new List<string>();
 839              UI.ShownFileTypes.NSP.Value = true;
 840              UI.ShownFileTypes.PFS0.Value = true;
 841              UI.ShownFileTypes.XCI.Value = true;
 842              UI.ShownFileTypes.NCA.Value = true;
 843              UI.ShownFileTypes.NRO.Value = true;
 844              UI.ShownFileTypes.NSO.Value = true;
 845              UI.EnableCustomTheme.Value = true;
 846              UI.LanguageCode.Value = "en_US";
 847              UI.CustomThemePath.Value = "";
 848              UI.BaseStyle.Value = "Dark";
 849              UI.GameListViewMode.Value = 0;
 850              UI.ShowNames.Value = true;
 851              UI.GridSize.Value = 2;
 852              UI.ApplicationSort.Value = 0;
 853              UI.IsAscendingOrder.Value = true;
 854              UI.StartFullscreen.Value = false;
 855              UI.ShowConsole.Value = true;
 856              UI.WindowStartup.WindowSizeWidth.Value = 1280;
 857              UI.WindowStartup.WindowSizeHeight.Value = 760;
 858              UI.WindowStartup.WindowPositionX.Value = 0;
 859              UI.WindowStartup.WindowPositionY.Value = 0;
 860              UI.WindowStartup.WindowMaximized.Value = false;
 861              Hid.EnableKeyboard.Value = false;
 862              Hid.EnableMouse.Value = false;
 863              Hid.Hotkeys.Value = new KeyboardHotkeys
 864              {
 865                  ToggleVsync = Key.F1,
 866                  ToggleMute = Key.F2,
 867                  Screenshot = Key.F8,
 868                  ShowUI = Key.F4,
 869                  Pause = Key.F5,
 870                  ResScaleUp = Key.Unbound,
 871                  ResScaleDown = Key.Unbound,
 872                  VolumeUp = Key.Unbound,
 873                  VolumeDown = Key.Unbound,
 874              };
 875              Hid.InputConfig.Value = new List<InputConfig>
 876              {
 877                  new StandardKeyboardInputConfig
 878                  {
 879                      Version = InputConfig.CurrentVersion,
 880                      Backend = InputBackendType.WindowKeyboard,
 881                      Id = "0",
 882                      PlayerIndex = PlayerIndex.Player1,
 883                      ControllerType = ControllerType.JoyconPair,
 884                      LeftJoycon = new LeftJoyconCommonConfig<Key>
 885                      {
 886                          DpadUp = Key.Up,
 887                          DpadDown = Key.Down,
 888                          DpadLeft = Key.Left,
 889                          DpadRight = Key.Right,
 890                          ButtonMinus = Key.Minus,
 891                          ButtonL = Key.E,
 892                          ButtonZl = Key.Q,
 893                          ButtonSl = Key.Unbound,
 894                          ButtonSr = Key.Unbound,
 895                      },
 896                      LeftJoyconStick = new JoyconConfigKeyboardStick<Key>
 897                      {
 898                          StickUp = Key.W,
 899                          StickDown = Key.S,
 900                          StickLeft = Key.A,
 901                          StickRight = Key.D,
 902                          StickButton = Key.F,
 903                      },
 904                      RightJoycon = new RightJoyconCommonConfig<Key>
 905                      {
 906                          ButtonA = Key.Z,
 907                          ButtonB = Key.X,
 908                          ButtonX = Key.C,
 909                          ButtonY = Key.V,
 910                          ButtonPlus = Key.Plus,
 911                          ButtonR = Key.U,
 912                          ButtonZr = Key.O,
 913                          ButtonSl = Key.Unbound,
 914                          ButtonSr = Key.Unbound,
 915                      },
 916                      RightJoyconStick = new JoyconConfigKeyboardStick<Key>
 917                      {
 918                          StickUp = Key.I,
 919                          StickDown = Key.K,
 920                          StickLeft = Key.J,
 921                          StickRight = Key.L,
 922                          StickButton = Key.H,
 923                      },
 924                  },
 925              };
 926          }
 927  
 928          public void Load(ConfigurationFileFormat configurationFileFormat, string configurationFilePath)
 929          {
 930              bool configurationFileUpdated = false;
 931  
 932              if (configurationFileFormat.Version < 0 || configurationFileFormat.Version > ConfigurationFileFormat.CurrentVersion)
 933              {
 934                  Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Unsupported configuration version {configurationFileFormat.Version}, loading default.");
 935  
 936                  LoadDefault();
 937              }
 938  
 939              if (configurationFileFormat.Version < 2)
 940              {
 941                  Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 2.");
 942  
 943                  configurationFileFormat.SystemRegion = Region.USA;
 944  
 945                  configurationFileUpdated = true;
 946              }
 947  
 948              if (configurationFileFormat.Version < 3)
 949              {
 950                  Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 3.");
 951  
 952                  configurationFileFormat.SystemTimeZone = "UTC";
 953  
 954                  configurationFileUpdated = true;
 955              }
 956  
 957              if (configurationFileFormat.Version < 4)
 958              {
 959                  Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 4.");
 960  
 961                  configurationFileFormat.MaxAnisotropy = -1;
 962  
 963                  configurationFileUpdated = true;
 964              }
 965  
 966              if (configurationFileFormat.Version < 5)
 967              {
 968                  Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 5.");
 969  
 970                  configurationFileFormat.SystemTimeOffset = 0;
 971  
 972                  configurationFileUpdated = true;
 973              }
 974  
 975              if (configurationFileFormat.Version < 8)
 976              {
 977                  Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 8.");
 978  
 979                  configurationFileFormat.EnablePtc = true;
 980  
 981                  configurationFileUpdated = true;
 982              }
 983  
 984              if (configurationFileFormat.Version < 9)
 985              {
 986                  Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 9.");
 987  
 988                  configurationFileFormat.ColumnSort = new ColumnSort
 989                  {
 990                      SortColumnId = 0,
 991                      SortAscending = false,
 992                  };
 993  
 994                  configurationFileFormat.Hotkeys = new KeyboardHotkeys
 995                  {
 996                      ToggleVsync = Key.F1,
 997                  };
 998  
 999                  configurationFileUpdated = true;
1000              }
1001  
1002              if (configurationFileFormat.Version < 10)
1003              {
1004                  Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 10.");
1005  
1006                  configurationFileFormat.AudioBackend = AudioBackend.OpenAl;
1007  
1008                  configurationFileUpdated = true;
1009              }
1010  
1011              if (configurationFileFormat.Version < 11)
1012              {
1013                  Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 11.");
1014  
1015                  configurationFileFormat.ResScale = 1;
1016                  configurationFileFormat.ResScaleCustom = 1.0f;
1017  
1018                  configurationFileUpdated = true;
1019              }
1020  
1021              if (configurationFileFormat.Version < 12)
1022              {
1023                  Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 12.");
1024  
1025                  configurationFileFormat.LoggingGraphicsDebugLevel = GraphicsDebugLevel.None;
1026  
1027                  configurationFileUpdated = true;
1028              }
1029  
1030              // configurationFileFormat.Version == 13 -> LDN1
1031  
1032              if (configurationFileFormat.Version < 14)
1033              {
1034                  Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 14.");
1035  
1036                  configurationFileFormat.CheckUpdatesOnStart = true;
1037  
1038                  configurationFileUpdated = true;
1039              }
1040  
1041              if (configurationFileFormat.Version < 16)
1042              {
1043                  Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 16.");
1044  
1045                  configurationFileFormat.EnableShaderCache = true;
1046  
1047                  configurationFileUpdated = true;
1048              }
1049  
1050              if (configurationFileFormat.Version < 17)
1051              {
1052                  Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 17.");
1053  
1054                  configurationFileFormat.StartFullscreen = false;
1055  
1056                  configurationFileUpdated = true;
1057              }
1058  
1059              if (configurationFileFormat.Version < 18)
1060              {
1061                  Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 18.");
1062  
1063                  configurationFileFormat.AspectRatio = AspectRatio.Fixed16x9;
1064  
1065                  configurationFileUpdated = true;
1066              }
1067  
1068              // configurationFileFormat.Version == 19 -> LDN2
1069  
1070              if (configurationFileFormat.Version < 20)
1071              {
1072                  Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 20.");
1073  
1074                  configurationFileFormat.ShowConfirmExit = true;
1075  
1076                  configurationFileUpdated = true;
1077              }
1078  
1079              if (configurationFileFormat.Version < 21)
1080              {
1081                  Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 21.");
1082  
1083                  // Initialize network config.
1084  
1085                  configurationFileFormat.MultiplayerMode = MultiplayerMode.Disabled;
1086                  configurationFileFormat.MultiplayerLanInterfaceId = "0";
1087  
1088                  configurationFileUpdated = true;
1089              }
1090  
1091              if (configurationFileFormat.Version < 22)
1092              {
1093                  Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 22.");
1094  
1095                  configurationFileFormat.HideCursor = HideCursorMode.Never;
1096  
1097                  configurationFileUpdated = true;
1098              }
1099  
1100              if (configurationFileFormat.Version < 24)
1101              {
1102                  Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 24.");
1103  
1104                  configurationFileFormat.InputConfig = new List<InputConfig>
1105                  {
1106                      new StandardKeyboardInputConfig
1107                      {
1108                          Version = InputConfig.CurrentVersion,
1109                          Backend = InputBackendType.WindowKeyboard,
1110                          Id = "0",
1111                          PlayerIndex = PlayerIndex.Player1,
1112                          ControllerType = ControllerType.JoyconPair,
1113                          LeftJoycon = new LeftJoyconCommonConfig<Key>
1114                          {
1115                              DpadUp = Key.Up,
1116                              DpadDown = Key.Down,
1117                              DpadLeft = Key.Left,
1118                              DpadRight = Key.Right,
1119                              ButtonMinus = Key.Minus,
1120                              ButtonL = Key.E,
1121                              ButtonZl = Key.Q,
1122                              ButtonSl = Key.Unbound,
1123                              ButtonSr = Key.Unbound,
1124                          },
1125                          LeftJoyconStick = new JoyconConfigKeyboardStick<Key>
1126                          {
1127                              StickUp = Key.W,
1128                              StickDown = Key.S,
1129                              StickLeft = Key.A,
1130                              StickRight = Key.D,
1131                              StickButton = Key.F,
1132                          },
1133                          RightJoycon = new RightJoyconCommonConfig<Key>
1134                          {
1135                              ButtonA = Key.Z,
1136                              ButtonB = Key.X,
1137                              ButtonX = Key.C,
1138                              ButtonY = Key.V,
1139                              ButtonPlus = Key.Plus,
1140                              ButtonR = Key.U,
1141                              ButtonZr = Key.O,
1142                              ButtonSl = Key.Unbound,
1143                              ButtonSr = Key.Unbound,
1144                          },
1145                          RightJoyconStick = new JoyconConfigKeyboardStick<Key>
1146                          {
1147                              StickUp = Key.I,
1148                              StickDown = Key.K,
1149                              StickLeft = Key.J,
1150                              StickRight = Key.L,
1151                              StickButton = Key.H,
1152                          },
1153                      },
1154                  };
1155  
1156                  configurationFileUpdated = true;
1157              }
1158  
1159              if (configurationFileFormat.Version < 25)
1160              {
1161                  Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 25.");
1162  
1163                  configurationFileUpdated = true;
1164              }
1165  
1166              if (configurationFileFormat.Version < 26)
1167              {
1168                  Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 26.");
1169  
1170                  configurationFileFormat.MemoryManagerMode = MemoryManagerMode.HostMappedUnsafe;
1171  
1172                  configurationFileUpdated = true;
1173              }
1174  
1175              if (configurationFileFormat.Version < 27)
1176              {
1177                  Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 27.");
1178  
1179                  configurationFileFormat.EnableMouse = false;
1180  
1181                  configurationFileUpdated = true;
1182              }
1183  
1184              if (configurationFileFormat.Version < 28)
1185              {
1186                  Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 28.");
1187  
1188                  configurationFileFormat.Hotkeys = new KeyboardHotkeys
1189                  {
1190                      ToggleVsync = Key.F1,
1191                      Screenshot = Key.F8,
1192                  };
1193  
1194                  configurationFileUpdated = true;
1195              }
1196  
1197              if (configurationFileFormat.Version < 29)
1198              {
1199                  Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 29.");
1200  
1201                  configurationFileFormat.Hotkeys = new KeyboardHotkeys
1202                  {
1203                      ToggleVsync = Key.F1,
1204                      Screenshot = Key.F8,
1205                      ShowUI = Key.F4,
1206                  };
1207  
1208                  configurationFileUpdated = true;
1209              }
1210  
1211              if (configurationFileFormat.Version < 30)
1212              {
1213                  Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 30.");
1214  
1215                  foreach (InputConfig config in configurationFileFormat.InputConfig)
1216                  {
1217                      if (config is StandardControllerInputConfig controllerConfig)
1218                      {
1219                          controllerConfig.Rumble = new RumbleConfigController
1220                          {
1221                              EnableRumble = false,
1222                              StrongRumble = 1f,
1223                              WeakRumble = 1f,
1224                          };
1225                      }
1226                  }
1227  
1228                  configurationFileUpdated = true;
1229              }
1230  
1231              if (configurationFileFormat.Version < 31)
1232              {
1233                  Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 31.");
1234  
1235                  configurationFileFormat.BackendThreading = BackendThreading.Auto;
1236  
1237                  configurationFileUpdated = true;
1238              }
1239  
1240              if (configurationFileFormat.Version < 32)
1241              {
1242                  Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 32.");
1243  
1244                  configurationFileFormat.Hotkeys = new KeyboardHotkeys
1245                  {
1246                      ToggleVsync = configurationFileFormat.Hotkeys.ToggleVsync,
1247                      Screenshot = configurationFileFormat.Hotkeys.Screenshot,
1248                      ShowUI = configurationFileFormat.Hotkeys.ShowUI,
1249                      Pause = Key.F5,
1250                  };
1251  
1252                  configurationFileUpdated = true;
1253              }
1254  
1255              if (configurationFileFormat.Version < 33)
1256              {
1257                  Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 33.");
1258  
1259                  configurationFileFormat.Hotkeys = new KeyboardHotkeys
1260                  {
1261                      ToggleVsync = configurationFileFormat.Hotkeys.ToggleVsync,
1262                      Screenshot = configurationFileFormat.Hotkeys.Screenshot,
1263                      ShowUI = configurationFileFormat.Hotkeys.ShowUI,
1264                      Pause = configurationFileFormat.Hotkeys.Pause,
1265                      ToggleMute = Key.F2,
1266                  };
1267  
1268                  configurationFileFormat.AudioVolume = 1;
1269  
1270                  configurationFileUpdated = true;
1271              }
1272  
1273              if (configurationFileFormat.Version < 34)
1274              {
1275                  Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 34.");
1276  
1277                  configurationFileFormat.EnableInternetAccess = false;
1278  
1279                  configurationFileUpdated = true;
1280              }
1281  
1282              if (configurationFileFormat.Version < 35)
1283              {
1284                  Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 35.");
1285  
1286                  foreach (InputConfig config in configurationFileFormat.InputConfig)
1287                  {
1288                      if (config is StandardControllerInputConfig controllerConfig)
1289                      {
1290                          controllerConfig.RangeLeft = 1.0f;
1291                          controllerConfig.RangeRight = 1.0f;
1292                      }
1293                  }
1294  
1295                  configurationFileUpdated = true;
1296              }
1297  
1298              if (configurationFileFormat.Version < 36)
1299              {
1300                  Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 36.");
1301  
1302                  configurationFileFormat.LoggingEnableTrace = false;
1303  
1304                  configurationFileUpdated = true;
1305              }
1306  
1307              if (configurationFileFormat.Version < 37)
1308              {
1309                  Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 37.");
1310  
1311                  configurationFileFormat.ShowConsole = true;
1312  
1313                  configurationFileUpdated = true;
1314              }
1315  
1316              if (configurationFileFormat.Version < 38)
1317              {
1318                  Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 38.");
1319  
1320                  configurationFileFormat.BaseStyle = "Dark";
1321                  configurationFileFormat.GameListViewMode = 0;
1322                  configurationFileFormat.ShowNames = true;
1323                  configurationFileFormat.GridSize = 2;
1324                  configurationFileFormat.LanguageCode = "en_US";
1325  
1326                  configurationFileUpdated = true;
1327              }
1328  
1329              if (configurationFileFormat.Version < 39)
1330              {
1331                  Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 39.");
1332  
1333                  configurationFileFormat.Hotkeys = new KeyboardHotkeys
1334                  {
1335                      ToggleVsync = configurationFileFormat.Hotkeys.ToggleVsync,
1336                      Screenshot = configurationFileFormat.Hotkeys.Screenshot,
1337                      ShowUI = configurationFileFormat.Hotkeys.ShowUI,
1338                      Pause = configurationFileFormat.Hotkeys.Pause,
1339                      ToggleMute = configurationFileFormat.Hotkeys.ToggleMute,
1340                      ResScaleUp = Key.Unbound,
1341                      ResScaleDown = Key.Unbound,
1342                  };
1343  
1344                  configurationFileUpdated = true;
1345              }
1346  
1347              if (configurationFileFormat.Version < 40)
1348              {
1349                  Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 40.");
1350  
1351                  configurationFileFormat.GraphicsBackend = GraphicsBackend.OpenGl;
1352  
1353                  configurationFileUpdated = true;
1354              }
1355  
1356              if (configurationFileFormat.Version < 41)
1357              {
1358                  Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 41.");
1359  
1360                  configurationFileFormat.Hotkeys = new KeyboardHotkeys
1361                  {
1362                      ToggleVsync = configurationFileFormat.Hotkeys.ToggleVsync,
1363                      Screenshot = configurationFileFormat.Hotkeys.Screenshot,
1364                      ShowUI = configurationFileFormat.Hotkeys.ShowUI,
1365                      Pause = configurationFileFormat.Hotkeys.Pause,
1366                      ToggleMute = configurationFileFormat.Hotkeys.ToggleMute,
1367                      ResScaleUp = configurationFileFormat.Hotkeys.ResScaleUp,
1368                      ResScaleDown = configurationFileFormat.Hotkeys.ResScaleDown,
1369                      VolumeUp = Key.Unbound,
1370                      VolumeDown = Key.Unbound,
1371                  };
1372              }
1373  
1374              if (configurationFileFormat.Version < 42)
1375              {
1376                  Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 42.");
1377  
1378                  configurationFileFormat.EnableMacroHLE = true;
1379              }
1380  
1381              if (configurationFileFormat.Version < 43)
1382              {
1383                  Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 43.");
1384  
1385                  configurationFileFormat.UseHypervisor = true;
1386              }
1387  
1388              if (configurationFileFormat.Version < 44)
1389              {
1390                  Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 44.");
1391  
1392                  configurationFileFormat.AntiAliasing = AntiAliasing.None;
1393                  configurationFileFormat.ScalingFilter = ScalingFilter.Bilinear;
1394                  configurationFileFormat.ScalingFilterLevel = 80;
1395  
1396                  configurationFileUpdated = true;
1397              }
1398  
1399              if (configurationFileFormat.Version < 45)
1400              {
1401                  Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 45.");
1402  
1403                  configurationFileFormat.ShownFileTypes = new ShownFileTypes
1404                  {
1405                      NSP = true,
1406                      PFS0 = true,
1407                      XCI = true,
1408                      NCA = true,
1409                      NRO = true,
1410                      NSO = true,
1411                  };
1412  
1413                  configurationFileUpdated = true;
1414              }
1415  
1416              if (configurationFileFormat.Version < 46)
1417              {
1418                  Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 46.");
1419  
1420                  configurationFileFormat.MultiplayerLanInterfaceId = "0";
1421  
1422                  configurationFileUpdated = true;
1423              }
1424  
1425              if (configurationFileFormat.Version < 47)
1426              {
1427                  Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 47.");
1428  
1429                  configurationFileFormat.WindowStartup = new WindowStartup
1430                  {
1431                      WindowPositionX = 0,
1432                      WindowPositionY = 0,
1433                      WindowSizeHeight = 760,
1434                      WindowSizeWidth = 1280,
1435                      WindowMaximized = false,
1436                  };
1437  
1438                  configurationFileUpdated = true;
1439              }
1440  
1441              if (configurationFileFormat.Version < 48)
1442              {
1443                  Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 48.");
1444  
1445                  configurationFileFormat.EnableColorSpacePassthrough = false;
1446  
1447                  configurationFileUpdated = true;
1448              }
1449  
1450              if (configurationFileFormat.Version < 49)
1451              {
1452                  Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 49.");
1453  
1454                  if (OperatingSystem.IsMacOS())
1455                  {
1456                      AppDataManager.FixMacOSConfigurationFolders();
1457                  }
1458  
1459                  configurationFileUpdated = true;
1460              }
1461  
1462              if (configurationFileFormat.Version < 50)
1463              {
1464                  Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 50.");
1465  
1466                  configurationFileFormat.EnableHardwareAcceleration = true;
1467  
1468                  configurationFileUpdated = true;
1469              }
1470  
1471              if (configurationFileFormat.Version < 51)
1472              {
1473                  Ryujinx.Common.Logging.Logger.Warning?.Print(LogClass.Application, $"Outdated configuration version {configurationFileFormat.Version}, migrating to version 51.");
1474  
1475                  configurationFileFormat.RememberWindowState = true;
1476  
1477                  configurationFileUpdated = true;
1478              }
1479  
1480              Logger.EnableFileLog.Value = configurationFileFormat.EnableFileLog;
1481              Graphics.ResScale.Value = configurationFileFormat.ResScale;
1482              Graphics.ResScaleCustom.Value = configurationFileFormat.ResScaleCustom;
1483              Graphics.MaxAnisotropy.Value = configurationFileFormat.MaxAnisotropy;
1484              Graphics.AspectRatio.Value = configurationFileFormat.AspectRatio;
1485              Graphics.ShadersDumpPath.Value = configurationFileFormat.GraphicsShadersDumpPath;
1486              Graphics.BackendThreading.Value = configurationFileFormat.BackendThreading;
1487              Graphics.GraphicsBackend.Value = configurationFileFormat.GraphicsBackend;
1488              Graphics.PreferredGpu.Value = configurationFileFormat.PreferredGpu;
1489              Graphics.AntiAliasing.Value = configurationFileFormat.AntiAliasing;
1490              Graphics.ScalingFilter.Value = configurationFileFormat.ScalingFilter;
1491              Graphics.ScalingFilterLevel.Value = configurationFileFormat.ScalingFilterLevel;
1492              Logger.EnableDebug.Value = configurationFileFormat.LoggingEnableDebug;
1493              Logger.EnableStub.Value = configurationFileFormat.LoggingEnableStub;
1494              Logger.EnableInfo.Value = configurationFileFormat.LoggingEnableInfo;
1495              Logger.EnableWarn.Value = configurationFileFormat.LoggingEnableWarn;
1496              Logger.EnableError.Value = configurationFileFormat.LoggingEnableError;
1497              Logger.EnableTrace.Value = configurationFileFormat.LoggingEnableTrace;
1498              Logger.EnableGuest.Value = configurationFileFormat.LoggingEnableGuest;
1499              Logger.EnableFsAccessLog.Value = configurationFileFormat.LoggingEnableFsAccessLog;
1500              Logger.FilteredClasses.Value = configurationFileFormat.LoggingFilteredClasses;
1501              Logger.GraphicsDebugLevel.Value = configurationFileFormat.LoggingGraphicsDebugLevel;
1502              System.Language.Value = configurationFileFormat.SystemLanguage;
1503              System.Region.Value = configurationFileFormat.SystemRegion;
1504              System.TimeZone.Value = configurationFileFormat.SystemTimeZone;
1505              System.SystemTimeOffset.Value = configurationFileFormat.SystemTimeOffset;
1506              System.EnableDockedMode.Value = configurationFileFormat.DockedMode;
1507              EnableDiscordIntegration.Value = configurationFileFormat.EnableDiscordIntegration;
1508              CheckUpdatesOnStart.Value = configurationFileFormat.CheckUpdatesOnStart;
1509              ShowConfirmExit.Value = configurationFileFormat.ShowConfirmExit;
1510              RememberWindowState.Value = configurationFileFormat.RememberWindowState;
1511              EnableHardwareAcceleration.Value = configurationFileFormat.EnableHardwareAcceleration;
1512              HideCursor.Value = configurationFileFormat.HideCursor;
1513              Graphics.EnableVsync.Value = configurationFileFormat.EnableVsync;
1514              Graphics.EnableShaderCache.Value = configurationFileFormat.EnableShaderCache;
1515              Graphics.EnableTextureRecompression.Value = configurationFileFormat.EnableTextureRecompression;
1516              Graphics.EnableMacroHLE.Value = configurationFileFormat.EnableMacroHLE;
1517              Graphics.EnableColorSpacePassthrough.Value = configurationFileFormat.EnableColorSpacePassthrough;
1518              System.EnablePtc.Value = configurationFileFormat.EnablePtc;
1519              System.EnableInternetAccess.Value = configurationFileFormat.EnableInternetAccess;
1520              System.EnableFsIntegrityChecks.Value = configurationFileFormat.EnableFsIntegrityChecks;
1521              System.FsGlobalAccessLogMode.Value = configurationFileFormat.FsGlobalAccessLogMode;
1522              System.AudioBackend.Value = configurationFileFormat.AudioBackend;
1523              System.AudioVolume.Value = configurationFileFormat.AudioVolume;
1524              System.MemoryManagerMode.Value = configurationFileFormat.MemoryManagerMode;
1525              System.ExpandRam.Value = configurationFileFormat.ExpandRam;
1526              System.IgnoreMissingServices.Value = configurationFileFormat.IgnoreMissingServices;
1527              System.UseHypervisor.Value = configurationFileFormat.UseHypervisor;
1528              UI.GuiColumns.FavColumn.Value = configurationFileFormat.GuiColumns.FavColumn;
1529              UI.GuiColumns.IconColumn.Value = configurationFileFormat.GuiColumns.IconColumn;
1530              UI.GuiColumns.AppColumn.Value = configurationFileFormat.GuiColumns.AppColumn;
1531              UI.GuiColumns.DevColumn.Value = configurationFileFormat.GuiColumns.DevColumn;
1532              UI.GuiColumns.VersionColumn.Value = configurationFileFormat.GuiColumns.VersionColumn;
1533              UI.GuiColumns.TimePlayedColumn.Value = configurationFileFormat.GuiColumns.TimePlayedColumn;
1534              UI.GuiColumns.LastPlayedColumn.Value = configurationFileFormat.GuiColumns.LastPlayedColumn;
1535              UI.GuiColumns.FileExtColumn.Value = configurationFileFormat.GuiColumns.FileExtColumn;
1536              UI.GuiColumns.FileSizeColumn.Value = configurationFileFormat.GuiColumns.FileSizeColumn;
1537              UI.GuiColumns.PathColumn.Value = configurationFileFormat.GuiColumns.PathColumn;
1538              UI.ColumnSort.SortColumnId.Value = configurationFileFormat.ColumnSort.SortColumnId;
1539              UI.ColumnSort.SortAscending.Value = configurationFileFormat.ColumnSort.SortAscending;
1540              UI.GameDirs.Value = configurationFileFormat.GameDirs;
1541              UI.ShownFileTypes.NSP.Value = configurationFileFormat.ShownFileTypes.NSP;
1542              UI.ShownFileTypes.PFS0.Value = configurationFileFormat.ShownFileTypes.PFS0;
1543              UI.ShownFileTypes.XCI.Value = configurationFileFormat.ShownFileTypes.XCI;
1544              UI.ShownFileTypes.NCA.Value = configurationFileFormat.ShownFileTypes.NCA;
1545              UI.ShownFileTypes.NRO.Value = configurationFileFormat.ShownFileTypes.NRO;
1546              UI.ShownFileTypes.NSO.Value = configurationFileFormat.ShownFileTypes.NSO;
1547              UI.EnableCustomTheme.Value = configurationFileFormat.EnableCustomTheme;
1548              UI.LanguageCode.Value = configurationFileFormat.LanguageCode;
1549              UI.CustomThemePath.Value = configurationFileFormat.CustomThemePath;
1550              UI.BaseStyle.Value = configurationFileFormat.BaseStyle;
1551              UI.GameListViewMode.Value = configurationFileFormat.GameListViewMode;
1552              UI.ShowNames.Value = configurationFileFormat.ShowNames;
1553              UI.IsAscendingOrder.Value = configurationFileFormat.IsAscendingOrder;
1554              UI.GridSize.Value = configurationFileFormat.GridSize;
1555              UI.ApplicationSort.Value = configurationFileFormat.ApplicationSort;
1556              UI.StartFullscreen.Value = configurationFileFormat.StartFullscreen;
1557              UI.ShowConsole.Value = configurationFileFormat.ShowConsole;
1558              UI.WindowStartup.WindowSizeWidth.Value = configurationFileFormat.WindowStartup.WindowSizeWidth;
1559              UI.WindowStartup.WindowSizeHeight.Value = configurationFileFormat.WindowStartup.WindowSizeHeight;
1560              UI.WindowStartup.WindowPositionX.Value = configurationFileFormat.WindowStartup.WindowPositionX;
1561              UI.WindowStartup.WindowPositionY.Value = configurationFileFormat.WindowStartup.WindowPositionY;
1562              UI.WindowStartup.WindowMaximized.Value = configurationFileFormat.WindowStartup.WindowMaximized;
1563              Hid.EnableKeyboard.Value = configurationFileFormat.EnableKeyboard;
1564              Hid.EnableMouse.Value = configurationFileFormat.EnableMouse;
1565              Hid.Hotkeys.Value = configurationFileFormat.Hotkeys;
1566              Hid.InputConfig.Value = configurationFileFormat.InputConfig;
1567  
1568              if (Hid.InputConfig.Value == null)
1569              {
1570                  Hid.InputConfig.Value = new List<InputConfig>();
1571              }
1572  
1573              Multiplayer.LanInterfaceId.Value = configurationFileFormat.MultiplayerLanInterfaceId;
1574              Multiplayer.Mode.Value = configurationFileFormat.MultiplayerMode;
1575  
1576              if (configurationFileUpdated)
1577              {
1578                  ToFileFormat().SaveConfig(configurationFilePath);
1579  
1580                  Ryujinx.Common.Logging.Logger.Notice.Print(LogClass.Application, $"Configuration file updated to version {ConfigurationFileFormat.CurrentVersion}");
1581              }
1582          }
1583  
1584          private static GraphicsBackend DefaultGraphicsBackend()
1585          {
1586              // Any system running macOS or returning any amount of valid Vulkan devices should default to Vulkan.
1587              // Checks for if the Vulkan version and featureset is compatible should be performed within VulkanRenderer.
1588              if (OperatingSystem.IsMacOS() || VulkanRenderer.GetPhysicalDevices().Length > 0)
1589              {
1590                  return GraphicsBackend.Vulkan;
1591              }
1592  
1593              return GraphicsBackend.OpenGl;
1594          }
1595  
1596          private static void LogValueChange<T>(ReactiveEventArgs<T> eventArgs, string valueName)
1597          {
1598              string message = string.Create(CultureInfo.InvariantCulture, $"{valueName} set to: {eventArgs.NewValue}");
1599  
1600              Ryujinx.Common.Logging.Logger.Info?.Print(LogClass.Configuration, message);
1601          }
1602  
1603          public static void Initialize()
1604          {
1605              if (Instance != null)
1606              {
1607                  throw new InvalidOperationException("Configuration is already initialized");
1608              }
1609  
1610              Instance = new ConfigurationState();
1611          }
1612      }
1613  }