From ea65296ab771462fb4c6acc796b3f18ac7b4aeea Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Fri, 17 Nov 2023 16:51:09 +0100 Subject: [PATCH] Add EphemeralConfig. --- Penumbra/CommandHandler.cs | 8 +- Penumbra/Configuration.cs | 66 +++++--------- Penumbra/EphemeralConfig.cs | 86 +++++++++++++++++++ Penumbra/Penumbra.cs | 2 +- Penumbra/Services/BackupService.cs | 4 + Penumbra/Services/ConfigMigrationService.cs | 44 +++++++++- Penumbra/Services/FilenameService.cs | 10 ++- Penumbra/Services/ServiceManager.cs | 3 +- Penumbra/UI/ChangedItemDrawer.cs | 20 ++--- Penumbra/UI/Changelog.cs | 16 +++- Penumbra/UI/ConfigWindow.cs | 10 +-- .../UI/ResourceWatcher/ResourceWatcher.cs | 52 +++++------ .../ResourceWatcher/ResourceWatcherTable.cs | 14 +-- Penumbra/UI/Tabs/CollectionsTab.cs | 4 +- Penumbra/UI/Tabs/DebugTab.cs | 16 ++-- Penumbra/UI/Tabs/SettingsTab.cs | 28 ++++-- Penumbra/UI/TutorialService.cs | 6 +- 17 files changed, 264 insertions(+), 125 deletions(-) create mode 100644 Penumbra/EphemeralConfig.cs diff --git a/Penumbra/CommandHandler.cs b/Penumbra/CommandHandler.cs index b6c675a2..c151e7e4 100644 --- a/Penumbra/CommandHandler.cs +++ b/Penumbra/CommandHandler.cs @@ -184,8 +184,8 @@ public class CommandHandler : IDisposable private bool SetUiLockState(string arguments) { - var value = ParseTrueFalseToggle(arguments) ?? !_config.FixMainWindow; - if (value == _config.FixMainWindow) + var value = ParseTrueFalseToggle(arguments) ?? !_config.Ephemeral.FixMainWindow; + if (value == _config.Ephemeral.FixMainWindow) return false; if (value) @@ -199,8 +199,8 @@ public class CommandHandler : IDisposable _configWindow.Flags &= ~(ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoResize); } - _config.FixMainWindow = value; - _config.Save(); + _config.Ephemeral.FixMainWindow = value; + _config.Ephemeral.Save(); return true; } diff --git a/Penumbra/Configuration.cs b/Penumbra/Configuration.cs index a1cf6a72..8f21ee52 100644 --- a/Penumbra/Configuration.cs +++ b/Penumbra/Configuration.cs @@ -5,17 +5,13 @@ using OtterGui; using OtterGui.Classes; using OtterGui.Filesystem; using OtterGui.Widgets; -using Penumbra.Api.Enums; -using Penumbra.Enums; using Penumbra.Import.Structs; using Penumbra.Interop.Services; using Penumbra.Mods; using Penumbra.Mods.Manager; using Penumbra.Services; -using Penumbra.UI; using Penumbra.UI.Classes; using Penumbra.UI.ResourceWatcher; -using Penumbra.UI.Tabs; using ErrorEventArgs = Newtonsoft.Json.Serialization.ErrorEventArgs; namespace Penumbra; @@ -26,9 +22,11 @@ public class Configuration : IPluginConfiguration, ISavable [JsonIgnore] private readonly SaveService _saveService; + [JsonIgnore] + public readonly EphemeralConfig Ephemeral; + public int Version { get; set; } = Constants.CurrentVersion; - public int LastSeenVersion { get; set; } = PenumbraChangelog.LastChangelogVersion; public ChangeLogDisplayType ChangeLogDisplayType { get; set; } = ChangeLogDisplayType.New; public bool EnableMods { get; set; } = true; @@ -53,52 +51,33 @@ public class Configuration : IPluginConfiguration, ISavable public bool HideRedrawBar { get; set; } = false; public int OptionGroupCollapsibleMin { get; set; } = 5; - public bool DebugSeparateWindow = false; - public Vector2 MinimumSize = new(Constants.MinimumSizeX, Constants.MinimumSizeY); + public Vector2 MinimumSize = new(Constants.MinimumSizeX, Constants.MinimumSizeY); #if DEBUG public bool DebugMode { get; set; } = true; #else public bool DebugMode { get; set; } = false; #endif - - public int TutorialStep { get; set; } = 0; - - public bool EnableResourceLogging { get; set; } = false; - public string ResourceLoggingFilter { get; set; } = string.Empty; - public bool EnableResourceWatcher { get; set; } = false; - public bool OnlyAddMatchingResources { get; set; } = true; - public int MaxResourceWatcherRecords { get; set; } = ResourceWatcher.DefaultMaxEntries; - - public ResourceTypeFlag ResourceWatcherResourceTypes { get; set; } = ResourceExtensions.AllResourceTypes; - public ResourceCategoryFlag ResourceWatcherResourceCategories { get; set; } = ResourceExtensions.AllResourceCategories; - public RecordType ResourceWatcherRecordTypes { get; set; } = ResourceWatcher.AllRecords; - + public int MaxResourceWatcherRecords { get; set; } = ResourceWatcher.DefaultMaxEntries; [JsonConverter(typeof(SortModeConverter))] [JsonProperty(Order = int.MaxValue)] public ISortMode SortMode = ISortMode.FoldersFirst; - public bool ScaleModSelector { get; set; } = false; - public float ModSelectorAbsoluteSize { get; set; } = Constants.DefaultAbsoluteSize; - public int ModSelectorScaledSize { get; set; } = Constants.DefaultScaledSize; - public bool OpenFoldersByDefault { get; set; } = false; - public int SingleGroupRadioMax { get; set; } = 2; - public string DefaultImportFolder { get; set; } = string.Empty; - public string QuickMoveFolder1 { get; set; } = string.Empty; - public string QuickMoveFolder2 { get; set; } = string.Empty; - public string QuickMoveFolder3 { get; set; } = string.Empty; - public DoubleModifier DeleteModModifier { get; set; } = new(ModifierHotkey.Control, ModifierHotkey.Shift); - public CollectionsTab.PanelMode CollectionPanel { get; set; } = CollectionsTab.PanelMode.SimpleAssignment; - public TabType SelectedTab { get; set; } = TabType.Settings; - - public ChangedItemDrawer.ChangedItemIcon ChangedItemFilter { get; set; } = ChangedItemDrawer.DefaultFlags; - - public bool PrintSuccessfulCommandsToChat { get; set; } = true; - public bool FixMainWindow { get; set; } = false; - public bool AutoDeduplicateOnImport { get; set; } = true; - public bool UseFileSystemCompression { get; set; } = true; - public bool EnableHttpApi { get; set; } = true; + public bool ScaleModSelector { get; set; } = false; + public float ModSelectorAbsoluteSize { get; set; } = Constants.DefaultAbsoluteSize; + public int ModSelectorScaledSize { get; set; } = Constants.DefaultScaledSize; + public bool OpenFoldersByDefault { get; set; } = false; + public int SingleGroupRadioMax { get; set; } = 2; + public string DefaultImportFolder { get; set; } = string.Empty; + public string QuickMoveFolder1 { get; set; } = string.Empty; + public string QuickMoveFolder2 { get; set; } = string.Empty; + public string QuickMoveFolder3 { get; set; } = string.Empty; + public DoubleModifier DeleteModModifier { get; set; } = new(ModifierHotkey.Control, ModifierHotkey.Shift); + public bool PrintSuccessfulCommandsToChat { get; set; } = true; + public bool AutoDeduplicateOnImport { get; set; } = true; + public bool UseFileSystemCompression { get; set; } = true; + public bool EnableHttpApi { get; set; } = true; public string DefaultModImportPath { get; set; } = string.Empty; public bool AlwaysOpenDefaultImport { get; set; } = false; @@ -112,9 +91,10 @@ public class Configuration : IPluginConfiguration, ISavable /// Load the current configuration. /// Includes adding new colors and migrating from old versions. /// - public Configuration(CharacterUtility utility, ConfigMigrationService migrator, SaveService saveService) + public Configuration(CharacterUtility utility, ConfigMigrationService migrator, SaveService saveService, EphemeralConfig ephemeral) { _saveService = saveService; + Ephemeral = ephemeral; Load(utility, migrator); } @@ -148,12 +128,12 @@ public class Configuration : IPluginConfiguration, ISavable /// Save the current configuration. public void Save() - => _saveService.DelaySave(this); + => _saveService.QueueSave(this); /// Contains some default values or boundaries for config values. public static class Constants { - public const int CurrentVersion = 7; + public const int CurrentVersion = 8; public const float MaxAbsoluteSize = 600; public const int DefaultAbsoluteSize = 250; public const float MinAbsoluteSize = 50; diff --git a/Penumbra/EphemeralConfig.cs b/Penumbra/EphemeralConfig.cs new file mode 100644 index 00000000..8003629d --- /dev/null +++ b/Penumbra/EphemeralConfig.cs @@ -0,0 +1,86 @@ +using Dalamud.Interface.Internal.Notifications; +using Newtonsoft.Json; +using OtterGui.Classes; +using Penumbra.Api.Enums; +using Penumbra.Enums; +using Penumbra.Interop.Services; +using Penumbra.Services; +using Penumbra.UI; +using Penumbra.UI.ResourceWatcher; +using Penumbra.UI.Tabs; +using ErrorEventArgs = Newtonsoft.Json.Serialization.ErrorEventArgs; + +namespace Penumbra; + +public class EphemeralConfig : ISavable +{ + [JsonIgnore] + private readonly SaveService _saveService; + + public int Version { get; set; } = Configuration.Constants.CurrentVersion; + public int LastSeenVersion { get; set; } = PenumbraChangelog.LastChangelogVersion; + public bool DebugSeparateWindow { get; set; } = false; + public int TutorialStep { get; set; } = 0; + public bool EnableResourceLogging { get; set; } = false; + public string ResourceLoggingFilter { get; set; } = string.Empty; + public bool EnableResourceWatcher { get; set; } = false; + public bool OnlyAddMatchingResources { get; set; } = true; + public ResourceTypeFlag ResourceWatcherResourceTypes { get; set; } = ResourceExtensions.AllResourceTypes; + public ResourceCategoryFlag ResourceWatcherResourceCategories { get; set; } = ResourceExtensions.AllResourceCategories; + public RecordType ResourceWatcherRecordTypes { get; set; } = ResourceWatcher.AllRecords; + public CollectionsTab.PanelMode CollectionPanel { get; set; } = CollectionsTab.PanelMode.SimpleAssignment; + public TabType SelectedTab { get; set; } = TabType.Settings; + public ChangedItemDrawer.ChangedItemIcon ChangedItemFilter { get; set; } = ChangedItemDrawer.DefaultFlags; + public bool FixMainWindow { get; set; } = false; + + /// + /// Load the current configuration. + /// Includes adding new colors and migrating from old versions. + /// + public EphemeralConfig(SaveService saveService) + { + _saveService = saveService; + Load(); + } + + private void Load() + { + static void HandleDeserializationError(object? sender, ErrorEventArgs errorArgs) + { + Penumbra.Log.Error( + $"Error parsing Configuration at {errorArgs.ErrorContext.Path}, using default or migrating:\n{errorArgs.ErrorContext.Error}"); + errorArgs.ErrorContext.Handled = true; + } + + if (File.Exists(_saveService.FileNames.EphemeralConfigFile)) + try + { + var text = File.ReadAllText(_saveService.FileNames.EphemeralConfigFile); + JsonConvert.PopulateObject(text, this, new JsonSerializerSettings + { + Error = HandleDeserializationError, + }); + } + catch (Exception ex) + { + Penumbra.Messager.NotificationMessage(ex, + "Error reading ephemeral Configuration, reverting to default.", + "Error reading ephemeral Configuration", NotificationType.Error); + } + } + + /// Save the current configuration. + public void Save() + => _saveService.DelaySave(this, TimeSpan.FromSeconds(5)); + + + public string ToFilename(FilenameService fileNames) + => fileNames.EphemeralConfigFile; + + public void Save(StreamWriter writer) + { + using var jWriter = new JsonTextWriter(writer) { Formatting = Formatting.Indented }; + var serializer = new JsonSerializer { Formatting = Formatting.Indented }; + serializer.Serialize(jWriter, this); + } +} diff --git a/Penumbra/Penumbra.cs b/Penumbra/Penumbra.cs index d7daaf70..ef8a1a05 100644 --- a/Penumbra/Penumbra.cs +++ b/Penumbra/Penumbra.cs @@ -201,7 +201,7 @@ public class Penumbra : IDalamudPlugin sb.Append( $"> **`Synchronous Load (Dalamud): `** {(_services.GetRequiredService().GetDalamudConfig(DalamudServices.WaitingForPluginsOption, out bool v) ? v.ToString() : "Unknown")}\n"); sb.Append( - $"> **`Logging: `** Log: {_config.EnableResourceLogging}, Watcher: {_config.EnableResourceWatcher} ({_config.MaxResourceWatcherRecords})\n"); + $"> **`Logging: `** Log: {_config.Ephemeral.EnableResourceLogging}, Watcher: {_config.Ephemeral.EnableResourceWatcher} ({_config.MaxResourceWatcherRecords})\n"); sb.Append($"> **`Use Ownership: `** {_config.UseOwnerNameForCharacterCollection}\n"); sb.AppendLine("**Mods**"); sb.Append($"> **`Installed Mods: `** {_modManager.Count}\n"); diff --git a/Penumbra/Services/BackupService.cs b/Penumbra/Services/BackupService.cs index e623be3e..7b8ace29 100644 --- a/Penumbra/Services/BackupService.cs +++ b/Penumbra/Services/BackupService.cs @@ -14,6 +14,10 @@ public class BackupService Backup.CreateAutomaticBackup(logger, new DirectoryInfo(fileNames.ConfigDirectory), files); } + public static void CreatePermanentBackup(FilenameService fileNames) + => Backup.CreatePermanentBackup(Penumbra.Log, new DirectoryInfo(fileNames.ConfigDirectory), PenumbraFiles(fileNames), + "pre_ephemeral_config"); + // Collect all relevant files for penumbra configuration. private static IReadOnlyList PenumbraFiles(FilenameService fileNames) { diff --git a/Penumbra/Services/ConfigMigrationService.cs b/Penumbra/Services/ConfigMigrationService.cs index d896e526..03aedc57 100644 --- a/Penumbra/Services/ConfigMigrationService.cs +++ b/Penumbra/Services/ConfigMigrationService.cs @@ -1,14 +1,20 @@ using Newtonsoft.Json; using Newtonsoft.Json.Linq; +using OtterGui.Classes; using OtterGui.Filesystem; +using Penumbra.Api.Enums; using Penumbra.Collections; using Penumbra.Collections.Manager; +using Penumbra.Enums; using Penumbra.Interop.Services; using Penumbra.Mods; using Penumbra.Mods.Editor; using Penumbra.Mods.Manager; using Penumbra.Mods.Subclasses; +using Penumbra.UI; using Penumbra.UI.Classes; +using Penumbra.UI.ResourceWatcher; +using Penumbra.UI.Tabs; namespace Penumbra.Services; @@ -26,7 +32,7 @@ public class ConfigMigrationService public string CurrentCollection = ModCollection.DefaultCollectionName; public string DefaultCollection = ModCollection.DefaultCollectionName; public string ForcedCollection = string.Empty; - public Dictionary CharacterCollections = new(); + public Dictionary CharacterCollections = []; public Dictionary ModSortOrder = new(); public bool InvertModListOrder; public bool SortFoldersFirst; @@ -71,9 +77,41 @@ public class ConfigMigrationService Version4To5(); Version5To6(); Version6To7(); + Version7To8(); AddColors(config, true); } + // Migrate to ephemeral config. + private void Version7To8() + { + if (_config.Version != 7) + return; + + _config.Version = 8; + _config.Ephemeral.Version = 8; + + _config.Ephemeral.LastSeenVersion = _data["LastSeenVersion"]?.ToObject() ?? _config.Ephemeral.LastSeenVersion; + _config.Ephemeral.DebugSeparateWindow = _data["DebugSeparateWindow"]?.ToObject() ?? _config.Ephemeral.DebugSeparateWindow; + _config.Ephemeral.TutorialStep = _data["TutorialStep"]?.ToObject() ?? _config.Ephemeral.TutorialStep; + _config.Ephemeral.EnableResourceLogging = _data["EnableResourceLogging"]?.ToObject() ?? _config.Ephemeral.EnableResourceLogging; + _config.Ephemeral.ResourceLoggingFilter = _data["ResourceLoggingFilter"]?.ToObject() ?? _config.Ephemeral.ResourceLoggingFilter; + _config.Ephemeral.EnableResourceWatcher = _data["EnableResourceWatcher"]?.ToObject() ?? _config.Ephemeral.EnableResourceWatcher; + _config.Ephemeral.OnlyAddMatchingResources = + _data["OnlyAddMatchingResources"]?.ToObject() ?? _config.Ephemeral.OnlyAddMatchingResources; + _config.Ephemeral.ResourceWatcherResourceTypes = _data["ResourceWatcherResourceTypes"]?.ToObject() + ?? _config.Ephemeral.ResourceWatcherResourceTypes; + _config.Ephemeral.ResourceWatcherResourceCategories = _data["ResourceWatcherResourceCategories"]?.ToObject() + ?? _config.Ephemeral.ResourceWatcherResourceCategories; + _config.Ephemeral.ResourceWatcherRecordTypes = + _data["ResourceWatcherRecordTypes"]?.ToObject() ?? _config.Ephemeral.ResourceWatcherRecordTypes; + _config.Ephemeral.CollectionPanel = _data["CollectionPanel"]?.ToObject() ?? _config.Ephemeral.CollectionPanel; + _config.Ephemeral.SelectedTab = _data["SelectedTab"]?.ToObject() ?? _config.Ephemeral.SelectedTab; + _config.Ephemeral.ChangedItemFilter = _data["ChangedItemFilter"]?.ToObject() + ?? _config.Ephemeral.ChangedItemFilter; + _config.Ephemeral.FixMainWindow = _data["FixMainWindow"]?.ToObject() ?? _config.Ephemeral.FixMainWindow; + _config.Ephemeral.Save(); + } + // Gendered special collections were added. private void Version6To7() { @@ -93,8 +131,8 @@ public class ConfigMigrationService if (_config.Version != 5) return; - if (_config.TutorialStep == 25) - _config.TutorialStep = 27; + if (_config.Ephemeral.TutorialStep == 25) + _config.Ephemeral.TutorialStep = 27; _config.Version = 6; } diff --git a/Penumbra/Services/FilenameService.cs b/Penumbra/Services/FilenameService.cs index c7ed6061..e525c1f4 100644 --- a/Penumbra/Services/FilenameService.cs +++ b/Penumbra/Services/FilenameService.cs @@ -11,17 +11,19 @@ public class FilenameService public readonly string CollectionDirectory; public readonly string LocalDataDirectory; public readonly string ConfigFile; + public readonly string EphemeralConfigFile; public readonly string FilesystemFile; public readonly string ActiveCollectionsFile; public FilenameService(DalamudPluginInterface pi) { ConfigDirectory = pi.ConfigDirectory.FullName; - CollectionDirectory = Path.Combine(pi.GetPluginConfigDirectory(), "collections"); - LocalDataDirectory = Path.Combine(pi.ConfigDirectory.FullName, "mod_data"); + CollectionDirectory = Path.Combine(pi.ConfigDirectory.FullName, "collections"); + LocalDataDirectory = Path.Combine(pi.ConfigDirectory.FullName, "mod_data"); ConfigFile = pi.ConfigFile.FullName; - FilesystemFile = Path.Combine(pi.GetPluginConfigDirectory(), "sort_order.json"); - ActiveCollectionsFile = Path.Combine(pi.ConfigDirectory.FullName, "active_collections.json"); + FilesystemFile = Path.Combine(pi.ConfigDirectory.FullName, "sort_order.json"); + ActiveCollectionsFile = Path.Combine(pi.ConfigDirectory.FullName, "active_collections.json"); + EphemeralConfigFile = Path.Combine(pi.ConfigDirectory.FullName, "ephemeral_config.json"); } /// Obtain the path of a collection file given its name. diff --git a/Penumbra/Services/ServiceManager.cs b/Penumbra/Services/ServiceManager.cs index 2c4f385d..227f65d7 100644 --- a/Penumbra/Services/ServiceManager.cs +++ b/Penumbra/Services/ServiceManager.cs @@ -95,7 +95,8 @@ public static class ServiceManager private static IServiceCollection AddConfiguration(this IServiceCollection services) => services.AddTransient() - .AddSingleton(); + .AddSingleton() + .AddSingleton(); private static IServiceCollection AddCollections(this IServiceCollection services) => services.AddSingleton() diff --git a/Penumbra/UI/ChangedItemDrawer.cs b/Penumbra/UI/ChangedItemDrawer.cs index 3c74aa20..8916d365 100644 --- a/Penumbra/UI/ChangedItemDrawer.cs +++ b/Penumbra/UI/ChangedItemDrawer.cs @@ -70,7 +70,7 @@ public class ChangedItemDrawer : IDisposable /// Check if a changed item should be drawn based on its category. public bool FilterChangedItem(string name, object? data, LowerString filter) - => (_config.ChangedItemFilter == AllFlags || _config.ChangedItemFilter.HasFlag(GetCategoryIcon(name, data))) + => (_config.Ephemeral.ChangedItemFilter == AllFlags || _config.Ephemeral.ChangedItemFilter.HasFlag(GetCategoryIcon(name, data))) && (filter.IsEmpty || filter.IsContained(ChangedItemFilterName(name, data))); /// Draw the icon corresponding to the category of a changed item. @@ -172,20 +172,20 @@ public class ChangedItemDrawer : IDisposable void DrawIcon(ChangedItemIcon type) { var icon = _icons[type]; - var flag = _config.ChangedItemFilter.HasFlag(type); + var flag = _config.Ephemeral.ChangedItemFilter.HasFlag(type); ImGui.Image(icon.ImGuiHandle, size, Vector2.Zero, Vector2.One, flag ? Vector4.One : new Vector4(0.6f, 0.3f, 0.3f, 1f)); if (ImGui.IsItemClicked(ImGuiMouseButton.Left)) { - _config.ChangedItemFilter = flag ? _config.ChangedItemFilter & ~type : _config.ChangedItemFilter | type; - _config.Save(); + _config.Ephemeral.ChangedItemFilter = flag ? _config.Ephemeral.ChangedItemFilter & ~type : _config.Ephemeral.ChangedItemFilter | type; + _config.Ephemeral.Save(); } using var popup = ImRaii.ContextPopupItem(type.ToString()); if (popup) if (ImGui.MenuItem("Enable Only This")) { - _config.ChangedItemFilter = type; - _config.Save(); + _config.Ephemeral.ChangedItemFilter = type; + _config.Ephemeral.Save(); ImGui.CloseCurrentPopup(); } @@ -206,12 +206,12 @@ public class ChangedItemDrawer : IDisposable ImGui.SetCursorPosX(ImGui.GetContentRegionMax().X - size.X); ImGui.Image(_icons[AllFlags].ImGuiHandle, size, Vector2.Zero, Vector2.One, - _config.ChangedItemFilter == 0 ? new Vector4(0.6f, 0.3f, 0.3f, 1f) : - _config.ChangedItemFilter == AllFlags ? new Vector4(0.75f, 0.75f, 0.75f, 1f) : new Vector4(0.5f, 0.5f, 1f, 1f)); + _config.Ephemeral.ChangedItemFilter == 0 ? new Vector4(0.6f, 0.3f, 0.3f, 1f) : + _config.Ephemeral.ChangedItemFilter == AllFlags ? new Vector4(0.75f, 0.75f, 0.75f, 1f) : new Vector4(0.5f, 0.5f, 1f, 1f)); if (ImGui.IsItemClicked()) { - _config.ChangedItemFilter = _config.ChangedItemFilter == AllFlags ? 0 : AllFlags; - _config.Save(); + _config.Ephemeral.ChangedItemFilter = _config.Ephemeral.ChangedItemFilter == AllFlags ? 0 : AllFlags; + _config.Ephemeral.Save(); } } diff --git a/Penumbra/UI/Changelog.cs b/Penumbra/UI/Changelog.cs index 7589e6ec..dac415d5 100644 --- a/Penumbra/UI/Changelog.cs +++ b/Penumbra/UI/Changelog.cs @@ -627,12 +627,20 @@ public class PenumbraChangelog #endregion private (int, ChangeLogDisplayType) ConfigData() - => (_config.LastSeenVersion, _config.ChangeLogDisplayType); + => (_config.Ephemeral.LastSeenVersion, _config.ChangeLogDisplayType); private void Save(int version, ChangeLogDisplayType type) { - _config.LastSeenVersion = version; - _config.ChangeLogDisplayType = type; - _config.Save(); + if (_config.Ephemeral.LastSeenVersion != version) + { + _config.Ephemeral.LastSeenVersion = version; + _config.Ephemeral.Save(); + } + + if (_config.ChangeLogDisplayType != type) + { + _config.ChangeLogDisplayType = type; + _config.Save(); + } } } diff --git a/Penumbra/UI/ConfigWindow.cs b/Penumbra/UI/ConfigWindow.cs index 804a1d01..d52ebb99 100644 --- a/Penumbra/UI/ConfigWindow.cs +++ b/Penumbra/UI/ConfigWindow.cs @@ -39,7 +39,7 @@ public sealed class ConfigWindow : Window { _penumbra = penumbra; _configTabs = configTabs; - _configTabs.SelectTab = _config.SelectedTab; + _configTabs.SelectTab = _config.Ephemeral.SelectedTab; } public override bool DrawConditions() @@ -47,7 +47,7 @@ public sealed class ConfigWindow : Window public override void PreDraw() { - if (_config.FixMainWindow) + if (_config.Ephemeral.FixMainWindow) Flags |= ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoMove; else Flags &= ~(ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoMove); @@ -99,10 +99,10 @@ public sealed class ConfigWindow : Window else { var type = _configTabs.Draw(); - if (type != _config.SelectedTab) + if (type != _config.Ephemeral.SelectedTab) { - _config.SelectedTab = type; - _config.Save(); + _config.Ephemeral.SelectedTab = type; + _config.Ephemeral.Save(); } } diff --git a/Penumbra/UI/ResourceWatcher/ResourceWatcher.cs b/Penumbra/UI/ResourceWatcher/ResourceWatcher.cs index 000e50db..0ac3b9a0 100644 --- a/Penumbra/UI/ResourceWatcher/ResourceWatcher.cs +++ b/Penumbra/UI/ResourceWatcher/ResourceWatcher.cs @@ -21,6 +21,7 @@ public class ResourceWatcher : IDisposable, ITab public const RecordType AllRecords = RecordType.Request | RecordType.ResourceLoad | RecordType.FileLoad | RecordType.Destruction; private readonly Configuration _config; + private readonly EphemeralConfig _ephemeral; private readonly ResourceService _resources; private readonly ResourceLoader _loader; private readonly ActorService _actors; @@ -35,14 +36,15 @@ public class ResourceWatcher : IDisposable, ITab { _actors = actors; _config = config; + _ephemeral = config.Ephemeral; _resources = resources; _loader = loader; - _table = new ResourceWatcherTable(config, _records); + _table = new ResourceWatcherTable(config.Ephemeral, _records); _resources.ResourceRequested += OnResourceRequested; _resources.ResourceHandleDestructor += OnResourceDestroyed; _loader.ResourceLoaded += OnResourceLoaded; _loader.FileLoaded += OnFileLoaded; - UpdateFilter(_config.ResourceLoggingFilter, false); + UpdateFilter(_ephemeral.ResourceLoggingFilter, false); _newMaxEntries = _config.MaxResourceWatcherRecords; } @@ -71,11 +73,11 @@ public class ResourceWatcher : IDisposable, ITab UpdateRecords(); ImGui.SetCursorPosY(ImGui.GetCursorPosY() + ImGui.GetTextLineHeightWithSpacing() / 2); - var isEnabled = _config.EnableResourceWatcher; + var isEnabled = _ephemeral.EnableResourceWatcher; if (ImGui.Checkbox("Enable", ref isEnabled)) { - _config.EnableResourceWatcher = isEnabled; - _config.Save(); + _ephemeral.EnableResourceWatcher = isEnabled; + _ephemeral.Save(); } ImGui.SameLine(); @@ -85,19 +87,19 @@ public class ResourceWatcher : IDisposable, ITab Clear(); ImGui.SameLine(); - var onlyMatching = _config.OnlyAddMatchingResources; + var onlyMatching = _ephemeral.OnlyAddMatchingResources; if (ImGui.Checkbox("Store Only Matching", ref onlyMatching)) { - _config.OnlyAddMatchingResources = onlyMatching; - _config.Save(); + _ephemeral.OnlyAddMatchingResources = onlyMatching; + _ephemeral.Save(); } ImGui.SameLine(); - var writeToLog = _config.EnableResourceLogging; + var writeToLog = _ephemeral.EnableResourceLogging; if (ImGui.Checkbox("Write to Log", ref writeToLog)) { - _config.EnableResourceLogging = writeToLog; - _config.Save(); + _ephemeral.EnableResourceLogging = writeToLog; + _ephemeral.Save(); } ImGui.SameLine(); @@ -136,8 +138,8 @@ public class ResourceWatcher : IDisposable, ITab if (config) { - _config.ResourceLoggingFilter = newString; - _config.Save(); + _ephemeral.ResourceLoggingFilter = newString; + _ephemeral.Save(); } } @@ -196,20 +198,20 @@ public class ResourceWatcher : IDisposable, ITab Utf8GamePath original, GetResourceParameters* parameters, ref bool sync, ref ResourceHandle* returnValue) { - if (_config.EnableResourceLogging && FilterMatch(original.Path, out var match)) + if (_ephemeral.EnableResourceLogging && FilterMatch(original.Path, out var match)) Penumbra.Log.Information($"[ResourceLoader] [REQ] {match} was requested {(sync ? "synchronously." : "asynchronously.")}"); - if (!_config.EnableResourceWatcher) + if (!_ephemeral.EnableResourceWatcher) return; var record = Record.CreateRequest(original.Path, sync); - if (!_config.OnlyAddMatchingResources || _table.WouldBeVisible(record)) + if (!_ephemeral.OnlyAddMatchingResources || _table.WouldBeVisible(record)) _newRecords.Enqueue(record); } private unsafe void OnResourceLoaded(ResourceHandle* handle, Utf8GamePath path, FullPath? manipulatedPath, ResolveData data) { - if (_config.EnableResourceLogging) + if (_ephemeral.EnableResourceLogging) { var log = FilterMatch(path.Path, out var name); var name2 = string.Empty; @@ -224,41 +226,41 @@ public class ResourceWatcher : IDisposable, ITab } } - if (!_config.EnableResourceWatcher) + if (!_ephemeral.EnableResourceWatcher) return; var record = manipulatedPath == null ? Record.CreateDefaultLoad(path.Path, handle, data.ModCollection, Name(data)) : Record.CreateLoad(manipulatedPath.Value.InternalName, path.Path, handle, data.ModCollection, Name(data)); - if (!_config.OnlyAddMatchingResources || _table.WouldBeVisible(record)) + if (!_ephemeral.OnlyAddMatchingResources || _table.WouldBeVisible(record)) _newRecords.Enqueue(record); } private unsafe void OnFileLoaded(ResourceHandle* resource, ByteString path, bool success, bool custom, ByteString _) { - if (_config.EnableResourceLogging && FilterMatch(path, out var match)) + if (_ephemeral.EnableResourceLogging && FilterMatch(path, out var match)) Penumbra.Log.Information( $"[ResourceLoader] [FILE] [{resource->FileType}] Loading {match} from {(custom ? "local files" : "SqPack")} into 0x{(ulong)resource:X} returned {success}."); - if (!_config.EnableResourceWatcher) + if (!_ephemeral.EnableResourceWatcher) return; var record = Record.CreateFileLoad(path, resource, success, custom); - if (!_config.OnlyAddMatchingResources || _table.WouldBeVisible(record)) + if (!_ephemeral.OnlyAddMatchingResources || _table.WouldBeVisible(record)) _newRecords.Enqueue(record); } private unsafe void OnResourceDestroyed(ResourceHandle* resource) { - if (_config.EnableResourceLogging && FilterMatch(resource->FileName(), out var match)) + if (_ephemeral.EnableResourceLogging && FilterMatch(resource->FileName(), out var match)) Penumbra.Log.Information( $"[ResourceLoader] [DEST] [{resource->FileType}] Destroyed {match} at 0x{(ulong)resource:X}."); - if (!_config.EnableResourceWatcher) + if (!_ephemeral.EnableResourceWatcher) return; var record = Record.CreateDestruction(resource); - if (!_config.OnlyAddMatchingResources || _table.WouldBeVisible(record)) + if (!_ephemeral.OnlyAddMatchingResources || _table.WouldBeVisible(record)) _newRecords.Enqueue(record); } diff --git a/Penumbra/UI/ResourceWatcher/ResourceWatcherTable.cs b/Penumbra/UI/ResourceWatcher/ResourceWatcherTable.cs index 89dd42bb..b47574d0 100644 --- a/Penumbra/UI/ResourceWatcher/ResourceWatcherTable.cs +++ b/Penumbra/UI/ResourceWatcher/ResourceWatcherTable.cs @@ -13,7 +13,7 @@ namespace Penumbra.UI.ResourceWatcher; internal sealed class ResourceWatcherTable : Table { - public ResourceWatcherTable(Configuration config, IReadOnlyCollection records) + public ResourceWatcherTable(EphemeralConfig config, IReadOnlyCollection records) : base("##records", records, new PathColumn { Label = "Path" }, @@ -86,9 +86,9 @@ internal sealed class ResourceWatcherTable : Table private sealed class RecordTypeColumn : ColumnFlags { - private readonly Configuration _config; + private readonly EphemeralConfig _config; - public RecordTypeColumn(Configuration config) + public RecordTypeColumn(EphemeralConfig config) { AllFlags = ResourceWatcher.AllRecords; _config = config; @@ -174,9 +174,9 @@ internal sealed class ResourceWatcherTable : Table private sealed class ResourceCategoryColumn : ColumnFlags { - private readonly Configuration _config; + private readonly EphemeralConfig _config; - public ResourceCategoryColumn(Configuration config) + public ResourceCategoryColumn(EphemeralConfig config) { _config = config; AllFlags = ResourceExtensions.AllResourceCategories; @@ -209,9 +209,9 @@ internal sealed class ResourceWatcherTable : Table private sealed class ResourceTypeColumn : ColumnFlags { - private readonly Configuration _config; + private readonly EphemeralConfig _config; - public ResourceTypeColumn(Configuration config) + public ResourceTypeColumn(EphemeralConfig config) { _config = config; AllFlags = Enum.GetValues().Aggregate((v, f) => v | f); diff --git a/Penumbra/UI/Tabs/CollectionsTab.cs b/Penumbra/UI/Tabs/CollectionsTab.cs index 24aa933c..2d30f9cf 100644 --- a/Penumbra/UI/Tabs/CollectionsTab.cs +++ b/Penumbra/UI/Tabs/CollectionsTab.cs @@ -16,7 +16,7 @@ namespace Penumbra.UI.Tabs; public class CollectionsTab : IDisposable, ITab { - private readonly Configuration _config; + private readonly EphemeralConfig _config; private readonly CollectionSelector _selector; private readonly CollectionPanel _panel; private readonly TutorialService _tutorial; @@ -42,7 +42,7 @@ public class CollectionsTab : IDisposable, ITab public CollectionsTab(DalamudPluginInterface pi, Configuration configuration, CommunicatorService communicator, CollectionManager collectionManager, ModStorage modStorage, ActorService actors, ITargetManager targets, TutorialService tutorial) { - _config = configuration; + _config = configuration.Ephemeral; _tutorial = tutorial; _selector = new CollectionSelector(configuration, communicator, collectionManager.Storage, collectionManager.Active, _tutorial); _panel = new CollectionPanel(pi, communicator, collectionManager, _selector, actors, targets, modStorage); diff --git a/Penumbra/UI/Tabs/DebugTab.cs b/Penumbra/UI/Tabs/DebugTab.cs index c5811051..4f554ac5 100644 --- a/Penumbra/UI/Tabs/DebugTab.cs +++ b/Penumbra/UI/Tabs/DebugTab.cs @@ -115,7 +115,7 @@ public class DebugTab : Window, ITab => "Debug"u8; public bool IsVisible - => _config.DebugMode && !_config.DebugSeparateWindow; + => _config is { DebugMode: true, Ephemeral.DebugSeparateWindow: false }; #if DEBUG private const string DebugVersionString = "(Debug)"; @@ -201,12 +201,12 @@ public class DebugTab : Window, ITab if (!ImGui.CollapsingHeader("General")) return; - var separateWindow = _config.DebugSeparateWindow; + var separateWindow = _config.Ephemeral.DebugSeparateWindow; if (ImGui.Checkbox("Draw as Separate Window", ref separateWindow)) { - IsOpen = true; - _config.DebugSeparateWindow = separateWindow; - _config.Save(); + IsOpen = true; + _config.Ephemeral.DebugSeparateWindow = separateWindow; + _config.Ephemeral.Save(); } using (var table = Table("##DebugGeneralTable", 2, ImGuiTableFlags.SizingFixedFit)) @@ -949,11 +949,11 @@ public class DebugTab : Window, ITab => DrawContent(); public override bool DrawConditions() - => _config.DebugMode && _config.DebugSeparateWindow; + => _config.DebugMode && _config.Ephemeral.DebugSeparateWindow; public override void OnClose() { - _config.DebugSeparateWindow = false; - _config.Save(); + _config.Ephemeral.DebugSeparateWindow = false; + _config.Ephemeral.Save(); } } diff --git a/Penumbra/UI/Tabs/SettingsTab.cs b/Penumbra/UI/Tabs/SettingsTab.cs index 6274f209..70a94ecd 100644 --- a/Penumbra/UI/Tabs/SettingsTab.cs +++ b/Penumbra/UI/Tabs/SettingsTab.cs @@ -78,8 +78,8 @@ public class SettingsTab : ITab return; DrawEnabledBox(); - Checkbox("Lock Main Window", "Prevent the main window from being resized or moved.", _config.FixMainWindow, - v => _config.FixMainWindow = v); + EphemeralCheckbox("Lock Main Window", "Prevent the main window from being resized or moved.", _config.Ephemeral.FixMainWindow, + v => _config.Ephemeral.FixMainWindow = v); ImGui.NewLine(); DrawRootFolder(); @@ -107,6 +107,21 @@ public class SettingsTab : ITab ImGuiUtil.LabeledHelpMarker(label, tooltip); } + [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] + private void EphemeralCheckbox(string label, string tooltip, bool current, Action setter) + { + using var id = ImRaii.PushId(label); + var tmp = current; + if (ImGui.Checkbox(string.Empty, ref tmp) && tmp != current) + { + setter(tmp); + _config.Ephemeral.Save(); + } + + ImGui.SameLine(); + ImGuiUtil.LabeledHelpMarker(label, tooltip); + } + #region Main Settings /// @@ -384,7 +399,10 @@ public class SettingsTab : ITab { _config.HideChangedItemFilters = v; if (v) - _config.ChangedItemFilter = ChangedItemDrawer.AllFlags; + { + _config.Ephemeral.ChangedItemFilter = ChangedItemDrawer.AllFlags; + _config.Ephemeral.Save(); + } }); Checkbox("Hide Priority Numbers in Mod Selector", "Hides the bracketed non-zero priority numbers displayed in the mod selector when there is enough space for them.", @@ -863,8 +881,8 @@ public class SettingsTab : ITab ImGui.SetCursorPos(new Vector2(xPos, 3 * ImGui.GetFrameHeightWithSpacing())); if (ImGui.Button("Restart Tutorial", new Vector2(width, 0))) { - _config.TutorialStep = 0; - _config.Save(); + _config.Ephemeral.TutorialStep = 0; + _config.Ephemeral.Save(); } ImGui.SetCursorPos(new Vector2(xPos, 4 * ImGui.GetFrameHeightWithSpacing())); diff --git a/Penumbra/UI/TutorialService.cs b/Penumbra/UI/TutorialService.cs index 86c4dd46..6c6b0612 100644 --- a/Penumbra/UI/TutorialService.cs +++ b/Penumbra/UI/TutorialService.cs @@ -55,10 +55,10 @@ public class TutorialService + " - 'furniture': most indoor furniture, does not currently work outdoors\n" + " - any specific actor name to redraw all actors of that exactly matching name."; - private readonly Configuration _config; - private readonly Tutorial _tutorial; + private readonly EphemeralConfig _config; + private readonly Tutorial _tutorial; - public TutorialService(Configuration config) + public TutorialService(EphemeralConfig config) { _config = config; _tutorial = new Tutorial()