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))
.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)
mergedDesign.ResetTemporarySettings = true;
_state.ApplyDesign(state, mergedDesign, new ApplySettings(0, StateSource.Fixed, respectManual, fromJobChange, false, false, false));
forcedRedraw = mergedDesign.ForcedRedraw;

View file

@ -444,8 +444,9 @@ public class AutoDesignManager : ISavable, IReadOnlyList<AutoDesignSet>, IDispos
var set = new AutoDesignSet(name, group)
{
Enabled = obj["Enabled"]?.ToObject<bool>() ?? false,
BaseState = obj["BaseState"]?.ToObject<AutoDesignSet.Base>() ?? AutoDesignSet.Base.Current,
Enabled = obj["Enabled"]?.ToObject<bool>() ?? false,
ResetTemporarySettings = obj["ResetTemporarySettings"]?.ToObject<bool>() ?? false,
BaseState = obj["BaseState"]?.ToObject<AutoDesignSet.Base>() ?? AutoDesignSet.Base.Current,
};
if (set.Enabled)
@ -602,9 +603,9 @@ public class AutoDesignManager : ISavable, IReadOnlyList<AutoDesignSet>, IDispos
? ActorIdentifier.RetainerType.Mannequin
: ActorIdentifier.RetainerType.Bell).CreatePermanent(),
],
IdentifierType.Npc => CreateNpcs(_actors, identifier),
IdentifierType.Npc => CreateNpcs(_actors, identifier),
IdentifierType.Owned => CreateNpcs(_actors, identifier),
_ => [],
_ => [],
};
static ActorIdentifier[] CreateNpcs(ActorManager manager, ActorIdentifier identifier)

View file

