This commit is contained in:
Ottermandias 2024-01-20 15:13:23 +01:00
parent 1a409d475a
commit c7430e59b3
35 changed files with 1118 additions and 376 deletions

View file

@ -0,0 +1,62 @@
using Glamourer.Designs;
using Glamourer.GameData;
using Penumbra.GameData.Enums;
namespace Glamourer.Automation;
[Flags]
public enum ApplicationType : byte
{
Armor = 0x01,
Customizations = 0x02,
Weapons = 0x04,
GearCustomization = 0x08,
Accessories = 0x10,
All = Armor | Accessories | Customizations | Weapons | GearCustomization,
}
public static class ApplicationTypeExtensions
{
public static (EquipFlag Equip, CustomizeFlag Customize, CrestFlag Crest, CustomizeParameterFlag Parameters, bool ApplyHat, bool ApplyVisor,
bool
ApplyWeapon, bool ApplyWet) ApplyWhat(this ApplicationType type, DesignBase? design)
{
var equipFlags = (type.HasFlag(ApplicationType.Weapons) ? WeaponFlags : 0)
| (type.HasFlag(ApplicationType.Armor) ? ArmorFlags : 0)
| (type.HasFlag(ApplicationType.Accessories) ? AccessoryFlags : 0)
| (type.HasFlag(ApplicationType.GearCustomization) ? StainFlags : 0);
var customizeFlags = type.HasFlag(ApplicationType.Customizations) ? CustomizeFlagExtensions.All : 0;
var parameterFlags = type.HasFlag(ApplicationType.Customizations) ? CustomizeParameterExtensions.All : 0;
var crestFlag = type.HasFlag(ApplicationType.GearCustomization) ? CrestExtensions.AllRelevant : 0;
if (design == null)
return (equipFlags, customizeFlags, crestFlag, parameterFlags, type.HasFlag(ApplicationType.Armor),
type.HasFlag(ApplicationType.Armor),
type.HasFlag(ApplicationType.Weapons), type.HasFlag(ApplicationType.Customizations));
return (equipFlags & design!.ApplyEquip, customizeFlags & design.ApplyCustomize, crestFlag & design.ApplyCrest,
parameterFlags & design.ApplyParameters,
type.HasFlag(ApplicationType.Armor) && design.DoApplyHatVisible(),
type.HasFlag(ApplicationType.Armor) && design.DoApplyVisorToggle(),
type.HasFlag(ApplicationType.Weapons) && design.DoApplyWeaponVisible(),
type.HasFlag(ApplicationType.Customizations) && design.DoApplyWetness());
}
public const EquipFlag WeaponFlags = EquipFlag.Mainhand | EquipFlag.Offhand;
public const EquipFlag ArmorFlags = EquipFlag.Head | EquipFlag.Body | EquipFlag.Hands | EquipFlag.Legs | EquipFlag.Feet;
public const EquipFlag AccessoryFlags = EquipFlag.Ears | EquipFlag.Neck | EquipFlag.Wrist | EquipFlag.RFinger | EquipFlag.LFinger;
public const EquipFlag StainFlags = EquipFlag.MainhandStain
| EquipFlag.OffhandStain
| EquipFlag.HeadStain
| EquipFlag.BodyStain
| EquipFlag.HandsStain
| EquipFlag.LegsStain
| EquipFlag.FeetStain
| EquipFlag.EarsStain
| EquipFlag.NeckStain
| EquipFlag.WristStain
| EquipFlag.RFingerStain
| EquipFlag.LFingerStain;
}

View file

