From cf42b5e591b121dfeba28b27513124c9850d6cde Mon Sep 17 00:00:00 2001 From: Hondacrx Date: Mon, 19 Aug 2024 12:24:24 -0400 Subject: [PATCH] Core/Auras: Implemented OnHeartbeat AuraScript hook and refactored an aurascript to use it as example Port From (https://github.com/TrinityCore/TrinityCore/commit/55ce5b150f716b6d470af80a9c31adf78e4cc198) --- Source/Framework/Constants/ScriptsConst.cs | 1 + Source/Game/Entities/Unit/Unit.cs | 2 +- Source/Game/Scripting/SpellScript.cs | 20 +++++++++++++++++++- Source/Game/Spells/Auras/Aura.cs | 17 ++++++++++++++++- Source/Scripts/Spells/Item.cs | 17 ++++------------- 5 files changed, 41 insertions(+), 16 deletions(-) diff --git a/Source/Framework/Constants/ScriptsConst.cs b/Source/Framework/Constants/ScriptsConst.cs index 917a1ce32..455cf18b6 100644 --- a/Source/Framework/Constants/ScriptsConst.cs +++ b/Source/Framework/Constants/ScriptsConst.cs @@ -59,6 +59,7 @@ namespace Framework.Constants CheckAreaTarget, Dispel, AfterDispel, + OnHeartbeat, EnterLeaveCombat, // Spell Proc Hooks CheckProc, diff --git a/Source/Game/Entities/Unit/Unit.cs b/Source/Game/Entities/Unit/Unit.cs index eb8727b7f..fbdc928ec 100644 --- a/Source/Game/Entities/Unit/Unit.cs +++ b/Source/Game/Entities/Unit/Unit.cs @@ -2562,7 +2562,7 @@ namespace Game.Entities // SMSG_FLIGHT_SPLINE_SYNC for cyclic splines SendFlightSplineSyncUpdate(); - // Trigger heartbeat procs and generic aura behavior such as food emotes + // Trigger heartbeat procs and generic aura behavior such as food emotes and invoking aura script hooks TriggerAuraHeartbeat(); // Update Vignette position and visibility diff --git a/Source/Game/Scripting/SpellScript.cs b/Source/Game/Scripting/SpellScript.cs index d08753851..2d95b64c9 100644 --- a/Source/Game/Scripting/SpellScript.cs +++ b/Source/Game/Scripting/SpellScript.cs @@ -1094,6 +1094,7 @@ namespace Game.Scripting // DO NOT OVERRIDE THESE IN SCRIPTS public delegate bool AuraCheckAreaTargetDelegate(Unit target); public delegate void AuraDispelDelegate(DispelInfo dispelInfo); + public delegate void AuraHeartbeatDelegate(); public delegate void AuraEffectDamageAndHealingCalcFnType(AuraEffect aurEff, Unit victim, ref int damageOrHealing, ref int flatMod, ref float pctMod); public delegate void AuraEffectApplicationModeDelegate(AuraEffect aura, AuraEffectHandleModes auraMode); public delegate void AuraEffectPeriodicDelegate(AuraEffect aura); @@ -1135,6 +1136,18 @@ namespace Game.Scripting } } + public class AuraHeartbeatHandler + { + AuraHeartbeatDelegate _callImpl; + + public AuraHeartbeatHandler(AuraHeartbeatDelegate callImpl) { _callImpl = callImpl; } + + public void Call(AuraScript auraScript) + { + _callImpl(); + } + } + public class EffectBase : EffectHook { AuraType _effAurName; @@ -1264,7 +1277,7 @@ namespace Game.Scripting _callImpl(aurEff, victim, ref damageOrHealing, ref flatMod, ref pctMod); } } - + public class EffectApplyHandler : EffectBase { AuraEffectApplicationModeDelegate _callImpl; @@ -1601,6 +1614,11 @@ namespace Game.Scripting // where function is: void function (DispelInfo dispelInfo); public List AfterDispel = new(); + // executed on every heartbeat of a unit + // example: OnHeartbeat += AuraHeartbeatFn(class::function); + // where function is: void function (); + public List OnHeartbeat = new(); + // executed when aura effect is applied with specified mode to target // should be used 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); diff --git a/Source/Game/Spells/Auras/Aura.cs b/Source/Game/Spells/Auras/Aura.cs index cb0c534bf..7df7dc9a8 100644 --- a/Source/Game/Spells/Auras/Aura.cs +++ b/Source/Game/Spells/Auras/Aura.cs @@ -1986,6 +1986,18 @@ namespace Game.Spells } } + public void CallScriptOnHeartbeat() + { + foreach (var script in m_loadedScripts) + { + script._PrepareScriptCall(AuraScriptHookType.OnHeartbeat); + foreach (var onHeartbeat in script.OnHeartbeat) + onHeartbeat.Call(script); + + script._FinishScriptCall(); + } + } + public bool CallScriptEffectApplyHandlers(AuraEffect aurEff, AuraApplication aurApp, AuraEffectHandleModes mode) { bool preventDefault = false; @@ -2865,12 +2877,15 @@ namespace Game.Spells _staticApplications[target.GetGUID()] |= effMask; } - void Heartbeat() + public override void Heartbeat() { base.Heartbeat(); // Periodic food and drink emote animation HandlePeriodicFoodSpellVisualKit(); + + // Invoke the OnHeartbeat AuraScript hook + CallScriptOnHeartbeat(); } void HandlePeriodicFoodSpellVisualKit() diff --git a/Source/Scripts/Spells/Item.cs b/Source/Scripts/Spells/Item.cs index 242d763e8..6cf221907 100644 --- a/Source/Scripts/Spells/Item.cs +++ b/Source/Scripts/Spells/Item.cs @@ -3883,17 +3883,9 @@ namespace Scripts.Spells.Azerite return ValidateSpellInfo(SpellFragileEchoesMonk, SpellFragileEchoesShaman, SpellFragileEchoesPriestDiscipline, SpellFragileEchoesPaladin, SpellFragileEchoesDruid, SpellFragileEchoesPriestHoly); } - void ForcePeriodic(AuraEffect aurEff, ref bool isPeriodic, ref int amplitude) + void UpdateSpecAura() { - // simulate heartbeat timer - isPeriodic = true; - amplitude = 5000; - } - - void UpdateSpecAura(AuraEffect aurEff) - { - PreventDefaultAction(); - Player target = GetTarget().ToPlayer(); + Player target = GetUnitOwner().ToPlayer(); if (target == null) return; @@ -3902,7 +3894,7 @@ namespace Scripts.Spells.Azerite if (target.GetPrimarySpecialization() != spec) target.RemoveAurasDueToSpell(aura); else if (!target.HasAura(aura)) - target.CastSpell(target, aura, aurEff); + target.CastSpell(target, aura, GetEffect(0)); } switch (target.GetClass()) @@ -3930,8 +3922,7 @@ namespace Scripts.Spells.Azerite public override void Register() { - DoEffectCalcPeriodic.Add(new(ForcePeriodic, 0, AuraType.Dummy)); - OnEffectPeriodic.Add(new(UpdateSpecAura, 0, AuraType.Dummy)); + OnHeartbeat.Add(new(UpdateSpecAura)); } }