From c1f84b4303b76f935a1f6023f12308868dc4a00a Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Thu, 20 Feb 2025 00:16:49 +0100 Subject: [PATCH] Differentiate between temporary settings through manual and automatic application. --- Glamourer/Automation/AutoDesignApplier.cs | 10 ++- Glamourer/Gui/DesignQuickBar.cs | 9 ++- Glamourer/Gui/Tabs/AutomationTab/SetPanel.cs | 77 +++++++++---------- .../Gui/Tabs/DesignTab/ModAssociationsTab.cs | 5 +- Glamourer/Interop/ObjectManager.cs | 10 ++- .../Interop/Penumbra/ModSettingApplier.cs | 26 ++++--- Glamourer/Interop/Penumbra/PenumbraService.cs | 44 +++++++---- Glamourer/Services/CommandService.cs | 2 +- Glamourer/State/StateEditor.cs | 2 +- 9 files changed, 108 insertions(+), 77 deletions(-) diff --git a/Glamourer/Automation/AutoDesignApplier.cs b/Glamourer/Automation/AutoDesignApplier.cs index 7f75674..545dff7 100644 --- a/Glamourer/Automation/AutoDesignApplier.cs +++ b/Glamourer/Automation/AutoDesignApplier.cs @@ -293,8 +293,16 @@ public sealed class AutoDesignApplier : IDisposable set.Designs.Where(d => d.IsActive(actor)) .SelectMany(d => d.Design.AllLinks(newApplication).Select(l => (l.Design, l.Flags & d.Type, d.Jobs.Flags))), state.ModelData.Customize, state.BaseData, true, _config.AlwaysApplyAssociatedMods); - if (set.ResetTemporarySettings) + + if (_objects.IsInGPose && actor.IsGPoseOrCutscene) + { + mergedDesign.ResetTemporarySettings = false; + mergedDesign.AssociatedMods.Clear(); + } + else if (set.ResetTemporarySettings) + { mergedDesign.ResetTemporarySettings = true; + } _state.ApplyDesign(state, mergedDesign, new ApplySettings(0, StateSource.Fixed, respectManual, fromJobChange, false, false, false)); forcedRedraw = mergedDesign.ForcedRedraw; diff --git a/Glamourer/Gui/DesignQuickBar.cs b/Glamourer/Gui/DesignQuickBar.cs index 1e2904c..b125b37 100644 --- a/Glamourer/Gui/DesignQuickBar.cs +++ b/Glamourer/Gui/DesignQuickBar.cs @@ -409,7 +409,7 @@ public sealed class DesignQuickBar : Window, IDisposable if (_playerIdentifier.IsValid && _playerData.Valid) { available |= 1; - tooltip = $"Left-Click: Reset all temporary settings applied by Glamourer to the collection affecting {_playerIdentifier}."; + tooltip = $"Left-Click: Reset all temporary settings applied by Glamourer (manually or through automation) to the collection affecting {_playerIdentifier}."; } if (_targetIdentifier.IsValid && _targetData.Valid) @@ -417,7 +417,7 @@ public sealed class DesignQuickBar : Window, IDisposable if (available != 0) tooltip += '\n'; available |= 2; - tooltip += $"Right-Click: Reset all temporary settings applied by Glamourer to the collection affecting {_targetIdentifier}."; + tooltip += $"Right-Click: Reset all temporary settings applied by Glamourer (manually or through automation) to the collection affecting {_targetIdentifier}."; } if (available == 0) @@ -426,7 +426,10 @@ public sealed class DesignQuickBar : Window, IDisposable var (clicked, _, data, _) = ResolveTarget(FontAwesomeIcon.Cog, buttonSize, tooltip, available); ImGui.SameLine(); if (clicked) - _penumbra.RemoveAllTemporarySettings(data.Objects[0].Index); + { + _penumbra.RemoveAllTemporarySettings(data.Objects[0].Index, StateSource.Manual); + _penumbra.RemoveAllTemporarySettings(data.Objects[0].Index, StateSource.Fixed); + } } private (bool, ActorIdentifier, ActorData, ActorState?) ResolveTarget(FontAwesomeIcon icon, Vector2 buttonSize, string tooltip, diff --git a/Glamourer/Gui/Tabs/AutomationTab/SetPanel.cs b/Glamourer/Gui/Tabs/AutomationTab/SetPanel.cs index caa7d60..680e0e9 100644 --- a/Glamourer/Gui/Tabs/AutomationTab/SetPanel.cs +++ b/Glamourer/Gui/Tabs/AutomationTab/SetPanel.cs @@ -52,7 +52,7 @@ public class SetPanel( private void DrawPanel() { - using var child = ImRaii.Child("##Panel", -Vector2.One, true); + using var child = ImUtf8.Child("##Panel"u8, -Vector2.One, true); if (!child || !_selector.HasSelection) return; @@ -63,20 +63,20 @@ public class SetPanel( using (ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, spacing)) { var enabled = Selection.Enabled; - if (ImGui.Checkbox("##Enabled", ref enabled)) + if (ImUtf8.Checkbox("##Enabled"u8, ref enabled)) _manager.SetState(_selector.SelectionIndex, enabled); - ImGuiUtil.LabeledHelpMarker("Enabled", - "Whether the designs in this set should be applied at all. Only one set can be enabled for a character at the same time."); + ImUtf8.LabeledHelpMarker("Enabled"u8, + "Whether the designs in this set should be applied at all. Only one set can be enabled for a character at the same time."u8); } using (ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, spacing)) { var useGame = _selector.Selection!.BaseState is AutoDesignSet.Base.Game; - if (ImGui.Checkbox("##gameState", ref useGame)) + if (ImUtf8.Checkbox("##gameState"u8, ref useGame)) _manager.ChangeBaseState(_selector.SelectionIndex, useGame ? AutoDesignSet.Base.Game : AutoDesignSet.Base.Current); - ImGuiUtil.LabeledHelpMarker("Use Game State as Base", - "When this is enabled, the designs matching conditions will be applied successively on top of what your character is supposed to look like for the game. " - + "Otherwise, they will be applied on top of the characters actual current look using Glamourer."); + ImUtf8.LabeledHelpMarker("Use Game State as Base"u8, + "When this is enabled, the designs matching conditions will be applied successively on top of what your character is supposed to look like for the game. "u8 + + "Otherwise, they will be applied on top of the characters actual current look using Glamourer."u8); } } @@ -86,14 +86,14 @@ public class SetPanel( using (ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, spacing)) { var editing = _config.ShowAutomationSetEditing; - if (ImGui.Checkbox("##Show Editing", ref editing)) + if (ImUtf8.Checkbox("##Show Editing"u8, ref editing)) { _config.ShowAutomationSetEditing = editing; _config.Save(); } - ImGuiUtil.LabeledHelpMarker("Show Editing", - "Show options to change the name or the associated character or NPC of this design set."); + ImUtf8.LabeledHelpMarker("Show Editing"u8, + "Show options to change the name or the associated character or NPC of this design set."u8); } using (ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, spacing)) @@ -102,8 +102,8 @@ public class SetPanel( if (ImGui.Checkbox("##resetSettings", ref resetSettings)) _manager.ChangeResetSettings(_selector.SelectionIndex, resetSettings); - ImGuiUtil.LabeledHelpMarker("Reset Temporary Settings", - "Always reset all temporary settings applied by Glamourer when this automation set is applied, regardless of active designs."); + ImUtf8.LabeledHelpMarker("Reset Temporary Settings"u8, + "Always reset all temporary settings applied by Glamourer when this automation set is applied, regardless of active designs."u8); } } @@ -160,42 +160,42 @@ public class SetPanel( (false, false) => 4, }; - using var table = ImRaii.Table("SetTable", numRows, ImGuiTableFlags.RowBg | ImGuiTableFlags.ScrollX | ImGuiTableFlags.ScrollY); + using var table = ImUtf8.Table("SetTable"u8, numRows, ImGuiTableFlags.RowBg | ImGuiTableFlags.ScrollX | ImGuiTableFlags.ScrollY); if (!table) return; - ImGui.TableSetupColumn("##del", ImGuiTableColumnFlags.WidthFixed, ImGui.GetFrameHeight()); - ImGui.TableSetupColumn("##Index", ImGuiTableColumnFlags.WidthFixed, 30 * ImGuiHelpers.GlobalScale); + ImUtf8.TableSetupColumn("##del"u8, ImGuiTableColumnFlags.WidthFixed, ImGui.GetFrameHeight()); + ImUtf8.TableSetupColumn("##Index"u8, ImGuiTableColumnFlags.WidthFixed, 30 * ImGuiHelpers.GlobalScale); if (singleRow) { - ImGui.TableSetupColumn("Design", ImGuiTableColumnFlags.WidthFixed, 220 * ImGuiHelpers.GlobalScale); + ImUtf8.TableSetupColumn("Design"u8, ImGuiTableColumnFlags.WidthFixed, 220 * ImGuiHelpers.GlobalScale); if (_config.ShowAllAutomatedApplicationRules) - ImGui.TableSetupColumn("Application", ImGuiTableColumnFlags.WidthFixed, + ImUtf8.TableSetupColumn("Application"u8, ImGuiTableColumnFlags.WidthFixed, 6 * ImGui.GetFrameHeight() + 10 * ImGuiHelpers.GlobalScale); else - ImGui.TableSetupColumn("Use", ImGuiTableColumnFlags.WidthFixed, ImGui.CalcTextSize("Use").X); + ImUtf8.TableSetupColumn("Use"u8, ImGuiTableColumnFlags.WidthFixed, ImGui.CalcTextSize("Use").X); } else { - ImGui.TableSetupColumn("Design / Job Restrictions", ImGuiTableColumnFlags.WidthFixed, 250 * ImGuiHelpers.GlobalScale); + ImUtf8.TableSetupColumn("Design / Job Restrictions"u8, ImGuiTableColumnFlags.WidthFixed, 250 * ImGuiHelpers.GlobalScale); if (_config.ShowAllAutomatedApplicationRules) - ImGui.TableSetupColumn("Application", ImGuiTableColumnFlags.WidthFixed, + ImUtf8.TableSetupColumn("Application"u8, ImGuiTableColumnFlags.WidthFixed, 3 * ImGui.GetFrameHeight() + 4 * ImGuiHelpers.GlobalScale); else - ImGui.TableSetupColumn("Use", ImGuiTableColumnFlags.WidthFixed, ImGui.CalcTextSize("Use").X); + ImUtf8.TableSetupColumn("Use"u8, ImGuiTableColumnFlags.WidthFixed, ImGui.CalcTextSize("Use").X); } if (singleRow) - ImGui.TableSetupColumn("Job Restrictions", ImGuiTableColumnFlags.WidthStretch); + ImUtf8.TableSetupColumn("Job Restrictions"u8, ImGuiTableColumnFlags.WidthStretch); if (_config.ShowUnlockedItemWarnings) - ImGui.TableSetupColumn(string.Empty, ImGuiTableColumnFlags.WidthFixed, 2 * ImGui.GetFrameHeight() + 4 * ImGuiHelpers.GlobalScale); + ImUtf8.TableSetupColumn(""u8, ImGuiTableColumnFlags.WidthFixed, 2 * ImGui.GetFrameHeight() + 4 * ImGuiHelpers.GlobalScale); ImGui.TableHeadersRow(); foreach (var (design, idx) in Selection.Designs.WithIndex()) { - using var id = ImRaii.PushId(idx); + using var id = ImUtf8.PushId(idx); ImGui.TableNextColumn(); var keyValid = _config.DeleteDesignModifier.IsActive(); var tt = keyValid @@ -205,7 +205,7 @@ public class SetPanel( if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Trash.ToIconString(), new Vector2(ImGui.GetFrameHeight()), tt, !keyValid, true)) _endAction = () => _manager.DeleteDesign(Selection, idx); ImGui.TableNextColumn(); - ImGui.Selectable($"#{idx + 1:D2}"); + ImUtf8.Selectable($"#{idx + 1:D2}"); DrawDragDrop(Selection, idx); ImGui.TableNextColumn(); DrawRandomEditing(Selection, design, idx); @@ -234,8 +234,7 @@ public class SetPanel( ImGui.TableNextColumn(); ImGui.TableNextColumn(); - ImGui.AlignTextToFramePadding(); - ImGui.TextUnformatted("New"); + ImUtf8.TextFrameAligned("New"u8); ImGui.TableNextColumn(); _designCombo.Draw(Selection, null, -1); ImGui.TableNextRow(); @@ -250,20 +249,20 @@ public class SetPanel( private void DrawConditions(AutoDesign design, int idx) { var usingGearset = design.GearsetIndex >= 0; - if (ImGui.Button($"{(usingGearset ? "Gearset:" : "Jobs:")}##usingGearset")) + if (ImUtf8.Button($"{(usingGearset ? "Gearset:" : "Jobs:")}##usingGearset")) { usingGearset = !usingGearset; _manager.ChangeGearsetCondition(Selection, idx, (short)(usingGearset ? 0 : -1)); } - ImGuiUtil.HoverTooltip("Click to switch between Job and Gearset restrictions."); + ImUtf8.HoverTooltip("Click to switch between Job and Gearset restrictions."u8); ImGui.SameLine(0, ImGui.GetStyle().ItemInnerSpacing.X); if (usingGearset) { var set = 1 + (_tmpGearset == int.MaxValue || _whichIndex != idx ? design.GearsetIndex : _tmpGearset); ImGui.SetNextItemWidth(ImGui.GetContentRegionAvail().X); - if (ImGui.InputInt("##whichGearset", ref set, 0, 0)) + if (ImUtf8.InputScalar("##whichGearset"u8, ref set)) { _whichIndex = idx; _tmpGearset = Math.Clamp(set, 1, 100); @@ -361,12 +360,12 @@ public class SetPanel( ImGuiUtil.DrawTextButton(FontAwesomeIcon.ExclamationCircle.ToIconString(), size, color); } - ImGuiUtil.HoverTooltip(sb.ToString()); + ImUtf8.HoverTooltip($"{sb}"); } else { ImGuiUtil.DrawTextButton(string.Empty, size, 0); - ImGuiUtil.HoverTooltip(good); + ImUtf8.HoverTooltip(good); } } } @@ -374,7 +373,7 @@ public class SetPanel( private void DrawDragDrop(AutoDesignSet set, int index) { const string dragDropLabel = "DesignDragDrop"; - using (var target = ImRaii.DragDropTarget()) + using (var target = ImUtf8.DragDropTarget()) { if (target.Success && ImGuiUtil.IsDropping(dragDropLabel)) { @@ -388,11 +387,11 @@ public class SetPanel( } } - using (var source = ImRaii.DragDropSource()) + using (var source = ImUtf8.DragDropSource()) { if (source) { - ImGui.TextUnformatted($"Moving design #{index + 1:D2}..."); + ImUtf8.Text($"Moving design #{index + 1:D2}..."); if (ImGui.SetDragDropPayload(dragDropLabel, nint.Zero, 0)) { _dragIndex = index; @@ -415,16 +414,16 @@ public class SetPanel( } style.Pop(); - ImGuiUtil.HoverTooltip("Toggle all application modes at once."); + ImUtf8.HoverTooltip("Toggle all application modes at once."u8); if (_config.ShowAllAutomatedApplicationRules) { void Box(int idx) { var (type, description) = ApplicationTypeExtensions.Types[idx]; var value = design.Type.HasFlag(type); - if (ImGui.Checkbox($"##{(byte)type}", ref value)) + if (ImUtf8.Checkbox($"##{(byte)type}", ref value)) newType = value ? newType | type : newType & ~type; - ImGuiUtil.HoverTooltip(description); + ImUtf8.HoverTooltip(description); } ImGui.SameLine(); diff --git a/Glamourer/Gui/Tabs/DesignTab/ModAssociationsTab.cs b/Glamourer/Gui/Tabs/DesignTab/ModAssociationsTab.cs index feff657..5856fcc 100644 --- a/Glamourer/Gui/Tabs/DesignTab/ModAssociationsTab.cs +++ b/Glamourer/Gui/Tabs/DesignTab/ModAssociationsTab.cs @@ -4,6 +4,7 @@ using Dalamud.Interface.Utility; using Dalamud.Utility; using Glamourer.Designs; using Glamourer.Interop.Penumbra; +using Glamourer.State; using ImGuiNET; using OtterGui; using OtterGui.Classes; @@ -83,7 +84,7 @@ public class ModAssociationsTab(PenumbraService penumbra, DesignFileSystemSelect public void ApplyAll() { foreach (var (mod, settings) in selector.Selected!.AssociatedMods) - penumbra.SetMod(mod, settings); + penumbra.SetMod(mod, settings, StateSource.Manual); } private void DrawTable() @@ -218,7 +219,7 @@ public class ModAssociationsTab(PenumbraService penumbra, DesignFileSystemSelect if (ImGuiUtil.DrawDisabledButton("Apply", new Vector2(ImGui.GetContentRegionAvail().X, 0), string.Empty, !penumbra.Available)) { - var text = penumbra.SetMod(mod, settings); + var text = penumbra.SetMod(mod, settings, StateSource.Manual); if (text.Length > 0) Glamourer.Messager.NotificationMessage(text, NotificationType.Warning, false); } diff --git a/Glamourer/Interop/ObjectManager.cs b/Glamourer/Interop/ObjectManager.cs index 47f7ad5..471a49b 100644 --- a/Glamourer/Interop/ObjectManager.cs +++ b/Glamourer/Interop/ObjectManager.cs @@ -2,6 +2,7 @@ using Dalamud.Plugin; using Dalamud.Plugin.Services; using FFXIVClientStructs.FFXIV.Client.Game.Control; +using Glamourer.Events; using Glamourer.Interop.Structs; using OtterGui.Log; using Penumbra.GameData.Actors; @@ -24,8 +25,11 @@ public class ObjectManager( => LastFrame; private DateTime _identifierUpdate; - public bool IsInGPose { get; private set; } - public ushort World { get; private set; } + + public bool IsInGPose + => clientState.IsGPosing; + + public ushort World { get; private set; } private readonly Dictionary _identifiers = new(200); private readonly Dictionary _allWorldIdentifiers = new(200); @@ -76,8 +80,6 @@ public class ObjectManager( HandleIdentifier(identifier, actor); } - var gPose = GPosePlayer; - IsInGPose = gPose.Utf8Name.Length > 0; return true; } diff --git a/Glamourer/Interop/Penumbra/ModSettingApplier.cs b/Glamourer/Interop/Penumbra/ModSettingApplier.cs index 60f07e4..82a840c 100644 --- a/Glamourer/Interop/Penumbra/ModSettingApplier.cs +++ b/Glamourer/Interop/Penumbra/ModSettingApplier.cs @@ -12,7 +12,7 @@ public class ModSettingApplier(PenumbraService penumbra, PenumbraAutoRedrawSkip { private readonly HashSet _collectionTracker = []; - public void HandleStateApplication(ActorState state, MergedDesign design, bool skipAutoRedraw) + public void HandleStateApplication(ActorState state, MergedDesign design, StateSource source, bool skipAutoRedraw, bool respectManual) { if (!config.AlwaysApplyAssociatedMods || (design.AssociatedMods.Count == 0 && !design.ResetTemporarySettings)) return; @@ -36,10 +36,10 @@ public class ModSettingApplier(PenumbraService penumbra, PenumbraAutoRedrawSkip if (!_collectionTracker.Add(collection)) continue; - var index = ResetOldSettings(collection, actor, design.ResetTemporarySettings); + var index = ResetOldSettings(collection, actor, source, design.ResetTemporarySettings, respectManual); foreach (var (mod, setting) in design.AssociatedMods) { - var message = penumbra.SetMod(mod, setting, collection, index); + var message = penumbra.SetMod(mod, setting, source, collection, index); if (message.Length > 0) Glamourer.Log.Verbose($"[Mod Applier] Error applying mod settings: {message}"); else @@ -50,7 +50,7 @@ public class ModSettingApplier(PenumbraService penumbra, PenumbraAutoRedrawSkip } public (List Messages, int Applied, Guid Collection, string Name, bool Overridden) ApplyModSettings( - IReadOnlyDictionary settings, Actor actor, bool resetOther) + IReadOnlyDictionary settings, Actor actor, StateSource source, bool resetOther) { var (collection, name, overridden) = overrides.GetCollection(actor); if (collection == Guid.Empty) @@ -59,10 +59,10 @@ public class ModSettingApplier(PenumbraService penumbra, PenumbraAutoRedrawSkip var messages = new List(); var appliedMods = 0; - var index = ResetOldSettings(collection, actor, resetOther); + var index = ResetOldSettings(collection, actor, source, resetOther, true); foreach (var (mod, setting) in settings) { - var message = penumbra.SetMod(mod, setting, collection, index); + var message = penumbra.SetMod(mod, setting, source, collection, index); if (message.Length > 0) messages.Add($"Error applying mod settings: {message}"); else @@ -73,16 +73,24 @@ public class ModSettingApplier(PenumbraService penumbra, PenumbraAutoRedrawSkip } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private ObjectIndex? ResetOldSettings(Guid collection, Actor actor, bool resetOther) + private ObjectIndex? ResetOldSettings(Guid collection, Actor actor, StateSource source, bool resetOther, bool respectManual) { ObjectIndex? index = actor.Valid ? actor.Index : null; if (!resetOther) return index; if (index == null) - penumbra.RemoveAllTemporarySettings(collection); + { + penumbra.RemoveAllTemporarySettings(collection, source); + if (!respectManual && source.IsFixed()) + penumbra.RemoveAllTemporarySettings(collection, StateSource.Manual); + } else - penumbra.RemoveAllTemporarySettings(index.Value); + { + penumbra.RemoveAllTemporarySettings(index.Value, source); + if (!respectManual && source.IsFixed()) + penumbra.RemoveAllTemporarySettings(index.Value, StateSource.Manual); + } return index; } } diff --git a/Glamourer/Interop/Penumbra/PenumbraService.cs b/Glamourer/Interop/Penumbra/PenumbraService.cs index e0c445b..d9b4d27 100644 --- a/Glamourer/Interop/Penumbra/PenumbraService.cs +++ b/Glamourer/Interop/Penumbra/PenumbraService.cs @@ -1,6 +1,7 @@ using Dalamud.Interface.ImGuiNotification; using Dalamud.Plugin; using Glamourer.Events; +using Glamourer.State; using OtterGui.Classes; using Penumbra.Api.Enums; using Penumbra.Api.Helpers; @@ -40,7 +41,10 @@ public class PenumbraService : IDisposable public const int RequiredPenumbraFeatureVersionTemp3 = 6; public const int RequiredPenumbraFeatureVersionTemp4 = 7; - private const int Key = -1610; + private const int KeyFixed = -1610; + private const string NameFixed = "Glamourer (Automation)"; + private const int KeyManual = -6160; + private const string NameManual = "Glamourer (Manually)"; private readonly IDalamudPluginInterface _pluginInterface; private readonly Configuration _config; @@ -160,7 +164,7 @@ public class PenumbraService : IDisposable if (_getCurrentSettingsWithTemp != null) { source = string.Empty; - var (ec, tuple) = _getCurrentSettingsWithTemp!.Invoke(collection, modDirectory, modName, false, false, Key); + var (ec, tuple) = _getCurrentSettingsWithTemp!.Invoke(collection, modDirectory, modName, false, false, KeyFixed); if (ec is not PenumbraApiEc.Success) return ModSettings.Empty; @@ -216,7 +220,7 @@ public class PenumbraService : IDisposable { if (_getAllSettings != null) { - var allSettings = _getAllSettings.Invoke(collection, false, false, Key); + var allSettings = _getAllSettings.Invoke(collection, false, false, KeyFixed); if (allSettings.Item1 is PenumbraApiEc.Success) return mods.Select(m => (new Mod(m.Value, m.Key), allSettings.Item2!.TryGetValue(m.Key, out var s) @@ -276,7 +280,7 @@ public class PenumbraService : IDisposable /// Try to set all mod settings as desired. Only sets when the mod should be enabled. /// If it is disabled, ignore all other settings. /// - public string SetMod(Mod mod, ModSettings settings, Guid? collectionInput = null, ObjectIndex? index = null) + public string SetMod(Mod mod, ModSettings settings, StateSource source, Guid? collectionInput = null, ObjectIndex? index = null) { if (!Available) return "Penumbra is not available."; @@ -286,7 +290,7 @@ public class PenumbraService : IDisposable { var collection = collectionInput ?? _currentCollection!.Invoke(ApiCollectionType.Current)!.Value.Id; if (_config.UseTemporarySettings && _setTemporaryModSettings != null) - SetModTemporary(sb, mod, settings, collection, index); + SetModTemporary(sb, mod, settings, collection, index, source); else SetModPermanent(sb, mod, settings, collection); @@ -298,37 +302,43 @@ public class PenumbraService : IDisposable } } - public void RemoveAllTemporarySettings(Guid collection) - => _removeAllTemporaryModSettings?.Invoke(collection, Key); + public void RemoveAllTemporarySettings(Guid collection, StateSource source) + => _removeAllTemporaryModSettings?.Invoke(collection, source.IsFixed() ? KeyFixed : KeyManual); - public void RemoveAllTemporarySettings(ObjectIndex index) - => _removeAllTemporaryModSettingsPlayer?.Invoke(index.Index, Key); + public void RemoveAllTemporarySettings(ObjectIndex index, StateSource source) + => _removeAllTemporaryModSettingsPlayer?.Invoke(index.Index, source.IsFixed() ? KeyFixed : KeyManual); - public void ClearAllTemporarySettings() + public void ClearAllTemporarySettings(bool fix, bool manual) { if (!Available || _removeAllTemporaryModSettings == null) return; var collections = _collections!.Invoke(); foreach (var collection in collections) - RemoveAllTemporarySettings(collection.Key); + { + if (fix) + RemoveAllTemporarySettings(collection.Key, StateSource.Fixed); + if (manual) + RemoveAllTemporarySettings(collection.Key, StateSource.Manual); + } } public (string ModDirectory, string ModName)[] CheckCurrentChangedItem(string changedItem) => _checkCurrentChangedItems?.Invoke(changedItem) ?? []; - private void SetModTemporary(StringBuilder sb, Mod mod, ModSettings settings, Guid collection, ObjectIndex? index) + private void SetModTemporary(StringBuilder sb, Mod mod, ModSettings settings, Guid collection, ObjectIndex? index, StateSource source) { + var (key, name) = source.IsFixed() ? (KeyFixed, NameFixed) : (KeyManual, NameManual); var ex = settings.Remove ? index.HasValue - ? _removeTemporaryModSettingsPlayer!.Invoke(index.Value.Index, mod.DirectoryName, Key) - : _removeTemporaryModSettings!.Invoke(collection, mod.DirectoryName, Key) + ? _removeTemporaryModSettingsPlayer!.Invoke(index.Value.Index, mod.DirectoryName, key) + : _removeTemporaryModSettings!.Invoke(collection, mod.DirectoryName, key) : index.HasValue ? _setTemporaryModSettingsPlayer!.Invoke(index.Value.Index, mod.DirectoryName, settings.ForceInherit, settings.Enabled, settings.Priority, - settings.Settings.ToDictionary(kvp => kvp.Key, kvp => (IReadOnlyList)kvp.Value), "Glamourer", Key) + settings.Settings.ToDictionary(kvp => kvp.Key, kvp => (IReadOnlyList)kvp.Value), name, key) : _setTemporaryModSettings!.Invoke(collection, mod.DirectoryName, settings.ForceInherit, settings.Enabled, settings.Priority, - settings.Settings.ToDictionary(kvp => kvp.Key, kvp => (IReadOnlyList)kvp.Value), "Glamourer", Key); + settings.Settings.ToDictionary(kvp => kvp.Key, kvp => (IReadOnlyList)kvp.Value), name, key); switch (ex) { case PenumbraApiEc.InvalidArgument: @@ -586,7 +596,7 @@ public class PenumbraService : IDisposable public void Dispose() { - ClearAllTemporarySettings(); + ClearAllTemporarySettings(true, true); Unattach(); _tooltipSubscriber.Dispose(); _clickSubscriber.Dispose(); diff --git a/Glamourer/Services/CommandService.cs b/Glamourer/Services/CommandService.cs index bffc072..4b8ea3d 100644 --- a/Glamourer/Services/CommandService.cs +++ b/Glamourer/Services/CommandService.cs @@ -694,7 +694,7 @@ public class CommandService : IDisposable, IApiService if (!applyMods || design is not Design d) return; - var (messages, appliedMods, _, name, overridden) = _modApplier.ApplyModSettings(d.AssociatedMods, actor, d.ResetTemporarySettings); + var (messages, appliedMods, _, name, overridden) = _modApplier.ApplyModSettings(d.AssociatedMods, actor, StateSource.Manual, d.ResetTemporarySettings); foreach (var message in messages) Glamourer.Messager.Chat.Print($"Error applying mod settings: {message}"); diff --git a/Glamourer/State/StateEditor.cs b/Glamourer/State/StateEditor.cs index 7eea607..1fa1ffe 100644 --- a/Glamourer/State/StateEditor.cs +++ b/Glamourer/State/StateEditor.cs @@ -262,7 +262,7 @@ public class StateEditor( public void ApplyDesign(object data, MergedDesign mergedDesign, ApplySettings settings) { var state = (ActorState)data; - modApplier.HandleStateApplication(state, mergedDesign, true); + modApplier.HandleStateApplication(state, mergedDesign, settings.Source, true, settings.RespectManual); if (!Editor.ChangeModelId(state, mergedDesign.Design.DesignData.ModelId, mergedDesign.Design.DesignData.Customize, mergedDesign.Design.GetDesignDataRef().GetEquipmentPtr(), settings.Source, out var oldModelId, settings.Key)) return;