mirror of
https://github.com/goatcorp/Dalamud.git
synced 2026-01-02 05:43:40 +01:00
Include argument data in event information.
This commit is contained in:
parent
dc54f040b9
commit
0636a03e41
14 changed files with 209 additions and 45 deletions
|
|
@ -160,7 +160,7 @@ internal unsafe class AddonEventManager : IDisposable, IServiceType
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="eventType">Event type that triggered this call.</param>
|
/// <param name="eventType">Event type that triggered this call.</param>
|
||||||
/// <param name="addonInfo">Addon that triggered this call.</param>
|
/// <param name="addonInfo">Addon that triggered this call.</param>
|
||||||
private void OnAddonFinalize(AddonEvent eventType, AddonArgs addonInfo)
|
private void OnAddonFinalize(AddonEvent eventType, IAddonArgs addonInfo)
|
||||||
{
|
{
|
||||||
// It shouldn't be possible for this event to be anything other than PreFinalize.
|
// It shouldn't be possible for this event to be anything other than PreFinalize.
|
||||||
if (eventType != AddonEvent.PreFinalize) return;
|
if (eventType != AddonEvent.PreFinalize) return;
|
||||||
|
|
|
||||||
13
Dalamud/Game/AddonLifecycle/AddonArgTypes/AddonDrawArgs.cs
Normal file
13
Dalamud/Game/AddonLifecycle/AddonArgTypes/AddonDrawArgs.cs
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
namespace Dalamud.Game.Addon.AddonArgTypes;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Addon argument data for Finalize events.
|
||||||
|
/// </summary>
|
||||||
|
public class AddonDrawArgs : IAddonArgs
|
||||||
|
{
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public nint Addon { get; init; }
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public AddonArgsType Type => AddonArgsType.Draw;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
namespace Dalamud.Game.Addon.AddonArgTypes;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Addon argument data for Finalize events.
|
||||||
|
/// </summary>
|
||||||
|
public class AddonFinalizeArgs : IAddonArgs
|
||||||
|
{
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public nint Addon { get; init; }
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public AddonArgsType Type => AddonArgsType.Finalize;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
namespace Dalamud.Game.Addon.AddonArgTypes;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Addon argument data for Finalize events.
|
||||||
|
/// </summary>
|
||||||
|
public class AddonRefreshArgs : IAddonArgs
|
||||||
|
{
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public nint Addon { get; init; }
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public AddonArgsType Type => AddonArgsType.Refresh;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the number of AtkValues.
|
||||||
|
/// </summary>
|
||||||
|
public uint AtkValueCount { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the address of the AtkValue array.
|
||||||
|
/// </summary>
|
||||||
|
public nint AtkValues { get; init; }
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
namespace Dalamud.Game.Addon.AddonArgTypes;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Addon argument data for Finalize events.
|
||||||
|
/// </summary>
|
||||||
|
public class AddonRequestedUpdateArgs : IAddonArgs
|
||||||
|
{
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public nint Addon { get; init; }
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public AddonArgsType Type => AddonArgsType.RequestedUpdate;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the NumberArrayData** for this event.
|
||||||
|
/// </summary>
|
||||||
|
public nint NumberArrayData { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the StringArrayData** for this event.
|
||||||
|
/// </summary>
|
||||||
|
public nint StringArrayData { get; init; }
|
||||||
|
}
|
||||||
13
Dalamud/Game/AddonLifecycle/AddonArgTypes/AddonSetupArgs.cs
Normal file
13
Dalamud/Game/AddonLifecycle/AddonArgTypes/AddonSetupArgs.cs
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
namespace Dalamud.Game.Addon.AddonArgTypes;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Addon argument data for Setup events.
|
||||||
|
/// </summary>
|
||||||
|
public class AddonSetupArgs : IAddonArgs
|
||||||
|
{
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public nint Addon { get; init; }
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public AddonArgsType Type => AddonArgsType.Setup;
|
||||||
|
}
|
||||||
18
Dalamud/Game/AddonLifecycle/AddonArgTypes/AddonUpdateArgs.cs
Normal file
18
Dalamud/Game/AddonLifecycle/AddonArgTypes/AddonUpdateArgs.cs
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
namespace Dalamud.Game.Addon.AddonArgTypes;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Addon argument data for Finalize events.
|
||||||
|
/// </summary>
|
||||||
|
public class AddonUpdateArgs : IAddonArgs
|
||||||
|
{
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public nint Addon { get; init; }
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public AddonArgsType Type => AddonArgsType.Update;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the time since the last update.
|
||||||
|
/// </summary>
|
||||||
|
public float TimeDelta { get; init; }
|
||||||
|
}
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
using Dalamud.Memory;
|
|
||||||
using FFXIVClientStructs.FFXIV.Component.GUI;
|
|
||||||
|
|
||||||
namespace Dalamud.Game.Addon;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Addon argument data for use in event subscribers.
|
|
||||||
/// </summary>
|
|
||||||
public unsafe class AddonArgs
|
|
||||||
{
|
|
||||||
private string? addonName;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the name of the addon this args referrers to.
|
|
||||||
/// </summary>
|
|
||||||
public string AddonName => this.Addon == nint.Zero ? "NullAddon" : this.addonName ??= MemoryHelper.ReadString((nint)((AtkUnitBase*)this.Addon)->Name, 0x20);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the pointer to the addons AtkUnitBase.
|
|
||||||
/// </summary>
|
|
||||||
required public nint Addon { get; init; }
|
|
||||||
}
|
|
||||||
37
Dalamud/Game/AddonLifecycle/AddonArgsType.cs
Normal file
37
Dalamud/Game/AddonLifecycle/AddonArgsType.cs
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
namespace Dalamud.Game.Addon;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Enumeration for available AddonLifecycle arg data
|
||||||
|
/// </summary>
|
||||||
|
public enum AddonArgsType
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Contains argument data for Setup.
|
||||||
|
/// </summary>
|
||||||
|
Setup,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Contains argument data for Update.
|
||||||
|
/// </summary>
|
||||||
|
Update,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Contains argument data for Draw.
|
||||||
|
/// </summary>
|
||||||
|
Draw,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Contains argument data for Finalize.
|
||||||
|
/// </summary>
|
||||||
|
Finalize,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Contains argument data for RequestedUpdate.
|
||||||
|
/// </summary>
|
||||||
|
RequestedUpdate,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Contains argument data for Refresh.
|
||||||
|
/// </summary>
|
||||||
|
Refresh,
|
||||||
|
}
|
||||||
|
|
@ -3,6 +3,7 @@ using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
|
using Dalamud.Game.Addon.AddonArgTypes;
|
||||||
using Dalamud.Hooking;
|
using Dalamud.Hooking;
|
||||||
using Dalamud.Hooking.Internal;
|
using Dalamud.Hooking.Internal;
|
||||||
using Dalamud.IoC;
|
using Dalamud.IoC;
|
||||||
|
|
@ -127,7 +128,7 @@ internal unsafe class AddonLifecycle : IDisposable, IServiceType
|
||||||
this.onAddonRequestedUpdateHook.Enable();
|
this.onAddonRequestedUpdateHook.Enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InvokeListeners(AddonEvent eventType, AddonArgs args)
|
private void InvokeListeners(AddonEvent eventType, IAddonArgs args)
|
||||||
{
|
{
|
||||||
// Match on string.empty for listeners that want events for all addons.
|
// Match on string.empty for listeners that want events for all addons.
|
||||||
foreach (var listener in this.eventListeners.Where(listener => listener.EventType == eventType && (listener.AddonName == args.AddonName || listener.AddonName == string.Empty)))
|
foreach (var listener in this.eventListeners.Where(listener => listener.EventType == eventType && (listener.AddonName == args.AddonName || listener.AddonName == string.Empty)))
|
||||||
|
|
@ -140,7 +141,7 @@ internal unsafe class AddonLifecycle : IDisposable, IServiceType
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
this.InvokeListeners(AddonEvent.PreSetup, new AddonArgs { Addon = (nint)addon });
|
this.InvokeListeners(AddonEvent.PreSetup, new AddonSetupArgs { Addon = (nint)addon });
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
|
@ -151,7 +152,7 @@ internal unsafe class AddonLifecycle : IDisposable, IServiceType
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
this.InvokeListeners(AddonEvent.PostSetup, new AddonArgs { Addon = (nint)addon });
|
this.InvokeListeners(AddonEvent.PostSetup, new AddonSetupArgs { Addon = (nint)addon });
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
|
@ -165,7 +166,7 @@ internal unsafe class AddonLifecycle : IDisposable, IServiceType
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
this.InvokeListeners(AddonEvent.PreFinalize, new AddonArgs { Addon = (nint)atkUnitBase[0] });
|
this.InvokeListeners(AddonEvent.PreFinalize, new AddonFinalizeArgs { Addon = (nint)atkUnitBase[0] });
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
|
@ -179,7 +180,7 @@ internal unsafe class AddonLifecycle : IDisposable, IServiceType
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
this.InvokeListeners(AddonEvent.PreDraw, new AddonArgs { Addon = (nint)addon });
|
this.InvokeListeners(AddonEvent.PreDraw, new AddonDrawArgs { Addon = (nint)addon });
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
|
@ -190,7 +191,7 @@ internal unsafe class AddonLifecycle : IDisposable, IServiceType
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
this.InvokeListeners(AddonEvent.PostDraw, new AddonArgs { Addon = (nint)addon });
|
this.InvokeListeners(AddonEvent.PostDraw, new AddonDrawArgs { Addon = (nint)addon });
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
|
@ -202,7 +203,7 @@ internal unsafe class AddonLifecycle : IDisposable, IServiceType
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
this.InvokeListeners(AddonEvent.PreUpdate, new AddonArgs { Addon = (nint)addon });
|
this.InvokeListeners(AddonEvent.PreUpdate, new AddonUpdateArgs { Addon = (nint)addon, TimeDelta = delta });
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
|
@ -213,7 +214,7 @@ internal unsafe class AddonLifecycle : IDisposable, IServiceType
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
this.InvokeListeners(AddonEvent.PostUpdate, new AddonArgs { Addon = (nint)addon });
|
this.InvokeListeners(AddonEvent.PostUpdate, new AddonUpdateArgs { Addon = (nint)addon, TimeDelta = delta });
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
|
@ -225,7 +226,12 @@ internal unsafe class AddonLifecycle : IDisposable, IServiceType
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
this.InvokeListeners(AddonEvent.PreRefresh, new AddonArgs { Addon = (nint)addon });
|
this.InvokeListeners(AddonEvent.PreRefresh, new AddonRefreshArgs
|
||||||
|
{
|
||||||
|
Addon = (nint)addon,
|
||||||
|
AtkValueCount = valueCount,
|
||||||
|
AtkValues = (nint)values,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
|
@ -236,7 +242,12 @@ internal unsafe class AddonLifecycle : IDisposable, IServiceType
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
this.InvokeListeners(AddonEvent.PostRefresh, new AddonArgs { Addon = (nint)addon });
|
this.InvokeListeners(AddonEvent.PostRefresh, new AddonRefreshArgs
|
||||||
|
{
|
||||||
|
Addon = (nint)addon,
|
||||||
|
AtkValueCount = valueCount,
|
||||||
|
AtkValues = (nint)values,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
|
@ -250,7 +261,12 @@ internal unsafe class AddonLifecycle : IDisposable, IServiceType
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
this.InvokeListeners(AddonEvent.PreRequestedUpdate, new AddonArgs { Addon = (nint)addon });
|
this.InvokeListeners(AddonEvent.PreRequestedUpdate, new AddonRequestedUpdateArgs
|
||||||
|
{
|
||||||
|
Addon = (nint)addon,
|
||||||
|
NumberArrayData = (nint)numberArrayData,
|
||||||
|
StringArrayData = (nint)stringArrayData,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
|
@ -261,7 +277,12 @@ internal unsafe class AddonLifecycle : IDisposable, IServiceType
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
this.InvokeListeners(AddonEvent.PostRequestedUpdate, new AddonArgs { Addon = (nint)addon });
|
this.InvokeListeners(AddonEvent.PostRequestedUpdate, new AddonRequestedUpdateArgs
|
||||||
|
{
|
||||||
|
Addon = (nint)addon,
|
||||||
|
NumberArrayData = (nint)numberArrayData,
|
||||||
|
StringArrayData = (nint)stringArrayData,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
25
Dalamud/Game/AddonLifecycle/IAddonArgs.cs
Normal file
25
Dalamud/Game/AddonLifecycle/IAddonArgs.cs
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
using Dalamud.Memory;
|
||||||
|
using FFXIVClientStructs.FFXIV.Component.GUI;
|
||||||
|
|
||||||
|
namespace Dalamud.Game.Addon;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Interface representing the argument data for AddonLifecycle events.
|
||||||
|
/// </summary>
|
||||||
|
public unsafe interface IAddonArgs
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the name of the addon this args referrers to.
|
||||||
|
/// </summary>
|
||||||
|
string AddonName => this.Addon == nint.Zero ? "NullAddon" : MemoryHelper.ReadString((nint)((AtkUnitBase*)this.Addon)->Name, 0x20);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the pointer to the addons AtkUnitBase.
|
||||||
|
/// </summary>
|
||||||
|
nint Addon { get; init; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the type of these args.
|
||||||
|
/// </summary>
|
||||||
|
AddonArgsType Type { get; }
|
||||||
|
}
|
||||||
|
|
@ -255,7 +255,7 @@ public sealed unsafe class DtrBar : IDisposable, IServiceType, IDtrBar
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnDtrPostDraw(AddonEvent eventType, AddonArgs addonInfo)
|
private void OnDtrPostDraw(AddonEvent eventType, IAddonArgs addonInfo)
|
||||||
{
|
{
|
||||||
var addon = (AtkUnitBase*)addonInfo.Addon;
|
var addon = (AtkUnitBase*)addonInfo.Addon;
|
||||||
|
|
||||||
|
|
@ -300,7 +300,7 @@ public sealed unsafe class DtrBar : IDisposable, IServiceType, IDtrBar
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnAddonRequestedUpdateDetour(AddonEvent eventType, AddonArgs addonInfo)
|
private void OnAddonRequestedUpdateDetour(AddonEvent eventType, IAddonArgs addonInfo)
|
||||||
{
|
{
|
||||||
var addon = (AtkUnitBase*)addonInfo.Addon;
|
var addon = (AtkUnitBase*)addonInfo.Addon;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -100,32 +100,32 @@ internal class AddonLifecycleAgingStep : IAgingStep
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PostSetup(AddonEvent eventType, AddonArgs addonInfo)
|
private void PostSetup(AddonEvent eventType, IAddonArgs addonInfo)
|
||||||
{
|
{
|
||||||
if (this.currentStep is TestStep.CharacterSetup) this.currentStep++;
|
if (this.currentStep is TestStep.CharacterSetup) this.currentStep++;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PostUpdate(AddonEvent eventType, AddonArgs addonInfo)
|
private void PostUpdate(AddonEvent eventType, IAddonArgs addonInfo)
|
||||||
{
|
{
|
||||||
if (this.currentStep is TestStep.CharacterUpdate) this.currentStep++;
|
if (this.currentStep is TestStep.CharacterUpdate) this.currentStep++;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PostDraw(AddonEvent eventType, AddonArgs addonInfo)
|
private void PostDraw(AddonEvent eventType, IAddonArgs addonInfo)
|
||||||
{
|
{
|
||||||
if (this.currentStep is TestStep.CharacterDraw) this.currentStep++;
|
if (this.currentStep is TestStep.CharacterDraw) this.currentStep++;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PostRefresh(AddonEvent eventType, AddonArgs addonInfo)
|
private void PostRefresh(AddonEvent eventType, IAddonArgs addonInfo)
|
||||||
{
|
{
|
||||||
if (this.currentStep is TestStep.CharacterRefresh) this.currentStep++;
|
if (this.currentStep is TestStep.CharacterRefresh) this.currentStep++;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PostRequestedUpdate(AddonEvent eventType, AddonArgs addonInfo)
|
private void PostRequestedUpdate(AddonEvent eventType, IAddonArgs addonInfo)
|
||||||
{
|
{
|
||||||
if (this.currentStep is TestStep.CharacterRequestedUpdate) this.currentStep++;
|
if (this.currentStep is TestStep.CharacterRequestedUpdate) this.currentStep++;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void PreFinalize(AddonEvent eventType, AddonArgs addonInfo)
|
private void PreFinalize(AddonEvent eventType, IAddonArgs addonInfo)
|
||||||
{
|
{
|
||||||
if (this.currentStep is TestStep.CharacterFinalize) this.currentStep++;
|
if (this.currentStep is TestStep.CharacterFinalize) this.currentStep++;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,8 @@ public interface IAddonLifecycle
|
||||||
/// Delegate for receiving addon lifecycle event messages.
|
/// Delegate for receiving addon lifecycle event messages.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="eventType">The event type that triggered the message.</param>
|
/// <param name="eventType">The event type that triggered the message.</param>
|
||||||
/// <param name="addonInfo">Information about what addon triggered the message.</param>
|
/// <param name="args">Information about what addon triggered the message.</param>
|
||||||
public delegate void AddonEventDelegate(AddonEvent eventType, AddonArgs addonInfo);
|
public delegate void AddonEventDelegate(AddonEvent eventType, IAddonArgs args);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Register a listener that will trigger on the specified event and any of the specified addons.
|
/// Register a listener that will trigger on the specified event and any of the specified addons.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue