SettingsViewModel.cs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602
  1. using Avalonia.Collections;
  2. using Avalonia.Controls;
  3. using Avalonia.Threading;
  4. using LibHac.Tools.FsSystem;
  5. using Ryujinx.Audio.Backends.OpenAL;
  6. using Ryujinx.Audio.Backends.SDL2;
  7. using Ryujinx.Audio.Backends.SoundIo;
  8. using Ryujinx.Ava.Common.Locale;
  9. using Ryujinx.Ava.UI.Helpers;
  10. using Ryujinx.Ava.UI.Models.Input;
  11. using Ryujinx.Ava.UI.Windows;
  12. using Ryujinx.Common.Configuration;
  13. using Ryujinx.Common.Configuration.Multiplayer;
  14. using Ryujinx.Common.GraphicsDriver;
  15. using Ryujinx.Common.Logging;
  16. using Ryujinx.Graphics.Vulkan;
  17. using Ryujinx.HLE.FileSystem;
  18. using Ryujinx.HLE.HOS.Services.Time.TimeZone;
  19. using Ryujinx.UI.Common.Configuration;
  20. using Ryujinx.UI.Common.Configuration.System;
  21. using System;
  22. using System.Collections.Generic;
  23. using System.Collections.ObjectModel;
  24. using System.Linq;
  25. using System.Net.NetworkInformation;
  26. using System.Runtime.InteropServices;
  27. using System.Threading.Tasks;
  28. using TimeZone = Ryujinx.Ava.UI.Models.TimeZone;
  29. namespace Ryujinx.Ava.UI.ViewModels
  30. {
  31. public class SettingsViewModel : BaseModel
  32. {
  33. private readonly VirtualFileSystem _virtualFileSystem;
  34. private readonly ContentManager _contentManager;
  35. private TimeZoneContentManager _timeZoneContentManager;
  36. private readonly List<string> _validTzRegions;
  37. private readonly Dictionary<string, string> _networkInterfaces;
  38. private float _customResolutionScale;
  39. private int _resolutionScale;
  40. private int _graphicsBackendMultithreadingIndex;
  41. private float _volume;
  42. private bool _isVulkanAvailable = true;
  43. private bool _directoryChanged;
  44. private readonly List<string> _gpuIds = new();
  45. private int _graphicsBackendIndex;
  46. private int _scalingFilter;
  47. private int _scalingFilterLevel;
  48. public event Action CloseWindow;
  49. public event Action SaveSettingsEvent;
  50. private int _networkInterfaceIndex;
  51. private int _multiplayerModeIndex;
  52. public int ResolutionScale
  53. {
  54. get => _resolutionScale;
  55. set
  56. {
  57. _resolutionScale = value;
  58. OnPropertyChanged(nameof(CustomResolutionScale));
  59. OnPropertyChanged(nameof(IsCustomResolutionScaleActive));
  60. }
  61. }
  62. public int GraphicsBackendMultithreadingIndex
  63. {
  64. get => _graphicsBackendMultithreadingIndex;
  65. set
  66. {
  67. _graphicsBackendMultithreadingIndex = value;
  68. if (_graphicsBackendMultithreadingIndex != (int)ConfigurationState.Instance.Graphics.BackendThreading.Value)
  69. {
  70. Dispatcher.UIThread.InvokeAsync(() =>
  71. ContentDialogHelper.CreateInfoDialog(LocaleManager.Instance[LocaleKeys.DialogSettingsBackendThreadingWarningMessage],
  72. "",
  73. "",
  74. LocaleManager.Instance[LocaleKeys.InputDialogOk],
  75. LocaleManager.Instance[LocaleKeys.DialogSettingsBackendThreadingWarningTitle])
  76. );
  77. }
  78. OnPropertyChanged();
  79. }
  80. }
  81. public float CustomResolutionScale
  82. {
  83. get => _customResolutionScale;
  84. set
  85. {
  86. _customResolutionScale = MathF.Round(value, 1);
  87. OnPropertyChanged();
  88. }
  89. }
  90. public bool IsVulkanAvailable
  91. {
  92. get => _isVulkanAvailable;
  93. set
  94. {
  95. _isVulkanAvailable = value;
  96. OnPropertyChanged();
  97. }
  98. }
  99. public bool IsOpenGLAvailable => !OperatingSystem.IsMacOS();
  100. public bool IsHypervisorAvailable => OperatingSystem.IsMacOS() && RuntimeInformation.ProcessArchitecture == Architecture.Arm64;
  101. public bool DirectoryChanged
  102. {
  103. get => _directoryChanged;
  104. set
  105. {
  106. _directoryChanged = value;
  107. OnPropertyChanged();
  108. }
  109. }
  110. public bool IsMacOS => OperatingSystem.IsMacOS();
  111. public bool EnableDiscordIntegration { get; set; }
  112. public bool CheckUpdatesOnStart { get; set; }
  113. public bool ShowConfirmExit { get; set; }
  114. public bool RememberWindowState { get; set; }
  115. public int HideCursor { get; set; }
  116. public bool EnableDockedMode { get; set; }
  117. public bool EnableKeyboard { get; set; }
  118. public bool EnableMouse { get; set; }
  119. public bool EnableVsync { get; set; }
  120. public bool EnablePptc { get; set; }
  121. public bool EnableInternetAccess { get; set; }
  122. public bool EnableFsIntegrityChecks { get; set; }
  123. public bool IgnoreMissingServices { get; set; }
  124. public bool ExpandDramSize { get; set; }
  125. public bool EnableShaderCache { get; set; }
  126. public bool EnableTextureRecompression { get; set; }
  127. public bool EnableMacroHLE { get; set; }
  128. public bool EnableColorSpacePassthrough { get; set; }
  129. public bool ColorSpacePassthroughAvailable => IsMacOS;
  130. public bool EnableFileLog { get; set; }
  131. public bool EnableStub { get; set; }
  132. public bool EnableInfo { get; set; }
  133. public bool EnableWarn { get; set; }
  134. public bool EnableError { get; set; }
  135. public bool EnableTrace { get; set; }
  136. public bool EnableGuest { get; set; }
  137. public bool EnableFsAccessLog { get; set; }
  138. public bool EnableDebug { get; set; }
  139. public bool IsOpenAlEnabled { get; set; }
  140. public bool IsSoundIoEnabled { get; set; }
  141. public bool IsSDL2Enabled { get; set; }
  142. public bool IsCustomResolutionScaleActive => _resolutionScale == 4;
  143. public bool IsScalingFilterActive => _scalingFilter == (int)Ryujinx.Common.Configuration.ScalingFilter.Fsr;
  144. public bool IsVulkanSelected => GraphicsBackendIndex == 0;
  145. public bool UseHypervisor { get; set; }
  146. public string TimeZone { get; set; }
  147. public string ShaderDumpPath { get; set; }
  148. public int Language { get; set; }
  149. public int Region { get; set; }
  150. public int FsGlobalAccessLogMode { get; set; }
  151. public int AudioBackend { get; set; }
  152. public int MaxAnisotropy { get; set; }
  153. public int AspectRatio { get; set; }
  154. public int AntiAliasingEffect { get; set; }
  155. public string ScalingFilterLevelText => ScalingFilterLevel.ToString("0");
  156. public int ScalingFilterLevel
  157. {
  158. get => _scalingFilterLevel;
  159. set
  160. {
  161. _scalingFilterLevel = value;
  162. OnPropertyChanged();
  163. OnPropertyChanged(nameof(ScalingFilterLevelText));
  164. }
  165. }
  166. public int OpenglDebugLevel { get; set; }
  167. public int MemoryMode { get; set; }
  168. public int BaseStyleIndex { get; set; }
  169. public int GraphicsBackendIndex
  170. {
  171. get => _graphicsBackendIndex;
  172. set
  173. {
  174. _graphicsBackendIndex = value;
  175. OnPropertyChanged();
  176. OnPropertyChanged(nameof(IsVulkanSelected));
  177. }
  178. }
  179. public int ScalingFilter
  180. {
  181. get => _scalingFilter;
  182. set
  183. {
  184. _scalingFilter = value;
  185. OnPropertyChanged();
  186. OnPropertyChanged(nameof(IsScalingFilterActive));
  187. }
  188. }
  189. public int PreferredGpuIndex { get; set; }
  190. public float Volume
  191. {
  192. get => _volume;
  193. set
  194. {
  195. _volume = value;
  196. ConfigurationState.Instance.System.AudioVolume.Value = _volume / 100;
  197. OnPropertyChanged();
  198. }
  199. }
  200. public DateTimeOffset CurrentDate { get; set; }
  201. public TimeSpan CurrentTime { get; set; }
  202. internal AvaloniaList<TimeZone> TimeZones { get; set; }
  203. public AvaloniaList<string> GameDirectories { get; set; }
  204. public ObservableCollection<ComboBoxItem> AvailableGpus { get; set; }
  205. public AvaloniaList<string> NetworkInterfaceList
  206. {
  207. get => new(_networkInterfaces.Keys);
  208. }
  209. public HotkeyConfig KeyboardHotkey { get; set; }
  210. public int NetworkInterfaceIndex
  211. {
  212. get => _networkInterfaceIndex;
  213. set
  214. {
  215. _networkInterfaceIndex = value != -1 ? value : 0;
  216. ConfigurationState.Instance.Multiplayer.LanInterfaceId.Value = _networkInterfaces[NetworkInterfaceList[_networkInterfaceIndex]];
  217. }
  218. }
  219. public int MultiplayerModeIndex
  220. {
  221. get => _multiplayerModeIndex;
  222. set
  223. {
  224. _multiplayerModeIndex = value;
  225. ConfigurationState.Instance.Multiplayer.Mode.Value = (MultiplayerMode)_multiplayerModeIndex;
  226. }
  227. }
  228. public SettingsViewModel(VirtualFileSystem virtualFileSystem, ContentManager contentManager) : this()
  229. {
  230. _virtualFileSystem = virtualFileSystem;
  231. _contentManager = contentManager;
  232. if (Program.PreviewerDetached)
  233. {
  234. Task.Run(LoadTimeZones);
  235. }
  236. }
  237. public SettingsViewModel()
  238. {
  239. GameDirectories = new AvaloniaList<string>();
  240. TimeZones = new AvaloniaList<TimeZone>();
  241. AvailableGpus = new ObservableCollection<ComboBoxItem>();
  242. _validTzRegions = new List<string>();
  243. _networkInterfaces = new Dictionary<string, string>();
  244. Task.Run(CheckSoundBackends);
  245. Task.Run(PopulateNetworkInterfaces);
  246. if (Program.PreviewerDetached)
  247. {
  248. Task.Run(LoadAvailableGpus);
  249. LoadCurrentConfiguration();
  250. }
  251. }
  252. public async Task CheckSoundBackends()
  253. {
  254. IsOpenAlEnabled = OpenALHardwareDeviceDriver.IsSupported;
  255. IsSoundIoEnabled = SoundIoHardwareDeviceDriver.IsSupported;
  256. IsSDL2Enabled = SDL2HardwareDeviceDriver.IsSupported;
  257. await Dispatcher.UIThread.InvokeAsync(() =>
  258. {
  259. OnPropertyChanged(nameof(IsOpenAlEnabled));
  260. OnPropertyChanged(nameof(IsSoundIoEnabled));
  261. OnPropertyChanged(nameof(IsSDL2Enabled));
  262. });
  263. }
  264. private async Task LoadAvailableGpus()
  265. {
  266. AvailableGpus.Clear();
  267. var devices = VulkanRenderer.GetPhysicalDevices();
  268. if (devices.Length == 0)
  269. {
  270. IsVulkanAvailable = false;
  271. GraphicsBackendIndex = 1;
  272. }
  273. else
  274. {
  275. foreach (var device in devices)
  276. {
  277. await Dispatcher.UIThread.InvokeAsync(() =>
  278. {
  279. _gpuIds.Add(device.Id);
  280. AvailableGpus.Add(new ComboBoxItem { Content = $"{device.Name} {(device.IsDiscrete ? "(dGPU)" : "")}" });
  281. });
  282. }
  283. }
  284. // GPU configuration needs to be loaded during the async method or it will always return 0.
  285. PreferredGpuIndex = _gpuIds.Contains(ConfigurationState.Instance.Graphics.PreferredGpu) ?
  286. _gpuIds.IndexOf(ConfigurationState.Instance.Graphics.PreferredGpu) : 0;
  287. Dispatcher.UIThread.Post(() => OnPropertyChanged(nameof(PreferredGpuIndex)));
  288. }
  289. public async Task LoadTimeZones()
  290. {
  291. _timeZoneContentManager = new TimeZoneContentManager();
  292. _timeZoneContentManager.InitializeInstance(_virtualFileSystem, _contentManager, IntegrityCheckLevel.None);
  293. foreach ((int offset, string location, string abbr) in _timeZoneContentManager.ParseTzOffsets())
  294. {
  295. int hours = Math.DivRem(offset, 3600, out int seconds);
  296. int minutes = Math.Abs(seconds) / 60;
  297. string abbr2 = abbr.StartsWith('+') || abbr.StartsWith('-') ? string.Empty : abbr;
  298. await Dispatcher.UIThread.InvokeAsync(() =>
  299. {
  300. TimeZones.Add(new TimeZone($"UTC{hours:+0#;-0#;+00}:{minutes:D2}", location, abbr2));
  301. _validTzRegions.Add(location);
  302. });
  303. }
  304. Dispatcher.UIThread.Post(() => OnPropertyChanged(nameof(TimeZone)));
  305. }
  306. private async Task PopulateNetworkInterfaces()
  307. {
  308. _networkInterfaces.Clear();
  309. _networkInterfaces.Add(LocaleManager.Instance[LocaleKeys.NetworkInterfaceDefault], "0");
  310. foreach (NetworkInterface networkInterface in NetworkInterface.GetAllNetworkInterfaces())
  311. {
  312. await Dispatcher.UIThread.InvokeAsync(() =>
  313. {
  314. _networkInterfaces.Add(networkInterface.Name, networkInterface.Id);
  315. });
  316. }
  317. // Network interface index needs to be loaded during the async method or it will always return 0.
  318. NetworkInterfaceIndex = _networkInterfaces.Values.ToList().IndexOf(ConfigurationState.Instance.Multiplayer.LanInterfaceId.Value);
  319. Dispatcher.UIThread.Post(() => OnPropertyChanged(nameof(NetworkInterfaceIndex)));
  320. }
  321. public void ValidateAndSetTimeZone(string location)
  322. {
  323. if (_validTzRegions.Contains(location))
  324. {
  325. TimeZone = location;
  326. }
  327. }
  328. public void LoadCurrentConfiguration()
  329. {
  330. ConfigurationState config = ConfigurationState.Instance;
  331. // User Interface
  332. EnableDiscordIntegration = config.EnableDiscordIntegration;
  333. CheckUpdatesOnStart = config.CheckUpdatesOnStart;
  334. ShowConfirmExit = config.ShowConfirmExit;
  335. RememberWindowState = config.RememberWindowState;
  336. HideCursor = (int)config.HideCursor.Value;
  337. GameDirectories.Clear();
  338. GameDirectories.AddRange(config.UI.GameDirs.Value);
  339. BaseStyleIndex = config.UI.BaseStyle == "Light" ? 0 : 1;
  340. // Input
  341. EnableDockedMode = config.System.EnableDockedMode;
  342. EnableKeyboard = config.Hid.EnableKeyboard;
  343. EnableMouse = config.Hid.EnableMouse;
  344. // Keyboard Hotkeys
  345. KeyboardHotkey = new HotkeyConfig(config.Hid.Hotkeys.Value);
  346. // System
  347. Region = (int)config.System.Region.Value;
  348. Language = (int)config.System.Language.Value;
  349. TimeZone = config.System.TimeZone;
  350. DateTime currentDateTime = DateTime.Now;
  351. CurrentDate = currentDateTime.Date;
  352. CurrentTime = currentDateTime.TimeOfDay.Add(TimeSpan.FromSeconds(config.System.SystemTimeOffset));
  353. EnableVsync = config.Graphics.EnableVsync;
  354. EnableFsIntegrityChecks = config.System.EnableFsIntegrityChecks;
  355. ExpandDramSize = config.System.ExpandRam;
  356. IgnoreMissingServices = config.System.IgnoreMissingServices;
  357. // CPU
  358. EnablePptc = config.System.EnablePtc;
  359. MemoryMode = (int)config.System.MemoryManagerMode.Value;
  360. UseHypervisor = config.System.UseHypervisor;
  361. // Graphics
  362. GraphicsBackendIndex = (int)config.Graphics.GraphicsBackend.Value;
  363. // Physical devices are queried asynchronously hence the prefered index config value is loaded in LoadAvailableGpus().
  364. EnableShaderCache = config.Graphics.EnableShaderCache;
  365. EnableTextureRecompression = config.Graphics.EnableTextureRecompression;
  366. EnableMacroHLE = config.Graphics.EnableMacroHLE;
  367. EnableColorSpacePassthrough = config.Graphics.EnableColorSpacePassthrough;
  368. ResolutionScale = config.Graphics.ResScale == -1 ? 4 : config.Graphics.ResScale - 1;
  369. CustomResolutionScale = config.Graphics.ResScaleCustom;
  370. MaxAnisotropy = config.Graphics.MaxAnisotropy == -1 ? 0 : (int)(MathF.Log2(config.Graphics.MaxAnisotropy));
  371. AspectRatio = (int)config.Graphics.AspectRatio.Value;
  372. GraphicsBackendMultithreadingIndex = (int)config.Graphics.BackendThreading.Value;
  373. ShaderDumpPath = config.Graphics.ShadersDumpPath;
  374. AntiAliasingEffect = (int)config.Graphics.AntiAliasing.Value;
  375. ScalingFilter = (int)config.Graphics.ScalingFilter.Value;
  376. ScalingFilterLevel = config.Graphics.ScalingFilterLevel.Value;
  377. // Audio
  378. AudioBackend = (int)config.System.AudioBackend.Value;
  379. Volume = config.System.AudioVolume * 100;
  380. // Network
  381. EnableInternetAccess = config.System.EnableInternetAccess;
  382. // LAN interface index is loaded asynchronously in PopulateNetworkInterfaces()
  383. // Logging
  384. EnableFileLog = config.Logger.EnableFileLog;
  385. EnableStub = config.Logger.EnableStub;
  386. EnableInfo = config.Logger.EnableInfo;
  387. EnableWarn = config.Logger.EnableWarn;
  388. EnableError = config.Logger.EnableError;
  389. EnableTrace = config.Logger.EnableTrace;
  390. EnableGuest = config.Logger.EnableGuest;
  391. EnableDebug = config.Logger.EnableDebug;
  392. EnableFsAccessLog = config.Logger.EnableFsAccessLog;
  393. FsGlobalAccessLogMode = config.System.FsGlobalAccessLogMode;
  394. OpenglDebugLevel = (int)config.Logger.GraphicsDebugLevel.Value;
  395. MultiplayerModeIndex = (int)config.Multiplayer.Mode.Value;
  396. }
  397. public void SaveSettings()
  398. {
  399. ConfigurationState config = ConfigurationState.Instance;
  400. // User Interface
  401. config.EnableDiscordIntegration.Value = EnableDiscordIntegration;
  402. config.CheckUpdatesOnStart.Value = CheckUpdatesOnStart;
  403. config.ShowConfirmExit.Value = ShowConfirmExit;
  404. config.RememberWindowState.Value = RememberWindowState;
  405. config.HideCursor.Value = (HideCursorMode)HideCursor;
  406. if (_directoryChanged)
  407. {
  408. List<string> gameDirs = new(GameDirectories);
  409. config.UI.GameDirs.Value = gameDirs;
  410. }
  411. config.UI.BaseStyle.Value = BaseStyleIndex == 0 ? "Light" : "Dark";
  412. // Input
  413. config.System.EnableDockedMode.Value = EnableDockedMode;
  414. config.Hid.EnableKeyboard.Value = EnableKeyboard;
  415. config.Hid.EnableMouse.Value = EnableMouse;
  416. // Keyboard Hotkeys
  417. config.Hid.Hotkeys.Value = KeyboardHotkey.GetConfig();
  418. // System
  419. config.System.Region.Value = (Region)Region;
  420. config.System.Language.Value = (Language)Language;
  421. if (_validTzRegions.Contains(TimeZone))
  422. {
  423. config.System.TimeZone.Value = TimeZone;
  424. }
  425. config.System.SystemTimeOffset.Value = Convert.ToInt64((CurrentDate.ToUnixTimeSeconds() + CurrentTime.TotalSeconds) - DateTimeOffset.Now.ToUnixTimeSeconds());
  426. config.Graphics.EnableVsync.Value = EnableVsync;
  427. config.System.EnableFsIntegrityChecks.Value = EnableFsIntegrityChecks;
  428. config.System.ExpandRam.Value = ExpandDramSize;
  429. config.System.IgnoreMissingServices.Value = IgnoreMissingServices;
  430. // CPU
  431. config.System.EnablePtc.Value = EnablePptc;
  432. config.System.MemoryManagerMode.Value = (MemoryManagerMode)MemoryMode;
  433. config.System.UseHypervisor.Value = UseHypervisor;
  434. // Graphics
  435. config.Graphics.GraphicsBackend.Value = (GraphicsBackend)GraphicsBackendIndex;
  436. config.Graphics.PreferredGpu.Value = _gpuIds.ElementAtOrDefault(PreferredGpuIndex);
  437. config.Graphics.EnableShaderCache.Value = EnableShaderCache;
  438. config.Graphics.EnableTextureRecompression.Value = EnableTextureRecompression;
  439. config.Graphics.EnableMacroHLE.Value = EnableMacroHLE;
  440. config.Graphics.EnableColorSpacePassthrough.Value = EnableColorSpacePassthrough;
  441. config.Graphics.ResScale.Value = ResolutionScale == 4 ? -1 : ResolutionScale + 1;
  442. config.Graphics.ResScaleCustom.Value = CustomResolutionScale;
  443. config.Graphics.MaxAnisotropy.Value = MaxAnisotropy == 0 ? -1 : MathF.Pow(2, MaxAnisotropy);
  444. config.Graphics.AspectRatio.Value = (AspectRatio)AspectRatio;
  445. config.Graphics.AntiAliasing.Value = (AntiAliasing)AntiAliasingEffect;
  446. config.Graphics.ScalingFilter.Value = (ScalingFilter)ScalingFilter;
  447. config.Graphics.ScalingFilterLevel.Value = ScalingFilterLevel;
  448. if (ConfigurationState.Instance.Graphics.BackendThreading != (BackendThreading)GraphicsBackendMultithreadingIndex)
  449. {
  450. DriverUtilities.ToggleOGLThreading(GraphicsBackendMultithreadingIndex == (int)BackendThreading.Off);
  451. }
  452. config.Graphics.BackendThreading.Value = (BackendThreading)GraphicsBackendMultithreadingIndex;
  453. config.Graphics.ShadersDumpPath.Value = ShaderDumpPath;
  454. // Audio
  455. AudioBackend audioBackend = (AudioBackend)AudioBackend;
  456. if (audioBackend != config.System.AudioBackend.Value)
  457. {
  458. config.System.AudioBackend.Value = audioBackend;
  459. Logger.Info?.Print(LogClass.Application, $"AudioBackend toggled to: {audioBackend}");
  460. }
  461. config.System.AudioVolume.Value = Volume / 100;
  462. // Network
  463. config.System.EnableInternetAccess.Value = EnableInternetAccess;
  464. // Logging
  465. config.Logger.EnableFileLog.Value = EnableFileLog;
  466. config.Logger.EnableStub.Value = EnableStub;
  467. config.Logger.EnableInfo.Value = EnableInfo;
  468. config.Logger.EnableWarn.Value = EnableWarn;
  469. config.Logger.EnableError.Value = EnableError;
  470. config.Logger.EnableTrace.Value = EnableTrace;
  471. config.Logger.EnableGuest.Value = EnableGuest;
  472. config.Logger.EnableDebug.Value = EnableDebug;
  473. config.Logger.EnableFsAccessLog.Value = EnableFsAccessLog;
  474. config.System.FsGlobalAccessLogMode.Value = FsGlobalAccessLogMode;
  475. config.Logger.GraphicsDebugLevel.Value = (GraphicsDebugLevel)OpenglDebugLevel;
  476. config.Multiplayer.LanInterfaceId.Value = _networkInterfaces[NetworkInterfaceList[NetworkInterfaceIndex]];
  477. config.Multiplayer.Mode.Value = (MultiplayerMode)MultiplayerModeIndex;
  478. config.ToFileFormat().SaveConfig(Program.ConfigurationPath);
  479. MainWindow.UpdateGraphicsConfig();
  480. SaveSettingsEvent?.Invoke();
  481. _directoryChanged = false;
  482. }
  483. private static void RevertIfNotSaved()
  484. {
  485. Program.ReloadConfig();
  486. }
  487. public void ApplyButton()
  488. {
  489. SaveSettings();
  490. }
  491. public void OkButton()
  492. {
  493. SaveSettings();
  494. CloseWindow?.Invoke();
  495. }
  496. public void CancelButton()
  497. {
  498. RevertIfNotSaved();
  499. CloseWindow?.Invoke();
  500. }
  501. }
  502. }