From 80ad0d774b91349655c7c3ec8ef17d06ad438283 Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Sat, 21 Aug 2021 00:52:46 +0200 Subject: [PATCH] So much stuff... --- .../Customization/ActorCustomization.cs | 56 +- .../Customization/CustomizationId.cs | 2 +- Glamourer.zip | Bin 91343 -> 105713 bytes Glamourer/ActorExtensions.cs | 79 ++ Glamourer/CharacterSave.cs | 275 ++++++ Glamourer/Designs/Design.cs | 22 + Glamourer/Designs/DesignManager.cs | 165 ++++ Glamourer/FileSystem/FileSystem.cs | 153 +++ Glamourer/FileSystem/FileSystemImGui.cs | 57 ++ Glamourer/FileSystem/Folder.cs | 178 ++++ Glamourer/FileSystem/IFolderStructure.cs | 66 ++ Glamourer/FileSystem/Link.cs | 20 + Glamourer/Glamourer.csproj | 12 +- Glamourer/Glamourer.json | 2 +- Glamourer/Gui/Interface.cs | 903 +----------------- Glamourer/Gui/InterfaceActorPanel.cs | 188 ++++ Glamourer/Gui/InterfaceActorSelector.cs | 151 +++ Glamourer/Gui/InterfaceCustomization.cs | 480 ++++++++++ Glamourer/Gui/InterfaceDesigns.cs | 343 +++++++ Glamourer/Gui/InterfaceEquipment.cs | 138 +++ Glamourer/Gui/InterfaceHelpers.cs | 208 ++++ Glamourer/Gui/InterfaceInitialization.cs | 83 ++ Glamourer/Gui/InterfaceMiscellaneous.cs | 64 ++ Glamourer/Main.cs | 319 ++++--- Glamourer/Managers/CommandManager.cs | 73 -- Glamourer/SeFunctions/BaseUiObject.cs | 11 - Glamourer/SeFunctions/GetUiModule.cs | 14 - Glamourer/SeFunctions/ProcessChatBox.cs | 14 - Glamourer/SeFunctions/SeAddressBase.cs | 20 - Glamourer/SeFunctions/SeFunctionBase.cs | 75 -- repo.json | 4 +- 31 files changed, 2949 insertions(+), 1226 deletions(-) create mode 100644 Glamourer/ActorExtensions.cs create mode 100644 Glamourer/CharacterSave.cs create mode 100644 Glamourer/Designs/Design.cs create mode 100644 Glamourer/Designs/DesignManager.cs create mode 100644 Glamourer/FileSystem/FileSystem.cs create mode 100644 Glamourer/FileSystem/FileSystemImGui.cs create mode 100644 Glamourer/FileSystem/Folder.cs create mode 100644 Glamourer/FileSystem/IFolderStructure.cs create mode 100644 Glamourer/FileSystem/Link.cs create mode 100644 Glamourer/Gui/InterfaceActorPanel.cs create mode 100644 Glamourer/Gui/InterfaceActorSelector.cs create mode 100644 Glamourer/Gui/InterfaceCustomization.cs create mode 100644 Glamourer/Gui/InterfaceDesigns.cs create mode 100644 Glamourer/Gui/InterfaceEquipment.cs create mode 100644 Glamourer/Gui/InterfaceHelpers.cs create mode 100644 Glamourer/Gui/InterfaceInitialization.cs create mode 100644 Glamourer/Gui/InterfaceMiscellaneous.cs delete mode 100644 Glamourer/Managers/CommandManager.cs delete mode 100644 Glamourer/SeFunctions/BaseUiObject.cs delete mode 100644 Glamourer/SeFunctions/GetUiModule.cs delete mode 100644 Glamourer/SeFunctions/ProcessChatBox.cs delete mode 100644 Glamourer/SeFunctions/SeAddressBase.cs delete mode 100644 Glamourer/SeFunctions/SeFunctionBase.cs diff --git a/Glamourer.GameData/Customization/ActorCustomization.cs b/Glamourer.GameData/Customization/ActorCustomization.cs index 8d54bda..cbfd3ac 100644 --- a/Glamourer.GameData/Customization/ActorCustomization.cs +++ b/Glamourer.GameData/Customization/ActorCustomization.cs @@ -1,5 +1,6 @@ using System; using System.Runtime.InteropServices; +using Dalamud.Game.ClientState.Actors.Types; using Penumbra.GameData.Enums; namespace Glamourer.Customization @@ -13,6 +14,9 @@ namespace Glamourer.Customization public ref ActorCustomization Value => ref *Address; + + public LazyCustomization(ActorCustomization data) + => Address = &data; } @@ -22,7 +26,36 @@ namespace Glamourer.Customization public const int CustomizationOffset = 0x1898; public const int CustomizationBytes = 26; - private byte _race; + public static ActorCustomization Default = new() + { + Race = Race.Hyur, + Gender = Gender.Male, + BodyType = 1, + Height = 50, + Clan = SubRace.Midlander, + Face = 1, + Hairstyle = 1, + HighlightsOn = false, + SkinColor = 1, + EyeColorRight = 1, + HighlightsColor = 1, + FacialFeatures = 0, + TattooColor = 1, + Eyebrow = 1, + EyeColorLeft = 1, + EyeShape = 1, + Nose = 1, + Jaw = 1, + Mouth = 1, + LipColor = 1, + MuscleMass = 50, + TailShape = 1, + BustSize = 50, + FacePaint = 1, + FacePaintColor = 1, + }; + + public Race Race; private byte _gender; public byte BodyType; public byte Height; @@ -49,12 +82,6 @@ namespace Glamourer.Customization private byte _facePaint; public byte FacePaintColor; - public Race Race - { - get => (Race) (_race > (byte) Race.Midlander ? _race + 1 : _race); - set => _race = (byte) (value > Race.Highlander ? value - 1 : value); - } - public Gender Gender { get => (Gender) (_gender + 1); @@ -117,12 +144,21 @@ namespace Glamourer.Customization public unsafe void Read(IntPtr customizeAddress) { - fixed (byte* ptr = &_race) + fixed (Race* ptr = &Race) { Buffer.MemoryCopy(customizeAddress.ToPointer(), ptr, CustomizationBytes, CustomizationBytes); } } + public void Read(Actor actor) + => Read(actor.Address + CustomizationOffset); + + public ActorCustomization(Actor actor) + : this() + { + Read(actor.Address + CustomizationOffset); + } + public byte this[CustomizationId id] { get => id switch @@ -244,7 +280,7 @@ namespace Glamourer.Customization public unsafe void Write(IntPtr actorAddress) { - fixed (byte* ptr = &_race) + fixed (Race* ptr = &Race) { Buffer.MemoryCopy(ptr, (byte*) actorAddress + CustomizationOffset, CustomizationBytes, CustomizationBytes); } @@ -252,7 +288,7 @@ namespace Glamourer.Customization public unsafe void WriteBytes(byte[] array, int offset = 0) { - fixed (byte* ptr = &_race) + fixed (Race* ptr = &Race) { Marshal.Copy(new IntPtr(ptr), array, offset, CustomizationBytes); } diff --git a/Glamourer.GameData/Customization/CustomizationId.cs b/Glamourer.GameData/Customization/CustomizationId.cs index 19dc004..cbc15f9 100644 --- a/Glamourer.GameData/Customization/CustomizationId.cs +++ b/Glamourer.GameData/Customization/CustomizationId.cs @@ -68,7 +68,7 @@ namespace Glamourer.Customization _ => throw new ArgumentOutOfRangeException(nameof(customizationId), customizationId, null), }; - public static CharaMakeParams.MenuType ToType(this CustomizationId customizationId, Race race = Race.Midlander) + public static CharaMakeParams.MenuType ToType(this CustomizationId customizationId, Race race = Race.Hyur) => customizationId switch { CustomizationId.Race => CharaMakeParams.MenuType.IconSelector, diff --git a/Glamourer.zip b/Glamourer.zip index 2c8d1da30ec1a7fc1aa555a607e201177ce8ce57..84df4849f749475279903a6d9e456fbe1737d7e2 100644 GIT binary patch literal 105713 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

;_*tL34W4^ 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 G(*FQ{X-_}^ literal 91343 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 diff --git a/Glamourer/ActorExtensions.cs b/Glamourer/ActorExtensions.cs new file mode 100644 index 0000000..b2456dd --- /dev/null +++ b/Glamourer/ActorExtensions.cs @@ -0,0 +1,79 @@ +using Dalamud.Game.ClientState.Actors.Types; + +namespace Glamourer +{ + public static class ActorExtensions + { + public const int WetnessOffset = 0x19A5; + public const byte WetnessFlag = 0x10; + public const int StateFlagsOffset = 0x106C; + public const byte HatHiddenFlag = 0x01; + public const byte VisorToggledFlag = 0x10; + public const int AlphaOffset = 0x182C; + public const int WeaponHiddenOffset = 0xF64; + public const byte WeaponHiddenFlag = 0x02; + + public static unsafe bool IsWet(this Actor a) + => (*((byte*) a.Address + WetnessOffset) & WetnessFlag) != 0; + + public static unsafe bool SetWetness(this Actor a, bool value) + { + var current = a.IsWet(); + if (current == value) + return false; + + if (value) + *((byte*) a.Address + WetnessOffset) = (byte) (*((byte*) a.Address + WetnessOffset) | WetnessFlag); + else + *((byte*) a.Address + WetnessOffset) = (byte) (*((byte*) a.Address + WetnessOffset) & ~WetnessFlag); + return true; + } + + public static unsafe ref byte StateFlags(this Actor a) + => ref *((byte*) a.Address + StateFlagsOffset); + + public static bool SetStateFlag(this Actor a, bool value, byte flag) + { + var current = a.StateFlags(); + var previousValue = (current & flag) != 0; + if (previousValue == value) + return false; + + if (value) + a.StateFlags() = (byte) (current | flag); + else + a.StateFlags() = (byte) (current & ~flag); + return true; + } + + public static bool IsHatHidden(this Actor a) + => (a.StateFlags() & HatHiddenFlag) != 0; + + public static unsafe bool IsWeaponHidden(this Actor a) + => (a.StateFlags() & WeaponHiddenFlag) != 0 + && (*((byte*) a.Address + WeaponHiddenOffset) & WeaponHiddenFlag) != 0; + + public static bool IsVisorToggled(this Actor a) + => (a.StateFlags() & VisorToggledFlag) != 0; + + public static bool SetHatHidden(this Actor a, bool value) + => SetStateFlag(a, value, HatHiddenFlag); + + public static unsafe bool SetWeaponHidden(this Actor a, bool value) + { + var ret = SetStateFlag(a, value, WeaponHiddenFlag); + var val = *((byte*) a.Address + WeaponHiddenOffset); + if (value) + *((byte*) a.Address + WeaponHiddenOffset) = (byte) (val | WeaponHiddenFlag); + else + *((byte*) a.Address + WeaponHiddenOffset) = (byte) (val & ~WeaponHiddenFlag); + return ret || ((val & WeaponHiddenFlag) != 0) != value; + } + + public static bool SetVisorToggled(this Actor a, bool value) + => SetStateFlag(a, value, VisorToggledFlag); + + public static unsafe ref float Alpha(this Actor a) + => ref *(float*) ((byte*) a.Address + AlphaOffset); + } +} diff --git a/Glamourer/CharacterSave.cs b/Glamourer/CharacterSave.cs new file mode 100644 index 0000000..19fd66a --- /dev/null +++ b/Glamourer/CharacterSave.cs @@ -0,0 +1,275 @@ +using System; +using Dalamud.Game.ClientState.Actors.Types; +using Glamourer.Customization; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Penumbra.GameData.Structs; + +namespace Glamourer +{ + public class CharacterSaveConverter : JsonConverter + { + public override bool CanConvert(Type objectType) + => objectType == typeof(CharacterSave); + + public override object ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) + { + var token = JToken.Load(reader); + var s = token.ToObject(); + return CharacterSave.FromString(s!); + } + + public override bool CanWrite + => true; + + public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer) + { + if (value != null) + { + var s = ((CharacterSave) value).ToBase64(); + serializer.Serialize(writer, s); + } + } + } + + [JsonConverter(typeof(CharacterSaveConverter))] + public class CharacterSave + { + public const byte CurrentVersion = 2; + public const byte TotalSizeVersion1 = 1 + 1 + 2 + 56 + ActorCustomization.CustomizationBytes; + public const byte TotalSizeVersion2 = 1 + 1 + 2 + 56 + ActorCustomization.CustomizationBytes + 4 + 1; + + public const byte TotalSize = TotalSizeVersion2; + + private readonly byte[] _bytes = new byte[TotalSize]; + + public CharacterSave() + { + _bytes[0] = CurrentVersion; + Alpha = 1.0f; + } + + public CharacterSave Copy() + { + var ret = new CharacterSave(); + _bytes.CopyTo((Span) ret._bytes); + return ret; + } + + public byte Version + => _bytes[0]; + + public bool WriteCustomizations + { + get => (_bytes[1] & 0x01) != 0; + set => _bytes[1] = (byte) (value ? _bytes[1] | 0x01 : _bytes[1] & ~0x01); + } + + public bool IsWet + { + get => (_bytes[1] & 0x02) != 0; + set => _bytes[1] = (byte) (value ? _bytes[1] | 0x02 : _bytes[1] & ~0x02); + } + + public bool SetHatState + { + get => (_bytes[1] & 0x04) != 0; + set => _bytes[1] = (byte)(value ? _bytes[1] | 0x04 : _bytes[1] & ~0x04); + } + + public bool SetWeaponState + { + get => (_bytes[1] & 0x08) != 0; + set => _bytes[1] = (byte)(value ? _bytes[1] | 0x08 : _bytes[1] & ~0x08); + } + + public bool SetVisorState + { + get => (_bytes[1] & 0x10) != 0; + set => _bytes[1] = (byte)(value ? _bytes[1] | 0x10 : _bytes[1] & ~0x10); + } + + public bool WriteProtected + { + get => (_bytes[1] & 0x20) != 0; + set => _bytes[1] = (byte)(value ? _bytes[1] | 0x20 : _bytes[1] & ~0x20); + } + + public byte StateFlags + { + get => _bytes[64 + ActorCustomization.CustomizationBytes]; + set => _bytes[64 + ActorCustomization.CustomizationBytes] = value; + } + + public bool HatState + { + get => (StateFlags & 0x01) == 0; + set => StateFlags = (byte) (value ? StateFlags & ~0x01 : StateFlags | 0x01); + } + + public bool VisorState + { + get => (StateFlags & 0x10) != 0; + set => StateFlags = (byte)(value ? StateFlags | 0x10 : StateFlags & ~0x10); + } + + public bool WeaponState + { + get => (StateFlags & 0x02) == 0; + set => StateFlags = (byte)(value ? StateFlags & ~0x02 : StateFlags | 0x02); + } + + public ActorEquipMask WriteEquipment + { + get => (ActorEquipMask) ((ushort) _bytes[2] | ((ushort) _bytes[3] << 8)); + set + { + _bytes[2] = (byte) ((ushort) value & 0xFF); + _bytes[3] = (byte) ((ushort) value >> 8); + } + } + + public unsafe float Alpha + { + get + { + fixed (byte* ptr = &_bytes[60 + ActorCustomization.CustomizationBytes]) + { + return *(float*) ptr; + } + } + set + { + fixed (byte* ptr = _bytes) + { + *(ptr + 60 + ActorCustomization.CustomizationBytes + 0) = *((byte*) &value + 0); + *(ptr + 60 + ActorCustomization.CustomizationBytes + 1) = *((byte*) &value + 1); + *(ptr + 60 + ActorCustomization.CustomizationBytes + 2) = *((byte*) &value + 2); + *(ptr + 60 + ActorCustomization.CustomizationBytes + 3) = *((byte*) &value + 3); + } + } + } + + public void Load(ActorCustomization customization) + { + WriteCustomizations = true; + customization.WriteBytes(_bytes, 4); + } + + public void Load(ActorEquipment equipment, ActorEquipMask mask = ActorEquipMask.All) + { + WriteEquipment = mask; + equipment.WriteBytes(_bytes, 4 + ActorCustomization.CustomizationBytes); + } + + public string ToBase64() + => Convert.ToBase64String(_bytes); + + private static void CheckSize(int length, int requiredLength) + { + if (length != requiredLength) + throw new Exception( + $"Can not parse Base64 string into CharacterSave:\n\tInvalid size {length} instead of {requiredLength}."); + } + + private static void CheckRange(int idx, byte value, byte min, byte max) + { + if (value < min || value > max) + throw new Exception( + $"Can not parse Base64 string into CharacterSave:\n\tInvalid value {value} in byte {idx}, should be in [{min},{max}]."); + } + + private static void CheckActorMask(byte val1, byte val2) + { + var mask = (ActorEquipMask)((ushort)val1 | ((ushort)val2 << 8)); + if (mask > ActorEquipMask.All) + throw new Exception($"Can not parse Base64 string into CharacterSave:\n\tInvalid value {mask} in byte 3 and 4."); + } + + public void LoadActor(Actor a) + { + WriteCustomizations = true; + Load(new ActorCustomization(a)); + + Load(new ActorEquipment(a), ActorEquipMask.All); + + SetHatState = true; + SetVisorState = true; + SetWeaponState = true; + StateFlags = a.StateFlags(); + + IsWet = a.IsWet(); + Alpha = a.Alpha(); + } + + public void Apply(Actor a) + { + if (WriteCustomizations) + Customizations.Write(a.Address); + if (WriteEquipment != ActorEquipMask.None) + Equipment.Write(a.Address, WriteEquipment, WriteEquipment); + a.SetWetness(IsWet); + a.Alpha() = Alpha; + if ((_bytes[1] & 0b11100) == 0b11100) + a.StateFlags() = StateFlags; + else + { + if (SetHatState) + a.SetHatHidden(HatState); + if (SetVisorState) + a.SetVisorToggled(VisorState); + if (SetWeaponState) + a.SetWeaponHidden(WeaponState); + } + } + + public void Load(string base64) + { + var bytes = Convert.FromBase64String(base64); + switch (bytes[0]) + { + case 1: + CheckSize(bytes.Length, TotalSizeVersion1); + CheckRange(2, bytes[1], 0, 1); + Alpha = 1.0f; + bytes[0] = CurrentVersion; + break; + case 2: + CheckSize(bytes.Length, TotalSizeVersion2); + CheckRange(2, bytes[1], 0, 0x3F); + break; + default: throw new Exception($"Can not parse Base64 string into CharacterSave:\n\tInvalid Version {bytes[0]}."); + } + CheckActorMask(bytes[2], bytes[3]); + bytes.CopyTo(_bytes, 0); + } + + public static CharacterSave FromString(string base64) + { + var ret = new CharacterSave(); + ret.Load(base64); + return ret; + } + + public unsafe ref ActorCustomization Customizations + { + get + { + fixed (byte* ptr = _bytes) + { + return ref *((ActorCustomization*) (ptr + 4)); + } + } + } + + public ActorEquipment Equipment + { + get + { + var ret = new ActorEquipment(); + ret.FromBytes(_bytes, 4 + ActorCustomization.CustomizationBytes); + return ret; + } + } + } +} diff --git a/Glamourer/Designs/Design.cs b/Glamourer/Designs/Design.cs new file mode 100644 index 0000000..9251a73 --- /dev/null +++ b/Glamourer/Designs/Design.cs @@ -0,0 +1,22 @@ +using Glamourer.FileSystem; + +namespace Glamourer.Designs +{ + public class Design : IFileSystemBase + { + public Folder Parent { get; set; } + public string Name { get; set; } + + public CharacterSave Data { get; set; } + + internal Design(Folder parent, string name) + { + Parent = parent; + Name = name; + Data = new CharacterSave(); + } + + public override string ToString() + => Name; + } +} diff --git a/Glamourer/Designs/DesignManager.cs b/Glamourer/Designs/DesignManager.cs new file mode 100644 index 0000000..908776f --- /dev/null +++ b/Glamourer/Designs/DesignManager.cs @@ -0,0 +1,165 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.IO; +using System.Linq; +using Dalamud.Plugin; +using Glamourer.FileSystem; +using Newtonsoft.Json; + +namespace Glamourer.Designs +{ + public class DesignManager + { + public const string FileName = "Designs.json"; + private readonly FileInfo _saveFile; + + public SortedList Designs = null!; + public FileSystem.FileSystem FileSystem { get; } = new(); + + public DesignManager(DalamudPluginInterface pi) + { + var saveFolder = new DirectoryInfo(pi.GetPluginConfigDirectory()); + if (!saveFolder.Exists) + Directory.CreateDirectory(saveFolder.FullName); + + _saveFile = new FileInfo(Path.Combine(saveFolder.FullName, FileName)); + + LoadFromFile(); + } + + private void BuildStructure() + { + FileSystem.Clear(); + var anyChanges = false; + foreach (var kvp in Designs.ToArray()) + { + var path = kvp.Key; + var save = kvp.Value; + + try + { + var (folder, name) = FileSystem.CreateAllFolders(path); + var design = new Design(folder, name) { Data = save }; + folder.FindOrAddChild(design); + var fixedPath = design.FullName(); + if (!string.Equals(fixedPath, path, StringComparison.InvariantCultureIgnoreCase)) + { + Designs.Remove(path); + Designs[fixedPath] = save; + anyChanges = true; + PluginLog.Debug($"Problem loading saved designs, {path} was renamed to {fixedPath}."); + } + } + catch (Exception e) + { + PluginLog.Error($"Problem loading saved designs, {path} was removed because:\n{e}"); + Designs.Remove(path); + } + } + + if (anyChanges) + SaveToFile(); + } + + private bool UpdateRoot(string oldPath, Design child) + { + var newPath = child.FullName(); + if (string.Equals(newPath, oldPath, StringComparison.InvariantCultureIgnoreCase)) + return false; + + Designs.Remove(oldPath); + Designs[child.FullName()] = child.Data; + return true; + } + + private void UpdateChild(string oldRootPath, string newRootPath, Design child) + { + var newPath = child.FullName(); + var oldPath = $"{oldRootPath}{newPath.Remove(0, newRootPath.Length)}"; + Designs.Remove(oldPath); + Designs[newPath] = child.Data; + } + + public void DeleteAllChildren(IFileSystemBase root, bool deleteEmpty) + { + if (root is Folder f) + { + foreach (var child in f.AllLeaves(SortMode.Lexicographical)) + Designs.Remove(child.FullName()); + } + var fullPath = root.FullName(); + root.Parent.RemoveChild(root, deleteEmpty); + Designs.Remove(fullPath); + + SaveToFile(); + } + + public void UpdateAllChildren(string oldPath, IFileSystemBase root) + { + var changes = false; + switch (root) + { + case Design d: + changes |= UpdateRoot(oldPath, d); + break; + case Folder f: + { + var newRootPath = root.FullName(); + if (!string.Equals(oldPath, newRootPath, StringComparison.InvariantCultureIgnoreCase)) + { + changes = true; + foreach (var descendant in f.AllLeaves(SortMode.Lexicographical).Where(l => l is Design).Cast()) + UpdateChild(oldPath, newRootPath, descendant); + } + + break; + } + } + + if (changes) + SaveToFile(); + } + + public void SaveToFile() + { + try + { + var data = JsonConvert.SerializeObject(Designs, Formatting.Indented); + File.WriteAllText(_saveFile.FullName, data); + } + catch (Exception e) + { + PluginLog.Error($"Could not write to save file {_saveFile.FullName}:\n{e}"); + } + } + + public void LoadFromFile() + { + _saveFile.Refresh(); + SortedList? designs = null; + if (_saveFile.Exists) + try + { + var data = File.ReadAllText(_saveFile.FullName); + designs = JsonConvert.DeserializeObject>(data); + } + catch (Exception e) + { + PluginLog.Error($"Could not load save file {_saveFile.FullName}:\n{e}"); + } + + if (designs == null) + { + Designs = new SortedList(); + SaveToFile(); + } + else + { + Designs = designs; + } + + BuildStructure(); + } + } +} diff --git a/Glamourer/FileSystem/FileSystem.cs b/Glamourer/FileSystem/FileSystem.cs new file mode 100644 index 0000000..ca71f74 --- /dev/null +++ b/Glamourer/FileSystem/FileSystem.cs @@ -0,0 +1,153 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Glamourer.FileSystem +{ + public class FileSystem + { + public Folder Root { get; } = Folder.CreateRoot(); + + public void Clear() + => Root.Children.Clear(); + + // Find a specific child by its path from Root. + // Returns true if the folder was found, and false if not. + // The out parameter will contain the furthest existing folder. + public bool Find(string path, out IFileSystemBase child) + { + var split = Split(path); + var folder = Root; + child = Root; + foreach (var part in split) + { + if (!folder.FindChild(part, out var c)) + { + child = folder; + return false; + } + + child = c; + if (c is not Folder f) + return part == split.Last(); + + folder = f; + } + + return true; + } + + public Folder CreateAllFolders(IEnumerable names) + { + var last = Root; + foreach (var name in names) + last = last.FindOrCreateSubFolder(name).Item1; + return last; + } + + public (Folder, string) CreateAllFolders(string path) + { + if (!path.Any()) + return (Root, string.Empty); + + var split = Split(path); + if (split.Length == 1) + return (Root, path); + + return (CreateAllFolders(split.Take(split.Length - 1)), split.Last()); + } + + public bool Rename(IFileSystemBase child, string newName) + { + if (ReferenceEquals(child, Root)) + throw new InvalidOperationException("Can not rename root."); + + newName = FixName(newName); + if (child.Name == newName) + return false; + + if (child.Parent.FindChild(newName, out var preExisting)) + { + if (MergeIfFolders(child, preExisting, false)) + return true; + + throw new Exception($"Can not rename {child.Name} in {child.Parent.FullName()} to {newName} because {newName} already exists."); + } + + var parent = child.Parent; + parent.RemoveChildIgnoreEmpty(child); + child.Name = newName; + parent.FindOrAddChild(child); + return true; + } + + public bool Move(IFileSystemBase child, Folder newParent, bool deleteEmpty) + { + var oldParent = child.Parent; + if (ReferenceEquals(newParent, oldParent)) + return false; + + // Moving into its own subfolder or itself is not allowed. + if (child.IsFolder(out var f) + && (ReferenceEquals(newParent, f) + || newParent.FullName().StartsWith(f.FullName(), StringComparison.InvariantCultureIgnoreCase))) + return false; + + if (newParent.FindChild(child.Name, out var conflict)) + { + if (MergeIfFolders(child, conflict, deleteEmpty)) + return true; + + throw new Exception($"Can not move {child.Name} into {newParent.FullName()} because {conflict.FullName()} already exists."); + } + + oldParent.RemoveChild(child, deleteEmpty); + newParent.FindOrAddChild(child); + return true; + } + + public bool Merge(Folder source, Folder target, bool deleteEmpty) + { + if (ReferenceEquals(source, target)) + return false; + + if (!source.Children.Any()) + { + if (deleteEmpty) + { + source.Parent.RemoveChild(source, true); + return true; + } + + return false; + } + + while (source.Children.Count > 0) + Move(source.Children.First(), target, deleteEmpty); // Can throw. + + source.Parent.RemoveChild(source, deleteEmpty); + + return true; + } + + private bool MergeIfFolders(IFileSystemBase source, IFileSystemBase target, bool deleteEmpty) + { + if (source is Folder childF && target.IsFolder(out var preF)) + { + Merge(childF, preF, deleteEmpty); + return true; + } + + return false; + } + + private static string[] Split(string path) + => path.Split(new[] + { + '/', + }, StringSplitOptions.RemoveEmptyEntries); + + private static string FixName(string name) + => name.Replace('/', '\\'); + } +} diff --git a/Glamourer/FileSystem/FileSystemImGui.cs b/Glamourer/FileSystem/FileSystemImGui.cs new file mode 100644 index 0000000..a358be2 --- /dev/null +++ b/Glamourer/FileSystem/FileSystemImGui.cs @@ -0,0 +1,57 @@ +using System; +using System.Linq; +using Dalamud.Plugin; +using ImGuiNET; + +namespace Glamourer.FileSystem +{ + public static class FileSystemImGui + { + public const string DraggedObjectLabel = "FSDrag"; + + private static unsafe bool IsDropping(string name) + => ImGui.AcceptDragDropPayload(name).NativePtr != null; + + private static IFileSystemBase? _draggedObject = null; + + public static bool DragDropTarget(FileSystem fs, IFileSystemBase child, out string oldPath, out IFileSystemBase? draggedChild) + { + oldPath = string.Empty; + draggedChild = null; + var ret = false; + if (!ImGui.BeginDragDropTarget()) + return ret; + + if (IsDropping(DraggedObjectLabel)) + { + if (_draggedObject != null) + try + { + oldPath = _draggedObject.FullName(); + draggedChild = _draggedObject; + ret = fs.Move(_draggedObject, child.IsFolder(out var folder) ? folder : child.Parent, false); + } + catch (Exception e) + { + PluginLog.Error($"Could not drag {_draggedObject.Name} onto {child.FullName()}:\n{e}"); + } + + _draggedObject = null; + } + + ImGui.EndDragDropTarget(); + return ret; + } + + public static void DragDropSource(IFileSystemBase child) + { + if (!ImGui.BeginDragDropSource()) + return; + + ImGui.SetDragDropPayload(DraggedObjectLabel, IntPtr.Zero, 0); + ImGui.Text($"Moving {child.Name}..."); + _draggedObject = child; + ImGui.EndDragDropSource(); + } + } +} diff --git a/Glamourer/FileSystem/Folder.cs b/Glamourer/FileSystem/Folder.cs new file mode 100644 index 0000000..de5d699 --- /dev/null +++ b/Glamourer/FileSystem/Folder.cs @@ -0,0 +1,178 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; + +namespace Glamourer.FileSystem +{ + public enum SortMode + { + FoldersFirst = 0x00, + Lexicographical = 0x01, + } + + public class Folder : IFileSystemBase + { + public Folder Parent { get; set; } + public string Name { get; set; } + public readonly List Children = new(); + + public Folder(Folder parent, string name) + { + Parent = parent; + Name = name; + } + + public override string ToString() + => this.FullName(); + + // Return the number of all leaves with this folder in their path. + public int TotalDescendantLeaves() + { + var sum = 0; + foreach (var child in Children) + { + switch (child) + { + case Folder f: + sum += f.TotalDescendantLeaves(); + break; + case Link l: + sum += l.Data is Folder fl ? fl.TotalDescendantLeaves() : 1; + break; + default: + ++sum; + break; + } + } + + return sum; + } + + // Return all descendant mods in the specified order. + public IEnumerable AllLeaves(SortMode mode) + { + return GetSortedEnumerator(mode).SelectMany(f => + { + if (f.IsFolder(out var folder)) + return folder.AllLeaves(mode); + + return new[] + { + f, + }; + }); + } + + public IEnumerable AllChildren(SortMode mode) + => GetSortedEnumerator(mode); + + // Get an enumerator for actually sorted objects instead of folder-first objects. + private IEnumerable GetSortedEnumerator(SortMode mode) + { + switch (mode) + { + case SortMode.FoldersFirst: + foreach (var child in Children.Where(c => c.IsFolder())) + yield return child; + + foreach (var child in Children.Where(c => c.IsLeaf())) + yield return child; + + break; + case SortMode.Lexicographical: + foreach (var child in Children) + yield return child; + + break; + default: throw new InvalidEnumArgumentException(); + } + } + + internal static Folder CreateRoot() + => new(null!, ""); + + // Find a subfolder by name. Returns true and sets folder to it if it exists. + public bool FindChild(string name, out IFileSystemBase ret) + { + var idx = Search(name); + ret = idx >= 0 ? Children[idx] : this; + return idx >= 0; + } + + // Checks if an equivalent child to child already exists and returns its index. + // If it does not exist, inserts child as a child and returns the new index. + // Also sets this as childs parent. + public int FindOrAddChild(IFileSystemBase child) + { + var idx = Search(child); + if (idx >= 0) + return idx; + + idx = ~idx; + Children.Insert(idx, child); + child.Parent = this; + return idx; + } + + // Checks if an equivalent child to child already exists and throws if it does. + // If it does not exist, inserts child as a child and returns the new index. + // Also sets this as childs parent. + public int AddChild(IFileSystemBase child) + { + var idx = Search(child); + if (idx >= 0) + throw new Exception("Could not add child: Child of that name already exists."); + + idx = ~idx; + Children.Insert(idx, child); + child.Parent = this; + return idx; + } + + // Checks if a subfolder with the given name already exists and returns it and its index. + // If it does not exists, creates and inserts it and returns the new subfolder and its index. + public (Folder, int) FindOrCreateSubFolder(string name) + { + var subFolder = new Folder(this, name); + var idx = FindOrAddChild(subFolder); + var child = Children[idx]; + if (!child.IsFolder(out var folder)) + throw new Exception($"The child {name} already exists in {this.FullName()} but is not a folder."); + + return (folder, idx); + } + + // Remove child if it exists. + // If this folder is empty afterwards and deleteEmpty is true, remove it from its parent. + public void RemoveChild(IFileSystemBase child, bool deleteEmpty) + { + RemoveChildIgnoreEmpty(child); + if (deleteEmpty) + CheckEmpty(); + } + + private void CheckEmpty() + { + if (Children.Count == 0) + Parent?.RemoveChild(this, true); + } + + // Remove a child but do not remove this folder from its parent if it is empty afterwards. + internal void RemoveChildIgnoreEmpty(IFileSystemBase folder) + { + var idx = Search(folder); + if (idx < 0) + return; + + Children[idx].Parent = null!; + Children.RemoveAt(idx); + } + + private int Search(string name) + => Children.BinarySearch(new FileSystemObject(name), FolderStructureComparer.Default); + + private int Search(IFileSystemBase child) + => Children.BinarySearch(child, FolderStructureComparer.Default); + } +} diff --git a/Glamourer/FileSystem/IFolderStructure.cs b/Glamourer/FileSystem/IFolderStructure.cs new file mode 100644 index 0000000..f4bf01b --- /dev/null +++ b/Glamourer/FileSystem/IFolderStructure.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Glamourer.Designs; + +namespace Glamourer.FileSystem +{ + internal class FolderStructureComparer : IComparer + { + // Compare only the direct folder names since this is only used inside an enumeration of children of one folder. + public static int Cmp(IFileSystemBase x, IFileSystemBase y) + => ReferenceEquals(x, y) ? 0 : string.Compare(x.Name, y.Name, StringComparison.InvariantCultureIgnoreCase); + + public int Compare(IFileSystemBase x, IFileSystemBase y) + => Cmp(x, y); + + internal static readonly FolderStructureComparer Default = new(); + } + + public interface IFileSystemBase + { + public Folder Parent { get; set; } + public string Name { get; set; } + } + + public static class FileSystemExtensions + { + public static string FullName(this IFileSystemBase data) + => data.Parent?.Name.Any() ?? false ? $"{data.Parent.FullName()}/{data.Name}" : data.Name; + + public static bool IsLeaf(this IFileSystemBase data) + => data is not Folder && data is not Link { Data: Folder }; + + public static bool IsFolder(this IFileSystemBase data) + => data.IsFolder(out _); + + public static bool IsFolder(this IFileSystemBase data, out Folder folder) + { + switch (data) + { + case Folder f: + folder = f; + return true; + case Link { Data: Folder fl }: + folder = fl; + return true; + default: + folder = null!; + return false; + } + } + } + + + public class FileSystemObject : IFileSystemBase + { + public FileSystemObject(string name) + => Name = name; + + public Folder Parent { get; set; } = null!; + public string Name { get; set; } + + public string FullName() + => Name; + } +} diff --git a/Glamourer/FileSystem/Link.cs b/Glamourer/FileSystem/Link.cs new file mode 100644 index 0000000..e064982 --- /dev/null +++ b/Glamourer/FileSystem/Link.cs @@ -0,0 +1,20 @@ +using Glamourer.Designs; + +namespace Glamourer.FileSystem +{ + public class Link : IFileSystemBase + { + public Folder Parent { get; set; } + + public string Name { get; set; } + + public IFileSystemBase Data { get; } + + public Link(Folder parent, string name, IFileSystemBase data) + { + Parent = parent; + Name = name; + Data = data; + } + } +} diff --git a/Glamourer/Glamourer.csproj b/Glamourer/Glamourer.csproj index 16644ef..9249764 100644 --- a/Glamourer/Glamourer.csproj +++ b/Glamourer/Glamourer.csproj @@ -4,8 +4,8 @@ preview Glamourer Glamourer - 0.0.2.0 - 0.0.2.0 + 0.0.3.0 + 0.0.3.0 SoftOtter Glamourer Copyright © 2020 @@ -91,13 +91,13 @@ - - PreserveNewest - + - + + PreserveNewest + diff --git a/Glamourer/Glamourer.json b/Glamourer/Glamourer.json index f90f939..6556e2d 100644 --- a/Glamourer/Glamourer.json +++ b/Glamourer/Glamourer.json @@ -3,7 +3,7 @@ "Name": "Glamourer", "Description": "Adds functionality to change appearance of actors. Requires Penumbra to be installed and activated to work.", "InternalName": "Glamourer", - "AssemblyVersion": "0.0.2.0", + "AssemblyVersion": "0.0.3.0", "RepoUrl": "https://github.com/Ottermandias/Glamourer", "ApplicableVersion": "any", "DalamudApiLevel": 3, diff --git a/Glamourer/Gui/Interface.cs b/Glamourer/Gui/Interface.cs index 848e906..60456a3 100644 --- a/Glamourer/Gui/Interface.cs +++ b/Glamourer/Gui/Interface.cs @@ -2,397 +2,55 @@ using System.Collections.Generic; using System.Linq; using System.Numerics; -using System.Reflection; -using System.Windows.Forms; using Dalamud.Game.ClientState.Actors; -using Dalamud.Game.ClientState.Actors.Types; -using Dalamud.Interface; -using Dalamud.Plugin; -using Glamourer.Customization; +using Glamourer.Designs; using ImGuiNET; -using Lumina.Excel.GeneratedSheets; -using Penumbra.Api; using Penumbra.GameData; using Penumbra.GameData.Enums; -using Penumbra.GameData.Structs; -using Penumbra.PlayerWatch; -using Race = Penumbra.GameData.Enums.Race; namespace Glamourer.Gui { - internal partial class Interface - { - // Push the stain color to type and if it is too bright, turn the text color black. - // Return number of pushed styles. - private static int PushColor(Stain stain, ImGuiCol type = ImGuiCol.Button) - { - ImGui.PushStyleColor(type, stain.RgbaColor); - if (stain.Intensity > 127) - { - ImGui.PushStyleColor(ImGuiCol.Text, 0xFF101010); - return 2; - } - - return 1; - } - - // Update actors without triggering PlayerWatcher Events, - // then manually redraw using Penumbra. - public void UpdateActors(Actor actor) - { - var newEquip = _playerWatcher.UpdateActorWithoutEvent(actor); - GlamourerPlugin.Penumbra?.RedrawActor(actor, RedrawType.WithSettings); - - // Special case for carrying over changes to the gPose actor to the regular player actor, too. - var gPose = _actors[GPoseActorId]; - var player = _actors[0]; - if (gPose != null && actor.Address == gPose.Address && player != null) - newEquip.Write(player.Address); - } - - // Go through a whole customization struct and fix up all settings that need fixing. - private static void FixUpAttributes(LazyCustomization customization) - { - var set = GlamourerPlugin.Customization.GetList(customization.Value.Clan, customization.Value.Gender); - foreach (CustomizationId id in Enum.GetValues(typeof(CustomizationId))) - { - switch (id) - { - case CustomizationId.Race: break; - case CustomizationId.Clan: break; - case CustomizationId.BodyType: break; - case CustomizationId.Gender: break; - case CustomizationId.FacialFeaturesTattoos: break; - case CustomizationId.HighlightsOnFlag: break; - case CustomizationId.Face: - if (customization.Value.Race != Race.Hrothgar) - goto default; - break; - default: - var count = set.Count(id); - if (customization.Value[id] >= count) - if (count == 0) - customization.Value[id] = 0; - else - customization.Value[id] = set.Data(id, 0).Value; - break; - } - } - } - - // Change a race and fix up all required customizations afterwards. - private static bool ChangeRace(LazyCustomization customization, SubRace clan) - { - if (clan == customization.Value.Clan) - return false; - - var race = clan.ToRace(); - customization.Value.Race = race; - customization.Value.Clan = clan; - - customization.Value.Gender = race switch - { - Race.Hrothgar => Gender.Male, - Race.Viera => Gender.Female, - _ => customization.Value.Gender, - }; - - FixUpAttributes(customization); - - return true; - } - - // Change a gender and fix up all required customizations afterwards. - private static bool ChangeGender(LazyCustomization customization, Gender gender) - { - if (gender == customization.Value.Gender) - return false; - - customization.Value.Gender = gender; - FixUpAttributes(customization); - - return true; - } - } - - internal partial class Interface - { - private const float ColorButtonWidth = 22.5f; - private const float ColorComboWidth = 140f; - private const float ItemComboWidth = 300f; - - private ComboWithFilter CreateDefaultStainCombo(IReadOnlyList stains) - => new("##StainCombo", ColorComboWidth, ColorButtonWidth, stains, - s => s.Name.ToString()) - { - Flags = ImGuiComboFlags.NoArrowButton | ImGuiComboFlags.HeightLarge, - PreList = () => - { - ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, Vector2.Zero); - ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, Vector2.Zero); - ImGui.PushStyleVar(ImGuiStyleVar.FrameRounding, 0); - }, - PostList = () => { ImGui.PopStyleVar(3); }, - CreateSelectable = s => - { - var push = PushColor(s); - var ret = ImGui.Button($"{s.Name}##Stain{(byte) s.RowIndex}", - Vector2.UnitX * (ColorComboWidth - ImGui.GetStyle().ScrollbarSize)); - ImGui.PopStyleColor(push); - return ret; - }, - ItemsAtOnce = 12, - }; - - - private ComboWithFilter CreateItemCombo(EquipSlot slot, IReadOnlyList items) - => new($"{_equipSlotNames[slot]}##Equip", ItemComboWidth, ItemComboWidth, items, i => i.Name) - { - Flags = ImGuiComboFlags.HeightLarge, - }; - - private (ComboWithFilter, ComboWithFilter) CreateCombos(EquipSlot slot, IReadOnlyList items, - ComboWithFilter defaultStain) - => (CreateItemCombo(slot, items), new ComboWithFilter($"##{slot}Stain", defaultStain)); - } - - internal partial class Interface - { - private bool DrawStainSelector(ComboWithFilter stainCombo, EquipSlot slot, StainId stainIdx) - { - stainCombo.PostPreview = null; - if (_stains.TryGetValue((byte) stainIdx, out var stain)) - { - var previewPush = PushColor(stain, ImGuiCol.FrameBg); - stainCombo.PostPreview = () => ImGui.PopStyleColor(previewPush); - } - - if (stainCombo.Draw(string.Empty, out var newStain) && _player != null && !newStain.RowIndex.Equals(stainIdx)) - { - newStain.Write(_player.Address, slot); - return true; - } - - return false; - } - - private bool DrawItemSelector(ComboWithFilter equipCombo, Lumina.Excel.GeneratedSheets.Item? item) - { - var currentName = item?.Name.ToString() ?? "Nothing"; - if (equipCombo.Draw(currentName, out var newItem, _itemComboWidth) && _player != null && newItem.Base.RowId != item?.RowId) - { - newItem.Write(_player.Address); - return true; - } - - return false; - } - - private bool DrawEquip(EquipSlot slot, ActorArmor equip) - { - var (equipCombo, stainCombo) = _combos[slot]; - - var ret = DrawStainSelector(stainCombo, slot, equip.Stain); - ImGui.SameLine(); - var item = _identifier.Identify(equip.Set, new WeaponType(), equip.Variant, slot); - ret |= DrawItemSelector(equipCombo, item); - - return ret; - } - - private bool DrawWeapon(EquipSlot slot, ActorWeapon weapon) - { - var (equipCombo, stainCombo) = _combos[slot]; - - var ret = DrawStainSelector(stainCombo, slot, weapon.Stain); - ImGui.SameLine(); - var item = _identifier.Identify(weapon.Set, weapon.Type, weapon.Variant, slot); - ret |= DrawItemSelector(equipCombo, item); - - return ret; - } - } - - internal partial class Interface - { - private static bool DrawColorPickerPopup(string label, CustomizationSet set, CustomizationId id, out Customization.Customization value) - { - value = default; - if (!ImGui.BeginPopup(label, ImGuiWindowFlags.AlwaysAutoResize)) - return false; - - var ret = false; - var count = set.Count(id); - using var raii = new ImGuiRaii().PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero) - .PushStyle(ImGuiStyleVar.FrameRounding, 0); - for (var i = 0; i < count; ++i) - { - var custom = set.Data(id, i); - if (ImGui.ColorButton((i + 1).ToString(), ImGui.ColorConvertU32ToFloat4(custom.Color))) - { - value = custom; - ret = true; - ImGui.CloseCurrentPopup(); - } - - if (i % 8 != 7) - ImGui.SameLine(); - } - - ImGui.EndPopup(); - return ret; - } - - private Vector2 _iconSize = Vector2.Zero; - private Vector2 _actualIconSize = Vector2.Zero; - private float _raceSelectorWidth = 0; - private float _inputIntSize = 0; - private float _comboSelectorSize = 0; - private float _percentageSize = 0; - private float _itemComboWidth = 0; - - private bool InputInt(string label, ref int value, int minValue, int maxValue) - { - var ret = false; - var tmp = value + 1; - ImGui.SetNextItemWidth(_inputIntSize); - if (ImGui.InputInt(label, ref tmp, 1) && tmp != value + 1 && tmp >= minValue && tmp <= maxValue) - { - value = tmp - 1; - ret = true; - } - - if (ImGui.IsItemHovered()) - ImGui.SetTooltip($"Input Range: [{minValue}, {maxValue}]"); - - return ret; - } - - private static (int, Customization.Customization) GetCurrentCustomization(LazyCustomization customization, CustomizationId id, - CustomizationSet set) - { - var current = set.DataByValue(id, customization.Value[id], out var custom); - if (current < 0) - { - PluginLog.Warning($"Read invalid customization value {customization.Value[id]} for {id}."); - current = 0; - custom = set.Data(id, 0); - } - - return (current, custom!.Value); - } - - private bool DrawColorPicker(string label, string tooltip, LazyCustomization customization, CustomizationId id, - CustomizationSet set) - { - var ret = false; - var count = set.Count(id); - - var (current, custom) = GetCurrentCustomization(customization, id, set); - - var popupName = $"Color Picker##{id}"; - if (ImGui.ColorButton($"{current + 1}##color_{id}", ImGui.ColorConvertU32ToFloat4(custom.Color), ImGuiColorEditFlags.None, - _actualIconSize)) - ImGui.OpenPopup(popupName); - - ImGui.SameLine(); - - using (var group = ImGuiRaii.NewGroup()) - { - if (InputInt($"##text_{id}", ref current, 1, count)) - { - customization.Value[id] = set.Data(id, current - 1).Value; - ret = true; - } - - - ImGui.Text(label); - if (tooltip.Any() && ImGui.IsItemHovered()) - ImGui.SetTooltip(tooltip); - } - - if (!DrawColorPickerPopup(popupName, set, id, out var newCustom)) - return ret; - - customization.Value[id] = newCustom.Value; - ret = true; - - return ret; - } - } - internal partial class Interface : IDisposable { - public const int GPoseActorId = 201; - private const string PluginName = "Glamourer"; + public const float SelectorWidth = 200; + public const float MinWindowWidth = 675; + public const int GPoseActorId = 201; + private const string PluginName = "Glamourer"; private readonly string _glamourerHeader; private readonly IReadOnlyDictionary _stains; - private readonly IReadOnlyDictionary> _equip; private readonly ActorTable _actors; private readonly IObjectIdentifier _identifier; private readonly Dictionary, ComboWithFilter)> _combos; - private readonly IPlayerWatcher _playerWatcher; private readonly ImGuiScene.TextureWrap? _legacyTattooIcon; private readonly Dictionary _equipSlotNames; + private readonly DesignManager _designs; + private readonly GlamourerPlugin _plugin; private bool _visible = false; + private bool _inGPose = false; - private Actor? _player; - - private static ImGuiScene.TextureWrap? GetLegacyTattooIcon() - { - using var resource = Assembly.GetExecutingAssembly().GetManifestResourceStream("Glamourer.LegacyTattoo.raw"); - if (resource != null) - { - var rawImage = new byte[resource.Length]; - resource.Read(rawImage, 0, (int) resource.Length); - return GlamourerPlugin.PluginInterface.UiBuilder.LoadImageRaw(rawImage, 192, 192, 4); - } - - return null; - } - - private static Dictionary GetEquipSlotNames() - { - var sheet = GlamourerPlugin.PluginInterface.Data.GetExcelSheet(); - var ret = new Dictionary(12) - { - [EquipSlot.MainHand] = sheet.GetRow(738)?.Text.ToString() ?? "Main Hand", - [EquipSlot.OffHand] = sheet.GetRow(739)?.Text.ToString() ?? "Off Hand", - [EquipSlot.Head] = sheet.GetRow(740)?.Text.ToString() ?? "Head", - [EquipSlot.Body] = sheet.GetRow(741)?.Text.ToString() ?? "Body", - [EquipSlot.Hands] = sheet.GetRow(750)?.Text.ToString() ?? "Hands", - [EquipSlot.Legs] = sheet.GetRow(742)?.Text.ToString() ?? "Legs", - [EquipSlot.Feet] = sheet.GetRow(744)?.Text.ToString() ?? "Feet", - [EquipSlot.Ears] = sheet.GetRow(745)?.Text.ToString() ?? "Ears", - [EquipSlot.Neck] = sheet.GetRow(746)?.Text.ToString() ?? "Neck", - [EquipSlot.Wrists] = sheet.GetRow(747)?.Text.ToString() ?? "Wrists", - [EquipSlot.RFinger] = sheet.GetRow(748)?.Text.ToString() ?? "Right Ring", - [EquipSlot.LFinger] = sheet.GetRow(749)?.Text.ToString() ?? "Left Ring", - }; - return ret; - } - - public Interface() + public Interface(GlamourerPlugin plugin) { + _plugin = plugin; + _designs = plugin.Designs; _glamourerHeader = GlamourerPlugin.Version.Length > 0 ? $"{PluginName} v{GlamourerPlugin.Version}###{PluginName}Main" : $"{PluginName}###{PluginName}Main"; - GlamourerPlugin.PluginInterface.UiBuilder.OnBuildUi += Draw; - GlamourerPlugin.PluginInterface.UiBuilder.OnOpenConfigUi += ToggleVisibility; + GlamourerPlugin.PluginInterface.UiBuilder.DisableGposeUiHide = true; + GlamourerPlugin.PluginInterface.UiBuilder.OnBuildUi += Draw; + GlamourerPlugin.PluginInterface.UiBuilder.OnOpenConfigUi += ToggleVisibility; _equipSlotNames = GetEquipSlotNames(); - _stains = GameData.Stains(GlamourerPlugin.PluginInterface); - _equip = GameData.ItemsBySlot(GlamourerPlugin.PluginInterface); - _identifier = Penumbra.GameData.GameData.GetIdentifier(GlamourerPlugin.PluginInterface); - _actors = GlamourerPlugin.PluginInterface.ClientState.Actors; - _playerWatcher = PlayerWatchFactory.Create(GlamourerPlugin.PluginInterface); + _stains = GameData.Stains(GlamourerPlugin.PluginInterface); + _identifier = Penumbra.GameData.GameData.GetIdentifier(GlamourerPlugin.PluginInterface); + _actors = GlamourerPlugin.PluginInterface.ClientState.Actors; var stainCombo = CreateDefaultStainCombo(_stains.Values.ToArray()); - _combos = _equip.ToDictionary(kvp => kvp.Key, kvp => CreateCombos(kvp.Key, kvp.Value, stainCombo)); + var equip = GameData.ItemsBySlot(GlamourerPlugin.PluginInterface); + _combos = equip.ToDictionary(kvp => kvp.Key, kvp => CreateCombos(kvp.Key, kvp.Value, stainCombo)); _legacyTattooIcon = GetLegacyTattooIcon(); } @@ -402,524 +60,37 @@ namespace Glamourer.Gui public void Dispose() { _legacyTattooIcon?.Dispose(); - _playerWatcher?.Dispose(); GlamourerPlugin.PluginInterface.UiBuilder.OnBuildUi -= Draw; GlamourerPlugin.PluginInterface.UiBuilder.OnOpenConfigUi -= ToggleVisibility; } - private string _currentActorName = ""; - - private SubRace _currentSubRace = SubRace.Midlander; - private Gender _currentGender = Gender.Male; - - private bool DrawListSelector(string label, string tooltip, LazyCustomization customization, CustomizationId id, - CustomizationSet set) - { - using var bigGroup = ImGuiRaii.NewGroup(); - var ret = false; - int current = customization.Value[id]; - var count = set.Count(id); - - ImGui.SetNextItemWidth(_comboSelectorSize * ImGui.GetIO().FontGlobalScale); - if (ImGui.BeginCombo($"##combo_{id}", $"{set.Option(id)} #{current + 1}")) - { - for (var i = 0; i < count; ++i) - { - if (ImGui.Selectable($"{set.Option(id)} #{i + 1}##combo", i == current) && i != current) - { - customization.Value[id] = (byte) i; - ret = true; - } - } - - ImGui.EndCombo(); - } - - ImGui.SameLine(); - if (InputInt($"##text_{id}", ref current, 1, count)) - { - customization.Value[id] = set.Data(id, current).Value; - ret = true; - } - - ImGui.SameLine(); - ImGui.Text(label); - if (tooltip.Any() && ImGui.IsItemHovered()) - ImGui.SetTooltip(tooltip); - - return ret; - } - - private static readonly Vector4 NoColor = new(1f, 1f, 1f, 1f); - private static readonly Vector4 RedColor = new(0.6f, 0.3f, 0.3f, 1f); - - private bool DrawMultiSelector(LazyCustomization customization, CustomizationSet set) - { - using var bigGroup = ImGuiRaii.NewGroup(); - var ret = false; - var count = set.Count(CustomizationId.FacialFeaturesTattoos); - using (var raii = ImGuiRaii.NewGroup()) - { - for (var i = 0; i < count; ++i) - { - var enabled = customization.Value.FacialFeature(i); - var feature = set.FacialFeature(set.Race == Race.Hrothgar ? customization.Value.Hairstyle : customization.Value.Face, i); - var icon = i == count - 1 - ? _legacyTattooIcon ?? GlamourerPlugin.Customization.GetIcon(feature.IconId) - : GlamourerPlugin.Customization.GetIcon(feature.IconId); - if (ImGui.ImageButton(icon.ImGuiHandle, _iconSize, Vector2.Zero, Vector2.One, (int) ImGui.GetStyle().FramePadding.X, - Vector4.Zero, - enabled ? NoColor : RedColor)) - { - ret = true; - customization.Value.FacialFeature(i, !enabled); - } - - if (ImGui.IsItemHovered()) - { - using var tt = ImGuiRaii.NewTooltip(); - ImGui.Image(icon.ImGuiHandle, new Vector2(icon.Width, icon.Height)); - } - - if (i % 4 != 3) - ImGui.SameLine(); - } - } - - ImGui.SameLine(); - using var group = ImGuiRaii.NewGroup(); - ImGui.SetCursorPosY(ImGui.GetCursorPosY() + ImGui.GetTextLineHeightWithSpacing() + 3 * ImGui.GetStyle().ItemSpacing.Y / 2); - int value = customization.Value[CustomizationId.FacialFeaturesTattoos]; - if (InputInt($"##{CustomizationId.FacialFeaturesTattoos}", ref value, 1, 256)) - { - customization.Value[CustomizationId.FacialFeaturesTattoos] = (byte) value; - ret = true; - } - - ImGui.Text(set.Option(CustomizationId.FacialFeaturesTattoos)); - - return ret; - } - - private bool DrawIconPickerPopup(string label, CustomizationSet set, CustomizationId id, out Customization.Customization value) - { - value = default; - if (!ImGui.BeginPopup(label, ImGuiWindowFlags.AlwaysAutoResize)) - return false; - - var ret = false; - var count = set.Count(id); - using var raii = new ImGuiRaii().PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero) - .PushStyle(ImGuiStyleVar.FrameRounding, 0); - for (var i = 0; i < count; ++i) - { - var custom = set.Data(id, i); - var icon = GlamourerPlugin.Customization.GetIcon(custom.IconId); - if (ImGui.ImageButton(icon.ImGuiHandle, _iconSize)) - { - value = custom; - ret = true; - ImGui.CloseCurrentPopup(); - } - - if (ImGui.IsItemHovered()) - { - using var tt = ImGuiRaii.NewTooltip(); - ImGui.Image(icon.ImGuiHandle, new Vector2(icon.Width, icon.Height)); - } - - if (i % 8 != 7) - ImGui.SameLine(); - } - - ImGui.EndPopup(); - return ret; - } - - private bool DrawIconSelector(string label, string tooltip, LazyCustomization customization, CustomizationId id, - CustomizationSet set) - { - using var bigGroup = ImGuiRaii.NewGroup(); - var ret = false; - var count = set.Count(id); - - var current = set.DataByValue(id, customization.Value[id], out var custom); - if (current < 0) - { - PluginLog.Warning($"Read invalid customization value {customization.Value[id]} for {id}."); - current = 0; - custom = set.Data(id, 0); - } - - var popupName = $"Style Picker##{id}"; - var icon = GlamourerPlugin.Customization.GetIcon(custom!.Value.IconId); - if (ImGui.ImageButton(icon.ImGuiHandle, _iconSize)) - ImGui.OpenPopup(popupName); - - if (ImGui.IsItemHovered()) - { - using var tt = ImGuiRaii.NewTooltip(); - ImGui.Image(icon.ImGuiHandle, new Vector2(icon.Width, icon.Height)); - } - - ImGui.SameLine(); - using var group = ImGuiRaii.NewGroup(); - if (InputInt($"##text_{id}", ref current, 1, count)) - { - customization.Value[id] = set.Data(id, current).Value; - ret = true; - } - - if (DrawIconPickerPopup(popupName, set, id, out var newCustom)) - { - customization.Value[id] = newCustom.Value; - ret = true; - } - - ImGui.Text(label); - if (tooltip.Any() && ImGui.IsItemHovered()) - ImGui.SetTooltip(tooltip); - - return ret; - } - - - private bool DrawPercentageSelector(string label, string tooltip, LazyCustomization customization, CustomizationId id, - CustomizationSet set) - { - using var bigGroup = ImGuiRaii.NewGroup(); - var ret = false; - int value = customization.Value[id]; - var count = set.Count(id); - ImGui.SetNextItemWidth(_percentageSize * ImGui.GetIO().FontGlobalScale); - if (ImGui.SliderInt($"##slider_{id}", ref value, 0, count - 1, "") && value != customization.Value[id]) - { - customization.Value[id] = (byte) value; - ret = true; - } - - ImGui.SameLine(); - --value; - if (InputInt($"##input_{id}", ref value, 0, count - 1)) - { - customization.Value[id] = (byte) (value + 1); - ret = true; - } - - ImGui.SameLine(); - ImGui.Text(label); - if (tooltip.Any() && ImGui.IsItemHovered()) - ImGui.SetTooltip(tooltip); - - return ret; - } - - private string ClanName(SubRace race, Gender gender) - { - if (gender == Gender.Female) - return race switch - { - SubRace.Midlander => GlamourerPlugin.Customization.GetName(CustomName.MidlanderM), - SubRace.Highlander => GlamourerPlugin.Customization.GetName(CustomName.HighlanderM), - SubRace.Wildwood => GlamourerPlugin.Customization.GetName(CustomName.WildwoodM), - SubRace.Duskwight => GlamourerPlugin.Customization.GetName(CustomName.DuskwightM), - SubRace.Plainsfolk => GlamourerPlugin.Customization.GetName(CustomName.PlainsfolkM), - SubRace.Dunesfolk => GlamourerPlugin.Customization.GetName(CustomName.DunesfolkM), - SubRace.SeekerOfTheSun => GlamourerPlugin.Customization.GetName(CustomName.SeekerOfTheSunM), - SubRace.KeeperOfTheMoon => GlamourerPlugin.Customization.GetName(CustomName.KeeperOfTheMoonM), - SubRace.Seawolf => GlamourerPlugin.Customization.GetName(CustomName.SeawolfM), - SubRace.Hellsguard => GlamourerPlugin.Customization.GetName(CustomName.HellsguardM), - SubRace.Raen => GlamourerPlugin.Customization.GetName(CustomName.RaenM), - SubRace.Xaela => GlamourerPlugin.Customization.GetName(CustomName.XaelaM), - SubRace.Helion => GlamourerPlugin.Customization.GetName(CustomName.HelionM), - SubRace.Lost => GlamourerPlugin.Customization.GetName(CustomName.LostM), - SubRace.Rava => GlamourerPlugin.Customization.GetName(CustomName.RavaF), - SubRace.Veena => GlamourerPlugin.Customization.GetName(CustomName.VeenaF), - _ => throw new ArgumentOutOfRangeException(nameof(race), race, null), - }; - - return race switch - { - SubRace.Midlander => GlamourerPlugin.Customization.GetName(CustomName.MidlanderF), - SubRace.Highlander => GlamourerPlugin.Customization.GetName(CustomName.HighlanderF), - SubRace.Wildwood => GlamourerPlugin.Customization.GetName(CustomName.WildwoodF), - SubRace.Duskwight => GlamourerPlugin.Customization.GetName(CustomName.DuskwightF), - SubRace.Plainsfolk => GlamourerPlugin.Customization.GetName(CustomName.PlainsfolkF), - SubRace.Dunesfolk => GlamourerPlugin.Customization.GetName(CustomName.DunesfolkF), - SubRace.SeekerOfTheSun => GlamourerPlugin.Customization.GetName(CustomName.SeekerOfTheSunF), - SubRace.KeeperOfTheMoon => GlamourerPlugin.Customization.GetName(CustomName.KeeperOfTheMoonF), - SubRace.Seawolf => GlamourerPlugin.Customization.GetName(CustomName.SeawolfF), - SubRace.Hellsguard => GlamourerPlugin.Customization.GetName(CustomName.HellsguardF), - SubRace.Raen => GlamourerPlugin.Customization.GetName(CustomName.RaenF), - SubRace.Xaela => GlamourerPlugin.Customization.GetName(CustomName.XaelaF), - SubRace.Helion => GlamourerPlugin.Customization.GetName(CustomName.HelionM), - SubRace.Lost => GlamourerPlugin.Customization.GetName(CustomName.LostM), - SubRace.Rava => GlamourerPlugin.Customization.GetName(CustomName.RavaF), - SubRace.Veena => GlamourerPlugin.Customization.GetName(CustomName.VeenaF), - _ => throw new ArgumentOutOfRangeException(nameof(race), race, null), - }; - } - - private bool DrawRaceSelector(LazyCustomization customization) - { - using var group = ImGuiRaii.NewGroup(); - var ret = false; - _currentSubRace = customization.Value.Clan; - ImGui.SetNextItemWidth(_raceSelectorWidth); - if (ImGui.BeginCombo("##subRaceCombo", ClanName(_currentSubRace, customization.Value.Gender))) - { - for (var i = 0; i < (int) SubRace.Veena; ++i) - { - if (ImGui.Selectable(ClanName((SubRace) i + 1, customization.Value.Gender), (int) _currentSubRace == i + 1)) - { - _currentSubRace = (SubRace) i + 1; - ret |= ChangeRace(customization, _currentSubRace); - } - } - - ImGui.EndCombo(); - } - - ImGui.Text( - $"{GlamourerPlugin.Customization.GetName(CustomName.Gender)} & {GlamourerPlugin.Customization.GetName(CustomName.Clan)}"); - - return ret; - } - - private bool DrawGenderSelector(LazyCustomization customization) - { - var ret = false; - ImGui.PushFont(UiBuilder.IconFont); - var icon = _currentGender == Gender.Male ? FontAwesomeIcon.Mars : FontAwesomeIcon.Venus; - var restricted = false; - if (customization.Value.Race == Race.Viera) - { - ImGui.PushStyleVar(ImGuiStyleVar.Alpha, 0.25f); - icon = FontAwesomeIcon.VenusDouble; - restricted = true; - } - else if (customization.Value.Race == Race.Hrothgar) - { - ImGui.PushStyleVar(ImGuiStyleVar.Alpha, 0.25f); - icon = FontAwesomeIcon.MarsDouble; - restricted = true; - } - - if (ImGui.Button(icon.ToIconString(), _actualIconSize) && !restricted) - { - _currentGender = _currentGender == Gender.Male ? Gender.Female : Gender.Male; - ret = ChangeGender(customization, _currentGender); - } - - if (restricted) - ImGui.PopStyleVar(); - ImGui.PopFont(); - return ret; - } - - private bool DrawPicker(CustomizationSet set, CustomizationId id, LazyCustomization customization) - { - if (!set.IsAvailable(id)) - return false; - - switch (set.Type(id)) - { - case CharaMakeParams.MenuType.ColorPicker: return DrawColorPicker(set.OptionName[(int) id], "", customization, id, set); - case CharaMakeParams.MenuType.ListSelector: return DrawListSelector(set.OptionName[(int) id], "", customization, id, set); - case CharaMakeParams.MenuType.IconSelector: return DrawIconSelector(set.OptionName[(int) id], "", customization, id, set); - case CharaMakeParams.MenuType.MultiIconSelector: return DrawMultiSelector(customization, set); - case CharaMakeParams.MenuType.Percentage: return DrawPercentageSelector(set.OptionName[(int) id], "", customization, id, set); - } - - return false; - } - - private static readonly CustomizationId[] AllCustomizations = (CustomizationId[]) Enum.GetValues(typeof(CustomizationId)); - - private bool DrawStuff(LazyCustomization x) - { - _currentSubRace = x.Value.Clan; - _currentGender = x.Value.Gender; - var ret = DrawGenderSelector(x); - ImGui.SameLine(); - ret |= DrawRaceSelector(x); - - var set = GlamourerPlugin.Customization.GetList(_currentSubRace, _currentGender); - - - foreach (var id in AllCustomizations.Where(c => set.Type(c) == CharaMakeParams.MenuType.Percentage)) - ret |= DrawPicker(set, id, x); - - var odd = true; - foreach (var id in AllCustomizations.Where((c, i) => set.Type(c) == CharaMakeParams.MenuType.IconSelector)) - { - ret |= DrawPicker(set, id, x); - if (odd) - ImGui.SameLine(); - odd = !odd; - } - - if (!odd) - ImGui.NewLine(); - - ret |= DrawPicker(set, CustomizationId.FacialFeaturesTattoos, x); - - foreach (var id in AllCustomizations.Where(c => set.Type(c) == CharaMakeParams.MenuType.ListSelector)) - ret |= DrawPicker(set, id, x); - - odd = true; - foreach (var id in AllCustomizations.Where(c => set.Type(c) == CharaMakeParams.MenuType.ColorPicker)) - { - ret |= DrawPicker(set, id, x); - if (odd) - ImGui.SameLine(); - odd = !odd; - } - - if (!odd) - ImGui.NewLine(); - - var tmp = x.Value.HighlightsOn; - if (ImGui.Checkbox(set.Option(CustomizationId.HighlightsOnFlag), ref tmp) && tmp != x.Value.HighlightsOn) - { - x.Value.HighlightsOn = tmp; - ret = true; - } - - var xPos = _inputIntSize + _actualIconSize.X + 3 * ImGui.GetStyle().ItemSpacing.X; - ImGui.SameLine(xPos); - tmp = x.Value.FacePaintReversed; - if (ImGui.Checkbox($"{GlamourerPlugin.Customization.GetName(CustomName.Reverse)} {set.Option(CustomizationId.FacePaint)}", ref tmp) - && tmp != x.Value.FacePaintReversed) - { - x.Value.FacePaintReversed = tmp; - ret = true; - } - - tmp = x.Value.SmallIris; - if (ImGui.Checkbox($"{GlamourerPlugin.Customization.GetName(CustomName.IrisSmall)} {set.Option(CustomizationId.EyeColorL)}", - ref tmp) - && tmp != x.Value.SmallIris) - { - x.Value.SmallIris = tmp; - ret = true; - } - - if (x.Value.Race != Race.Hrothgar) - { - tmp = x.Value.Lipstick; - ImGui.SameLine(xPos); - if (ImGui.Checkbox(set.Option(CustomizationId.LipColor), ref tmp) && tmp != x.Value.Lipstick) - { - x.Value.Lipstick = tmp; - ret = true; - } - } - - return ret; - } - - private void Draw() { - ImGui.SetNextWindowSizeConstraints(Vector2.One * 450 * ImGui.GetIO().FontGlobalScale, + if (!_visible) + return; + + ImGui.SetNextWindowSizeConstraints(Vector2.One * MinWindowWidth * ImGui.GetIO().FontGlobalScale, Vector2.One * 5000 * ImGui.GetIO().FontGlobalScale); - if (!_visible || !ImGui.Begin(_glamourerHeader, ref _visible)) + if (!ImGui.Begin(_glamourerHeader, ref _visible)) return; try { - var inCombo = ImGui.BeginCombo("Actor", _currentActorName); - var idx = 0; - _player = null; - foreach (var actor in _actors.Where(a => a.ObjectKind == ObjectKind.Player)) - { - if (_currentActorName == actor.Name) - _player = actor; + using var raii = new ImGuiRaii(); + if (!raii.Begin(() => ImGui.BeginTabBar("##tabBar"), ImGui.EndTabBar)) + return; - if (inCombo && ImGui.Selectable($"{actor.Name}##{idx++}")) - _currentActorName = actor.Name; - } + _inGPose = _actors[GPoseActorId] != null; + _iconSize = Vector2.One * ImGui.GetTextLineHeightWithSpacing() * 2; + _actualIconSize = _iconSize + 2 * ImGui.GetStyle().FramePadding; + _comboSelectorSize = 4 * _actualIconSize.X + 3 * ImGui.GetStyle().ItemSpacing.X; + _percentageSize = _comboSelectorSize; + _inputIntSize = 2 * _actualIconSize.X + ImGui.GetStyle().ItemSpacing.X; + _raceSelectorWidth = _inputIntSize + _percentageSize - _actualIconSize.X; + _itemComboWidth = 6 * _actualIconSize.X + 4 * ImGui.GetStyle().ItemSpacing.X - ColorButtonWidth + 1; - if (_player == null) - { - _player = _actors[0]; - _currentActorName = _player?.Name ?? string.Empty; - } - - if (inCombo) - ImGui.EndCombo(); - - if (_player == _actors[0] && _actors[GPoseActorId] != null) - _player = _actors[GPoseActorId]; - if (_player == null || !GlamourerPlugin.PluginInterface.ClientState.Condition.Any()) - { - ImGui.TextColored(new Vector4(0.4f, 0.1f, 0.1f, 1f), - "No player character available."); - } - else - { - var equip = new ActorEquipment(_player); - _iconSize = Vector2.One * ImGui.GetTextLineHeightWithSpacing() * 2; - _actualIconSize = _iconSize + 2 * ImGui.GetStyle().FramePadding; - _comboSelectorSize = 4 * _actualIconSize.X + 3 * ImGui.GetStyle().ItemSpacing.X; - _percentageSize = _comboSelectorSize; - _inputIntSize = 2 * _actualIconSize.X + ImGui.GetStyle().ItemSpacing.X; - _raceSelectorWidth = _inputIntSize + _percentageSize - _actualIconSize.X; - _itemComboWidth = 6 * _actualIconSize.X + 4 * ImGui.GetStyle().ItemSpacing.X - ColorButtonWidth + 1; - var changes = false; - - if (ImGui.CollapsingHeader("Character Equipment")) - { - changes |= DrawWeapon(EquipSlot.MainHand, equip.MainHand); - changes |= DrawWeapon(EquipSlot.OffHand, equip.OffHand); - changes |= DrawEquip(EquipSlot.Head, equip.Head); - changes |= DrawEquip(EquipSlot.Body, equip.Body); - changes |= DrawEquip(EquipSlot.Hands, equip.Hands); - changes |= DrawEquip(EquipSlot.Legs, equip.Legs); - changes |= DrawEquip(EquipSlot.Feet, equip.Feet); - changes |= DrawEquip(EquipSlot.Ears, equip.Ears); - changes |= DrawEquip(EquipSlot.Neck, equip.Neck); - changes |= DrawEquip(EquipSlot.Wrists, equip.Wrists); - changes |= DrawEquip(EquipSlot.RFinger, equip.RFinger); - changes |= DrawEquip(EquipSlot.LFinger, equip.LFinger); - } - - var x = new LazyCustomization(_player!.Address); - if (ImGui.CollapsingHeader("Character Customization")) - changes |= DrawStuff(x); - - if (ImGui.Button("Copy to Clipboard")) - { - var save = new CharacterSave(); - save.Load(x.Value); - save.Load(equip); - Clipboard.SetText(save.ToBase64()); - } - - ImGui.SameLine(); - if (ImGui.Button("Apply from Clipboard")) - { - var text = Clipboard.GetText(); - if (text.Any()) - { - try - { - var save = CharacterSave.FromString(text); - save.Customizations.Write(_player.Address); - save.Equipment.Write(_player.Address); - changes = true; - } - catch (Exception e) - { - PluginLog.Information($"{e}"); - } - } - } - - if (changes) - UpdateActors(_player); - } + DrawActorTab(); + DrawSaves(); } finally { diff --git a/Glamourer/Gui/InterfaceActorPanel.cs b/Glamourer/Gui/InterfaceActorPanel.cs new file mode 100644 index 0000000..589a4d5 --- /dev/null +++ b/Glamourer/Gui/InterfaceActorPanel.cs @@ -0,0 +1,188 @@ +using System; +using System.Linq; +using System.Numerics; +using System.Windows.Forms; +using Dalamud.Interface; +using Dalamud.Plugin; +using Glamourer.Designs; +using Glamourer.FileSystem; +using ImGuiNET; + +namespace Glamourer.Gui +{ + internal partial class Interface + { + private readonly CharacterSave _currentSave = new(); + private string _newDesignName = string.Empty; + private bool _keyboardFocus = false; + private const string DesignNamePopupLabel = "Save Design As..."; + private const uint RedHeaderColor = 0xFF1818C0; + private const uint GreenHeaderColor = 0xFF18C018; + + private void DrawActorHeader() + { + var color = _player == null ? RedHeaderColor : GreenHeaderColor; + var buttonColor = ImGui.GetColorU32(ImGuiCol.FrameBg); + using var raii = new ImGuiRaii() + .PushColor(ImGuiCol.Text, color) + .PushColor(ImGuiCol.Button, buttonColor) + .PushColor(ImGuiCol.ButtonHovered, buttonColor) + .PushColor(ImGuiCol.ButtonActive, buttonColor) + .PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero) + .PushStyle(ImGuiStyleVar.FrameRounding, 0); + ImGui.Button($"{_currentActorName}##actorHeader", -Vector2.UnitX * 0.0001f); + } + + private static void DrawCopyClipboardButton(CharacterSave save) + { + ImGui.PushFont(UiBuilder.IconFont); + if (ImGui.Button(FontAwesomeIcon.Clipboard.ToIconString())) + Clipboard.SetText(save.ToBase64()); + ImGui.PopFont(); + if (ImGui.IsItemHovered()) + ImGui.SetTooltip("Copy customization code to clipboard."); + } + + private bool DrawApplyClipboardButton() + { + ImGui.PushFont(UiBuilder.IconFont); + var applyButton = ImGui.Button(FontAwesomeIcon.Paste.ToIconString()) && _player != null; + ImGui.PopFont(); + if (ImGui.IsItemHovered()) + ImGui.SetTooltip("Apply customization code from clipboard."); + + if (!applyButton) + return false; + + var text = Clipboard.GetText(); + if (!text.Any()) + return false; + + try + { + var save = CharacterSave.FromString(text); + save.Apply(_player!); + } + catch (Exception e) + { + PluginLog.Information($"{e}"); + return false; + } + + return true; + } + + private void DrawSaveDesignButton() + { + ImGui.PushFont(UiBuilder.IconFont); + if (ImGui.Button(FontAwesomeIcon.Save.ToIconString())) + OpenDesignNamePopup(DesignNameUse.SaveCurrent); + + ImGui.PopFont(); + if (ImGui.IsItemHovered()) + ImGui.SetTooltip("Save the current design."); + + DrawDesignNamePopup(DesignNameUse.SaveCurrent); + } + + private void DrawTargetPlayerButton() + { + if (ImGui.Button("Target Player")) + GlamourerPlugin.PluginInterface.ClientState.Targets.SetCurrentTarget(_player); + } + + private void DrawApplyToPlayerButton(CharacterSave save) + { + if (ImGui.Button("Apply to Self")) + { + var player = _inGPose + ? GlamourerPlugin.PluginInterface.ClientState.Actors[GPoseActorId] + : GlamourerPlugin.PluginInterface.ClientState.LocalPlayer; + var fallback = _inGPose ? GlamourerPlugin.PluginInterface.ClientState.LocalPlayer : null; + if (player != null) + { + save.Apply(player); + if (_inGPose) + save.Apply(fallback!); + _plugin.UpdateActors(player, fallback); + } + } + } + + private void DrawApplyToTargetButton(CharacterSave save) + { + if (ImGui.Button("Apply to Target")) + { + var player = GlamourerPlugin.PluginInterface.ClientState.Targets.CurrentTarget; + if (player != null) + { + var fallBackActor = _playerNames[player.Name]; + save.Apply(player); + if (fallBackActor != null) + save.Apply(fallBackActor); + _plugin.UpdateActors(player, fallBackActor); + } + } + } + + private void SaveNewDesign(CharacterSave save) + { + try + { + var (folder, name) = _designs.FileSystem.CreateAllFolders(_newDesignName); + if (name.Any()) + { + var newDesign = new Design(folder, name) { Data = save }; + folder.AddChild(newDesign); + _designs.Designs[newDesign.FullName()] = save; + _designs.SaveToFile(); + } + } + catch (Exception e) + { + PluginLog.Error($"Could not save new design {_newDesignName}:\n{e}"); + } + } + + private void DrawActorPanel() + { + ImGui.BeginGroup(); + DrawActorHeader(); + if (!ImGui.BeginChild("##actorData", -Vector2.One, true)) + return; + + DrawCopyClipboardButton(_currentSave); + ImGui.SameLine(); + var changes = DrawApplyClipboardButton(); + ImGui.SameLine(); + DrawSaveDesignButton(); + ImGui.SameLine(); + DrawApplyToPlayerButton(_currentSave); + if (!_inGPose) + { + ImGui.SameLine(); + DrawApplyToTargetButton(_currentSave); + if (_player != null) + { + ImGui.SameLine(); + DrawTargetPlayerButton(); + } + } + + + if (DrawCustomization(ref _currentSave.Customizations) && _player != null) + { + _currentSave.Customizations.Write(_player.Address); + changes = true; + } + + changes |= DrawEquip(_currentSave.Equipment); + changes |= DrawMiscellaneous(_currentSave, _player); + + if (_player != null && changes) + _plugin.UpdateActors(_player); + ImGui.EndChild(); + ImGui.EndGroup(); + } + } +} diff --git a/Glamourer/Gui/InterfaceActorSelector.cs b/Glamourer/Gui/InterfaceActorSelector.cs new file mode 100644 index 0000000..b8dc648 --- /dev/null +++ b/Glamourer/Gui/InterfaceActorSelector.cs @@ -0,0 +1,151 @@ +using System.Collections.Generic; +using System.Linq; +using System.Numerics; +using Dalamud.Game.ClientState.Actors; +using Dalamud.Game.ClientState.Actors.Types; +using Dalamud.Interface; +using ImGuiNET; + +namespace Glamourer.Gui +{ + internal partial class Interface + { + private Actor? _player; + private string _currentActorName = string.Empty; + private string _actorFilter = string.Empty; + private string _actorFilterLower = string.Empty; + private readonly Dictionary _playerNames = new(400); + + private void DrawActorFilter() + { + using var raii = new ImGuiRaii() + .PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero) + .PushStyle(ImGuiStyleVar.FrameRounding, 0); + ImGui.SetNextItemWidth(SelectorWidth * ImGui.GetIO().FontGlobalScale); + if (ImGui.InputTextWithHint("##actorFilter", "Filter Players...", ref _actorFilter, 32)) + _actorFilterLower = _actorFilter.ToLowerInvariant(); + } + + private void DrawActorSelectable(Actor actor, bool gPose) + { + var actorName = actor.Name; + if (!actorName.Any()) + return; + + if (_playerNames.ContainsKey(actorName)) + { + _playerNames[actorName] = actor; + return; + } + + _playerNames.Add(actorName, null); + + var label = gPose ? $"{actorName} (GPose)" : actorName; + if (!_actorFilterLower.Any() || actorName.ToLowerInvariant().Contains(_actorFilterLower)) + if (ImGui.Selectable(label, _currentActorName == actorName)) + { + _currentActorName = actorName; + _currentSave.LoadActor(actor); + _player = actor; + return; + } + + if (_currentActorName == actor.Name) + { + _currentSave.LoadActor(actor); + _player = actor; + } + } + + private void DrawSelectionButtons() + { + using var raii = new ImGuiRaii() + .PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero) + .PushStyle(ImGuiStyleVar.FrameRounding, 0) + .PushFont(UiBuilder.IconFont); + Actor? select = null; + var buttonWidth = Vector2.UnitX * SelectorWidth / 2; + if (ImGui.Button(FontAwesomeIcon.UserCircle.ToIconString(), buttonWidth)) + select = GlamourerPlugin.PluginInterface.ClientState.LocalPlayer; + raii.PopFonts(); + if (ImGui.IsItemHovered()) + ImGui.SetTooltip("Select the local player character."); + ImGui.SameLine(); + raii.PushFont(UiBuilder.IconFont); + if (_inGPose) + { + raii.PushStyle(ImGuiStyleVar.Alpha, 0.5f); + ImGui.Button(FontAwesomeIcon.HandPointer.ToIconString(), buttonWidth); + raii.PopStyles(); + } + else + { + if (ImGui.Button(FontAwesomeIcon.HandPointer.ToIconString(), buttonWidth)) + select = GlamourerPlugin.PluginInterface.ClientState.Targets.CurrentTarget; + } + + raii.PopFonts(); + if (ImGui.IsItemHovered()) + ImGui.SetTooltip("Select the current target, if it is a player actor."); + + if (select == null || select.ObjectKind != ObjectKind.Player) + return; + + _player = select; + _currentActorName = _player.Name; + _currentSave.LoadActor(_player); + } + + private void DrawActorSelector() + { + ImGui.BeginGroup(); + DrawActorFilter(); + if (!ImGui.BeginChild("##actorSelector", + new Vector2(SelectorWidth * ImGui.GetIO().FontGlobalScale, -ImGui.GetFrameHeight() - 1), true)) + return; + + _playerNames.Clear(); + for (var i = GPoseActorId; i < GPoseActorId + 48; ++i) + { + var actor = _actors[i]; + if (actor == null) + break; + + if (actor.ObjectKind == ObjectKind.Player) + DrawActorSelectable(actor, true); + } + + for (var i = 0; i < GPoseActorId; i += 2) + { + var actor = _actors[i]; + if (actor != null && actor.ObjectKind == ObjectKind.Player) + DrawActorSelectable(actor, false); + } + + + using (var raii = new ImGuiRaii().PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero)) + { + ImGui.EndChild(); + } + + DrawSelectionButtons(); + ImGui.EndGroup(); + } + + private void DrawActorTab() + { + using var raii = new ImGuiRaii(); + if (!raii.Begin(() => ImGui.BeginTabItem("Current Players"), ImGui.EndTabItem)) + return; + + _player = null; + DrawActorSelector(); + + if (!_currentActorName.Any()) + return; + + ImGui.SameLine(); + DrawActorPanel(); + } + } +} diff --git a/Glamourer/Gui/InterfaceCustomization.cs b/Glamourer/Gui/InterfaceCustomization.cs new file mode 100644 index 0000000..ab4a911 --- /dev/null +++ b/Glamourer/Gui/InterfaceCustomization.cs @@ -0,0 +1,480 @@ +using System; +using System.Linq; +using System.Numerics; +using Dalamud.Interface; +using Dalamud.Plugin; +using Glamourer.Customization; +using ImGuiNET; +using Penumbra.GameData.Enums; + +namespace Glamourer.Gui +{ + internal partial class Interface + { + private static bool DrawColorPickerPopup(string label, CustomizationSet set, CustomizationId id, out Customization.Customization value) + { + value = default; + if (!ImGui.BeginPopup(label, ImGuiWindowFlags.AlwaysAutoResize)) + return false; + + var ret = false; + var count = set.Count(id); + using var raii = new ImGuiRaii().PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero) + .PushStyle(ImGuiStyleVar.FrameRounding, 0); + for (var i = 0; i < count; ++i) + { + var custom = set.Data(id, i); + if (ImGui.ColorButton((i + 1).ToString(), ImGui.ColorConvertU32ToFloat4(custom.Color))) + { + value = custom; + ret = true; + ImGui.CloseCurrentPopup(); + } + + if (i % 8 != 7) + ImGui.SameLine(); + } + + ImGui.EndPopup(); + return ret; + } + + private Vector2 _iconSize = Vector2.Zero; + private Vector2 _actualIconSize = Vector2.Zero; + private float _raceSelectorWidth = 0; + private float _inputIntSize = 0; + private float _comboSelectorSize = 0; + private float _percentageSize = 0; + private float _itemComboWidth = 0; + + private bool InputInt(string label, ref int value, int minValue, int maxValue) + { + var ret = false; + var tmp = value + 1; + ImGui.SetNextItemWidth(_inputIntSize); + if (ImGui.InputInt(label, ref tmp, 1) && tmp != value + 1 && tmp >= minValue && tmp <= maxValue) + { + value = tmp - 1; + ret = true; + } + + if (ImGui.IsItemHovered()) + ImGui.SetTooltip($"Input Range: [{minValue}, {maxValue}]"); + + return ret; + } + + private static (int, Customization.Customization) GetCurrentCustomization(ref ActorCustomization customization, CustomizationId id, + CustomizationSet set) + { + var current = set.DataByValue(id, customization[id], out var custom); + if (set.IsAvailable(id) && current < 0) + { + PluginLog.Warning($"Read invalid customization value {customization[id]} for {id}."); + current = 0; + custom = set.Data(id, 0); + } + + return (current, custom!.Value); + } + + private bool DrawColorPicker(string label, string tooltip, ref ActorCustomization customization, CustomizationId id, + CustomizationSet set) + { + var ret = false; + var count = set.Count(id); + + var (current, custom) = GetCurrentCustomization(ref customization, id, set); + + var popupName = $"Color Picker##{id}"; + if (ImGui.ColorButton($"{current + 1}##color_{id}", ImGui.ColorConvertU32ToFloat4(custom.Color), ImGuiColorEditFlags.None, + _actualIconSize)) + ImGui.OpenPopup(popupName); + + ImGui.SameLine(); + + using (var group = ImGuiRaii.NewGroup()) + { + if (InputInt($"##text_{id}", ref current, 1, count)) + { + customization[id] = set.Data(id, current - 1).Value; + ret = true; + } + + + ImGui.Text(label); + if (tooltip.Any() && ImGui.IsItemHovered()) + ImGui.SetTooltip(tooltip); + } + + if (!DrawColorPickerPopup(popupName, set, id, out var newCustom)) + return ret; + + customization[id] = newCustom.Value; + ret = true; + + return ret; + } + + private bool DrawListSelector(string label, string tooltip, ref ActorCustomization customization, CustomizationId id, + CustomizationSet set) + { + using var bigGroup = ImGuiRaii.NewGroup(); + var ret = false; + int current = customization[id]; + var count = set.Count(id); + + ImGui.SetNextItemWidth(_comboSelectorSize * ImGui.GetIO().FontGlobalScale); + if (ImGui.BeginCombo($"##combo_{id}", $"{set.Option(id)} #{current + 1}")) + { + for (var i = 0; i < count; ++i) + { + if (ImGui.Selectable($"{set.Option(id)} #{i + 1}##combo", i == current) && i != current) + { + customization[id] = (byte) i; + ret = true; + } + } + + ImGui.EndCombo(); + } + + ImGui.SameLine(); + if (InputInt($"##text_{id}", ref current, 1, count)) + { + customization[id] = set.Data(id, current).Value; + ret = true; + } + + ImGui.SameLine(); + ImGui.Text(label); + if (tooltip.Any() && ImGui.IsItemHovered()) + ImGui.SetTooltip(tooltip); + + return ret; + } + + + private static readonly Vector4 NoColor = new(1f, 1f, 1f, 1f); + private static readonly Vector4 RedColor = new(0.6f, 0.3f, 0.3f, 1f); + + private bool DrawMultiSelector(ref ActorCustomization customization, CustomizationSet set) + { + using var bigGroup = ImGuiRaii.NewGroup(); + var ret = false; + var count = set.Count(CustomizationId.FacialFeaturesTattoos); + using (var _ = ImGuiRaii.NewGroup()) + { + for (var i = 0; i < count; ++i) + { + var enabled = customization.FacialFeature(i); + var feature = set.FacialFeature(set.Race == Race.Hrothgar ? customization.Hairstyle : customization.Face, i); + var icon = i == count - 1 + ? _legacyTattooIcon ?? GlamourerPlugin.Customization.GetIcon(feature.IconId) + : GlamourerPlugin.Customization.GetIcon(feature.IconId); + if (ImGui.ImageButton(icon.ImGuiHandle, _iconSize, Vector2.Zero, Vector2.One, (int) ImGui.GetStyle().FramePadding.X, + Vector4.Zero, + enabled ? NoColor : RedColor)) + { + ret = true; + customization.FacialFeature(i, !enabled); + } + + if (ImGui.IsItemHovered()) + { + using var tt = ImGuiRaii.NewTooltip(); + ImGui.Image(icon.ImGuiHandle, new Vector2(icon.Width, icon.Height)); + } + + if (i % 4 != 3) + ImGui.SameLine(); + } + } + + ImGui.SameLine(); + using var group = ImGuiRaii.NewGroup(); + ImGui.SetCursorPosY(ImGui.GetCursorPosY() + ImGui.GetTextLineHeightWithSpacing() + 3 * ImGui.GetStyle().ItemSpacing.Y / 2); + int value = customization[CustomizationId.FacialFeaturesTattoos]; + if (InputInt($"##{CustomizationId.FacialFeaturesTattoos}", ref value, 1, 256)) + { + customization[CustomizationId.FacialFeaturesTattoos] = (byte) value; + ret = true; + } + + ImGui.Text(set.Option(CustomizationId.FacialFeaturesTattoos)); + + return ret; + } + + + private bool DrawIconPickerPopup(string label, CustomizationSet set, CustomizationId id, out Customization.Customization value) + { + value = default; + if (!ImGui.BeginPopup(label, ImGuiWindowFlags.AlwaysAutoResize)) + return false; + + var ret = false; + var count = set.Count(id); + using var raii = new ImGuiRaii().PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero) + .PushStyle(ImGuiStyleVar.FrameRounding, 0); + for (var i = 0; i < count; ++i) + { + var custom = set.Data(id, i); + var icon = GlamourerPlugin.Customization.GetIcon(custom.IconId); + if (ImGui.ImageButton(icon.ImGuiHandle, _iconSize)) + { + value = custom; + ret = true; + ImGui.CloseCurrentPopup(); + } + + if (ImGui.IsItemHovered()) + { + using var tt = ImGuiRaii.NewTooltip(); + ImGui.Image(icon.ImGuiHandle, new Vector2(icon.Width, icon.Height)); + } + + if (i % 8 != 7) + ImGui.SameLine(); + } + + ImGui.EndPopup(); + return ret; + } + + private bool DrawIconSelector(string label, string tooltip, ref ActorCustomization customization, CustomizationId id, + CustomizationSet set) + { + using var bigGroup = ImGuiRaii.NewGroup(); + var ret = false; + var count = set.Count(id); + + var current = set.DataByValue(id, customization[id], out var custom); + if (current < 0) + { + PluginLog.Warning($"Read invalid customization value {customization[id]} for {id}."); + current = 0; + custom = set.Data(id, 0); + } + + var popupName = $"Style Picker##{id}"; + var icon = GlamourerPlugin.Customization.GetIcon(custom!.Value.IconId); + if (ImGui.ImageButton(icon.ImGuiHandle, _iconSize)) + ImGui.OpenPopup(popupName); + + if (ImGui.IsItemHovered()) + { + using var tt = ImGuiRaii.NewTooltip(); + ImGui.Image(icon.ImGuiHandle, new Vector2(icon.Width, icon.Height)); + } + + ImGui.SameLine(); + using var group = ImGuiRaii.NewGroup(); + if (InputInt($"##text_{id}", ref current, 1, count)) + { + customization[id] = set.Data(id, current).Value; + ret = true; + } + + if (DrawIconPickerPopup(popupName, set, id, out var newCustom)) + { + customization[id] = newCustom.Value; + ret = true; + } + + ImGui.Text(label); + if (tooltip.Any() && ImGui.IsItemHovered()) + ImGui.SetTooltip(tooltip); + + return ret; + } + + + private bool DrawPercentageSelector(string label, string tooltip, ref ActorCustomization customization, CustomizationId id, + CustomizationSet set) + { + using var bigGroup = ImGuiRaii.NewGroup(); + var ret = false; + int value = customization[id]; + var count = set.Count(id); + ImGui.SetNextItemWidth(_percentageSize * ImGui.GetIO().FontGlobalScale); + if (ImGui.SliderInt($"##slider_{id}", ref value, 0, count - 1, "") && value != customization[id]) + { + customization[id] = (byte) value; + ret = true; + } + + ImGui.SameLine(); + --value; + if (InputInt($"##input_{id}", ref value, 0, count - 1)) + { + customization[id] = (byte) (value + 1); + ret = true; + } + + ImGui.SameLine(); + ImGui.Text(label); + if (tooltip.Any() && ImGui.IsItemHovered()) + ImGui.SetTooltip(tooltip); + + return ret; + } + + private bool DrawRaceSelector(ref ActorCustomization customization) + { + using var group = ImGuiRaii.NewGroup(); + var ret = false; + ImGui.SetNextItemWidth(_raceSelectorWidth); + if (ImGui.BeginCombo("##subRaceCombo", ClanName(customization.Clan, customization.Gender))) + { + for (var i = 0; i < (int)SubRace.Veena; ++i) + { + if (ImGui.Selectable(ClanName((SubRace)i + 1, customization.Gender), (int)customization.Clan == i + 1)) + { + var race = (SubRace)i + 1; + ret |= ChangeRace(ref customization, race); + } + } + + ImGui.EndCombo(); + } + + ImGui.Text( + $"{GlamourerPlugin.Customization.GetName(CustomName.Gender)} & {GlamourerPlugin.Customization.GetName(CustomName.Clan)}"); + + return ret; + } + + private bool DrawGenderSelector(ref ActorCustomization customization) + { + var ret = false; + ImGui.PushFont(UiBuilder.IconFont); + var icon = customization.Gender == Gender.Male ? FontAwesomeIcon.Mars : FontAwesomeIcon.Venus; + var restricted = false; + if (customization.Race == Race.Viera) + { + ImGui.PushStyleVar(ImGuiStyleVar.Alpha, 0.25f); + icon = FontAwesomeIcon.VenusDouble; + restricted = true; + } + else if (customization.Race == Race.Hrothgar) + { + ImGui.PushStyleVar(ImGuiStyleVar.Alpha, 0.25f); + icon = FontAwesomeIcon.MarsDouble; + restricted = true; + } + + if (ImGui.Button(icon.ToIconString(), _actualIconSize) && !restricted) + { + var gender = customization.Gender == Gender.Male ? Gender.Female : Gender.Male; + ret = ChangeGender(ref customization, gender); + } + + if (restricted) + ImGui.PopStyleVar(); + ImGui.PopFont(); + return ret; + } + + private bool DrawPicker(CustomizationSet set, CustomizationId id, ref ActorCustomization customization) + { + if (!set.IsAvailable(id)) + return false; + + switch (set.Type(id)) + { + case CharaMakeParams.MenuType.ColorPicker: return DrawColorPicker(set.OptionName[(int)id], "", ref customization, id, set); + case CharaMakeParams.MenuType.ListSelector: return DrawListSelector(set.OptionName[(int)id], "", ref customization, id, set); + case CharaMakeParams.MenuType.IconSelector: return DrawIconSelector(set.OptionName[(int)id], "", ref customization, id, set); + case CharaMakeParams.MenuType.MultiIconSelector: return DrawMultiSelector(ref customization, set); + case CharaMakeParams.MenuType.Percentage: return DrawPercentageSelector(set.OptionName[(int)id], "", ref customization, id, set); + } + + return false; + } + + private static readonly CustomizationId[] AllCustomizations = (CustomizationId[])Enum.GetValues(typeof(CustomizationId)); + private bool DrawCustomization(ref ActorCustomization custom) + { + if (!ImGui.CollapsingHeader("Character Customization")) + return false; + + var ret = DrawGenderSelector(ref custom); + ImGui.SameLine(); + ret |= DrawRaceSelector(ref custom); + + var set = GlamourerPlugin.Customization.GetList(custom.Clan, custom.Gender); + + foreach (var id in AllCustomizations.Where(c => set.Type(c) == CharaMakeParams.MenuType.Percentage)) + ret |= DrawPicker(set, id, ref custom); + + var odd = true; + foreach (var id in AllCustomizations.Where((c, _) => set.Type(c) == CharaMakeParams.MenuType.IconSelector)) + { + ret |= DrawPicker(set, id, ref custom); + if (odd) + ImGui.SameLine(); + odd = !odd; + } + + if (!odd) + ImGui.NewLine(); + + ret |= DrawPicker(set, CustomizationId.FacialFeaturesTattoos, ref custom); + + foreach (var id in AllCustomizations.Where(c => set.Type(c) == CharaMakeParams.MenuType.ListSelector)) + ret |= DrawPicker(set, id, ref custom); + + odd = true; + foreach (var id in AllCustomizations.Where(c => set.Type(c) == CharaMakeParams.MenuType.ColorPicker)) + { + ret |= DrawPicker(set, id, ref custom); + if (odd) + ImGui.SameLine(); + odd = !odd; + } + + if (!odd) + ImGui.NewLine(); + + var tmp = custom.HighlightsOn; + if (ImGui.Checkbox(set.Option(CustomizationId.HighlightsOnFlag), ref tmp) && tmp != custom.HighlightsOn) + { + custom.HighlightsOn = tmp; + ret = true; + } + + var xPos = _inputIntSize + _actualIconSize.X + 3 * ImGui.GetStyle().ItemSpacing.X; + ImGui.SameLine(xPos); + tmp = custom.FacePaintReversed; + if (ImGui.Checkbox($"{GlamourerPlugin.Customization.GetName(CustomName.Reverse)} {set.Option(CustomizationId.FacePaint)}", ref tmp) + && tmp != custom.FacePaintReversed) + { + custom.FacePaintReversed = tmp; + ret = true; + } + + tmp = custom.SmallIris; + if (ImGui.Checkbox($"{GlamourerPlugin.Customization.GetName(CustomName.IrisSmall)} {set.Option(CustomizationId.EyeColorL)}", + ref tmp) + && tmp != custom.SmallIris) + { + custom.SmallIris = tmp; + ret = true; + } + + if (custom.Race != Race.Hrothgar) + { + tmp = custom.Lipstick; + ImGui.SameLine(xPos); + if (ImGui.Checkbox(set.Option(CustomizationId.LipColor), ref tmp) && tmp != custom.Lipstick) + { + custom.Lipstick = tmp; + ret = true; + } + } + + return ret; + } + } +} diff --git a/Glamourer/Gui/InterfaceDesigns.cs b/Glamourer/Gui/InterfaceDesigns.cs new file mode 100644 index 0000000..e81a16f --- /dev/null +++ b/Glamourer/Gui/InterfaceDesigns.cs @@ -0,0 +1,343 @@ +using System; +using System.Linq; +using System.Numerics; +using System.Windows.Forms; +using Dalamud.Interface; +using Dalamud.Plugin; +using Glamourer.Designs; +using Glamourer.FileSystem; +using ImGuiNET; + +namespace Glamourer.Gui +{ + internal partial class Interface + { + private int _totalObject = 0; + + private Design? _selection = null; + private string _newChildName = string.Empty; + + private void DrawDesignSelector() + { + _totalObject = 0; + ImGui.BeginGroup(); + if (ImGui.BeginChild("##selector", new Vector2(SelectorWidth * ImGui.GetIO().FontGlobalScale, - ImGui.GetFrameHeight() - 1) , true)) + { + DrawFolderContent(_designs.FileSystem.Root, SortMode.FoldersFirst); + ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, Vector2.Zero); + ImGui.EndChild(); + ImGui.PopStyleVar(); + } + DrawDesignSelectorButtons(); + ImGui.EndGroup(); + } + + private void DrawPasteClipboardButton() + { + if (_selection!.Data.WriteProtected) + ImGui.PushStyleVar(ImGuiStyleVar.Alpha, 0.5f); + + ImGui.PushFont(UiBuilder.IconFont); + var applyButton = ImGui.Button(FontAwesomeIcon.Paste.ToIconString()); + ImGui.PopFont(); + if (_selection!.Data.WriteProtected) + ImGui.PopStyleVar(); + + if (ImGui.IsItemHovered()) + ImGui.SetTooltip("Overwrite with customization code from clipboard."); + + if (_selection!.Data.WriteProtected || !applyButton) + return; + + var text = Clipboard.GetText(); + if (!text.Any()) + return; + + try + { + _selection!.Data = CharacterSave.FromString(text); + _designs.SaveToFile(); + } + catch (Exception e) + { + PluginLog.Information($"{e}"); + } + } + + private void DrawNewFolderButton() + { + ImGui.PushFont(UiBuilder.IconFont); + if (ImGui.Button(FontAwesomeIcon.FolderPlus.ToIconString(), Vector2.UnitX * SelectorWidth / 5)) + OpenDesignNamePopup(DesignNameUse.NewFolder); + ImGui.PopFont(); + if (ImGui.IsItemHovered()) + ImGui.SetTooltip("Create a new, empty Folder."); + + DrawDesignNamePopup(DesignNameUse.NewFolder); + } + + private void DrawNewDesignButton() + { + ImGui.PushFont(UiBuilder.IconFont); + if (ImGui.Button(FontAwesomeIcon.Plus.ToIconString(), Vector2.UnitX * SelectorWidth / 5)) + OpenDesignNamePopup(DesignNameUse.NewDesign); + ImGui.PopFont(); + if (ImGui.IsItemHovered()) + ImGui.SetTooltip("Create a new, empty Design."); + + DrawDesignNamePopup(DesignNameUse.NewDesign); + } + + private void DrawClipboardDesignButton() + { + ImGui.PushFont(UiBuilder.IconFont); + if (ImGui.Button(FontAwesomeIcon.Paste.ToIconString(), Vector2.UnitX * SelectorWidth / 5)) + OpenDesignNamePopup(DesignNameUse.FromClipboard); + ImGui.PopFont(); + if (ImGui.IsItemHovered()) + ImGui.SetTooltip("Create a new design from the customization string in your clipboard."); + + DrawDesignNamePopup(DesignNameUse.FromClipboard); + } + + private void DrawDeleteDesignButton() + { + ImGui.PushFont(UiBuilder.IconFont); + var style = _selection == null; + if (style) + ImGui.PushStyleVar(ImGuiStyleVar.Alpha, 0.5f); + if (ImGui.Button(FontAwesomeIcon.Trash.ToIconString(), Vector2.UnitX * SelectorWidth / 5) && _selection != null) + { + _designs.DeleteAllChildren(_selection, false); + _selection = null; + } + + ImGui.PopFont(); + if (style) + ImGui.PopStyleVar(); + if (ImGui.IsItemHovered()) + ImGui.SetTooltip("Delete the currently selected Design."); + } + + private void DrawDuplicateDesignButton() + { + ImGui.PushFont(UiBuilder.IconFont); + if (_selection == null) + ImGui.PushStyleVar(ImGuiStyleVar.Alpha, 0.5f); + if (ImGui.Button(FontAwesomeIcon.Clone.ToIconString(), Vector2.UnitX * SelectorWidth / 5) && _selection != null) + OpenDesignNamePopup(DesignNameUse.DuplicateDesign); + ImGui.PopFont(); + if (_selection == null) + ImGui.PopStyleVar(); + if (ImGui.IsItemHovered()) + ImGui.SetTooltip("Clone the currently selected Design."); + + DrawDesignNamePopup(DesignNameUse.DuplicateDesign); + } + + private void DrawDesignSelectorButtons() + { + using var raii = new ImGuiRaii() + .PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero) + .PushStyle(ImGuiStyleVar.FrameRounding, 0f); + + DrawNewFolderButton(); + ImGui.SameLine(); + DrawNewDesignButton(); + ImGui.SameLine(); + DrawClipboardDesignButton(); + ImGui.SameLine(); + DrawDuplicateDesignButton(); + ImGui.SameLine(); + DrawDeleteDesignButton(); + } + + private void DrawDesignHeaderButtons() + { + DrawCopyClipboardButton(_selection!.Data); + ImGui.SameLine(); + DrawPasteClipboardButton(); + ImGui.SameLine(); + DrawApplyToPlayerButton(_selection!.Data); + if (!_inGPose) + { + ImGui.SameLine(); + DrawApplyToTargetButton(_selection!.Data); + } + + ImGui.SameLine(); + DrawCheckbox("Write Protected", _selection!.Data.WriteProtected, v => _selection!.Data.WriteProtected = v, false); + } + + private void DrawDesignPanel() + { + if (ImGui.BeginChild("##details", -Vector2.One * 0.001f, true)) + { + DrawDesignHeaderButtons(); + var data = _selection!.Data; + var prot = _selection!.Data.WriteProtected; + if (prot) + { + ImGui.PushStyleVar(ImGuiStyleVar.Alpha, 0.8f); + data = data.Copy(); + } + + DrawGeneralSettings(data, prot); + var mask = data.WriteEquipment; + if (DrawEquip(data.Equipment, ref mask) && !prot) + { + data.WriteEquipment = mask; + _designs.SaveToFile(); + } + + if (DrawCustomization(ref data.Customizations) && !prot) + _designs.SaveToFile(); + + if (DrawMiscellaneous(data, null) && !prot) + _designs.SaveToFile(); + + if (prot) + ImGui.PopStyleVar(); + + ImGui.EndChild(); + } + } + + private void DrawSaves() + { + using var raii = new ImGuiRaii(); + raii.PushStyle(ImGuiStyleVar.IndentSpacing, 25f); + if (!raii.Begin(() => ImGui.BeginTabItem("Saves"), ImGui.EndTabItem)) + return; + + DrawDesignSelector(); + + if (_selection != null) + { + ImGui.SameLine(); + DrawDesignPanel(); + } + } + + private void DrawCheckbox(string label, bool value, Action setter, bool prot) + { + var tmp = value; + if (ImGui.Checkbox(label, ref tmp) && tmp != value) + { + setter(tmp); + if (!prot) + _designs.SaveToFile(); + } + } + + private void DrawGeneralSettings(CharacterSave data, bool prot) + { + ImGui.BeginGroup(); + DrawCheckbox("Apply Customizations", data.WriteCustomizations, v => data.WriteCustomizations = v, prot); + DrawCheckbox("Write Weapon State", data.SetWeaponState, v => data.SetWeaponState = v, prot); + ImGui.EndGroup(); + ImGui.SameLine(); + ImGui.BeginGroup(); + DrawCheckbox("Write Hat State", data.SetHatState, v => data.SetHatState = v, prot); + DrawCheckbox("Write Visor State", data.SetVisorState, v => data.SetVisorState = v, prot); + ImGui.EndGroup(); + } + + private void RenameChildInput(IFileSystemBase child) + { + ImGui.SetNextItemWidth(150); + if (!ImGui.InputTextWithHint("##fsNewName", "Rename...", ref _newChildName, 64, + ImGuiInputTextFlags.EnterReturnsTrue)) + return; + + if (_newChildName.Any() && _newChildName != child.Name) + try + { + var oldPath = child.FullName(); + if (_designs.FileSystem.Rename(child, _newChildName)) + _designs.UpdateAllChildren(oldPath, child); + } + catch (Exception e) + { + PluginLog.Error($"Could not rename {child.Name} to {_newChildName}:\n{e}"); + } + else if (child is Folder f) + try + { + var oldPath = child.FullName(); + if (_designs.FileSystem.Merge(f, f.Parent, true)) + _designs.UpdateAllChildren(oldPath, f.Parent); + } + catch (Exception e) + { + PluginLog.Error($"Could not merge folder {child.Name} into parent:\n{e}"); + } + + _newChildName = string.Empty; + } + + private void ContextMenu(IFileSystemBase child) + { + var label = $"##fsPopup{child.FullName()}"; + var renameLabel = $"{label}_rename"; + if (ImGui.BeginPopup(label)) + { + if (ImGui.MenuItem("Delete")) + _designs.DeleteAllChildren(child, false); + + RenameChildInput(child); + + if (child is Design d && ImGui.MenuItem("Copy to Clipboard")) + Clipboard.SetText(d.Data.ToBase64()); + + ImGui.EndPopup(); + } + + if (ImGui.IsItemClicked(ImGuiMouseButton.Right)) + { + _newChildName = child.Name; + ImGui.OpenPopup(label); + } + } + + private void DrawFolderContent(Folder folder, SortMode mode) + { + foreach (var child in folder.AllChildren(mode).ToArray()) + { + if (child.IsFolder(out var subFolder)) + { + var treeNode = ImGui.TreeNodeEx($"{subFolder.Name}##{_totalObject}"); + DrawOrnaments(child); + + if (treeNode) + { + DrawFolderContent(subFolder, mode); + ImGui.TreePop(); + } + else + { + _totalObject += subFolder.TotalDescendantLeaves(); + } + } + else + { + ++_totalObject; + var selected = ImGui.Selectable($"{child.Name}##{_totalObject}", ReferenceEquals(child, _selection)); + DrawOrnaments(child); + + if (selected) + if (child is Design d) + _selection = d; + } + } + } + + private void DrawOrnaments(IFileSystemBase child) + { + FileSystemImGui.DragDropSource(child); + if (FileSystemImGui.DragDropTarget(_designs.FileSystem, child, out var oldPath, out var draggedFolder)) + _designs.UpdateAllChildren(oldPath, draggedFolder!); + ContextMenu(child); + } + } +} diff --git a/Glamourer/Gui/InterfaceEquipment.cs b/Glamourer/Gui/InterfaceEquipment.cs new file mode 100644 index 0000000..56233a9 --- /dev/null +++ b/Glamourer/Gui/InterfaceEquipment.cs @@ -0,0 +1,138 @@ +using ImGuiNET; +using Penumbra.GameData.Enums; +using Penumbra.GameData.Structs; + +namespace Glamourer.Gui +{ + internal partial class Interface + { + private bool DrawStainSelector(ComboWithFilter stainCombo, EquipSlot slot, StainId stainIdx) + { + stainCombo.PostPreview = null; + if (_stains.TryGetValue((byte) stainIdx, out var stain)) + { + var previewPush = PushColor(stain, ImGuiCol.FrameBg); + stainCombo.PostPreview = () => ImGui.PopStyleColor(previewPush); + } + + if (stainCombo.Draw(string.Empty, out var newStain) && _player != null && !newStain.RowIndex.Equals(stainIdx)) + { + newStain.Write(_player.Address, slot); + return true; + } + + return false; + } + + private bool DrawItemSelector(ComboWithFilter equipCombo, Lumina.Excel.GeneratedSheets.Item? item) + { + var currentName = item?.Name.ToString() ?? "Nothing"; + if (equipCombo.Draw(currentName, out var newItem, _itemComboWidth) && _player != null && newItem.Base.RowId != item?.RowId) + { + newItem.Write(_player.Address); + return true; + } + + return false; + } + + private static bool DrawCheckbox(ActorEquipMask flag, ref ActorEquipMask mask) + { + var tmp = (uint) mask; + var ret = false; + if (ImGui.CheckboxFlags($"##flag_{(uint) flag}", ref tmp, (uint) flag) && tmp != (uint) mask) + { + mask = (ActorEquipMask) tmp; + ret = true; + } + + if (ImGui.IsItemHovered()) + ImGui.SetTooltip("Enable writing this slot in this save."); + return ret; + } + + private bool DrawEquipSlot(EquipSlot slot, ActorArmor equip) + { + var (equipCombo, stainCombo) = _combos[slot]; + + var ret = DrawStainSelector(stainCombo, slot, equip.Stain); + ImGui.SameLine(); + var item = _identifier.Identify(equip.Set, new WeaponType(), equip.Variant, slot); + ret |= DrawItemSelector(equipCombo, item); + + return ret; + } + + private bool DrawEquipSlotWithCheck(EquipSlot slot, ActorArmor equip, ActorEquipMask flag, ref ActorEquipMask mask) + { + var ret = DrawCheckbox(flag, ref mask); + ImGui.SameLine(); + ret |= DrawEquipSlot(slot, equip); + return ret; + } + + private bool DrawWeapon(EquipSlot slot, ActorWeapon weapon) + { + var (equipCombo, stainCombo) = _combos[slot]; + + var ret = DrawStainSelector(stainCombo, slot, weapon.Stain); + ImGui.SameLine(); + var item = _identifier.Identify(weapon.Set, weapon.Type, weapon.Variant, slot); + ret |= DrawItemSelector(equipCombo, item); + + return ret; + } + + private bool DrawWeaponWithCheck(EquipSlot slot, ActorWeapon weapon, ActorEquipMask flag, ref ActorEquipMask mask) + { + var ret = DrawCheckbox(flag, ref mask); + ImGui.SameLine(); + ret |= DrawWeapon(slot, weapon); + return ret; + } + + private bool DrawEquip(ActorEquipment equip) + { + var ret = false; + if (ImGui.CollapsingHeader("Character Equipment")) + { + ret |= DrawWeapon(EquipSlot.MainHand, equip.MainHand); + ret |= DrawWeapon(EquipSlot.OffHand, equip.OffHand); + ret |= DrawEquipSlot(EquipSlot.Head, equip.Head); + ret |= DrawEquipSlot(EquipSlot.Body, equip.Body); + ret |= DrawEquipSlot(EquipSlot.Hands, equip.Hands); + ret |= DrawEquipSlot(EquipSlot.Legs, equip.Legs); + ret |= DrawEquipSlot(EquipSlot.Feet, equip.Feet); + ret |= DrawEquipSlot(EquipSlot.Ears, equip.Ears); + ret |= DrawEquipSlot(EquipSlot.Neck, equip.Neck); + ret |= DrawEquipSlot(EquipSlot.Wrists, equip.Wrists); + ret |= DrawEquipSlot(EquipSlot.RFinger, equip.RFinger); + ret |= DrawEquipSlot(EquipSlot.LFinger, equip.LFinger); + } + + return ret; + } + + private bool DrawEquip(ActorEquipment equip, ref ActorEquipMask mask) + { + var ret = false; + if (ImGui.CollapsingHeader("Character Equipment")) + { + ret |= DrawWeaponWithCheck(EquipSlot.MainHand, equip.MainHand, ActorEquipMask.MainHand, ref mask); + ret |= DrawWeaponWithCheck(EquipSlot.OffHand, equip.OffHand, ActorEquipMask.OffHand, ref mask); + ret |= DrawEquipSlotWithCheck(EquipSlot.Head, equip.Head, ActorEquipMask.Head, ref mask); + ret |= DrawEquipSlotWithCheck(EquipSlot.Body, equip.Body, ActorEquipMask.Body, ref mask); + ret |= DrawEquipSlotWithCheck(EquipSlot.Hands, equip.Hands, ActorEquipMask.Hands, ref mask); + ret |= DrawEquipSlotWithCheck(EquipSlot.Legs, equip.Legs, ActorEquipMask.Legs, ref mask); + ret |= DrawEquipSlotWithCheck(EquipSlot.Feet, equip.Feet, ActorEquipMask.Feet, ref mask); + ret |= DrawEquipSlotWithCheck(EquipSlot.Ears, equip.Ears, ActorEquipMask.Ears, ref mask); + ret |= DrawEquipSlotWithCheck(EquipSlot.Neck, equip.Neck, ActorEquipMask.Neck, ref mask); + ret |= DrawEquipSlotWithCheck(EquipSlot.Wrists, equip.Wrists, ActorEquipMask.Wrists, ref mask); + ret |= DrawEquipSlotWithCheck(EquipSlot.RFinger, equip.RFinger, ActorEquipMask.RFinger, ref mask); + ret |= DrawEquipSlotWithCheck(EquipSlot.LFinger, equip.LFinger, ActorEquipMask.LFinger, ref mask); + } + + return ret; + } + } +} diff --git a/Glamourer/Gui/InterfaceHelpers.cs b/Glamourer/Gui/InterfaceHelpers.cs new file mode 100644 index 0000000..a7e2036 --- /dev/null +++ b/Glamourer/Gui/InterfaceHelpers.cs @@ -0,0 +1,208 @@ +using System; +using System.Linq; +using System.Windows.Forms; +using Dalamud.Game.ClientState.Actors.Types; +using Dalamud.Plugin; +using Glamourer.Customization; +using ImGuiNET; +using Penumbra.Api; +using Penumbra.GameData.Enums; + +namespace Glamourer.Gui +{ + internal partial class Interface + { + // Push the stain color to type and if it is too bright, turn the text color black. + // Return number of pushed styles. + private static int PushColor(Stain stain, ImGuiCol type = ImGuiCol.Button) + { + ImGui.PushStyleColor(type, stain.RgbaColor); + if (stain.Intensity > 127) + { + ImGui.PushStyleColor(ImGuiCol.Text, 0xFF101010); + return 2; + } + + return 1; + } + + // Go through a whole customization struct and fix up all settings that need fixing. + private static void FixUpAttributes(ref ActorCustomization customization) + { + var set = GlamourerPlugin.Customization.GetList(customization.Clan, customization.Gender); + foreach (CustomizationId id in Enum.GetValues(typeof(CustomizationId))) + { + switch (id) + { + case CustomizationId.Race: break; + case CustomizationId.Clan: break; + case CustomizationId.BodyType: break; + case CustomizationId.Gender: break; + case CustomizationId.FacialFeaturesTattoos: break; + case CustomizationId.HighlightsOnFlag: break; + case CustomizationId.Face: + if (customization.Race != Race.Hrothgar) + goto default; + break; + default: + var count = set.Count(id); + if (set.DataByValue(id, customization[id], out var value) < 0) + if (count == 0) + customization[id] = 0; + else + customization[id] = set.Data(id, 0).Value; + break; + } + } + } + + // Change a race and fix up all required customizations afterwards. + private static bool ChangeRace(ref ActorCustomization customization, SubRace clan) + { + if (clan == customization.Clan) + return false; + + var race = clan.ToRace(); + customization.Race = race; + customization.Clan = clan; + + customization.Gender = race switch + { + Race.Hrothgar => Gender.Male, + Race.Viera => Gender.Female, + _ => customization.Gender, + }; + + FixUpAttributes(ref customization); + + return true; + } + + // Change a gender and fix up all required customizations afterwards. + private static bool ChangeGender(ref ActorCustomization customization, Gender gender) + { + if (gender == customization.Gender) + return false; + + customization.Gender = gender; + FixUpAttributes(ref customization); + + return true; + } + + private static string ClanName(SubRace race, Gender gender) + { + if (gender == Gender.Female) + return race switch + { + SubRace.Midlander => GlamourerPlugin.Customization.GetName(CustomName.MidlanderM), + SubRace.Highlander => GlamourerPlugin.Customization.GetName(CustomName.HighlanderM), + SubRace.Wildwood => GlamourerPlugin.Customization.GetName(CustomName.WildwoodM), + SubRace.Duskwight => GlamourerPlugin.Customization.GetName(CustomName.DuskwightM), + SubRace.Plainsfolk => GlamourerPlugin.Customization.GetName(CustomName.PlainsfolkM), + SubRace.Dunesfolk => GlamourerPlugin.Customization.GetName(CustomName.DunesfolkM), + SubRace.SeekerOfTheSun => GlamourerPlugin.Customization.GetName(CustomName.SeekerOfTheSunM), + SubRace.KeeperOfTheMoon => GlamourerPlugin.Customization.GetName(CustomName.KeeperOfTheMoonM), + SubRace.Seawolf => GlamourerPlugin.Customization.GetName(CustomName.SeawolfM), + SubRace.Hellsguard => GlamourerPlugin.Customization.GetName(CustomName.HellsguardM), + SubRace.Raen => GlamourerPlugin.Customization.GetName(CustomName.RaenM), + SubRace.Xaela => GlamourerPlugin.Customization.GetName(CustomName.XaelaM), + SubRace.Helion => GlamourerPlugin.Customization.GetName(CustomName.HelionM), + SubRace.Lost => GlamourerPlugin.Customization.GetName(CustomName.LostM), + SubRace.Rava => GlamourerPlugin.Customization.GetName(CustomName.RavaF), + SubRace.Veena => GlamourerPlugin.Customization.GetName(CustomName.VeenaF), + _ => throw new ArgumentOutOfRangeException(nameof(race), race, null), + }; + + return race switch + { + SubRace.Midlander => GlamourerPlugin.Customization.GetName(CustomName.MidlanderF), + SubRace.Highlander => GlamourerPlugin.Customization.GetName(CustomName.HighlanderF), + SubRace.Wildwood => GlamourerPlugin.Customization.GetName(CustomName.WildwoodF), + SubRace.Duskwight => GlamourerPlugin.Customization.GetName(CustomName.DuskwightF), + SubRace.Plainsfolk => GlamourerPlugin.Customization.GetName(CustomName.PlainsfolkF), + SubRace.Dunesfolk => GlamourerPlugin.Customization.GetName(CustomName.DunesfolkF), + SubRace.SeekerOfTheSun => GlamourerPlugin.Customization.GetName(CustomName.SeekerOfTheSunF), + SubRace.KeeperOfTheMoon => GlamourerPlugin.Customization.GetName(CustomName.KeeperOfTheMoonF), + SubRace.Seawolf => GlamourerPlugin.Customization.GetName(CustomName.SeawolfF), + SubRace.Hellsguard => GlamourerPlugin.Customization.GetName(CustomName.HellsguardF), + SubRace.Raen => GlamourerPlugin.Customization.GetName(CustomName.RaenF), + SubRace.Xaela => GlamourerPlugin.Customization.GetName(CustomName.XaelaF), + SubRace.Helion => GlamourerPlugin.Customization.GetName(CustomName.HelionM), + SubRace.Lost => GlamourerPlugin.Customization.GetName(CustomName.LostM), + SubRace.Rava => GlamourerPlugin.Customization.GetName(CustomName.RavaF), + SubRace.Veena => GlamourerPlugin.Customization.GetName(CustomName.VeenaF), + _ => throw new ArgumentOutOfRangeException(nameof(race), race, null), + }; + } + + private enum DesignNameUse + { + SaveCurrent, + NewDesign, + DuplicateDesign, + NewFolder, + FromClipboard, + } + + private void DrawDesignNamePopup(DesignNameUse use) + { + if (ImGui.BeginPopup($"{DesignNamePopupLabel}{use}")) + { + if (ImGui.InputText("##designName", ref _newDesignName, 64, ImGuiInputTextFlags.EnterReturnsTrue) + && _newDesignName.Any()) + { + switch (use) + { + case DesignNameUse.SaveCurrent: + SaveNewDesign(_currentSave); + break; + case DesignNameUse.NewDesign: + var empty = new CharacterSave(); + empty.Load(ActorCustomization.Default); + empty.WriteCustomizations = false; + SaveNewDesign(empty); + break; + case DesignNameUse.DuplicateDesign: + SaveNewDesign(_selection!.Data.Copy()); + break; + case DesignNameUse.NewFolder: + _designs.FileSystem.CreateAllFolders($"{_newDesignName}/a"); // Filename is just ignored, but all folders are created. + break; + case DesignNameUse.FromClipboard: + try + { + var text = Clipboard.GetText(); + var save = CharacterSave.FromString(text); + SaveNewDesign(save); + } + catch (Exception e) + { + PluginLog.Information($"Could not save new Design from Clipboard:\n{e}"); + } + + break; + } + + _newDesignName = string.Empty; + ImGui.CloseCurrentPopup(); + } + + if (_keyboardFocus) + { + ImGui.SetKeyboardFocusHere(); + _keyboardFocus = false; + } + + ImGui.EndPopup(); + } + } + + private void OpenDesignNamePopup(DesignNameUse use) + { + _newDesignName = string.Empty; + _keyboardFocus = true; + ImGui.OpenPopup($"{DesignNamePopupLabel}{use}"); + } + } +} diff --git a/Glamourer/Gui/InterfaceInitialization.cs b/Glamourer/Gui/InterfaceInitialization.cs new file mode 100644 index 0000000..c393ac3 --- /dev/null +++ b/Glamourer/Gui/InterfaceInitialization.cs @@ -0,0 +1,83 @@ +using System.Collections.Generic; +using System.Numerics; +using System.Reflection; +using ImGuiNET; +using Penumbra.GameData.Enums; +using Lumina.Excel.GeneratedSheets; + +namespace Glamourer.Gui +{ + internal partial class Interface + { + private const float ColorButtonWidth = 22.5f; + private const float ColorComboWidth = 140f; + private const float ItemComboWidth = 300f; + + private static ComboWithFilter CreateDefaultStainCombo(IReadOnlyList stains) + => new("##StainCombo", ColorComboWidth, ColorButtonWidth, stains, + s => s.Name.ToString()) + { + Flags = ImGuiComboFlags.NoArrowButton | ImGuiComboFlags.HeightLarge, + PreList = () => + { + ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, Vector2.Zero); + ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, Vector2.Zero); + ImGui.PushStyleVar(ImGuiStyleVar.FrameRounding, 0); + }, + PostList = () => { ImGui.PopStyleVar(3); }, + CreateSelectable = s => + { + var push = PushColor(s); + var ret = ImGui.Button($"{s.Name}##Stain{(byte) s.RowIndex}", + Vector2.UnitX * (ColorComboWidth - ImGui.GetStyle().ScrollbarSize)); + ImGui.PopStyleColor(push); + return ret; + }, + ItemsAtOnce = 12, + }; + + private ComboWithFilter CreateItemCombo(EquipSlot slot, IReadOnlyList items) + => new($"{_equipSlotNames[slot]}##Equip", ItemComboWidth, ItemComboWidth, items, i => i.Name) + { + Flags = ImGuiComboFlags.HeightLarge, + }; + + private (ComboWithFilter, ComboWithFilter) CreateCombos(EquipSlot slot, IReadOnlyList items, + ComboWithFilter defaultStain) + => (CreateItemCombo(slot, items), new ComboWithFilter($"##{slot}Stain", defaultStain)); + + private static ImGuiScene.TextureWrap? GetLegacyTattooIcon() + { + using var resource = Assembly.GetExecutingAssembly().GetManifestResourceStream("Glamourer.LegacyTattoo.raw"); + if (resource != null) + { + var rawImage = new byte[resource.Length]; + resource.Read(rawImage, 0, (int) resource.Length); + return GlamourerPlugin.PluginInterface.UiBuilder.LoadImageRaw(rawImage, 192, 192, 4); + } + + return null; + } + + private static Dictionary GetEquipSlotNames() + { + var sheet = GlamourerPlugin.PluginInterface.Data.GetExcelSheet(); + var ret = new Dictionary(12) + { + [EquipSlot.MainHand] = sheet.GetRow(738)?.Text.ToString() ?? "Main Hand", + [EquipSlot.OffHand] = sheet.GetRow(739)?.Text.ToString() ?? "Off Hand", + [EquipSlot.Head] = sheet.GetRow(740)?.Text.ToString() ?? "Head", + [EquipSlot.Body] = sheet.GetRow(741)?.Text.ToString() ?? "Body", + [EquipSlot.Hands] = sheet.GetRow(742)?.Text.ToString() ?? "Hands", + [EquipSlot.Legs] = sheet.GetRow(744)?.Text.ToString() ?? "Legs", + [EquipSlot.Feet] = sheet.GetRow(745)?.Text.ToString() ?? "Feet", + [EquipSlot.Ears] = sheet.GetRow(746)?.Text.ToString() ?? "Ears", + [EquipSlot.Neck] = sheet.GetRow(747)?.Text.ToString() ?? "Neck", + [EquipSlot.Wrists] = sheet.GetRow(748)?.Text.ToString() ?? "Wrists", + [EquipSlot.RFinger] = sheet.GetRow(749)?.Text.ToString() ?? "Right Ring", + [EquipSlot.LFinger] = sheet.GetRow(750)?.Text.ToString() ?? "Left Ring", + }; + return ret; + } + } +} diff --git a/Glamourer/Gui/InterfaceMiscellaneous.cs b/Glamourer/Gui/InterfaceMiscellaneous.cs new file mode 100644 index 0000000..b14850d --- /dev/null +++ b/Glamourer/Gui/InterfaceMiscellaneous.cs @@ -0,0 +1,64 @@ +using System; +using Dalamud.Game.ClientState.Actors.Types; +using ImGuiNET; + +namespace Glamourer.Gui +{ + internal partial class Interface + { + private static bool DrawCheckMark(string label, bool value, Action setter) + { + var startValue = value; + if (ImGui.Checkbox(label, ref startValue) && startValue != value) + { + setter(startValue); + return true; + } + + return false; + } + + private static bool DrawMiscellaneous(CharacterSave save, Actor? player) + { + var ret = false; + if (!ImGui.CollapsingHeader("Miscellaneous")) + return ret; + + ret |= DrawCheckMark("Hat Visible", save.HatState, v => + { + save.HatState = v; + player?.SetHatHidden(!v); + }); + + ret |= DrawCheckMark("Weapon Visible", save.WeaponState, v => + { + save.WeaponState = v; + player?.SetWeaponHidden(!v); + }); + + ret |= DrawCheckMark("Visor Toggled", save.VisorState, v => + { + save.VisorState = v; + player?.SetVisorToggled(v); + }); + + ret |= DrawCheckMark("Is Wet", save.IsWet, v => + { + save.IsWet = v; + player?.SetWetness(v); + }); + + var alpha = save.Alpha; + if (ImGui.DragFloat("Alpha", ref alpha, 0.01f, 0f, 1f, "%.2f") && alpha != save.Alpha) + { + alpha = (float) Math.Round(alpha > 1 ? 1 : alpha < 0 ? 0 : alpha, 2); + save.Alpha = alpha; + ret = true; + if (player != null) + player.Alpha() = alpha; + } + + return ret; + } + } +} diff --git a/Glamourer/Main.cs b/Glamourer/Main.cs index ad4e953..3a6b063 100644 --- a/Glamourer/Main.cs +++ b/Glamourer/Main.cs @@ -1,144 +1,36 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Security.Cryptography; +using System.Windows.Forms; +using Dalamud.Game.ClientState.Actors.Types; using Dalamud.Game.Command; using Dalamud.Plugin; using Glamourer.Customization; +using Glamourer.Designs; +using Glamourer.FileSystem; using Glamourer.Gui; using ImGuiNET; +using Lumina.Data; using Penumbra.Api; -using Penumbra.GameData.Structs; -using CommandManager = Glamourer.Managers.CommandManager; +using Penumbra.PlayerWatch; namespace Glamourer { - public class CharacterSave - { - public const byte CurrentVersion = 1; - public const byte TotalSizeVersion1 = 1 + 1 + 2 + 56 + ActorCustomization.CustomizationBytes; - - public const byte TotalSize = TotalSizeVersion1; - - private readonly byte[] _bytes = new byte[TotalSize]; - - public CharacterSave() - => _bytes[0] = CurrentVersion; - - public byte Version - => _bytes[0]; - - public bool WriteCustomizations - { - get => _bytes[1] != 0; - set => _bytes[1] = (byte) (value ? 1 : 0); - } - - public ActorEquipMask WriteEquipment - { - get => (ActorEquipMask) ((ushort) _bytes[2] | ((ushort) _bytes[3] << 8)); - set - { - _bytes[2] = (byte) (((ushort) value) & 0xFF); - _bytes[3] = (byte) (((ushort) value) >> 8); - } - } - - public void Load(ActorCustomization customization) - { - WriteCustomizations = true; - customization.WriteBytes(_bytes, 4); - } - - public void Load(ActorEquipment equipment, ActorEquipMask mask = ActorEquipMask.All) - { - WriteEquipment = mask; - equipment.WriteBytes(_bytes, 4 + ActorCustomization.CustomizationBytes); - } - - public string ToBase64() - => System.Convert.ToBase64String(_bytes); - - public void Load(string base64) - { - var bytes = System.Convert.FromBase64String(base64); - switch (bytes[0]) - { - case 1: - if (bytes.Length != TotalSizeVersion1) - throw new Exception( - $"Can not parse Base64 string into CharacterSave:\n\tInvalid size {bytes.Length} instead of {TotalSizeVersion1}."); - if (bytes[1] != 0 && bytes[1] != 1) - throw new Exception( - $"Can not parse Base64 string into CharacterSave:\n\tInvalid value {bytes[1]} in byte 2, should be either 0 or 1."); - - var mask = (ActorEquipMask) ((ushort) bytes[2] | ((ushort) bytes[3] << 8)); - if (!Enum.IsDefined(typeof(ActorEquipMask), mask)) - throw new Exception($"Can not parse Base64 string into CharacterSave:\n\tInvalid value {mask} in byte 3 and 4."); - bytes.CopyTo(_bytes, 0); - break; - default: - throw new Exception($"Can not parse Base64 string into CharacterSave:\n\tInvalid Version {bytes[0]}."); - } - } - - public static CharacterSave FromString(string base64) - { - var ret = new CharacterSave(); - ret.Load(base64); - return ret; - } - - public unsafe ActorCustomization Customizations - { - get - { - var ret = new ActorCustomization(); - fixed (byte* ptr = _bytes) - { - ret.Read(new IntPtr(ptr) + 4); - } - - return ret; - } - } - - public ActorEquipment Equipment - { - get - { - var ret = new ActorEquipment(); - ret.FromBytes(_bytes, 4 + ActorCustomization.CustomizationBytes); - return ret; - } - } - } - - internal class Glamourer - { - private readonly DalamudPluginInterface _pluginInterface; - private readonly CommandManager _commands; - - public Glamourer(DalamudPluginInterface pi) - { - _pluginInterface = pi; - _commands = new CommandManager(_pluginInterface); - } - } - public class GlamourerPlugin : IDalamudPlugin { public const int RequiredPenumbraShareVersion = 1; + private const string HelpString = "[Copy|Apply|Save],[Name or PlaceHolder],"; + public string Name => "Glamourer"; public static DalamudPluginInterface PluginInterface = null!; - private Glamourer _glamourer = null!; private Interface _interface = null!; public static ICustomizationManager Customization = null!; + public DesignManager Designs = null!; + public IPlayerWatcher PlayerWatcher = null!; public static string Version = string.Empty; @@ -166,13 +58,19 @@ namespace Glamourer { if (button == MouseButton.Right && it is Lumina.Excel.GeneratedSheets.Item item) { - var actors = PluginInterface.ClientState.Actors; - var player = actors[Interface.GPoseActorId] ?? actors[0]; - if (player != null) + var actors = PluginInterface.ClientState.Actors; + var gPose = actors[Interface.GPoseActorId]; + var player = actors[0]; + var writeItem = new Item(item, string.Empty); + if (gPose != null) + { + writeItem.Write(gPose.Address); + UpdateActors(gPose, player); + } + else if (player != null) { - var writeItem = new Item(item, string.Empty); writeItem.Write(player.Address); - _interface.UpdateActors(player); + UpdateActors(player); } } } @@ -244,32 +142,187 @@ namespace Glamourer Customization = CustomizationManager.Create(PluginInterface); SetDalamud(PluginInterface); SetPlugins(PluginInterface); + Designs = new DesignManager(PluginInterface); GetPenumbra(); + PlayerWatcher = PlayerWatchFactory.Create(PluginInterface); - PluginInterface.CommandManager.AddHandler("/glamour", new CommandInfo(OnCommand) + PluginInterface.CommandManager.AddHandler("/glamourer", new CommandInfo(OnGlamourer) { - HelpMessage = "/penumbra - toggle ui\n/penumbra reload - reload mod file lists & discover any new mods", + HelpMessage = "Open or close the Glamourer window.", + }); + PluginInterface.CommandManager.AddHandler("/glamour", new CommandInfo(OnGlamour) + { + HelpMessage = $"Use Glamourer Functions: {HelpString}", }); - _glamourer = new Glamourer(PluginInterface); - _interface = new Interface(); + _interface = new Interface(this); } - public void OnCommand(string command, string arguments) + public void OnGlamourer(string command, string arguments) + => _interface?.ToggleVisibility(null!, null!); + + private Actor? GetActor(string name) { - if (GetPenumbra()) - Penumbra!.RedrawAll(RedrawType.WithSettings); - else - PluginLog.Information("Could not get Penumbra."); + var lowerName = name.ToLowerInvariant(); + return lowerName switch + { + "" => null, + "" => PluginInterface.ClientState.Actors[Interface.GPoseActorId] ?? PluginInterface.ClientState.LocalPlayer, + "self" => PluginInterface.ClientState.Actors[Interface.GPoseActorId] ?? PluginInterface.ClientState.LocalPlayer, + "" => PluginInterface.ClientState.Targets.CurrentTarget, + "target" => PluginInterface.ClientState.Targets.CurrentTarget, + "" => PluginInterface.ClientState.Targets.FocusTarget, + "focus" => PluginInterface.ClientState.Targets.FocusTarget, + "" => PluginInterface.ClientState.Targets.MouseOverTarget, + "mouseover" => PluginInterface.ClientState.Targets.MouseOverTarget, + _ => PluginInterface.ClientState.Actors.LastOrDefault( + a => string.Equals(a.Name, lowerName, StringComparison.InvariantCultureIgnoreCase)), + }; } + public void CopyToClipboard(Actor actor) + { + var save = new CharacterSave(); + save.LoadActor(actor); + Clipboard.SetText(save.ToBase64()); + } + + public void ApplyCommand(Actor actor, string target) + { + CharacterSave? save = null; + if (target.ToLowerInvariant() == "clipboard") + { + try + { + save = CharacterSave.FromString(Clipboard.GetText()); + } + catch (Exception) + { + PluginInterface.Framework.Gui.Chat.PrintError("Clipboard does not contain a valid customization string."); + } + } + else if (!Designs.FileSystem.Find(target, out var child) || child is not Design d) + { + PluginInterface.Framework.Gui.Chat.PrintError("The given path to a saved design does not exist or does not point to a design."); + } + else + { + save = d.Data; + } + + save?.Apply(actor); + UpdateActors(actor); + } + + public void SaveCommand(Actor actor, string path) + { + var save = new CharacterSave(); + save.LoadActor(actor); + try + { + var (folder, name) = Designs.FileSystem.CreateAllFolders(path); + var design = new Design(folder, name) { Data = save }; + folder.FindOrAddChild(design); + Designs.Designs.Add(design.FullName(), design.Data); + Designs.SaveToFile(); + } + catch (Exception e) + { + PluginInterface.Framework.Gui.Chat.PrintError("Could not save file:"); + PluginInterface.Framework.Gui.Chat.PrintError($" {e.Message}"); + } + } + + public void OnGlamour(string command, string arguments) + { + static void PrintHelp() + { + PluginInterface.Framework.Gui.Chat.Print("Usage:"); + PluginInterface.Framework.Gui.Chat.Print($" {HelpString}"); + } + + arguments = arguments.Trim(); + if (!arguments.Any()) + { + PrintHelp(); + return; + } + + var split = arguments.Split(new[] + { + ',', + }, 3, StringSplitOptions.RemoveEmptyEntries); + + if (split.Length < 2) + { + PrintHelp(); + return; + } + + var actor = GetActor(split[1]); + if (actor == null) + { + PluginInterface.Framework.Gui.Chat.Print($"Could not find actor for {split[1]}."); + return; + } + + switch (split[0].ToLowerInvariant()) + { + case "copy": + CopyToClipboard(actor); + return; + case "apply": + { + if (split.Length < 3) + { + PluginInterface.Framework.Gui.Chat.Print("Applying requires a name for the save to be applied or 'clipboard'."); + return; + } + ApplyCommand(actor, split[2]); + + return; + } + case "save": + { + if (split.Length < 3) + { + PluginInterface.Framework.Gui.Chat.Print("Saving requires a name for the save."); + return; + } + SaveCommand(actor, split[2]); + return; + } + default: + PrintHelp(); + return; + } + } + public void Dispose() { + PlayerWatcher?.Dispose(); UnregisterFunctions(); _interface?.Dispose(); PluginInterface.CommandManager.RemoveHandler("/glamour"); + PluginInterface.CommandManager.RemoveHandler("/glamourer"); PluginInterface.Dispose(); } + + // Update actors without triggering PlayerWatcher Events, + // then manually redraw using Penumbra. + public void UpdateActors(Actor actor, Actor? gPoseOriginalActor = null) + { + var newEquip = PlayerWatcher.UpdateActorWithoutEvent(actor); + Penumbra?.RedrawActor(actor, RedrawType.WithSettings); + + // Special case for carrying over changes to the gPose actor to the regular player actor, too. + if (gPoseOriginalActor != null) + { + newEquip.Write(gPoseOriginalActor.Address); + PlayerWatcher.UpdateActorWithoutEvent(gPoseOriginalActor); + Penumbra?.RedrawActor(gPoseOriginalActor, RedrawType.AfterGPoseWithSettings); + } + } } } diff --git a/Glamourer/Managers/CommandManager.cs b/Glamourer/Managers/CommandManager.cs deleted file mode 100644 index 68f1ab1..0000000 --- a/Glamourer/Managers/CommandManager.cs +++ /dev/null @@ -1,73 +0,0 @@ -using System; -using System.Runtime.InteropServices; -using System.Text; -using Dalamud.Plugin; -using Glamourer.SeFunctions; - -namespace Glamourer.Managers -{ - public class CommandManager - { - private readonly ProcessChatBox _processChatBox; - private readonly Dalamud.Game.Command.CommandManager _dalamudCommands; - - private readonly IntPtr _uiModulePtr; - - public CommandManager(DalamudPluginInterface pi, BaseUiObject baseUiObject, GetUiModule getUiModule, ProcessChatBox processChatBox) - { - _dalamudCommands = pi.CommandManager; - _processChatBox = processChatBox; - _uiModulePtr = getUiModule.Invoke(Marshal.ReadIntPtr(baseUiObject.Address)); - } - - public CommandManager(DalamudPluginInterface pi) - : this(pi, new BaseUiObject(pi.TargetModuleScanner), new GetUiModule(pi.TargetModuleScanner), - new ProcessChatBox(pi.TargetModuleScanner)) - { } - - public bool Execute(string message) - { - // First try to process the command through Dalamud. - if (_dalamudCommands.ProcessCommand(message)) - { - PluginLog.Verbose("Executed Dalamud command \"{Message:l}\".", message); - return true; - } - - if (_uiModulePtr == IntPtr.Zero) - { - PluginLog.Error("Can not execute \"{Message:l}\" because no uiModulePtr is available.", message); - return false; - } - - // Then prepare a string to send to the game itself. - var (text, length) = PrepareString(message); - var payload = PrepareContainer(text, length); - - _processChatBox.Invoke(_uiModulePtr, payload, IntPtr.Zero, (byte) 0); - - Marshal.FreeHGlobal(payload); - Marshal.FreeHGlobal(text); - return false; - } - - private static (IntPtr, long) PrepareString(string message) - { - var bytes = Encoding.UTF8.GetBytes(message); - var mem = Marshal.AllocHGlobal(bytes.Length + 30); - Marshal.Copy(bytes, 0, mem, bytes.Length); - Marshal.WriteByte(mem + bytes.Length, 0); - return (mem, bytes.Length + 1); - } - - private static IntPtr PrepareContainer(IntPtr message, long length) - { - var mem = Marshal.AllocHGlobal(400); - Marshal.WriteInt64(mem, message.ToInt64()); - Marshal.WriteInt64(mem + 0x8, 64); - Marshal.WriteInt64(mem + 0x10, length); - Marshal.WriteInt64(mem + 0x18, 0); - return mem; - } - } -} diff --git a/Glamourer/SeFunctions/BaseUiObject.cs b/Glamourer/SeFunctions/BaseUiObject.cs deleted file mode 100644 index 9ad54f6..0000000 --- a/Glamourer/SeFunctions/BaseUiObject.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Dalamud.Game; - -namespace Glamourer.SeFunctions -{ - public sealed class BaseUiObject : SeAddressBase - { - public BaseUiObject(SigScanner sigScanner) - : base(sigScanner, "48 8B 0D ?? ?? ?? ?? 48 8D 54 24 ?? 48 83 C1 10 E8") - { } - } -} diff --git a/Glamourer/SeFunctions/GetUiModule.cs b/Glamourer/SeFunctions/GetUiModule.cs deleted file mode 100644 index 8404e50..0000000 --- a/Glamourer/SeFunctions/GetUiModule.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; -using Dalamud.Game; - -namespace Glamourer.SeFunctions -{ - public delegate IntPtr GetUiModuleDelegate(IntPtr baseUiObj); - - public sealed class GetUiModule : SeFunctionBase - { - public GetUiModule(SigScanner sigScanner) - : base(sigScanner, "E8 ?? ?? ?? ?? 48 83 7F ?? 00 48 8B F0") - { } - } -} diff --git a/Glamourer/SeFunctions/ProcessChatBox.cs b/Glamourer/SeFunctions/ProcessChatBox.cs deleted file mode 100644 index 74e2872..0000000 --- a/Glamourer/SeFunctions/ProcessChatBox.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; -using Dalamud.Game; - -namespace Glamourer.SeFunctions -{ - public delegate IntPtr ProcessChatBoxDelegate(IntPtr uiModule, IntPtr message, IntPtr unk1, byte unk2); - - public sealed class ProcessChatBox : SeFunctionBase - { - public ProcessChatBox(SigScanner sigScanner) - : base(sigScanner, "48 89 5C 24 ?? 57 48 83 EC 20 48 8B FA 48 8B D9 45 84 C9") - { } - } -} diff --git a/Glamourer/SeFunctions/SeAddressBase.cs b/Glamourer/SeFunctions/SeAddressBase.cs deleted file mode 100644 index fb4120f..0000000 --- a/Glamourer/SeFunctions/SeAddressBase.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using Dalamud.Game; -using Dalamud.Plugin; - -namespace Glamourer.SeFunctions -{ - public class SeAddressBase - { - public readonly IntPtr Address; - - public SeAddressBase(SigScanner sigScanner, string signature, int offset = 0) - { - Address = sigScanner.GetStaticAddressFromSig(signature); - if (Address != IntPtr.Zero) - Address += offset; - var baseOffset = (ulong) Address.ToInt64() - (ulong) sigScanner.Module.BaseAddress.ToInt64(); - PluginLog.Debug($"{GetType().Name} address 0x{Address.ToInt64():X16}, baseOffset 0x{baseOffset:X16}."); - } - } -} diff --git a/Glamourer/SeFunctions/SeFunctionBase.cs b/Glamourer/SeFunctions/SeFunctionBase.cs deleted file mode 100644 index 38addd9..0000000 --- a/Glamourer/SeFunctions/SeFunctionBase.cs +++ /dev/null @@ -1,75 +0,0 @@ -using System; -using System.Runtime.InteropServices; -using Dalamud.Game; -using Dalamud.Hooking; -using Dalamud.Plugin; - -namespace Glamourer.SeFunctions -{ - public class SeFunctionBase where T : Delegate - { - public IntPtr Address; - protected T? FuncDelegate; - - public SeFunctionBase(SigScanner sigScanner, int offset) - { - Address = sigScanner.Module.BaseAddress + offset; - PluginLog.Debug($"{GetType().Name} address 0x{Address.ToInt64():X16}, baseOffset 0x{offset:X16}."); - } - - public SeFunctionBase(SigScanner sigScanner, string signature, int offset = 0) - { - Address = sigScanner.ScanText(signature); - if (Address != IntPtr.Zero) - Address += offset; - var baseOffset = (ulong) Address.ToInt64() - (ulong) sigScanner.Module.BaseAddress.ToInt64(); - PluginLog.Debug($"{GetType().Name} address 0x{Address.ToInt64():X16}, baseOffset 0x{baseOffset:X16}."); - } - - public T? Delegate() - { - if (FuncDelegate != null) - return FuncDelegate; - - if (Address != IntPtr.Zero) - { - FuncDelegate = Marshal.GetDelegateForFunctionPointer(Address); - return FuncDelegate; - } - - PluginLog.Error($"Trying to generate delegate for {GetType().Name}, but no pointer available."); - return null; - } - - public dynamic? Invoke(params dynamic[] parameters) - { - if (FuncDelegate != null) - return FuncDelegate.DynamicInvoke(parameters); - - if (Address != IntPtr.Zero) - { - FuncDelegate = Marshal.GetDelegateForFunctionPointer(Address); - return FuncDelegate!.DynamicInvoke(parameters); - } - else - { - PluginLog.Error($"Trying to call {GetType().Name}, but no pointer available."); - return null; - } - } - - public Hook? CreateHook(T detour) - { - if (Address != IntPtr.Zero) - { - var hook = new Hook(Address, detour); - hook.Enable(); - PluginLog.Debug($"Hooked onto {GetType().Name} at address 0x{Address.ToInt64():X16}."); - return hook; - } - - PluginLog.Error($"Trying to create Hook for {GetType().Name}, but no pointer available."); - return null; - } - } -} diff --git a/repo.json b/repo.json index 82aa6b8..7f258ea 100644 --- a/repo.json +++ b/repo.json @@ -4,8 +4,8 @@ "Name": "Glamourer", "Description": "Adds functionality to change appearance of actors. Requires Penumbra to be installed and activated to work.", "InternalName": "Glamourer", - "AssemblyVersion": "0.0.2.0", - "TestingAssemblyVersion": "0.0.2.0", + "AssemblyVersion": "0.0.3.0", + "TestingAssemblyVersion": "0.0.3.0", "RepoUrl": "https://github.com/Ottermandias/Glamourer", "ApplicableVersion": "any", "DalamudApiLevel": 3,