diff --git a/Glamourer/Glamourer.csproj b/Glamourer/Glamourer.csproj index a552f17..673a70b 100644 --- a/Glamourer/Glamourer.csproj +++ b/Glamourer/Glamourer.csproj @@ -88,7 +88,6 @@ - diff --git a/Glamourer/Interop/ContextMenuService.cs b/Glamourer/Interop/ContextMenuService.cs index 3cfca50..bd8c333 100644 --- a/Glamourer/Interop/ContextMenuService.cs +++ b/Glamourer/Interop/ContextMenuService.cs @@ -1,8 +1,6 @@ -using Dalamud.ContextMenu; -using Dalamud.Game.Text; -using Dalamud.Game.Text.SeStringHandling; -using Dalamud.Plugin; +using Dalamud.Game.Gui.ContextMenu; using Dalamud.Plugin.Services; +using FFXIVClientStructs.FFXIV.Client.UI.Agent; using Glamourer.Designs; using Glamourer.Services; using Glamourer.State; @@ -16,142 +14,119 @@ public class ContextMenuService : IDisposable public const int ItemSearchContextItemId = 0x1738; public const int ChatLogContextItemId = 0x948; - private readonly ItemManager _items; - private readonly DalamudContextMenu _contextMenu; - private readonly StateManager _state; - private readonly ObjectManager _objects; - private readonly IGameGui _gameGui; + private readonly ItemManager _items; + private readonly IContextMenu _contextMenu; + private readonly StateManager _state; + private readonly ObjectManager _objects; + private readonly IGameGui _gameGui; + private EquipItem _lastItem; + private StainId _lastStain; + + private readonly MenuItem _inventoryItem; public ContextMenuService(ItemManager items, StateManager state, ObjectManager objects, IGameGui gameGui, Configuration config, - DalamudPluginInterface pi) + IContextMenu context) { - _contextMenu = new DalamudContextMenu(pi); + _contextMenu = context; _items = items; _state = state; _objects = objects; _gameGui = gameGui; if (config.EnableGameContextMenu) Enable(); + + _inventoryItem = new MenuItem + { + IsEnabled = true, + IsReturn = false, + PrefixChar = 'G', + Name = "Try On", + OnClicked = OnClick, + IsSubmenu = false, + PrefixColor = 541, + }; } public void Enable() { - _contextMenu.OnOpenGameObjectContextMenu += AddGameObjectItem; - _contextMenu.OnOpenInventoryContextMenu += AddInventoryItem; + _contextMenu.OnMenuOpened += OnMenuOpened; + } + + private unsafe void OnMenuOpened(MenuOpenedArgs args) + { + if (args.MenuType is ContextMenuType.Inventory) + { + var arg = (MenuTargetInventory)args.Target; + if (arg.TargetItem.HasValue && HandleItem(arg.TargetItem.Value.ItemId)) + { + _lastStain = arg.TargetItem.Value.Stain; + args.AddMenuItem(_inventoryItem); + } + } + else + { + switch (args.AddonName) + { + case "ItemSearch" when args.AgentPtr != nint.Zero: + { + if (HandleItem((ItemId)AgentContext.Instance()->UpdateCheckerParam)) + args.AddMenuItem(_inventoryItem); + + break; + } + case "ChatLog": + { + var agent = _gameGui.FindAgentInterface("ChatLog"); + if (agent == nint.Zero || !ValidateChatLogContext(agent)) + return; + + if (HandleItem(*(ItemId*)(agent + ChatLogContextItemId))) + { + _lastStain = 0; + args.AddMenuItem(_inventoryItem); + } + + break; + } + } + } + } + + private bool HandleItem(ItemId id) + { + var itemId = Math.Clamp(id.Id, 0, 500000u); + return _items.ItemData.TryGetValue(itemId, EquipSlot.MainHand, out _lastItem); } public void Disable() { - _contextMenu.OnOpenGameObjectContextMenu -= AddGameObjectItem; - _contextMenu.OnOpenInventoryContextMenu -= AddInventoryItem; + _contextMenu.OnMenuOpened -= OnMenuOpened; } public void Dispose() { Disable(); - _contextMenu.Dispose(); } - private static readonly SeString TryOnString = new SeStringBuilder().AddUiForeground(SeIconChar.BoxedLetterG.ToIconString(), 541) - .AddText(" Try On").AddUiForegroundOff().BuiltString; - - private void AddInventoryItem(InventoryContextMenuOpenArgs args) + private void OnClick(MenuItemClickedArgs _) { - var item = CheckInventoryItem(args.ItemId); - if (item != null) - args.AddCustomItem(item); - } + var (id, playerData) = _objects.PlayerData; + if (!playerData.Valid) + return; - private InventoryContextMenuItem? CheckInventoryItem(uint itemId) - { - if (itemId > 500000) - itemId -= 500000; + if (!_state.GetOrCreate(id, playerData.Objects[0], out var state)) + return; - if (!_items.ItemData.TryGetValue(itemId, EquipSlot.MainHand, out var item)) - return null; + var slot = _lastItem.Type.ToSlot(); + _state.ChangeEquip(state, slot, _lastItem, _lastStain, ApplySettings.Manual); + if (!_lastItem.Type.ValidOffhand().IsOffhandType()) + return; - return new InventoryContextMenuItem(TryOnString, GetInventoryAction(item)); - } - - - private GameObjectContextMenuItem? CheckGameObjectItem(uint itemId) - { - if (itemId > 500000) - itemId -= 500000; - - if (!_items.ItemData.TryGetValue(itemId, EquipSlot.MainHand, out var item)) - return null; - - return new GameObjectContextMenuItem(TryOnString, GetGameObjectAction(item)); - } - - private unsafe GameObjectContextMenuItem? CheckGameObjectItem(IntPtr agent, int offset, Func validate) - => agent != IntPtr.Zero && validate(agent) ? CheckGameObjectItem(*(uint*)(agent + offset)) : null; - - private unsafe GameObjectContextMenuItem? CheckGameObjectItem(IntPtr agent, int offset) - => agent != IntPtr.Zero ? CheckGameObjectItem(*(uint*)(agent + offset)) : null; - - private GameObjectContextMenuItem? CheckGameObjectItem(string name, int offset, Func validate) - => CheckGameObjectItem(_gameGui.FindAgentInterface(name), offset, validate); - - private void AddGameObjectItem(GameObjectContextMenuOpenArgs args) - { - var item = args.ParentAddonName switch - { - "ItemSearch" => CheckGameObjectItem(args.Agent, ItemSearchContextItemId), - "ChatLog" => CheckGameObjectItem("ChatLog", ChatLogContextItemId, ValidateChatLogContext), - _ => null, - }; - if (item != null) - args.AddCustomItem(item); - } - - private DalamudContextMenu.InventoryContextMenuItemSelectedDelegate GetInventoryAction(EquipItem item) - { - return _ => - { - var (id, playerData) = _objects.PlayerData; - if (!playerData.Valid) - return; - - if (!_state.GetOrCreate(id, playerData.Objects[0], out var state)) - return; - - var slot = item.Type.ToSlot(); - _state.ChangeEquip(state, slot, item, 0, ApplySettings.Manual); - if (item.Type.ValidOffhand().IsOffhandType()) - { - if (item.PrimaryId.Id is > 1600 and < 1651 - && _items.ItemData.TryGetValue(item.ItemId, EquipSlot.Hands, out var gauntlets)) - _state.ChangeEquip(state, EquipSlot.Hands, gauntlets, 0, ApplySettings.Manual); - if (_items.ItemData.TryGetValue(item.ItemId, EquipSlot.OffHand, out var offhand)) - _state.ChangeEquip(state, EquipSlot.OffHand, offhand, 0, ApplySettings.Manual); - } - }; - } - - private DalamudContextMenu.GameObjectContextMenuItemSelectedDelegate GetGameObjectAction(EquipItem item) - { - return _ => - { - var (id, playerData) = _objects.PlayerData; - if (!playerData.Valid) - return; - - if (!_state.GetOrCreate(id, playerData.Objects[0], out var state)) - return; - - var slot = item.Type.ToSlot(); - _state.ChangeEquip(state, slot, item, 0, ApplySettings.Manual); - if (item.Type.ValidOffhand().IsOffhandType()) - { - if (item.PrimaryId.Id is > 1600 and < 1651 - && _items.ItemData.TryGetValue(item.ItemId, EquipSlot.Hands, out var gauntlets)) - _state.ChangeEquip(state, EquipSlot.Hands, gauntlets, 0, ApplySettings.Manual); - if (_items.ItemData.TryGetValue(item.ItemId, EquipSlot.OffHand, out var offhand)) - _state.ChangeEquip(state, EquipSlot.OffHand, offhand, 0, ApplySettings.Manual); - } - }; + if (_lastItem.PrimaryId.Id is > 1600 and < 1651 + && _items.ItemData.TryGetValue(_lastItem.ItemId, EquipSlot.Hands, out var gauntlets)) + _state.ChangeEquip(state, EquipSlot.Hands, gauntlets, _lastStain, ApplySettings.Manual); + if (_items.ItemData.TryGetValue(_lastItem.ItemId, EquipSlot.OffHand, out var offhand)) + _state.ChangeEquip(state, EquipSlot.OffHand, offhand, _lastStain, ApplySettings.Manual); } private static unsafe bool ValidateChatLogContext(nint agent) diff --git a/Glamourer/Services/DalamudServices.cs b/Glamourer/Services/DalamudServices.cs index 66cb97b..fd001d7 100644 --- a/Glamourer/Services/DalamudServices.cs +++ b/Glamourer/Services/DalamudServices.cs @@ -27,5 +27,6 @@ public class DalamudServices services.AddDalamudService(pi); services.AddDalamudService(pi); services.AddDalamudService(pi); + services.AddDalamudService(pi); } }