From d7e61d9cfb12229e1f227e6cfa3d168f5d832fa1 Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Wed, 27 Jul 2022 10:02:31 +0200 Subject: [PATCH] More stuff. --- Glamourer.GameData/CharacterEquip.cs | 105 ------ .../Customization/CustomizationData.cs | 356 +++++++++--------- Glamourer/ObjectManager.cs | 1 - 3 files changed, 168 insertions(+), 294 deletions(-) delete mode 100644 Glamourer.GameData/CharacterEquip.cs diff --git a/Glamourer.GameData/CharacterEquip.cs b/Glamourer.GameData/CharacterEquip.cs deleted file mode 100644 index c16a69a..0000000 --- a/Glamourer.GameData/CharacterEquip.cs +++ /dev/null @@ -1,105 +0,0 @@ -using System; -using Penumbra.GameData.Enums; -using Penumbra.GameData.Structs; - -namespace Glamourer; - -public readonly unsafe struct CharacterEquip -{ - public static readonly CharacterEquip Null = new(null); - - private readonly CharacterArmor* _armor; - - public IntPtr Address - => (IntPtr)_armor; - - public ref CharacterArmor this[int idx] - => ref _armor[idx]; - - public ref CharacterArmor this[uint idx] - => ref _armor[idx]; - - public ref CharacterArmor this[EquipSlot slot] - => ref _armor[IndexOf(slot)]; - - - public ref CharacterArmor Head - => ref _armor[0]; - - public ref CharacterArmor Body - => ref _armor[1]; - - public ref CharacterArmor Hands - => ref _armor[2]; - - public ref CharacterArmor Legs - => ref _armor[3]; - - public ref CharacterArmor Feet - => ref _armor[4]; - - public ref CharacterArmor Ears - => ref _armor[5]; - - public ref CharacterArmor Neck - => ref _armor[6]; - - public ref CharacterArmor Wrists - => ref _armor[7]; - - public ref CharacterArmor RFinger - => ref _armor[8]; - - public ref CharacterArmor LFinger - => ref _armor[9]; - - public CharacterEquip(CharacterArmor* val) - => _armor = val; - - public static implicit operator CharacterEquip(CharacterArmor* val) - => new(val); - - public static implicit operator CharacterEquip(IntPtr val) - => new((CharacterArmor*)val); - - public static implicit operator CharacterEquip(ReadOnlySpan val) - { - if (val.Length != 10) - throw new ArgumentException("Invalid number of equipment pieces in span."); - - fixed (CharacterArmor* ptr = val) - { - return new CharacterEquip(ptr); - } - } - - public static implicit operator bool(CharacterEquip equip) - => equip._armor != null; - - public static bool operator true(CharacterEquip equip) - => equip._armor != null; - - public static bool operator false(CharacterEquip equip) - => equip._armor == null; - - public static bool operator !(CharacterEquip equip) - => equip._armor == null; - - private static int IndexOf(EquipSlot slot) - { - return slot switch - { - EquipSlot.Head => 0, - EquipSlot.Body => 1, - EquipSlot.Hands => 2, - EquipSlot.Legs => 3, - EquipSlot.Feet => 4, - EquipSlot.Ears => 5, - EquipSlot.Neck => 6, - EquipSlot.Wrists => 7, - EquipSlot.RFinger => 8, - EquipSlot.LFinger => 9, - _ => throw new ArgumentOutOfRangeException(nameof(slot), slot, null), - }; - } -} diff --git a/Glamourer.GameData/Customization/CustomizationData.cs b/Glamourer.GameData/Customization/CustomizationData.cs index 05e8507..707623e 100644 --- a/Glamourer.GameData/Customization/CustomizationData.cs +++ b/Glamourer.GameData/Customization/CustomizationData.cs @@ -1,171 +1,156 @@ using System; -using System.Runtime.InteropServices; -using System.Text; -using Dalamud.Game.ClientState.Objects.Types; -using FFXIVClientStructs.FFXIV.Client.Graphics.Scene; using Penumbra.GameData.Enums; +using Penumbra.GameData.Structs; namespace Glamourer.Customization; -[StructLayout(LayoutKind.Sequential, Pack = 1)] -public struct CustomizationData +public unsafe ref struct Customize { - public const int CustomizationOffset = 0x830; - public const int CustomizationBytes = 26; + private readonly CustomizeData* _data; - public Race Race; - private byte _gender; - public byte BodyType; - public byte Height; - public SubRace Clan; - public byte Face; - public byte Hairstyle; - private byte _highlightsOn; - public byte SkinColor; - public byte EyeColorRight; - public byte HairColor; - public byte HighlightsColor; - public byte FacialFeatures; - public byte TattooColor; - public byte Eyebrow; - public byte EyeColorLeft; - private byte _eyeShape; - public byte Nose; - public byte Jaw; - private byte _mouth; - public byte LipColor; - public byte MuscleMass; - public byte TailShape; - public byte BustSize; - private byte _facePaint; - public byte FacePaintColor; + private Customize(CustomizeData* data) + => _data = data; + + public Race Race + { + get => (Race)_data->Data[0]; + set => _data->Data[0] = (byte)value; + } // Skip Unknown Gender public Gender Gender { - get => (Gender)(_gender + 1); - set => _gender = (byte)(value - 1); + get => (Gender)(_data->Data[1] + 1); + set => _data->Data[1] = (byte)(value - 1); } - // Single bit flag. + public ref byte BodyType + => ref _data->Data[2]; + + public ref byte Height + => ref _data->Data[3]; + + public SubRace Clan + { + get => (SubRace)_data->Data[4]; + set => _data->Data[4] = (byte)value; + } + + public ref byte Face + => ref _data->Data[5]; + + public ref byte Hairstyle + => ref _data->Data[6]; + public bool HighlightsOn { - get => (_highlightsOn & 128) == 128; - set => _highlightsOn = (byte)(value ? _highlightsOn | 128 : _highlightsOn & 127); + get => _data->Data[7] >> 7 == 1; + set => _data->Data[7] = (byte)(value ? _data->Data[7] | 0x80 : _data->Data[7] & 0x7F); } - // Get status of specific facial feature 0-7. - public bool FacialFeature(int idx) - => (FacialFeatures & (1 << idx)) != 0; + public ref byte SkinColor + => ref _data->Data[8]; - // Set value of specific facial feature 0-7. - public void FacialFeature(int idx, bool set) + public ref byte EyeColorRight + => ref _data->Data[9]; + + public ref byte HairColor + => ref _data->Data[10]; + + public ref byte HighlightsColor + => ref _data->Data[11]; + + public readonly ref struct FacialFeatureStruct { - if (set) - FacialFeatures |= (byte)(1 << idx); - else - FacialFeatures &= (byte)~(1 << idx); + private readonly byte* _bitfield; + + public FacialFeatureStruct(byte* data) + => _bitfield = data; + + public bool this[int idx] + { + get => (*_bitfield & (1 << idx)) != 0; + set => *_bitfield = (byte)(value ? *_bitfield | (1 << idx) : *_bitfield & ~(1 << idx)); + } + + public void Clear() + => *_bitfield = 0; + + public void All() + => *_bitfield = 0xFF; } - // Lower 7 bits + public FacialFeatureStruct FacialFeatures + => new(_data->Data + 12); + + public ref byte TattooColor + => ref _data->Data[13]; + + public ref byte Eyebrows + => ref _data->Data[14]; + + public ref byte EyeColorLeft + => ref _data->Data[15]; + public byte EyeShape { - get => (byte)(_eyeShape & 127); - set => _eyeShape = (byte)((value & 127) | (_eyeShape & 128)); + get => (byte)(_data->Data[16] & 0x7F); + set => _data->Data[16] = (byte)((value & 0x7F) | (_data->Data[16] & 0x80)); } - // Uppermost bit flag. public bool SmallIris { - get => (_eyeShape & 128) == 128; - set => _eyeShape = (byte)(value ? _eyeShape | 128 : _eyeShape & 127); + get => _data->Data[16] >> 7 == 1; + set => _data->Data[16] = (byte)(value ? _data->Data[16] | 0x80 : _data->Data[16] & 0x7F); } - // Lower 7 bits. + public ref byte Nose + => ref _data->Data[17]; + + public ref byte Jaw + => ref _data->Data[18]; + public byte Mouth { - get => (byte)(_mouth & 127); - set => _mouth = (byte)((value & 127) | (_mouth & 128)); + get => (byte)(_data->Data[19] & 0x7F); + set => _data->Data[19] = (byte)((value & 0x7F) | (_data->Data[19] & 0x80)); } - // Uppermost bit flag. public bool Lipstick { - get => (_mouth & 128) == 128; - set => _mouth = (byte)(value ? _mouth | 128 : _mouth & 127); + get => _data->Data[19] >> 7 == 1; + set => _data->Data[19] = (byte)(value ? _data->Data[19] | 0x80 : _data->Data[19] & 0x7F); } - // Lower 7 bits. + public ref byte LipColor + => ref _data->Data[20]; + + public ref byte MuscleMass + => ref _data->Data[21]; + + public ref byte TailShape + => ref _data->Data[22]; + + public ref byte BustSize + => ref _data->Data[23]; + public byte FacePaint { - get => (byte)(_facePaint & 127); - set => _facePaint = (byte)((value & 127) | (_facePaint & 128)); + get => (byte)(_data->Data[24] & 0x7F); + set => _data->Data[24] = (byte)((value & 0x7F) | (_data->Data[24] & 0x80)); } - // Uppermost bit flag. public bool FacePaintReversed { - get => (_facePaint & 128) == 128; - set => _facePaint = (byte)(value ? _facePaint | 128 : _facePaint & 127); + get => _data->Data[24] >> 7 == 1; + set => _data->Data[24] = (byte)(value ? _data->Data[24] | 0x80 : _data->Data[24] & 0x7F); } - public static CustomizationData Default = new() - { - Race = Race.Hyur, - Gender = Gender.Male, - BodyType = 1, - Height = 50, - Clan = SubRace.Midlander, - Face = 1, - Hairstyle = 1, - HighlightsOn = false, - SkinColor = 1, - EyeColorRight = 1, - HighlightsColor = 1, - FacialFeatures = 0, - TattooColor = 1, - Eyebrow = 1, - EyeColorLeft = 1, - EyeShape = 1, - Nose = 1, - Jaw = 1, - Mouth = 1, - LipColor = 1, - MuscleMass = 50, - TailShape = 1, - BustSize = 50, - FacePaint = 1, - FacePaintColor = 1, - }; + public ref byte FacePaintColor + => ref _data->Data[25]; - public unsafe void Read(CustomizationData* customize) - { - fixed (CustomizationData* ptr = &this) - { - *ptr = *customize; - } - } - - public unsafe void Read(IntPtr customizeAddress) - => Read((CustomizationData*)customizeAddress); - - public void Read(Character character) - => Read(character.Address + CustomizationOffset); - - public unsafe void Read(Human* human) - => Read((CustomizationData*)human->CustomizeData); - - public CustomizationData(Character character) - : this() - { - Read(character.Address + CustomizationOffset); - } - - public unsafe CustomizationData(Human* human) - : this() - { - Read(human); - } + internal static readonly CustomizeData Default = GenerateDefault(); + internal static readonly CustomizeData Empty = new(); public byte Get(CustomizationId id) => id switch @@ -177,14 +162,14 @@ public struct CustomizationData CustomizationId.Clan => (byte)Clan, CustomizationId.Face => Face, CustomizationId.Hairstyle => Hairstyle, - CustomizationId.HighlightsOnFlag => _highlightsOn, + CustomizationId.HighlightsOnFlag => _data->Data[7], CustomizationId.SkinColor => SkinColor, CustomizationId.EyeColorR => EyeColorRight, CustomizationId.HairColor => HairColor, CustomizationId.HighlightColor => HighlightsColor, - CustomizationId.FacialFeaturesTattoos => FacialFeatures, + CustomizationId.FacialFeaturesTattoos => _data->Data[12], CustomizationId.TattooColor => TattooColor, - CustomizationId.Eyebrows => Eyebrow, + CustomizationId.Eyebrows => Eyebrows, CustomizationId.EyeColorL => EyeColorLeft, CustomizationId.EyeShape => EyeShape, CustomizationId.Nose => Nose, @@ -204,83 +189,78 @@ public struct CustomizationData switch (id) { // @formatter:off - case CustomizationId.Race: Race = (Race)value; break; - case CustomizationId.Gender: Gender = (Gender)value; break; - case CustomizationId.BodyType: BodyType = value; break; - case CustomizationId.Height: Height = value; break; - case CustomizationId.Clan: Clan = (SubRace)value; break; - case CustomizationId.Face: Face = value; break; - case CustomizationId.Hairstyle: Hairstyle = value; break; - case CustomizationId.HighlightsOnFlag: HighlightsOn = (value & 128) == 128; break; - case CustomizationId.SkinColor: SkinColor = value; break; - case CustomizationId.EyeColorR: EyeColorRight = value; break; - case CustomizationId.HairColor: HairColor = value; break; - case CustomizationId.HighlightColor: HighlightsColor = value; break; - case CustomizationId.FacialFeaturesTattoos: FacialFeatures = value; break; - case CustomizationId.TattooColor: TattooColor = value; break; - case CustomizationId.Eyebrows: Eyebrow = value; break; - case CustomizationId.EyeColorL: EyeColorLeft = value; break; - case CustomizationId.EyeShape: EyeShape = value; break; - case CustomizationId.Nose: Nose = value; break; - case CustomizationId.Jaw: Jaw = value; break; - case CustomizationId.Mouth: Mouth = value; break; - case CustomizationId.LipColor: LipColor = value; break; - case CustomizationId.MuscleToneOrTailEarLength: MuscleMass = value; break; - case CustomizationId.TailEarShape: TailShape = value; break; - case CustomizationId.BustSize: BustSize = value; break; - case CustomizationId.FacePaint: FacePaint = value; break; - case CustomizationId.FacePaintColor: FacePaintColor = value; break; + case CustomizationId.Race: Race = (Race)value; break; + case CustomizationId.Gender: Gender = (Gender)value; break; + case CustomizationId.BodyType: BodyType = value; break; + case CustomizationId.Height: Height = value; break; + case CustomizationId.Clan: Clan = (SubRace)value; break; + case CustomizationId.Face: Face = value; break; + case CustomizationId.Hairstyle: Hairstyle = value; break; + case CustomizationId.HighlightsOnFlag: HighlightsOn = (value & 128) == 128; break; + case CustomizationId.SkinColor: SkinColor = value; break; + case CustomizationId.EyeColorR: EyeColorRight = value; break; + case CustomizationId.HairColor: HairColor = value; break; + case CustomizationId.HighlightColor: HighlightsColor = value; break; + case CustomizationId.FacialFeaturesTattoos: _data->Data[12] = value; break; + case CustomizationId.TattooColor: TattooColor = value; break; + case CustomizationId.Eyebrows: Eyebrows = value; break; + case CustomizationId.EyeColorL: EyeColorLeft = value; break; + case CustomizationId.EyeShape: EyeShape = value; break; + case CustomizationId.Nose: Nose = value; break; + case CustomizationId.Jaw: Jaw = value; break; + case CustomizationId.Mouth: Mouth = value; break; + case CustomizationId.LipColor: LipColor = value; break; + case CustomizationId.MuscleToneOrTailEarLength: MuscleMass = value; break; + case CustomizationId.TailEarShape: TailShape = value; break; + case CustomizationId.BustSize: BustSize = value; break; + case CustomizationId.FacePaint: FacePaint = value; break; + case CustomizationId.FacePaintColor: FacePaintColor = value; break; default: throw new ArgumentOutOfRangeException(nameof(id), id, null); // @formatter:on } } + public bool Equals(Customize other) + => throw new NotImplementedException(); + public byte this[CustomizationId id] { get => Get(id); set => Set(id, value); } - public unsafe void Write(FFXIVClientStructs.FFXIV.Client.Game.Character.Character* character) + private static CustomizeData GenerateDefault() { - fixed (CustomizationData* ptr = &this) + var ret = new CustomizeData(); + var customize = new Customize(&ret) { - Buffer.MemoryCopy(ptr, character->CustomizeData, CustomizationBytes, CustomizationBytes); - } - } + Race = Race.Hyur, + Gender = Gender.Male, + BodyType = 1, + Height = 50, + Clan = SubRace.Midlander, + Face = 1, + Hairstyle = 1, + HighlightsOn = false, + SkinColor = 1, + EyeColorRight = 1, + HighlightsColor = 1, + TattooColor = 1, + Eyebrows = 1, + EyeColorLeft = 1, + EyeShape = 1, + Nose = 1, + Jaw = 1, + Mouth = 1, + LipColor = 1, + MuscleMass = 50, + TailShape = 1, + BustSize = 50, + FacePaint = 1, + FacePaintColor = 1, + }; + customize.FacialFeatures.Clear(); - public unsafe void Write(IntPtr characterAddress) - => Write((FFXIVClientStructs.FFXIV.Client.Game.Character.Character*)characterAddress); - - public unsafe void WriteBytes(byte[] array, int offset = 0) - { - fixed (Race* ptr = &Race) - { - Marshal.Copy(new IntPtr(ptr), array, offset, CustomizationBytes); - } - } - - public byte[] ToBytes() - { - var ret = new byte[CustomizationBytes]; - WriteBytes(ret); return ret; } - - public string HumanReadable() - { - // TODO - var sb = new StringBuilder(); - sb.Append($"Race: {Race.ToName()} - {Clan.ToName()}\n"); - sb.Append($"Gender: {Gender.ToName()}\n"); - sb.Append($"Height: {Height}%\n"); - sb.Append($"Face: #{Face}\n"); - sb.Append($"Hairstyle: #{Hairstyle}\n"); - sb.Append($"Haircolor: #{HairColor}"); - if (HighlightsOn) - sb.Append($" with Highlights #{HighlightsColor}\n"); - else - sb.Append('\n'); - return sb.ToString(); - } } diff --git a/Glamourer/ObjectManager.cs b/Glamourer/ObjectManager.cs index 39ac988..5e7c7e0 100644 --- a/Glamourer/ObjectManager.cs +++ b/Glamourer/ObjectManager.cs @@ -1,6 +1,5 @@ using System.Collections.Generic; using Dalamud.Game.ClientState.Objects.Enums; -using Dalamud.Game.ClientState.Objects.Types; using Penumbra.GameData.ByteString; namespace Glamourer;