Refactor IAddonEventManager (#2299)

This commit is contained in:
MidoriKami 2025-06-17 10:51:00 -07:00 committed by GitHub
parent b1986bd3d1
commit 13306e24ba
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 199 additions and 42 deletions

View file

@ -0,0 +1,46 @@
namespace Dalamud.Game.Addon.Events;
/// <summary>
/// Object representing data that is relevant in handling native events.
/// </summary>
public class AddonEventData
{
/// <summary>
/// Gets the AtkEventType for this event.
/// </summary>
public AddonEventType AtkEventType { get; internal set; }
/// <summary>
/// Gets the param field for this event.
/// </summary>
public uint Param { get; internal set; }
/// <summary>
/// Gets the pointer to the AtkEvent object for this event.
/// </summary>
/// <remarks>Note: This is not a pointer to the AtkEventData object.<br/><br/></remarks>
/// <remarks>Warning: AtkEvent->Node has been modified to be the AtkUnitBase*, and AtkEvent->Target has been modified to be the AtkResNode* that triggered this event.</remarks>
public nint AtkEventPointer { get; internal set; }
/// <summary>
/// Gets the pointer to the AtkEventData object for this event.
/// </summary>
/// <remarks>This field will contain relevant data such as left vs right click, scroll up vs scroll down.</remarks>
public nint AtkEventDataPointer { get; internal set; }
/// <summary>
/// Gets the pointer to the AtkUnitBase that is handling this event.
/// </summary>
public nint AddonPointer { get; internal set; }
/// <summary>
/// Gets the pointer to the AtkResNode that triggered this event.
/// </summary>
public nint NodeTargetPointer { get; internal set; }
/// <summary>
/// Gets or sets a pointer to the AtkEventListener responsible for handling this event.
/// Note: As the event listener is dalamud allocated, there's no reason to expose this field.
/// </summary>
internal nint AtkEventListener { get; set; }
}

View file

@ -1,5 +1,6 @@
using Dalamud.Memory;
using Dalamud.Plugin.Services;
using Dalamud.Plugin.Services;
using Dalamud.Utility;
using FFXIVClientStructs.FFXIV.Component.GUI;
namespace Dalamud.Game.Addon.Events;
@ -35,7 +36,14 @@ internal unsafe class AddonEventEntry
/// <summary>
/// Gets the handler that gets called when this event is triggered.
/// </summary>
public required IAddonEventManager.AddonEventHandler Handler { get; init; }
[Obsolete("Use AddonEventDelegate Delegate instead")]
public IAddonEventManager.AddonEventHandler Handler { get; init; }
/// <summary>
/// Gets the delegate that gets called when this event is triggered.
/// </summary>
[Api13ToDo("Make this field required")]
public IAddonEventManager.AddonEventDelegate Delegate { get; init; }
/// <summary>
/// Gets the unique id for this event.

View file

@ -96,6 +96,29 @@ internal unsafe class AddonEventManager : IInternalDisposableService
return null;
}
/// <summary>
/// Registers an event handler for the specified addon, node, and type.
/// </summary>
/// <param name="pluginId">Unique ID for this plugin.</param>
/// <param name="atkUnitBase">The parent addon for this event.</param>
/// <param name="atkResNode">The node that will trigger this event.</param>
/// <param name="eventType">The event type for this event.</param>
/// <param name="eventDelegate">The delegate to call when event is triggered.</param>
/// <returns>IAddonEventHandle used to remove the event.</returns>
internal IAddonEventHandle? AddEvent(Guid pluginId, nint atkUnitBase, nint atkResNode, AddonEventType eventType, IAddonEventManager.AddonEventDelegate eventDelegate)
{
if (this.pluginEventControllers.TryGetValue(pluginId, out var controller))
{
return controller.AddEvent(atkUnitBase, atkResNode, eventType, eventDelegate);
}
else
{
Log.Verbose($"Unable to locate controller for {pluginId}. No event was added.");
}
return null;
}
/// <summary>
/// Unregisters an event handler with the specified event id and event type.
/// </summary>
@ -241,6 +264,10 @@ internal class AddonEventManagerPluginScoped : IInternalDisposableService, IAddo
public IAddonEventHandle? AddEvent(IntPtr atkUnitBase, IntPtr atkResNode, AddonEventType eventType, IAddonEventManager.AddonEventHandler eventHandler)
=> this.eventManagerService.AddEvent(this.plugin.EffectiveWorkingPluginId, atkUnitBase, atkResNode, eventType, eventHandler);
/// <inheritdoc/>
public IAddonEventHandle? AddEvent(nint atkUnitBase, nint atkResNode, AddonEventType eventType, IAddonEventManager.AddonEventDelegate eventDelegate)
=> this.eventManagerService.AddEvent(this.plugin.EffectiveWorkingPluginId, atkUnitBase, atkResNode, eventType, eventDelegate);
/// <inheritdoc/>
public void RemoveEvent(IAddonEventHandle eventHandle)
=> this.eventManagerService.RemoveEvent(this.plugin.EffectiveWorkingPluginId, eventHandle);

View file

