diff options
author | Shauren <shauren.trinity@gmail.com> | 2023-07-27 19:37:57 +0200 |
---|---|---|
committer | Shauren <shauren.trinity@gmail.com> | 2023-07-27 19:37:57 +0200 |
commit | 46b67ec20555d86340407926ad69979475b8668e (patch) | |
tree | d80682561fe694444de0f09c65e98e5b40527f30 | |
parent | f94e341a0314bc956726e11dfb435e09b7ee696f (diff) |
Core/Scripts: Fixed unsafe function pointer type casting in spell scripts
-rw-r--r-- | src/server/game/Spells/Auras/SpellAuras.cpp | 8 | ||||
-rw-r--r-- | src/server/game/Spells/SpellScript.cpp | 436 | ||||
-rw-r--r-- | src/server/game/Spells/SpellScript.h | 1322 | ||||
-rw-r--r-- | src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp | 2 | ||||
-rw-r--r-- | src/server/scripts/Spells/spell_shaman.cpp | 2 |
5 files changed, 980 insertions, 790 deletions
diff --git a/src/server/game/Spells/Auras/SpellAuras.cpp b/src/server/game/Spells/Auras/SpellAuras.cpp index 03c7eac2081..100ab9e4de7 100644 --- a/src/server/game/Spells/Auras/SpellAuras.cpp +++ b/src/server/game/Spells/Auras/SpellAuras.cpp @@ -2060,7 +2060,7 @@ bool Aura::CallScriptEffectApplyHandlers(AuraEffect const* aurEff, AuraApplicati { script->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_APPLY, aurApp); for (AuraScript::EffectApplyHandler const& onEffectApply : script->OnEffectApply) - if (onEffectApply.IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()) && onEffectApply.GetMode() & mode) + if (onEffectApply.IsEffectAffected(m_spellInfo, aurEff->GetEffIndex())) onEffectApply.Call(script, aurEff, mode); if (!preventDefault) @@ -2079,7 +2079,7 @@ bool Aura::CallScriptEffectRemoveHandlers(AuraEffect const* aurEff, AuraApplicat { script->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_REMOVE, aurApp); for (AuraScript::EffectApplyHandler const& onEffectRemove : script->OnEffectRemove) - if (onEffectRemove.IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()) && onEffectRemove.GetMode() & mode) + if (onEffectRemove.IsEffectAffected(m_spellInfo, aurEff->GetEffIndex())) onEffectRemove.Call(script, aurEff, mode); if (!preventDefault) @@ -2096,7 +2096,7 @@ void Aura::CallScriptAfterEffectApplyHandlers(AuraEffect const* aurEff, AuraAppl { script->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_AFTER_APPLY, aurApp); for (AuraScript::EffectApplyHandler const& afterEffectApply : script->AfterEffectApply) - if (afterEffectApply.IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()) && afterEffectApply.GetMode() & mode) + if (afterEffectApply.IsEffectAffected(m_spellInfo, aurEff->GetEffIndex())) afterEffectApply.Call(script, aurEff, mode); script->_FinishScriptCall(); @@ -2109,7 +2109,7 @@ void Aura::CallScriptAfterEffectRemoveHandlers(AuraEffect const* aurEff, AuraApp { script->_PrepareScriptCall(AURA_SCRIPT_HOOK_EFFECT_AFTER_REMOVE, aurApp); for (AuraScript::EffectApplyHandler const& afterEffectRemove : script->AfterEffectRemove) - if (afterEffectRemove.IsEffectAffected(m_spellInfo, aurEff->GetEffIndex()) && afterEffectRemove.GetMode() & mode) + if (afterEffectRemove.IsEffectAffected(m_spellInfo, aurEff->GetEffIndex())) afterEffectRemove.Call(script, aurEff, mode); script->_FinishScriptCall(); diff --git a/src/server/game/Spells/SpellScript.cpp b/src/server/game/Spells/SpellScript.cpp index 50ca1ba5653..21fde125cbc 100644 --- a/src/server/game/Spells/SpellScript.cpp +++ b/src/server/game/Spells/SpellScript.cpp @@ -150,118 +150,36 @@ std::string SpellScriptBase::EffectHook::EffIndexToString() const return "Invalid Value"; } -namespace EffectNameCheck +SpellScript::EffectBase::EffectBase(uint8 effIndex, uint16 effName) + : EffectHook(effIndex), _effName(effName) { -bool Check(SpellInfo const* spellInfo, uint8 effIndex, uint16 effName) -{ - if (spellInfo->GetEffects().size() <= effIndex) - return false; - SpellEffectInfo const& spellEffectInfo = spellInfo->GetEffect(SpellEffIndex(effIndex)); - if (!spellEffectInfo.Effect && !effName) - return true; - if (!spellEffectInfo.Effect) - return false; - return (effName == SPELL_EFFECT_ANY) || (spellEffectInfo.Effect == effName); } -std::string ToString(uint16 effName) +SpellScript::EffectBase::EffectBase(EffectBase&& right) noexcept = default; +SpellScript::EffectBase& SpellScript::EffectBase::operator=(EffectBase&& right) noexcept = default; +SpellScript::EffectBase::~EffectBase() = default; + +std::string SpellScript::EffectBase::ToString() const { - switch (effName) + switch (_effName) { case SPELL_EFFECT_ANY: - return "SPELL_EFFECT_ANY"; + return Trinity::StringFormat("Index: {}, Effect: SPELL_EFFECT_ANY", EffIndexToString()); default: - return Trinity::ToString(effName); + return Trinity::StringFormat("Index: {}, Effect: SPELL_EFFECT_{}", EffIndexToString(), _effName); } } -}; - -SpellScript::CastHandler::CastHandler(SpellCastFnType callImpl) : _callImpl(callImpl) -{ -} - -SpellScript::CastHandler::CastHandler(CastHandler&& right) noexcept = default; -SpellScript::CastHandler& SpellScript::CastHandler::operator=(CastHandler&& right) noexcept = default; -SpellScript::CastHandler::~CastHandler() = default; - -void SpellScript::CastHandler::Call(SpellScript* spellScript) const -{ - (spellScript->*_callImpl)(); -} - -SpellScript::CheckCastHandler::CheckCastHandler(SpellCheckCastFnType callImpl) : _callImpl(callImpl) -{ -} - -SpellScript::CheckCastHandler::CheckCastHandler(CheckCastHandler&& right) noexcept = default; -SpellScript::CheckCastHandler& SpellScript::CheckCastHandler::operator=(CheckCastHandler&& right) noexcept = default; -SpellScript::CheckCastHandler::~CheckCastHandler() = default; - -SpellCastResult SpellScript::CheckCastHandler::Call(SpellScript* spellScript) const -{ - return (spellScript->*_callImpl)(); -} - -SpellScript::EffectHandler::EffectHandler(SpellEffectFnType callImpl, uint8 effIndex, uint16 effName) - : EffectHook(effIndex), _callImpl(callImpl), _effName(effName) -{ -} - -SpellScript::EffectHandler::EffectHandler(EffectHandler&& right) noexcept = default; -SpellScript::EffectHandler& SpellScript::EffectHandler::operator=(EffectHandler&& right) noexcept = default; -SpellScript::EffectHandler::~EffectHandler() = default; - -std::string SpellScript::EffectHandler::ToString() const -{ - return "Index: " + EffIndexToString() + " Name: " + EffectNameCheck::ToString(_effName); -} - -bool SpellScript::EffectHandler::CheckEffect(SpellInfo const* spellInfo, uint8 effIndex) const -{ - return EffectNameCheck::Check(spellInfo, effIndex, _effName); -} - -void SpellScript::EffectHandler::Call(SpellScript* spellScript, SpellEffIndex effIndex) const -{ - (spellScript->*_callImpl)(effIndex); -} - -SpellScript::BeforeHitHandler::BeforeHitHandler(SpellBeforeHitFnType callImpl) : _callImpl(callImpl) -{ -} - -SpellScript::BeforeHitHandler::BeforeHitHandler(BeforeHitHandler&& right) noexcept = default; -SpellScript::BeforeHitHandler& SpellScript::BeforeHitHandler::operator=(BeforeHitHandler&& right) noexcept = default; -SpellScript::BeforeHitHandler::~BeforeHitHandler() = default; - -void SpellScript::BeforeHitHandler::Call(SpellScript* spellScript, SpellMissInfo missInfo) const -{ - (spellScript->*_callImpl)(missInfo); -} -SpellScript::HitHandler::HitHandler(SpellHitFnType callImpl) : _callImpl(callImpl) -{ } - -SpellScript::HitHandler::HitHandler(HitHandler&& right) noexcept = default; -SpellScript::HitHandler& SpellScript::HitHandler::operator=(HitHandler&& right) noexcept = default; -SpellScript::HitHandler::~HitHandler() = default; - -void SpellScript::HitHandler::Call(SpellScript* spellScript) const -{ - (spellScript->*_callImpl)(); -} - -SpellScript::OnCalcCritChanceHandler::OnCalcCritChanceHandler(SpellOnCalcCritChanceFnType callImpl) : _callImpl(callImpl) -{ -} - -SpellScript::OnCalcCritChanceHandler::OnCalcCritChanceHandler(OnCalcCritChanceHandler&& right) noexcept = default; -SpellScript::OnCalcCritChanceHandler& SpellScript::OnCalcCritChanceHandler::operator=(OnCalcCritChanceHandler&& right) noexcept = default; -SpellScript::OnCalcCritChanceHandler::~OnCalcCritChanceHandler() = default; - -void SpellScript::OnCalcCritChanceHandler::Call(SpellScript* spellScript, Unit const* victim, float& critChance) const +bool SpellScript::EffectBase::CheckEffect(SpellInfo const* spellInfo, uint8 effIndex) const { - return (spellScript->*_callImpl)(victim, critChance); + if (spellInfo->GetEffects().size() <= effIndex) + return false; + SpellEffectInfo const& spellEffectInfo = spellInfo->GetEffect(SpellEffIndex(effIndex)); + if (!spellEffectInfo.Effect && !_effName) + return true; + if (!spellEffectInfo.Effect) + return false; + return (_effName == SPELL_EFFECT_ANY) || (spellEffectInfo.Effect == _effName); } SpellScript::TargetHook::TargetHook(uint8 effectIndex, uint16 targetType, bool area, bool dest) @@ -330,61 +248,6 @@ bool SpellScript::TargetHook::CheckEffect(SpellInfo const* spellInfo, uint8 effI return false; } -SpellScript::ObjectAreaTargetSelectHandler::ObjectAreaTargetSelectHandler(SpellObjectAreaTargetSelectFnType callImpl, uint8 effIndex, uint16 targetType) - : TargetHook(effIndex, targetType, true, false), _callImpl(callImpl) -{ -} - -SpellScript::ObjectAreaTargetSelectHandler::ObjectAreaTargetSelectHandler(ObjectAreaTargetSelectHandler&& right) noexcept = default; -SpellScript::ObjectAreaTargetSelectHandler& SpellScript::ObjectAreaTargetSelectHandler::operator=(ObjectAreaTargetSelectHandler&& right) noexcept = default; -SpellScript::ObjectAreaTargetSelectHandler::~ObjectAreaTargetSelectHandler() = default; - -void SpellScript::ObjectAreaTargetSelectHandler::Call(SpellScript* spellScript, std::list<WorldObject*>& targets) const -{ - (spellScript->*_callImpl)(targets); -} - -SpellScript::ObjectTargetSelectHandler::ObjectTargetSelectHandler(SpellObjectTargetSelectFnType callImpl, uint8 effIndex, uint16 targetType) - : TargetHook(effIndex, targetType, false, false), _callImpl(callImpl) -{ -} - -SpellScript::ObjectTargetSelectHandler::ObjectTargetSelectHandler(ObjectTargetSelectHandler&& right) noexcept = default; -SpellScript::ObjectTargetSelectHandler& SpellScript::ObjectTargetSelectHandler::operator=(ObjectTargetSelectHandler&& right) noexcept = default; -SpellScript::ObjectTargetSelectHandler::~ObjectTargetSelectHandler() = default; - -void SpellScript::ObjectTargetSelectHandler::Call(SpellScript* spellScript, WorldObject*& target) const -{ - (spellScript->*_callImpl)(target); -} - -SpellScript::DestinationTargetSelectHandler::DestinationTargetSelectHandler(SpellDestinationTargetSelectFnType callImpl, uint8 effIndex, uint16 targetType) - : TargetHook(effIndex, targetType, false, true), _callImpl(callImpl) -{ -} - -SpellScript::DestinationTargetSelectHandler::DestinationTargetSelectHandler(DestinationTargetSelectHandler&& right) noexcept = default; -SpellScript::DestinationTargetSelectHandler& SpellScript::DestinationTargetSelectHandler::operator=(DestinationTargetSelectHandler&& right) noexcept = default; -SpellScript::DestinationTargetSelectHandler::~DestinationTargetSelectHandler() = default; - -void SpellScript::DestinationTargetSelectHandler::Call(SpellScript* spellScript, SpellDestination& target) const -{ - (spellScript->*_callImpl)(target); -} - -SpellScript::OnCalculateResistAbsorbHandler::OnCalculateResistAbsorbHandler(SpellOnResistAbsorbCalculateFnType callImpl) : _callImpl(callImpl) -{ -} - -SpellScript::OnCalculateResistAbsorbHandler::OnCalculateResistAbsorbHandler(OnCalculateResistAbsorbHandler&& right) noexcept = default; -SpellScript::OnCalculateResistAbsorbHandler& SpellScript::OnCalculateResistAbsorbHandler::operator=(OnCalculateResistAbsorbHandler&& right) noexcept = default; -SpellScript::OnCalculateResistAbsorbHandler::~OnCalculateResistAbsorbHandler() = default; - -void SpellScript::OnCalculateResistAbsorbHandler::Call(SpellScript* spellScript, DamageInfo const& damageInfo, uint32& resistAmount, int32& absorbAmount) const -{ - (spellScript->*_callImpl)(damageInfo, resistAmount, absorbAmount); -} - SpellScript::SpellScript(): m_spell(nullptr), m_hitPreventEffectMask(0), m_hitPreventDefaultEffectMask(0) { } @@ -887,31 +750,6 @@ Difficulty SpellScript::GetCastDifficulty() const return m_spell->GetCastDifficulty(); } -namespace EffectAuraNameCheck -{ -bool Check(SpellInfo const* spellEntry, uint8 effIndex, uint16 auraType) -{ - if (spellEntry->GetEffects().size() <= effIndex) - return false; - SpellEffectInfo const& spellEffectInfo = spellEntry->GetEffect(SpellEffIndex(effIndex)); - if (!spellEffectInfo.ApplyAuraName && !auraType) - return true; - if (!spellEffectInfo.ApplyAuraName) - return false; - return (auraType == SPELL_AURA_ANY) || (spellEffectInfo.ApplyAuraName == auraType); -} - -std::string ToString(uint16 effAurName) -{ - switch (effAurName) - { - case SPELL_AURA_ANY: - return "SPELL_AURA_ANY"; - default: - return Trinity::ToString(effAurName); - } -} -} bool AuraScript::_Validate(SpellInfo const* entry) { @@ -1018,32 +856,6 @@ bool AuraScript::_Validate(SpellInfo const* entry) return SpellScriptBase::_Validate(entry); } -AuraScript::CheckAreaTargetHandler::CheckAreaTargetHandler(AuraCheckAreaTargetFnType callImpl) : _callImpl(callImpl) -{ -} - -AuraScript::CheckAreaTargetHandler::CheckAreaTargetHandler(CheckAreaTargetHandler&& right) noexcept = default; -AuraScript::CheckAreaTargetHandler& AuraScript::CheckAreaTargetHandler::operator=(CheckAreaTargetHandler&& right) noexcept = default; -AuraScript::CheckAreaTargetHandler::~CheckAreaTargetHandler() = default; - -bool AuraScript::CheckAreaTargetHandler::Call(AuraScript* auraScript, Unit* _target) const -{ - return (auraScript->*_callImpl)(_target); -} - -AuraScript::AuraDispelHandler::AuraDispelHandler(AuraDispelFnType callImpl) : _callImpl(callImpl) -{ -} - -AuraScript::AuraDispelHandler::AuraDispelHandler(AuraDispelHandler&& right) noexcept = default; -AuraScript::AuraDispelHandler& AuraScript::AuraDispelHandler::operator=(AuraDispelHandler&& right) noexcept = default; -AuraScript::AuraDispelHandler::~AuraDispelHandler() = default; - -void AuraScript::AuraDispelHandler::Call(AuraScript* auraScript, DispelInfo* dispelInfo) const -{ - (auraScript->*_callImpl)(dispelInfo); -} - AuraScript::EffectBase::EffectBase(uint8 effIndex, uint16 auraType) : EffectHook(effIndex), _auraType(auraType) { } @@ -1053,205 +865,25 @@ AuraScript::EffectBase::~EffectBase() = default; bool AuraScript::EffectBase::CheckEffect(SpellInfo const* spellInfo, uint8 effIndex) const { - return EffectAuraNameCheck::Check(spellInfo, effIndex, _auraType); + if (spellInfo->GetEffects().size() <= effIndex) + return false; + SpellEffectInfo const& spellEffectInfo = spellInfo->GetEffect(SpellEffIndex(effIndex)); + if (!spellEffectInfo.ApplyAuraName && !_auraType) + return true; + if (!spellEffectInfo.ApplyAuraName) + return false; + return (_auraType == SPELL_AURA_ANY) || (spellEffectInfo.ApplyAuraName == _auraType); } std::string AuraScript::EffectBase::ToString() const { - return "Index: " + EffIndexToString() + " AuraName: " + EffectAuraNameCheck::ToString(_auraType); -} - -AuraScript::EffectPeriodicHandler::EffectPeriodicHandler(AuraEffectPeriodicFnType callImpl, uint8 effIndex, uint16 auraType) - : EffectBase(effIndex, auraType), _callImpl(callImpl) -{ -} - -AuraScript::EffectPeriodicHandler::EffectPeriodicHandler(EffectPeriodicHandler&& right) noexcept = default; -AuraScript::EffectPeriodicHandler& AuraScript::EffectPeriodicHandler::operator=(EffectPeriodicHandler&& right) noexcept = default; -AuraScript::EffectPeriodicHandler::~EffectPeriodicHandler() = default; - -void AuraScript::EffectPeriodicHandler::Call(AuraScript* auraScript, AuraEffect const* aurEff) const -{ - (auraScript->*_callImpl)(aurEff); -} - -AuraScript::EffectUpdatePeriodicHandler::EffectUpdatePeriodicHandler(AuraEffectUpdatePeriodicFnType callImpl, uint8 effIndex, uint16 auraType) - : EffectBase(effIndex, auraType), _callImpl(callImpl) -{ -} - -AuraScript::EffectUpdatePeriodicHandler::EffectUpdatePeriodicHandler(EffectUpdatePeriodicHandler&& right) noexcept = default; -AuraScript::EffectUpdatePeriodicHandler& AuraScript::EffectUpdatePeriodicHandler::operator=(EffectUpdatePeriodicHandler&& right) noexcept = default; -AuraScript::EffectUpdatePeriodicHandler::~EffectUpdatePeriodicHandler() = default; - -void AuraScript::EffectUpdatePeriodicHandler::Call(AuraScript* auraScript, AuraEffect* aurEff) const -{ - (auraScript->*_callImpl)(aurEff); -} - -AuraScript::EffectCalcAmountHandler::EffectCalcAmountHandler(AuraEffectCalcAmountFnType callImpl, uint8 effIndex, uint16 auraType) - : EffectBase(effIndex, auraType), _callImpl(callImpl) -{ -} - -AuraScript::EffectCalcAmountHandler::EffectCalcAmountHandler(EffectCalcAmountHandler&& right) noexcept = default; -AuraScript::EffectCalcAmountHandler& AuraScript::EffectCalcAmountHandler::operator=(EffectCalcAmountHandler&& right) noexcept = default; -AuraScript::EffectCalcAmountHandler::~EffectCalcAmountHandler() = default; - -void AuraScript::EffectCalcAmountHandler::Call(AuraScript* auraScript, AuraEffect const* aurEff, int32& amount, bool& canBeRecalculated) const -{ - (auraScript->*_callImpl)(aurEff, amount, canBeRecalculated); -} - -AuraScript::EffectCalcPeriodicHandler::EffectCalcPeriodicHandler(AuraEffectCalcPeriodicFnType callImpl, uint8 effIndex, uint16 auraType) - : EffectBase(effIndex, auraType), _callImpl(callImpl) -{ -} - -AuraScript::EffectCalcPeriodicHandler::EffectCalcPeriodicHandler(EffectCalcPeriodicHandler&& right) noexcept = default; -AuraScript::EffectCalcPeriodicHandler& AuraScript::EffectCalcPeriodicHandler::operator=(EffectCalcPeriodicHandler&& right) noexcept = default; -AuraScript::EffectCalcPeriodicHandler::~EffectCalcPeriodicHandler() = default; - -void AuraScript::EffectCalcPeriodicHandler::Call(AuraScript* auraScript, AuraEffect const* aurEff, bool& isPeriodic, int32& periodicTimer) const -{ - (auraScript->*_callImpl)(aurEff, isPeriodic, periodicTimer); -} - -AuraScript::EffectCalcSpellModHandler::EffectCalcSpellModHandler(AuraEffectCalcSpellModFnType callImpl, uint8 effIndex, uint16 auraType) - : EffectBase(effIndex, auraType), _callImpl(callImpl) -{ -} - -AuraScript::EffectCalcSpellModHandler::EffectCalcSpellModHandler(EffectCalcSpellModHandler&& right) noexcept = default; -AuraScript::EffectCalcSpellModHandler& AuraScript::EffectCalcSpellModHandler::operator=(EffectCalcSpellModHandler&& right) noexcept = default; -AuraScript::EffectCalcSpellModHandler::~EffectCalcSpellModHandler() = default; - -void AuraScript::EffectCalcSpellModHandler::Call(AuraScript* auraScript, AuraEffect const* aurEff, SpellModifier*& spellMod) const -{ - (auraScript->*_callImpl)(aurEff, spellMod); -} - -AuraScript::EffectCalcCritChanceHandler::EffectCalcCritChanceHandler(AuraEffectCalcCritChanceFnType callImpl, uint8 effIndex, uint16 auraType) - : EffectBase(effIndex, auraType), _callImpl(callImpl) -{ -} - -AuraScript::EffectCalcCritChanceHandler::EffectCalcCritChanceHandler(EffectCalcCritChanceHandler&& right) noexcept = default; -AuraScript::EffectCalcCritChanceHandler& AuraScript::EffectCalcCritChanceHandler::operator=(EffectCalcCritChanceHandler&& right) noexcept = default; -AuraScript::EffectCalcCritChanceHandler::~EffectCalcCritChanceHandler() = default; - -void AuraScript::EffectCalcCritChanceHandler::Call(AuraScript* auraScript, AuraEffect const* aurEff, Unit const* victim, float& critChance) const -{ - (auraScript->*_callImpl)(aurEff, victim, critChance); -} - -AuraScript::EffectApplyHandler::EffectApplyHandler(AuraEffectApplicationModeFnType callImpl, uint8 effIndex, uint16 auraType, AuraEffectHandleModes mode) - : EffectBase(effIndex, auraType), _callImpl(callImpl), _mode(mode) -{ -} - -AuraScript::EffectApplyHandler::EffectApplyHandler(EffectApplyHandler&& right) noexcept = default; -AuraScript::EffectApplyHandler& AuraScript::EffectApplyHandler::operator=(EffectApplyHandler&& right) noexcept = default; -AuraScript::EffectApplyHandler::~EffectApplyHandler() = default; - -void AuraScript::EffectApplyHandler::Call(AuraScript* auraScript, AuraEffect const* aurEff, AuraEffectHandleModes mode) const -{ - (auraScript->*_callImpl)(aurEff, mode); -} - -AuraScript::EffectAbsorbHandler::EffectAbsorbHandler(AuraEffectAbsorbFnType callImpl, uint8 effIndex, uint16 auraType) - : EffectBase(effIndex, auraType), _callImpl(callImpl) -{ -} - -AuraScript::EffectAbsorbHandler::EffectAbsorbHandler(EffectAbsorbHandler&& right) noexcept = default; -AuraScript::EffectAbsorbHandler& AuraScript::EffectAbsorbHandler::operator=(EffectAbsorbHandler&& right) noexcept = default; -AuraScript::EffectAbsorbHandler::~EffectAbsorbHandler() = default; - -void AuraScript::EffectAbsorbHandler::Call(AuraScript* auraScript, AuraEffect* aurEff, DamageInfo& dmgInfo, uint32& absorbAmount) const -{ - (auraScript->*_callImpl)(aurEff, dmgInfo, absorbAmount); -} - -AuraScript::EffectAbsorbHealHandler::EffectAbsorbHealHandler(AuraEffectAbsorbHealFnType callImpl, uint8 effIndex, uint16 auraType) - : EffectBase(effIndex, auraType), _callImpl(callImpl) -{ -} - -AuraScript::EffectAbsorbHealHandler::EffectAbsorbHealHandler(EffectAbsorbHealHandler&& right) noexcept = default; -AuraScript::EffectAbsorbHealHandler& AuraScript::EffectAbsorbHealHandler::operator=(EffectAbsorbHealHandler&& right) noexcept = default; -AuraScript::EffectAbsorbHealHandler::~EffectAbsorbHealHandler() = default; - -void AuraScript::EffectAbsorbHealHandler::Call(AuraScript* auraScript, AuraEffect* aurEff, HealInfo& healInfo, uint32& absorbAmount) const -{ - (auraScript->*_callImpl)(aurEff, healInfo, absorbAmount); -} - -AuraScript::CheckProcHandler::CheckProcHandler(AuraCheckProcFnType callImpl) : _callImpl(callImpl) -{ -} - -AuraScript::CheckProcHandler::CheckProcHandler(CheckProcHandler&& right) noexcept = default; -AuraScript::CheckProcHandler& AuraScript::CheckProcHandler::operator=(CheckProcHandler&& right) noexcept = default; -AuraScript::CheckProcHandler::~CheckProcHandler() = default; - -bool AuraScript::CheckProcHandler::Call(AuraScript* auraScript, ProcEventInfo& eventInfo) const -{ - return (auraScript->*_callImpl)(eventInfo); -} - -AuraScript::CheckEffectProcHandler::CheckEffectProcHandler(AuraCheckEffectProcFnType callImpl, uint8 effIndex, uint16 auraType) - : EffectBase(effIndex, auraType), _callImpl(callImpl) -{ -} - -AuraScript::CheckEffectProcHandler::CheckEffectProcHandler(CheckEffectProcHandler&& right) noexcept = default; -AuraScript::CheckEffectProcHandler& AuraScript::CheckEffectProcHandler::operator=(CheckEffectProcHandler&& right) noexcept = default; -AuraScript::CheckEffectProcHandler::~CheckEffectProcHandler() = default; - -bool AuraScript::CheckEffectProcHandler::Call(AuraScript* auraScript, AuraEffect const* aurEff, ProcEventInfo& eventInfo) const -{ - return (auraScript->*_callImpl)(aurEff, eventInfo); -} - -AuraScript::AuraProcHandler::AuraProcHandler(AuraProcFnType callImpl) : _callImpl(callImpl) -{ -} - -AuraScript::AuraProcHandler::AuraProcHandler(AuraProcHandler&& right) noexcept = default; -AuraScript::AuraProcHandler& AuraScript::AuraProcHandler::operator=(AuraProcHandler&& right) noexcept = default; -AuraScript::AuraProcHandler::~AuraProcHandler() = default; - -void AuraScript::AuraProcHandler::Call(AuraScript* auraScript, ProcEventInfo& eventInfo) const -{ - (auraScript->*_callImpl)(eventInfo); -} - -AuraScript::EffectProcHandler::EffectProcHandler(AuraEffectProcFnType callImpl, uint8 effIndex, uint16 auraType) - : EffectBase(effIndex, auraType), _callImpl(callImpl) -{ -} - -AuraScript::EffectProcHandler::EffectProcHandler(EffectProcHandler&& right) noexcept = default; -AuraScript::EffectProcHandler& AuraScript::EffectProcHandler::operator=(EffectProcHandler&& right) noexcept = default; -AuraScript::EffectProcHandler::~EffectProcHandler() = default; - -void AuraScript::EffectProcHandler::Call(AuraScript* auraScript, AuraEffect* aurEff, ProcEventInfo& eventInfo) const -{ - (auraScript->*_callImpl)(aurEff, eventInfo); -} - -AuraScript::EnterLeaveCombatHandler::EnterLeaveCombatHandler(AuraEnterLeaveCombatFnType callImpl) : _callImpl(callImpl) -{ -} - -AuraScript::EnterLeaveCombatHandler::EnterLeaveCombatHandler(EnterLeaveCombatHandler&& right) noexcept = default; -AuraScript::EnterLeaveCombatHandler& AuraScript::EnterLeaveCombatHandler::operator=(EnterLeaveCombatHandler&& right) noexcept = default; -AuraScript::EnterLeaveCombatHandler::~EnterLeaveCombatHandler() = default; - -void AuraScript::EnterLeaveCombatHandler::Call(AuraScript* auraScript, bool isNowInCombat) const -{ - (auraScript->*_callImpl)(isNowInCombat); + switch (_auraType) + { + case SPELL_AURA_ANY: + return Trinity::StringFormat("Index: {}, AuraName: SPELL_AURA_ANY", EffIndexToString()); + default: + return Trinity::StringFormat("Index: {}, AuraName: SPELL_AURA_{}", EffIndexToString(), _auraType); + } } AuraScript::AuraScript(): SpellScriptBase(), m_aura(nullptr), m_auraApplication(nullptr), m_defaultActionPrevented(false) diff --git a/src/server/game/Spells/SpellScript.h b/src/server/game/Spells/SpellScript.h index 5f7b7367d5e..651906e4e50 100644 --- a/src/server/game/Spells/SpellScript.h +++ b/src/server/game/Spells/SpellScript.h @@ -246,187 +246,268 @@ class TC_GAME_API SpellScript : public SpellScriptBase // internal use classes & functions // DO NOT OVERRIDE THESE IN SCRIPTS public: - class TC_GAME_API CastHandler + class CastHandler final { public: using SpellCastFnType = void(SpellScript::*)(); + using SafeWrapperType = void(*)(SpellScript* spellScript, SpellCastFnType callImpl); + template<typename ScriptFunc> - static CastHandler Create(ScriptFunc handler) + explicit CastHandler(ScriptFunc handler) { using ScriptClass = GetScriptClass_t<ScriptFunc>; static_assert(sizeof(SpellCastFnType) >= sizeof(ScriptFunc)); static_assert(alignof(SpellCastFnType) >= alignof(ScriptFunc)); + static_assert(std::is_invocable_v<ScriptFunc, ScriptClass> && std::is_same_v<std::invoke_result_t<ScriptFunc, ScriptClass>, void>, "CastHandler signature must be \"void HandleCast()\""); - return { reinterpret_cast<SpellCastFnType>(handler) }; + _callImpl = reinterpret_cast<SpellCastFnType>(handler); + _safeWrapper = [](SpellScript* spellScript, SpellCastFnType callImpl) + { + return (static_cast<ScriptClass*>(spellScript)->*reinterpret_cast<ScriptFunc>(callImpl))(); + }; } - CastHandler(SpellCastFnType callImpl); - CastHandler(CastHandler const& right) = delete; - CastHandler(CastHandler&& right) noexcept; - CastHandler& operator=(CastHandler const& right) = delete; - CastHandler& operator=(CastHandler&& right) noexcept; - ~CastHandler(); - void Call(SpellScript* spellScript) const; + void Call(SpellScript* spellScript) const + { + return _safeWrapper(spellScript, _callImpl); + } private: SpellCastFnType _callImpl; + SafeWrapperType _safeWrapper; }; - class TC_GAME_API CheckCastHandler + class CheckCastHandler final { public: - using SpellCheckCastFnType = SpellCastResult(SpellScript::*)(); + union SpellCheckCastFnType + { + SpellCastResult(SpellScript::* Member)(); + SpellCastResult(*Static)(); + }; + + using SafeWrapperType = SpellCastResult(*)(SpellScript* spellScript, SpellCheckCastFnType callImpl); template<typename ScriptFunc> - static CheckCastHandler Create(ScriptFunc handler) + explicit CheckCastHandler(ScriptFunc handler) { using ScriptClass = GetScriptClass_t<ScriptFunc>; static_assert(sizeof(SpellCheckCastFnType) >= sizeof(ScriptFunc)); static_assert(alignof(SpellCheckCastFnType) >= alignof(ScriptFunc)); - static_assert(std::is_invocable_v<ScriptFunc, ScriptClass> - && std::is_same_v<std::invoke_result_t<ScriptFunc, ScriptClass>, SpellCastResult>, - "CheckCastHandler signature must be \"SpellCastResult CheckCast()\""); - return { reinterpret_cast<SpellCheckCastFnType>(handler) }; + if constexpr (!std::is_void_v<ScriptClass>) + { + static_assert(std::is_invocable_v<ScriptFunc, ScriptClass> + && std::is_same_v<std::invoke_result_t<ScriptFunc, ScriptClass>, SpellCastResult>, + "CheckCastHandler signature must be \"SpellCastResult CheckCast()\""); + + _callImpl = { .Member = reinterpret_cast<decltype(SpellCheckCastFnType::Member)>(handler) }; + _safeWrapper = [](SpellScript* spellScript, SpellCheckCastFnType callImpl) + { + return (static_cast<ScriptClass*>(spellScript)->*reinterpret_cast<ScriptFunc>(callImpl.Member))(); + }; + } + else + { + static_assert(std::is_invocable_v<ScriptFunc> + && std::is_same_v<std::invoke_result_t<ScriptFunc>, SpellCastResult>, + "CheckCastHandler signature must be \"static SpellCastResult CheckCast()\""); + + _callImpl = { .Static = reinterpret_cast<decltype(SpellCheckCastFnType::Static)>(handler) }; + _safeWrapper = [](SpellScript* /*spellScript*/, SpellCheckCastFnType callImpl) + { + return reinterpret_cast<ScriptFunc>(callImpl.Static)(); + }; + } } - CheckCastHandler(SpellCheckCastFnType callImpl); - CheckCastHandler(CheckCastHandler const& right) = delete; - CheckCastHandler(CheckCastHandler&& right) noexcept; - CheckCastHandler& operator=(CheckCastHandler const& right) = delete; - CheckCastHandler& operator=(CheckCastHandler&& right) noexcept; - ~CheckCastHandler(); - SpellCastResult Call(SpellScript* spellScript) const; + SpellCastResult Call(SpellScript* spellScript) const + { + return _safeWrapper(spellScript, _callImpl); + } private: SpellCheckCastFnType _callImpl; + SafeWrapperType _safeWrapper; }; - class TC_GAME_API EffectHandler : public EffectHook + class TC_GAME_API EffectBase : public EffectHook { public: - using SpellEffectFnType = void(SpellScript::*)(SpellEffIndex); + EffectBase(uint8 effIndex, uint16 effName); + EffectBase(EffectBase const& right) = delete; + EffectBase(EffectBase&& right) noexcept; + EffectBase& operator=(EffectBase const& right) = delete; + EffectBase& operator=(EffectBase&& right) noexcept; + ~EffectBase(); + std::string ToString() const; + bool CheckEffect(SpellInfo const* spellInfo, uint8 effIndex) const override; + private: + uint16 _effName; + }; + + class EffectHandler final : public EffectBase + { + public: + using SpellEffectFnType = void(SpellScript::*)(SpellEffIndex effIndex); + + using SafeWrapperType = void(*)(SpellScript* spellScript, SpellEffIndex effIndex, SpellEffectFnType callImpl); template<typename ScriptFunc> - static EffectHandler Create(ScriptFunc handler, uint8 effIndex, uint16 effName) + explicit EffectHandler(ScriptFunc handler, uint8 effIndex, uint16 effName) + : EffectBase(effIndex, effName) { using ScriptClass = GetScriptClass_t<ScriptFunc>; static_assert(sizeof(SpellEffectFnType) >= sizeof(ScriptFunc)); static_assert(alignof(SpellEffectFnType) >= alignof(ScriptFunc)); + static_assert(std::is_invocable_v<ScriptFunc, ScriptClass, SpellEffIndex> && std::is_same_v<std::invoke_result_t<ScriptFunc, ScriptClass, SpellEffIndex>, void>, "EffectHandler signature must be \"void HandleEffect(SpellEffIndex effIndex)\""); - return { reinterpret_cast<SpellEffectFnType>(handler), effIndex, effName }; + _callImpl = reinterpret_cast<SpellEffectFnType>(handler); + _safeWrapper = [](SpellScript* spellScript, SpellEffIndex effIndex, SpellEffectFnType callImpl) + { + return (static_cast<ScriptClass*>(spellScript)->*reinterpret_cast<ScriptFunc>(callImpl))(effIndex); + }; } - EffectHandler(SpellEffectFnType callImpl, uint8 effIndex, uint16 effName); - EffectHandler(EffectHandler const& right) = delete; - EffectHandler(EffectHandler&& right) noexcept; - EffectHandler& operator=(EffectHandler const& right) = delete; - EffectHandler& operator=(EffectHandler&& right) noexcept; - ~EffectHandler(); - std::string ToString() const; - bool CheckEffect(SpellInfo const* spellInfo, uint8 effIndex) const override; - void Call(SpellScript* spellScript, SpellEffIndex effIndex) const; + void Call(SpellScript* spellScript, SpellEffIndex effIndex) const + { + return _safeWrapper(spellScript, effIndex, _callImpl); + } private: SpellEffectFnType _callImpl; - uint16 _effName; + SafeWrapperType _safeWrapper; }; - class TC_GAME_API BeforeHitHandler + class BeforeHitHandler final { public: using SpellBeforeHitFnType = void(SpellScript::*)(SpellMissInfo missInfo); + using SafeWrapperType = void(*)(SpellScript* spellScript, SpellMissInfo missInfo, SpellBeforeHitFnType callImpl); + template<typename ScriptFunc> - static BeforeHitHandler Create(ScriptFunc handler) + explicit BeforeHitHandler(ScriptFunc handler) { using ScriptClass = GetScriptClass_t<ScriptFunc>; static_assert(sizeof(SpellBeforeHitFnType) >= sizeof(ScriptFunc)); static_assert(alignof(SpellBeforeHitFnType) >= alignof(ScriptFunc)); + static_assert(std::is_invocable_v<ScriptFunc, ScriptClass, SpellMissInfo> && std::is_same_v<std::invoke_result_t<ScriptFunc, ScriptClass, SpellMissInfo>, void>, "BeforeHitHandler signature must be \"void HandleBeforeHit(SpellMissInfo missInfo)\""); - return { reinterpret_cast<SpellBeforeHitFnType>(handler) }; + _callImpl = reinterpret_cast<SpellBeforeHitFnType>(handler); + _safeWrapper = [](SpellScript* spellScript, SpellMissInfo missInfo, SpellBeforeHitFnType callImpl) + { + return (static_cast<ScriptClass*>(spellScript)->*reinterpret_cast<ScriptFunc>(callImpl))(missInfo); + }; } - BeforeHitHandler(SpellBeforeHitFnType callImpl); - BeforeHitHandler(BeforeHitHandler const& right) = delete; - BeforeHitHandler(BeforeHitHandler&& right) noexcept; - BeforeHitHandler& operator=(BeforeHitHandler const& right) = delete; - BeforeHitHandler& operator=(BeforeHitHandler&& right) noexcept; - ~BeforeHitHandler(); - void Call(SpellScript* spellScript, SpellMissInfo missInfo) const; + void Call(SpellScript* spellScript, SpellMissInfo missInfo) const + { + return _safeWrapper(spellScript, missInfo, _callImpl); + } private: SpellBeforeHitFnType _callImpl; + SafeWrapperType _safeWrapper; }; - class TC_GAME_API HitHandler + class HitHandler final { public: using SpellHitFnType = void(SpellScript::*)(); + using SafeWrapperType = void(*)(SpellScript* spellScript, SpellHitFnType callImpl); + template<typename ScriptFunc> - static HitHandler Create(ScriptFunc handler) + explicit HitHandler(ScriptFunc handler) { using ScriptClass = GetScriptClass_t<ScriptFunc>; static_assert(sizeof(SpellHitFnType) >= sizeof(ScriptFunc)); static_assert(alignof(SpellHitFnType) >= alignof(ScriptFunc)); + static_assert(std::is_invocable_v<ScriptFunc, ScriptClass> && std::is_same_v<std::invoke_result_t<ScriptFunc, ScriptClass>, void>, "HitHandler signature must be \"void HandleHit()\""); - return { reinterpret_cast<SpellHitFnType>(handler) }; + _callImpl = reinterpret_cast<SpellHitFnType>(handler); + _safeWrapper = [](SpellScript* spellScript, SpellHitFnType callImpl) + { + return (static_cast<ScriptClass*>(spellScript)->*reinterpret_cast<ScriptFunc>(callImpl))(); + }; } - HitHandler(SpellHitFnType callImpl); - HitHandler(HitHandler const& right) = delete; - HitHandler(HitHandler&& right) noexcept; - HitHandler& operator=(HitHandler const& right) = delete; - HitHandler& operator=(HitHandler&& right) noexcept; - virtual ~HitHandler(); - void Call(SpellScript* spellScript) const; + void Call(SpellScript* spellScript) const + { + return _safeWrapper(spellScript, _callImpl); + } private: SpellHitFnType _callImpl; + SafeWrapperType _safeWrapper; }; - class TC_GAME_API OnCalcCritChanceHandler + class OnCalcCritChanceHandler final { public: - using SpellOnCalcCritChanceFnType = void(SpellScript::*)(Unit const* victim, float& chance); + union SpellOnCalcCritChanceFnType + { + void(SpellScript::* Member)(Unit const* victim, float& critChance); + void(*Static)(Unit const* victim, float& critChance); + }; + + using SafeWrapperType = void(*)(SpellScript* spellScript, Unit const* victim, float& critChance, SpellOnCalcCritChanceFnType callImpl); template<typename ScriptFunc> - static OnCalcCritChanceHandler Create(ScriptFunc handler) + explicit OnCalcCritChanceHandler(ScriptFunc handler) { using ScriptClass = GetScriptClass_t<ScriptFunc>; static_assert(sizeof(SpellOnCalcCritChanceFnType) >= sizeof(ScriptFunc)); static_assert(alignof(SpellOnCalcCritChanceFnType) >= alignof(ScriptFunc)); - static_assert(std::is_invocable_v<ScriptFunc, ScriptClass, Unit const*, float&> - && std::is_same_v<std::invoke_result_t<ScriptFunc, ScriptClass, Unit const*, float&>, void>, - "OnCalcCritChanceHandler signature must be \"void CalcCritChance(Unit const* victim, float& critChance)\""); - return { reinterpret_cast<SpellOnCalcCritChanceFnType>(handler) }; + if constexpr (!std::is_void_v<ScriptClass>) + { + static_assert(std::is_invocable_v<ScriptFunc, ScriptClass, Unit const*, float&> + && std::is_same_v<std::invoke_result_t<ScriptFunc, ScriptClass, Unit const*, float&>, void>, + "OnCalcCritChanceHandler signature must be \"void CalcCritChance(Unit const* victim, float& critChance)\""); + + _callImpl = { .Member = reinterpret_cast<decltype(SpellOnCalcCritChanceFnType::Member)>(handler) }; + _safeWrapper = [](SpellScript* spellScript, Unit const* victim, float& critChance, SpellOnCalcCritChanceFnType callImpl) + { + return (static_cast<ScriptClass*>(spellScript)->*reinterpret_cast<ScriptFunc>(callImpl.Member))(victim, critChance); + }; + } + else + { + static_assert(std::is_invocable_v<ScriptFunc, Unit const*, float&> + && std::is_same_v<std::invoke_result_t<ScriptFunc, Unit const*, float&>, void>, + "OnCalcCritChanceHandler signature must be \"static void CalcCritChance(Unit const* victim, float& critChance)\""); + + _callImpl = { .Static = reinterpret_cast<decltype(SpellOnCalcCritChanceFnType::Static)>(handler) }; + _safeWrapper = [](SpellScript* /*spellScript*/, Unit const* victim, float& critChance, SpellOnCalcCritChanceFnType callImpl) + { + return reinterpret_cast<ScriptFunc>(callImpl.Static)(victim, critChance); + }; + } } - OnCalcCritChanceHandler(SpellOnCalcCritChanceFnType callImpl); - OnCalcCritChanceHandler(OnCalcCritChanceHandler const& right) = delete; - OnCalcCritChanceHandler(OnCalcCritChanceHandler&& right) noexcept; - OnCalcCritChanceHandler& operator=(OnCalcCritChanceHandler const& right) = delete; - OnCalcCritChanceHandler& operator=(OnCalcCritChanceHandler&& right) noexcept; - virtual ~OnCalcCritChanceHandler(); - void Call(SpellScript* spellScript, Unit const* victim, float& critChance) const; + void Call(SpellScript* spellScript, Unit const* victim, float& critChance) const + { + return _safeWrapper(spellScript, victim, critChance, _callImpl); + } private: SpellOnCalcCritChanceFnType _callImpl; + SafeWrapperType _safeWrapper; }; class TC_GAME_API TargetHook : public EffectHook @@ -447,128 +528,227 @@ public: bool _dest; }; - class TC_GAME_API ObjectAreaTargetSelectHandler : public TargetHook + class ObjectAreaTargetSelectHandler final : public TargetHook { public: - using SpellObjectAreaTargetSelectFnType = void(SpellScript::*)(std::list<WorldObject*>&); + union SpellObjectAreaTargetSelectFnType + { + void(SpellScript::* Member)(std::list<WorldObject*>& targets); + void(*Static)(std::list<WorldObject*>& targets); + }; + + using SafeWrapperType = void(*)(SpellScript* spellScript, std::list<WorldObject*>& targets, SpellObjectAreaTargetSelectFnType callImpl); template<typename ScriptFunc> - static ObjectAreaTargetSelectHandler Create(ScriptFunc handler, uint8 effIndex, uint16 targetType) + explicit ObjectAreaTargetSelectHandler(ScriptFunc handler, uint8 effIndex, uint16 targetType) + : TargetHook(effIndex, targetType, true, false) { using ScriptClass = GetScriptClass_t<ScriptFunc>; static_assert(sizeof(SpellObjectAreaTargetSelectFnType) >= sizeof(ScriptFunc)); static_assert(alignof(SpellObjectAreaTargetSelectFnType) >= alignof(ScriptFunc)); - static_assert(std::is_invocable_v<ScriptFunc, ScriptClass, std::list<WorldObject*>&> - && std::is_same_v<std::invoke_result_t<ScriptFunc, ScriptClass, std::list<WorldObject*>&>, void>, - "ObjectAreaTargetSelectHandler signature must be \"void SetTargets(std::list<WorldObject*>& targets)\""); - return { reinterpret_cast<SpellObjectAreaTargetSelectFnType>(handler), effIndex, targetType }; + if constexpr (!std::is_void_v<ScriptClass>) + { + static_assert(std::is_invocable_v<ScriptFunc, ScriptClass, std::list<WorldObject*>&> + && std::is_same_v<std::invoke_result_t<ScriptFunc, ScriptClass, std::list<WorldObject*>&>, void>, + "ObjectAreaTargetSelectHandler signature must be \"void SetTargets(std::list<WorldObject*>& targets)\""); + + _callImpl = { .Member = reinterpret_cast<decltype(SpellObjectAreaTargetSelectFnType::Member)>(handler) }; + _safeWrapper = [](SpellScript* spellScript, std::list<WorldObject*>& targets, SpellObjectAreaTargetSelectFnType callImpl) + { + return (static_cast<ScriptClass*>(spellScript)->*reinterpret_cast<ScriptFunc>(callImpl.Member))(targets); + }; + } + else + { + static_assert(std::is_invocable_v<ScriptFunc, std::list<WorldObject*>&> + && std::is_same_v<std::invoke_result_t<ScriptFunc, std::list<WorldObject*>&>, void>, + "ObjectAreaTargetSelectHandler signature must be \"static void SetTargets(std::list<WorldObject*>& targets)\""); + + _callImpl = { .Static = reinterpret_cast<decltype(SpellObjectAreaTargetSelectFnType::Static)>(handler) }; + _safeWrapper = [](SpellScript* /*spellScript*/, std::list<WorldObject*>& targets, SpellObjectAreaTargetSelectFnType callImpl) + { + return reinterpret_cast<ScriptFunc>(callImpl.Static)(targets); + }; + } } - ObjectAreaTargetSelectHandler(SpellObjectAreaTargetSelectFnType callImpl, uint8 effIndex, uint16 targetType); - ObjectAreaTargetSelectHandler(ObjectAreaTargetSelectHandler const& right) = delete; - ObjectAreaTargetSelectHandler(ObjectAreaTargetSelectHandler&& right) noexcept; - ObjectAreaTargetSelectHandler& operator=(ObjectAreaTargetSelectHandler const& right) = delete; - ObjectAreaTargetSelectHandler& operator=(ObjectAreaTargetSelectHandler&& right) noexcept; - ~ObjectAreaTargetSelectHandler(); - void Call(SpellScript* spellScript, std::list<WorldObject*>& targets) const; + void Call(SpellScript* spellScript, std::list<WorldObject*>& targets) const + { + return _safeWrapper(spellScript, targets, _callImpl); + } private: SpellObjectAreaTargetSelectFnType _callImpl; + SafeWrapperType _safeWrapper; }; - class TC_GAME_API ObjectTargetSelectHandler : public TargetHook + class ObjectTargetSelectHandler final : public TargetHook { public: - using SpellObjectTargetSelectFnType = void(SpellScript::*)(WorldObject*&); + union SpellObjectTargetSelectFnType + { + void(SpellScript::* Member)(WorldObject*& target); + void(*Static)(WorldObject*& target); + }; + + using SafeWrapperType = void(*)(SpellScript* spellScript, WorldObject*& target, SpellObjectTargetSelectFnType callImpl); template<typename ScriptFunc> - static ObjectTargetSelectHandler Create(ScriptFunc handler, uint8 effIndex, uint16 targetType) + explicit ObjectTargetSelectHandler(ScriptFunc handler, uint8 effIndex, uint16 targetType) + : TargetHook(effIndex, targetType, false, false) { using ScriptClass = GetScriptClass_t<ScriptFunc>; static_assert(sizeof(SpellObjectTargetSelectFnType) >= sizeof(ScriptFunc)); static_assert(alignof(SpellObjectTargetSelectFnType) >= alignof(ScriptFunc)); - static_assert(std::is_invocable_v<ScriptFunc, ScriptClass, WorldObject*&> - && std::is_same_v<std::invoke_result_t<ScriptFunc, ScriptClass, WorldObject*&>, void>, - "ObjectTargetSelectHandler signature must be \"void SetTarget(WorldObject*& target)\""); - return { reinterpret_cast<SpellObjectTargetSelectFnType>(handler), effIndex, targetType }; + if constexpr (!std::is_void_v<ScriptClass>) + { + static_assert(std::is_invocable_v<ScriptFunc, ScriptClass, WorldObject*&> + && std::is_same_v<std::invoke_result_t<ScriptFunc, ScriptClass, WorldObject*&>, void>, + "ObjectTargetSelectHandler signature must be \"void SetTarget(WorldObject*& target)\""); + + _callImpl = { .Member = reinterpret_cast<decltype(SpellObjectTargetSelectFnType::Member)>(handler) }; + _safeWrapper = [](SpellScript* spellScript, WorldObject*& target, SpellObjectTargetSelectFnType callImpl) + { + return (static_cast<ScriptClass*>(spellScript)->*reinterpret_cast<ScriptFunc>(callImpl.Member))(target); + }; + } + else + { + static_assert(std::is_invocable_v<ScriptFunc, WorldObject*&> + && std::is_same_v<std::invoke_result_t<ScriptFunc, WorldObject*&>, void>, + "ObjectTargetSelectHandler signature must be \"static void SetTarget(WorldObject*& target)\""); + + _callImpl = { .Static = reinterpret_cast<decltype(SpellObjectTargetSelectFnType::Static)>(handler) }; + _safeWrapper = [](SpellScript* /*spellScript*/, WorldObject*& target, SpellObjectTargetSelectFnType callImpl) + { + return reinterpret_cast<ScriptFunc>(callImpl.Static)(target); + }; + } } - ObjectTargetSelectHandler(SpellObjectTargetSelectFnType callImpl, uint8 effIndex, uint16 targetType); - ObjectTargetSelectHandler(ObjectTargetSelectHandler const& right) = delete; - ObjectTargetSelectHandler(ObjectTargetSelectHandler&& right) noexcept; - ObjectTargetSelectHandler& operator=(ObjectTargetSelectHandler const& right) = delete; - ObjectTargetSelectHandler& operator=(ObjectTargetSelectHandler&& right) noexcept; - ~ObjectTargetSelectHandler(); - void Call(SpellScript* spellScript, WorldObject*& target) const; + void Call(SpellScript* spellScript, WorldObject*& target) const + { + return _safeWrapper(spellScript, target, _callImpl); + } private: SpellObjectTargetSelectFnType _callImpl; + SafeWrapperType _safeWrapper; }; - class TC_GAME_API DestinationTargetSelectHandler : public TargetHook + class DestinationTargetSelectHandler final : public TargetHook { public: - using SpellDestinationTargetSelectFnType = void(SpellScript::*)(SpellDestination&); + union SpellDestinationTargetSelectFnType + { + void(SpellScript::* Member)(SpellDestination& target); + void(*Static)(SpellDestination& target); + }; + + using SafeWrapperType = void(*)(SpellScript* spellScript, SpellDestination& target, SpellDestinationTargetSelectFnType callImpl); template<typename ScriptFunc> - static DestinationTargetSelectHandler Create(ScriptFunc handler, uint8 effIndex, uint16 targetType) + explicit DestinationTargetSelectHandler(ScriptFunc handler, uint8 effIndex, uint16 targetType) + : TargetHook(effIndex, targetType, false, true) { using ScriptClass = GetScriptClass_t<ScriptFunc>; static_assert(sizeof(SpellDestinationTargetSelectFnType) >= sizeof(ScriptFunc)); static_assert(alignof(SpellDestinationTargetSelectFnType) >= alignof(ScriptFunc)); - static_assert(std::is_invocable_v<ScriptFunc, ScriptClass, SpellDestination&> - && std::is_same_v<std::invoke_result_t<ScriptFunc, ScriptClass, SpellDestination&>, void>, - "DestinationTargetSelectHandler signature must be \"void SetTarget(SpellDestination& target)\""); - return { reinterpret_cast<SpellDestinationTargetSelectFnType>(handler), effIndex, targetType }; + if constexpr (!std::is_void_v<ScriptClass>) + { + static_assert(std::is_invocable_v<ScriptFunc, ScriptClass, SpellDestination&> + && std::is_same_v<std::invoke_result_t<ScriptFunc, ScriptClass, SpellDestination&>, void>, + "DestinationTargetSelectHandler signature must be \"void SetTarget(SpellDestination& target)\""); + + _callImpl = { .Member = reinterpret_cast<decltype(SpellDestinationTargetSelectFnType::Member)>(handler) }; + _safeWrapper = [](SpellScript* spellScript, SpellDestination& target, SpellDestinationTargetSelectFnType callImpl) + { + return (static_cast<ScriptClass*>(spellScript)->*reinterpret_cast<ScriptFunc>(callImpl.Member))(target); + }; + } + else + { + static_assert(std::is_invocable_v<ScriptFunc, SpellDestination&> + && std::is_same_v<std::invoke_result_t<ScriptFunc, SpellDestination&>, void>, + "DestinationTargetSelectHandler signature must be \"static void SetTarget(SpellDestination& target)\""); + + _callImpl = { .Static = reinterpret_cast<decltype(SpellDestinationTargetSelectFnType::Static)>(handler) }; + _safeWrapper = [](SpellScript* /*spellScript*/, SpellDestination& target, SpellDestinationTargetSelectFnType callImpl) + { + return reinterpret_cast<ScriptFunc>(callImpl.Static)(target); + }; + } } - DestinationTargetSelectHandler(SpellDestinationTargetSelectFnType callImpl, uint8 effIndex, uint16 targetType); - DestinationTargetSelectHandler(DestinationTargetSelectHandler const& right) = delete; - DestinationTargetSelectHandler(DestinationTargetSelectHandler&& right) noexcept; - DestinationTargetSelectHandler& operator=(DestinationTargetSelectHandler const& right) = delete; - DestinationTargetSelectHandler& operator=(DestinationTargetSelectHandler&& right) noexcept; - ~DestinationTargetSelectHandler(); - void Call(SpellScript* spellScript, SpellDestination& target) const; + void Call(SpellScript* spellScript, SpellDestination& target) const + { + return _safeWrapper(spellScript, target, _callImpl); + } private: SpellDestinationTargetSelectFnType _callImpl; + SafeWrapperType _safeWrapper; }; - class TC_GAME_API OnCalculateResistAbsorbHandler + class OnCalculateResistAbsorbHandler final { public: - using SpellOnResistAbsorbCalculateFnType = void(SpellScript::*)(DamageInfo const& damageInfo, uint32& resistAmount, int32& absorbAmount); + union SpellOnResistAbsorbCalculateFnType + { + void(SpellScript::* Member)(DamageInfo const& damageInfo, uint32& resistAmount, int32& absorbAmount); + void(*Static)(DamageInfo const& damageInfo, uint32& resistAmount, int32& absorbAmount); + }; + + using SafeWrapperType = void(*)(SpellScript* spellScript, DamageInfo const& damageInfo, uint32& resistAmount, int32& absorbAmount, SpellOnResistAbsorbCalculateFnType callImpl); template<typename ScriptFunc> - static OnCalculateResistAbsorbHandler Create(ScriptFunc handler) + explicit OnCalculateResistAbsorbHandler(ScriptFunc handler) { using ScriptClass = GetScriptClass_t<ScriptFunc>; static_assert(sizeof(SpellOnResistAbsorbCalculateFnType) >= sizeof(ScriptFunc)); static_assert(alignof(SpellOnResistAbsorbCalculateFnType) >= alignof(ScriptFunc)); - static_assert(std::is_invocable_v<ScriptFunc, ScriptClass, DamageInfo const&, uint32&, int32&> - && std::is_same_v<std::invoke_result_t<ScriptFunc, ScriptClass, DamageInfo const&, uint32&, int32&>, void>, - "OnCalculateResistAbsorbHandler signature must be \"void CalcAbsorbResist(DamageInfo const& damageInfo, uint32& resistAmount, int32& absorbAmount)\""); - return { reinterpret_cast<SpellOnResistAbsorbCalculateFnType>(handler) }; + if constexpr (!std::is_void_v<ScriptClass>) + { + static_assert(std::is_invocable_v<ScriptFunc, ScriptClass, DamageInfo const&, uint32&, int32&> + && std::is_same_v<std::invoke_result_t<ScriptFunc, ScriptClass, DamageInfo const&, uint32&, int32&>, void>, + "OnCalculateResistAbsorbHandler signature must be \"void CalcAbsorbResist(DamageInfo const& damageInfo, uint32& resistAmount, int32& absorbAmount)\""); + + _callImpl = { .Member = reinterpret_cast<decltype(SpellOnResistAbsorbCalculateFnType::Member)>(handler) }; + _safeWrapper = [](SpellScript* spellScript, DamageInfo const& damageInfo, uint32& resistAmount, int32& absorbAmount, SpellOnResistAbsorbCalculateFnType callImpl) + { + return (static_cast<ScriptClass*>(spellScript)->*reinterpret_cast<ScriptFunc>(callImpl.Member))(damageInfo, resistAmount, absorbAmount); + }; + } + else + { + static_assert(std::is_invocable_v<ScriptFunc, DamageInfo const&, uint32&, int32&> + && std::is_same_v<std::invoke_result_t<ScriptFunc, DamageInfo const&, uint32&, int32&>, void>, + "OnCalculateResistAbsorbHandler signature must be \"static void CalcAbsorbResist(DamageInfo const& damageInfo, uint32& resistAmount, int32& absorbAmount)\""); + + _callImpl = { .Static = reinterpret_cast<decltype(SpellOnResistAbsorbCalculateFnType::Static)>(handler) }; + _safeWrapper = [](SpellScript* /*spellScript*/, DamageInfo const& damageInfo, uint32& resistAmount, int32& absorbAmount, SpellOnResistAbsorbCalculateFnType callImpl) + { + return reinterpret_cast<ScriptFunc>(callImpl.Static)(damageInfo, resistAmount, absorbAmount); + }; + } } - OnCalculateResistAbsorbHandler(SpellOnResistAbsorbCalculateFnType callImpl); - OnCalculateResistAbsorbHandler(OnCalculateResistAbsorbHandler const& right) = delete; - OnCalculateResistAbsorbHandler(OnCalculateResistAbsorbHandler&& right) noexcept; - OnCalculateResistAbsorbHandler& operator=(OnCalculateResistAbsorbHandler const& right) = delete; - OnCalculateResistAbsorbHandler& operator=(OnCalculateResistAbsorbHandler&& right) noexcept; - ~OnCalculateResistAbsorbHandler(); - void Call(SpellScript* spellScript, DamageInfo const& damageInfo, uint32& resistAmount, int32& absorbAmount) const; + void Call(SpellScript* spellScript, DamageInfo const& damageInfo, uint32& resistAmount, int32& absorbAmount) const + { + return _safeWrapper(spellScript, damageInfo, resistAmount, absorbAmount, _callImpl); + } private: SpellOnResistAbsorbCalculateFnType _callImpl; + SafeWrapperType _safeWrapper; }; // left for custom compatibility only, DO NOT USE - #define PrepareSpellScript(CLASSNAME) using silence_semicolon_warning = void + #define PrepareSpellScript(CLASSNAME) SpellScript(); ~SpellScript(); @@ -604,12 +784,12 @@ public: HookList<CastHandler> OnCast; // example: AfterCast += SpellCastFn(class::function); HookList<CastHandler> AfterCast; - #define SpellCastFn(F) CastHandler::Create(&F) + #define SpellCastFn(F) CastHandler(&F) // example: OnCheckCast += SpellCheckCastFn(); // where function is SpellCastResult function() HookList<CheckCastHandler> OnCheckCast; - #define SpellCheckCastFn(F) CheckCastHandler::Create(&F) + #define SpellCheckCastFn(F) CheckCastHandler(&F) // example: int32 CalcCastTime(int32 castTime) override { return 1500; } virtual int32 CalcCastTime(int32 castTime) { return castTime; } @@ -621,44 +801,44 @@ public: HookList<EffectHandler> OnEffectHit; HookList<EffectHandler> OnEffectHitTarget; HookList<EffectHandler> OnEffectSuccessfulDispel; - #define SpellEffectFn(F, I, N) EffectHandler::Create(&F, I, N) + #define SpellEffectFn(F, I, N) EffectHandler(&F, I, N) // example: BeforeHit += BeforeSpellHitFn(class::function); // where function is void function(SpellMissInfo missInfo) HookList<BeforeHitHandler> BeforeHit; - #define BeforeSpellHitFn(F) BeforeHitHandler::Create(&F) + #define BeforeSpellHitFn(F) BeforeHitHandler(&F) // example: OnHit += SpellHitFn(class::function); HookList<HitHandler> OnHit; // example: AfterHit += SpellHitFn(class::function); HookList<HitHandler> AfterHit; // where function is: void function() - #define SpellHitFn(F) HitHandler::Create(&F) + #define SpellHitFn(F) HitHandler(&F) // example: OnCalcCritChance += SpellOnCalcCritChanceFn(class::function); // where function is: void function(Unit* victim, float& critChance) HookList<OnCalcCritChanceHandler> OnCalcCritChance; - #define SpellOnCalcCritChanceFn(F) OnCalcCritChanceHandler::Create(&F) + #define SpellOnCalcCritChanceFn(F) OnCalcCritChanceHandler(&F) // example: OnObjectAreaTargetSelect += SpellObjectAreaTargetSelectFn(class::function, EffectIndexSpecifier, TargetsNameSpecifier); // where function is void function(std::list<WorldObject*>& targets) HookList<ObjectAreaTargetSelectHandler> OnObjectAreaTargetSelect; - #define SpellObjectAreaTargetSelectFn(F, I, N) ObjectAreaTargetSelectHandler::Create(&F, I, N) + #define SpellObjectAreaTargetSelectFn(F, I, N) ObjectAreaTargetSelectHandler(&F, I, N) // example: OnObjectTargetSelect += SpellObjectTargetSelectFn(class::function, EffectIndexSpecifier, TargetsNameSpecifier); // where function is void function(WorldObject*& target) HookList<ObjectTargetSelectHandler> OnObjectTargetSelect; - #define SpellObjectTargetSelectFn(F, I, N) ObjectTargetSelectHandler::Create(&F, I, N) + #define SpellObjectTargetSelectFn(F, I, N) ObjectTargetSelectHandler(&F, I, N) // example: OnDestinationTargetSelect += SpellDestinationTargetSelectFn(class::function, EffectIndexSpecifier, TargetsNameSpecifier); // where function is void function(SpellDestination& target) HookList<DestinationTargetSelectHandler> OnDestinationTargetSelect; - #define SpellDestinationTargetSelectFn(F, I, N) DestinationTargetSelectHandler::Create(&F, I, N) + #define SpellDestinationTargetSelectFn(F, I, N) DestinationTargetSelectHandler(&F, I, N) // example: OnCalculateResistAbsorb += SpellOnResistAbsorbCalculateFn(class::function); // where function is void function(DamageInfo const& damageInfo, uint32& resistAmount, int32& absorbAmount) HookList<OnCalculateResistAbsorbHandler> OnCalculateResistAbsorb; - #define SpellOnResistAbsorbCalculateFn(F) OnCalculateResistAbsorbHandler::Create(&F) + #define SpellOnResistAbsorbCalculateFn(F) OnCalculateResistAbsorbHandler(&F) // hooks are executed in following order, at specified event of spell: // 1. OnPrecast - executed during spell preparation (before cast bar starts) @@ -839,64 +1019,112 @@ class TC_GAME_API AuraScript : public SpellScriptBase // internal use classes & functions // DO NOT OVERRIDE THESE IN SCRIPTS public: - class TC_GAME_API CheckAreaTargetHandler + class CheckAreaTargetHandler final { public: - using AuraCheckAreaTargetFnType = bool(AuraScript::*)(Unit* target); + union AuraCheckAreaTargetFnType + { + bool(AuraScript::* Member)(Unit* target); + bool(*Static)(Unit* target); + }; + + using SafeWrapperType = bool(*)(AuraScript* auraScript, Unit* target, AuraCheckAreaTargetFnType callImpl); template<typename ScriptFunc> - static CheckAreaTargetHandler Create(ScriptFunc handler) + explicit CheckAreaTargetHandler(ScriptFunc handler) { using ScriptClass = GetScriptClass_t<ScriptFunc>; static_assert(sizeof(AuraCheckAreaTargetFnType) >= sizeof(ScriptFunc)); static_assert(alignof(AuraCheckAreaTargetFnType) >= alignof(ScriptFunc)); - static_assert(std::is_invocable_v<ScriptFunc, ScriptClass, Unit*> - && std::is_same_v<std::invoke_result_t<ScriptFunc, ScriptClass, Unit*>, bool>, - "CheckAreaTargetHandler signature must be \"bool CheckTarget(Unit* target)\""); - return { reinterpret_cast<AuraCheckAreaTargetFnType>(handler) }; + if constexpr (!std::is_void_v<ScriptClass>) + { + static_assert(std::is_invocable_v<ScriptFunc, ScriptClass, Unit*> + && std::is_same_v<std::invoke_result_t<ScriptFunc, ScriptClass, Unit*>, bool>, + "CheckAreaTargetHandler signature must be \"bool CheckTarget(Unit* target)\""); + + _callImpl = { .Member = reinterpret_cast<decltype(AuraCheckAreaTargetFnType::Member)>(handler) }; + _safeWrapper = [](AuraScript* auraScript, Unit* target, AuraCheckAreaTargetFnType callImpl) + { + return (static_cast<ScriptClass*>(auraScript)->*reinterpret_cast<ScriptFunc>(callImpl.Member))(target); + }; + } + else + { + static_assert(std::is_invocable_v<ScriptFunc, Unit*> + && std::is_same_v<std::invoke_result_t<ScriptFunc, Unit*>, bool>, + "CheckAreaTargetHandler signature must be \"static bool CheckTarget(Unit* target)\""); + + _callImpl = { .Static = reinterpret_cast<decltype(AuraCheckAreaTargetFnType::Static)>(handler) }; + _safeWrapper = [](AuraScript* /*auraScript*/, Unit* target, AuraCheckAreaTargetFnType callImpl) + { + return reinterpret_cast<ScriptFunc>(callImpl.Static)(target); + }; + } } - CheckAreaTargetHandler(AuraCheckAreaTargetFnType callImpl); - CheckAreaTargetHandler(CheckAreaTargetHandler const& right) = delete; - CheckAreaTargetHandler(CheckAreaTargetHandler&& right) noexcept; - CheckAreaTargetHandler& operator=(CheckAreaTargetHandler const& right) = delete; - CheckAreaTargetHandler& operator=(CheckAreaTargetHandler&& right) noexcept; - ~CheckAreaTargetHandler(); - bool Call(AuraScript* auraScript, Unit* target) const; + bool Call(AuraScript* auraScript, Unit* target) const + { + return _safeWrapper(auraScript, target, _callImpl); + } private: AuraCheckAreaTargetFnType _callImpl; + SafeWrapperType _safeWrapper; }; - class TC_GAME_API AuraDispelHandler + class AuraDispelHandler final { public: - using AuraDispelFnType = void(AuraScript::*)(DispelInfo* dispelInfo); + union AuraDispelFnType + { + void(AuraScript::* Member)(DispelInfo* dispelInfo); + void(*Static)(DispelInfo* dispelInfo); + }; + + using SafeWrapperType = void(*)(AuraScript* auraScript, DispelInfo* dispelInfo, AuraDispelFnType callImpl); template<typename ScriptFunc> - static AuraDispelHandler Create(ScriptFunc handler) + explicit AuraDispelHandler(ScriptFunc handler) { using ScriptClass = GetScriptClass_t<ScriptFunc>; static_assert(sizeof(AuraDispelFnType) >= sizeof(ScriptFunc)); static_assert(alignof(AuraDispelFnType) >= alignof(ScriptFunc)); - static_assert(std::is_invocable_v<ScriptFunc, ScriptClass, DispelInfo*> - && std::is_same_v<std::invoke_result_t<ScriptFunc, ScriptClass, DispelInfo*>, void>, - "AuraDispelHandler signature must be \"void HandleDispel(DispelInfo* dispelInfo)\""); - return { reinterpret_cast<AuraDispelFnType>(handler) }; + if constexpr (!std::is_void_v<ScriptClass>) + { + static_assert(std::is_invocable_v<ScriptFunc, ScriptClass, DispelInfo*> + && std::is_same_v<std::invoke_result_t<ScriptFunc, ScriptClass, DispelInfo*>, void>, + "AuraDispelHandler signature must be \"void HandleDispel(DispelInfo* dispelInfo)\""); + + _callImpl = { .Member = reinterpret_cast<decltype(AuraDispelFnType::Member)>(handler) }; + _safeWrapper = [](AuraScript* auraScript, DispelInfo* dispelInfo, AuraDispelFnType callImpl) + { + return (static_cast<ScriptClass*>(auraScript)->*reinterpret_cast<ScriptFunc>(callImpl.Member))(dispelInfo); + }; + } + else + { + static_assert(std::is_invocable_v<ScriptFunc, DispelInfo*> + && std::is_same_v<std::invoke_result_t<ScriptFunc, DispelInfo*>, void>, + "AuraDispelHandler signature must be \"static void HandleDispel(DispelInfo* dispelInfo)\""); + + _callImpl = { .Static = reinterpret_cast<decltype(AuraDispelFnType::Static)>(handler) }; + _safeWrapper = [](AuraScript* /*auraScript*/, DispelInfo* dispelInfo, AuraDispelFnType callImpl) + { + return reinterpret_cast<ScriptFunc>(callImpl.Static)(dispelInfo); + }; + } } - AuraDispelHandler(AuraDispelFnType callImpl); - AuraDispelHandler(AuraDispelHandler const& right) = delete; - AuraDispelHandler(AuraDispelHandler&& right) noexcept; - AuraDispelHandler& operator=(AuraDispelHandler const& right) = delete; - AuraDispelHandler& operator=(AuraDispelHandler&& right) noexcept; - ~AuraDispelHandler(); - void Call(AuraScript* auraScript, DispelInfo* dispelInfo) const; + void Call(AuraScript* auraScript, DispelInfo* dispelInfo) const + { + return _safeWrapper(auraScript, dispelInfo, _callImpl); + } private: AuraDispelFnType _callImpl; + SafeWrapperType _safeWrapper; }; class TC_GAME_API EffectBase : public EffectHook @@ -914,430 +1142,760 @@ public: uint16 _auraType; }; - class TC_GAME_API EffectPeriodicHandler : public EffectBase + class EffectPeriodicHandler final : public EffectBase { public: - using AuraEffectPeriodicFnType = void(AuraScript::*)(AuraEffect const* aurEff); + union AuraEffectPeriodicFnType + { + void(AuraScript::* Member)(AuraEffect const* aurEff); + void(*Static)(AuraEffect const* aurEff); + }; + + using SafeWrapperType = void(*)(AuraScript* auraScript, AuraEffect const* aurEff, AuraEffectPeriodicFnType callImpl); template<typename ScriptFunc> - static EffectPeriodicHandler Create(ScriptFunc handler, uint8 effIndex, uint16 auraType) + explicit EffectPeriodicHandler(ScriptFunc handler, uint8 effIndex, uint16 auraType) + : EffectBase(effIndex, auraType) { using ScriptClass = GetScriptClass_t<ScriptFunc>; static_assert(sizeof(AuraEffectPeriodicFnType) >= sizeof(ScriptFunc)); static_assert(alignof(AuraEffectPeriodicFnType) >= alignof(ScriptFunc)); - static_assert(std::is_invocable_v<ScriptFunc, ScriptClass, AuraEffect const*> - && std::is_same_v<std::invoke_result_t<ScriptFunc, ScriptClass, AuraEffect const*>, void>, - "EffectPeriodicHandler signature must be \"void HandlePeriodic(AuraEffect const* aurEff)\""); - return { reinterpret_cast<AuraEffectPeriodicFnType>(handler), effIndex, auraType }; + if constexpr (!std::is_void_v<ScriptClass>) + { + static_assert(std::is_invocable_v<ScriptFunc, ScriptClass, AuraEffect const*> + && std::is_same_v<std::invoke_result_t<ScriptFunc, ScriptClass, AuraEffect const*>, void>, + "EffectPeriodicHandler signature must be \"void HandlePeriodic(AuraEffect const* aurEff)\""); + + _callImpl = { .Member = reinterpret_cast<decltype(AuraEffectPeriodicFnType::Member)>(handler) }; + _safeWrapper = [](AuraScript* auraScript, AuraEffect const* aurEff, AuraEffectPeriodicFnType callImpl) + { + return (static_cast<ScriptClass*>(auraScript)->*reinterpret_cast<ScriptFunc>(callImpl.Member))(aurEff); + }; + } + else + { + static_assert(std::is_invocable_v<ScriptFunc, AuraEffect const*> + && std::is_same_v<std::invoke_result_t<ScriptFunc, AuraEffect const*>, void>, + "EffectPeriodicHandler signature must be \"static void HandlePeriodic(AuraEffect const* aurEff)\""); + + _callImpl = { .Static = reinterpret_cast<decltype(AuraEffectPeriodicFnType::Static)>(handler) }; + _safeWrapper = [](AuraScript* /*auraScript*/, AuraEffect const* aurEff, AuraEffectPeriodicFnType callImpl) + { + return reinterpret_cast<ScriptFunc>(callImpl.Static)(aurEff); + }; + } } - EffectPeriodicHandler(AuraEffectPeriodicFnType callImpl, uint8 effIndex, uint16 auraType); - EffectPeriodicHandler(EffectPeriodicHandler const& right) = delete; - EffectPeriodicHandler(EffectPeriodicHandler&& right) noexcept; - EffectPeriodicHandler& operator=(EffectPeriodicHandler const& right) = delete; - EffectPeriodicHandler& operator=(EffectPeriodicHandler&& right) noexcept; - ~EffectPeriodicHandler(); - void Call(AuraScript* auraScript, AuraEffect const* aurEff) const; + void Call(AuraScript* auraScript, AuraEffect const* aurEff) const + { + return _safeWrapper(auraScript, aurEff, _callImpl); + } private: AuraEffectPeriodicFnType _callImpl; + SafeWrapperType _safeWrapper; }; - class TC_GAME_API EffectUpdatePeriodicHandler : public EffectBase + class EffectUpdatePeriodicHandler final : public EffectBase { public: - using AuraEffectUpdatePeriodicFnType = void(AuraScript::*)(AuraEffect* aurEff); + union AuraEffectUpdatePeriodicFnType + { + void(AuraScript::* Member)(AuraEffect* aurEff); + void(*Static)(AuraEffect* aurEff); + }; + + using SafeWrapperType = void(*)(AuraScript* auraScript, AuraEffect* aurEff, AuraEffectUpdatePeriodicFnType callImpl); template<typename ScriptFunc> - static EffectUpdatePeriodicHandler Create(ScriptFunc handler, uint8 effIndex, uint16 auraType) + explicit EffectUpdatePeriodicHandler(ScriptFunc handler, uint8 effIndex, uint16 auraType) + : EffectBase(effIndex, auraType) { using ScriptClass = GetScriptClass_t<ScriptFunc>; static_assert(sizeof(AuraEffectUpdatePeriodicFnType) >= sizeof(ScriptFunc)); static_assert(alignof(AuraEffectUpdatePeriodicFnType) >= alignof(ScriptFunc)); - static_assert(std::is_invocable_v<ScriptFunc, ScriptClass, AuraEffect*> - && std::is_same_v<std::invoke_result_t<ScriptFunc, ScriptClass, AuraEffect*>, void>, - "EffectUpdatePeriodicHandler signature must be \"void HandleUpdatePeriodic(AuraEffect* aurEff)\""); - return { reinterpret_cast<AuraEffectUpdatePeriodicFnType>(handler), effIndex, auraType }; + if constexpr (!std::is_void_v<ScriptClass>) + { + static_assert(std::is_invocable_v<ScriptFunc, ScriptClass, AuraEffect*> + && std::is_same_v<std::invoke_result_t<ScriptFunc, ScriptClass, AuraEffect*>, void>, + "EffectUpdatePeriodicHandler signature must be \"void HandleUpdatePeriodic(AuraEffect* aurEff)\""); + + _callImpl = { .Member = reinterpret_cast<decltype(AuraEffectUpdatePeriodicFnType::Member)>(handler) }; + _safeWrapper = [](AuraScript* auraScript, AuraEffect* aurEff, AuraEffectUpdatePeriodicFnType callImpl) + { + return (static_cast<ScriptClass*>(auraScript)->*reinterpret_cast<ScriptFunc>(callImpl.Member))(aurEff); + }; + } + else + { + static_assert(std::is_invocable_v<ScriptFunc, AuraEffect*> + && std::is_same_v<std::invoke_result_t<ScriptFunc, AuraEffect*>, void>, + "EffectUpdatePeriodicHandler signature must be \"static void HandleUpdatePeriodic(AuraEffect* aurEff)\""); + + _callImpl = { .Static = reinterpret_cast<decltype(AuraEffectUpdatePeriodicFnType::Static)>(handler) }; + _safeWrapper = [](AuraScript* /*auraScript*/, AuraEffect* aurEff, AuraEffectUpdatePeriodicFnType callImpl) + { + return reinterpret_cast<ScriptFunc>(callImpl.Static)(aurEff); + }; + } } - EffectUpdatePeriodicHandler(AuraEffectUpdatePeriodicFnType callImpl, uint8 effIndex, uint16 auraType); - EffectUpdatePeriodicHandler(EffectUpdatePeriodicHandler const& right) = delete; - EffectUpdatePeriodicHandler(EffectUpdatePeriodicHandler&& right) noexcept; - EffectUpdatePeriodicHandler& operator=(EffectUpdatePeriodicHandler const& right) = delete; - EffectUpdatePeriodicHandler& operator=(EffectUpdatePeriodicHandler&& right) noexcept; - ~EffectUpdatePeriodicHandler(); - void Call(AuraScript* auraScript, AuraEffect* aurEff) const; + void Call(AuraScript* auraScript, AuraEffect* aurEff) const + { + return _safeWrapper(auraScript, aurEff, _callImpl); + } private: AuraEffectUpdatePeriodicFnType _callImpl; + SafeWrapperType _safeWrapper; }; - class TC_GAME_API EffectCalcAmountHandler : public EffectBase + class EffectCalcAmountHandler final : public EffectBase { public: - using AuraEffectCalcAmountFnType = void(AuraScript::*)(AuraEffect const* aurEff, int32& amount, bool& canBeRecalculated); + union AuraEffectCalcAmountFnType + { + void(AuraScript::* Member)(AuraEffect const* aurEff, int32& amount, bool& canBeRecalculated); + void(*Static)(AuraEffect const* aurEff, int32& amount, bool& canBeRecalculated); + }; + + using SafeWrapperType = void(*)(AuraScript* auraScript, AuraEffect const* aurEff, int32& amount, bool& canBeRecalculated, AuraEffectCalcAmountFnType callImpl); template<typename ScriptFunc> - static EffectCalcAmountHandler Create(ScriptFunc handler, uint8 effIndex, uint16 auraType) + explicit EffectCalcAmountHandler(ScriptFunc handler, uint8 effIndex, uint16 auraType) + : EffectBase(effIndex, auraType) { using ScriptClass = GetScriptClass_t<ScriptFunc>; static_assert(sizeof(AuraEffectCalcAmountFnType) >= sizeof(ScriptFunc)); static_assert(alignof(AuraEffectCalcAmountFnType) >= alignof(ScriptFunc)); - static_assert(std::is_invocable_v<ScriptFunc, ScriptClass, AuraEffect const*, int32&, bool&> - && std::is_same_v<std::invoke_result_t<ScriptFunc, ScriptClass, AuraEffect const*, int32&, bool&>, void>, - "EffectCalcAmountHandler signature must be \"void CalcAmount(AuraEffect const* aurEff, int32& amount, bool& canBeRecalculated)\""); - return { reinterpret_cast<AuraEffectCalcAmountFnType>(handler), effIndex, auraType }; + if constexpr (!std::is_void_v<ScriptClass>) + { + static_assert(std::is_invocable_v<ScriptFunc, ScriptClass, AuraEffect const*, int32&, bool&> + && std::is_same_v<std::invoke_result_t<ScriptFunc, ScriptClass, AuraEffect const*, int32&, bool&>, void>, + "EffectCalcAmountHandler signature must be \"void CalcAmount(AuraEffect const* aurEff, int32& amount, bool& canBeRecalculated)\""); + + _callImpl = { .Member = reinterpret_cast<decltype(AuraEffectCalcAmountFnType::Member)>(handler) }; + _safeWrapper = [](AuraScript* auraScript, AuraEffect const* aurEff, int32& amount, bool& canBeRecalculated, AuraEffectCalcAmountFnType callImpl) + { + return (static_cast<ScriptClass*>(auraScript)->*reinterpret_cast<ScriptFunc>(callImpl.Member))(aurEff, amount, canBeRecalculated); + }; + } + else + { + static_assert(std::is_invocable_v<ScriptFunc, AuraEffect const*, int32&, bool&> + && std::is_same_v<std::invoke_result_t<ScriptFunc, AuraEffect const*, int32&, bool&>, void>, + "EffectCalcAmountHandler signature must be \"static void CalcAmount(AuraEffect const* aurEff, int32& amount, bool& canBeRecalculated)\""); + + _callImpl = { .Static = reinterpret_cast<decltype(AuraEffectCalcAmountFnType::Static)>(handler) }; + _safeWrapper = [](AuraScript* /*auraScript*/, AuraEffect const* aurEff, int32& amount, bool& canBeRecalculated, AuraEffectCalcAmountFnType callImpl) + { + return reinterpret_cast<ScriptFunc>(callImpl.Static)(aurEff, amount, canBeRecalculated); + }; + } } - EffectCalcAmountHandler(AuraEffectCalcAmountFnType callImpl, uint8 effIndex, uint16 auraType); - EffectCalcAmountHandler(EffectCalcAmountHandler const& right) = delete; - EffectCalcAmountHandler(EffectCalcAmountHandler&& right) noexcept; - EffectCalcAmountHandler& operator=(EffectCalcAmountHandler const& right) = delete; - EffectCalcAmountHandler& operator=(EffectCalcAmountHandler&& right) noexcept; - ~EffectCalcAmountHandler(); - void Call(AuraScript* auraScript, AuraEffect const* aurEff, int32& amount, bool& canBeRecalculated) const; + void Call(AuraScript* auraScript, AuraEffect const* aurEff, int32& amount, bool& canBeRecalculated) const + { + return _safeWrapper(auraScript, aurEff, amount, canBeRecalculated, _callImpl); + } private: AuraEffectCalcAmountFnType _callImpl; + SafeWrapperType _safeWrapper; }; - class TC_GAME_API EffectCalcPeriodicHandler : public EffectBase + class EffectCalcPeriodicHandler final : public EffectBase { public: - using AuraEffectCalcPeriodicFnType = void(AuraScript::*)(AuraEffect const* aurEff, bool& isPeriodic, int32& periodicTimer); + union AuraEffectCalcPeriodicFnType + { + void(AuraScript::* Member)(AuraEffect const* aurEff, bool& isPeriodic, int32& periodicTimer); + void(*Static)(AuraEffect const* aurEff, bool& isPeriodic, int32& periodicTimer); + }; + + using SafeWrapperType = void(*)(AuraScript* auraScript, AuraEffect const* aurEff, bool& isPeriodic, int32& periodicTimer, AuraEffectCalcPeriodicFnType callImpl); template<typename ScriptFunc> - static EffectCalcPeriodicHandler Create(ScriptFunc handler, uint8 effIndex, uint16 auraType) + explicit EffectCalcPeriodicHandler(ScriptFunc handler, uint8 effIndex, uint16 auraType) + : EffectBase(effIndex, auraType) { using ScriptClass = GetScriptClass_t<ScriptFunc>; static_assert(sizeof(AuraEffectCalcPeriodicFnType) >= sizeof(ScriptFunc)); static_assert(alignof(AuraEffectCalcPeriodicFnType) >= alignof(ScriptFunc)); - static_assert(std::is_invocable_v<ScriptFunc, ScriptClass, AuraEffect const*, bool&, int32&> - && std::is_same_v<std::invoke_result_t<ScriptFunc, ScriptClass, AuraEffect const*, bool&, int32&>, void>, - "EffectCalcPeriodicHandler signature must be \"void CalcPeriodic(AuraEffect const* aurEff, bool& isPeriodic, int32& periodicTimer)\""); - return { reinterpret_cast<AuraEffectCalcPeriodicFnType>(handler), effIndex, auraType }; + if constexpr (!std::is_void_v<ScriptClass>) + { + static_assert(std::is_invocable_v<ScriptFunc, ScriptClass, AuraEffect const*, bool&, int32&> + && std::is_same_v<std::invoke_result_t<ScriptFunc, ScriptClass, AuraEffect const*, bool&, int32&>, void>, + "EffectCalcPeriodicHandler signature must be \"void CalcPeriodic(AuraEffect const* aurEff, bool& isPeriodic, int32& periodicTimer)\""); + + _callImpl = { .Member = reinterpret_cast<decltype(AuraEffectCalcPeriodicFnType::Member)>(handler) }; + _safeWrapper = [](AuraScript* auraScript, AuraEffect const* aurEff, bool& isPeriodic, int32& periodicTimer, AuraEffectCalcPeriodicFnType callImpl) + { + return (static_cast<ScriptClass*>(auraScript)->*reinterpret_cast<ScriptFunc>(callImpl.Member))(aurEff, isPeriodic, periodicTimer); + }; + } + else + { + static_assert(std::is_invocable_v<ScriptFunc, AuraEffect const*, bool&, int32&> + && std::is_same_v<std::invoke_result_t<ScriptFunc, AuraEffect const*, bool&, int32&>, void>, + "EffectCalcPeriodicHandler signature must be \"static void CalcPeriodic(AuraEffect const* aurEff, bool& isPeriodic, int32& periodicTimer)\""); + + _callImpl = { .Static = reinterpret_cast<decltype(AuraEffectCalcPeriodicFnType::Static)>(handler) }; + _safeWrapper = [](AuraScript* /*auraScript*/, AuraEffect const* aurEff, bool& isPeriodic, int32& periodicTimer, AuraEffectCalcPeriodicFnType callImpl) + { + return reinterpret_cast<ScriptFunc>(callImpl.Static)(aurEff, isPeriodic, periodicTimer); + }; + } } - EffectCalcPeriodicHandler(AuraEffectCalcPeriodicFnType callImpl, uint8 effIndex, uint16 auraType); - EffectCalcPeriodicHandler(EffectCalcPeriodicHandler const& right) = delete; - EffectCalcPeriodicHandler(EffectCalcPeriodicHandler&& right) noexcept; - EffectCalcPeriodicHandler& operator=(EffectCalcPeriodicHandler const& right) = delete; - EffectCalcPeriodicHandler& operator=(EffectCalcPeriodicHandler&& right) noexcept; - ~EffectCalcPeriodicHandler(); - void Call(AuraScript* auraScript, AuraEffect const* aurEff, bool& isPeriodic, int32& periodicTimer) const; + void Call(AuraScript* auraScript, AuraEffect const* aurEff, bool& isPeriodic, int32& periodicTimer) const + { + return _safeWrapper(auraScript, aurEff, isPeriodic, periodicTimer, _callImpl); + } private: AuraEffectCalcPeriodicFnType _callImpl; + SafeWrapperType _safeWrapper; }; - class TC_GAME_API EffectCalcSpellModHandler : public EffectBase + class EffectCalcSpellModHandler final : public EffectBase { public: - using AuraEffectCalcSpellModFnType = void(AuraScript::*)(AuraEffect const* aurEff, SpellModifier*& spellMod); + union AuraEffectCalcSpellModFnType + { + void(AuraScript::* Member)(AuraEffect const* aurEff, SpellModifier*& spellMod); + void(*Static)(AuraEffect const* aurEff, SpellModifier*& spellMod); + }; + + using SafeWrapperType = void(*)(AuraScript* auraScript, AuraEffect const* aurEff, SpellModifier*& spellMod, AuraEffectCalcSpellModFnType callImpl); template<typename ScriptFunc> - static EffectCalcSpellModHandler Create(ScriptFunc handler, uint8 effIndex, uint16 auraType) + explicit EffectCalcSpellModHandler(ScriptFunc handler, uint8 effIndex, uint16 auraType) + : EffectBase(effIndex, auraType) { using ScriptClass = GetScriptClass_t<ScriptFunc>; static_assert(sizeof(AuraEffectCalcSpellModFnType) >= sizeof(ScriptFunc)); static_assert(alignof(AuraEffectCalcSpellModFnType) >= alignof(ScriptFunc)); - static_assert(std::is_invocable_v<ScriptFunc, ScriptClass, AuraEffect const*, SpellModifier*&> - && std::is_same_v<std::invoke_result_t<ScriptFunc, ScriptClass, AuraEffect const*, SpellModifier*&>, void>, - "EffectCalcSpellModHandler signature must be \"void CalcSpellMod(AuraEffect const* aurEff, SpellModifier*& spellMod)\""); - return { reinterpret_cast<AuraEffectCalcSpellModFnType>(handler), effIndex, auraType }; + if constexpr (!std::is_void_v<ScriptClass>) + { + static_assert(std::is_invocable_v<ScriptFunc, ScriptClass, AuraEffect const*, SpellModifier*&> + && std::is_same_v<std::invoke_result_t<ScriptFunc, ScriptClass, AuraEffect const*, SpellModifier*&>, void>, + "EffectCalcSpellModHandler signature must be \"void CalcSpellMod(AuraEffect const* aurEff, SpellModifier*& spellMod)\""); + + _callImpl = { .Member = reinterpret_cast<decltype(AuraEffectCalcSpellModFnType::Member)>(handler) }; + _safeWrapper = [](AuraScript* auraScript, AuraEffect const* aurEff, SpellModifier*& spellMod, AuraEffectCalcSpellModFnType callImpl) + { + return (static_cast<ScriptClass*>(auraScript)->*reinterpret_cast<ScriptFunc>(callImpl.Member))(aurEff, spellMod); + }; + } + else + { + static_assert(std::is_invocable_v<ScriptFunc, AuraEffect const*, SpellModifier*&> + && std::is_same_v<std::invoke_result_t<ScriptFunc, AuraEffect const*, SpellModifier*&>, void>, + "EffectCalcSpellModHandler signature must be \"static void CalcSpellMod(AuraEffect const* aurEff, SpellModifier*& spellMod)\""); + + _callImpl = { .Static = reinterpret_cast<decltype(AuraEffectCalcSpellModFnType::Static)>(handler) }; + _safeWrapper = [](AuraScript* /*auraScript*/, AuraEffect const* aurEff, SpellModifier*& spellMod, AuraEffectCalcSpellModFnType callImpl) + { + return reinterpret_cast<ScriptFunc>(callImpl.Static)(aurEff, spellMod); + }; + } } - EffectCalcSpellModHandler(AuraEffectCalcSpellModFnType callImpl, uint8 effIndex, uint16 auraType); - EffectCalcSpellModHandler(EffectCalcSpellModHandler const& right) = delete; - EffectCalcSpellModHandler(EffectCalcSpellModHandler&& right) noexcept; - EffectCalcSpellModHandler& operator=(EffectCalcSpellModHandler const& right) = delete; - EffectCalcSpellModHandler& operator=(EffectCalcSpellModHandler&& right) noexcept; - ~EffectCalcSpellModHandler(); - void Call(AuraScript* auraScript, AuraEffect const* aurEff, SpellModifier*& spellMod) const; + void Call(AuraScript* auraScript, AuraEffect const* aurEff, SpellModifier*& spellMod) const + { + return _safeWrapper(auraScript, aurEff, spellMod, _callImpl); + } private: AuraEffectCalcSpellModFnType _callImpl; + SafeWrapperType _safeWrapper; }; - class TC_GAME_API EffectCalcCritChanceHandler : public EffectBase + class EffectCalcCritChanceHandler final : public EffectBase { public: - using AuraEffectCalcCritChanceFnType = void(AuraScript::*)(AuraEffect const* aurEff, Unit const* victim, float& critChance); + union AuraEffectCalcCritChanceFnType + { + void(AuraScript::* Member)(AuraEffect const* aurEff, Unit const* victim, float& critChance); + void(*Static)(AuraEffect const* aurEff, Unit const* victim, float& critChance); + }; + + using SafeWrapperType = void(*)(AuraScript* auraScript, AuraEffect const* aurEff, Unit const* victim, float& critChance, AuraEffectCalcCritChanceFnType callImpl); template<typename ScriptFunc> - static EffectCalcCritChanceHandler Create(ScriptFunc handler, uint8 effIndex, uint16 auraType) + explicit EffectCalcCritChanceHandler(ScriptFunc handler, uint8 effIndex, uint16 auraType) + : EffectBase(effIndex, auraType) { using ScriptClass = GetScriptClass_t<ScriptFunc>; static_assert(sizeof(AuraEffectCalcCritChanceFnType) >= sizeof(ScriptFunc)); static_assert(alignof(AuraEffectCalcCritChanceFnType) >= alignof(ScriptFunc)); - static_assert(std::is_invocable_v<ScriptFunc, ScriptClass, AuraEffect const*, Unit const*, float&> - && std::is_same_v<std::invoke_result_t<ScriptFunc, ScriptClass, AuraEffect const*, Unit const*, float&>, void>, - "EffectCalcSpellModHandler signature must be \"void CalcCritChance(AuraEffect const* aurEff, Unit const* victim, float& critChance)\""); - return { reinterpret_cast<AuraEffectCalcCritChanceFnType>(handler), effIndex, auraType }; + if constexpr (!std::is_void_v<ScriptClass>) + { + static_assert(std::is_invocable_v<ScriptFunc, ScriptClass, AuraEffect const*, Unit const*, float&> + && std::is_same_v<std::invoke_result_t<ScriptFunc, ScriptClass, AuraEffect const*, Unit const*, float&>, void>, + "EffectCalcSpellModHandler signature must be \"void CalcCritChance(AuraEffect const* aurEff, Unit const* victim, float& critChance)\""); + + _callImpl = { .Member = reinterpret_cast<decltype(AuraEffectCalcCritChanceFnType::Member)>(handler) }; + _safeWrapper = [](AuraScript* auraScript, AuraEffect const* aurEff, Unit const* victim, float& critChance, AuraEffectCalcCritChanceFnType callImpl) + { + return (static_cast<ScriptClass*>(auraScript)->*reinterpret_cast<ScriptFunc>(callImpl.Member))(aurEff, victim, critChance); + }; + } + else + { + static_assert(std::is_invocable_v<ScriptFunc, AuraEffect const*, Unit const*, float&> + && std::is_same_v<std::invoke_result_t<ScriptFunc, AuraEffect const*, Unit const*, float&>, void>, + "EffectCalcSpellModHandler signature must be \"static void CalcCritChance(AuraEffect const* aurEff, Unit const* victim, float& critChance)\""); + + _callImpl = { .Static = reinterpret_cast<decltype(AuraEffectCalcCritChanceFnType::Static)>(handler) }; + _safeWrapper = [](AuraScript* /*auraScript*/, AuraEffect const* aurEff, Unit const* victim, float& critChance, AuraEffectCalcCritChanceFnType callImpl) + { + return reinterpret_cast<ScriptFunc>(callImpl.Static)(aurEff, victim, critChance); + }; + } } - EffectCalcCritChanceHandler(AuraEffectCalcCritChanceFnType callImpl, uint8 effIndex, uint16 auraType); - EffectCalcCritChanceHandler(EffectCalcCritChanceHandler const& right) = delete; - EffectCalcCritChanceHandler(EffectCalcCritChanceHandler&& right) noexcept; - EffectCalcCritChanceHandler& operator=(EffectCalcCritChanceHandler const& right) = delete; - EffectCalcCritChanceHandler& operator=(EffectCalcCritChanceHandler&& right) noexcept; - ~EffectCalcCritChanceHandler(); - void Call(AuraScript* auraScript, AuraEffect const* aurEff, Unit const* victim, float& critChance) const; + void Call(AuraScript* auraScript, AuraEffect const* aurEff, Unit const* victim, float& critChance) const + { + return _safeWrapper(auraScript, aurEff, victim, critChance, _callImpl); + } private: AuraEffectCalcCritChanceFnType _callImpl; + SafeWrapperType _safeWrapper; }; - class TC_GAME_API EffectApplyHandler : public EffectBase + class EffectApplyHandler final : public EffectBase { public: - using AuraEffectApplicationModeFnType = void(AuraScript::*)(AuraEffect const* aurEff, AuraEffectHandleModes mode); + union AuraEffectApplicationModeFnType + { + void(AuraScript::* Member)(AuraEffect const* aurEff, AuraEffectHandleModes mode); + void(*Static)(AuraEffect const* aurEff, AuraEffectHandleModes mode); + }; + + using SafeWrapperType = void(*)(AuraScript* auraScript, AuraEffect const* aurEff, AuraEffectHandleModes mode, AuraEffectApplicationModeFnType callImpl); template<typename ScriptFunc> - static EffectApplyHandler Create(ScriptFunc handler, uint8 effIndex, uint16 auraType, AuraEffectHandleModes mode) + explicit EffectApplyHandler(ScriptFunc handler, uint8 effIndex, uint16 auraType, AuraEffectHandleModes mode) + : EffectBase(effIndex, auraType), _mode(mode) { using ScriptClass = GetScriptClass_t<ScriptFunc>; static_assert(sizeof(AuraEffectApplicationModeFnType) >= sizeof(ScriptFunc)); static_assert(alignof(AuraEffectApplicationModeFnType) >= alignof(ScriptFunc)); - static_assert(std::is_invocable_v<ScriptFunc, ScriptClass, AuraEffect const*, AuraEffectHandleModes> - && std::is_same_v<std::invoke_result_t<ScriptFunc, ScriptClass, AuraEffect const*, AuraEffectHandleModes>, void>, - "EffectApplyHandler signature must be \"void HandleApplyOrRemove(AuraEffect const* aurEff, AuraEffectHandleModes mode)\""); - return { reinterpret_cast<AuraEffectApplicationModeFnType>(handler), effIndex, auraType, mode }; + if constexpr (!std::is_void_v<ScriptClass>) + { + static_assert(std::is_invocable_v<ScriptFunc, ScriptClass, AuraEffect const*, AuraEffectHandleModes> + && std::is_same_v<std::invoke_result_t<ScriptFunc, ScriptClass, AuraEffect const*, AuraEffectHandleModes>, void>, + "EffectApplyHandler signature must be \"void HandleApplyOrRemove(AuraEffect const* aurEff, AuraEffectHandleModes mode)\""); + + _callImpl = { .Member = reinterpret_cast<decltype(AuraEffectApplicationModeFnType::Member)>(handler) }; + _safeWrapper = [](AuraScript* auraScript, AuraEffect const* aurEff, AuraEffectHandleModes mode, AuraEffectApplicationModeFnType callImpl) + { + return (static_cast<ScriptClass*>(auraScript)->*reinterpret_cast<ScriptFunc>(callImpl.Member))(aurEff, mode); + }; + } + else + { + static_assert(std::is_invocable_v<ScriptFunc, AuraEffect const*, AuraEffectHandleModes> + && std::is_same_v<std::invoke_result_t<ScriptFunc, AuraEffect const*, AuraEffectHandleModes>, void>, + "EffectApplyHandler signature must be \"static void HandleApplyOrRemove(AuraEffect const* aurEff, AuraEffectHandleModes mode)\""); + + _callImpl = { .Static = reinterpret_cast<decltype(AuraEffectApplicationModeFnType::Static)>(handler) }; + _safeWrapper = [](AuraScript* /*auraScript*/, AuraEffect const* aurEff, AuraEffectHandleModes mode, AuraEffectApplicationModeFnType callImpl) + { + return reinterpret_cast<ScriptFunc>(callImpl.Static)(aurEff, mode); + }; + } } - EffectApplyHandler(AuraEffectApplicationModeFnType callImpl, uint8 effIndex, uint16 auraType, AuraEffectHandleModes mode); - EffectApplyHandler(EffectApplyHandler const& right) = delete; - EffectApplyHandler(EffectApplyHandler&& right) noexcept; - EffectApplyHandler& operator=(EffectApplyHandler const& right) = delete; - EffectApplyHandler& operator=(EffectApplyHandler&& right) noexcept; - ~EffectApplyHandler(); - AuraEffectHandleModes GetMode() const { return _mode; } - void Call(AuraScript* auraScript, AuraEffect const* aurEff, AuraEffectHandleModes mode) const; + void Call(AuraScript* auraScript, AuraEffect const* aurEff, AuraEffectHandleModes mode) const + { + if (!(_mode & mode)) + return; + + return _safeWrapper(auraScript, aurEff, mode, _callImpl); + } private: AuraEffectApplicationModeFnType _callImpl; + SafeWrapperType _safeWrapper; AuraEffectHandleModes _mode; }; - class TC_GAME_API EffectAbsorbHandler : public EffectBase + class EffectAbsorbHandler final : public EffectBase { public: - using AuraEffectAbsorbFnType = void(AuraScript::*)(AuraEffect* aurEff, DamageInfo& dmgInfo, uint32& absorbAmount); + union AuraEffectAbsorbFnType + { + void(AuraScript::* Member)(AuraEffect* aurEff, DamageInfo& dmgInfo, uint32& absorbAmount); + void(*Static)(AuraEffect* aurEff, DamageInfo& dmgInfo, uint32& absorbAmount); + }; + + using SafeWrapperType = void(*)(AuraScript* auraScript, AuraEffect* aurEff, DamageInfo& dmgInfo, uint32& absorbAmount, AuraEffectAbsorbFnType callImpl); template<typename ScriptFunc> - static EffectAbsorbHandler Create(ScriptFunc handler, uint8 effIndex, uint16 auraType) + explicit EffectAbsorbHandler(ScriptFunc handler, uint8 effIndex, uint16 auraType) + : EffectBase(effIndex, auraType) { using ScriptClass = GetScriptClass_t<ScriptFunc>; static_assert(sizeof(AuraEffectAbsorbFnType) >= sizeof(ScriptFunc)); static_assert(alignof(AuraEffectAbsorbFnType) >= alignof(ScriptFunc)); - static_assert(std::is_invocable_v<ScriptFunc, ScriptClass, AuraEffect*, DamageInfo&, uint32&> - && std::is_same_v<std::invoke_result_t<ScriptFunc, ScriptClass, AuraEffect*, DamageInfo&, uint32&>, void>, - "EffectAbsorbHandler signature must be \"void HandleAbsorb(AuraEffect* aurEff, DamageInfo& dmgInfo, uint32& absorbAmount)\""); - return { reinterpret_cast<AuraEffectAbsorbFnType>(handler), effIndex, auraType }; + if constexpr (!std::is_void_v<ScriptClass>) + { + static_assert(std::is_invocable_v<ScriptFunc, ScriptClass, AuraEffect*, DamageInfo&, uint32&> + && std::is_same_v<std::invoke_result_t<ScriptFunc, ScriptClass, AuraEffect*, DamageInfo&, uint32&>, void>, + "EffectAbsorbHandler signature must be \"void HandleAbsorb(AuraEffect* aurEff, DamageInfo& dmgInfo, uint32& absorbAmount)\""); + + _callImpl = { .Member = reinterpret_cast<decltype(AuraEffectAbsorbFnType::Member)>(handler) }; + _safeWrapper = [](AuraScript* auraScript, AuraEffect* aurEff, DamageInfo& dmgInfo, uint32& absorbAmount, AuraEffectAbsorbFnType callImpl) + { + return (static_cast<ScriptClass*>(auraScript)->*reinterpret_cast<ScriptFunc>(callImpl.Member))(aurEff, dmgInfo, absorbAmount); + }; + } + else + { + static_assert(std::is_invocable_v<ScriptFunc, AuraEffect*, DamageInfo&, uint32&> + && std::is_same_v<std::invoke_result_t<ScriptFunc, AuraEffect*, DamageInfo&, uint32&>, void>, + "EffectAbsorbHandler signature must be \"static void HandleAbsorb(AuraEffect* aurEff, DamageInfo& dmgInfo, uint32& absorbAmount)\""); + + _callImpl = { .Static = reinterpret_cast<decltype(AuraEffectAbsorbFnType::Static)>(handler) }; + _safeWrapper = [](AuraScript* /*auraScript*/, AuraEffect* aurEff, DamageInfo& dmgInfo, uint32& absorbAmount, AuraEffectAbsorbFnType callImpl) + { + return reinterpret_cast<ScriptFunc>(callImpl.Static)(aurEff, dmgInfo, absorbAmount); + }; + } } - EffectAbsorbHandler(AuraEffectAbsorbFnType callImpl, uint8 effIndex, uint16 auraType); - EffectAbsorbHandler(EffectAbsorbHandler const& right) = delete; - EffectAbsorbHandler(EffectAbsorbHandler&& right) noexcept; - EffectAbsorbHandler& operator=(EffectAbsorbHandler const& right) = delete; - EffectAbsorbHandler& operator=(EffectAbsorbHandler&& right) noexcept; - ~EffectAbsorbHandler(); - void Call(AuraScript* auraScript, AuraEffect* aurEff, DamageInfo& dmgInfo, uint32& absorbAmount) const; + void Call(AuraScript* auraScript, AuraEffect* aurEff, DamageInfo& dmgInfo, uint32& absorbAmount) const + { + return _safeWrapper(auraScript, aurEff, dmgInfo, absorbAmount, _callImpl); + } private: AuraEffectAbsorbFnType _callImpl; + SafeWrapperType _safeWrapper; }; - class TC_GAME_API EffectAbsorbHealHandler : public EffectBase + class EffectAbsorbHealHandler final : public EffectBase { public: - using AuraEffectAbsorbHealFnType = void(AuraScript::*)(AuraEffect* aurEff, HealInfo& healInfo, uint32& absorbAmount); + union AuraEffectAbsorbHealFnType + { + void(AuraScript::* Member)(AuraEffect* aurEff, HealInfo& healInfo, uint32& absorbAmount); + void(*Static)(AuraEffect* aurEff, HealInfo& healInfo, uint32& absorbAmount); + }; + + using SafeWrapperType = void(*)(AuraScript* auraScript, AuraEffect* aurEff, HealInfo& healInfo, uint32& absorbAmount, AuraEffectAbsorbHealFnType callImpl); template<typename ScriptFunc> - static EffectAbsorbHealHandler Create(ScriptFunc handler, uint8 effIndex, uint16 auraType) + explicit EffectAbsorbHealHandler(ScriptFunc handler, uint8 effIndex, uint16 auraType) + : EffectBase(effIndex, auraType) { using ScriptClass = GetScriptClass_t<ScriptFunc>; static_assert(sizeof(AuraEffectAbsorbHealFnType) >= sizeof(ScriptFunc)); static_assert(alignof(AuraEffectAbsorbHealFnType) >= alignof(ScriptFunc)); - static_assert(std::is_invocable_v<ScriptFunc, ScriptClass, AuraEffect*, HealInfo&, uint32&> - && std::is_same_v<std::invoke_result_t<ScriptFunc, ScriptClass, AuraEffect*, HealInfo&, uint32&>, void>, - "EffectAbsorbHealHandler signature must be \"void HandleAbsorb(AuraEffect* aurEff, HealInfo& healInfo, uint32& absorbAmount)\""); - return { reinterpret_cast<AuraEffectAbsorbHealFnType>(handler), effIndex, auraType }; + if constexpr (!std::is_void_v<ScriptClass>) + { + static_assert(std::is_invocable_v<ScriptFunc, ScriptClass, AuraEffect*, HealInfo&, uint32&> + && std::is_same_v<std::invoke_result_t<ScriptFunc, ScriptClass, AuraEffect*, HealInfo&, uint32&>, void>, + "EffectAbsorbHealHandler signature must be \"void HandleAbsorb(AuraEffect* aurEff, HealInfo& healInfo, uint32& absorbAmount)\""); + + _callImpl = { .Member = reinterpret_cast<decltype(AuraEffectAbsorbHealFnType::Member)>(handler) }; + _safeWrapper = [](AuraScript* auraScript, AuraEffect* aurEff, HealInfo& healInfo, uint32& absorbAmount, AuraEffectAbsorbHealFnType callImpl) + { + return (static_cast<ScriptClass*>(auraScript)->*reinterpret_cast<ScriptFunc>(callImpl.Member))(aurEff, healInfo, absorbAmount); + }; + } + else + { + static_assert(std::is_invocable_v<ScriptFunc, AuraEffect*, HealInfo&, uint32&> + && std::is_same_v<std::invoke_result_t<ScriptFunc, AuraEffect*, HealInfo&, uint32&>, void>, + "EffectAbsorbHealHandler signature must be \"static void HandleAbsorb(AuraEffect* aurEff, HealInfo& healInfo, uint32& absorbAmount)\""); + + _callImpl = { .Static = reinterpret_cast<decltype(AuraEffectAbsorbHealFnType::Static)>(handler) }; + _safeWrapper = [](AuraScript* /*auraScript*/, AuraEffect* aurEff, HealInfo& healInfo, uint32& absorbAmount, AuraEffectAbsorbHealFnType callImpl) + { + return reinterpret_cast<ScriptFunc>(callImpl.Static)(aurEff, healInfo, absorbAmount); + }; + } } - EffectAbsorbHealHandler(AuraEffectAbsorbHealFnType callImpl, uint8 effIndex, uint16 auraType); - EffectAbsorbHealHandler(EffectAbsorbHealHandler const& right) = delete; - EffectAbsorbHealHandler(EffectAbsorbHealHandler&& right) noexcept; - EffectAbsorbHealHandler& operator=(EffectAbsorbHealHandler const& right) = delete; - EffectAbsorbHealHandler& operator=(EffectAbsorbHealHandler&& right) noexcept; - ~EffectAbsorbHealHandler(); - void Call(AuraScript* auraScript, AuraEffect* aurEff, HealInfo& healInfo, uint32& absorbAmount) const; + void Call(AuraScript* auraScript, AuraEffect* aurEff, HealInfo& healInfo, uint32& absorbAmount) const + { + return _safeWrapper(auraScript, aurEff, healInfo, absorbAmount, _callImpl); + } private: AuraEffectAbsorbHealFnType _callImpl; + SafeWrapperType _safeWrapper; }; - class TC_GAME_API CheckProcHandler + class CheckProcHandler final { public: - using AuraCheckProcFnType = bool(AuraScript::*)(ProcEventInfo& eventInfo); + union AuraCheckProcFnType + { + bool(AuraScript::* Member)(ProcEventInfo& eventInfo); + bool(*Static)(ProcEventInfo& eventInfo); + }; + + using SafeWrapperType = bool(*)(AuraScript* auraScript, ProcEventInfo& eventInfo, AuraCheckProcFnType callImpl); template<typename ScriptFunc> - static CheckProcHandler Create(ScriptFunc handler) + explicit CheckProcHandler(ScriptFunc handler) { using ScriptClass = GetScriptClass_t<ScriptFunc>; static_assert(sizeof(AuraCheckProcFnType) >= sizeof(ScriptFunc)); static_assert(alignof(AuraCheckProcFnType) >= alignof(ScriptFunc)); - static_assert(std::is_invocable_v<ScriptFunc, ScriptClass, ProcEventInfo&> - && std::is_same_v<std::invoke_result_t<ScriptFunc, ScriptClass, ProcEventInfo&>, bool>, - "CheckProcHandler signature must be \"bool CheckProc(ProcEventInfo& eventInfo)\""); - return { reinterpret_cast<AuraCheckProcFnType>(handler) }; + if constexpr (!std::is_void_v<ScriptClass>) + { + static_assert(std::is_invocable_v<ScriptFunc, ScriptClass, ProcEventInfo&> + && std::is_same_v<std::invoke_result_t<ScriptFunc, ScriptClass, ProcEventInfo&>, bool>, + "CheckProcHandler signature must be \"bool CheckProc(ProcEventInfo& eventInfo)\""); + + _callImpl = { .Member = reinterpret_cast<decltype(AuraCheckProcFnType::Member)>(handler) }; + _safeWrapper = [](AuraScript* auraScript, ProcEventInfo& eventInfo, AuraCheckProcFnType callImpl) + { + return (static_cast<ScriptClass*>(auraScript)->*reinterpret_cast<ScriptFunc>(callImpl.Member))(eventInfo); + }; + } + else + { + static_assert(std::is_invocable_v<ScriptFunc, ProcEventInfo&> + && std::is_same_v<std::invoke_result_t<ScriptFunc, ProcEventInfo&>, bool>, + "CheckProcHandler signature must be \"static bool CheckProc(ProcEventInfo& eventInfo)\""); + + _callImpl = { .Static = reinterpret_cast<decltype(AuraCheckProcFnType::Static)>(handler) }; + _safeWrapper = [](AuraScript* /*auraScript*/, ProcEventInfo& eventInfo, AuraCheckProcFnType callImpl) + { + return reinterpret_cast<ScriptFunc>(callImpl.Static)(eventInfo); + }; + } } - CheckProcHandler(AuraCheckProcFnType callImpl); - CheckProcHandler(CheckProcHandler const& right) = delete; - CheckProcHandler(CheckProcHandler&& right) noexcept; - CheckProcHandler& operator=(CheckProcHandler const& right) = delete; - CheckProcHandler& operator=(CheckProcHandler&& right) noexcept; - ~CheckProcHandler(); - bool Call(AuraScript* auraScript, ProcEventInfo& eventInfo) const; + bool Call(AuraScript* auraScript, ProcEventInfo& eventInfo) const + { + return _safeWrapper(auraScript, eventInfo, _callImpl); + } private: AuraCheckProcFnType _callImpl; + SafeWrapperType _safeWrapper; }; - class TC_GAME_API CheckEffectProcHandler : public EffectBase + class CheckEffectProcHandler final : public EffectBase { public: - using AuraCheckEffectProcFnType = bool(AuraScript::*)(AuraEffect const* aurEff, ProcEventInfo& eventInfo); + union AuraCheckEffectProcFnType + { + bool(AuraScript::* Member)(AuraEffect const* aurEff, ProcEventInfo& eventInfo); + bool(*Static)(AuraEffect const* aurEff, ProcEventInfo& eventInfo); + }; + + using SafeWrapperType = bool(*)(AuraScript* auraScript, AuraEffect const* aurEff, ProcEventInfo& eventInfo, AuraCheckEffectProcFnType callImpl); template<typename ScriptFunc> - static CheckEffectProcHandler Create(ScriptFunc handler, uint8 effIndex, uint16 auraType) + explicit CheckEffectProcHandler(ScriptFunc handler, uint8 effIndex, uint16 auraType) + : EffectBase(effIndex, auraType) { using ScriptClass = GetScriptClass_t<ScriptFunc>; static_assert(sizeof(AuraCheckEffectProcFnType) >= sizeof(ScriptFunc)); static_assert(alignof(AuraCheckEffectProcFnType) >= alignof(ScriptFunc)); - static_assert(std::is_invocable_v<ScriptFunc, ScriptClass, AuraEffect const*, ProcEventInfo&> - && std::is_same_v<std::invoke_result_t<ScriptFunc, ScriptClass, AuraEffect const*, ProcEventInfo&>, bool>, - "CheckEffectProcHandler signature must be \"bool CheckProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)\""); - return { reinterpret_cast<AuraCheckEffectProcFnType>(handler), effIndex, auraType }; + if constexpr (!std::is_void_v<ScriptClass>) + { + static_assert(std::is_invocable_v<ScriptFunc, ScriptClass, AuraEffect const*, ProcEventInfo&> + && std::is_same_v<std::invoke_result_t<ScriptFunc, ScriptClass, AuraEffect const*, ProcEventInfo&>, bool>, + "CheckEffectProcHandler signature must be \"bool CheckProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)\""); + + _callImpl = { .Member = reinterpret_cast<decltype(AuraCheckEffectProcFnType::Member)>(handler) }; + _safeWrapper = [](AuraScript* auraScript, AuraEffect const* aurEff, ProcEventInfo& eventInfo, AuraCheckEffectProcFnType callImpl) + { + return (static_cast<ScriptClass*>(auraScript)->*reinterpret_cast<ScriptFunc>(callImpl.Member))(aurEff, eventInfo); + }; + } + else + { + static_assert(std::is_invocable_v<ScriptFunc, AuraEffect const*, ProcEventInfo&> + && std::is_same_v<std::invoke_result_t<ScriptFunc, AuraEffect const*, ProcEventInfo&>, bool>, + "CheckEffectProcHandler signature must be \"static bool CheckProc(AuraEffect const* aurEff, ProcEventInfo& eventInfo)\""); + + _callImpl = { .Static = reinterpret_cast<decltype(AuraCheckEffectProcFnType::Static)>(handler) }; + _safeWrapper = [](AuraScript* /*auraScript*/, AuraEffect const* aurEff, ProcEventInfo& eventInfo, AuraCheckEffectProcFnType callImpl) + { + return reinterpret_cast<ScriptFunc>(callImpl.Static)(aurEff, eventInfo); + }; + } } - CheckEffectProcHandler(AuraCheckEffectProcFnType callImpl, uint8 effIndex, uint16 auraType); - CheckEffectProcHandler(CheckEffectProcHandler const& right) = delete; - CheckEffectProcHandler(CheckEffectProcHandler&& right) noexcept; - CheckEffectProcHandler& operator=(CheckEffectProcHandler const& right) = delete; - CheckEffectProcHandler& operator=(CheckEffectProcHandler&& right) noexcept; - ~CheckEffectProcHandler(); - bool Call(AuraScript* auraScript, AuraEffect const* aurEff, ProcEventInfo& eventInfo) const; + bool Call(AuraScript* auraScript, AuraEffect const* aurEff, ProcEventInfo& eventInfo) const + { + return _safeWrapper(auraScript, aurEff, eventInfo, _callImpl); + } private: AuraCheckEffectProcFnType _callImpl; + SafeWrapperType _safeWrapper; }; - class TC_GAME_API AuraProcHandler + class AuraProcHandler final { public: - using AuraProcFnType = void(AuraScript::*)(ProcEventInfo&); + union AuraProcFnType + { + void(AuraScript::* Member)(ProcEventInfo& eventInfo); + void(*Static)(ProcEventInfo& eventInfo); + }; + + using SafeWrapperType = void(*)(AuraScript* auraScript, ProcEventInfo& eventInfo, AuraProcFnType callImpl); template<typename ScriptFunc> - static AuraProcHandler Create(ScriptFunc handler) + explicit AuraProcHandler(ScriptFunc handler) { using ScriptClass = GetScriptClass_t<ScriptFunc>; static_assert(sizeof(AuraProcFnType) >= sizeof(ScriptFunc)); static_assert(alignof(AuraProcFnType) >= alignof(ScriptFunc)); - static_assert(std::is_invocable_v<ScriptFunc, ScriptClass, ProcEventInfo&> - && std::is_same_v<std::invoke_result_t<ScriptFunc, ScriptClass, ProcEventInfo&>, void>, - "AuraProcHandler signature must be \"void HandleProc(ProcEventInfo& eventInfo)\""); - return { reinterpret_cast<AuraProcFnType>(handler) }; + if constexpr (!std::is_void_v<ScriptClass>) + { + static_assert(std::is_invocable_v<ScriptFunc, ScriptClass, ProcEventInfo&> + && std::is_same_v<std::invoke_result_t<ScriptFunc, ScriptClass, ProcEventInfo&>, void>, + "AuraProcHandler signature must be \"void HandleProc(ProcEventInfo& eventInfo)\""); + + _callImpl = { .Member = reinterpret_cast<decltype(AuraProcFnType::Member)>(handler) }; + _safeWrapper = [](AuraScript* auraScript, ProcEventInfo& eventInfo, AuraProcFnType callImpl) + { + return (static_cast<ScriptClass*>(auraScript)->*reinterpret_cast<ScriptFunc>(callImpl.Member))(eventInfo); + }; + } + else + { + static_assert(std::is_invocable_v<ScriptFunc, ProcEventInfo&> + && std::is_same_v<std::invoke_result_t<ScriptFunc, ProcEventInfo&>, void>, + "AuraProcHandler signature must be \"static void HandleProc(ProcEventInfo& eventInfo)\""); + + _callImpl = { .Member = reinterpret_cast<decltype(AuraProcFnType::Member)>(handler) }; + _safeWrapper = [](AuraScript* /*auraScript*/, ProcEventInfo& eventInfo, AuraProcFnType callImpl) + { + return reinterpret_cast<ScriptFunc>(callImpl.Member)(eventInfo); + }; + } } - AuraProcHandler(AuraProcFnType callImpl); - AuraProcHandler(AuraProcHandler const& right) = delete; - AuraProcHandler(AuraProcHandler&& right) noexcept; - AuraProcHandler& operator=(AuraProcHandler const& right) = delete; - AuraProcHandler& operator=(AuraProcHandler&& right) noexcept; - virtual ~AuraProcHandler(); - void Call(AuraScript* auraScript, ProcEventInfo& eventInfo) const; + void Call(AuraScript* auraScript, ProcEventInfo& eventInfo) const + { + return _safeWrapper(auraScript, eventInfo, _callImpl); + } private: AuraProcFnType _callImpl; + SafeWrapperType _safeWrapper; }; - class TC_GAME_API EffectProcHandler : public EffectBase + class EffectProcHandler final : public EffectBase { public: - using AuraEffectProcFnType = void(AuraScript::*)(AuraEffect*, ProcEventInfo&); + union AuraEffectProcFnType + { + void(AuraScript::* Member)(AuraEffect* aurEff, ProcEventInfo& eventInfo); + void(*Static)(AuraEffect* aurEff, ProcEventInfo& eventInfo); + }; + + using SafeWrapperType = void (*)(AuraScript* auraScript, AuraEffect* aurEff, ProcEventInfo& eventInfo, AuraEffectProcFnType callImpl); template<typename ScriptFunc> - static EffectProcHandler Create(ScriptFunc handler, uint8 effIndex, uint16 auraType) + explicit EffectProcHandler(ScriptFunc handler, uint8 effIndex, uint16 auraType) + : EffectBase(effIndex, auraType) { using ScriptClass = GetScriptClass_t<ScriptFunc>; static_assert(sizeof(AuraEffectProcFnType) >= sizeof(ScriptFunc)); static_assert(alignof(AuraEffectProcFnType) >= alignof(ScriptFunc)); - static_assert(std::is_invocable_v<ScriptFunc, ScriptClass, AuraEffect*, ProcEventInfo&> - && std::is_same_v<std::invoke_result_t<ScriptFunc, ScriptClass, AuraEffect*, ProcEventInfo&>, void>, - "EffectProcHandler signature must be \"void HandleProc(AuraEffect* aurEff, ProcEventInfo& eventInfo)\""); - return { reinterpret_cast<AuraEffectProcFnType>(handler), effIndex, auraType }; + if constexpr (!std::is_void_v<ScriptClass>) + { + static_assert(std::is_invocable_v<ScriptFunc, ScriptClass, AuraEffect*, ProcEventInfo&> + && std::is_same_v<std::invoke_result_t<ScriptFunc, ScriptClass, AuraEffect*, ProcEventInfo&>, void>, + "EffectProcHandler signature must be \"void HandleProc(AuraEffect* aurEff, ProcEventInfo& eventInfo)\""); + + _callImpl = { .Member = reinterpret_cast<decltype(AuraEffectProcFnType::Member)>(handler) }; + _safeWrapper = [](AuraScript* auraScript, AuraEffect* aurEff, ProcEventInfo& eventInfo, AuraEffectProcFnType callImpl) + { + return (static_cast<ScriptClass*>(auraScript)->*reinterpret_cast<ScriptFunc>(callImpl.Member))(aurEff, eventInfo); + }; + } + else + { + static_assert(std::is_invocable_v<ScriptFunc, AuraEffect*, ProcEventInfo&> + && std::is_same_v<std::invoke_result_t<ScriptFunc, AuraEffect*, ProcEventInfo&>, void>, + "EffectProcHandler signature must be \"static void HandleProc(AuraEffect* aurEff, ProcEventInfo& eventInfo)\""); + + _callImpl = { .Static = reinterpret_cast<decltype(AuraEffectProcFnType::Static)>(handler) }; + _safeWrapper = [](AuraScript* /*auraScript*/, AuraEffect* aurEff, ProcEventInfo& eventInfo, AuraEffectProcFnType callImpl) + { + return reinterpret_cast<ScriptFunc>(callImpl.Static)(aurEff, eventInfo); + }; + } } - EffectProcHandler(AuraEffectProcFnType callImpl, uint8 effIndex, uint16 auraType); - EffectProcHandler(EffectProcHandler const& right) = delete; - EffectProcHandler(EffectProcHandler&& right) noexcept; - EffectProcHandler& operator=(EffectProcHandler const& right) = delete; - EffectProcHandler& operator=(EffectProcHandler&& right) noexcept; - ~EffectProcHandler(); - void Call(AuraScript* auraScript, AuraEffect* aurEff, ProcEventInfo& eventInfo) const; + void Call(AuraScript* auraScript, AuraEffect* aurEff, ProcEventInfo& eventInfo) const + { + return _safeWrapper(auraScript, aurEff, eventInfo, _callImpl); + } private: AuraEffectProcFnType _callImpl; + SafeWrapperType _safeWrapper; }; - class TC_GAME_API EnterLeaveCombatHandler + class EnterLeaveCombatHandler final { public: - using AuraEnterLeaveCombatFnType = void(AuraScript::*)(bool); + using AuraEnterLeaveCombatFnType = void(AuraScript::*)(bool isNowInCombat); + + using SafeWrapperType = void(*)(AuraScript* auraScript, bool isNowInCombat, AuraEnterLeaveCombatFnType callImpl); template<typename ScriptFunc> - static EnterLeaveCombatHandler Create(ScriptFunc handler) + explicit EnterLeaveCombatHandler(ScriptFunc handler) { using ScriptClass = GetScriptClass_t<ScriptFunc>; static_assert(sizeof(AuraEnterLeaveCombatFnType) >= sizeof(ScriptFunc)); static_assert(alignof(AuraEnterLeaveCombatFnType) >= alignof(ScriptFunc)); + static_assert(std::is_invocable_v<ScriptFunc, ScriptClass, bool> && std::is_same_v<std::invoke_result_t<ScriptFunc, ScriptClass, bool>, void>, "EnterLeaveCombatHandler signature must be \"void HandleEnterLeaveCombat(bool isNowInCombat)\""); - return { reinterpret_cast<AuraEnterLeaveCombatFnType>(handler) }; + _callImpl = reinterpret_cast<AuraEnterLeaveCombatFnType>(handler); + _safeWrapper = [](AuraScript* auraScript, bool isNowInCombat, AuraEnterLeaveCombatFnType callImpl) + { + return (static_cast<ScriptClass*>(auraScript)->*reinterpret_cast<ScriptFunc>(callImpl))(isNowInCombat); + }; } - EnterLeaveCombatHandler(AuraEnterLeaveCombatFnType callImpl); - EnterLeaveCombatHandler(EnterLeaveCombatHandler const& right) = delete; - EnterLeaveCombatHandler(EnterLeaveCombatHandler&& right) noexcept; - EnterLeaveCombatHandler& operator=(EnterLeaveCombatHandler const& right) = delete; - EnterLeaveCombatHandler& operator=(EnterLeaveCombatHandler&& right) noexcept; - ~EnterLeaveCombatHandler(); - void Call(AuraScript* auraScript, bool isNowInCombat) const; + void Call(AuraScript* auraScript, bool isNowInCombat) const + { + return _safeWrapper(auraScript, isNowInCombat, _callImpl); + } private: AuraEnterLeaveCombatFnType _callImpl; + SafeWrapperType _safeWrapper; }; // left for custom compatibility only, DO NOT USE - #define PrepareAuraScript(CLASSNAME) using silence_semicolon_warning_2 = void + #define PrepareAuraScript(CLASSNAME) public: AuraScript(); @@ -1374,7 +1932,7 @@ public: // example: OnEffectApply += AuraEffectApplyFn(class::function); // where function is: bool function (Unit* target); HookList<CheckAreaTargetHandler> DoCheckAreaTarget; - #define AuraCheckAreaTargetFn(F) CheckAreaTargetHandler::Create(&F) + #define AuraCheckAreaTargetFn(F) CheckAreaTargetHandler(&F) // executed when aura is dispelled by a unit // example: OnDispel += AuraDispelFn(class::function); @@ -1384,7 +1942,7 @@ public: // example: AfterDispel += AuraDispelFn(class::function); // where function is: void function (DispelInfo* dispelInfo); HookList<AuraDispelHandler> AfterDispel; - #define AuraDispelFn(F) AuraDispelHandler::Create(&F) + #define AuraDispelFn(F) AuraDispelHandler(&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 @@ -1395,7 +1953,7 @@ public: // example: AfterEffectApply += AuraEffectApplyFn(class::function, EffectIndexSpecifier, EffectAuraNameSpecifier, AuraEffectHandleModes); // where function is: void function (AuraEffect const* aurEff, AuraEffectHandleModes mode); HookList<EffectApplyHandler> AfterEffectApply; - #define AuraEffectApplyFn(F, I, N, M) EffectApplyHandler::Create(&F, I, N, M) + #define AuraEffectApplyFn(F, I, N, M) EffectApplyHandler(&F, I, N, M) // executed after aura effect is removed with specified mode from 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 @@ -1406,50 +1964,50 @@ public: // example: AfterEffectRemove += AuraEffectRemoveFn(class::function, EffectIndexSpecifier, EffectAuraNameSpecifier, AuraEffectHandleModes); // where function is: void function (AuraEffect const* aurEff, AuraEffectHandleModes mode); HookList<EffectApplyHandler> AfterEffectRemove; - #define AuraEffectRemoveFn(F, I, N, M) EffectApplyHandler::Create(&F, I, N, M) + #define AuraEffectRemoveFn(F, I, N, M) EffectApplyHandler(&F, I, N, M) // executed when periodic aura effect ticks on target // example: OnEffectPeriodic += AuraEffectPeriodicFn(class::function, EffectIndexSpecifier, EffectAuraNameSpecifier); // where function is: void function (AuraEffect const* aurEff); HookList<EffectPeriodicHandler> OnEffectPeriodic; - #define AuraEffectPeriodicFn(F, I, N) EffectPeriodicHandler::Create(&F, I, N) + #define AuraEffectPeriodicFn(F, I, N) EffectPeriodicHandler(&F, I, N) // executed when periodic aura effect is updated // example: OnEffectUpdatePeriodic += AuraEffectUpdatePeriodicFn(class::function, EffectIndexSpecifier, EffectAuraNameSpecifier); // where function is: void function (AuraEffect* aurEff); HookList<EffectUpdatePeriodicHandler> OnEffectUpdatePeriodic; - #define AuraEffectUpdatePeriodicFn(F, I, N) EffectUpdatePeriodicHandler::Create(&F, I, N) + #define AuraEffectUpdatePeriodicFn(F, I, N) EffectUpdatePeriodicHandler(&F, I, N) // executed when aura effect calculates amount // example: DoEffectCalcAmount += AuraEffectCalcAmounFn(class::function, EffectIndexSpecifier, EffectAuraNameSpecifier); // where function is: void function (AuraEffect* aurEff, int32& amount, bool& canBeRecalculated); HookList<EffectCalcAmountHandler> DoEffectCalcAmount; - #define AuraEffectCalcAmountFn(F, I, N) EffectCalcAmountHandler::Create(&F, I, N) + #define AuraEffectCalcAmountFn(F, I, N) EffectCalcAmountHandler(&F, I, N) // executed when aura effect calculates periodic data // example: DoEffectCalcPeriodic += AuraEffectCalcPeriodicFn(class::function, EffectIndexSpecifier, EffectAuraNameSpecifier); // where function is: void function (AuraEffect const* aurEff, bool& isPeriodic, int32& amplitude); HookList<EffectCalcPeriodicHandler> DoEffectCalcPeriodic; - #define AuraEffectCalcPeriodicFn(F, I, N) EffectCalcPeriodicHandler::Create(&F, I, N) + #define AuraEffectCalcPeriodicFn(F, I, N) EffectCalcPeriodicHandler(&F, I, N) // executed when aura effect calculates spellmod // example: DoEffectCalcSpellMod += AuraEffectCalcSpellModFn(class::function, EffectIndexSpecifier, EffectAuraNameSpecifier); // where function is: void function (AuraEffect const* aurEff, SpellModifier*& spellMod); HookList<EffectCalcSpellModHandler> DoEffectCalcSpellMod; - #define AuraEffectCalcSpellModFn(F, I, N) EffectCalcSpellModHandler::Create(&F, I, N) + #define AuraEffectCalcSpellModFn(F, I, N) EffectCalcSpellModHandler(&F, I, N) // executed when aura effect calculates crit chance for dots and hots // example: DoEffectCalcCritChance += AuraEffectCalcCritChanceFn(class::function, EffectIndexSpecifier, EffectAuraNameSpecifier); // where function is: void function (AuraEffect const* aurEff, Unit* victim, float& critChance); HookList<EffectCalcCritChanceHandler> DoEffectCalcCritChance; - #define AuraEffectCalcCritChanceFn(F, I, N) EffectCalcCritChanceHandler::Create(&F, I, N) + #define AuraEffectCalcCritChanceFn(F, I, N) EffectCalcCritChanceHandler(&F, I, N) // executed when absorb aura effect is going to reduce damage // example: OnEffectAbsorb += AuraEffectAbsorbFn(class::function, EffectIndexSpecifier); // where function is: void function (AuraEffect* aurEff, DamageInfo& dmgInfo, uint32& absorbAmount); HookList<EffectAbsorbHandler> OnEffectAbsorb; - #define AuraEffectAbsorbFn(F, I) EffectAbsorbHandler::Create(&F, I, SPELL_AURA_SCHOOL_ABSORB) - #define AuraEffectAbsorbOverkillFn(F, I) EffectAbsorbHandler::Create(&F, I, SPELL_AURA_SCHOOL_ABSORB_OVERKILL) + #define AuraEffectAbsorbFn(F, I) EffectAbsorbHandler(&F, I, SPELL_AURA_SCHOOL_ABSORB) + #define AuraEffectAbsorbOverkillFn(F, I) EffectAbsorbHandler(&F, I, SPELL_AURA_SCHOOL_ABSORB_OVERKILL) // executed after absorb aura effect reduced damage to target - absorbAmount is real amount absorbed by aura // example: AfterEffectAbsorb += AuraEffectAbsorbFn(class::function, EffectIndexSpecifier); @@ -1460,7 +2018,7 @@ public: // example: OnEffectAbsorbHeal += AuraEffectAbsorbHealFn(class::function, EffectIndexSpecifier); // where function is: void function (AuraEffect const* aurEff, HealInfo& healInfo, uint32& absorbAmount); HookList<EffectAbsorbHealHandler> OnEffectAbsorbHeal; - #define AuraEffectAbsorbHealFn(F, I) EffectAbsorbHealHandler::Create(&F, I, SPELL_AURA_SCHOOL_HEAL_ABSORB) + #define AuraEffectAbsorbHealFn(F, I) EffectAbsorbHealHandler(&F, I, SPELL_AURA_SCHOOL_HEAL_ABSORB) // executed after absorb aura effect reduced heal to target - absorbAmount is real amount absorbed by aura // example: AfterEffectAbsorbHeal += AuraEffectAbsorbHealFn(class::function, EffectIndexSpecifier); @@ -1471,7 +2029,7 @@ public: // example: OnEffectManaShield += AuraEffectManaShieldFn(class::function, EffectIndexSpecifier); // where function is: void function (AuraEffect* aurEff, DamageInfo& dmgInfo, uint32& absorbAmount); HookList<EffectAbsorbHandler> OnEffectManaShield; - #define AuraEffectManaShieldFn(F, I) EffectAbsorbHandler::Create(&F, I, SPELL_AURA_MANA_SHIELD) + #define AuraEffectManaShieldFn(F, I) EffectAbsorbHandler(&F, I, SPELL_AURA_MANA_SHIELD) // executed after mana shield aura effect reduced damage to target - absorbAmount is real amount absorbed by aura // example: AfterEffectManaShield += AuraEffectManaShieldFn(class::function, EffectIndexSpecifier); @@ -1482,19 +2040,19 @@ public: // example: OnEffectSplit += AuraEffectSplitFn(class::function, EffectIndexSpecifier); // where function is: void function (AuraEffect* aurEff, DamageInfo& dmgInfo, uint32& splitAmount); HookList<EffectAbsorbHandler> OnEffectSplit; - #define AuraEffectSplitFn(F, I) EffectAbsorbHandler::Create(&F, I, SPELL_AURA_SPLIT_DAMAGE_PCT) + #define AuraEffectSplitFn(F, I) EffectAbsorbHandler(&F, I, SPELL_AURA_SPLIT_DAMAGE_PCT) // executed when aura checks if it can proc // example: DoCheckProc += AuraCheckProcFn(class::function); // where function is: bool function (ProcEventInfo& eventInfo); HookList<CheckProcHandler> DoCheckProc; - #define AuraCheckProcFn(F) CheckProcHandler::Create(&F) + #define AuraCheckProcFn(F) CheckProcHandler(&F) // executed when aura effect checks if it can proc the aura // example: DoCheckEffectProc += AuraCheckEffectProcFn(class::function, EffectIndexSpecifier, EffectAuraNameSpecifier); // where function is bool function (AuraEffect const* aurEff, ProcEventInfo& eventInfo); HookList<CheckEffectProcHandler> DoCheckEffectProc; - #define AuraCheckEffectProcFn(F, I, N) CheckEffectProcHandler::Create(&F, I, N) + #define AuraCheckEffectProcFn(F, I, N) CheckEffectProcHandler(&F, I, N) // executed before aura procs (possibility to prevent charge drop/cooldown) // example: DoPrepareProc += AuraProcFn(class::function); @@ -1508,7 +2066,7 @@ public: // example: AfterProc += AuraProcFn(class::function); // where function is: void function (ProcEventInfo& eventInfo); HookList<AuraProcHandler> AfterProc; - #define AuraProcFn(F) AuraProcHandler::Create(&F) + #define AuraProcFn(F) AuraProcHandler(&F) // executed when aura effect procs // example: OnEffectProc += AuraEffectProcFn(class::function, EffectIndexSpecifier, EffectAuraNameSpecifier); @@ -1518,13 +2076,13 @@ public: // example: AfterEffectProc += AuraEffectProcFn(class::function, EffectIndexSpecifier, EffectAuraNameSpecifier); // where function is: void function (AuraEffect* aurEff, ProcEventInfo& procInfo); HookList<EffectProcHandler> AfterEffectProc; - #define AuraEffectProcFn(F, I, N) EffectProcHandler::Create(&F, I, N) + #define AuraEffectProcFn(F, I, N) EffectProcHandler(&F, I, N) // executed when target enters or leaves combat // example: OnEnterLeaveCombat += AuraEnterLeaveCombatFn(class::function) // where function is: void function (bool isNowInCombat); HookList<EnterLeaveCombatHandler> OnEnterLeaveCombat; - #define AuraEnterLeaveCombatFn(F) EnterLeaveCombatHandler::Create(&F) + #define AuraEnterLeaveCombatFn(F) EnterLeaveCombatHandler(&F) // AuraScript interface - hook/effect execution manipulators diff --git a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp index 8546a606d64..3d9b5808204 100644 --- a/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp +++ b/src/server/scripts/Northrend/IcecrownCitadel/icecrown_citadel.cpp @@ -1460,7 +1460,7 @@ class spell_icc_harvest_blight_specimen : public SpellScript // 72585 - Soul Missile class spell_icc_soul_missile : public SpellScript { - void RelocateDest(SpellDestination& dest) + static void RelocateDest(SpellDestination& dest) { static Position const offset = { 0.0f, 0.0f, 200.0f, 0.0f }; dest.RelocateOffset(offset); diff --git a/src/server/scripts/Spells/spell_shaman.cpp b/src/server/scripts/Spells/spell_shaman.cpp index 1bd95e858ae..d179e94d0b0 100644 --- a/src/server/scripts/Spells/spell_shaman.cpp +++ b/src/server/scripts/Spells/spell_shaman.cpp @@ -212,7 +212,7 @@ class spell_sha_ancestral_guidance_heal : public SpellScript return ValidateSpellInfo({ SPELL_SHAMAN_ANCESTRAL_GUIDANCE }); } - void ResizeTargets(std::list<WorldObject*>& targets) + static void ResizeTargets(std::list<WorldObject*>& targets) { Trinity::SelectRandomInjuredTargets(targets, 3, true); } |