mirror of
https://github.com/Ottermandias/Glamourer.git
synced 2025-12-12 10:17:23 +01:00
Bloop
This commit is contained in:
parent
d7e61d9cfb
commit
15d93830a3
15 changed files with 244 additions and 418 deletions
|
|
@ -1,162 +0,0 @@
|
|||
using System;
|
||||
using Glamourer.Customization;
|
||||
using Penumbra.GameData.Enums;
|
||||
|
||||
namespace Glamourer;
|
||||
|
||||
public readonly unsafe struct CharacterCustomization
|
||||
{
|
||||
public static readonly CharacterCustomization Null = new(null);
|
||||
|
||||
private readonly CustomizationData* _data;
|
||||
|
||||
public IntPtr Address
|
||||
=> (IntPtr)_data;
|
||||
|
||||
public CharacterCustomization(CustomizationData* data)
|
||||
=> _data = data;
|
||||
|
||||
public void Load(CharacterCustomization other)
|
||||
=> *_data = *other._data;
|
||||
|
||||
public ref Race Race
|
||||
=> ref _data->Race;
|
||||
|
||||
public ref SubRace Clan
|
||||
=> ref _data->Clan;
|
||||
|
||||
public Gender Gender
|
||||
{
|
||||
get => _data->Gender;
|
||||
set => _data->Gender = value;
|
||||
}
|
||||
|
||||
public ref byte BodyType
|
||||
=> ref _data->BodyType;
|
||||
|
||||
public ref byte Height
|
||||
=> ref _data->Height;
|
||||
|
||||
public ref byte Face
|
||||
=> ref _data->Face;
|
||||
|
||||
public ref byte Hairstyle
|
||||
=> ref _data->Hairstyle;
|
||||
|
||||
public bool HighlightsOn
|
||||
{
|
||||
get => _data->HighlightsOn;
|
||||
set => _data->HighlightsOn = value;
|
||||
}
|
||||
|
||||
public ref byte SkinColor
|
||||
=> ref _data->SkinColor;
|
||||
|
||||
public ref byte EyeColorRight
|
||||
=> ref _data->EyeColorRight;
|
||||
|
||||
public ref byte HairColor
|
||||
=> ref _data->HairColor;
|
||||
|
||||
public ref byte HighlightsColor
|
||||
=> ref _data->HighlightsColor;
|
||||
|
||||
public ref byte FacialFeatures
|
||||
=> ref _data->FacialFeatures;
|
||||
|
||||
public ref byte TattooColor
|
||||
=> ref _data->TattooColor;
|
||||
|
||||
public ref byte Eyebrow
|
||||
=> ref _data->Eyebrow;
|
||||
|
||||
public ref byte EyeColorLeft
|
||||
=> ref _data->EyeColorLeft;
|
||||
|
||||
public byte EyeShape
|
||||
{
|
||||
get => _data->EyeShape;
|
||||
set => _data->EyeShape = value;
|
||||
}
|
||||
|
||||
public byte FacePaint
|
||||
{
|
||||
get => _data->FacePaint;
|
||||
set => _data->FacePaint = value;
|
||||
}
|
||||
|
||||
public bool FacePaintReversed
|
||||
{
|
||||
get => _data->FacePaintReversed;
|
||||
set => _data->FacePaintReversed = value;
|
||||
}
|
||||
|
||||
public byte Mouth
|
||||
{
|
||||
get => _data->Mouth;
|
||||
set => _data->Mouth = value;
|
||||
}
|
||||
|
||||
public bool SmallIris
|
||||
{
|
||||
get => _data->SmallIris;
|
||||
set => _data->SmallIris = value;
|
||||
}
|
||||
|
||||
public bool Lipstick
|
||||
{
|
||||
get => _data->Lipstick;
|
||||
set => _data->Lipstick = value;
|
||||
}
|
||||
|
||||
public ref byte Nose
|
||||
=> ref _data->Nose;
|
||||
|
||||
public ref byte Jaw
|
||||
=> ref _data->Jaw;
|
||||
|
||||
public ref byte LipColor
|
||||
=> ref _data->LipColor;
|
||||
|
||||
public ref byte MuscleMass
|
||||
=> ref _data->MuscleMass;
|
||||
|
||||
public ref byte TailShape
|
||||
=> ref _data->TailShape;
|
||||
|
||||
public ref byte BustSize
|
||||
=> ref _data->BustSize;
|
||||
|
||||
public ref byte FacePaintColor
|
||||
=> ref _data->FacePaintColor;
|
||||
|
||||
public bool FacialFeature(int idx)
|
||||
=> _data->FacialFeature(idx);
|
||||
|
||||
public void FacialFeature(int idx, bool set)
|
||||
=> _data->FacialFeature(idx, set);
|
||||
|
||||
public byte this[CustomizationId id]
|
||||
{
|
||||
get => _data->Get(id);
|
||||
set => _data->Set(id, value);
|
||||
}
|
||||
|
||||
public static implicit operator CharacterCustomization(CustomizationData* val)
|
||||
=> new(val);
|
||||
|
||||
public static implicit operator CharacterCustomization(IntPtr val)
|
||||
=> new((CustomizationData*)val);
|
||||
|
||||
public static implicit operator bool(CharacterCustomization customize)
|
||||
=> customize._data != null;
|
||||
|
||||
public static bool operator true(CharacterCustomization customize)
|
||||
=> customize._data != null;
|
||||
|
||||
public static bool operator false(CharacterCustomization customize)
|
||||
=> customize._data == null;
|
||||
|
||||
public static bool operator !(CharacterCustomization customize)
|
||||
=> customize._data == null;
|
||||
}
|
||||
|
|
@ -1,168 +0,0 @@
|
|||
using System;
|
||||
using System.ComponentModel;
|
||||
using Glamourer.Structs;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
namespace Glamourer;
|
||||
|
||||
public static class WriteExtensions
|
||||
{
|
||||
private static unsafe void Write(IntPtr characterPtr, EquipSlot slot, SetId? id, WeaponType? type, ushort? variant, StainId? stain)
|
||||
{
|
||||
void WriteWeapon(int offset)
|
||||
{
|
||||
var address = (byte*)characterPtr + offset;
|
||||
if (id.HasValue)
|
||||
*(ushort*)address = (ushort)id.Value;
|
||||
|
||||
if (type.HasValue)
|
||||
*(ushort*)(address + 2) = (ushort)type.Value;
|
||||
|
||||
if (variant.HasValue)
|
||||
*(ushort*)(address + 4) = variant.Value;
|
||||
|
||||
if (stain.HasValue)
|
||||
*(address + 6) = (byte)stain.Value;
|
||||
}
|
||||
|
||||
void WriteEquip(int offset)
|
||||
{
|
||||
var address = (uint*)characterPtr + offset;
|
||||
if (id.HasValue)
|
||||
*(ushort*)address = (ushort)id.Value;
|
||||
|
||||
if (variant < byte.MaxValue)
|
||||
*(address + 2) = (byte)variant.Value;
|
||||
|
||||
if (stain.HasValue)
|
||||
*(address + 3) = (byte)stain.Value;
|
||||
}
|
||||
|
||||
switch (slot)
|
||||
{
|
||||
case EquipSlot.MainHand:
|
||||
WriteWeapon(CharacterEquipment.MainWeaponOffset);
|
||||
break;
|
||||
case EquipSlot.OffHand:
|
||||
WriteWeapon(CharacterEquipment.OffWeaponOffset);
|
||||
break;
|
||||
case EquipSlot.Head:
|
||||
WriteEquip(CharacterEquipment.EquipmentOffset);
|
||||
break;
|
||||
case EquipSlot.Body:
|
||||
WriteEquip(CharacterEquipment.EquipmentOffset + 4);
|
||||
break;
|
||||
case EquipSlot.Hands:
|
||||
WriteEquip(CharacterEquipment.EquipmentOffset + 8);
|
||||
break;
|
||||
case EquipSlot.Legs:
|
||||
WriteEquip(CharacterEquipment.EquipmentOffset + 12);
|
||||
break;
|
||||
case EquipSlot.Feet:
|
||||
WriteEquip(CharacterEquipment.EquipmentOffset + 16);
|
||||
break;
|
||||
case EquipSlot.Ears:
|
||||
WriteEquip(CharacterEquipment.EquipmentOffset + 20);
|
||||
break;
|
||||
case EquipSlot.Neck:
|
||||
WriteEquip(CharacterEquipment.EquipmentOffset + 24);
|
||||
break;
|
||||
case EquipSlot.Wrists:
|
||||
WriteEquip(CharacterEquipment.EquipmentOffset + 28);
|
||||
break;
|
||||
case EquipSlot.RFinger:
|
||||
WriteEquip(CharacterEquipment.EquipmentOffset + 32);
|
||||
break;
|
||||
case EquipSlot.LFinger:
|
||||
WriteEquip(CharacterEquipment.EquipmentOffset + 36);
|
||||
break;
|
||||
default: throw new InvalidEnumArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
public static void Write(this Stain stain, IntPtr characterPtr, EquipSlot slot)
|
||||
=> Write(characterPtr, slot, null, null, null, stain.RowIndex);
|
||||
|
||||
public static void Write(this Item item, IntPtr characterAddress)
|
||||
{
|
||||
var (id, type, variant) = item.MainModel;
|
||||
Write(characterAddress, item.EquippableTo, id, type, variant, null);
|
||||
if (item.EquippableTo == EquipSlot.MainHand && item.HasSubModel)
|
||||
{
|
||||
var (subId, subType, subVariant) = item.SubModel;
|
||||
Write(characterAddress, EquipSlot.OffHand, subId, subType, subVariant, null);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Write(this CharacterArmor armor, IntPtr characterAddress, EquipSlot slot)
|
||||
=> Write(characterAddress, slot, armor.Set, null, armor.Variant, armor.Stain);
|
||||
|
||||
public static void Write(this CharacterWeapon weapon, IntPtr characterAddress, EquipSlot slot)
|
||||
=> Write(characterAddress, slot, weapon.Set, weapon.Type, weapon.Variant, weapon.Stain);
|
||||
|
||||
public static unsafe void Write(this CharacterEquipment equip, IntPtr characterAddress)
|
||||
{
|
||||
if (equip.IsSet == 0)
|
||||
return;
|
||||
|
||||
Write(characterAddress, EquipSlot.MainHand, equip.MainHand.Set, equip.MainHand.Type, equip.MainHand.Variant, equip.MainHand.Stain);
|
||||
Write(characterAddress, EquipSlot.OffHand, equip.OffHand.Set, equip.OffHand.Type, equip.OffHand.Variant, equip.OffHand.Stain);
|
||||
|
||||
fixed (CharacterArmor* equipment = &equip.Head)
|
||||
{
|
||||
Buffer.MemoryCopy(equipment, (byte*)characterAddress + CharacterEquipment.EquipmentOffset,
|
||||
CharacterEquipment.EquipmentSlots * sizeof(CharacterArmor), CharacterEquipment.EquipmentSlots * sizeof(CharacterArmor));
|
||||
}
|
||||
}
|
||||
|
||||
public static void Write(this CharacterEquipment equip, IntPtr characterAddress, CharacterEquipMask models, CharacterEquipMask stains)
|
||||
{
|
||||
if (models == CharacterEquipMask.All && stains == CharacterEquipMask.All)
|
||||
{
|
||||
equip.Write(characterAddress);
|
||||
return;
|
||||
}
|
||||
|
||||
if (models.HasFlag(CharacterEquipMask.MainHand))
|
||||
Write(characterAddress, EquipSlot.MainHand, equip.MainHand.Set, equip.MainHand.Type, equip.MainHand.Variant, null);
|
||||
if (stains.HasFlag(CharacterEquipMask.MainHand))
|
||||
Write(characterAddress, EquipSlot.MainHand, null, null, null, equip.MainHand.Stain);
|
||||
if (models.HasFlag(CharacterEquipMask.OffHand))
|
||||
Write(characterAddress, EquipSlot.OffHand, equip.OffHand.Set, equip.OffHand.Type, equip.OffHand.Variant, null);
|
||||
if (stains.HasFlag(CharacterEquipMask.OffHand))
|
||||
Write(characterAddress, EquipSlot.OffHand, null, null, null, equip.OffHand.Stain);
|
||||
|
||||
if (models.HasFlag(CharacterEquipMask.Head))
|
||||
Write(characterAddress, EquipSlot.Head, equip.Head.Set, null, equip.Head.Variant, null);
|
||||
if (stains.HasFlag(CharacterEquipMask.Head))
|
||||
Write(characterAddress, EquipSlot.Head, null, null, null, equip.Head.Stain);
|
||||
if (models.HasFlag(CharacterEquipMask.Body))
|
||||
Write(characterAddress, EquipSlot.Body, equip.Body.Set, null, equip.Body.Variant, null);
|
||||
if (stains.HasFlag(CharacterEquipMask.Body))
|
||||
Write(characterAddress, EquipSlot.Body, null, null, null, equip.Body.Stain);
|
||||
if (models.HasFlag(CharacterEquipMask.Hands))
|
||||
Write(characterAddress, EquipSlot.Hands, equip.Hands.Set, null, equip.Hands.Variant, null);
|
||||
if (stains.HasFlag(CharacterEquipMask.Hands))
|
||||
Write(characterAddress, EquipSlot.Hands, null, null, null, equip.Hands.Stain);
|
||||
if (models.HasFlag(CharacterEquipMask.Legs))
|
||||
Write(characterAddress, EquipSlot.Legs, equip.Legs.Set, null, equip.Legs.Variant, null);
|
||||
if (stains.HasFlag(CharacterEquipMask.Legs))
|
||||
Write(characterAddress, EquipSlot.Legs, null, null, null, equip.Legs.Stain);
|
||||
if (models.HasFlag(CharacterEquipMask.Feet))
|
||||
Write(characterAddress, EquipSlot.Feet, equip.Feet.Set, null, equip.Feet.Variant, null);
|
||||
if (stains.HasFlag(CharacterEquipMask.Feet))
|
||||
Write(characterAddress, EquipSlot.Feet, null, null, null, equip.Feet.Stain);
|
||||
|
||||
if (models.HasFlag(CharacterEquipMask.Ears))
|
||||
Write(characterAddress, EquipSlot.Ears, equip.Ears.Set, null, equip.Ears.Variant, null);
|
||||
if (models.HasFlag(CharacterEquipMask.Neck))
|
||||
Write(characterAddress, EquipSlot.Neck, equip.Neck.Set, null, equip.Neck.Variant, null);
|
||||
if (models.HasFlag(CharacterEquipMask.Wrists))
|
||||
Write(characterAddress, EquipSlot.Wrists, equip.Wrists.Set, null, equip.Wrists.Variant, null);
|
||||
if (models.HasFlag(CharacterEquipMask.LFinger))
|
||||
Write(characterAddress, EquipSlot.LFinger, equip.LFinger.Set, null, equip.LFinger.Variant, null);
|
||||
if (models.HasFlag(CharacterEquipMask.RFinger))
|
||||
Write(characterAddress, EquipSlot.RFinger, equip.RFinger.Set, null, equip.RFinger.Variant, null);
|
||||
}
|
||||
}
|
||||
|
|
@ -4,11 +4,11 @@ using Penumbra.GameData.Structs;
|
|||
|
||||
namespace Glamourer.Customization;
|
||||
|
||||
public unsafe ref struct Customize
|
||||
public unsafe struct Customize
|
||||
{
|
||||
private readonly CustomizeData* _data;
|
||||
|
||||
private Customize(CustomizeData* data)
|
||||
public Customize(CustomizeData* data)
|
||||
=> _data = data;
|
||||
|
||||
public Race Race
|
||||
|
|
@ -70,7 +70,7 @@ public unsafe ref struct Customize
|
|||
public bool this[int idx]
|
||||
{
|
||||
get => (*_bitfield & (1 << idx)) != 0;
|
||||
set => *_bitfield = (byte)(value ? *_bitfield | (1 << idx) : *_bitfield & ~(1 << idx));
|
||||
set => Set(idx, value);
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
|
|
@ -78,6 +78,9 @@ public unsafe ref struct Customize
|
|||
|
||||
public void All()
|
||||
=> *_bitfield = 0xFF;
|
||||
|
||||
public void Set(int idx, bool value)
|
||||
=> *_bitfield = (byte)(value ? *_bitfield | (1 << idx) : *_bitfield & ~(1 << idx));
|
||||
}
|
||||
|
||||
public FacialFeatureStruct FacialFeatures
|
||||
|
|
@ -149,8 +152,8 @@ public unsafe ref struct Customize
|
|||
public ref byte FacePaintColor
|
||||
=> ref _data->Data[25];
|
||||
|
||||
internal static readonly CustomizeData Default = GenerateDefault();
|
||||
internal static readonly CustomizeData Empty = new();
|
||||
public static readonly CustomizeData Default = GenerateDefault();
|
||||
public static readonly CustomizeData Empty = new();
|
||||
|
||||
public byte Get(CustomizationId id)
|
||||
=> id switch
|
||||
|
|
@ -263,4 +266,7 @@ public unsafe ref struct Customize
|
|||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void Load(Customize other)
|
||||
=> _data->Read(other._data);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ public class CustomizationSet
|
|||
public int NumJawShapes { get; internal init; }
|
||||
public int NumMouthShapes { get; internal init; }
|
||||
|
||||
public string ToHumanReadable(CustomizationData customizationData)
|
||||
public string ToHumanReadable(Customize customizationData)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
foreach (var id in Enum.GetValues<CustomizationId>().Where(IsAvailable))
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue