mirror of
https://github.com/goatcorp/Dalamud.git
synced 2025-12-12 18:27:23 +01:00
AddonLifecycle Add AddonReceiveEvent (#1473)
This commit is contained in:
parent
8be1e4b8ef
commit
d15e35f3f6
9 changed files with 145 additions and 6 deletions
|
|
@ -1,7 +1,7 @@
|
|||
namespace Dalamud.Game.Addon.Lifecycle.AddonArgTypes;
|
||||
|
||||
/// <summary>
|
||||
/// Addon argument data for Finalize events.
|
||||
/// Addon argument data for Draw events.
|
||||
/// </summary>
|
||||
public class AddonDrawArgs : AddonArgs
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
namespace Dalamud.Game.Addon.Lifecycle.AddonArgTypes;
|
||||
|
||||
/// <summary>
|
||||
/// Addon argument data for Finalize events.
|
||||
/// Addon argument data for ReceiveEvent events.
|
||||
/// </summary>
|
||||
public class AddonFinalizeArgs : AddonArgs
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
namespace Dalamud.Game.Addon.Lifecycle.AddonArgTypes;
|
||||
|
||||
/// <summary>
|
||||
/// Addon argument data for ReceiveEvent events.
|
||||
/// </summary>
|
||||
public class AddonReceiveEventArgs : AddonArgs
|
||||
{
|
||||
/// <inheritdoc/>
|
||||
public override AddonArgsType Type => AddonArgsType.ReceiveEvent;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the AtkEventType for this event message.
|
||||
/// </summary>
|
||||
public byte AtkEventType { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the event id for this event message.
|
||||
/// </summary>
|
||||
public int EventParam { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the pointer to an AtkEvent for this event message.
|
||||
/// </summary>
|
||||
public nint AtkEvent { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the pointer to a block of data for this event message.
|
||||
/// </summary>
|
||||
public nint Data { get; init; }
|
||||
}
|
||||
|
|
@ -3,7 +3,7 @@ using FFXIVClientStructs.FFXIV.Component.GUI;
|
|||
namespace Dalamud.Game.Addon.Lifecycle.AddonArgTypes;
|
||||
|
||||
/// <summary>
|
||||
/// Addon argument data for Finalize events.
|
||||
/// Addon argument data for Refresh events.
|
||||
/// </summary>
|
||||
public class AddonRefreshArgs : AddonArgs
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
namespace Dalamud.Game.Addon.Lifecycle.AddonArgTypes;
|
||||
|
||||
/// <summary>
|
||||
/// Addon argument data for Finalize events.
|
||||
/// Addon argument data for OnRequestedUpdate events.
|
||||
/// </summary>
|
||||
public class AddonRequestedUpdateArgs : AddonArgs
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
namespace Dalamud.Game.Addon.Lifecycle.AddonArgTypes;
|
||||
|
||||
/// <summary>
|
||||
/// Addon argument data for Finalize events.
|
||||
/// Addon argument data for Update events.
|
||||
/// </summary>
|
||||
public class AddonUpdateArgs : AddonArgs
|
||||
{
|
||||
|
|
|
|||
|
|
@ -34,4 +34,9 @@ public enum AddonArgsType
|
|||
/// Contains argument data for Refresh.
|
||||
/// </summary>
|
||||
Refresh,
|
||||
|
||||
/// <summary>
|
||||
/// Contains argument data for ReceiveEvent.
|
||||
/// </summary>
|
||||
ReceiveEvent,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,4 +59,14 @@ public enum AddonEvent
|
|||
/// Event that is fired after an addon has finished a refresh.
|
||||
/// </summary>
|
||||
PostRefresh,
|
||||
|
||||
/// <summary>
|
||||
/// Event that is fired before an addon begins processing an event.
|
||||
/// </summary>
|
||||
PreReceiveEvent,
|
||||
|
||||
/// <summary>
|
||||
/// Event that is fired after an addon has processed an event.
|
||||
/// </summary>
|
||||
PostReceiveEvent,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ using Dalamud.Hooking.Internal;
|
|||
using Dalamud.IoC;
|
||||
using Dalamud.IoC.Internal;
|
||||
using Dalamud.Logging.Internal;
|
||||
using Dalamud.Memory;
|
||||
using Dalamud.Plugin.Services;
|
||||
using FFXIVClientStructs.FFXIV.Component.GUI;
|
||||
|
||||
|
|
@ -38,6 +39,8 @@ internal unsafe class AddonLifecycle : IDisposable, IServiceType
|
|||
private readonly ConcurrentBag<AddonLifecycleEventListener> removeEventListeners = new();
|
||||
private readonly List<AddonLifecycleEventListener> eventListeners = new();
|
||||
|
||||
private readonly Dictionary<string, Hook<AddonReceiveEventDelegate>> receiveEventHooks = new();
|
||||
|
||||
[ServiceManager.ServiceConstructor]
|
||||
private AddonLifecycle(TargetSigScanner sigScanner)
|
||||
{
|
||||
|
|
@ -67,6 +70,8 @@ internal unsafe class AddonLifecycle : IDisposable, IServiceType
|
|||
|
||||
private delegate byte AddonOnRefreshDelegate(AtkUnitManager* unitManager, AtkUnitBase* addon, uint valueCount, AtkValue* values);
|
||||
|
||||
private delegate void AddonReceiveEventDelegate(AtkUnitBase* addon, AtkEventType eventType, int eventParam, AtkEvent* atkEvent, nint a5);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Dispose()
|
||||
{
|
||||
|
|
@ -79,6 +84,11 @@ internal unsafe class AddonLifecycle : IDisposable, IServiceType
|
|||
this.onAddonUpdateHook.Dispose();
|
||||
this.onAddonRefreshHook.Dispose();
|
||||
this.onAddonRequestedUpdateHook.Dispose();
|
||||
|
||||
foreach (var (_, hook) in this.receiveEventHooks)
|
||||
{
|
||||
hook.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -104,7 +114,21 @@ internal unsafe class AddonLifecycle : IDisposable, IServiceType
|
|||
{
|
||||
if (this.newEventListeners.Any())
|
||||
{
|
||||
this.eventListeners.AddRange(this.newEventListeners);
|
||||
foreach (var toAddListener in this.newEventListeners)
|
||||
{
|
||||
this.eventListeners.Add(toAddListener);
|
||||
|
||||
// If we want receive event messages have an already active addon, enable the receive event hook.
|
||||
// If the addon isn't active yet, we'll grab the hook when it sets up.
|
||||
if (toAddListener is { EventType: AddonEvent.PreReceiveEvent or AddonEvent.PostReceiveEvent })
|
||||
{
|
||||
if (this.receiveEventHooks.TryGetValue(toAddListener.AddonName, out var hook))
|
||||
{
|
||||
hook.Enable();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.newEventListeners.Clear();
|
||||
}
|
||||
|
||||
|
|
@ -142,6 +166,23 @@ internal unsafe class AddonLifecycle : IDisposable, IServiceType
|
|||
|
||||
private void OnAddonSetup(AtkUnitBase* addon, uint valueCount, AtkValue* values)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Hook the addon's ReceiveEvent function here, but only enable the hook if we have an active listener.
|
||||
var addonName = MemoryHelper.ReadStringNullTerminated((nint)addon->Name);
|
||||
var receiveEventHook = Hook<AddonReceiveEventDelegate>.FromAddress((nint)addon->VTable->ReceiveEvent, this.OnReceiveEvent);
|
||||
this.receiveEventHooks.TryAdd(addonName, receiveEventHook);
|
||||
|
||||
if (this.eventListeners.Any(listener => listener.EventType is AddonEvent.PostReceiveEvent or AddonEvent.PreReceiveEvent))
|
||||
{
|
||||
receiveEventHook.Enable();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e, "Exception in OnAddonSetup ReceiveEvent Registration.");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
this.InvokeListeners(AddonEvent.PreSetup, new AddonSetupArgs
|
||||
|
|
@ -175,6 +216,21 @@ internal unsafe class AddonLifecycle : IDisposable, IServiceType
|
|||
|
||||
private void OnAddonFinalize(AtkUnitManager* unitManager, AtkUnitBase** atkUnitBase)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Remove this addons ReceiveEvent Registration
|
||||
var addonName = MemoryHelper.ReadStringNullTerminated((nint)atkUnitBase[0]->Name);
|
||||
if (this.receiveEventHooks.TryGetValue(addonName, out var hook))
|
||||
{
|
||||
hook.Dispose();
|
||||
this.receiveEventHooks.Remove(addonName);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e, "Exception in OnAddonFinalize ReceiveEvent Removal.");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
this.InvokeListeners(AddonEvent.PreFinalize, new AddonFinalizeArgs { Addon = (nint)atkUnitBase[0] });
|
||||
|
|
@ -300,6 +356,44 @@ internal unsafe class AddonLifecycle : IDisposable, IServiceType
|
|||
Log.Error(e, "Exception in OnRequestedUpdate post-requestedUpdate invoke.");
|
||||
}
|
||||
}
|
||||
|
||||
private void OnReceiveEvent(AtkUnitBase* addon, AtkEventType eventType, int eventParam, AtkEvent* atkEvent, nint data)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.InvokeListeners(AddonEvent.PreReceiveEvent, new AddonReceiveEventArgs
|
||||
{
|
||||
Addon = (nint)addon,
|
||||
AtkEventType = (byte)eventType,
|
||||
EventParam = eventParam,
|
||||
AtkEvent = (nint)atkEvent,
|
||||
Data = data,
|
||||
});
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e, "Exception in OnReceiveEvent pre-receiveEvent invoke.");
|
||||
}
|
||||
|
||||
var addonName = MemoryHelper.ReadStringNullTerminated((nint)addon->Name);
|
||||
this.receiveEventHooks[addonName].Original(addon, eventType, eventParam, atkEvent, data);
|
||||
|
||||
try
|
||||
{
|
||||
this.InvokeListeners(AddonEvent.PostReceiveEvent, new AddonReceiveEventArgs
|
||||
{
|
||||
Addon = (nint)addon,
|
||||
AtkEventType = (byte)eventType,
|
||||
EventParam = eventParam,
|
||||
AtkEvent = (nint)atkEvent,
|
||||
Data = data,
|
||||
});
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error(e, "Exception in OnAddonRefresh post-receiveEvent invoke.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue