mirror of
https://github.com/xivdev/Penumbra.git
synced 2026-01-03 06:13:45 +01:00
Add support for Global EQP Changes.
This commit is contained in:
parent
f9527970cb
commit
ed083f2a4c
15 changed files with 471 additions and 133 deletions
80
Penumbra/Meta/Manipulations/GlobalEqpCache.cs
Normal file
80
Penumbra/Meta/Manipulations/GlobalEqpCache.cs
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
using OtterGui.Services;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
namespace Penumbra.Meta.Manipulations;
|
||||
|
||||
public struct GlobalEqpCache : IService
|
||||
{
|
||||
private readonly HashSet<PrimaryId> _doNotHideEarrings = [];
|
||||
private readonly HashSet<PrimaryId> _doNotHideNecklace = [];
|
||||
private readonly HashSet<PrimaryId> _doNotHideBracelets = [];
|
||||
private readonly HashSet<PrimaryId> _doNotHideRingL = [];
|
||||
private readonly HashSet<PrimaryId> _doNotHideRingR = [];
|
||||
private bool _doNotHideVieraHats;
|
||||
private bool _doNotHideHrothgarHats;
|
||||
|
||||
public GlobalEqpCache()
|
||||
{ }
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
_doNotHideEarrings.Clear();
|
||||
_doNotHideNecklace.Clear();
|
||||
_doNotHideBracelets.Clear();
|
||||
_doNotHideRingL.Clear();
|
||||
_doNotHideRingR.Clear();
|
||||
_doNotHideHrothgarHats = false;
|
||||
_doNotHideVieraHats = false;
|
||||
}
|
||||
|
||||
public unsafe EqpEntry Apply(EqpEntry original, CharacterArmor* armor)
|
||||
{
|
||||
if (_doNotHideVieraHats)
|
||||
original |= EqpEntry.HeadShowVieraHat;
|
||||
|
||||
if (_doNotHideHrothgarHats)
|
||||
original |= EqpEntry.HeadShowHrothgarHat;
|
||||
|
||||
if (_doNotHideEarrings.Contains(armor[5].Set))
|
||||
original |= EqpEntry.HeadShowEarrings | EqpEntry.HeadShowEarringsAura | EqpEntry.HeadShowEarringsHuman;
|
||||
|
||||
if (_doNotHideNecklace.Contains(armor[6].Set))
|
||||
original |= EqpEntry.BodyShowNecklace | EqpEntry.HeadShowNecklace;
|
||||
|
||||
if (_doNotHideBracelets.Contains(armor[7].Set))
|
||||
original |= EqpEntry.BodyShowBracelet | EqpEntry.HandShowBracelet;
|
||||
|
||||
if (_doNotHideBracelets.Contains(armor[8].Set))
|
||||
original |= EqpEntry.HandShowRingR;
|
||||
|
||||
if (_doNotHideBracelets.Contains(armor[9].Set))
|
||||
original |= EqpEntry.HandShowRingL;
|
||||
return original;
|
||||
}
|
||||
|
||||
public bool Add(GlobalEqpManipulation manipulation)
|
||||
=> manipulation.Type switch
|
||||
{
|
||||
GlobalEqpType.DoNotHideEarrings => _doNotHideEarrings.Add(manipulation.Condition),
|
||||
GlobalEqpType.DoNotHideNecklace => _doNotHideNecklace.Add(manipulation.Condition),
|
||||
GlobalEqpType.DoNotHideBracelets => _doNotHideBracelets.Add(manipulation.Condition),
|
||||
GlobalEqpType.DoNotHideRingR => _doNotHideRingR.Add(manipulation.Condition),
|
||||
GlobalEqpType.DoNotHideRingL => _doNotHideRingL.Add(manipulation.Condition),
|
||||
GlobalEqpType.DoNotHideHrothgarHats => !_doNotHideHrothgarHats && (_doNotHideHrothgarHats = true),
|
||||
GlobalEqpType.DoNotHideVieraHats => !_doNotHideVieraHats && (_doNotHideVieraHats = true),
|
||||
_ => false,
|
||||
};
|
||||
|
||||
public bool Remove(GlobalEqpManipulation manipulation)
|
||||
=> manipulation.Type switch
|
||||
{
|
||||
GlobalEqpType.DoNotHideEarrings => _doNotHideEarrings.Remove(manipulation.Condition),
|
||||
GlobalEqpType.DoNotHideNecklace => _doNotHideNecklace.Remove(manipulation.Condition),
|
||||
GlobalEqpType.DoNotHideBracelets => _doNotHideBracelets.Remove(manipulation.Condition),
|
||||
GlobalEqpType.DoNotHideRingR => _doNotHideRingR.Remove(manipulation.Condition),
|
||||
GlobalEqpType.DoNotHideRingL => _doNotHideRingL.Remove(manipulation.Condition),
|
||||
GlobalEqpType.DoNotHideHrothgarHats => _doNotHideHrothgarHats && !(_doNotHideHrothgarHats = false),
|
||||
GlobalEqpType.DoNotHideVieraHats => _doNotHideVieraHats && !(_doNotHideVieraHats = false),
|
||||
_ => false,
|
||||
};
|
||||
}
|
||||
50
Penumbra/Meta/Manipulations/GlobalEqpManipulation.cs
Normal file
50
Penumbra/Meta/Manipulations/GlobalEqpManipulation.cs
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
using Penumbra.GameData.Structs;
|
||||
using Penumbra.Interop.Structs;
|
||||
|
||||
namespace Penumbra.Meta.Manipulations;
|
||||
|
||||
public readonly struct GlobalEqpManipulation : IMetaManipulation<GlobalEqpManipulation>
|
||||
{
|
||||
public GlobalEqpType Type { get; init; }
|
||||
public PrimaryId Condition { get; init; }
|
||||
|
||||
public bool Validate()
|
||||
{
|
||||
if (!Enum.IsDefined(Type))
|
||||
return false;
|
||||
|
||||
if (Type is GlobalEqpType.DoNotHideVieraHats or GlobalEqpType.DoNotHideHrothgarHats)
|
||||
return Condition == 0;
|
||||
|
||||
return Condition != 0;
|
||||
}
|
||||
|
||||
|
||||
public bool Equals(GlobalEqpManipulation other)
|
||||
=> Type == other.Type
|
||||
&& Condition.Equals(other.Condition);
|
||||
|
||||
public int CompareTo(GlobalEqpManipulation other)
|
||||
{
|
||||
var typeComp = Type.CompareTo(other);
|
||||
return typeComp != 0 ? typeComp : Condition.Id.CompareTo(other.Condition.Id);
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
=> obj is GlobalEqpManipulation other && Equals(other);
|
||||
|
||||
public override int GetHashCode()
|
||||
=> HashCode.Combine((int)Type, Condition);
|
||||
|
||||
public static bool operator ==(GlobalEqpManipulation left, GlobalEqpManipulation right)
|
||||
=> left.Equals(right);
|
||||
|
||||
public static bool operator !=(GlobalEqpManipulation left, GlobalEqpManipulation right)
|
||||
=> !left.Equals(right);
|
||||
|
||||
public override string ToString()
|
||||
=> $"Global EQP - {Type}{(Condition != 0 ? $" - {Condition.Id}" : string.Empty)}";
|
||||
|
||||
public MetaIndex FileIndex()
|
||||
=> (MetaIndex)(-1);
|
||||
}
|
||||
61
Penumbra/Meta/Manipulations/GlobalEqpType.cs
Normal file
61
Penumbra/Meta/Manipulations/GlobalEqpType.cs
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
namespace Penumbra.Meta.Manipulations;
|
||||
|
||||
public enum GlobalEqpType
|
||||
{
|
||||
DoNotHideEarrings,
|
||||
DoNotHideNecklace,
|
||||
DoNotHideBracelets,
|
||||
DoNotHideRingR,
|
||||
DoNotHideRingL,
|
||||
DoNotHideHrothgarHats,
|
||||
DoNotHideVieraHats,
|
||||
}
|
||||
|
||||
public static class GlobalEqpExtensions
|
||||
{
|
||||
public static bool HasCondition(this GlobalEqpType type)
|
||||
=> type switch
|
||||
{
|
||||
GlobalEqpType.DoNotHideEarrings => true,
|
||||
GlobalEqpType.DoNotHideNecklace => true,
|
||||
GlobalEqpType.DoNotHideBracelets => true,
|
||||
GlobalEqpType.DoNotHideRingR => true,
|
||||
GlobalEqpType.DoNotHideRingL => true,
|
||||
GlobalEqpType.DoNotHideHrothgarHats => false,
|
||||
GlobalEqpType.DoNotHideVieraHats => false,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
|
||||
public static ReadOnlySpan<byte> ToName(this GlobalEqpType type)
|
||||
=> type switch
|
||||
{
|
||||
GlobalEqpType.DoNotHideEarrings => "Do Not Hide Earrings"u8,
|
||||
GlobalEqpType.DoNotHideNecklace => "Do Not Hide Necklaces"u8,
|
||||
GlobalEqpType.DoNotHideBracelets => "Do Not Hide Bracelets"u8,
|
||||
GlobalEqpType.DoNotHideRingR => "Do Not Hide Rings (Right Finger)"u8,
|
||||
GlobalEqpType.DoNotHideRingL => "Do Not Hide Rings (Left Finger)"u8,
|
||||
GlobalEqpType.DoNotHideHrothgarHats => "Do Not Hide Hats for Hrothgar"u8,
|
||||
GlobalEqpType.DoNotHideVieraHats => "Do Not Hide Hats for Viera"u8,
|
||||
_ => "\0"u8,
|
||||
};
|
||||
|
||||
public static ReadOnlySpan<byte> ToDescription(this GlobalEqpType type)
|
||||
=> type switch
|
||||
{
|
||||
GlobalEqpType.DoNotHideEarrings => "Prevents the game from hiding earrings through other models when a specific earring is worn."u8,
|
||||
GlobalEqpType.DoNotHideNecklace =>
|
||||
"Prevents the game from hiding necklaces through other models when a specific necklace is worn."u8,
|
||||
GlobalEqpType.DoNotHideBracelets =>
|
||||
"Prevents the game from hiding bracelets through other models when a specific bracelet is worn."u8,
|
||||
GlobalEqpType.DoNotHideRingR =>
|
||||
"Prevents the game from hiding rings worn on the right finger through other models when a specific ring is worn on the right finger."u8,
|
||||
GlobalEqpType.DoNotHideRingL =>
|
||||
"Prevents the game from hiding rings worn on the left finger through other models when a specific ring is worn on the left finger."u8,
|
||||
GlobalEqpType.DoNotHideHrothgarHats =>
|
||||
"Prevents the game from hiding any hats for Hrothgar that are normally flagged to not display on them."u8,
|
||||
GlobalEqpType.DoNotHideVieraHats =>
|
||||
"Prevents the game from hiding any hats for Viera that are normally flagged to not display on them."u8,
|
||||
_ => "\0"u8,
|
||||
};
|
||||
}
|
||||
|
|
@ -21,13 +21,14 @@ public readonly struct MetaManipulation : IEquatable<MetaManipulation>, ICompara
|
|||
|
||||
public enum Type : byte
|
||||
{
|
||||
Unknown = 0,
|
||||
Imc = 1,
|
||||
Eqdp = 2,
|
||||
Eqp = 3,
|
||||
Est = 4,
|
||||
Gmp = 5,
|
||||
Rsp = 6,
|
||||
Unknown = 0,
|
||||
Imc = 1,
|
||||
Eqdp = 2,
|
||||
Eqp = 3,
|
||||
Est = 4,
|
||||
Gmp = 5,
|
||||
Rsp = 6,
|
||||
GlobalEqp = 7,
|
||||
}
|
||||
|
||||
[FieldOffset(0)]
|
||||
|
|
@ -54,6 +55,10 @@ public readonly struct MetaManipulation : IEquatable<MetaManipulation>, ICompara
|
|||
[JsonIgnore]
|
||||
public readonly ImcManipulation Imc = default;
|
||||
|
||||
[FieldOffset(0)]
|
||||
[JsonIgnore]
|
||||
public readonly GlobalEqpManipulation GlobalEqp = default;
|
||||
|
||||
[FieldOffset(15)]
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
[JsonProperty("Type")]
|
||||
|
|
@ -63,14 +68,15 @@ public readonly struct MetaManipulation : IEquatable<MetaManipulation>, ICompara
|
|||
{
|
||||
get => ManipulationType switch
|
||||
{
|
||||
Type.Unknown => null,
|
||||
Type.Imc => Imc,
|
||||
Type.Eqdp => Eqdp,
|
||||
Type.Eqp => Eqp,
|
||||
Type.Est => Est,
|
||||
Type.Gmp => Gmp,
|
||||
Type.Rsp => Rsp,
|
||||
_ => null,
|
||||
Type.Unknown => null,
|
||||
Type.Imc => Imc,
|
||||
Type.Eqdp => Eqdp,
|
||||
Type.Eqp => Eqp,
|
||||
Type.Est => Est,
|
||||
Type.Gmp => Gmp,
|
||||
Type.Rsp => Rsp,
|
||||
Type.GlobalEqp => GlobalEqp,
|
||||
_ => null,
|
||||
};
|
||||
init
|
||||
{
|
||||
|
|
@ -100,6 +106,10 @@ public readonly struct MetaManipulation : IEquatable<MetaManipulation>, ICompara
|
|||
Imc = m;
|
||||
ManipulationType = m.Validate(true) ? Type.Imc : Type.Unknown;
|
||||
return;
|
||||
case GlobalEqpManipulation m:
|
||||
GlobalEqp = m;
|
||||
ManipulationType = m.Validate() ? Type.GlobalEqp : Type.Unknown;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -108,13 +118,14 @@ public readonly struct MetaManipulation : IEquatable<MetaManipulation>, ICompara
|
|||
{
|
||||
return ManipulationType switch
|
||||
{
|
||||
Type.Imc => Imc.Validate(true),
|
||||
Type.Eqdp => Eqdp.Validate(),
|
||||
Type.Eqp => Eqp.Validate(),
|
||||
Type.Est => Est.Validate(),
|
||||
Type.Gmp => Gmp.Validate(),
|
||||
Type.Rsp => Rsp.Validate(),
|
||||
_ => false,
|
||||
Type.Imc => Imc.Validate(true),
|
||||
Type.Eqdp => Eqdp.Validate(),
|
||||
Type.Eqp => Eqp.Validate(),
|
||||
Type.Est => Est.Validate(),
|
||||
Type.Gmp => Gmp.Validate(),
|
||||
Type.Rsp => Rsp.Validate(),
|
||||
Type.GlobalEqp => GlobalEqp.Validate(),
|
||||
_ => false,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -154,6 +165,12 @@ public readonly struct MetaManipulation : IEquatable<MetaManipulation>, ICompara
|
|||
ManipulationType = Type.Imc;
|
||||
}
|
||||
|
||||
public MetaManipulation(GlobalEqpManipulation eqp)
|
||||
{
|
||||
GlobalEqp = eqp;
|
||||
ManipulationType = Type.GlobalEqp;
|
||||
}
|
||||
|
||||
public static implicit operator MetaManipulation(EqpManipulation eqp)
|
||||
=> new(eqp);
|
||||
|
||||
|
|
@ -172,6 +189,9 @@ public readonly struct MetaManipulation : IEquatable<MetaManipulation>, ICompara
|
|||
public static implicit operator MetaManipulation(ImcManipulation imc)
|
||||
=> new(imc);
|
||||
|
||||
public static implicit operator MetaManipulation(GlobalEqpManipulation eqp)
|
||||
=> new(eqp);
|
||||
|
||||
public bool EntryEquals(MetaManipulation other)
|
||||
{
|
||||
if (ManipulationType != other.ManipulationType)
|
||||
|
|
@ -179,13 +199,14 @@ public readonly struct MetaManipulation : IEquatable<MetaManipulation>, ICompara
|
|||
|
||||
return ManipulationType switch
|
||||
{
|
||||
Type.Eqp => Eqp.Entry.Equals(other.Eqp.Entry),
|
||||
Type.Gmp => Gmp.Entry.Equals(other.Gmp.Entry),
|
||||
Type.Eqdp => Eqdp.Entry.Equals(other.Eqdp.Entry),
|
||||
Type.Est => Est.Entry.Equals(other.Est.Entry),
|
||||
Type.Rsp => Rsp.Entry.Equals(other.Rsp.Entry),
|
||||
Type.Imc => Imc.Entry.Equals(other.Imc.Entry),
|
||||
_ => throw new ArgumentOutOfRangeException(),
|
||||
Type.Eqp => Eqp.Entry.Equals(other.Eqp.Entry),
|
||||
Type.Gmp => Gmp.Entry.Equals(other.Gmp.Entry),
|
||||
Type.Eqdp => Eqdp.Entry.Equals(other.Eqdp.Entry),
|
||||
Type.Est => Est.Entry.Equals(other.Est.Entry),
|
||||
Type.Rsp => Rsp.Entry.Equals(other.Rsp.Entry),
|
||||
Type.Imc => Imc.Entry.Equals(other.Imc.Entry),
|
||||
Type.GlobalEqp => true,
|
||||
_ => throw new ArgumentOutOfRangeException(),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -196,13 +217,14 @@ public readonly struct MetaManipulation : IEquatable<MetaManipulation>, ICompara
|
|||
|
||||
return ManipulationType switch
|
||||
{
|
||||
Type.Eqp => Eqp.Equals(other.Eqp),
|
||||
Type.Gmp => Gmp.Equals(other.Gmp),
|
||||
Type.Eqdp => Eqdp.Equals(other.Eqdp),
|
||||
Type.Est => Est.Equals(other.Est),
|
||||
Type.Rsp => Rsp.Equals(other.Rsp),
|
||||
Type.Imc => Imc.Equals(other.Imc),
|
||||
_ => false,
|
||||
Type.Eqp => Eqp.Equals(other.Eqp),
|
||||
Type.Gmp => Gmp.Equals(other.Gmp),
|
||||
Type.Eqdp => Eqdp.Equals(other.Eqdp),
|
||||
Type.Est => Est.Equals(other.Est),
|
||||
Type.Rsp => Rsp.Equals(other.Rsp),
|
||||
Type.Imc => Imc.Equals(other.Imc),
|
||||
Type.GlobalEqp => GlobalEqp.Equals(other.GlobalEqp),
|
||||
_ => false,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -213,13 +235,14 @@ public readonly struct MetaManipulation : IEquatable<MetaManipulation>, ICompara
|
|||
|
||||
return ManipulationType switch
|
||||
{
|
||||
Type.Eqp => Eqp.Copy(other.Eqp.Entry),
|
||||
Type.Gmp => Gmp.Copy(other.Gmp.Entry),
|
||||
Type.Eqdp => Eqdp.Copy(other.Eqdp),
|
||||
Type.Est => Est.Copy(other.Est.Entry),
|
||||
Type.Rsp => Rsp.Copy(other.Rsp.Entry),
|
||||
Type.Imc => Imc.Copy(other.Imc.Entry),
|
||||
_ => throw new ArgumentOutOfRangeException(),
|
||||
Type.Eqp => Eqp.Copy(other.Eqp.Entry),
|
||||
Type.Gmp => Gmp.Copy(other.Gmp.Entry),
|
||||
Type.Eqdp => Eqdp.Copy(other.Eqdp),
|
||||
Type.Est => Est.Copy(other.Est.Entry),
|
||||
Type.Rsp => Rsp.Copy(other.Rsp.Entry),
|
||||
Type.Imc => Imc.Copy(other.Imc.Entry),
|
||||
Type.GlobalEqp => GlobalEqp,
|
||||
_ => throw new ArgumentOutOfRangeException(),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -229,13 +252,14 @@ public readonly struct MetaManipulation : IEquatable<MetaManipulation>, ICompara
|
|||
public override int GetHashCode()
|
||||
=> ManipulationType switch
|
||||
{
|
||||
Type.Eqp => Eqp.GetHashCode(),
|
||||
Type.Gmp => Gmp.GetHashCode(),
|
||||
Type.Eqdp => Eqdp.GetHashCode(),
|
||||
Type.Est => Est.GetHashCode(),
|
||||
Type.Rsp => Rsp.GetHashCode(),
|
||||
Type.Imc => Imc.GetHashCode(),
|
||||
_ => 0,
|
||||
Type.Eqp => Eqp.GetHashCode(),
|
||||
Type.Gmp => Gmp.GetHashCode(),
|
||||
Type.Eqdp => Eqdp.GetHashCode(),
|
||||
Type.Est => Est.GetHashCode(),
|
||||
Type.Rsp => Rsp.GetHashCode(),
|
||||
Type.Imc => Imc.GetHashCode(),
|
||||
Type.GlobalEqp => GlobalEqp.GetHashCode(),
|
||||
_ => 0,
|
||||
};
|
||||
|
||||
public unsafe int CompareTo(MetaManipulation other)
|
||||
|
|
@ -249,13 +273,14 @@ public readonly struct MetaManipulation : IEquatable<MetaManipulation>, ICompara
|
|||
public override string ToString()
|
||||
=> ManipulationType switch
|
||||
{
|
||||
Type.Eqp => Eqp.ToString(),
|
||||
Type.Gmp => Gmp.ToString(),
|
||||
Type.Eqdp => Eqdp.ToString(),
|
||||
Type.Est => Est.ToString(),
|
||||
Type.Rsp => Rsp.ToString(),
|
||||
Type.Imc => Imc.ToString(),
|
||||
_ => "Invalid",
|
||||
Type.Eqp => Eqp.ToString(),
|
||||
Type.Gmp => Gmp.ToString(),
|
||||
Type.Eqdp => Eqdp.ToString(),
|
||||
Type.Est => Est.ToString(),
|
||||
Type.Rsp => Rsp.ToString(),
|
||||
Type.Imc => Imc.ToString(),
|
||||
Type.GlobalEqp => GlobalEqp.ToString(),
|
||||
_ => "Invalid",
|
||||
};
|
||||
|
||||
public string EntryToString()
|
||||
|
|
@ -263,14 +288,15 @@ public readonly struct MetaManipulation : IEquatable<MetaManipulation>, ICompara
|
|||
{
|
||||
Type.Imc =>
|
||||
$"{Imc.Entry.DecalId}-{Imc.Entry.MaterialId}-{Imc.Entry.VfxId}-{Imc.Entry.SoundId}-{Imc.Entry.MaterialAnimationId}-{Imc.Entry.AttributeMask}",
|
||||
Type.Eqdp => $"{(ushort)Eqdp.Entry:X}",
|
||||
Type.Eqp => $"{(ulong)Eqp.Entry:X}",
|
||||
Type.Est => $"{Est.Entry}",
|
||||
Type.Gmp => $"{Gmp.Entry.Value}",
|
||||
Type.Rsp => $"{Rsp.Entry}",
|
||||
_ => string.Empty,
|
||||
};
|
||||
|
||||
Type.Eqdp => $"{(ushort)Eqdp.Entry:X}",
|
||||
Type.Eqp => $"{(ulong)Eqp.Entry:X}",
|
||||
Type.Est => $"{Est.Entry}",
|
||||
Type.Gmp => $"{Gmp.Entry.Value}",
|
||||
Type.Rsp => $"{Rsp.Entry}",
|
||||
Type.GlobalEqp => string.Empty,
|
||||
_ => string.Empty,
|
||||
};
|
||||
|
||||
public static bool operator ==(MetaManipulation left, MetaManipulation right)
|
||||
=> left.Equals(right);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue