mirror of
https://github.com/TrinityCore/TrinityCore.git
synced 2026-01-16 07:30:42 +01:00
Core/Spells: Added additional validation to loading spell_linked_spell to prevent infinite loops
Closes #28753
This commit is contained in:
@@ -1357,7 +1357,7 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b
|
||||
// apply linked auras
|
||||
if (apply)
|
||||
{
|
||||
if (std::vector<int32> const* spellTriggered = sSpellMgr->GetSpellLinked(GetId() + SPELL_LINK_AURA))
|
||||
if (std::vector<int32> const* spellTriggered = sSpellMgr->GetSpellLinked(SPELL_LINK_AURA, GetId()))
|
||||
{
|
||||
for (std::vector<int32>::const_iterator itr = spellTriggered->begin(); itr != spellTriggered->end(); ++itr)
|
||||
{
|
||||
@@ -1371,7 +1371,7 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b
|
||||
else
|
||||
{
|
||||
// remove linked auras
|
||||
if (std::vector<int32> const* spellTriggered = sSpellMgr->GetSpellLinked(-(int32)GetId()))
|
||||
if (std::vector<int32> const* spellTriggered = sSpellMgr->GetSpellLinked(SPELL_LINK_REMOVE, GetId()))
|
||||
{
|
||||
for (std::vector<int32>::const_iterator itr = spellTriggered->begin(); itr != spellTriggered->end(); ++itr)
|
||||
{
|
||||
@@ -1383,7 +1383,7 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b
|
||||
.SetOriginalCastId(GetCastId()));
|
||||
}
|
||||
}
|
||||
if (std::vector<int32> const* spellTriggered = sSpellMgr->GetSpellLinked(GetId() + SPELL_LINK_AURA))
|
||||
if (std::vector<int32> const* spellTriggered = sSpellMgr->GetSpellLinked(SPELL_LINK_AURA, GetId()))
|
||||
{
|
||||
for (std::vector<int32>::const_iterator itr = spellTriggered->begin(); itr != spellTriggered->end(); ++itr)
|
||||
{
|
||||
@@ -1398,7 +1398,7 @@ void Aura::HandleAuraSpecificMods(AuraApplication const* aurApp, Unit* caster, b
|
||||
else if (apply)
|
||||
{
|
||||
// modify stack amount of linked auras
|
||||
if (std::vector<int32> const* spellTriggered = sSpellMgr->GetSpellLinked(GetId() + SPELL_LINK_AURA))
|
||||
if (std::vector<int32> const* spellTriggered = sSpellMgr->GetSpellLinked(SPELL_LINK_AURA, GetId()))
|
||||
{
|
||||
for (std::vector<int32>::const_iterator itr = spellTriggered->begin(); itr != spellTriggered->end(); ++itr)
|
||||
if (*itr > 0)
|
||||
|
||||
@@ -3205,7 +3205,7 @@ void Spell::DoTriggersOnSpellHit(Unit* unit)
|
||||
|
||||
// trigger linked auras remove/apply
|
||||
/// @todo remove/cleanup this, as this table is not documented and people are doing stupid things with it
|
||||
if (std::vector<int32> const* spellTriggered = sSpellMgr->GetSpellLinked(m_spellInfo->Id + SPELL_LINK_HIT))
|
||||
if (std::vector<int32> const* spellTriggered = sSpellMgr->GetSpellLinked(SPELL_LINK_HIT, m_spellInfo->Id))
|
||||
{
|
||||
for (std::vector<int32>::const_iterator i = spellTriggered->begin(); i != spellTriggered->end(); ++i)
|
||||
{
|
||||
@@ -3746,7 +3746,7 @@ void Spell::_cast(bool skipCheck)
|
||||
|
||||
CallScriptAfterCastHandlers();
|
||||
|
||||
if (std::vector<int32> const* spell_triggered = sSpellMgr->GetSpellLinked(m_spellInfo->Id))
|
||||
if (std::vector<int32> const* spell_triggered = sSpellMgr->GetSpellLinked(SPELL_LINK_CAST, m_spellInfo->Id))
|
||||
{
|
||||
for (int32 id : *spell_triggered)
|
||||
{
|
||||
|
||||
@@ -625,9 +625,9 @@ bool SpellMgr::IsArenaAllowedEnchancment(uint32 ench_id) const
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<int32> const* SpellMgr::GetSpellLinked(int32 spell_id) const
|
||||
std::vector<int32> const* SpellMgr::GetSpellLinked(SpellLinkedType type, uint32 spell_id) const
|
||||
{
|
||||
return Trinity::Containers::MapGetValuePtr(mSpellLinkedMap, spell_id);
|
||||
return Trinity::Containers::MapGetValuePtr(mSpellLinkedMap, { type, spell_id });
|
||||
}
|
||||
|
||||
PetLevelupSpellSet const* SpellMgr::GetPetLevelupSpellList(uint32 petFamily) const
|
||||
@@ -2047,7 +2047,7 @@ void SpellMgr::LoadSpellLinked()
|
||||
|
||||
int32 trigger = fields[0].GetInt32();
|
||||
int32 effect = fields[1].GetInt32();
|
||||
int32 type = fields[2].GetUInt8();
|
||||
SpellLinkedType type = SpellLinkedType(fields[2].GetUInt8());
|
||||
|
||||
SpellInfo const* spellInfo = GetSpellInfo(abs(trigger), DIFFICULTY_NONE);
|
||||
if (!spellInfo)
|
||||
@@ -2057,11 +2057,13 @@ void SpellMgr::LoadSpellLinked()
|
||||
}
|
||||
|
||||
if (effect >= 0)
|
||||
{
|
||||
for (SpellEffectInfo const& spellEffectInfo : spellInfo->GetEffects())
|
||||
{
|
||||
if (spellEffectInfo.CalcValue() == abs(effect))
|
||||
TC_LOG_ERROR("sql.sql", "The spell {} Effect: {} listed in `spell_linked_spell` has same bp{} like effect (possible hack).", abs(trigger), abs(effect), uint32(spellEffectInfo.EffectIndex));
|
||||
}
|
||||
}
|
||||
|
||||
spellInfo = GetSpellInfo(abs(effect), DIFFICULTY_NONE);
|
||||
if (!spellInfo)
|
||||
@@ -2070,14 +2072,31 @@ void SpellMgr::LoadSpellLinked()
|
||||
continue;
|
||||
}
|
||||
|
||||
if (type) //we will find a better way when more types are needed
|
||||
if (type < SPELL_LINK_CAST || type > SPELL_LINK_REMOVE)
|
||||
{
|
||||
if (trigger > 0)
|
||||
trigger += SPELL_LINKED_MAX_SPELLS * type;
|
||||
else
|
||||
trigger -= SPELL_LINKED_MAX_SPELLS * type;
|
||||
TC_LOG_ERROR("sql.sql", "The spell trigger {}, effect {} listed in `spell_linked_spell` has invalid link type {}, skipped.", trigger, effect, type);
|
||||
continue;
|
||||
}
|
||||
mSpellLinkedMap[trigger].push_back(effect);
|
||||
|
||||
if (trigger < 0)
|
||||
{
|
||||
if (type != SPELL_LINK_CAST)
|
||||
TC_LOG_ERROR("sql.sql", "The spell trigger {} listed in `spell_linked_spell` has invalid link type {}, changed to 0.", trigger, type);
|
||||
|
||||
trigger = -trigger;
|
||||
type = SPELL_LINK_REMOVE;
|
||||
}
|
||||
|
||||
if (type != SPELL_LINK_AURA)
|
||||
{
|
||||
if (trigger == effect)
|
||||
{
|
||||
TC_LOG_ERROR("sql.sql", "The spell trigger {}, effect {} listed in `spell_linked_spell` triggers itself (infinite loop), skipped.", trigger, effect);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
mSpellLinkedMap[{ type, trigger }].push_back(effect);
|
||||
|
||||
++count;
|
||||
} while (result->NextRow());
|
||||
|
||||
@@ -118,14 +118,12 @@ enum SpellFamilyFlag
|
||||
SPELLFAMILYFLAG_SHAMAN_TOTEM_EFFECTS = 0x04000000 // Seems to be linked to most totems and some totem effects
|
||||
};
|
||||
|
||||
#define SPELL_LINKED_MAX_SPELLS 200000
|
||||
|
||||
enum SpellLinkedType
|
||||
{
|
||||
SPELL_LINK_CAST = 0, // +: cast; -: remove
|
||||
SPELL_LINK_HIT = 1 * 200000,
|
||||
SPELL_LINK_AURA = 2 * 200000, // +: aura; -: immune
|
||||
SPELL_LINK_REMOVE = 0
|
||||
SPELL_LINK_HIT = 1,
|
||||
SPELL_LINK_AURA = 2, // +: aura; -: immune
|
||||
SPELL_LINK_REMOVE = 3
|
||||
};
|
||||
|
||||
// Spell proc event related declarations (accessed using SpellMgr functions)
|
||||
@@ -617,7 +615,7 @@ struct PetDefaultSpellsEntry
|
||||
// < 0 for petspelldata id, > 0 for creature_id
|
||||
typedef std::map<int32, PetDefaultSpellsEntry> PetDefaultSpellsMap;
|
||||
|
||||
typedef std::unordered_map<int32, std::vector<int32>> SpellLinkedMap;
|
||||
typedef std::unordered_map<std::pair<SpellLinkedType, uint32>, std::vector<int32>> SpellLinkedMap;
|
||||
|
||||
bool IsPrimaryProfessionSkill(uint32 skill);
|
||||
|
||||
@@ -733,7 +731,7 @@ class TC_GAME_API SpellMgr
|
||||
SpellEnchantProcEntry const* GetSpellEnchantProcEvent(uint32 enchId) const;
|
||||
bool IsArenaAllowedEnchancment(uint32 ench_id) const;
|
||||
|
||||
std::vector<int32> const* GetSpellLinked(int32 spell_id) const;
|
||||
std::vector<int32> const* GetSpellLinked(SpellLinkedType type, uint32 spell_id) const;
|
||||
|
||||
PetLevelupSpellSet const* GetPetLevelupSpellList(uint32 petFamily) const;
|
||||
PetDefaultSpellsEntry const* GetPetDefaultSpellsEntry(int32 id) const;
|
||||
|
||||
Reference in New Issue
Block a user