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)