mirror of
https://github.com/goatcorp/Dalamud.git
synced 2025-12-12 18:27:23 +01:00
Auto generate paramkeys and return handles to events.
This commit is contained in:
parent
3b5995e6ab
commit
26838d9f5c
7 changed files with 127 additions and 40 deletions
|
|
@ -1,4 +1,6 @@
|
|||
using Dalamud.Memory;
|
||||
using System;
|
||||
|
||||
using Dalamud.Memory;
|
||||
using Dalamud.Plugin.Services;
|
||||
using FFXIVClientStructs.FFXIV.Component.GUI;
|
||||
|
||||
|
|
@ -46,9 +48,14 @@ internal unsafe class AddonEventEntry
|
|||
/// Gets the event type for this event.
|
||||
/// </summary>
|
||||
required public AddonEventType EventType { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the event handle for this event.
|
||||
/// </summary>
|
||||
required internal IAddonEventHandle Handle { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the formatted log string for this AddonEventEntry.
|
||||
/// </summary>
|
||||
internal string LogString => $"ParamKey: {this.ParamKey}, Addon: {this.AddonName}, Event: {this.EventType}";
|
||||
internal string LogString => $"ParamKey: {this.ParamKey}, Addon: {this.AddonName}, Event: {this.EventType}, GUID: {this.Handle.EventGuid}";
|
||||
}
|
||||
|
|
|
|||
21
Dalamud/Game/AddonEventManager/AddonEventHandle.cs
Normal file
21
Dalamud/Game/AddonEventManager/AddonEventHandle.cs
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
using System;
|
||||
|
||||
namespace Dalamud.Game.Addon;
|
||||
|
||||
/// <summary>
|
||||
/// Class that represents a addon event handle.
|
||||
/// </summary>
|
||||
public class AddonEventHandle : IAddonEventHandle
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public uint ParamKey { get; init; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public string AddonName { get; init; } = "NullAddon";
|
||||
|
||||
/// <inheritdoc/>
|
||||
public AddonEventType EventType { get; init; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public Guid EventGuid { get; init; }
|
||||
}
|
||||
|
|
@ -77,33 +77,32 @@ internal unsafe class AddonEventManager : IDisposable, IServiceType
|
|||
/// Registers an event handler for the specified addon, node, and type.
|
||||
/// </summary>
|
||||
/// <param name="pluginId">Unique ID for this plugin.</param>
|
||||
/// <param name="eventId">Unique Id for this event, maximum 0x10000.</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="eventHandler">The handler to call when event is triggered.</param>
|
||||
internal void AddEvent(string pluginId, uint eventId, IntPtr atkUnitBase, IntPtr atkResNode, AddonEventType eventType, IAddonEventManager.AddonEventHandler eventHandler)
|
||||
/// <returns>IAddonEventHandle used to remove the event.</returns>
|
||||
internal IAddonEventHandle? AddEvent(string pluginId, IntPtr atkUnitBase, IntPtr atkResNode, AddonEventType eventType, IAddonEventManager.AddonEventHandler eventHandler)
|
||||
{
|
||||
if (this.pluginEventControllers.FirstOrDefault(entry => entry.PluginId == pluginId) is { } eventController)
|
||||
{
|
||||
eventController.AddEvent(eventId, atkUnitBase, atkResNode, eventType, eventHandler);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Verbose($"Unable to locate controller for {pluginId}. No event was added.");
|
||||
return eventController.AddEvent(atkUnitBase, atkResNode, eventType, eventHandler);
|
||||
}
|
||||
|
||||
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>
|
||||
/// <param name="pluginId">Unique ID for this plugin.</param>
|
||||
/// <param name="eventId">The Unique Id for this event.</param>
|
||||
internal void RemoveEvent(string pluginId, uint eventId)
|
||||
/// <param name="eventHandle">The Unique Id for this event.</param>
|
||||
internal void RemoveEvent(string pluginId, IAddonEventHandle eventHandle)
|
||||
{
|
||||
if (this.pluginEventControllers.FirstOrDefault(entry => entry.PluginId == pluginId) is { } eventController)
|
||||
{
|
||||
eventController.RemoveEvent(eventId);
|
||||
eventController.RemoveEvent(eventHandle);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -239,12 +238,12 @@ internal class AddonEventManagerPluginScoped : IDisposable, IServiceType, IAddon
|
|||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void AddEvent(uint eventId, IntPtr atkUnitBase, IntPtr atkResNode, AddonEventType eventType, IAddonEventManager.AddonEventHandler eventHandler)
|
||||
=> this.eventManagerService.AddEvent(this.plugin.Manifest.WorkingPluginId.ToString(), eventId, atkUnitBase, atkResNode, eventType, eventHandler);
|
||||
public IAddonEventHandle? AddEvent(IntPtr atkUnitBase, IntPtr atkResNode, AddonEventType eventType, IAddonEventManager.AddonEventHandler eventHandler)
|
||||
=> this.eventManagerService.AddEvent(this.plugin.Manifest.WorkingPluginId.ToString(), atkUnitBase, atkResNode, eventType, eventHandler);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void RemoveEvent(uint eventId)
|
||||
=> this.eventManagerService.RemoveEvent(this.plugin.Manifest.WorkingPluginId.ToString(), eventId);
|
||||
public void RemoveEvent(IAddonEventHandle eventHandle)
|
||||
=> this.eventManagerService.RemoveEvent(this.plugin.Manifest.WorkingPluginId.ToString(), eventHandle);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void SetCursor(AddonCursorType cursor)
|
||||
|
|
|
|||
29
Dalamud/Game/AddonEventManager/IAddonEventHandle.cs
Normal file
29
Dalamud/Game/AddonEventManager/IAddonEventHandle.cs
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
using System;
|
||||
|
||||
namespace Dalamud.Game.Addon;
|
||||
|
||||
/// <summary>
|
||||
/// Interface representing the data used for managing AddonEvents.
|
||||
/// </summary>
|
||||
public interface IAddonEventHandle
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the param key associated with this event.
|
||||
/// </summary>
|
||||
public uint ParamKey { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the addon that this event was attached to.
|
||||
/// </summary>
|
||||
public string AddonName { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the event type associated with this handle.
|
||||
/// </summary>
|
||||
public AddonEventType EventType { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the unique ID for this handle.
|
||||
/// </summary>
|
||||
public Guid EventGuid { get; init; }
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@ using System.Linq;
|
|||
|
||||
using Dalamud.Game.Gui;
|
||||
using Dalamud.Logging.Internal;
|
||||
using Dalamud.Memory;
|
||||
using Dalamud.Plugin.Services;
|
||||
using FFXIVClientStructs.FFXIV.Component.GUI;
|
||||
|
||||
|
|
@ -39,17 +40,27 @@ internal unsafe class PluginEventController : IDisposable
|
|||
/// <summary>
|
||||
/// Adds a tracked event.
|
||||
/// </summary>
|
||||
/// <param name="eventId">Unique ID of the event to add.</param>
|
||||
/// <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="handler">The delegate to call when invoking this event.</param>
|
||||
public void AddEvent(uint eventId, nint atkUnitBase, nint atkResNode, AddonEventType atkEventType, IAddonEventManager.AddonEventHandler handler)
|
||||
/// <returns>IAddonEventHandle used to remove the event.</returns>
|
||||
public IAddonEventHandle AddEvent(nint atkUnitBase, nint atkResNode, AddonEventType atkEventType, IAddonEventManager.AddonEventHandler handler)
|
||||
{
|
||||
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 = MemoryHelper.ReadStringNullTerminated((nint)addon->Name),
|
||||
ParamKey = eventId,
|
||||
EventType = atkEventType,
|
||||
EventGuid = eventGuid,
|
||||
};
|
||||
|
||||
var eventEntry = new AddonEventEntry
|
||||
{
|
||||
Addon = atkUnitBase,
|
||||
|
|
@ -57,22 +68,25 @@ internal unsafe class PluginEventController : IDisposable
|
|||
Node = atkResNode,
|
||||
EventType = atkEventType,
|
||||
ParamKey = eventId,
|
||||
Handle = eventHandle,
|
||||
};
|
||||
|
||||
Log.Verbose($"Adding Event: {eventEntry.LogString}");
|
||||
Log.Verbose($"Adding Event. {eventEntry.LogString}");
|
||||
this.EventListener.RegisterEvent(addon, node, eventType, eventId);
|
||||
this.Events.Add(eventEntry);
|
||||
|
||||
return eventHandle;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a tracked event, also attempts to un-attach the event from native.
|
||||
/// </summary>
|
||||
/// <param name="eventId">Unique ID of the event to remove.</param>
|
||||
public void RemoveEvent(uint eventId)
|
||||
/// <param name="handle">Unique ID of the event to remove.</param>
|
||||
public void RemoveEvent(IAddonEventHandle handle)
|
||||
{
|
||||
if (this.Events.FirstOrDefault(registeredEvent => registeredEvent.ParamKey == eventId) is not { } targetEvent) return;
|
||||
if (this.Events.FirstOrDefault(registeredEvent => registeredEvent.Handle == handle) is not { } targetEvent) return;
|
||||
|
||||
Log.Verbose($"Removing Event: {targetEvent.LogString}");
|
||||
Log.Verbose($"Removing Event. {targetEvent.LogString}");
|
||||
this.TryRemoveEventFromNative(targetEvent);
|
||||
this.Events.Remove(targetEvent);
|
||||
}
|
||||
|
|
@ -89,7 +103,7 @@ internal unsafe class PluginEventController : IDisposable
|
|||
|
||||
foreach (var registeredEvent in events)
|
||||
{
|
||||
this.RemoveEvent(registeredEvent.ParamKey);
|
||||
this.RemoveEvent(registeredEvent.Handle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -99,11 +113,21 @@ internal unsafe class PluginEventController : IDisposable
|
|||
{
|
||||
foreach (var registeredEvent in this.Events.ToList())
|
||||
{
|
||||
this.RemoveEvent(registeredEvent.ParamKey);
|
||||
this.RemoveEvent(registeredEvent.Handle);
|
||||
}
|
||||
|
||||
this.EventListener.Dispose();
|
||||
}
|
||||
|
||||
private uint GetNextParamKey()
|
||||
{
|
||||
for (var i = 0u; i < uint.MaxValue; ++i)
|
||||
{
|
||||
if (this.Events.All(registeredEvent => registeredEvent.ParamKey != i)) return i;
|
||||
}
|
||||
|
||||
throw new OverflowException($"uint.MaxValue number of ParamKeys used for {this.PluginId}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to remove a tracked event from native UI.
|
||||
|
|
|
|||
|
|
@ -25,9 +25,6 @@ namespace Dalamud.Game.Gui.Dtr;
|
|||
public sealed unsafe class DtrBar : IDisposable, IServiceType, IDtrBar
|
||||
{
|
||||
private const uint BaseNodeId = 1000;
|
||||
private const uint MouseOverEventIdOffset = 10000;
|
||||
private const uint MouseOutEventIdOffset = 20000;
|
||||
private const uint MouseClickEventIdOffset = 30000;
|
||||
|
||||
private static readonly ModuleLog Log = new("DtrBar");
|
||||
|
||||
|
|
@ -51,6 +48,8 @@ public sealed unsafe class DtrBar : IDisposable, IServiceType, IDtrBar
|
|||
|
||||
private readonly ConcurrentBag<DtrBarEntry> newEntries = new();
|
||||
private readonly List<DtrBarEntry> entries = new();
|
||||
|
||||
private readonly Dictionary<uint, List<IAddonEventHandle>> eventHandles = new();
|
||||
|
||||
private uint runningNodeIds = BaseNodeId;
|
||||
|
||||
|
|
@ -328,6 +327,11 @@ public sealed unsafe class DtrBar : IDisposable, IServiceType, IDtrBar
|
|||
private void RecreateNodes()
|
||||
{
|
||||
this.runningNodeIds = BaseNodeId;
|
||||
if (this.entries.Any())
|
||||
{
|
||||
this.eventHandles.Clear();
|
||||
}
|
||||
|
||||
foreach (var entry in this.entries)
|
||||
{
|
||||
entry.TextNode = this.MakeNode(++this.runningNodeIds);
|
||||
|
|
@ -362,10 +366,14 @@ public sealed unsafe class DtrBar : IDisposable, IServiceType, IDtrBar
|
|||
var dtr = this.GetDtr();
|
||||
if (dtr == null || dtr->RootNode == null || dtr->UldManager.NodeList == null || node == null) return false;
|
||||
|
||||
this.uiEventManager.AddEvent(AddonEventManager.DalamudInternalKey, node->AtkResNode.NodeID + MouseOverEventIdOffset, (nint)dtr, (nint)node, AddonEventType.MouseOver, this.DtrEventHandler);
|
||||
this.uiEventManager.AddEvent(AddonEventManager.DalamudInternalKey, node->AtkResNode.NodeID + MouseOutEventIdOffset, (nint)dtr, (nint)node, AddonEventType.MouseOut, this.DtrEventHandler);
|
||||
this.uiEventManager.AddEvent(AddonEventManager.DalamudInternalKey, node->AtkResNode.NodeID + MouseClickEventIdOffset, (nint)dtr, (nint)node, AddonEventType.MouseClick, this.DtrEventHandler);
|
||||
|
||||
this.eventHandles.TryAdd(node->AtkResNode.NodeID, new List<IAddonEventHandle>());
|
||||
this.eventHandles[node->AtkResNode.NodeID].AddRange(new List<IAddonEventHandle>
|
||||
{
|
||||
this.uiEventManager.AddEvent(AddonEventManager.DalamudInternalKey, (nint)dtr, (nint)node, AddonEventType.MouseOver, this.DtrEventHandler),
|
||||
this.uiEventManager.AddEvent(AddonEventManager.DalamudInternalKey, (nint)dtr, (nint)node, AddonEventType.MouseOut, this.DtrEventHandler),
|
||||
this.uiEventManager.AddEvent(AddonEventManager.DalamudInternalKey, (nint)dtr, (nint)node, AddonEventType.MouseClick, this.DtrEventHandler),
|
||||
});
|
||||
|
||||
var lastChild = dtr->RootNode->ChildNode;
|
||||
while (lastChild->PrevSiblingNode != null) lastChild = lastChild->PrevSiblingNode;
|
||||
Log.Debug($"Found last sibling: {(ulong)lastChild:X}");
|
||||
|
|
@ -387,9 +395,8 @@ public sealed unsafe class DtrBar : IDisposable, IServiceType, IDtrBar
|
|||
var dtr = this.GetDtr();
|
||||
if (dtr == null || dtr->RootNode == null || dtr->UldManager.NodeList == null || node == null) return;
|
||||
|
||||
this.uiEventManager.RemoveEvent(AddonEventManager.DalamudInternalKey, node->AtkResNode.NodeID + MouseOverEventIdOffset);
|
||||
this.uiEventManager.RemoveEvent(AddonEventManager.DalamudInternalKey, node->AtkResNode.NodeID + MouseOutEventIdOffset);
|
||||
this.uiEventManager.RemoveEvent(AddonEventManager.DalamudInternalKey, node->AtkResNode.NodeID + MouseClickEventIdOffset);
|
||||
this.eventHandles[node->AtkResNode.NodeID].ForEach(handle => this.uiEventManager.RemoveEvent(AddonEventManager.DalamudInternalKey, handle));
|
||||
this.eventHandles[node->AtkResNode.NodeID].Clear();
|
||||
|
||||
var tmpPrevNode = node->AtkResNode.PrevSiblingNode;
|
||||
var tmpNextNode = node->AtkResNode.NextSiblingNode;
|
||||
|
|
|
|||
|
|
@ -18,18 +18,18 @@ public interface IAddonEventManager
|
|||
/// <summary>
|
||||
/// Registers an event handler for the specified addon, node, and type.
|
||||
/// </summary>
|
||||
/// <param name="eventId">Unique Id for this event, maximum 0x10000.</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="eventHandler">The handler to call when event is triggered.</param>
|
||||
void AddEvent(uint eventId, nint atkUnitBase, nint atkResNode, AddonEventType eventType, AddonEventHandler eventHandler);
|
||||
/// <returns>IAddonEventHandle used to remove the event. Null if no event was added.</returns>
|
||||
IAddonEventHandle? AddEvent(nint atkUnitBase, nint atkResNode, AddonEventType eventType, AddonEventHandler eventHandler);
|
||||
|
||||
/// <summary>
|
||||
/// Unregisters an event handler with the specified event id and event type.
|
||||
/// </summary>
|
||||
/// <param name="eventId">The Unique Id for this event.</param>
|
||||
void RemoveEvent(uint eventId);
|
||||
/// <param name="eventHandle">Unique handle identifying this event.</param>
|
||||
void RemoveEvent(IAddonEventHandle eventHandle);
|
||||
|
||||
/// <summary>
|
||||
/// Force the game cursor to be the specified cursor.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue