mirror of
https://github.com/Ottermandias/Glamourer.git
synced 2025-12-12 18:27:24 +01:00
Add interop for Actor and Model.
This commit is contained in:
parent
6f4a7661d7
commit
512d0a1a5f
6 changed files with 98 additions and 27 deletions
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.InstanceContent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using Penumbra.GameData.Enums;
|
||||
|
||||
namespace Glamourer.Structs;
|
||||
|
|
@ -15,23 +16,37 @@ public enum CrestFlag : ushort
|
|||
Feet = 0x0010,
|
||||
Ears = 0x0020,
|
||||
Neck = 0x0040,
|
||||
Wrist = 0x0080,
|
||||
Wrists = 0x0080,
|
||||
RFinger = 0x0100,
|
||||
LFinger = 0x0200,
|
||||
Mainhand = 0x0400,
|
||||
Offhand = 0x0800,
|
||||
MainHand = 0x0400,
|
||||
OffHand = 0x0800,
|
||||
}
|
||||
|
||||
public static class CrestExtensions
|
||||
{
|
||||
public const CrestFlag All = (CrestFlag)(((ulong)EquipFlag.Offhand << 1) - 1);
|
||||
public const CrestFlag AllRelevant = CrestFlag.Body;
|
||||
public const CrestFlag AllRelevant = CrestFlag.Head | CrestFlag.Body | CrestFlag.OffHand;
|
||||
|
||||
public static readonly IReadOnlyList<CrestFlag> AllRelevantSet = Enum.GetValues<CrestFlag>().Where(f => f.ToRelevantIndex() >= 0).ToArray();
|
||||
|
||||
public static int ToIndex(this CrestFlag flag)
|
||||
=> BitOperations.TrailingZeroCount((uint)flag);
|
||||
|
||||
public static int ToRelevantIndex(this CrestFlag flag)
|
||||
=> flag switch
|
||||
{
|
||||
CrestFlag.Head => 0,
|
||||
CrestFlag.Body => 1,
|
||||
CrestFlag.OffHand => 2,
|
||||
_ => -1,
|
||||
};
|
||||
|
||||
public static CrestFlag ToCrestFlag(this EquipSlot slot)
|
||||
=> slot switch
|
||||
{
|
||||
EquipSlot.MainHand => CrestFlag.Mainhand,
|
||||
EquipSlot.OffHand => CrestFlag.Offhand,
|
||||
EquipSlot.MainHand => CrestFlag.MainHand,
|
||||
EquipSlot.OffHand => CrestFlag.OffHand,
|
||||
EquipSlot.Head => CrestFlag.Head,
|
||||
EquipSlot.Body => CrestFlag.Body,
|
||||
EquipSlot.Hands => CrestFlag.Hands,
|
||||
|
|
@ -39,12 +54,27 @@ public static class CrestExtensions
|
|||
EquipSlot.Feet => CrestFlag.Feet,
|
||||
EquipSlot.Ears => CrestFlag.Ears,
|
||||
EquipSlot.Neck => CrestFlag.Neck,
|
||||
EquipSlot.Wrists => CrestFlag.Wrist,
|
||||
EquipSlot.Wrists => CrestFlag.Wrists,
|
||||
EquipSlot.RFinger => CrestFlag.RFinger,
|
||||
EquipSlot.LFinger => CrestFlag.LFinger,
|
||||
_ => 0,
|
||||
};
|
||||
|
||||
public static bool Valid(this CrestFlag crest)
|
||||
=> AllRelevant.HasFlag(crest);
|
||||
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,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -118,6 +118,7 @@ public sealed class DesignFileSystemSelector : FileSystemSelector<Design, Design
|
|||
case DesignChanged.Type.ApplyCustomize:
|
||||
case DesignChanged.Type.ApplyEquip:
|
||||
case DesignChanged.Type.ApplyStain:
|
||||
case DesignChanged.Type.ApplyCrest:
|
||||
case DesignChanged.Type.Customize:
|
||||
case DesignChanged.Type.Equip:
|
||||
case DesignChanged.Type.ChangedColor:
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
using System;
|
||||
using System.Numerics;
|
||||
using Dalamud.Interface;
|
||||
using Dalamud.Interface.Utility;
|
||||
|
|
@ -16,20 +15,6 @@ using Penumbra.GameData.Structs;
|
|||
|
||||
namespace Glamourer.Gui;
|
||||
|
||||
[Flags]
|
||||
public enum DataChange : byte
|
||||
{
|
||||
None = 0x00,
|
||||
Item = 0x01,
|
||||
Stain = 0x02,
|
||||
ApplyItem = 0x04,
|
||||
ApplyStain = 0x08,
|
||||
Item2 = 0x10,
|
||||
Stain2 = 0x20,
|
||||
ApplyItem2 = 0x40,
|
||||
ApplyStain2 = 0x80,
|
||||
}
|
||||
|
||||
public static class UiHelpers
|
||||
{
|
||||
/// <summary> Open a combo popup with another method than the combo itself. </summary>
|
||||
|
|
|
|||
|
|
@ -106,6 +106,9 @@ public readonly unsafe struct Actor : IEquatable<Actor>
|
|||
public CharacterArmor GetArmor(EquipSlot slot)
|
||||
=> ((CharacterArmor*)&AsCharacter->DrawData.Head)[slot.ToIndex()];
|
||||
|
||||
public bool GetCrest(EquipSlot slot)
|
||||
=> (GetFreeCompanyCrestBitfield() & CrestMask(slot)) != 0;
|
||||
|
||||
public CharacterWeapon GetMainhand()
|
||||
=> new(AsCharacter->DrawData.Weapon(DrawDataContainer.WeaponSlot.MainHand).ModelId.Value);
|
||||
|
||||
|
|
@ -115,6 +118,22 @@ public readonly unsafe struct Actor : IEquatable<Actor>
|
|||
public Customize GetCustomize()
|
||||
=> *(Customize*)&AsCharacter->DrawData.CustomizeData;
|
||||
|
||||
// TODO remove this when available in ClientStructs
|
||||
private byte GetFreeCompanyCrestBitfield()
|
||||
=> ((byte*)Address)[0x1BBB];
|
||||
|
||||
private static byte CrestMask(EquipSlot slot)
|
||||
=> slot switch
|
||||
{
|
||||
EquipSlot.OffHand => 0x01,
|
||||
EquipSlot.Head => 0x02,
|
||||
EquipSlot.Body => 0x04,
|
||||
EquipSlot.Hands => 0x08,
|
||||
EquipSlot.Legs => 0x10,
|
||||
EquipSlot.Feet => 0x20,
|
||||
_ => 0x00,
|
||||
};
|
||||
|
||||
public override string ToString()
|
||||
=> $"0x{Address:X}";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -91,6 +91,9 @@ public readonly unsafe struct Model : IEquatable<Model>
|
|||
public CharacterArmor GetArmor(EquipSlot slot)
|
||||
=> ((CharacterArmor*)&AsHuman->Head)[slot.ToIndex()];
|
||||
|
||||
public bool GetCrest(EquipSlot slot)
|
||||
=> IsFreeCompanyCrestVisibleOnSlot(slot);
|
||||
|
||||
public Customize GetCustomize()
|
||||
=> *(Customize*)&AsHuman->Customize;
|
||||
|
||||
|
|
@ -195,6 +198,35 @@ public readonly unsafe struct Model : IEquatable<Model>
|
|||
return discriminator1 == 0 && discriminator2 != 0 ? (second, first) : (first, second);
|
||||
}
|
||||
|
||||
// TODO remove these when available in ClientStructs
|
||||
private bool IsFreeCompanyCrestVisibleOnSlot(EquipSlot slot)
|
||||
{
|
||||
if (!IsCharacterBase)
|
||||
return false;
|
||||
|
||||
var index = (byte)slot.ToIndex();
|
||||
if (index >= 12)
|
||||
return false;
|
||||
|
||||
var characterBase = AsCharacterBase;
|
||||
var getter = (delegate* unmanaged<CharacterBase*, byte, byte>)((nint*)characterBase->VTable)[95];
|
||||
return getter(characterBase, index) != 0;
|
||||
}
|
||||
|
||||
public void SetFreeCompanyCrestVisibleOnSlot(EquipSlot slot, bool visible)
|
||||
{
|
||||
if (!IsCharacterBase)
|
||||
return;
|
||||
|
||||
var index = (byte)slot.ToIndex();
|
||||
if (index >= 12)
|
||||
return;
|
||||
|
||||
var characterBase = AsCharacterBase;
|
||||
var setter = (delegate* unmanaged<CharacterBase*, byte, byte, void>)((nint*)characterBase->VTable)[96];
|
||||
setter(characterBase, index, visible ? (byte)1 : (byte)0);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
=> $"0x{Address:X}";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -80,7 +80,8 @@ public class ActorState
|
|||
|
||||
/// <summary> This contains whether a change to the base data was made by the game, the user via manual input or through automatic application. </summary>
|
||||
private readonly StateChanged.Source[] _sources = Enumerable
|
||||
.Repeat(StateChanged.Source.Game, EquipFlagExtensions.NumEquipFlags + CustomizationExtensions.NumIndices + 5).ToArray();
|
||||
.Repeat(StateChanged.Source.Game,
|
||||
EquipFlagExtensions.NumEquipFlags + CustomizationExtensions.NumIndices + 5 + CrestExtensions.AllRelevantSet.Count).ToArray();
|
||||
|
||||
internal ActorState(ActorIdentifier identifier)
|
||||
=> Identifier = identifier.CreatePermanent();
|
||||
|
|
@ -88,6 +89,9 @@ public class ActorState
|
|||
public ref StateChanged.Source this[EquipSlot slot, bool stain]
|
||||
=> ref _sources[slot.ToIndex() + (stain ? EquipFlagExtensions.NumEquipFlags / 2 : 0)];
|
||||
|
||||
public ref StateChanged.Source this[CrestFlag slot]
|
||||
=> ref _sources[EquipFlagExtensions.NumEquipFlags + CustomizationExtensions.NumIndices + 5 + slot.ToRelevantIndex()];
|
||||
|
||||
public ref StateChanged.Source this[CustomizeIndex type]
|
||||
=> ref _sources[EquipFlagExtensions.NumEquipFlags + (int)type];
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue