diff --git a/Glamourer/Automation/AutoDesignApplier.cs b/Glamourer/Automation/AutoDesignApplier.cs
index f8ca397..55359ca 100644
--- a/Glamourer/Automation/AutoDesignApplier.cs
+++ b/Glamourer/Automation/AutoDesignApplier.cs
@@ -262,7 +262,8 @@ public sealed class AutoDesignApplier : IDisposable
if (!_humans.IsHuman((uint)actor.AsCharacter->CharacterData.ModelCharaId))
return;
- var mergedDesign = _designMerger.Merge(set.Designs.Where(d => d.IsActive(actor)).Select(d => ((DesignBase?)d.Design, d.Type)),
+ var mergedDesign = _designMerger.Merge(
+ set.Designs.Where(d => d.IsActive(actor)).SelectMany(d => d.Design?.AllLinks ?? [(d.Design, d.Type)]),
state.ModelData, true, false);
_state.ApplyDesign(state, mergedDesign, new ApplySettings(0, StateSource.Fixed, respectManual, fromJobChange, false));
}
diff --git a/Glamourer/Designs/Design.cs b/Glamourer/Designs/Design.cs
index 9f74af0..89dd62f 100644
--- a/Glamourer/Designs/Design.cs
+++ b/Glamourer/Designs/Design.cs
@@ -46,6 +46,9 @@ public sealed class Design : DesignBase, ISavable
public string Incognito
=> Identifier.ToString()[..8];
+ public IEnumerable<(DesignBase? Design, ApplicationType Flags)> AllLinks
+ => LinkContainer.GetAllLinks(this).Select(t => ((DesignBase?)t.Link.Link, t.Link.Type));
+
#endregion
#region Serialization
diff --git a/Glamourer/Designs/IDesignEditor.cs b/Glamourer/Designs/IDesignEditor.cs
index a4da53c..b655327 100644
--- a/Glamourer/Designs/IDesignEditor.cs
+++ b/Glamourer/Designs/IDesignEditor.cs
@@ -11,7 +11,8 @@ public readonly record struct ApplySettings(
StateSource Source = StateSource.Manual,
bool RespectManual = false,
bool FromJobChange = false,
- bool UseSingleSource = false)
+ bool UseSingleSource = false,
+ bool MergeLinks = false)
{
public static readonly ApplySettings Manual = new()
{
@@ -20,6 +21,7 @@ public readonly record struct ApplySettings(
FromJobChange = false,
RespectManual = false,
UseSingleSource = false,
+ MergeLinks = false,
};
public static readonly ApplySettings Game = new()
@@ -29,6 +31,7 @@ public readonly record struct ApplySettings(
FromJobChange = false,
RespectManual = false,
UseSingleSource = false,
+ MergeLinks = false,
};
}
diff --git a/Glamourer/Designs/Links/DesignMerger.cs b/Glamourer/Designs/Links/DesignMerger.cs
index 7670498..438c0f4 100644
--- a/Glamourer/Designs/Links/DesignMerger.cs
+++ b/Glamourer/Designs/Links/DesignMerger.cs
@@ -15,6 +15,9 @@ public class DesignMerger(
ItemUnlockManager _itemUnlocks,
CustomizeUnlockManager _customizeUnlocks) : IService
{
+ public MergedDesign Merge(LinkContainer designs, in DesignData baseRef, bool respectOwnership, bool modAssociations)
+ => Merge(designs.Select(d => ((DesignBase?) d.Link, d.Type)), baseRef, respectOwnership, modAssociations);
+
public MergedDesign Merge(IEnumerable<(DesignBase?, ApplicationType)> designs, in DesignData baseRef, bool respectOwnership,
bool modAssociations)
{
diff --git a/Glamourer/Gui/Tabs/ActorTab/ActorPanel.cs b/Glamourer/Gui/Tabs/ActorTab/ActorPanel.cs
index 15f5bd0..bef2ea5 100644
--- a/Glamourer/Gui/Tabs/ActorTab/ActorPanel.cs
+++ b/Glamourer/Gui/Tabs/ActorTab/ActorPanel.cs
@@ -339,7 +339,7 @@ public class ActorPanel(
var text = ImGui.GetClipboardText();
var design = _converter.FromBase64(text, applyCustomize, applyGear, out _)
?? throw new Exception("The clipboard did not contain valid data.");
- _stateManager.ApplyDesign(_state!, design, ApplySettings.Manual);
+ _stateManager.ApplyDesign(_state!, design, ApplySettings.Manual with { MergeLinks = true });
}
catch (Exception ex)
{
diff --git a/Glamourer/Gui/Tabs/DesignTab/DesignPanel.cs b/Glamourer/Gui/Tabs/DesignTab/DesignPanel.cs
index 83da487..93ebad5 100644
--- a/Glamourer/Gui/Tabs/DesignTab/DesignPanel.cs
+++ b/Glamourer/Gui/Tabs/DesignTab/DesignPanel.cs
@@ -438,7 +438,7 @@ public class DesignPanel(
{
var (applyGear, applyCustomize, applyCrest, applyParameters) = UiHelpers.ConvertKeysToFlags();
using var _ = _selector.Selected!.TemporarilyRestrictApplication(applyGear, applyCustomize, applyCrest, applyParameters);
- _state.ApplyDesign(state, _selector.Selected!, ApplySettings.Manual);
+ _state.ApplyDesign(state, _selector.Selected!, ApplySettings.Manual with { MergeLinks = true });
}
}
@@ -457,7 +457,7 @@ public class DesignPanel(
{
var (applyGear, applyCustomize, applyCrest, applyParameters) = UiHelpers.ConvertKeysToFlags();
using var _ = _selector.Selected!.TemporarilyRestrictApplication(applyGear, applyCustomize, applyCrest, applyParameters);
- _state.ApplyDesign(state, _selector.Selected!, ApplySettings.Manual);
+ _state.ApplyDesign(state, _selector.Selected!, ApplySettings.Manual with {MergeLinks = true});
}
}
diff --git a/Glamourer/Services/CommandService.cs b/Glamourer/Services/CommandService.cs
index ddc7217..eb0e792 100644
--- a/Glamourer/Services/CommandService.cs
+++ b/Glamourer/Services/CommandService.cs
@@ -419,7 +419,7 @@ public class CommandService : IDisposable
if (!_objects.TryGetValue(identifier, out var actors))
{
if (_stateManager.TryGetValue(identifier, out var state))
- _stateManager.ApplyDesign(state, design, ApplySettings.Manual);
+ _stateManager.ApplyDesign(state, design, ApplySettings.Manual with { MergeLinks = true });
}
else
{
@@ -428,7 +428,7 @@ public class CommandService : IDisposable
if (_stateManager.GetOrCreate(actor.GetIdentifier(_actors), actor, out var state))
{
ApplyModSettings(design, actor, applyMods);
- _stateManager.ApplyDesign(state, design, ApplySettings.Manual);
+ _stateManager.ApplyDesign(state, design, ApplySettings.Manual with { MergeLinks = true });
}
}
}
diff --git a/Glamourer/State/StateEditor.cs b/Glamourer/State/StateEditor.cs
index 48b2c8b..2b1337e 100644
--- a/Glamourer/State/StateEditor.cs
+++ b/Glamourer/State/StateEditor.cs
@@ -15,7 +15,8 @@ public class StateEditor(
StateChanged stateChanged,
JobChangeState jobChange,
Configuration config,
- ItemManager items) : IDesignEditor
+ ItemManager items,
+ DesignMerger merger) : IDesignEditor
{
protected readonly InternalStateEditor Editor = editor;
protected readonly StateApplier Applier = applier;
@@ -293,12 +294,19 @@ public class StateEditor(
}
public void ApplyDesign(object data, DesignBase design, ApplySettings settings)
- => ApplyDesign(data, new MergedDesign(design), settings with
+ {
+ var merged = settings.MergeLinks && design is Design d
+ ? merger.Merge(d.AllLinks, ((ActorState)data).ModelData, false, false)
+ : new MergedDesign(design);
+
+ ApplyDesign(data, merged, settings with
{
FromJobChange = false,
RespectManual = false,
UseSingleSource = true,
});
+ }
+
/// Apply offhand item and potentially gauntlets if configured.
private void ApplyMainhandPeriphery(ActorState state, EquipItem? newMainhand, ApplySettings settings)
diff --git a/Glamourer/State/StateManager.cs b/Glamourer/State/StateManager.cs
index 5d0e01f..2643271 100644
--- a/Glamourer/State/StateManager.cs
+++ b/Glamourer/State/StateManager.cs
@@ -1,5 +1,6 @@
using Dalamud.Plugin.Services;
using Glamourer.Designs;
+using Glamourer.Designs.Links;
using Glamourer.Events;
using Glamourer.GameData;
using Glamourer.Interop;
@@ -21,8 +22,9 @@ public sealed class StateManager(
HumanModelList _humans,
IClientState _clientState,
Configuration config,
- JobChangeState jobChange)
- : StateEditor(editor, applier, @event, jobChange, config, items), IReadOnlyDictionary
+ JobChangeState jobChange,
+ DesignMerger merger)
+ : StateEditor(editor, applier, @event, jobChange, config, items, merger), IReadOnlyDictionary
{
private readonly Dictionary _states = [];