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 }