From e54b09a3c5c132ac2989cbf682bf4a35b82d0064 Mon Sep 17 00:00:00 2001
From: MidoriKami <9083275+MidoriKami@users.noreply.github.com>
Date: Thu, 7 Sep 2023 12:24:45 -0700
Subject: [PATCH] Add Addon.OnRefresh
---
Dalamud/Game/AddonLifecycle/AddonEvent.cs | 10 ++++++
Dalamud/Game/AddonLifecycle/AddonLifecycle.cs | 31 ++++++++++++++++++-
.../AddonLifecycleAddressResolver.cs | 6 ++++
3 files changed, 46 insertions(+), 1 deletion(-)
diff --git a/Dalamud/Game/AddonLifecycle/AddonEvent.cs b/Dalamud/Game/AddonLifecycle/AddonEvent.cs
index 30121d162..faef30c88 100644
--- a/Dalamud/Game/AddonLifecycle/AddonEvent.cs
+++ b/Dalamud/Game/AddonLifecycle/AddonEvent.cs
@@ -49,4 +49,14 @@ public enum AddonEvent
/// Event that is fired after an addon finishes a requested update.
///
PostRequestedUpdate,
+
+ ///
+ /// Event that is fired before an addon begins a refresh.
+ ///
+ PreRefresh,
+
+ ///
+ /// Event that is fired after an addon has finished a refresh.
+ ///
+ PostRefresh,
}
diff --git a/Dalamud/Game/AddonLifecycle/AddonLifecycle.cs b/Dalamud/Game/AddonLifecycle/AddonLifecycle.cs
index 9bc792f46..d6da18dd5 100644
--- a/Dalamud/Game/AddonLifecycle/AddonLifecycle.cs
+++ b/Dalamud/Game/AddonLifecycle/AddonLifecycle.cs
@@ -30,6 +30,7 @@ internal unsafe class AddonLifecycle : IDisposable, IServiceType
private readonly Hook onAddonFinalizeHook;
private readonly CallHook onAddonDrawHook;
private readonly CallHook onAddonUpdateHook;
+ private readonly Hook onAddonRefreshHook;
// private readonly CallHook onAddonRequestedUpdateHook; // See Note in Ctor
private readonly ConcurrentBag newEventListeners = new();
@@ -48,6 +49,7 @@ internal unsafe class AddonLifecycle : IDisposable, IServiceType
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);
+ this.onAddonRefreshHook = Hook.FromAddress(this.address.AddonOnRefresh, this.OnAddonRefresh);
// todo: reenable this. WARNING: This hook overwrites a system that SimpleTweaks uses, causing SimpleTweaks to report exceptions.
// this.onAddonRequestedUpdateHook = new CallHook(this.address.AddonOnRequestedUpdate, this.OnRequestedUpdate);
@@ -61,7 +63,9 @@ internal unsafe class AddonLifecycle : IDisposable, IServiceType
private delegate void AddonUpdateDelegate(AtkUnitBase* addon, float delta);
- private delegate void AddonOnRequestedUpdate(AtkUnitBase* addon, NumberArrayData** numberArrayData, StringArrayData** stringArrayData);
+ private delegate void AddonOnRequestedUpdateDelegate(AtkUnitBase* addon, NumberArrayData** numberArrayData, StringArrayData** stringArrayData);
+
+ private delegate void AddonOnRefreshDelegate(AtkUnitManager* unitManager, AtkUnitBase* addon, uint valueCount, AtkValue* values);
///
public void Dispose()
@@ -72,6 +76,7 @@ internal unsafe class AddonLifecycle : IDisposable, IServiceType
this.onAddonFinalizeHook.Dispose();
this.onAddonDrawHook.Dispose();
this.onAddonUpdateHook.Dispose();
+ this.onAddonRefreshHook.Dispose();
// this.onAddonRequestedUpdateHook.Dispose(); // See Note in Ctor
}
@@ -120,6 +125,7 @@ internal unsafe class AddonLifecycle : IDisposable, IServiceType
this.onAddonFinalizeHook.Enable();
this.onAddonDrawHook.Enable();
this.onAddonUpdateHook.Enable();
+ this.onAddonRefreshHook.Enable();
// this.onAddonRequestedUpdateHook.Enable(); // See Note in Ctor
}
@@ -226,6 +232,29 @@ internal unsafe class AddonLifecycle : IDisposable, IServiceType
}
}
+ private void OnAddonRefresh(AtkUnitManager* atkUnitManager, AtkUnitBase* addon, uint valueCount, AtkValue* values)
+ {
+ try
+ {
+ this.InvokeListeners(AddonEvent.PreRefresh, new IAddonLifecycle.AddonArgs { Addon = (nint)addon });
+ }
+ catch (Exception e)
+ {
+ Log.Error(e, "Exception in OnAddonRefresh pre-refresh invoke.");
+ }
+
+ this.onAddonRefreshHook.Original(atkUnitManager, addon, valueCount, values);
+
+ try
+ {
+ this.InvokeListeners(AddonEvent.PostRefresh, new IAddonLifecycle.AddonArgs { Addon = (nint)addon });
+ }
+ catch (Exception e)
+ {
+ Log.Error(e, "Exception in OnAddonRefresh post-refresh invoke.");
+ }
+ }
+
private void OnRequestedUpdate(AtkUnitBase* addon, NumberArrayData** numberArrayData, StringArrayData** stringArrayData)
{
try
diff --git a/Dalamud/Game/AddonLifecycle/AddonLifecycleAddressResolver.cs b/Dalamud/Game/AddonLifecycle/AddonLifecycleAddressResolver.cs
index 557cedc34..079e09c80 100644
--- a/Dalamud/Game/AddonLifecycle/AddonLifecycleAddressResolver.cs
+++ b/Dalamud/Game/AddonLifecycle/AddonLifecycleAddressResolver.cs
@@ -29,6 +29,11 @@ internal class AddonLifecycleAddressResolver : BaseAddressResolver
/// Gets the address of the addon onRequestedUpdate hook invoked by virtual function call.
///
public nint AddonOnRequestedUpdate { get; private set; }
+
+ ///
+ /// Gets the address of AtkUnitManager_vf10 which triggers addon onRefresh.
+ ///
+ public nint AddonOnRefresh { get; private set; }
///
/// Scan for and setup any configured address pointers.
@@ -41,5 +46,6 @@ internal class AddonLifecycleAddressResolver : BaseAddressResolver
this.AddonDraw = sig.ScanText("FF 90 ?? ?? ?? ?? 83 EB 01 79 C1");
this.AddonUpdate = sig.ScanText("FF 90 ?? ?? ?? ?? 40 88 AF");
this.AddonOnRequestedUpdate = sig.ScanText("FF 90 90 01 00 00 48 8B 5C 24 30 48 83 C4 20");
+ this.AddonOnRefresh = sig.ScanText("48 89 5C 24 08 57 48 83 EC 20 41 8B F8 48 8B DA");
}
}