mirror of
https://github.com/Ottermandias/Glamourer.git
synced 2025-12-14 20:54:17 +01:00
More stuff.
This commit is contained in:
parent
a160276cc5
commit
d7e61d9cfb
3 changed files with 168 additions and 294 deletions
|
|
@ -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<CharacterArmor> 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),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,171 +1,156 @@
|
||||||
using System;
|
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.Enums;
|
||||||
|
using Penumbra.GameData.Structs;
|
||||||
|
|
||||||
namespace Glamourer.Customization;
|
namespace Glamourer.Customization;
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential, Pack = 1)]
|
public unsafe ref struct Customize
|
||||||
public struct CustomizationData
|
|
||||||
{
|
{
|
||||||
public const int CustomizationOffset = 0x830;
|
private readonly CustomizeData* _data;
|
||||||
public const int CustomizationBytes = 26;
|
|
||||||
|
|
||||||
public Race Race;
|
private Customize(CustomizeData* data)
|
||||||
private byte _gender;
|
=> _data = data;
|
||||||
public byte BodyType;
|
|
||||||
public byte Height;
|
public Race Race
|
||||||
public SubRace Clan;
|
{
|
||||||
public byte Face;
|
get => (Race)_data->Data[0];
|
||||||
public byte Hairstyle;
|
set => _data->Data[0] = (byte)value;
|
||||||
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;
|
|
||||||
|
|
||||||
// Skip Unknown Gender
|
// Skip Unknown Gender
|
||||||
public Gender Gender
|
public Gender Gender
|
||||||
{
|
{
|
||||||
get => (Gender)(_gender + 1);
|
get => (Gender)(_data->Data[1] + 1);
|
||||||
set => _gender = (byte)(value - 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
|
public bool HighlightsOn
|
||||||
{
|
{
|
||||||
get => (_highlightsOn & 128) == 128;
|
get => _data->Data[7] >> 7 == 1;
|
||||||
set => _highlightsOn = (byte)(value ? _highlightsOn | 128 : _highlightsOn & 127);
|
set => _data->Data[7] = (byte)(value ? _data->Data[7] | 0x80 : _data->Data[7] & 0x7F);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get status of specific facial feature 0-7.
|
public ref byte SkinColor
|
||||||
public bool FacialFeature(int idx)
|
=> ref _data->Data[8];
|
||||||
=> (FacialFeatures & (1 << idx)) != 0;
|
|
||||||
|
|
||||||
// Set value of specific facial feature 0-7.
|
public ref byte EyeColorRight
|
||||||
public void FacialFeature(int idx, bool set)
|
=> 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)
|
private readonly byte* _bitfield;
|
||||||
FacialFeatures |= (byte)(1 << idx);
|
|
||||||
else
|
public FacialFeatureStruct(byte* data)
|
||||||
FacialFeatures &= (byte)~(1 << idx);
|
=> _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
|
public byte EyeShape
|
||||||
{
|
{
|
||||||
get => (byte)(_eyeShape & 127);
|
get => (byte)(_data->Data[16] & 0x7F);
|
||||||
set => _eyeShape = (byte)((value & 127) | (_eyeShape & 128));
|
set => _data->Data[16] = (byte)((value & 0x7F) | (_data->Data[16] & 0x80));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Uppermost bit flag.
|
|
||||||
public bool SmallIris
|
public bool SmallIris
|
||||||
{
|
{
|
||||||
get => (_eyeShape & 128) == 128;
|
get => _data->Data[16] >> 7 == 1;
|
||||||
set => _eyeShape = (byte)(value ? _eyeShape | 128 : _eyeShape & 127);
|
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
|
public byte Mouth
|
||||||
{
|
{
|
||||||
get => (byte)(_mouth & 127);
|
get => (byte)(_data->Data[19] & 0x7F);
|
||||||
set => _mouth = (byte)((value & 127) | (_mouth & 128));
|
set => _data->Data[19] = (byte)((value & 0x7F) | (_data->Data[19] & 0x80));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Uppermost bit flag.
|
|
||||||
public bool Lipstick
|
public bool Lipstick
|
||||||
{
|
{
|
||||||
get => (_mouth & 128) == 128;
|
get => _data->Data[19] >> 7 == 1;
|
||||||
set => _mouth = (byte)(value ? _mouth | 128 : _mouth & 127);
|
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
|
public byte FacePaint
|
||||||
{
|
{
|
||||||
get => (byte)(_facePaint & 127);
|
get => (byte)(_data->Data[24] & 0x7F);
|
||||||
set => _facePaint = (byte)((value & 127) | (_facePaint & 128));
|
set => _data->Data[24] = (byte)((value & 0x7F) | (_data->Data[24] & 0x80));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Uppermost bit flag.
|
|
||||||
public bool FacePaintReversed
|
public bool FacePaintReversed
|
||||||
{
|
{
|
||||||
get => (_facePaint & 128) == 128;
|
get => _data->Data[24] >> 7 == 1;
|
||||||
set => _facePaint = (byte)(value ? _facePaint | 128 : _facePaint & 127);
|
set => _data->Data[24] = (byte)(value ? _data->Data[24] | 0x80 : _data->Data[24] & 0x7F);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CustomizationData Default = new()
|
public ref byte FacePaintColor
|
||||||
{
|
=> ref _data->Data[25];
|
||||||
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 unsafe void Read(CustomizationData* customize)
|
internal static readonly CustomizeData Default = GenerateDefault();
|
||||||
{
|
internal static readonly CustomizeData Empty = new();
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte Get(CustomizationId id)
|
public byte Get(CustomizationId id)
|
||||||
=> id switch
|
=> id switch
|
||||||
|
|
@ -177,14 +162,14 @@ public struct CustomizationData
|
||||||
CustomizationId.Clan => (byte)Clan,
|
CustomizationId.Clan => (byte)Clan,
|
||||||
CustomizationId.Face => Face,
|
CustomizationId.Face => Face,
|
||||||
CustomizationId.Hairstyle => Hairstyle,
|
CustomizationId.Hairstyle => Hairstyle,
|
||||||
CustomizationId.HighlightsOnFlag => _highlightsOn,
|
CustomizationId.HighlightsOnFlag => _data->Data[7],
|
||||||
CustomizationId.SkinColor => SkinColor,
|
CustomizationId.SkinColor => SkinColor,
|
||||||
CustomizationId.EyeColorR => EyeColorRight,
|
CustomizationId.EyeColorR => EyeColorRight,
|
||||||
CustomizationId.HairColor => HairColor,
|
CustomizationId.HairColor => HairColor,
|
||||||
CustomizationId.HighlightColor => HighlightsColor,
|
CustomizationId.HighlightColor => HighlightsColor,
|
||||||
CustomizationId.FacialFeaturesTattoos => FacialFeatures,
|
CustomizationId.FacialFeaturesTattoos => _data->Data[12],
|
||||||
CustomizationId.TattooColor => TattooColor,
|
CustomizationId.TattooColor => TattooColor,
|
||||||
CustomizationId.Eyebrows => Eyebrow,
|
CustomizationId.Eyebrows => Eyebrows,
|
||||||
CustomizationId.EyeColorL => EyeColorLeft,
|
CustomizationId.EyeColorL => EyeColorLeft,
|
||||||
CustomizationId.EyeShape => EyeShape,
|
CustomizationId.EyeShape => EyeShape,
|
||||||
CustomizationId.Nose => Nose,
|
CustomizationId.Nose => Nose,
|
||||||
|
|
@ -204,83 +189,78 @@ public struct CustomizationData
|
||||||
switch (id)
|
switch (id)
|
||||||
{
|
{
|
||||||
// @formatter:off
|
// @formatter:off
|
||||||
case CustomizationId.Race: Race = (Race)value; break;
|
case CustomizationId.Race: Race = (Race)value; break;
|
||||||
case CustomizationId.Gender: Gender = (Gender)value; break;
|
case CustomizationId.Gender: Gender = (Gender)value; break;
|
||||||
case CustomizationId.BodyType: BodyType = value; break;
|
case CustomizationId.BodyType: BodyType = value; break;
|
||||||
case CustomizationId.Height: Height = value; break;
|
case CustomizationId.Height: Height = value; break;
|
||||||
case CustomizationId.Clan: Clan = (SubRace)value; break;
|
case CustomizationId.Clan: Clan = (SubRace)value; break;
|
||||||
case CustomizationId.Face: Face = value; break;
|
case CustomizationId.Face: Face = value; break;
|
||||||
case CustomizationId.Hairstyle: Hairstyle = value; break;
|
case CustomizationId.Hairstyle: Hairstyle = value; break;
|
||||||
case CustomizationId.HighlightsOnFlag: HighlightsOn = (value & 128) == 128; break;
|
case CustomizationId.HighlightsOnFlag: HighlightsOn = (value & 128) == 128; break;
|
||||||
case CustomizationId.SkinColor: SkinColor = value; break;
|
case CustomizationId.SkinColor: SkinColor = value; break;
|
||||||
case CustomizationId.EyeColorR: EyeColorRight = value; break;
|
case CustomizationId.EyeColorR: EyeColorRight = value; break;
|
||||||
case CustomizationId.HairColor: HairColor = value; break;
|
case CustomizationId.HairColor: HairColor = value; break;
|
||||||
case CustomizationId.HighlightColor: HighlightsColor = value; break;
|
case CustomizationId.HighlightColor: HighlightsColor = value; break;
|
||||||
case CustomizationId.FacialFeaturesTattoos: FacialFeatures = value; break;
|
case CustomizationId.FacialFeaturesTattoos: _data->Data[12] = value; break;
|
||||||
case CustomizationId.TattooColor: TattooColor = value; break;
|
case CustomizationId.TattooColor: TattooColor = value; break;
|
||||||
case CustomizationId.Eyebrows: Eyebrow = value; break;
|
case CustomizationId.Eyebrows: Eyebrows = value; break;
|
||||||
case CustomizationId.EyeColorL: EyeColorLeft = value; break;
|
case CustomizationId.EyeColorL: EyeColorLeft = value; break;
|
||||||
case CustomizationId.EyeShape: EyeShape = value; break;
|
case CustomizationId.EyeShape: EyeShape = value; break;
|
||||||
case CustomizationId.Nose: Nose = value; break;
|
case CustomizationId.Nose: Nose = value; break;
|
||||||
case CustomizationId.Jaw: Jaw = value; break;
|
case CustomizationId.Jaw: Jaw = value; break;
|
||||||
case CustomizationId.Mouth: Mouth = value; break;
|
case CustomizationId.Mouth: Mouth = value; break;
|
||||||
case CustomizationId.LipColor: LipColor = value; break;
|
case CustomizationId.LipColor: LipColor = value; break;
|
||||||
case CustomizationId.MuscleToneOrTailEarLength: MuscleMass = value; break;
|
case CustomizationId.MuscleToneOrTailEarLength: MuscleMass = value; break;
|
||||||
case CustomizationId.TailEarShape: TailShape = value; break;
|
case CustomizationId.TailEarShape: TailShape = value; break;
|
||||||
case CustomizationId.BustSize: BustSize = value; break;
|
case CustomizationId.BustSize: BustSize = value; break;
|
||||||
case CustomizationId.FacePaint: FacePaint = value; break;
|
case CustomizationId.FacePaint: FacePaint = value; break;
|
||||||
case CustomizationId.FacePaintColor: FacePaintColor = value; break;
|
case CustomizationId.FacePaintColor: FacePaintColor = value; break;
|
||||||
default: throw new ArgumentOutOfRangeException(nameof(id), id, null);
|
default: throw new ArgumentOutOfRangeException(nameof(id), id, null);
|
||||||
// @formatter:on
|
// @formatter:on
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool Equals(Customize other)
|
||||||
|
=> throw new NotImplementedException();
|
||||||
|
|
||||||
public byte this[CustomizationId id]
|
public byte this[CustomizationId id]
|
||||||
{
|
{
|
||||||
get => Get(id);
|
get => Get(id);
|
||||||
set => Set(id, value);
|
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;
|
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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Dalamud.Game.ClientState.Objects.Enums;
|
using Dalamud.Game.ClientState.Objects.Enums;
|
||||||
using Dalamud.Game.ClientState.Objects.Types;
|
|
||||||
using Penumbra.GameData.ByteString;
|
using Penumbra.GameData.ByteString;
|
||||||
|
|
||||||
namespace Glamourer;
|
namespace Glamourer;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue