From fc2575833b5b434c9c8d74c6144f32484b4c1dea Mon Sep 17 00:00:00 2001 From: erik Date: Tue, 29 Apr 2025 20:22:19 +0200 Subject: [PATCH] Bugfix in PluginSettings. --- MosswartMassacre/PluginSettings.cs | 83 ++++++++++++++++++++++-------- 1 file changed, 62 insertions(+), 21 deletions(-) diff --git a/MosswartMassacre/PluginSettings.cs b/MosswartMassacre/PluginSettings.cs index 9a72ea4..da0de30 100644 --- a/MosswartMassacre/PluginSettings.cs +++ b/MosswartMassacre/PluginSettings.cs @@ -10,35 +10,59 @@ namespace MosswartMassacre { private static PluginSettings _instance; private static string _filePath; + private static readonly object _sync = new object(); + + // backing fields private bool _remoteCommandsEnabled = false; private bool _rareMetaEnabled = true; private bool _httpServerEnabled = false; - private string _charTag = "default"; private bool _telemetryEnabled = false; - public static PluginSettings Instance => _instance; + private string _charTag = "default"; + + public static PluginSettings Instance => _instance + ?? throw new InvalidOperationException("PluginSettings not initialized"); public static void Initialize() { + // determine settings file path string characterName = CoreManager.Current.CharacterFilter.Name; - string pluginFolder = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location); + string pluginFolder = Path.GetDirectoryName( + typeof(PluginSettings).Assembly.Location); _filePath = Path.Combine(pluginFolder, $"{characterName}.yaml"); + // build serializer/deserializer once + var builder = new DeserializerBuilder() + .WithNamingConvention(UnderscoredNamingConvention.Instance); + var deserializer = builder.Build(); + + PluginSettings loaded = null; + if (File.Exists(_filePath)) { - var deserializer = new DeserializerBuilder() - .WithNamingConvention(UnderscoredNamingConvention.Instance) - .Build(); + try + { + string yaml = File.ReadAllText(_filePath); + loaded = deserializer.Deserialize(yaml); + } + catch (Exception ex) + { + PluginCore.DispatchChatToBoxWithPluginIntercept( + $"[MosswartMassacre] Error reading settings, using defaults: {ex.Message}"); + } + } - string yaml = File.ReadAllText(_filePath); - _instance = deserializer.Deserialize(yaml); + if (loaded == null) + { + // either file didn't exist, was empty, or deserialized as null + _instance = new PluginSettings(); + Save(); // write out default skeleton } else { - _instance = new PluginSettings(); - Save(); + _instance = loaded; } - // Apply settings to runtime state + // apply into runtime PluginCore.RareMetaEnabled = _instance.RareMetaEnabled; PluginCore.RemoteCommandsEnabled = _instance.RemoteCommandsEnabled; PluginCore.HttpServerEnabled = _instance.HttpServerEnabled; @@ -48,14 +72,29 @@ namespace MosswartMassacre public static void Save() { - var serializer = new SerializerBuilder() - .WithNamingConvention(UnderscoredNamingConvention.Instance) - .Build(); + lock (_sync) + { + try + { + var serializer = new SerializerBuilder() + .WithNamingConvention(UnderscoredNamingConvention.Instance) + .Build(); + var yaml = serializer.Serialize(_instance); - string yaml = serializer.Serialize(_instance); - File.WriteAllText(_filePath, yaml); + // atomic write: write to .tmp then replace + var temp = _filePath + ".tmp"; + File.WriteAllText(temp, yaml); + File.Replace(temp, _filePath, null); + } + catch (Exception ex) + { + PluginCore.DispatchChatToBoxWithPluginIntercept( + $"[MosswartMassacre] Error saving settings: {ex.Message}"); + } + } } + // public properties public bool RemoteCommandsEnabled { get => _remoteCommandsEnabled; @@ -73,15 +112,17 @@ namespace MosswartMassacre get => _httpServerEnabled; set { _httpServerEnabled = value; Save(); } } - public string CharTag - { - get => _charTag; - set { _charTag = value; Save(); } - } + public bool TelemetryEnabled { get => _telemetryEnabled; set { _telemetryEnabled = value; Save(); } } + + public string CharTag + { + get => _charTag; + set { _charTag = value; Save(); } + } } }