mirror of
https://github.com/goatcorp/Dalamud.git
synced 2025-12-14 20:54:16 +01:00
[AddonEventManager] Add Cursor Control
This commit is contained in:
parent
7ac37a579b
commit
ad06b5f054
4 changed files with 196 additions and 4 deletions
97
Dalamud/Game/AddonEventManager/AddonCursorType.cs
Normal file
97
Dalamud/Game/AddonEventManager/AddonCursorType.cs
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
namespace Dalamud.Game.AddonEventManager;
|
||||
|
||||
/// <summary>
|
||||
/// Reimplementation of CursorType.
|
||||
/// </summary>
|
||||
public enum AddonCursorType
|
||||
{
|
||||
/// <summary>
|
||||
/// Arrow.
|
||||
/// </summary>
|
||||
Arrow,
|
||||
|
||||
/// <summary>
|
||||
/// Boot.
|
||||
/// </summary>
|
||||
Boot,
|
||||
|
||||
/// <summary>
|
||||
/// Search.
|
||||
/// </summary>
|
||||
Search,
|
||||
|
||||
/// <summary>
|
||||
/// Chat Pointer.
|
||||
/// </summary>
|
||||
ChatPointer,
|
||||
|
||||
/// <summary>
|
||||
/// Interact.
|
||||
/// </summary>
|
||||
Interact,
|
||||
|
||||
/// <summary>
|
||||
/// Attack.
|
||||
/// </summary>
|
||||
Attack,
|
||||
|
||||
/// <summary>
|
||||
/// Hand.
|
||||
/// </summary>
|
||||
Hand,
|
||||
|
||||
/// <summary>
|
||||
/// Resizeable Left-Right.
|
||||
/// </summary>
|
||||
ResizeWE,
|
||||
|
||||
/// <summary>
|
||||
/// Resizeable Up-Down.
|
||||
/// </summary>
|
||||
ResizeNS,
|
||||
|
||||
/// <summary>
|
||||
/// Resizeable.
|
||||
/// </summary>
|
||||
ResizeNWSR,
|
||||
|
||||
/// <summary>
|
||||
/// Resizeable 4-way.
|
||||
/// </summary>
|
||||
ResizeNESW,
|
||||
|
||||
/// <summary>
|
||||
/// Clickable.
|
||||
/// </summary>
|
||||
Clickable,
|
||||
|
||||
/// <summary>
|
||||
/// Text Input.
|
||||
/// </summary>
|
||||
TextInput,
|
||||
|
||||
/// <summary>
|
||||
/// Text Click.
|
||||
/// </summary>
|
||||
TextClick,
|
||||
|
||||
/// <summary>
|
||||
/// Grab.
|
||||
/// </summary>
|
||||
Grab,
|
||||
|
||||
/// <summary>
|
||||
/// Chat Bubble.
|
||||
/// </summary>
|
||||
ChatBubble,
|
||||
|
||||
/// <summary>
|
||||
/// No Access.
|
||||
/// </summary>
|
||||
NoAccess,
|
||||
|
||||
/// <summary>
|
||||
/// Hidden.
|
||||
/// </summary>
|
||||
Hidden,
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ using Dalamud.IoC;
|
|||
using Dalamud.IoC.Internal;
|
||||
using Dalamud.Logging.Internal;
|
||||
using Dalamud.Plugin.Services;
|
||||
using FFXIVClientStructs.FFXIV.Client.UI;
|
||||
using FFXIVClientStructs.FFXIV.Component.GUI;
|
||||
|
||||
namespace Dalamud.Game.AddonEventManager;
|
||||
|
|
@ -32,9 +33,13 @@ internal unsafe class AddonEventManager : IDisposable, IServiceType
|
|||
|
||||
private static readonly ModuleLog Log = new("AddonEventManager");
|
||||
private readonly AddonEventManagerAddressResolver address;
|
||||
private readonly Hook<GlobalEventHandlerDetour> onGlobalEventHook;
|
||||
private readonly Hook<GlobalEventHandlerDelegate> onGlobalEventHook;
|
||||
private readonly Hook<UpdateCursorDelegate> onUpdateCursor;
|
||||
private readonly Dictionary<uint, IAddonEventManager.AddonEventHandler> eventHandlers;
|
||||
|
||||
private AddonCursorType currentCursor;
|
||||
private bool cursorSet;
|
||||
|
||||
private uint currentPluginParamStart = ParamKeyStart;
|
||||
|
||||
[ServiceManager.ServiceConstructor]
|
||||
|
|
@ -44,16 +49,21 @@ internal unsafe class AddonEventManager : IDisposable, IServiceType
|
|||
this.address.Setup(sigScanner);
|
||||
|
||||
this.eventHandlers = new Dictionary<uint, IAddonEventManager.AddonEventHandler>();
|
||||
this.currentCursor = AddonCursorType.Arrow;
|
||||
|
||||
this.onGlobalEventHook = Hook<GlobalEventHandlerDetour>.FromAddress(this.address.GlobalEventHandler, this.GlobalEventHandler);
|
||||
this.onGlobalEventHook = Hook<GlobalEventHandlerDelegate>.FromAddress(this.address.GlobalEventHandler, this.GlobalEventHandler);
|
||||
this.onUpdateCursor = Hook<UpdateCursorDelegate>.FromAddress(this.address.UpdateCursor, this.UpdateCursorDetour);
|
||||
}
|
||||
|
||||
private delegate nint GlobalEventHandlerDetour(AtkUnitBase* atkUnitBase, AtkEventType eventType, uint eventParam, AtkResNode** eventData, nint unknown);
|
||||
private delegate nint GlobalEventHandlerDelegate(AtkUnitBase* atkUnitBase, AtkEventType eventType, uint eventParam, AtkResNode** eventData, nint unknown);
|
||||
|
||||
private delegate nint UpdateCursorDelegate(RaptureAtkModule* module);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
{
|
||||
this.onGlobalEventHook.Dispose();
|
||||
this.onUpdateCursor.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -86,11 +96,31 @@ internal unsafe class AddonEventManager : IDisposable, IServiceType
|
|||
/// </summary>
|
||||
/// <param name="eventId">Event id to unregister.</param>
|
||||
public void RemoveEvent(uint eventId) => this.eventHandlers.Remove(eventId);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the game cursor.
|
||||
/// </summary>
|
||||
/// <param name="cursor">Cursor type to set.</param>
|
||||
public void SetCursor(AddonCursorType cursor)
|
||||
{
|
||||
this.currentCursor = cursor;
|
||||
this.cursorSet = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Resets and un-forces custom cursor.
|
||||
/// </summary>
|
||||
public void ResetCursor()
|
||||
{
|
||||
this.currentCursor = AddonCursorType.Arrow;
|
||||
this.cursorSet = false;
|
||||
}
|
||||
|
||||
[ServiceManager.CallWhenServicesReady]
|
||||
private void ContinueConstruction()
|
||||
{
|
||||
this.onGlobalEventHook.Enable();
|
||||
this.onUpdateCursor.Enable();
|
||||
}
|
||||
|
||||
private nint GlobalEventHandler(AtkUnitBase* atkUnitBase, AtkEventType eventType, uint eventParam, AtkResNode** eventData, nint unknown)
|
||||
|
|
@ -117,6 +147,31 @@ internal unsafe class AddonEventManager : IDisposable, IServiceType
|
|||
|
||||
return this.onGlobalEventHook!.Original(atkUnitBase, eventType, eventParam, eventData, unknown);
|
||||
}
|
||||
|
||||
private nint UpdateCursorDetour(RaptureAtkModule* module)
|
||||
{
|
||||
try
|
||||
{
|
||||
var atkStage = AtkStage.GetSingleton();
|
||||
|
||||
if (this.cursorSet && atkStage is not null)
|
||||
{
|
||||
var cursor = (AddonCursorType)atkStage->AtkCursor.Type;
|
||||
if (cursor != this.currentCursor)
|
||||
{
|
||||
AtkStage.GetSingleton()->AtkCursor.SetCursorType((AtkCursor.CursorType)this.currentCursor, 1);
|
||||
}
|
||||
|
||||
return nint.Zero;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e, "Exception in UpdateCursorDetour.");
|
||||
}
|
||||
|
||||
return this.onUpdateCursor!.Original(module);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -137,6 +192,7 @@ internal unsafe class AddonEventManagerPluginScoped : IDisposable, IServiceType,
|
|||
|
||||
private readonly uint paramKeyStartRange;
|
||||
private readonly List<uint> activeParamKeys;
|
||||
private bool isForcingCursor;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AddonEventManagerPluginScoped"/> class.
|
||||
|
|
@ -154,6 +210,12 @@ internal unsafe class AddonEventManagerPluginScoped : IDisposable, IServiceType,
|
|||
{
|
||||
this.baseEventManager.RemoveEvent(activeKey);
|
||||
}
|
||||
|
||||
// if multiple plugins force cursors and dispose without un-forcing them then all forces will be cleared.
|
||||
if (this.isForcingCursor)
|
||||
{
|
||||
this.baseEventManager.ResetCursor();
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
|
@ -204,4 +266,20 @@ internal unsafe class AddonEventManagerPluginScoped : IDisposable, IServiceType,
|
|||
Log.Warning($"Attempted to unregister already unregistered eventId: {eventId}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void SetCursor(AddonCursorType cursor)
|
||||
{
|
||||
this.isForcingCursor = true;
|
||||
|
||||
this.baseEventManager.SetCursor(cursor);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void ResetCursor()
|
||||
{
|
||||
this.isForcingCursor = false;
|
||||
|
||||
this.baseEventManager.ResetCursor();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,9 +6,14 @@
|
|||
internal class AddonEventManagerAddressResolver : BaseAddressResolver
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the address of the global atkevent handler
|
||||
/// Gets the address of the global AtkEvent handler.
|
||||
/// </summary>
|
||||
public nint GlobalEventHandler { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the address of the AtkModule UpdateCursor method.
|
||||
/// </summary>
|
||||
public nint UpdateCursor { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Scan for and setup any configured address pointers.
|
||||
|
|
@ -17,5 +22,6 @@ internal class AddonEventManagerAddressResolver : BaseAddressResolver
|
|||
protected override void Setup64Bit(SigScanner scanner)
|
||||
{
|
||||
this.GlobalEventHandler = scanner.ScanText("48 89 5C 24 ?? 48 89 7C 24 ?? 55 41 56 41 57 48 8B EC 48 83 EC 50 44 0F B7 F2");
|
||||
this.UpdateCursor = scanner.ScanText("48 89 74 24 ?? 48 89 7C 24 ?? 41 56 48 83 EC 20 4C 8B F1 E8 ?? ?? ?? ?? 49 8B CE");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,4 +33,15 @@ public interface IAddonEventManager
|
|||
/// <param name="atkResNode">The node for this event.</param>
|
||||
/// <param name="eventType">The event type for this event.</param>
|
||||
void RemoveEvent(uint eventId, nint atkUnitBase, nint atkResNode, AddonEventType eventType);
|
||||
|
||||
/// <summary>
|
||||
/// Force the game cursor to be the specified cursor.
|
||||
/// </summary>
|
||||
/// <param name="cursor">Which cursor to use.</param>
|
||||
void SetCursor(AddonCursorType cursor);
|
||||
|
||||
/// <summary>
|
||||
/// Un-forces the game cursor.
|
||||
/// </summary>
|
||||
void ResetCursor();
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue