Add initial support for setting temporary mod settings.

This commit is contained in:
Ottermandias 2024-12-31 16:35:08 +01:00
parent e41755ed7e
commit 24452f3c79
22 changed files with 394 additions and 202 deletions

View file

@ -293,6 +293,8 @@ 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)
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

@ -445,6 +445,7 @@ public class AutoDesignManager : ISavable, IReadOnlyList<AutoDesignSet>, IDispos
var set = new AutoDesignSet(name, group) var set = new AutoDesignSet(name, group)
{ {
Enabled = obj["Enabled"]?.ToObject<bool>() ?? false, Enabled = obj["Enabled"]?.ToObject<bool>() ?? false,
ResetTemporarySettings = obj["ResetTemporarySettings"]?.ToObject<bool>() ?? false,
BaseState = obj["BaseState"]?.ToObject<AutoDesignSet.Base>() ?? AutoDesignSet.Base.Current, BaseState = obj["BaseState"]?.ToObject<AutoDesignSet.Base>() ?? AutoDesignSet.Base.Current,
}; };

View file

@ -11,6 +11,7 @@ public class AutoDesignSet(string name, ActorIdentifier[] identifiers, List<Auto
public ActorIdentifier[] Identifiers = identifiers; public ActorIdentifier[] Identifiers = identifiers;
public bool Enabled; public bool Enabled;
public Base BaseState = Base.Current; public Base BaseState = Base.Current;
public bool ResetTemporarySettings = false;
public JObject Serialize() public JObject Serialize()
{ {
@ -24,6 +25,7 @@ public class AutoDesignSet(string name, ActorIdentifier[] identifiers, List<Auto
["Identifier"] = Identifiers[0].ToJson(), ["Identifier"] = Identifiers[0].ToJson(),
["Enabled"] = Enabled, ["Enabled"] = Enabled,
["BaseState"] = BaseState.ToString(), ["BaseState"] = BaseState.ToString(),
["ResetTemporarySettings"] = ResetTemporarySettings.ToString(),
["Designs"] = list, ["Designs"] = list,
}; };
} }

View file

@ -30,6 +30,7 @@ public class DefaultDesignSettings
public bool AlwaysForceRedrawing = false; public bool AlwaysForceRedrawing = false;
public bool ResetAdvancedDyes = false; public bool ResetAdvancedDyes = false;
public bool ShowQuickDesignBar = true; public bool ShowQuickDesignBar = true;
public bool ResetTemporarySettings = false;
} }
public class Configuration : IPluginConfiguration, ISavable public class Configuration : IPluginConfiguration, ISavable
@ -63,6 +64,7 @@ public class Configuration : IPluginConfiguration, ISavable
public bool ShowColorConfig { get; set; } = true; public bool ShowColorConfig { get; set; } = true;
public bool ChangeEntireItem { get; set; } = false; public bool ChangeEntireItem { get; set; } = false;
public bool AlwaysApplyAssociatedMods { get; set; } = false; public bool AlwaysApplyAssociatedMods { get; set; } = false;
public bool UseTemporarySettings { get; set; } = true;
public bool AllowDoubleClickToApply { get; set; } = false; public bool AllowDoubleClickToApply { get; set; } = false;
public bool RespectManualOnAutomationUpdate { get; set; } = false; public bool RespectManualOnAutomationUpdate { get; set; } = false;

View file

@ -33,6 +33,7 @@ public sealed class Design : DesignBase, ISavable, IDesignStandIn
QuickDesign = other.QuickDesign; QuickDesign = other.QuickDesign;
ForcedRedraw = other.ForcedRedraw; ForcedRedraw = other.ForcedRedraw;
ResetAdvancedDyes = other.ResetAdvancedDyes; ResetAdvancedDyes = other.ResetAdvancedDyes;
ResetTemporarySettings = other.ResetTemporarySettings;
Color = other.Color; Color = other.Color;
AssociatedMods = new SortedList<Mod, ModSettings>(other.AssociatedMods); AssociatedMods = new SortedList<Mod, ModSettings>(other.AssociatedMods);
Links = Links.Clone(); Links = Links.Clone();
@ -50,6 +51,7 @@ public sealed class Design : DesignBase, ISavable, IDesignStandIn
public int Index { get; internal set; } public int Index { get; internal set; }
public bool ForcedRedraw { get; internal set; } public bool ForcedRedraw { get; internal set; }
public bool ResetAdvancedDyes { get; internal set; } public bool ResetAdvancedDyes { get; internal set; }
public bool ResetTemporarySettings { get; internal set; }
public bool QuickDesign { get; internal set; } = true; public bool QuickDesign { get; internal set; } = true;
public string Color { get; internal set; } = string.Empty; public string Color { get; internal set; } = string.Empty;
public SortedList<Mod, ModSettings> AssociatedMods { get; private set; } = []; public SortedList<Mod, ModSettings> AssociatedMods { get; private set; } = [];
@ -108,6 +110,7 @@ public sealed class Design : DesignBase, ISavable, IDesignStandIn
["Description"] = Description, ["Description"] = Description,
["ForcedRedraw"] = ForcedRedraw, ["ForcedRedraw"] = ForcedRedraw,
["ResetAdvancedDyes"] = ResetAdvancedDyes, ["ResetAdvancedDyes"] = ResetAdvancedDyes,
["ResetTemporarySettings"] = ResetTemporarySettings,
["Color"] = Color, ["Color"] = Color,
["QuickDesign"] = QuickDesign, ["QuickDesign"] = QuickDesign,
["Tags"] = JArray.FromObject(Tags), ["Tags"] = JArray.FromObject(Tags),
@ -253,6 +256,7 @@ public sealed class Design : DesignBase, ISavable, IDesignStandIn
design.Color = json["Color"]?.ToObject<string>() ?? string.Empty; design.Color = json["Color"]?.ToObject<string>() ?? string.Empty;
design.ForcedRedraw = json["ForcedRedraw"]?.ToObject<bool>() ?? false; design.ForcedRedraw = json["ForcedRedraw"]?.ToObject<bool>() ?? false;
design.ResetAdvancedDyes = json["ResetAdvancedDyes"]?.ToObject<bool>() ?? false; design.ResetAdvancedDyes = json["ResetAdvancedDyes"]?.ToObject<bool>() ?? false;
design.ResetTemporarySettings = json["ResetTemporarySettings"]?.ToObject<bool>() ?? false;
return design; return design;
static string[] ParseTags(JObject json) static string[] ParseTags(JObject json)
@ -278,12 +282,15 @@ public sealed class Design : DesignBase, ISavable, IDesignStandIn
continue; continue;
} }
var forceInherit = tok["Inherit"]?.ToObject<bool>() ?? false;
var removeSetting = tok["Remove"]?.ToObject<bool>() ?? false;
var settingsDict = tok["Settings"]?.ToObject<Dictionary<string, List<string>>>() ?? []; var settingsDict = tok["Settings"]?.ToObject<Dictionary<string, List<string>>>() ?? [];
var settings = new Dictionary<string, List<string>>(settingsDict.Count); var settings = new Dictionary<string, List<string>>(settingsDict.Count);
foreach (var (key, value) in settingsDict) foreach (var (key, value) in settingsDict)
settings.Add(key, value); settings.Add(key, value);
var priority = tok["Priority"]?.ToObject<int>() ?? 0; var priority = tok["Priority"]?.ToObject<int>() ?? 0;
if (!design.AssociatedMods.TryAdd(new Mod(name, directory), new ModSettings(settings, priority, enabled.Value))) if (!design.AssociatedMods.TryAdd(new Mod(name, directory),
new ModSettings(settings, priority, enabled.Value, forceInherit, removeSetting)))
Glamourer.Messager.NotificationMessage("The loaded design contains a mod more than once, skipped.", NotificationType.Warning); Glamourer.Messager.NotificationMessage("The loaded design contains a mod more than once, skipped.", NotificationType.Warning);
} }
} }

View file

@ -107,6 +107,7 @@ public sealed class DesignManager : DesignEditor
ForcedRedraw = Config.DefaultDesignSettings.AlwaysForceRedrawing, ForcedRedraw = Config.DefaultDesignSettings.AlwaysForceRedrawing,
ResetAdvancedDyes = Config.DefaultDesignSettings.ResetAdvancedDyes, ResetAdvancedDyes = Config.DefaultDesignSettings.ResetAdvancedDyes,
QuickDesign = Config.DefaultDesignSettings.ShowQuickDesignBar, QuickDesign = Config.DefaultDesignSettings.ShowQuickDesignBar,
ResetTemporarySettings = Config.DefaultDesignSettings.ResetTemporarySettings,
}; };
Designs.Add(design); Designs.Add(design);
Glamourer.Log.Debug($"Added new design {design.Identifier}."); Glamourer.Log.Debug($"Added new design {design.Identifier}.");
@ -129,6 +130,7 @@ public sealed class DesignManager : DesignEditor
ForcedRedraw = Config.DefaultDesignSettings.AlwaysForceRedrawing, ForcedRedraw = Config.DefaultDesignSettings.AlwaysForceRedrawing,
ResetAdvancedDyes = Config.DefaultDesignSettings.ResetAdvancedDyes, ResetAdvancedDyes = Config.DefaultDesignSettings.ResetAdvancedDyes,
QuickDesign = Config.DefaultDesignSettings.ShowQuickDesignBar, QuickDesign = Config.DefaultDesignSettings.ShowQuickDesignBar,
ResetTemporarySettings = Config.DefaultDesignSettings.ResetTemporarySettings,
}; };
Designs.Add(design); Designs.Add(design);
@ -351,6 +353,17 @@ public sealed class DesignManager : DesignEditor
DesignChanged.Invoke(DesignChanged.Type.ResetAdvancedDyes, design, null); DesignChanged.Invoke(DesignChanged.Type.ResetAdvancedDyes, design, null);
} }
public void ChangeResetTemporarySettings(Design design, bool resetTemporarySettings)
{
if (design.ResetTemporarySettings == resetTemporarySettings)
return;
design.ResetTemporarySettings = resetTemporarySettings;
SaveService.QueueSave(design);
Glamourer.Log.Debug($"Set {design.Identifier} to {(resetTemporarySettings ? string.Empty : "not")} reset temporary settings.");
DesignChanged.Invoke(DesignChanged.Type.ResetTemporarySettings, design, null);
}
/// <summary> Change whether to apply a specific customize value. </summary> /// <summary> Change whether to apply a specific customize value. </summary>
public void ChangeApplyCustomize(Design design, CustomizeIndex idx, bool value) public void ChangeApplyCustomize(Design design, CustomizeIndex idx, bool value)
{ {

View file

@ -27,4 +27,5 @@ public interface IDesignStandIn : IEquatable<IDesignStandIn>
public bool ForcedRedraw { get; } public bool ForcedRedraw { get; }
public bool ResetAdvancedDyes { get; } public bool ResetAdvancedDyes { get; }
public bool ResetTemporarySettings { get; }
} }

View file

@ -58,6 +58,8 @@ public class DesignMerger(
ret.ForcedRedraw = true; ret.ForcedRedraw = true;
if (design.ResetAdvancedDyes) if (design.ResetAdvancedDyes)
ret.ResetAdvancedDyes = true; ret.ResetAdvancedDyes = true;
if (design.ResetTemporarySettings)
ret.ResetTemporarySettings = true;
} }
ApplyFixFlags(ret, fixFlags); ApplyFixFlags(ret, fixFlags);

View file

@ -101,4 +101,5 @@ public sealed class MergedDesign
public StateSources Sources = new(); public StateSources Sources = new();
public bool ForcedRedraw; public bool ForcedRedraw;
public bool ResetAdvancedDyes; public bool ResetAdvancedDyes;
public bool ResetTemporarySettings;
} }

View file

@ -56,4 +56,7 @@ public class QuickSelectedDesign(QuickDesignCombo combo) : IDesignStandIn, IServ
public bool ResetAdvancedDyes public bool ResetAdvancedDyes
=> combo.Design?.ResetAdvancedDyes ?? false; => combo.Design?.ResetAdvancedDyes ?? false;
public bool ResetTemporarySettings
=> combo.Design?.ResetTemporarySettings ?? false;
} }

View file

@ -92,8 +92,11 @@ public class RandomDesign(RandomDesignGenerator rng) : IDesignStandIn
} }
public bool ForcedRedraw public bool ForcedRedraw
=> false; => _currentDesign?.ForcedRedraw ?? false;
public bool ResetAdvancedDyes public bool ResetAdvancedDyes
=> false; => _currentDesign?.ResetAdvancedDyes ?? false;
public bool ResetTemporarySettings
=> _currentDesign?.ResetTemporarySettings ?? false;
} }

View file

@ -48,4 +48,7 @@ public class RevertDesign : IDesignStandIn
public bool ResetAdvancedDyes public bool ResetAdvancedDyes
=> true; => true;
public bool ResetTemporarySettings
=> true;
} }

View file

@ -93,6 +93,9 @@ public sealed class DesignChanged()
/// <summary> An existing design had changed whether it always resets advanced dyes or not. </summary> /// <summary> An existing design had changed whether it always resets advanced dyes or not. </summary>
ResetAdvancedDyes, ResetAdvancedDyes,
/// <summary> An existing design had changed whether it always resets all prior temporary settings or not. </summary>
ResetTemporarySettings,
/// <summary> An existing design changed whether a specific customization is applied. </summary> /// <summary> An existing design changed whether a specific customization is applied. </summary>
ApplyCustomize, ApplyCustomize,

View file

@ -159,6 +159,7 @@ public class ActorPanel
return; return;
ImGui.TableSetupScrollFreeze(0, 1); ImGui.TableSetupScrollFreeze(0, 1);
ImGui.TableNextColumn(); ImGui.TableNextColumn();
ImGui.Dummy(Vector2.Zero);
var transformationId = _actor.IsCharacter ? _actor.AsCharacter->CharacterData.TransformationId : 0; var transformationId = _actor.IsCharacter ? _actor.AsCharacter->CharacterData.TransformationId : 0;
if (transformationId != 0) if (transformationId != 0)
ImGuiUtil.DrawTextButton($"Currently transformed to Transformation {transformationId}.", ImGuiUtil.DrawTextButton($"Currently transformed to Transformation {transformationId}.",

View file

@ -6,6 +6,7 @@ using ImGuiNET;
using OtterGui; using OtterGui;
using OtterGui.Classes; using OtterGui.Classes;
using OtterGui.Raii; using OtterGui.Raii;
using OtterGui.Text;
using OtterGui.Widgets; using OtterGui.Widgets;
namespace Glamourer.Gui.Tabs.DesignTab; namespace Glamourer.Gui.Tabs.DesignTab;
@ -41,7 +42,7 @@ public class DesignDetailTab
public void Draw() public void Draw()
{ {
using var h = ImRaii.CollapsingHeader("Design Details"); using var h = ImUtf8.CollapsingHeaderId("Design Details"u8);
if (!h) if (!h)
return; return;
@ -54,19 +55,19 @@ public class DesignDetailTab
private void DrawDesignInfoTable() private void DrawDesignInfoTable()
{ {
using var style = ImRaii.PushStyle(ImGuiStyleVar.ButtonTextAlign, new Vector2(0, 0.5f)); using var style = ImRaii.PushStyle(ImGuiStyleVar.ButtonTextAlign, new Vector2(0, 0.5f));
using var table = ImRaii.Table("Details", 2); using var table = ImUtf8.Table("Details"u8, 2);
if (!table) if (!table)
return; return;
ImGui.TableSetupColumn("Type", ImGuiTableColumnFlags.WidthFixed, ImGui.CalcTextSize("Reset Advanced Dyes").X); ImUtf8.TableSetupColumn("Type"u8, ImGuiTableColumnFlags.WidthFixed, ImUtf8.CalcTextSize("Reset Temporary Settings"u8).X);
ImGui.TableSetupColumn("Data", ImGuiTableColumnFlags.WidthStretch); ImUtf8.TableSetupColumn("Data"u8, ImGuiTableColumnFlags.WidthStretch);
ImGuiUtil.DrawFrameColumn("Design Name"); ImUtf8.DrawFrameColumn("Design Name"u8);
ImGui.TableNextColumn(); ImGui.TableNextColumn();
var width = new Vector2(ImGui.GetContentRegionAvail().X, 0); var width = new Vector2(ImGui.GetContentRegionAvail().X, 0);
var name = _newName ?? _selector.Selected!.Name; var name = _newName ?? _selector.Selected!.Name;
ImGui.SetNextItemWidth(width.X); ImGui.SetNextItemWidth(width.X);
if (ImGui.InputText("##Name", ref name, 128)) if (ImUtf8.InputText("##Name"u8, ref name))
{ {
_newName = name; _newName = name;
_changeDesign = _selector.Selected; _changeDesign = _selector.Selected;
@ -80,10 +81,10 @@ public class DesignDetailTab
} }
var identifier = _selector.Selected!.Identifier.ToString(); var identifier = _selector.Selected!.Identifier.ToString();
ImGuiUtil.DrawFrameColumn("Unique Identifier"); ImUtf8.DrawFrameColumn("Unique Identifier"u8);
ImGui.TableNextColumn(); ImGui.TableNextColumn();
var fileName = _saveService.FileNames.DesignFile(_selector.Selected!); var fileName = _saveService.FileNames.DesignFile(_selector.Selected!);
using (var mono = ImRaii.PushFont(UiBuilder.MonoFont)) using (ImRaii.PushFont(UiBuilder.MonoFont))
{ {
if (ImGui.Button(identifier, width)) if (ImGui.Button(identifier, width))
try try
@ -100,14 +101,14 @@ public class DesignDetailTab
ImGui.SetClipboardText(identifier); ImGui.SetClipboardText(identifier);
} }
ImGuiUtil.HoverTooltip( ImUtf8.HoverTooltip(
$"Open the file\n\t{fileName}\ncontaining this design in the .json-editor of your choice.\n\nRight-Click to copy identifier to clipboard."); $"Open the file\n\t{fileName}\ncontaining this design in the .json-editor of your choice.\n\nRight-Click to copy identifier to clipboard.");
ImGuiUtil.DrawFrameColumn("Full Selector Path"); ImUtf8.DrawFrameColumn("Full Selector Path"u8);
ImGui.TableNextColumn(); ImGui.TableNextColumn();
var path = _newPath ?? _selector.SelectedLeaf!.FullName(); var path = _newPath ?? _selector.SelectedLeaf!.FullName();
ImGui.SetNextItemWidth(width.X); ImGui.SetNextItemWidth(width.X);
if (ImGui.InputText("##Path", ref path, 1024)) if (ImUtf8.InputText("##Path"u8, ref path))
{ {
_newPath = path; _newPath = path;
_changeLeaf = _selector.SelectedLeaf!; _changeLeaf = _selector.SelectedLeaf!;
@ -125,32 +126,42 @@ public class DesignDetailTab
Glamourer.Messager.NotificationMessage(ex, ex.Message, "Could not rename or move design", NotificationType.Error); Glamourer.Messager.NotificationMessage(ex, ex.Message, "Could not rename or move design", NotificationType.Error);
} }
ImGuiUtil.DrawFrameColumn("Quick Design Bar"); ImUtf8.DrawFrameColumn("Quick Design Bar"u8);
ImGui.TableNextColumn(); ImGui.TableNextColumn();
if (ImGui.RadioButton("Display##qdb", _selector.Selected.QuickDesign)) if (ImUtf8.RadioButton("Display##qdb"u8, _selector.Selected.QuickDesign))
_manager.SetQuickDesign(_selector.Selected!, true); _manager.SetQuickDesign(_selector.Selected!, true);
var hovered = ImGui.IsItemHovered(); var hovered = ImGui.IsItemHovered();
ImGui.SameLine(); ImGui.SameLine();
if (ImGui.RadioButton("Hide##qdb", !_selector.Selected.QuickDesign)) if (ImUtf8.RadioButton("Hide##qdb"u8, !_selector.Selected.QuickDesign))
_manager.SetQuickDesign(_selector.Selected!, false); _manager.SetQuickDesign(_selector.Selected!, false);
if (hovered || ImGui.IsItemHovered()) if (hovered || ImGui.IsItemHovered())
ImGui.SetTooltip("Display or hide this design in your quick design bar."); {
using var tt = ImUtf8.Tooltip();
ImUtf8.Text("Display or hide this design in your quick design bar."u8);
}
var forceRedraw = _selector.Selected!.ForcedRedraw; var forceRedraw = _selector.Selected!.ForcedRedraw;
ImGuiUtil.DrawFrameColumn("Force Redrawing"); ImUtf8.DrawFrameColumn("Force Redrawing"u8);
ImGui.TableNextColumn(); ImGui.TableNextColumn();
if (ImGui.Checkbox("##ForceRedraw", ref forceRedraw)) if (ImUtf8.Checkbox("##ForceRedraw"u8, ref forceRedraw))
_manager.ChangeForcedRedraw(_selector.Selected!, forceRedraw); _manager.ChangeForcedRedraw(_selector.Selected!, forceRedraw);
ImGuiUtil.HoverTooltip("Set this design to always force a redraw when it is applied through any means."); ImUtf8.HoverTooltip("Set this design to always force a redraw when it is applied through any means."u8);
var resetAdvancedDyes = _selector.Selected!.ResetAdvancedDyes; var resetAdvancedDyes = _selector.Selected!.ResetAdvancedDyes;
ImGuiUtil.DrawFrameColumn("Reset Advanced Dyes"); ImUtf8.DrawFrameColumn("Reset Advanced Dyes"u8);
ImGui.TableNextColumn(); ImGui.TableNextColumn();
if (ImGui.Checkbox("##ResetAdvancedDyes", ref resetAdvancedDyes)) if (ImUtf8.Checkbox("##ResetAdvancedDyes"u8, ref resetAdvancedDyes))
_manager.ChangeResetAdvancedDyes(_selector.Selected!, resetAdvancedDyes); _manager.ChangeResetAdvancedDyes(_selector.Selected!, resetAdvancedDyes);
ImGuiUtil.HoverTooltip("Set this design to reset any previously applied advanced dyes when it is applied through any means."); ImUtf8.HoverTooltip("Set this design to reset any previously applied advanced dyes when it is applied through any means."u8);
ImGuiUtil.DrawFrameColumn("Color"); var resetTemporarySettings = _selector.Selected!.ResetTemporarySettings;
ImUtf8.DrawFrameColumn("Reset Temporary Settings"u8);
ImGui.TableNextColumn();
if (ImUtf8.Checkbox("##ResetTemporarySettings"u8, ref resetTemporarySettings))
_manager.ChangeResetTemporarySettings(_selector.Selected!, resetTemporarySettings);
ImUtf8.HoverTooltip("Set this design to reset any temporary settings previously applied to the associated collection when it is applied through any means."u8);
ImUtf8.DrawFrameColumn("Color"u8);
var colorName = _selector.Selected!.Color.Length == 0 ? DesignColors.AutomaticName : _selector.Selected!.Color; var colorName = _selector.Selected!.Color.Length == 0 ? DesignColors.AutomaticName : _selector.Selected!.Color;
ImGui.TableNextColumn(); ImGui.TableNextColumn();
if (_colorCombo.Draw("##colorCombo", colorName, "Associate a color with this design.\n" if (_colorCombo.Draw("##colorCombo", colorName, "Associate a color with this design.\n"
@ -178,18 +189,18 @@ public class DesignDetailTab
var size = new Vector2(ImGui.GetFrameHeight()); var size = new Vector2(ImGui.GetFrameHeight());
using var font = ImRaii.PushFont(UiBuilder.IconFont); using var font = ImRaii.PushFont(UiBuilder.IconFont);
ImGuiUtil.DrawTextButton(FontAwesomeIcon.ExclamationCircle.ToIconString(), size, 0, _colors.MissingColor); ImGuiUtil.DrawTextButton(FontAwesomeIcon.ExclamationCircle.ToIconString(), size, 0, _colors.MissingColor);
ImGuiUtil.HoverTooltip("The color associated with this design does not exist."); ImUtf8.HoverTooltip("The color associated with this design does not exist."u8);
} }
ImGuiUtil.DrawFrameColumn("Creation Date"); ImUtf8.DrawFrameColumn("Creation Date"u8);
ImGui.TableNextColumn(); ImGui.TableNextColumn();
ImGuiUtil.DrawTextButton(_selector.Selected!.CreationDate.LocalDateTime.ToString("F"), width, 0); ImGuiUtil.DrawTextButton(_selector.Selected!.CreationDate.LocalDateTime.ToString("F"), width, 0);
ImGuiUtil.DrawFrameColumn("Last Update Date"); ImUtf8.DrawFrameColumn("Last Update Date"u8);
ImGui.TableNextColumn(); ImGui.TableNextColumn();
ImGuiUtil.DrawTextButton(_selector.Selected!.LastEdit.LocalDateTime.ToString("F"), width, 0); ImGuiUtil.DrawTextButton(_selector.Selected!.LastEdit.LocalDateTime.ToString("F"), width, 0);
ImGuiUtil.DrawFrameColumn("Tags"); ImUtf8.DrawFrameColumn("Tags"u8);
ImGui.TableNextColumn(); ImGui.TableNextColumn();
DrawTags(); DrawTags();
} }
@ -219,18 +230,18 @@ public class DesignDetailTab
var size = new Vector2(ImGui.GetContentRegionAvail().X, 12 * ImGui.GetTextLineHeightWithSpacing()); var size = new Vector2(ImGui.GetContentRegionAvail().X, 12 * ImGui.GetTextLineHeightWithSpacing());
if (!_editDescriptionMode) if (!_editDescriptionMode)
{ {
using (var textBox = ImRaii.ListBox("##desc", size)) using (var textBox = ImUtf8.ListBox("##desc"u8, size))
{ {
ImGuiUtil.TextWrapped(desc); ImUtf8.TextWrapped(desc);
} }
if (ImGui.Button("Edit Description")) if (ImUtf8.Button("Edit Description"u8))
_editDescriptionMode = true; _editDescriptionMode = true;
} }
else else
{ {
var edit = _newDescription ?? desc; var edit = _newDescription ?? desc;
if (ImGui.InputTextMultiline("##desc", ref edit, (uint)Math.Max(2000, 4 * edit.Length), size)) if (ImUtf8.InputMultiLine("##desc"u8, ref edit, size))
_newDescription = edit; _newDescription = edit;
if (ImGui.IsItemDeactivatedAfterEdit()) if (ImGui.IsItemDeactivatedAfterEdit())
@ -239,7 +250,7 @@ public class DesignDetailTab
_newDescription = null; _newDescription = null;
} }
if (ImGui.Button("Stop Editing")) if (ImUtf8.Button("Stop Editing"u8))
_editDescriptionMode = false; _editDescriptionMode = false;
} }
} }

View file

@ -423,6 +423,7 @@ public class DesignPanel
ImGui.TableNextColumn(); ImGui.TableNextColumn();
if (_selector.Selected == null) if (_selector.Selected == null)
return; return;
ImGui.Dummy(Vector2.Zero);
DrawButtonRow(); DrawButtonRow();
ImGui.TableNextColumn(); ImGui.TableNextColumn();
@ -438,7 +439,6 @@ public class DesignPanel
private void DrawButtonRow() private void DrawButtonRow()
{ {
ImGui.Dummy(Vector2.Zero);
DrawApplyToSelf(); DrawApplyToSelf();
ImGui.SameLine(); ImGui.SameLine();
DrawApplyToTarget(); DrawApplyToTarget();

View file

@ -88,16 +88,18 @@ public class ModAssociationsTab(PenumbraService penumbra, DesignFileSystemSelect
private void DrawTable() private void DrawTable()
{ {
using var table = ImRaii.Table("Mods", 5, ImGuiTableFlags.RowBg); using var table = ImUtf8.Table("Mods"u8, 7, ImGuiTableFlags.RowBg);
if (!table) if (!table)
return; return;
ImGui.TableSetupColumn("##Buttons", ImGuiTableColumnFlags.WidthFixed, ImUtf8.TableSetupColumn("##Buttons"u8, ImGuiTableColumnFlags.WidthFixed,
ImGui.GetFrameHeight() * 3 + ImGui.GetStyle().ItemInnerSpacing.X * 2); ImGui.GetFrameHeight() * 3 + ImGui.GetStyle().ItemInnerSpacing.X * 2);
ImGui.TableSetupColumn("Mod Name", ImGuiTableColumnFlags.WidthStretch); ImUtf8.TableSetupColumn("Mod Name"u8, ImGuiTableColumnFlags.WidthStretch);
ImGui.TableSetupColumn("State", ImGuiTableColumnFlags.WidthFixed, ImGui.CalcTextSize("State").X); ImUtf8.TableSetupColumn("Remove"u8, ImGuiTableColumnFlags.WidthFixed, ImUtf8.CalcTextSize("Remove"u8).X);
ImGui.TableSetupColumn("Priority", ImGuiTableColumnFlags.WidthFixed, ImGui.CalcTextSize("Priority").X); ImUtf8.TableSetupColumn("Inherit"u8, ImGuiTableColumnFlags.WidthFixed, ImUtf8.CalcTextSize("Inherit"u8).X);
ImGui.TableSetupColumn("##Options", ImGuiTableColumnFlags.WidthFixed, ImGui.CalcTextSize("Applym").X); ImUtf8.TableSetupColumn("State"u8, ImGuiTableColumnFlags.WidthFixed, ImUtf8.CalcTextSize("State"u8).X);
ImUtf8.TableSetupColumn("Priority"u8, ImGuiTableColumnFlags.WidthFixed, ImUtf8.CalcTextSize("Priority"u8).X);
ImUtf8.TableSetupColumn("##Options"u8, ImGuiTableColumnFlags.WidthFixed, ImUtf8.CalcTextSize("Applym"u8).X);
ImGui.TableHeadersRow(); ImGui.TableHeadersRow();
Mod? removedMod = null; Mod? removedMod = null;
@ -183,6 +185,17 @@ public class ModAssociationsTab(PenumbraService penumbra, DesignFileSystemSelect
if (ImGui.IsItemHovered()) if (ImGui.IsItemHovered())
ImGui.SetTooltip($"Mod Directory: {mod.DirectoryName}\n\nClick to open mod page in Penumbra."); ImGui.SetTooltip($"Mod Directory: {mod.DirectoryName}\n\nClick to open mod page in Penumbra.");
ImGui.TableNextColumn(); ImGui.TableNextColumn();
var remove = settings.Remove;
if (TwoStateCheckbox.Instance.Draw("##Remove"u8, ref remove))
updatedMod = (mod, settings with { Remove = remove });
ImUtf8.HoverTooltip(
"Remove any temporary settings applied by Glamourer instead of applying the configured settings. Only works when using temporary settings, ignored otherwise."u8);
ImGui.TableNextColumn();
var inherit = settings.ForceInherit;
if (TwoStateCheckbox.Instance.Draw("##Enabled"u8, ref inherit))
updatedMod = (mod, settings with { ForceInherit = inherit });
ImUtf8.HoverTooltip("Force the mod to inherit its settings from inherited collections."u8);
ImGui.TableNextColumn();
var enabled = settings.Enabled; var enabled = settings.Enabled;
if (TwoStateCheckbox.Instance.Draw("##Enabled"u8, ref enabled)) if (TwoStateCheckbox.Instance.Draw("##Enabled"u8, ref enabled))
updatedMod = (mod, settings with { Enabled = enabled }); updatedMod = (mod, settings with { Enabled = enabled });

View file

@ -106,6 +106,9 @@ public class SettingsTab(
+ "Glamourer will NOT revert these applied settings automatically. This may mess up your collection and configuration.\n\n" + "Glamourer will NOT revert these applied settings automatically. This may mess up your collection and configuration.\n\n"
+ "If you enable this setting, you are aware that any resulting misconfiguration is your own fault.", + "If you enable this setting, you are aware that any resulting misconfiguration is your own fault.",
config.AlwaysApplyAssociatedMods, v => config.AlwaysApplyAssociatedMods = v); config.AlwaysApplyAssociatedMods, v => config.AlwaysApplyAssociatedMods = v);
Checkbox("Use Temporary Mod Settings",
"Apply all settings as temporary settings so they will be reset when Glamourer or the game shut down.", config.UseTemporarySettings,
v => config.UseTemporarySettings = v);
ImGui.NewLine(); ImGui.NewLine();
} }
@ -120,6 +123,8 @@ public class SettingsTab(
config.DefaultDesignSettings.ResetAdvancedDyes, v => config.DefaultDesignSettings.ResetAdvancedDyes = v); config.DefaultDesignSettings.ResetAdvancedDyes, v => config.DefaultDesignSettings.ResetAdvancedDyes = v);
Checkbox("Always Force Redraw", "Newly created designs will be configured to force character redraws on application by default.", Checkbox("Always Force Redraw", "Newly created designs will be configured to force character redraws on application by default.",
config.DefaultDesignSettings.AlwaysForceRedrawing, v => config.DefaultDesignSettings.AlwaysForceRedrawing = v); config.DefaultDesignSettings.AlwaysForceRedrawing, v => config.DefaultDesignSettings.AlwaysForceRedrawing = v);
Checkbox("Reset Temporary Settings", "Newly created designs will be configured to clear all advanced settings applied by Glamourer to the collection by default.",
config.DefaultDesignSettings.ResetTemporarySettings, v => config.DefaultDesignSettings.ResetTemporarySettings = v);
} }
private void DrawInterfaceSettings() private void DrawInterfaceSettings()

View file

@ -3,12 +3,15 @@ using Glamourer.Services;
using Glamourer.State; using Glamourer.State;
using OtterGui.Services; using OtterGui.Services;
using Penumbra.GameData.Interop; using Penumbra.GameData.Interop;
using Penumbra.GameData.Structs;
namespace Glamourer.Interop.Penumbra; namespace Glamourer.Interop.Penumbra;
public class ModSettingApplier(PenumbraService penumbra, Configuration config, ObjectManager objects, CollectionOverrideService overrides) public class ModSettingApplier(PenumbraService penumbra, Configuration config, ObjectManager objects, CollectionOverrideService overrides)
: IService : IService
{ {
private readonly HashSet<Guid> _collectionTracker = [];
public void HandleStateApplication(ActorState state, MergedDesign design) public void HandleStateApplication(ActorState state, MergedDesign design)
{ {
if (!config.AlwaysApplyAssociatedMods || design.AssociatedMods.Count == 0) if (!config.AlwaysApplyAssociatedMods || design.AssociatedMods.Count == 0)
@ -22,20 +25,20 @@ public class ModSettingApplier(PenumbraService penumbra, Configuration config, O
return; return;
} }
var collections = new HashSet<Guid>(); _collectionTracker.Clear();
foreach (var actor in data.Objects) foreach (var actor in data.Objects)
{ {
var (collection, _, overridden) = overrides.GetCollection(actor, state.Identifier); var (collection, _, overridden) = overrides.GetCollection(actor, state.Identifier);
if (collection == Guid.Empty) if (collection == Guid.Empty)
continue; continue;
if (!collections.Add(collection)) if (!_collectionTracker.Add(collection))
continue; continue;
var index = ResetOldSettings(collection, actor, design.ResetTemporarySettings);
foreach (var (mod, setting) in design.AssociatedMods) foreach (var (mod, setting) in design.AssociatedMods)
{ {
var message = penumbra.SetMod(mod, setting, collection); var message = penumbra.SetMod(mod, setting, 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
@ -45,7 +48,8 @@ public class ModSettingApplier(PenumbraService penumbra, Configuration config, O
} }
} }
public (List<string> Messages, int Applied, Guid Collection, string Name, bool Overridden) ApplyModSettings(IReadOnlyDictionary<Mod, ModSettings> settings, Actor actor) public (List<string> Messages, int Applied, Guid Collection, string Name, bool Overridden) ApplyModSettings(
IReadOnlyDictionary<Mod, ModSettings> settings, Actor actor, bool resetOther)
{ {
var (collection, name, overridden) = overrides.GetCollection(actor); var (collection, name, overridden) = overrides.GetCollection(actor);
if (collection == Guid.Empty) if (collection == Guid.Empty)
@ -53,9 +57,11 @@ public class ModSettingApplier(PenumbraService penumbra, Configuration config, O
var messages = new List<string>(); var messages = new List<string>();
var appliedMods = 0; var appliedMods = 0;
var index = ResetOldSettings(collection, actor, resetOther);
foreach (var (mod, setting) in settings) foreach (var (mod, setting) in settings)
{ {
var message = penumbra.SetMod(mod, setting, collection); var message = penumbra.SetMod(mod, setting, 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
@ -64,4 +70,18 @@ public class ModSettingApplier(PenumbraService penumbra, Configuration config, O
return (messages, appliedMods, collection, name, overridden); return (messages, appliedMods, collection, name, overridden);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private ObjectIndex? ResetOldSettings(Guid collection, Actor actor, bool resetOther)
{
ObjectIndex? index = actor.Valid ? actor.Index : null;
if (!resetOther)
return index;
if (index == null)
penumbra.RemoveAllTemporarySettings(collection);
else
penumbra.RemoveAllTemporarySettings(index.Value);
return index;
}
} }

View file

@ -21,10 +21,10 @@ public readonly record struct Mod(string Name, string DirectoryName) : IComparab
} }
} }
public readonly record struct ModSettings(Dictionary<string, List<string>> Settings, int Priority, bool Enabled) public readonly record struct ModSettings(Dictionary<string, List<string>> Settings, int Priority, bool Enabled, bool ForceInherit, bool Remove)
{ {
public ModSettings() public ModSettings()
: this(new Dictionary<string, List<string>>(), 0, false) : this(new Dictionary<string, List<string>>(), 0, false, false, false)
{ } { }
public static ModSettings Empty public static ModSettings Empty
@ -34,9 +34,13 @@ public readonly record struct ModSettings(Dictionary<string, List<string>> Setti
public class PenumbraService : IDisposable public class PenumbraService : IDisposable
{ {
public const int RequiredPenumbraBreakingVersion = 5; public const int RequiredPenumbraBreakingVersion = 5;
public const int RequiredPenumbraFeatureVersion = 0; public const int RequiredPenumbraFeatureVersion = 3;
public const int RequiredPenumbraFeatureVersionTemp = 4;
private const int Key = -1610;
private readonly IDalamudPluginInterface _pluginInterface; private readonly IDalamudPluginInterface _pluginInterface;
private readonly Configuration _config;
private readonly EventSubscriber<ChangedItemType, uint> _tooltipSubscriber; private readonly EventSubscriber<ChangedItemType, uint> _tooltipSubscriber;
private readonly EventSubscriber<MouseButton, ChangedItemType, uint> _clickSubscriber; private readonly EventSubscriber<MouseButton, ChangedItemType, uint> _clickSubscriber;
private readonly EventSubscriber<nint, Guid, nint, nint, nint> _creatingCharacterBase; private readonly EventSubscriber<nint, Guid, nint, nint, nint> _creatingCharacterBase;
@ -52,10 +56,17 @@ public class PenumbraService : IDisposable
private global::Penumbra.Api.IpcSubscribers.GetModList? _getMods; private global::Penumbra.Api.IpcSubscribers.GetModList? _getMods;
private global::Penumbra.Api.IpcSubscribers.GetCollection? _currentCollection; private global::Penumbra.Api.IpcSubscribers.GetCollection? _currentCollection;
private global::Penumbra.Api.IpcSubscribers.GetCurrentModSettings? _getCurrentSettings; private global::Penumbra.Api.IpcSubscribers.GetCurrentModSettings? _getCurrentSettings;
private global::Penumbra.Api.IpcSubscribers.TryInheritMod? _inheritMod;
private global::Penumbra.Api.IpcSubscribers.TrySetMod? _setMod; private global::Penumbra.Api.IpcSubscribers.TrySetMod? _setMod;
private global::Penumbra.Api.IpcSubscribers.TrySetModPriority? _setModPriority; private global::Penumbra.Api.IpcSubscribers.TrySetModPriority? _setModPriority;
private global::Penumbra.Api.IpcSubscribers.TrySetModSetting? _setModSetting; private global::Penumbra.Api.IpcSubscribers.TrySetModSetting? _setModSetting;
private global::Penumbra.Api.IpcSubscribers.TrySetModSettings? _setModSettings; private global::Penumbra.Api.IpcSubscribers.TrySetModSettings? _setModSettings;
private global::Penumbra.Api.IpcSubscribers.SetTemporaryModSettings? _setTemporaryModSettings;
private global::Penumbra.Api.IpcSubscribers.SetTemporaryModSettingsPlayer? _setTemporaryModSettingsPlayer;
private global::Penumbra.Api.IpcSubscribers.RemoveTemporaryModSettings? _removeTemporaryModSettings;
private global::Penumbra.Api.IpcSubscribers.RemoveTemporaryModSettingsPlayer? _removeTemporaryModSettingsPlayer;
private global::Penumbra.Api.IpcSubscribers.RemoveAllTemporaryModSettings? _removeAllTemporaryModSettings;
private global::Penumbra.Api.IpcSubscribers.RemoveAllTemporaryModSettingsPlayer? _removeAllTemporaryModSettingsPlayer;
private global::Penumbra.Api.IpcSubscribers.OpenMainWindow? _openModPage; private global::Penumbra.Api.IpcSubscribers.OpenMainWindow? _openModPage;
private readonly IDisposable _initializedEvent; private readonly IDisposable _initializedEvent;
@ -68,10 +79,11 @@ public class PenumbraService : IDisposable
public int CurrentMinor { get; private set; } public int CurrentMinor { get; private set; }
public DateTime AttachTime { get; private set; } public DateTime AttachTime { get; private set; }
public PenumbraService(IDalamudPluginInterface pi, PenumbraReloaded penumbraReloaded) public PenumbraService(IDalamudPluginInterface pi, PenumbraReloaded penumbraReloaded, Configuration config)
{ {
_pluginInterface = pi; _pluginInterface = pi;
_penumbraReloaded = penumbraReloaded; _penumbraReloaded = penumbraReloaded;
_config = config;
_initializedEvent = global::Penumbra.Api.IpcSubscribers.Initialized.Subscriber(pi, Reattach); _initializedEvent = global::Penumbra.Api.IpcSubscribers.Initialized.Subscriber(pi, Reattach);
_disposedEvent = global::Penumbra.Api.IpcSubscribers.Disposed.Subscriber(pi, Unattach); _disposedEvent = global::Penumbra.Api.IpcSubscribers.Disposed.Subscriber(pi, Unattach);
_tooltipSubscriber = global::Penumbra.Api.IpcSubscribers.ChangedItemTooltip.Subscriber(pi); _tooltipSubscriber = global::Penumbra.Api.IpcSubscribers.ChangedItemTooltip.Subscriber(pi);
@ -128,7 +140,7 @@ public class PenumbraService : IDisposable
if (ec is not PenumbraApiEc.Success) if (ec is not PenumbraApiEc.Success)
return ModSettings.Empty; return ModSettings.Empty;
return tuple.HasValue ? new ModSettings(tuple.Value.Item3, tuple.Value.Item2, tuple.Value.Item1) : ModSettings.Empty; return tuple.HasValue ? new ModSettings(tuple.Value.Item3, tuple.Value.Item2, tuple.Value.Item1, false, false) : ModSettings.Empty;
} }
catch (Exception ex) catch (Exception ex)
{ {
@ -164,7 +176,7 @@ public class PenumbraService : IDisposable
.Select(t => (new Mod(t.Item2, t.Item1), .Select(t => (new Mod(t.Item2, t.Item1),
!t.Item3.Item2.HasValue !t.Item3.Item2.HasValue
? ModSettings.Empty ? ModSettings.Empty
: new ModSettings(t.Item3.Item2!.Value.Item3, t.Item3.Item2!.Value.Item2, t.Item3.Item2!.Value.Item1))) : new ModSettings(t.Item3.Item2!.Value.Item3, t.Item3.Item2!.Value.Item2, t.Item3.Item2!.Value.Item1, false, false)))
.OrderByDescending(p => p.Item2.Enabled) .OrderByDescending(p => p.Item2.Enabled)
.ThenBy(p => p.Item1.Name) .ThenBy(p => p.Item1.Name)
.ThenBy(p => p.Item1.DirectoryName) .ThenBy(p => p.Item1.DirectoryName)
@ -195,7 +207,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) public string SetMod(Mod mod, ModSettings settings, Guid? collectionInput = null, ObjectIndex? index = null)
{ {
if (!Available) if (!Available)
return "Penumbra is not available."; return "Penumbra is not available.";
@ -204,15 +216,88 @@ public class PenumbraService : IDisposable
try try
{ {
var collection = collectionInput ?? _currentCollection!.Invoke(ApiCollectionType.Current)!.Value.Id; var collection = collectionInput ?? _currentCollection!.Invoke(ApiCollectionType.Current)!.Value.Id;
var ec = _setMod!.Invoke(collection, mod.DirectoryName, settings.Enabled); if (_config.UseTemporarySettings && _setTemporaryModSettings != null)
switch (ec) SetModTemporary(sb, mod, settings, collection, index);
else
SetModPermanent(sb, mod, settings, collection);
return sb.ToString();
}
catch (Exception ex)
{ {
case PenumbraApiEc.ModMissing: return $"The mod {mod.Name} [{mod.DirectoryName}] could not be found."; return sb.AppendLine(ex.Message).ToString();
case PenumbraApiEc.CollectionMissing: return $"The collection {collection} could not be found."; }
} }
if (!settings.Enabled) public void RemoveAllTemporarySettings(Guid collection)
return string.Empty; => _removeAllTemporaryModSettings?.Invoke(collection, Key);
public void RemoveAllTemporarySettings(ObjectIndex index)
=> _removeAllTemporaryModSettingsPlayer?.Invoke(index.Index, Key);
public void ClearAllTemporarySettings()
{
if (!Available || _removeAllTemporaryModSettings == null)
return;
var collections = _collections!.Invoke();
foreach (var collection in collections)
RemoveAllTemporarySettings(collection.Key);
}
private void SetModTemporary(StringBuilder sb, Mod mod, ModSettings settings, Guid collection, ObjectIndex? index)
{
var ex = settings.Remove
? index.HasValue
? _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<string>)kvp.Value), "Glamourer", Key)
: _setTemporaryModSettings!.Invoke(collection, mod.DirectoryName, settings.ForceInherit, settings.Enabled, settings.Priority,
settings.Settings.ToDictionary(kvp => kvp.Key, kvp => (IReadOnlyList<string>)kvp.Value), "Glamourer", Key);
switch (ex)
{
case PenumbraApiEc.InvalidArgument:
sb.Append($"No actor with index {index!.Value.Index} could be identified.");
return;
case PenumbraApiEc.ModMissing:
sb.Append($"The mod {mod.Name} [{mod.DirectoryName}] could not be found.");
return;
case PenumbraApiEc.CollectionMissing:
sb.Append($"The collection {collection} could not be found.");
return;
case PenumbraApiEc.TemporarySettingImpossible:
sb.Append($"The collection {collection} can not have settings.");
return;
case PenumbraApiEc.TemporarySettingDisallowed:
sb.Append($"The mod {mod.Name} [{mod.DirectoryName}] already has temporary settings with a different key in {collection}.");
return;
case PenumbraApiEc.OptionGroupMissing:
case PenumbraApiEc.OptionMissing:
sb.Append($"The provided settings for {mod.Name} [{mod.DirectoryName}] did not correspond to its actual options.");
return;
}
}
private void SetModPermanent(StringBuilder sb, Mod mod, ModSettings settings, Guid collection)
{
var ec = settings.ForceInherit
? _inheritMod!.Invoke(collection, mod.DirectoryName, true)
: _setMod!.Invoke(collection, mod.DirectoryName, settings.Enabled);
switch (ec)
{
case PenumbraApiEc.ModMissing:
sb.Append($"The mod {mod.Name} [{mod.DirectoryName}] could not be found.");
return;
case PenumbraApiEc.CollectionMissing:
sb.Append($"The collection {collection} could not be found.");
return;
}
if (settings.ForceInherit || !settings.Enabled)
return;
ec = _setModPriority!.Invoke(collection, mod.DirectoryName, settings.Priority); ec = _setModPriority!.Invoke(collection, mod.DirectoryName, settings.Priority);
Debug.Assert(ec is PenumbraApiEc.Success or PenumbraApiEc.NothingChanged, "Setting Priority should not be able to fail."); Debug.Assert(ec is PenumbraApiEc.Success or PenumbraApiEc.NothingChanged, "Setting Priority should not be able to fail.");
@ -238,14 +323,8 @@ public class PenumbraService : IDisposable
break; break;
} }
} }
}
return sb.ToString();
}
catch (Exception ex)
{
return sb.AppendLine(ex.Message).ToString();
}
}
/// <summary> Obtain the name of the collection currently assigned to the player. </summary> /// <summary> Obtain the name of the collection currently assigned to the player. </summary>
public Guid GetCurrentPlayerCollection() public Guid GetCurrentPlayerCollection()
@ -347,11 +426,23 @@ public class PenumbraService : IDisposable
_getMods = new global::Penumbra.Api.IpcSubscribers.GetModList(_pluginInterface); _getMods = new global::Penumbra.Api.IpcSubscribers.GetModList(_pluginInterface);
_currentCollection = new global::Penumbra.Api.IpcSubscribers.GetCollection(_pluginInterface); _currentCollection = new global::Penumbra.Api.IpcSubscribers.GetCollection(_pluginInterface);
_getCurrentSettings = new global::Penumbra.Api.IpcSubscribers.GetCurrentModSettings(_pluginInterface); _getCurrentSettings = new global::Penumbra.Api.IpcSubscribers.GetCurrentModSettings(_pluginInterface);
_inheritMod = new global::Penumbra.Api.IpcSubscribers.TryInheritMod(_pluginInterface);
_setMod = new global::Penumbra.Api.IpcSubscribers.TrySetMod(_pluginInterface); _setMod = new global::Penumbra.Api.IpcSubscribers.TrySetMod(_pluginInterface);
_setModPriority = new global::Penumbra.Api.IpcSubscribers.TrySetModPriority(_pluginInterface); _setModPriority = new global::Penumbra.Api.IpcSubscribers.TrySetModPriority(_pluginInterface);
_setModSetting = new global::Penumbra.Api.IpcSubscribers.TrySetModSetting(_pluginInterface); _setModSetting = new global::Penumbra.Api.IpcSubscribers.TrySetModSetting(_pluginInterface);
_setModSettings = new global::Penumbra.Api.IpcSubscribers.TrySetModSettings(_pluginInterface); _setModSettings = new global::Penumbra.Api.IpcSubscribers.TrySetModSettings(_pluginInterface);
_openModPage = new global::Penumbra.Api.IpcSubscribers.OpenMainWindow(_pluginInterface); _openModPage = new global::Penumbra.Api.IpcSubscribers.OpenMainWindow(_pluginInterface);
if (CurrentMinor >= RequiredPenumbraFeatureVersionTemp)
{
_setTemporaryModSettings = new global::Penumbra.Api.IpcSubscribers.SetTemporaryModSettings(_pluginInterface);
_setTemporaryModSettingsPlayer = new global::Penumbra.Api.IpcSubscribers.SetTemporaryModSettingsPlayer(_pluginInterface);
_removeTemporaryModSettings = new global::Penumbra.Api.IpcSubscribers.RemoveTemporaryModSettings(_pluginInterface);
_removeTemporaryModSettingsPlayer = new global::Penumbra.Api.IpcSubscribers.RemoveTemporaryModSettingsPlayer(_pluginInterface);
_removeAllTemporaryModSettings = new global::Penumbra.Api.IpcSubscribers.RemoveAllTemporaryModSettings(_pluginInterface);
_removeAllTemporaryModSettingsPlayer =
new global::Penumbra.Api.IpcSubscribers.RemoveAllTemporaryModSettingsPlayer(_pluginInterface);
}
Available = true; Available = true;
_penumbraReloaded.Invoke(); _penumbraReloaded.Invoke();
Glamourer.Log.Debug("Glamourer attached to Penumbra."); Glamourer.Log.Debug("Glamourer attached to Penumbra.");
@ -382,11 +473,18 @@ public class PenumbraService : IDisposable
_getMods = null; _getMods = null;
_currentCollection = null; _currentCollection = null;
_getCurrentSettings = null; _getCurrentSettings = null;
_inheritMod = null;
_setMod = null; _setMod = null;
_setModPriority = null; _setModPriority = null;
_setModSetting = null; _setModSetting = null;
_setModSettings = null; _setModSettings = null;
_openModPage = null; _openModPage = null;
_setTemporaryModSettings = null;
_setTemporaryModSettingsPlayer = null;
_removeTemporaryModSettings = null;
_removeTemporaryModSettingsPlayer = null;
_removeAllTemporaryModSettings = null;
_removeAllTemporaryModSettingsPlayer = null;
Available = false; Available = false;
Glamourer.Log.Debug("Glamourer detached from Penumbra."); Glamourer.Log.Debug("Glamourer detached from Penumbra.");
} }
@ -394,6 +492,7 @@ public class PenumbraService : IDisposable
public void Dispose() public void Dispose()
{ {
ClearAllTemporarySettings();
Unattach(); Unattach();
_tooltipSubscriber.Dispose(); _tooltipSubscriber.Dispose();
_clickSubscriber.Dispose(); _clickSubscriber.Dispose();

View file

@ -691,7 +691,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); var (messages, appliedMods, _, name, overridden) = _modApplier.ApplyModSettings(d.AssociatedMods, actor, 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}");

@ -1 +1 @@
Subproject commit 882b778e78bb0806dd7d38e8b3670ff138a84a31 Subproject commit de0f281fbf9d8d9d3aa8463a28025d54877cde8d