@ -4,6 +4,7 @@ using System.Linq;
using Dalamud.Game.Gui;
using Dalamud.Logging.Internal;
using Dalamud.Plugin.Services;
using Dalamud.Utility;
using FFXIVClientStructs.FFXIV.Component.GUI;
@ -36,6 +37,7 @@ internal unsafe class PluginEventController : IDisposable
/// <param name="atkEventType">The Event Type.</param>
/// <param name="handler">The delegate to call when invoking this event.</param>
/// <returns>IAddonEventHandle used to remove the event.</returns>
[Obsolete("Use AddEvent that uses AddonEventDelegate instead of AddonEventHandler")]
public IAddonEventHandle AddEvent(nint atkUnitBase, nint atkResNode, AddonEventType atkEventType, IAddonEventManager.AddonEventHandler handler)
{
var node = (AtkResNode*)atkResNode;
@ -56,6 +58,49 @@ internal unsafe class PluginEventController : IDisposable
{
Addon = atkUnitBase,
Handler = handler,
Delegate = null,
Node = atkResNode,
EventType = atkEventType,
ParamKey = eventId,
Handle = eventHandle,
};
Log.Verbose($"Adding Event. {eventEntry.LogString}");
this.EventListener.RegisterEvent(addon, node, eventType, eventId);
this.Events.Add(eventEntry);
return eventHandle;
}
/// <summary>
/// Adds a tracked event.
/// </summary>
/// <param name="atkUnitBase">The Parent addon for the event.</param>
/// <param name="atkResNode">The Node for the event.</param>
/// <param name="atkEventType">The Event Type.</param>
/// <param name="eventDelegate">The delegate to call when invoking this event.</param>
/// <returns>IAddonEventHandle used to remove the event.</returns>
public IAddonEventHandle AddEvent(nint atkUnitBase, nint atkResNode, AddonEventType atkEventType, IAddonEventManager.AddonEventDelegate eventDelegate)
{
var node = (AtkResNode*)atkResNode;
var addon = (AtkUnitBase*)atkUnitBase;
var eventType = (AtkEventType)atkEventType;
var eventId = this.GetNextParamKey();
var eventGuid = Guid.NewGuid();
var eventHandle = new AddonEventHandle
{
AddonName = addon->NameString,
ParamKey = eventId,
EventType = atkEventType,
EventGuid = eventGuid,
};
var eventEntry = new AddonEventEntry
{
Addon = atkUnitBase,
Delegate = eventDelegate,
Handler = null,
Node = atkResNode,
EventType = atkEventType,
ParamKey = eventId,
@ -185,6 +230,7 @@ internal unsafe class PluginEventController : IDisposable
this.EventListener.UnregisterEvent(atkResNode, eventType, eventEntry.ParamKey);
}
[Api13ToDo("Remove invoke from eventInfo.Handler, and remove nullability from eventInfo.Delegate?.Invoke")]
private void PluginEventListHandler(AtkEventListener* self, AtkEventType eventType, uint eventParam, AtkEvent* eventPtr, AtkEventData* eventDataPtr)
{
try
@ -193,7 +239,18 @@ internal unsafe class PluginEventController : IDisposable
if (this.Events.FirstOrDefault(handler => handler.ParamKey == eventParam) is not { } eventInfo) return;
// We stored the AtkUnitBase* in EventData->Node, and EventData->Target contains the node that triggered the event.
eventInfo.Handler.Invoke((AddonEventType)eventType, (nint)eventPtr->Node, (nint)eventPtr->Target);
eventInfo.Handler?.Invoke((AddonEventType)eventType, (nint)eventPtr->Node, (nint)eventPtr->Target);
eventInfo.Delegate?.Invoke((AddonEventType)eventType, new AddonEventData
{
AddonPointer = (nint)eventPtr->Node,
NodeTargetPointer = (nint)eventPtr->Target,
AtkEventDataPointer = (nint)eventDataPtr,
AtkEventListener = (nint)self,
AtkEventType = (AddonEventType)eventType,
Param = eventParam,
AtkEventPointer = (nint)eventPtr,
});
}
catch (Exception exception)
{

View file

@ -13,8 +13,16 @@ public interface IAddonEventManager
/// <param name="atkEventType">Event type for this event handler.</param>
/// <param name="atkUnitBase">The parent addon for this event handler.</param>
/// <param name="atkResNode">The specific node that will trigger this event handler.</param>
[Obsolete("Use AddonEventDelegate instead")]
public delegate void AddonEventHandler(AddonEventType atkEventType, nint atkUnitBase, nint atkResNode);
/// <summary>
/// Delegate to be called when an event is received.
/// </summary>
/// <param name="atkEventType">The AtkEventType that triggered this event.</param>
/// <param name="data">The event data object for use in handling this event.</param>
public delegate void AddonEventDelegate(AddonEventType atkEventType, AddonEventData data);
/// <summary>
/// Registers an event handler for the specified addon, node, and type.
/// </summary>
@ -23,8 +31,19 @@ public interface IAddonEventManager
/// <param name="eventType">The event type for this event.</param>
/// <param name="eventHandler">The handler to call when event is triggered.</param>
/// <returns>IAddonEventHandle used to remove the event. Null if no event was added.</returns>
[Obsolete("Use AddEvent with AddonEventDelegate instead of AddonEventHandler")]
IAddonEventHandle? AddEvent(nint atkUnitBase, nint atkResNode, AddonEventType eventType, AddonEventHandler eventHandler);
/// <summary>
/// Registers an event handler for the specified addon, node, and type.
/// </summary>
/// <param name="atkUnitBase">The parent addon for this event.</param>
/// <param name="atkResNode">The node that will trigger this event.</param>
/// <param name="eventType">The event type for this event.</param>
/// <param name="eventDelegate">The handler to call when event is triggered.</param>
/// <returns>IAddonEventHandle used to remove the event. Null if no event was added.</returns>
IAddonEventHandle? AddEvent(nint atkUnitBase, nint atkResNode, AddonEventType eventType, AddonEventDelegate eventDelegate);
/// <summary>
/// Unregisters an event handler with the specified event id and event type.
/// </summary>