From 1133bd7af0cf06cd10de8200052b2ff205d7ef36 Mon Sep 17 00:00:00 2001 From: Cara Date: Fri, 29 Jan 2021 12:24:43 +1030 Subject: [PATCH] add Hovered Action --- Dalamud/Game/Internal/Gui/GameGui.cs | 76 +++++++++++++++++++ .../Internal/Gui/GameGuiAddressResolver.cs | 4 + Dalamud/Game/Internal/Gui/HoverActionKind.cs | 16 ++++ Dalamud/Game/Internal/Gui/HoveredAction.cs | 19 +++++ 4 files changed, 115 insertions(+) create mode 100644 Dalamud/Game/Internal/Gui/HoverActionKind.cs create mode 100644 Dalamud/Game/Internal/Gui/HoveredAction.cs diff --git a/Dalamud/Game/Internal/Gui/GameGui.cs b/Dalamud/Game/Internal/Gui/GameGui.cs index 702f49ec3..b15effe7d 100644 --- a/Dalamud/Game/Internal/Gui/GameGui.cs +++ b/Dalamud/Game/Internal/Gui/GameGui.cs @@ -23,6 +23,14 @@ namespace Dalamud.Game.Internal.Gui { private delegate IntPtr HandleItemOutDelegate(IntPtr hoverState, IntPtr a2, IntPtr a3, ulong a4); private readonly Hook handleItemOutHook; + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + private delegate void HandleActionHoverDelegate(IntPtr hoverState, HoverActionKind a2, uint a3, int a4, byte a5); + private readonly Hook handleActionHoverHook; + + [UnmanagedFunctionPointer(CallingConvention.ThisCall)] + private delegate IntPtr HandleActionOutDelegate(IntPtr agentActionDetail, IntPtr a2, IntPtr a3, int a4); + private Hook handleActionOutHook; + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate IntPtr GetUIObjectDelegate(); private readonly GetUIObjectDelegate getUIObject; @@ -69,11 +77,21 @@ namespace Dalamud.Game.Internal.Gui { /// If > 1.000.000, subtract 1.000.000 and treat it as HQ /// public ulong HoveredItem { get; set; } + + /// + /// The action ID that is current hovered by the player. 0 when no action is hovered. + /// + public HoveredAction HoveredAction { get; } = new HoveredAction(); /// /// Event that is fired when the currently hovered item changes. /// public EventHandler HoveredItemChanged { get; set; } + + /// + /// Event that is fired when the currently hovered action changes. + /// + public EventHandler HoveredActionChanged { get; set; } public GameGui(IntPtr baseAddress, SigScanner scanner, Dalamud dalamud) { Address = new GameGuiAddressResolver(baseAddress); @@ -103,6 +121,15 @@ namespace Dalamud.Game.Internal.Gui { new HandleItemOutDelegate(HandleItemOutDetour), this); + this.handleActionHoverHook = + new Hook(Address.HandleActionHover, + new HandleActionHoverDelegate(HandleActionHoverDetour), + this); + this.handleActionOutHook = + new Hook(Address.HandleActionOut, + new HandleActionOutDelegate(HandleActionOutDetour), + this); + this.getUIObject = Marshal.GetDelegateForFunctionPointer(Address.GetUIObject); this.getMatrixSingleton = @@ -167,6 +194,51 @@ namespace Dalamud.Game.Internal.Gui { return retVal; } + private void HandleActionHoverDetour(IntPtr hoverState, HoverActionKind actionKind, uint actionId, int a4, byte a5) + { + handleActionHoverHook.Original(hoverState, actionKind, actionId, a4, a5); + HoveredAction.ActionKind = actionKind; + HoveredAction.BaseActionID = actionId; + HoveredAction.ActionID = (uint) Marshal.ReadInt32(hoverState, 0x3C); + try + { + HoveredActionChanged?.Invoke(this, this.HoveredAction); + } catch (Exception e) + { + Log.Error(e, "Could not dispatch HoveredItemChanged event."); + } + Log.Verbose("HoverActionId: {0}/{1} this:{2}", actionKind, actionId, hoverState.ToInt64().ToString("X")); + } + + private IntPtr HandleActionOutDetour(IntPtr agentActionDetail, IntPtr a2, IntPtr a3, int a4) + { + var retVal = handleActionOutHook.Original(agentActionDetail, a2, a3, a4); + + if (a3 != IntPtr.Zero && a4 == 1) + { + var a3Val = Marshal.ReadByte(a3, 0x8); + + if (a3Val == 255) + { + this.HoveredAction.ActionKind = HoverActionKind.None; + HoveredAction.BaseActionID = 0; + HoveredAction.ActionID = 0; + + try + { + HoveredActionChanged?.Invoke(this, this.HoveredAction); + } catch (Exception e) + { + Log.Error(e, "Could not dispatch HoveredActionChanged event."); + } + + Log.Verbose("HoverActionId: 0"); + } + } + + return retVal; + } + /// /// Opens the in-game map with a flag on the location of the parameter /// @@ -347,6 +419,8 @@ namespace Dalamud.Game.Internal.Gui { this.handleItemHoverHook.Enable(); this.handleItemOutHook.Enable(); this.toggleUiHideHook.Enable(); + this.handleActionHoverHook.Enable(); + this.handleActionOutHook.Enable(); } public void Dispose() { @@ -355,6 +429,8 @@ namespace Dalamud.Game.Internal.Gui { this.handleItemHoverHook.Dispose(); this.handleItemOutHook.Dispose(); this.toggleUiHideHook.Dispose(); + this.handleActionHoverHook.Dispose(); + this.handleActionOutHook.Dispose(); } } } diff --git a/Dalamud/Game/Internal/Gui/GameGuiAddressResolver.cs b/Dalamud/Game/Internal/Gui/GameGuiAddressResolver.cs index 47e758da7..7a06ae264 100644 --- a/Dalamud/Game/Internal/Gui/GameGuiAddressResolver.cs +++ b/Dalamud/Game/Internal/Gui/GameGuiAddressResolver.cs @@ -11,6 +11,8 @@ namespace Dalamud.Game.Internal.Gui { public IntPtr SetGlobalBgm { get; private set; } public IntPtr HandleItemHover { get; set; } public IntPtr HandleItemOut { get; set; } + public IntPtr HandleActionHover { get; set; } + public IntPtr HandleActionOut { get; set; } public IntPtr GetUIObject { get; private set; } public IntPtr GetMatrixSingleton { get; private set; } public IntPtr ScreenToWorld { get; private set; } @@ -35,6 +37,8 @@ namespace Dalamud.Game.Internal.Gui { SetGlobalBgm = sig.ScanText("4C 8B 15 ?? ?? ?? ?? 4D 85 D2 74 58"); HandleItemHover = sig.ScanText("E8 ?? ?? ?? ?? 48 8B 5C 24 ?? 48 89 AE ?? ?? ?? ??"); HandleItemOut = sig.ScanText("48 89 5C 24 ?? 57 48 83 EC 20 48 8B FA 48 8B D9 4D"); + HandleActionHover = sig.ScanText("E8 ?? ?? ?? ?? E9 ?? ?? ?? ?? 83 F8 0F"); + HandleActionOut = sig.ScanText("48 89 5C 24 ?? 57 48 83 EC 20 48 8B DA 48 8B F9 4D 85 C0 74 1F"); GetUIObject = sig.ScanText("E8 ?? ?? ?? ?? 48 8B C8 48 8B 10 FF 52 40 80 88 ?? ?? ?? ?? 01 E9"); GetMatrixSingleton = sig.ScanText("E8 ?? ?? ?? ?? 48 8D 4C 24 ?? 48 89 4c 24 ?? 4C 8D 4D ?? 4C 8D 44 24 ??"); ScreenToWorld = sig.ScanText("48 83 EC 48 48 8B 05 ?? ?? ?? ?? 4D 8B D1"); diff --git a/Dalamud/Game/Internal/Gui/HoverActionKind.cs b/Dalamud/Game/Internal/Gui/HoverActionKind.cs new file mode 100644 index 000000000..a3a8ad859 --- /dev/null +++ b/Dalamud/Game/Internal/Gui/HoverActionKind.cs @@ -0,0 +1,16 @@ +namespace Dalamud.Game.Internal.Gui { + + /// + /// ActionKinds used in AgentActionDetail. + /// + public enum HoverActionKind { + None = 0, + Action = 21, + GeneralAction = 23, + CompanionOrder = 24, + MainCommand = 25, + ExtraCommand = 26, + PetOrder = 28, + Trait = 29, + } +} diff --git a/Dalamud/Game/Internal/Gui/HoveredAction.cs b/Dalamud/Game/Internal/Gui/HoveredAction.cs new file mode 100644 index 000000000..51d573bd7 --- /dev/null +++ b/Dalamud/Game/Internal/Gui/HoveredAction.cs @@ -0,0 +1,19 @@ +namespace Dalamud.Game.Internal.Gui { + public class HoveredAction { + + /// + /// The base action ID + /// + public uint BaseActionID { get; set; } = 0; + + /// + /// Action ID accounting for automatic upgrades. + /// + public uint ActionID { get; set; } = 0; + + /// + /// The type of action + /// + public HoverActionKind ActionKind { get; set; } = HoverActionKind.None; + } +}