Add toggle for always applying mod associations.

This commit is contained in:
Ottermandias 2024-01-30 18:30:51 +01:00
parent 818bf71032
commit d10043a69a
6 changed files with 84 additions and 21 deletions

View file

@ -264,7 +264,7 @@ public sealed class AutoDesignApplier : IDisposable
var mergedDesign = _designMerger.Merge( var mergedDesign = _designMerger.Merge(
set.Designs.Where(d => d.IsActive(actor)).SelectMany(d => d.Design?.AllLinks.Select(l => (l.Design, l.Flags & d.Type)) ?? [(d.Design, d.Type)]), set.Designs.Where(d => d.IsActive(actor)).SelectMany(d => d.Design?.AllLinks.Select(l => (l.Design, l.Flags & d.Type)) ?? [(d.Design, d.Type)]),
state.ModelData, true, false); state.ModelData, true, _config.AlwaysApplyAssociatedMods);
_state.ApplyDesign(state, mergedDesign, new ApplySettings(0, StateSource.Fixed, respectManual, fromJobChange, false)); _state.ApplyDesign(state, mergedDesign, new ApplySettings(0, StateSource.Fixed, respectManual, fromJobChange, false));
} }

View file

@ -89,12 +89,12 @@ public class SettingsTab(
Checkbox("Enable Advanced Customization Options", Checkbox("Enable Advanced Customization Options",
"Enable the display and editing of advanced customization options like arbitrary colors.", "Enable the display and editing of advanced customization options like arbitrary colors.",
config.UseAdvancedParameters, paletteChecker.SetAdvancedParameters); config.UseAdvancedParameters, paletteChecker.SetAdvancedParameters);
PaletteImportButton();
Checkbox("Always Apply Associated Mods", Checkbox("Always Apply Associated Mods",
"Whenever a design is applied to a character (including via automation), Glamourer will try to apply its associated mod settings to the collection currently associated with that character, if it is available.\n\n" "Whenever a design is applied to a character (including via automation), Glamourer will try to apply its associated mod settings to the collection currently associated with that character, if it is available.\n\n"
+ "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);
PaletteImportButton();
ImGui.NewLine(); ImGui.NewLine();
} }

View file

@ -0,0 +1,67 @@
using Glamourer.Designs.Links;
using Glamourer.Interop.Structs;
using Glamourer.State;
using OtterGui.Services;
namespace Glamourer.Interop.Penumbra;
public class ModSettingApplier(PenumbraService penumbra, Configuration config, ObjectManager objects) : IService
{
public void HandleStateApplication(ActorState state, MergedDesign design)
{
if (!config.AlwaysApplyAssociatedMods || design.AssociatedMods.Count == 0)
return;
objects.Update();
if (!objects.TryGetValue(state.Identifier, out var data))
{
Glamourer.Log.Verbose(
$"[Mod Applier] No mod settings applied because no actor for {state.Identifier} could be found to associate collection.");
return;
}
var collections = new HashSet<string>();
foreach (var actor in data.Objects)
{
var collection = penumbra.GetActorCollection(actor);
if (collection.Length == 0)
{
Glamourer.Log.Verbose($"[Mod Applier] Could not obtain associated collection for {actor.Utf8Name}.");
continue;
}
if (!collections.Add(collection))
continue;
foreach (var (mod, setting) in design.AssociatedMods)
{
var message = penumbra.SetMod(mod, setting, collection);
if (message.Length > 0)
Glamourer.Log.Verbose($"[Mod Applier] Error applying mod settings: {message}");
else
Glamourer.Log.Verbose($"[Mod Applier] Set mod settings for {mod.DirectoryName} in {collection}.");
}
}
}
public (List<string> Messages, int Applied, string Collection) ApplyModSettings(IReadOnlyDictionary<Mod, ModSettings> settings, Actor actor)
{
var collection = penumbra.GetActorCollection(actor);
if (collection.Length <= 0)
return ([$"Could not obtain associated collection for {actor.Utf8Name}."], 0, string.Empty);
var messages = new List<string>();
var appliedMods = 0;
foreach (var (mod, setting) in settings)
{
var message = penumbra.SetMod(mod, setting, collection);
if (message.Length > 0)
messages.Add($"Error applying mod settings: {message}");
else
++appliedMods;
}
return (messages, appliedMods, collection);
}
}

View file

@ -33,11 +33,11 @@ public class CommandService : IDisposable
private readonly DesignConverter _converter; private readonly DesignConverter _converter;
private readonly DesignFileSystem _designFileSystem; private readonly DesignFileSystem _designFileSystem;
private readonly Configuration _config; private readonly Configuration _config;
private readonly PenumbraService _penumbra; private readonly ModSettingApplier _modApplier;
public CommandService(ICommandManager commands, MainWindow mainWindow, IChatGui chat, ActorManager actors, ObjectManager objects, public CommandService(ICommandManager commands, MainWindow mainWindow, IChatGui chat, ActorManager actors, ObjectManager objects,
AutoDesignApplier autoDesignApplier, StateManager stateManager, DesignManager designManager, DesignConverter converter, AutoDesignApplier autoDesignApplier, StateManager stateManager, DesignManager designManager, DesignConverter converter,
DesignFileSystem designFileSystem, AutoDesignManager autoDesignManager, Configuration config, PenumbraService penumbra) DesignFileSystem designFileSystem, AutoDesignManager autoDesignManager, Configuration config, ModSettingApplier modApplier)
{ {
_commands = commands; _commands = commands;
_mainWindow = mainWindow; _mainWindow = mainWindow;
@ -51,7 +51,7 @@ public class CommandService : IDisposable
_designFileSystem = designFileSystem; _designFileSystem = designFileSystem;
_autoDesignManager = autoDesignManager; _autoDesignManager = autoDesignManager;
_config = config; _config = config;
_penumbra = penumbra; _modApplier = modApplier;
_commands.AddHandler(MainCommandString, new CommandInfo(OnGlamourer) { HelpMessage = "Open or close the Glamourer window." }); _commands.AddHandler(MainCommandString, new CommandInfo(OnGlamourer) { HelpMessage = "Open or close the Glamourer window." });
_commands.AddHandler(ApplyCommandString, _commands.AddHandler(ApplyCommandString,
@ -440,19 +440,10 @@ public class CommandService : IDisposable
if (!applyMods || design is not Design d) if (!applyMods || design is not Design d)
return; return;
var collection = _penumbra.GetActorCollection(actor); var (messages, appliedMods, collection) = _modApplier.ApplyModSettings(d.AssociatedMods, actor);
if (collection.Length <= 0)
return;
var appliedMods = 0; foreach (var message in messages)
foreach (var (mod, setting) in d.AssociatedMods) Glamourer.Messager.Chat.Print($"Error applying mod settings: {message}");
{
var message = _penumbra.SetMod(mod, setting, collection);
if (message.Length > 0)
Glamourer.Messager.Chat.Print($"Error applying mod settings: {message}");
else
++appliedMods;
}
if (appliedMods > 0) if (appliedMods > 0)
Glamourer.Messager.Chat.Print($"Applied {appliedMods} mod settings to {collection}."); Glamourer.Messager.Chat.Print($"Applied {appliedMods} mod settings to {collection}.");

View file

@ -2,6 +2,7 @@ using Glamourer.Designs;
using Glamourer.Designs.Links; using Glamourer.Designs.Links;
using Glamourer.Events; using Glamourer.Events;
using Glamourer.GameData; using Glamourer.GameData;
using Glamourer.Interop.Penumbra;
using Glamourer.Interop.Structs; using Glamourer.Interop.Structs;
using Glamourer.Services; using Glamourer.Services;
using Penumbra.GameData.Enums; using Penumbra.GameData.Enums;
@ -16,7 +17,8 @@ public class StateEditor(
JobChangeState jobChange, JobChangeState jobChange,
Configuration config, Configuration config,
ItemManager items, ItemManager items,
DesignMerger merger) : IDesignEditor DesignMerger merger,
ModSettingApplier modApplier) : IDesignEditor
{ {
protected readonly InternalStateEditor Editor = editor; protected readonly InternalStateEditor Editor = editor;
protected readonly StateApplier Applier = applier; protected readonly StateApplier Applier = applier;
@ -181,6 +183,7 @@ public class StateEditor(
public void ApplyDesign(object data, MergedDesign mergedDesign, ApplySettings settings) public void ApplyDesign(object data, MergedDesign mergedDesign, ApplySettings settings)
{ {
var state = (ActorState)data; var state = (ActorState)data;
modApplier.HandleStateApplication(state, mergedDesign);
if (!Editor.ChangeModelId(state, mergedDesign.Design.DesignData.ModelId, mergedDesign.Design.DesignData.Customize, if (!Editor.ChangeModelId(state, mergedDesign.Design.DesignData.ModelId, mergedDesign.Design.DesignData.Customize,
mergedDesign.Design.GetDesignDataRef().GetEquipmentPtr(), settings.Source, out var oldModelId, settings.Key)) mergedDesign.Design.GetDesignDataRef().GetEquipmentPtr(), settings.Source, out var oldModelId, settings.Key))
return; return;
@ -294,7 +297,7 @@ public class StateEditor(
public void ApplyDesign(object data, DesignBase design, ApplySettings settings) public void ApplyDesign(object data, DesignBase design, ApplySettings settings)
{ {
var merged = settings.MergeLinks && design is Design d var merged = settings.MergeLinks && design is Design d
? merger.Merge(d.AllLinks, ((ActorState)data).ModelData, false, false) ? merger.Merge(d.AllLinks, ((ActorState)data).ModelData, false, Config.AlwaysApplyAssociatedMods)
: new MergedDesign(design); : new MergedDesign(design);
ApplyDesign(data, merged, settings with ApplyDesign(data, merged, settings with

View file

@ -4,6 +4,7 @@ using Glamourer.Designs.Links;
using Glamourer.Events; using Glamourer.Events;
using Glamourer.GameData; using Glamourer.GameData;
using Glamourer.Interop; using Glamourer.Interop;
using Glamourer.Interop.Penumbra;
using Glamourer.Interop.Structs; using Glamourer.Interop.Structs;
using Glamourer.Services; using Glamourer.Services;
using Penumbra.GameData.Actors; using Penumbra.GameData.Actors;
@ -23,8 +24,9 @@ public sealed class StateManager(
IClientState _clientState, IClientState _clientState,
Configuration config, Configuration config,
JobChangeState jobChange, JobChangeState jobChange,
DesignMerger merger) DesignMerger merger,
: StateEditor(editor, applier, @event, jobChange, config, items, merger), IReadOnlyDictionary<ActorIdentifier, ActorState> ModSettingApplier modApplier)
: StateEditor(editor, applier, @event, jobChange, config, items, merger, modApplier), IReadOnlyDictionary<ActorIdentifier, ActorState>
{ {
private readonly Dictionary<ActorIdentifier, ActorState> _states = []; private readonly Dictionary<ActorIdentifier, ActorState> _states = [];