using FFXIVClientStructs.FFXIV.Client.Game.Object; using Penumbra.GameData.Structs; namespace Glamourer.GameData; /// A struct containing everything to replicate the appearance of a human NPC. public unsafe struct NpcData { /// The name of the NPC. public string Name; /// The customizations of the NPC. public CustomizeArray Customize; /// The equipment appearance of the NPC, 10 * CharacterArmor. private fixed byte _equip[40]; /// The mainhand weapon appearance of the NPC. public CharacterWeapon Mainhand; /// The offhand weapon appearance of the NPC. public CharacterWeapon Offhand; /// The data ID of the NPC, either event NPC or battle NPC name. public NpcId Id; /// The Model ID of the NPC. public uint ModelId; /// Whether the NPCs visor is toggled. public bool VisorToggled; /// Whether the NPC is an event NPC or a battle NPC. public ObjectKind Kind; /// Obtain the equipment as CharacterArmors. public ReadOnlySpan Equip { get { fixed (byte* ptr = _equip) { return new ReadOnlySpan((CharacterArmor*)ptr, 10); } } } /// Write all the gear appearance to a single string. public string WriteGear() { var sb = new StringBuilder(128); var span = Equip; for (var i = 0; i < 10; ++i) { sb.Append(span[i].Set.Id.ToString("D4")) .Append('-') .Append(span[i].Variant.Id.ToString("D3")) .Append('-') .Append(span[i].Stain.Id.ToString("D3")) .Append(", "); } sb.Append(Mainhand.Skeleton.Id.ToString("D4")) .Append('-') .Append(Mainhand.Weapon.Id.ToString("D4")) .Append('-') .Append(Mainhand.Variant.Id.ToString("D3")) .Append('-') .Append(Mainhand.Stain.Id.ToString("D4")) .Append(", ") .Append(Offhand.Skeleton.Id.ToString("D4")) .Append('-') .Append(Offhand.Weapon.Id.ToString("D4")) .Append('-') .Append(Offhand.Variant.Id.ToString("D3")) .Append('-') .Append(Offhand.Stain.Id.ToString("D3")); return sb.ToString(); } /// Set an equipment piece to a given value. internal void Set(int idx, uint value) { fixed (byte* ptr = _equip) { ((uint*)ptr)[idx] = value; } } /// Check if the appearance data, excluding ID and Name, of two NpcData is equal. public bool DataEquals(in NpcData other) { if (ModelId != other.ModelId) return false; if (VisorToggled != other.VisorToggled) return false; if (!Customize.Equals(other.Customize)) return false; if (!Mainhand.Equals(other.Mainhand)) return false; if (!Offhand.Equals(other.Offhand)) return false; fixed (byte* ptr1 = _equip, ptr2 = other._equip) { return new ReadOnlySpan(ptr1, 40).SequenceEqual(new ReadOnlySpan(ptr2, 40)); } } }