mirror of
https://github.com/Ottermandias/Glamourer.git
synced 2025-12-15 13:14:17 +01:00
Revamp, temp state.
This commit is contained in:
parent
358e33346f
commit
cc09cced61
22 changed files with 365 additions and 298 deletions
|
|
@ -8,18 +8,18 @@ namespace Glamourer.Structs;
|
||||||
[Flags]
|
[Flags]
|
||||||
public enum CrestFlag : ushort
|
public enum CrestFlag : ushort
|
||||||
{
|
{
|
||||||
Head = 0x0001,
|
OffHand = 0x0001,
|
||||||
Body = 0x0002,
|
Head = 0x0002,
|
||||||
Hands = 0x0004,
|
Body = 0x0004,
|
||||||
Legs = 0x0008,
|
Hands = 0x0008,
|
||||||
Feet = 0x0010,
|
Legs = 0x0010,
|
||||||
Ears = 0x0020,
|
Feet = 0x0020,
|
||||||
Neck = 0x0040,
|
Ears = 0x0040,
|
||||||
Wrists = 0x0080,
|
Neck = 0x0080,
|
||||||
RFinger = 0x0100,
|
Wrists = 0x0100,
|
||||||
LFinger = 0x0200,
|
RFinger = 0x0200,
|
||||||
MainHand = 0x0400,
|
LFinger = 0x0400,
|
||||||
OffHand = 0x0800,
|
MainHand = 0x0800,
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum CrestType : byte
|
public enum CrestType : byte
|
||||||
|
|
@ -32,7 +32,7 @@ public enum CrestType : byte
|
||||||
|
|
||||||
public static class CrestExtensions
|
public static class CrestExtensions
|
||||||
{
|
{
|
||||||
public const CrestFlag All = (CrestFlag)(((ulong)EquipFlag.Offhand << 1) - 1);
|
public const CrestFlag All = (CrestFlag)(((ulong)EquipFlag.Mainhand << 1) - 1);
|
||||||
public const CrestFlag AllRelevant = CrestFlag.Head | CrestFlag.Body | CrestFlag.OffHand;
|
public const CrestFlag AllRelevant = CrestFlag.Head | CrestFlag.Body | CrestFlag.OffHand;
|
||||||
|
|
||||||
public static readonly IReadOnlyList<CrestFlag> AllRelevantSet = Enum.GetValues<CrestFlag>().Where(f => AllRelevant.HasFlag(f)).ToArray();
|
public static readonly IReadOnlyList<CrestFlag> AllRelevantSet = Enum.GetValues<CrestFlag>().Where(f => AllRelevant.HasFlag(f)).ToArray();
|
||||||
|
|
@ -82,24 +82,6 @@ public static class CrestExtensions
|
||||||
_ => 0,
|
_ => 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
public static EquipSlot ToSlot(this CrestFlag flag)
|
|
||||||
=> flag switch
|
|
||||||
{
|
|
||||||
CrestFlag.MainHand => EquipSlot.MainHand,
|
|
||||||
CrestFlag.OffHand => EquipSlot.OffHand,
|
|
||||||
CrestFlag.Head => EquipSlot.Head,
|
|
||||||
CrestFlag.Body => EquipSlot.Body,
|
|
||||||
CrestFlag.Hands => EquipSlot.Hands,
|
|
||||||
CrestFlag.Legs => EquipSlot.Legs,
|
|
||||||
CrestFlag.Feet => EquipSlot.Feet,
|
|
||||||
CrestFlag.Ears => EquipSlot.Ears,
|
|
||||||
CrestFlag.Neck => EquipSlot.Neck,
|
|
||||||
CrestFlag.Wrists => EquipSlot.Wrists,
|
|
||||||
CrestFlag.RFinger => EquipSlot.RFinger,
|
|
||||||
CrestFlag.LFinger => EquipSlot.LFinger,
|
|
||||||
_ => 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
public static string ToLabel(this CrestFlag flag)
|
public static string ToLabel(this CrestFlag flag)
|
||||||
=> flag switch
|
=> flag switch
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -15,13 +15,13 @@ public class AutoDesign
|
||||||
[Flags]
|
[Flags]
|
||||||
public enum Type : byte
|
public enum Type : byte
|
||||||
{
|
{
|
||||||
Armor = 0x01,
|
Armor = 0x01,
|
||||||
Customizations = 0x02,
|
Customizations = 0x02,
|
||||||
Weapons = 0x04,
|
Weapons = 0x04,
|
||||||
Stains = 0x08,
|
GearCustomization = 0x08,
|
||||||
Accessories = 0x10,
|
Accessories = 0x10,
|
||||||
|
|
||||||
All = Armor | Accessories | Customizations | Weapons | Stains,
|
All = Armor | Accessories | Customizations | Weapons | GearCustomization,
|
||||||
}
|
}
|
||||||
|
|
||||||
public Design? Design;
|
public Design? Design;
|
||||||
|
|
@ -80,19 +80,20 @@ public class AutoDesign
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
public (EquipFlag Equip, CustomizeFlag Customize, bool ApplyHat, bool ApplyVisor, bool ApplyWeapon, bool ApplyWet) ApplyWhat()
|
public (EquipFlag Equip, CustomizeFlag Customize, CrestFlag Crest, bool ApplyHat, bool ApplyVisor, bool ApplyWeapon, bool ApplyWet) ApplyWhat()
|
||||||
{
|
{
|
||||||
var equipFlags = (ApplicationType.HasFlag(Type.Weapons) ? WeaponFlags : 0)
|
var equipFlags = (ApplicationType.HasFlag(Type.Weapons) ? WeaponFlags : 0)
|
||||||
| (ApplicationType.HasFlag(Type.Armor) ? ArmorFlags : 0)
|
| (ApplicationType.HasFlag(Type.Armor) ? ArmorFlags : 0)
|
||||||
| (ApplicationType.HasFlag(Type.Accessories) ? AccessoryFlags : 0)
|
| (ApplicationType.HasFlag(Type.Accessories) ? AccessoryFlags : 0)
|
||||||
| (ApplicationType.HasFlag(Type.Stains) ? StainFlags : 0);
|
| (ApplicationType.HasFlag(Type.GearCustomization) ? StainFlags : 0);
|
||||||
var customizeFlags = ApplicationType.HasFlag(Type.Customizations) ? CustomizeFlagExtensions.All : 0;
|
var customizeFlags = ApplicationType.HasFlag(Type.Customizations) ? CustomizeFlagExtensions.All : 0;
|
||||||
|
var crestFlag = ApplicationType.HasFlag(Type.GearCustomization) ? CrestExtensions.AllRelevant : 0;
|
||||||
|
|
||||||
if (Revert)
|
if (Revert)
|
||||||
return (equipFlags, customizeFlags, ApplicationType.HasFlag(Type.Armor), ApplicationType.HasFlag(Type.Armor),
|
return (equipFlags, customizeFlags, crestFlag, ApplicationType.HasFlag(Type.Armor), ApplicationType.HasFlag(Type.Armor),
|
||||||
ApplicationType.HasFlag(Type.Weapons), ApplicationType.HasFlag(Type.Customizations));
|
ApplicationType.HasFlag(Type.Weapons), ApplicationType.HasFlag(Type.Customizations));
|
||||||
|
|
||||||
return (equipFlags & Design!.ApplyEquip, customizeFlags & Design.ApplyCustomize,
|
return (equipFlags & Design!.ApplyEquip, customizeFlags & Design.ApplyCustomize, crestFlag & Design.ApplyCrest,
|
||||||
ApplicationType.HasFlag(Type.Armor) && Design.DoApplyHatVisible(),
|
ApplicationType.HasFlag(Type.Armor) && Design.DoApplyHatVisible(),
|
||||||
ApplicationType.HasFlag(Type.Armor) && Design.DoApplyVisorToggle(),
|
ApplicationType.HasFlag(Type.Armor) && Design.DoApplyVisorToggle(),
|
||||||
ApplicationType.HasFlag(Type.Weapons) && Design.DoApplyWeaponVisible(),
|
ApplicationType.HasFlag(Type.Weapons) && Design.DoApplyWeaponVisible(),
|
||||||
|
|
|
||||||
|
|
@ -268,6 +268,7 @@ public class AutoDesignApplier : IDisposable
|
||||||
{
|
{
|
||||||
EquipFlag totalEquipFlags = 0;
|
EquipFlag totalEquipFlags = 0;
|
||||||
CustomizeFlag totalCustomizeFlags = 0;
|
CustomizeFlag totalCustomizeFlags = 0;
|
||||||
|
CrestFlag totalCrestFlags = 0;
|
||||||
byte totalMetaFlags = 0;
|
byte totalMetaFlags = 0;
|
||||||
if (set.BaseState == AutoDesignSet.Base.Game)
|
if (set.BaseState == AutoDesignSet.Base.Game)
|
||||||
_state.ResetStateFixed(state);
|
_state.ResetStateFixed(state);
|
||||||
|
|
@ -291,10 +292,11 @@ public class AutoDesignApplier : IDisposable
|
||||||
if (!data.IsHuman)
|
if (!data.IsHuman)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var (equipFlags, customizeFlags, applyHat, applyVisor, applyWeapon, applyWet) = design.ApplyWhat();
|
var (equipFlags, customizeFlags, crestFlags, applyHat, applyVisor, applyWeapon, applyWet) = design.ApplyWhat();
|
||||||
ReduceMeta(state, data, applyHat, applyVisor, applyWeapon, applyWet, ref totalMetaFlags, respectManual, source);
|
ReduceMeta(state, data, applyHat, applyVisor, applyWeapon, applyWet, ref totalMetaFlags, respectManual, source);
|
||||||
ReduceCustomize(state, data, customizeFlags, ref totalCustomizeFlags, respectManual, source);
|
ReduceCustomize(state, data, customizeFlags, ref totalCustomizeFlags, respectManual, source);
|
||||||
ReduceEquip(state, data, equipFlags, ref totalEquipFlags, respectManual, source, fromJobChange);
|
ReduceEquip(state, data, equipFlags, ref totalEquipFlags, respectManual, source, fromJobChange);
|
||||||
|
ReduceCrests(state, data, crestFlags, ref totalCrestFlags, respectManual, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (totalCustomizeFlags != 0)
|
if (totalCustomizeFlags != 0)
|
||||||
|
|
@ -324,6 +326,24 @@ public class AutoDesignApplier : IDisposable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void ReduceCrests(ActorState state, in DesignData design, CrestFlag crestFlags, ref CrestFlag totalCrestFlags, bool respectManual,
|
||||||
|
StateChanged.Source source)
|
||||||
|
{
|
||||||
|
crestFlags &= ~totalCrestFlags;
|
||||||
|
if (crestFlags == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
foreach (var slot in CrestExtensions.AllRelevantSet)
|
||||||
|
{
|
||||||
|
if (!crestFlags.HasFlag(slot))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!respectManual || state[slot] is not StateChanged.Source.Manual)
|
||||||
|
_state.ChangeCrest(state, slot, design.Crest(slot), source);
|
||||||
|
totalCrestFlags |= slot;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void ReduceEquip(ActorState state, in DesignData design, EquipFlag equipFlags, ref EquipFlag totalEquipFlags, bool respectManual,
|
private void ReduceEquip(ActorState state, in DesignData design, EquipFlag equipFlags, ref EquipFlag totalEquipFlags, bool respectManual,
|
||||||
StateChanged.Source source, bool fromJobChange)
|
StateChanged.Source source, bool fromJobChange)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,6 @@ using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Dalamud.Interface.Internal.Notifications;
|
using Dalamud.Interface.Internal.Notifications;
|
||||||
using Glamourer.Customization;
|
|
||||||
using Glamourer.Gui;
|
|
||||||
using Glamourer.Interop.Penumbra;
|
using Glamourer.Interop.Penumbra;
|
||||||
using Glamourer.Services;
|
using Glamourer.Services;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
|
@ -28,8 +26,8 @@ public sealed class Design : DesignBase, ISavable
|
||||||
internal Design(Design other)
|
internal Design(Design other)
|
||||||
: base(other)
|
: base(other)
|
||||||
{
|
{
|
||||||
Tags = Tags.ToArray();
|
Tags = other.Tags.ToArray();
|
||||||
Description = Description;
|
Description = other.Description;
|
||||||
AssociatedMods = new SortedList<Mod, ModSettings>(other.AssociatedMods);
|
AssociatedMods = new SortedList<Mod, ModSettings>(other.AssociatedMods);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -69,8 +67,7 @@ public sealed class Design : DesignBase, ISavable
|
||||||
["Equipment"] = SerializeEquipment(),
|
["Equipment"] = SerializeEquipment(),
|
||||||
["Customize"] = SerializeCustomize(),
|
["Customize"] = SerializeCustomize(),
|
||||||
["Mods"] = SerializeMods(),
|
["Mods"] = SerializeMods(),
|
||||||
}
|
};
|
||||||
;
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,4 @@
|
||||||
using System;
|
using Dalamud.Interface.Internal.Notifications;
|
||||||
using System.Linq;
|
|
||||||
using Dalamud.Interface.Internal.Notifications;
|
|
||||||
using Glamourer.Customization;
|
using Glamourer.Customization;
|
||||||
using Glamourer.Services;
|
using Glamourer.Services;
|
||||||
using Glamourer.Structs;
|
using Glamourer.Structs;
|
||||||
|
|
@ -9,6 +7,8 @@ using OtterGui.Classes;
|
||||||
using Penumbra.GameData.Data;
|
using Penumbra.GameData.Data;
|
||||||
using Penumbra.GameData.Enums;
|
using Penumbra.GameData.Enums;
|
||||||
using Penumbra.GameData.Structs;
|
using Penumbra.GameData.Structs;
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace Glamourer.Designs;
|
namespace Glamourer.Designs;
|
||||||
|
|
||||||
|
|
@ -169,8 +169,8 @@ public class DesignBase
|
||||||
public bool DoApplyCustomize(CustomizeIndex idx)
|
public bool DoApplyCustomize(CustomizeIndex idx)
|
||||||
=> ApplyCustomize.HasFlag(idx.ToFlag());
|
=> ApplyCustomize.HasFlag(idx.ToFlag());
|
||||||
|
|
||||||
public bool DoApplyCrest(EquipSlot slot)
|
public bool DoApplyCrest(CrestFlag slot)
|
||||||
=> ApplyCrest.HasFlag(slot.ToCrestFlag());
|
=> ApplyCrest.HasFlag(slot);
|
||||||
|
|
||||||
internal bool SetApplyEquip(EquipSlot slot, bool value)
|
internal bool SetApplyEquip(EquipSlot slot, bool value)
|
||||||
{
|
{
|
||||||
|
|
@ -202,9 +202,9 @@ public class DesignBase
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal bool SetApplyCrest(EquipSlot slot, bool value)
|
internal bool SetApplyCrest(CrestFlag slot, bool value)
|
||||||
{
|
{
|
||||||
var newValue = value ? ApplyCrest | slot.ToCrestFlag() : ApplyCrest & ~slot.ToCrestFlag();
|
var newValue = value ? ApplyCrest | slot : ApplyCrest & ~slot;
|
||||||
if (newValue == ApplyCrest)
|
if (newValue == ApplyCrest)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
@ -212,28 +212,32 @@ public class DesignBase
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal FlagRestrictionResetter TemporarilyRestrictApplication(EquipFlag equipFlags, CustomizeFlag customizeFlags)
|
internal FlagRestrictionResetter TemporarilyRestrictApplication(EquipFlag equipFlags, CustomizeFlag customizeFlags, CrestFlag crestFlags)
|
||||||
=> new(this, equipFlags, customizeFlags);
|
=> new(this, equipFlags, customizeFlags, crestFlags);
|
||||||
|
|
||||||
internal readonly struct FlagRestrictionResetter : IDisposable
|
internal readonly struct FlagRestrictionResetter : IDisposable
|
||||||
{
|
{
|
||||||
private readonly DesignBase _design;
|
private readonly DesignBase _design;
|
||||||
private readonly EquipFlag _oldEquipFlags;
|
private readonly EquipFlag _oldEquipFlags;
|
||||||
private readonly CustomizeFlag _oldCustomizeFlags;
|
private readonly CustomizeFlag _oldCustomizeFlags;
|
||||||
|
private readonly CrestFlag _oldCrestFlags;
|
||||||
|
|
||||||
public FlagRestrictionResetter(DesignBase d, EquipFlag equipFlags, CustomizeFlag customizeFlags)
|
public FlagRestrictionResetter(DesignBase d, EquipFlag equipFlags, CustomizeFlag customizeFlags, CrestFlag crestFlags)
|
||||||
{
|
{
|
||||||
_design = d;
|
_design = d;
|
||||||
_oldEquipFlags = d.ApplyEquip;
|
_oldEquipFlags = d.ApplyEquip;
|
||||||
_oldCustomizeFlags = d.ApplyCustomizeRaw;
|
_oldCustomizeFlags = d.ApplyCustomizeRaw;
|
||||||
|
_oldCrestFlags = d.ApplyCrest;
|
||||||
d.ApplyEquip &= equipFlags;
|
d.ApplyEquip &= equipFlags;
|
||||||
d.ApplyCustomize &= customizeFlags;
|
d.ApplyCustomize &= customizeFlags;
|
||||||
|
d.ApplyCrest &= crestFlags;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
_design.ApplyEquip = _oldEquipFlags;
|
_design.ApplyEquip = _oldEquipFlags;
|
||||||
_design.ApplyCustomize = _oldCustomizeFlags;
|
_design.ApplyCustomize = _oldCustomizeFlags;
|
||||||
|
_design.ApplyCrest = _oldCrestFlags;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -275,10 +279,11 @@ public class DesignBase
|
||||||
{
|
{
|
||||||
foreach (var slot in EquipSlotExtensions.EqdpSlots.Prepend(EquipSlot.OffHand).Prepend(EquipSlot.MainHand))
|
foreach (var slot in EquipSlotExtensions.EqdpSlots.Prepend(EquipSlot.OffHand).Prepend(EquipSlot.MainHand))
|
||||||
{
|
{
|
||||||
var item = _designData.Item(slot);
|
var item = _designData.Item(slot);
|
||||||
var stain = _designData.Stain(slot);
|
var stain = _designData.Stain(slot);
|
||||||
var crest = _designData.Crest(slot);
|
var crestSlot = slot.ToCrestFlag();
|
||||||
ret[slot.ToString()] = Serialize(item.Id, stain, crest, DoApplyEquip(slot), DoApplyStain(slot), DoApplyCrest(slot));
|
var crest = _designData.Crest(crestSlot);
|
||||||
|
ret[slot.ToString()] = Serialize(item.Id, stain, crest, DoApplyEquip(slot), DoApplyStain(slot), DoApplyCrest(crestSlot));
|
||||||
}
|
}
|
||||||
|
|
||||||
ret["Hat"] = new QuadBool(_designData.IsHatVisible(), DoApplyHatVisible()).ToJObject("Show", "Apply");
|
ret["Hat"] = new QuadBool(_designData.IsHatVisible(), DoApplyHatVisible()).ToJObject("Show", "Apply");
|
||||||
|
|
@ -365,7 +370,7 @@ public class DesignBase
|
||||||
{
|
{
|
||||||
var id = item?["ItemId"]?.ToObject<ulong>() ?? ItemManager.NothingId(slot).Id;
|
var id = item?["ItemId"]?.ToObject<ulong>() ?? ItemManager.NothingId(slot).Id;
|
||||||
var stain = (StainId)(item?["Stain"]?.ToObject<byte>() ?? 0);
|
var stain = (StainId)(item?["Stain"]?.ToObject<byte>() ?? 0);
|
||||||
var crest = (item?["Crest"]?.ToObject<bool>() ?? false);
|
var crest = item?["Crest"]?.ToObject<bool>() ?? false;
|
||||||
var apply = item?["Apply"]?.ToObject<bool>() ?? false;
|
var apply = item?["Apply"]?.ToObject<bool>() ?? false;
|
||||||
var applyStain = item?["ApplyStain"]?.ToObject<bool>() ?? false;
|
var applyStain = item?["ApplyStain"]?.ToObject<bool>() ?? false;
|
||||||
var applyCrest = item?["ApplyCrest"]?.ToObject<bool>() ?? false;
|
var applyCrest = item?["ApplyCrest"]?.ToObject<bool>() ?? false;
|
||||||
|
|
@ -384,19 +389,21 @@ public class DesignBase
|
||||||
|
|
||||||
PrintWarning(items.ValidateItem(slot, id, out var item, allowUnknown));
|
PrintWarning(items.ValidateItem(slot, id, out var item, allowUnknown));
|
||||||
PrintWarning(items.ValidateStain(stain, out stain, allowUnknown));
|
PrintWarning(items.ValidateStain(stain, out stain, allowUnknown));
|
||||||
|
var crestSlot = slot.ToCrestFlag();
|
||||||
design._designData.SetItem(slot, item);
|
design._designData.SetItem(slot, item);
|
||||||
design._designData.SetStain(slot, stain);
|
design._designData.SetStain(slot, stain);
|
||||||
design._designData.SetCrest(slot, crest);
|
design._designData.SetCrest(crestSlot, crest);
|
||||||
design.SetApplyEquip(slot, apply);
|
design.SetApplyEquip(slot, apply);
|
||||||
design.SetApplyStain(slot, applyStain);
|
design.SetApplyStain(slot, applyStain);
|
||||||
design.SetApplyCrest(slot, applyCrest);
|
design.SetApplyCrest(crestSlot, applyCrest);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
var (id, stain, crest, apply, applyStain, applyCrest) = ParseItem(EquipSlot.MainHand, equip[EquipSlot.MainHand.ToString()]);
|
var (id, stain, crest, apply, applyStain, applyCrest) = ParseItem(EquipSlot.MainHand, equip[EquipSlot.MainHand.ToString()]);
|
||||||
if (id == ItemManager.NothingId(EquipSlot.MainHand))
|
if (id == ItemManager.NothingId(EquipSlot.MainHand))
|
||||||
id = items.DefaultSword.ItemId;
|
id = items.DefaultSword.ItemId;
|
||||||
var (idOff, stainOff, crestOff, applyOff, applyStainOff, applyCrestOff) = ParseItem(EquipSlot.OffHand, equip[EquipSlot.OffHand.ToString()]);
|
var (idOff, stainOff, crestOff, applyOff, applyStainOff, applyCrestOff) =
|
||||||
|
ParseItem(EquipSlot.OffHand, equip[EquipSlot.OffHand.ToString()]);
|
||||||
if (id == ItemManager.NothingId(EquipSlot.OffHand))
|
if (id == ItemManager.NothingId(EquipSlot.OffHand))
|
||||||
id = ItemManager.NothingId(FullEquipType.Shield);
|
id = ItemManager.NothingId(FullEquipType.Shield);
|
||||||
|
|
||||||
|
|
@ -407,14 +414,14 @@ public class DesignBase
|
||||||
design._designData.SetItem(EquipSlot.OffHand, off);
|
design._designData.SetItem(EquipSlot.OffHand, off);
|
||||||
design._designData.SetStain(EquipSlot.MainHand, stain);
|
design._designData.SetStain(EquipSlot.MainHand, stain);
|
||||||
design._designData.SetStain(EquipSlot.OffHand, stainOff);
|
design._designData.SetStain(EquipSlot.OffHand, stainOff);
|
||||||
design._designData.SetCrest(EquipSlot.MainHand, crest);
|
design._designData.SetCrest(CrestFlag.MainHand, crest);
|
||||||
design._designData.SetCrest(EquipSlot.OffHand, crestOff);
|
design._designData.SetCrest(CrestFlag.OffHand, crestOff);
|
||||||
design.SetApplyEquip(EquipSlot.MainHand, apply);
|
design.SetApplyEquip(EquipSlot.MainHand, apply);
|
||||||
design.SetApplyEquip(EquipSlot.OffHand, applyOff);
|
design.SetApplyEquip(EquipSlot.OffHand, applyOff);
|
||||||
design.SetApplyStain(EquipSlot.MainHand, applyStain);
|
design.SetApplyStain(EquipSlot.MainHand, applyStain);
|
||||||
design.SetApplyStain(EquipSlot.OffHand, applyStainOff);
|
design.SetApplyStain(EquipSlot.OffHand, applyStainOff);
|
||||||
design.SetApplyCrest(EquipSlot.MainHand, applyCrest);
|
design.SetApplyCrest(CrestFlag.MainHand, applyCrest);
|
||||||
design.SetApplyCrest(EquipSlot.OffHand, applyCrestOff);
|
design.SetApplyCrest(CrestFlag.OffHand, applyCrestOff);
|
||||||
}
|
}
|
||||||
var metaValue = QuadBool.FromJObject(equip["Hat"], "Show", "Apply", QuadBool.NullFalse);
|
var metaValue = QuadBool.FromJObject(equip["Hat"], "Show", "Apply", QuadBool.NullFalse);
|
||||||
design.SetApplyHatVisible(metaValue.Enabled);
|
design.SetApplyHatVisible(metaValue.Enabled);
|
||||||
|
|
|
||||||
|
|
@ -13,22 +13,9 @@ using Penumbra.GameData.Enums;
|
||||||
|
|
||||||
namespace Glamourer.Designs;
|
namespace Glamourer.Designs;
|
||||||
|
|
||||||
public class DesignConverter
|
public class DesignConverter(ItemManager _items, DesignManager _designs, CustomizationService _customize, HumanModelList _humans)
|
||||||
{
|
{
|
||||||
public const byte Version = 5;
|
public const byte Version = 6;
|
||||||
|
|
||||||
private readonly ItemManager _items;
|
|
||||||
private readonly DesignManager _designs;
|
|
||||||
private readonly CustomizationService _customize;
|
|
||||||
private readonly HumanModelList _humans;
|
|
||||||
|
|
||||||
public DesignConverter(ItemManager items, DesignManager designs, CustomizationService customize, HumanModelList humans)
|
|
||||||
{
|
|
||||||
_items = items;
|
|
||||||
_designs = designs;
|
|
||||||
_customize = customize;
|
|
||||||
_humans = humans;
|
|
||||||
}
|
|
||||||
|
|
||||||
public JObject ShareJObject(DesignBase design)
|
public JObject ShareJObject(DesignBase design)
|
||||||
=> design.JsonSerialize();
|
=> design.JsonSerialize();
|
||||||
|
|
@ -36,32 +23,33 @@ public class DesignConverter
|
||||||
public JObject ShareJObject(Design design)
|
public JObject ShareJObject(Design design)
|
||||||
=> design.JsonSerialize();
|
=> design.JsonSerialize();
|
||||||
|
|
||||||
public JObject ShareJObject(ActorState state, EquipFlag equipFlags, CustomizeFlag customizeFlags)
|
public JObject ShareJObject(ActorState state, EquipFlag equipFlags, CustomizeFlag customizeFlags, CrestFlag crestFlags)
|
||||||
{
|
{
|
||||||
var design = Convert(state, equipFlags, customizeFlags);
|
var design = Convert(state, equipFlags, customizeFlags, crestFlags);
|
||||||
return ShareJObject(design);
|
return ShareJObject(design);
|
||||||
}
|
}
|
||||||
|
|
||||||
public string ShareBase64(Design design)
|
public string ShareBase64(Design design)
|
||||||
=> ShareBackwardCompatible(ShareJObject(design), design);
|
=> ShareBase64(ShareJObject(design));
|
||||||
|
|
||||||
public string ShareBase64(DesignBase design)
|
public string ShareBase64(DesignBase design)
|
||||||
=> ShareBackwardCompatible(ShareJObject(design), design);
|
=> ShareBase64(ShareJObject(design));
|
||||||
|
|
||||||
public string ShareBase64(ActorState state)
|
public string ShareBase64(ActorState state)
|
||||||
=> ShareBase64(state, EquipFlagExtensions.All, CustomizeFlagExtensions.All);
|
=> ShareBase64(state, EquipFlagExtensions.All, CustomizeFlagExtensions.All, CrestExtensions.All);
|
||||||
|
|
||||||
public string ShareBase64(ActorState state, EquipFlag equipFlags, CustomizeFlag customizeFlags)
|
public string ShareBase64(ActorState state, EquipFlag equipFlags, CustomizeFlag customizeFlags, CrestFlag crestFlags)
|
||||||
{
|
{
|
||||||
var design = Convert(state, equipFlags, customizeFlags);
|
var design = Convert(state, equipFlags, customizeFlags, crestFlags);
|
||||||
return ShareBackwardCompatible(ShareJObject(design), design);
|
return ShareBase64(ShareJObject(design));
|
||||||
}
|
}
|
||||||
|
|
||||||
public DesignBase Convert(ActorState state, EquipFlag equipFlags, CustomizeFlag customizeFlags)
|
public DesignBase Convert(ActorState state, EquipFlag equipFlags, CustomizeFlag customizeFlags, CrestFlag crestFlags)
|
||||||
{
|
{
|
||||||
var design = _designs.CreateTemporary();
|
var design = _designs.CreateTemporary();
|
||||||
design.ApplyEquip = equipFlags & EquipFlagExtensions.All;
|
design.ApplyEquip = equipFlags & EquipFlagExtensions.All;
|
||||||
design.ApplyCustomize = customizeFlags;
|
design.ApplyCustomize = customizeFlags & CustomizeFlagExtensions.AllRelevant;
|
||||||
|
design.ApplyCrest = crestFlags & CrestExtensions.All;
|
||||||
design.SetApplyHatVisible(design.DoApplyEquip(EquipSlot.Head));
|
design.SetApplyHatVisible(design.DoApplyEquip(EquipSlot.Head));
|
||||||
design.SetApplyVisorToggle(design.DoApplyEquip(EquipSlot.Head));
|
design.SetApplyVisorToggle(design.DoApplyEquip(EquipSlot.Head));
|
||||||
design.SetApplyWeaponVisible(design.DoApplyEquip(EquipSlot.MainHand) || design.DoApplyEquip(EquipSlot.OffHand));
|
design.SetApplyWeaponVisible(design.DoApplyEquip(EquipSlot.MainHand) || design.DoApplyEquip(EquipSlot.OffHand));
|
||||||
|
|
@ -123,6 +111,16 @@ public class DesignConverter
|
||||||
: DesignBase.LoadDesignBase(_customize, _items, jObj2);
|
: DesignBase.LoadDesignBase(_customize, _items, jObj2);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case Version:
|
||||||
|
{
|
||||||
|
version = bytes.DecompressToString(out var decompressed);
|
||||||
|
var jObj2 = JObject.Parse(decompressed);
|
||||||
|
Debug.Assert(version == Version);
|
||||||
|
ret = jObj2["Identifier"] != null
|
||||||
|
? Design.LoadDesign(_customize, _items, jObj2)
|
||||||
|
: DesignBase.LoadDesignBase(_customize, _items, jObj2);
|
||||||
|
break;
|
||||||
|
}
|
||||||
default: throw new Exception($"Unknown Version {bytes[0]}.");
|
default: throw new Exception($"Unknown Version {bytes[0]}.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -138,6 +136,7 @@ public class DesignConverter
|
||||||
if (!equip)
|
if (!equip)
|
||||||
{
|
{
|
||||||
ret.ApplyEquip = 0;
|
ret.ApplyEquip = 0;
|
||||||
|
ret.ApplyCrest = 0;
|
||||||
ret.SetApplyHatVisible(false);
|
ret.SetApplyHatVisible(false);
|
||||||
ret.SetApplyWeaponVisible(false);
|
ret.SetApplyWeaponVisible(false);
|
||||||
ret.SetApplyVisorToggle(false);
|
ret.SetApplyVisorToggle(false);
|
||||||
|
|
@ -146,23 +145,10 @@ public class DesignConverter
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string ShareBase64(JObject jObj)
|
private static string ShareBase64(JObject jObject)
|
||||||
{
|
{
|
||||||
var json = jObj.ToString(Formatting.None);
|
var json = jObject.ToString(Formatting.None);
|
||||||
var compressed = json.Compress(Version);
|
var compressed = json.Compress(Version);
|
||||||
return System.Convert.ToBase64String(compressed);
|
return System.Convert.ToBase64String(compressed);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static string ShareBackwardCompatible(JObject jObject, DesignBase design)
|
|
||||||
{
|
|
||||||
var oldBase64 = DesignBase64Migration.CreateOldBase64(design.DesignData, design.ApplyEquip, design.ApplyCustomizeRaw,
|
|
||||||
design.DoApplyHatVisible(), design.DoApplyVisorToggle(), design.DoApplyWeaponVisible(), design.WriteProtected(), 1f);
|
|
||||||
var oldBytes = System.Convert.FromBase64String(oldBase64);
|
|
||||||
var json = jObject.ToString(Formatting.None);
|
|
||||||
var compressed = json.Compress(Version);
|
|
||||||
var bytes = new byte[oldBytes.Length + compressed.Length];
|
|
||||||
oldBytes.CopyTo(bytes, 0);
|
|
||||||
compressed.CopyTo(bytes, oldBytes.Length);
|
|
||||||
return System.Convert.ToBase64String(bytes);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -61,8 +61,8 @@ public unsafe struct DesignData
|
||||||
return index > 11 ? (StainId)0 : _equipmentBytes[4 * index + 3];
|
return index > 11 ? (StainId)0 : _equipmentBytes[4 * index + 3];
|
||||||
}
|
}
|
||||||
|
|
||||||
public readonly bool Crest(EquipSlot slot)
|
public readonly bool Crest(CrestFlag slot)
|
||||||
=> CrestVisibility.HasFlag(slot.ToCrestFlag());
|
=> CrestVisibility.HasFlag(slot);
|
||||||
|
|
||||||
|
|
||||||
public FullEquipType MainhandType
|
public FullEquipType MainhandType
|
||||||
|
|
@ -179,9 +179,9 @@ public unsafe struct DesignData
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
|
|
||||||
public bool SetCrest(EquipSlot slot, bool visible)
|
public bool SetCrest(CrestFlag slot, bool visible)
|
||||||
{
|
{
|
||||||
var newValue = visible ? CrestVisibility | slot.ToCrestFlag() : CrestVisibility & ~slot.ToCrestFlag();
|
var newValue = visible ? CrestVisibility | slot : CrestVisibility & ~slot;
|
||||||
if (newValue == CrestVisibility)
|
if (newValue == CrestVisibility)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
@ -244,15 +244,15 @@ public unsafe struct DesignData
|
||||||
{
|
{
|
||||||
SetItem(slot, ItemManager.NothingItem(slot));
|
SetItem(slot, ItemManager.NothingItem(slot));
|
||||||
SetStain(slot, 0);
|
SetStain(slot, 0);
|
||||||
SetCrest(slot, false);
|
SetCrest(slot.ToCrestFlag(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
SetItem(EquipSlot.MainHand, items.DefaultSword);
|
SetItem(EquipSlot.MainHand, items.DefaultSword);
|
||||||
SetStain(EquipSlot.MainHand, 0);
|
SetStain(EquipSlot.MainHand, 0);
|
||||||
SetCrest(EquipSlot.MainHand, false);
|
SetCrest(CrestFlag.MainHand, false);
|
||||||
SetItem(EquipSlot.OffHand, ItemManager.NothingItem(FullEquipType.Shield));
|
SetItem(EquipSlot.OffHand, ItemManager.NothingItem(FullEquipType.Shield));
|
||||||
SetStain(EquipSlot.OffHand, 0);
|
SetStain(EquipSlot.OffHand, 0);
|
||||||
SetCrest(EquipSlot.OffHand, false);
|
SetCrest(CrestFlag.OffHand, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ using Glamourer.Events;
|
||||||
using Glamourer.Interop.Penumbra;
|
using Glamourer.Interop.Penumbra;
|
||||||
using Glamourer.Services;
|
using Glamourer.Services;
|
||||||
using Glamourer.State;
|
using Glamourer.State;
|
||||||
|
using Glamourer.Structs;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Newtonsoft.Json.Linq;
|
using Newtonsoft.Json.Linq;
|
||||||
using OtterGui;
|
using OtterGui;
|
||||||
|
|
@ -447,7 +448,7 @@ public class DesignManager
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Change the crest visibility for any equipment piece. </summary>
|
/// <summary> Change the crest visibility for any equipment piece. </summary>
|
||||||
public void ChangeCrest(Design design, EquipSlot slot, bool crest)
|
public void ChangeCrest(Design design, CrestFlag slot, bool crest)
|
||||||
{
|
{
|
||||||
var oldCrest = design.DesignData.Crest(slot);
|
var oldCrest = design.DesignData.Crest(slot);
|
||||||
if (!design.GetDesignDataRef().SetCrest(slot, crest))
|
if (!design.GetDesignDataRef().SetCrest(slot, crest))
|
||||||
|
|
@ -460,7 +461,7 @@ public class DesignManager
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Change whether to apply a specific crest visibility. </summary>
|
/// <summary> Change whether to apply a specific crest visibility. </summary>
|
||||||
public void ChangeApplyCrest(Design design, EquipSlot slot, bool value)
|
public void ChangeApplyCrest(Design design, CrestFlag slot, bool value)
|
||||||
{
|
{
|
||||||
if (!design.SetApplyCrest(slot, value))
|
if (!design.SetApplyCrest(slot, value))
|
||||||
return;
|
return;
|
||||||
|
|
@ -539,7 +540,10 @@ public class DesignManager
|
||||||
|
|
||||||
if (other.DoApplyStain(slot))
|
if (other.DoApplyStain(slot))
|
||||||
ChangeStain(design, slot, other.DesignData.Stain(slot));
|
ChangeStain(design, slot, other.DesignData.Stain(slot));
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var slot in Enum.GetValues<CrestFlag>())
|
||||||
|
{
|
||||||
if (other.DoApplyCrest(slot))
|
if (other.DoApplyCrest(slot))
|
||||||
ChangeCrest(design, slot, other.DesignData.Crest(slot));
|
ChangeCrest(design, slot, other.DesignData.Crest(slot));
|
||||||
}
|
}
|
||||||
|
|
@ -556,12 +560,6 @@ public class DesignManager
|
||||||
|
|
||||||
if (other.DoApplyStain(EquipSlot.OffHand))
|
if (other.DoApplyStain(EquipSlot.OffHand))
|
||||||
ChangeStain(design, EquipSlot.OffHand, other.DesignData.Stain(EquipSlot.OffHand));
|
ChangeStain(design, EquipSlot.OffHand, other.DesignData.Stain(EquipSlot.OffHand));
|
||||||
|
|
||||||
if (other.DoApplyCrest(EquipSlot.MainHand))
|
|
||||||
ChangeCrest(design, EquipSlot.MainHand, other.DesignData.Crest(EquipSlot.MainHand));
|
|
||||||
|
|
||||||
if (other.DoApplyCrest(EquipSlot.OffHand))
|
|
||||||
ChangeCrest(design, EquipSlot.OffHand, other.DesignData.Crest(EquipSlot.OffHand));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UndoDesignChange(Design design)
|
public void UndoDesignChange(Design design)
|
||||||
|
|
|
||||||
|
|
@ -159,8 +159,8 @@ public class DesignQuickBar : Window, IDisposable
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var (applyGear, applyCustomize) = UiHelpers.ConvertKeysToFlags();
|
var (applyGear, applyCustomize, applyCrest) = UiHelpers.ConvertKeysToFlags();
|
||||||
using var _ = design!.TemporarilyRestrictApplication(applyGear, applyCustomize);
|
using var _ = design!.TemporarilyRestrictApplication(applyGear, applyCustomize, applyCrest);
|
||||||
_stateManager.ApplyDesign(design, state, StateChanged.Source.Manual);
|
_stateManager.ApplyDesign(design, state, StateChanged.Source.Manual);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ using Dalamud.Interface;
|
||||||
using Dalamud.Interface.Internal.Notifications;
|
using Dalamud.Interface.Internal.Notifications;
|
||||||
using Dalamud.Plugin.Services;
|
using Dalamud.Plugin.Services;
|
||||||
using FFXIVClientStructs.FFXIV.Client.Game;
|
using FFXIVClientStructs.FFXIV.Client.Game;
|
||||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Render;
|
|
||||||
using Glamourer.Automation;
|
using Glamourer.Automation;
|
||||||
using Glamourer.Customization;
|
using Glamourer.Customization;
|
||||||
using Glamourer.Designs;
|
using Glamourer.Designs;
|
||||||
|
|
@ -16,6 +15,7 @@ using Glamourer.Interop;
|
||||||
using Glamourer.Interop.Structs;
|
using Glamourer.Interop.Structs;
|
||||||
using Glamourer.Services;
|
using Glamourer.Services;
|
||||||
using Glamourer.State;
|
using Glamourer.State;
|
||||||
|
using Glamourer.Structs;
|
||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
using OtterGui;
|
using OtterGui;
|
||||||
using OtterGui.Classes;
|
using OtterGui.Classes;
|
||||||
|
|
@ -167,21 +167,21 @@ public class ActorPanel(ActorSelector _selector, StateManager _stateManager, Cus
|
||||||
using (var _ = ImRaii.Group())
|
using (var _ = ImRaii.Group())
|
||||||
{
|
{
|
||||||
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.FromState(ActorState.MetaIndex.HatState, _stateManager, _state!));
|
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.FromState(ActorState.MetaIndex.HatState, _stateManager, _state!));
|
||||||
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.CrestFromState(EquipSlot.Head, _stateManager, _state!));
|
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.CrestFromState(CrestFlag.Head, _stateManager, _state!));
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
using (var _ = ImRaii.Group())
|
using (var _ = ImRaii.Group())
|
||||||
{
|
{
|
||||||
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.FromState(ActorState.MetaIndex.VisorState, _stateManager, _state!));
|
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.FromState(ActorState.MetaIndex.VisorState, _stateManager, _state!));
|
||||||
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.CrestFromState(EquipSlot.Body, _stateManager, _state!));
|
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.CrestFromState(CrestFlag.Body, _stateManager, _state!));
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
using (var _ = ImRaii.Group())
|
using (var _ = ImRaii.Group())
|
||||||
{
|
{
|
||||||
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.FromState(ActorState.MetaIndex.WeaponState, _stateManager, _state!));
|
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.FromState(ActorState.MetaIndex.WeaponState, _stateManager, _state!));
|
||||||
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.CrestFromState(EquipSlot.OffHand, _stateManager, _state!));
|
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.CrestFromState(CrestFlag.OffHand, _stateManager, _state!));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -296,8 +296,8 @@ public class ActorPanel(ActorSelector _selector, StateManager _stateManager, Cus
|
||||||
{
|
{
|
||||||
ImGui.OpenPopup("Save as Design");
|
ImGui.OpenPopup("Save as Design");
|
||||||
_newName = _state!.Identifier.ToName();
|
_newName = _state!.Identifier.ToName();
|
||||||
var (applyGear, applyCustomize) = UiHelpers.ConvertKeysToFlags();
|
var (applyGear, applyCustomize, applyCrest) = UiHelpers.ConvertKeysToFlags();
|
||||||
_newDesign = _converter.Convert(_state, applyGear, applyCustomize);
|
_newDesign = _converter.Convert(_state, applyGear, applyCustomize, applyCrest);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SaveDesignDrawPopup()
|
private void SaveDesignDrawPopup()
|
||||||
|
|
@ -332,8 +332,8 @@ public class ActorPanel(ActorSelector _selector, StateManager _stateManager, Cus
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var (applyGear, applyCustomize) = UiHelpers.ConvertKeysToFlags();
|
var (applyGear, applyCustomize, applyCrest) = UiHelpers.ConvertKeysToFlags();
|
||||||
var text = _converter.ShareBase64(_state!, applyGear, applyCustomize);
|
var text = _converter.ShareBase64(_state!, applyGear, applyCustomize, applyCrest);
|
||||||
ImGui.SetClipboardText(text);
|
ImGui.SetClipboardText(text);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
|
@ -372,9 +372,9 @@ public class ActorPanel(ActorSelector _selector, StateManager _stateManager, Cus
|
||||||
!data.Valid || id == _identifier || _state!.ModelData.ModelId != 0))
|
!data.Valid || id == _identifier || _state!.ModelData.ModelId != 0))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var (applyGear, applyCustomize) = UiHelpers.ConvertKeysToFlags();
|
var (applyGear, applyCustomize, applyCrest) = UiHelpers.ConvertKeysToFlags();
|
||||||
if (_stateManager.GetOrCreate(id, data.Objects[0], out var state))
|
if (_stateManager.GetOrCreate(id, data.Objects[0], out var state))
|
||||||
_stateManager.ApplyDesign(_converter.Convert(_state!, applyGear, applyCustomize), state,
|
_stateManager.ApplyDesign(_converter.Convert(_state!, applyGear, applyCustomize, applyCrest), state,
|
||||||
StateChanged.Source.Manual);
|
StateChanged.Source.Manual);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -390,9 +390,9 @@ public class ActorPanel(ActorSelector _selector, StateManager _stateManager, Cus
|
||||||
!data.Valid || id == _identifier || _state!.ModelData.ModelId != 0))
|
!data.Valid || id == _identifier || _state!.ModelData.ModelId != 0))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var (applyGear, applyCustomize) = UiHelpers.ConvertKeysToFlags();
|
var (applyGear, applyCustomize, applyCrest) = UiHelpers.ConvertKeysToFlags();
|
||||||
if (_stateManager.GetOrCreate(id, data.Objects[0], out var state))
|
if (_stateManager.GetOrCreate(id, data.Objects[0], out var state))
|
||||||
_stateManager.ApplyDesign(_converter.Convert(_state!, applyGear, applyCustomize), state,
|
_stateManager.ApplyDesign(_converter.Convert(_state!, applyGear, applyCustomize, applyCrest), state,
|
||||||
StateChanged.Source.Manual);
|
StateChanged.Source.Manual);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -286,7 +286,7 @@ public class SetPanel
|
||||||
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();
|
||||||
foreach (var slot in EquipSlotExtensions.EqdpSlots.Append(EquipSlot.MainHand).Append(EquipSlot.OffHand))
|
foreach (var slot in EquipSlotExtensions.EqdpSlots.Append(EquipSlot.MainHand).Append(EquipSlot.OffHand))
|
||||||
{
|
{
|
||||||
|
|
@ -457,7 +457,7 @@ public class SetPanel
|
||||||
"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."),
|
||||||
(AutoDesign.Type.Armor, "Apply all armor piece changes that are enabled in this design and that are valid in a fixed design."),
|
(AutoDesign.Type.Armor, "Apply all armor piece changes that are enabled in this design and that are valid in a fixed design."),
|
||||||
(AutoDesign.Type.Accessories, "Apply all accessory changes that are enabled in this design and that are valid in a fixed design."),
|
(AutoDesign.Type.Accessories, "Apply all accessory changes that are enabled in this design and that are valid in a fixed design."),
|
||||||
(AutoDesign.Type.Stains, "Apply all dye changes that are enabled in this design."),
|
(AutoDesign.Type.GearCustomization, "Apply all dye and crest changes that are enabled in this design."),
|
||||||
(AutoDesign.Type.Weapons, "Apply all weapon changes that are enabled in this design and that are valid with the current weapon worn."),
|
(AutoDesign.Type.Weapons, "Apply all weapon changes that are enabled in this design and that are valid with the current weapon worn."),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -113,21 +113,21 @@ public class DesignPanel(DesignFileSystemSelector _selector, CustomizationDrawer
|
||||||
using (var _ = ImRaii.Group())
|
using (var _ = ImRaii.Group())
|
||||||
{
|
{
|
||||||
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.FromDesign(ActorState.MetaIndex.HatState, _manager, _selector.Selected!));
|
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.FromDesign(ActorState.MetaIndex.HatState, _manager, _selector.Selected!));
|
||||||
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.CrestFromDesign(EquipSlot.Head, _manager, _selector.Selected!));
|
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.CrestFromDesign(CrestFlag.Head, _manager, _selector.Selected!));
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
using (var _ = ImRaii.Group())
|
using (var _ = ImRaii.Group())
|
||||||
{
|
{
|
||||||
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.FromDesign(ActorState.MetaIndex.VisorState, _manager, _selector.Selected!));
|
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.FromDesign(ActorState.MetaIndex.VisorState, _manager, _selector.Selected!));
|
||||||
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.CrestFromDesign(EquipSlot.Body, _manager, _selector.Selected!));
|
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.CrestFromDesign(CrestFlag.Body, _manager, _selector.Selected!));
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui.SameLine();
|
ImGui.SameLine();
|
||||||
using (var _ = ImRaii.Group())
|
using (var _ = ImRaii.Group())
|
||||||
{
|
{
|
||||||
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.FromDesign(ActorState.MetaIndex.WeaponState, _manager, _selector.Selected!));
|
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.FromDesign(ActorState.MetaIndex.WeaponState, _manager, _selector.Selected!));
|
||||||
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.CrestFromDesign(EquipSlot.OffHand, _manager, _selector.Selected!));
|
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.CrestFromDesign(CrestFlag.OffHand, _manager, _selector.Selected!));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -191,10 +191,9 @@ public class DesignPanel(DesignFileSystemSelector _selector, CustomizationDrawer
|
||||||
var bigChange = ImGui.CheckboxFlags("Apply All Crests", ref flags, (uint)CrestExtensions.AllRelevant);
|
var bigChange = ImGui.CheckboxFlags("Apply All Crests", ref flags, (uint)CrestExtensions.AllRelevant);
|
||||||
foreach (var flag in CrestExtensions.AllRelevantSet)
|
foreach (var flag in CrestExtensions.AllRelevantSet)
|
||||||
{
|
{
|
||||||
var slot = flag.ToSlot();
|
var apply = bigChange ? ((CrestFlag)flags & flag) == flag : _selector.Selected!.DoApplyCrest(flag);
|
||||||
var apply = bigChange ? ((CrestFlag)flags & flag) == flag : _selector.Selected!.DoApplyCrest(slot);
|
|
||||||
if (ImGui.Checkbox($"Apply {flag.ToLabel()} Crest", ref apply) || bigChange)
|
if (ImGui.Checkbox($"Apply {flag.ToLabel()} Crest", ref apply) || bigChange)
|
||||||
_manager.ChangeApplyCrest(_selector.Selected!, slot, apply);
|
_manager.ChangeApplyCrest(_selector.Selected!, flag, apply);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -389,8 +388,8 @@ public class DesignPanel(DesignFileSystemSelector _selector, CustomizationDrawer
|
||||||
|
|
||||||
if (_state.GetOrCreate(id, data.Objects[0], out var state))
|
if (_state.GetOrCreate(id, data.Objects[0], out var state))
|
||||||
{
|
{
|
||||||
var (applyGear, applyCustomize) = UiHelpers.ConvertKeysToFlags();
|
var (applyGear, applyCustomize, applyCrest) = UiHelpers.ConvertKeysToFlags();
|
||||||
using var _ = _selector.Selected!.TemporarilyRestrictApplication(applyGear, applyCustomize);
|
using var _ = _selector.Selected!.TemporarilyRestrictApplication(applyGear, applyCustomize, applyCrest);
|
||||||
_state.ApplyDesign(_selector.Selected!, state, StateChanged.Source.Manual);
|
_state.ApplyDesign(_selector.Selected!, state, StateChanged.Source.Manual);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -408,8 +407,8 @@ public class DesignPanel(DesignFileSystemSelector _selector, CustomizationDrawer
|
||||||
|
|
||||||
if (_state.GetOrCreate(id, data.Objects[0], out var state))
|
if (_state.GetOrCreate(id, data.Objects[0], out var state))
|
||||||
{
|
{
|
||||||
var (applyGear, applyCustomize) = UiHelpers.ConvertKeysToFlags();
|
var (applyGear, applyCustomize, applyCrest) = UiHelpers.ConvertKeysToFlags();
|
||||||
using var _ = _selector.Selected!.TemporarilyRestrictApplication(applyGear, applyCustomize);
|
using var _ = _selector.Selected!.TemporarilyRestrictApplication(applyGear, applyCustomize, applyCrest);
|
||||||
_state.ApplyDesign(_selector.Selected!, state, StateChanged.Source.Manual);
|
_state.ApplyDesign(_selector.Selected!, state, StateChanged.Source.Manual);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -52,10 +52,10 @@ public ref struct ToggleDrawData
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ToggleDrawData CrestFromDesign(EquipSlot slot, DesignManager manager, Design design)
|
public static ToggleDrawData CrestFromDesign(CrestFlag slot, DesignManager manager, Design design)
|
||||||
=> new()
|
=> new()
|
||||||
{
|
{
|
||||||
Label = $"{slot.ToCrestFlag().ToLabel()} Crest",
|
Label = $"{slot.ToLabel()} Crest",
|
||||||
Tooltip = string.Empty,
|
Tooltip = string.Empty,
|
||||||
Locked = design.WriteProtected(),
|
Locked = design.WriteProtected(),
|
||||||
DisplayApplication = true,
|
DisplayApplication = true,
|
||||||
|
|
@ -65,14 +65,14 @@ public ref struct ToggleDrawData
|
||||||
SetApply = v => manager.ChangeApplyCrest(design, slot, v),
|
SetApply = v => manager.ChangeApplyCrest(design, slot, v),
|
||||||
};
|
};
|
||||||
|
|
||||||
public static ToggleDrawData CrestFromState(EquipSlot slot, StateManager manager, ActorState state)
|
public static ToggleDrawData CrestFromState(CrestFlag slot, StateManager manager, ActorState state)
|
||||||
=> new()
|
=> new()
|
||||||
{
|
{
|
||||||
Label = $"{slot.ToCrestFlag().ToLabel()} Crest",
|
Label = $"{slot.ToLabel()} Crest",
|
||||||
Tooltip = "Hide or show your free company crest on this piece of gear.",
|
Tooltip = "Hide or show your free company crest on this piece of gear.",
|
||||||
Locked = state.IsLocked,
|
Locked = state.IsLocked,
|
||||||
CurrentValue = state.ModelData.Crest(slot), // TODO
|
CurrentValue = state.ModelData.Crest(slot),
|
||||||
SetValue = v => { }, //manager.ChangeCrest(state, slot, v, StateChanged.Source.Manual),
|
SetValue = v => manager.ChangeCrest(state, slot, v, StateChanged.Source.Manual),
|
||||||
};
|
};
|
||||||
|
|
||||||
public static ToggleDrawData FromState(ActorState.MetaIndex index, StateManager manager, ActorState state)
|
public static ToggleDrawData FromState(ActorState.MetaIndex index, StateManager manager, ActorState state)
|
||||||
|
|
|
||||||
|
|
@ -88,13 +88,13 @@ public static class UiHelpers
|
||||||
return (currentValue != newValue, currentApply != newApply);
|
return (currentValue != newValue, currentApply != newApply);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static (EquipFlag, CustomizeFlag) ConvertKeysToFlags()
|
public static (EquipFlag, CustomizeFlag, CrestFlag) ConvertKeysToFlags()
|
||||||
=> (ImGui.GetIO().KeyCtrl, ImGui.GetIO().KeyShift) switch
|
=> (ImGui.GetIO().KeyCtrl, ImGui.GetIO().KeyShift) switch
|
||||||
{
|
{
|
||||||
(false, false) => (EquipFlagExtensions.All, CustomizeFlagExtensions.AllRelevant),
|
(false, false) => (EquipFlagExtensions.All, CustomizeFlagExtensions.AllRelevant, CrestExtensions.All),
|
||||||
(true, true) => (EquipFlagExtensions.All, CustomizeFlagExtensions.AllRelevant),
|
(true, true) => (EquipFlagExtensions.All, CustomizeFlagExtensions.AllRelevant, CrestExtensions.All),
|
||||||
(true, false) => (EquipFlagExtensions.All, (CustomizeFlag)0),
|
(true, false) => (EquipFlagExtensions.All, (CustomizeFlag)0, CrestExtensions.All),
|
||||||
(false, true) => ((EquipFlag)0, CustomizeFlagExtensions.AllRelevant),
|
(false, true) => ((EquipFlag)0, CustomizeFlagExtensions.AllRelevant, 0),
|
||||||
};
|
};
|
||||||
|
|
||||||
public static (bool, bool) ConvertKeysToBool()
|
public static (bool, bool) ConvertKeysToBool()
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
using Dalamud.Hooking;
|
using Dalamud.Hooking;
|
||||||
using Dalamud.Plugin.Services;
|
using Dalamud.Plugin.Services;
|
||||||
using Dalamud.Utility.Signatures;
|
using Dalamud.Utility.Signatures;
|
||||||
|
|
@ -19,11 +20,11 @@ namespace Glamourer.Interop;
|
||||||
/// <item>Parameter is the whether the crest will be shown. </item>
|
/// <item>Parameter is the whether the crest will be shown. </item>
|
||||||
/// </list>
|
/// </list>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed unsafe class CrestService : EventWrapper<Action<Model, EquipSlot, Ref<bool>>, CrestService.Priority>, IDisposable
|
public sealed unsafe class CrestService : EventWrapper<Action<Actor, CrestFlag, Ref<bool>>, CrestService.Priority>
|
||||||
{
|
{
|
||||||
public enum Priority
|
public enum Priority
|
||||||
{
|
{
|
||||||
/// <seealso cref="State.StateListener.OnCrestVisibilityUpdating"/>
|
/// <seealso cref="State.StateListener.OnCrestChange"/>
|
||||||
StateListener = 0,
|
StateListener = 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -37,19 +38,51 @@ public sealed unsafe class CrestService : EventWrapper<Action<Model, EquipSlot,
|
||||||
interop.HookFromAddress<SetCrestDelegateIntern>(_weaponVTable[96], WeaponSetFreeCompanyCrestVisibleOnSlotDetour);
|
interop.HookFromAddress<SetCrestDelegateIntern>(_weaponVTable[96], WeaponSetFreeCompanyCrestVisibleOnSlotDetour);
|
||||||
_humanSetFreeCompanyCrestVisibleOnSlot.Enable();
|
_humanSetFreeCompanyCrestVisibleOnSlot.Enable();
|
||||||
_weaponSetFreeCompanyCrestVisibleOnSlot.Enable();
|
_weaponSetFreeCompanyCrestVisibleOnSlot.Enable();
|
||||||
|
_crestChangeHook.Enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void UpdateCrests(Actor gameObject, CrestFlag flags)
|
||||||
|
{
|
||||||
|
if (!gameObject.IsCharacter)
|
||||||
|
return;
|
||||||
|
|
||||||
|
flags &= CrestExtensions.AllRelevant;
|
||||||
|
var currentCrests = gameObject.CrestBitfield;
|
||||||
|
using var update = _inUpdate.EnterMethod();
|
||||||
|
_crestChangeHook.Original(gameObject.AsCharacter, (byte) flags);
|
||||||
|
gameObject.CrestBitfield = currentCrests;
|
||||||
|
}
|
||||||
|
|
||||||
|
public delegate void DrawObjectCrestUpdateDelegate(Model drawObject, CrestFlag slot, ref bool value);
|
||||||
|
|
||||||
|
public event DrawObjectCrestUpdateDelegate? ModelCrestSetup;
|
||||||
|
|
||||||
protected override void Dispose(bool _)
|
protected override void Dispose(bool _)
|
||||||
{
|
{
|
||||||
_humanSetFreeCompanyCrestVisibleOnSlot.Dispose();
|
_humanSetFreeCompanyCrestVisibleOnSlot.Dispose();
|
||||||
_weaponSetFreeCompanyCrestVisibleOnSlot.Dispose();
|
_weaponSetFreeCompanyCrestVisibleOnSlot.Dispose();
|
||||||
|
_crestChangeHook.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Invoke(Model model, EquipSlot slot, ref bool visible)
|
private delegate void CrestChangeDelegate(Character* character, byte crestFlags);
|
||||||
|
|
||||||
|
[Signature("E8 ?? ?? ?? ?? 48 8B 55 ?? 49 8B CE E8", DetourName = nameof(CrestChangeDetour))]
|
||||||
|
private readonly Hook<CrestChangeDelegate> _crestChangeHook = null!;
|
||||||
|
|
||||||
|
private void CrestChangeDetour(Character* character, byte crestFlags)
|
||||||
{
|
{
|
||||||
var ret = new Ref<bool>(visible);
|
var actor = (Actor)character;
|
||||||
Invoke(this, model, slot, ret);
|
foreach (var slot in CrestExtensions.AllRelevantSet)
|
||||||
visible = ret;
|
{
|
||||||
|
var newValue = new Ref<bool>(((CrestFlag)crestFlags).HasFlag(slot));
|
||||||
|
Invoke(this, actor, slot, newValue);
|
||||||
|
crestFlags = (byte)(newValue.Value ? crestFlags | (byte)slot : crestFlags & (byte)~slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
Glamourer.Log.Information(
|
||||||
|
$"Called CrestChange on {(ulong)character:X} with {crestFlags:X} and prior flags {((Actor)character).CrestBitfield}.");
|
||||||
|
using var _ = _inUpdate.EnterMethod();
|
||||||
|
_crestChangeHook.Original(character, crestFlags);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool GetModelCrest(Actor gameObject, CrestFlag slot)
|
public static bool GetModelCrest(Actor gameObject, CrestFlag slot)
|
||||||
|
|
@ -83,42 +116,9 @@ public sealed unsafe class CrestService : EventWrapper<Action<Model, EquipSlot,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateCrest(Actor gameObject, CrestFlag slot, bool crest)
|
|
||||||
{
|
|
||||||
if (!gameObject.IsCharacter)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var (type, index) = slot.ToIndex();
|
|
||||||
switch (type)
|
|
||||||
{
|
|
||||||
case CrestType.Human:
|
|
||||||
{
|
|
||||||
var model = gameObject.Model;
|
|
||||||
if (!model.IsHuman)
|
|
||||||
return;
|
|
||||||
|
|
||||||
using var _ = _inUpdate.EnterMethod();
|
|
||||||
var setter = (delegate* unmanaged<Human*, byte, byte, void>)((nint*)model.AsCharacterBase->VTable)[96];
|
|
||||||
setter(model.AsHuman, index, crest ? (byte)1 : (byte)0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case CrestType.Offhand:
|
|
||||||
{
|
|
||||||
var model = (Model)gameObject.AsCharacter->DrawData.Weapon(DrawDataContainer.WeaponSlot.OffHand).DrawObject;
|
|
||||||
if (!model.IsWeapon)
|
|
||||||
return;
|
|
||||||
|
|
||||||
using var _ = _inUpdate.EnterMethod();
|
|
||||||
var setter = (delegate* unmanaged<Weapon*, byte, byte, void>)((nint*)model.AsCharacterBase->VTable)[96];
|
|
||||||
setter(model.AsWeapon, index, crest ? (byte)1 : (byte)0);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly InMethodChecker _inUpdate = new();
|
private readonly InMethodChecker _inUpdate = new();
|
||||||
|
|
||||||
private delegate void SetCrestDelegateIntern(nint drawObject, byte slot, byte visible);
|
private delegate void SetCrestDelegateIntern(DrawObject* drawObject, byte slot, byte visible);
|
||||||
|
|
||||||
[Signature(global::Penumbra.GameData.Sigs.HumanVTable, ScanType = ScanType.StaticAddress)]
|
[Signature(global::Penumbra.GameData.Sigs.HumanVTable, ScanType = ScanType.StaticAddress)]
|
||||||
private readonly nint* _humanVTable = null!;
|
private readonly nint* _humanVTable = null!;
|
||||||
|
|
@ -129,26 +129,27 @@ public sealed unsafe class CrestService : EventWrapper<Action<Model, EquipSlot,
|
||||||
private readonly Hook<SetCrestDelegateIntern> _humanSetFreeCompanyCrestVisibleOnSlot;
|
private readonly Hook<SetCrestDelegateIntern> _humanSetFreeCompanyCrestVisibleOnSlot;
|
||||||
private readonly Hook<SetCrestDelegateIntern> _weaponSetFreeCompanyCrestVisibleOnSlot;
|
private readonly Hook<SetCrestDelegateIntern> _weaponSetFreeCompanyCrestVisibleOnSlot;
|
||||||
|
|
||||||
private void HumanSetFreeCompanyCrestVisibleOnSlotDetour(nint drawObject, byte slotIdx, byte visible)
|
private void HumanSetFreeCompanyCrestVisibleOnSlotDetour(DrawObject* drawObject, byte slotIdx, byte visible)
|
||||||
{
|
{
|
||||||
var slot = ((uint)slotIdx).ToEquipSlot();
|
|
||||||
var rVisible = visible != 0;
|
var rVisible = visible != 0;
|
||||||
var inUpdate = _inUpdate.InMethod;
|
var inUpdate = _inUpdate.InMethod;
|
||||||
|
var slot = (CrestFlag)((ushort)CrestFlag.Head << slotIdx);
|
||||||
if (!inUpdate)
|
if (!inUpdate)
|
||||||
Invoke(drawObject, slot, ref rVisible);
|
ModelCrestSetup?.Invoke(drawObject, slot, ref rVisible);
|
||||||
|
|
||||||
Glamourer.Log.Excessive(
|
Glamourer.Log.Excessive(
|
||||||
$"[Human.SetFreeCompanyCrestVisibleOnSlot] Called with 0x{drawObject:X} for slot {slot} with {rVisible} (original: {visible != 0}, in update: {inUpdate}).");
|
$"[Human.SetFreeCompanyCrestVisibleOnSlot] Called with 0x{(ulong)drawObject:X} for slot {slot} with {rVisible} (original: {visible != 0}, in update: {inUpdate}).");
|
||||||
_humanSetFreeCompanyCrestVisibleOnSlot.Original(drawObject, slotIdx, rVisible ? (byte)1 : (byte)0);
|
_humanSetFreeCompanyCrestVisibleOnSlot.Original(drawObject, slotIdx, rVisible ? (byte)1 : (byte)0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void WeaponSetFreeCompanyCrestVisibleOnSlotDetour(nint drawObject, byte slotIdx, byte visible)
|
private void WeaponSetFreeCompanyCrestVisibleOnSlotDetour(DrawObject* drawObject, byte slotIdx, byte visible)
|
||||||
{
|
{
|
||||||
var rVisible = visible != 0;
|
var rVisible = visible != 0;
|
||||||
var inUpdate = _inUpdate.InMethod;
|
var inUpdate = _inUpdate.InMethod;
|
||||||
if (!inUpdate)
|
if (!inUpdate && slotIdx == 0)
|
||||||
Invoke(drawObject, EquipSlot.BothHand, ref rVisible);
|
ModelCrestSetup?.Invoke(drawObject, CrestFlag.OffHand, ref rVisible);
|
||||||
Glamourer.Log.Excessive(
|
Glamourer.Log.Excessive(
|
||||||
$"[Weapon.SetFreeCompanyCrestVisibleOnSlot] Called with 0x{drawObject:X} with {rVisible} (original: {visible != 0}, in update: {inUpdate}).");
|
$"[Weapon.SetFreeCompanyCrestVisibleOnSlot] Called with 0x{(ulong)drawObject:X} with {rVisible} (original: {visible != 0}, in update: {inUpdate}).");
|
||||||
_weaponSetFreeCompanyCrestVisibleOnSlot.Original(drawObject, slotIdx, rVisible ? (byte)1 : (byte)0);
|
_weaponSetFreeCompanyCrestVisibleOnSlot.Original(drawObject, slotIdx, rVisible ? (byte)1 : (byte)0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -108,7 +108,7 @@ public readonly unsafe struct Actor : IEquatable<Actor>
|
||||||
=> ((CharacterArmor*)&AsCharacter->DrawData.Head)[slot.ToIndex()];
|
=> ((CharacterArmor*)&AsCharacter->DrawData.Head)[slot.ToIndex()];
|
||||||
|
|
||||||
public bool GetCrest(CrestFlag slot)
|
public bool GetCrest(CrestFlag slot)
|
||||||
=> (GetFreeCompanyCrestBitfield() & CrestMask(slot)) != 0;
|
=> CrestBitfield.HasFlag(slot);
|
||||||
|
|
||||||
public CharacterWeapon GetMainhand()
|
public CharacterWeapon GetMainhand()
|
||||||
=> new(AsCharacter->DrawData.Weapon(DrawDataContainer.WeaponSlot.MainHand).ModelId.Value);
|
=> new(AsCharacter->DrawData.Weapon(DrawDataContainer.WeaponSlot.MainHand).ModelId.Value);
|
||||||
|
|
@ -120,20 +120,8 @@ public readonly unsafe struct Actor : IEquatable<Actor>
|
||||||
=> *(Customize*)&AsCharacter->DrawData.CustomizeData;
|
=> *(Customize*)&AsCharacter->DrawData.CustomizeData;
|
||||||
|
|
||||||
// TODO remove this when available in ClientStructs
|
// TODO remove this when available in ClientStructs
|
||||||
private byte GetFreeCompanyCrestBitfield()
|
internal ref CrestFlag CrestBitfield
|
||||||
=> ((byte*)Address)[0x1BBB];
|
=> ref *(CrestFlag*)((byte*)Address + 0x1BBB);
|
||||||
|
|
||||||
private static byte CrestMask(CrestFlag slot)
|
|
||||||
=> slot switch
|
|
||||||
{
|
|
||||||
CrestFlag.OffHand => 0x01,
|
|
||||||
CrestFlag.Head => 0x02,
|
|
||||||
CrestFlag.Body => 0x04,
|
|
||||||
CrestFlag.Hands => 0x08,
|
|
||||||
CrestFlag.Legs => 0x10,
|
|
||||||
CrestFlag.Feet => 0x20,
|
|
||||||
_ => 0x00,
|
|
||||||
};
|
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
=> $"0x{Address:X}";
|
=> $"0x{Address:X}";
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ using Dalamud.Plugin.Services;
|
||||||
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
||||||
using Glamourer.Events;
|
using Glamourer.Events;
|
||||||
using Glamourer.Interop.Structs;
|
using Glamourer.Interop.Structs;
|
||||||
|
using Glamourer.Structs;
|
||||||
using Penumbra.GameData.Enums;
|
using Penumbra.GameData.Enums;
|
||||||
using Penumbra.GameData.Structs;
|
using Penumbra.GameData.Structs;
|
||||||
|
|
||||||
|
|
@ -13,6 +14,7 @@ namespace Glamourer.Interop;
|
||||||
public unsafe class WeaponService : IDisposable
|
public unsafe class WeaponService : IDisposable
|
||||||
{
|
{
|
||||||
private readonly WeaponLoading _event;
|
private readonly WeaponLoading _event;
|
||||||
|
private readonly CrestService _crestService;
|
||||||
private readonly ThreadLocal<bool> _inUpdate = new(() => false);
|
private readonly ThreadLocal<bool> _inUpdate = new(() => false);
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -20,9 +22,10 @@ public unsafe class WeaponService : IDisposable
|
||||||
_original;
|
_original;
|
||||||
|
|
||||||
|
|
||||||
public WeaponService(WeaponLoading @event, IGameInteropProvider interop)
|
public WeaponService(WeaponLoading @event, IGameInteropProvider interop, CrestService crestService)
|
||||||
{
|
{
|
||||||
_event = @event;
|
_event = @event;
|
||||||
|
_crestService = crestService;
|
||||||
_loadWeaponHook =
|
_loadWeaponHook =
|
||||||
interop.HookFromAddress<LoadWeaponDelegate>((nint)DrawDataContainer.MemberFunctionPointers.LoadWeapon, LoadWeaponDetour);
|
interop.HookFromAddress<LoadWeaponDelegate>((nint)DrawDataContainer.MemberFunctionPointers.LoadWeapon, LoadWeaponDetour);
|
||||||
_original =
|
_original =
|
||||||
|
|
@ -69,6 +72,7 @@ public unsafe class WeaponService : IDisposable
|
||||||
_event.Invoke(actor, EquipSlot.MainHand, ref tmpWeapon);
|
_event.Invoke(actor, EquipSlot.MainHand, ref tmpWeapon);
|
||||||
|
|
||||||
_loadWeaponHook.Original(drawData, slot, weapon.Value, redrawOnEquality, unk2, skipGameObject, unk4);
|
_loadWeaponHook.Original(drawData, slot, weapon.Value, redrawOnEquality, unk2, skipGameObject, unk4);
|
||||||
|
|
||||||
if (tmpWeapon.Value != weapon.Value)
|
if (tmpWeapon.Value != weapon.Value)
|
||||||
{
|
{
|
||||||
if (tmpWeapon.Set.Id == 0)
|
if (tmpWeapon.Set.Id == 0)
|
||||||
|
|
|
||||||
|
|
@ -165,7 +165,7 @@ public class CommandService : IDisposable
|
||||||
.AddInitialPurple("Customizations, ")
|
.AddInitialPurple("Customizations, ")
|
||||||
.AddInitialPurple("Equipment, ")
|
.AddInitialPurple("Equipment, ")
|
||||||
.AddInitialPurple("Accessories, ")
|
.AddInitialPurple("Accessories, ")
|
||||||
.AddInitialPurple("Dyes and ")
|
.AddInitialPurple("Dyes & Crests and ")
|
||||||
.AddInitialPurple("Weapons, where ").AddPurple("CEADW")
|
.AddInitialPurple("Weapons, where ").AddPurple("CEADW")
|
||||||
.AddText(" means everything should be toggled on, and no value means nothing should be toggled on.")
|
.AddText(" means everything should be toggled on, and no value means nothing should be toggled on.")
|
||||||
.BuiltString);
|
.BuiltString);
|
||||||
|
|
@ -268,7 +268,7 @@ public class CommandService : IDisposable
|
||||||
applicationFlags |= AutoDesign.Type.Accessories;
|
applicationFlags |= AutoDesign.Type.Accessories;
|
||||||
break;
|
break;
|
||||||
case 'd':
|
case 'd':
|
||||||
applicationFlags |= AutoDesign.Type.Stains;
|
applicationFlags |= AutoDesign.Type.GearCustomization;
|
||||||
break;
|
break;
|
||||||
case 'w':
|
case 'w':
|
||||||
applicationFlags |= AutoDesign.Type.Weapons;
|
applicationFlags |= AutoDesign.Type.Weapons;
|
||||||
|
|
@ -472,7 +472,7 @@ public class CommandService : IDisposable
|
||||||
&& _stateManager.GetOrCreate(identifier, data.Objects[0], out state)))
|
&& _stateManager.GetOrCreate(identifier, data.Objects[0], out state)))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var design = _converter.Convert(state, EquipFlagExtensions.All, CustomizeFlagExtensions.AllRelevant);
|
var design = _converter.Convert(state, EquipFlagExtensions.All, CustomizeFlagExtensions.AllRelevant, CrestExtensions.All);
|
||||||
_designManager.CreateClone(design, split[0], true);
|
_designManager.CreateClone(design, split[0], true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,12 @@
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
|
||||||
using Glamourer.Customization;
|
using Glamourer.Customization;
|
||||||
using Glamourer.Events;
|
using Glamourer.Events;
|
||||||
using Glamourer.Interop;
|
using Glamourer.Interop;
|
||||||
using Glamourer.Interop.Penumbra;
|
using Glamourer.Interop.Penumbra;
|
||||||
using Glamourer.Interop.Structs;
|
using Glamourer.Interop.Structs;
|
||||||
using Glamourer.Services;
|
using Glamourer.Services;
|
||||||
|
using Glamourer.Structs;
|
||||||
using Penumbra.Api.Enums;
|
using Penumbra.Api.Enums;
|
||||||
using Penumbra.GameData.Actors;
|
|
||||||
using Penumbra.GameData.Enums;
|
using Penumbra.GameData.Enums;
|
||||||
using Penumbra.GameData.Structs;
|
using Penumbra.GameData.Structs;
|
||||||
|
|
||||||
|
|
@ -17,30 +16,9 @@ namespace Glamourer.State;
|
||||||
/// This class applies changes made to state to actual objects in the game.
|
/// This class applies changes made to state to actual objects in the game.
|
||||||
/// It handles applying those changes as well as redrawing the actor if necessary.
|
/// It handles applying those changes as well as redrawing the actor if necessary.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class StateApplier
|
public class StateApplier(UpdateSlotService _updateSlot, VisorService _visor, WeaponService _weapon, ChangeCustomizeService _changeCustomize,
|
||||||
|
ItemManager _items, PenumbraService _penumbra, MetaService _metaService, ObjectManager _objects, CrestService _crests)
|
||||||
{
|
{
|
||||||
private readonly PenumbraService _penumbra;
|
|
||||||
private readonly UpdateSlotService _updateSlot;
|
|
||||||
private readonly VisorService _visor;
|
|
||||||
private readonly WeaponService _weapon;
|
|
||||||
private readonly MetaService _metaService;
|
|
||||||
private readonly ChangeCustomizeService _changeCustomize;
|
|
||||||
private readonly ItemManager _items;
|
|
||||||
private readonly ObjectManager _objects;
|
|
||||||
|
|
||||||
public StateApplier(UpdateSlotService updateSlot, VisorService visor, WeaponService weapon, ChangeCustomizeService changeCustomize,
|
|
||||||
ItemManager items, PenumbraService penumbra, MetaService metaService, ObjectManager objects)
|
|
||||||
{
|
|
||||||
_updateSlot = updateSlot;
|
|
||||||
_visor = visor;
|
|
||||||
_weapon = weapon;
|
|
||||||
_changeCustomize = changeCustomize;
|
|
||||||
_items = items;
|
|
||||||
_penumbra = penumbra;
|
|
||||||
_metaService = metaService;
|
|
||||||
_objects = objects;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary> Simply force a redraw regardless of conditions. </summary>
|
/// <summary> Simply force a redraw regardless of conditions. </summary>
|
||||||
public void ForceRedraw(ActorData data)
|
public void ForceRedraw(ActorData data)
|
||||||
{
|
{
|
||||||
|
|
@ -279,6 +257,22 @@ public class StateApplier
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary> Change the crest state on actors. </summary>
|
||||||
|
public void ChangeCrests(ActorData data, CrestFlag flags)
|
||||||
|
{
|
||||||
|
foreach (var actor in data.Objects.Where(a => a.IsCharacter))
|
||||||
|
_crests.UpdateCrests(actor, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc cref="ChangeCrests(ActorData, CrestFlag)"/>
|
||||||
|
public ActorData ChangeCrests(ActorState state, bool apply)
|
||||||
|
{
|
||||||
|
var data = GetData(state);
|
||||||
|
if (apply)
|
||||||
|
ChangeCrests(data, state.ModelData.CrestVisibility);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
private ActorData GetData(ActorState state)
|
private ActorData GetData(ActorState state)
|
||||||
{
|
{
|
||||||
_objects.Update();
|
_objects.Update();
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ using Dalamud.Plugin.Services;
|
||||||
using Glamourer.Customization;
|
using Glamourer.Customization;
|
||||||
using Glamourer.Events;
|
using Glamourer.Events;
|
||||||
using Glamourer.Services;
|
using Glamourer.Services;
|
||||||
|
using Glamourer.Structs;
|
||||||
using Penumbra.GameData.Data;
|
using Penumbra.GameData.Data;
|
||||||
using Penumbra.GameData.Enums;
|
using Penumbra.GameData.Enums;
|
||||||
using Penumbra.GameData.Structs;
|
using Penumbra.GameData.Structs;
|
||||||
|
|
@ -197,6 +198,18 @@ public class StateEditor
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary> Change the crest of an equipment piece. </summary>
|
||||||
|
public bool ChangeCrest(ActorState state, CrestFlag slot, bool crest, StateChanged.Source source, out bool oldCrest, uint key = 0)
|
||||||
|
{
|
||||||
|
oldCrest = state.ModelData.Crest(slot);
|
||||||
|
if (!state.CanUnlock(key))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
state.ModelData.SetCrest(slot, crest);
|
||||||
|
state[slot] = source;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public bool ChangeMetaState(ActorState state, ActorState.MetaIndex index, bool value, StateChanged.Source source, out bool oldValue,
|
public bool ChangeMetaState(ActorState state, ActorState.MetaIndex index, bool value, StateChanged.Source source, out bool oldValue,
|
||||||
uint key = 0)
|
uint key = 0)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ using Penumbra.GameData.Structs;
|
||||||
using System;
|
using System;
|
||||||
using Dalamud.Game.ClientState.Conditions;
|
using Dalamud.Game.ClientState.Conditions;
|
||||||
using Dalamud.Plugin.Services;
|
using Dalamud.Plugin.Services;
|
||||||
|
using Glamourer.Structs;
|
||||||
|
|
||||||
namespace Glamourer.State;
|
namespace Glamourer.State;
|
||||||
|
|
||||||
|
|
@ -42,6 +43,7 @@ public class StateListener : IDisposable
|
||||||
private readonly MovedEquipment _movedEquipment;
|
private readonly MovedEquipment _movedEquipment;
|
||||||
private readonly GPoseService _gPose;
|
private readonly GPoseService _gPose;
|
||||||
private readonly ChangeCustomizeService _changeCustomizeService;
|
private readonly ChangeCustomizeService _changeCustomizeService;
|
||||||
|
private readonly CrestService _crestService;
|
||||||
private readonly ICondition _condition;
|
private readonly ICondition _condition;
|
||||||
|
|
||||||
private ActorIdentifier _creatingIdentifier = ActorIdentifier.Invalid;
|
private ActorIdentifier _creatingIdentifier = ActorIdentifier.Invalid;
|
||||||
|
|
@ -52,7 +54,7 @@ public class StateListener : IDisposable
|
||||||
SlotUpdating slotUpdating, WeaponLoading weaponLoading, VisorStateChanged visorState, WeaponVisibilityChanged weaponVisibility,
|
SlotUpdating slotUpdating, WeaponLoading weaponLoading, VisorStateChanged visorState, WeaponVisibilityChanged weaponVisibility,
|
||||||
HeadGearVisibilityChanged headGearVisibility, AutoDesignApplier autoDesignApplier, FunModule funModule, HumanModelList humans,
|
HeadGearVisibilityChanged headGearVisibility, AutoDesignApplier autoDesignApplier, FunModule funModule, HumanModelList humans,
|
||||||
StateApplier applier, MovedEquipment movedEquipment, ObjectManager objects, GPoseService gPose,
|
StateApplier applier, MovedEquipment movedEquipment, ObjectManager objects, GPoseService gPose,
|
||||||
ChangeCustomizeService changeCustomizeService, CustomizationService customizations, ICondition condition)
|
ChangeCustomizeService changeCustomizeService, CustomizationService customizations, ICondition condition, CrestService crestService)
|
||||||
{
|
{
|
||||||
_manager = manager;
|
_manager = manager;
|
||||||
_items = items;
|
_items = items;
|
||||||
|
|
@ -74,6 +76,7 @@ public class StateListener : IDisposable
|
||||||
_changeCustomizeService = changeCustomizeService;
|
_changeCustomizeService = changeCustomizeService;
|
||||||
_customizations = customizations;
|
_customizations = customizations;
|
||||||
_condition = condition;
|
_condition = condition;
|
||||||
|
_crestService = crestService;
|
||||||
Subscribe();
|
Subscribe();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -405,6 +408,58 @@ public class StateListener : IDisposable
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnCrestChange(Actor actor, CrestFlag slot, Ref<bool> value)
|
||||||
|
{
|
||||||
|
if (_condition[ConditionFlag.CreatingCharacter] && actor.Index >= ObjectIndex.CutsceneStart)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!actor.Identifier(_actors.AwaitedService, out var identifier)
|
||||||
|
|| !_manager.TryGetValue(identifier, out var state))
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (UpdateBaseCrest(actor, state, slot, value.Value))
|
||||||
|
{
|
||||||
|
case UpdateState.Change:
|
||||||
|
if (state[slot] is not StateChanged.Source.Fixed and not StateChanged.Source.Ipc)
|
||||||
|
_manager.ChangeCrest(state, slot, state.BaseData.Crest(slot), StateChanged.Source.Game);
|
||||||
|
else
|
||||||
|
value.Value = state.ModelData.Crest(slot);
|
||||||
|
break;
|
||||||
|
case UpdateState.NoChange:
|
||||||
|
case UpdateState.HatHack:
|
||||||
|
value.Value = state.ModelData.Crest(slot);
|
||||||
|
break;
|
||||||
|
case UpdateState.Transformed: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnModelCrestSetup(Model model, CrestFlag slot, ref bool value)
|
||||||
|
{
|
||||||
|
var actor = _penumbra.GameObjectFromDrawObject(model);
|
||||||
|
if (_condition[ConditionFlag.CreatingCharacter] && actor.Index >= ObjectIndex.CutsceneStart)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!actor.Identifier(_actors.AwaitedService, out var identifier)
|
||||||
|
|| !_manager.TryGetValue(identifier, out var state))
|
||||||
|
return;
|
||||||
|
|
||||||
|
value = state.ModelData.Crest(slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static UpdateState UpdateBaseCrest(Actor actor, ActorState state, CrestFlag slot, bool visible)
|
||||||
|
{
|
||||||
|
if (actor.IsTransformed)
|
||||||
|
return UpdateState.Transformed;
|
||||||
|
|
||||||
|
if (state.BaseData.Crest(slot) != visible)
|
||||||
|
{
|
||||||
|
state.BaseData.SetCrest(slot, visible);
|
||||||
|
return UpdateState.Change;
|
||||||
|
}
|
||||||
|
|
||||||
|
return UpdateState.NoChange;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary> Update base data for a single changed weapon slot. </summary>
|
/// <summary> Update base data for a single changed weapon slot. </summary>
|
||||||
private unsafe UpdateState UpdateBaseData(Actor actor, ActorState state, EquipSlot slot, CharacterWeapon weapon)
|
private unsafe UpdateState UpdateBaseData(Actor actor, ActorState state, EquipSlot slot, CharacterWeapon weapon)
|
||||||
{
|
{
|
||||||
|
|
@ -616,6 +671,8 @@ public class StateListener : IDisposable
|
||||||
_headGearVisibility.Subscribe(OnHeadGearVisibilityChange, HeadGearVisibilityChanged.Priority.StateListener);
|
_headGearVisibility.Subscribe(OnHeadGearVisibilityChange, HeadGearVisibilityChanged.Priority.StateListener);
|
||||||
_weaponVisibility.Subscribe(OnWeaponVisibilityChange, WeaponVisibilityChanged.Priority.StateListener);
|
_weaponVisibility.Subscribe(OnWeaponVisibilityChange, WeaponVisibilityChanged.Priority.StateListener);
|
||||||
_changeCustomizeService.Subscribe(OnCustomizeChange, ChangeCustomizeService.Priority.StateListener);
|
_changeCustomizeService.Subscribe(OnCustomizeChange, ChangeCustomizeService.Priority.StateListener);
|
||||||
|
_crestService.Subscribe(OnCrestChange, CrestService.Priority.StateListener);
|
||||||
|
_crestService.ModelCrestSetup += OnModelCrestSetup;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Unsubscribe()
|
private void Unsubscribe()
|
||||||
|
|
@ -629,6 +686,8 @@ public class StateListener : IDisposable
|
||||||
_headGearVisibility.Unsubscribe(OnHeadGearVisibilityChange);
|
_headGearVisibility.Unsubscribe(OnHeadGearVisibilityChange);
|
||||||
_weaponVisibility.Unsubscribe(OnWeaponVisibilityChange);
|
_weaponVisibility.Unsubscribe(OnWeaponVisibilityChange);
|
||||||
_changeCustomizeService.Unsubscribe(OnCustomizeChange);
|
_changeCustomizeService.Unsubscribe(OnCustomizeChange);
|
||||||
|
_crestService.Unsubscribe(OnCrestChange);
|
||||||
|
_crestService.ModelCrestSetup -= OnModelCrestSetup;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnCreatedCharacterBase(nint gameObject, string _, nint drawObject)
|
private void OnCreatedCharacterBase(nint gameObject, string _, nint drawObject)
|
||||||
|
|
@ -639,8 +698,9 @@ public class StateListener : IDisposable
|
||||||
if (_creatingState == null)
|
if (_creatingState == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_applier.ChangeHatState(new ActorData(gameObject, _creatingIdentifier.ToName()), _creatingState.ModelData.IsHatVisible());
|
var data = new ActorData(gameObject, _creatingIdentifier.ToName());
|
||||||
_applier.ChangeWeaponState(new ActorData(gameObject, _creatingIdentifier.ToName()), _creatingState.ModelData.IsWeaponVisible());
|
_applier.ChangeHatState(data, _creatingState.ModelData.IsHatVisible());
|
||||||
_applier.ChangeWetness(new ActorData(gameObject, _creatingIdentifier.ToName()), _creatingState.ModelData.IsWet());
|
_applier.ChangeWeaponState(data, _creatingState.ModelData.IsWeaponVisible());
|
||||||
|
_applier.ChangeWetness(data, _creatingState.ModelData.IsWet());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ using Glamourer.Events;
|
||||||
using Glamourer.Interop;
|
using Glamourer.Interop;
|
||||||
using Glamourer.Interop.Structs;
|
using Glamourer.Interop.Structs;
|
||||||
using Glamourer.Services;
|
using Glamourer.Services;
|
||||||
|
using Glamourer.Structs;
|
||||||
using Penumbra.GameData.Actors;
|
using Penumbra.GameData.Actors;
|
||||||
using Penumbra.GameData.Data;
|
using Penumbra.GameData.Data;
|
||||||
using Penumbra.GameData.Enums;
|
using Penumbra.GameData.Enums;
|
||||||
|
|
@ -17,32 +18,12 @@ using Penumbra.GameData.Structs;
|
||||||
|
|
||||||
namespace Glamourer.State;
|
namespace Glamourer.State;
|
||||||
|
|
||||||
public class StateManager : IReadOnlyDictionary<ActorIdentifier, ActorState>
|
public class StateManager(ActorService _actors, ItemManager _items, StateChanged _event, StateApplier _applier, StateEditor _editor,
|
||||||
|
HumanModelList _humans, ICondition _condition, IClientState _clientState)
|
||||||
|
: IReadOnlyDictionary<ActorIdentifier, ActorState>
|
||||||
{
|
{
|
||||||
private readonly ActorService _actors;
|
|
||||||
private readonly ItemManager _items;
|
|
||||||
private readonly HumanModelList _humans;
|
|
||||||
private readonly StateChanged _event;
|
|
||||||
private readonly StateApplier _applier;
|
|
||||||
private readonly StateEditor _editor;
|
|
||||||
private readonly ICondition _condition;
|
|
||||||
private readonly IClientState _clientState;
|
|
||||||
|
|
||||||
private readonly Dictionary<ActorIdentifier, ActorState> _states = new();
|
private readonly Dictionary<ActorIdentifier, ActorState> _states = new();
|
||||||
|
|
||||||
public StateManager(ActorService actors, ItemManager items, StateChanged @event, StateApplier applier, StateEditor editor,
|
|
||||||
HumanModelList humans, ICondition condition, IClientState clientState)
|
|
||||||
{
|
|
||||||
_actors = actors;
|
|
||||||
_items = items;
|
|
||||||
_event = @event;
|
|
||||||
_applier = applier;
|
|
||||||
_editor = editor;
|
|
||||||
_humans = humans;
|
|
||||||
_condition = condition;
|
|
||||||
_clientState = clientState;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerator<KeyValuePair<ActorIdentifier, ActorState>> GetEnumerator()
|
public IEnumerator<KeyValuePair<ActorIdentifier, ActorState>> GetEnumerator()
|
||||||
=> _states.GetEnumerator();
|
=> _states.GetEnumerator();
|
||||||
|
|
||||||
|
|
@ -83,7 +64,7 @@ public class StateManager : IReadOnlyDictionary<ActorIdentifier, ActorState>
|
||||||
// and the draw objects data for the model data (where possible).
|
// and the draw objects data for the model data (where possible).
|
||||||
state = new ActorState(identifier)
|
state = new ActorState(identifier)
|
||||||
{
|
{
|
||||||
ModelData = FromActor(actor, true, false),
|
ModelData = FromActor(actor, true, false),
|
||||||
BaseData = FromActor(actor, false, false),
|
BaseData = FromActor(actor, false, false),
|
||||||
LastJob = (byte)(actor.IsCharacter ? actor.AsCharacter->CharacterData.ClassJob : 0),
|
LastJob = (byte)(actor.IsCharacter ? actor.AsCharacter->CharacterData.ClassJob : 0),
|
||||||
LastTerritory = _clientState.TerritoryType,
|
LastTerritory = _clientState.TerritoryType,
|
||||||
|
|
@ -162,6 +143,9 @@ public class StateManager : IReadOnlyDictionary<ActorIdentifier, ActorState>
|
||||||
|
|
||||||
// Visor state is a flag on the game object, but we can see the actual state on the draw object.
|
// Visor state is a flag on the game object, but we can see the actual state on the draw object.
|
||||||
ret.SetVisor(VisorService.GetVisorState(model));
|
ret.SetVisor(VisorService.GetVisorState(model));
|
||||||
|
|
||||||
|
foreach (var slot in CrestExtensions.AllRelevantSet)
|
||||||
|
ret.SetCrest(slot, CrestService.GetModelCrest(actor, slot));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -180,6 +164,9 @@ public class StateManager : IReadOnlyDictionary<ActorIdentifier, ActorState>
|
||||||
off = actor.GetOffhand();
|
off = actor.GetOffhand();
|
||||||
FistWeaponHack(ref ret, ref main, ref off);
|
FistWeaponHack(ref ret, ref main, ref off);
|
||||||
ret.SetVisor(actor.AsCharacter->DrawData.IsVisorToggled);
|
ret.SetVisor(actor.AsCharacter->DrawData.IsVisorToggled);
|
||||||
|
|
||||||
|
foreach (var slot in CrestExtensions.AllRelevantSet)
|
||||||
|
ret.SetCrest(slot, actor.GetCrest(slot));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the weapons regardless of source.
|
// Set the weapons regardless of source.
|
||||||
|
|
@ -206,7 +193,7 @@ public class StateManager : IReadOnlyDictionary<ActorIdentifier, ActorState>
|
||||||
if (mainhand.Set.Id is < 1601 or >= 1651)
|
if (mainhand.Set.Id is < 1601 or >= 1651)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var gauntlets = _items.Identify(EquipSlot.Hands, offhand.Set, (Variant) offhand.Type.Id);
|
var gauntlets = _items.Identify(EquipSlot.Hands, offhand.Set, (Variant)offhand.Type.Id);
|
||||||
offhand.Set = (SetId)(mainhand.Set.Id + 50);
|
offhand.Set = (SetId)(mainhand.Set.Id + 50);
|
||||||
offhand.Variant = mainhand.Variant;
|
offhand.Variant = mainhand.Variant;
|
||||||
offhand.Type = mainhand.Type;
|
offhand.Type = mainhand.Type;
|
||||||
|
|
@ -304,6 +291,18 @@ public class StateManager : IReadOnlyDictionary<ActorIdentifier, ActorState>
|
||||||
_event.Invoke(StateChanged.Type.Stain, source, state, actors, (old, stain, slot));
|
_event.Invoke(StateChanged.Type.Stain, source, state, actors, (old, stain, slot));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary> Change the crest of an equipment piece. </summary>
|
||||||
|
public void ChangeCrest(ActorState state, CrestFlag slot, bool crest, StateChanged.Source source, uint key = 0)
|
||||||
|
{
|
||||||
|
if (!_editor.ChangeCrest(state, slot, crest, source, out var old, key))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var actors = _applier.ChangeCrests(state, source is StateChanged.Source.Manual or StateChanged.Source.Ipc);
|
||||||
|
Glamourer.Log.Verbose(
|
||||||
|
$"Set {slot.ToLabel()} crest in state {state.Identifier.Incognito(null)} from {old} to {crest}. [Affecting {actors.ToLazyString("nothing")}.]");
|
||||||
|
_event.Invoke(StateChanged.Type.Crest, source, state, actors, (old, crest, slot));
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary> Change hat visibility. </summary>
|
/// <summary> Change hat visibility. </summary>
|
||||||
public void ChangeHatState(ActorState state, bool value, StateChanged.Source source, uint key = 0)
|
public void ChangeHatState(ActorState state, bool value, StateChanged.Source source, uint key = 0)
|
||||||
{
|
{
|
||||||
|
|
@ -356,19 +355,8 @@ public class StateManager : IReadOnlyDictionary<ActorIdentifier, ActorState>
|
||||||
|
|
||||||
public void ApplyDesign(DesignBase design, ActorState state, StateChanged.Source source, uint key = 0)
|
public void ApplyDesign(DesignBase design, ActorState state, StateChanged.Source source, uint key = 0)
|
||||||
{
|
{
|
||||||
void HandleEquip(EquipSlot slot, bool applyPiece, bool applyStain)
|
if (!_editor.ChangeModelId(state, design.DesignData.ModelId, design.DesignData.Customize, design.GetDesignDataRef().GetEquipmentPtr(),
|
||||||
{
|
source,
|
||||||
var unused = (applyPiece, applyStain) switch
|
|
||||||
{
|
|
||||||
(false, false) => false,
|
|
||||||
(true, false) => _editor.ChangeItem(state, slot, design.DesignData.Item(slot), source, out _, key),
|
|
||||||
(false, true) => _editor.ChangeStain(state, slot, design.DesignData.Stain(slot), source, out _, key),
|
|
||||||
(true, true) => _editor.ChangeEquip(state, slot, design.DesignData.Item(slot), design.DesignData.Stain(slot), source, out _,
|
|
||||||
out _, key),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_editor.ChangeModelId(state, design.DesignData.ModelId, design.DesignData.Customize, design.GetDesignDataRef().GetEquipmentPtr(), source,
|
|
||||||
out var oldModelId, key))
|
out var oldModelId, key))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
@ -393,12 +381,28 @@ public class StateManager : IReadOnlyDictionary<ActorIdentifier, ActorState>
|
||||||
|
|
||||||
foreach (var slot in EquipSlotExtensions.FullSlots)
|
foreach (var slot in EquipSlotExtensions.FullSlots)
|
||||||
HandleEquip(slot, design.DoApplyEquip(slot), design.DoApplyStain(slot));
|
HandleEquip(slot, design.DoApplyEquip(slot), design.DoApplyStain(slot));
|
||||||
|
|
||||||
|
foreach (var slot in CrestExtensions.AllRelevantSet.Where(design.DoApplyCrest))
|
||||||
|
_editor.ChangeCrest(state, slot, design.DesignData.Crest(slot), source, out _, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
var actors = ApplyAll(state, redraw, false);
|
var actors = ApplyAll(state, redraw, false);
|
||||||
Glamourer.Log.Verbose(
|
Glamourer.Log.Verbose(
|
||||||
$"Applied design to {state.Identifier.Incognito(null)}. [Affecting {actors.ToLazyString("nothing")}.]");
|
$"Applied design to {state.Identifier.Incognito(null)}. [Affecting {actors.ToLazyString("nothing")}.]");
|
||||||
_event.Invoke(StateChanged.Type.Design, state[ActorState.MetaIndex.Wetness], state, actors, design);
|
_event.Invoke(StateChanged.Type.Design, state[ActorState.MetaIndex.Wetness], state, actors, design);
|
||||||
|
return;
|
||||||
|
|
||||||
|
void HandleEquip(EquipSlot slot, bool applyPiece, bool applyStain)
|
||||||
|
{
|
||||||
|
var unused = (applyPiece, applyStain) switch
|
||||||
|
{
|
||||||
|
(false, false) => false,
|
||||||
|
(true, false) => _editor.ChangeItem(state, slot, design.DesignData.Item(slot), source, out _, key),
|
||||||
|
(false, true) => _editor.ChangeStain(state, slot, design.DesignData.Stain(slot), source, out _, key),
|
||||||
|
(true, true) => _editor.ChangeEquip(state, slot, design.DesignData.Item(slot), design.DesignData.Stain(slot), source, out _,
|
||||||
|
out _, key),
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ActorData ApplyAll(ActorState state, bool redraw, bool withLock)
|
private ActorData ApplyAll(ActorState state, bool redraw, bool withLock)
|
||||||
|
|
@ -430,6 +434,7 @@ public class StateManager : IReadOnlyDictionary<ActorIdentifier, ActorState>
|
||||||
_applier.ChangeHatState(actors, state.ModelData.IsHatVisible());
|
_applier.ChangeHatState(actors, state.ModelData.IsHatVisible());
|
||||||
_applier.ChangeWeaponState(actors, state.ModelData.IsWeaponVisible());
|
_applier.ChangeWeaponState(actors, state.ModelData.IsWeaponVisible());
|
||||||
_applier.ChangeVisor(actors, state.ModelData.IsVisorToggled());
|
_applier.ChangeVisor(actors, state.ModelData.IsVisorToggled());
|
||||||
|
_applier.ChangeCrests(actors, state.ModelData.CrestVisibility);
|
||||||
}
|
}
|
||||||
|
|
||||||
return actors;
|
return actors;
|
||||||
|
|
@ -453,10 +458,13 @@ public class StateManager : IReadOnlyDictionary<ActorIdentifier, ActorState>
|
||||||
state[slot, true] = StateChanged.Source.Game;
|
state[slot, true] = StateChanged.Source.Game;
|
||||||
state[slot, false] = StateChanged.Source.Game;
|
state[slot, false] = StateChanged.Source.Game;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var type in Enum.GetValues<ActorState.MetaIndex>())
|
foreach (var type in Enum.GetValues<ActorState.MetaIndex>())
|
||||||
state[type] = StateChanged.Source.Game;
|
state[type] = StateChanged.Source.Game;
|
||||||
|
|
||||||
|
foreach (var slot in CrestExtensions.AllRelevantSet)
|
||||||
|
state[slot] = StateChanged.Source.Game;
|
||||||
|
|
||||||
var actors = ActorData.Invalid;
|
var actors = ActorData.Invalid;
|
||||||
if (source is StateChanged.Source.Manual or StateChanged.Source.Ipc)
|
if (source is StateChanged.Source.Manual or StateChanged.Source.Ipc)
|
||||||
actors = ApplyAll(state, redraw, true);
|
actors = ApplyAll(state, redraw, true);
|
||||||
|
|
@ -491,6 +499,15 @@ public class StateManager : IReadOnlyDictionary<ActorIdentifier, ActorState>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (var slot in CrestExtensions.AllRelevantSet)
|
||||||
|
{
|
||||||
|
if (state[slot] is StateChanged.Source.Fixed)
|
||||||
|
{
|
||||||
|
state[slot] = StateChanged.Source.Game;
|
||||||
|
state.ModelData.SetCrest(slot, state.BaseData.Crest(slot));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (state[ActorState.MetaIndex.HatState] is StateChanged.Source.Fixed)
|
if (state[ActorState.MetaIndex.HatState] is StateChanged.Source.Fixed)
|
||||||
{
|
{
|
||||||
state[ActorState.MetaIndex.HatState] = StateChanged.Source.Game;
|
state[ActorState.MetaIndex.HatState] = StateChanged.Source.Game;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue