mirror of
https://github.com/Ottermandias/Glamourer.git
synced 2025-12-12 18:27:24 +01:00
Add some new things, rework Revert-handling.
This commit is contained in:
parent
f2951ca800
commit
1cf0e2f70e
21 changed files with 477 additions and 181 deletions
|
|
@ -18,18 +18,18 @@ public enum ApplicationType : byte
|
||||||
|
|
||||||
public static class ApplicationTypeExtensions
|
public static class ApplicationTypeExtensions
|
||||||
{
|
{
|
||||||
public static readonly IReadOnlyList<(ApplicationType, string)> Types = new[]
|
public static readonly IReadOnlyList<(ApplicationType, string)> Types =
|
||||||
{
|
[
|
||||||
(ApplicationType.Customizations,
|
(ApplicationType.Customizations,
|
||||||
"Apply all customization changes that are enabled in this design and that are valid in a fixed design and for the given race and gender."),
|
"Apply all customization changes that are enabled in this design and that are valid in a fixed design and for the given race and gender."),
|
||||||
(ApplicationType.Armor, "Apply all armor piece changes that are enabled in this design and that are valid in a fixed design."),
|
(ApplicationType.Armor, "Apply all armor piece changes that are enabled in this design and that are valid in a fixed design."),
|
||||||
(ApplicationType.Accessories, "Apply all accessory changes that are enabled in this design and that are valid in a fixed design."),
|
(ApplicationType.Accessories, "Apply all accessory changes that are enabled in this design and that are valid in a fixed design."),
|
||||||
(ApplicationType.GearCustomization, "Apply all dye and crest changes that are enabled in this design."),
|
(ApplicationType.GearCustomization, "Apply all dye and crest changes that are enabled in this design."),
|
||||||
(ApplicationType.Weapons, "Apply all weapon changes that are enabled in this design and that are valid with the current weapon worn."),
|
(ApplicationType.Weapons, "Apply all weapon changes that are enabled in this design and that are valid with the current weapon worn."),
|
||||||
};
|
];
|
||||||
|
|
||||||
public static (EquipFlag Equip, CustomizeFlag Customize, CrestFlag Crest, CustomizeParameterFlag Parameters, MetaFlag Meta) ApplyWhat(
|
public static (EquipFlag Equip, CustomizeFlag Customize, CrestFlag Crest, CustomizeParameterFlag Parameters, MetaFlag Meta) ApplyWhat(
|
||||||
this ApplicationType type, DesignBase? design)
|
this ApplicationType type, IDesignStandIn designStandIn)
|
||||||
{
|
{
|
||||||
var equipFlags = (type.HasFlag(ApplicationType.Weapons) ? WeaponFlags : 0)
|
var equipFlags = (type.HasFlag(ApplicationType.Weapons) ? WeaponFlags : 0)
|
||||||
| (type.HasFlag(ApplicationType.Armor) ? ArmorFlags : 0)
|
| (type.HasFlag(ApplicationType.Armor) ? ArmorFlags : 0)
|
||||||
|
|
@ -42,7 +42,7 @@ public static class ApplicationTypeExtensions
|
||||||
| (type.HasFlag(ApplicationType.Weapons) ? MetaFlag.WeaponState : 0)
|
| (type.HasFlag(ApplicationType.Weapons) ? MetaFlag.WeaponState : 0)
|
||||||
| (type.HasFlag(ApplicationType.Customizations) ? MetaFlag.Wetness : 0);
|
| (type.HasFlag(ApplicationType.Customizations) ? MetaFlag.Wetness : 0);
|
||||||
|
|
||||||
if (design == null)
|
if (designStandIn is not DesignBase design)
|
||||||
return (equipFlags, customizeFlags, crestFlag, parameterFlags, metaFlag);
|
return (equipFlags, customizeFlags, crestFlag, parameterFlags, metaFlag);
|
||||||
|
|
||||||
return (equipFlags & design!.ApplyEquip, customizeFlags & design.ApplyCustomize, crestFlag & design.ApplyCrest,
|
return (equipFlags & design!.ApplyEquip, customizeFlags & design.ApplyCustomize, crestFlag & design.ApplyCrest,
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
using Glamourer.Designs;
|
using Glamourer.Designs;
|
||||||
using Glamourer.GameData;
|
using Glamourer.GameData;
|
||||||
using Glamourer.Interop.Structs;
|
using Glamourer.Interop.Structs;
|
||||||
using Glamourer.State;
|
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using Penumbra.GameData.Enums;
|
using Penumbra.GameData.Enums;
|
||||||
using Penumbra.GameData.Structs;
|
using Penumbra.GameData.Structs;
|
||||||
|
|
@ -12,20 +11,11 @@ public class AutoDesign
|
||||||
{
|
{
|
||||||
public const string RevertName = "Revert";
|
public const string RevertName = "Revert";
|
||||||
|
|
||||||
public Design? Design;
|
public IDesignStandIn Design = new RevertDesign();
|
||||||
public JobGroup Jobs;
|
public JobGroup Jobs;
|
||||||
public ApplicationType Type;
|
public ApplicationType Type;
|
||||||
public short GearsetIndex = -1;
|
public short GearsetIndex = -1;
|
||||||
|
|
||||||
public string Name(bool incognito)
|
|
||||||
=> Revert ? RevertName : incognito ? Design!.Incognito : Design!.Name.Text;
|
|
||||||
|
|
||||||
public ref readonly DesignData GetDesignData(ActorState state)
|
|
||||||
=> ref Design == null ? ref state.BaseData : ref Design.DesignData;
|
|
||||||
|
|
||||||
public bool Revert
|
|
||||||
=> Design == null;
|
|
||||||
|
|
||||||
public AutoDesign Clone()
|
public AutoDesign Clone()
|
||||||
=> new()
|
=> new()
|
||||||
{
|
{
|
||||||
|
|
@ -50,12 +40,16 @@ public class AutoDesign
|
||||||
}
|
}
|
||||||
|
|
||||||
public JObject Serialize()
|
public JObject Serialize()
|
||||||
=> new()
|
{
|
||||||
|
var ret = new JObject
|
||||||
{
|
{
|
||||||
["Design"] = Design?.Identifier.ToString(),
|
["Design"] = Design.SerializeName(),
|
||||||
["Type"] = (uint)Type,
|
["Type"] = (uint)Type,
|
||||||
["Conditions"] = CreateConditionObject(),
|
["Conditions"] = CreateConditionObject(),
|
||||||
};
|
};
|
||||||
|
Design.AddData(ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
private JObject CreateConditionObject()
|
private JObject CreateConditionObject()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -263,7 +263,7 @@ public sealed class AutoDesignApplier : IDisposable
|
||||||
return;
|
return;
|
||||||
|
|
||||||
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))),
|
||||||
state.ModelData.Customize, state.BaseData, true, _config.AlwaysApplyAssociatedMods);
|
state.ModelData.Customize, state.BaseData, true, _config.AlwaysApplyAssociatedMods);
|
||||||
_state.ApplyDesign(state, mergedDesign, new ApplySettings(0, StateSource.Fixed, respectManual, fromJobChange, false, false, set.BaseState is AutoDesignSet.Base.Game));
|
_state.ApplyDesign(state, mergedDesign, new ApplySettings(0, StateSource.Fixed, respectManual, fromJobChange, false, false, set.BaseState is AutoDesignSet.Base.Game));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,11 +21,12 @@ public class AutoDesignManager : ISavable, IReadOnlyList<AutoDesignSet>, IDispos
|
||||||
|
|
||||||
private readonly SaveService _saveService;
|
private readonly SaveService _saveService;
|
||||||
|
|
||||||
private readonly JobService _jobs;
|
private readonly JobService _jobs;
|
||||||
private readonly DesignManager _designs;
|
private readonly DesignManager _designs;
|
||||||
private readonly ActorManager _actors;
|
private readonly ActorManager _actors;
|
||||||
private readonly AutomationChanged _event;
|
private readonly AutomationChanged _event;
|
||||||
private readonly DesignChanged _designEvent;
|
private readonly DesignChanged _designEvent;
|
||||||
|
private readonly RandomDesignGenerator _randomDesigns;
|
||||||
|
|
||||||
private readonly List<AutoDesignSet> _data = [];
|
private readonly List<AutoDesignSet> _data = [];
|
||||||
private readonly Dictionary<ActorIdentifier, AutoDesignSet> _enabled = [];
|
private readonly Dictionary<ActorIdentifier, AutoDesignSet> _enabled = [];
|
||||||
|
|
@ -34,14 +35,15 @@ public class AutoDesignManager : ISavable, IReadOnlyList<AutoDesignSet>, IDispos
|
||||||
=> _enabled;
|
=> _enabled;
|
||||||
|
|
||||||
public AutoDesignManager(JobService jobs, ActorManager actors, SaveService saveService, DesignManager designs, AutomationChanged @event,
|
public AutoDesignManager(JobService jobs, ActorManager actors, SaveService saveService, DesignManager designs, AutomationChanged @event,
|
||||||
FixedDesignMigrator migrator, DesignFileSystem fileSystem, DesignChanged designEvent)
|
FixedDesignMigrator migrator, DesignFileSystem fileSystem, DesignChanged designEvent, RandomDesignGenerator randomDesigns)
|
||||||
{
|
{
|
||||||
_jobs = jobs;
|
_jobs = jobs;
|
||||||
_actors = actors;
|
_actors = actors;
|
||||||
_saveService = saveService;
|
_saveService = saveService;
|
||||||
_designs = designs;
|
_designs = designs;
|
||||||
_event = @event;
|
_event = @event;
|
||||||
_designEvent = designEvent;
|
_designEvent = designEvent;
|
||||||
|
_randomDesigns = randomDesigns;
|
||||||
_designEvent.Subscribe(OnDesignChange, DesignChanged.Priority.AutoDesignManager);
|
_designEvent.Subscribe(OnDesignChange, DesignChanged.Priority.AutoDesignManager);
|
||||||
Load();
|
Load();
|
||||||
migrator.ConsumeMigratedData(_actors, fileSystem, this);
|
migrator.ConsumeMigratedData(_actors, fileSystem, this);
|
||||||
|
|
@ -227,7 +229,7 @@ public class AutoDesignManager : ISavable, IReadOnlyList<AutoDesignSet>, IDispos
|
||||||
_event.Invoke(AutomationChanged.Type.ChangedBase, set, (old, newBase));
|
_event.Invoke(AutomationChanged.Type.ChangedBase, set, (old, newBase));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddDesign(AutoDesignSet set, Design? design)
|
public void AddDesign(AutoDesignSet set, IDesignStandIn design)
|
||||||
{
|
{
|
||||||
var newDesign = new AutoDesign()
|
var newDesign = new AutoDesign()
|
||||||
{
|
{
|
||||||
|
|
@ -238,7 +240,7 @@ public class AutoDesignManager : ISavable, IReadOnlyList<AutoDesignSet>, IDispos
|
||||||
set.Designs.Add(newDesign);
|
set.Designs.Add(newDesign);
|
||||||
Save();
|
Save();
|
||||||
Glamourer.Log.Debug(
|
Glamourer.Log.Debug(
|
||||||
$"Added new associated design {design?.Identifier.ToString() ?? "Reverter"} as design {set.Designs.Count} to design set.");
|
$"Added new associated design {design.ResolveName(true)} as design {set.Designs.Count} to design set.");
|
||||||
_event.Invoke(AutomationChanged.Type.AddedDesign, set, set.Designs.Count - 1);
|
_event.Invoke(AutomationChanged.Type.AddedDesign, set, set.Designs.Count - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -278,20 +280,20 @@ public class AutoDesignManager : ISavable, IReadOnlyList<AutoDesignSet>, IDispos
|
||||||
_event.Invoke(AutomationChanged.Type.MovedDesign, set, (from, to));
|
_event.Invoke(AutomationChanged.Type.MovedDesign, set, (from, to));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ChangeDesign(AutoDesignSet set, int which, Design? newDesign)
|
public void ChangeDesign(AutoDesignSet set, int which, IDesignStandIn newDesign)
|
||||||
{
|
{
|
||||||
if (which >= set.Designs.Count || which < 0)
|
if (which >= set.Designs.Count || which < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var design = set.Designs[which];
|
var design = set.Designs[which];
|
||||||
if (design.Design?.Identifier == newDesign?.Identifier)
|
if (design.Design.Equals(newDesign))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var old = design.Design;
|
var old = design.Design;
|
||||||
design.Design = newDesign;
|
design.Design = newDesign;
|
||||||
Save();
|
Save();
|
||||||
Glamourer.Log.Debug(
|
Glamourer.Log.Debug(
|
||||||
$"Changed linked design from {old?.Identifier.ToString() ?? "Reverter"} to {newDesign?.Identifier.ToString() ?? "Reverter"} for associated design {which + 1} in design set.");
|
$"Changed linked design from {old.ResolveName(true)} to {newDesign.ResolveName(true)} for associated design {which + 1} in design set.");
|
||||||
_event.Invoke(AutomationChanged.Type.ChangedDesign, set, (which, old, newDesign));
|
_event.Invoke(AutomationChanged.Type.ChangedDesign, set, (which, old, newDesign));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -450,8 +452,7 @@ public class AutoDesignManager : ISavable, IReadOnlyList<AutoDesignSet>, IDispos
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var design = ToDesignObject(set.Name, j);
|
if (ToDesignObject(set.Name, j) is { } design)
|
||||||
if (design != null)
|
|
||||||
set.Designs.Add(design);
|
set.Designs.Add(design);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -459,10 +460,18 @@ public class AutoDesignManager : ISavable, IReadOnlyList<AutoDesignSet>, IDispos
|
||||||
|
|
||||||
private AutoDesign? ToDesignObject(string setName, JObject jObj)
|
private AutoDesign? ToDesignObject(string setName, JObject jObj)
|
||||||
{
|
{
|
||||||
var designIdentifier = jObj["Design"]?.ToObject<string?>();
|
var designIdentifier = jObj["Design"]?.ToObject<string?>();
|
||||||
Design? design = null;
|
IDesignStandIn? design;
|
||||||
// designIdentifier == null means Revert-Design.
|
// designIdentifier == null means Revert-Design for backwards compatibility
|
||||||
if (designIdentifier != null)
|
if (designIdentifier is null or RevertDesign.SerializedName)
|
||||||
|
{
|
||||||
|
design = new RevertDesign();
|
||||||
|
}
|
||||||
|
else if (designIdentifier is RandomDesign.SerializedName)
|
||||||
|
{
|
||||||
|
design = new RandomDesign(_randomDesigns);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
if (designIdentifier.Length == 0)
|
if (designIdentifier.Length == 0)
|
||||||
{
|
{
|
||||||
|
|
@ -480,14 +489,17 @@ public class AutoDesignManager : ISavable, IReadOnlyList<AutoDesignSet>, IDispos
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_designs.Designs.TryGetValue(guid, out design))
|
if (!_designs.Designs.TryGetValue(guid, out var d))
|
||||||
{
|
{
|
||||||
Glamourer.Messager.NotificationMessage(
|
Glamourer.Messager.NotificationMessage(
|
||||||
$"Error parsing automatically applied design for set {setName}: The specified design {guid} does not exist.",
|
$"Error parsing automatically applied design for set {setName}: The specified design {guid} does not exist.",
|
||||||
NotificationType.Warning);
|
NotificationType.Warning);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
design = d;
|
||||||
}
|
}
|
||||||
|
design.ParseData(jObj);
|
||||||
|
|
||||||
// ApplicationType is a migration from an older property name.
|
// ApplicationType is a migration from an older property name.
|
||||||
var applicationType = (ApplicationType)(jObj["Type"]?.ToObject<uint>() ?? jObj["ApplicationType"]?.ToObject<uint>() ?? 0);
|
var applicationType = (ApplicationType)(jObj["Type"]?.ToObject<uint>() ?? jObj["ApplicationType"]?.ToObject<uint>() ?? 0);
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ public class AutoDesignSet(string name, ActorIdentifier[] identifiers, List<Auto
|
||||||
}
|
}
|
||||||
|
|
||||||
public AutoDesignSet(string name, params ActorIdentifier[] identifiers)
|
public AutoDesignSet(string name, params ActorIdentifier[] identifiers)
|
||||||
: this(name, identifiers, new List<AutoDesign>())
|
: this(name, identifiers, [])
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
public enum Base : byte
|
public enum Base : byte
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,17 @@
|
||||||
using Dalamud.Interface.Internal.Notifications;
|
using Dalamud.Interface.Internal.Notifications;
|
||||||
using Glamourer.Automation;
|
using Glamourer.Automation;
|
||||||
using Glamourer.Designs.Links;
|
using Glamourer.Designs.Links;
|
||||||
|
using Glamourer.Interop.Material;
|
||||||
using Glamourer.Interop.Penumbra;
|
using Glamourer.Interop.Penumbra;
|
||||||
using Glamourer.Services;
|
using Glamourer.Services;
|
||||||
|
using Glamourer.State;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using OtterGui.Classes;
|
using OtterGui.Classes;
|
||||||
|
|
||||||
namespace Glamourer.Designs;
|
namespace Glamourer.Designs;
|
||||||
|
|
||||||
public sealed class Design : DesignBase, ISavable
|
public sealed class Design : DesignBase, ISavable, IDesignStandIn
|
||||||
{
|
{
|
||||||
#region Data
|
#region Data
|
||||||
|
|
||||||
|
|
@ -48,8 +50,36 @@ public sealed class Design : DesignBase, ISavable
|
||||||
public string Incognito
|
public string Incognito
|
||||||
=> Identifier.ToString()[..8];
|
=> Identifier.ToString()[..8];
|
||||||
|
|
||||||
public IEnumerable<(DesignBase? Design, ApplicationType Flags)> AllLinks
|
public IEnumerable<(IDesignStandIn Design, ApplicationType Flags)> AllLinks
|
||||||
=> LinkContainer.GetAllLinks(this).Select(t => ((DesignBase?)t.Link.Link, t.Link.Type));
|
=> LinkContainer.GetAllLinks(this).Select(t => ((IDesignStandIn)t.Link.Link, t.Link.Type));
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region IDesignStandIn
|
||||||
|
|
||||||
|
public string ResolveName(bool incognito)
|
||||||
|
=> incognito ? Incognito : Name.Text;
|
||||||
|
|
||||||
|
public string SerializeName()
|
||||||
|
=> Identifier.ToString();
|
||||||
|
|
||||||
|
public ref readonly DesignData GetDesignData(in DesignData baseData)
|
||||||
|
=> ref GetDesignDataRef();
|
||||||
|
|
||||||
|
public IReadOnlyList<(uint, MaterialValueDesign)> GetMaterialData()
|
||||||
|
=> Materials;
|
||||||
|
|
||||||
|
public bool Equals(IDesignStandIn? other)
|
||||||
|
=> other is Design d && d.Identifier == Identifier;
|
||||||
|
|
||||||
|
public StateSource AssociatedSource()
|
||||||
|
=> StateSource.Manual;
|
||||||
|
|
||||||
|
public void AddData(JObject _)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public void ParseData(JObject _)
|
||||||
|
{ }
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -149,8 +149,11 @@ public class DesignColors : ISavable, IReadOnlyDictionary<string, uint>
|
||||||
Load();
|
Load();
|
||||||
}
|
}
|
||||||
|
|
||||||
public uint GetColor(Design design)
|
public uint GetColor(Design? design)
|
||||||
{
|
{
|
||||||
|
if (design == null)
|
||||||
|
return ColorId.NormalDesign.Value();
|
||||||
|
|
||||||
if (design.Color.Length == 0)
|
if (design.Color.Length == 0)
|
||||||
return AutoColor(design);
|
return AutoColor(design);
|
||||||
|
|
||||||
|
|
|
||||||
23
Glamourer/Designs/IDesignStandIn.cs
Normal file
23
Glamourer/Designs/IDesignStandIn.cs
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
using Glamourer.Automation;
|
||||||
|
using Glamourer.Interop.Material;
|
||||||
|
using Glamourer.State;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
|
namespace Glamourer.Designs;
|
||||||
|
|
||||||
|
public interface IDesignStandIn : IEquatable<IDesignStandIn>
|
||||||
|
{
|
||||||
|
public string ResolveName(bool incognito);
|
||||||
|
public ref readonly DesignData GetDesignData(in DesignData baseRef);
|
||||||
|
|
||||||
|
public IReadOnlyList<(uint, MaterialValueDesign)> GetMaterialData();
|
||||||
|
|
||||||
|
public string SerializeName();
|
||||||
|
public StateSource AssociatedSource();
|
||||||
|
|
||||||
|
public IEnumerable<(IDesignStandIn Design, ApplicationType Flags)> AllLinks { get; }
|
||||||
|
|
||||||
|
public void AddData(JObject jObj);
|
||||||
|
|
||||||
|
public void ParseData(JObject jObj);
|
||||||
|
}
|
||||||
|
|
@ -17,13 +17,15 @@ public class DesignMerger(
|
||||||
ItemUnlockManager _itemUnlocks,
|
ItemUnlockManager _itemUnlocks,
|
||||||
CustomizeUnlockManager _customizeUnlocks) : IService
|
CustomizeUnlockManager _customizeUnlocks) : IService
|
||||||
{
|
{
|
||||||
public MergedDesign Merge(LinkContainer designs, in CustomizeArray currentCustomize, in DesignData baseRef, bool respectOwnership, bool modAssociations)
|
public MergedDesign Merge(LinkContainer designs, in CustomizeArray currentCustomize, in DesignData baseRef, bool respectOwnership,
|
||||||
=> Merge(designs.Select(d => ((DesignBase?) d.Link, d.Type)), currentCustomize, baseRef, respectOwnership, modAssociations);
|
bool modAssociations)
|
||||||
|
=> Merge(designs.Select(d => ((IDesignStandIn)d.Link, d.Type)), currentCustomize, baseRef, respectOwnership, modAssociations);
|
||||||
|
|
||||||
public MergedDesign Merge(IEnumerable<(DesignBase?, ApplicationType)> designs, in CustomizeArray currentCustomize, in DesignData baseRef, bool respectOwnership,
|
public MergedDesign Merge(IEnumerable<(IDesignStandIn, ApplicationType)> designs, in CustomizeArray currentCustomize, in DesignData baseRef,
|
||||||
|
bool respectOwnership,
|
||||||
bool modAssociations)
|
bool modAssociations)
|
||||||
{
|
{
|
||||||
var ret = new MergedDesign(designManager);
|
var ret = new MergedDesign(designManager);
|
||||||
ret.Design.SetCustomize(_customize, currentCustomize);
|
ret.Design.SetCustomize(_customize, currentCustomize);
|
||||||
CustomizeFlag fixFlags = 0;
|
CustomizeFlag fixFlags = 0;
|
||||||
respectOwnership &= _config.UnlockedItemMode;
|
respectOwnership &= _config.UnlockedItemMode;
|
||||||
|
|
@ -32,8 +34,8 @@ public class DesignMerger(
|
||||||
if (type is 0)
|
if (type is 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
ref readonly var data = ref design == null ? ref baseRef : ref design.GetDesignDataRef();
|
ref readonly var data = ref design.GetDesignData(baseRef);
|
||||||
var source = design == null ? StateSource.Game : StateSource.Manual;
|
var source = design.AssociatedSource();
|
||||||
|
|
||||||
if (!data.IsHuman)
|
if (!data.IsHuman)
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -56,10 +58,11 @@ public class DesignMerger(
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static void ReduceMaterials(DesignBase? design, MergedDesign ret)
|
private static void ReduceMaterials(IDesignStandIn designStandIn, MergedDesign ret)
|
||||||
{
|
{
|
||||||
if (design == null)
|
if (designStandIn is not DesignBase design)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var materials = ret.Design.GetMaterialDataRef();
|
var materials = ret.Design.GetMaterialDataRef();
|
||||||
foreach (var (key, value) in design.Materials.Where(p => p.Item2.Enabled))
|
foreach (var (key, value) in design.Materials.Where(p => p.Item2.Enabled))
|
||||||
materials.TryAddValue(MaterialValueIndex.FromKey(key), value);
|
materials.TryAddValue(MaterialValueIndex.FromKey(key), value);
|
||||||
|
|
@ -243,7 +246,7 @@ public class DesignMerger(
|
||||||
ret.Sources[CustomizeIndex.Face] = source;
|
ret.Sources[CustomizeIndex.Face] = source;
|
||||||
}
|
}
|
||||||
|
|
||||||
var set = _customize.Manager.GetSet(customize.Clan, customize.Gender);
|
var set = _customize.Manager.GetSet(customize.Clan, customize.Gender);
|
||||||
var face = customize.Face;
|
var face = customize.Face;
|
||||||
foreach (var index in Enum.GetValues<CustomizeIndex>())
|
foreach (var index in Enum.GetValues<CustomizeIndex>())
|
||||||
{
|
{
|
||||||
|
|
|
||||||
69
Glamourer/Designs/RandomDesign.cs
Normal file
69
Glamourer/Designs/RandomDesign.cs
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
using Glamourer.Automation;
|
||||||
|
using Glamourer.Interop.Material;
|
||||||
|
using Glamourer.State;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
|
namespace Glamourer.Designs;
|
||||||
|
|
||||||
|
public class RandomDesign(RandomDesignGenerator rng) : IDesignStandIn
|
||||||
|
{
|
||||||
|
public const string SerializedName = "//Random";
|
||||||
|
public const string ResolvedName = "Random";
|
||||||
|
private Design? _currentDesign;
|
||||||
|
|
||||||
|
public string Restrictions { get; internal set; } = string.Empty;
|
||||||
|
|
||||||
|
public string ResolveName(bool _)
|
||||||
|
=> ResolvedName;
|
||||||
|
|
||||||
|
public ref readonly DesignData GetDesignData(in DesignData baseRef)
|
||||||
|
{
|
||||||
|
_currentDesign ??= rng.Design(Restrictions);
|
||||||
|
if (_currentDesign == null)
|
||||||
|
return ref baseRef;
|
||||||
|
|
||||||
|
return ref _currentDesign.GetDesignDataRef();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IReadOnlyList<(uint, MaterialValueDesign)> GetMaterialData()
|
||||||
|
{
|
||||||
|
_currentDesign ??= rng.Design(Restrictions);
|
||||||
|
if (_currentDesign == null)
|
||||||
|
return [];
|
||||||
|
|
||||||
|
return _currentDesign.Materials;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string SerializeName()
|
||||||
|
=> SerializedName;
|
||||||
|
|
||||||
|
public bool Equals(IDesignStandIn? other)
|
||||||
|
=> other is RandomDesign r && string.Equals(r.Restrictions, Restrictions, StringComparison.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
public StateSource AssociatedSource()
|
||||||
|
=> StateSource.Manual;
|
||||||
|
|
||||||
|
public IEnumerable<(IDesignStandIn Design, ApplicationType Flags)> AllLinks
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
_currentDesign = rng.Design(Restrictions);
|
||||||
|
if (_currentDesign == null)
|
||||||
|
yield break;
|
||||||
|
|
||||||
|
foreach (var (link, type) in _currentDesign.AllLinks)
|
||||||
|
yield return (link, type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddData(JObject jObj)
|
||||||
|
{
|
||||||
|
jObj["Restrictions"] = Restrictions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ParseData(JObject jObj)
|
||||||
|
{
|
||||||
|
var restrictions = jObj["Restrictions"]?.ToObject<string>() ?? string.Empty;
|
||||||
|
Restrictions = restrictions;
|
||||||
|
}
|
||||||
|
}
|
||||||
91
Glamourer/Designs/RandomDesignGenerator.cs
Normal file
91
Glamourer/Designs/RandomDesignGenerator.cs
Normal file
|
|
@ -0,0 +1,91 @@
|
||||||
|
using OtterGui;
|
||||||
|
using OtterGui.Services;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Glamourer.Designs;
|
||||||
|
|
||||||
|
public class RandomDesignGenerator(DesignStorage designs, DesignFileSystem fileSystem) : IService
|
||||||
|
{
|
||||||
|
private readonly Random _rng = new();
|
||||||
|
|
||||||
|
public Design? Design(IReadOnlyList<Design> localDesigns)
|
||||||
|
{
|
||||||
|
if (localDesigns.Count == 0)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var idx = _rng.Next(0, localDesigns.Count - 1);
|
||||||
|
Glamourer.Log.Verbose($"[Random Design] Chose design {idx} out of {localDesigns.Count}: {localDesigns[idx].Incognito}.");
|
||||||
|
return localDesigns[idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
public Design? Design()
|
||||||
|
=> Design(designs);
|
||||||
|
|
||||||
|
public Design? Design(string restrictions)
|
||||||
|
{
|
||||||
|
if (restrictions.Length == 0)
|
||||||
|
return Design(designs);
|
||||||
|
|
||||||
|
List<Func<string, string, string, bool>> predicates = [];
|
||||||
|
|
||||||
|
switch (restrictions[0])
|
||||||
|
{
|
||||||
|
case '{':
|
||||||
|
var end = restrictions.IndexOf('}');
|
||||||
|
if (end == -1)
|
||||||
|
throw new ArgumentException($"The restriction group '{restrictions}' is not properly terminated.");
|
||||||
|
|
||||||
|
restrictions = restrictions[1..end];
|
||||||
|
var split = restrictions.Split(';', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
|
||||||
|
foreach (var item in split.Distinct())
|
||||||
|
predicates.Add(item[0] == '/' ? CreatePredicateSlash(item) : CreatePredicate(item));
|
||||||
|
break;
|
||||||
|
case '/':
|
||||||
|
predicates.Add(CreatePredicateSlash(restrictions));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
predicates.Add(CreatePredicate(restrictions));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (predicates.Count == 1)
|
||||||
|
{
|
||||||
|
var p = predicates[0];
|
||||||
|
return Design(designs.Select(Transform).Where(t => p(t.NameLower, t.Identifier, t.PathLower)).Select(t => t.Design).ToList());
|
||||||
|
}
|
||||||
|
|
||||||
|
return Design(designs.Select(Transform).Where(t => predicates.Any(p => p(t.NameLower, t.Identifier, t.PathLower))).Select(t => t.Design)
|
||||||
|
.ToList());
|
||||||
|
|
||||||
|
(Design Design, string NameLower, string Identifier, string PathLower) Transform(Design design)
|
||||||
|
{
|
||||||
|
var name = design.Name.Lower;
|
||||||
|
var identifier = design.Identifier.ToString();
|
||||||
|
var path = fileSystem.FindLeaf(design, out var leaf) ? leaf.FullName().ToLowerInvariant() : string.Empty;
|
||||||
|
return (design, name, identifier, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
Func<string, string, string, bool> CreatePredicate(string input)
|
||||||
|
{
|
||||||
|
var value = input.ToLowerInvariant();
|
||||||
|
return (string nameLower, string identifier, string pathLower) =>
|
||||||
|
{
|
||||||
|
if (nameLower.Contains(value))
|
||||||
|
return true;
|
||||||
|
if (identifier.Contains(value))
|
||||||
|
return true;
|
||||||
|
if (pathLower.Contains(value))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Func<string, string, string, bool> CreatePredicateSlash(string input)
|
||||||
|
{
|
||||||
|
var value = input[1..].ToLowerInvariant();
|
||||||
|
return (string nameLower, string identifier, string pathLower)
|
||||||
|
=> pathLower.StartsWith(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
41
Glamourer/Designs/RevertDesign.cs
Normal file
41
Glamourer/Designs/RevertDesign.cs
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
using Glamourer.Automation;
|
||||||
|
using Glamourer.Interop.Material;
|
||||||
|
using Glamourer.State;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
|
namespace Glamourer.Designs;
|
||||||
|
|
||||||
|
public class RevertDesign : IDesignStandIn
|
||||||
|
{
|
||||||
|
public const string SerializedName = "//Revert";
|
||||||
|
public const string ResolvedName = "Revert";
|
||||||
|
|
||||||
|
public string ResolveName(bool _)
|
||||||
|
=> ResolvedName;
|
||||||
|
|
||||||
|
public ref readonly DesignData GetDesignData(in DesignData baseRef)
|
||||||
|
=> ref baseRef;
|
||||||
|
|
||||||
|
public IReadOnlyList<(uint, MaterialValueDesign)> GetMaterialData()
|
||||||
|
=> [];
|
||||||
|
|
||||||
|
public string SerializeName()
|
||||||
|
=> SerializedName;
|
||||||
|
|
||||||
|
public bool Equals(IDesignStandIn? other)
|
||||||
|
=> other is RevertDesign;
|
||||||
|
|
||||||
|
public StateSource AssociatedSource()
|
||||||
|
=> StateSource.Game;
|
||||||
|
|
||||||
|
public IEnumerable<(IDesignStandIn Design, ApplicationType Flags)> AllLinks
|
||||||
|
{
|
||||||
|
get { yield return (this, ApplicationType.All); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddData(JObject jObj)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public void ParseData(JObject jObj)
|
||||||
|
{ }
|
||||||
|
}
|
||||||
|
|
@ -122,7 +122,7 @@ public sealed class DesignChanged()
|
||||||
/// <seealso cref="Gui.Tabs.DesignTab.DesignFileSystemSelector.OnDesignChange"/>
|
/// <seealso cref="Gui.Tabs.DesignTab.DesignFileSystemSelector.OnDesignChange"/>
|
||||||
DesignFileSystemSelector = -1,
|
DesignFileSystemSelector = -1,
|
||||||
|
|
||||||
/// <seealso cref="RevertDesignCombo.OnDesignChange"/>
|
/// <seealso cref="SpecialDesignCombo.OnDesignChange"/>
|
||||||
DesignCombo = -2,
|
DesignCombo = -2,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,26 +3,24 @@ using Dalamud.Interface.Utility.Raii;
|
||||||
using Glamourer.Automation;
|
using Glamourer.Automation;
|
||||||
using Glamourer.Designs;
|
using Glamourer.Designs;
|
||||||
using Glamourer.Events;
|
using Glamourer.Events;
|
||||||
using Glamourer.Services;
|
|
||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
using OtterGui;
|
using OtterGui;
|
||||||
using OtterGui.Classes;
|
using OtterGui.Classes;
|
||||||
using OtterGui.Log;
|
using OtterGui.Log;
|
||||||
using OtterGui.Widgets;
|
using OtterGui.Widgets;
|
||||||
using Penumbra.GameData.Enums;
|
|
||||||
|
|
||||||
namespace Glamourer.Gui;
|
namespace Glamourer.Gui;
|
||||||
|
|
||||||
public abstract class DesignComboBase : FilterComboCache<Tuple<Design, string>>, IDisposable
|
public abstract class DesignComboBase : FilterComboCache<Tuple<IDesignStandIn, string>>, IDisposable
|
||||||
{
|
{
|
||||||
private readonly EphemeralConfig _config;
|
private readonly EphemeralConfig _config;
|
||||||
private readonly DesignChanged _designChanged;
|
private readonly DesignChanged _designChanged;
|
||||||
private readonly DesignColors _designColors;
|
private readonly DesignColors _designColors;
|
||||||
protected readonly TabSelected TabSelected;
|
protected readonly TabSelected TabSelected;
|
||||||
protected float InnerWidth;
|
protected float InnerWidth;
|
||||||
private Design? _currentDesign;
|
private IDesignStandIn? _currentDesign;
|
||||||
|
|
||||||
protected DesignComboBase(Func<IReadOnlyList<Tuple<Design, string>>> generator, Logger log, DesignChanged designChanged,
|
protected DesignComboBase(Func<IReadOnlyList<Tuple<IDesignStandIn, string>>> generator, Logger log, DesignChanged designChanged,
|
||||||
TabSelected tabSelected, EphemeralConfig config, DesignColors designColors)
|
TabSelected tabSelected, EphemeralConfig config, DesignColors designColors)
|
||||||
: base(generator, MouseWheelType.Control, log)
|
: base(generator, MouseWheelType.Control, log)
|
||||||
{
|
{
|
||||||
|
|
@ -46,28 +44,34 @@ public abstract class DesignComboBase : FilterComboCache<Tuple<Design, string>>,
|
||||||
{
|
{
|
||||||
var (design, path) = Items[globalIdx];
|
var (design, path) = Items[globalIdx];
|
||||||
bool ret;
|
bool ret;
|
||||||
using (var color = ImRaii.PushColor(ImGuiCol.Text, _designColors.GetColor(design)))
|
if (design is Design realDesign)
|
||||||
|
{
|
||||||
|
using var color = ImRaii.PushColor(ImGuiCol.Text, _designColors.GetColor(realDesign));
|
||||||
|
ret = base.DrawSelectable(globalIdx, selected);
|
||||||
|
|
||||||
|
if (path.Length > 0 && realDesign.Name != path)
|
||||||
|
{
|
||||||
|
var start = ImGui.GetItemRectMin();
|
||||||
|
var pos = start.X + ImGui.CalcTextSize(realDesign.Name).X;
|
||||||
|
var maxSize = ImGui.GetWindowPos().X + ImGui.GetWindowContentRegionMax().X;
|
||||||
|
var remainingSpace = maxSize - pos;
|
||||||
|
var requiredSize = ImGui.CalcTextSize(path).X + ImGui.GetStyle().ItemInnerSpacing.X;
|
||||||
|
var offset = remainingSpace - requiredSize;
|
||||||
|
if (ImGui.GetScrollMaxY() == 0)
|
||||||
|
offset -= ImGui.GetStyle().ItemInnerSpacing.X;
|
||||||
|
|
||||||
|
if (offset < ImGui.GetStyle().ItemSpacing.X)
|
||||||
|
ImGuiUtil.HoverTooltip(path);
|
||||||
|
else
|
||||||
|
ImGui.GetWindowDrawList().AddText(start with { X = pos + offset },
|
||||||
|
ImGui.GetColorU32(ImGuiCol.TextDisabled), path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
ret = base.DrawSelectable(globalIdx, selected);
|
ret = base.DrawSelectable(globalIdx, selected);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (path.Length > 0 && design.Name != path)
|
|
||||||
{
|
|
||||||
var start = ImGui.GetItemRectMin();
|
|
||||||
var pos = start.X + ImGui.CalcTextSize(design.Name).X;
|
|
||||||
var maxSize = ImGui.GetWindowPos().X + ImGui.GetWindowContentRegionMax().X;
|
|
||||||
var remainingSpace = maxSize - pos;
|
|
||||||
var requiredSize = ImGui.CalcTextSize(path).X + ImGui.GetStyle().ItemInnerSpacing.X;
|
|
||||||
var offset = remainingSpace - requiredSize;
|
|
||||||
if (ImGui.GetScrollMaxY() == 0)
|
|
||||||
offset -= ImGui.GetStyle().ItemInnerSpacing.X;
|
|
||||||
|
|
||||||
if (offset < ImGui.GetStyle().ItemSpacing.X)
|
|
||||||
ImGuiUtil.HoverTooltip(path);
|
|
||||||
else
|
|
||||||
ImGui.GetWindowDrawList().AddText(start with { X = pos + offset },
|
|
||||||
ImGui.GetColorU32(ImGuiCol.TextDisabled), path);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
@ -79,22 +83,22 @@ public abstract class DesignComboBase : FilterComboCache<Tuple<Design, string>>,
|
||||||
return CurrentSelectionIdx;
|
return CurrentSelectionIdx;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected bool Draw(Design? currentDesign, string? label, float width)
|
protected bool Draw(IDesignStandIn? currentDesign, string? label, float width)
|
||||||
{
|
{
|
||||||
_currentDesign = currentDesign;
|
_currentDesign = currentDesign;
|
||||||
InnerWidth = 400 * ImGuiHelpers.GlobalScale;
|
InnerWidth = 400 * ImGuiHelpers.GlobalScale;
|
||||||
var name = label ?? "Select Design Here...";
|
var name = label ?? "Select Design Here...";
|
||||||
bool ret;
|
bool ret;
|
||||||
using (_ = currentDesign != null ? ImRaii.PushColor(ImGuiCol.Text, _designColors.GetColor(currentDesign)) : null)
|
using (_ = currentDesign != null ? ImRaii.PushColor(ImGuiCol.Text, _designColors.GetColor(currentDesign as Design)) : null)
|
||||||
{
|
{
|
||||||
ret = Draw("##design", name, string.Empty, width, ImGui.GetTextLineHeightWithSpacing())
|
ret = Draw("##design", name, string.Empty, width, ImGui.GetTextLineHeightWithSpacing())
|
||||||
&& CurrentSelection != null;
|
&& CurrentSelection != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentDesign != null)
|
if (currentDesign is Design design)
|
||||||
{
|
{
|
||||||
if (ImGui.IsItemClicked(ImGuiMouseButton.Right) && ImGui.GetIO().KeyCtrl)
|
if (ImGui.IsItemClicked(ImGuiMouseButton.Right) && ImGui.GetIO().KeyCtrl)
|
||||||
TabSelected.Invoke(MainWindow.TabType.Designs, currentDesign);
|
TabSelected.Invoke(MainWindow.TabType.Designs, design);
|
||||||
ImGuiUtil.HoverTooltip("Control + Right-Click to move to design.");
|
ImGuiUtil.HoverTooltip("Control + Right-Click to move to design.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -102,8 +106,8 @@ public abstract class DesignComboBase : FilterComboCache<Tuple<Design, string>>,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override string ToString(Tuple<Design, string> obj)
|
protected override string ToString(Tuple<IDesignStandIn, string> obj)
|
||||||
=> obj.Item1.Name.Text;
|
=> obj.Item1.ResolveName(Incognito);
|
||||||
|
|
||||||
protected override float GetFilterWidth()
|
protected override float GetFilterWidth()
|
||||||
=> InnerWidth - 2 * ImGui.GetStyle().FramePadding.X;
|
=> InnerWidth - 2 * ImGui.GetStyle().FramePadding.X;
|
||||||
|
|
@ -111,7 +115,7 @@ public abstract class DesignComboBase : FilterComboCache<Tuple<Design, string>>,
|
||||||
protected override bool IsVisible(int globalIndex, LowerString filter)
|
protected override bool IsVisible(int globalIndex, LowerString filter)
|
||||||
{
|
{
|
||||||
var (design, path) = Items[globalIndex];
|
var (design, path) = Items[globalIndex];
|
||||||
return filter.IsContained(path) || design.Name.Lower.Contains(filter.Lower);
|
return filter.IsContained(path) || filter.IsContained(design.ResolveName(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnDesignChange(DesignChanged.Type type, Design design, object? data = null)
|
private void OnDesignChange(DesignChanged.Type type, Design design, object? data = null)
|
||||||
|
|
@ -151,7 +155,7 @@ public abstract class DesignComboBase : FilterComboCache<Tuple<Design, string>>,
|
||||||
public abstract class DesignCombo : DesignComboBase
|
public abstract class DesignCombo : DesignComboBase
|
||||||
{
|
{
|
||||||
protected DesignCombo(Logger log, DesignChanged designChanged, TabSelected tabSelected,
|
protected DesignCombo(Logger log, DesignChanged designChanged, TabSelected tabSelected,
|
||||||
EphemeralConfig config, DesignColors designColors, Func<IReadOnlyList<Tuple<Design, string>>> generator)
|
EphemeralConfig config, DesignColors designColors, Func<IReadOnlyList<Tuple<IDesignStandIn, string>>> generator)
|
||||||
: base(generator, log, designChanged, tabSelected, config, designColors)
|
: base(generator, log, designChanged, tabSelected, config, designColors)
|
||||||
{
|
{
|
||||||
if (Items.Count == 0)
|
if (Items.Count == 0)
|
||||||
|
|
@ -162,11 +166,11 @@ public abstract class DesignCombo : DesignComboBase
|
||||||
base.Cleanup();
|
base.Cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Design? Design
|
public IDesignStandIn? Design
|
||||||
=> CurrentSelection?.Item1;
|
=> CurrentSelection?.Item1;
|
||||||
|
|
||||||
public void Draw(float width)
|
public void Draw(float width)
|
||||||
=> Draw(Design, (Incognito ? Design?.Incognito : Design?.Name.Text) ?? string.Empty, width);
|
=> Draw(Design, Design?.ResolveName(Incognito) ?? string.Empty, width);
|
||||||
}
|
}
|
||||||
|
|
||||||
public sealed class QuickDesignCombo : DesignCombo
|
public sealed class QuickDesignCombo : DesignCombo
|
||||||
|
|
@ -182,7 +186,7 @@ public sealed class QuickDesignCombo : DesignCombo
|
||||||
[
|
[
|
||||||
.. designs.Designs
|
.. designs.Designs
|
||||||
.Where(d => d.QuickDesign)
|
.Where(d => d.QuickDesign)
|
||||||
.Select(d => new Tuple<Design, string>(d, fileSystem.FindLeaf(d, out var l) ? l.FullName() : string.Empty))
|
.Select(d => new Tuple<IDesignStandIn, string>(d, fileSystem.FindLeaf(d, out var l) ? l.FullName() : string.Empty))
|
||||||
.OrderBy(d => d.Item2),
|
.OrderBy(d => d.Item2),
|
||||||
])
|
])
|
||||||
=> AllowMouseWheel = MouseWheelType.Unmodified;
|
=> AllowMouseWheel = MouseWheelType.Unmodified;
|
||||||
|
|
@ -199,51 +203,35 @@ public sealed class LinkDesignCombo(
|
||||||
: DesignCombo(log, designChanged, tabSelected, config, designColors, () =>
|
: DesignCombo(log, designChanged, tabSelected, config, designColors, () =>
|
||||||
[
|
[
|
||||||
.. designs.Designs
|
.. designs.Designs
|
||||||
.Select(d => new Tuple<Design, string>(d, fileSystem.FindLeaf(d, out var l) ? l.FullName() : string.Empty))
|
.Select(d => new Tuple<IDesignStandIn, string>(d, fileSystem.FindLeaf(d, out var l) ? l.FullName() : string.Empty))
|
||||||
.OrderBy(d => d.Item2),
|
.OrderBy(d => d.Item2),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
public sealed class RevertDesignCombo : DesignComboBase
|
public sealed class SpecialDesignCombo(
|
||||||
|
DesignManager designs,
|
||||||
|
DesignFileSystem fileSystem,
|
||||||
|
TabSelected tabSelected,
|
||||||
|
DesignColors designColors,
|
||||||
|
Logger log,
|
||||||
|
DesignChanged designChanged,
|
||||||
|
AutoDesignManager autoDesignManager,
|
||||||
|
EphemeralConfig config,
|
||||||
|
RandomDesignGenerator rng)
|
||||||
|
: DesignComboBase(() => designs.Designs
|
||||||
|
.Select(d => new Tuple<IDesignStandIn, string>(d, fileSystem.FindLeaf(d, out var l) ? l.FullName() : string.Empty))
|
||||||
|
.OrderBy(d => d.Item2)
|
||||||
|
.Prepend(new Tuple<IDesignStandIn, string>(new RandomDesign(rng), string.Empty))
|
||||||
|
.Prepend(new Tuple<IDesignStandIn, string>(new RevertDesign(), string.Empty))
|
||||||
|
.ToList(), log, designChanged, tabSelected, config, designColors)
|
||||||
{
|
{
|
||||||
public const int RevertDesignIndex = -1228;
|
|
||||||
public readonly Design RevertDesign;
|
|
||||||
private readonly AutoDesignManager _autoDesignManager;
|
|
||||||
|
|
||||||
public RevertDesignCombo(DesignManager designs, DesignFileSystem fileSystem, TabSelected tabSelected, DesignColors designColors,
|
|
||||||
ItemManager items, CustomizeService customize, Logger log, DesignChanged designChanged, AutoDesignManager autoDesignManager,
|
|
||||||
EphemeralConfig config)
|
|
||||||
: this(designs, fileSystem, tabSelected, designColors, CreateRevertDesign(customize, items), log, designChanged, autoDesignManager,
|
|
||||||
config)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
private RevertDesignCombo(DesignManager designs, DesignFileSystem fileSystem, TabSelected tabSelected, DesignColors designColors,
|
|
||||||
Design revertDesign, Logger log, DesignChanged designChanged, AutoDesignManager autoDesignManager, EphemeralConfig config)
|
|
||||||
: base(() => designs.Designs
|
|
||||||
.Select(d => new Tuple<Design, string>(d, fileSystem.FindLeaf(d, out var l) ? l.FullName() : string.Empty))
|
|
||||||
.OrderBy(d => d.Item2)
|
|
||||||
.Prepend(new Tuple<Design, string>(revertDesign, string.Empty))
|
|
||||||
.ToList(), log, designChanged, tabSelected, config, designColors)
|
|
||||||
{
|
|
||||||
RevertDesign = revertDesign;
|
|
||||||
_autoDesignManager = autoDesignManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Draw(AutoDesignSet set, AutoDesign? design, int autoDesignIndex)
|
public void Draw(AutoDesignSet set, AutoDesign? design, int autoDesignIndex)
|
||||||
{
|
{
|
||||||
if (!Draw(design?.Design, design?.Name(Incognito), ImGui.GetContentRegionAvail().X))
|
if (!Draw(design?.Design, design?.Design.ResolveName(Incognito), ImGui.GetContentRegionAvail().X))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (autoDesignIndex >= 0)
|
if (autoDesignIndex >= 0)
|
||||||
_autoDesignManager.ChangeDesign(set, autoDesignIndex, CurrentSelection!.Item1 == RevertDesign ? null : CurrentSelection!.Item1);
|
autoDesignManager.ChangeDesign(set, autoDesignIndex, CurrentSelection!.Item1);
|
||||||
else
|
else
|
||||||
_autoDesignManager.AddDesign(set, CurrentSelection!.Item1 == RevertDesign ? null : CurrentSelection!.Item1);
|
autoDesignManager.AddDesign(set, CurrentSelection!.Item1);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Design CreateRevertDesign(CustomizeService customize, ItemManager items)
|
|
||||||
=> new(customize, items)
|
|
||||||
{
|
|
||||||
Index = RevertDesignIndex,
|
|
||||||
Name = AutoDesign.RevertName,
|
|
||||||
ApplyCustomize = CustomizeFlagExtensions.AllRelevant,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -123,7 +123,7 @@ public sealed class DesignQuickBar : Window, IDisposable
|
||||||
|
|
||||||
private void DrawApplyButton(Vector2 size)
|
private void DrawApplyButton(Vector2 size)
|
||||||
{
|
{
|
||||||
var design = _designCombo.Design;
|
var design = _designCombo.Design as Design;
|
||||||
var available = 0;
|
var available = 0;
|
||||||
var tooltip = string.Empty;
|
var tooltip = string.Empty;
|
||||||
if (design == null)
|
if (design == null)
|
||||||
|
|
@ -135,7 +135,7 @@ public sealed class DesignQuickBar : Window, IDisposable
|
||||||
if (_playerIdentifier.IsValid && _playerData.Valid)
|
if (_playerIdentifier.IsValid && _playerData.Valid)
|
||||||
{
|
{
|
||||||
available |= 1;
|
available |= 1;
|
||||||
tooltip = $"Left-Click: Apply {(_config.Ephemeral.IncognitoMode ? design.Incognito : design.Name)} to yourself.";
|
tooltip = $"Left-Click: Apply {design.ResolveName(_config.Ephemeral.IncognitoMode)} to yourself.";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_targetIdentifier.IsValid && _targetData.Valid)
|
if (_targetIdentifier.IsValid && _targetData.Valid)
|
||||||
|
|
@ -143,7 +143,7 @@ public sealed class DesignQuickBar : Window, IDisposable
|
||||||
if (available != 0)
|
if (available != 0)
|
||||||
tooltip += '\n';
|
tooltip += '\n';
|
||||||
available |= 2;
|
available |= 2;
|
||||||
tooltip += $"Right-Click: Apply {(_config.Ephemeral.IncognitoMode ? design.Incognito : design.Name)} to {_targetIdentifier}.";
|
tooltip += $"Right-Click: Apply {design.ResolveName(_config.Ephemeral.IncognitoMode)} to {_targetIdentifier}.";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (available == 0)
|
if (available == 0)
|
||||||
|
|
@ -157,7 +157,7 @@ public sealed class DesignQuickBar : Window, IDisposable
|
||||||
|
|
||||||
if (state == null && !_stateManager.GetOrCreate(id, data.Objects[0], out state))
|
if (state == null && !_stateManager.GetOrCreate(id, data.Objects[0], out state))
|
||||||
{
|
{
|
||||||
Glamourer.Messager.NotificationMessage($"Could not apply {design!.Incognito} to {id.Incognito(null)}: Failed to create state.");
|
Glamourer.Messager.NotificationMessage($"Could not apply {design!.ResolveName(true)} to {id.Incognito(null)}: Failed to create state.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
using Dalamud.Interface;
|
using Dalamud.Interface;
|
||||||
using Dalamud.Interface.Utility;
|
using Dalamud.Interface.Utility;
|
||||||
using Glamourer.Automation;
|
using Glamourer.Automation;
|
||||||
|
using Glamourer.Designs;
|
||||||
using Glamourer.Interop;
|
using Glamourer.Interop;
|
||||||
using Glamourer.Services;
|
using Glamourer.Services;
|
||||||
using Glamourer.Unlocks;
|
using Glamourer.Unlocks;
|
||||||
|
|
@ -20,7 +21,7 @@ public class SetPanel(
|
||||||
AutoDesignManager _manager,
|
AutoDesignManager _manager,
|
||||||
JobService _jobs,
|
JobService _jobs,
|
||||||
ItemUnlockManager _itemUnlocks,
|
ItemUnlockManager _itemUnlocks,
|
||||||
RevertDesignCombo _designCombo,
|
SpecialDesignCombo _designCombo,
|
||||||
CustomizeUnlockManager _customizeUnlocks,
|
CustomizeUnlockManager _customizeUnlocks,
|
||||||
CustomizeService _customizations,
|
CustomizeService _customizations,
|
||||||
IdentifierDrawer _identifierDrawer,
|
IdentifierDrawer _identifierDrawer,
|
||||||
|
|
@ -258,21 +259,22 @@ public class SetPanel(
|
||||||
|
|
||||||
private void DrawWarnings(AutoDesign design)
|
private void DrawWarnings(AutoDesign design)
|
||||||
{
|
{
|
||||||
if (design.Revert)
|
if (design.Design is not DesignBase)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var size = new Vector2(ImGui.GetFrameHeight());
|
var size = new Vector2(ImGui.GetFrameHeight());
|
||||||
size.X += ImGuiHelpers.GlobalScale;
|
size.X += ImGuiHelpers.GlobalScale;
|
||||||
|
|
||||||
var (equipFlags, customizeFlags, _, _, _) = design.ApplyWhat();
|
var (equipFlags, customizeFlags, _, _, _) = design.ApplyWhat();
|
||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
|
var designData = design.Design.GetDesignData(default);
|
||||||
foreach (var slot in EquipSlotExtensions.EqdpSlots.Append(EquipSlot.MainHand).Append(EquipSlot.OffHand))
|
foreach (var slot in EquipSlotExtensions.EqdpSlots.Append(EquipSlot.MainHand).Append(EquipSlot.OffHand))
|
||||||
{
|
{
|
||||||
var flag = slot.ToFlag();
|
var flag = slot.ToFlag();
|
||||||
if (!equipFlags.HasFlag(flag))
|
if (!equipFlags.HasFlag(flag))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var item = design.Design!.DesignData.Item(slot);
|
var item = designData.Item(slot);
|
||||||
if (!_itemUnlocks.IsUnlocked(item.Id, out _))
|
if (!_itemUnlocks.IsUnlocked(item.Id, out _))
|
||||||
sb.AppendLine($"{item.Name} in {slot.ToName()} slot is not unlocked. Consider obtaining it via gameplay means!");
|
sb.AppendLine($"{item.Name} in {slot.ToName()} slot is not unlocked. Consider obtaining it via gameplay means!");
|
||||||
}
|
}
|
||||||
|
|
@ -286,8 +288,8 @@ public class SetPanel(
|
||||||
|
|
||||||
sb.Clear();
|
sb.Clear();
|
||||||
var sb2 = new StringBuilder();
|
var sb2 = new StringBuilder();
|
||||||
var customize = design.Design!.DesignData.Customize;
|
var customize = designData.Customize;
|
||||||
if (!design.Design.DesignData.IsHuman)
|
if (!designData.IsHuman)
|
||||||
sb.AppendLine("The base model id can not be changed automatically to something non-human.");
|
sb.AppendLine("The base model id can not be changed automatically to something non-human.");
|
||||||
|
|
||||||
var set = _customizations.Manager.GetSet(customize.Clan, customize.Gender);
|
var set = _customizations.Manager.GetSet(customize.Clan, customize.Gender);
|
||||||
|
|
|
||||||
|
|
@ -41,7 +41,7 @@ public class AutoDesignPanel(AutoDesignManager _autoDesignManager) : IGameDataDr
|
||||||
|
|
||||||
foreach (var (design, designIdx) in set.Designs.WithIndex())
|
foreach (var (design, designIdx) in set.Designs.WithIndex())
|
||||||
{
|
{
|
||||||
ImGuiUtil.DrawTableColumn($"{design.Name(false)} ({designIdx})");
|
ImGuiUtil.DrawTableColumn($"{design.Design.ResolveName(false)} ({designIdx})");
|
||||||
ImGuiUtil.DrawTableColumn($"{design.Type} {design.Jobs.Name}");
|
ImGuiUtil.DrawTableColumn($"{design.Type} {design.Jobs.Name}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -152,32 +152,33 @@ public class DesignLinkDrawer(DesignLinkManager _linkManager, DesignFileSystemSe
|
||||||
ImGui.TableNextColumn();
|
ImGui.TableNextColumn();
|
||||||
string ttBefore, ttAfter;
|
string ttBefore, ttAfter;
|
||||||
bool canAddBefore, canAddAfter;
|
bool canAddBefore, canAddAfter;
|
||||||
if (_combo.Design == null)
|
var design = _combo.Design as Design;
|
||||||
|
if (design == null)
|
||||||
{
|
{
|
||||||
ttAfter = ttBefore = "Select a design first.";
|
ttAfter = ttBefore = "Select a design first.";
|
||||||
canAddBefore = canAddAfter = false;
|
canAddBefore = canAddAfter = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
canAddBefore = LinkContainer.CanAddLink(_selector.Selected!, _combo.Design, LinkOrder.Before, out var error);
|
canAddBefore = LinkContainer.CanAddLink(_selector.Selected!, design, LinkOrder.Before, out var error);
|
||||||
ttBefore = canAddBefore
|
ttBefore = canAddBefore
|
||||||
? $"Add a link at the top of the list to {_combo.Design.Name}."
|
? $"Add a link at the top of the list to {design.Name}."
|
||||||
: $"Can not add a link to {_combo.Design.Name}:\n{error}";
|
: $"Can not add a link to {design.Name}:\n{error}";
|
||||||
canAddAfter = LinkContainer.CanAddLink(_selector.Selected!, _combo.Design, LinkOrder.After, out error);
|
canAddAfter = LinkContainer.CanAddLink(_selector.Selected!, design, LinkOrder.After, out error);
|
||||||
ttAfter = canAddAfter
|
ttAfter = canAddAfter
|
||||||
? $"Add a link at the bottom of the list to {_combo.Design.Name}."
|
? $"Add a link at the bottom of the list to {design.Name}."
|
||||||
: $"Can not add a link to {_combo.Design.Name}:\n{error}";
|
: $"Can not add a link to {design.Name}:\n{error}";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.ArrowCircleUp.ToIconString(), buttonSize, ttBefore, !canAddBefore, true))
|
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.ArrowCircleUp.ToIconString(), buttonSize, ttBefore, !canAddBefore, true))
|
||||||
{
|
{
|
||||||
_linkManager.AddDesignLink(_selector.Selected!, _combo.Design!, LinkOrder.Before);
|
_linkManager.AddDesignLink(_selector.Selected!, design!, LinkOrder.Before);
|
||||||
_linkManager.MoveDesignLink(_selector.Selected!, _selector.Selected!.Links.Before.Count - 1, LinkOrder.Before, 0, LinkOrder.Before);
|
_linkManager.MoveDesignLink(_selector.Selected!, _selector.Selected!.Links.Before.Count - 1, LinkOrder.Before, 0, LinkOrder.Before);
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.ArrowCircleDown.ToIconString(), buttonSize, ttAfter, !canAddAfter, true))
|
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.ArrowCircleDown.ToIconString(), buttonSize, ttAfter, !canAddAfter, true))
|
||||||
_linkManager.AddDesignLink(_selector.Selected!, _combo.Design!, LinkOrder.After);
|
_linkManager.AddDesignLink(_selector.Selected!, design!, LinkOrder.After);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DrawDragDrop(Design design, LinkOrder order, int index)
|
private void DrawDragDrop(Design design, LinkOrder order, int index)
|
||||||
|
|
|
||||||
|
|
@ -19,28 +19,30 @@ namespace Glamourer.Services;
|
||||||
|
|
||||||
public class CommandService : IDisposable
|
public class CommandService : IDisposable
|
||||||
{
|
{
|
||||||
|
private const string RandomString = "random";
|
||||||
private const string MainCommandString = "/glamourer";
|
private const string MainCommandString = "/glamourer";
|
||||||
private const string ApplyCommandString = "/glamour";
|
private const string ApplyCommandString = "/glamour";
|
||||||
|
|
||||||
private readonly ICommandManager _commands;
|
private readonly ICommandManager _commands;
|
||||||
private readonly MainWindow _mainWindow;
|
private readonly MainWindow _mainWindow;
|
||||||
private readonly IChatGui _chat;
|
private readonly IChatGui _chat;
|
||||||
private readonly ActorManager _actors;
|
private readonly ActorManager _actors;
|
||||||
private readonly ObjectManager _objects;
|
private readonly ObjectManager _objects;
|
||||||
private readonly StateManager _stateManager;
|
private readonly StateManager _stateManager;
|
||||||
private readonly AutoDesignApplier _autoDesignApplier;
|
private readonly AutoDesignApplier _autoDesignApplier;
|
||||||
private readonly AutoDesignManager _autoDesignManager;
|
private readonly AutoDesignManager _autoDesignManager;
|
||||||
private readonly DesignManager _designManager;
|
private readonly DesignManager _designManager;
|
||||||
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 ModSettingApplier _modApplier;
|
private readonly ModSettingApplier _modApplier;
|
||||||
private readonly ItemManager _items;
|
private readonly ItemManager _items;
|
||||||
|
private readonly RandomDesignGenerator _randomDesign;
|
||||||
|
|
||||||
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, ModSettingApplier modApplier,
|
DesignFileSystem designFileSystem, AutoDesignManager autoDesignManager, Configuration config, ModSettingApplier modApplier,
|
||||||
ItemManager items)
|
ItemManager items, RandomDesignGenerator randomDesign)
|
||||||
{
|
{
|
||||||
_commands = commands;
|
_commands = commands;
|
||||||
_mainWindow = mainWindow;
|
_mainWindow = mainWindow;
|
||||||
|
|
@ -56,6 +58,7 @@ public class CommandService : IDisposable
|
||||||
_config = config;
|
_config = config;
|
||||||
_modApplier = modApplier;
|
_modApplier = modApplier;
|
||||||
_items = items;
|
_items = items;
|
||||||
|
_randomDesign = randomDesign;
|
||||||
|
|
||||||
_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,
|
||||||
|
|
@ -394,7 +397,8 @@ public class CommandService : IDisposable
|
||||||
if (_items.ItemData.Primary.TryGetValue(id, out var main))
|
if (_items.ItemData.Primary.TryGetValue(id, out var main))
|
||||||
items[0] = main;
|
items[0] = main;
|
||||||
}
|
}
|
||||||
else if (_items.ItemData.Primary.FindFirst(pair => string.Equals(pair.Value.Name, split[0], StringComparison.OrdinalIgnoreCase), out var i))
|
else if (_items.ItemData.Primary.FindFirst(pair => string.Equals(pair.Value.Name, split[0], StringComparison.OrdinalIgnoreCase),
|
||||||
|
out var i))
|
||||||
{
|
{
|
||||||
items[0] = i.Value;
|
items[0] = i.Value;
|
||||||
}
|
}
|
||||||
|
|
@ -448,7 +452,8 @@ public class CommandService : IDisposable
|
||||||
var split = arguments.Split('|', 2, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
|
var split = arguments.Split('|', 2, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
|
||||||
if (split.Length is not 2)
|
if (split.Length is not 2)
|
||||||
{
|
{
|
||||||
_chat.Print(new SeStringBuilder().AddText("Use with /glamour apply ").AddYellow("[Design Name, Path or Identifier, or Clipboard]")
|
_chat.Print(new SeStringBuilder().AddText("Use with /glamour apply ")
|
||||||
|
.AddYellow("[Design Name, Path or Identifier, Random, or Clipboard]")
|
||||||
.AddText(" | ")
|
.AddText(" | ")
|
||||||
.AddGreen("[Character Identifier]")
|
.AddGreen("[Character Identifier]")
|
||||||
.AddText("; ")
|
.AddText("; ")
|
||||||
|
|
@ -467,6 +472,13 @@ public class CommandService : IDisposable
|
||||||
.BuiltString);
|
.BuiltString);
|
||||||
_chat.Print(new SeStringBuilder()
|
_chat.Print(new SeStringBuilder()
|
||||||
.AddText(" 》 Clipboard as a single word will try to apply a design string currently in your clipboard.").BuiltString);
|
.AddText(" 》 Clipboard as a single word will try to apply a design string currently in your clipboard.").BuiltString);
|
||||||
|
_chat.Print(new SeStringBuilder()
|
||||||
|
.AddText(" 》 ").AddYellow("Random").AddText(" supports the following restrictions:").BuiltString);
|
||||||
|
_chat.Print(new SeStringBuilder()
|
||||||
|
.AddText(" 》》》 ").AddYellow("Random").AddText(", choosing a random design out of all your designs.").BuiltString);
|
||||||
|
_chat.Print(new SeStringBuilder().AddText(" 》》》 ").AddYellow("Random:{List of [text] or /[text]}").AddText(", containing a list of restrictions within swirly braces, separated by semicolons.").BuiltString);
|
||||||
|
_chat.Print(new SeStringBuilder().AddText(" 》》》 ").AddYellow("Random:[text]").AddText(", choosing a random design where the path, name or identifier contains 'text' (no brackets).").BuiltString);
|
||||||
|
_chat.Print(new SeStringBuilder().AddText(" 》》》 ").AddYellow("Random:/[text]").AddText(", choosing a random design where the path starts with 'text' (no brackets).").BuiltString);
|
||||||
_chat.Print(new SeStringBuilder()
|
_chat.Print(new SeStringBuilder()
|
||||||
.AddText(" 》 ").AddBlue("<Enable Mods>").AddText(" is optional and can be omitted (together with the ;), ").AddBlue("true")
|
.AddText(" 》 ").AddBlue("<Enable Mods>").AddText(" is optional and can be omitted (together with the ;), ").AddBlue("true")
|
||||||
.AddText(" or ").AddBlue("false").AddText(".").BuiltString);
|
.AddText(" or ").AddBlue("false").AddText(".").BuiltString);
|
||||||
|
|
@ -628,30 +640,57 @@ public class CommandService : IDisposable
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool GetDesign(string argument, [NotNullWhen(true)] out DesignBase? design, bool allowClipboard)
|
private bool GetDesign(string argument, [NotNullWhen(true)] out DesignBase? design, bool allowSpecial)
|
||||||
{
|
{
|
||||||
design = null;
|
design = null;
|
||||||
if (argument.Length == 0)
|
if (argument.Length == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (allowClipboard && string.Equals("clipboard", argument, StringComparison.OrdinalIgnoreCase))
|
if (allowSpecial)
|
||||||
{
|
{
|
||||||
try
|
if (string.Equals("clipboard", argument, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
var clipboardText = ImGui.GetClipboardText();
|
try
|
||||||
if (clipboardText.Length > 0)
|
{
|
||||||
design = _converter.FromBase64(clipboardText, true, true, out _);
|
var clipboardText = ImGui.GetClipboardText();
|
||||||
}
|
if (clipboardText.Length > 0)
|
||||||
catch
|
design = _converter.FromBase64(clipboardText, true, true, out _);
|
||||||
{
|
}
|
||||||
// ignored
|
catch
|
||||||
|
{
|
||||||
|
// ignored
|
||||||
|
}
|
||||||
|
|
||||||
|
if (design != null)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
_chat.Print(new SeStringBuilder().AddText("Your current clipboard did not contain a valid design string.").BuiltString);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (design != null)
|
if (argument.StartsWith(RandomString, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (argument.Length == RandomString.Length)
|
||||||
|
design = _randomDesign.Design();
|
||||||
|
else if (argument[RandomString.Length] == ':')
|
||||||
|
design = _randomDesign.Design(argument[(RandomString.Length + 1)..]);
|
||||||
|
if (design == null)
|
||||||
|
{
|
||||||
|
_chat.Print(new SeStringBuilder().AddText("No design matched your restrictions.").BuiltString);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
_chat.Print($"Chose random design {((Design)design).Name}.");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_chat.Print(new SeStringBuilder().AddText($"Error in the restriction string: {ex.Message}").BuiltString);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
_chat.Print(new SeStringBuilder().AddText("Your current clipboard did not contain a valid design string.").BuiltString);
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Guid.TryParse(argument, out var guid))
|
if (Guid.TryParse(argument, out var guid))
|
||||||
|
|
|
||||||
|
|
@ -149,7 +149,7 @@ public static class ServiceManagerA
|
||||||
.AddSingleton<DesignTab>()
|
.AddSingleton<DesignTab>()
|
||||||
.AddSingleton<QuickDesignCombo>()
|
.AddSingleton<QuickDesignCombo>()
|
||||||
.AddSingleton<LinkDesignCombo>()
|
.AddSingleton<LinkDesignCombo>()
|
||||||
.AddSingleton<RevertDesignCombo>()
|
.AddSingleton<SpecialDesignCombo>()
|
||||||
.AddSingleton<ModAssociationsTab>()
|
.AddSingleton<ModAssociationsTab>()
|
||||||
.AddSingleton<DesignDetailTab>()
|
.AddSingleton<DesignDetailTab>()
|
||||||
.AddSingleton<UnlockTable>()
|
.AddSingleton<UnlockTable>()
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit 44021b93e6901c84b739bbf4d1c6350f4486cdbf
|
Subproject commit d0db2f1fbc3ce26d0756da5118157e5fc723c62f
|
||||||
Loading…
Add table
Add a link
Reference in a new issue