aboutsummaryrefslogtreecommitdiff
path: root/src/server/game/Spells/SpellScript.h
diff options
context:
space:
mode:
authorOvahlord <dreadkiller@gmx.de>2024-04-27 19:04:10 +0200
committerOvahlord <dreadkiller@gmx.de>2024-05-28 16:45:30 +0200
commitcbc6aed4375d4f06cd22a1a86dfe1cd9913cde5e (patch)
tree1722fee4a870da4753cf6e620b17dbb731d51e8f /src/server/game/Spells/SpellScript.h
parent4de67994030ce9248324b1a86effa6bded506f40 (diff)
Core/Auras: Implemented OnHeartbeat AuraScript hook and refactored an aurascript to use it as example (#29945)
* Updated Amalgam's Seventh Spine dummy aura script to use the new AuraScript hook (cherry picked from commit 55ce5b150f716b6d470af80a9c31adf78e4cc198)
Diffstat (limited to 'src/server/game/Spells/SpellScript.h')
-rw-r--r--src/server/game/Spells/SpellScript.h59
1 files changed, 59 insertions, 0 deletions
diff --git a/src/server/game/Spells/SpellScript.h b/src/server/game/Spells/SpellScript.h
index abe0608b45a..9c28dd10d7d 100644
--- a/src/server/game/Spells/SpellScript.h
+++ b/src/server/game/Spells/SpellScript.h
@@ -1048,6 +1048,7 @@ enum AuraScriptHookType
AURA_SCRIPT_HOOK_CHECK_AREA_TARGET,
AURA_SCRIPT_HOOK_DISPEL,
AURA_SCRIPT_HOOK_AFTER_DISPEL,
+ AURA_SCRIPT_HOOK_ON_HEARTBEAT,
AURA_SCRIPT_HOOK_ENTER_LEAVE_COMBAT,
// Spell Proc Hooks
AURA_SCRIPT_HOOK_CHECK_PROC,
@@ -1174,6 +1175,58 @@ public:
SafeWrapperType _safeWrapper;
};
+ class AuraHeartbeatHandler final
+ {
+ public:
+ union AuraHeartbeatFnType
+ {
+ void(AuraScript::* Member)();
+ void(*Static)();
+ };
+
+ using SafeWrapperType = void(*)(AuraScript* auraScript, AuraHeartbeatFnType callImpl);
+
+ template<typename ScriptFunc>
+ explicit AuraHeartbeatHandler(ScriptFunc handler)
+ {
+ using ScriptClass = GetScriptClass_t<ScriptFunc>;
+
+ static_assert(sizeof(AuraHeartbeatFnType) >= sizeof(ScriptFunc));
+ static_assert(alignof(AuraHeartbeatFnType) >= alignof(ScriptFunc));
+
+ if constexpr (!std::is_void_v<ScriptClass>)
+ {
+ static_assert(std::is_invocable_r_v<void, ScriptFunc, ScriptClass>,
+ "AuraHeartbeat signature must be \"void HandleHeartbeat()\"");
+
+ _callImpl = { .Member = reinterpret_cast<decltype(AuraHeartbeatFnType::Member)>(handler) };
+ _safeWrapper = [](AuraScript* auraScript, AuraHeartbeatFnType callImpl) -> void
+ {
+ return (static_cast<ScriptClass*>(auraScript)->*reinterpret_cast<ScriptFunc>(callImpl.Member))();
+ };
+ }
+ else
+ {
+ static_assert(std::is_invocable_r_v<void, ScriptFunc>,
+ "AuraHeartbeatHandler signature must be \"static void HandleHeartbeat()\"");
+
+ _callImpl = { .Static = reinterpret_cast<decltype(AuraHeartbeatFnType::Static)>(handler) };
+ _safeWrapper = [](AuraScript* /*auraScript*/, AuraHeartbeatFnType callImpl) -> void
+ {
+ return reinterpret_cast<ScriptFunc>(callImpl.Static)();
+ };
+ }
+ }
+
+ void Call(AuraScript* auraScript) const
+ {
+ return _safeWrapper(auraScript, _callImpl);
+ }
+ private:
+ AuraHeartbeatFnType _callImpl;
+ SafeWrapperType _safeWrapper;
+ };
+
class TC_GAME_API EffectBase : public EffectHook
{
public:
@@ -2017,6 +2070,12 @@ public:
HookList<AuraDispelHandler> AfterDispel;
#define AuraDispelFn(F) AuraDispelHandler(&F)
+ // executed on every heartbeat of a unit
+ // example: OnHeartbeat += AuraHeartbeatFn(class::function);
+ // where function is: void function ();
+ HookList<AuraHeartbeatHandler> OnHeartbeat;
+ #define AuraHeartbeatFn(F) AuraHeartbeatHandler(&F)
+
// executed when aura effect is applied with specified mode to target
// should be used when when effect handler preventing/replacing is needed, do not use this hook for triggering spellcasts/removing auras etc - may be unsafe
// example: OnEffectApply += AuraEffectApplyFn(class::function, EffectIndexSpecifier, EffectAuraNameSpecifier, AuraEffectHandleModes);