@ -12,22 +12,10 @@ public class AutoDesign
{
public const string RevertName = "Revert";
[Flags]
public enum Type : byte
{
Armor = 0x01,
Customizations = 0x02,
Weapons = 0x04,
GearCustomization = 0x08,
Accessories = 0x10,
All = Armor | Accessories | Customizations | Weapons | GearCustomization,
}
public Design? Design;
public JobGroup Jobs;
public Type ApplicationType;
public short GearsetIndex = -1;
public Design? Design;
public JobGroup Jobs;
public ApplicationType Type;
public short GearsetIndex = -1;
public string Name(bool incognito)
=> Revert ? RevertName : incognito ? Design!.Incognito : Design!.Name.Text;
@ -41,10 +29,10 @@ public class AutoDesign
public AutoDesign Clone()
=> new()
{
Design = Design,
ApplicationType = ApplicationType,
Jobs = Jobs,
GearsetIndex = GearsetIndex,
Design = Design,
Type = Type,
Jobs = Jobs,
GearsetIndex = GearsetIndex,
};
public unsafe bool IsActive(Actor actor)
@ -64,9 +52,9 @@ public class AutoDesign
public JObject Serialize()
=> new()
{
["Design"] = Design?.Identifier.ToString(),
["ApplicationType"] = (uint)ApplicationType,
["Conditions"] = CreateConditionObject(),
["Design"] = Design?.Identifier.ToString(),
["Type"] = (uint)Type,
["Conditions"] = CreateConditionObject(),
};
private JObject CreateConditionObject()
@ -82,42 +70,5 @@ public class AutoDesign
public (EquipFlag Equip, CustomizeFlag Customize, CrestFlag Crest, CustomizeParameterFlag Parameters, bool ApplyHat, bool ApplyVisor, bool
ApplyWeapon, bool ApplyWet) ApplyWhat()
{
var equipFlags = (ApplicationType.HasFlag(Type.Weapons) ? WeaponFlags : 0)
| (ApplicationType.HasFlag(Type.Armor) ? ArmorFlags : 0)
| (ApplicationType.HasFlag(Type.Accessories) ? AccessoryFlags : 0)
| (ApplicationType.HasFlag(Type.GearCustomization) ? StainFlags : 0);
var customizeFlags = ApplicationType.HasFlag(Type.Customizations) ? CustomizeFlagExtensions.All : 0;
var parameterFlags = ApplicationType.HasFlag(Type.Customizations) ? CustomizeParameterExtensions.All : 0;
var crestFlag = ApplicationType.HasFlag(Type.GearCustomization) ? CrestExtensions.AllRelevant : 0;
if (Revert)
return (equipFlags, customizeFlags, crestFlag, parameterFlags, ApplicationType.HasFlag(Type.Armor),
ApplicationType.HasFlag(Type.Armor),
ApplicationType.HasFlag(Type.Weapons), ApplicationType.HasFlag(Type.Customizations));
return (equipFlags & Design!.ApplyEquip, customizeFlags & Design.ApplyCustomize, crestFlag & Design.ApplyCrest,
parameterFlags & Design.ApplyParameters,
ApplicationType.HasFlag(Type.Armor) && Design.DoApplyHatVisible(),
ApplicationType.HasFlag(Type.Armor) && Design.DoApplyVisorToggle(),
ApplicationType.HasFlag(Type.Weapons) && Design.DoApplyWeaponVisible(),
ApplicationType.HasFlag(Type.Customizations) && Design.DoApplyWetness());
}
public const EquipFlag WeaponFlags = EquipFlag.Mainhand | EquipFlag.Offhand;
public const EquipFlag ArmorFlags = EquipFlag.Head | EquipFlag.Body | EquipFlag.Hands | EquipFlag.Legs | EquipFlag.Feet;
public const EquipFlag AccessoryFlags = EquipFlag.Ears | EquipFlag.Neck | EquipFlag.Wrist | EquipFlag.RFinger | EquipFlag.LFinger;
public const EquipFlag StainFlags = EquipFlag.MainhandStain
| EquipFlag.OffhandStain
| EquipFlag.HeadStain
| EquipFlag.BodyStain
| EquipFlag.HandsStain
| EquipFlag.LegsStain
| EquipFlag.FeetStain
| EquipFlag.EarsStain
| EquipFlag.NeckStain
| EquipFlag.WristStain
| EquipFlag.RFingerStain
| EquipFlag.LFingerStain;
=> Type.ApplyWhat(Design);
}