@ -10,7 +10,8 @@ public class AutoDesignSet(string name, ActorIdentifier[] identifiers, List<Auto
public string Name = name;
public ActorIdentifier[] Identifiers = identifiers;
public bool Enabled;
public Base BaseState = Base.Current;
public Base BaseState = Base.Current;
public bool ResetTemporarySettings = false;
public JObject Serialize()
{
@ -20,11 +21,12 @@ public class AutoDesignSet(string name, ActorIdentifier[] identifiers, List<Auto
return new JObject()
{
["Name"] = Name,
["Identifier"] = Identifiers[0].ToJson(),
["Enabled"] = Enabled,
["BaseState"] = BaseState.ToString(),
["Designs"] = list,
["Name"] = Name,
["Identifier"] = Identifiers[0].ToJson(),
["Enabled"] = Enabled,
["BaseState"] = BaseState.ToString(),
["ResetTemporarySettings"] = ResetTemporarySettings.ToString(),
["Designs"] = list,
};
}

View file

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

View file

@ -28,32 +28,34 @@ public sealed class Design : DesignBase, ISavable, IDesignStandIn
internal Design(Design other)
: base(other)
{
Tags = [.. other.Tags];
Description = other.Description;
QuickDesign = other.QuickDesign;
ForcedRedraw = other.ForcedRedraw;
ResetAdvancedDyes = other.ResetAdvancedDyes;
Color = other.Color;
AssociatedMods = new SortedList<Mod, ModSettings>(other.AssociatedMods);
Links = Links.Clone();
Tags = [.. other.Tags];
Description = other.Description;
QuickDesign = other.QuickDesign;
ForcedRedraw = other.ForcedRedraw;
ResetAdvancedDyes = other.ResetAdvancedDyes;
ResetTemporarySettings = other.ResetTemporarySettings;
Color = other.Color;
AssociatedMods = new SortedList<Mod, ModSettings>(other.AssociatedMods);
Links = Links.Clone();
}
// Metadata
public new const int FileVersion = 2;
public Guid Identifier { get; internal init; }
public DateTimeOffset CreationDate { get; internal init; }
public DateTimeOffset LastEdit { get; internal set; }
public LowerString Name { get; internal set; } = LowerString.Empty;
public string Description { get; internal set; } = string.Empty;
public string[] Tags { get; internal set; } = [];
public int Index { get; internal set; }
public bool ForcedRedraw { get; internal set; }
public bool ResetAdvancedDyes { get; internal set; }
public bool QuickDesign { get; internal set; } = true;
public string Color { get; internal set; } = string.Empty;
public SortedList<Mod, ModSettings> AssociatedMods { get; private set; } = [];
public LinkContainer Links { get; private set; } = [];
public Guid Identifier { get; internal init; }
public DateTimeOffset CreationDate { get; internal init; }
public DateTimeOffset LastEdit { get; internal set; }
public LowerString Name { get; internal set; } = LowerString.Empty;
public string Description { get; internal set; } = string.Empty;
public string[] Tags { get; internal set; } = [];
public int Index { get; internal set; }
public bool ForcedRedraw { get; internal set; }
public bool ResetAdvancedDyes { get; internal set; }
public bool ResetTemporarySettings { get; internal set; }
public bool QuickDesign { get; internal set; } = true;
public string Color { get; internal set; } = string.Empty;
public SortedList<Mod, ModSettings> AssociatedMods { get; private set; } = [];
public LinkContainer Links { get; private set; } = [];
public string Incognito
=> Identifier.ToString()[..8];
@ -100,25 +102,26 @@ public sealed class Design : DesignBase, ISavable, IDesignStandIn
{
var ret = new JObject()
{
["FileVersion"] = FileVersion,
["Identifier"] = Identifier,
["CreationDate"] = CreationDate,
["LastEdit"] = LastEdit,
["Name"] = Name.Text,
["Description"] = Description,
["ForcedRedraw"] = ForcedRedraw,
["ResetAdvancedDyes"] = ResetAdvancedDyes,
["Color"] = Color,
["QuickDesign"] = QuickDesign,
["Tags"] = JArray.FromObject(Tags),
["WriteProtected"] = WriteProtected(),
["Equipment"] = SerializeEquipment(),
["Bonus"] = SerializeBonusItems(),
["Customize"] = SerializeCustomize(),
["Parameters"] = SerializeParameters(),
["Materials"] = SerializeMaterials(),
["Mods"] = SerializeMods(),
["Links"] = Links.Serialize(),
["FileVersion"] = FileVersion,
["Identifier"] = Identifier,
["CreationDate"] = CreationDate,
["LastEdit"] = LastEdit,
["Name"] = Name.Text,
["Description"] = Description,
["ForcedRedraw"] = ForcedRedraw,
["ResetAdvancedDyes"] = ResetAdvancedDyes,
["ResetTemporarySettings"] = ResetTemporarySettings,
["Color"] = Color,
["QuickDesign"] = QuickDesign,
["Tags"] = JArray.FromObject(Tags),
["WriteProtected"] = WriteProtected(),
["Equipment"] = SerializeEquipment(),
["Bonus"] = SerializeBonusItems(),
["Customize"] = SerializeCustomize(),
["Parameters"] = SerializeParameters(),
["Materials"] = SerializeMaterials(),
["Mods"] = SerializeMods(),
["Links"] = Links.Serialize(),
};
return ret;
}
@ -250,9 +253,10 @@ public sealed class Design : DesignBase, ISavable, IDesignStandIn
LoadParameters(json["Parameters"], design, design.Name);
LoadMaterials(json["Materials"], design, design.Name);
LoadLinks(linkLoader, json["Links"], design);
design.Color = json["Color"]?.ToObject<string>() ?? string.Empty;
design.ForcedRedraw = json["ForcedRedraw"]?.ToObject<bool>() ?? false;
design.ResetAdvancedDyes = json["ResetAdvancedDyes"]?.ToObject<bool>() ?? false;
design.Color = json["Color"]?.ToObject<string>() ?? string.Empty;
design.ForcedRedraw = json["ForcedRedraw"]?.ToObject<bool>() ?? false;
design.ResetAdvancedDyes = json["ResetAdvancedDyes"]?.ToObject<bool>() ?? false;
design.ResetTemporarySettings = json["ResetTemporarySettings"]?.ToObject<bool>() ?? false;
return design;
static string[] ParseTags(JObject json)
@ -278,12 +282,15 @@ public sealed class Design : DesignBase, ISavable, IDesignStandIn
continue;
}
var settingsDict = tok["Settings"]?.ToObject<Dictionary<string, List<string>>>() ?? [];
var settings = new Dictionary<string, List<string>>(settingsDict.Count);
var forceInherit = tok["Inherit"]?.ToObject<bool>() ?? false;
var removeSetting = tok["Remove"]?.ToObject<bool>() ?? false;
var settingsDict = tok["Settings"]?.ToObject<Dictionary<string, List<string>>>() ?? [];
var settings = new Dictionary<string, List<string>>(settingsDict.Count);
foreach (var (key, value) in settingsDict)
settings.Add(key, value);
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);
}
}

