fix(Core/Player): Unlearn invalid spells for race/class on login (#22370)

Co-authored-by: Andrew <47818697+Nyeriah@users.noreply.github.com>
This commit is contained in:
Kitzunu
2025-07-19 11:35:26 +02:00
committed by GitHub
parent 5dbcdfcbd5
commit cbd8596184
3 changed files with 34 additions and 14 deletions

View File

@@ -3101,6 +3101,28 @@ bool Player::addSpell(uint32 spellId, uint8 addSpecMask, bool updateActive, bool
return true;
}
bool Player::CheckSkillLearnedBySpell(uint32 spellId)
{
SkillLineAbilityMapBounds skill_bounds = sSpellMgr->GetSkillLineAbilityMapBounds(spellId);
for (SkillLineAbilityMap::const_iterator sla = skill_bounds.first; sla != skill_bounds.second; ++sla)
{
SkillLineEntry const* pSkill = sSkillLineStore.LookupEntry(sla->second->SkillLine);
if (!pSkill)
continue;
SkillRaceClassInfoEntry const* rcEntry = GetSkillRaceClassInfo(pSkill->id, getRace(), getClass());
if (!rcEntry)
{
LOG_ERROR("entities.player", "Player {} (GUID: {}), has spell ({}) that teach skill ({}) which is invalid for the race/class combination (Race: {}, Class: {}). Will be deleted.",
GetName(), GetGUID().GetCounter(), spellId, pSkill->id, getRace(), getClass());
return false;
}
}
return true;
}
bool Player::_addSpell(uint32 spellId, uint8 addSpecMask, bool temporary, bool learnFromSkill /*= false*/)
{
// pussywizard: this can be called to OVERWRITE currently existing spell params! usually to set active = false for lower ranks of a spell
@@ -3242,27 +3264,17 @@ bool Player::_addSpell(uint32 spellId, uint8 addSpecMask, bool temporary, bool l
{
SkillLineEntry const* pSkill = sSkillLineStore.LookupEntry(_spell_idx->second->SkillLine);
if (!pSkill)
{
continue;
}
/// @todo confirm if rogues start wth lockpicking skill at level 1 but only recieve the spell to use it at level 16
/// @todo confirm if rogues start wth lockpicking skill at level 1 but only recieve the spell to use it at level 16
// Added for runeforging, it is confirmed via sniff that this happens when death knights learn the spell, not on character creation.
if ((_spell_idx->second->AcquireMethod == SKILL_LINE_ABILITY_LEARNED_ON_SKILL_LEARN && !HasSkill(pSkill->id)) || ((pSkill->id == SKILL_LOCKPICKING || pSkill->id == SKILL_RUNEFORGING) && _spell_idx->second->TrivialSkillLineRankHigh == 0))
{
LearnDefaultSkill(pSkill->id, 0);
}
if (pSkill->id == SKILL_MOUNTS && !Has310Flyer(false))
{
for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
{
if (spellInfo->Effects[i].ApplyAuraName == SPELL_AURA_MOD_INCREASE_MOUNTED_FLIGHT_SPEED && spellInfo->Effects[i].CalcValue() == 310)
{
SetHas310Flyer(true);
}
}
}
}
}

View File

@@ -1720,6 +1720,7 @@ public:
void learnQuestRewardedSpells();
void learnQuestRewardedSpells(Quest const* quest);
void learnSpellHighRank(uint32 spellid);
bool CheckSkillLearnedBySpell(uint32 spellId);
void SetReputation(uint32 factionentry, float value);
[[nodiscard]] uint32 GetReputation(uint32 factionentry) const;
std::string const& GetGuildName();

View File

@@ -6472,9 +6472,16 @@ void Player::_LoadSpells(PreparedQueryResult result)
if (result)
{
do
// xinef: checked
addSpell((*result)[0].Get<uint32>(), (*result)[1].Get<uint8>(), true);
while (result->NextRow());
{
Field* fields = result->Fetch();
uint32 spellId = fields[0].Get<uint32>();
uint8 specMask = fields[1].Get<uint8>();
if (CheckSkillLearnedBySpell(spellId))
addSpell(spellId, specMask, true);
else
removeSpell(spellId, SPEC_MASK_ALL, false);
} while (result->NextRow());
}
}