diff --git a/Dalamud/Configuration/Internal/DalamudConfiguration.cs b/Dalamud/Configuration/Internal/DalamudConfiguration.cs index d4efde61c..f623f8007 100644 --- a/Dalamud/Configuration/Internal/DalamudConfiguration.cs +++ b/Dalamud/Configuration/Internal/DalamudConfiguration.cs @@ -6,6 +6,7 @@ using System.Linq; using Dalamud.Game.Text; using Dalamud.Interface.Style; +using Dalamud.Utility; using Newtonsoft.Json; using Serilog; using Serilog.Events; @@ -28,6 +29,9 @@ internal sealed class DalamudConfiguration : IServiceType [JsonIgnore] private string configPath; + [JsonIgnore] + private bool isSaveQueued; + /// /// Delegate for the event that occurs when the dalamud configuration is saved. /// @@ -368,8 +372,29 @@ internal sealed class DalamudConfiguration : IServiceType /// /// Save the configuration at the path it was loaded from. /// - public void Save() + public void QueueSave() { + this.isSaveQueued = true; + } + + /// + /// Save the file, if needed. Only needs to be done once a frame. + /// + internal void Update() + { + if (this.isSaveQueued) + { + this.Save(); + this.isSaveQueued = false; + + Log.Verbose("Config saved"); + } + } + + private void Save() + { + ThreadSafety.AssertMainThread(); + File.WriteAllText(this.configPath, JsonConvert.SerializeObject(this, SerializerSettings)); this.DalamudConfigurationSaved?.Invoke(this); } diff --git a/Dalamud/EntryPoint.cs b/Dalamud/EntryPoint.cs index 48692e323..c1bff4598 100644 --- a/Dalamud/EntryPoint.cs +++ b/Dalamud/EntryPoint.cs @@ -334,7 +334,7 @@ public sealed class EntryPoint Log.Information("User chose to disable plugins on next launch..."); var config = Service.Get(); config.PluginSafeMode = true; - config.Save(); + config.QueueSave(); } Log.CloseAndFlush(); diff --git a/Dalamud/Game/ChatHandlers.cs b/Dalamud/Game/ChatHandlers.cs index 03e28073a..9250ef70c 100644 --- a/Dalamud/Game/ChatHandlers.cs +++ b/Dalamud/Game/ChatHandlers.cs @@ -269,7 +269,7 @@ public class ChatHandlers : IServiceType } this.configuration.LastVersion = assemblyVersion; - this.configuration.Save(); + this.configuration.QueueSave(); } this.hasSeenLoadingMsg = true; diff --git a/Dalamud/Game/Framework.cs b/Dalamud/Game/Framework.cs index 2de448aae..98f430d4a 100644 --- a/Dalamud/Game/Framework.cs +++ b/Dalamud/Game/Framework.cs @@ -6,6 +6,7 @@ using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; +using Dalamud.Configuration.Internal; using Dalamud.Game.Gui; using Dalamud.Game.Gui.Toast; using Dalamud.Game.Network; @@ -372,12 +373,15 @@ public sealed class Framework : IDisposable, IServiceType var chatGui = Service.GetNullable(); var toastGui = Service.GetNullable(); var gameNetwork = Service.GetNullable(); + var config = Service.GetNullable(); if (chatGui == null || toastGui == null || gameNetwork == null) goto original; chatGui.UpdateQueue(); toastGui.UpdateQueue(); gameNetwork.UpdateQueue(); + + config?.Update(); } catch (Exception ex) { diff --git a/Dalamud/Game/Gui/Dtr/DtrBar.cs b/Dalamud/Game/Gui/Dtr/DtrBar.cs index e351320b9..d77b406f0 100644 --- a/Dalamud/Game/Gui/Dtr/DtrBar.cs +++ b/Dalamud/Game/Gui/Dtr/DtrBar.cs @@ -41,7 +41,7 @@ public sealed unsafe class DtrBar : IDisposable, IServiceType this.configuration.DtrOrder ??= new List(); this.configuration.DtrIgnore ??= new List(); - this.configuration.Save(); + this.configuration.QueueSave(); } /// diff --git a/Dalamud/Game/Internal/DXGI/SwapChainVtableResolver.cs b/Dalamud/Game/Internal/DXGI/SwapChainVtableResolver.cs index 94d5e3be6..f6072c00b 100644 --- a/Dalamud/Game/Internal/DXGI/SwapChainVtableResolver.cs +++ b/Dalamud/Game/Internal/DXGI/SwapChainVtableResolver.cs @@ -65,10 +65,12 @@ public class SwapChainVtableResolver : BaseAddressResolver, ISwapChainAddressRes // var p = processModule.BaseAddress + 0x82C7E0; // DXGISwapChain::Present // var p = processModule.BaseAddress + 0x82FAC0; // DXGISwapChain::runtime_present + // DXGISwapChain::handle_device_loss => DXGISwapChain::Present => DXGISwapChain::runtime_present + var scanner = new SigScanner(processModule); try { - var p = scanner.ScanText("F6 C2 01 0F 85 ?? ?? ?? ??"); + var p = scanner.ScanText("E8 ?? ?? ?? ?? 45 0F B6 5E ??"); Log.Information($"ReShade DLL: {processModule.FileName} with DXGISwapChain::runtime_present at {p:X}"); this.Present = p; diff --git a/Dalamud/Interface/Internal/DalamudCommands.cs b/Dalamud/Interface/Internal/DalamudCommands.cs index 35e216eef..2d49a8163 100644 --- a/Dalamud/Interface/Internal/DalamudCommands.cs +++ b/Dalamud/Interface/Internal/DalamudCommands.cs @@ -179,7 +179,7 @@ internal class DalamudCommands : IServiceType configuration.BadWords.Add(arguments); - configuration.Save(); + configuration.QueueSave(); chatGui.Print(string.Format(Loc.Localize("DalamudMuted", "Muted \"{0}\"."), arguments)); } @@ -197,7 +197,7 @@ internal class DalamudCommands : IServiceType return; } - configuration.Save(); + configuration.QueueSave(); foreach (var word in configuration.BadWords) chatGui.Print($"\"{word}\""); @@ -212,7 +212,7 @@ internal class DalamudCommands : IServiceType configuration.BadWords.RemoveAll(x => x == arguments); - configuration.Save(); + configuration.QueueSave(); chatGui.Print(string.Format(Loc.Localize("DalamudUnmuted", "Unmuted \"{0}\"."), arguments)); } @@ -354,7 +354,7 @@ internal class DalamudCommands : IServiceType chatGui.Print(string.Format(Loc.Localize("DalamudLanguageSetTo", "Language set to {0}"), "default")); } - configuration.Save(); + configuration.QueueSave(); } private void OnOpenSettingsCommand(string command, string arguments) diff --git a/Dalamud/Interface/Internal/DalamudInterface.cs b/Dalamud/Interface/Internal/DalamudInterface.cs index ae00d5f44..078bbd661 100644 --- a/Dalamud/Interface/Internal/DalamudInterface.cs +++ b/Dalamud/Interface/Internal/DalamudInterface.cs @@ -515,7 +515,7 @@ internal class DalamudInterface : IDisposable, IServiceType if (ImGui.MenuItem("Draw dev menu at startup", string.Empty, ref devBarAtStartup)) { configuration.DevBarOpenAtStartup ^= true; - configuration.Save(); + configuration.QueueSave(); } ImGui.Separator(); @@ -533,7 +533,7 @@ internal class DalamudInterface : IDisposable, IServiceType { EntryPoint.LogLevelSwitch.MinimumLevel = logLevel; configuration.LogLevel = logLevel; - configuration.Save(); + configuration.QueueSave(); } } @@ -544,7 +544,7 @@ internal class DalamudInterface : IDisposable, IServiceType if (ImGui.MenuItem("Log Synchronously", null, ref logSynchronously)) { configuration.LogSynchronously = logSynchronously; - configuration.Save(); + configuration.QueueSave(); var startupInfo = Service.Get(); EntryPoint.InitLogging( @@ -563,7 +563,7 @@ internal class DalamudInterface : IDisposable, IServiceType antiDebug.Disable(); configuration.IsAntiAntiDebugEnabled = newEnabled; - configuration.Save(); + configuration.QueueSave(); } ImGui.Separator(); @@ -693,7 +693,7 @@ internal class DalamudInterface : IDisposable, IServiceType if (ImGui.MenuItem("Enable asserts at startup", null, configuration.AssertsEnabledAtStartup)) { configuration.AssertsEnabledAtStartup = !configuration.AssertsEnabledAtStartup; - configuration.Save(); + configuration.QueueSave(); } if (ImGui.MenuItem("Clear focus")) diff --git a/Dalamud/Interface/Internal/InterfaceManager.cs b/Dalamud/Interface/Internal/InterfaceManager.cs index 56687ef49..5e6da15c1 100644 --- a/Dalamud/Interface/Internal/InterfaceManager.cs +++ b/Dalamud/Interface/Internal/InterfaceManager.cs @@ -484,7 +484,7 @@ internal class InterfaceManager : IDisposable, IServiceType { style = StyleModelV1.DalamudStandard; configuration.ChosenStyle = style.Name; - configuration.Save(); + configuration.QueueSave(); } style.Apply(); diff --git a/Dalamud/Interface/Internal/Windows/BranchSwitcherWindow.cs b/Dalamud/Interface/Internal/Windows/BranchSwitcherWindow.cs index 0fff8111c..e934f9df6 100644 --- a/Dalamud/Interface/Internal/Windows/BranchSwitcherWindow.cs +++ b/Dalamud/Interface/Internal/Windows/BranchSwitcherWindow.cs @@ -88,7 +88,7 @@ public class BranchSwitcherWindow : Window var config = Service.Get(); config.DalamudBetaKind = pickedBranch.Key; config.DalamudBetaKey = pickedBranch.Value.Key; - config.Save(); + config.QueueSave(); } if (ImGui.Button("Pick")) diff --git a/Dalamud/Interface/Internal/Windows/ConsoleWindow.cs b/Dalamud/Interface/Internal/Windows/ConsoleWindow.cs index ffa3323dd..0d19a340a 100644 --- a/Dalamud/Interface/Internal/Windows/ConsoleWindow.cs +++ b/Dalamud/Interface/Internal/Windows/ConsoleWindow.cs @@ -130,13 +130,13 @@ internal class ConsoleWindow : Window, IDisposable if (ImGui.Checkbox("Auto-scroll", ref this.autoScroll)) { configuration.LogAutoScroll = this.autoScroll; - configuration.Save(); + configuration.QueueSave(); } if (ImGui.Checkbox("Open at startup", ref this.openAtStartup)) { configuration.LogOpenAtStartup = this.openAtStartup; - configuration.Save(); + configuration.QueueSave(); } var prevLevel = (int)EntryPoint.LogLevelSwitch.MinimumLevel; @@ -144,7 +144,7 @@ internal class ConsoleWindow : Window, IDisposable { EntryPoint.LogLevelSwitch.MinimumLevel = (LogEventLevel)prevLevel; configuration.LogLevel = (LogEventLevel)prevLevel; - configuration.Save(); + configuration.QueueSave(); } ImGui.EndPopup(); diff --git a/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs b/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs index 7c11139d8..3d048d43c 100644 --- a/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs +++ b/Dalamud/Interface/Internal/Windows/PluginInstaller/PluginInstallerWindow.cs @@ -207,7 +207,7 @@ internal class PluginInstallerWindow : Window, IDisposable /// public override void OnClose() { - Service.Get().Save(); + Service.Get().QueueSave(); } /// @@ -477,7 +477,7 @@ internal class PluginInstallerWindow : Window, IDisposable if (ImGui.Button(closeText)) { this.IsOpen = false; - configuration.Save(); + configuration.QueueSave(); } } @@ -1834,7 +1834,7 @@ internal class PluginInstallerWindow : Window, IDisposable if (ImGui.Selectable(Locs.PluginContext_MarkAllSeen)) { configuration.SeenPluginInternalName.AddRange(this.pluginListAvailable.Select(x => x.InternalName)); - configuration.Save(); + configuration.QueueSave(); pluginManager.RefilterPluginMasters(); } @@ -1842,7 +1842,7 @@ internal class PluginInstallerWindow : Window, IDisposable { Log.Debug($"Adding {manifest.InternalName} to hidden plugins"); configuration.HiddenPluginInternalName.Add(manifest.InternalName); - configuration.Save(); + configuration.QueueSave(); pluginManager.RefilterPluginMasters(); } @@ -2146,7 +2146,7 @@ internal class PluginInstallerWindow : Window, IDisposable configuration.PluginTestingOptIns!.Add(new PluginTestingOptIn(plugin.Manifest.InternalName)); } - configuration.Save(); + configuration.QueueSave(); } if (repoManifest?.IsTestingExclusive == true) @@ -2419,7 +2419,7 @@ internal class PluginInstallerWindow : Window, IDisposable if (ImGuiComponents.IconButton(FontAwesomeIcon.PowerOff)) { plugin.StartOnBoot ^= true; - configuration.Save(); + configuration.QueueSave(); } ImGui.PopStyleColor(2); @@ -2437,7 +2437,7 @@ internal class PluginInstallerWindow : Window, IDisposable if (ImGuiComponents.IconButton(FontAwesomeIcon.SyncAlt)) { plugin.AutomaticReload ^= true; - configuration.Save(); + configuration.QueueSave(); } ImGui.PopStyleColor(2); diff --git a/Dalamud/Interface/Internal/Windows/SettingsWindow.cs b/Dalamud/Interface/Internal/Windows/SettingsWindow.cs index bf67c160e..72292faa3 100644 --- a/Dalamud/Interface/Internal/Windows/SettingsWindow.cs +++ b/Dalamud/Interface/Internal/Windows/SettingsWindow.cs @@ -974,7 +974,7 @@ internal class SettingsWindow : Window configuration.DoButtonsSystemMenu = this.doButtonsSystemMenu; configuration.DisableRmtFiltering = this.disableRmtFiltering; - configuration.Save(); + configuration.QueueSave(); _ = Service.Get().ReloadPluginMastersAsync(); Service.Get().RebuildFonts(); diff --git a/Dalamud/Interface/Internal/Windows/StyleEditor/StyleEditorWindow.cs b/Dalamud/Interface/Internal/Windows/StyleEditor/StyleEditorWindow.cs index 8ad4e98e6..8fe978ef1 100644 --- a/Dalamud/Interface/Internal/Windows/StyleEditor/StyleEditorWindow.cs +++ b/Dalamud/Interface/Internal/Windows/StyleEditor/StyleEditorWindow.cs @@ -105,7 +105,7 @@ public class StyleEditorWindow : Window newStyle.Apply(); appliedThisFrame = true; - config.Save(); + config.QueueSave(); } ImGui.SameLine(); @@ -119,7 +119,7 @@ public class StyleEditorWindow : Window config.SavedStyles.RemoveAt(this.currentSel + 1); - config.Save(); + config.QueueSave(); } if (ImGui.IsItemHovered()) @@ -180,7 +180,7 @@ public class StyleEditorWindow : Window this.currentSel = config.SavedStyles.Count - 1; - config.Save(); + config.QueueSave(); } catch (Exception ex) { @@ -366,7 +366,7 @@ public class StyleEditorWindow : Window if (ImGui.Button("OK", new Vector2(buttonWidth, 40))) { config.SavedStyles[this.currentSel].Name = this.renameText; - config.Save(); + config.QueueSave(); ImGui.CloseCurrentPopup(); } @@ -396,6 +396,6 @@ public class StyleEditorWindow : Window config.SavedStyles[this.currentSel] = newStyle; newStyle.Apply(); - config.Save(); + config.QueueSave(); } } diff --git a/Dalamud/Interface/Style/StyleModel.cs b/Dalamud/Interface/Style/StyleModel.cs index 89f5c39a6..172c105b0 100644 --- a/Dalamud/Interface/Style/StyleModel.cs +++ b/Dalamud/Interface/Style/StyleModel.cs @@ -93,7 +93,7 @@ public abstract class StyleModel Log.Information("Transferred {NumStyles} styles", configuration.SavedStyles.Count); configuration.SavedStylesOld = null; - configuration.Save(); + configuration.QueueSave(); } /// diff --git a/Dalamud/Plugin/Internal/PluginManager.cs b/Dalamud/Plugin/Internal/PluginManager.cs index 6299a40a5..2daee9d90 100644 --- a/Dalamud/Plugin/Internal/PluginManager.cs +++ b/Dalamud/Plugin/Internal/PluginManager.cs @@ -106,7 +106,7 @@ Thanks and have fun!"; if (this.SafeMode) { this.configuration.PluginSafeMode = false; - this.configuration.Save(); + this.configuration.QueueSave(); } this.PluginConfigs = new PluginConfigurations(Path.Combine(Path.GetDirectoryName(this.startInfo.ConfigurationPath) ?? string.Empty, "pluginConfigs")); @@ -409,7 +409,7 @@ Thanks and have fun!"; } } - this.configuration.Save(); + this.configuration.QueueSave(); try { @@ -716,8 +716,9 @@ Thanks and have fun!"; // Ensure that we have a testing opt-in for this plugin if we are installing a testing version if (useTesting && this.configuration.PluginTestingOptIns!.All(x => x.InternalName != repoManifest.InternalName)) { + // TODO: this isn't safe this.configuration.PluginTestingOptIns.Add(new PluginTestingOptIn(repoManifest.InternalName)); - this.configuration.Save(); + this.configuration.QueueSave(); } var downloadUrl = useTesting ? repoManifest.DownloadLinkTesting : repoManifest.DownloadLinkInstall; diff --git a/Dalamud/Plugin/Internal/Types/LocalDevPlugin.cs b/Dalamud/Plugin/Internal/Types/LocalDevPlugin.cs index e32f0f4c7..cb051fa59 100644 --- a/Dalamud/Plugin/Internal/Types/LocalDevPlugin.cs +++ b/Dalamud/Plugin/Internal/Types/LocalDevPlugin.cs @@ -37,7 +37,7 @@ internal class LocalDevPlugin : LocalPlugin, IDisposable if (!configuration.DevPluginSettings.TryGetValue(dllFile.FullName, out this.devSettings)) { configuration.DevPluginSettings[dllFile.FullName] = this.devSettings = new DevPluginSettings(); - configuration.Save(); + configuration.QueueSave(); } if (this.AutomaticReload)