diff --git a/Glamourer.GameData/Customization/CustomizationOptions.cs b/Glamourer.GameData/Customization/CustomizationOptions.cs index 6ee80d3..0830457 100644 --- a/Glamourer.GameData/Customization/CustomizationOptions.cs +++ b/Glamourer.GameData/Customization/CustomizationOptions.cs @@ -150,7 +150,7 @@ namespace Glamourer.Customization var row = _listSheet.GetRow(((uint) race - 1) * 2 - 1 + (uint) gender)!; var set = new CustomizationSet(race, gender) { - HairStyles = race.ToRace() == Race.Hrothgar ? HrothgarFaces(row) : GetHairStyles(race, gender), + HairStyles = GetHairStyles(race, gender), HairColors = hair, SkinColors = skin, EyeColors = _eyeColorPicker, diff --git a/Glamourer.GameData/Glamourer.GameData.csproj b/Glamourer.GameData/Glamourer.GameData.csproj index 560f5bf..c2b60ab 100644 --- a/Glamourer.GameData/Glamourer.GameData.csproj +++ b/Glamourer.GameData/Glamourer.GameData.csproj @@ -55,8 +55,9 @@ $(AppData)\XIVLauncher\addon\Hooks\dev\Lumina.Excel.dll False - - ..\..\Penumbra\Penumbra\bin\$(Configuration)\$(TargetFramework)\Penumbra.GameData.dll - + + + + diff --git a/Glamourer.sln b/Glamourer.sln index 8b1bc26..56bc1ba 100644 --- a/Glamourer.sln +++ b/Glamourer.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.29613.14 +# Visual Studio Version 17 +VisualStudioVersion = 17.2.32210.308 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Glamourer", "Glamourer\Glamourer.csproj", "{A5439F6B-83C1-4078-9371-354A147FF554}" EndProject @@ -13,6 +13,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Glamourer.GameData", "Glamourer.GameData\Glamourer.GameData.csproj", "{51F4DDB0-1FA0-4629-9CFE-C55B6062907B}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Penumbra.GameData", "..\Penumbra\Penumbra.GameData\Penumbra.GameData.csproj", "{9BEE2336-AA93-4669-8EEA-4756B3B2D024}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Penumbra.PlayerWatch", "..\Penumbra\Penumbra.PlayerWatch\Penumbra.PlayerWatch.csproj", "{FECEDB39-C103-4333-82A6-A422BDC51EEE}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -47,6 +51,30 @@ Global {51F4DDB0-1FA0-4629-9CFE-C55B6062907B}.Release|x64.Build.0 = Release|Any CPU {51F4DDB0-1FA0-4629-9CFE-C55B6062907B}.Release|x86.ActiveCfg = Release|Any CPU {51F4DDB0-1FA0-4629-9CFE-C55B6062907B}.Release|x86.Build.0 = Release|Any CPU + {9BEE2336-AA93-4669-8EEA-4756B3B2D024}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9BEE2336-AA93-4669-8EEA-4756B3B2D024}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9BEE2336-AA93-4669-8EEA-4756B3B2D024}.Debug|x64.ActiveCfg = Debug|Any CPU + {9BEE2336-AA93-4669-8EEA-4756B3B2D024}.Debug|x64.Build.0 = Debug|Any CPU + {9BEE2336-AA93-4669-8EEA-4756B3B2D024}.Debug|x86.ActiveCfg = Debug|Any CPU + {9BEE2336-AA93-4669-8EEA-4756B3B2D024}.Debug|x86.Build.0 = Debug|Any CPU + {9BEE2336-AA93-4669-8EEA-4756B3B2D024}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9BEE2336-AA93-4669-8EEA-4756B3B2D024}.Release|Any CPU.Build.0 = Release|Any CPU + {9BEE2336-AA93-4669-8EEA-4756B3B2D024}.Release|x64.ActiveCfg = Release|Any CPU + {9BEE2336-AA93-4669-8EEA-4756B3B2D024}.Release|x64.Build.0 = Release|Any CPU + {9BEE2336-AA93-4669-8EEA-4756B3B2D024}.Release|x86.ActiveCfg = Release|Any CPU + {9BEE2336-AA93-4669-8EEA-4756B3B2D024}.Release|x86.Build.0 = Release|Any CPU + {FECEDB39-C103-4333-82A6-A422BDC51EEE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FECEDB39-C103-4333-82A6-A422BDC51EEE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FECEDB39-C103-4333-82A6-A422BDC51EEE}.Debug|x64.ActiveCfg = Debug|Any CPU + {FECEDB39-C103-4333-82A6-A422BDC51EEE}.Debug|x64.Build.0 = Debug|Any CPU + {FECEDB39-C103-4333-82A6-A422BDC51EEE}.Debug|x86.ActiveCfg = Debug|Any CPU + {FECEDB39-C103-4333-82A6-A422BDC51EEE}.Debug|x86.Build.0 = Debug|Any CPU + {FECEDB39-C103-4333-82A6-A422BDC51EEE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FECEDB39-C103-4333-82A6-A422BDC51EEE}.Release|Any CPU.Build.0 = Release|Any CPU + {FECEDB39-C103-4333-82A6-A422BDC51EEE}.Release|x64.ActiveCfg = Release|Any CPU + {FECEDB39-C103-4333-82A6-A422BDC51EEE}.Release|x64.Build.0 = Release|Any CPU + {FECEDB39-C103-4333-82A6-A422BDC51EEE}.Release|x86.ActiveCfg = Release|Any CPU + {FECEDB39-C103-4333-82A6-A422BDC51EEE}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Glamourer.sln.DotSettings.user b/Glamourer.sln.DotSettings.user index e414fe4..12f85e0 100644 --- a/Glamourer.sln.DotSettings.user +++ b/Glamourer.sln.DotSettings.user @@ -1,4 +1,6 @@  <AssemblyExplorer> <Assembly Path="H:\Projects\FFPlugins\Penumbra\Penumbra\bin\Debug\net472\Penumbra.GameData.dll" /> + <Assembly Path="C:\Users\Ozy\AppData\Roaming\XIVLauncher\addon\Hooks\dev\Dalamud.dll" /> + <Assembly Path="H:\Projects\FFPlugins\Penumbra\Penumbra\bin\Debug\net5.0-windows\Penumbra.GameData.dll" /> </AssemblyExplorer> \ No newline at end of file diff --git a/Glamourer.zip b/Glamourer.zip index aa4d873..e74dd0d 100644 Binary files a/Glamourer.zip and b/Glamourer.zip differ diff --git a/Glamourer/CharacterExtensions.cs b/Glamourer/CharacterExtensions.cs index 4a38366..0d28e13 100644 --- a/Glamourer/CharacterExtensions.cs +++ b/Glamourer/CharacterExtensions.cs @@ -4,20 +4,8 @@ namespace Glamourer; public static class CharacterExtensions { - public const int WetnessOffset = 0x1ADA; - public const byte WetnessFlag = 0x80; - public const int HatVisibleOffset = 0x84E; - public const int VisorToggledOffset = 0x84F; - public const byte HatHiddenFlag = 0x01; - public const byte VisorToggledFlag = 0x08; - public const int AlphaOffset = 0x19E0; - public const int WeaponHiddenOffset1 = 0x84F; - public const int WeaponHiddenOffset2 = 0x72C; // maybe - public const byte WeaponHiddenFlag1 = 0x01; - public const byte WeaponHiddenFlag2 = 0x02; - public static unsafe bool IsWet(this Character a) - => (*((byte*)a.Address + WetnessOffset) & WetnessFlag) != 0; + => (*((byte*)a.Address + Offsets.Character.Wetness) & Offsets.Character.Flags.IsWet) != 0; public static unsafe bool SetWetness(this Character a, bool value) { @@ -26,14 +14,16 @@ public static class CharacterExtensions return false; if (value) - *((byte*)a.Address + WetnessOffset) = (byte)(*((byte*)a.Address + WetnessOffset) | WetnessFlag); + *((byte*)a.Address + Offsets.Character.Wetness) = + (byte)(*((byte*)a.Address + Offsets.Character.Wetness) | Offsets.Character.Flags.IsWet); else - *((byte*)a.Address + WetnessOffset) = (byte)(*((byte*)a.Address + WetnessOffset) & ~WetnessFlag); + *((byte*)a.Address + Offsets.Character.Wetness) = + (byte)(*((byte*)a.Address + Offsets.Character.Wetness) & ~Offsets.Character.Flags.IsWet); return true; } public static unsafe bool IsHatVisible(this Character a) - => (*((byte*)a.Address + HatVisibleOffset) & HatHiddenFlag) == 0; + => (*((byte*)a.Address + Offsets.Character.HatVisible) & Offsets.Character.Flags.IsHatHidden) == 0; public static unsafe bool SetHatVisible(this Character a, bool visible) { @@ -42,14 +32,17 @@ public static class CharacterExtensions return false; if (visible) - *((byte*)a.Address + HatVisibleOffset) = (byte)(*((byte*)a.Address + HatVisibleOffset) & ~HatHiddenFlag); + *((byte*)a.Address + Offsets.Character.HatVisible) = + (byte)(*((byte*)a.Address + Offsets.Character.HatVisible) & ~Offsets.Character.Flags.IsHatHidden); else - *((byte*)a.Address + HatVisibleOffset) = (byte)(*((byte*)a.Address + HatVisibleOffset) | HatHiddenFlag); + *((byte*)a.Address + Offsets.Character.HatVisible) = + (byte)(*((byte*)a.Address + Offsets.Character.HatVisible) | Offsets.Character.Flags.IsHatHidden); return true; } public static unsafe bool IsVisorToggled(this Character a) - => (*((byte*)a.Address + VisorToggledOffset) & VisorToggledFlag) == VisorToggledFlag; + => (*((byte*)a.Address + Offsets.Character.VisorToggled) & Offsets.Character.Flags.IsVisorToggled) + == Offsets.Character.Flags.IsVisorToggled; public static unsafe bool SetVisorToggled(this Character a, bool toggled) { @@ -58,15 +51,19 @@ public static class CharacterExtensions return false; if (toggled) - *((byte*)a.Address + VisorToggledOffset) = (byte)(*((byte*)a.Address + VisorToggledOffset) | VisorToggledFlag); + *((byte*)a.Address + Offsets.Character.VisorToggled) = + (byte)(*((byte*)a.Address + Offsets.Character.VisorToggled) | Offsets.Character.Flags.IsVisorToggled); else - *((byte*)a.Address + VisorToggledOffset) = (byte)(*((byte*)a.Address + VisorToggledOffset) & ~VisorToggledFlag); + *((byte*)a.Address + Offsets.Character.VisorToggled) = + (byte)(*((byte*)a.Address + Offsets.Character.VisorToggled) & ~Offsets.Character.Flags.IsVisorToggled); return true; } public static unsafe bool IsWeaponHidden(this Character a) - => (*((byte*)a.Address + WeaponHiddenOffset1) & WeaponHiddenFlag1) == WeaponHiddenFlag1 - && (*((byte*)a.Address + WeaponHiddenOffset2) & WeaponHiddenFlag2) == WeaponHiddenFlag2; + => (*((byte*)a.Address + Offsets.Character.WeaponHidden1) & Offsets.Character.Flags.IsWeaponHidden1) + == Offsets.Character.Flags.IsWeaponHidden1 + && (*((byte*)a.Address + Offsets.Character.WeaponHidden2) & Offsets.Character.Flags.IsWeaponHidden2) + == Offsets.Character.Flags.IsWeaponHidden2; public static unsafe bool SetWeaponHidden(this Character a, bool value) { @@ -74,21 +71,22 @@ public static class CharacterExtensions if (hidden == value) return false; - var val1 = *((byte*)a.Address + WeaponHiddenOffset1); - var val2 = *((byte*)a.Address + WeaponHiddenOffset2); + var val1 = *((byte*)a.Address + Offsets.Character.WeaponHidden1); + var val2 = *((byte*)a.Address + Offsets.Character.WeaponHidden2); if (value) { - *((byte*)a.Address + WeaponHiddenOffset1) = (byte)(val1 | WeaponHiddenFlag1); - *((byte*)a.Address + WeaponHiddenOffset2) = (byte)(val2 | WeaponHiddenFlag2); + *((byte*)a.Address + Offsets.Character.WeaponHidden1) = (byte)(val1 | Offsets.Character.Flags.IsWeaponHidden1); + *((byte*)a.Address + Offsets.Character.WeaponHidden2) = (byte)(val2 | Offsets.Character.Flags.IsWeaponHidden2); } else { - *((byte*)a.Address + WeaponHiddenOffset1) = (byte)(val1 & ~WeaponHiddenFlag1); - *((byte*)a.Address + WeaponHiddenOffset2) = (byte)(val2 & ~WeaponHiddenFlag2); + *((byte*)a.Address + Offsets.Character.WeaponHidden1) = (byte)(val1 & ~Offsets.Character.Flags.IsWeaponHidden1); + *((byte*)a.Address + Offsets.Character.WeaponHidden2) = (byte)(val2 & ~Offsets.Character.Flags.IsWeaponHidden2); } + return true; } public static unsafe ref float Alpha(this Character a) - => ref *(float*)((byte*)a.Address + AlphaOffset); + => ref *(float*)((byte*)a.Address + Offsets.Character.Alpha); } diff --git a/Glamourer/CharacterSave.cs b/Glamourer/CharacterSave.cs index eeeca88..c9dd7ea 100644 --- a/Glamourer/CharacterSave.cs +++ b/Glamourer/CharacterSave.cs @@ -310,11 +310,11 @@ public class CharacterSave a.SetWetness(IsWet); a.Alpha() = Alpha; if (SetHatState) - a.SetHatVisible(!HatState); + a.SetHatVisible(HatState); if (SetVisorState) a.SetVisorToggled(VisorState); if (SetWeaponState) - a.SetWeaponHidden(WeaponState); + a.SetWeaponHidden(!WeaponState); } public void ApplyOnlyEquipment(Character a) diff --git a/Glamourer/Designs/FixedDesigns.cs b/Glamourer/Designs/FixedDesigns.cs index 2c56197..5d0804f 100644 --- a/Glamourer/Designs/FixedDesigns.cs +++ b/Glamourer/Designs/FixedDesigns.cs @@ -134,7 +134,7 @@ namespace Glamourer.Designs design.Jobs.Name); design.Design.Data.Apply(character); Glamourer.PlayerWatcher.UpdatePlayerWithoutEvent(character); - Glamourer.Penumbra.RedrawObject(character, RedrawType.WithSettings, false); + Glamourer.Penumbra.RedrawObject(character, RedrawType.Redraw, false); } public void Add(string name, Design design, JobGroup group, bool enabled = false) diff --git a/Glamourer/Glamourer.csproj b/Glamourer/Glamourer.csproj index 08e8b63..5e183c7 100644 --- a/Glamourer/Glamourer.csproj +++ b/Glamourer/Glamourer.csproj @@ -17,6 +17,7 @@ enable bin\$(Configuration)\ $(MSBuildWarningsAsMessages);MSB3277 + true @@ -69,23 +70,35 @@ $(appdata)\XIVLauncher\addon\Hooks\dev\Lumina.Excel.dll False - - ..\..\Penumbra\Penumbra\bin\$(Configuration)\$(TargetFramework)\Penumbra.GameData.dll - True - - - ..\..\Penumbra\Penumbra\bin\$(Configuration)\$(TargetFramework)\Penumbra.PlayerWatch.dll - True - - + + false + + + + + + + + + True + True + Resources.resx + + + + + + ResXFileCodeGenerator + Resources.Designer.cs + diff --git a/Glamourer/Gui/InterfaceActorPanel.cs b/Glamourer/Gui/InterfaceActorPanel.cs index 49f1914..3ff2f14 100644 --- a/Glamourer/Gui/InterfaceActorPanel.cs +++ b/Glamourer/Gui/InterfaceActorPanel.cs @@ -18,12 +18,14 @@ namespace Glamourer.Gui { internal partial class Interface { - private readonly CharacterSave _currentSave = new(); - private string _newDesignName = string.Empty; - private bool _keyboardFocus; - private const string DesignNamePopupLabel = "Save Design As..."; - private const uint RedHeaderColor = 0xFF1818C0; - private const uint GreenHeaderColor = 0xFF18C018; + private readonly CharacterSave _currentSave = new(); + private string _newDesignName = string.Empty; + private bool _keyboardFocus; + private bool _holdShift; + private bool _holdCtrl; + private const string DesignNamePopupLabel = "Save Design As..."; + private const uint RedHeaderColor = 0xFF1818C0; + private const uint GreenHeaderColor = 0xFF18C018; private void DrawPlayerHeader() { @@ -58,10 +60,10 @@ namespace Glamourer.Gui save.Apply(player); } - private CharacterSave ConditionalCopy(CharacterSave save) + private static CharacterSave ConditionalCopy(CharacterSave save, bool shift, bool ctrl) { var copy = save.Copy(); - if (ImGui.GetIO().KeyShift) + if (shift) { copy.Load(new CharacterEquipment()); copy.SetHatState = false; @@ -69,7 +71,7 @@ namespace Glamourer.Gui copy.SetWeaponState = false; copy.WriteEquipment = CharacterEquipMask.None; } - else if (ImGui.GetIO().KeyCtrl) + else if (ctrl) { copy.Load(CharacterCustomization.Default); copy.SetHatState = false; @@ -77,8 +79,8 @@ namespace Glamourer.Gui copy.SetWeaponState = false; copy.WriteCustomizations = false; } - - return save.Copy(); + + return copy; } private bool DrawApplyClipboardButton() diff --git a/Glamourer/Gui/InterfaceCustomization.cs b/Glamourer/Gui/InterfaceCustomization.cs index a797bdf..31c500f 100644 --- a/Glamourer/Gui/InterfaceCustomization.cs +++ b/Glamourer/Gui/InterfaceCustomization.cs @@ -162,7 +162,7 @@ namespace Glamourer.Gui var count = set.Count(CustomizationId.FacialFeaturesTattoos); using (var _ = ImGuiRaii.NewGroup()) { - var face = set.Race == Race.Hrothgar ? customization.Hairstyle : customization.Face; + var face = customization.Face; if (set.Faces.Count < face) face = 1; for (var i = 0; i < count; ++i) @@ -288,9 +288,6 @@ namespace Glamourer.Gui ret = true; } - if (id == CustomizationId.Hairstyle && customization.Race == Race.Hrothgar) - customization[CustomizationId.Face] = (byte) ((customization[CustomizationId.Hairstyle] + 1) / 2); - ImGui.Text($"{label} ({custom.Value.Value})"); ImGuiCustom.HoverTooltip(tooltip); diff --git a/Glamourer/Gui/InterfaceEquipment.cs b/Glamourer/Gui/InterfaceEquipment.cs index c7ffc33..019fc64 100644 --- a/Glamourer/Gui/InterfaceEquipment.cs +++ b/Glamourer/Gui/InterfaceEquipment.cs @@ -57,6 +57,7 @@ namespace Glamourer.Gui if (!change) return false; + newItem = new Item(newItem.Base, newItem.Name, slot); if (_player == null) return _inDesignMode && (_selection?.Data.WriteItem(newItem) ?? false); diff --git a/Glamourer/Gui/InterfaceHelpers.cs b/Glamourer/Gui/InterfaceHelpers.cs index 1a0e8cd..88845ec 100644 --- a/Glamourer/Gui/InterfaceHelpers.cs +++ b/Glamourer/Gui/InterfaceHelpers.cs @@ -37,10 +37,7 @@ namespace Glamourer.Gui case CustomizationId.Gender: break; case CustomizationId.FacialFeaturesTattoos: break; case CustomizationId.HighlightsOnFlag: break; - case CustomizationId.Face: - if (customization.Race != Race.Hrothgar) - goto default; - break; + case CustomizationId.Face: break; default: var count = set.Count(id); if (set.DataByValue(id, customization[id], out _) < 0) @@ -148,7 +145,7 @@ namespace Glamourer.Gui switch (use) { case DesignNameUse.SaveCurrent: - SaveNewDesign(ConditionalCopy(_currentSave)); + SaveNewDesign(ConditionalCopy(_currentSave, _holdShift, _holdCtrl)); break; case DesignNameUse.NewDesign: var empty = new CharacterSave(); @@ -157,7 +154,7 @@ namespace Glamourer.Gui SaveNewDesign(empty); break; case DesignNameUse.DuplicateDesign: - SaveNewDesign(ConditionalCopy(_selection!.Data)); + SaveNewDesign(ConditionalCopy(_selection!.Data, _holdShift, _holdCtrl)); break; case DesignNameUse.NewFolder: _designs.FileSystem @@ -196,6 +193,8 @@ namespace Glamourer.Gui { _newDesignName = string.Empty; _keyboardFocus = true; + _holdCtrl = ImGui.GetIO().KeyCtrl; + _holdShift = ImGui.GetIO().KeyShift; ImGui.OpenPopup($"{DesignNamePopupLabel}{use}"); } } diff --git a/Glamourer/Offsets.cs b/Glamourer/Offsets.cs new file mode 100644 index 0000000..8c08073 --- /dev/null +++ b/Glamourer/Offsets.cs @@ -0,0 +1,23 @@ +namespace Glamourer; + +public static class Offsets +{ + public static class Character + { + public const int Wetness = 0x1ADA; + public const int HatVisible = 0x84E; + public const int VisorToggled = 0x84F; + public const int WeaponHidden1 = 0x84F; + public const int WeaponHidden2 = 0x72C; + public const int Alpha = 0x19E0; + + public static class Flags + { + public const byte IsHatHidden = 0x01; + public const byte IsVisorToggled = 0x08; + public const byte IsWet = 0x80; + public const byte IsWeaponHidden1 = 0x01; + public const byte IsWeaponHidden2 = 0x02; + } + } +} diff --git a/Glamourer/PenumbraAttach.cs b/Glamourer/PenumbraAttach.cs index 3b75c86..68c8619 100644 --- a/Glamourer/PenumbraAttach.cs +++ b/Glamourer/PenumbraAttach.cs @@ -6,135 +6,155 @@ using Glamourer.Gui; using ImGuiNET; using Penumbra.GameData.Enums; -namespace Glamourer +namespace Glamourer; + +public class PenumbraAttach : IDisposable { - public class PenumbraAttach : IDisposable + public const int RequiredPenumbraShareVersion = 4; + + private ICallGateSubscriber? _tooltipSubscriber; + private ICallGateSubscriber? _clickSubscriber; + private ICallGateSubscriber? _redrawSubscriberName; + private ICallGateSubscriber? _redrawSubscriberObject; + + private readonly ICallGateSubscriber _initializedEvent; + private readonly ICallGateSubscriber _disposedEvent; + + public PenumbraAttach(bool attach) { - public const int RequiredPenumbraShareVersion = 3; + _initializedEvent = Dalamud.PluginInterface.GetIpcSubscriber("Penumbra.Initialized"); + _disposedEvent = Dalamud.PluginInterface.GetIpcSubscriber("Penumbra.Disposed"); + _initializedEvent.Subscribe(Reattach); + _disposedEvent.Subscribe(Unattach); + Reattach(attach); + } - private ICallGateSubscriber? _tooltipSubscriber; - private ICallGateSubscriber? _clickSubscriber; - private ICallGateSubscriber? _redrawSubscriberName; - private ICallGateSubscriber? _redrawSubscriberObject; + private void Reattach() + => Reattach(Glamourer.Config.AttachToPenumbra); - public PenumbraAttach(bool attach) - => Reattach(attach); + public void Reattach(bool attach) + { + try + { + Unattach(); - public void Reattach(bool attach) + var versionSubscriber = Dalamud.PluginInterface.GetIpcSubscriber("Penumbra.ApiVersion"); + var version = versionSubscriber.InvokeFunc(); + if (version != RequiredPenumbraShareVersion) + throw new Exception($"Invalid Version {version}, required Version {RequiredPenumbraShareVersion}."); + + _redrawSubscriberName = Dalamud.PluginInterface.GetIpcSubscriber("Penumbra.RedrawObjectByName"); + _redrawSubscriberObject = Dalamud.PluginInterface.GetIpcSubscriber("Penumbra.RedrawObject"); + + if (!attach) + return; + + _tooltipSubscriber = Dalamud.PluginInterface.GetIpcSubscriber("Penumbra.ChangedItemTooltip"); + _clickSubscriber = + Dalamud.PluginInterface.GetIpcSubscriber("Penumbra.ChangedItemClick"); + _tooltipSubscriber.Subscribe(PenumbraTooltip); + _clickSubscriber.Subscribe(PenumbraRightClick); + PluginLog.Debug("Glamourer attached to Penumbra."); + } + catch (Exception e) + { + PluginLog.Debug($"Could not attach to Penumbra:\n{e}"); + } + } + + public void Unattach() + { + _tooltipSubscriber?.Unsubscribe(PenumbraTooltip); + _clickSubscriber?.Unsubscribe(PenumbraRightClick); + _tooltipSubscriber = null; + _clickSubscriber = null; + _redrawSubscriberName = null; + if (_redrawSubscriberObject != null) + { + PluginLog.Debug("Glamourer detached from Penumbra."); + _redrawSubscriberObject = null; + } + } + + public void Dispose() + { + _initializedEvent.Unsubscribe(Reattach); + _disposedEvent.Unsubscribe(Unattach); + Unattach(); + } + + private static void PenumbraTooltip(ChangedItemType type, uint _) + { + if (type == ChangedItemType.Item) + ImGui.Text("Right click to apply to current Glamourer Set. [Glamourer]"); + } + + private void PenumbraRightClick(MouseButton button, ChangedItemType type, uint id) + { + if (button != MouseButton.Right || type != ChangedItemType.Item) + return; + + var gPose = Dalamud.Objects[Interface.GPoseObjectId] as Character; + var player = Dalamud.Objects[0] as Character; + var item = (Lumina.Excel.GeneratedSheets.Item)type.GetObject(id)!; + var writeItem = new Item(item, string.Empty); + if (gPose != null) + { + writeItem.Write(gPose.Address); + UpdateCharacters(gPose, player); + } + else if (player != null) + { + writeItem.Write(player.Address); + UpdateCharacters(player); + } + } + + public void RedrawObject(GameObject actor, RedrawType settings, bool repeat) + { + if (_redrawSubscriberObject != null) { try { - Unattach(); - - var versionSubscriber = Dalamud.PluginInterface.GetIpcSubscriber("Penumbra.ApiVersion"); - var version = versionSubscriber.InvokeFunc(); - if (version != RequiredPenumbraShareVersion) - throw new Exception($"Invalid Version {version}, required Version {RequiredPenumbraShareVersion}."); - - _redrawSubscriberName = Dalamud.PluginInterface.GetIpcSubscriber("Penumbra.RedrawObjectByName"); - _redrawSubscriberObject = Dalamud.PluginInterface.GetIpcSubscriber("Penumbra.RedrawObject"); - - if (!attach) - return; - - _tooltipSubscriber = Dalamud.PluginInterface.GetIpcSubscriber("Penumbra.ChangedItemTooltip"); - _clickSubscriber = - Dalamud.PluginInterface.GetIpcSubscriber("Penumbra.ChangedItemClick"); - _tooltipSubscriber.Subscribe(PenumbraTooltip); - _clickSubscriber.Subscribe(PenumbraRightClick); + _redrawSubscriberObject.InvokeAction(actor, (int)settings); } catch (Exception e) { - PluginLog.Debug($"Could not attach to Penumbra:\n{e}"); - } - } - - public void Unattach() - { - _tooltipSubscriber?.Unsubscribe(PenumbraTooltip); - _clickSubscriber?.Unsubscribe(PenumbraRightClick); - _tooltipSubscriber = null; - _clickSubscriber = null; - _redrawSubscriberName = null; - _redrawSubscriberObject = null; - } - - public void Dispose() - => Unattach(); - - private static void PenumbraTooltip(ChangedItemType type, uint _) - { - if (type == ChangedItemType.Item) - ImGui.Text("Right click to apply to current Glamourer Set. [Glamourer]"); - } - - private void PenumbraRightClick(MouseButton button, ChangedItemType type, uint id) - { - if (button != MouseButton.Right || type != ChangedItemType.Item) - return; - - var gPose = Dalamud.Objects[Interface.GPoseObjectId] as Character; - var player = Dalamud.Objects[0] as Character; - var item = (Lumina.Excel.GeneratedSheets.Item) type.GetObject(id)!; - var writeItem = new Item(item, string.Empty); - if (gPose != null) - { - writeItem.Write(gPose.Address); - UpdateCharacters(gPose, player); - } - else if (player != null) - { - writeItem.Write(player.Address); - UpdateCharacters(player); - } - } - - public void RedrawObject(GameObject actor, RedrawType settings, bool repeat) - { - if (_redrawSubscriberObject != null) - { - try + if (repeat) { - _redrawSubscriberObject.InvokeAction(actor, (int) settings); + Reattach(Glamourer.Config.AttachToPenumbra); + RedrawObject(actor, settings, false); } - catch (Exception e) + else { - if (repeat) - { - Reattach(Glamourer.Config.AttachToPenumbra); - RedrawObject(actor, settings, false); - } - else - { - PluginLog.Debug($"Failure redrawing object:\n{e}"); - } + PluginLog.Debug($"Failure redrawing object:\n{e}"); } } - else if (repeat) - { - Reattach(Glamourer.Config.AttachToPenumbra); - RedrawObject(actor, settings, false); - } - else - { - PluginLog.Debug("Trying to redraw object, but not attached to Penumbra."); - } } - - // Update objects without triggering PlayerWatcher Events, - // then manually redraw using Penumbra. - public void UpdateCharacters(Character character, Character? gPoseOriginalCharacter = null) + else if (repeat) { - var newEquip = Glamourer.PlayerWatcher.UpdatePlayerWithoutEvent(character); - RedrawObject(character, RedrawType.WithSettings, true); - - // Special case for carrying over changes to the gPose player to the regular player, too. - if (gPoseOriginalCharacter == null) - return; - - newEquip.Write(gPoseOriginalCharacter.Address); - Glamourer.PlayerWatcher.UpdatePlayerWithoutEvent(gPoseOriginalCharacter); - RedrawObject(gPoseOriginalCharacter, RedrawType.AfterGPoseWithSettings, false); + Reattach(Glamourer.Config.AttachToPenumbra); + RedrawObject(actor, settings, false); + } + else + { + PluginLog.Debug("Trying to redraw object, but not attached to Penumbra."); } } + + // Update objects without triggering PlayerWatcher Events, + // then manually redraw using Penumbra. + public void UpdateCharacters(Character character, Character? gPoseOriginalCharacter = null) + { + var newEquip = Glamourer.PlayerWatcher.UpdatePlayerWithoutEvent(character); + RedrawObject(character, RedrawType.Redraw, true); + + // Special case for carrying over changes to the gPose player to the regular player, too. + if (gPoseOriginalCharacter == null) + return; + + newEquip.Write(gPoseOriginalCharacter.Address); + Glamourer.PlayerWatcher.UpdatePlayerWithoutEvent(gPoseOriginalCharacter); + RedrawObject(gPoseOriginalCharacter, RedrawType.AfterGPose, false); + } }