diff --git a/Dalamud/Game/AddonLifecycle/AddonArgTypes/AddonArgs.cs b/Dalamud/Game/AddonLifecycle/AddonArgTypes/AddonArgs.cs
new file mode 100644
index 000000000..949d3fde9
--- /dev/null
+++ b/Dalamud/Game/AddonLifecycle/AddonArgTypes/AddonArgs.cs
@@ -0,0 +1,46 @@
+using Dalamud.Memory;
+using FFXIVClientStructs.FFXIV.Component.GUI;
+
+namespace Dalamud.Game.Addon;
+
+///
+/// Base class for AddonLifecycle AddonArgTypes.
+///
+public abstract unsafe class AddonArgs
+{
+ ///
+ /// Constant string representing the name of an addon that is invalid.
+ ///
+ public const string InvalidAddon = "NullAddon";
+
+ private string? addonName;
+
+ ///
+ /// Gets the name of the addon this args referrers to.
+ ///
+ public string AddonName => this.GetAddonName();
+
+ ///
+ /// Gets the pointer to the addons AtkUnitBase.
+ ///
+ public nint Addon { get; init; }
+
+ ///
+ /// Gets the type of these args.
+ ///
+ public abstract AddonArgsType Type { get; }
+
+ ///
+ /// Helper method for ensuring the name of the addon is valid.
+ ///
+ /// The name of the addon for this object. when invalid.
+ private string GetAddonName()
+ {
+ if (this.Addon == nint.Zero) return InvalidAddon;
+
+ var addonPointer = (AtkUnitBase*)this.Addon;
+ if (addonPointer->Name is null) return InvalidAddon;
+
+ return this.addonName ??= MemoryHelper.ReadString((nint)addonPointer->Name, 0x20);
+ }
+}
diff --git a/Dalamud/Game/AddonLifecycle/AddonArgTypes/AddonDrawArgs.cs b/Dalamud/Game/AddonLifecycle/AddonArgTypes/AddonDrawArgs.cs
new file mode 100644
index 000000000..d93001d1c
--- /dev/null
+++ b/Dalamud/Game/AddonLifecycle/AddonArgTypes/AddonDrawArgs.cs
@@ -0,0 +1,10 @@
+namespace Dalamud.Game.Addon;
+
+///
+/// Addon argument data for Finalize events.
+///
+public class AddonDrawArgs : AddonArgs
+{
+ ///
+ public override AddonArgsType Type => AddonArgsType.Draw;
+}
diff --git a/Dalamud/Game/AddonLifecycle/AddonArgTypes/AddonFinalizeArgs.cs b/Dalamud/Game/AddonLifecycle/AddonArgTypes/AddonFinalizeArgs.cs
new file mode 100644
index 000000000..ed7aa1b3c
--- /dev/null
+++ b/Dalamud/Game/AddonLifecycle/AddonArgTypes/AddonFinalizeArgs.cs
@@ -0,0 +1,10 @@
+namespace Dalamud.Game.Addon;
+
+///
+/// Addon argument data for Finalize events.
+///
+public class AddonFinalizeArgs : AddonArgs
+{
+ ///
+ public override AddonArgsType Type => AddonArgsType.Finalize;
+}
diff --git a/Dalamud/Game/AddonLifecycle/AddonArgTypes/AddonRefreshArgs.cs b/Dalamud/Game/AddonLifecycle/AddonArgTypes/AddonRefreshArgs.cs
new file mode 100644
index 000000000..60ccaf8ea
--- /dev/null
+++ b/Dalamud/Game/AddonLifecycle/AddonArgTypes/AddonRefreshArgs.cs
@@ -0,0 +1,28 @@
+using System;
+using FFXIVClientStructs.FFXIV.Component.GUI;
+
+namespace Dalamud.Game.Addon;
+
+///
+/// Addon argument data for Finalize events.
+///
+public class AddonRefreshArgs : AddonArgs
+{
+ ///
+ public override AddonArgsType Type => AddonArgsType.Refresh;
+
+ ///
+ /// Gets the number of AtkValues.
+ ///
+ public uint AtkValueCount { get; init; }
+
+ ///
+ /// Gets the address of the AtkValue array.
+ ///
+ public nint AtkValues { get; init; }
+
+ ///
+ /// Gets the AtkValues in the form of a span.
+ ///
+ public unsafe Span AtkValueSpan => new(this.AtkValues.ToPointer(), (int)this.AtkValueCount);
+}
diff --git a/Dalamud/Game/AddonLifecycle/AddonArgTypes/AddonRequestedUpdateArgs.cs b/Dalamud/Game/AddonLifecycle/AddonArgTypes/AddonRequestedUpdateArgs.cs
new file mode 100644
index 000000000..a31369aaf
--- /dev/null
+++ b/Dalamud/Game/AddonLifecycle/AddonArgTypes/AddonRequestedUpdateArgs.cs
@@ -0,0 +1,20 @@
+namespace Dalamud.Game.Addon;
+
+///
+/// Addon argument data for Finalize events.
+///
+public class AddonRequestedUpdateArgs : AddonArgs
+{
+ ///
+ public override AddonArgsType Type => AddonArgsType.RequestedUpdate;
+
+ ///
+ /// Gets the NumberArrayData** for this event.
+ ///
+ public nint NumberArrayData { get; init; }
+
+ ///
+ /// Gets the StringArrayData** for this event.
+ ///
+ public nint StringArrayData { get; init; }
+}
diff --git a/Dalamud/Game/AddonLifecycle/AddonArgTypes/AddonSetupArgs.cs b/Dalamud/Game/AddonLifecycle/AddonArgTypes/AddonSetupArgs.cs
new file mode 100644
index 000000000..17c87967a
--- /dev/null
+++ b/Dalamud/Game/AddonLifecycle/AddonArgTypes/AddonSetupArgs.cs
@@ -0,0 +1,29 @@
+using System;
+
+using FFXIVClientStructs.FFXIV.Component.GUI;
+
+namespace Dalamud.Game.Addon;
+
+///
+/// Addon argument data for Setup events.
+///
+public class AddonSetupArgs : AddonArgs
+{
+ ///
+ public override AddonArgsType Type => AddonArgsType.Setup;
+
+ ///
+ /// Gets the number of AtkValues.
+ ///
+ public uint AtkValueCount { get; init; }
+
+ ///
+ /// Gets the address of the AtkValue array.
+ ///
+ public nint AtkValues { get; init; }
+
+ ///
+ /// Gets the AtkValues in the form of a span.
+ ///
+ public unsafe Span AtkValueSpan => new(this.AtkValues.ToPointer(), (int)this.AtkValueCount);
+}
diff --git a/Dalamud/Game/AddonLifecycle/AddonArgTypes/AddonUpdateArgs.cs b/Dalamud/Game/AddonLifecycle/AddonArgTypes/AddonUpdateArgs.cs
new file mode 100644
index 000000000..993883d77
--- /dev/null
+++ b/Dalamud/Game/AddonLifecycle/AddonArgTypes/AddonUpdateArgs.cs
@@ -0,0 +1,15 @@
+namespace Dalamud.Game.Addon;
+
+///
+/// Addon argument data for Finalize events.
+///
+public class AddonUpdateArgs : AddonArgs
+{
+ ///
+ public override AddonArgsType Type => AddonArgsType.Update;
+
+ ///
+ /// Gets the time since the last update.
+ ///
+ public float TimeDelta { get; init; }
+}
diff --git a/Dalamud/Game/AddonLifecycle/AddonArgs.cs b/Dalamud/Game/AddonLifecycle/AddonArgs.cs
deleted file mode 100644
index 4ae306817..000000000
--- a/Dalamud/Game/AddonLifecycle/AddonArgs.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-using Dalamud.Memory;
-using FFXIVClientStructs.FFXIV.Component.GUI;
-
-namespace Dalamud.Game.Addon;
-
-///
-/// Addon argument data for use in event subscribers.
-///
-public unsafe class AddonArgs
-{
- private string? addonName;
-
- ///
- /// Gets the name of the addon this args referrers to.
- ///
- public string AddonName => this.Addon == nint.Zero ? "NullAddon" : this.addonName ??= MemoryHelper.ReadString((nint)((AtkUnitBase*)this.Addon)->Name, 0x20);
-
- ///
- /// Gets the pointer to the addons AtkUnitBase.
- ///
- required public nint Addon { get; init; }
-}
diff --git a/Dalamud/Game/AddonLifecycle/AddonArgsType.cs b/Dalamud/Game/AddonLifecycle/AddonArgsType.cs
new file mode 100644
index 000000000..8a07d445b
--- /dev/null
+++ b/Dalamud/Game/AddonLifecycle/AddonArgsType.cs
@@ -0,0 +1,37 @@
+namespace Dalamud.Game.Addon;
+
+///
+/// Enumeration for available AddonLifecycle arg data.
+///
+public enum AddonArgsType
+{
+ ///
+ /// Contains argument data for Setup.
+ ///
+ Setup,
+
+ ///
+ /// Contains argument data for Update.
+ ///
+ Update,
+
+ ///
+ /// Contains argument data for Draw.
+ ///
+ Draw,
+
+ ///
+ /// Contains argument data for Finalize.
+ ///
+ Finalize,
+
+ ///
+ /// Contains argument data for RequestedUpdate.
+ ///
+ RequestedUpdate,
+
+ ///
+ /// Contains argument data for Refresh.
+ ///
+ Refresh,
+}
diff --git a/Dalamud/Game/AddonLifecycle/AddonLifecycle.cs b/Dalamud/Game/AddonLifecycle/AddonLifecycle.cs
index 68233eeb8..17afbaeac 100644
--- a/Dalamud/Game/AddonLifecycle/AddonLifecycle.cs
+++ b/Dalamud/Game/AddonLifecycle/AddonLifecycle.cs
@@ -26,7 +26,7 @@ internal unsafe class AddonLifecycle : IDisposable, IServiceType
private readonly Framework framework = Service.Get();
private readonly AddonLifecycleAddressResolver address;
- private readonly Hook onAddonSetupHook;
+ private readonly CallHook onAddonSetupHook;
private readonly Hook onAddonFinalizeHook;
private readonly CallHook onAddonDrawHook;
private readonly CallHook onAddonUpdateHook;
@@ -45,7 +45,7 @@ private AddonLifecycle(SigScanner sigScanner)
this.framework.Update += this.OnFrameworkUpdate;
- this.onAddonSetupHook = Hook.FromAddress(this.address.AddonSetup, this.OnAddonSetup);
+ this.onAddonSetupHook = new CallHook(this.address.AddonSetup, this.OnAddonSetup);
this.onAddonFinalizeHook = Hook.FromAddress(this.address.AddonFinalize, this.OnAddonFinalize);
this.onAddonDrawHook = new CallHook(this.address.AddonDraw, this.OnAddonDraw);
this.onAddonUpdateHook = new CallHook(this.address.AddonUpdate, this.OnAddonUpdate);
@@ -53,7 +53,7 @@ private AddonLifecycle(SigScanner sigScanner)
this.onAddonRequestedUpdateHook = new CallHook(this.address.AddonOnRequestedUpdate, this.OnRequestedUpdate);
}
- private delegate nint AddonSetupDelegate(AtkUnitBase* addon);
+ private delegate void AddonSetupDelegate(AtkUnitBase* addon, uint valueCount, AtkValue* values);
private delegate void AddonFinalizeDelegate(AtkUnitManager* unitManager, AtkUnitBase** atkUnitBase);
@@ -136,36 +136,44 @@ private void InvokeListeners(AddonEvent eventType, AddonArgs args)
}
}
- private nint OnAddonSetup(AtkUnitBase* addon)
+ private void OnAddonSetup(AtkUnitBase* addon, uint valueCount, AtkValue* values)
{
try
{
- this.InvokeListeners(AddonEvent.PreSetup, new AddonArgs { Addon = (nint)addon });
+ this.InvokeListeners(AddonEvent.PreSetup, new AddonSetupArgs
+ {
+ Addon = (nint)addon,
+ AtkValueCount = valueCount,
+ AtkValues = (nint)values,
+ });
}
catch (Exception e)
{
Log.Error(e, "Exception in OnAddonSetup pre-setup invoke.");
}
- var result = this.onAddonSetupHook.Original(addon);
+ addon->OnSetup(valueCount, values);
try
{
- this.InvokeListeners(AddonEvent.PostSetup, new AddonArgs { Addon = (nint)addon });
+ this.InvokeListeners(AddonEvent.PostSetup, new AddonSetupArgs
+ {
+ Addon = (nint)addon,
+ AtkValueCount = valueCount,
+ AtkValues = (nint)values,
+ });
}
catch (Exception e)
{
Log.Error(e, "Exception in OnAddonSetup post-setup invoke.");
}
-
- return result;
}
private void OnAddonFinalize(AtkUnitManager* unitManager, AtkUnitBase** atkUnitBase)
{
try
{
- this.InvokeListeners(AddonEvent.PreFinalize, new AddonArgs { Addon = (nint)atkUnitBase[0] });
+ this.InvokeListeners(AddonEvent.PreFinalize, new AddonFinalizeArgs { Addon = (nint)atkUnitBase[0] });
}
catch (Exception e)
{
@@ -179,7 +187,7 @@ private void OnAddonDraw(AtkUnitBase* addon)
{
try
{
- this.InvokeListeners(AddonEvent.PreDraw, new AddonArgs { Addon = (nint)addon });
+ this.InvokeListeners(AddonEvent.PreDraw, new AddonDrawArgs { Addon = (nint)addon });
}
catch (Exception e)
{
@@ -190,7 +198,7 @@ private void OnAddonDraw(AtkUnitBase* addon)
try
{
- this.InvokeListeners(AddonEvent.PostDraw, new AddonArgs { Addon = (nint)addon });
+ this.InvokeListeners(AddonEvent.PostDraw, new AddonDrawArgs { Addon = (nint)addon });
}
catch (Exception e)
{
@@ -202,7 +210,7 @@ private void OnAddonUpdate(AtkUnitBase* addon, float delta)
{
try
{
- this.InvokeListeners(AddonEvent.PreUpdate, new AddonArgs { Addon = (nint)addon });
+ this.InvokeListeners(AddonEvent.PreUpdate, new AddonUpdateArgs { Addon = (nint)addon, TimeDelta = delta });
}
catch (Exception e)
{
@@ -213,7 +221,7 @@ private void OnAddonUpdate(AtkUnitBase* addon, float delta)
try
{
- this.InvokeListeners(AddonEvent.PostUpdate, new AddonArgs { Addon = (nint)addon });
+ this.InvokeListeners(AddonEvent.PostUpdate, new AddonUpdateArgs { Addon = (nint)addon, TimeDelta = delta });
}
catch (Exception e)
{
@@ -225,7 +233,12 @@ private byte OnAddonRefresh(AtkUnitManager* atkUnitManager, AtkUnitBase* addon,
{
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)
{
@@ -236,7 +249,12 @@ private byte OnAddonRefresh(AtkUnitManager* atkUnitManager, AtkUnitBase* addon,
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)
{
@@ -250,7 +268,12 @@ private void OnRequestedUpdate(AtkUnitBase* addon, NumberArrayData** numberArray
{
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)
{
@@ -261,7 +284,12 @@ private void OnRequestedUpdate(AtkUnitBase* addon, NumberArrayData** numberArray
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)
{
diff --git a/Dalamud/Game/AddonLifecycle/AddonLifecycleAddressResolver.cs b/Dalamud/Game/AddonLifecycle/AddonLifecycleAddressResolver.cs
index d68fee9ed..16fd54832 100644
--- a/Dalamud/Game/AddonLifecycle/AddonLifecycleAddressResolver.cs
+++ b/Dalamud/Game/AddonLifecycle/AddonLifecycleAddressResolver.cs
@@ -41,7 +41,7 @@ internal class AddonLifecycleAddressResolver : BaseAddressResolver
/// The signature scanner to facilitate setup.
protected override void Setup64Bit(SigScanner sig)
{
- this.AddonSetup = sig.ScanText("E8 ?? ?? ?? ?? 8B 83 ?? ?? ?? ?? C1 E8 14");
+ this.AddonSetup = sig.ScanText("FF 90 ?? ?? ?? ?? 48 8B 93 ?? ?? ?? ?? 80 8B");
this.AddonFinalize = sig.ScanText("E8 ?? ?? ?? ?? 48 8B 7C 24 ?? 41 8B C6");
this.AddonDraw = sig.ScanText("FF 90 ?? ?? ?? ?? 83 EB 01 79 C1");
this.AddonUpdate = sig.ScanText("FF 90 ?? ?? ?? ?? 40 88 AF");
diff --git a/Dalamud/Plugin/Services/IAddonLifecycle.cs b/Dalamud/Plugin/Services/IAddonLifecycle.cs
index e455754a1..2bc41a366 100644
--- a/Dalamud/Plugin/Services/IAddonLifecycle.cs
+++ b/Dalamud/Plugin/Services/IAddonLifecycle.cs
@@ -13,9 +13,9 @@ public interface IAddonLifecycle
///
/// Delegate for receiving addon lifecycle event messages.
///
- /// The event type that triggered the message.
- /// Information about what addon triggered the message.
- public delegate void AddonEventDelegate(AddonEvent eventType, AddonArgs addonInfo);
+ /// The event type that triggered the message.
+ /// Information about what addon triggered the message.
+ public delegate void AddonEventDelegate(AddonEvent type, AddonArgs args);
///
/// Register a listener that will trigger on the specified event and any of the specified addons.