From 1fbd43fea29f1d6405ee4616bb461cd14971f547 Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Thu, 29 Sep 2022 10:35:26 +0200 Subject: [PATCH] bl --- .../Customization/CustomizationData.cs | 91 +++++-- Glamourer/Glamourer.cs | 70 +++--- Glamourer/Gui/Interface.Actors.cs | 1 - Glamourer/Gui/Interface.Customization.cs | 2 +- Glamourer/Gui/Interface.DebugStateTab.cs | 99 ++++++++ Glamourer/Gui/Interface.Equipment.cs | 228 ++++++++++++++++++ Glamourer/Gui/Interface.State.cs | 23 +- Glamourer/Gui/Interface.cs | 88 ------- Glamourer/Gui/InterfaceEquipment.cs | 1 - Glamourer/Interop/RedrawManager.cs | 37 ++- Glamourer/State/CurrentDesign.cs | 12 +- Glamourer/Util/CustomizeExtensions.cs | 2 - 12 files changed, 470 insertions(+), 184 deletions(-) create mode 100644 Glamourer/Gui/Interface.DebugStateTab.cs create mode 100644 Glamourer/Gui/Interface.Equipment.cs diff --git a/Glamourer.GameData/Customization/CustomizationData.cs b/Glamourer.GameData/Customization/CustomizationData.cs index 7135d65..5420e5a 100644 --- a/Glamourer.GameData/Customization/CustomizationData.cs +++ b/Glamourer.GameData/Customization/CustomizationData.cs @@ -24,11 +24,17 @@ public unsafe struct Customize set => Data->Data[1] = (byte)(value - 1); } - public ref byte BodyType - => ref Data->Data[2]; + public byte BodyType + { + get => Data->Data[2]; + set => Data->Data[2] = value; + } - public ref byte Height - => ref Data->Data[3]; + public byte Height + { + get => Data->Data[3]; + set => Data->Data[3] = value; + } public SubRace Clan { @@ -36,11 +42,17 @@ public unsafe struct Customize set => Data->Data[4] = (byte)value; } - public ref byte Face - => ref Data->Data[5]; + public byte Face + { + get => Data->Data[5]; + set => Data->Data[5] = value; + } - public ref byte Hairstyle - => ref Data->Data[6]; + public byte Hairstyle + { + get => Data->Data[6]; + set => Data->Data[6] = value; + } public bool HighlightsOn { @@ -48,17 +60,29 @@ public unsafe struct Customize set => Data->Data[7] = (byte)(value ? Data->Data[7] | 0x80 : Data->Data[7] & 0x7F); } - public ref byte SkinColor - => ref Data->Data[8]; + public byte SkinColor + { + get => Data->Data[8]; + set => Data->Data[8] = value; + } - public ref byte EyeColorRight - => ref Data->Data[9]; + public byte EyeColorRight + { + get => Data->Data[9]; + set => Data->Data[9] = value; + } - public ref byte HairColor - => ref Data->Data[10]; + public byte HairColor + { + get => Data->Data[10]; + set => Data->Data[10] = value; + } - public ref byte HighlightsColor - => ref Data->Data[11]; + public byte HighlightsColor + { + get => Data->Data[11]; + set => Data->Data[11] = value; + } public readonly ref struct FacialFeatureStruct { @@ -86,14 +110,23 @@ public unsafe struct Customize public FacialFeatureStruct FacialFeatures => new(Data->Data + 12); - public ref byte TattooColor - => ref Data->Data[13]; + public byte TattooColor + { + get => Data->Data[13]; + set => Data->Data[13] = value; + } - public ref byte Eyebrows - => ref Data->Data[14]; + public byte Eyebrows + { + get => Data->Data[14]; + set => Data->Data[14] = value; + } - public ref byte EyeColorLeft - => ref Data->Data[15]; + public byte EyeColorLeft + { + get => Data->Data[15]; + set => Data->Data[15] = value; + } public byte EyeShape { @@ -107,11 +140,17 @@ public unsafe struct Customize set => Data->Data[16] = (byte)(value ? Data->Data[16] | 0x80 : Data->Data[16] & 0x7F); } - public ref byte Nose - => ref Data->Data[17]; + public byte Nose + { + get => Data->Data[17]; + set => Data->Data[17] = value; + } - public ref byte Jaw - => ref Data->Data[18]; + public byte Jaw + { + get => Data->Data[18]; + set => Data->Data[18] = value; + } public byte Mouth { diff --git a/Glamourer/Glamourer.cs b/Glamourer/Glamourer.cs index a00f66a..b7eb16f 100644 --- a/Glamourer/Glamourer.cs +++ b/Glamourer/Glamourer.cs @@ -52,42 +52,54 @@ public class Glamourer : IDalamudPlugin public unsafe Glamourer(DalamudPluginInterface pluginInterface) { - Dalamud.Initialize(pluginInterface); - Customization = CustomizationManager.Create(Dalamud.PluginInterface, Dalamud.GameData, Dalamud.ClientState.ClientLanguage); - RestrictedGear = GameData.RestrictedGear(Dalamud.GameData); - Models = GameData.Models(Dalamud.GameData); - Identifier = global::Penumbra.GameData.GameData.GetIdentifier(Dalamud.GameData); - Config = GlamourerConfig.Load(); - Penumbra = new PenumbraAttach(Config.AttachToPenumbra); - FixedDesigns = new FixedDesigns(); - CurrentManipulations = new CurrentManipulations(); - //Designs = new DesignManager(); - - //GlamourerIpc = new GlamourerIpc(Dalamud.ClientState, Dalamud.Objects, Dalamud.PluginInterface); - RedrawManager = new RedrawManager(FixedDesigns, CurrentManipulations); - - Dalamud.Commands.AddHandler(MainCommandString, new CommandInfo(OnGlamourer) + try { - HelpMessage = "Open or close the Glamourer window.", - }); - Dalamud.Commands.AddHandler(ApplyCommandString, new CommandInfo(OnGlamour) - { - HelpMessage = $"Use Glamourer Functions: {HelpString}", - }); + Dalamud.Initialize(pluginInterface); - _interface = new Interface(this); - _windowSystem.AddWindow(_interface); - Dalamud.PluginInterface.UiBuilder.Draw += _windowSystem.Draw; - //FixedDesignManager.Flag((Human*)((Actor)Dalamud.ClientState.LocalPlayer?.Address).Pointer->GameObject.DrawObject, 0, &x); + Customization = CustomizationManager.Create(Dalamud.PluginInterface, Dalamud.GameData, Dalamud.ClientState.ClientLanguage); + RestrictedGear = GameData.RestrictedGear(Dalamud.GameData); + Models = GameData.Models(Dalamud.GameData); + + Config = GlamourerConfig.Load(); + + Identifier = global::Penumbra.GameData.GameData.GetIdentifier(Dalamud.GameData); + Penumbra = new PenumbraAttach(Config.AttachToPenumbra); + FixedDesigns = new FixedDesigns(); + CurrentManipulations = new CurrentManipulations(); + //Designs = new DesignManager(); + + //GlamourerIpc = new GlamourerIpc(Dalamud.ClientState, Dalamud.Objects, Dalamud.PluginInterface); + RedrawManager = new RedrawManager(FixedDesigns, CurrentManipulations); + + Dalamud.Commands.AddHandler(MainCommandString, new CommandInfo(OnGlamourer) + { + HelpMessage = "Open or close the Glamourer window.", + }); + Dalamud.Commands.AddHandler(ApplyCommandString, new CommandInfo(OnGlamour) + { + HelpMessage = $"Use Glamourer Functions: {HelpString}", + }); + + _interface = new Interface(this); + _windowSystem.AddWindow(_interface); + Dalamud.PluginInterface.UiBuilder.Draw += _windowSystem.Draw; + //FixedDesignManager.Flag((Human*)((Actor)Dalamud.ClientState.LocalPlayer?.Address).Pointer->GameObject.DrawObject, 0, &x); + } + catch + { + Dispose(); + throw; + } } public void Dispose() { - RedrawManager.Dispose(); - Penumbra.Dispose(); - Dalamud.PluginInterface.UiBuilder.Draw -= _windowSystem.Draw; - _interface.Dispose(); + RedrawManager?.Dispose(); + Penumbra?.Dispose(); + if (_windowSystem != null) + Dalamud.PluginInterface.UiBuilder.Draw -= _windowSystem.Draw; + _interface?.Dispose(); //GlamourerIpc.Dispose(); Dalamud.Commands.RemoveHandler(ApplyCommandString); Dalamud.Commands.RemoveHandler(MainCommandString); diff --git a/Glamourer/Gui/Interface.Actors.cs b/Glamourer/Gui/Interface.Actors.cs index 4d521e4..8f6b1ad 100644 --- a/Glamourer/Gui/Interface.Actors.cs +++ b/Glamourer/Gui/Interface.Actors.cs @@ -1,5 +1,4 @@ using System; -using System.Linq; using System.Numerics; using Dalamud.Interface; using FFXIVClientStructs.FFXIV.Client.Graphics.Scene; diff --git a/Glamourer/Gui/Interface.Customization.cs b/Glamourer/Gui/Interface.Customization.cs index 3ef734f..f966bfc 100644 --- a/Glamourer/Gui/Interface.Customization.cs +++ b/Glamourer/Gui/Interface.Customization.cs @@ -33,7 +33,7 @@ internal partial class Interface _equip = equip, _actors = actors, }; - + if (!ImGui.CollapsingHeader("Character Customization")) return; diff --git a/Glamourer/Gui/Interface.DebugStateTab.cs b/Glamourer/Gui/Interface.DebugStateTab.cs new file mode 100644 index 0000000..bfe0aeb --- /dev/null +++ b/Glamourer/Gui/Interface.DebugStateTab.cs @@ -0,0 +1,99 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Numerics; +using Glamourer.Interop; +using Glamourer.State; +using ImGuiNET; +using OtterGui; +using OtterGui.Classes; +using OtterGui.Raii; + +namespace Glamourer.Gui; + +internal partial class Interface +{ + private class DebugStateTab + { + private readonly CurrentManipulations _currentManipulations; + + private LowerString _manipulationFilter = LowerString.Empty; + private Actor.IIdentifier _selection = Actor.IIdentifier.Invalid; + private CurrentDesign? _save = null; + private bool _delete = false; + + public DebugStateTab(CurrentManipulations currentManipulations) + => _currentManipulations = currentManipulations; + + [Conditional("DEBUG")] + public void Draw() + { + using var tab = ImRaii.TabItem("Current Manipulations"); + if (!tab) + return; + + DrawManipulationSelector(); + if (_save == null) + return; + + ImGui.SameLine(); + DrawActorPanel(); + if (_delete) + { + _delete = false; + _currentManipulations.DeleteSave(_selection); + _selection = Actor.IIdentifier.Invalid; + } + } + + private void DrawSelector(Vector2 oldSpacing) + { + using var child = ImRaii.Child("##actorSelector", new Vector2(_actorSelectorWidth, -1), true); + if (!child) + return; + + using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, oldSpacing); + var skips = ImGuiClip.GetNecessarySkips(ImGui.GetTextLineHeight()); + var remainder = ImGuiClip.FilteredClippedDraw(_currentManipulations, skips, CheckFilter, DrawSelectable); + ImGuiClip.DrawEndDummy(remainder, ImGui.GetTextLineHeight()); + } + + private void DrawManipulationSelector() + { + using var group = ImRaii.Group(); + var oldSpacing = ImGui.GetStyle().ItemSpacing; + using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero) + .Push(ImGuiStyleVar.FrameRounding, 0); + ImGui.SetNextItemWidth(_actorSelectorWidth); + LowerString.InputWithHint("##actorFilter", "Filter...", ref _manipulationFilter, 64); + + _save = null; + DrawSelector(oldSpacing); + } + + private bool CheckFilter(KeyValuePair data) + { + if (data.Key.Equals(_selection)) + _save = data.Value; + return _manipulationFilter.Length == 0 || _manipulationFilter.IsContained(data.Key.ToString()!); + } + + private void DrawSelectable(KeyValuePair data) + { + var equal = data.Key.Equals(_selection); + if (ImGui.Selectable(data.Key.ToString(), equal)) + { + _selection = data.Key; + _save = data.Value; + } + } + + private void DrawActorPanel() + { + using var group = ImRaii.Group(); + if (ImGui.Button("Delete")) + _delete = true; + CustomizationDrawer.Draw(_save!.Data.Customize, _save.Data.Equipment, Array.Empty(), false); + } + } +} diff --git a/Glamourer/Gui/Interface.Equipment.cs b/Glamourer/Gui/Interface.Equipment.cs new file mode 100644 index 0000000..251ad60 --- /dev/null +++ b/Glamourer/Gui/Interface.Equipment.cs @@ -0,0 +1,228 @@ +using System; +using System.Collections.Generic; +using Dalamud.Interface; +using Glamourer.Customization; +using Glamourer.Interop; +using Glamourer.Structs; +using ImGuiNET; +using Lumina.Text; +using OtterGui; +using OtterGui.Raii; +using Penumbra.GameData.Enums; +using Penumbra.GameData.Structs; +using static Glamourer.Interop.Actor; +using static Lumina.Data.Parsing.Layer.LayerCommon; + +namespace Glamourer.Gui; + +internal partial class Interface +{ + //public class EquipmentDrawer + //{ + // private static + // + // private Race _race; + // private Gender _gender; + // private CharacterEquip _equip; + // private IReadOnlyCollection _actors = Array.Empty(); + // + // public static void Draw(Customize customize, CharacterEquip equip, IReadOnlyCollection actors, bool locked) + // { + // var d = new EquipmentDrawer() + // { + // _race = customize.Race, + // _gender = customize.Gender, + // _actors = actors, + // }; + // + // if (!ImGui.CollapsingHeader("Character Equipment")) + // return; + // + // using var disabled = ImRaii.Disabled(locked); + // } + // + // 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); + // } + // + // var change = stainCombo.Draw(string.Empty, out var newStain) && !newStain.RowIndex.Equals(stainIdx); + // if (!change && (byte)stainIdx != 0) + // { + // ImGuiUtil.HoverTooltip("Right-click to clear."); + // if (ImGui.IsItemClicked(ImGuiMouseButton.Right)) + // { + // change = true; + // newStain = Stain.None; + // } + // } + // + // if (!change) + // return false; + // + // if (_player == null) + // return _inDesignMode && (_selection?.Data.WriteStain(slot, newStain.RowIndex) ?? false); + // + // Glamourer.RevertableDesigns.Add(_player); + // newStain.Write(_player.Address, slot); + // return true; + // } + // + // private bool DrawItemSelector(ComboWithFilter equipCombo, Lumina.Excel.GeneratedSheets.Item item, EquipSlot slot = EquipSlot.Unknown) + // { + // var currentName = item.Name.ToString(); + // var change = equipCombo.Draw(currentName, out var newItem, _itemComboWidth) && newItem.Base.RowId != item.RowId; + // if (!change && !ReferenceEquals(item, SmallClothes)) + // { + // ImGuiUtil.HoverTooltip("Right-click to clear."); + // if (ImGui.IsItemClicked(ImGuiMouseButton.Right)) + // { + // change = true; + // newItem = Item.Nothing(slot); + // } + // } + // + // if (!change) + // return false; + // + // newItem = new Item(newItem.Base, newItem.Name, slot); + // if (_player == null) + // return _inDesignMode && (_selection?.Data.WriteItem(newItem) ?? false); + // + // Glamourer.RevertableDesigns.Add(_player); + // newItem.Write(_player.Address); + // return true; + // } + // + // private static bool DrawCheckbox(CharacterEquipMask flag, ref CharacterEquipMask mask) + // { + // var tmp = (uint)mask; + // var ret = false; + // if (ImGui.CheckboxFlags($"##flag_{(uint)flag}", ref tmp, (uint)flag) && tmp != (uint)mask) + // { + // mask = (CharacterEquipMask)tmp; + // ret = true; + // } + // + // if (ImGui.IsItemHovered()) + // ImGui.SetTooltip("Enable writing this slot in this save."); + // return ret; + // } + // + // private static readonly Lumina.Excel.GeneratedSheets.Item SmallClothes = new() + // { + // Name = new SeString("Nothing"), + // RowId = 0, + // }; + // + // private static readonly Lumina.Excel.GeneratedSheets.Item SmallClothesNpc = new() + // { + // Name = new SeString("Smallclothes (NPC)"), + // RowId = 1, + // }; + // + // private static readonly Lumina.Excel.GeneratedSheets.Item Unknown = new() + // { + // Name = new SeString("Unknown"), + // RowId = 2, + // }; + // + // private Lumina.Excel.GeneratedSheets.Item Identify(SetId set, WeaponType weapon, ushort variant, EquipSlot slot) + // { + // return (uint)set switch + // { + // 0 => SmallClothes, + // 9903 => SmallClothesNpc, + // _ => _identifier.Identify(set, weapon, variant, slot) ?? Unknown, + // }; + // } + // + // private bool DrawEquipSlot(EquipSlot slot, CharacterArmor equip) + // { + // var (equipCombo, stainCombo) = _combos[slot]; + // + // var ret = DrawStainSelector(stainCombo, slot, equip.Stain); + // ImGui.SameLine(); + // var item = Identify(equip.Set, new WeaponType(), equip.Variant, slot); + // ret |= DrawItemSelector(equipCombo, item, slot); + // + // return ret; + // } + // + // private bool DrawEquipSlotWithCheck(EquipSlot slot, CharacterArmor equip, CharacterEquipMask flag, ref CharacterEquipMask mask) + // { + // var ret = DrawCheckbox(flag, ref mask); + // ImGui.SameLine(); + // ret |= DrawEquipSlot(slot, equip); + // return ret; + // } + // + // private bool DrawWeapon(EquipSlot slot, CharacterWeapon weapon) + // { + // var (equipCombo, stainCombo) = _combos[slot]; + // + // var ret = DrawStainSelector(stainCombo, slot, weapon.Stain); + // ImGui.SameLine(); + // var item = Identify(weapon.Set, weapon.Type, weapon.Variant, slot); + // ret |= DrawItemSelector(equipCombo, item, slot); + // + // return ret; + // } + // + // private bool DrawWeaponWithCheck(EquipSlot slot, CharacterWeapon weapon, CharacterEquipMask flag, ref CharacterEquipMask mask) + // { + // var ret = DrawCheckbox(flag, ref mask); + // ImGui.SameLine(); + // ret |= DrawWeapon(slot, weapon); + // return ret; + // } + // + // private bool DrawEquip(CharacterEquipment 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(CharacterEquipment equip, ref CharacterEquipMask mask) + // { + // var ret = false; + // if (ImGui.CollapsingHeader("Character Equipment")) + // { + // ret |= DrawWeaponWithCheck(EquipSlot.MainHand, equip.MainHand, CharacterEquipMask.MainHand, ref mask); + // ret |= DrawWeaponWithCheck(EquipSlot.OffHand, equip.OffHand, CharacterEquipMask.OffHand, ref mask); + // ret |= DrawEquipSlotWithCheck(EquipSlot.Head, equip.Head, CharacterEquipMask.Head, ref mask); + // ret |= DrawEquipSlotWithCheck(EquipSlot.Body, equip.Body, CharacterEquipMask.Body, ref mask); + // ret |= DrawEquipSlotWithCheck(EquipSlot.Hands, equip.Hands, CharacterEquipMask.Hands, ref mask); + // ret |= DrawEquipSlotWithCheck(EquipSlot.Legs, equip.Legs, CharacterEquipMask.Legs, ref mask); + // ret |= DrawEquipSlotWithCheck(EquipSlot.Feet, equip.Feet, CharacterEquipMask.Feet, ref mask); + // ret |= DrawEquipSlotWithCheck(EquipSlot.Ears, equip.Ears, CharacterEquipMask.Ears, ref mask); + // ret |= DrawEquipSlotWithCheck(EquipSlot.Neck, equip.Neck, CharacterEquipMask.Neck, ref mask); + // ret |= DrawEquipSlotWithCheck(EquipSlot.Wrists, equip.Wrists, CharacterEquipMask.Wrists, ref mask); + // ret |= DrawEquipSlotWithCheck(EquipSlot.RFinger, equip.RFinger, CharacterEquipMask.RFinger, ref mask); + // ret |= DrawEquipSlotWithCheck(EquipSlot.LFinger, equip.LFinger, CharacterEquipMask.LFinger, ref mask); + // } + // + // return ret; + // } + //} +} diff --git a/Glamourer/Gui/Interface.State.cs b/Glamourer/Gui/Interface.State.cs index 1639135..a9b07b8 100644 --- a/Glamourer/Gui/Interface.State.cs +++ b/Glamourer/Gui/Interface.State.cs @@ -2,8 +2,6 @@ using System.Numerics; using System.Reflection; using Dalamud.Interface; -using Glamourer.Customization; -using Glamourer.Interop; using ImGuiNET; namespace Glamourer.Gui; @@ -13,7 +11,6 @@ internal partial class Interface private static readonly ImGuiScene.TextureWrap? LegacyTattoo = GetLegacyTattooIcon(); private static readonly Vector4 RedTint = new(0.6f, 0.3f, 0.3f, 1f); - private static Vector2 _iconSize = Vector2.Zero; private static Vector2 _framedIconSize = Vector2.Zero; private static Vector2 _spacing = Vector2.Zero; @@ -22,7 +19,6 @@ internal partial class Interface private static float _comboSelectorSize; private static float _raceSelectorWidth; - private static void UpdateState() { // General @@ -35,23 +31,18 @@ internal partial class Interface _inputIntSize = 2 * _framedIconSize.X + ImGui.GetStyle().ItemSpacing.X; _comboSelectorSize = 4 * _framedIconSize.X + 3 * ImGui.GetStyle().ItemSpacing.X; _raceSelectorWidth = _inputIntSize + _comboSelectorSize - _framedIconSize.X; - - // _itemComboWidth = 6 * _actualIconSize.X + 4 * ImGui.GetStyle().ItemSpacing.X - ColorButtonWidth + 1; } private static ImGuiScene.TextureWrap? GetLegacyTattooIcon() { using var resource = Assembly.GetExecutingAssembly().GetManifestResourceStream("Glamourer.LegacyTattoo.raw"); - if (resource != null) - { - var rawImage = new byte[resource.Length]; - var length = resource.Read(rawImage, 0, (int)resource.Length); - if (length != resource.Length) - return null; + if (resource == null) + return null; - return Dalamud.PluginInterface.UiBuilder.LoadImageRaw(rawImage, 192, 192, 4); - } - - return null; + var rawImage = new byte[resource.Length]; + var length = resource.Read(rawImage, 0, (int)resource.Length); + return length == resource.Length + ? Dalamud.PluginInterface.UiBuilder.LoadImageRaw(rawImage, 192, 192, 4) + : null; } } diff --git a/Glamourer/Gui/Interface.cs b/Glamourer/Gui/Interface.cs index 77478f7..df81459 100644 --- a/Glamourer/Gui/Interface.cs +++ b/Glamourer/Gui/Interface.cs @@ -1,103 +1,15 @@ using System; -using System.Collections.Generic; using System.Linq; using System.Numerics; using Dalamud.Interface.Windowing; using Dalamud.Logging; -using Glamourer.Interop; -using Glamourer.State; using ImGuiNET; -using OtterGui; -using OtterGui.Classes; using OtterGui.Raii; namespace Glamourer.Gui; internal partial class Interface : Window, IDisposable { - private class DebugStateTab - { - private readonly CurrentManipulations _currentManipulations; - - private LowerString _manipulationFilter = LowerString.Empty; - private Actor.IIdentifier _selection = Actor.IIdentifier.Invalid; - private CurrentDesign? _save = null; - private bool _delete = false; - - public DebugStateTab(CurrentManipulations currentManipulations) - => _currentManipulations = currentManipulations; - - public void Draw() - { - using var tab = ImRaii.TabItem("Current Manipulations"); - if (!tab) - return; - - DrawManipulationSelector(); - if (_save == null) - return; - - ImGui.SameLine(); - DrawActorPanel(); - if (_delete) - { - _delete = false; - _currentManipulations.DeleteSave(_selection); - _selection = Actor.IIdentifier.Invalid; - } - } - - private void DrawSelector(Vector2 oldSpacing) - { - using var child = ImRaii.Child("##actorSelector", new Vector2(_actorSelectorWidth, -1), true); - if (!child) - return; - - using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, oldSpacing); - var skips = ImGuiClip.GetNecessarySkips(ImGui.GetTextLineHeight()); - var remainder = ImGuiClip.FilteredClippedDraw(_currentManipulations, skips, CheckFilter, DrawSelectable); - ImGuiClip.DrawEndDummy(remainder, ImGui.GetTextLineHeight()); - } - - private void DrawManipulationSelector() - { - using var group = ImRaii.Group(); - var oldSpacing = ImGui.GetStyle().ItemSpacing; - using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, Vector2.Zero) - .Push(ImGuiStyleVar.FrameRounding, 0); - ImGui.SetNextItemWidth(_actorSelectorWidth); - LowerString.InputWithHint("##actorFilter", "Filter...", ref _manipulationFilter, 64); - - _save = null; - DrawSelector(oldSpacing); - } - - private bool CheckFilter(KeyValuePair data) - { - if (data.Key.Equals(_selection)) - _save = data.Value; - return _manipulationFilter.Length == 0 || _manipulationFilter.IsContained(data.Key.ToString()!); - } - - private void DrawSelectable(KeyValuePair data) - { - var equal = data.Key.Equals(_selection); - if (ImGui.Selectable(data.Key.ToString(), equal)) - { - _selection = data.Key; - _save = data.Value; - } - } - - private void DrawActorPanel() - { - using var group = ImRaii.Group(); - if (ImGui.Button("Delete")) - _delete = true; - CustomizationDrawer.Draw(_save!.Data.Customize, _save.Data.Equipment, Array.Empty(), false); - } - } - private readonly Glamourer _plugin; private readonly ActorTab _actorTab; diff --git a/Glamourer/Gui/InterfaceEquipment.cs b/Glamourer/Gui/InterfaceEquipment.cs index f58d5b0..fdf6156 100644 --- a/Glamourer/Gui/InterfaceEquipment.cs +++ b/Glamourer/Gui/InterfaceEquipment.cs @@ -5,7 +5,6 @@ using Lumina.Text; using OtterGui; using Penumbra.GameData.Enums; using Penumbra.GameData.Structs; -using Penumbra.PlayerWatch; namespace Glamourer.Gui; diff --git a/Glamourer/Interop/RedrawManager.cs b/Glamourer/Interop/RedrawManager.cs index 02d7254..3722c7a 100644 --- a/Glamourer/Interop/RedrawManager.cs +++ b/Glamourer/Interop/RedrawManager.cs @@ -54,7 +54,7 @@ public unsafe partial class RedrawManager { PluginLog.Information($"Updated {slot} from current designs for {identifier}."); (var replaced, *data) = - Glamourer.RestrictedGear.ResolveRestricted(*data, slot, (Race)drawObject->Race, (Gender)drawObject->Sex); + Glamourer.RestrictedGear.ResolveRestricted(*data, slot, (Race)drawObject->Race, (Gender)(drawObject->Sex + 1)); save2.Data.Equipment[slot] = *data; } } @@ -214,25 +214,24 @@ public unsafe partial class RedrawManager : IDisposable if (!(_currentManipulations.TryGetDesign(identifier, out var save) || _fixedDesigns.TryGetDesign(identifier, out var save2))) return; - // Compare game object customize data against draw object customize data for transformations. // Apply customization if they correspond and there is customization to apply. - //var gameObjectCustomize = new Customize((CustomizeData*)actor.Pointer->CustomizeData); - //if (gameObjectCustomize.Equals(customize)) - // customize.Load(save.Customize); - // - //// Compare game object equip data against draw object equip data for transformations. - //// Apply each piece of equip that should be applied if they correspond. - //var gameObjectEquip = new CharacterEquip((CharacterArmor*)actor.Pointer->EquipSlotData); - //if (gameObjectEquip.Equals(equip)) - //{ - // var saveEquip = save.Equipment; - // foreach (var slot in EquipSlotExtensions.EqdpSlots) - // { - // (var _, equip[slot]) = - // Glamourer.RestrictedGear.ResolveRestricted(true ? equip[slot] : saveEquip[slot], slot, customize.Race, customize.Gender); - // } - //} + var gameObjectCustomize = new Customize((CustomizeData*)actor.Pointer->CustomizeData); + if (gameObjectCustomize.Equals(customize)) + customize.Load(save.Data.Customize); + + // Compare game object equip data against draw object equip data for transformations. + // Apply each piece of equip that should be applied if they correspond. + var gameObjectEquip = new CharacterEquip((CharacterArmor*)actor.Pointer->EquipSlotData); + if (gameObjectEquip.Equals(equip)) + { + var saveEquip = save.Data.Equipment; + foreach (var slot in EquipSlotExtensions.EqdpSlots) + { + (var _, equip[slot]) = + Glamourer.RestrictedGear.ResolveRestricted(true ? equip[slot] : saveEquip[slot], slot, customize.Race, customize.Gender); + } + } } private void OnCharacterRedraw(IntPtr gameObject, IntPtr modelId, IntPtr customize, IntPtr equipData) @@ -267,7 +266,7 @@ public unsafe partial class RedrawManager : IDisposable { if (!drawObject.Valid) return false; - + return _changeCustomize(drawObject.Pointer, (byte*)customize.Data, 1); } diff --git a/Glamourer/State/CurrentDesign.cs b/Glamourer/State/CurrentDesign.cs index 6e7693a..34fc6ea 100644 --- a/Glamourer/State/CurrentDesign.cs +++ b/Glamourer/State/CurrentDesign.cs @@ -1,4 +1,7 @@ -using Glamourer.Interop; +using System.Collections.Generic; +using System.Linq; +using Glamourer.Customization; +using Glamourer.Interop; using Penumbra.GameData.Enums; namespace Glamourer.State; @@ -25,6 +28,13 @@ public unsafe class CurrentDesign : ICharacterData _drawData = _initialData.Clone(); } + public void SaveCustomization(Customize customize, IReadOnlyCollection actors) + { + _drawData.Customize.Load(customize); + foreach (var actor in actors.Where(a => a && a.DrawObject)) + Glamourer.RedrawManager.UpdateCustomize(actor.DrawObject, _drawData.Customize); + } + public void Update(Actor actor) { if (!actor) diff --git a/Glamourer/Util/CustomizeExtensions.cs b/Glamourer/Util/CustomizeExtensions.cs index d08824c..973c309 100644 --- a/Glamourer/Util/CustomizeExtensions.cs +++ b/Glamourer/Util/CustomizeExtensions.cs @@ -1,7 +1,5 @@ using System; -using System.Net.Http; using Glamourer.Customization; -using Glamourer.State; using Penumbra.GameData.Enums; using Penumbra.GameData.Structs;