View file

@ -1,6 +1,7 @@
using Dalamud.Plugin.Services;
using FFXIVClientStructs.FFXIV.Client.UI.Misc;
using Glamourer.Designs;
using Glamourer.Designs.Links;
using Glamourer.Events;
using Glamourer.GameData;
using Glamourer.Interop;
@ -15,7 +16,7 @@ using Penumbra.GameData.Structs;
namespace Glamourer.Automation;
public class AutoDesignApplier : IDisposable
public sealed class AutoDesignApplier : IDisposable
{
private readonly Configuration _config;
private readonly AutoDesignManager _manager;
@ -30,6 +31,7 @@ public class AutoDesignApplier : IDisposable
private readonly ObjectManager _objects;
private readonly WeaponLoading _weapons;
private readonly HumanModelList _humans;
private readonly DesignMerger _designMerger;
private readonly IClientState _clientState;
private ActorState? _jobChangeState;
@ -182,7 +184,7 @@ public class AutoDesignApplier : IDisposable
}
else if (_state.TryGetValue(id, out var state))
{
state.RemoveFixedDesignSources();
state.Source.RemoveFixedDesignSources();
}
}
}
@ -196,9 +198,9 @@ public class AutoDesignApplier : IDisposable
{
if (id.Type is IdentifierType.Player && id.HomeWorld == WorldId.AnyWorld)
foreach (var state in _state.Where(kvp => kvp.Key.PlayerName == id.PlayerName).Select(kvp => kvp.Value))
state.RemoveFixedDesignSources();
state.Source.RemoveFixedDesignSources();
else if (_state.TryGetValue(id, out var state))
state.RemoveFixedDesignSources();
state.Source.RemoveFixedDesignSources();
}
}
}
@ -276,7 +278,7 @@ public class AutoDesignApplier : IDisposable
if (set.BaseState == AutoDesignSet.Base.Game)
_state.ResetStateFixed(state, respectManual);
else if (!respectManual)
state.RemoveFixedDesignSources();
state.Source.RemoveFixedDesignSources();
if (!_humans.IsHuman((uint)actor.AsCharacter->CharacterData.ModelCharaId))
return;
@ -286,7 +288,7 @@ public class AutoDesignApplier : IDisposable
if (!design.IsActive(actor))
continue;
if (design.ApplicationType is 0)
if (design.Type is 0)
continue;
ref readonly var data = ref design.GetDesignData(state);
@ -342,7 +344,7 @@ public class AutoDesignApplier : IDisposable
if (!crestFlags.HasFlag(slot))
continue;
if (!respectManual || state[slot] is not StateChanged.Source.Manual)
if (!respectManual || state.Source[slot] is not StateChanged.Source.Manual)
_state.ChangeCrest(state, slot, design.Crest(slot), source);
totalCrestFlags |= slot;
}
@ -360,7 +362,7 @@ public class AutoDesignApplier : IDisposable
if (!parameterFlags.HasFlag(flag))
continue;
if (!respectManual || state[flag] is not StateChanged.Source.Manual and not StateChanged.Source.Pending)
if (!respectManual || state.Source[flag] is not StateChanged.Source.Manual and not StateChanged.Source.Pending)
_state.ChangeCustomizeParameter(state, flag, design.Parameters[flag], source);
totalParameterFlags |= flag;
}
@ -381,7 +383,7 @@ public class AutoDesignApplier : IDisposable
var item = design.Item(slot);
if (!_config.UnlockedItemMode || _itemUnlocks.IsUnlocked(item.Id, out _))
{
if (!respectManual || state[slot, false] is not StateChanged.Source.Manual)
if (!respectManual || state.Source[slot, false] is not StateChanged.Source.Manual)
_state.ChangeItem(state, slot, item, source);
totalEquipFlags |= flag;
}
@ -390,7 +392,7 @@ public class AutoDesignApplier : IDisposable
var stainFlag = slot.ToStainFlag();
if (equipFlags.HasFlag(stainFlag))
{
if (!respectManual || state[slot, true] is not StateChanged.Source.Manual)
if (!respectManual || state.Source[slot, true] is not StateChanged.Source.Manual)
_state.ChangeStain(state, slot, design.Stain(slot), source);
totalEquipFlags |= stainFlag;
}
@ -400,7 +402,7 @@ public class AutoDesignApplier : IDisposable
{
var item = design.Item(EquipSlot.MainHand);
var checkUnlock = !_config.UnlockedItemMode || _itemUnlocks.IsUnlocked(item.Id, out _);
var checkState = !respectManual || state[EquipSlot.MainHand, false] is not StateChanged.Source.Manual;
var checkState = !respectManual || state.Source[EquipSlot.MainHand, false] is not StateChanged.Source.Manual;
if (checkUnlock && checkState)
{
if (fromJobChange)
@ -420,7 +422,7 @@ public class AutoDesignApplier : IDisposable
{
var item = design.Item(EquipSlot.OffHand);
var checkUnlock = !_config.UnlockedItemMode || _itemUnlocks.IsUnlocked(item.Id, out _);
var checkState = !respectManual || state[EquipSlot.OffHand, false] is not StateChanged.Source.Manual;
var checkState = !respectManual || state.Source[EquipSlot.OffHand, false] is not StateChanged.Source.Manual;
if (checkUnlock && checkState)
{
if (fromJobChange)
@ -438,14 +440,14 @@ public class AutoDesignApplier : IDisposable
if (equipFlags.HasFlag(EquipFlag.MainhandStain))
{
if (!respectManual || state[EquipSlot.MainHand, true] is not StateChanged.Source.Manual)
if (!respectManual || state.Source[EquipSlot.MainHand, true] is not StateChanged.Source.Manual)
_state.ChangeStain(state, EquipSlot.MainHand, design.Stain(EquipSlot.MainHand), source);
totalEquipFlags |= EquipFlag.MainhandStain;
}
if (equipFlags.HasFlag(EquipFlag.OffhandStain))
{
if (!respectManual || state[EquipSlot.OffHand, true] is not StateChanged.Source.Manual)
if (!respectManual || state.Source[EquipSlot.OffHand, true] is not StateChanged.Source.Manual)
_state.ChangeStain(state, EquipSlot.OffHand, design.Stain(EquipSlot.OffHand), source);
totalEquipFlags |= EquipFlag.OffhandStain;
}
@ -467,7 +469,7 @@ public class AutoDesignApplier : IDisposable
if (customizeFlags.HasFlag(CustomizeFlag.Clan))
{
if (!respectManual || state[CustomizeIndex.Clan] is not StateChanged.Source.Manual)
if (!respectManual || state.Source[CustomizeIndex.Clan] is not StateChanged.Source.Manual)
fixFlags |= _customizations.ChangeClan(ref customize, design.Customize.Clan);
customizeFlags &= ~(CustomizeFlag.Clan | CustomizeFlag.Race);
totalCustomizeFlags |= CustomizeFlag.Clan | CustomizeFlag.Race;
@ -475,7 +477,7 @@ public class AutoDesignApplier : IDisposable
if (customizeFlags.HasFlag(CustomizeFlag.Gender))
{
if (!respectManual || state[CustomizeIndex.Gender] is not StateChanged.Source.Manual)
if (!respectManual || state.Source[CustomizeIndex.Gender] is not StateChanged.Source.Manual)
fixFlags |= _customizations.ChangeGender(ref customize, design.Customize.Gender);
customizeFlags &= ~CustomizeFlag.Gender;
totalCustomizeFlags |= CustomizeFlag.Gender;
@ -486,7 +488,7 @@ public class AutoDesignApplier : IDisposable
if (customizeFlags.HasFlag(CustomizeFlag.Face))
{
if (!respectManual || state[CustomizeIndex.Face] is not StateChanged.Source.Manual)
if (!respectManual || state.Source[CustomizeIndex.Face] is not StateChanged.Source.Manual)
_state.ChangeCustomize(state, CustomizeIndex.Face, design.Customize.Face, source);
customizeFlags &= ~CustomizeFlag.Face;
totalCustomizeFlags |= CustomizeFlag.Face;
@ -506,7 +508,7 @@ public class AutoDesignApplier : IDisposable
if (data.HasValue && _config.UnlockedItemMode && !_customizeUnlocks.IsUnlocked(data.Value, out _))
continue;
if (!respectManual || state[index] is not StateChanged.Source.Manual)
if (!respectManual || state.Source[index] is not StateChanged.Source.Manual)
_state.ChangeCustomize(state, index, value, source);
totalCustomizeFlags |= flag;
}
@ -518,28 +520,28 @@ public class AutoDesignApplier : IDisposable
{
if (applyHat && (totalMetaFlags & 0x01) == 0)
{
if (!respectManual || state[ActorState.MetaIndex.HatState] is not StateChanged.Source.Manual)
if (!respectManual || state.Source[MetaIndex.HatState] is not StateChanged.Source.Manual)
_state.ChangeHatState(state, design.IsHatVisible(), source);
totalMetaFlags |= 0x01;
}
if (applyVisor && (totalMetaFlags & 0x02) == 0)
{
if (!respectManual || state[ActorState.MetaIndex.VisorState] is not StateChanged.Source.Manual)
if (!respectManual || state.Source[MetaIndex.VisorState] is not StateChanged.Source.Manual)
_state.ChangeVisorState(state, design.IsVisorToggled(), source);
totalMetaFlags |= 0x02;
}
if (applyWeapon && (totalMetaFlags & 0x04) == 0)
{
if (!respectManual || state[ActorState.MetaIndex.WeaponState] is not StateChanged.Source.Manual)
if (!respectManual || state.Source[MetaIndex.WeaponState] is not StateChanged.Source.Manual)
_state.ChangeWeaponState(state, design.IsWeaponVisible(), source);
totalMetaFlags |= 0x04;
}
if (applyWet && (totalMetaFlags & 0x08) == 0)
{
if (!respectManual || state[ActorState.MetaIndex.Wetness] is not StateChanged.Source.Manual)
if (!respectManual || state.Source[MetaIndex.Wetness] is not StateChanged.Source.Manual)
_state.ChangeWetness(state, design.IsWet(), source);
totalMetaFlags |= 0x08;
}

View file

@ -232,7 +232,7 @@ public class AutoDesignManager : ISavable, IReadOnlyList<AutoDesignSet>, IDispos
var newDesign = new AutoDesign()
{
Design = design,
ApplicationType = AutoDesign.Type.All,
Type = ApplicationType.All,
Jobs = _jobs.JobGroups[1],
};
set.Designs.Add(newDesign);
@ -328,21 +328,21 @@ public class AutoDesignManager : ISavable, IReadOnlyList<AutoDesignSet>, IDispos
_event.Invoke(AutomationChanged.Type.ChangedConditions, set, (which, old, index));
}
public void ChangeApplicationType(AutoDesignSet set, int which, AutoDesign.Type type)
public void ChangeApplicationType(AutoDesignSet set, int which, ApplicationType applicationType)
{
if (which >= set.Designs.Count || which < 0)
return;
type &= AutoDesign.Type.All;
applicationType &= ApplicationType.All;
var design = set.Designs[which];
if (design.ApplicationType == type)
if (design.Type == applicationType)
return;
var old = design.ApplicationType;
design.ApplicationType = type;
var old = design.Type;
design.Type = applicationType;
Save();
Glamourer.Log.Debug($"Changed application type from {old} to {type} for associated design {which + 1} in design set.");
_event.Invoke(AutomationChanged.Type.ChangedType, set, (which, old, type));
Glamourer.Log.Debug($"Changed application type from {old} to {applicationType} for associated design {which + 1} in design set.");
_event.Invoke(AutomationChanged.Type.ChangedType, set, (which, old, applicationType));
}
public string ToFilename(FilenameService fileNames)
@ -490,12 +490,13 @@ public class AutoDesignManager : ISavable, IReadOnlyList<AutoDesignSet>, IDispos
}
}
var applicationType = (AutoDesign.Type)(jObj["ApplicationType"]?.ToObject<uint>() ?? 0);
// ApplicationType is a migration from an older property name.
var applicationType = (ApplicationType)(jObj["Type"]?.ToObject<uint>() ?? jObj["ApplicationType"]?.ToObject<uint>() ?? 0);
var ret = new AutoDesign()
var ret = new AutoDesign
{
Design = design,
ApplicationType = applicationType & AutoDesign.Type.All,
Type = applicationType & ApplicationType.All,
};
return ParseConditions(setName, jObj, ret) ? ret : null;
}
@ -550,7 +551,24 @@ public class AutoDesignManager : ISavable, IReadOnlyList<AutoDesignSet>, IDispos
private ActorIdentifier[] GetGroup(ActorIdentifier identifier)
{
if (!identifier.IsValid)
return Array.Empty<ActorIdentifier>();
return [];
return identifier.Type switch
{
IdentifierType.Player =>
[
identifier.CreatePermanent(),
],
IdentifierType.Retainer =>
[
_actors.CreateRetainer(identifier.PlayerName,
identifier.Retainer == ActorIdentifier.RetainerType.Mannequin
? ActorIdentifier.RetainerType.Mannequin
: ActorIdentifier.RetainerType.Bell).CreatePermanent(),
],
IdentifierType.Npc => CreateNpcs(_actors, identifier),
_ => [],
};
static ActorIdentifier[] CreateNpcs(ActorManager manager, ActorIdentifier identifier)
{
@ -566,23 +584,6 @@ public class AutoDesignManager : ISavable, IReadOnlyList<AutoDesignSet>, IDispos
identifier.Kind,
kvp.Key)).ToArray();
}
return identifier.Type switch
{
IdentifierType.Player => new[]
{
identifier.CreatePermanent(),
},
IdentifierType.Retainer => new[]
{
_actors.CreateRetainer(identifier.PlayerName,
identifier.Retainer == ActorIdentifier.RetainerType.Mannequin
? ActorIdentifier.RetainerType.Mannequin
: ActorIdentifier.RetainerType.Bell).CreatePermanent(),
},
IdentifierType.Npc => CreateNpcs(_actors, identifier),
_ => Array.Empty<ActorIdentifier>(),
};
}
private void OnDesignChange(DesignChanged.Type type, Design design, object? data)

View file

@ -3,12 +3,12 @@ using Penumbra.GameData.Actors;
namespace Glamourer.Automation;
public class AutoDesignSet
public class AutoDesignSet(string name, ActorIdentifier[] identifiers, List<AutoDesign> designs)
{
public readonly List<AutoDesign> Designs;
public readonly List<AutoDesign> Designs = designs;
public string Name;
public ActorIdentifier[] Identifiers;
public string Name = name;
public ActorIdentifier[] Identifiers = identifiers;
public bool Enabled;
public Base BaseState = Base.Current;
@ -32,13 +32,6 @@ public class AutoDesignSet
: this(name, identifiers, new List<AutoDesign>())
{ }
public AutoDesignSet(string name, ActorIdentifier[] identifiers, List<AutoDesign> designs)
{
Name = name;
Identifiers = identifiers;
Designs = designs;
}
public enum Base : byte
{
Current,

View file

@ -56,7 +56,7 @@ public class FixedDesignMigrator(JobService jobs)
autoManager.AddDesign(set, leaf.Value);
autoManager.ChangeJobCondition(set, set.Designs.Count - 1, design.Item2);
autoManager.ChangeApplicationType(set, set.Designs.Count - 1, design.Item3 ? AutoDesign.Type.All : 0);
autoManager.ChangeApplicationType(set, set.Designs.Count - 1, design.Item3 ? ApplicationType.All : 0);
}
}
}