View file

@ -99,14 +99,15 @@ public sealed class DesignManager : DesignEditor
var (actualName, path) = ParseName(name, handlePath);
var design = new Design(Customizations, Items)
{
CreationDate = DateTimeOffset.UtcNow,
LastEdit = DateTimeOffset.UtcNow,
Identifier = CreateNewGuid(),
Name = actualName,
Index = Designs.Count,
ForcedRedraw = Config.DefaultDesignSettings.AlwaysForceRedrawing,
ResetAdvancedDyes = Config.DefaultDesignSettings.ResetAdvancedDyes,
QuickDesign = Config.DefaultDesignSettings.ShowQuickDesignBar,
CreationDate = DateTimeOffset.UtcNow,
LastEdit = DateTimeOffset.UtcNow,
Identifier = CreateNewGuid(),
Name = actualName,
Index = Designs.Count,
ForcedRedraw = Config.DefaultDesignSettings.AlwaysForceRedrawing,
ResetAdvancedDyes = Config.DefaultDesignSettings.ResetAdvancedDyes,
QuickDesign = Config.DefaultDesignSettings.ShowQuickDesignBar,
ResetTemporarySettings = Config.DefaultDesignSettings.ResetTemporarySettings,
};
Designs.Add(design);
Glamourer.Log.Debug($"Added new design {design.Identifier}.");
@ -121,14 +122,15 @@ public sealed class DesignManager : DesignEditor
var (actualName, path) = ParseName(name, handlePath);
var design = new Design(clone)
{
CreationDate = DateTimeOffset.UtcNow,
LastEdit = DateTimeOffset.UtcNow,
Identifier = CreateNewGuid(),
Name = actualName,
Index = Designs.Count,
ForcedRedraw = Config.DefaultDesignSettings.AlwaysForceRedrawing,
ResetAdvancedDyes = Config.DefaultDesignSettings.ResetAdvancedDyes,
QuickDesign = Config.DefaultDesignSettings.ShowQuickDesignBar,
CreationDate = DateTimeOffset.UtcNow,
LastEdit = DateTimeOffset.UtcNow,
Identifier = CreateNewGuid(),
Name = actualName,
Index = Designs.Count,
ForcedRedraw = Config.DefaultDesignSettings.AlwaysForceRedrawing,
ResetAdvancedDyes = Config.DefaultDesignSettings.ResetAdvancedDyes,
QuickDesign = Config.DefaultDesignSettings.ShowQuickDesignBar,
ResetTemporarySettings = Config.DefaultDesignSettings.ResetTemporarySettings,
};
Designs.Add(design);
@ -144,11 +146,11 @@ public sealed class DesignManager : DesignEditor
var (actualName, path) = ParseName(name, handlePath);
var design = new Design(clone)
{
CreationDate = DateTimeOffset.UtcNow,
LastEdit = DateTimeOffset.UtcNow,
Identifier = CreateNewGuid(),
Name = actualName,
Index = Designs.Count,
CreationDate = DateTimeOffset.UtcNow,
LastEdit = DateTimeOffset.UtcNow,
Identifier = CreateNewGuid(),
Name = actualName,
Index = Designs.Count,
};
Designs.Add(design);
Glamourer.Log.Debug(
@ -351,6 +353,17 @@ public sealed class DesignManager : DesignEditor
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>
public void ChangeApplyCustomize(Design design, CustomizeIndex idx, bool value)
{

View file

@ -26,5 +26,6 @@ public interface IDesignStandIn : IEquatable<IDesignStandIn>
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;
if (design.ResetAdvancedDyes)
ret.ResetAdvancedDyes = true;
if (design.ResetTemporarySettings)
ret.ResetTemporarySettings = true;
}
ApplyFixFlags(ret, fixFlags);

View file

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

View file

@ -56,4 +56,7 @@ public class QuickSelectedDesign(QuickDesignCombo combo) : IDesignStandIn, IServ
public bool ResetAdvancedDyes
=> 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
=> false;
=> _currentDesign?.ForcedRedraw ?? false;
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
=> 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>
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>
ApplyCustomize,

View file

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

View file

@ -6,6 +6,7 @@ using ImGuiNET;
using OtterGui;
using OtterGui.Classes;
using OtterGui.Raii;
using OtterGui.Text;
using OtterGui.Widgets;
namespace Glamourer.Gui.Tabs.DesignTab;
@ -41,7 +42,7 @@ public class DesignDetailTab
public void Draw()
{
using var h = ImRaii.CollapsingHeader("Design Details");
using var h = ImUtf8.CollapsingHeaderId("Design Details"u8);
if (!h)
return;
@ -54,19 +55,19 @@ public class DesignDetailTab
private void DrawDesignInfoTable()
{
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)
return;
ImGui.TableSetupColumn("Type", ImGuiTableColumnFlags.WidthFixed, ImGui.CalcTextSize("Reset Advanced Dyes").X);
ImGui.TableSetupColumn("Data", ImGuiTableColumnFlags.WidthStretch);
ImUtf8.TableSetupColumn("Type"u8, ImGuiTableColumnFlags.WidthFixed, ImUtf8.CalcTextSize("Reset Temporary Settings"u8).X);
ImUtf8.TableSetupColumn("Data"u8, ImGuiTableColumnFlags.WidthStretch);
ImGuiUtil.DrawFrameColumn("Design Name");
ImUtf8.DrawFrameColumn("Design Name"u8);
ImGui.TableNextColumn();
var width = new Vector2(ImGui.GetContentRegionAvail().X, 0);
var name = _newName ?? _selector.Selected!.Name;
ImGui.SetNextItemWidth(width.X);
if (ImGui.InputText("##Name", ref name, 128))
if (ImUtf8.InputText("##Name"u8, ref name))
{
_newName = name;
_changeDesign = _selector.Selected;
@ -80,10 +81,10 @@ public class DesignDetailTab
}
var identifier = _selector.Selected!.Identifier.ToString();
ImGuiUtil.DrawFrameColumn("Unique Identifier");
ImUtf8.DrawFrameColumn("Unique Identifier"u8);
ImGui.TableNextColumn();
var fileName = _saveService.FileNames.DesignFile(_selector.Selected!);
using (var mono = ImRaii.PushFont(UiBuilder.MonoFont))
using (ImRaii.PushFont(UiBuilder.MonoFont))
{
if (ImGui.Button(identifier, width))
try
@ -100,14 +101,14 @@ public class DesignDetailTab
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.");
ImGuiUtil.DrawFrameColumn("Full Selector Path");
ImUtf8.DrawFrameColumn("Full Selector Path"u8);
ImGui.TableNextColumn();
var path = _newPath ?? _selector.SelectedLeaf!.FullName();
ImGui.SetNextItemWidth(width.X);
if (ImGui.InputText("##Path", ref path, 1024))
if (ImUtf8.InputText("##Path"u8, ref path))
{
_newPath = path;
_changeLeaf = _selector.SelectedLeaf!;
@ -125,32 +126,42 @@ public class DesignDetailTab
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();
if (ImGui.RadioButton("Display##qdb", _selector.Selected.QuickDesign))
if (ImUtf8.RadioButton("Display##qdb"u8, _selector.Selected.QuickDesign))
_manager.SetQuickDesign(_selector.Selected!, true);
var hovered = ImGui.IsItemHovered();
ImGui.SameLine();
if (ImGui.RadioButton("Hide##qdb", !_selector.Selected.QuickDesign))
if (ImUtf8.RadioButton("Hide##qdb"u8, !_selector.Selected.QuickDesign))
_manager.SetQuickDesign(_selector.Selected!, false);
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;
ImGuiUtil.DrawFrameColumn("Force Redrawing");
ImUtf8.DrawFrameColumn("Force Redrawing"u8);
ImGui.TableNextColumn();
if (ImGui.Checkbox("##ForceRedraw", ref forceRedraw))
if (ImUtf8.Checkbox("##ForceRedraw"u8, ref 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;
ImGuiUtil.DrawFrameColumn("Reset Advanced Dyes");
ImUtf8.DrawFrameColumn("Reset Advanced Dyes"u8);
ImGui.TableNextColumn();
if (ImGui.Checkbox("##ResetAdvancedDyes", ref resetAdvancedDyes))
if (ImUtf8.Checkbox("##ResetAdvancedDyes"u8, ref 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;
ImGui.TableNextColumn();
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());
using var font = ImRaii.PushFont(UiBuilder.IconFont);
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();
ImGuiUtil.DrawTextButton(_selector.Selected!.CreationDate.LocalDateTime.ToString("F"), width, 0);
ImGuiUtil.DrawFrameColumn("Last Update Date");
ImUtf8.DrawFrameColumn("Last Update Date"u8);
ImGui.TableNextColumn();
ImGuiUtil.DrawTextButton(_selector.Selected!.LastEdit.LocalDateTime.ToString("F"), width, 0);
ImGuiUtil.DrawFrameColumn("Tags");
ImUtf8.DrawFrameColumn("Tags"u8);
ImGui.TableNextColumn();
DrawTags();
}
@ -219,18 +230,18 @@ public class DesignDetailTab
var size = new Vector2(ImGui.GetContentRegionAvail().X, 12 * ImGui.GetTextLineHeightWithSpacing());
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;
}
else
{
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;
if (ImGui.IsItemDeactivatedAfterEdit())
@ -239,7 +250,7 @@ public class DesignDetailTab
_newDescription = null;
}
if (ImGui.Button("Stop Editing"))
if (ImUtf8.Button("Stop Editing"u8))
_editDescriptionMode = false;
}
}

View file

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

View file

@ -88,16 +88,18 @@ public class ModAssociationsTab(PenumbraService penumbra, DesignFileSystemSelect
private void DrawTable()
{
using var table = ImRaii.Table("Mods", 5, ImGuiTableFlags.RowBg);
using var table = ImUtf8.Table("Mods"u8, 7, ImGuiTableFlags.RowBg);
if (!table)
return;
ImGui.TableSetupColumn("##Buttons", ImGuiTableColumnFlags.WidthFixed,
ImUtf8.TableSetupColumn("##Buttons"u8, ImGuiTableColumnFlags.WidthFixed,
ImGui.GetFrameHeight() * 3 + ImGui.GetStyle().ItemInnerSpacing.X * 2);
ImGui.TableSetupColumn("Mod Name", ImGuiTableColumnFlags.WidthStretch);
ImGui.TableSetupColumn("State", ImGuiTableColumnFlags.WidthFixed, ImGui.CalcTextSize("State").X);
ImGui.TableSetupColumn("Priority", ImGuiTableColumnFlags.WidthFixed, ImGui.CalcTextSize("Priority").X);
ImGui.TableSetupColumn("##Options", ImGuiTableColumnFlags.WidthFixed, ImGui.CalcTextSize("Applym").X);
ImUtf8.TableSetupColumn("Mod Name"u8, ImGuiTableColumnFlags.WidthStretch);
ImUtf8.TableSetupColumn("Remove"u8, ImGuiTableColumnFlags.WidthFixed, ImUtf8.CalcTextSize("Remove"u8).X);
ImUtf8.TableSetupColumn("Inherit"u8, ImGuiTableColumnFlags.WidthFixed, ImUtf8.CalcTextSize("Inherit"u8).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();
Mod? removedMod = null;
@ -183,6 +185,17 @@ public class ModAssociationsTab(PenumbraService penumbra, DesignFileSystemSelect
if (ImGui.IsItemHovered())
ImGui.SetTooltip($"Mod Directory: {mod.DirectoryName}\n\nClick to open mod page in Penumbra.");
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;
if (TwoStateCheckbox.Instance.Draw("##Enabled"u8, ref 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"
+ "If you enable this setting, you are aware that any resulting misconfiguration is your own fault.",
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();
}
@ -120,6 +123,8 @@ public class SettingsTab(
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.",
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()

View file

@ -3,12 +3,15 @@ using Glamourer.Services;
using Glamourer.State;
using OtterGui.Services;
using Penumbra.GameData.Interop;
using Penumbra.GameData.Structs;
namespace Glamourer.Interop.Penumbra;
public class ModSettingApplier(PenumbraService penumbra, Configuration config, ObjectManager objects, CollectionOverrideService overrides)
: IService
{
private readonly HashSet<Guid> _collectionTracker = [];
public void HandleStateApplication(ActorState state, MergedDesign design)
{
if (!config.AlwaysApplyAssociatedMods || design.AssociatedMods.Count == 0)
@ -22,20 +25,20 @@ public class ModSettingApplier(PenumbraService penumbra, Configuration config, O
return;
}
var collections = new HashSet<Guid>();
_collectionTracker.Clear();
foreach (var actor in data.Objects)
{
var (collection, _, overridden) = overrides.GetCollection(actor, state.Identifier);
if (collection == Guid.Empty)
continue;
if (!collections.Add(collection))
if (!_collectionTracker.Add(collection))
continue;
var index = ResetOldSettings(collection, actor, design.ResetTemporarySettings);
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)
Glamourer.Log.Verbose($"[Mod Applier] Error applying mod settings: {message}");
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);
if (collection == Guid.Empty)
@ -53,9 +57,11 @@ public class ModSettingApplier(PenumbraService penumbra, Configuration config, O
var messages = new List<string>();
var appliedMods = 0;
var index = ResetOldSettings(collection, actor, resetOther);
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)
messages.Add($"Error applying mod settings: {message}");
else
@ -64,4 +70,18 @@ public class ModSettingApplier(PenumbraService penumbra, Configuration config, O
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()
: this(new Dictionary<string, List<string>>(), 0, false)
: this(new Dictionary<string, List<string>>(), 0, false, false, false)
{ }
public static ModSettings Empty
@ -33,30 +33,41 @@ public readonly record struct ModSettings(Dictionary<string, List<string>> Setti
public class PenumbraService : IDisposable
{
public const int RequiredPenumbraBreakingVersion = 5;
public const int RequiredPenumbraFeatureVersion = 0;
public const int RequiredPenumbraBreakingVersion = 5;
public const int RequiredPenumbraFeatureVersion = 3;
public const int RequiredPenumbraFeatureVersionTemp = 4;
private readonly IDalamudPluginInterface _pluginInterface;
private const int Key = -1610;
private readonly IDalamudPluginInterface _pluginInterface;
private readonly Configuration _config;
private readonly EventSubscriber<ChangedItemType, uint> _tooltipSubscriber;
private readonly EventSubscriber<MouseButton, ChangedItemType, uint> _clickSubscriber;
private readonly EventSubscriber<nint, Guid, nint, nint, nint> _creatingCharacterBase;
private readonly EventSubscriber<nint, Guid, nint> _createdCharacterBase;
private readonly EventSubscriber<ModSettingChange, Guid, string, bool> _modSettingChanged;
private global::Penumbra.Api.IpcSubscribers.GetCollectionsByIdentifier? _collectionByIdentifier;
private global::Penumbra.Api.IpcSubscribers.GetCollections? _collections;
private global::Penumbra.Api.IpcSubscribers.RedrawObject? _redraw;
private global::Penumbra.Api.IpcSubscribers.GetDrawObjectInfo? _drawObjectInfo;
private global::Penumbra.Api.IpcSubscribers.GetCutsceneParentIndex? _cutsceneParent;
private global::Penumbra.Api.IpcSubscribers.GetCollectionForObject? _objectCollection;
private global::Penumbra.Api.IpcSubscribers.GetModList? _getMods;
private global::Penumbra.Api.IpcSubscribers.GetCollection? _currentCollection;
private global::Penumbra.Api.IpcSubscribers.GetCurrentModSettings? _getCurrentSettings;
private global::Penumbra.Api.IpcSubscribers.TrySetMod? _setMod;
private global::Penumbra.Api.IpcSubscribers.TrySetModPriority? _setModPriority;
private global::Penumbra.Api.IpcSubscribers.TrySetModSetting? _setModSetting;
private global::Penumbra.Api.IpcSubscribers.TrySetModSettings? _setModSettings;
private global::Penumbra.Api.IpcSubscribers.OpenMainWindow? _openModPage;
private global::Penumbra.Api.IpcSubscribers.GetCollectionsByIdentifier? _collectionByIdentifier;
private global::Penumbra.Api.IpcSubscribers.GetCollections? _collections;
private global::Penumbra.Api.IpcSubscribers.RedrawObject? _redraw;
private global::Penumbra.Api.IpcSubscribers.GetDrawObjectInfo? _drawObjectInfo;
private global::Penumbra.Api.IpcSubscribers.GetCutsceneParentIndex? _cutsceneParent;
private global::Penumbra.Api.IpcSubscribers.GetCollectionForObject? _objectCollection;
private global::Penumbra.Api.IpcSubscribers.GetModList? _getMods;
private global::Penumbra.Api.IpcSubscribers.GetCollection? _currentCollection;
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.TrySetModPriority? _setModPriority;
private global::Penumbra.Api.IpcSubscribers.TrySetModSetting? _setModSetting;
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 readonly IDisposable _initializedEvent;
private readonly IDisposable _disposedEvent;
@ -68,10 +79,11 @@ public class PenumbraService : IDisposable
public int CurrentMinor { 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;
_penumbraReloaded = penumbraReloaded;
_config = config;
_initializedEvent = global::Penumbra.Api.IpcSubscribers.Initialized.Subscriber(pi, Reattach);
_disposedEvent = global::Penumbra.Api.IpcSubscribers.Disposed.Subscriber(pi, Unattach);
_tooltipSubscriber = global::Penumbra.Api.IpcSubscribers.ChangedItemTooltip.Subscriber(pi);
@ -128,7 +140,7 @@ public class PenumbraService : IDisposable
if (ec is not PenumbraApiEc.Success)
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)
{
@ -164,7 +176,7 @@ public class PenumbraService : IDisposable
.Select(t => (new Mod(t.Item2, t.Item1),
!t.Item3.Item2.HasValue
? 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)
.ThenBy(p => p.Item1.Name)
.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.
/// If it is disabled, ignore all other settings.
/// </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)
return "Penumbra is not available.";
@ -204,40 +216,10 @@ public class PenumbraService : IDisposable
try
{
var collection = collectionInput ?? _currentCollection!.Invoke(ApiCollectionType.Current)!.Value.Id;
var ec = _setMod!.Invoke(collection, mod.DirectoryName, settings.Enabled);
switch (ec)
{
case PenumbraApiEc.ModMissing: return $"The mod {mod.Name} [{mod.DirectoryName}] could not be found.";
case PenumbraApiEc.CollectionMissing: return $"The collection {collection} could not be found.";
}
if (!settings.Enabled)
return string.Empty;
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.");
foreach (var (setting, list) in settings.Settings)
{
ec = list.Count == 1
? _setModSetting!.Invoke(collection, mod.DirectoryName, setting, list[0])
: _setModSettings!.Invoke(collection, mod.DirectoryName, setting, list);
switch (ec)
{
case PenumbraApiEc.OptionGroupMissing:
sb.AppendLine($"Could not find the option group {setting} in mod {mod.Name}.");
break;
case PenumbraApiEc.OptionMissing:
sb.AppendLine($"Could not find all desired options in the option group {setting} in mod {mod.Name}.");
break;
case PenumbraApiEc.Success:
case PenumbraApiEc.NothingChanged:
break;
default:
sb.AppendLine($"Could not apply options in the option group {setting} in mod {mod.Name} for unknown reason {ec}.");
break;
}
}
if (_config.UseTemporarySettings && _setTemporaryModSettings != null)
SetModTemporary(sb, mod, settings, collection, index);
else
SetModPermanent(sb, mod, settings, collection);
return sb.ToString();
}
@ -247,6 +229,103 @@ public class PenumbraService : IDisposable
}
}
public void RemoveAllTemporarySettings(Guid collection)
=> _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);
Debug.Assert(ec is PenumbraApiEc.Success or PenumbraApiEc.NothingChanged, "Setting Priority should not be able to fail.");
foreach (var (setting, list) in settings.Settings)
{
ec = list.Count == 1
? _setModSetting!.Invoke(collection, mod.DirectoryName, setting, list[0])
: _setModSettings!.Invoke(collection, mod.DirectoryName, setting, list);
switch (ec)
{
case PenumbraApiEc.OptionGroupMissing:
sb.AppendLine($"Could not find the option group {setting} in mod {mod.Name}.");
break;
case PenumbraApiEc.OptionMissing:
sb.AppendLine($"Could not find all desired options in the option group {setting} in mod {mod.Name}.");
break;
case PenumbraApiEc.Success:
case PenumbraApiEc.NothingChanged:
break;
default:
sb.AppendLine($"Could not apply options in the option group {setting} in mod {mod.Name} for unknown reason {ec}.");
break;
}
}
}
/// <summary> Obtain the name of the collection currently assigned to the player. </summary>
public Guid GetCurrentPlayerCollection()
{
@ -347,12 +426,24 @@ public class PenumbraService : IDisposable
_getMods = new global::Penumbra.Api.IpcSubscribers.GetModList(_pluginInterface);
_currentCollection = new global::Penumbra.Api.IpcSubscribers.GetCollection(_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);
_setModPriority = new global::Penumbra.Api.IpcSubscribers.TrySetModPriority(_pluginInterface);
_setModSetting = new global::Penumbra.Api.IpcSubscribers.TrySetModSetting(_pluginInterface);
_setModSettings = new global::Penumbra.Api.IpcSubscribers.TrySetModSettings(_pluginInterface);
_openModPage = new global::Penumbra.Api.IpcSubscribers.OpenMainWindow(_pluginInterface);
Available = true;
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;
_penumbraReloaded.Invoke();
Glamourer.Log.Debug("Glamourer attached to Penumbra.");
}
@ -373,27 +464,35 @@ public class PenumbraService : IDisposable
_modSettingChanged.Disable();
if (Available)
{
_collectionByIdentifier = null;
_collections = null;
_redraw = null;
_drawObjectInfo = null;
_cutsceneParent = null;
_objectCollection = null;
_getMods = null;
_currentCollection = null;
_getCurrentSettings = null;
_setMod = null;
_setModPriority = null;
_setModSetting = null;
_setModSettings = null;
_openModPage = null;
Available = false;
_collectionByIdentifier = null;
_collections = null;
_redraw = null;
_drawObjectInfo = null;
_cutsceneParent = null;
_objectCollection = null;
_getMods = null;
_currentCollection = null;
_getCurrentSettings = null;
_inheritMod = null;
_setMod = null;
_setModPriority = null;
_setModSetting = null;
_setModSettings = null;
_openModPage = null;
_setTemporaryModSettings = null;
_setTemporaryModSettingsPlayer = null;
_removeTemporaryModSettings = null;
_removeTemporaryModSettingsPlayer = null;
_removeAllTemporaryModSettings = null;
_removeAllTemporaryModSettingsPlayer = null;
Available = false;
Glamourer.Log.Debug("Glamourer detached from Penumbra.");
}
}
public void Dispose()
{
ClearAllTemporarySettings();
Unattach();
_tooltipSubscriber.Dispose();
_clickSubscriber.Dispose();

View file

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

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