mirror of
https://github.com/Ottermandias/Glamourer.git
synced 2025-12-13 12:14:18 +01:00
Do the Reworkings
This commit is contained in:
parent
a67cd8ad89
commit
e3a58340b3
23 changed files with 1067 additions and 943 deletions
|
|
@ -1,314 +1,33 @@
|
|||
using System;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Glamourer.Customization;
|
||||
|
||||
public unsafe struct Customize
|
||||
// Any customization value can be represented in 8 bytes by its ID,
|
||||
// a byte value, an optional value-id and an optional icon or color.
|
||||
[StructLayout(LayoutKind.Explicit)]
|
||||
public readonly struct CustomizationData
|
||||
{
|
||||
public readonly CustomizeData* Data;
|
||||
[FieldOffset(0)]
|
||||
public readonly CustomizationId Id;
|
||||
|
||||
public Customize(CustomizeData* data)
|
||||
=> Data = data;
|
||||
[FieldOffset(1)]
|
||||
public readonly CustomizationByteValue Value;
|
||||
|
||||
public Race Race
|
||||
[FieldOffset(2)]
|
||||
public readonly ushort CustomizeId;
|
||||
|
||||
[FieldOffset(4)]
|
||||
public readonly uint IconId;
|
||||
|
||||
[FieldOffset(4)]
|
||||
public readonly uint Color;
|
||||
|
||||
public CustomizationData(CustomizationId id, CustomizationByteValue value, uint data = 0, ushort customizeId = 0)
|
||||
{
|
||||
get => (Race)Data->Data[0];
|
||||
set => Data->Data[0] = (byte)value;
|
||||
Id = id;
|
||||
Value = value;
|
||||
IconId = data;
|
||||
Color = data;
|
||||
CustomizeId = customizeId;
|
||||
}
|
||||
|
||||
// Skip Unknown Gender
|
||||
public Gender Gender
|
||||
{
|
||||
get => (Gender)(Data->Data[1] + 1);
|
||||
set => Data->Data[1] = (byte)(value - 1);
|
||||
}
|
||||
|
||||
public byte BodyType
|
||||
{
|
||||
get => Data->Data[2];
|
||||
set => Data->Data[2] = value;
|
||||
}
|
||||
|
||||
public byte Height
|
||||
{
|
||||
get => Data->Data[3];
|
||||
set => Data->Data[3] = value;
|
||||
}
|
||||
|
||||
public SubRace Clan
|
||||
{
|
||||
get => (SubRace)Data->Data[4];
|
||||
set => Data->Data[4] = (byte)value;
|
||||
}
|
||||
|
||||
public byte Face
|
||||
{
|
||||
get => Data->Data[5];
|
||||
set => Data->Data[5] = value;
|
||||
}
|
||||
|
||||
public byte Hairstyle
|
||||
{
|
||||
get => Data->Data[6];
|
||||
set => Data->Data[6] = value;
|
||||
}
|
||||
|
||||
public bool HighlightsOn
|
||||
{
|
||||
get => Data->Data[7] >> 7 == 1;
|
||||
set => Data->Data[7] = (byte)(value ? Data->Data[7] | 0x80 : Data->Data[7] & 0x7F);
|
||||
}
|
||||
|
||||
public byte SkinColor
|
||||
{
|
||||
get => Data->Data[8];
|
||||
set => Data->Data[8] = value;
|
||||
}
|
||||
|
||||
public byte EyeColorRight
|
||||
{
|
||||
get => Data->Data[9];
|
||||
set => Data->Data[9] = value;
|
||||
}
|
||||
|
||||
public byte HairColor
|
||||
{
|
||||
get => Data->Data[10];
|
||||
set => Data->Data[10] = value;
|
||||
}
|
||||
|
||||
public byte HighlightsColor
|
||||
{
|
||||
get => Data->Data[11];
|
||||
set => Data->Data[11] = value;
|
||||
}
|
||||
|
||||
public readonly ref struct FacialFeatureStruct
|
||||
{
|
||||
private readonly byte* _bitfield;
|
||||
|
||||
public FacialFeatureStruct(byte* data)
|
||||
=> _bitfield = data;
|
||||
|
||||
public bool this[int idx]
|
||||
{
|
||||
get => (*_bitfield & (1 << idx)) != 0;
|
||||
set => Set(idx, value);
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
=> *_bitfield = 0;
|
||||
|
||||
public void All()
|
||||
=> *_bitfield = 0xFF;
|
||||
|
||||
public void Set(int idx, bool value)
|
||||
=> *_bitfield = (byte)(value ? *_bitfield | (1 << idx) : *_bitfield & ~(1 << idx));
|
||||
}
|
||||
|
||||
public FacialFeatureStruct FacialFeatures
|
||||
=> new(Data->Data + 12);
|
||||
|
||||
public byte TattooColor
|
||||
{
|
||||
get => Data->Data[13];
|
||||
set => Data->Data[13] = value;
|
||||
}
|
||||
|
||||
public byte Eyebrows
|
||||
{
|
||||
get => Data->Data[14];
|
||||
set => Data->Data[14] = value;
|
||||
}
|
||||
|
||||
public byte EyeColorLeft
|
||||
{
|
||||
get => Data->Data[15];
|
||||
set => Data->Data[15] = value;
|
||||
}
|
||||
|
||||
public byte EyeShape
|
||||
{
|
||||
get => (byte)(Data->Data[16] & 0x7F);
|
||||
set => Data->Data[16] = (byte)((value & 0x7F) | (Data->Data[16] & 0x80));
|
||||
}
|
||||
|
||||
public bool SmallIris
|
||||
{
|
||||
get => Data->Data[16] >> 7 == 1;
|
||||
set => Data->Data[16] = (byte)(value ? Data->Data[16] | 0x80 : Data->Data[16] & 0x7F);
|
||||
}
|
||||
|
||||
public byte Nose
|
||||
{
|
||||
get => Data->Data[17];
|
||||
set => Data->Data[17] = value;
|
||||
}
|
||||
|
||||
public byte Jaw
|
||||
{
|
||||
get => Data->Data[18];
|
||||
set => Data->Data[18] = value;
|
||||
}
|
||||
|
||||
public byte Mouth
|
||||
{
|
||||
get => (byte)(Data->Data[19] & 0x7F);
|
||||
set => Data->Data[19] = (byte)((value & 0x7F) | (Data->Data[19] & 0x80));
|
||||
}
|
||||
|
||||
public bool Lipstick
|
||||
{
|
||||
get => Data->Data[19] >> 7 == 1;
|
||||
set => Data->Data[19] = (byte)(value ? Data->Data[19] | 0x80 : Data->Data[19] & 0x7F);
|
||||
}
|
||||
|
||||
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)(Data->Data[24] & 0x7F);
|
||||
set => Data->Data[24] = (byte)((value & 0x7F) | (Data->Data[24] & 0x80));
|
||||
}
|
||||
|
||||
public bool FacePaintReversed
|
||||
{
|
||||
get => Data->Data[24] >> 7 == 1;
|
||||
set => Data->Data[24] = (byte)(value ? Data->Data[24] | 0x80 : Data->Data[24] & 0x7F);
|
||||
}
|
||||
|
||||
public ref byte FacePaintColor
|
||||
=> ref Data->Data[25];
|
||||
|
||||
public static readonly CustomizeData Default = GenerateDefault();
|
||||
public static readonly CustomizeData Empty = new();
|
||||
|
||||
public byte Get(CustomizationId id)
|
||||
=> id switch
|
||||
{
|
||||
CustomizationId.Race => (byte)Race,
|
||||
CustomizationId.Gender => (byte)Gender,
|
||||
CustomizationId.BodyType => BodyType,
|
||||
CustomizationId.Height => Height,
|
||||
CustomizationId.Clan => (byte)Clan,
|
||||
CustomizationId.Face => Face,
|
||||
CustomizationId.Hairstyle => Hairstyle,
|
||||
CustomizationId.HighlightsOnFlag => Data->Data[7],
|
||||
CustomizationId.SkinColor => SkinColor,
|
||||
CustomizationId.EyeColorR => EyeColorRight,
|
||||
CustomizationId.HairColor => HairColor,
|
||||
CustomizationId.HighlightColor => HighlightsColor,
|
||||
CustomizationId.FacialFeaturesTattoos => Data->Data[12],
|
||||
CustomizationId.TattooColor => TattooColor,
|
||||
CustomizationId.Eyebrows => Eyebrows,
|
||||
CustomizationId.EyeColorL => EyeColorLeft,
|
||||
CustomizationId.EyeShape => EyeShape,
|
||||
CustomizationId.Nose => Nose,
|
||||
CustomizationId.Jaw => Jaw,
|
||||
CustomizationId.Mouth => Mouth,
|
||||
CustomizationId.LipColor => LipColor,
|
||||
CustomizationId.MuscleToneOrTailEarLength => MuscleMass,
|
||||
CustomizationId.TailEarShape => TailShape,
|
||||
CustomizationId.BustSize => BustSize,
|
||||
CustomizationId.FacePaint => FacePaint,
|
||||
CustomizationId.FacePaintColor => FacePaintColor,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(id), id, null),
|
||||
};
|
||||
|
||||
public void Set(CustomizationId id, byte value)
|
||||
{
|
||||
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: 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)
|
||||
=> CustomizeData.Equals(Data, other.Data);
|
||||
|
||||
public byte this[CustomizationId id]
|
||||
{
|
||||
get => Get(id);
|
||||
set => Set(id, value);
|
||||
}
|
||||
|
||||
private static CustomizeData GenerateDefault()
|
||||
{
|
||||
var ret = new CustomizeData();
|
||||
var customize = new Customize(&ret)
|
||||
{
|
||||
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();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void Load(Customize other)
|
||||
=> Data->Read(other.Data);
|
||||
|
||||
public void Write(IntPtr target)
|
||||
=> Data->Write((void*)target);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue