From 129f9e070fac4a71a32f7d34d45205979b553011 Mon Sep 17 00:00:00 2001 From: Ottermandias Date: Wed, 12 Jul 2023 18:29:21 +0200 Subject: [PATCH] Some more interface work. --- Glamourer/Designs/DesignBase64Migration.cs | 2 +- Glamourer/Designs/DesignManager.cs | 6 +- Glamourer/Gui/Equipment/EquipmentDrawer.cs | 373 +++++++++++++----- Glamourer/Gui/Equipment/ItemCombo.cs | 2 +- Glamourer/Gui/Equipment/WeaponCombo.cs | 2 +- Glamourer/Gui/MainWindow.cs | 2 +- Glamourer/Gui/PenumbraChangedItemTooltip.cs | 2 +- Glamourer/Gui/Tabs/ActorTab/ActorPanel.cs | 161 +++++--- Glamourer/Gui/Tabs/DesignTab/DesignPanel.cs | 100 ++--- Glamourer/Gui/Tabs/HeaderDrawer.cs | 18 +- .../Gui/Tabs/UnlocksTab/UnlockOverview.cs | 2 +- Glamourer/Gui/Tabs/UnlocksTab/UnlockTable.cs | 4 +- Glamourer/Gui/UiHelpers.cs | 26 +- Glamourer/Interop/WeaponService.cs | 6 +- Glamourer/Services/ItemManager.cs | 18 +- Glamourer/State/StateApplier.cs | 2 +- Glamourer/State/StateEditor.cs | 2 +- 17 files changed, 485 insertions(+), 243 deletions(-) diff --git a/Glamourer/Designs/DesignBase64Migration.cs b/Glamourer/Designs/DesignBase64Migration.cs index 3a18ec5..99d8347 100644 --- a/Glamourer/Designs/DesignBase64Migration.cs +++ b/Glamourer/Designs/DesignBase64Migration.cs @@ -81,7 +81,7 @@ public static class DesignBase64Migration data.SetItem(EquipSlot.MainHand, main); data.SetStain(EquipSlot.MainHand, cur[0].Stain); var off = items.Identify(EquipSlot.OffHand, cur[1].Set, cur[1].Type, (byte)cur[1].Variant, main.Type); - if (main.Type.Offhand() != FullEquipType.Unknown && !off.Valid) + if (main.Type.ValidOffhand() != FullEquipType.Unknown && !off.Valid) throw new Exception($"Base64 string invalid, weapon could not be identified."); data.SetItem(EquipSlot.OffHand, off); diff --git a/Glamourer/Designs/DesignManager.cs b/Glamourer/Designs/DesignManager.cs index f705faa..7ab1657 100644 --- a/Glamourer/Designs/DesignManager.cs +++ b/Glamourer/Designs/DesignManager.cs @@ -337,10 +337,8 @@ public class DesignManager if (item.Type != currentMain.Type) { - var newOffId = item.Type.Offhand().IsOffhandType() - ? item.ItemId - : ItemManager.NothingId(item.Type.Offhand()); - if (!_items.IsOffhandValid(item, newOffId, out newOff)) + var defaultOffhand = _items.GetDefaultOffhand(item); + if (!_items.IsOffhandValid(item, defaultOffhand.ItemId, out newOff)) return; } diff --git a/Glamourer/Gui/Equipment/EquipmentDrawer.cs b/Glamourer/Gui/Equipment/EquipmentDrawer.cs index e5cffde..b46161f 100644 --- a/Glamourer/Gui/Equipment/EquipmentDrawer.cs +++ b/Glamourer/Gui/Equipment/EquipmentDrawer.cs @@ -7,6 +7,7 @@ using Dalamud.Data; using Dalamud.Interface; using Glamourer.Designs; using Glamourer.Services; +using Glamourer.Structs; using ImGuiNET; using OtterGui; using OtterGui.Raii; @@ -33,7 +34,7 @@ public class EquipmentDrawer _codes = codes; _textures = textures; _stainData = items.Stains; - _stainCombo = new FilterComboColors(140, + _stainCombo = new FilterComboColors(280, _stainData.Data.Prepend(new KeyValuePair(0, ("None", 0, false)))); _itemCombo = EquipSlotExtensions.EqdpSlots.Select(e => new ItemCombo(gameData, items, e, textures)).ToArray(); _weaponCombo = new Dictionary(FullEquipTypeExtensions.WeaponTypes.Count * 2); @@ -54,39 +55,262 @@ public class EquipmentDrawer public void Prepare() { _iconSize = new Vector2(2 * ImGui.GetFrameHeight() + ImGui.GetStyle().ItemSpacing.Y); - _comboLength = 320 * ImGuiHelpers.GlobalScale; + _comboLength = 300 * ImGuiHelpers.GlobalScale; } - private string VerifyRestrictedGear(EquipItem gear, EquipSlot slot, Gender gender, Race race) + private bool VerifyRestrictedGear(EquipSlot slot, EquipItem gear, Gender gender, Race race) { if (slot.IsAccessory()) - return gear.Name; + return false; var (changed, _) = _items.ResolveRestrictedGear(gear.Armor(), slot, race, gender); - if (changed) - return gear.Name + " (Restricted)"; - - return gear.Name; + return changed; } - public bool DrawArmor(EquipItem current, EquipSlot slot, out EquipItem armor, Gender gender = Gender.Unknown, Race race = Race.Unknown) + [Flags] + public enum EquipChange : byte { - Debug.Assert(slot.IsEquipment() || slot.IsAccessory(), $"Called {nameof(DrawArmor)} on {slot}."); + None = 0x00, + Item = 0x01, + Stain = 0x02, + ApplyItem = 0x04, + ApplyStain = 0x08, + Item2 = 0x10, + Stain2 = 0x20, + ApplyItem2 = 0x40, + ApplyStain2 = 0x80, + } - if (_codes.EnabledArtisan) - return DrawArmorArtisan(current, slot, out armor, gender, race); + public EquipChange DrawEquip(EquipSlot slot, in DesignData designData, out EquipItem rArmor, out StainId rStain, EquipFlag? cApply, + out bool rApply, out bool rApplyStain, bool locked) + => DrawEquip(slot, designData.Item(slot), out rArmor, designData.Stain(slot), out rStain, cApply, out rApply, out rApplyStain, locked, + designData.Customize.Gender, designData.Customize.Race); - current.DrawIcon(_textures, _iconSize); + public EquipChange DrawEquip(EquipSlot slot, EquipItem cArmor, out EquipItem rArmor, StainId cStain, out StainId rStain, EquipFlag? cApply, + out bool rApply, out bool rApplyStain, bool locked, Gender gender = Gender.Unknown, Race race = Race.Unknown) + { + if (!locked && _codes.EnabledArtisan) + return DrawEquipArtisan(slot, cArmor, out rArmor, cStain, out rStain, cApply, out rApply, out rApplyStain); + + var spacing = ImGui.GetStyle().ItemInnerSpacing with { Y = ImGui.GetStyle().ItemSpacing.Y }; + using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, spacing); + + var changes = EquipChange.None; + cArmor.DrawIcon(_textures, _iconSize); ImGui.SameLine(); using var group = ImRaii.Group(); + if (DrawItem(slot, cArmor, out rArmor, out var label, locked)) + changes |= EquipChange.Item; + if (cApply.HasValue) + { + ImGui.SameLine(); + if (DrawApply(slot, cApply.Value, out rApply, locked)) + changes |= EquipChange.ApplyItem; + } + else + { + rApply = true; + } + ImGui.SameLine(); + ImGui.TextUnformatted(label); + if (DrawStain(slot, cStain, out rStain, locked)) + changes |= EquipChange.Stain; + if (cApply.HasValue) + { + ImGui.SameLine(); + if (DrawApplyStain(slot, cApply.Value, out rApplyStain, locked)) + changes |= EquipChange.ApplyStain; + } + else + { + rApplyStain = true; + } + + if (VerifyRestrictedGear(slot, rArmor, gender, race)) + { + ImGui.SameLine(); + ImGui.TextUnformatted("(Restricted)"); + } + + return changes; + } + + public EquipChange DrawWeapons(in DesignData designData, out EquipItem rMainhand, out EquipItem rOffhand, out StainId rMainhandStain, + out StainId rOffhandStain, EquipFlag? cApply, out bool rApplyMainhand, out bool rApplyMainhandStain, out bool rApplyOffhand, + out bool rApplyOffhandStain, bool locked) + => DrawWeapons(designData.Item(EquipSlot.MainHand), out rMainhand, designData.Item(EquipSlot.OffHand), out rOffhand, + designData.Stain(EquipSlot.MainHand), out rMainhandStain, designData.Stain(EquipSlot.OffHand), out rOffhandStain, cApply, + out rApplyMainhand, out rApplyMainhandStain, out rApplyOffhand, out rApplyOffhandStain, locked); + + public EquipChange DrawWeapons(EquipItem cMainhand, out EquipItem rMainhand, EquipItem cOffhand, out EquipItem rOffhand, + StainId cMainhandStain, out StainId rMainhandStain, StainId cOffhandStain, out StainId rOffhandStain, EquipFlag? cApply, + out bool rApplyMainhand, out bool rApplyMainhandStain, out bool rApplyOffhand, out bool rApplyOffhandStain, bool locked) + { + var changes = EquipChange.None; + + using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, + ImGui.GetStyle().ItemInnerSpacing with { Y = ImGui.GetStyle().ItemSpacing.Y }); + + cMainhand.DrawIcon(_textures, _iconSize); + ImGui.SameLine(); + using (var group = ImRaii.Group()) + { + rOffhand = cOffhand; + if (DrawMainhand(cMainhand, cApply.HasValue, out rMainhand, out var mainhandLabel, locked)) + { + changes |= EquipChange.Item; + if (rMainhand.Type.ValidOffhand() != cMainhand.Type.ValidOffhand()) + { + rOffhand = _items.GetDefaultOffhand(rMainhand); + changes |= EquipChange.Item2; + } + } + + if (cApply.HasValue) + { + ImGui.SameLine(); + if (DrawApply(EquipSlot.MainHand, cApply.Value, out rApplyMainhand, locked)) + changes |= EquipChange.ApplyItem; + } + else + { + rApplyMainhand = true; + } + + ImGui.SameLine(); + ImGui.TextUnformatted(mainhandLabel); + + if (DrawStain(EquipSlot.MainHand, cMainhandStain, out rMainhandStain, locked)) + changes |= EquipChange.Stain; + if (cApply.HasValue) + { + ImGui.SameLine(); + if (DrawApplyStain(EquipSlot.MainHand, cApply.Value, out rApplyMainhandStain, locked)) + changes |= EquipChange.ApplyStain; + } + else + { + rApplyMainhandStain = true; + } + } + + if (rOffhand.Type is FullEquipType.Unknown) + { + rOffhandStain = cOffhandStain; + rApplyOffhand = false; + rApplyOffhandStain = false; + return changes; + } + + rOffhand.DrawIcon(_textures, _iconSize); + ImGui.SameLine(); + using (var group = ImRaii.Group()) + { + if (DrawOffhand(rMainhand, rOffhand, out rOffhand, out var offhandLabel, locked)) + changes |= EquipChange.Item2; + if (cApply.HasValue) + { + ImGui.SameLine(); + if (DrawApply(EquipSlot.OffHand, cApply.Value, out rApplyOffhand, locked)) + changes |= EquipChange.ApplyItem2; + } + else + { + rApplyOffhand = true; + } + + ImGui.SameLine(); + ImGui.TextUnformatted(offhandLabel); + + if (DrawStain(EquipSlot.OffHand, cOffhandStain, out rOffhandStain, locked)) + changes |= EquipChange.Stain2; + if (cApply.HasValue) + { + ImGui.SameLine(); + if (DrawApplyStain(EquipSlot.OffHand, cApply.Value, out rApplyOffhandStain, locked)) + changes |= EquipChange.ApplyStain2; + } + else + { + rApplyOffhandStain = true; + } + } + + return changes; + } + + + public bool DrawMainhand(EquipItem current, bool drawAll, out EquipItem weapon, out string label, bool locked) + { + weapon = current; + if (!_weaponCombo.TryGetValue(drawAll ? FullEquipType.Unknown : current.Type, out var combo)) + { + label = string.Empty; + return false; + } + + label = combo.Label; + using var disabled = ImRaii.Disabled(locked); + if (!combo.Draw(weapon.Name, weapon.ItemId, _comboLength)) + return false; + + weapon = combo.CurrentSelection; + return true; + } + + public bool DrawOffhand(EquipItem mainhand, EquipItem current, out EquipItem weapon, out string label, bool locked) + { + weapon = current; + if (!_weaponCombo.TryGetValue(current.Type, out var combo)) + { + label = string.Empty; + return false; + } + + label = combo.Label; + using var disabled = ImRaii.Disabled(locked); + var change = combo.Draw(weapon.Name, weapon.ItemId, _comboLength); + if (change) + weapon = combo.CurrentSelection; + + if (!locked) + { + var defaultOffhand = _items.GetDefaultOffhand(mainhand); + if (defaultOffhand.Id != weapon.Id) + { + ImGuiUtil.HoverTooltip("Right-click to set to Default."); + if (ImGui.IsItemClicked(ImGuiMouseButton.Right)) + { + change = true; + weapon = defaultOffhand; + } + } + } + + return change; + } + + public bool DrawApply(EquipSlot slot, EquipFlag flags, out bool enabled, bool locked) + => UiHelpers.DrawCheckbox($"##apply{slot}", "Apply this item when applying the Design.", flags.HasFlag(slot.ToFlag()), out enabled, + locked); + + public bool DrawApplyStain(EquipSlot slot, EquipFlag flags, out bool enabled, bool locked) + => UiHelpers.DrawCheckbox($"##applyStain{slot}", "Apply this dye when applying the Design.", flags.HasFlag(slot.ToStainFlag()), + out enabled, locked); + + private bool DrawItem(EquipSlot slot, EquipItem current, out EquipItem armor, out string label, bool locked) + { + Debug.Assert(slot.IsEquipment() || slot.IsAccessory(), $"Called {nameof(DrawItem)} on {slot}."); var combo = _itemCombo[slot.ToIndex()]; + label = combo.Label; armor = current; - var change = combo.Draw(VerifyRestrictedGear(armor, slot, gender, race), armor.ItemId, _comboLength); + using var disabled = ImRaii.Disabled(locked); + var change = combo.Draw(armor.Name, armor.ItemId, _comboLength); if (change) armor = combo.CurrentSelection; - if (armor.ModelId.Value != 0) + if (!locked && armor.ModelId.Value != 0) { ImGuiUtil.HoverTooltip("Right-click to clear."); if (ImGui.IsItemClicked(ImGuiMouseButton.Right)) @@ -99,101 +323,34 @@ public class EquipmentDrawer return change; } - public bool DrawStain(StainId current, EquipSlot slot, out StainId ret) + private bool DrawStain(EquipSlot slot, StainId current, out StainId ret, bool locked) { - if (_codes.EnabledArtisan) - return DrawStainArtisan(current, slot, out ret); - - var found = _stainData.TryGetValue(current, out var stain); - var change = _stainCombo.Draw($"##stain{slot}", stain.RgbaColor, stain.Name, found, stain.Gloss, _comboLength); + var found = _stainData.TryGetValue(current, out var stain); + using var disabled = ImRaii.Disabled(locked); + var change = _stainCombo.Draw($"##stain{slot}", stain.RgbaColor, stain.Name, found, stain.Gloss, _comboLength); ret = current; if (change && _stainData.TryGetValue(_stainCombo.CurrentSelection.Key, out stain)) ret = stain.RowIndex; - ImGuiUtil.HoverTooltip("Right-click to clear."); - if (ImGui.IsItemClicked(ImGuiMouseButton.Right)) - { - ret = Stain.None.RowIndex; - change = true; - } - - return change; - } - - public bool DrawMainhand(EquipItem current, bool drawAll, out EquipItem weapon) - { - weapon = current; - if (!_weaponCombo.TryGetValue(drawAll ? FullEquipType.Unknown : current.Type, out var combo)) - return false; - - if (!combo.Draw(weapon.Name, weapon.ItemId, 320 * ImGuiHelpers.GlobalScale)) - return false; - - weapon = combo.CurrentSelection; - return true; - } - - public bool DrawOffhand(EquipItem current, FullEquipType mainType, out EquipItem weapon) - { - weapon = current; - var offType = mainType.Offhand(); - if (offType == FullEquipType.Unknown) - return false; - - if (!_weaponCombo.TryGetValue(offType, out var combo)) - return false; - - var change = combo.Draw(weapon.Name, weapon.ItemId, 320 * ImGuiHelpers.GlobalScale); - if (change) - { - weapon = combo.CurrentSelection; - } - else if (!offType.IsOffhandType() && weapon.ModelId.Value != 0) + if (!locked && ret != Stain.None.RowIndex) { ImGuiUtil.HoverTooltip("Right-click to clear."); if (ImGui.IsItemClicked(ImGuiMouseButton.Right)) { + ret = Stain.None.RowIndex; change = true; - weapon = ItemManager.NothingItem(offType); } } return change; } - public bool DrawApply(Design design, EquipSlot slot, out bool enabled) - => DrawCheckbox($"##apply{slot}", design.DoApplyEquip(slot), out enabled); - - public bool DrawApplyStain(Design design, EquipSlot slot, out bool enabled) - => DrawCheckbox($"##applyStain{slot}", design.DoApplyStain(slot), out enabled); - - private static bool DrawCheckbox(string label, bool value, out bool on) - { - var ret = ImGuiUtil.Checkbox(label, string.Empty, value, v => value = v); - on = value; - return ret; - } - - public bool DrawVisor(bool current, out bool on) - => DrawCheckbox("##visorToggled", current, out on); - - public bool DrawHat(bool current, out bool on) - => DrawCheckbox("##hatVisible", current, out on); - - public bool DrawWeapon(bool current, out bool on) - => DrawCheckbox("##weaponVisible", current, out on); - - public bool DrawWetness(bool current, out bool on) - => DrawCheckbox("##wetness", current, out on); - /// Draw an input for armor that can set arbitrary values instead of choosing items. - private bool DrawArmorArtisan(EquipItem current, EquipSlot slot, out EquipItem armor, Gender gender = Gender.Unknown, - Race race = Race.Unknown) + private bool DrawArmorArtisan(EquipSlot slot, EquipItem current, out EquipItem armor) { - using var id = ImRaii.PushId((int)slot); - int setId = current.ModelId.Value; - int variant = current.Variant; - var ret = false; + int setId = current.ModelId.Value; + int variant = current.Variant; + var ret = false; armor = current; ImGui.SetNextItemWidth(80 * ImGuiHelpers.GlobalScale); if (ImGui.InputInt("##setId", ref setId, 0, 0)) @@ -222,10 +379,9 @@ public class EquipmentDrawer } /// Draw an input for stain that can set arbitrary values instead of choosing valid stains. - private bool DrawStainArtisan(StainId current, EquipSlot slot, out StainId stain) + private bool DrawStainArtisan(EquipSlot slot, StainId current, out StainId stain) { - using var id = ImRaii.PushId((int)slot); - int stainId = current.Value; + int stainId = current.Value; ImGui.SetNextItemWidth(40 * ImGuiHelpers.GlobalScale); if (ImGui.InputInt("##stain", ref stainId, 0, 0)) { @@ -240,4 +396,31 @@ public class EquipmentDrawer stain = current; return false; } + + private EquipChange DrawEquipArtisan(EquipSlot slot, EquipItem cArmor, out EquipItem rArmor, StainId cStain, out StainId rStain, + EquipFlag? cApply, out bool rApply, out bool rApplyStain) + { + var changes = EquipChange.None; + if (DrawStainArtisan(slot, cStain, out rStain)) + changes |= EquipChange.Stain; + ImGui.SameLine(); + if (DrawArmorArtisan(slot, cArmor, out rArmor)) + changes |= EquipChange.Item; + if (cApply.HasValue) + { + ImGui.SameLine(); + if (DrawApply(slot, cApply.Value, out rApply, false)) + changes |= EquipChange.ApplyItem; + ImGui.SameLine(); + if (DrawApplyStain(slot, cApply.Value, out rApplyStain, false)) + changes |= EquipChange.ApplyStain; + } + else + { + rApply = false; + rApplyStain = false; + } + + return changes; + } } diff --git a/Glamourer/Gui/Equipment/ItemCombo.cs b/Glamourer/Gui/Equipment/ItemCombo.cs index 805049a..a65a5d7 100644 --- a/Glamourer/Gui/Equipment/ItemCombo.cs +++ b/Glamourer/Gui/Equipment/ItemCombo.cs @@ -48,7 +48,7 @@ public sealed class ItemCombo : FilterComboCache public bool Draw(string previewName, uint previewIdx, float width) { _currentItem = previewIdx; - return Draw(Label, previewName, string.Empty, width, ImGui.GetTextLineHeightWithSpacing()); + return Draw($"##{Label}", previewName, string.Empty, width, ImGui.GetTextLineHeightWithSpacing()); } protected override bool DrawSelectable(int globalIdx, bool selected) diff --git a/Glamourer/Gui/Equipment/WeaponCombo.cs b/Glamourer/Gui/Equipment/WeaponCombo.cs index 4946906..a6c05bb 100644 --- a/Glamourer/Gui/Equipment/WeaponCombo.cs +++ b/Glamourer/Gui/Equipment/WeaponCombo.cs @@ -41,7 +41,7 @@ public sealed class WeaponCombo : FilterComboCache public bool Draw(string previewName, uint previewId, float width) { _currentItemId = previewId; - return Draw(Label, previewName, string.Empty, width, ImGui.GetTextLineHeightWithSpacing()); + return Draw($"##{Label}", previewName, string.Empty, width, ImGui.GetTextLineHeightWithSpacing()); } protected override bool DrawSelectable(int globalIdx, bool selected) diff --git a/Glamourer/Gui/MainWindow.cs b/Glamourer/Gui/MainWindow.cs index d9ebf9b..7dac26e 100644 --- a/Glamourer/Gui/MainWindow.cs +++ b/Glamourer/Gui/MainWindow.cs @@ -45,7 +45,7 @@ public class MainWindow : Window pi.UiBuilder.DisableGposeUiHide = true; SizeConstraints = new WindowSizeConstraints() { - MinimumSize = new Vector2(675, 675), + MinimumSize = new Vector2(700, 675), MaximumSize = ImGui.GetIO().DisplaySize, }; Settings = settings; diff --git a/Glamourer/Gui/PenumbraChangedItemTooltip.cs b/Glamourer/Gui/PenumbraChangedItemTooltip.cs index c51ad04..fe93876 100644 --- a/Glamourer/Gui/PenumbraChangedItemTooltip.cs +++ b/Glamourer/Gui/PenumbraChangedItemTooltip.cs @@ -177,7 +177,7 @@ public class PenumbraChangedItemTooltip : IDisposable if (slot == EquipSlot.MainHand) return item.Type == mainItem.Type; - return item.Type == mainItem.Type.Offhand(); + return item.Type == mainItem.Type.ValidOffhand(); } private void OnPenumbraClick(MouseButton button, ChangedItemType type, uint id) diff --git a/Glamourer/Gui/Tabs/ActorTab/ActorPanel.cs b/Glamourer/Gui/Tabs/ActorTab/ActorPanel.cs index 4bb66e0..426c857 100644 --- a/Glamourer/Gui/Tabs/ActorTab/ActorPanel.cs +++ b/Glamourer/Gui/Tabs/ActorTab/ActorPanel.cs @@ -69,8 +69,11 @@ public class ActorPanel { var textColor = !_identifier.IsValid ? ImGui.GetColorU32(ImGuiCol.Text) : _data.Valid ? ColorId.ActorAvailable.Value() : ColorId.ActorUnavailable.Value(); - HeaderDrawer.Draw(_actorName, textColor, ImGui.GetColorU32(ImGuiCol.FrameBg), 0, + HeaderDrawer.Draw(_actorName, textColor, ImGui.GetColorU32(ImGuiCol.FrameBg), + 3, SetFromClipboardButton(), ExportToClipboardButton(), SaveAsDesignButton(), LockedButton(), HeaderDrawer.Button.IncognitoButton(_selector.IncognitoMode, v => _selector.IncognitoMode = v)); + + SaveDesignDrawPopup(); } private (string, Actor) GetHeaderName() @@ -90,12 +93,6 @@ public class ActorPanel if (!child || !_selector.HasSelection || !_stateManager.GetOrCreate(_identifier, _actor, out _state)) return; - SetFromClipboard(); - ImGui.SameLine(); - ExportToClipboardButton(); - ImGui.SameLine(); - SaveDesignButton(); - ImGui.SameLine(); DrawApplyToSelf(); ImGui.SameLine(); DrawApplyToTarget(); @@ -116,36 +113,40 @@ public class ActorPanel _equipmentDrawer.Prepare(); foreach (var slot in EquipSlotExtensions.EqdpSlots) { - var stain = _state.ModelData.Stain(slot); - if (_equipmentDrawer.DrawStain(stain, slot, out var newStain)) - _stateManager.ChangeStain(_state, slot, newStain, StateChanged.Source.Manual); - - ImGui.SameLine(); - var armor = _state.ModelData.Item(slot); - if (_equipmentDrawer.DrawArmor(armor, slot, out var newArmor, _state.ModelData.Customize.Gender, _state.ModelData.Customize.Race)) - _stateManager.ChangeEquip(_state, slot, newArmor, newStain, StateChanged.Source.Manual); + var changes = _equipmentDrawer.DrawEquip(slot, _state.ModelData, out var newArmor, out var newStain, null, out _, out _, + _state.IsLocked); + switch (changes) + { + case EquipmentDrawer.EquipChange.Item: + _stateManager.ChangeItem(_state, slot, newArmor, StateChanged.Source.Manual); + break; + case EquipmentDrawer.EquipChange.Stain: + _stateManager.ChangeStain(_state, slot, newStain, StateChanged.Source.Manual); + break; + case EquipmentDrawer.EquipChange.Item | EquipmentDrawer.EquipChange.Stain: + _stateManager.ChangeEquip(_state, slot, newArmor, newStain, StateChanged.Source.Manual); + break; + } } - var mhStain = _state.ModelData.Stain(EquipSlot.MainHand); - if (_equipmentDrawer.DrawStain(mhStain, EquipSlot.MainHand, out var newMhStain)) - _stateManager.ChangeStain(_state, EquipSlot.MainHand, newMhStain, StateChanged.Source.Manual); + var weaponChanges = _equipmentDrawer.DrawWeapons(_state.ModelData, out var newMainhand, out var newOffhand, out var newMainhandStain, + out var newOffhandStain, null, out _, out _, out _, out _, _state.IsLocked); - ImGui.SameLine(); - var mh = _state.ModelData.Item(EquipSlot.MainHand); - if (_equipmentDrawer.DrawMainhand(mh, false, out var newMh)) - _stateManager.ChangeEquip(_state, EquipSlot.MainHand, newMh, newMhStain, StateChanged.Source.Manual); + if (weaponChanges.HasFlag(EquipmentDrawer.EquipChange.Item)) + if (weaponChanges.HasFlag(EquipmentDrawer.EquipChange.Stain)) + _stateManager.ChangeEquip(_state, EquipSlot.MainHand, newMainhand, newMainhandStain, StateChanged.Source.Manual); + else + _stateManager.ChangeItem(_state, EquipSlot.MainHand, newMainhand, StateChanged.Source.Manual); + else if (weaponChanges.HasFlag(EquipmentDrawer.EquipChange.Stain)) + _stateManager.ChangeStain(_state, EquipSlot.MainHand, newMainhandStain, StateChanged.Source.Manual); - if (newMh.Type.Offhand() is not FullEquipType.Unknown) - { - var ohStain = _state.ModelData.Stain(EquipSlot.OffHand); - if (_equipmentDrawer.DrawStain(ohStain, EquipSlot.OffHand, out var newOhStain)) - _stateManager.ChangeStain(_state, EquipSlot.OffHand, newOhStain, StateChanged.Source.Manual); - - ImGui.SameLine(); - var oh = _state.ModelData.Item(EquipSlot.OffHand); - if (_equipmentDrawer.DrawOffhand(oh, newMh.Type, out var newOh)) - _stateManager.ChangeEquip(_state, EquipSlot.OffHand, newOh, newOhStain, StateChanged.Source.Manual); - } + if (weaponChanges.HasFlag(EquipmentDrawer.EquipChange.Item2)) + if (weaponChanges.HasFlag(EquipmentDrawer.EquipChange.Stain2)) + _stateManager.ChangeEquip(_state, EquipSlot.OffHand, newOffhand, newOffhandStain, StateChanged.Source.Manual); + else + _stateManager.ChangeItem(_state, EquipSlot.OffHand, newOffhand, StateChanged.Source.Manual); + else if (weaponChanges.HasFlag(EquipmentDrawer.EquipChange.Stain2)) + _stateManager.ChangeStain(_state, EquipSlot.OffHand, newOffhandStain, StateChanged.Source.Manual); } private void DrawMonsterPanel() @@ -209,12 +210,68 @@ public class ActorPanel _stateManager.TurnHuman(_state, StateChanged.Source.Manual); } - private void SetFromClipboard() + private HeaderDrawer.Button SetFromClipboardButton() + => new() + { + Description = "Try to apply a design from your clipboard.", + Icon = FontAwesomeIcon.Clipboard, + OnClick = SetFromClipboard, + Visible = _state != null, + }; + + private HeaderDrawer.Button ExportToClipboardButton() + => new() + { + Description = "Copy the current design to your clipboard.", + Icon = FontAwesomeIcon.Copy, + OnClick = ExportToClipboard, + Visible = _state?.ModelData.IsHuman ?? false, + }; + + private HeaderDrawer.Button SaveAsDesignButton() + => new() + { + Description = "Save the current state as a design.", + Icon = FontAwesomeIcon.Save, + OnClick = SaveDesignOpen, + Visible = _state?.ModelData.IsHuman ?? false, + }; + + private HeaderDrawer.Button LockedButton() + => new() + { + Description = "The current state of this actor is locked by external tools.", + Icon = FontAwesomeIcon.Lock, + OnClick = () => { }, + Disabled = true, + Visible = _state?.IsLocked ?? false, + TextColor = ColorId.ActorUnavailable.Value(), + BorderColor = ColorId.ActorUnavailable.Value(), + }; + + private string _newName = string.Empty; + private DesignBase? _newDesign = null; + + private void SaveDesignOpen() { - if (!ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Clipboard.ToIconString(), new Vector2(ImGui.GetFrameHeight()), - "Try to apply a design from your clipboard.", false, true)) + ImGui.OpenPopup("Save as Design"); + _newName = _state!.Identifier.ToName(); + _newDesign = _converter.Convert(_state, EquipFlagExtensions.All, CustomizeFlagExtensions.All); + } + + private void SaveDesignDrawPopup() + { + if (!ImGuiUtil.OpenNameField("Save as Design", ref _newName)) return; + if (_newDesign != null && _newName.Length > 0) + _designManager.CreateClone(_newDesign, _newName); + _newDesign = null; + _newName = string.Empty; + } + + private void SetFromClipboard() + { try { var text = ImGui.GetClipboardText(); @@ -228,12 +285,8 @@ public class ActorPanel } } - private void ExportToClipboardButton() + private void ExportToClipboard() { - if (!ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Copy.ToIconString(), new Vector2(ImGui.GetFrameHeight()), - "Copy the current design to your clipboard.", false, true)) - return; - try { var text = _converter.ShareBase64(_state!); @@ -267,7 +320,7 @@ public class ActorPanel { var (id, data) = _objects.PlayerData; if (!ImGuiUtil.DrawDisabledButton("Apply to Yourself", Vector2.Zero, "Apply the current state to your own character.", - !data.Valid || id == _identifier)) + !data.Valid || id == _identifier || !_state!.ModelData.IsHuman)) return; if (_stateManager.GetOrCreate(id, data.Objects[0], out var state)) @@ -283,33 +336,11 @@ public class ActorPanel ? "Apply the current state to your current target." : "The current target can not be manipulated." : "No valid target selected."; - if (!ImGuiUtil.DrawDisabledButton("Apply to Target", Vector2.Zero, tt, !data.Valid || id == _identifier)) + if (!ImGuiUtil.DrawDisabledButton("Apply to Target", Vector2.Zero, tt, !data.Valid || id == _identifier || !_state!.ModelData.IsHuman)) return; if (_stateManager.GetOrCreate(id, data.Objects[0], out var state)) _stateManager.ApplyDesign(_converter.Convert(_state!, EquipFlagExtensions.All, CustomizeFlagExtensions.AllRelevant), state, StateChanged.Source.Manual); } - - private string _newName = string.Empty; - private DesignBase? _newDesign = null; - - private void SaveDesignButton() - { - if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Save.ToIconString(), new Vector2(ImGui.GetFrameHeight()), - "Save the current state as a design.", !_state!.ModelData.IsHuman, true)) - { - ImGui.OpenPopup("Save as Design"); - _newName = _state.Identifier.ToName(); - _newDesign = _converter.Convert(_state, EquipFlagExtensions.All, CustomizeFlagExtensions.All); - } - - if (ImGuiUtil.OpenNameField("Save as Design", ref _newName)) - { - if (_newDesign != null && _newName.Length > 0) - _designManager.CreateClone(_newDesign, _newName); - _newDesign = null; - _newName = string.Empty; - } - } } diff --git a/Glamourer/Gui/Tabs/DesignTab/DesignPanel.cs b/Glamourer/Gui/Tabs/DesignTab/DesignPanel.cs index f514403..13777b3 100644 --- a/Glamourer/Gui/Tabs/DesignTab/DesignPanel.cs +++ b/Glamourer/Gui/Tabs/DesignTab/DesignPanel.cs @@ -57,23 +57,39 @@ public class DesignPanel : _selector.Selected.WriteProtected() ? new HeaderDrawer.Button { - BorderColor = ColorId.HeaderButtons.Value(), - TextColor = ColorId.HeaderButtons.Value(), Description = "Make this design editable.", Icon = FontAwesomeIcon.Lock, OnClick = () => _manager.SetWriteProtection(_selector.Selected!, false), } : new HeaderDrawer.Button { - BorderColor = ColorId.HeaderButtons.Value(), - TextColor = ColorId.HeaderButtons.Value(), Description = "Write-protect this design.", Icon = FontAwesomeIcon.LockOpen, OnClick = () => _manager.SetWriteProtection(_selector.Selected!, true), }; + private HeaderDrawer.Button SetFromClipboardButton() + => new() + { + Description = "Try to apply a design from your clipboard over this design.", + Icon = FontAwesomeIcon.Clipboard, + OnClick = SetFromClipboard, + Visible = _selector.Selected != null, + Disabled = _selector.Selected?.WriteProtected() ?? true, + }; + + private HeaderDrawer.Button ExportToClipboardButton() + => new() + { + Description = "Copy the current design to your clipboard.", + Icon = FontAwesomeIcon.Copy, + OnClick = ExportToClipboard, + Visible = _selector.Selected != null, + }; + private void DrawHeader() - => HeaderDrawer.Draw(SelectionName, 0, ImGui.GetColorU32(ImGuiCol.FrameBg), 0, LockButton(), + => HeaderDrawer.Draw(SelectionName, 0, ImGui.GetColorU32(ImGuiCol.FrameBg), + 2, SetFromClipboardButton(), ExportToClipboardButton(), LockButton(), HeaderDrawer.Button.IncognitoButton(_selector.IncognitoMode, v => _selector.IncognitoMode = v)); private string SelectionName @@ -117,37 +133,37 @@ public class DesignPanel _equipmentDrawer.Prepare(); foreach (var slot in EquipSlotExtensions.EqdpSlots) { - var stain = _selector.Selected!.DesignData.Stain(slot); - if (_equipmentDrawer.DrawStain(stain, slot, out var newStain)) - _manager.ChangeStain(_selector.Selected!, slot, newStain); - - ImGui.SameLine(); - var armor = _selector.Selected!.DesignData.Item(slot); - if (_equipmentDrawer.DrawArmor(armor, slot, out var newArmor, _selector.Selected!.DesignData.Customize.Gender, - _selector.Selected!.DesignData.Customize.Race)) - _manager.ChangeEquip(_selector.Selected!, slot, newArmor); + var changes = _equipmentDrawer.DrawEquip(slot, _selector.Selected!.DesignData, out var newArmor, out var newStain, + _selector.Selected.ApplyEquip, out var newApply, out var newApplyStain, _selector.Selected!.WriteProtected()); + if (changes.HasFlag(EquipmentDrawer.EquipChange.Item)) + _manager.ChangeEquip(_selector.Selected, slot, newArmor); + if (changes.HasFlag(EquipmentDrawer.EquipChange.Stain)) + _manager.ChangeStain(_selector.Selected, slot, newStain); + if (changes.HasFlag(EquipmentDrawer.EquipChange.ApplyItem)) + _manager.ChangeApplyEquip(_selector.Selected, slot, newApply); + if (changes.HasFlag(EquipmentDrawer.EquipChange.ApplyStain)) + _manager.ChangeApplyStain(_selector.Selected, slot, newApplyStain); } - var mhStain = _selector.Selected!.DesignData.Stain(EquipSlot.MainHand); - if (_equipmentDrawer.DrawStain(mhStain, EquipSlot.MainHand, out var newMhStain)) - _manager.ChangeStain(_selector.Selected!, EquipSlot.MainHand, newMhStain); - - ImGui.SameLine(); - var mh = _selector.Selected!.DesignData.Item(EquipSlot.MainHand); - if (_equipmentDrawer.DrawMainhand(mh, true, out var newMh)) - _manager.ChangeWeapon(_selector.Selected!, EquipSlot.MainHand, newMh); - - if (newMh.Type.Offhand() is not FullEquipType.Unknown) - { - var ohStain = _selector.Selected!.DesignData.Stain(EquipSlot.OffHand); - if (_equipmentDrawer.DrawStain(ohStain, EquipSlot.OffHand, out var newOhStain)) - _manager.ChangeStain(_selector.Selected!, EquipSlot.OffHand, newOhStain); - - ImGui.SameLine(); - var oh = _selector.Selected!.DesignData.Item(EquipSlot.OffHand); - if (_equipmentDrawer.DrawOffhand(oh, newMh.Type, out var newOh)) - _manager.ChangeWeapon(_selector.Selected!, EquipSlot.OffHand, newOh); - } + var weaponChanges = _equipmentDrawer.DrawWeapons(_selector.Selected!.DesignData, out var newMainhand, out var newOffhand, + out var newMainhandStain, out var newOffhandStain, _selector.Selected.ApplyEquip, out var applyMain, out var applyMainStain, + out var applyOff, out var applyOffStain, _selector.Selected!.WriteProtected()); + if (weaponChanges.HasFlag(EquipmentDrawer.EquipChange.Item)) + _manager.ChangeWeapon(_selector.Selected, EquipSlot.MainHand, newMainhand); + if (weaponChanges.HasFlag(EquipmentDrawer.EquipChange.Stain)) + _manager.ChangeStain(_selector.Selected, EquipSlot.MainHand, newMainhandStain); + if (weaponChanges.HasFlag(EquipmentDrawer.EquipChange.ApplyItem)) + _manager.ChangeApplyEquip(_selector.Selected, EquipSlot.MainHand, applyMain); + if (weaponChanges.HasFlag(EquipmentDrawer.EquipChange.ApplyStain)) + _manager.ChangeApplyStain(_selector.Selected, EquipSlot.MainHand, applyMainStain); + if (weaponChanges.HasFlag(EquipmentDrawer.EquipChange.Item2)) + _manager.ChangeWeapon(_selector.Selected, EquipSlot.OffHand, newOffhand); + if (weaponChanges.HasFlag(EquipmentDrawer.EquipChange.Stain2)) + _manager.ChangeStain(_selector.Selected, EquipSlot.OffHand, newOffhandStain); + if (weaponChanges.HasFlag(EquipmentDrawer.EquipChange.ApplyItem2)) + _manager.ChangeApplyEquip(_selector.Selected, EquipSlot.OffHand, applyOff); + if (weaponChanges.HasFlag(EquipmentDrawer.EquipChange.ApplyStain2)) + _manager.ChangeApplyStain(_selector.Selected, EquipSlot.OffHand, applyOffStain); } private void DrawCustomize() @@ -279,21 +295,13 @@ public class DesignPanel private void DrawButtonRow() { - SetFromClipboardButton(); - ImGui.SameLine(); - ExportToClipboardButton(); - ImGui.SameLine(); DrawApplyToSelf(); ImGui.SameLine(); DrawApplyToTarget(); } - private void SetFromClipboardButton() + private void SetFromClipboard() { - if (!ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Clipboard.ToIconString(), new Vector2(ImGui.GetFrameHeight()), - "Try to apply a design from your clipboard.", _selector.Selected!.WriteProtected(), true)) - return; - try { var text = ImGui.GetClipboardText(); @@ -307,12 +315,8 @@ public class DesignPanel } } - private void ExportToClipboardButton() + private void ExportToClipboard() { - if (!ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Copy.ToIconString(), new Vector2(ImGui.GetFrameHeight()), - "Copy the current design to your clipboard.", false, true)) - return; - try { var text = _converter.ShareBase64(_selector.Selected!); diff --git a/Glamourer/Gui/Tabs/HeaderDrawer.cs b/Glamourer/Gui/Tabs/HeaderDrawer.cs index 9e6f543..2963c0c 100644 --- a/Glamourer/Gui/Tabs/HeaderDrawer.cs +++ b/Glamourer/Gui/Tabs/HeaderDrawer.cs @@ -29,9 +29,11 @@ public static class HeaderDrawer public Button() { - Visible = true; - Width = ImGui.GetFrameHeightWithSpacing(); - Disabled = false; + Visible = true; + Width = ImGui.GetFrameHeightWithSpacing(); + BorderColor = ColorId.HeaderButtons.Value(); + TextColor = ColorId.HeaderButtons.Value(); + Disabled = false; } public readonly void Draw() @@ -41,24 +43,22 @@ public static class HeaderDrawer using var color = ImRaii.PushColor(ImGuiCol.Border, BorderColor) .Push(ImGuiCol.Text, TextColor, TextColor != 0); - if (ImGuiUtil.DrawDisabledButton(Icon.ToIconString(), new Vector2(Width, ImGui.GetFrameHeight()), Description, Disabled, true)) + if (ImGuiUtil.DrawDisabledButton(Icon.ToIconString(), new Vector2(Width, ImGui.GetFrameHeight()), string.Empty, Disabled, true)) OnClick?.Invoke(); + color.Pop(); + ImGuiUtil.HoverTooltip(Description); } public static Button IncognitoButton(bool current, Action setter) => current ? new Button { - BorderColor = ColorId.HeaderButtons.Value(), - TextColor = ColorId.HeaderButtons.Value(), Description = "Toggle incognito mode off.", Icon = FontAwesomeIcon.EyeSlash, OnClick = () => setter(false), } : new Button { - BorderColor = ColorId.HeaderButtons.Value(), - TextColor = ColorId.HeaderButtons.Value(), Description = "Toggle incognito mode on.", Icon = FontAwesomeIcon.Eye, OnClick = () => setter(true), @@ -83,7 +83,7 @@ public static class HeaderDrawer var midSize = ImGui.GetContentRegionAvail().X - rightButtonSize - ImGuiHelpers.GlobalScale; style.Pop(); - style.Push(ImGuiStyleVar.ButtonTextAlign, new Vector2(0.5f + (rightButtonSize - leftButtonSize) / 2 / midSize, 0.5f)); + style.Push(ImGuiStyleVar.ButtonTextAlign, new Vector2(0.5f + (rightButtonSize - leftButtonSize) / midSize, 0.5f)); if (textColor != 0) ImGuiUtil.DrawTextButton(text, new Vector2(midSize, ImGui.GetFrameHeight()), frameColor, textColor); else diff --git a/Glamourer/Gui/Tabs/UnlocksTab/UnlockOverview.cs b/Glamourer/Gui/Tabs/UnlocksTab/UnlockOverview.cs index 97f7d1d..2efa4d8 100644 --- a/Glamourer/Gui/Tabs/UnlocksTab/UnlockOverview.cs +++ b/Glamourer/Gui/Tabs/UnlocksTab/UnlockOverview.cs @@ -177,7 +177,7 @@ public class UnlockOverview ImGui.TextUnformatted(item.Name); var slot = item.Type.ToSlot(); ImGui.TextUnformatted($"{item.Type.ToName()} ({slot.ToName()})"); - if (item.Type.Offhand().IsOffhandType()) + if (item.Type.ValidOffhand().IsOffhandType()) ImGui.TextUnformatted( $"{item.Weapon()}{(_items.ItemService.AwaitedService.TryGetValue(item.ItemId, false, out var offhand) ? $" | {offhand.Weapon()}" : string.Empty)}"); else diff --git a/Glamourer/Gui/Tabs/UnlocksTab/UnlockTable.cs b/Glamourer/Gui/Tabs/UnlocksTab/UnlockTable.cs index a6b6b1e..1e4101c 100644 --- a/Glamourer/Gui/Tabs/UnlocksTab/UnlockTable.cs +++ b/Glamourer/Gui/Tabs/UnlocksTab/UnlockTable.cs @@ -241,7 +241,7 @@ public class UnlockTable : Table, IDisposable ImGui.AlignTextToFramePadding(); ImGuiUtil.RightAlign(item.ModelString); if (ImGui.IsItemHovered() - && item.Type.Offhand().IsOffhandType() + && item.Type.ValidOffhand().IsOffhandType() && _items.ItemService.AwaitedService.TryGetValue(item.ItemId, false, out var offhand)) { using var tt = ImRaii.Tooltip(); @@ -260,7 +260,7 @@ public class UnlockTable : Table, IDisposable if (FilterRegex?.IsMatch(item.ModelString) ?? item.ModelString.Contains(FilterValue, StringComparison.OrdinalIgnoreCase)) return true; - if (item.Type.Offhand().IsOffhandType() && _items.ItemService.AwaitedService.TryGetValue(item.ItemId, false, out var offhand)) + if (item.Type.ValidOffhand().IsOffhandType() && _items.ItemService.AwaitedService.TryGetValue(item.ItemId, false, out var offhand)) return FilterRegex?.IsMatch(offhand.ModelString) ?? offhand.ModelString.Contains(FilterValue, StringComparison.OrdinalIgnoreCase); diff --git a/Glamourer/Gui/UiHelpers.cs b/Glamourer/Gui/UiHelpers.cs index 69d4287..6d13818 100644 --- a/Glamourer/Gui/UiHelpers.cs +++ b/Glamourer/Gui/UiHelpers.cs @@ -1,16 +1,15 @@ - using System.Numerics; using Dalamud.Interface; using Glamourer.Services; using ImGuiNET; using OtterGui; +using OtterGui.Raii; using Penumbra.GameData.Structs; namespace Glamourer.Gui; public static class UiHelpers { - public static void DrawIcon(this EquipItem item, TextureService textures, Vector2 size) { var isEmpty = item.ModelId.Value == 0; @@ -31,4 +30,25 @@ public static class UiHelpers ImGuiUtil.HoverIcon(ptr, textureSize, size); } } -} \ No newline at end of file + + public static bool DrawCheckbox(string label, string tooltip, bool value, out bool on, bool locked) + { + using var disabled = ImRaii.Disabled(locked); + var ret = ImGuiUtil.Checkbox(label, string.Empty, value, v => value = v); + ImGuiUtil.HoverTooltip(tooltip); + on = value; + return ret; + } + + public static bool DrawVisor(bool current, out bool on, bool locked) + => DrawCheckbox("##visorToggled", string.Empty, current, out on, locked); + + public static bool DrawHat(bool current, out bool on, bool locked) + => DrawCheckbox("##hatVisible", string.Empty, current, out on, locked); + + public static bool DrawWeapon(bool current, out bool on, bool locked) + => DrawCheckbox("##weaponVisible", string.Empty, current, out on, locked); + + public static bool DrawWetness(bool current, out bool on, bool locked) + => DrawCheckbox("##wetness", string.Empty, current, out on, locked); +} diff --git a/Glamourer/Interop/WeaponService.cs b/Glamourer/Interop/WeaponService.cs index f52e565..90df4c8 100644 --- a/Glamourer/Interop/WeaponService.cs +++ b/Glamourer/Interop/WeaponService.cs @@ -40,9 +40,7 @@ public unsafe class WeaponService : IDisposable private readonly Hook _loadWeaponHook; - private void LoadWeaponDetour(DrawDataContainer* drawData, uint slot, ulong weaponValue, byte redrawOnEquality, byte unk2, - byte skipGameObject, - byte unk4) + private void LoadWeaponDetour(DrawDataContainer* drawData, uint slot, ulong weaponValue, byte redrawOnEquality, byte unk2, byte skipGameObject, byte unk4) { var actor = (Actor)((nint*)drawData)[1]; var weapon = new CharacterWeapon(weaponValue); @@ -61,7 +59,7 @@ public unsafe class WeaponService : IDisposable _loadWeaponHook.Original(drawData, slot, weapon.Value, redrawOnEquality, unk2, skipGameObject, unk4); if (tmpWeapon.Value != weapon.Value) _loadWeaponHook.Original(drawData, slot, tmpWeapon.Value, 1, unk2, 1, unk4); - Glamourer.Log.Excessive( + Glamourer.Log.Information( $"Weapon reloaded for 0x{actor.Address:X} ({actor.Utf8Name}) with attributes {slot} {weapon.Value:X14}, {redrawOnEquality}, {unk2}, {skipGameObject}, {unk4}"); } diff --git a/Glamourer/Services/ItemManager.cs b/Glamourer/Services/ItemManager.cs index 91b8fd3..dee02d4 100644 --- a/Glamourer/Services/ItemManager.cs +++ b/Glamourer/Services/ItemManager.cs @@ -7,7 +7,6 @@ using Lumina.Excel; using Penumbra.GameData.Data; using Penumbra.GameData.Enums; using Penumbra.GameData.Structs; -using static OtterGui.Raii.ImRaii; using Race = Penumbra.GameData.Enums.Race; namespace Glamourer.Services; @@ -116,12 +115,21 @@ public class ItemManager : IDisposable } } + /// Return the default offhand for a given mainhand, that is for both handed weapons, return the correct offhand part, and for everything else Nothing. + public EquipItem GetDefaultOffhand(EquipItem mainhand) + { + var offhandType = mainhand.Type.ValidOffhand(); + if (offhandType.IsOffhandType()) + return Resolve(offhandType, mainhand.ItemId); + + return NothingItem(offhandType); + } public EquipItem Identify(EquipSlot slot, SetId id, WeaponType type, byte variant, FullEquipType mainhandType = FullEquipType.Unknown) { if (slot is EquipSlot.OffHand) { - var weaponType = mainhandType.Offhand(); + var weaponType = mainhandType.ValidOffhand(); if (id.Value == 0) return NothingItem(weaponType); } @@ -161,7 +169,7 @@ public class ItemManager : IDisposable return allowUnknown ? string.Empty : $"The item {itemId} yields an unknown item."; } - if (IsItemValid(slot, (uint) itemId, out item)) + if (IsItemValid(slot, (uint)itemId, out item)) return string.Empty; item = NothingItem(slot); @@ -201,7 +209,7 @@ public class ItemManager : IDisposable /// Returns whether an offhand is valid given mainhand. [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] public bool IsOffhandValid(in EquipItem main, uint offId, out EquipItem off) - => IsOffhandValid(main.Type.Offhand(), offId, out off); + => IsOffhandValid(main.Type.ValidOffhand(), offId, out off); /// /// Check whether a combination of an item id for a mainhand and for an offhand is valid. @@ -219,7 +227,7 @@ public class ItemManager : IDisposable ret = $"The mainhand weapon {mainId} does not exist, reset to default sword."; } - var offType = main.Type.Offhand(); + var offType = main.Type.ValidOffhand(); if (IsOffhandValid(offType, offId, out off)) return ret; diff --git a/Glamourer/State/StateApplier.cs b/Glamourer/State/StateApplier.cs index b32e3f5..c826f1e 100644 --- a/Glamourer/State/StateApplier.cs +++ b/Glamourer/State/StateApplier.cs @@ -172,7 +172,7 @@ public class StateApplier /// public void ChangeMainhand(ActorData data, EquipItem weapon, StainId stain) { - var slot = weapon.Type.Offhand() == FullEquipType.Unknown ? EquipSlot.BothHand : EquipSlot.MainHand; + var slot = weapon.Type.ValidOffhand() == FullEquipType.Unknown ? EquipSlot.BothHand : EquipSlot.MainHand; foreach (var actor in data.Objects.Where(a => a.Model.IsHuman)) _weapon.LoadWeapon(actor, slot, weapon.Weapon().With(stain)); } diff --git a/Glamourer/State/StateEditor.cs b/Glamourer/State/StateEditor.cs index 9b7c0e7..dd6e549 100644 --- a/Glamourer/State/StateEditor.cs +++ b/Glamourer/State/StateEditor.cs @@ -138,7 +138,7 @@ public class StateEditor // Can not change weapon type from expected type in state. if (slot is EquipSlot.MainHand && item.Type != state.BaseData.MainhandType - || slot is EquipSlot.OffHand && item.Type != state.BaseData.MainhandType.Offhand()) + || slot is EquipSlot.OffHand && item.Type != state.BaseData.MainhandType.ValidOffhand()) return false; state.ModelData.SetItem(slot, item);