Differentiate between temporary settings through manual and automatic application.

This commit is contained in:
Ottermandias 2025-02-20 00:16:49 +01:00
parent 5a9e9513f4
commit c1f84b4303
9 changed files with 108 additions and 77 deletions

View file

@ -293,8 +293,16 @@ public sealed class AutoDesignApplier : IDisposable
set.Designs.Where(d => d.IsActive(actor)) set.Designs.Where(d => d.IsActive(actor))
.SelectMany(d => d.Design.AllLinks(newApplication).Select(l => (l.Design, l.Flags & d.Type, d.Jobs.Flags))), .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); 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; mergedDesign.ResetTemporarySettings = true;
}
_state.ApplyDesign(state, mergedDesign, new ApplySettings(0, StateSource.Fixed, respectManual, fromJobChange, false, false, false)); _state.ApplyDesign(state, mergedDesign, new ApplySettings(0, StateSource.Fixed, respectManual, fromJobChange, false, false, false));
forcedRedraw = mergedDesign.ForcedRedraw; forcedRedraw = mergedDesign.ForcedRedraw;

View file

@ -409,7 +409,7 @@ public sealed class DesignQuickBar : Window, IDisposable
if (_playerIdentifier.IsValid && _playerData.Valid) if (_playerIdentifier.IsValid && _playerData.Valid)
{ {
available |= 1; 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) if (_targetIdentifier.IsValid && _targetData.Valid)
@ -417,7 +417,7 @@ public sealed class DesignQuickBar : Window, IDisposable
if (available != 0) if (available != 0)
tooltip += '\n'; tooltip += '\n';
available |= 2; 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) if (available == 0)
@ -426,7 +426,10 @@ public sealed class DesignQuickBar : Window, IDisposable
var (clicked, _, data, _) = ResolveTarget(FontAwesomeIcon.Cog, buttonSize, tooltip, available); var (clicked, _, data, _) = ResolveTarget(FontAwesomeIcon.Cog, buttonSize, tooltip, available);
ImGui.SameLine(); ImGui.SameLine();
if (clicked) 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, private (bool, ActorIdentifier, ActorData, ActorState?) ResolveTarget(FontAwesomeIcon icon, Vector2 buttonSize, string tooltip,

View file

@ -52,7 +52,7 @@ public class SetPanel(
private void DrawPanel() 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) if (!child || !_selector.HasSelection)
return; return;
@ -63,20 +63,20 @@ public class SetPanel(
using (ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, spacing)) using (ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, spacing))
{ {
var enabled = Selection.Enabled; var enabled = Selection.Enabled;
if (ImGui.Checkbox("##Enabled", ref enabled)) if (ImUtf8.Checkbox("##Enabled"u8, ref enabled))
_manager.SetState(_selector.SelectionIndex, enabled); _manager.SetState(_selector.SelectionIndex, enabled);
ImGuiUtil.LabeledHelpMarker("Enabled", 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."); "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)) using (ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, spacing))
{ {
var useGame = _selector.Selection!.BaseState is AutoDesignSet.Base.Game; 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); _manager.ChangeBaseState(_selector.SelectionIndex, useGame ? AutoDesignSet.Base.Game : AutoDesignSet.Base.Current);
ImGuiUtil.LabeledHelpMarker("Use Game State as Base", 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. " "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."); + "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)) using (ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, spacing))
{ {
var editing = _config.ShowAutomationSetEditing; var editing = _config.ShowAutomationSetEditing;
if (ImGui.Checkbox("##Show Editing", ref editing)) if (ImUtf8.Checkbox("##Show Editing"u8, ref editing))
{ {
_config.ShowAutomationSetEditing = editing; _config.ShowAutomationSetEditing = editing;
_config.Save(); _config.Save();
} }
ImGuiUtil.LabeledHelpMarker("Show Editing", ImUtf8.LabeledHelpMarker("Show Editing"u8,
"Show options to change the name or the associated character or NPC of this design set."); "Show options to change the name or the associated character or NPC of this design set."u8);
} }
using (ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, spacing)) using (ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, spacing))
@ -102,8 +102,8 @@ public class SetPanel(
if (ImGui.Checkbox("##resetSettings", ref resetSettings)) if (ImGui.Checkbox("##resetSettings", ref resetSettings))
_manager.ChangeResetSettings(_selector.SelectionIndex, resetSettings); _manager.ChangeResetSettings(_selector.SelectionIndex, resetSettings);
ImGuiUtil.LabeledHelpMarker("Reset Temporary Settings", ImUtf8.LabeledHelpMarker("Reset Temporary Settings"u8,
"Always reset all temporary settings applied by Glamourer when this automation set is applied, regardless of active designs."); "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, (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) if (!table)
return; return;
ImGui.TableSetupColumn("##del", ImGuiTableColumnFlags.WidthFixed, ImGui.GetFrameHeight()); ImUtf8.TableSetupColumn("##del"u8, ImGuiTableColumnFlags.WidthFixed, ImGui.GetFrameHeight());
ImGui.TableSetupColumn("##Index", ImGuiTableColumnFlags.WidthFixed, 30 * ImGuiHelpers.GlobalScale); ImUtf8.TableSetupColumn("##Index"u8, ImGuiTableColumnFlags.WidthFixed, 30 * ImGuiHelpers.GlobalScale);
if (singleRow) if (singleRow)
{ {
ImGui.TableSetupColumn("Design", ImGuiTableColumnFlags.WidthFixed, 220 * ImGuiHelpers.GlobalScale); ImUtf8.TableSetupColumn("Design"u8, ImGuiTableColumnFlags.WidthFixed, 220 * ImGuiHelpers.GlobalScale);
if (_config.ShowAllAutomatedApplicationRules) if (_config.ShowAllAutomatedApplicationRules)
ImGui.TableSetupColumn("Application", ImGuiTableColumnFlags.WidthFixed, ImUtf8.TableSetupColumn("Application"u8, ImGuiTableColumnFlags.WidthFixed,
6 * ImGui.GetFrameHeight() + 10 * ImGuiHelpers.GlobalScale); 6 * ImGui.GetFrameHeight() + 10 * ImGuiHelpers.GlobalScale);
else else
ImGui.TableSetupColumn("Use", ImGuiTableColumnFlags.WidthFixed, ImGui.CalcTextSize("Use").X); ImUtf8.TableSetupColumn("Use"u8, ImGuiTableColumnFlags.WidthFixed, ImGui.CalcTextSize("Use").X);
} }
else 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) if (_config.ShowAllAutomatedApplicationRules)
ImGui.TableSetupColumn("Application", ImGuiTableColumnFlags.WidthFixed, ImUtf8.TableSetupColumn("Application"u8, ImGuiTableColumnFlags.WidthFixed,
3 * ImGui.GetFrameHeight() + 4 * ImGuiHelpers.GlobalScale); 3 * ImGui.GetFrameHeight() + 4 * ImGuiHelpers.GlobalScale);
else else
ImGui.TableSetupColumn("Use", ImGuiTableColumnFlags.WidthFixed, ImGui.CalcTextSize("Use").X); ImUtf8.TableSetupColumn("Use"u8, ImGuiTableColumnFlags.WidthFixed, ImGui.CalcTextSize("Use").X);
} }
if (singleRow) if (singleRow)
ImGui.TableSetupColumn("Job Restrictions", ImGuiTableColumnFlags.WidthStretch); ImUtf8.TableSetupColumn("Job Restrictions"u8, ImGuiTableColumnFlags.WidthStretch);
if (_config.ShowUnlockedItemWarnings) 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(); ImGui.TableHeadersRow();
foreach (var (design, idx) in Selection.Designs.WithIndex()) foreach (var (design, idx) in Selection.Designs.WithIndex())
{ {
using var id = ImRaii.PushId(idx); using var id = ImUtf8.PushId(idx);
ImGui.TableNextColumn(); ImGui.TableNextColumn();
var keyValid = _config.DeleteDesignModifier.IsActive(); var keyValid = _config.DeleteDesignModifier.IsActive();
var tt = keyValid var tt = keyValid
@ -205,7 +205,7 @@ public class SetPanel(
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Trash.ToIconString(), new Vector2(ImGui.GetFrameHeight()), tt, !keyValid, true)) if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Trash.ToIconString(), new Vector2(ImGui.GetFrameHeight()), tt, !keyValid, true))
_endAction = () => _manager.DeleteDesign(Selection, idx); _endAction = () => _manager.DeleteDesign(Selection, idx);
ImGui.TableNextColumn(); ImGui.TableNextColumn();
ImGui.Selectable($"#{idx + 1:D2}"); ImUtf8.Selectable($"#{idx + 1:D2}");
DrawDragDrop(Selection, idx); DrawDragDrop(Selection, idx);
ImGui.TableNextColumn(); ImGui.TableNextColumn();
DrawRandomEditing(Selection, design, idx); DrawRandomEditing(Selection, design, idx);
@ -234,8 +234,7 @@ public class SetPanel(
ImGui.TableNextColumn(); ImGui.TableNextColumn();
ImGui.TableNextColumn(); ImGui.TableNextColumn();
ImGui.AlignTextToFramePadding(); ImUtf8.TextFrameAligned("New"u8);
ImGui.TextUnformatted("New");
ImGui.TableNextColumn(); ImGui.TableNextColumn();
_designCombo.Draw(Selection, null, -1); _designCombo.Draw(Selection, null, -1);
ImGui.TableNextRow(); ImGui.TableNextRow();
@ -250,20 +249,20 @@ public class SetPanel(
private void DrawConditions(AutoDesign design, int idx) private void DrawConditions(AutoDesign design, int idx)
{ {
var usingGearset = design.GearsetIndex >= 0; var usingGearset = design.GearsetIndex >= 0;
if (ImGui.Button($"{(usingGearset ? "Gearset:" : "Jobs:")}##usingGearset")) if (ImUtf8.Button($"{(usingGearset ? "Gearset:" : "Jobs:")}##usingGearset"))
{ {
usingGearset = !usingGearset; usingGearset = !usingGearset;
_manager.ChangeGearsetCondition(Selection, idx, (short)(usingGearset ? 0 : -1)); _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); ImGui.SameLine(0, ImGui.GetStyle().ItemInnerSpacing.X);
if (usingGearset) if (usingGearset)
{ {
var set = 1 + (_tmpGearset == int.MaxValue || _whichIndex != idx ? design.GearsetIndex : _tmpGearset); var set = 1 + (_tmpGearset == int.MaxValue || _whichIndex != idx ? design.GearsetIndex : _tmpGearset);
ImGui.SetNextItemWidth(ImGui.GetContentRegionAvail().X); ImGui.SetNextItemWidth(ImGui.GetContentRegionAvail().X);
if (ImGui.InputInt("##whichGearset", ref set, 0, 0)) if (ImUtf8.InputScalar("##whichGearset"u8, ref set))
{ {
_whichIndex = idx; _whichIndex = idx;
_tmpGearset = Math.Clamp(set, 1, 100); _tmpGearset = Math.Clamp(set, 1, 100);
@ -361,12 +360,12 @@ public class SetPanel(
ImGuiUtil.DrawTextButton(FontAwesomeIcon.ExclamationCircle.ToIconString(), size, color); ImGuiUtil.DrawTextButton(FontAwesomeIcon.ExclamationCircle.ToIconString(), size, color);
} }
ImGuiUtil.HoverTooltip(sb.ToString()); ImUtf8.HoverTooltip($"{sb}");
} }
else else
{ {
ImGuiUtil.DrawTextButton(string.Empty, size, 0); 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) private void DrawDragDrop(AutoDesignSet set, int index)
{ {
const string dragDropLabel = "DesignDragDrop"; const string dragDropLabel = "DesignDragDrop";
using (var target = ImRaii.DragDropTarget()) using (var target = ImUtf8.DragDropTarget())
{ {
if (target.Success && ImGuiUtil.IsDropping(dragDropLabel)) 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) if (source)
{ {
ImGui.TextUnformatted($"Moving design #{index + 1:D2}..."); ImUtf8.Text($"Moving design #{index + 1:D2}...");
if (ImGui.SetDragDropPayload(dragDropLabel, nint.Zero, 0)) if (ImGui.SetDragDropPayload(dragDropLabel, nint.Zero, 0))
{ {
_dragIndex = index; _dragIndex = index;
@ -415,16 +414,16 @@ public class SetPanel(
} }
style.Pop(); style.Pop();
ImGuiUtil.HoverTooltip("Toggle all application modes at once."); ImUtf8.HoverTooltip("Toggle all application modes at once."u8);
if (_config.ShowAllAutomatedApplicationRules) if (_config.ShowAllAutomatedApplicationRules)
{ {
void Box(int idx) void Box(int idx)
{ {
var (type, description) = ApplicationTypeExtensions.Types[idx]; var (type, description) = ApplicationTypeExtensions.Types[idx];
var value = design.Type.HasFlag(type); 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; newType = value ? newType | type : newType & ~type;
ImGuiUtil.HoverTooltip(description); ImUtf8.HoverTooltip(description);
} }
ImGui.SameLine(); ImGui.SameLine();

View file

@ -4,6 +4,7 @@ using Dalamud.Interface.Utility;
using Dalamud.Utility; using Dalamud.Utility;
using Glamourer.Designs; using Glamourer.Designs;
using Glamourer.Interop.Penumbra; using Glamourer.Interop.Penumbra;
using Glamourer.State;
using ImGuiNET; using ImGuiNET;
using OtterGui; using OtterGui;
using OtterGui.Classes; using OtterGui.Classes;
@ -83,7 +84,7 @@ public class ModAssociationsTab(PenumbraService penumbra, DesignFileSystemSelect
public void ApplyAll() public void ApplyAll()
{ {
foreach (var (mod, settings) in selector.Selected!.AssociatedMods) foreach (var (mod, settings) in selector.Selected!.AssociatedMods)
penumbra.SetMod(mod, settings); penumbra.SetMod(mod, settings, StateSource.Manual);
} }
private void DrawTable() 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, if (ImGuiUtil.DrawDisabledButton("Apply", new Vector2(ImGui.GetContentRegionAvail().X, 0), string.Empty,
!penumbra.Available)) !penumbra.Available))
{ {
var text = penumbra.SetMod(mod, settings); var text = penumbra.SetMod(mod, settings, StateSource.Manual);
if (text.Length > 0) if (text.Length > 0)
Glamourer.Messager.NotificationMessage(text, NotificationType.Warning, false); Glamourer.Messager.NotificationMessage(text, NotificationType.Warning, false);
} }

View file

@ -2,6 +2,7 @@
using Dalamud.Plugin; using Dalamud.Plugin;
using Dalamud.Plugin.Services; using Dalamud.Plugin.Services;
using FFXIVClientStructs.FFXIV.Client.Game.Control; using FFXIVClientStructs.FFXIV.Client.Game.Control;
using Glamourer.Events;
using Glamourer.Interop.Structs; using Glamourer.Interop.Structs;
using OtterGui.Log; using OtterGui.Log;
using Penumbra.GameData.Actors; using Penumbra.GameData.Actors;
@ -24,7 +25,10 @@ public class ObjectManager(
=> LastFrame; => LastFrame;
private DateTime _identifierUpdate; private DateTime _identifierUpdate;
public bool IsInGPose { get; private set; }
public bool IsInGPose
=> clientState.IsGPosing;
public ushort World { get; private set; } public ushort World { get; private set; }
private readonly Dictionary<ActorIdentifier, ActorData> _identifiers = new(200); private readonly Dictionary<ActorIdentifier, ActorData> _identifiers = new(200);
@ -76,8 +80,6 @@ public class ObjectManager(
HandleIdentifier(identifier, actor); HandleIdentifier(identifier, actor);
} }
var gPose = GPosePlayer;
IsInGPose = gPose.Utf8Name.Length > 0;
return true; return true;
} }

View file

@ -12,7 +12,7 @@ public class ModSettingApplier(PenumbraService penumbra, PenumbraAutoRedrawSkip
{ {
private readonly HashSet<Guid> _collectionTracker = []; private readonly HashSet<Guid> _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)) if (!config.AlwaysApplyAssociatedMods || (design.AssociatedMods.Count == 0 && !design.ResetTemporarySettings))
return; return;
@ -36,10 +36,10 @@ public class ModSettingApplier(PenumbraService penumbra, PenumbraAutoRedrawSkip
if (!_collectionTracker.Add(collection)) if (!_collectionTracker.Add(collection))
continue; continue;
var index = ResetOldSettings(collection, actor, design.ResetTemporarySettings); var index = ResetOldSettings(collection, actor, source, design.ResetTemporarySettings, respectManual);
foreach (var (mod, setting) in design.AssociatedMods) 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) if (message.Length > 0)
Glamourer.Log.Verbose($"[Mod Applier] Error applying mod settings: {message}"); Glamourer.Log.Verbose($"[Mod Applier] Error applying mod settings: {message}");
else else
@ -50,7 +50,7 @@ public class ModSettingApplier(PenumbraService penumbra, PenumbraAutoRedrawSkip
} }
public (List<string> Messages, int Applied, Guid Collection, string Name, bool Overridden) ApplyModSettings( public (List<string> Messages, int Applied, Guid Collection, string Name, bool Overridden) ApplyModSettings(
IReadOnlyDictionary<Mod, ModSettings> settings, Actor actor, bool resetOther) IReadOnlyDictionary<Mod, ModSettings> settings, Actor actor, StateSource source, bool resetOther)
{ {
var (collection, name, overridden) = overrides.GetCollection(actor); var (collection, name, overridden) = overrides.GetCollection(actor);
if (collection == Guid.Empty) if (collection == Guid.Empty)
@ -59,10 +59,10 @@ public class ModSettingApplier(PenumbraService penumbra, PenumbraAutoRedrawSkip
var messages = new List<string>(); var messages = new List<string>();
var appliedMods = 0; var appliedMods = 0;
var index = ResetOldSettings(collection, actor, resetOther); var index = ResetOldSettings(collection, actor, source, resetOther, true);
foreach (var (mod, setting) in settings) 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) if (message.Length > 0)
messages.Add($"Error applying mod settings: {message}"); messages.Add($"Error applying mod settings: {message}");
else else
@ -73,16 +73,24 @@ public class ModSettingApplier(PenumbraService penumbra, PenumbraAutoRedrawSkip
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [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; ObjectIndex? index = actor.Valid ? actor.Index : null;
if (!resetOther) if (!resetOther)
return index; return index;
if (index == null) if (index == null)
penumbra.RemoveAllTemporarySettings(collection); {
penumbra.RemoveAllTemporarySettings(collection, source);
if (!respectManual && source.IsFixed())
penumbra.RemoveAllTemporarySettings(collection, StateSource.Manual);
}
else else
penumbra.RemoveAllTemporarySettings(index.Value); {
penumbra.RemoveAllTemporarySettings(index.Value, source);
if (!respectManual && source.IsFixed())
penumbra.RemoveAllTemporarySettings(index.Value, StateSource.Manual);
}
return index; return index;
} }
} }

View file

@ -1,6 +1,7 @@
using Dalamud.Interface.ImGuiNotification; using Dalamud.Interface.ImGuiNotification;
using Dalamud.Plugin; using Dalamud.Plugin;
using Glamourer.Events; using Glamourer.Events;
using Glamourer.State;
using OtterGui.Classes; using OtterGui.Classes;
using Penumbra.Api.Enums; using Penumbra.Api.Enums;
using Penumbra.Api.Helpers; using Penumbra.Api.Helpers;
@ -40,7 +41,10 @@ public class PenumbraService : IDisposable
public const int RequiredPenumbraFeatureVersionTemp3 = 6; public const int RequiredPenumbraFeatureVersionTemp3 = 6;
public const int RequiredPenumbraFeatureVersionTemp4 = 7; 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 IDalamudPluginInterface _pluginInterface;
private readonly Configuration _config; private readonly Configuration _config;
@ -160,7 +164,7 @@ public class PenumbraService : IDisposable
if (_getCurrentSettingsWithTemp != null) if (_getCurrentSettingsWithTemp != null)
{ {
source = string.Empty; 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) if (ec is not PenumbraApiEc.Success)
return ModSettings.Empty; return ModSettings.Empty;
@ -216,7 +220,7 @@ public class PenumbraService : IDisposable
{ {
if (_getAllSettings != null) 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) if (allSettings.Item1 is PenumbraApiEc.Success)
return mods.Select(m => (new Mod(m.Value, m.Key), return mods.Select(m => (new Mod(m.Value, m.Key),
allSettings.Item2!.TryGetValue(m.Key, out var s) 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. /// Try to set all mod settings as desired. Only sets when the mod should be enabled.
/// If it is disabled, ignore all other settings. /// If it is disabled, ignore all other settings.
/// </summary> /// </summary>
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) if (!Available)
return "Penumbra is not available."; return "Penumbra is not available.";
@ -286,7 +290,7 @@ public class PenumbraService : IDisposable
{ {
var collection = collectionInput ?? _currentCollection!.Invoke(ApiCollectionType.Current)!.Value.Id; var collection = collectionInput ?? _currentCollection!.Invoke(ApiCollectionType.Current)!.Value.Id;
if (_config.UseTemporarySettings && _setTemporaryModSettings != null) if (_config.UseTemporarySettings && _setTemporaryModSettings != null)
SetModTemporary(sb, mod, settings, collection, index); SetModTemporary(sb, mod, settings, collection, index, source);
else else
SetModPermanent(sb, mod, settings, collection); SetModPermanent(sb, mod, settings, collection);
@ -298,37 +302,43 @@ public class PenumbraService : IDisposable
} }
} }
public void RemoveAllTemporarySettings(Guid collection) public void RemoveAllTemporarySettings(Guid collection, StateSource source)
=> _removeAllTemporaryModSettings?.Invoke(collection, Key); => _removeAllTemporaryModSettings?.Invoke(collection, source.IsFixed() ? KeyFixed : KeyManual);
public void RemoveAllTemporarySettings(ObjectIndex index) public void RemoveAllTemporarySettings(ObjectIndex index, StateSource source)
=> _removeAllTemporaryModSettingsPlayer?.Invoke(index.Index, Key); => _removeAllTemporaryModSettingsPlayer?.Invoke(index.Index, source.IsFixed() ? KeyFixed : KeyManual);
public void ClearAllTemporarySettings() public void ClearAllTemporarySettings(bool fix, bool manual)
{ {
if (!Available || _removeAllTemporaryModSettings == null) if (!Available || _removeAllTemporaryModSettings == null)
return; return;
var collections = _collections!.Invoke(); var collections = _collections!.Invoke();
foreach (var collection in collections) 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) public (string ModDirectory, string ModName)[] CheckCurrentChangedItem(string changedItem)
=> _checkCurrentChangedItems?.Invoke(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 var ex = settings.Remove
? index.HasValue ? index.HasValue
? _removeTemporaryModSettingsPlayer!.Invoke(index.Value.Index, mod.DirectoryName, Key) ? _removeTemporaryModSettingsPlayer!.Invoke(index.Value.Index, mod.DirectoryName, key)
: _removeTemporaryModSettings!.Invoke(collection, mod.DirectoryName, Key) : _removeTemporaryModSettings!.Invoke(collection, mod.DirectoryName, key)
: index.HasValue : index.HasValue
? _setTemporaryModSettingsPlayer!.Invoke(index.Value.Index, mod.DirectoryName, settings.ForceInherit, settings.Enabled, ? _setTemporaryModSettingsPlayer!.Invoke(index.Value.Index, mod.DirectoryName, settings.ForceInherit, settings.Enabled,
settings.Priority, settings.Priority,
settings.Settings.ToDictionary(kvp => kvp.Key, kvp => (IReadOnlyList<string>)kvp.Value), "Glamourer", Key) settings.Settings.ToDictionary(kvp => kvp.Key, kvp => (IReadOnlyList<string>)kvp.Value), name, key)
: _setTemporaryModSettings!.Invoke(collection, mod.DirectoryName, settings.ForceInherit, settings.Enabled, settings.Priority, : _setTemporaryModSettings!.Invoke(collection, mod.DirectoryName, settings.ForceInherit, settings.Enabled, settings.Priority,
settings.Settings.ToDictionary(kvp => kvp.Key, kvp => (IReadOnlyList<string>)kvp.Value), "Glamourer", Key); settings.Settings.ToDictionary(kvp => kvp.Key, kvp => (IReadOnlyList<string>)kvp.Value), name, key);
switch (ex) switch (ex)
{ {
case PenumbraApiEc.InvalidArgument: case PenumbraApiEc.InvalidArgument:
@ -586,7 +596,7 @@ public class PenumbraService : IDisposable
public void Dispose() public void Dispose()
{ {
ClearAllTemporarySettings(); ClearAllTemporarySettings(true, true);
Unattach(); Unattach();
_tooltipSubscriber.Dispose(); _tooltipSubscriber.Dispose();
_clickSubscriber.Dispose(); _clickSubscriber.Dispose();

View file

@ -694,7 +694,7 @@ public class CommandService : IDisposable, IApiService
if (!applyMods || design is not Design d) if (!applyMods || design is not Design d)
return; 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) foreach (var message in messages)
Glamourer.Messager.Chat.Print($"Error applying mod settings: {message}"); Glamourer.Messager.Chat.Print($"Error applying mod settings: {message}");

View file

@ -262,7 +262,7 @@ public class StateEditor(
public void ApplyDesign(object data, MergedDesign mergedDesign, ApplySettings settings) public void ApplyDesign(object data, MergedDesign mergedDesign, ApplySettings settings)
{ {
var state = (ActorState)data; 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, if (!Editor.ChangeModelId(state, mergedDesign.Design.DesignData.ModelId, mergedDesign.Design.DesignData.Customize,
mergedDesign.Design.GetDesignDataRef().GetEquipmentPtr(), settings.Source, out var oldModelId, settings.Key)) mergedDesign.Design.GetDesignDataRef().GetEquipmentPtr(), settings.Source, out var oldModelId, settings.Key))
return; return;