mirror of
https://github.com/Ottermandias/Glamourer.git
synced 2025-12-12 10:17:23 +01:00
Remove GameData, move a bunch of customization data to Penumbra.GameData and the rest to Glamourer, update accordingly. Some reformatting and cleanup.
This commit is contained in:
parent
e9d0e61b4c
commit
987c26a51d
83 changed files with 444 additions and 1620 deletions
|
|
@ -1,46 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Dalamud.Logging;
|
||||
using Dalamud.Plugin.Services;
|
||||
|
||||
namespace Glamourer.Customization;
|
||||
|
||||
// Convert the Human.Cmp file into color sets.
|
||||
// If the file can not be read due to TexTools corruption, create a 0-array of size MinSize.
|
||||
internal class CmpFile
|
||||
{
|
||||
private readonly Lumina.Data.FileResource? _file;
|
||||
private readonly uint[] _rgbaColors;
|
||||
|
||||
// No error checking since only called internally.
|
||||
public IEnumerable<uint> GetSlice(int offset, int count)
|
||||
=> _rgbaColors.Length >= offset + count ? _rgbaColors.Skip(offset).Take(count) : Enumerable.Repeat(0u, count);
|
||||
|
||||
public bool Valid
|
||||
=> _file != null;
|
||||
|
||||
public CmpFile(IDataManager gameData, IPluginLog log)
|
||||
{
|
||||
try
|
||||
{
|
||||
_file = gameData.GetFile("chara/xls/charamake/human.cmp")!;
|
||||
_rgbaColors = new uint[_file.Data.Length >> 2];
|
||||
for (var i = 0; i < _file.Data.Length; i += 4)
|
||||
{
|
||||
_rgbaColors[i >> 2] = _file.Data[i]
|
||||
| (uint)(_file.Data[i + 1] << 8)
|
||||
| (uint)(_file.Data[i + 2] << 16)
|
||||
| (uint)(_file.Data[i + 3] << 24);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
log.Error("READ THIS\n======== Could not obtain the human.cmp file which is necessary for color sets.\n"
|
||||
+ "======== This usually indicates an error with your index files caused by TexTools modifications.\n"
|
||||
+ "======== If you have used TexTools before, you will probably need to start over in it to use Glamourer.", e);
|
||||
_file = null;
|
||||
_rgbaColors = Array.Empty<uint>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,124 +0,0 @@
|
|||
using System;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
namespace Glamourer.Customization;
|
||||
|
||||
public unsafe struct Customize
|
||||
{
|
||||
public CustomizeArray Data;
|
||||
|
||||
public Customize(in CustomizeArray data)
|
||||
{
|
||||
Data = data.Clone();
|
||||
}
|
||||
|
||||
public Race Race
|
||||
{
|
||||
get => (Race)Data.Get(CustomizeIndex.Race).Value;
|
||||
set => Data.Set(CustomizeIndex.Race, (CustomizeValue)(byte)value);
|
||||
}
|
||||
|
||||
public Gender Gender
|
||||
{
|
||||
get => (Gender)Data.Get(CustomizeIndex.Gender).Value + 1;
|
||||
set => Data.Set(CustomizeIndex.Gender, (CustomizeValue)(byte)value - 1);
|
||||
}
|
||||
|
||||
public CustomizeValue BodyType
|
||||
{
|
||||
get => Data.Get(CustomizeIndex.BodyType);
|
||||
set => Data.Set(CustomizeIndex.BodyType, value);
|
||||
}
|
||||
|
||||
public SubRace Clan
|
||||
{
|
||||
get => (SubRace)Data.Get(CustomizeIndex.Clan).Value;
|
||||
set => Data.Set(CustomizeIndex.Clan, (CustomizeValue)(byte)value);
|
||||
}
|
||||
|
||||
public CustomizeValue Face
|
||||
{
|
||||
get => Data.Get(CustomizeIndex.Face);
|
||||
set => Data.Set(CustomizeIndex.Face, value);
|
||||
}
|
||||
|
||||
|
||||
public static readonly Customize Default = GenerateDefault();
|
||||
public static readonly Customize Empty = new();
|
||||
|
||||
public CustomizeValue Get(CustomizeIndex index)
|
||||
=> Data.Get(index);
|
||||
|
||||
public bool Set(CustomizeIndex flag, CustomizeValue index)
|
||||
=> Data.Set(flag, index);
|
||||
|
||||
public bool Equals(Customize other)
|
||||
=> Equals(Data, other.Data);
|
||||
|
||||
public CustomizeValue this[CustomizeIndex index]
|
||||
{
|
||||
get => Get(index);
|
||||
set => Set(index, value);
|
||||
}
|
||||
|
||||
private static Customize GenerateDefault()
|
||||
{
|
||||
var ret = new Customize
|
||||
{
|
||||
Race = Race.Hyur,
|
||||
Clan = SubRace.Midlander,
|
||||
Gender = Gender.Male,
|
||||
};
|
||||
ret.Set(CustomizeIndex.BodyType, (CustomizeValue)1);
|
||||
ret.Set(CustomizeIndex.Height, (CustomizeValue)50);
|
||||
ret.Set(CustomizeIndex.Face, (CustomizeValue)1);
|
||||
ret.Set(CustomizeIndex.Hairstyle, (CustomizeValue)1);
|
||||
ret.Set(CustomizeIndex.SkinColor, (CustomizeValue)1);
|
||||
ret.Set(CustomizeIndex.EyeColorRight, (CustomizeValue)1);
|
||||
ret.Set(CustomizeIndex.HighlightsColor, (CustomizeValue)1);
|
||||
ret.Set(CustomizeIndex.TattooColor, (CustomizeValue)1);
|
||||
ret.Set(CustomizeIndex.Eyebrows, (CustomizeValue)1);
|
||||
ret.Set(CustomizeIndex.EyeColorLeft, (CustomizeValue)1);
|
||||
ret.Set(CustomizeIndex.EyeShape, (CustomizeValue)1);
|
||||
ret.Set(CustomizeIndex.Nose, (CustomizeValue)1);
|
||||
ret.Set(CustomizeIndex.Jaw, (CustomizeValue)1);
|
||||
ret.Set(CustomizeIndex.Mouth, (CustomizeValue)1);
|
||||
ret.Set(CustomizeIndex.LipColor, (CustomizeValue)1);
|
||||
ret.Set(CustomizeIndex.MuscleMass, (CustomizeValue)50);
|
||||
ret.Set(CustomizeIndex.TailShape, (CustomizeValue)1);
|
||||
ret.Set(CustomizeIndex.BustSize, (CustomizeValue)50);
|
||||
ret.Set(CustomizeIndex.FacePaint, (CustomizeValue)1);
|
||||
ret.Set(CustomizeIndex.FacePaintColor, (CustomizeValue)1);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void Load(Customize other)
|
||||
=> Data.Read(&other.Data);
|
||||
|
||||
public readonly void Write(nint target)
|
||||
=> Data.Write((void*)target);
|
||||
|
||||
public bool LoadBase64(string data)
|
||||
=> Data.LoadBase64(data);
|
||||
|
||||
public readonly string WriteBase64()
|
||||
=> Data.WriteBase64();
|
||||
|
||||
public static CustomizeFlag Compare(Customize lhs, Customize rhs)
|
||||
{
|
||||
CustomizeFlag ret = 0;
|
||||
foreach (var idx in Enum.GetValues<CustomizeIndex>())
|
||||
{
|
||||
var l = lhs[idx];
|
||||
var r = rhs[idx];
|
||||
if (l.Value != r.Value)
|
||||
ret |= idx.ToFlag();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
=> Data.ToString();
|
||||
}
|
||||
|
|
@ -1,114 +0,0 @@
|
|||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Glamourer.Customization;
|
||||
|
||||
[Flags]
|
||||
public enum CustomizeFlag : ulong
|
||||
{
|
||||
Invalid = 0,
|
||||
Race = 1ul << CustomizeIndex.Race,
|
||||
Gender = 1ul << CustomizeIndex.Gender,
|
||||
BodyType = 1ul << CustomizeIndex.BodyType,
|
||||
Height = 1ul << CustomizeIndex.Height,
|
||||
Clan = 1ul << CustomizeIndex.Clan,
|
||||
Face = 1ul << CustomizeIndex.Face,
|
||||
Hairstyle = 1ul << CustomizeIndex.Hairstyle,
|
||||
Highlights = 1ul << CustomizeIndex.Highlights,
|
||||
SkinColor = 1ul << CustomizeIndex.SkinColor,
|
||||
EyeColorRight = 1ul << CustomizeIndex.EyeColorRight,
|
||||
HairColor = 1ul << CustomizeIndex.HairColor,
|
||||
HighlightsColor = 1ul << CustomizeIndex.HighlightsColor,
|
||||
FacialFeature1 = 1ul << CustomizeIndex.FacialFeature1,
|
||||
FacialFeature2 = 1ul << CustomizeIndex.FacialFeature2,
|
||||
FacialFeature3 = 1ul << CustomizeIndex.FacialFeature3,
|
||||
FacialFeature4 = 1ul << CustomizeIndex.FacialFeature4,
|
||||
FacialFeature5 = 1ul << CustomizeIndex.FacialFeature5,
|
||||
FacialFeature6 = 1ul << CustomizeIndex.FacialFeature6,
|
||||
FacialFeature7 = 1ul << CustomizeIndex.FacialFeature7,
|
||||
LegacyTattoo = 1ul << CustomizeIndex.LegacyTattoo,
|
||||
TattooColor = 1ul << CustomizeIndex.TattooColor,
|
||||
Eyebrows = 1ul << CustomizeIndex.Eyebrows,
|
||||
EyeColorLeft = 1ul << CustomizeIndex.EyeColorLeft,
|
||||
EyeShape = 1ul << CustomizeIndex.EyeShape,
|
||||
SmallIris = 1ul << CustomizeIndex.SmallIris,
|
||||
Nose = 1ul << CustomizeIndex.Nose,
|
||||
Jaw = 1ul << CustomizeIndex.Jaw,
|
||||
Mouth = 1ul << CustomizeIndex.Mouth,
|
||||
Lipstick = 1ul << CustomizeIndex.Lipstick,
|
||||
LipColor = 1ul << CustomizeIndex.LipColor,
|
||||
MuscleMass = 1ul << CustomizeIndex.MuscleMass,
|
||||
TailShape = 1ul << CustomizeIndex.TailShape,
|
||||
BustSize = 1ul << CustomizeIndex.BustSize,
|
||||
FacePaint = 1ul << CustomizeIndex.FacePaint,
|
||||
FacePaintReversed = 1ul << CustomizeIndex.FacePaintReversed,
|
||||
FacePaintColor = 1ul << CustomizeIndex.FacePaintColor,
|
||||
}
|
||||
|
||||
public static class CustomizeFlagExtensions
|
||||
{
|
||||
public const CustomizeFlag All = (CustomizeFlag)(((ulong)CustomizeFlag.FacePaintColor << 1) - 1ul);
|
||||
public const CustomizeFlag AllRelevant = All & ~CustomizeFlag.BodyType & ~CustomizeFlag.Race;
|
||||
|
||||
public const CustomizeFlag RedrawRequired =
|
||||
CustomizeFlag.Race | CustomizeFlag.Clan | CustomizeFlag.Gender | CustomizeFlag.Face | CustomizeFlag.BodyType;
|
||||
|
||||
public static CustomizeFlag FixApplication(this CustomizeFlag flag, CustomizationSet set)
|
||||
=> flag & (set.SettingAvailable | CustomizeFlag.Clan | CustomizeFlag.Gender);
|
||||
|
||||
public static bool RequiresRedraw(this CustomizeFlag flags)
|
||||
=> (flags & RedrawRequired) != 0;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
public static CustomizeIndex ToIndex(this CustomizeFlag flag)
|
||||
=> flag switch
|
||||
{
|
||||
CustomizeFlag.Race => CustomizeIndex.Race,
|
||||
CustomizeFlag.Gender => CustomizeIndex.Gender,
|
||||
CustomizeFlag.BodyType => CustomizeIndex.BodyType,
|
||||
CustomizeFlag.Height => CustomizeIndex.Height,
|
||||
CustomizeFlag.Clan => CustomizeIndex.Clan,
|
||||
CustomizeFlag.Face => CustomizeIndex.Face,
|
||||
CustomizeFlag.Hairstyle => CustomizeIndex.Hairstyle,
|
||||
CustomizeFlag.Highlights => CustomizeIndex.Highlights,
|
||||
CustomizeFlag.SkinColor => CustomizeIndex.SkinColor,
|
||||
CustomizeFlag.EyeColorRight => CustomizeIndex.EyeColorRight,
|
||||
CustomizeFlag.HairColor => CustomizeIndex.HairColor,
|
||||
CustomizeFlag.HighlightsColor => CustomizeIndex.HighlightsColor,
|
||||
CustomizeFlag.FacialFeature1 => CustomizeIndex.FacialFeature1,
|
||||
CustomizeFlag.FacialFeature2 => CustomizeIndex.FacialFeature2,
|
||||
CustomizeFlag.FacialFeature3 => CustomizeIndex.FacialFeature3,
|
||||
CustomizeFlag.FacialFeature4 => CustomizeIndex.FacialFeature4,
|
||||
CustomizeFlag.FacialFeature5 => CustomizeIndex.FacialFeature5,
|
||||
CustomizeFlag.FacialFeature6 => CustomizeIndex.FacialFeature6,
|
||||
CustomizeFlag.FacialFeature7 => CustomizeIndex.FacialFeature7,
|
||||
CustomizeFlag.LegacyTattoo => CustomizeIndex.LegacyTattoo,
|
||||
CustomizeFlag.TattooColor => CustomizeIndex.TattooColor,
|
||||
CustomizeFlag.Eyebrows => CustomizeIndex.Eyebrows,
|
||||
CustomizeFlag.EyeColorLeft => CustomizeIndex.EyeColorLeft,
|
||||
CustomizeFlag.EyeShape => CustomizeIndex.EyeShape,
|
||||
CustomizeFlag.SmallIris => CustomizeIndex.SmallIris,
|
||||
CustomizeFlag.Nose => CustomizeIndex.Nose,
|
||||
CustomizeFlag.Jaw => CustomizeIndex.Jaw,
|
||||
CustomizeFlag.Mouth => CustomizeIndex.Mouth,
|
||||
CustomizeFlag.Lipstick => CustomizeIndex.Lipstick,
|
||||
CustomizeFlag.LipColor => CustomizeIndex.LipColor,
|
||||
CustomizeFlag.MuscleMass => CustomizeIndex.MuscleMass,
|
||||
CustomizeFlag.TailShape => CustomizeIndex.TailShape,
|
||||
CustomizeFlag.BustSize => CustomizeIndex.BustSize,
|
||||
CustomizeFlag.FacePaint => CustomizeIndex.FacePaint,
|
||||
CustomizeFlag.FacePaintReversed => CustomizeIndex.FacePaintReversed,
|
||||
CustomizeFlag.FacePaintColor => CustomizeIndex.FacePaintColor,
|
||||
_ => (CustomizeIndex)byte.MaxValue,
|
||||
};
|
||||
|
||||
public static bool SetIfDifferent(ref this CustomizeFlag flags, CustomizeFlag flag, bool value)
|
||||
{
|
||||
var newValue = value ? flags | flag : flags & ~flag;
|
||||
if (newValue == flags)
|
||||
return false;
|
||||
|
||||
flags = newValue;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,183 +0,0 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Glamourer.Customization;
|
||||
|
||||
public enum CustomizeIndex : byte
|
||||
{
|
||||
Race,
|
||||
Gender,
|
||||
BodyType,
|
||||
Height,
|
||||
Clan,
|
||||
Face,
|
||||
Hairstyle,
|
||||
Highlights,
|
||||
SkinColor,
|
||||
EyeColorRight,
|
||||
HairColor,
|
||||
HighlightsColor,
|
||||
FacialFeature1,
|
||||
FacialFeature2,
|
||||
FacialFeature3,
|
||||
FacialFeature4,
|
||||
FacialFeature5,
|
||||
FacialFeature6,
|
||||
FacialFeature7,
|
||||
LegacyTattoo,
|
||||
TattooColor,
|
||||
Eyebrows,
|
||||
EyeColorLeft,
|
||||
EyeShape,
|
||||
SmallIris,
|
||||
Nose,
|
||||
Jaw,
|
||||
Mouth,
|
||||
Lipstick,
|
||||
LipColor,
|
||||
MuscleMass,
|
||||
TailShape,
|
||||
BustSize,
|
||||
FacePaint,
|
||||
FacePaintReversed,
|
||||
FacePaintColor,
|
||||
}
|
||||
|
||||
public static class CustomizationExtensions
|
||||
{
|
||||
public const int NumIndices = (int)CustomizeIndex.FacePaintColor + 1;
|
||||
|
||||
public static readonly CustomizeIndex[] All = Enum.GetValues<CustomizeIndex>()
|
||||
.Where(v => v is not CustomizeIndex.Race and not CustomizeIndex.BodyType).ToArray();
|
||||
|
||||
public static readonly CustomizeIndex[] AllBasic = All
|
||||
.Where(v => v is not CustomizeIndex.Gender and not CustomizeIndex.Clan).ToArray();
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
public static (int ByteIdx, byte Mask) ToByteAndMask(this CustomizeIndex index)
|
||||
=> index switch
|
||||
{
|
||||
CustomizeIndex.Race => (0, 0xFF),
|
||||
CustomizeIndex.Gender => (1, 0xFF),
|
||||
CustomizeIndex.BodyType => (2, 0xFF),
|
||||
CustomizeIndex.Height => (3, 0xFF),
|
||||
CustomizeIndex.Clan => (4, 0xFF),
|
||||
CustomizeIndex.Face => (5, 0xFF),
|
||||
CustomizeIndex.Hairstyle => (6, 0xFF),
|
||||
CustomizeIndex.Highlights => (7, 0x80),
|
||||
CustomizeIndex.SkinColor => (8, 0xFF),
|
||||
CustomizeIndex.EyeColorRight => (9, 0xFF),
|
||||
CustomizeIndex.HairColor => (10, 0xFF),
|
||||
CustomizeIndex.HighlightsColor => (11, 0xFF),
|
||||
CustomizeIndex.FacialFeature1 => (12, 0x01),
|
||||
CustomizeIndex.FacialFeature2 => (12, 0x02),
|
||||
CustomizeIndex.FacialFeature3 => (12, 0x04),
|
||||
CustomizeIndex.FacialFeature4 => (12, 0x08),
|
||||
CustomizeIndex.FacialFeature5 => (12, 0x10),
|
||||
CustomizeIndex.FacialFeature6 => (12, 0x20),
|
||||
CustomizeIndex.FacialFeature7 => (12, 0x40),
|
||||
CustomizeIndex.LegacyTattoo => (12, 0x80),
|
||||
CustomizeIndex.TattooColor => (13, 0xFF),
|
||||
CustomizeIndex.Eyebrows => (14, 0xFF),
|
||||
CustomizeIndex.EyeColorLeft => (15, 0xFF),
|
||||
CustomizeIndex.EyeShape => (16, 0x7F),
|
||||
CustomizeIndex.SmallIris => (16, 0x80),
|
||||
CustomizeIndex.Nose => (17, 0xFF),
|
||||
CustomizeIndex.Jaw => (18, 0xFF),
|
||||
CustomizeIndex.Mouth => (19, 0x7F),
|
||||
CustomizeIndex.Lipstick => (19, 0x80),
|
||||
CustomizeIndex.LipColor => (20, 0xFF),
|
||||
CustomizeIndex.MuscleMass => (21, 0xFF),
|
||||
CustomizeIndex.TailShape => (22, 0xFF),
|
||||
CustomizeIndex.BustSize => (23, 0xFF),
|
||||
CustomizeIndex.FacePaint => (24, 0x7F),
|
||||
CustomizeIndex.FacePaintReversed => (24, 0x80),
|
||||
CustomizeIndex.FacePaintColor => (25, 0xFF),
|
||||
_ => (0, 0x00),
|
||||
};
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
public static CustomizeFlag ToFlag(this CustomizeIndex index)
|
||||
=> (CustomizeFlag)(1ul << (int)index);
|
||||
|
||||
public static string ToDefaultName(this CustomizeIndex customizeIndex)
|
||||
=> customizeIndex switch
|
||||
{
|
||||
CustomizeIndex.Race => "Race",
|
||||
CustomizeIndex.Gender => "Gender",
|
||||
CustomizeIndex.BodyType => "Body Type",
|
||||
CustomizeIndex.Height => "Height",
|
||||
CustomizeIndex.Clan => "Clan",
|
||||
CustomizeIndex.Face => "Head Style",
|
||||
CustomizeIndex.Hairstyle => "Hair Style",
|
||||
CustomizeIndex.Highlights => "Enable Highlights",
|
||||
CustomizeIndex.SkinColor => "Skin Color",
|
||||
CustomizeIndex.EyeColorRight => "Left Eye", // inverted due to compatibility fuckup.
|
||||
CustomizeIndex.HairColor => "Hair Color",
|
||||
CustomizeIndex.HighlightsColor => "Highlights Color",
|
||||
CustomizeIndex.TattooColor => "Tattoo Color",
|
||||
CustomizeIndex.Eyebrows => "Eyebrow Style",
|
||||
CustomizeIndex.EyeColorLeft => "Right Eye", // inverted due to compatibility fuckup.
|
||||
CustomizeIndex.EyeShape => "Small Pupils",
|
||||
CustomizeIndex.Nose => "Nose Style",
|
||||
CustomizeIndex.Jaw => "Jaw Style",
|
||||
CustomizeIndex.Mouth => "Mouth Style",
|
||||
CustomizeIndex.MuscleMass => "Muscle Tone",
|
||||
CustomizeIndex.TailShape => "Tail Shape",
|
||||
CustomizeIndex.BustSize => "Bust Size",
|
||||
CustomizeIndex.FacePaint => "Face Paint",
|
||||
CustomizeIndex.FacePaintColor => "Face Paint Color",
|
||||
CustomizeIndex.LipColor => "Lip Color",
|
||||
CustomizeIndex.FacialFeature1 => "Facial Feature 1",
|
||||
CustomizeIndex.FacialFeature2 => "Facial Feature 2",
|
||||
CustomizeIndex.FacialFeature3 => "Facial Feature 3",
|
||||
CustomizeIndex.FacialFeature4 => "Facial Feature 4",
|
||||
CustomizeIndex.FacialFeature5 => "Facial Feature 5",
|
||||
CustomizeIndex.FacialFeature6 => "Facial Feature 6",
|
||||
CustomizeIndex.FacialFeature7 => "Facial Feature 7",
|
||||
CustomizeIndex.LegacyTattoo => "Legacy Tattoo",
|
||||
CustomizeIndex.SmallIris => "Small Iris",
|
||||
CustomizeIndex.Lipstick => "Enable Lipstick",
|
||||
CustomizeIndex.FacePaintReversed => "Reverse Face Paint",
|
||||
_ => string.Empty,
|
||||
};
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
public static unsafe CustomizeValue Get(this in Penumbra.GameData.Structs.CustomizeArray data, CustomizeIndex index)
|
||||
{
|
||||
var (offset, mask) = index.ToByteAndMask();
|
||||
return (CustomizeValue)(data.Data[offset] & mask);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
public static unsafe bool Set(this ref Penumbra.GameData.Structs.CustomizeArray data, CustomizeIndex index, CustomizeValue value)
|
||||
{
|
||||
var (offset, mask) = index.ToByteAndMask();
|
||||
return mask != 0xFF
|
||||
? SetIfDifferentMasked(ref data.Data[offset], value, mask)
|
||||
: SetIfDifferent(ref data.Data[offset], value);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
private static bool SetIfDifferentMasked(ref byte oldValue, CustomizeValue newValue, byte mask)
|
||||
{
|
||||
var tmp = (byte)(newValue.Value & mask);
|
||||
tmp = (byte)(tmp | (oldValue & ~mask));
|
||||
if (oldValue == tmp)
|
||||
return false;
|
||||
|
||||
oldValue = tmp;
|
||||
return true;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
|
||||
private static bool SetIfDifferent(ref byte oldValue, CustomizeValue newValue)
|
||||
{
|
||||
if (oldValue == newValue.Value)
|
||||
return false;
|
||||
|
||||
oldValue = newValue.Value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,34 +0,0 @@
|
|||
namespace Glamourer.Customization;
|
||||
|
||||
public record struct CustomizeValue(byte Value)
|
||||
{
|
||||
public static readonly CustomizeValue Zero = new(0);
|
||||
public static readonly CustomizeValue Max = new(0xFF);
|
||||
|
||||
public static CustomizeValue Bool(bool b)
|
||||
=> b ? Max : Zero;
|
||||
|
||||
public static explicit operator CustomizeValue(byte value)
|
||||
=> new(value);
|
||||
|
||||
public static CustomizeValue operator ++(CustomizeValue v)
|
||||
=> new(++v.Value);
|
||||
|
||||
public static CustomizeValue operator --(CustomizeValue v)
|
||||
=> new(--v.Value);
|
||||
|
||||
public static bool operator <(CustomizeValue v, int count)
|
||||
=> v.Value < count;
|
||||
|
||||
public static bool operator >(CustomizeValue v, int count)
|
||||
=> v.Value > count;
|
||||
|
||||
public static CustomizeValue operator +(CustomizeValue v, int rhs)
|
||||
=> new((byte)(v.Value + rhs));
|
||||
|
||||
public static CustomizeValue operator -(CustomizeValue v, int rhs)
|
||||
=> new((byte)(v.Value - rhs));
|
||||
|
||||
public override string ToString()
|
||||
=> Value.ToString();
|
||||
}
|
||||
|
|
@ -1,149 +0,0 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using Dalamud.Memory;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
namespace Glamourer.Customization;
|
||||
|
||||
[StructLayout(LayoutKind.Explicit, Size = Size)]
|
||||
public unsafe struct DatCharacterFile
|
||||
{
|
||||
public const int Size = 4 + 4 + 4 + 4 + CustomizeArray.Size + 2 + 4 + 41 * 4; // 212
|
||||
|
||||
[FieldOffset(0)]
|
||||
private fixed byte _data[Size];
|
||||
|
||||
[FieldOffset(0)]
|
||||
public readonly uint Magic = 0x2013FF14;
|
||||
|
||||
[FieldOffset(4)]
|
||||
public readonly uint Version = 0x05;
|
||||
|
||||
[FieldOffset(8)]
|
||||
private uint _checksum;
|
||||
|
||||
[FieldOffset(12)]
|
||||
private readonly uint _padding = 0;
|
||||
|
||||
[FieldOffset(16)]
|
||||
private CustomizeArray _customize;
|
||||
|
||||
[FieldOffset(16 + CustomizeArray.Size)]
|
||||
private ushort _voice;
|
||||
|
||||
[FieldOffset(16 + CustomizeArray.Size + 2)]
|
||||
private uint _timeStamp;
|
||||
|
||||
[FieldOffset(Size - 41 * 4)]
|
||||
private fixed byte _description[41 * 4];
|
||||
|
||||
public readonly void Write(Stream stream)
|
||||
{
|
||||
for (var i = 0; i < Size; ++i)
|
||||
stream.WriteByte(_data[i]);
|
||||
}
|
||||
|
||||
public static bool Read(Stream stream, out DatCharacterFile file)
|
||||
{
|
||||
if (stream.Length - stream.Position != Size)
|
||||
{
|
||||
file = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
file = new DatCharacterFile(stream);
|
||||
return true;
|
||||
}
|
||||
|
||||
private DatCharacterFile(Stream stream)
|
||||
{
|
||||
for (var i = 0; i < Size; ++i)
|
||||
_data[i] = (byte)stream.ReadByte();
|
||||
}
|
||||
|
||||
public DatCharacterFile(in Customize customize, byte voice, string text)
|
||||
{
|
||||
SetCustomize(customize);
|
||||
SetVoice(voice);
|
||||
SetTime(DateTimeOffset.UtcNow);
|
||||
SetDescription(text);
|
||||
_checksum = CalculateChecksum();
|
||||
}
|
||||
|
||||
public readonly uint CalculateChecksum()
|
||||
{
|
||||
var ret = 0u;
|
||||
for (var i = 16; i < Size; i++)
|
||||
ret ^= (uint)(_data[i] << ((i - 16) % 24));
|
||||
return ret;
|
||||
}
|
||||
|
||||
public readonly uint Checksum
|
||||
=> _checksum;
|
||||
|
||||
public Customize Customize
|
||||
{
|
||||
readonly get => new(_customize);
|
||||
set
|
||||
{
|
||||
SetCustomize(value);
|
||||
_checksum = CalculateChecksum();
|
||||
}
|
||||
}
|
||||
|
||||
public ushort Voice
|
||||
{
|
||||
readonly get => _voice;
|
||||
set
|
||||
{
|
||||
SetVoice(value);
|
||||
_checksum = CalculateChecksum();
|
||||
}
|
||||
}
|
||||
|
||||
public string Description
|
||||
{
|
||||
readonly get
|
||||
{
|
||||
fixed (byte* ptr = _description)
|
||||
{
|
||||
return MemoryHelper.ReadStringNullTerminated((nint)ptr);
|
||||
}
|
||||
}
|
||||
set
|
||||
{
|
||||
SetDescription(value);
|
||||
_checksum = CalculateChecksum();
|
||||
}
|
||||
}
|
||||
|
||||
public DateTimeOffset Time
|
||||
{
|
||||
readonly get => DateTimeOffset.FromUnixTimeSeconds(_timeStamp);
|
||||
set
|
||||
{
|
||||
SetTime(value);
|
||||
_checksum = CalculateChecksum();
|
||||
}
|
||||
}
|
||||
|
||||
private void SetTime(DateTimeOffset time)
|
||||
=> _timeStamp = (uint)time.ToUnixTimeSeconds();
|
||||
|
||||
private void SetCustomize(in Customize customize)
|
||||
=> _customize = customize.Data.Clone();
|
||||
|
||||
private void SetVoice(ushort voice)
|
||||
=> _voice = voice;
|
||||
|
||||
private void SetDescription(string text)
|
||||
{
|
||||
fixed (byte* ptr = _description)
|
||||
{
|
||||
var span = new Span<byte>(ptr, 41 * 4);
|
||||
Encoding.UTF8.GetBytes(text.AsSpan(0, Math.Min(40, text.Length)), span);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,88 +0,0 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Dalamud;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Glamourer.Structs;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
|
||||
namespace Glamourer;
|
||||
|
||||
public static class GameData
|
||||
{
|
||||
private static Dictionary<byte, Job>? _jobs;
|
||||
private static Dictionary<ushort, JobGroup>? _jobGroups;
|
||||
private static JobGroup[]? _allJobGroups;
|
||||
|
||||
public static IReadOnlyDictionary<byte, Job> Jobs(IDataManager dataManager)
|
||||
{
|
||||
if (_jobs != null)
|
||||
return _jobs;
|
||||
|
||||
var sheet = dataManager.GetExcelSheet<ClassJob>()!;
|
||||
_jobs = sheet.Where(j => j.Abbreviation.RawData.Length > 0).ToDictionary(j => (byte)j.RowId, j => new Job(j));
|
||||
return _jobs;
|
||||
}
|
||||
|
||||
public static IReadOnlyList<JobGroup> AllJobGroups(IDataManager dataManager)
|
||||
{
|
||||
if (_allJobGroups != null)
|
||||
return _allJobGroups;
|
||||
|
||||
var sheet = dataManager.GetExcelSheet<ClassJobCategory>()!;
|
||||
var jobs = dataManager.GetExcelSheet<ClassJob>(ClientLanguage.English)!;
|
||||
_allJobGroups = sheet.Select(j => new JobGroup(j, jobs)).ToArray();
|
||||
return _allJobGroups;
|
||||
}
|
||||
|
||||
public static IReadOnlyDictionary<ushort, JobGroup> JobGroups(IDataManager dataManager)
|
||||
{
|
||||
if (_jobGroups != null)
|
||||
return _jobGroups;
|
||||
|
||||
static bool ValidIndex(uint idx)
|
||||
{
|
||||
if (idx is > 0 and < 36)
|
||||
return true;
|
||||
|
||||
return idx switch
|
||||
{
|
||||
// Single jobs and big groups
|
||||
91 => true,
|
||||
92 => true,
|
||||
96 => true,
|
||||
98 => true,
|
||||
99 => true,
|
||||
111 => true,
|
||||
112 => true,
|
||||
129 => true,
|
||||
149 => true,
|
||||
150 => true,
|
||||
156 => true,
|
||||
157 => true,
|
||||
158 => true,
|
||||
159 => true,
|
||||
180 => true,
|
||||
181 => true,
|
||||
188 => true,
|
||||
189 => true,
|
||||
|
||||
// Class + Job
|
||||
38 => true,
|
||||
41 => true,
|
||||
44 => true,
|
||||
47 => true,
|
||||
50 => true,
|
||||
53 => true,
|
||||
55 => true,
|
||||
69 => true,
|
||||
68 => true,
|
||||
93 => true,
|
||||
_ => false,
|
||||
};
|
||||
}
|
||||
|
||||
_jobGroups = AllJobGroups(dataManager).Where(j => ValidIndex(j.Id))
|
||||
.ToDictionary(j => (ushort) j.Id, j => j);
|
||||
return _jobGroups;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net472</TargetFramework>
|
||||
<LangVersion>preview</LangVersion>
|
||||
<RootNamespace>Glamourer</RootNamespace>
|
||||
<AssemblyName>Glamourer.GameData</AssemblyName>
|
||||
<FileVersion>1.0.0.0</FileVersion>
|
||||
<AssemblyVersion>1.0.0.0</AssemblyVersion>
|
||||
<Company>SoftOtter</Company>
|
||||
<Product>Glamourer</Product>
|
||||
<Copyright>Copyright © 2020</Copyright>
|
||||
<Deterministic>true</Deterministic>
|
||||
<OutputType>Library</OutputType>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<Nullable>enable</Nullable>
|
||||
<OutputPath>bin\$(Configuration)\</OutputPath>
|
||||
<MSBuildWarningsAsMessages>$(MSBuildWarningsAsMessages);MSB3277</MSBuildWarningsAsMessages>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugType>full</DebugType>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<MSBuildWarningsAsMessages>$(MSBuildWarningsAsMessages);MSB3277</MSBuildWarningsAsMessages>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="Dalamud">
|
||||
<HintPath>$(DALAMUD_ROOT)\Dalamud.dll</HintPath>
|
||||
<HintPath>..\libs\Dalamud.dll</HintPath>
|
||||
<HintPath>$(AppData)\XIVLauncher\addon\Hooks\dev\Dalamud.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="Lumina">
|
||||
<HintPath>$(DALAMUD_ROOT)\Lumina.dll</HintPath>
|
||||
<HintPath>..\libs\Lumina.dll</HintPath>
|
||||
<HintPath>$(AppData)\XIVLauncher\addon\Hooks\dev\Lumina.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="Lumina.Excel">
|
||||
<HintPath>$(DALAMUD_ROOT)\Lumina.Excel.dll</HintPath>
|
||||
<HintPath>..\libs\Lumina.Excel.dll</HintPath>
|
||||
<HintPath>$(AppData)\XIVLauncher\addon\Hooks\dev\Lumina.Excel.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="Penumbra.GameData">
|
||||
<HintPath>..\..\Penumbra\Penumbra\bin\$(Configuration)\net472\Penumbra.GameData.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Util\" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0-windows</TargetFramework>
|
||||
<LangVersion>preview</LangVersion>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<RootNamespace>Glamourer</RootNamespace>
|
||||
<AssemblyName>Glamourer.GameData</AssemblyName>
|
||||
<FileVersion>1.0.0.0</FileVersion>
|
||||
<AssemblyVersion>1.0.0.0</AssemblyVersion>
|
||||
<Company>SoftOtter</Company>
|
||||
<Product>Glamourer</Product>
|
||||
<Copyright>Copyright © 2020</Copyright>
|
||||
<Deterministic>true</Deterministic>
|
||||
<OutputType>Library</OutputType>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<Nullable>enable</Nullable>
|
||||
<OutputPath>bin\$(Configuration)\</OutputPath>
|
||||
<MSBuildWarningsAsMessages>$(MSBuildWarningsAsMessages);MSB3277</MSBuildWarningsAsMessages>
|
||||
<ProduceReferenceAssembly>false</ProduceReferenceAssembly>
|
||||
<AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugType>full</DebugType>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<MSBuildWarningsAsMessages>$(MSBuildWarningsAsMessages);MSB3277</MSBuildWarningsAsMessages>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<DalamudLibPath>$(AppData)\XIVLauncher\addon\Hooks\dev\</DalamudLibPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Reference Include="Dalamud">
|
||||
<HintPath>$(DalamudLibPath)Dalamud.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="FFXIVClientStructs">
|
||||
<HintPath>$(DalamudLibPath)FFXIVClientStructs.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="Lumina">
|
||||
<HintPath>$(DalamudLibPath)Lumina.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="Lumina.Excel">
|
||||
<HintPath>$(DalamudLibPath)Lumina.Excel.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="Newtonsoft.Json">
|
||||
<HintPath>$(DalamudLibPath)Newtonsoft.Json.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="ImGuiScene">
|
||||
<HintPath>$(DalamudLibPath)ImGuiScene.dll</HintPath>
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Penumbra.GameData\Penumbra.GameData.csproj" />
|
||||
<ProjectReference Include="..\OtterGui\OtterGui.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
namespace Glamourer;
|
||||
|
||||
public static class Sigs
|
||||
{
|
||||
public const string ChangeJob = "48 89 5C 24 ?? 48 89 6C 24 ?? 48 89 74 24 ?? 57 41 56 41 57 48 83 EC ?? 80 61";
|
||||
public const string FlagSlotForUpdate = "48 89 5C 24 ?? 48 89 74 24 ?? 57 48 83 EC 20 8B DA 49 8B F0 48 8B F9 83 FA 0A";
|
||||
}
|
||||
|
|
@ -1,102 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Penumbra.GameData.Enums;
|
||||
|
||||
namespace Glamourer.Structs;
|
||||
|
||||
[Flags]
|
||||
public enum CrestFlag : ushort
|
||||
{
|
||||
OffHand = 0x0001,
|
||||
Head = 0x0002,
|
||||
Body = 0x0004,
|
||||
Hands = 0x0008,
|
||||
Legs = 0x0010,
|
||||
Feet = 0x0020,
|
||||
Ears = 0x0040,
|
||||
Neck = 0x0080,
|
||||
Wrists = 0x0100,
|
||||
RFinger = 0x0200,
|
||||
LFinger = 0x0400,
|
||||
MainHand = 0x0800,
|
||||
}
|
||||
|
||||
public enum CrestType : byte
|
||||
{
|
||||
None,
|
||||
Human,
|
||||
Mainhand,
|
||||
Offhand,
|
||||
};
|
||||
|
||||
public static class CrestExtensions
|
||||
{
|
||||
public const CrestFlag All = (CrestFlag)(((ulong)EquipFlag.Mainhand << 1) - 1);
|
||||
public const CrestFlag AllRelevant = CrestFlag.Head | CrestFlag.Body | CrestFlag.OffHand;
|
||||
|
||||
public static readonly IReadOnlyList<CrestFlag> AllRelevantSet = Enum.GetValues<CrestFlag>().Where(f => AllRelevant.HasFlag(f)).ToArray();
|
||||
|
||||
public static int ToInternalIndex(this CrestFlag flag)
|
||||
=> flag switch
|
||||
{
|
||||
CrestFlag.Head => 0,
|
||||
CrestFlag.Body => 1,
|
||||
CrestFlag.OffHand => 2,
|
||||
_ => -1,
|
||||
};
|
||||
|
||||
public static (CrestType Type, byte Index) ToIndex(this CrestFlag flag)
|
||||
=> flag switch
|
||||
{
|
||||
CrestFlag.Head => (CrestType.Human, 0),
|
||||
CrestFlag.Body => (CrestType.Human, 1),
|
||||
CrestFlag.Hands => (CrestType.Human, 2),
|
||||
CrestFlag.Legs => (CrestType.Human, 3),
|
||||
CrestFlag.Feet => (CrestType.Human, 4),
|
||||
CrestFlag.Ears => (CrestType.None, 0),
|
||||
CrestFlag.Neck => (CrestType.None, 0),
|
||||
CrestFlag.Wrists => (CrestType.None, 0),
|
||||
CrestFlag.RFinger => (CrestType.None, 0),
|
||||
CrestFlag.LFinger => (CrestType.None, 0),
|
||||
CrestFlag.MainHand => (CrestType.None, 0),
|
||||
CrestFlag.OffHand => (CrestType.Offhand, 0),
|
||||
_ => (CrestType.None, 0),
|
||||
};
|
||||
|
||||
public static CrestFlag ToCrestFlag(this EquipSlot slot)
|
||||
=> slot switch
|
||||
{
|
||||
EquipSlot.MainHand => CrestFlag.MainHand,
|
||||
EquipSlot.OffHand => CrestFlag.OffHand,
|
||||
EquipSlot.Head => CrestFlag.Head,
|
||||
EquipSlot.Body => CrestFlag.Body,
|
||||
EquipSlot.Hands => CrestFlag.Hands,
|
||||
EquipSlot.Legs => CrestFlag.Legs,
|
||||
EquipSlot.Feet => CrestFlag.Feet,
|
||||
EquipSlot.Ears => CrestFlag.Ears,
|
||||
EquipSlot.Neck => CrestFlag.Neck,
|
||||
EquipSlot.Wrists => CrestFlag.Wrists,
|
||||
EquipSlot.RFinger => CrestFlag.RFinger,
|
||||
EquipSlot.LFinger => CrestFlag.LFinger,
|
||||
_ => 0,
|
||||
};
|
||||
|
||||
public static string ToLabel(this CrestFlag flag)
|
||||
=> flag switch
|
||||
{
|
||||
CrestFlag.Head => "Head",
|
||||
CrestFlag.Body => "Chest",
|
||||
CrestFlag.Hands => "Gauntlets",
|
||||
CrestFlag.Legs => "Pants",
|
||||
CrestFlag.Feet => "Boot",
|
||||
CrestFlag.Ears => "Earrings",
|
||||
CrestFlag.Neck => "Necklace",
|
||||
CrestFlag.Wrists => "Bracelet",
|
||||
CrestFlag.RFinger => "Right Ring",
|
||||
CrestFlag.LFinger => "Left Ring",
|
||||
CrestFlag.MainHand => "Weapon",
|
||||
CrestFlag.OffHand => "Shield",
|
||||
_ => string.Empty,
|
||||
};
|
||||
}
|
||||
|
|
@ -1,93 +0,0 @@
|
|||
using System;
|
||||
using Penumbra.GameData.Enums;
|
||||
|
||||
namespace Glamourer.Structs;
|
||||
|
||||
[Flags]
|
||||
public enum EquipFlag : uint
|
||||
{
|
||||
Head = 0x00000001,
|
||||
Body = 0x00000002,
|
||||
Hands = 0x00000004,
|
||||
Legs = 0x00000008,
|
||||
Feet = 0x00000010,
|
||||
Ears = 0x00000020,
|
||||
Neck = 0x00000040,
|
||||
Wrist = 0x00000080,
|
||||
RFinger = 0x00000100,
|
||||
LFinger = 0x00000200,
|
||||
Mainhand = 0x00000400,
|
||||
Offhand = 0x00000800,
|
||||
HeadStain = 0x00001000,
|
||||
BodyStain = 0x00002000,
|
||||
HandsStain = 0x00004000,
|
||||
LegsStain = 0x00008000,
|
||||
FeetStain = 0x00010000,
|
||||
EarsStain = 0x00020000,
|
||||
NeckStain = 0x00040000,
|
||||
WristStain = 0x00080000,
|
||||
RFingerStain = 0x00100000,
|
||||
LFingerStain = 0x00200000,
|
||||
MainhandStain = 0x00400000,
|
||||
OffhandStain = 0x00800000,
|
||||
}
|
||||
|
||||
public static class EquipFlagExtensions
|
||||
{
|
||||
public const EquipFlag All = (EquipFlag)(((uint)EquipFlag.OffhandStain << 1) - 1);
|
||||
public const int NumEquipFlags = 24;
|
||||
|
||||
public static EquipFlag ToFlag(this EquipSlot slot)
|
||||
=> slot switch
|
||||
{
|
||||
EquipSlot.MainHand => EquipFlag.Mainhand,
|
||||
EquipSlot.OffHand => EquipFlag.Offhand,
|
||||
EquipSlot.Head => EquipFlag.Head,
|
||||
EquipSlot.Body => EquipFlag.Body,
|
||||
EquipSlot.Hands => EquipFlag.Hands,
|
||||
EquipSlot.Legs => EquipFlag.Legs,
|
||||
EquipSlot.Feet => EquipFlag.Feet,
|
||||
EquipSlot.Ears => EquipFlag.Ears,
|
||||
EquipSlot.Neck => EquipFlag.Neck,
|
||||
EquipSlot.Wrists => EquipFlag.Wrist,
|
||||
EquipSlot.RFinger => EquipFlag.RFinger,
|
||||
EquipSlot.LFinger => EquipFlag.LFinger,
|
||||
_ => 0,
|
||||
};
|
||||
|
||||
public static EquipFlag ToStainFlag(this EquipSlot slot)
|
||||
=> slot switch
|
||||
{
|
||||
EquipSlot.MainHand => EquipFlag.MainhandStain,
|
||||
EquipSlot.OffHand => EquipFlag.OffhandStain,
|
||||
EquipSlot.Head => EquipFlag.HeadStain,
|
||||
EquipSlot.Body => EquipFlag.BodyStain,
|
||||
EquipSlot.Hands => EquipFlag.HandsStain,
|
||||
EquipSlot.Legs => EquipFlag.LegsStain,
|
||||
EquipSlot.Feet => EquipFlag.FeetStain,
|
||||
EquipSlot.Ears => EquipFlag.EarsStain,
|
||||
EquipSlot.Neck => EquipFlag.NeckStain,
|
||||
EquipSlot.Wrists => EquipFlag.WristStain,
|
||||
EquipSlot.RFinger => EquipFlag.RFingerStain,
|
||||
EquipSlot.LFinger => EquipFlag.LFingerStain,
|
||||
_ => 0,
|
||||
};
|
||||
|
||||
public static EquipFlag ToBothFlags(this EquipSlot slot)
|
||||
=> slot switch
|
||||
{
|
||||
EquipSlot.MainHand => EquipFlag.Mainhand | EquipFlag.MainhandStain,
|
||||
EquipSlot.OffHand => EquipFlag.Offhand | EquipFlag.OffhandStain,
|
||||
EquipSlot.Head => EquipFlag.Head | EquipFlag.HeadStain,
|
||||
EquipSlot.Body => EquipFlag.Body | EquipFlag.BodyStain,
|
||||
EquipSlot.Hands => EquipFlag.Hands | EquipFlag.HandsStain,
|
||||
EquipSlot.Legs => EquipFlag.Legs | EquipFlag.LegsStain,
|
||||
EquipSlot.Feet => EquipFlag.Feet | EquipFlag.FeetStain,
|
||||
EquipSlot.Ears => EquipFlag.Ears | EquipFlag.EarsStain,
|
||||
EquipSlot.Neck => EquipFlag.Neck | EquipFlag.NeckStain,
|
||||
EquipSlot.Wrists => EquipFlag.Wrist | EquipFlag.WristStain,
|
||||
EquipSlot.RFinger => EquipFlag.RFinger | EquipFlag.RFingerStain,
|
||||
EquipSlot.LFinger => EquipFlag.LFinger | EquipFlag.LFingerStain,
|
||||
_ => 0,
|
||||
};
|
||||
}
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
using Dalamud.Utility;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
|
||||
namespace Glamourer.Structs;
|
||||
|
||||
// A struct containing the different jobs the game supports.
|
||||
// Also contains the jobs Name and Abbreviation as strings.
|
||||
public readonly struct Job
|
||||
{
|
||||
public readonly string Name;
|
||||
public readonly string Abbreviation;
|
||||
public readonly ClassJob Base;
|
||||
|
||||
public uint Id
|
||||
=> Base.RowId;
|
||||
|
||||
public JobFlag Flag
|
||||
=> (JobFlag)(1ul << (int)Base.RowId);
|
||||
|
||||
public Job(ClassJob job)
|
||||
{
|
||||
Base = job;
|
||||
Name = job.Name.ToDalamudString().ToString();
|
||||
Abbreviation = job.Abbreviation.ToDalamudString().ToString();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
=> Name;
|
||||
}
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using Lumina.Excel;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
|
||||
namespace Glamourer.Structs;
|
||||
|
||||
[Flags]
|
||||
public enum JobFlag : ulong
|
||||
{ }
|
||||
|
||||
// The game specifies different job groups that can contain specific jobs or not.
|
||||
public readonly struct JobGroup
|
||||
{
|
||||
public readonly string Name;
|
||||
public readonly int Count;
|
||||
public readonly uint Id;
|
||||
private readonly JobFlag _flags;
|
||||
|
||||
// Create a job group from a given category and the ClassJob sheet.
|
||||
// It looks up the different jobs contained in the category and sets the flags appropriately.
|
||||
public JobGroup(ClassJobCategory group, ExcelSheet<ClassJob> jobs)
|
||||
{
|
||||
Count = 0;
|
||||
_flags = 0ul;
|
||||
Id = group.RowId;
|
||||
Name = group.Name.ToString();
|
||||
|
||||
Debug.Assert(jobs.RowCount < 64, $"Number of Jobs exceeded 63 ({jobs.RowCount}).");
|
||||
foreach (var job in jobs)
|
||||
{
|
||||
var abbr = job.Abbreviation.ToString();
|
||||
if (abbr.Length == 0)
|
||||
continue;
|
||||
|
||||
var prop = group.GetType().GetProperty(abbr);
|
||||
Debug.Assert(prop != null, $"Could not get job abbreviation {abbr} property.");
|
||||
|
||||
if (!(bool)prop.GetValue(group)!)
|
||||
continue;
|
||||
|
||||
++Count;
|
||||
_flags |= (JobFlag)(1ul << (int)job.RowId);
|
||||
}
|
||||
}
|
||||
|
||||
// Check if a job is contained inside this group.
|
||||
public bool Fits(Job job)
|
||||
=> _flags.HasFlag(job.Flag);
|
||||
|
||||
// Check if any of the jobs in the given flags fit this group.
|
||||
public bool Fits(JobFlag flag)
|
||||
=> (_flags & flag) != 0;
|
||||
|
||||
// Check if a job is contained inside this group.
|
||||
public bool Fits(uint jobId)
|
||||
{
|
||||
var flag = (JobFlag)(1ul << (int)jobId);
|
||||
return _flags.HasFlag(flag);
|
||||
}
|
||||
}
|
||||
|
|
@ -9,8 +9,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
|
|||
repo.json = repo.json
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Glamourer.GameData", "Glamourer.GameData\Glamourer.GameData.csproj", "{51F4DDB0-1FA0-4629-9CFE-C55B6062907B}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Glamourer", "Glamourer\Glamourer.csproj", "{01EB903D-871F-4285-A8CF-6486561D5B5B}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Penumbra.Api", "Penumbra.Api\Penumbra.Api.csproj", "{29C589ED-7AF1-4DE9-82EF-33EBEF19AAFA}"
|
||||
|
|
@ -27,10 +25,6 @@ Global
|
|||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{51F4DDB0-1FA0-4629-9CFE-C55B6062907B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{51F4DDB0-1FA0-4629-9CFE-C55B6062907B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{51F4DDB0-1FA0-4629-9CFE-C55B6062907B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{51F4DDB0-1FA0-4629-9CFE-C55B6062907B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{01EB903D-871F-4285-A8CF-6486561D5B5B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{01EB903D-871F-4285-A8CF-6486561D5B5B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{01EB903D-871F-4285-A8CF-6486561D5B5B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
|
|
|
|||
|
|
@ -1,11 +1,7 @@
|
|||
using System.Buffers.Text;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Dalamud.Game.ClientState.Objects.Types;
|
||||
using Dalamud.Plugin;
|
||||
using Glamourer.Customization;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.Structs;
|
||||
using Penumbra.Api.Helpers;
|
||||
using Penumbra.GameData.Actors;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
using System;
|
||||
using Glamourer.Customization;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.Interop.Structs;
|
||||
using Glamourer.State;
|
||||
using Glamourer.Structs;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
namespace Glamourer.Automation;
|
||||
|
||||
|
|
@ -74,7 +74,7 @@ public class AutoDesign
|
|||
var ret = new JObject
|
||||
{
|
||||
["Gearset"] = GearsetIndex,
|
||||
["JobGroup"] = Jobs.Id,
|
||||
["JobGroup"] = Jobs.Id.Id,
|
||||
};
|
||||
|
||||
return ret;
|
||||
|
|
|
|||
|
|
@ -4,14 +4,12 @@ using System.Diagnostics.CodeAnalysis;
|
|||
using System.Linq;
|
||||
using Dalamud.Plugin.Services;
|
||||
using FFXIVClientStructs.FFXIV.Client.UI.Misc;
|
||||
using Glamourer.Customization;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.Events;
|
||||
using Glamourer.Interop;
|
||||
using Glamourer.Interop.Structs;
|
||||
using Glamourer.Services;
|
||||
using Glamourer.State;
|
||||
using Glamourer.Structs;
|
||||
using Glamourer.Unlocks;
|
||||
using OtterGui.Classes;
|
||||
using Penumbra.GameData.Actors;
|
||||
|
|
@ -209,7 +207,7 @@ public class AutoDesignApplier : IDisposable
|
|||
if (!GetPlayerSet(id, out var set))
|
||||
{
|
||||
if (_state.TryGetValue(id, out var s))
|
||||
s.LastJob = (byte)newJob.Id;
|
||||
s.LastJob = newJob.Id;
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ using Glamourer.Designs;
|
|||
using Glamourer.Events;
|
||||
using Glamourer.Interop;
|
||||
using Glamourer.Services;
|
||||
using Glamourer.Structs;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using OtterGui;
|
||||
|
|
@ -516,7 +515,7 @@ public class AutoDesignManager : ISavable, IReadOnlyList<AutoDesignSet>, IDispos
|
|||
var jobs = conditions["JobGroup"]?.ToObject<int>() ?? -1;
|
||||
if (jobs >= 0)
|
||||
{
|
||||
if (!_jobs.JobGroups.TryGetValue((ushort)jobs, out var jobGroup))
|
||||
if (!_jobs.JobGroups.TryGetValue((JobGroupId)jobs, out var jobGroup))
|
||||
{
|
||||
Glamourer.Messager.NotificationMessage(
|
||||
$"Error parsing automatically applied design for set {setName}: The job condition {jobs} does not exist.",
|
||||
|
|
|
|||
|
|
@ -3,37 +3,30 @@ using System.Linq;
|
|||
using Dalamud.Interface.Internal.Notifications;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.Interop;
|
||||
using Glamourer.Services;
|
||||
using Glamourer.Structs;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using OtterGui.Classes;
|
||||
using Penumbra.GameData.Actors;
|
||||
using Penumbra.GameData.Structs;
|
||||
using Penumbra.String;
|
||||
|
||||
namespace Glamourer.Automation;
|
||||
|
||||
public class FixedDesignMigrator
|
||||
public class FixedDesignMigrator(JobService jobs)
|
||||
{
|
||||
private readonly JobService _jobs;
|
||||
private List<(string Name, List<(string, JobGroup, bool)> Data)>? _migratedData;
|
||||
|
||||
public FixedDesignMigrator(JobService jobs)
|
||||
=> _jobs = jobs;
|
||||
private List<(string Name, List<(string, JobGroup, bool)> Data)>? _migratedData;
|
||||
|
||||
public void ConsumeMigratedData(ActorManager actors, DesignFileSystem designFileSystem, AutoDesignManager autoManager)
|
||||
{
|
||||
if (_migratedData == null)
|
||||
return;
|
||||
|
||||
foreach (var data in _migratedData)
|
||||
foreach (var (name, data) in _migratedData)
|
||||
{
|
||||
var allEnabled = true;
|
||||
var name = data.Name;
|
||||
if (autoManager.Any(d => name == d.Name))
|
||||
continue;
|
||||
|
||||
var id = ActorIdentifier.Invalid;
|
||||
if (ByteString.FromString(data.Name, out var byteString, false))
|
||||
if (ByteString.FromString(name, out var byteString))
|
||||
{
|
||||
id = actors.CreatePlayer(byteString, ushort.MaxValue);
|
||||
if (!id.IsValid)
|
||||
|
|
@ -46,16 +39,15 @@ public class FixedDesignMigrator
|
|||
id = actors.CreatePlayer(byteString, actors.Data.Worlds.First().Key);
|
||||
if (!id.IsValid)
|
||||
{
|
||||
Glamourer.Messager.NotificationMessage($"Could not migrate fixed design {data.Name}.", NotificationType.Error);
|
||||
allEnabled = false;
|
||||
Glamourer.Messager.NotificationMessage($"Could not migrate fixed design {name}.", NotificationType.Error);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
autoManager.AddDesignSet(name, id);
|
||||
autoManager.SetState(autoManager.Count - 1, allEnabled);
|
||||
autoManager.SetState(autoManager.Count - 1, true);
|
||||
var set = autoManager[^1];
|
||||
foreach (var design in data.Data.AsEnumerable().Reverse())
|
||||
foreach (var design in data.AsEnumerable().Reverse())
|
||||
{
|
||||
if (!designFileSystem.Find(design.Item1, out var child) || child is not DesignFileSystem.Leaf leaf)
|
||||
{
|
||||
|
|
@ -96,7 +88,7 @@ public class FixedDesignMigrator
|
|||
}
|
||||
|
||||
var job = obj["JobGroups"]?.ToObject<int>() ?? -1;
|
||||
if (job < 0 || !_jobs.JobGroups.TryGetValue((ushort)job, out var group))
|
||||
if (job < 0 || !jobs.JobGroups.TryGetValue((JobGroupId)job, out var group))
|
||||
{
|
||||
Glamourer.Messager.NotificationMessage("Could not semi-migrate fixed design: Invalid job group specified.",
|
||||
NotificationType.Warning);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
using Dalamud.Interface.Internal.Notifications;
|
||||
using Glamourer.Customization;
|
||||
using Glamourer.GameData;
|
||||
using Glamourer.Services;
|
||||
using Glamourer.Structs;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using OtterGui.Classes;
|
||||
using Penumbra.GameData.Enums;
|
||||
|
|
@ -85,12 +84,12 @@ public class DesignBase
|
|||
internal CrestFlag ApplyCrest = CrestExtensions.AllRelevant;
|
||||
private DesignFlags _designFlags = DesignFlags.ApplyHatVisible | DesignFlags.ApplyVisorState | DesignFlags.ApplyWeaponVisible;
|
||||
|
||||
public bool SetCustomize(CustomizationService customizationService, Customize customize)
|
||||
public bool SetCustomize(CustomizationService customizationService, CustomizeArray customize)
|
||||
{
|
||||
if (customize.Equals(_designData.Customize))
|
||||
return false;
|
||||
|
||||
_designData.Customize.Load(customize);
|
||||
_designData.Customize = customize;
|
||||
CustomizationSet = customizationService.Service.GetList(customize.Clan, customize.Gender);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -443,7 +442,7 @@ public class DesignBase
|
|||
{
|
||||
design._designData.ModelId = 0;
|
||||
design._designData.IsHuman = true;
|
||||
design.SetCustomize(customizations, Customize.Default);
|
||||
design.SetCustomize(customizations, CustomizeArray.Default);
|
||||
Glamourer.Messager.NotificationMessage("The loaded design does not contain any customization data, reset to default.",
|
||||
NotificationType.Warning);
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
using System;
|
||||
using Glamourer.Customization;
|
||||
using Glamourer.Services;
|
||||
using Glamourer.Structs;
|
||||
using OtterGui;
|
||||
using Penumbra.GameData.DataContainers;
|
||||
using Penumbra.GameData.Enums;
|
||||
|
|
@ -62,7 +60,7 @@ public class DesignBase64Migration
|
|||
data.SetHatVisible((bytes[90] & 0x01) == 0);
|
||||
data.SetVisor((bytes[90] & 0x10) != 0);
|
||||
data.SetWeaponVisible((bytes[90] & 0x02) == 0);
|
||||
data.ModelId = (uint)bytes[91] | ((uint)bytes[92] << 8) | ((uint)bytes[93] << 16) | ((uint)bytes[94] << 24);
|
||||
data.ModelId = bytes[91] | ((uint)bytes[92] << 8) | ((uint)bytes[93] << 16) | ((uint)bytes[94] << 24);
|
||||
break;
|
||||
}
|
||||
case 5:
|
||||
|
|
@ -73,7 +71,7 @@ public class DesignBase64Migration
|
|||
data.SetHatVisible((bytes[90] & 0x01) == 0);
|
||||
data.SetVisor((bytes[90] & 0x10) != 0);
|
||||
data.SetWeaponVisible((bytes[90] & 0x02) == 0);
|
||||
data.ModelId = (uint)bytes[91] | ((uint)bytes[92] << 8) | ((uint)bytes[93] << 16) | ((uint)bytes[94] << 24);
|
||||
data.ModelId = bytes[91] | ((uint)bytes[92] << 8) | ((uint)bytes[93] << 16) | ((uint)bytes[94] << 24);
|
||||
break;
|
||||
default: throw new Exception($"Can not parse Base64 string into design for migration:\n\tInvalid Version {bytes[0]}.");
|
||||
}
|
||||
|
|
@ -102,11 +100,11 @@ public class DesignBase64Migration
|
|||
|
||||
if (!humans.IsHuman(data.ModelId))
|
||||
{
|
||||
data.LoadNonHuman(data.ModelId, *(Customize*)(ptr + 4), (nint)eq);
|
||||
data.LoadNonHuman(data.ModelId, *(CustomizeArray*)(ptr + 4), (nint)eq);
|
||||
return data;
|
||||
}
|
||||
|
||||
data.Customize.Load(*(Customize*)(ptr + 4));
|
||||
data.Customize = *(CustomizeArray*)(ptr + 4);
|
||||
foreach (var (slot, idx) in EquipSlotExtensions.EqdpSlots.WithIndex())
|
||||
{
|
||||
var mdl = eq[idx];
|
||||
|
|
@ -187,7 +185,7 @@ public class DesignBase64Migration
|
|||
| (equipFlags.HasFlag(EquipFlag.Wrist) ? 0x02 : 0)
|
||||
| (equipFlags.HasFlag(EquipFlag.RFinger) ? 0x04 : 0)
|
||||
| (equipFlags.HasFlag(EquipFlag.LFinger) ? 0x08 : 0));
|
||||
save.Customize.Write((nint)data + 4);
|
||||
save.Customize.Write(data + 4);
|
||||
((CharacterWeapon*)(data + 30))[0] = save.Item(EquipSlot.MainHand).Weapon(save.Stain(EquipSlot.MainHand));
|
||||
((CharacterWeapon*)(data + 30))[1] = save.Item(EquipSlot.OffHand).Weapon(save.Stain(EquipSlot.OffHand));
|
||||
foreach (var slot in EquipSlotExtensions.EqdpSlots)
|
||||
|
|
|
|||
|
|
@ -2,10 +2,8 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
using Glamourer.Customization;
|
||||
using Glamourer.Services;
|
||||
using Glamourer.State;
|
||||
using Glamourer.Structs;
|
||||
using Glamourer.Utility;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
|
@ -165,7 +163,7 @@ public class DesignConverter(ItemManager _items, DesignManager _designs, Customi
|
|||
yield return (slot, item, armor.Stain);
|
||||
}
|
||||
|
||||
var mh = _items.Identify(EquipSlot.MainHand, mainhand.Skeleton, mainhand.Weapon, mainhand.Variant, FullEquipType.Unknown);
|
||||
var mh = _items.Identify(EquipSlot.MainHand, mainhand.Skeleton, mainhand.Weapon, mainhand.Variant);
|
||||
if (!mh.Valid)
|
||||
{
|
||||
Glamourer.Log.Warning($"Appearance data {mainhand} for mainhand weapon invalid, item could not be identified.");
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using Glamourer.Customization;
|
||||
using Glamourer.Services;
|
||||
using Glamourer.Structs;
|
||||
using OtterGui.Classes;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
|
@ -12,30 +10,30 @@ namespace Glamourer.Designs;
|
|||
|
||||
public unsafe struct DesignData
|
||||
{
|
||||
private string _nameHead = string.Empty;
|
||||
private string _nameBody = string.Empty;
|
||||
private string _nameHands = string.Empty;
|
||||
private string _nameLegs = string.Empty;
|
||||
private string _nameFeet = string.Empty;
|
||||
private string _nameEars = string.Empty;
|
||||
private string _nameNeck = string.Empty;
|
||||
private string _nameWrists = string.Empty;
|
||||
private string _nameRFinger = string.Empty;
|
||||
private string _nameLFinger = string.Empty;
|
||||
private string _nameMainhand = string.Empty;
|
||||
private string _nameOffhand = string.Empty;
|
||||
private fixed uint _itemIds[12];
|
||||
private fixed ushort _iconIds[12];
|
||||
private fixed byte _equipmentBytes[48];
|
||||
public Customize Customize = Customize.Default;
|
||||
public uint ModelId;
|
||||
public CrestFlag CrestVisibility;
|
||||
private SecondaryId _secondaryMainhand;
|
||||
private SecondaryId _secondaryOffhand;
|
||||
private FullEquipType _typeMainhand;
|
||||
private FullEquipType _typeOffhand;
|
||||
private byte _states;
|
||||
public bool IsHuman = true;
|
||||
private string _nameHead = string.Empty;
|
||||
private string _nameBody = string.Empty;
|
||||
private string _nameHands = string.Empty;
|
||||
private string _nameLegs = string.Empty;
|
||||
private string _nameFeet = string.Empty;
|
||||
private string _nameEars = string.Empty;
|
||||
private string _nameNeck = string.Empty;
|
||||
private string _nameWrists = string.Empty;
|
||||
private string _nameRFinger = string.Empty;
|
||||
private string _nameLFinger = string.Empty;
|
||||
private string _nameMainhand = string.Empty;
|
||||
private string _nameOffhand = string.Empty;
|
||||
private fixed uint _itemIds[12];
|
||||
private fixed ushort _iconIds[12];
|
||||
private fixed byte _equipmentBytes[48];
|
||||
public CustomizeArray Customize = CustomizeArray.Default;
|
||||
public uint ModelId;
|
||||
public CrestFlag CrestVisibility;
|
||||
private SecondaryId _secondaryMainhand;
|
||||
private SecondaryId _secondaryOffhand;
|
||||
private FullEquipType _typeMainhand;
|
||||
private FullEquipType _typeOffhand;
|
||||
private byte _states;
|
||||
public bool IsHuman = true;
|
||||
|
||||
public DesignData()
|
||||
{ }
|
||||
|
|
@ -255,11 +253,11 @@ public unsafe struct DesignData
|
|||
}
|
||||
|
||||
|
||||
public bool LoadNonHuman(uint modelId, Customize customize, nint equipData)
|
||||
public bool LoadNonHuman(uint modelId, CustomizeArray customize, nint equipData)
|
||||
{
|
||||
ModelId = modelId;
|
||||
IsHuman = false;
|
||||
Customize.Load(customize);
|
||||
Customize.Read(customize.Data);
|
||||
fixed (byte* ptr = _equipmentBytes)
|
||||
{
|
||||
MemoryUtility.MemCpyUnchecked(ptr, (byte*)equipData, 40);
|
||||
|
|
@ -294,7 +292,7 @@ public unsafe struct DesignData
|
|||
public readonly byte[] GetCustomizeBytes()
|
||||
{
|
||||
var ret = new byte[CustomizeArray.Size];
|
||||
fixed (byte* retPtr = ret, inPtr = Customize.Data.Data)
|
||||
fixed (byte* retPtr = ret, inPtr = Customize.Data)
|
||||
{
|
||||
MemoryUtility.MemCpyUnchecked(retPtr, inPtr, ret.Length);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,12 +3,10 @@ using System.Collections.Generic;
|
|||
using System.IO;
|
||||
using System.Linq;
|
||||
using Dalamud.Utility;
|
||||
using Glamourer.Customization;
|
||||
using Glamourer.Events;
|
||||
using Glamourer.Interop.Penumbra;
|
||||
using Glamourer.Services;
|
||||
using Glamourer.State;
|
||||
using Glamourer.Structs;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using OtterGui;
|
||||
|
|
@ -25,8 +23,8 @@ public class DesignManager
|
|||
private readonly HumanModelList _humans;
|
||||
private readonly SaveService _saveService;
|
||||
private readonly DesignChanged _event;
|
||||
private readonly List<Design> _designs = new();
|
||||
private readonly Dictionary<Guid, DesignData> _undoStore = new();
|
||||
private readonly List<Design> _designs = [];
|
||||
private readonly Dictionary<Guid, DesignData> _undoStore = [];
|
||||
|
||||
public IReadOnlyList<Design> Designs
|
||||
=> _designs;
|
||||
|
|
@ -298,7 +296,7 @@ public class DesignManager
|
|||
return;
|
||||
case CustomizeIndex.Clan:
|
||||
{
|
||||
var customize = new Customize(design.DesignData.Customize.Data.Clone());
|
||||
var customize = design.DesignData.Customize;
|
||||
if (_customizations.ChangeClan(ref customize, (SubRace)value.Value) == 0)
|
||||
return;
|
||||
if (!design.SetCustomize(_customizations, customize))
|
||||
|
|
@ -308,7 +306,7 @@ public class DesignManager
|
|||
}
|
||||
case CustomizeIndex.Gender:
|
||||
{
|
||||
var customize = new Customize(design.DesignData.Customize.Data.Clone());
|
||||
var customize = design.DesignData.Customize;
|
||||
if (_customizations.ChangeGender(ref customize, (Gender)(value.Value + 1)) == 0)
|
||||
return;
|
||||
if (!design.SetCustomize(_customizations, customize))
|
||||
|
|
|
|||
|
|
@ -2,9 +2,11 @@
|
|||
using Lumina.Excel;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
|
||||
namespace Glamourer.Customization;
|
||||
namespace Glamourer.GameData;
|
||||
|
||||
// A custom version of CharaMakeParams that is easier to parse.
|
||||
/// <summary>
|
||||
/// A custom version of CharaMakeParams that is easier to parse.
|
||||
/// </summary>
|
||||
[Sheet("CharaMakeParams")]
|
||||
public class CharaMakeParams : ExcelRow
|
||||
{
|
||||
|
|
@ -64,7 +66,7 @@ public class CharaMakeParams : ExcelRow
|
|||
Race = new LazyRow<Race>(gameData, parser.ReadColumn<uint>(0), language);
|
||||
Tribe = new LazyRow<Tribe>(gameData, parser.ReadColumn<uint>(1), language);
|
||||
Gender = parser.ReadColumn<sbyte>(2);
|
||||
var currentOffset = 0;
|
||||
int currentOffset;
|
||||
for (var i = 0; i < NumMenus; ++i)
|
||||
{
|
||||
currentOffset = 3 + i;
|
||||
50
Glamourer/GameData/ColorParameters.cs
Normal file
50
Glamourer/GameData/ColorParameters.cs
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Penumbra.String.Functions;
|
||||
|
||||
namespace Glamourer.GameData;
|
||||
|
||||
public class ColorParameters : IReadOnlyList<uint>
|
||||
{
|
||||
private readonly uint[] _rgbaColors;
|
||||
|
||||
public ReadOnlySpan<uint> GetSlice(int offset, int count)
|
||||
=> _rgbaColors.AsSpan(offset, count);
|
||||
|
||||
public unsafe ColorParameters(IDataManager gameData, IPluginLog log)
|
||||
{
|
||||
try
|
||||
{
|
||||
var file = gameData.GetFile("chara/xls/charamake/human.cmp")!;
|
||||
_rgbaColors = new uint[file.Data.Length >> 2];
|
||||
fixed (byte* ptr1 = file.Data)
|
||||
{
|
||||
fixed (uint* ptr2 = _rgbaColors)
|
||||
{
|
||||
MemoryUtility.MemCpyUnchecked(ptr2, ptr1, file.Data.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
log.Error("READ THIS\n======== Could not obtain the human.cmp file which is necessary for color sets.\n"
|
||||
+ "======== This usually indicates an error with your index files caused by TexTools modifications.\n"
|
||||
+ "======== If you have used TexTools before, you will probably need to start over in it to use Glamourer.", e);
|
||||
_rgbaColors = Array.Empty<uint>();
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerator<uint> GetEnumerator()
|
||||
=> (IEnumerator<uint>)_rgbaColors.GetEnumerator();
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
=> GetEnumerator();
|
||||
|
||||
public int Count
|
||||
=> _rgbaColors.Length;
|
||||
|
||||
public uint this[int index]
|
||||
=> _rgbaColors[index];
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
namespace Glamourer.Customization;
|
||||
namespace Glamourer.GameData;
|
||||
|
||||
// Localization from the game files directly.
|
||||
/// <summary> For localization from the game files directly. </summary>
|
||||
public enum CustomName
|
||||
{
|
||||
MidlanderM,
|
||||
|
|
@ -3,7 +3,7 @@ using Dalamud.Interface.Internal;
|
|||
using Dalamud.Plugin.Services;
|
||||
using Penumbra.GameData.Enums;
|
||||
|
||||
namespace Glamourer.Customization;
|
||||
namespace Glamourer.GameData;
|
||||
|
||||
public class CustomizationManager : ICustomizationManager
|
||||
{
|
||||
|
|
@ -1,12 +1,14 @@
|
|||
using Penumbra.GameData.Enums;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
namespace Glamourer.Customization;
|
||||
namespace Glamourer.GameData;
|
||||
|
||||
public static class CustomizationNpcOptions
|
||||
{
|
||||
public static Dictionary<(SubRace, Gender), IReadOnlyList<(CustomizeIndex, CustomizeValue)>> CreateNpcData(CustomizationSet[] sets, NpcCustomizeSet npcCustomizeSet)
|
||||
public static Dictionary<(SubRace, Gender), IReadOnlyList<(CustomizeIndex, CustomizeValue)>> CreateNpcData(CustomizationSet[] sets,
|
||||
NpcCustomizeSet npcCustomizeSet)
|
||||
{
|
||||
var dict = new Dictionary<(SubRace, Gender), HashSet<(CustomizeIndex, CustomizeValue)>>();
|
||||
var customizeIndices = new[]
|
||||
|
|
@ -10,9 +10,10 @@ using Lumina.Excel;
|
|||
using Lumina.Excel.GeneratedSheets;
|
||||
using OtterGui.Classes;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
using Race = Penumbra.GameData.Enums.Race;
|
||||
|
||||
namespace Glamourer.Customization;
|
||||
namespace Glamourer.GameData;
|
||||
|
||||
// Generate everything about customization per tribe and gender.
|
||||
public partial class CustomizationOptions
|
||||
|
|
@ -66,7 +67,7 @@ public partial class CustomizationOptions
|
|||
{
|
||||
var tmp = new TemporaryData(gameData, this, log);
|
||||
_icons = new IconStorage(textures, gameData);
|
||||
SetNames(gameData, tmp);
|
||||
SetNames(gameData);
|
||||
foreach (var race in Clans)
|
||||
{
|
||||
foreach (var gender in Genders)
|
||||
|
|
@ -79,7 +80,7 @@ public partial class CustomizationOptions
|
|||
// Obtain localized names of customization options and race names from the game data.
|
||||
private readonly string[] _names = new string[Enum.GetValues<CustomName>().Length];
|
||||
|
||||
private void SetNames(IDataManager gameData, TemporaryData tmp)
|
||||
private void SetNames(IDataManager gameData)
|
||||
{
|
||||
var subRace = gameData.GetExcelSheet<Tribe>()!;
|
||||
|
||||
|
|
@ -122,9 +123,6 @@ public partial class CustomizationOptions
|
|||
|
||||
private class TemporaryData
|
||||
{
|
||||
public bool Valid
|
||||
=> _cmpFile.Valid;
|
||||
|
||||
public CustomizationSet GetSet(SubRace race, Gender gender)
|
||||
{
|
||||
var (skin, hair) = GetColors(race, gender);
|
||||
|
|
@ -177,10 +175,8 @@ public partial class CustomizationOptions
|
|||
public TemporaryData(IDataManager gameData, CustomizationOptions options, IPluginLog log)
|
||||
{
|
||||
_options = options;
|
||||
_cmpFile = new CmpFile(gameData, log);
|
||||
_cmpFile = new ColorParameters(gameData, log);
|
||||
_customizeSheet = gameData.GetExcelSheet<CharaMakeCustomize>(ClientLanguage.English)!;
|
||||
_bnpcCustomize = gameData.GetExcelSheet<BNpcCustomize>(ClientLanguage.English)!;
|
||||
_enpcBase = gameData.GetExcelSheet<ENpcBase>(ClientLanguage.English)!;
|
||||
Lobby = gameData.GetExcelSheet<Lobby>(ClientLanguage.English)!;
|
||||
var tmp = gameData.Excel.GetType().GetMethod("GetSheet", BindingFlags.Instance | BindingFlags.NonPublic)?
|
||||
.MakeGenericMethod(typeof(CharaMakeParams)).Invoke(gameData.Excel, new object?[]
|
||||
|
|
@ -204,10 +200,8 @@ public partial class CustomizationOptions
|
|||
private readonly ExcelSheet<CharaMakeCustomize> _customizeSheet;
|
||||
private readonly ExcelSheet<CharaMakeParams> _listSheet;
|
||||
private readonly ExcelSheet<HairMakeType> _hairSheet;
|
||||
private readonly ExcelSheet<BNpcCustomize> _bnpcCustomize;
|
||||
private readonly ExcelSheet<ENpcBase> _enpcBase;
|
||||
public readonly ExcelSheet<Lobby> Lobby;
|
||||
private readonly CmpFile _cmpFile;
|
||||
private readonly ColorParameters _cmpFile;
|
||||
|
||||
// Those values are shared between all races.
|
||||
private readonly CustomizeData[] _highlightPicker;
|
||||
|
|
@ -222,9 +216,17 @@ public partial class CustomizationOptions
|
|||
|
||||
|
||||
private CustomizeData[] CreateColorPicker(CustomizeIndex index, int offset, int num, bool light = false)
|
||||
=> _cmpFile.GetSlice(offset, num)
|
||||
.Select((c, i) => new CustomizeData(index, (CustomizeValue)(light ? 128 + i : 0 + i), c, (ushort)(offset + i)))
|
||||
.ToArray();
|
||||
{
|
||||
var ret = new CustomizeData[num];
|
||||
var idx = 0;
|
||||
foreach (var value in _cmpFile.GetSlice(offset, num))
|
||||
{
|
||||
ret[idx] = new CustomizeData(index, (CustomizeValue)(light ? 128 + idx : idx), value, (ushort)(offset + idx));
|
||||
++idx;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
private void SetHairByFace(CustomizationSet set)
|
||||
|
|
@ -299,15 +301,9 @@ public partial class CustomizationOptions
|
|||
// Set customizations available if they have any options.
|
||||
private static void SetAvailability(CustomizationSet set, CharaMakeParams row)
|
||||
{
|
||||
if (set.Race == Race.Hrothgar && set.Gender == Gender.Female)
|
||||
if (set is { Race: Race.Hrothgar, Gender: Gender.Female })
|
||||
return;
|
||||
|
||||
void Set(bool available, CustomizeIndex flag)
|
||||
{
|
||||
if (available)
|
||||
set.SetAvailable(flag);
|
||||
}
|
||||
|
||||
Set(true, CustomizeIndex.Height);
|
||||
Set(set.Faces.Count > 0, CustomizeIndex.Face);
|
||||
Set(true, CustomizeIndex.Hairstyle);
|
||||
|
|
@ -340,6 +336,13 @@ public partial class CustomizationOptions
|
|||
Set(true, CustomizeIndex.SmallIris);
|
||||
Set(set.Race != Race.Hrothgar, CustomizeIndex.Lipstick);
|
||||
Set(set.FacePaints.Count > 0, CustomizeIndex.FacePaintReversed);
|
||||
return;
|
||||
|
||||
void Set(bool available, CustomizeIndex flag)
|
||||
{
|
||||
if (available)
|
||||
set.SetAvailable(flag);
|
||||
}
|
||||
}
|
||||
|
||||
// Create a list of lists of facial features and the legacy tattoo.
|
||||
|
|
@ -348,9 +351,6 @@ public partial class CustomizationOptions
|
|||
var count = set.Faces.Count;
|
||||
set.FacialFeature1 = new List<(CustomizeData, CustomizeData)>(count);
|
||||
|
||||
static (CustomizeData, CustomizeData) Create(CustomizeIndex i, uint data)
|
||||
=> (new CustomizeData(i, CustomizeValue.Zero, data, 0), new CustomizeData(i, CustomizeValue.Max, data, 1));
|
||||
|
||||
set.LegacyTattoo = Create(CustomizeIndex.LegacyTattoo, 137905);
|
||||
|
||||
var tmp = Enumerable.Repeat(0, 7).Select(_ => new (CustomizeData, CustomizeData)[count + 1]).ToArray();
|
||||
|
|
@ -373,6 +373,10 @@ public partial class CustomizationOptions
|
|||
set.FacialFeature5 = tmp[4];
|
||||
set.FacialFeature6 = tmp[5];
|
||||
set.FacialFeature7 = tmp[6];
|
||||
return;
|
||||
|
||||
static (CustomizeData, CustomizeData) Create(CustomizeIndex i, uint data)
|
||||
=> (new CustomizeData(i, CustomizeValue.Zero, data), new CustomizeData(i, CustomizeValue.Max, data, 1));
|
||||
}
|
||||
|
||||
// Set the names for the given set of parameters.
|
||||
|
|
@ -414,7 +418,7 @@ public partial class CustomizationOptions
|
|||
nameArray[(int)CustomizeIndex.SmallIris] = CustomizeIndex.SmallIris.ToDefaultName();
|
||||
nameArray[(int)CustomizeIndex.Lipstick] = CustomizeIndex.Lipstick.ToDefaultName();
|
||||
nameArray[(int)CustomizeIndex.FacePaintReversed] = CustomizeIndex.FacePaintReversed.ToDefaultName();
|
||||
set.OptionName = nameArray;
|
||||
set.OptionName = nameArray;
|
||||
}
|
||||
|
||||
// Obtain available skin and hair colors for the given subrace and gender.
|
||||
|
|
@ -4,8 +4,9 @@ using System.Linq;
|
|||
using System.Runtime.CompilerServices;
|
||||
using OtterGui;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
namespace Glamourer.Customization;
|
||||
namespace Glamourer.GameData;
|
||||
|
||||
// Each Subrace and Gender combo has a customization set.
|
||||
// This describes the available customizations, their types and their names.
|
||||
|
|
@ -300,3 +301,10 @@ public class CustomizationSet
|
|||
private CustomizeValue HrothgarFaceHack(CustomizeValue value)
|
||||
=> Race == Race.Hrothgar && value.Value is > 4 and < 9 ? value - 4 : value;
|
||||
}
|
||||
|
||||
public static class CustomizationSetExtensions
|
||||
{
|
||||
/// <summary> Return only the available customizations in this set and Clan or Gender. </summary>
|
||||
public static CustomizeFlag FixApplication(this CustomizeFlag flag, CustomizationSet set)
|
||||
=> flag & (set.SettingAvailable | CustomizeFlag.Clan | CustomizeFlag.Gender);
|
||||
}
|
||||
|
|
@ -1,7 +1,9 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
namespace Glamourer.Customization;
|
||||
namespace Glamourer.GameData;
|
||||
|
||||
// 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.
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
using Dalamud.Interface.Internal;
|
||||
using Penumbra.GameData.Enums;
|
||||
|
||||
namespace Glamourer.Customization;
|
||||
namespace Glamourer.GameData;
|
||||
|
||||
public interface ICustomizationManager
|
||||
{
|
||||
|
|
@ -11,7 +11,7 @@ using OtterGui.Services;
|
|||
using Penumbra.GameData.DataContainers;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
namespace Glamourer.Customization;
|
||||
namespace Glamourer.GameData;
|
||||
|
||||
public class NpcCustomizeSet : IAsyncDataContainer, IReadOnlyList<NpcData>
|
||||
{
|
||||
|
|
@ -187,83 +187,83 @@ public class NpcCustomizeSet : IAsyncDataContainer, IReadOnlyList<NpcData>
|
|||
data.VisorToggled = row.Visor;
|
||||
}
|
||||
|
||||
private static (bool, Customize) FromBnpcCustomize(BNpcCustomize bnpcCustomize)
|
||||
private static (bool, CustomizeArray) FromBnpcCustomize(BNpcCustomize bnpcCustomize)
|
||||
{
|
||||
var customize = new Customize();
|
||||
customize.Data.Set(0, (byte)bnpcCustomize.Race.Row);
|
||||
customize.Data.Set(1, bnpcCustomize.Gender);
|
||||
customize.Data.Set(2, bnpcCustomize.BodyType);
|
||||
customize.Data.Set(3, bnpcCustomize.Height);
|
||||
customize.Data.Set(4, (byte)bnpcCustomize.Tribe.Row);
|
||||
customize.Data.Set(5, bnpcCustomize.Face);
|
||||
customize.Data.Set(6, bnpcCustomize.HairStyle);
|
||||
customize.Data.Set(7, bnpcCustomize.HairHighlight);
|
||||
customize.Data.Set(8, bnpcCustomize.SkinColor);
|
||||
customize.Data.Set(9, bnpcCustomize.EyeHeterochromia);
|
||||
customize.Data.Set(10, bnpcCustomize.HairColor);
|
||||
customize.Data.Set(11, bnpcCustomize.HairHighlightColor);
|
||||
customize.Data.Set(12, bnpcCustomize.FacialFeature);
|
||||
customize.Data.Set(13, bnpcCustomize.FacialFeatureColor);
|
||||
customize.Data.Set(14, bnpcCustomize.Eyebrows);
|
||||
customize.Data.Set(15, bnpcCustomize.EyeColor);
|
||||
customize.Data.Set(16, bnpcCustomize.EyeShape);
|
||||
customize.Data.Set(17, bnpcCustomize.Nose);
|
||||
customize.Data.Set(18, bnpcCustomize.Jaw);
|
||||
customize.Data.Set(19, bnpcCustomize.Mouth);
|
||||
customize.Data.Set(20, bnpcCustomize.LipColor);
|
||||
customize.Data.Set(21, bnpcCustomize.BustOrTone1);
|
||||
customize.Data.Set(22, bnpcCustomize.ExtraFeature1);
|
||||
customize.Data.Set(23, bnpcCustomize.ExtraFeature2OrBust);
|
||||
customize.Data.Set(24, bnpcCustomize.FacePaint);
|
||||
customize.Data.Set(25, bnpcCustomize.FacePaintColor);
|
||||
var customize = new CustomizeArray();
|
||||
customize.SetByIndex(0, (CustomizeValue) (byte)bnpcCustomize.Race.Row);
|
||||
customize.SetByIndex(1, (CustomizeValue) bnpcCustomize.Gender);
|
||||
customize.SetByIndex(2, (CustomizeValue) bnpcCustomize.BodyType);
|
||||
customize.SetByIndex(3, (CustomizeValue) bnpcCustomize.Height);
|
||||
customize.SetByIndex(4, (CustomizeValue) (byte)bnpcCustomize.Tribe.Row);
|
||||
customize.SetByIndex(5, (CustomizeValue) bnpcCustomize.Face);
|
||||
customize.SetByIndex(6, (CustomizeValue) bnpcCustomize.HairStyle);
|
||||
customize.SetByIndex(7, (CustomizeValue) bnpcCustomize.HairHighlight);
|
||||
customize.SetByIndex(8, (CustomizeValue) bnpcCustomize.SkinColor);
|
||||
customize.SetByIndex(9, (CustomizeValue) bnpcCustomize.EyeHeterochromia);
|
||||
customize.SetByIndex(10, (CustomizeValue) bnpcCustomize.HairColor);
|
||||
customize.SetByIndex(11, (CustomizeValue) bnpcCustomize.HairHighlightColor);
|
||||
customize.SetByIndex(12, (CustomizeValue) bnpcCustomize.FacialFeature);
|
||||
customize.SetByIndex(13, (CustomizeValue) bnpcCustomize.FacialFeatureColor);
|
||||
customize.SetByIndex(14, (CustomizeValue) bnpcCustomize.Eyebrows);
|
||||
customize.SetByIndex(15, (CustomizeValue) bnpcCustomize.EyeColor);
|
||||
customize.SetByIndex(16, (CustomizeValue) bnpcCustomize.EyeShape);
|
||||
customize.SetByIndex(17, (CustomizeValue) bnpcCustomize.Nose);
|
||||
customize.SetByIndex(18, (CustomizeValue) bnpcCustomize.Jaw);
|
||||
customize.SetByIndex(19, (CustomizeValue) bnpcCustomize.Mouth);
|
||||
customize.SetByIndex(20, (CustomizeValue) bnpcCustomize.LipColor);
|
||||
customize.SetByIndex(21, (CustomizeValue) bnpcCustomize.BustOrTone1);
|
||||
customize.SetByIndex(22, (CustomizeValue) bnpcCustomize.ExtraFeature1);
|
||||
customize.SetByIndex(23, (CustomizeValue) bnpcCustomize.ExtraFeature2OrBust);
|
||||
customize.SetByIndex(24, (CustomizeValue) bnpcCustomize.FacePaint);
|
||||
customize.SetByIndex(25, (CustomizeValue) bnpcCustomize.FacePaintColor);
|
||||
|
||||
if (customize.BodyType.Value != 1
|
||||
|| !CustomizationOptions.Races.Contains(customize.Race)
|
||||
|| !CustomizationOptions.Clans.Contains(customize.Clan)
|
||||
|| !CustomizationOptions.Genders.Contains(customize.Gender))
|
||||
return (false, Customize.Default);
|
||||
return (false, CustomizeArray.Default);
|
||||
|
||||
return (true, customize);
|
||||
}
|
||||
|
||||
private static (bool, Customize) FromEnpcBase(ENpcBase enpcBase)
|
||||
private static (bool, CustomizeArray) FromEnpcBase(ENpcBase enpcBase)
|
||||
{
|
||||
if (enpcBase.ModelChara.Value?.Type != 1)
|
||||
return (false, Customize.Default);
|
||||
return (false, CustomizeArray.Default);
|
||||
|
||||
var customize = new Customize();
|
||||
customize.Data.Set(0, (byte)enpcBase.Race.Row);
|
||||
customize.Data.Set(1, enpcBase.Gender);
|
||||
customize.Data.Set(2, enpcBase.BodyType);
|
||||
customize.Data.Set(3, enpcBase.Height);
|
||||
customize.Data.Set(4, (byte)enpcBase.Tribe.Row);
|
||||
customize.Data.Set(5, enpcBase.Face);
|
||||
customize.Data.Set(6, enpcBase.HairStyle);
|
||||
customize.Data.Set(7, enpcBase.HairHighlight);
|
||||
customize.Data.Set(8, enpcBase.SkinColor);
|
||||
customize.Data.Set(9, enpcBase.EyeHeterochromia);
|
||||
customize.Data.Set(10, enpcBase.HairColor);
|
||||
customize.Data.Set(11, enpcBase.HairHighlightColor);
|
||||
customize.Data.Set(12, enpcBase.FacialFeature);
|
||||
customize.Data.Set(13, enpcBase.FacialFeatureColor);
|
||||
customize.Data.Set(14, enpcBase.Eyebrows);
|
||||
customize.Data.Set(15, enpcBase.EyeColor);
|
||||
customize.Data.Set(16, enpcBase.EyeShape);
|
||||
customize.Data.Set(17, enpcBase.Nose);
|
||||
customize.Data.Set(18, enpcBase.Jaw);
|
||||
customize.Data.Set(19, enpcBase.Mouth);
|
||||
customize.Data.Set(20, enpcBase.LipColor);
|
||||
customize.Data.Set(21, enpcBase.BustOrTone1);
|
||||
customize.Data.Set(22, enpcBase.ExtraFeature1);
|
||||
customize.Data.Set(23, enpcBase.ExtraFeature2OrBust);
|
||||
customize.Data.Set(24, enpcBase.FacePaint);
|
||||
customize.Data.Set(25, enpcBase.FacePaintColor);
|
||||
var customize = new CustomizeArray();
|
||||
customize.SetByIndex(0, (CustomizeValue) (byte)enpcBase.Race.Row);
|
||||
customize.SetByIndex(1, (CustomizeValue) enpcBase.Gender);
|
||||
customize.SetByIndex(2, (CustomizeValue) enpcBase.BodyType);
|
||||
customize.SetByIndex(3, (CustomizeValue) enpcBase.Height);
|
||||
customize.SetByIndex(4, (CustomizeValue) (byte)enpcBase.Tribe.Row);
|
||||
customize.SetByIndex(5, (CustomizeValue) enpcBase.Face);
|
||||
customize.SetByIndex(6, (CustomizeValue) enpcBase.HairStyle);
|
||||
customize.SetByIndex(7, (CustomizeValue) enpcBase.HairHighlight);
|
||||
customize.SetByIndex(8, (CustomizeValue) enpcBase.SkinColor);
|
||||
customize.SetByIndex(9, (CustomizeValue) enpcBase.EyeHeterochromia);
|
||||
customize.SetByIndex(10, (CustomizeValue) enpcBase.HairColor);
|
||||
customize.SetByIndex(11, (CustomizeValue) enpcBase.HairHighlightColor);
|
||||
customize.SetByIndex(12, (CustomizeValue) enpcBase.FacialFeature);
|
||||
customize.SetByIndex(13, (CustomizeValue) enpcBase.FacialFeatureColor);
|
||||
customize.SetByIndex(14, (CustomizeValue) enpcBase.Eyebrows);
|
||||
customize.SetByIndex(15, (CustomizeValue) enpcBase.EyeColor);
|
||||
customize.SetByIndex(16, (CustomizeValue) enpcBase.EyeShape);
|
||||
customize.SetByIndex(17, (CustomizeValue) enpcBase.Nose);
|
||||
customize.SetByIndex(18, (CustomizeValue) enpcBase.Jaw);
|
||||
customize.SetByIndex(19, (CustomizeValue) enpcBase.Mouth);
|
||||
customize.SetByIndex(20, (CustomizeValue) enpcBase.LipColor);
|
||||
customize.SetByIndex(21, (CustomizeValue) enpcBase.BustOrTone1);
|
||||
customize.SetByIndex(22, (CustomizeValue) enpcBase.ExtraFeature1);
|
||||
customize.SetByIndex(23, (CustomizeValue) enpcBase.ExtraFeature2OrBust);
|
||||
customize.SetByIndex(24, (CustomizeValue) enpcBase.FacePaint);
|
||||
customize.SetByIndex(25, (CustomizeValue) enpcBase.FacePaintColor);
|
||||
|
||||
if (customize.BodyType.Value != 1
|
||||
|| !CustomizationOptions.Races.Contains(customize.Race)
|
||||
|| !CustomizationOptions.Clans.Contains(customize.Clan)
|
||||
|| !CustomizationOptions.Genders.Contains(customize.Gender))
|
||||
return (false, Customize.Default);
|
||||
return (false, CustomizeArray.Default);
|
||||
|
||||
return (true, customize);
|
||||
}
|
||||
|
|
@ -3,12 +3,12 @@ using System.Text;
|
|||
using FFXIVClientStructs.FFXIV.Client.Game.Object;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
namespace Glamourer.Customization;
|
||||
namespace Glamourer.GameData;
|
||||
|
||||
public unsafe struct NpcData
|
||||
{
|
||||
public string Name;
|
||||
public Customize Customize;
|
||||
public CustomizeArray Customize;
|
||||
private fixed byte _equip[40];
|
||||
public CharacterWeapon Mainhand;
|
||||
public CharacterWeapon Offhand;
|
||||
|
|
@ -84,7 +84,6 @@
|
|||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\OtterGui\OtterGui.csproj" />
|
||||
<ProjectReference Include="..\Glamourer.GameData\Glamourer.GameData.csproj" />
|
||||
<ProjectReference Include="..\Penumbra.Api\Penumbra.Api.csproj" />
|
||||
<ProjectReference Include="..\Penumbra.String\Penumbra.string.csproj" />
|
||||
<ProjectReference Include="..\Penumbra.GameData\Penumbra.GameData.csproj" />
|
||||
|
|
@ -109,8 +108,8 @@
|
|||
|
||||
<Target Name="GetGitHash" BeforeTargets="GetAssemblyVersion" Returns="InformationalVersion">
|
||||
<Exec Command="git rev-parse --short HEAD" ConsoleToMSBuild="true" StandardOutputImportance="low" ContinueOnError="true">
|
||||
<Output TaskParameter="ExitCode" PropertyName="GitCommitHashSuccess"/>
|
||||
<Output TaskParameter="ConsoleOutput" PropertyName="GitCommitHash" Condition="$(GitCommitHashSuccess) == 0"/>
|
||||
<Output TaskParameter="ExitCode" PropertyName="GitCommitHashSuccess" />
|
||||
<Output TaskParameter="ConsoleOutput" PropertyName="GitCommitHash" Condition="$(GitCommitHashSuccess) == 0" />
|
||||
</Exec>
|
||||
|
||||
<PropertyGroup>
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
using System.Numerics;
|
||||
using Dalamud.Interface;
|
||||
using Dalamud.Interface.Utility;
|
||||
using Glamourer.Customization;
|
||||
using Glamourer.GameData;
|
||||
using ImGuiNET;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
using Penumbra.GameData;
|
||||
using Penumbra.GameData.Enums;
|
||||
|
||||
namespace Glamourer.Gui.Customization;
|
||||
|
||||
|
|
@ -15,12 +15,12 @@ public partial class CustomizationDrawer
|
|||
|
||||
private void DrawColorPicker(CustomizeIndex index)
|
||||
{
|
||||
using var _ = SetId(index);
|
||||
using var id = SetId(index);
|
||||
var (current, custom) = GetCurrentCustomization(index);
|
||||
|
||||
var color = ImGui.ColorConvertU32ToFloat4(current < 0 ? ImGui.GetColorU32(ImGuiCol.FrameBg) : custom.Color);
|
||||
|
||||
using (var style = ImRaii.PushStyle(ImGuiStyleVar.FrameBorderSize, 2 * ImGuiHelpers.GlobalScale, current < 0))
|
||||
using (_ = ImRaii.PushStyle(ImGuiStyleVar.FrameBorderSize, 2 * ImGuiHelpers.GlobalScale, current < 0))
|
||||
{
|
||||
if (ImGui.ColorButton($"{_customize[index].Value}##color", color, ImGuiColorEditFlags.None, _framedIconSize))
|
||||
ImGui.OpenPopup(ColorPickerPopupName);
|
||||
|
|
@ -39,7 +39,7 @@ public partial class CustomizationDrawer
|
|||
|
||||
ImGui.SameLine();
|
||||
|
||||
using (var group = ImRaii.Group())
|
||||
using (_ = ImRaii.Group())
|
||||
{
|
||||
DataInputInt(current, npc);
|
||||
if (_withApply)
|
||||
|
|
@ -89,7 +89,7 @@ public partial class CustomizationDrawer
|
|||
{
|
||||
var current = _set.DataByValue(index, _customize[index], out var custom, _customize.Face);
|
||||
if (_set.IsAvailable(index) && current < 0)
|
||||
return (current, new CustomizeData(index, _customize[index], 0, 0));
|
||||
return (current, new CustomizeData(index, _customize[index]));
|
||||
|
||||
return (current, custom!.Value);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using Dalamud.Interface;
|
||||
using Glamourer.Customization;
|
||||
using Glamourer.GameData;
|
||||
using ImGuiNET;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
using System;
|
||||
using System.Numerics;
|
||||
using Glamourer.Customization;
|
||||
using Glamourer.GameData;
|
||||
using ImGuiNET;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
namespace Glamourer.Gui.Customization;
|
||||
|
||||
|
|
@ -13,7 +15,7 @@ public partial class CustomizationDrawer
|
|||
|
||||
private void DrawIconSelector(CustomizeIndex index)
|
||||
{
|
||||
using var _ = SetId(index);
|
||||
using var id = SetId(index);
|
||||
using var bigGroup = ImRaii.Group();
|
||||
var label = _currentOption;
|
||||
|
||||
|
|
@ -28,7 +30,7 @@ public partial class CustomizationDrawer
|
|||
}
|
||||
|
||||
var icon = _service.Service.GetIcon(custom!.Value.IconId);
|
||||
using (var disabled = ImRaii.Disabled(_locked || _currentIndex is CustomizeIndex.Face && _lockedRedraw))
|
||||
using (_ = ImRaii.Disabled(_locked || _currentIndex is CustomizeIndex.Face && _lockedRedraw))
|
||||
{
|
||||
if (ImGui.ImageButton(icon.ImGuiHandle, _iconSize))
|
||||
ImGui.OpenPopup(IconSelectorPopup);
|
||||
|
|
@ -37,7 +39,7 @@ public partial class CustomizationDrawer
|
|||
ImGuiUtil.HoverIconTooltip(icon, _iconSize);
|
||||
|
||||
ImGui.SameLine();
|
||||
using (var group = ImRaii.Group())
|
||||
using (_ = ImRaii.Group())
|
||||
{
|
||||
DataInputInt(current, npc);
|
||||
if (_lockedRedraw && ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenDisabled))
|
||||
|
|
@ -118,16 +120,16 @@ public partial class CustomizationDrawer
|
|||
ImGui.Dummy(new Vector2(ImGui.GetFrameHeight()));
|
||||
}
|
||||
|
||||
var oldValue = _customize.Data.At(_currentIndex.ToByteAndMask().ByteIdx);
|
||||
var tmp = (int)oldValue;
|
||||
var oldValue = _customize.AtIndex(_currentIndex.ToByteAndMask().ByteIdx);
|
||||
var tmp = (int)oldValue.Value;
|
||||
ImGui.SetNextItemWidth(_inputIntSize);
|
||||
if (ImGui.InputInt("##text", ref tmp, 1, 1))
|
||||
{
|
||||
tmp = Math.Clamp(tmp, 0, byte.MaxValue);
|
||||
if (tmp != oldValue)
|
||||
if (tmp != oldValue.Value)
|
||||
{
|
||||
_customize.Data.Set(_currentIndex.ToByteAndMask().ByteIdx, (byte)tmp);
|
||||
var changes = (byte)tmp ^ oldValue;
|
||||
_customize.SetByIndex(_currentIndex.ToByteAndMask().ByteIdx, (CustomizeValue)tmp);
|
||||
var changes = (byte)tmp ^ oldValue.Value;
|
||||
Changed |= ((changes & 0x01) == 0x01 ? CustomizeFlag.FacialFeature1 : 0)
|
||||
| ((changes & 0x02) == 0x02 ? CustomizeFlag.FacialFeature2 : 0)
|
||||
| ((changes & 0x04) == 0x04 ? CustomizeFlag.FacialFeature3 : 0)
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
using System;
|
||||
using System.Numerics;
|
||||
using Glamourer.Customization;
|
||||
using ImGuiNET;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
namespace Glamourer.Gui.Customization;
|
||||
|
||||
|
|
@ -91,10 +91,10 @@ public partial class CustomizationDrawer
|
|||
|
||||
private void DrawListSelector(CustomizeIndex index, bool indexedBy1)
|
||||
{
|
||||
using var _ = SetId(index);
|
||||
using var id = SetId(index);
|
||||
using var bigGroup = ImRaii.Group();
|
||||
|
||||
using (var disabled = ImRaii.Disabled(_locked))
|
||||
using (_ = ImRaii.Disabled(_locked))
|
||||
{
|
||||
if (indexedBy1)
|
||||
{
|
||||
|
|
@ -210,7 +210,7 @@ public partial class CustomizationDrawer
|
|||
}
|
||||
else
|
||||
{
|
||||
using (var disabled = ImRaii.Disabled(_locked))
|
||||
using (_ = ImRaii.Disabled(_locked))
|
||||
{
|
||||
if (ImGui.Checkbox("##toggle", ref tmp))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ using System.Reflection;
|
|||
using Dalamud.Interface.Internal;
|
||||
using Dalamud.Interface.Utility;
|
||||
using Dalamud.Plugin;
|
||||
using Glamourer.Customization;
|
||||
using Glamourer.GameData;
|
||||
using Glamourer.Services;
|
||||
using ImGuiNET;
|
||||
using OtterGui;
|
||||
|
|
@ -22,13 +22,12 @@ public partial class CustomizationDrawer(DalamudPluginInterface pi, Customizatio
|
|||
|
||||
private Exception? _terminate;
|
||||
|
||||
private Customize _customize = Customize.Default;
|
||||
private CustomizeArray _customize = CustomizeArray.Default;
|
||||
private CustomizationSet _set = null!;
|
||||
|
||||
public Customize Customize
|
||||
public CustomizeArray Customize
|
||||
=> _customize;
|
||||
|
||||
public CustomizeFlag CurrentFlag { get; private set; }
|
||||
public CustomizeFlag Changed { get; private set; }
|
||||
public CustomizeFlag ChangeApply { get; private set; }
|
||||
|
||||
|
|
@ -47,18 +46,16 @@ public partial class CustomizationDrawer(DalamudPluginInterface pi, Customizatio
|
|||
public void Dispose()
|
||||
=> _legacyTattoo?.Dispose();
|
||||
|
||||
public bool Draw(Customize current, bool locked, bool lockedRedraw)
|
||||
public bool Draw(CustomizeArray current, bool locked, bool lockedRedraw)
|
||||
{
|
||||
CurrentFlag = CustomizeFlagExtensions.All;
|
||||
_withApply = false;
|
||||
Init(current, locked, lockedRedraw);
|
||||
|
||||
return DrawInternal();
|
||||
}
|
||||
|
||||
public bool Draw(Customize current, CustomizeFlag apply, bool locked, bool lockedRedraw)
|
||||
public bool Draw(CustomizeArray current, CustomizeFlag apply, bool locked, bool lockedRedraw)
|
||||
{
|
||||
CurrentFlag = CustomizeFlagExtensions.All;
|
||||
ChangeApply = apply;
|
||||
_initialApply = apply;
|
||||
_withApply = !_config.HideApplyCheckmarks;
|
||||
|
|
@ -66,12 +63,12 @@ public partial class CustomizationDrawer(DalamudPluginInterface pi, Customizatio
|
|||
return DrawInternal();
|
||||
}
|
||||
|
||||
private void Init(Customize current, bool locked, bool lockedRedraw)
|
||||
private void Init(CustomizeArray current, bool locked, bool lockedRedraw)
|
||||
{
|
||||
UpdateSizes();
|
||||
_terminate = null;
|
||||
Changed = 0;
|
||||
_customize.Load(current);
|
||||
_terminate = null;
|
||||
Changed = 0;
|
||||
_customize = current;
|
||||
_locked = locked;
|
||||
_lockedRedraw = lockedRedraw;
|
||||
}
|
||||
|
|
@ -156,20 +153,20 @@ public partial class CustomizationDrawer(DalamudPluginInterface pi, Customizatio
|
|||
for (var i = 0; i < CustomizeArray.Size; ++i)
|
||||
{
|
||||
using var id = ImRaii.PushId(i);
|
||||
int value = _customize.Data.Data[i];
|
||||
int value = _customize.Data[i];
|
||||
ImGui.SetNextItemWidth(40 * ImGuiHelpers.GlobalScale);
|
||||
if (ImGui.InputInt(string.Empty, ref value, 0, 0))
|
||||
{
|
||||
var newValue = (byte)Math.Clamp(value, 0, byte.MaxValue);
|
||||
if (newValue != _customize.Data.Data[i])
|
||||
if (newValue != _customize.Data[i])
|
||||
foreach (var flag in Enum.GetValues<CustomizeIndex>())
|
||||
{
|
||||
var (j, mask) = flag.ToByteAndMask();
|
||||
var (j, _) = flag.ToByteAndMask();
|
||||
if (j == i)
|
||||
Changed |= flag.ToFlag();
|
||||
}
|
||||
|
||||
_customize.Data.Data[i] = newValue;
|
||||
_customize.Data[i] = newValue;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ using System.Linq;
|
|||
using Dalamud.Interface.Utility;
|
||||
using Dalamud.Interface.Utility.Raii;
|
||||
using Glamourer.Automation;
|
||||
using Glamourer.Customization;
|
||||
using Glamourer.GameData;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.Events;
|
||||
using Glamourer.Services;
|
||||
|
|
@ -13,6 +13,7 @@ using OtterGui;
|
|||
using OtterGui.Classes;
|
||||
using OtterGui.Log;
|
||||
using OtterGui.Widgets;
|
||||
using Penumbra.GameData.Enums;
|
||||
|
||||
namespace Glamourer.Gui;
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ using Glamourer.Interop;
|
|||
using Glamourer.Interop.Penumbra;
|
||||
using Glamourer.Services;
|
||||
using Glamourer.State;
|
||||
using Glamourer.Structs;
|
||||
using ImGuiNET;
|
||||
using OtterGui.Raii;
|
||||
using Penumbra.Api.Enums;
|
||||
|
|
@ -76,7 +75,7 @@ public class PenumbraChangedItemTooltip : IDisposable
|
|||
case EquipSlot.OffHand when !CanApplyWeapon(EquipSlot.OffHand, item):
|
||||
break;
|
||||
case EquipSlot.RFinger:
|
||||
using (var tt = !openTooltip ? null : ImRaii.Tooltip())
|
||||
using (_ = !openTooltip ? null : ImRaii.Tooltip())
|
||||
{
|
||||
ImGui.TextUnformatted($"{prefix}Right-Click to apply to current actor (Right Finger).");
|
||||
ImGui.TextUnformatted($"{prefix}Shift + Right-Click to apply to current actor (Left Finger).");
|
||||
|
|
@ -92,7 +91,7 @@ public class PenumbraChangedItemTooltip : IDisposable
|
|||
|
||||
break;
|
||||
default:
|
||||
using (var tt = !openTooltip ? null : ImRaii.Tooltip())
|
||||
using (_ = !openTooltip ? null : ImRaii.Tooltip())
|
||||
{
|
||||
ImGui.TextUnformatted($"{prefix}Right-Click to apply to current actor.");
|
||||
if (last.Valid)
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ using Dalamud.Interface.Internal.Notifications;
|
|||
using Dalamud.Plugin.Services;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game;
|
||||
using Glamourer.Automation;
|
||||
using Glamourer.Customization;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.Events;
|
||||
using Glamourer.Gui.Customization;
|
||||
|
|
@ -14,7 +13,6 @@ using Glamourer.Gui.Equipment;
|
|||
using Glamourer.Interop;
|
||||
using Glamourer.Interop.Structs;
|
||||
using Glamourer.State;
|
||||
using Glamourer.Structs;
|
||||
using ImGuiNET;
|
||||
using OtterGui;
|
||||
using OtterGui.Classes;
|
||||
|
|
@ -173,21 +171,21 @@ public class ActorPanel(
|
|||
|
||||
private void DrawEquipmentMetaToggles()
|
||||
{
|
||||
using (var _ = ImRaii.Group())
|
||||
using (_ = ImRaii.Group())
|
||||
{
|
||||
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.FromState(ActorState.MetaIndex.HatState, _stateManager, _state!));
|
||||
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.CrestFromState(CrestFlag.Head, _stateManager, _state!));
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
using (var _ = ImRaii.Group())
|
||||
using (_ = ImRaii.Group())
|
||||
{
|
||||
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.FromState(ActorState.MetaIndex.VisorState, _stateManager, _state!));
|
||||
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.CrestFromState(CrestFlag.Body, _stateManager, _state!));
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
using (var _ = ImRaii.Group())
|
||||
using (_ = ImRaii.Group())
|
||||
{
|
||||
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.FromState(ActorState.MetaIndex.WeaponState, _stateManager, _state!));
|
||||
EquipmentDrawer.DrawMetaToggle(ToggleDrawData.CrestFromState(CrestFlag.OffHand, _stateManager, _state!));
|
||||
|
|
@ -199,7 +197,7 @@ public class ActorPanel(
|
|||
var names = _modelChara[_state!.ModelData.ModelId];
|
||||
var turnHuman = ImGui.Button("Turn Human");
|
||||
ImGui.Separator();
|
||||
using (var box = ImRaii.ListBox("##MonsterList",
|
||||
using (_ = ImRaii.ListBox("##MonsterList",
|
||||
new Vector2(ImGui.GetContentRegionAvail().X, 10 * ImGui.GetTextLineHeightWithSpacing())))
|
||||
{
|
||||
if (names.Count == 0)
|
||||
|
|
@ -211,14 +209,14 @@ public class ActorPanel(
|
|||
|
||||
ImGui.Separator();
|
||||
ImGui.TextUnformatted("Customization Data");
|
||||
using (var font = ImRaii.PushFont(UiBuilder.MonoFont))
|
||||
using (_ = ImRaii.PushFont(UiBuilder.MonoFont))
|
||||
{
|
||||
foreach (var b in _state.ModelData.Customize.Data)
|
||||
foreach (var b in _state.ModelData.Customize)
|
||||
{
|
||||
using (var g = ImRaii.Group())
|
||||
using (_ = ImRaii.Group())
|
||||
{
|
||||
ImGui.TextUnformatted($" {b:X2}");
|
||||
ImGui.TextUnformatted($"{b,3}");
|
||||
ImGui.TextUnformatted($" {b.Value:X2}");
|
||||
ImGui.TextUnformatted($"{b.Value,3}");
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
|
|
@ -232,11 +230,11 @@ public class ActorPanel(
|
|||
|
||||
ImGui.Separator();
|
||||
ImGui.TextUnformatted("Equipment Data");
|
||||
using (var font = ImRaii.PushFont(UiBuilder.MonoFont))
|
||||
using (_ = ImRaii.PushFont(UiBuilder.MonoFont))
|
||||
{
|
||||
foreach (var b in _state.ModelData.GetEquipmentBytes())
|
||||
{
|
||||
using (var g = ImRaii.Group())
|
||||
using (_ = ImRaii.Group())
|
||||
{
|
||||
ImGui.TextUnformatted($" {b:X2}");
|
||||
ImGui.TextUnformatted($"{b,3}");
|
||||
|
|
@ -298,8 +296,8 @@ public class ActorPanel(
|
|||
BorderColor = ColorId.ActorUnavailable.Value(),
|
||||
};
|
||||
|
||||
private string _newName = string.Empty;
|
||||
private DesignBase? _newDesign = null;
|
||||
private string _newName = string.Empty;
|
||||
private DesignBase? _newDesign;
|
||||
|
||||
private void SaveDesignOpen()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -6,10 +6,8 @@ using System.Text;
|
|||
using Dalamud.Interface;
|
||||
using Dalamud.Interface.Utility;
|
||||
using Glamourer.Automation;
|
||||
using Glamourer.Customization;
|
||||
using Glamourer.Interop;
|
||||
using Glamourer.Services;
|
||||
using Glamourer.Structs;
|
||||
using Glamourer.Unlocks;
|
||||
using ImGuiNET;
|
||||
using OtterGui;
|
||||
|
|
@ -17,44 +15,29 @@ using OtterGui.Log;
|
|||
using OtterGui.Raii;
|
||||
using OtterGui.Widgets;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
using Action = System.Action;
|
||||
using CustomizeIndex = Glamourer.Customization.CustomizeIndex;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.AutomationTab;
|
||||
|
||||
public class SetPanel
|
||||
public class SetPanel(
|
||||
SetSelector _selector,
|
||||
AutoDesignManager _manager,
|
||||
JobService _jobs,
|
||||
ItemUnlockManager _itemUnlocks,
|
||||
RevertDesignCombo _designCombo,
|
||||
CustomizeUnlockManager _customizeUnlocks,
|
||||
CustomizationService _customizations,
|
||||
IdentifierDrawer _identifierDrawer,
|
||||
Configuration _config)
|
||||
{
|
||||
private readonly AutoDesignManager _manager;
|
||||
private readonly SetSelector _selector;
|
||||
private readonly ItemUnlockManager _itemUnlocks;
|
||||
private readonly CustomizeUnlockManager _customizeUnlocks;
|
||||
private readonly CustomizationService _customizations;
|
||||
|
||||
private readonly Configuration _config;
|
||||
private readonly RevertDesignCombo _designCombo;
|
||||
private readonly JobGroupCombo _jobGroupCombo;
|
||||
private readonly IdentifierDrawer _identifierDrawer;
|
||||
private readonly JobGroupCombo _jobGroupCombo = new(_manager, _jobs, Glamourer.Log);
|
||||
|
||||
private string? _tempName;
|
||||
private int _dragIndex = -1;
|
||||
|
||||
private Action? _endAction;
|
||||
|
||||
public SetPanel(SetSelector selector, AutoDesignManager manager, JobService jobs, ItemUnlockManager itemUnlocks,
|
||||
RevertDesignCombo designCombo,
|
||||
CustomizeUnlockManager customizeUnlocks, CustomizationService customizations, IdentifierDrawer identifierDrawer, Configuration config)
|
||||
{
|
||||
_selector = selector;
|
||||
_manager = manager;
|
||||
_itemUnlocks = itemUnlocks;
|
||||
_customizeUnlocks = customizeUnlocks;
|
||||
_customizations = customizations;
|
||||
_identifierDrawer = identifierDrawer;
|
||||
_config = config;
|
||||
_designCombo = designCombo;
|
||||
_jobGroupCombo = new JobGroupCombo(manager, jobs, Glamourer.Log);
|
||||
}
|
||||
|
||||
private AutoDesignSet Selection
|
||||
=> _selector.Selection!;
|
||||
|
||||
|
|
@ -77,7 +60,7 @@ public class SetPanel
|
|||
|
||||
var spacing = ImGui.GetStyle().ItemInnerSpacing with { Y = ImGui.GetStyle().ItemSpacing.Y };
|
||||
|
||||
using (var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, spacing))
|
||||
using (_ = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, spacing))
|
||||
{
|
||||
var enabled = Selection.Enabled;
|
||||
if (ImGui.Checkbox("##Enabled", ref enabled))
|
||||
|
|
@ -87,7 +70,7 @@ public class SetPanel
|
|||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
using (var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, spacing))
|
||||
using (_ = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, spacing))
|
||||
{
|
||||
var useGame = _selector.Selection!.BaseState is AutoDesignSet.Base.Game;
|
||||
if (ImGui.Checkbox("##gameState", ref useGame))
|
||||
|
|
@ -98,7 +81,7 @@ public class SetPanel
|
|||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
using (var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, spacing))
|
||||
using (_ = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, spacing))
|
||||
{
|
||||
var editing = _config.ShowAutomationSetEditing;
|
||||
if (ImGui.Checkbox("##Show Editing", ref editing))
|
||||
|
|
@ -230,7 +213,7 @@ public class SetPanel
|
|||
if (_config.ShowUnlockedItemWarnings)
|
||||
{
|
||||
ImGui.TableNextColumn();
|
||||
DrawWarnings(design, idx);
|
||||
DrawWarnings(design);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -278,7 +261,7 @@ public class SetPanel
|
|||
}
|
||||
}
|
||||
|
||||
private void DrawWarnings(AutoDesign design, int idx)
|
||||
private void DrawWarnings(AutoDesign design)
|
||||
{
|
||||
if (design.Revert)
|
||||
return;
|
||||
|
|
@ -301,27 +284,6 @@ public class SetPanel
|
|||
|
||||
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, new Vector2(2 * ImGuiHelpers.GlobalScale, 0));
|
||||
|
||||
|
||||
static void DrawWarning(StringBuilder sb, uint color, Vector2 size, string suffix, string good)
|
||||
{
|
||||
using var style = ImRaii.PushStyle(ImGuiStyleVar.FrameBorderSize, ImGuiHelpers.GlobalScale);
|
||||
if (sb.Length > 0)
|
||||
{
|
||||
sb.Append(suffix);
|
||||
using (var font = ImRaii.PushFont(UiBuilder.IconFont))
|
||||
{
|
||||
ImGuiUtil.DrawTextButton(FontAwesomeIcon.ExclamationCircle.ToIconString(), size, color);
|
||||
}
|
||||
|
||||
ImGuiUtil.HoverTooltip(sb.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGuiUtil.DrawTextButton(string.Empty, size, 0);
|
||||
ImGuiUtil.HoverTooltip(good);
|
||||
}
|
||||
}
|
||||
|
||||
var tt = _config.UnlockedItemMode
|
||||
? "\nThese items will be skipped when applied automatically.\n\nTo change this, disable the Obtained Item Mode setting."
|
||||
: string.Empty;
|
||||
|
|
@ -355,6 +317,27 @@ public class SetPanel
|
|||
: string.Empty;
|
||||
DrawWarning(sb2, _config.UnlockedItemMode ? 0xA03030F0 : 0x0, size, tt, "All customizations to be applied are unlocked.");
|
||||
ImGui.SameLine();
|
||||
return;
|
||||
|
||||
static void DrawWarning(StringBuilder sb, uint color, Vector2 size, string suffix, string good)
|
||||
{
|
||||
using var style = ImRaii.PushStyle(ImGuiStyleVar.FrameBorderSize, ImGuiHelpers.GlobalScale);
|
||||
if (sb.Length > 0)
|
||||
{
|
||||
sb.Append(suffix);
|
||||
using (_ = ImRaii.PushFont(UiBuilder.IconFont))
|
||||
{
|
||||
ImGuiUtil.DrawTextButton(FontAwesomeIcon.ExclamationCircle.ToIconString(), size, color);
|
||||
}
|
||||
|
||||
ImGuiUtil.HoverTooltip(sb.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGuiUtil.DrawTextButton(string.Empty, size, 0);
|
||||
ImGuiUtil.HoverTooltip(good);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawDragDrop(AutoDesignSet set, int index)
|
||||
|
|
@ -394,7 +377,7 @@ public class SetPanel
|
|||
var newType = design.ApplicationType;
|
||||
var newTypeInt = (uint)newType;
|
||||
style.Push(ImGuiStyleVar.FrameBorderSize, ImGuiHelpers.GlobalScale);
|
||||
using (var c = ImRaii.PushColor(ImGuiCol.Border, ColorId.FolderLine.Value()))
|
||||
using (_ = ImRaii.PushColor(ImGuiCol.Border, ColorId.FolderLine.Value()))
|
||||
{
|
||||
if (ImGui.CheckboxFlags("##all", ref newTypeInt, (uint)AutoDesign.Type.All))
|
||||
newType = (AutoDesign.Type)newTypeInt;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using Dalamud.Interface;
|
||||
using Glamourer.Customization;
|
||||
using Glamourer.GameData;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.Events;
|
||||
using Glamourer.Interop;
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
using System;
|
||||
using Glamourer.Customization;
|
||||
using Glamourer.GameData;
|
||||
using Glamourer.Services;
|
||||
using ImGuiNET;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
using Penumbra.GameData.Enums;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DebugTab;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
using System;
|
||||
using System.Numerics;
|
||||
using Glamourer.Customization;
|
||||
using Glamourer.Unlocks;
|
||||
using ImGuiNET;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
using Penumbra.GameData.Enums;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DebugTab;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
using System.IO;
|
||||
using System.Numerics;
|
||||
using Glamourer.Customization;
|
||||
using Glamourer.Interop;
|
||||
using ImGuiNET;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
using Penumbra.GameData.Files;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DebugTab;
|
||||
|
||||
|
|
@ -35,7 +34,7 @@ public class DatFilePanel(ImportService _importService) : IDebugTabTree
|
|||
ImGui.TextUnformatted(_datFile.Value.Version.ToString());
|
||||
ImGui.TextUnformatted(_datFile.Value.Time.LocalDateTime.ToString("g"));
|
||||
ImGui.TextUnformatted(_datFile.Value.Voice.ToString());
|
||||
ImGui.TextUnformatted(_datFile.Value.Customize.Data.ToString());
|
||||
ImGui.TextUnformatted(_datFile.Value.Customize.ToString());
|
||||
ImGui.TextUnformatted(_datFile.Value.Description);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using Dalamud.Interface;
|
||||
using Glamourer.Customization;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.Structs;
|
||||
using ImGuiNET;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using Dalamud.Interface;
|
||||
using Glamourer.Customization;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.Services;
|
||||
using Glamourer.Structs;
|
||||
using ImGuiNET;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
|
|
@ -85,7 +83,7 @@ public class DesignTesterPanel(ItemManager _items, HumanModelList _humans) : IDe
|
|||
DrawDesignData(_parse64);
|
||||
using var font = ImRaii.PushFont(UiBuilder.MonoFont);
|
||||
ImGui.TextUnformatted(_base64);
|
||||
using (var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, ImGui.GetStyle().ItemSpacing with { X = 0 }))
|
||||
using (_ = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, ImGui.GetStyle().ItemSpacing with { X = 0 }))
|
||||
{
|
||||
foreach (var (c1, c2) in _restore.Zip(_base64))
|
||||
{
|
||||
|
|
@ -99,7 +97,7 @@ public class DesignTesterPanel(ItemManager _items, HumanModelList _humans) : IDe
|
|||
|
||||
foreach (var ((b1, b2), idx) in _base64Bytes.Zip(_restoreBytes).WithIndex())
|
||||
{
|
||||
using (var group = ImRaii.Group())
|
||||
using (_ = ImRaii.Group())
|
||||
{
|
||||
ImGui.TextUnformatted(idx.ToString("D2"));
|
||||
ImGui.TextUnformatted(b1.ToString("X2"));
|
||||
|
|
@ -121,7 +119,7 @@ public class DesignTesterPanel(ItemManager _items, HumanModelList _humans) : IDe
|
|||
using var font = ImRaii.PushFont(UiBuilder.MonoFont);
|
||||
foreach (var (b, idx) in _base64Bytes.WithIndex())
|
||||
{
|
||||
using (var group = ImRaii.Group())
|
||||
using (_ = ImRaii.Group())
|
||||
{
|
||||
ImGui.TextUnformatted(idx.ToString("D2"));
|
||||
ImGui.TextUnformatted(b.ToString("X2"));
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ public class JobPanel(JobService _jobs) : IDebugTabTree
|
|||
|
||||
foreach (var (id, job) in _jobs.Jobs)
|
||||
{
|
||||
ImGuiUtil.DrawTableColumn(id.ToString("D3"));
|
||||
ImGuiUtil.DrawTableColumn(id.Id.ToString("D3"));
|
||||
ImGuiUtil.DrawTableColumn(job.Name);
|
||||
ImGuiUtil.DrawTableColumn(job.Abbreviation);
|
||||
}
|
||||
|
|
@ -68,7 +68,7 @@ public class JobPanel(JobService _jobs) : IDebugTabTree
|
|||
|
||||
foreach (var (id, group) in _jobs.JobGroups)
|
||||
{
|
||||
ImGuiUtil.DrawTableColumn(id.ToString("D3"));
|
||||
ImGuiUtil.DrawTableColumn(id.Id.ToString("D3"));
|
||||
ImGuiUtil.DrawTableColumn(group.Name);
|
||||
ImGuiUtil.DrawTableColumn(group.Count.ToString());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
using System;
|
||||
using System.Numerics;
|
||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
||||
using Glamourer.Customization;
|
||||
using Glamourer.Interop;
|
||||
using Glamourer.Interop.Structs;
|
||||
using Glamourer.Structs;
|
||||
using ImGuiNET;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
|
|
@ -126,15 +124,14 @@ public unsafe class ModelEvaluationPanel(
|
|||
model.AsHuman->Head.Value == 0 ? actor.GetArmor(EquipSlot.Head) : CharacterArmor.Empty);
|
||||
}
|
||||
|
||||
private void DrawWeaponState(Actor actor, Model model)
|
||||
private static void DrawWeaponState(Actor actor, Model model)
|
||||
{
|
||||
using var id = ImRaii.PushId("WeaponState");
|
||||
ImGuiUtil.DrawTableColumn("Weapon State");
|
||||
ImGuiUtil.DrawTableColumn(actor.IsCharacter
|
||||
? actor.AsCharacter->DrawData.IsWeaponHidden ? "Hidden" : "Visible"
|
||||
: "No Character");
|
||||
var text = string.Empty;
|
||||
|
||||
string text;
|
||||
if (!model.IsHuman)
|
||||
{
|
||||
text = "No Model";
|
||||
|
|
@ -146,19 +143,14 @@ public unsafe class ModelEvaluationPanel(
|
|||
else
|
||||
{
|
||||
var weapon = (DrawObject*)model.AsDrawObject->Object.ChildObject;
|
||||
if ((weapon->Flags & 0x09) == 0x09)
|
||||
text = "Visible";
|
||||
else
|
||||
text = "Hidden";
|
||||
text = (weapon->Flags & 0x09) == 0x09 ? "Visible" : "Hidden";
|
||||
}
|
||||
|
||||
ImGuiUtil.DrawTableColumn(text);
|
||||
ImGui.TableNextColumn();
|
||||
if (!model.IsHuman)
|
||||
return;
|
||||
}
|
||||
|
||||
private void DrawWetness(Actor actor, Model model)
|
||||
private static void DrawWetness(Actor actor, Model model)
|
||||
{
|
||||
using var id = ImRaii.PushId("Wetness");
|
||||
ImGuiUtil.DrawTableColumn("Wetness");
|
||||
|
|
@ -212,12 +204,12 @@ public unsafe class ModelEvaluationPanel(
|
|||
private void DrawCustomize(Actor actor, Model model)
|
||||
{
|
||||
using var id = ImRaii.PushId("Customize");
|
||||
var actorCustomize = new Customize(actor.IsCharacter
|
||||
var actorCustomize = actor.IsCharacter
|
||||
? *(CustomizeArray*)&actor.AsCharacter->DrawData.CustomizeData
|
||||
: new CustomizeArray());
|
||||
var modelCustomize = new Customize(model.IsHuman
|
||||
: new CustomizeArray();
|
||||
var modelCustomize = model.IsHuman
|
||||
? *(CustomizeArray*)model.AsHuman->Customize.Data
|
||||
: new CustomizeArray());
|
||||
: new CustomizeArray();
|
||||
foreach (var type in Enum.GetValues<CustomizeIndex>())
|
||||
{
|
||||
using var id2 = ImRaii.PushId((int)type);
|
||||
|
|
@ -235,7 +227,7 @@ public unsafe class ModelEvaluationPanel(
|
|||
var shift = BitOperations.TrailingZeroCount(mask);
|
||||
var newValue = value + (1 << shift);
|
||||
modelCustomize.Set(type, (CustomizeValue)newValue);
|
||||
_changeCustomizeService.UpdateCustomize(model, modelCustomize.Data);
|
||||
_changeCustomizeService.UpdateCustomize(model, modelCustomize);
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
|
|
@ -246,14 +238,14 @@ public unsafe class ModelEvaluationPanel(
|
|||
var shift = BitOperations.TrailingZeroCount(mask);
|
||||
var newValue = value - (1 << shift);
|
||||
modelCustomize.Set(type, (CustomizeValue)newValue);
|
||||
_changeCustomizeService.UpdateCustomize(model, modelCustomize.Data);
|
||||
_changeCustomizeService.UpdateCustomize(model, modelCustomize);
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
if (ImGui.SmallButton("Reset"))
|
||||
{
|
||||
modelCustomize.Set(type, actorCustomize[type]);
|
||||
_changeCustomizeService.UpdateCustomize(model, modelCustomize.Data);
|
||||
_changeCustomizeService.UpdateCustomize(model, modelCustomize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,14 +3,15 @@ using System.Numerics;
|
|||
using Dalamud.Interface;
|
||||
using Dalamud.Interface.Utility;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Object;
|
||||
using Glamourer.Customization;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.Events;
|
||||
using Glamourer.GameData;
|
||||
using Glamourer.Interop;
|
||||
using Glamourer.State;
|
||||
using ImGuiNET;
|
||||
using OtterGui;
|
||||
using OtterGui.Raii;
|
||||
using Penumbra.GameData.Enums;
|
||||
using ImGuiClip = OtterGui.ImGuiClip;
|
||||
|
||||
namespace Glamourer.Gui.Tabs.DebugTab;
|
||||
|
|
@ -24,7 +25,7 @@ public class NpcAppearancePanel(NpcCombo _npcCombo, StateManager _state, ObjectM
|
|||
=> false;
|
||||
|
||||
private string _npcFilter = string.Empty;
|
||||
private bool _customizeOrGear = false;
|
||||
private bool _customizeOrGear;
|
||||
|
||||
public void Draw()
|
||||
{
|
||||
|
|
@ -48,19 +49,17 @@ public class NpcAppearancePanel(NpcCombo _npcCombo, StateManager _state, ObjectM
|
|||
ImGui.TableNextRow();
|
||||
var idx = 0;
|
||||
var remainder = ImGuiClip.FilteredClippedDraw(_npcCombo.Items, skips,
|
||||
d => d.Name.Contains(_npcFilter, StringComparison.OrdinalIgnoreCase), Draw);
|
||||
d => d.Name.Contains(_npcFilter, StringComparison.OrdinalIgnoreCase), DrawData);
|
||||
ImGui.TableNextColumn();
|
||||
ImGuiClip.DrawEndDummy(remainder, ImGui.GetFrameHeightWithSpacing());
|
||||
|
||||
|
||||
return;
|
||||
|
||||
void Draw(NpcData data)
|
||||
void DrawData(NpcData data)
|
||||
{
|
||||
using var id = ImRaii.PushId(idx++);
|
||||
var disabled = !_state.GetOrCreate(_objectManager.Player, out var state);
|
||||
ImGui.TableNextColumn();
|
||||
if (ImGuiUtil.DrawDisabledButton("Apply", Vector2.Zero, string.Empty, disabled, false))
|
||||
if (ImGuiUtil.DrawDisabledButton("Apply", Vector2.Zero, string.Empty, disabled))
|
||||
{
|
||||
foreach (var (slot, item, stain) in _designConverter.FromDrawData(data.Equip.ToArray(), data.Mainhand, data.Offhand))
|
||||
_state.ChangeEquip(state!, slot, item, stain, StateChanged.Source.Manual);
|
||||
|
|
@ -76,7 +75,7 @@ public class NpcAppearancePanel(NpcCombo _npcCombo, StateManager _state, ObjectM
|
|||
ImGui.AlignTextToFramePadding();
|
||||
ImGui.TextUnformatted(data.Kind is ObjectKind.BattleNpc ? "B" : "E");
|
||||
|
||||
using (var icon = ImRaii.PushFont(UiBuilder.IconFont))
|
||||
using (_ = ImRaii.PushFont(UiBuilder.IconFont))
|
||||
{
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.AlignTextToFramePadding();
|
||||
|
|
@ -86,7 +85,7 @@ public class NpcAppearancePanel(NpcCombo _npcCombo, StateManager _state, ObjectM
|
|||
using var mono = ImRaii.PushFont(UiBuilder.MonoFont);
|
||||
ImGui.TableNextColumn();
|
||||
ImGui.AlignTextToFramePadding();
|
||||
ImGui.TextUnformatted(_customizeOrGear ? data.Customize.Data.ToString() : data.WriteGear());
|
||||
ImGui.TextUnformatted(_customizeOrGear ? data.Customize.ToString() : data.WriteGear());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,14 +7,12 @@ using Dalamud.Interface.ImGuiFileDialog;
|
|||
using Dalamud.Interface.Internal.Notifications;
|
||||
using FFXIVClientStructs.FFXIV.Client.System.Framework;
|
||||
using Glamourer.Automation;
|
||||
using Glamourer.Customization;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.Events;
|
||||
using Glamourer.Gui.Customization;
|
||||
using Glamourer.Gui.Equipment;
|
||||
using Glamourer.Interop;
|
||||
using Glamourer.State;
|
||||
using Glamourer.Structs;
|
||||
using ImGuiNET;
|
||||
using OtterGui;
|
||||
using OtterGui.Classes;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
using Glamourer.Customization;
|
||||
using Glamourer.GameData;
|
||||
using OtterGui.Widgets;
|
||||
|
||||
namespace Glamourer.Gui.Tabs;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ using System.Linq;
|
|||
using System.Numerics;
|
||||
using Dalamud.Game.Text.SeStringHandling;
|
||||
using Dalamud.Interface.Utility;
|
||||
using Glamourer.Customization;
|
||||
using Glamourer.GameData;
|
||||
using Glamourer.Interop;
|
||||
using Glamourer.Services;
|
||||
using Glamourer.Unlocks;
|
||||
|
|
|
|||
|
|
@ -8,7 +8,6 @@ using Dalamud.Interface.Utility;
|
|||
using Glamourer.Events;
|
||||
using Glamourer.Interop;
|
||||
using Glamourer.Services;
|
||||
using Glamourer.Structs;
|
||||
using Glamourer.Unlocks;
|
||||
using ImGuiNET;
|
||||
using OtterGui;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
using Glamourer.Designs;
|
||||
using Glamourer.Events;
|
||||
using Glamourer.State;
|
||||
using Glamourer.Structs;
|
||||
using Penumbra.GameData.Enums;
|
||||
|
||||
namespace Glamourer.Gui;
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
using System.Numerics;
|
||||
using Dalamud.Interface;
|
||||
using Dalamud.Interface.Utility;
|
||||
using Glamourer.Customization;
|
||||
using Glamourer.Services;
|
||||
using Glamourer.Structs;
|
||||
using Glamourer.Unlocks;
|
||||
using ImGuiNET;
|
||||
using Lumina.Misc;
|
||||
|
|
@ -61,7 +59,7 @@ public static class UiHelpers
|
|||
{
|
||||
var flags = (sbyte)(currentApply ? currentValue ? 1 : -1 : 0);
|
||||
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, ImGui.GetStyle().ItemInnerSpacing);
|
||||
using (var disabled = ImRaii.Disabled(locked))
|
||||
using (_ = ImRaii.Disabled(locked))
|
||||
{
|
||||
if (new TristateCheckbox(ColorId.TriStateCross.Value(), ColorId.TriStateCheck.Value(), ColorId.TriStateNeutral.Value()).Draw(
|
||||
"##" + label, flags, out flags))
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
using Dalamud.Hooking;
|
||||
using Dalamud.Plugin.Services;
|
||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
||||
using Glamourer.Customization;
|
||||
using Glamourer.Events;
|
||||
using Glamourer.Interop.Structs;
|
||||
using OtterGui.Classes;
|
||||
|
|
@ -15,7 +14,7 @@ namespace Glamourer.Interop;
|
|||
/// Changes in Race, body type or Gender are probably ignored.
|
||||
/// This operates on draw objects, not game objects.
|
||||
/// </summary>
|
||||
public unsafe class ChangeCustomizeService : EventWrapper<Action<Model, Ref<Customize>>, ChangeCustomizeService.Priority>
|
||||
public unsafe class ChangeCustomizeService : EventWrapper<Action<Model, Ref<CustomizeArray>>, ChangeCustomizeService.Priority>
|
||||
{
|
||||
private readonly PenumbraReloaded _penumbraReloaded;
|
||||
private readonly IGameInteropProvider _interop;
|
||||
|
|
@ -81,10 +80,11 @@ public unsafe class ChangeCustomizeService : EventWrapper<Action<Model, Ref<Cust
|
|||
{
|
||||
if (!InUpdate.InMethod)
|
||||
{
|
||||
var customize = new Ref<Customize>(new Customize(*(CustomizeArray*)data));
|
||||
var customize = new Ref<CustomizeArray>(*(CustomizeArray*)data);
|
||||
Invoke(this, (Model)human, customize);
|
||||
((Customize*)data)->Load(customize.Value);
|
||||
*(CustomizeArray*)data = customize.Value;
|
||||
}
|
||||
|
||||
return _changeCustomizeHook.Original(human, data, skipEquipment);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
using System;
|
||||
using Glamourer.Customization;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.Services;
|
||||
using Glamourer.Structs;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
|
@ -70,7 +68,7 @@ public sealed class CharaFile
|
|||
return;
|
||||
|
||||
data.SetItem(slot, item);
|
||||
data.SetStain(slot, (StainId)dye);
|
||||
data.SetStain(slot, dye);
|
||||
flags |= slot.ToFlag();
|
||||
flags |= slot.ToStainFlag();
|
||||
}
|
||||
|
|
@ -94,7 +92,7 @@ public sealed class CharaFile
|
|||
flags |= slot.ToStainFlag();
|
||||
}
|
||||
|
||||
private static CustomizeFlag ParseCustomize(JObject jObj, ref Customize customize)
|
||||
private static CustomizeFlag ParseCustomize(JObject jObj, ref CustomizeArray customize)
|
||||
{
|
||||
CustomizeFlag ret = 0;
|
||||
customize.Race = ParseRace(jObj, ref ret);
|
||||
|
|
@ -149,7 +147,7 @@ public sealed class CharaFile
|
|||
return id;
|
||||
}
|
||||
|
||||
private static void ParseFacial(JObject jObj, ref Customize customize, ref CustomizeFlag application)
|
||||
private static void ParseFacial(JObject jObj, ref CustomizeArray customize, ref CustomizeFlag application)
|
||||
{
|
||||
var jTok = jObj["FacialFeatures"];
|
||||
if (jTok == null)
|
||||
|
|
@ -186,7 +184,7 @@ public sealed class CharaFile
|
|||
customize[CustomizeIndex.LegacyTattoo] = CustomizeValue.Max;
|
||||
}
|
||||
|
||||
private static void ParseHighlights(JObject jObj, ref Customize customize, ref CustomizeFlag application)
|
||||
private static void ParseHighlights(JObject jObj, ref CustomizeArray customize, ref CustomizeFlag application)
|
||||
{
|
||||
var jTok = jObj["EnableHighlights"];
|
||||
if (jTok == null)
|
||||
|
|
@ -242,15 +240,15 @@ public sealed class CharaFile
|
|||
throw new Exception($"Age {age} != Normal is not supported.");
|
||||
}
|
||||
|
||||
private static unsafe void ParseByte(JObject jObj, string property, CustomizeIndex idx, ref Customize customize,
|
||||
private static unsafe void ParseByte(JObject jObj, string property, CustomizeIndex idx, ref CustomizeArray customize,
|
||||
ref CustomizeFlag application)
|
||||
{
|
||||
var jTok = jObj[property];
|
||||
if (jTok == null)
|
||||
return;
|
||||
|
||||
customize.Data.Data[idx.ToByteAndMask().ByteIdx] = jTok.ToObject<byte>();
|
||||
application |= idx.ToFlag();
|
||||
customize.Data[idx.ToByteAndMask().ByteIdx] = jTok.ToObject<byte>();
|
||||
application |= idx.ToFlag();
|
||||
}
|
||||
|
||||
private static SubRace ParseTribe(JObject jObj, ref CustomizeFlag application)
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ public sealed class CmaFile
|
|||
var byteData = Convert.FromHexString(bytes);
|
||||
fixed (byte* ptr = byteData)
|
||||
{
|
||||
data.Customize.Data.Read(ptr);
|
||||
data.Customize.Read(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -64,7 +64,7 @@ public sealed class CmaFile
|
|||
data.SetStain(slot, armor.Stain);
|
||||
}
|
||||
|
||||
data.Customize.Data.Read(ptr);
|
||||
data.Customize.Read(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,10 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using Dalamud.Hooking;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Dalamud.Utility.Signatures;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
||||
using Glamourer.Interop.Structs;
|
||||
using Glamourer.Structs;
|
||||
using OtterGui.Classes;
|
||||
using Penumbra.GameData.Enums;
|
||||
|
||||
|
|
|
|||
|
|
@ -4,13 +4,14 @@ using System.IO;
|
|||
using System.Linq;
|
||||
using Dalamud.Interface.DragDrop;
|
||||
using Dalamud.Interface.Internal.Notifications;
|
||||
using Glamourer.Customization;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.Interop.CharaFile;
|
||||
using Glamourer.Services;
|
||||
using Glamourer.Structs;
|
||||
using ImGuiNET;
|
||||
using OtterGui.Classes;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Files;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
namespace Glamourer.Interop;
|
||||
|
||||
|
|
@ -139,7 +140,7 @@ public class ImportService(CustomizationService _customizations, IDragDropManage
|
|||
return true;
|
||||
}
|
||||
|
||||
public bool SaveDesignAsDat(string path, in Customize input, string description)
|
||||
public bool SaveDesignAsDat(string path, in CustomizeArray input, string description)
|
||||
{
|
||||
if (!Verify(input, out var voice))
|
||||
return false;
|
||||
|
|
@ -168,7 +169,7 @@ public class ImportService(CustomizationService _customizations, IDragDropManage
|
|||
}
|
||||
}
|
||||
|
||||
public bool Verify(in Customize input, out byte voice, byte? inputVoice = null)
|
||||
public bool Verify(in CustomizeArray input, out byte voice, byte? inputVoice = null)
|
||||
{
|
||||
voice = 0;
|
||||
if (_customizations.ValidateClan(input.Clan, input.Race, out _, out _).Length > 0)
|
||||
|
|
|
|||
|
|
@ -6,7 +6,9 @@ using Dalamud.Plugin.Services;
|
|||
using Dalamud.Utility.Signatures;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
||||
using Glamourer.Interop.Structs;
|
||||
using Glamourer.Structs;
|
||||
using Penumbra.GameData;
|
||||
using Penumbra.GameData.DataContainers;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
namespace Glamourer.Interop;
|
||||
|
||||
|
|
@ -14,19 +16,20 @@ public class JobService : IDisposable
|
|||
{
|
||||
private readonly nint _characterDataOffset;
|
||||
|
||||
public readonly IReadOnlyDictionary<byte, Job> Jobs;
|
||||
public readonly IReadOnlyDictionary<ushort, JobGroup> JobGroups;
|
||||
public readonly IReadOnlyList<JobGroup> AllJobGroups;
|
||||
public readonly DictJob Jobs;
|
||||
public readonly DictJobGroup JobGroups;
|
||||
|
||||
public IReadOnlyList<JobGroup> AllJobGroups
|
||||
=> JobGroups.AllJobGroups;
|
||||
|
||||
public event Action<Actor, Job, Job>? JobChanged;
|
||||
|
||||
public JobService(IDataManager gameData, IGameInteropProvider interop)
|
||||
public JobService(DictJob jobs, DictJobGroup jobGroups, IDataManager gameData, IGameInteropProvider interop)
|
||||
{
|
||||
interop.InitializeFromAttributes(this);
|
||||
_characterDataOffset = Marshal.OffsetOf<Character>(nameof(Character.CharacterData));
|
||||
Jobs = GameData.Jobs(gameData);
|
||||
AllJobGroups = GameData.AllJobGroups(gameData);
|
||||
JobGroups = GameData.JobGroups(gameData);
|
||||
Jobs = jobs;
|
||||
JobGroups = jobGroups;
|
||||
_changeJobHook.Enable();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
using System;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Object;
|
||||
using Glamourer.Customization;
|
||||
using Glamourer.Structs;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
using Penumbra.String;
|
||||
|
|
@ -116,8 +114,8 @@ public readonly unsafe struct Actor : IEquatable<Actor>
|
|||
public CharacterWeapon GetOffhand()
|
||||
=> new(AsCharacter->DrawData.Weapon(DrawDataContainer.WeaponSlot.OffHand).ModelId.Value);
|
||||
|
||||
public Customize GetCustomize()
|
||||
=> *(Customize*)&AsCharacter->DrawData.CustomizeData;
|
||||
public CustomizeArray GetCustomize()
|
||||
=> *(CustomizeArray*)&AsCharacter->DrawData.CustomizeData;
|
||||
|
||||
// TODO remove this when available in ClientStructs
|
||||
internal ref CrestFlag CrestBitfield
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
using System;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
||||
using FFXIVClientStructs.FFXIV.Client.Graphics.Scene;
|
||||
using Glamourer.Customization;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
using Object = FFXIVClientStructs.FFXIV.Client.Graphics.Scene.Object;
|
||||
|
|
@ -91,8 +90,8 @@ public readonly unsafe struct Model : IEquatable<Model>
|
|||
public CharacterArmor GetArmor(EquipSlot slot)
|
||||
=> ((CharacterArmor*)&AsHuman->Head)[slot.ToIndex()];
|
||||
|
||||
public Customize GetCustomize()
|
||||
=> *(Customize*)&AsHuman->Customize;
|
||||
public CustomizeArray GetCustomize()
|
||||
=> *(CustomizeArray*)&AsHuman->Customize;
|
||||
|
||||
public (Model Address, CharacterWeapon Data) GetMainhand()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ using Dalamud.Plugin.Services;
|
|||
using Dalamud.Utility.Signatures;
|
||||
using Glamourer.Events;
|
||||
using Glamourer.Interop.Structs;
|
||||
using Penumbra.GameData;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ using Dalamud.Plugin.Services;
|
|||
using FFXIVClientStructs.FFXIV.Client.Game.Character;
|
||||
using Glamourer.Events;
|
||||
using Glamourer.Interop.Structs;
|
||||
using Glamourer.Structs;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
|
|
@ -14,18 +13,15 @@ namespace Glamourer.Interop;
|
|||
public unsafe class WeaponService : IDisposable
|
||||
{
|
||||
private readonly WeaponLoading _event;
|
||||
private readonly CrestService _crestService;
|
||||
private readonly ThreadLocal<bool> _inUpdate = new(() => false);
|
||||
|
||||
|
||||
private readonly delegate* unmanaged[Stdcall]<DrawDataContainer*, uint, ulong, byte, byte, byte, byte, void>
|
||||
_original;
|
||||
|
||||
|
||||
public WeaponService(WeaponLoading @event, IGameInteropProvider interop, CrestService crestService)
|
||||
public WeaponService(WeaponLoading @event, IGameInteropProvider interop)
|
||||
{
|
||||
_event = @event;
|
||||
_crestService = crestService;
|
||||
_event = @event;
|
||||
_loadWeaponHook =
|
||||
interop.HookFromAddress<LoadWeaponDelegate>((nint)DrawDataContainer.MemberFunctionPointers.LoadWeapon, LoadWeaponDetour);
|
||||
_original =
|
||||
|
|
|
|||
|
|
@ -5,13 +5,11 @@ using Dalamud.Game.Command;
|
|||
using Dalamud.Game.Text.SeStringHandling;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Glamourer.Automation;
|
||||
using Glamourer.Customization;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.Events;
|
||||
using Glamourer.Gui;
|
||||
using Glamourer.Interop;
|
||||
using Glamourer.State;
|
||||
using Glamourer.Structs;
|
||||
using ImGuiNET;
|
||||
using OtterGui;
|
||||
using OtterGui.Classes;
|
||||
|
|
|
|||
|
|
@ -2,10 +2,11 @@ using System.Linq;
|
|||
using System.Runtime.CompilerServices;
|
||||
using System.Threading.Tasks;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Glamourer.Customization;
|
||||
using Glamourer.GameData;
|
||||
using OtterGui.Services;
|
||||
using Penumbra.GameData.DataContainers;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
namespace Glamourer.Services;
|
||||
|
||||
|
|
@ -30,13 +31,12 @@ public sealed class CustomizationService(
|
|||
public Task Awaiter
|
||||
=> _task;
|
||||
|
||||
public (Customize NewValue, CustomizeFlag Applied, CustomizeFlag Changed) Combine(Customize oldValues, Customize newValues,
|
||||
public (CustomizeArray NewValue, CustomizeFlag Applied, CustomizeFlag Changed) Combine(CustomizeArray oldValues, CustomizeArray newValues,
|
||||
CustomizeFlag applyWhich, bool allowUnknown)
|
||||
{
|
||||
CustomizeFlag applied = 0;
|
||||
CustomizeFlag changed = 0;
|
||||
Customize ret = default;
|
||||
ret.Load(oldValues);
|
||||
var ret = oldValues;
|
||||
if (applyWhich.HasFlag(CustomizeFlag.Clan))
|
||||
{
|
||||
changed |= ChangeClan(ref ret, newValues.Clan);
|
||||
|
|
@ -247,7 +247,7 @@ public sealed class CustomizationService(
|
|||
}
|
||||
|
||||
/// <summary> Change a clan while keeping all other customizations valid. </summary>
|
||||
public CustomizeFlag ChangeClan(ref Customize customize, SubRace newClan)
|
||||
public CustomizeFlag ChangeClan(ref CustomizeArray customize, SubRace newClan)
|
||||
{
|
||||
if (customize.Clan == newClan)
|
||||
return 0;
|
||||
|
|
@ -271,7 +271,7 @@ public sealed class CustomizationService(
|
|||
}
|
||||
|
||||
/// <summary> Change a gender while keeping all other customizations valid. </summary>
|
||||
public CustomizeFlag ChangeGender(ref Customize customize, Gender newGender)
|
||||
public CustomizeFlag ChangeGender(ref CustomizeArray customize, Gender newGender)
|
||||
{
|
||||
if (customize.Gender == newGender)
|
||||
return 0;
|
||||
|
|
@ -288,7 +288,7 @@ public sealed class CustomizationService(
|
|||
return FixValues(set, ref customize) | CustomizeFlag.Gender;
|
||||
}
|
||||
|
||||
private static CustomizeFlag FixValues(CustomizationSet set, ref Customize customize)
|
||||
private static CustomizeFlag FixValues(CustomizationSet set, ref CustomizeArray customize)
|
||||
{
|
||||
CustomizeFlag flags = 0;
|
||||
foreach (var idx in CustomizationExtensions.AllBasic)
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ using Glamourer.Gui.Tabs.UnlocksTab;
|
|||
using Glamourer.Interop;
|
||||
using Glamourer.Interop.Penumbra;
|
||||
using Glamourer.State;
|
||||
using Glamourer.Structs;
|
||||
using Glamourer.Unlocks;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using OtterGui.Classes;
|
||||
|
|
@ -24,6 +23,7 @@ using OtterGui.Services;
|
|||
using Penumbra.GameData.Actors;
|
||||
using Penumbra.GameData.Data;
|
||||
using Penumbra.GameData.DataContainers;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
namespace Glamourer.Services;
|
||||
|
|
|
|||
|
|
@ -1,13 +1,11 @@
|
|||
using Glamourer.Customization;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.Events;
|
||||
using Glamourer.Structs;
|
||||
using Penumbra.GameData.Actors;
|
||||
using Penumbra.GameData.Enums;
|
||||
using System.Linq;
|
||||
using Dalamud.Game.ClientState.Conditions;
|
||||
using Dalamud.Plugin.Services;
|
||||
using CustomizeIndex = Glamourer.Customization.CustomizeIndex;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
namespace Glamourer.State;
|
||||
|
||||
|
|
@ -34,7 +32,7 @@ public class ActorState
|
|||
public DesignData ModelData;
|
||||
|
||||
/// <summary> The last seen job. </summary>
|
||||
public byte LastJob;
|
||||
public JobId LastJob;
|
||||
|
||||
/// <summary> The Lock-Key locking this state. </summary>
|
||||
public uint Combination;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
using System.Linq;
|
||||
using Dalamud.Game.ClientState.Objects.Enums;
|
||||
using Dalamud.Interface.Internal.Notifications;
|
||||
using Glamourer.Customization;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.Gui;
|
||||
using Glamourer.Interop;
|
||||
|
|
@ -12,7 +11,7 @@ using ImGuiNET;
|
|||
using OtterGui.Classes;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
using CustomizeIndex = Glamourer.Customization.CustomizeIndex;
|
||||
using CustomizeIndex = Penumbra.GameData.Enums.CustomizeIndex;
|
||||
|
||||
namespace Glamourer.State;
|
||||
|
||||
|
|
@ -107,7 +106,7 @@ public unsafe class FunModule : IDisposable
|
|||
}
|
||||
}
|
||||
|
||||
public void ApplyFun(Actor actor, Span<CharacterArmor> armor, ref Customize customize)
|
||||
public void ApplyFun(Actor actor, Span<CharacterArmor> armor, ref CustomizeArray customize)
|
||||
{
|
||||
if (!ValidFunTarget(actor))
|
||||
return;
|
||||
|
|
@ -181,7 +180,7 @@ public unsafe class FunModule : IDisposable
|
|||
}
|
||||
}
|
||||
|
||||
public void ApplyOops(ref Customize customize)
|
||||
public void ApplyOops(ref CustomizeArray customize)
|
||||
{
|
||||
if (_codes.EnabledOops == Race.Unknown)
|
||||
return;
|
||||
|
|
@ -193,7 +192,7 @@ public unsafe class FunModule : IDisposable
|
|||
_customizations.ChangeClan(ref customize, targetClan);
|
||||
}
|
||||
|
||||
public void ApplyIndividual(ref Customize customize)
|
||||
public void ApplyIndividual(ref CustomizeArray customize)
|
||||
{
|
||||
if (!_codes.EnabledIndividual)
|
||||
return;
|
||||
|
|
@ -209,7 +208,7 @@ public unsafe class FunModule : IDisposable
|
|||
}
|
||||
}
|
||||
|
||||
public void Apply63(ref Customize customize)
|
||||
public void Apply63(ref CustomizeArray customize)
|
||||
{
|
||||
if (!_codes.Enabled63 || customize.Race is Race.Hrothgar) // TODO Female Hrothgar
|
||||
return;
|
||||
|
|
@ -217,7 +216,7 @@ public unsafe class FunModule : IDisposable
|
|||
_customizations.ChangeGender(ref customize, customize.Gender is Gender.Male ? Gender.Female : Gender.Male);
|
||||
}
|
||||
|
||||
public void ApplySizing(Actor actor, ref Customize customize)
|
||||
public void ApplySizing(Actor actor, ref CustomizeArray customize)
|
||||
{
|
||||
if (_codes.EnabledSizing == CodeService.Sizing.None)
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -1,11 +1,9 @@
|
|||
using System.Linq;
|
||||
using Glamourer.Customization;
|
||||
using Glamourer.Events;
|
||||
using Glamourer.Interop;
|
||||
using Glamourer.Interop.Penumbra;
|
||||
using Glamourer.Interop.Structs;
|
||||
using Glamourer.Services;
|
||||
using Glamourer.Structs;
|
||||
using Penumbra.Api.Enums;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
|
@ -40,7 +38,7 @@ public class StateApplier(UpdateSlotService _updateSlot, VisorService _visor, We
|
|||
/// Change the customization values of actors either by applying them via update or redrawing,
|
||||
/// this depends on whether the changes include changes to Race, Gender, Body Type or Face.
|
||||
/// </summary>
|
||||
public unsafe void ChangeCustomize(ActorData data, in Customize customize, ActorState? state = null)
|
||||
public unsafe void ChangeCustomize(ActorData data, in CustomizeArray customize, ActorState? _ = null)
|
||||
{
|
||||
foreach (var actor in data.Objects)
|
||||
{
|
||||
|
|
@ -48,15 +46,15 @@ public class StateApplier(UpdateSlotService _updateSlot, VisorService _visor, We
|
|||
if (!mdl.IsCharacterBase)
|
||||
continue;
|
||||
|
||||
var flags = Customize.Compare(mdl.GetCustomize(), customize);
|
||||
var flags = CustomizeArray.Compare(mdl.GetCustomize(), customize);
|
||||
if (!flags.RequiresRedraw() || !mdl.IsHuman)
|
||||
{
|
||||
_changeCustomize.UpdateCustomize(mdl, customize.Data);
|
||||
_changeCustomize.UpdateCustomize(mdl, customize);
|
||||
}
|
||||
else if (data.Objects.Count > 1 && _objects.IsInGPose && !actor.IsGPoseOrCutscene)
|
||||
{
|
||||
var mdlCustomize = (Customize*)&mdl.AsHuman->Customize;
|
||||
mdlCustomize->Load(customize);
|
||||
var mdlCustomize = (CustomizeArray*)&mdl.AsHuman->Customize;
|
||||
*mdlCustomize = customize;
|
||||
_penumbra.RedrawObject(actor, RedrawType.AfterGPose);
|
||||
}
|
||||
else
|
||||
|
|
@ -66,7 +64,7 @@ public class StateApplier(UpdateSlotService _updateSlot, VisorService _visor, We
|
|||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="ChangeCustomize(ActorData, in Customize, ActorState?)"/>
|
||||
/// <inheritdoc cref="ChangeCustomize(ActorData, in CustomizeArray, ActorState?)"/>
|
||||
public ActorData ChangeCustomize(ActorState state, bool apply)
|
||||
{
|
||||
var data = GetData(state);
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Glamourer.Customization;
|
||||
using Glamourer.Events;
|
||||
using Glamourer.Services;
|
||||
using Glamourer.Structs;
|
||||
using Penumbra.GameData.DataContainers;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
|
@ -30,7 +28,7 @@ public class StateEditor
|
|||
|
||||
/// <summary> Change the model id. If the actor is changed from a human to another human, customize and equipData are unused. </summary>
|
||||
/// <remarks> We currently only allow changing things to humans, not humans to monsters. </remarks>
|
||||
public bool ChangeModelId(ActorState state, uint modelId, in Customize customize, nint equipData, StateChanged.Source source,
|
||||
public bool ChangeModelId(ActorState state, uint modelId, in CustomizeArray customize, nint equipData, StateChanged.Source source,
|
||||
out uint oldModelId, uint key = 0)
|
||||
{
|
||||
oldModelId = state.ModelData.ModelId;
|
||||
|
|
@ -57,7 +55,7 @@ public class StateEditor
|
|||
return false;
|
||||
|
||||
// Fix up everything else to make sure the result is a valid human.
|
||||
state.ModelData.Customize = Customize.Default;
|
||||
state.ModelData.Customize = CustomizeArray.Default;
|
||||
state.ModelData.SetDefaultEquipment(_items);
|
||||
state.ModelData.SetHatVisible(true);
|
||||
state.ModelData.SetWeaponVisible(true);
|
||||
|
|
@ -104,8 +102,8 @@ public class StateEditor
|
|||
}
|
||||
|
||||
/// <summary> Change an entire customization array according to flags. </summary>
|
||||
public bool ChangeHumanCustomize(ActorState state, in Customize customizeInput, CustomizeFlag applyWhich, StateChanged.Source source,
|
||||
out Customize old, out CustomizeFlag changed, uint key = 0)
|
||||
public bool ChangeHumanCustomize(ActorState state, in CustomizeArray customizeInput, CustomizeFlag applyWhich, StateChanged.Source source,
|
||||
out CustomizeArray old, out CustomizeFlag changed, uint key = 0)
|
||||
{
|
||||
old = state.ModelData.Customize;
|
||||
changed = 0;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
using Glamourer.Automation;
|
||||
using Glamourer.Customization;
|
||||
using Glamourer.Events;
|
||||
using Glamourer.Interop;
|
||||
using Glamourer.Interop.Penumbra;
|
||||
|
|
@ -12,7 +11,6 @@ using Penumbra.GameData.Structs;
|
|||
using System;
|
||||
using Dalamud.Game.ClientState.Conditions;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Glamourer.Structs;
|
||||
using Penumbra.GameData.DataContainers;
|
||||
|
||||
namespace Glamourer.State;
|
||||
|
|
@ -114,7 +112,7 @@ public class StateListener : IDisposable
|
|||
_creatingIdentifier = actor.GetIdentifier(_actors);
|
||||
|
||||
ref var modelId = ref *(uint*)modelPtr;
|
||||
ref var customize = ref *(Customize*)customizePtr;
|
||||
ref var customize = ref *(CustomizeArray*)customizePtr;
|
||||
if (_autoDesignApplier.Reduce(actor, _creatingIdentifier, out _creatingState))
|
||||
{
|
||||
switch (UpdateBaseData(actor, _creatingState, modelId, customizePtr, equipDataPtr))
|
||||
|
|
@ -140,7 +138,7 @@ public class StateListener : IDisposable
|
|||
ProtectRestrictedGear(equipDataPtr, customize.Race, customize.Gender);
|
||||
}
|
||||
|
||||
private unsafe void OnCustomizeChange(Model model, Ref<Customize> customize)
|
||||
private unsafe void OnCustomizeChange(Model model, Ref<CustomizeArray> customize)
|
||||
{
|
||||
if (!model.IsHuman)
|
||||
return;
|
||||
|
|
@ -156,7 +154,7 @@ public class StateListener : IDisposable
|
|||
UpdateCustomize(actor, state, ref customize.Value, false);
|
||||
}
|
||||
|
||||
private void UpdateCustomize(Actor actor, ActorState state, ref Customize customize, bool checkTransform)
|
||||
private void UpdateCustomize(Actor actor, ActorState state, ref CustomizeArray customize, bool checkTransform)
|
||||
{
|
||||
switch (UpdateBaseData(actor, state, customize, checkTransform))
|
||||
{
|
||||
|
|
@ -515,7 +513,7 @@ public class StateListener : IDisposable
|
|||
if (isHuman)
|
||||
state.BaseData = _manager.FromActor(actor, false, false);
|
||||
else
|
||||
state.BaseData.LoadNonHuman(modelId, *(Customize*)customizeData, equipData);
|
||||
state.BaseData.LoadNonHuman(modelId, *(CustomizeArray*)customizeData, equipData);
|
||||
|
||||
return UpdateState.Change;
|
||||
}
|
||||
|
|
@ -526,7 +524,7 @@ public class StateListener : IDisposable
|
|||
/// only if we kept track of state of someone who went to the aesthetician,
|
||||
/// or if they used other tools to change things.
|
||||
/// </summary>
|
||||
private UpdateState UpdateBaseData(Actor actor, ActorState state, Customize customize, bool checkTransform)
|
||||
private UpdateState UpdateBaseData(Actor actor, ActorState state, CustomizeArray customize, bool checkTransform)
|
||||
{
|
||||
// Customize array does not agree between game object and draw object => transformation.
|
||||
if (checkTransform && !actor.GetCustomize().Equals(customize))
|
||||
|
|
@ -537,7 +535,7 @@ public class StateListener : IDisposable
|
|||
return UpdateState.NoChange; // TODO: handle wrong base data.
|
||||
|
||||
// Update customize base state.
|
||||
state.BaseData.Customize.Load(customize);
|
||||
state.BaseData.Customize = customize;
|
||||
return UpdateState.Change;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,13 +4,11 @@ using System.Collections.Generic;
|
|||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using Dalamud.Plugin.Services;
|
||||
using Glamourer.Customization;
|
||||
using Glamourer.Designs;
|
||||
using Glamourer.Events;
|
||||
using Glamourer.Interop;
|
||||
using Glamourer.Interop.Structs;
|
||||
using Glamourer.Services;
|
||||
using Glamourer.Structs;
|
||||
using Penumbra.GameData.Actors;
|
||||
using Penumbra.GameData.DataContainers;
|
||||
using Penumbra.GameData.Enums;
|
||||
|
|
@ -18,8 +16,15 @@ using Penumbra.GameData.Structs;
|
|||
|
||||
namespace Glamourer.State;
|
||||
|
||||
public class StateManager(ActorManager _actors, ItemManager _items, StateChanged _event, StateApplier _applier, StateEditor _editor,
|
||||
HumanModelList _humans, ICondition _condition, IClientState _clientState)
|
||||
public class StateManager(
|
||||
ActorManager _actors,
|
||||
ItemManager _items,
|
||||
StateChanged _event,
|
||||
StateApplier _applier,
|
||||
StateEditor _editor,
|
||||
HumanModelList _humans,
|
||||
ICondition _condition,
|
||||
IClientState _clientState)
|
||||
: IReadOnlyDictionary<ActorIdentifier, ActorState>
|
||||
{
|
||||
private readonly Dictionary<ActorIdentifier, ActorState> _states = [];
|
||||
|
|
@ -102,7 +107,7 @@ public class StateManager(ActorManager _actors, ItemManager _items, StateChanged
|
|||
// TODO reverse search model data to get model id from model.
|
||||
if (!_humans.IsHuman((uint)actor.AsCharacter->CharacterData.ModelCharaId))
|
||||
{
|
||||
ret.LoadNonHuman((uint)actor.AsCharacter->CharacterData.ModelCharaId, *(Customize*)&actor.AsCharacter->DrawData.CustomizeData,
|
||||
ret.LoadNonHuman((uint)actor.AsCharacter->CharacterData.ModelCharaId, *(CustomizeArray*)&actor.AsCharacter->DrawData.CustomizeData,
|
||||
(nint)(&actor.AsCharacter->DrawData.Head));
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -194,9 +199,9 @@ public class StateManager(ActorManager _actors, ItemManager _items, StateChanged
|
|||
return;
|
||||
|
||||
var gauntlets = _items.Identify(EquipSlot.Hands, offhand.Skeleton, (Variant)offhand.Weapon.Id);
|
||||
offhand.Skeleton = (PrimaryId)(mainhand.Skeleton.Id + 50);
|
||||
offhand.Variant = mainhand.Variant;
|
||||
offhand.Weapon = mainhand.Weapon;
|
||||
offhand.Skeleton = (PrimaryId)(mainhand.Skeleton.Id + 50);
|
||||
offhand.Variant = mainhand.Variant;
|
||||
offhand.Weapon = mainhand.Weapon;
|
||||
ret.SetItem(EquipSlot.Hands, gauntlets);
|
||||
ret.SetStain(EquipSlot.Hands, mainhand.Stain);
|
||||
}
|
||||
|
|
@ -205,10 +210,10 @@ public class StateManager(ActorManager _actors, ItemManager _items, StateChanged
|
|||
|
||||
/// <summary> Turn an actor human. </summary>
|
||||
public void TurnHuman(ActorState state, StateChanged.Source source, uint key = 0)
|
||||
=> ChangeModelId(state, 0, Customize.Default, nint.Zero, source, key);
|
||||
=> ChangeModelId(state, 0, CustomizeArray.Default, nint.Zero, source, key);
|
||||
|
||||
/// <summary> Turn an actor to. </summary>
|
||||
public void ChangeModelId(ActorState state, uint modelId, Customize customize, nint equipData, StateChanged.Source source,
|
||||
public void ChangeModelId(ActorState state, uint modelId, CustomizeArray customize, nint equipData, StateChanged.Source source,
|
||||
uint key = 0)
|
||||
{
|
||||
if (!_editor.ChangeModelId(state, modelId, customize, equipData, source, out var old, key))
|
||||
|
|
@ -233,7 +238,8 @@ public class StateManager(ActorManager _actors, ItemManager _items, StateChanged
|
|||
}
|
||||
|
||||
/// <summary> Change an entire customization array according to flags. </summary>
|
||||
public void ChangeCustomize(ActorState state, in Customize customizeInput, CustomizeFlag apply, StateChanged.Source source, uint key = 0)
|
||||
public void ChangeCustomize(ActorState state, in CustomizeArray customizeInput, CustomizeFlag apply, StateChanged.Source source,
|
||||
uint key = 0)
|
||||
{
|
||||
if (!_editor.ChangeHumanCustomize(state, customizeInput, apply, source, out var old, out var applied, key))
|
||||
return;
|
||||
|
|
@ -447,7 +453,7 @@ public class StateManager(ActorManager _actors, ItemManager _items, StateChanged
|
|||
|
||||
var redraw = state.ModelData.ModelId != state.BaseData.ModelId
|
||||
|| !state.ModelData.IsHuman
|
||||
|| Customize.Compare(state.ModelData.Customize, state.BaseData.Customize).RequiresRedraw();
|
||||
|| CustomizeArray.Compare(state.ModelData.Customize, state.BaseData.Customize).RequiresRedraw();
|
||||
state.ModelData = state.BaseData;
|
||||
state.ModelData.SetIsWet(false);
|
||||
foreach (var index in Enum.GetValues<CustomizeIndex>())
|
||||
|
|
@ -470,7 +476,7 @@ public class StateManager(ActorManager _actors, ItemManager _items, StateChanged
|
|||
actors = ApplyAll(state, redraw, true);
|
||||
Glamourer.Log.Verbose(
|
||||
$"Reset entire state of {state.Identifier.Incognito(null)} to game base. [Affecting {actors.ToLazyString("nothing")}.]");
|
||||
_event.Invoke(StateChanged.Type.Reset, StateChanged.Source.Manual, state, actors, null);
|
||||
_event.Invoke(StateChanged.Type.Reset, StateChanged.Source.Manual, state, actors);
|
||||
}
|
||||
|
||||
public void ResetStateFixed(ActorState state, uint key = 0)
|
||||
|
|
@ -538,7 +544,7 @@ public class StateManager(ActorManager _actors, ItemManager _items, StateChanged
|
|||
if (!GetOrCreate(actor, out var state))
|
||||
return;
|
||||
|
||||
ApplyAll(state, !actor.Model.IsHuman || Customize.Compare(actor.Model.GetCustomize(), state.ModelData.Customize).RequiresRedraw(),
|
||||
ApplyAll(state, !actor.Model.IsHuman || CustomizeArray.Compare(actor.Model.GetCustomize(), state.ModelData.Customize).RequiresRedraw(),
|
||||
false);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Glamourer.Interop.Structs;
|
||||
using Glamourer.Structs;
|
||||
using Penumbra.GameData.Enums;
|
||||
using Penumbra.GameData.Structs;
|
||||
|
||||
|
|
|
|||
|
|
@ -8,10 +8,11 @@ using Dalamud.Plugin.Services;
|
|||
using Dalamud.Utility;
|
||||
using Dalamud.Utility.Signatures;
|
||||
using FFXIVClientStructs.FFXIV.Client.Game.UI;
|
||||
using Glamourer.Customization;
|
||||
using Glamourer.GameData;
|
||||
using Glamourer.Events;
|
||||
using Glamourer.Services;
|
||||
using Lumina.Excel.GeneratedSheets;
|
||||
using Penumbra.GameData.Enums;
|
||||
|
||||
namespace Glamourer.Unlocks;
|
||||
|
||||
|
|
@ -172,7 +173,7 @@ public class CustomizeUnlockManager : IDisposable, ISavable
|
|||
=> UnlockDictionaryHelpers.Load(ToFilename(_saveService.FileNames), _unlocked, id => Unlockable.Any(c => c.Value.Data == id),
|
||||
"customization");
|
||||
|
||||
/// <summary> Create a list of all unlockable hairstyles and facepaints. </summary>
|
||||
/// <summary> Create a list of all unlockable hairstyles and face paints. </summary>
|
||||
private static Dictionary<CustomizeData, (uint Data, string Name)> CreateUnlockableCustomizations(CustomizationService customizations,
|
||||
IDataManager gameData)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 3787e82d1b84d2542b6e4238060d75383a4b12a1
|
||||
Subproject commit d9a962748364b267df1b186cdaebb9ed9f3fceb6
|
||||
Loading…
Add table
Add a link
Reference in a new issue